Add alpha-cut

This commit is contained in:
Alexander Ignatov 2021-12-18 01:46:36 +02:00
parent c984d18854
commit 7d690c5985
8 changed files with 103 additions and 12 deletions

View File

@ -7,13 +7,17 @@ public struct ContinuousFuzzySet: FuzzySet {
self.membershipFunction = membershipFunction self.membershipFunction = membershipFunction
} }
public init(membershipFunction: @escaping (Universe) -> Grade) { public init(membershipFunction: @escaping MembershipFunction<Universe>.FunctionType) {
self.membershipFunction = MembershipFunction(membershipFunction) self.membershipFunction = MembershipFunction(membershipFunction)
} }
public func grade(forElement element: Universe) -> Grade { public func grade(forElement element: Universe) -> Grade {
membershipFunction(element) membershipFunction(element)
} }
public func alphaCut(_ alpha: Grade) -> Self {
.init { min(membershipFunction($0), alpha) }
}
} }
public extension ContinuousFuzzySet { public extension ContinuousFuzzySet {

View File

@ -1,6 +1,6 @@
public struct DiscreteMutableFuzzySet<Universe: Hashable>: FuzzySet { public struct DiscreteMutableFuzzySet<Universe: Hashable>: FuzzySet {
private var grades: [Universe: Grade] public private(set) var grades: [Universe: Grade]
public init(elementToGradeMap: [Universe: Grade] = [:]) { public init(elementToGradeMap: [Universe: Grade] = [:]) {
self.grades = elementToGradeMap self.grades = elementToGradeMap
@ -24,6 +24,20 @@ public struct DiscreteMutableFuzzySet<Universe: Hashable>: FuzzySet {
setGrade(newValue, forElement: element) setGrade(newValue, forElement: element)
} }
} }
public func alphaCut(_ alpha: Grade) -> Self {
var newSet = Self(elementToGradeMap: grades)
newSet.applyAlphaCut(alpha)
return newSet
}
public mutating func applyAlphaCut(_ alpha: Grade) {
let newGradeTuples = grades.map {
($0.key, min($0.value, alpha))
}
let newMap = Dictionary(uniqueKeysWithValues: newGradeTuples)
grades = newMap
}
} }
public extension DiscreteMutableFuzzySet { public extension DiscreteMutableFuzzySet {

View File

@ -7,6 +7,8 @@ public protocol FuzzySet {
func grade(forElement element: Universe) -> Grade func grade(forElement element: Universe) -> Grade
subscript(_ element: Universe) -> Grade { get } subscript(_ element: Universe) -> Grade { get }
func alphaCut(_ alpha: Grade) -> Self
} }
public extension FuzzySet { public extension FuzzySet {

View File

@ -19,6 +19,17 @@ public struct IterableFuzzySet<Universe: Strideable> {
self.range = range self.range = range
self.function = membershipFunction self.function = membershipFunction
} }
public init(range: StrideThrough<Universe>, membershipFunction: @escaping MembershipFunction<Universe>.FunctionType) {
self.range = range
self.function = .init(membershipFunction)
}
public func alphaCut(_ alpha: Grade) -> Self {
.init(range: range) {
Swift.min(function($0), alpha)
}
}
} }
extension IterableFuzzySet: FuzzySet { extension IterableFuzzySet: FuzzySet {

View File

@ -1,8 +1,10 @@
public struct MembershipFunction<U: Strideable> { public struct MembershipFunction<U: Strideable> {
private let function: (U) -> Grade public typealias FunctionType = (U) -> Grade
public init(_ function: @escaping (U) -> Grade) { private let function: FunctionType
public init(_ function: @escaping FunctionType) {
self.function = function self.function = function
} }

View File

@ -2,5 +2,20 @@ import XCTest
import FuzzyKit import FuzzyKit
final class ContinuousFuzzySetTests: XCTestCase { final class ContinuousFuzzySetTests: XCTestCase {
// TODO func test_triangular_alphaCut() {
let a = 3.0
let b = 5.0
let c = 8.0
let alpha = 0.5
let set = ContinuousFuzzySet(membershipFunction: .triangular(minimum: a, peak: b, maximum: c))
let sut = set.alphaCut(alpha)
let minResult = sut[a]
let peakResult = sut[b]
let maxResult = sut[c]
XCTAssertEqual(0, minResult)
XCTAssertEqual(alpha, peakResult)
XCTAssertEqual(0, maxResult)
}
} }

View File

@ -80,4 +80,35 @@ final class DiscreteMutableFuzzySetTests: XCTestCase {
assertExpectedGrade(element: element, expectedGrade: grade, sut: fs2) assertExpectedGrade(element: element, expectedGrade: grade, sut: fs2)
} }
} }
func test_alphaCut_gradesAreCorrect() {
let alpha = 0.5
let initial = [
"a": 1.0,
"b": 0.88,
"c": 0.69,
"d": 0.42,
"e": 0.001,
"f": 0.0,
]
let expected = [
"a": 0.5,
"b": 0.5,
"c": 0.5,
"d": 0.42,
"e": 0.001,
"f": 0.0,
]
let set = DiscreteMutableFuzzySet(elementToGradeMap: initial)
var sut2 = DiscreteMutableFuzzySet(elementToGradeMap: initial)
let sut1 = set.alphaCut(alpha)
sut2.applyAlphaCut(alpha)
for (element, grade) in expected {
assertExpectedGrade(element: element, expectedGrade: grade, sut: sut1)
assertExpectedGrade(element: element, expectedGrade: grade, sut: sut2)
}
}
} }

View File

@ -18,20 +18,18 @@ class IterableFuzzySetTests: XCTestCase {
func test_initFromIntRangeAndDiscreteFunction() { func test_initFromIntRangeAndDiscreteFunction() {
let expected = near4Support4 let expected = near4Support4
let range = stride(from: 0, through: 10, by: 1)
let sut = IterableFuzzySet( let sut = IterableFuzzySet(range: range) {
range: stride(from: 0, through: 10, by: 1), expected[$0].grade
membershipFunction: .init { }
expected[$0].grade
}
)
let result = Array(sut) let result = Array(sut)
XCTAssertEqual(result, expected) XCTAssertEqual(result, expected)
} }
func test_initFromIntRangeAndContinuousFunction() { func test_initFromDoubleRangeAndContinuousFunction() {
let expected = near4Support4.map { let expected = near4Support4.map {
IterableFuzzySet<Double>.Element(element: Double($0.element), grade: $0.grade) IterableFuzzySet<Double>.Element(element: Double($0.element), grade: $0.grade)
} }
@ -45,4 +43,18 @@ class IterableFuzzySetTests: XCTestCase {
XCTAssertEqual(result, expected) XCTAssertEqual(result, expected)
} }
func test_alphaCut_allValuesAreBelowAlpha() {
let alpha = 0.5
let set = IterableFuzzySet(
range: stride(from: 0.0, through: 100.0, by: 0.5),
membershipFunction: .triangular(minimum: 42.0, peak: 69.0, maximum: 88.88)
)
let sut = set.alphaCut(alpha)
let grades = Array(sut).map { $0.grade }
let allAreBelowAlpha = grades.allSatisfy { $0 <= alpha }
XCTAssertTrue(allAreBelowAlpha)
}
} }