Add basic fuzzy realtions
This commit is contained in:
parent
e7a2353f24
commit
968df3b5de
|
@ -7,6 +7,7 @@ enum SubmoduleName: String {
|
||||||
case fuzzyKit = "FuzzyKit"
|
case fuzzyKit = "FuzzyKit"
|
||||||
case fuzzySets = "FuzzySets"
|
case fuzzySets = "FuzzySets"
|
||||||
case fuzzyNumbers = "FuzzyNumbers"
|
case fuzzyNumbers = "FuzzyNumbers"
|
||||||
|
case fuzzyRelations = "FuzzyRelations"
|
||||||
|
|
||||||
var name: String { rawValue }
|
var name: String { rawValue }
|
||||||
var target: String { rawValue }
|
var target: String { rawValue }
|
||||||
|
@ -64,5 +65,18 @@ let package = Package(
|
||||||
.target(name: SubmoduleName.fuzzyNumbers.target),
|
.target(name: SubmoduleName.fuzzyNumbers.target),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
.target(
|
||||||
|
name: SubmoduleName.fuzzyRelations.target,
|
||||||
|
dependencies: [
|
||||||
|
.target(name: SubmoduleName.fuzzySets.target),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
.testTarget(
|
||||||
|
name: SubmoduleName.fuzzyRelations.testTarget,
|
||||||
|
dependencies: [
|
||||||
|
.target(name: SubmoduleName.fuzzyRelations.target),
|
||||||
|
.target(name: SubmoduleName.fuzzySets.target),
|
||||||
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public class BinaryCartesianProduct<A: FuzzySet, B: FuzzySet, U, V>
|
||||||
|
where A.Universe == U, B.Universe == V {
|
||||||
|
|
||||||
|
let first: A
|
||||||
|
let second: B
|
||||||
|
let function: MembershipFunction<(U, V)>
|
||||||
|
|
||||||
|
public init(_ a: A, _ b: B) {
|
||||||
|
self.first = a
|
||||||
|
self.second = b
|
||||||
|
self.function = .init { min(a[$0.0], b[$0.1]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(_ a: A, _ b: B, membershipFunction: MembershipFunction<(U, V)>) {
|
||||||
|
self.first = a
|
||||||
|
self.second = b
|
||||||
|
self.function = membershipFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(_ a: A, _ b: B, membershipFunction: @escaping MembershipFunction<(U, V)>.FunctionType) {
|
||||||
|
self.first = a
|
||||||
|
self.second = b
|
||||||
|
self.function = .init(membershipFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func grade(forElements elements: (U, V)) -> Grade {
|
||||||
|
function(elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscript(_ u: U, _ v: V) -> Grade {
|
||||||
|
grade(forElements: (u, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
public func asFuzzySet() -> AnyFuzzySet<(U, V)> {
|
||||||
|
.init(membershipFunction: function)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public class BinaryFuzzyRelation<U, V> {
|
||||||
|
|
||||||
|
let function: MembershipFunction<(U, V)>
|
||||||
|
|
||||||
|
public init(_ membershipFunction: MembershipFunction<(U, V)>) {
|
||||||
|
self.function = membershipFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(_ membershipFunction: @escaping MembershipFunction<(U, V)>.FunctionType) {
|
||||||
|
self.function = .init(membershipFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func grade(forElements elements: (U, V)) -> Grade {
|
||||||
|
function(elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscript(_ u: U, _ v: V) -> Grade {
|
||||||
|
grade(forElements: (u, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscript(_ x: (U, V)) -> Grade {
|
||||||
|
grade(forElements: x)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func asFuzzySet() -> AnyFuzzySet<(U, V)> {
|
||||||
|
.init(membershipFunction: function)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
class HomogenousFuzzyRelation<U> {
|
||||||
|
|
||||||
|
let function: MembershipFunction<[U]>
|
||||||
|
|
||||||
|
public init(_ membershipFunction: MembershipFunction<[U]>) {
|
||||||
|
self.function = membershipFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(_ membershipFunction: @escaping MembershipFunction<[U]>.FunctionType) {
|
||||||
|
self.function = .init(membershipFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func grade(forElements elements: [U]) -> Grade {
|
||||||
|
function(elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscript(_ u: U...) -> Grade {
|
||||||
|
grade(forElements: u)
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscript(_ u: [U]) -> Grade {
|
||||||
|
grade(forElements: u)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func asFuzzySet() -> AnyFuzzySet<[U]> {
|
||||||
|
.init(membershipFunction: function)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public class TernaryFuzzyRelation<U, V, W> {
|
||||||
|
|
||||||
|
let function: MembershipFunction<(U, V, W)>
|
||||||
|
|
||||||
|
public init(_ membershipFunction: MembershipFunction<(U, V, W)>) {
|
||||||
|
self.function = membershipFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(_ membershipFunction: @escaping MembershipFunction<(U, V, W)>.FunctionType) {
|
||||||
|
self.function = .init(membershipFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func grade(forElements elements: (U, V, W)) -> Grade {
|
||||||
|
function(elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscript(_ u: U, _ v: V, _ w: W) -> Grade {
|
||||||
|
grade(forElements: (u, v, w))
|
||||||
|
}
|
||||||
|
|
||||||
|
public subscript(_ x: (U, V, W)) -> Grade {
|
||||||
|
grade(forElements: x)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func asFuzzySet() -> AnyFuzzySet<(U, V, W)> {
|
||||||
|
.init(membershipFunction: function)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
import XCTest
|
||||||
|
import FuzzyRelations
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
final class FuzzyRelationsTests: XCTestCase {
|
||||||
|
func test_cartesianProduct_discreteSets() {
|
||||||
|
let fs1 = DiscreteMutableFuzzySet(elementToGradeMap: [
|
||||||
|
"a1": 1,
|
||||||
|
"a2": 0.6,
|
||||||
|
"a3": 0.3,
|
||||||
|
])
|
||||||
|
let fs2 = DiscreteMutableFuzzySet(elementToGradeMap: [
|
||||||
|
"b1": 0.6,
|
||||||
|
"b2": 0.9,
|
||||||
|
"b3": 0.1,
|
||||||
|
])
|
||||||
|
let expectedTuples = [
|
||||||
|
("a1", "b1"),
|
||||||
|
("a1", "b2"),
|
||||||
|
("a1", "b3"),
|
||||||
|
("a2", "b1"),
|
||||||
|
("a2", "b2"),
|
||||||
|
("a2", "b3"),
|
||||||
|
("a3", "b1"),
|
||||||
|
("a3", "b2"),
|
||||||
|
("a3", "b3"),
|
||||||
|
]
|
||||||
|
let expectedGrades = [
|
||||||
|
0.6,
|
||||||
|
0.9,
|
||||||
|
0.1,
|
||||||
|
0.6,
|
||||||
|
0.6,
|
||||||
|
0.1,
|
||||||
|
0.3,
|
||||||
|
0.3,
|
||||||
|
0.1,
|
||||||
|
]
|
||||||
|
|
||||||
|
let sut = BinaryCartesianProduct(fs1, fs2)
|
||||||
|
|
||||||
|
for (elements, grade) in zip(expectedTuples, expectedGrades) {
|
||||||
|
XCTAssertApproximatelyEqual(grade, sut[elements.0, elements.1])
|
||||||
|
XCTAssertApproximatelyEqual(grade, sut.grade(forElements: elements))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_customRelation_discreteSets() {
|
||||||
|
let sut = BinaryFuzzyRelation { (a: Int, b: Int) -> Grade in
|
||||||
|
switch abs(a - b) {
|
||||||
|
case 0: return 1
|
||||||
|
case 1: return 0.8
|
||||||
|
case 2: return 0.3
|
||||||
|
default: return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let expectedTuples = [
|
||||||
|
(1, 1),
|
||||||
|
(1, 2),
|
||||||
|
(1, 3),
|
||||||
|
(2, 1),
|
||||||
|
(2, 2),
|
||||||
|
(2, 3),
|
||||||
|
(3, 1),
|
||||||
|
(3, 2),
|
||||||
|
(3, 3),
|
||||||
|
]
|
||||||
|
let expectedGrades = [
|
||||||
|
1,
|
||||||
|
0.8,
|
||||||
|
0.3,
|
||||||
|
0.8,
|
||||||
|
1.0,
|
||||||
|
0.8,
|
||||||
|
0.3,
|
||||||
|
0.8,
|
||||||
|
1.00,
|
||||||
|
]
|
||||||
|
|
||||||
|
for (elements, grade) in zip(expectedTuples, expectedGrades) {
|
||||||
|
XCTAssertApproximatelyEqual(grade, sut[elements.0, elements.1])
|
||||||
|
XCTAssertApproximatelyEqual(grade, sut.grade(forElements: elements))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import XCTest
|
||||||
|
import FuzzySets
|
||||||
|
|
||||||
|
public func XCTAssertApproximatelyEqual(_ v1: Double, _ v2: Double, tolerance: Double = 0.0001) {
|
||||||
|
let diff = v1 - v2
|
||||||
|
XCTAssert(-tolerance <= diff && diff <= +tolerance)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func assertExpectedGrade<E, S: FuzzySet>(element: E, expectedGrade: Grade, sut: S)
|
||||||
|
where S.Universe == E {
|
||||||
|
let grade1 = sut[element]
|
||||||
|
let grade2 = sut.grade(forElement: element)
|
||||||
|
|
||||||
|
XCTAssertApproximatelyEqual(grade1, grade2)
|
||||||
|
XCTAssertApproximatelyEqual(expectedGrade, grade1)
|
||||||
|
XCTAssertApproximatelyEqual(expectedGrade, grade2)
|
||||||
|
}
|
Loading…
Reference in New Issue