Add basic fuzzy realtions
This commit is contained in:
parent
e7a2353f24
commit
968df3b5de
|
@ -7,6 +7,7 @@ enum SubmoduleName: String {
|
|||
case fuzzyKit = "FuzzyKit"
|
||||
case fuzzySets = "FuzzySets"
|
||||
case fuzzyNumbers = "FuzzyNumbers"
|
||||
case fuzzyRelations = "FuzzyRelations"
|
||||
|
||||
var name: String { rawValue }
|
||||
var target: String { rawValue }
|
||||
|
@ -64,5 +65,18 @@ let package = Package(
|
|||
.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