From 3f9857f8cc956bee6349d5652d647b21c806b3b4 Mon Sep 17 00:00:00 2001 From: Alexander Ignatov Date: Fri, 24 Dec 2021 01:07:41 +0200 Subject: [PATCH] Add fuzzy numbers and modularize --- Package.swift | 49 ++++++++++++-- Sources/FuzzyKit/FuzzyKit.swift | 4 ++ Sources/FuzzyNumbers/FuzzyNumber.swift | 18 +++++ .../TriangularFuzzyNumber.swift | 65 +++++++++++++++++++ .../Functions/MembershipFunction.swift | 0 .../Functions/OperatorFunctions.swift | 0 .../{FuzzyKit => FuzzySets}/FuzzySet.swift | 0 .../Implementations}/AnyFuzzySet.swift | 0 .../DiscreteMutableFuzzySet.swift | 0 .../Implementations}/IterableFuzzySet.swift | 0 .../TriangularFuzzyNumberTests.swift | 14 ++++ .../FuzzySetsTests/AnyFuzzySetTests.swift | 2 +- .../DiscreteMutableFuzzySetTests.swift | 2 +- .../MembershipFunctionTests.swift | 2 +- .../Helpers/Helpers.swift | 2 +- .../IterableFuzzySetTests.swift | 2 +- 16 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 Sources/FuzzyKit/FuzzyKit.swift create mode 100644 Sources/FuzzyNumbers/FuzzyNumber.swift create mode 100644 Sources/FuzzyNumbers/Implementations/TriangularFuzzyNumber.swift rename Sources/{FuzzyKit => FuzzySets}/Functions/MembershipFunction.swift (100%) rename Sources/{FuzzyKit => FuzzySets}/Functions/OperatorFunctions.swift (100%) rename Sources/{FuzzyKit => FuzzySets}/FuzzySet.swift (100%) rename Sources/{FuzzyKit/FuzzySetImplementations => FuzzySets/Implementations}/AnyFuzzySet.swift (100%) rename Sources/{FuzzyKit/FuzzySetImplementations => FuzzySets/Implementations}/DiscreteMutableFuzzySet.swift (100%) rename Sources/{FuzzyKit/FuzzySetImplementations => FuzzySets/Implementations}/IterableFuzzySet.swift (100%) create mode 100644 Tests/FuzzyNumbersTests/TriangularFuzzyNumberTests.swift rename Tests/{FuzzyKitTests => }/FuzzySetsTests/AnyFuzzySetTests.swift (99%) rename Tests/{FuzzyKitTests => }/FuzzySetsTests/DiscreteMutableFuzzySetTests.swift (99%) rename Tests/{FuzzyKitTests => FuzzySetsTests}/FunctionsTests/MembershipFunctionTests.swift (93%) rename Tests/{FuzzyKitTests => FuzzySetsTests}/Helpers/Helpers.swift (96%) rename Tests/{FuzzyKitTests => }/FuzzySetsTests/IterableFuzzySetTests.swift (99%) diff --git a/Package.swift b/Package.swift index f1ccf1f..b60d3f1 100644 --- a/Package.swift +++ b/Package.swift @@ -3,12 +3,30 @@ import PackageDescription +enum SubmoduleName: String { + case fuzzyKit = "FuzzyKit" + case fuzzySets = "FuzzySets" + case fuzzyNumbers = "FuzzyNumbers" + + var name: String { rawValue } + var target: String { rawValue } + var testTarget: String { rawValue + "Tests" } +} + let package = Package( name: "FuzzyKit", products: [ .library( - name: "FuzzyKit", - targets: ["FuzzyKit"] + name: SubmoduleName.fuzzyKit.name, + targets: [SubmoduleName.fuzzyKit.target] + ), + .library( + name: SubmoduleName.fuzzySets.name, + targets: [SubmoduleName.fuzzySets.target] + ), + .library( + name: SubmoduleName.fuzzyNumbers.name, + targets: [SubmoduleName.fuzzyNumbers.target] ), ], dependencies: [ @@ -16,14 +34,35 @@ let package = Package( ], targets: [ .target( - name: "FuzzyKit", + name: SubmoduleName.fuzzyKit.target, + dependencies: [ + .target(name: SubmoduleName.fuzzySets.target), + .target(name: SubmoduleName.fuzzyNumbers.target), + ] + ), + .target( + name: SubmoduleName.fuzzySets.target, dependencies: [ .product(name: "RealModule", package: "swift-numerics"), ] ), .testTarget( - name: "FuzzyKitTests", - dependencies: ["FuzzyKit"] + name: SubmoduleName.fuzzySets.testTarget, + dependencies: [ + .target(name: SubmoduleName.fuzzySets.target) + ] + ), + .target( + name: SubmoduleName.fuzzyNumbers.target, + dependencies: [ + .target(name: SubmoduleName.fuzzySets.target), + ] + ), + .testTarget( + name: SubmoduleName.fuzzyNumbers.testTarget, + dependencies: [ + .target(name: SubmoduleName.fuzzyNumbers.target), + ] ), ] ) diff --git a/Sources/FuzzyKit/FuzzyKit.swift b/Sources/FuzzyKit/FuzzyKit.swift new file mode 100644 index 0000000..d995cb3 --- /dev/null +++ b/Sources/FuzzyKit/FuzzyKit.swift @@ -0,0 +1,4 @@ +// A module that re-exports the complete FuzzyKit public API. + +@_exported import FuzzySets +@_exported import FuzzyNumbers diff --git a/Sources/FuzzyNumbers/FuzzyNumber.swift b/Sources/FuzzyNumbers/FuzzyNumber.swift new file mode 100644 index 0000000..f3539e7 --- /dev/null +++ b/Sources/FuzzyNumbers/FuzzyNumber.swift @@ -0,0 +1,18 @@ +import FuzzySets + +public protocol FuzzyNumber { + + typealias Universe = Double + + func eraseToAnyFuzzySet() -> AnyFuzzySet + + static func + (lhs: Self, rhs: Self) -> Self + + static func - (lhs: Self, rhs: Self) -> Self + + prefix static func - (x: Self) -> Self + +// func approximatelyMultiplied(by other: Self) -> Self +// +// func approximatelyDivided(by other: Self) -> Self +} diff --git a/Sources/FuzzyNumbers/Implementations/TriangularFuzzyNumber.swift b/Sources/FuzzyNumbers/Implementations/TriangularFuzzyNumber.swift new file mode 100644 index 0000000..ca7976b --- /dev/null +++ b/Sources/FuzzyNumbers/Implementations/TriangularFuzzyNumber.swift @@ -0,0 +1,65 @@ +import FuzzySets + +public struct TriangularFuzzyNumber: FuzzyNumber { + + public typealias Universe = Double + + public let minimum: Universe + public let peak: Universe + public let maximum: Universe + + internal let function: MembershipFunction + + public init(minimum: Universe, peak: Universe, maximum: Universe) { + self.minimum = minimum + self.peak = peak + self.maximum = maximum + self.function = .triangular(minimum: minimum, peak: peak, maximum: maximum) + } + + public init(peak: Universe, leftInterval: Universe, rightInterval: Universe) { + self.minimum = peak - leftInterval + self.peak = peak + self.maximum = peak + rightInterval + self.function = .triangular(minimum: minimum, peak: peak, maximum: maximum) + } + + public func eraseToAnyFuzzySet() -> AnyFuzzySet { + .init(membershipFunction: function) + } + + public static func + (lhs: TriangularFuzzyNumber, rhs: TriangularFuzzyNumber) -> TriangularFuzzyNumber { + .init( + minimum: lhs.minimum + rhs.minimum, + peak: lhs.peak + rhs.peak, + maximum: lhs.maximum + rhs.maximum + ) + } + + public static func - (lhs: TriangularFuzzyNumber, rhs: TriangularFuzzyNumber) -> TriangularFuzzyNumber { + .init( + minimum: lhs.minimum - rhs.maximum, + peak: lhs.peak - rhs.peak, + maximum: lhs.maximum - rhs.minimum + ) + } + + prefix public static func - (x: TriangularFuzzyNumber) -> TriangularFuzzyNumber { + .init(minimum: -x.maximum, peak: -x.peak, maximum: -x.minimum) + } + +// +// public func approximatelyMultiplied(by other: TriangularFuzzyNumber) -> TriangularFuzzyNumber { +// // TODO +// } +// +// public func approximatelyDivided(by other: TriangularFuzzyNumber) -> TriangularFuzzyNumber { +// // TODO +// } +} + +extension TriangularFuzzyNumber: Equatable { + public static func == (lhs: TriangularFuzzyNumber, rhs: TriangularFuzzyNumber) -> Bool { + lhs.minimum == rhs.minimum && lhs.peak == rhs.peak && lhs.maximum == rhs.maximum + } +} diff --git a/Sources/FuzzyKit/Functions/MembershipFunction.swift b/Sources/FuzzySets/Functions/MembershipFunction.swift similarity index 100% rename from Sources/FuzzyKit/Functions/MembershipFunction.swift rename to Sources/FuzzySets/Functions/MembershipFunction.swift diff --git a/Sources/FuzzyKit/Functions/OperatorFunctions.swift b/Sources/FuzzySets/Functions/OperatorFunctions.swift similarity index 100% rename from Sources/FuzzyKit/Functions/OperatorFunctions.swift rename to Sources/FuzzySets/Functions/OperatorFunctions.swift diff --git a/Sources/FuzzyKit/FuzzySet.swift b/Sources/FuzzySets/FuzzySet.swift similarity index 100% rename from Sources/FuzzyKit/FuzzySet.swift rename to Sources/FuzzySets/FuzzySet.swift diff --git a/Sources/FuzzyKit/FuzzySetImplementations/AnyFuzzySet.swift b/Sources/FuzzySets/Implementations/AnyFuzzySet.swift similarity index 100% rename from Sources/FuzzyKit/FuzzySetImplementations/AnyFuzzySet.swift rename to Sources/FuzzySets/Implementations/AnyFuzzySet.swift diff --git a/Sources/FuzzyKit/FuzzySetImplementations/DiscreteMutableFuzzySet.swift b/Sources/FuzzySets/Implementations/DiscreteMutableFuzzySet.swift similarity index 100% rename from Sources/FuzzyKit/FuzzySetImplementations/DiscreteMutableFuzzySet.swift rename to Sources/FuzzySets/Implementations/DiscreteMutableFuzzySet.swift diff --git a/Sources/FuzzyKit/FuzzySetImplementations/IterableFuzzySet.swift b/Sources/FuzzySets/Implementations/IterableFuzzySet.swift similarity index 100% rename from Sources/FuzzyKit/FuzzySetImplementations/IterableFuzzySet.swift rename to Sources/FuzzySets/Implementations/IterableFuzzySet.swift diff --git a/Tests/FuzzyNumbersTests/TriangularFuzzyNumberTests.swift b/Tests/FuzzyNumbersTests/TriangularFuzzyNumberTests.swift new file mode 100644 index 0000000..f2e3c26 --- /dev/null +++ b/Tests/FuzzyNumbersTests/TriangularFuzzyNumberTests.swift @@ -0,0 +1,14 @@ +import XCTest +import FuzzyNumbers + +final class TriangularFuzzyNumberTests: XCTestCase { + func test_addition() { + let a = TriangularFuzzyNumber(minimum: -3, peak: 2, maximum: 4) + let b = TriangularFuzzyNumber(minimum: -1, peak: 0, maximum: 6) + let expect = TriangularFuzzyNumber(minimum: -4, peak: 2, maximum: 10) + + let result = a + b + + XCTAssertEqual(result, expect) + } +} diff --git a/Tests/FuzzyKitTests/FuzzySetsTests/AnyFuzzySetTests.swift b/Tests/FuzzySetsTests/AnyFuzzySetTests.swift similarity index 99% rename from Tests/FuzzyKitTests/FuzzySetsTests/AnyFuzzySetTests.swift rename to Tests/FuzzySetsTests/AnyFuzzySetTests.swift index bc8bf12..cbc882b 100644 --- a/Tests/FuzzyKitTests/FuzzySetsTests/AnyFuzzySetTests.swift +++ b/Tests/FuzzySetsTests/AnyFuzzySetTests.swift @@ -1,5 +1,5 @@ import XCTest -import FuzzyKit +import FuzzySets final class AnyFuzzySetTests: XCTestCase { func test_initFromDiscreteMutableFuzzySet() { diff --git a/Tests/FuzzyKitTests/FuzzySetsTests/DiscreteMutableFuzzySetTests.swift b/Tests/FuzzySetsTests/DiscreteMutableFuzzySetTests.swift similarity index 99% rename from Tests/FuzzyKitTests/FuzzySetsTests/DiscreteMutableFuzzySetTests.swift rename to Tests/FuzzySetsTests/DiscreteMutableFuzzySetTests.swift index 6cccea3..c6ad0f5 100644 --- a/Tests/FuzzyKitTests/FuzzySetsTests/DiscreteMutableFuzzySetTests.swift +++ b/Tests/FuzzySetsTests/DiscreteMutableFuzzySetTests.swift @@ -1,5 +1,5 @@ import XCTest -import FuzzyKit +import FuzzySets final class DiscreteMutableFuzzySetTests: XCTestCase { func test_defaultInit_allGradesAreZero() throws { diff --git a/Tests/FuzzyKitTests/FunctionsTests/MembershipFunctionTests.swift b/Tests/FuzzySetsTests/FunctionsTests/MembershipFunctionTests.swift similarity index 93% rename from Tests/FuzzyKitTests/FunctionsTests/MembershipFunctionTests.swift rename to Tests/FuzzySetsTests/FunctionsTests/MembershipFunctionTests.swift index 5631c71..8b43698 100644 --- a/Tests/FuzzyKitTests/FunctionsTests/MembershipFunctionTests.swift +++ b/Tests/FuzzySetsTests/FunctionsTests/MembershipFunctionTests.swift @@ -1,5 +1,5 @@ import XCTest -import FuzzyKit +import FuzzySets final class MembershipFunctionTests: XCTestCase { func test_isCallable() throws { diff --git a/Tests/FuzzyKitTests/Helpers/Helpers.swift b/Tests/FuzzySetsTests/Helpers/Helpers.swift similarity index 96% rename from Tests/FuzzyKitTests/Helpers/Helpers.swift rename to Tests/FuzzySetsTests/Helpers/Helpers.swift index 1f3b419..a549a26 100644 --- a/Tests/FuzzyKitTests/Helpers/Helpers.swift +++ b/Tests/FuzzySetsTests/Helpers/Helpers.swift @@ -1,5 +1,5 @@ import XCTest -import FuzzyKit +import FuzzySets func XCTAssertApproximatelyEqual(_ v1: Double, _ v2: Double, tolerance: Double = 0.0001) { let diff = v1 - v2 diff --git a/Tests/FuzzyKitTests/FuzzySetsTests/IterableFuzzySetTests.swift b/Tests/FuzzySetsTests/IterableFuzzySetTests.swift similarity index 99% rename from Tests/FuzzyKitTests/FuzzySetsTests/IterableFuzzySetTests.swift rename to Tests/FuzzySetsTests/IterableFuzzySetTests.swift index 3f03b55..76a4b1d 100644 --- a/Tests/FuzzyKitTests/FuzzySetsTests/IterableFuzzySetTests.swift +++ b/Tests/FuzzySetsTests/IterableFuzzySetTests.swift @@ -1,5 +1,5 @@ import XCTest -import FuzzyKit +import FuzzySets class IterableFuzzySetTests: XCTestCase { private var near4Support4: [IterableFuzzySet>.Element] = [