Add basic fuzzy realtions

This commit is contained in:
Alexander Ignatov 2021-12-28 00:07:53 +02:00
parent e7a2353f24
commit 968df3b5de
7 changed files with 246 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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