Fuzzy sets and fuzzy logic theory implementations.
import FuzzyKit
enum Funding { case adequate, marginal, inadequate }
enum Staffing { case small, large }
enum Risk { case low, normal, high }
let funding: SimpleLinguisticVariable<Funding, AnyFuzzySet> = [
.inadequate: .init(membershipFunction: .leftOpen(slopeStart: 15, slopeEnd: 35)),
.marginal: .init(membershipFunction: .triangular(minimum: 21, peak: 41, maximum: 61)),
.adequate: .init(membershipFunction: .rightOpen(slopeStart: 55, slopeEnd: 75)),
]
let staffing: SimpleLinguisticVariable<Staffing, AnyFuzzySet> = [
.small: .init(membershipFunction: .leftOpen(slopeStart: 29, slopeEnd: 69)),
.large: .init(membershipFunction: .rightOpen(slopeStart: 37, slopeEnd: 77)),
]
let risk: SimpleLinguisticVariable<Risk, AnyFuzzySet> = [
.low: .init(membershipFunction: .leftOpen(slopeStart: 20, slopeEnd: 40)),
.normal: .init(membershipFunction: .triangular(minimum: 20, peak: 50, maximum: 80)),
.high: .init(membershipFunction: .rightOpen(slopeStart: 60, slopeEnd: 80)),
]
let Ø = AnyFuzzySet<Double>.empty
let ruleBase = FuzzyRuleBase {
funding.is(.adequate) || staffing.is(.small) --> risk.is(.low)
funding.is(.marginal) && staffing.is(.large) --> risk.is(.normal)
funding.is(.inadequate) || Ø --> risk.is(.high)
}
let flc = FuzzyLogicController(rules: ruleBase, settings: .init(implication: .mamdani))
flc.consequenceGrade(for: 50, usingSingletonFact: (8.8, 42)) // result is 0.675
Using the Swift Package Manager, don't forget to add the package as a dependency to your Package.swift
file:
dependencies: [
+ .package(url: "https://github.com/allexks/FuzzyKit", .upToNextMajor(from: "0.1.0")),
],
To be able to use everything from this package, you can import everything at once using this helper module:
.target(
name: "...",
dependencies: [
+ .product(name: "FuzzyKit", package: "FuzzyKit"),
]
),
import FuzzyKit
Or alternatively, import only the specific modules needed:
.target(
name: "...",
dependencies: [
+ .product(name: "FuzzySets", package: "FuzzyKit"),
+ .product(name: "FuzzyNumbers", package: "FuzzyKit"),
+ .product(name: "FuzzyRelations", package: "FuzzyKit"),
+ .product(name: "FuzzyLogic", package: "FuzzyKit"),
]
),
import FuzzySets
import FuzzyNumbers
import FuzzyRelations
import FuzzyLogic
API Reference automatically collected with jazzy
is published here with each new release.
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:
-
struct AnyFuzzySet
- allows type erasure. It only stores aMembershipFunction
and has non-mutable methods. -
struct IterableFuzzySet
- stores aMembershipFunction
as well as aSequence
of elements of the associated typeUniverse
. ImplementsSequence
so that it can easily be iterated over them. The elements of the iteration over anIterableFuzzySet
arestruct
s containinggrade
andelement
properties. It has non-mutable methods only. Includessupport
,core
andheight
computed properties. -
struct DiscreteMutableFuzzySet
- it is "discrete" because it doesn't stores aMembershipFunction
but instead keeps its elements and their grade in aDictionary
, and it is "mutable" because it contains mutable equivalents of all other methods that operate over the set (includingsubscript
). A default value of0
is returned for the grade of an element that is not in the dictionary (a different default value can be provided as well). Includessupport
,core
andheight
computed properties. A bonus feature is its debug print using Zadeh's notation.
Convertions between the 3 types are easy and possible using the eraseToAnyFuzzySet
, makeIterable
and makeDiscreteMutable
methods defined on them.
All 3 concrete types implement it. It requires the following methods that operate on fuzzy sets:
-
alphaCut(_:alpha:)
-
complement(method:)
-
intersection(_:method:)
-
union(_:method:)
-
difference(_:method:)
-
symmetricDifference(_:method:)
-
power(_:n:)
-
appliedCustomFunction(_:function:)