Add IterableFuzzySet and rename stuff

This commit is contained in:
Alexander Ignatov 2021-12-18 00:55:43 +02:00
parent 38477208d3
commit c984d18854
9 changed files with 129 additions and 30 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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