Add consequence method returning a fuzzy set
This commit is contained in:
parent
968e1db94f
commit
dd19a7eeac
|
@ -44,9 +44,9 @@ let ruleBase = FuzzyRuleBase {
|
|||
funding.is(.inadequate) || Ø --> risk.is(.high)
|
||||
}
|
||||
|
||||
let flc = FuzzyLinguisticController(rules: ruleBase, settings: .init(implication: .mamdani))
|
||||
let flc = FuzzyLogicController(rules: ruleBase, settings: .init(implication: .mamdani))
|
||||
|
||||
flc.consequenceGrade(for: 50, usingFact: .singleton((8.8, 42))) // result is 0.675
|
||||
flc.consequenceGrade(for: 50, usingSingletonFact: (8.8, 42)) // result is 0.675
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
import FuzzySets
|
||||
import FuzzyRelations
|
||||
|
||||
open class FuzzyLinguisticController<AntecedentUniverse, ConsequentUniverse> {
|
||||
|
||||
public var settings: OperationSettings
|
||||
public var ruleBase: FuzzyRuleBase<(AntecedentUniverse, ConsequentUniverse)>
|
||||
public var aggregatorFuction: (Grade, Grade) -> Grade
|
||||
|
||||
public init(
|
||||
rules: FuzzyRuleBase<(AntecedentUniverse, ConsequentUniverse)> = .init(),
|
||||
settings: OperationSettings = .init()
|
||||
) {
|
||||
self.ruleBase = rules
|
||||
self.settings = settings
|
||||
self.aggregatorFuction = settings.disjunction.function
|
||||
}
|
||||
|
||||
open func consequenceGrade<S: Sequence>(
|
||||
for value: ConsequentUniverse,
|
||||
usingFact fact: IterableFuzzySet<AntecedentUniverse, S>
|
||||
) -> Grade {
|
||||
ruleBase
|
||||
.map {
|
||||
FuzzySetComposition(set: fact, relation: $0.asRelation())
|
||||
}
|
||||
.map {
|
||||
$0.grade(forElement: value)
|
||||
}
|
||||
.reduce(0, aggregatorFuction)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
import FuzzySets
|
||||
import FuzzyRelations
|
||||
|
||||
open class FuzzyLogicController<AntecedentUniverse, ConsequentUniverse> {
|
||||
|
||||
public var settings: OperationSettings
|
||||
public var ruleBase: FuzzyRuleBase<(AntecedentUniverse, ConsequentUniverse)>
|
||||
public var aggregatorFunction: (Grade, Grade) -> Grade
|
||||
|
||||
public init(
|
||||
rules: FuzzyRuleBase<(AntecedentUniverse, ConsequentUniverse)> = .init(),
|
||||
settings: OperationSettings = .init(),
|
||||
aggregatorFunction: ((Grade, Grade) -> Grade)? = nil
|
||||
) {
|
||||
self.ruleBase = rules
|
||||
self.settings = settings
|
||||
self.aggregatorFunction = aggregatorFunction ?? settings.disjunction.function
|
||||
}
|
||||
|
||||
open func consequence<S: Sequence>(
|
||||
usingFact fact: IterableFuzzySet<AntecedentUniverse, S>
|
||||
) -> AnyFuzzySet<ConsequentUniverse> {
|
||||
ruleBase
|
||||
.map {
|
||||
FuzzySetComposition(set: fact, relation: $0.asRelation())
|
||||
.eraseToAnyFuzzySet()
|
||||
}
|
||||
.reduce(AnyFuzzySet<ConsequentUniverse>.empty) { partialResult, currentSet in
|
||||
.init { [aggregatorFunction] element in
|
||||
aggregatorFunction(partialResult(element), currentSet(element))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply generalized Modus Ponens to all rules using `fact` as input to the controller and return the grade membership of `value` in the fuzzy set output.
|
||||
open func consequenceGrade<S: Sequence>(
|
||||
for value: ConsequentUniverse,
|
||||
usingFact fact: IterableFuzzySet<AntecedentUniverse, S>
|
||||
) -> Grade {
|
||||
ruleBase
|
||||
.map {
|
||||
FuzzySetComposition(set: fact, relation: $0.asRelation())
|
||||
.grade(forElement: value)
|
||||
}
|
||||
.reduce(0, aggregatorFunction)
|
||||
}
|
||||
|
||||
/// Apply generalized Modus Ponens to all rules using `fact` as input to the controller and return the grade membership of `value` in the fuzzy set output.
|
||||
///
|
||||
/// Helper for the scenario when `AntecedentUniverse` does not conform to `Equatable`.
|
||||
/// One such example might be having a tuple as a universe of discourse - they still do not conform to `Equatable`, even if all of their elements are `Equatable`.
|
||||
open func consequenceGrade(
|
||||
for value: ConsequentUniverse,
|
||||
usingSingletonFact fact: AntecedentUniverse
|
||||
) -> Grade {
|
||||
consequenceGrade(for: value, usingFact: .init([fact], membershipFunction: .one))
|
||||
}
|
||||
}
|
|
@ -19,3 +19,11 @@ extension FuzzySetComposition: FuzzySet {
|
|||
}.max() ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
extension FuzzySetComposition: AnyFuzzySetRepresentable {
|
||||
public func eraseToAnyFuzzySet() -> AnyFuzzySet<V> {
|
||||
.init {
|
||||
self($0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,14 +33,18 @@ final class ControlTests: XCTestCase {
|
|||
funding.is(.inadequate) || Ø --> risk.is(.high)
|
||||
}
|
||||
|
||||
let sut = FuzzyLinguisticController(rules: ruleBase)
|
||||
let sut2 = FuzzyLinguisticController(rules: ruleBase, settings: .init(implication: .larsen))
|
||||
let sut = FuzzyLogicController(rules: ruleBase)
|
||||
let sut2 = FuzzyLogicController(rules: ruleBase, settings: .init(implication: .larsen))
|
||||
|
||||
let fact = IterableFuzzySet.singleton((8.8, 42.0))
|
||||
let tuple = (8.8, 42.0)
|
||||
let fact = IterableFuzzySet.singleton(tuple)
|
||||
|
||||
let result1 = sut.consequenceGrade(for: 100, usingFact: fact)
|
||||
let result2 = sut.consequenceGrade(for: 0, usingFact: fact)
|
||||
let result3 = sut.consequenceGrade(for: 50, usingFact: fact)
|
||||
let result11 = sut.consequenceGrade(for: 100, usingSingletonFact: tuple)
|
||||
let result22 = sut.consequenceGrade(for: 0, usingSingletonFact: tuple)
|
||||
let result33 = sut.consequenceGrade(for: 50, usingSingletonFact: tuple)
|
||||
|
||||
let result4 = sut2.consequenceGrade(for: 100, usingFact: fact)
|
||||
let result5 = sut2.consequenceGrade(for: 0, usingFact: fact)
|
||||
|
@ -49,6 +53,9 @@ final class ControlTests: XCTestCase {
|
|||
XCTAssertApproximatelyEqual(1.0, result1)
|
||||
XCTAssertApproximatelyEqual(0.675, result2)
|
||||
XCTAssertApproximatelyEqual(0.0, result3)
|
||||
XCTAssertApproximatelyEqual(1.0, result11)
|
||||
XCTAssertApproximatelyEqual(0.675, result22)
|
||||
XCTAssertApproximatelyEqual(0.0, result33)
|
||||
XCTAssertApproximatelyEqual(1.0, result4)
|
||||
XCTAssertApproximatelyEqual(0.675, result5)
|
||||
XCTAssertApproximatelyEqual(0.0, result6)
|
||||
|
|
Loading…
Reference in New Issue