Restructure FuzzyLogic module and add rule base DSL
This commit is contained in:
parent
065e729a98
commit
2b6a0516d9
|
@ -12,3 +12,9 @@ public extension BinaryFuzzyRelation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public extension FuzzyRule {
|
||||||
|
func asRelation<P, Q>() -> BinaryFuzzyRelation<P, Q> where Input == (P, Q) {
|
||||||
|
.init { (p, q) in self((p, q)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
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>(
|
||||||
|
_ 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,30 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public protocol FuzzyProposition {
|
||||||
|
associatedtype Input
|
||||||
|
func apply(_ x: Input, settings: OperationSettings) -> Grade
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension FuzzyProposition {
|
||||||
|
func callAsFunction(_ x: Input, settings: OperationSettings = .init()) -> Grade {
|
||||||
|
apply(x, settings: settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AnyFuzzySet: FuzzyProposition {
|
||||||
|
public func apply(_ x: Universe, settings: OperationSettings) -> Grade {
|
||||||
|
grade(forElement: x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension IterableFuzzySet: FuzzyProposition {
|
||||||
|
public func apply(_ x: Universe, settings: OperationSettings) -> Grade {
|
||||||
|
grade(forElement: x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DiscreteMutableFuzzySet: FuzzyProposition {
|
||||||
|
public func apply(_ x: Universe, settings: OperationSettings) -> Grade {
|
||||||
|
grade(forElement: x)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public struct FuzzyRuleBase<RuleInput> {
|
||||||
|
|
||||||
|
public typealias Rule = FuzzyRule<RuleInput>
|
||||||
|
|
||||||
|
@resultBuilder
|
||||||
|
public struct FuzzyRuleBaseBuilder {
|
||||||
|
public static func buildBlock() -> [Rule] { [] }
|
||||||
|
|
||||||
|
public static func buildBlock(_ rules: Rule...) -> [Rule] { rules }
|
||||||
|
|
||||||
|
public static func buildOptional(_ component: [Rule]?) -> [Rule] {
|
||||||
|
component ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func buildEither(first component: [Rule]) -> [Rule] {
|
||||||
|
component
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func buildEither(second component: [Rule]) -> [Rule] {
|
||||||
|
component
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func buildArray(_ components: [[Rule]]) -> [Rule] {
|
||||||
|
components.flatMap { $0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var rules: [Rule]
|
||||||
|
|
||||||
|
public init(_ rules: [Rule] = []) {
|
||||||
|
self.rules = rules
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(@FuzzyRuleBaseBuilder _ rulesBlock: () -> [Rule]) {
|
||||||
|
self.rules = rulesBlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FuzzyRuleBase: Sequence {
|
||||||
|
public func makeIterator() -> Array<Rule>.Iterator {
|
||||||
|
rules.makeIterator()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public struct FuzzyConjunction<Input>: FuzzyProposition {
|
||||||
|
|
||||||
|
private let function: (Input, OperationSettings) -> Grade
|
||||||
|
|
||||||
|
public init<P: FuzzyProposition, Q: FuzzyProposition>(lhs: P, rhs: Q) where Input == (P.Input, Q.Input) {
|
||||||
|
self.function = { (x, settings) -> Grade in
|
||||||
|
settings.conjunction.function(
|
||||||
|
lhs(x.0, settings: settings),
|
||||||
|
rhs(x.1, settings: settings)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func apply(_ values: Input, settings: OperationSettings = .init()) -> Grade {
|
||||||
|
function(values, settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func && <P: FuzzyProposition, Q: FuzzyProposition> (lhs: P, rhs: Q) -> FuzzyConjunction<(P.Input, Q.Input)> {
|
||||||
|
.init(lhs: lhs, rhs: rhs)
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public struct FuzzyDisjunction<Input>: FuzzyProposition {
|
||||||
|
|
||||||
|
private let function: (Input, OperationSettings) -> Grade
|
||||||
|
|
||||||
|
public init<P: FuzzyProposition, Q: FuzzyProposition>(lhs: P, rhs: Q) where Input == (P.Input, Q.Input) {
|
||||||
|
self.function = { (x, settings) -> Grade in
|
||||||
|
settings.disjunction.function(
|
||||||
|
lhs(x.0, settings: settings),
|
||||||
|
rhs(x.1, settings: settings)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func apply(_ values: Input, settings: OperationSettings = .init()) -> Grade {
|
||||||
|
function(values, settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func || <P: FuzzyProposition, Q: FuzzyProposition> (lhs: P, rhs: Q) -> FuzzyDisjunction<(P.Input, Q.Input)> {
|
||||||
|
.init(lhs: lhs, rhs: rhs)
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public struct FuzzyNegation<Input>: FuzzyProposition {
|
||||||
|
|
||||||
|
public let function: (Input, OperationSettings) -> Grade
|
||||||
|
|
||||||
|
public init<F: FuzzyProposition>(_ statement: F) where Input == F.Input {
|
||||||
|
self.function = { (input, settings) -> Grade in
|
||||||
|
settings.negation.function(statement(input, settings: settings))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func apply(_ value: Input, settings: OperationSettings = .init()) -> Grade {
|
||||||
|
function(value, settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public prefix func ! <F: FuzzyProposition>(statement: F) -> FuzzyNegation<F.Input> {
|
||||||
|
.init(statement)
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public struct FuzzyRule<Input>: FuzzyProposition {
|
||||||
|
|
||||||
|
private let function: (Input, OperationSettings) -> Grade
|
||||||
|
|
||||||
|
public init<P: FuzzyProposition, Q: FuzzyProposition>(antecedent: P, consequent: Q) where Input == (P.Input, Q.Input) {
|
||||||
|
self.function = { (x, settings) -> Grade in
|
||||||
|
settings.implication.function(
|
||||||
|
antecedent(x.0, settings: settings),
|
||||||
|
consequent(x.1, settings: settings)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func apply(_ values: Input, settings: OperationSettings = .init()) -> Grade {
|
||||||
|
function(values, settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
infix operator -->: TernaryPrecedence // lower than ==, &&, ||, etc
|
||||||
|
public func --> <P: FuzzyProposition, Q: FuzzyProposition> (lhs: P, rhs: Q) -> FuzzyRule<(P.Input, Q.Input)> {
|
||||||
|
.init(antecedent: lhs, consequent: rhs)
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public struct FuzzyXOR<Input>: FuzzyProposition {
|
||||||
|
|
||||||
|
private let function: (Input, OperationSettings) -> Grade
|
||||||
|
|
||||||
|
public init<P: FuzzyProposition, Q: FuzzyProposition>(lhs: P, rhs: Q) where Input == (P.Input, Q.Input) {
|
||||||
|
self.function = { (x, settings) -> Grade in
|
||||||
|
settings.xor.function(
|
||||||
|
lhs(x.0, settings: settings),
|
||||||
|
rhs(x.1, settings: settings)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func apply(_ values: Input, settings: OperationSettings = .init()) -> Grade {
|
||||||
|
function(values, settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
infix operator ^^: ComparisonPrecedence
|
||||||
|
public func ^^ <P: FuzzyProposition, Q: FuzzyProposition> (lhs: P, rhs: Q) -> FuzzyXOR<(P.Input, Q.Input)> {
|
||||||
|
.init(lhs: lhs, rhs: rhs)
|
||||||
|
}
|
|
@ -1,30 +0,0 @@
|
||||||
import FuzzySets
|
|
||||||
|
|
||||||
public protocol FuzzyProposition {
|
|
||||||
associatedtype U
|
|
||||||
func apply(_ u: U, settings: OperationSettings) -> Grade
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension FuzzyProposition {
|
|
||||||
func callAsFunction(_ u: U, settings: OperationSettings = .init()) -> Grade {
|
|
||||||
apply(u, settings: settings)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension AnyFuzzySet: FuzzyProposition {
|
|
||||||
public func apply(_ u: Universe, settings: OperationSettings) -> Grade {
|
|
||||||
grade(forElement: u)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension IterableFuzzySet: FuzzyProposition {
|
|
||||||
public func apply(_ u: Universe, settings: OperationSettings) -> Grade {
|
|
||||||
grade(forElement: u)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension DiscreteMutableFuzzySet: FuzzyProposition {
|
|
||||||
public func apply(_ u: Universe, settings: OperationSettings) -> Grade {
|
|
||||||
grade(forElement: u)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
import FuzzySets
|
|
||||||
|
|
||||||
public struct FuzzyConjunction<A: FuzzyProposition, B: FuzzyProposition>: FuzzyProposition {
|
|
||||||
|
|
||||||
public let first: A
|
|
||||||
public let second: B
|
|
||||||
|
|
||||||
public init(_ first: A, _ second: B) {
|
|
||||||
self.first = first
|
|
||||||
self.second = second
|
|
||||||
}
|
|
||||||
|
|
||||||
public func apply(_ values: (A.U, B.U), settings: OperationSettings = .init()) -> Grade {
|
|
||||||
settings.conjunction.function(
|
|
||||||
first(values.0, settings: settings),
|
|
||||||
second(values.1, settings: settings)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public func && <A: FuzzyProposition, B: FuzzyProposition>(lhs: A, rhs: B) -> FuzzyConjunction<A, B> {
|
|
||||||
.init(lhs, rhs)
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
import FuzzySets
|
|
||||||
|
|
||||||
public struct FuzzyDisjunction<A: FuzzyProposition, B: FuzzyProposition>: FuzzyProposition {
|
|
||||||
|
|
||||||
public let first: A
|
|
||||||
public let second: B
|
|
||||||
|
|
||||||
public init(_ first: A, _ second: B) {
|
|
||||||
self.first = first
|
|
||||||
self.second = second
|
|
||||||
}
|
|
||||||
|
|
||||||
public func apply(_ values: (A.U, B.U), settings: OperationSettings = .init()) -> Grade {
|
|
||||||
settings.disjunction.function(
|
|
||||||
first(values.0, settings: settings),
|
|
||||||
second(values.1, settings: settings)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public func || <A: FuzzyProposition, B: FuzzyProposition>(lhs: A, rhs: B) -> FuzzyDisjunction<A, B> {
|
|
||||||
.init(lhs, rhs)
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
import FuzzySets
|
|
||||||
|
|
||||||
public struct FuzzyNegation<FS: FuzzyProposition>: FuzzyProposition {
|
|
||||||
|
|
||||||
public let statement: FS
|
|
||||||
|
|
||||||
public init(_ statement: FS) {
|
|
||||||
self.statement = statement
|
|
||||||
}
|
|
||||||
|
|
||||||
public func apply(_ value: FS.U, settings: OperationSettings = .init()) -> Grade {
|
|
||||||
settings.negation.function(statement(value, settings: settings))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public prefix func ! <FS: FuzzyProposition>(statement: FS) -> FuzzyNegation<FS> {
|
|
||||||
.init(statement)
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import FuzzySets
|
|
||||||
|
|
||||||
public struct FuzzyRule<P: FuzzyProposition, Q: FuzzyProposition>: FuzzyProposition {
|
|
||||||
public let antecedent: P
|
|
||||||
public let consequent: Q
|
|
||||||
|
|
||||||
public init(antecedent: P, consequent: Q) {
|
|
||||||
self.antecedent = antecedent
|
|
||||||
self.consequent = consequent
|
|
||||||
}
|
|
||||||
|
|
||||||
public func apply(_ values: (P.U, Q.U), settings: OperationSettings = .init()) -> Grade {
|
|
||||||
settings.implication.function(
|
|
||||||
antecedent(values.0, settings: settings),
|
|
||||||
consequent(values.1, settings: settings)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
infix operator -->: TernaryPrecedence // lower than ==, &&, ||, etc
|
|
||||||
public func --> <P: FuzzyProposition, Q: FuzzyProposition> (lhs: P, rhs: Q) -> FuzzyRule<P, Q> {
|
|
||||||
.init(antecedent: lhs, consequent: rhs)
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
import FuzzySets
|
|
||||||
|
|
||||||
public struct FuzzyXOR<A: FuzzyProposition, B: FuzzyProposition>: FuzzyProposition {
|
|
||||||
|
|
||||||
public let first: A
|
|
||||||
public let second: B
|
|
||||||
|
|
||||||
public init(_ first: A, _ second: B) {
|
|
||||||
self.first = first
|
|
||||||
self.second = second
|
|
||||||
}
|
|
||||||
|
|
||||||
public func apply(_ values: (A.U, B.U), settings: OperationSettings = .init()) -> Grade {
|
|
||||||
settings.xor.function(
|
|
||||||
first(values.0, settings: settings),
|
|
||||||
second(values.1, settings: settings)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
infix operator ^^: ComparisonPrecedence
|
|
||||||
public func ^^ <A: FuzzyProposition, B: FuzzyProposition>(lhs: A, rhs: B) -> FuzzyXOR<A, B> {
|
|
||||||
.init(lhs, rhs)
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
import FuzzySets
|
|
||||||
|
|
||||||
open class ReasoningScheme {
|
|
||||||
// TODO
|
|
||||||
}
|
|
Loading…
Reference in New Issue