Add IterableFuzzySet and rename stuff
This commit is contained in:
parent
38477208d3
commit
c984d18854
|
@ -1,17 +1,17 @@
|
|||
public struct ContinuousFuzzySet: FuzzySet {
|
||||
public typealias Element = Double
|
||||
public typealias Universe = Double
|
||||
|
||||
private let membershipFunction: MembershipFunction
|
||||
private let membershipFunction: MembershipFunction<Universe>
|
||||
|
||||
public init(membershipFunction: MembershipFunction) {
|
||||
public init(membershipFunction: MembershipFunction<Universe>) {
|
||||
self.membershipFunction = membershipFunction
|
||||
}
|
||||
|
||||
public init(membershipFunction: @escaping (Element) -> Grade) {
|
||||
public init(membershipFunction: @escaping (Universe) -> Grade) {
|
||||
self.membershipFunction = MembershipFunction(membershipFunction)
|
||||
}
|
||||
|
||||
public func grade(forElement element: Element) -> Grade {
|
||||
public func grade(forElement element: Universe) -> Grade {
|
||||
membershipFunction(element)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
public struct DiscreteFuzzySet<Universe: Hashable>: FuzzySet {
|
||||
public struct DiscreteMutableFuzzySet<Universe: Hashable>: FuzzySet {
|
||||
|
||||
private var grades: [Universe: Grade]
|
||||
|
||||
|
@ -26,7 +26,7 @@ public struct DiscreteFuzzySet<Universe: Hashable>: FuzzySet {
|
|||
}
|
||||
}
|
||||
|
||||
public extension DiscreteFuzzySet {
|
||||
public extension DiscreteMutableFuzzySet {
|
||||
static func fromCrispSet(_ set: Set<Universe>) -> Self {
|
||||
let gradeTuples = set.map { ($0, 1.0 ) }
|
||||
let gradeDictionary = Dictionary(uniqueKeysWithValues: gradeTuples)
|
||||
|
@ -35,7 +35,7 @@ public extension DiscreteFuzzySet {
|
|||
}
|
||||
|
||||
public extension Set {
|
||||
func fuzzified() -> DiscreteFuzzySet<Set.Element> {
|
||||
DiscreteFuzzySet.fromCrispSet(self)
|
||||
func fuzzified() -> DiscreteMutableFuzzySet<Set.Element> {
|
||||
DiscreteMutableFuzzySet.fromCrispSet(self)
|
||||
}
|
||||
}
|
|
@ -2,15 +2,15 @@
|
|||
public typealias Grade = Double
|
||||
|
||||
public protocol FuzzySet {
|
||||
associatedtype Element
|
||||
associatedtype Universe
|
||||
|
||||
func grade(forElement element: Element) -> Grade
|
||||
func grade(forElement element: Universe) -> Grade
|
||||
|
||||
subscript(_ element: Element) -> Grade { get }
|
||||
subscript(_ element: Universe) -> Grade { get }
|
||||
}
|
||||
|
||||
public extension FuzzySet {
|
||||
subscript(_ element: Element) -> Grade {
|
||||
subscript(_ element: Universe) -> Grade {
|
||||
get {
|
||||
grade(forElement: element)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
public struct IterableFuzzySet<Universe: Strideable> {
|
||||
|
||||
public struct Element: Equatable {
|
||||
public let element: Universe
|
||||
public let grade: Grade
|
||||
|
||||
public init(element: Universe, grade: Grade) {
|
||||
self.element = element
|
||||
self.grade = grade
|
||||
}
|
||||
}
|
||||
|
||||
public typealias Iterator = Array<Element>.Iterator
|
||||
|
||||
private let range: StrideThrough<Universe>
|
||||
private let function: MembershipFunction<Universe>
|
||||
|
||||
public init(range: StrideThrough<Universe>, membershipFunction: MembershipFunction<Universe>) {
|
||||
self.range = range
|
||||
self.function = membershipFunction
|
||||
}
|
||||
}
|
||||
|
||||
extension IterableFuzzySet: FuzzySet {
|
||||
public func grade(forElement element: Universe) -> Grade {
|
||||
function(element)
|
||||
}
|
||||
}
|
||||
|
||||
extension IterableFuzzySet: Sequence {
|
||||
public func makeIterator() -> Iterator {
|
||||
range
|
||||
.map { .init(
|
||||
element: $0,
|
||||
grade: grade(forElement: $0)
|
||||
)}
|
||||
.makeIterator()
|
||||
}
|
||||
}
|
|
@ -1,28 +1,40 @@
|
|||
public struct MembershipFunction {
|
||||
public struct MembershipFunction<U: Strideable> {
|
||||
|
||||
private let function: (Double) -> Double
|
||||
private let function: (U) -> Grade
|
||||
|
||||
public init(_ function: @escaping (Double) -> Grade) {
|
||||
public init(_ function: @escaping (U) -> Grade) {
|
||||
self.function = function
|
||||
}
|
||||
|
||||
public func callAsFunction(_ x: Double) -> Double {
|
||||
function(x)
|
||||
public func callAsFunction(_ u: U) -> Grade {
|
||||
function(u)
|
||||
}
|
||||
}
|
||||
|
||||
/// Common membership functions
|
||||
public extension MembershipFunction {
|
||||
static var zero: Self {
|
||||
.init { _ in 0.0 }
|
||||
.init { _ in 0 }
|
||||
}
|
||||
|
||||
static var one: Self {
|
||||
.init { _ in 1.0 }
|
||||
.init { _ in 1 }
|
||||
}
|
||||
|
||||
static func fuzzySingleton(_ a: Double) -> Self {
|
||||
.init { $0 == a ? 1.0 : 0.0 }
|
||||
static func fuzzySingleton(_ onlyMember: U) -> Self {
|
||||
.init { $0 == onlyMember ? 1 : 0 }
|
||||
}
|
||||
}
|
||||
|
||||
public extension MembershipFunction where U == Double {
|
||||
static func triangular(minimum a: U, peak b: U, maximum c: U) -> Self {
|
||||
.init { u in
|
||||
switch u {
|
||||
case a...b: return (u - a) / (b - a)
|
||||
case b...c: return (c - u) / (c - b)
|
||||
default: return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add more
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import XCTest
|
||||
import FuzzyKit
|
||||
|
||||
final class DiscreteFuzzySetTests: XCTestCase {
|
||||
final class DiscreteMutableFuzzySetTests: XCTestCase {
|
||||
func test_defaultInit_allGradesAreZero() throws {
|
||||
let sut = DiscreteFuzzySet<String>()
|
||||
let sut = DiscreteMutableFuzzySet<String>()
|
||||
|
||||
let expected = [
|
||||
"a": 0.0,
|
||||
|
@ -22,7 +22,7 @@ final class DiscreteFuzzySetTests: XCTestCase {
|
|||
"c": 1.0,
|
||||
]
|
||||
|
||||
let sut = DiscreteFuzzySet(elementToGradeMap: parameters)
|
||||
let sut = DiscreteMutableFuzzySet(elementToGradeMap: parameters)
|
||||
|
||||
let expected = [
|
||||
"a": 0.69,
|
||||
|
@ -36,8 +36,8 @@ final class DiscreteFuzzySetTests: XCTestCase {
|
|||
}
|
||||
|
||||
func test_setGrade_gradesAreCorrect() throws {
|
||||
var sut1 = DiscreteFuzzySet<String>()
|
||||
var sut2 = DiscreteFuzzySet<String>()
|
||||
var sut1 = DiscreteMutableFuzzySet<String>()
|
||||
var sut2 = DiscreteMutableFuzzySet<String>()
|
||||
|
||||
let expected = [
|
||||
"a": 0.69,
|
||||
|
@ -73,7 +73,7 @@ final class DiscreteFuzzySetTests: XCTestCase {
|
|||
]
|
||||
|
||||
let fs1 = cs.fuzzified()
|
||||
let fs2 = DiscreteFuzzySet.fromCrispSet(cs)
|
||||
let fs2 = DiscreteMutableFuzzySet.fromCrispSet(cs)
|
||||
|
||||
for (element, grade) in expected {
|
||||
assertExpectedGrade(element: element, expectedGrade: grade, sut: fs1)
|
|
@ -2,7 +2,7 @@ import XCTest
|
|||
import FuzzyKit
|
||||
|
||||
func assertExpectedGrade<E, S: FuzzySet>(element: E, expectedGrade: Grade, sut: S)
|
||||
where S.Element == E {
|
||||
where S.Universe == E {
|
||||
let grade1 = sut[element]
|
||||
let grade2 = sut.grade(forElement: element)
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import XCTest
|
||||
import FuzzyKit
|
||||
|
||||
class IterableFuzzySetTests: XCTestCase {
|
||||
private var near4Support4: [IterableFuzzySet<Int>.Element] = [
|
||||
.init(element: 0, grade: 0.0),
|
||||
.init(element: 1, grade: 0.25),
|
||||
.init(element: 2, grade: 0.50),
|
||||
.init(element: 3, grade: 0.75),
|
||||
.init(element: 4, grade: 1.0),
|
||||
.init(element: 5, grade: 0.75),
|
||||
.init(element: 6, grade: 0.50),
|
||||
.init(element: 7, grade: 0.25),
|
||||
.init(element: 8, grade: 0.0),
|
||||
.init(element: 9, grade: 0.0),
|
||||
.init(element: 10, grade: 0.0),
|
||||
]
|
||||
|
||||
func test_initFromIntRangeAndDiscreteFunction() {
|
||||
let expected = near4Support4
|
||||
|
||||
let sut = IterableFuzzySet(
|
||||
range: stride(from: 0, through: 10, by: 1),
|
||||
membershipFunction: .init {
|
||||
expected[$0].grade
|
||||
}
|
||||
)
|
||||
|
||||
let result = Array(sut)
|
||||
|
||||
XCTAssertEqual(result, expected)
|
||||
}
|
||||
|
||||
func test_initFromIntRangeAndContinuousFunction() {
|
||||
let expected = near4Support4.map {
|
||||
IterableFuzzySet<Double>.Element(element: Double($0.element), grade: $0.grade)
|
||||
}
|
||||
|
||||
let sut = IterableFuzzySet(
|
||||
range: stride(from: 0.0, through: 10.0, by: 1),
|
||||
membershipFunction: .triangular(minimum: 0.0, peak: 4.0, maximum: 8.0)
|
||||
)
|
||||
|
||||
let result = Array(sut)
|
||||
|
||||
XCTAssertEqual(result, expected)
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ import FuzzyKit
|
|||
|
||||
final class MembershipFunctionTests: XCTestCase {
|
||||
func test_isCallable() throws {
|
||||
let sut = MembershipFunction.one
|
||||
let sut = MembershipFunction<Double>.one
|
||||
let x = 1.0
|
||||
|
||||
let result = sut(x)
|
||||
|
|
Loading…
Reference in New Issue