Restructure FuzzyLogic module and add rule base DSL

This commit is contained in:
Alexander Ignatov 2022-01-01 15:02:28 +02:00
parent 065e729a98
commit 2b6a0516d9
17 changed files with 228 additions and 149 deletions

View File

@ -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)) }
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -1,5 +0,0 @@
import FuzzySets
open class ReasoningScheme {
// TODO
}