Describe convertions in README and use Zadeh's notation
This commit is contained in:
parent
9a4241395f
commit
b42f827cc8
34
README.md
34
README.md
|
@ -101,27 +101,35 @@ API Reference automatically collected with `jazzy` is published [here](https://a
|
|||
|
||||
## `FuzzySets` Module
|
||||
|
||||
* `protocol FuzzySet`: This abstraction requires a fuzzy set to provide a `grade(forElement:)` method which accepts a parameter of an `associatedtype Universe` and returns its membership `Grade` in the set. There are 3 provided concrete implementations in this module:
|
||||
1. `struct AnyFuzzySet` - allows type erasure. It only stores a `MembershipFunction` and has non-mutable methods.
|
||||
2. `struct IterableFuzzySet` - stores a `MembershipFunction` as well as a `Sequence` of elements of the associated type `Universe`. Implements `Sequence` so that it can easily be iterated over them. The elements of the iteration over an `IterableFuzzySet` are `struct`s containing `grade` and `element` properties. It has non-mutable methods only.
|
||||
3. `struct DiscreteMutableFuzzySet` - it is "discrete" because it doesn't stores a `MembershipFunction` but instead keeps its elements and their grade in a `Dictionary`, and it is "mutable" because it contains mutable equivalents of all other methods that operate over the set (including `subscript`). A default value of `0` is returned for the grade of an element that is not in the dictionary (a different default value can be provided as well).
|
||||
### `protocol FuzzySet`
|
||||
This abstraction requires a fuzzy set to provide a `grade(forElement:)` method which accepts a parameter of an `associatedtype Universe` and returns its membership `Grade` in the set. There are 3 provided concrete implementations in this module:
|
||||
|
||||
* `protocol FuzzySetOperations` - all 3 concrete types implement it. It requires the following methods that operate on fuzzy sets:
|
||||
* `alphaCut(_:alpha:)`
|
||||
1. `struct AnyFuzzySet` - allows type erasure. It only stores a `MembershipFunction` and has non-mutable methods.
|
||||
|
||||
* `complement(method:)`
|
||||
2. `struct IterableFuzzySet` - stores a `MembershipFunction` as well as a `Sequence` of elements of the associated type `Universe`. Implements `Sequence` so that it can easily be iterated over them. The elements of the iteration over an `IterableFuzzySet` are `struct`s containing `grade` and `element` properties. It has non-mutable methods only. Includes `support`, `core` and `height` computed properties.
|
||||
|
||||
* `intersection(_:method:)`
|
||||
3. `struct DiscreteMutableFuzzySet` - it is "discrete" because it doesn't stores a `MembershipFunction` but instead keeps its elements and their grade in a `Dictionary`, and it is "mutable" because it contains mutable equivalents of all other methods that operate over the set (including `subscript`). A default value of `0` is returned for the grade of an element that is not in the dictionary (a different default value can be provided as well). Includes `support`, `core` and `height` computed properties. A bonus feature is its debug print using Zadeh's notation.
|
||||
|
||||
* `union(_:method:)`
|
||||
Convertions between the 3 types are easy and possible using the `eraseToAnyFuzzySet`, `makeIterable` and `makeDiscreteMutable` methods defined on them.
|
||||
|
||||
* `difference(_:method:)`
|
||||
### `protocol FuzzySetOperations`
|
||||
All 3 concrete types implement it. It requires the following methods that operate on fuzzy sets:
|
||||
|
||||
* `symmetricDifference(_:method:)`
|
||||
* `alphaCut(_:alpha:)`
|
||||
|
||||
* `power(_:n:)`
|
||||
* `complement(method:)`
|
||||
|
||||
* `appliedCustomFunction(_:function:)`
|
||||
* `intersection(_:method:)`
|
||||
|
||||
* `union(_:method:)`
|
||||
|
||||
* `difference(_:method:)`
|
||||
|
||||
* `symmetricDifference(_:method:)`
|
||||
|
||||
* `power(_:n:)`
|
||||
|
||||
* `appliedCustomFunction(_:function:)`
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ public struct DiscreteMutableFuzzySet<Universe: Hashable>: ExpressibleByDictiona
|
|||
extension DiscreteMutableFuzzySet: FuzzySet {
|
||||
/// - Complexity: O(1)
|
||||
public func grade(forElement element: Universe) -> Grade {
|
||||
grades[element] ?? defaultGrade
|
||||
grades[element, default: defaultGrade]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,25 @@ public extension DiscreteMutableFuzzySet {
|
|||
mutating func applyPower(_ n: Double) {
|
||||
applyFunction { Double.pow($0, n) }
|
||||
}
|
||||
|
||||
mutating func applyFunction(_ function: (Grade) -> Grade) {
|
||||
let newGradeTuples = grades.map {
|
||||
($0.key, function($0.value))
|
||||
}
|
||||
let newMap = Dictionary(uniqueKeysWithValues: newGradeTuples)
|
||||
grades = newMap
|
||||
defaultGrade = function(defaultGrade)
|
||||
sanitize()
|
||||
}
|
||||
|
||||
mutating func applyFunction(
|
||||
_ function: (Grade, Grade) -> Grade,
|
||||
whenMergingWith anotherSet: Self
|
||||
) {
|
||||
grades.merge(anotherSet.grades, uniquingKeysWith: function)
|
||||
defaultGrade = function(defaultGrade, anotherSet.defaultGrade)
|
||||
sanitize()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
@ -169,36 +188,49 @@ public extension DiscreteMutableFuzzySet {
|
|||
// MARK: - Debug
|
||||
|
||||
extension DiscreteMutableFuzzySet: CustomStringConvertible {
|
||||
/// Pretty-print contents of `self` using Zadeh's notation.
|
||||
public var description: String {
|
||||
let guts = grades.map {
|
||||
"\($0.value)/\($0.key)"
|
||||
}.joined(separator: ", ")
|
||||
}.joined(separator: " + ")
|
||||
return "<FuzzySet: {\(guts)}, other values == \(defaultGrade)>"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Convertion
|
||||
|
||||
public extension AnyFuzzySet where Universe: Hashable {
|
||||
func makeDiscreteMutable(
|
||||
takeOnly set: Set<Universe>,
|
||||
forOthersUse defaultValue: Grade = 0
|
||||
) -> DiscreteMutableFuzzySet<Universe> {
|
||||
.init(
|
||||
.init(uniqueKeysWithValues: set.map { ($0, self[$0]) }),
|
||||
defaultGrade: defaultValue
|
||||
)
|
||||
}
|
||||
|
||||
func makeDiscreteMutable<S: Sequence>(
|
||||
takeOnly sequence: S,
|
||||
forOthersUse defaultValue: Grade = 0
|
||||
) -> DiscreteMutableFuzzySet<Universe>
|
||||
where S.Element == Universe {
|
||||
.init(
|
||||
.init(uniqueKeysWithValues: sequence.map { ($0, self[$0]) }),
|
||||
defaultGrade: defaultValue
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public extension IterableFuzzySet where Universe: Hashable {
|
||||
func makeDiscreteMutable() -> DiscreteMutableFuzzySet<Universe> {
|
||||
.init(.init(uniqueKeysWithValues: sequence.map { ($0, self[$0]) }))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
extension DiscreteMutableFuzzySet {
|
||||
public mutating func applyFunction(_ function: (Grade) -> Grade) {
|
||||
let newGradeTuples = grades.map {
|
||||
($0.key, function($0.value))
|
||||
}
|
||||
let newMap = Dictionary(uniqueKeysWithValues: newGradeTuples)
|
||||
grades = newMap
|
||||
defaultGrade = function(defaultGrade)
|
||||
sanitize()
|
||||
}
|
||||
|
||||
public mutating func applyFunction(
|
||||
_ function: (Grade, Grade) -> Grade,
|
||||
whenMergingWith anotherSet: Self
|
||||
) {
|
||||
grades.merge(anotherSet.grades, uniquingKeysWith: function)
|
||||
defaultGrade = function(defaultGrade, anotherSet.defaultGrade)
|
||||
sanitize()
|
||||
}
|
||||
|
||||
private mutating func sanitize() {
|
||||
grades = grades.filter {
|
||||
$0.value != defaultGrade
|
||||
|
|
|
@ -142,12 +142,6 @@ public extension DiscreteMutableFuzzySet where Universe: CaseIterable {
|
|||
}
|
||||
}
|
||||
|
||||
public extension IterableFuzzySet where Universe: Hashable {
|
||||
func makeDiscreteMutable() -> DiscreteMutableFuzzySet<Universe> {
|
||||
.init(.init(uniqueKeysWithValues: sequence.map { ($0, self[$0]) }))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
public extension IterableFuzzySet {
|
||||
|
|
|
@ -41,8 +41,8 @@ final class DiscreteMutableFuzzySetTests: XCTestCase {
|
|||
"b": 1,
|
||||
]
|
||||
let sut = DiscreteMutableFuzzySet(parameters)
|
||||
let expected1 = "<FuzzySet: {0.69/a, 1.0/b}, other values == 0.0>"
|
||||
let expected2 = "<FuzzySet: {1.0/b, 0.69/a}, other values == 0.0>"
|
||||
let expected1 = "<FuzzySet: {0.69/a + 1.0/b}, other values == 0.0>"
|
||||
let expected2 = "<FuzzySet: {1.0/b + 0.69/a}, other values == 0.0>"
|
||||
|
||||
let result = String(describing: sut)
|
||||
|
||||
|
|
Loading…
Reference in New Issue