├── .swift-version
├── .gitignore
├── .xcodesamplecode.plist
├── Sources
├── EquationKitSupportBigInt
│ ├── EquationKitSupportBigInt.swift
│ ├── README.md
│ ├── Operators
│ │ ├── BigInt+IntegerNumberExpressible.swift
│ │ └── BigInt_Operators.swift
│ └── Variables
│ │ └── BigInt_Variables.swift
├── EquationKitSupportDouble
│ ├── EquationKitSupportDouble.swift
│ ├── README.md
│ ├── Variables
│ │ └── Double_Variables.swift
│ └── Operators
│ │ └── Double_Operators.swift
└── EquationKit
│ ├── Protocols
│ ├── Evaluatable.swift
│ ├── Negatable.swift
│ ├── AbsoluteConvertible.swift
│ ├── Differentiatable.swift
│ ├── Algebraic.swift
│ ├── Substitutionable+Evaluate.swift
│ ├── Solvable.swift
│ └── Substitutionable.swift
│ ├── Modulus
│ ├── ModulusMode.swift
│ ├── ModulusFunction.swift
│ └── Modulus.swift
│ ├── Term
│ ├── TermProtocol+Negatable.swift
│ ├── TermProtocol+AbsoluteConvertible.swift
│ ├── TermProtocol+Comparable.swift
│ ├── TermProtocol+Concatenation.swift
│ ├── TermProtocol+Sorting.swift
│ ├── TermProtocol+Concrete.swift
│ ├── TermProtocol+Substitionable.swift
│ ├── TermProtocol+CustomStringConvertible.swift
│ ├── TermProtocol+Differentiatable.swift
│ └── TermProtocol.swift
│ ├── Polynomial
│ ├── PolynomialProtocol+Negatable.swift
│ ├── PolynomialProtocol+AbsoluteConvertible.swift
│ ├── PolynomialProtocol+Equatable.swift
│ ├── PolynomialProtocol+Concrete.swift
│ ├── PolynomialProtocol+Substitutionable.swift
│ ├── PolynomialProtocol+Differentiatable.swift
│ ├── PolynomialProtocol+CustomStringConvertible.swift
│ ├── PolynomialProtocol.swift
│ └── PolynomialProtocol+Concatenation.swift
│ ├── MathematicalOperators
│ ├── ModularEvaluationOperand.swift
│ ├── Variable+Assignment.swift
│ ├── PolynomialEvaluationSubtitutionOfVariablesToConstantsOperators.swift
│ ├── PolynomialEvaluationOperators.swift
│ ├── IntermediateOperandsFor_N-ary_Operators
│ │ ├── CongruentEqualityOperand.swift
│ │ └── NumberAndConstants.swift
│ └── PolynomialCongruenceEvaluationOperators.swift
│ ├── NumberExpressible
│ ├── IntegerNumberExpressible.swift
│ ├── FloatingPointNumberExpressible.swift
│ ├── Int+IntegerNumberExpressible.swift
│ ├── Double+FloatingPointNumberExpressible.swift
│ └── NumberExpressible.swift
│ ├── CustomOperators.swift
│ ├── Extensions
│ ├── Comparable_Extension.swift
│ ├── Set_Extension.swift
│ └── Array_Extension.swift
│ ├── Exponentiation
│ ├── ExponentiationProtocol+Comparable.swift
│ ├── ExponentiationProtocol+Concrete.swift
│ ├── ExponentiationProtocol.swift
│ ├── ExponentiationProtocol+Substitionable.swift
│ ├── ExponentiationProtocol+CustomStringConvertible.swift
│ └── ExponentiationProtocol+Differentiatable.swift
│ ├── SortingOfTerms
│ ├── TermSorting.swift
│ ├── Sorting.swift
│ ├── SortingWithinTerm.swift
│ └── SortingBetweenTerms.swift
│ └── NamedVariables
│ ├── NamedVariable.swift
│ ├── Constant.swift
│ └── Variable.swift
├── Tests
├── EquationKitSupportBigIntTests
│ ├── LinuxMain.swift
│ └── Tests
│ │ ├── XCTestManifests.swift
│ │ ├── BigIntAdditionTests.swift
│ │ └── MathematicalOperatorTests.swift
└── EquationKitSupportDoubleTests
│ ├── LinuxMain.swift
│ ├── Tests
│ ├── XCTestManifests.swift
│ ├── ConstantSubstitutionTests.swift
│ ├── Concatenation
│ │ ├── Multiplication
│ │ │ └── ConcatenationByMultiplicationTests.swift
│ │ ├── Addition
│ │ │ └── ConcatenationByAdditionTests.swift
│ │ └── Subtraction
│ │ │ └── ConcatenationBySubtractionTests.swift
│ ├── ExponentiationArraySortingTests.swift
│ ├── ExploringRandomStuffTests.swift
│ ├── PolynomialMultipliedByPolynomialTests.swift
│ ├── PolynomialsExponentiatedTests.swift
│ ├── Differentiation
│ │ └── SimpleDifferentiationTests.swift
│ └── TermSortingTests.swift
│ └── DoubleTestsBase.swift
├── Package.resolved
├── Package.swift
├── README.md
└── LICENSE
/.swift-version:
--------------------------------------------------------------------------------
1 | 4.2
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /*XCTestManifests.swift
3 | /Test/LinuxMain.swift
4 | /.build
5 | /Packages
6 | /*.xcodeproj
7 | /.swiftpm
8 |
--------------------------------------------------------------------------------
/.xcodesamplecode.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Sources/EquationKitSupportBigInt/EquationKitSupportBigInt.swift:
--------------------------------------------------------------------------------
1 | // A module that re-exports the complete EquationKitSupportBigInt public API.
2 | @_exported import EquationKitBigIntOperators
3 | @_exported import EquationKitBigIntVariables
4 |
--------------------------------------------------------------------------------
/Sources/EquationKitSupportDouble/EquationKitSupportDouble.swift:
--------------------------------------------------------------------------------
1 | // A module that re-exports the complete EquationKitSupportDouble public API.
2 | @_exported import EquationKitDoubleOperators
3 | @_exported import EquationKitDoubleVariables
4 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Protocols/Evaluatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Evaluatable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportBigIntTests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | import EquationKitSupportBigIntTests
4 |
5 | var tests = [XCTestCaseEntry]()
6 | tests += BigIntAdditionTests.allTests()
7 | tests += MathematicalOperatorTests.allTests()
8 | XCTMain(tests)
9 |
--------------------------------------------------------------------------------
/Sources/EquationKitSupportBigInt/README.md:
--------------------------------------------------------------------------------
1 | # EquationKitSupportBigInt
2 |
3 | This umbrella module provides an easy way to get access to both the `BigInt` supoort for *Operators* and *Variables* with a single import statement:
4 |
5 | ```swift
6 | import EquationKitSupportBigInt
7 | ```
8 |
--------------------------------------------------------------------------------
/Sources/EquationKitSupportDouble/README.md:
--------------------------------------------------------------------------------
1 | # EquationKitSupportDouble
2 |
3 | This umbrella module provides an easy way to get access to both the `Doubble` supoort for *Operators* and *Variables* with a single import statement:
4 |
5 | ```swift
6 | import EquationKitSupportDouble
7 | ```
8 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportBigIntTests/Tests/XCTestManifests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | #if !canImport(ObjectiveC)
4 | public func allTests() -> [XCTestCaseEntry] {
5 | return [
6 | testCase(BigIntAdditionTests.allTests),
7 | testCase(MathematicalOperatorTests.allTests)
8 | ]
9 | }
10 | #endif
11 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Modulus/ModulusMode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModulusMode.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public enum ModulusMode {
12 | /// Swift style
13 | case allowNegative
14 |
15 | /// Python Style
16 | case alwaysPositive
17 | }
18 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "BigInt",
6 | "repositoryURL": "https://github.com/attaswift/BigInt",
7 | "state": {
8 | "branch": null,
9 | "revision": "19f5e8a48be155e34abb98a2bcf4a343316f0343",
10 | "version": "5.0.0"
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol+Negatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol+Negatable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Negatable
12 | public extension TermProtocol {
13 | func negated() -> Self {
14 | return Self(exponentiations: exponentiations, coefficient: coefficient.negated())!
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Polynomial/PolynomialProtocol+Negatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialProtocol+Negatable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Negatable
12 | public extension PolynomialProtocol {
13 | func negated() -> Self {
14 | return Self(terms: terms.negated(), constant: constant.negated())
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Protocols/Negatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Negatable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol Negatable {
12 | func negated() -> Self
13 | }
14 |
15 | extension Array: Negatable where Element: Negatable {
16 | public func negated() -> [Element] {
17 | return map { $0.negated() }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/EquationKit/MathematicalOperators/ModularEvaluationOperand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModularEvaluationOperand.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-01.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public func % (scalar: N, modulusConstants: ModularEvaluationOperand) -> CongruentEqualityOperand {
12 | return CongruentEqualityOperand(scalar: scalar, modulusConstants: modulusConstants)
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol+AbsoluteConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol+AbsoluteConvertible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-31.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - AbsoluteConvertible
12 | public extension TermProtocol {
13 | func absolute() -> Self {
14 | return Self(exponentiations: exponentiations, coefficient: coefficient.absolute())!
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Polynomial/PolynomialProtocol+AbsoluteConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialProtocol+AbsoluteConvertible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-31.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - AbsoluteConvertible
12 | public extension PolynomialProtocol {
13 | func absolute() -> Self {
14 | return Self(terms: terms.absolute(), constant: constant.absolute())
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Polynomial/PolynomialProtocol+Equatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialProtocol+Equatable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Equatable
12 | public extension PolynomialProtocol {
13 | static func == (lhs: Self, rhs: Self) -> Bool {
14 | return lhs.constant == rhs.constant
15 | && lhs.terms.sorted() == rhs.terms.sorted()
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Protocols/AbsoluteConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AbsoluteConvertible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-31.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol AbsoluteConvertible {
12 |
13 | /// Turns `3y - 2x - 5` => `3y + 2x + 5`
14 | func absolute() -> Self
15 |
16 | }
17 |
18 | extension Array: AbsoluteConvertible where Element: AbsoluteConvertible {
19 | public func absolute() -> [Element] {
20 | return map { $0.absolute() }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/EquationKit/NumberExpressible/IntegerNumberExpressible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntegerNumberExpressible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-26.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol IntegerNumberExpressible: NumberExpressible, BinaryInteger {
12 | init(_ int: Int)
13 | }
14 |
15 | public extension IntegerNumberExpressible {
16 | func mod(_ modulus: Self, mode: ModulusMode) -> Self {
17 | return EquationKit.mod(self, modulus: Modulus(modulus, mode: mode))
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/EquationKit/NumberExpressible/FloatingPointNumberExpressible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FloatingPointNumberExpressible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-26.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol FloatingPointNumberExpressible: NumberExpressible, BinaryFloatingPoint {
12 | init(_ float: Float)
13 | }
14 |
15 | public extension FloatingPointNumberExpressible {
16 | func mod(_ modulus: Self, mode: ModulusMode) -> Self {
17 | return EquationKit.mod(self, modulus: Modulus(modulus, mode: mode))
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/EquationKit/MathematicalOperators/Variable+Assignment.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Variable+Assignment.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-01.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | infix operator <-: AssignmentPrecedence
12 | infix operator ≔: AssignmentPrecedence
13 |
14 | public func <-(variable: VariableStruct, value: N) -> ConstantStruct where N: NumberExpressible {
15 | return ConstantStruct(variable, value: value)
16 | }
17 | public func ≔ (variable: VariableStruct, value: N) -> ConstantStruct {
18 | return variable <- value
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/EquationKit/CustomOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomOperators.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | precedencegroup ExponentiationPrecedence {
12 | higherThan: MultiplicationPrecedence
13 | associativity: left
14 | }
15 |
16 | infix operator ^^: ExponentiationPrecedence
17 |
18 | internal func += (lhs: inout N?, rhs: N) where N: Numeric {
19 | if let lhsIndeed = lhs {
20 | lhs = lhsIndeed + rhs
21 | } else {
22 | lhs = rhs
23 | }
24 | if lhs == 0 {
25 | lhs = nil
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Protocols/Differentiatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Differentiatable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public typealias PolynomialType = PolynomialStruct>>
12 |
13 | public protocol NumberTypeSpecifying {
14 | associatedtype NumberType: NumberExpressible
15 | }
16 |
17 | public protocol Differentiatable: NumberTypeSpecifying {
18 | func differentiateWithRespectTo(_ variableToDifferentiate: VariableStruct) -> PolynomialType?
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Extensions/Comparable_Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Comparable_Extension.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-21.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public extension Comparable {
12 | func compare(to other: Self) -> ComparisonResult {
13 | if self > other {
14 | return .orderedDescending
15 | } else if self < other {
16 | return .orderedAscending
17 | } else if self == other {
18 | return .orderedSame
19 | } else {
20 | fatalError("should not happen.")
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportDoubleTests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | import EquationKitSupportDoubleTests
4 |
5 | var tests = [XCTestCaseEntry]()
6 | tests += ConcatenationByAdditionTests.allTests)
7 | tests += ConcatenationByMultiplicationTests.allTests)
8 | tests += ConcatenationBySubtractionTests.allTests)
9 | tests += SimpleDifferentiationTests.allTests)
10 | tests += ConstantSubstitutionTests.allTests)
11 | tests += ExploringRandomStuffTests.allTests)
12 | tests += ExponentiationArraySortingTests.allTests)
13 | tests += PolynomialMultipliedByPolynomialTests.allTests)
14 | tests += PolynomialsExponentiatedTests.allTests)
15 | tests += TermSortingTests.allTests)
16 | XCTMain(tests)
17 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol+Comparable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol+Comparable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Equatable
12 | public extension TermProtocol {
13 | static func == (lhs: Self, rhs: Self) -> Bool {
14 | return lhs.exponentiations.sorted() == rhs.exponentiations.sorted() && lhs.coefficient == rhs.coefficient
15 | }
16 | }
17 |
18 | // MARK: - Comparable
19 | extension TermProtocol {
20 | public static func < (lhs: Self, rhs: Self) -> Bool {
21 | return [rhs, lhs].sorted() == [lhs, rhs]
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol+Concatenation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol+Concatenation.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Private Extension Term
12 | public extension TermProtocol {
13 | func multipliedBy(other: Self) -> Self {
14 | return Self(exponentiations: exponentiations + other.exponentiations, coefficient: coefficient*other.coefficient)!
15 | }
16 |
17 | func multiplyingCoefficientBy(constant: NumberType) -> Self? {
18 | return Self(exponentiations: exponentiations, coefficient: coefficient * constant)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Exponentiation/ExponentiationProtocol+Comparable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExponentiationProtocol+Comparable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Equatable
12 | public extension ExponentiationProtocol {
13 | static func == (lhs: Self, rhs: Self) -> Bool {
14 | return lhs.variable == rhs.variable && lhs.exponent == rhs.exponent
15 | }
16 | }
17 |
18 | // MARK: - Comparable
19 | extension ExponentiationProtocol {
20 | public static func < (lhs: Self, rhs: Self) -> Bool {
21 | return [rhs, lhs].sorted() == [lhs, rhs]
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol+Sorting.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol+Sorting.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public extension TermProtocol {
12 |
13 | func sortingExponentiations(by sorting: [SortingWithinTerm] = SortingWithinTerm.defaultArray) -> Self {
14 | return Self(exponentiations: exponentiations, sorting: sorting, coefficient: coefficient)!
15 | }
16 |
17 | func sortingExponentiations(by sorting: SortingWithinTerm) -> Self {
18 | return sortingExponentiations(by: [sorting])
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Exponentiation/ExponentiationProtocol+Concrete.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExponentiationProtocol+Concrete.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - ExponentiationStruct
12 | public struct ExponentiationStruct: ExponentiationProtocol {
13 |
14 | public typealias NumberType = Number
15 |
16 | public let variable: VariableStruct
17 | public let exponent: NumberType
18 |
19 | public init(variable: VariableStruct, exponent: NumberType) {
20 | self.variable = variable
21 | self.exponent = exponent
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportDoubleTests/Tests/XCTestManifests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | #if !canImport(ObjectiveC)
4 | public func allTests() -> [XCTestCaseEntry] {
5 | return [
6 | testCase(ConcatenationByAdditionTests.allTests),
7 | testCase(ConcatenationByMultiplicationTests.allTests),
8 | testCase(ConcatenationBySubtractionTests.allTests),
9 | testCase(SimpleDifferentiationTests.allTests),
10 | testCase(ConstantSubstitutionTests.allTests),
11 | testCase(ExploringRandomStuffTests.allTests),
12 | testCase(ExponentiationArraySortingTests.allTests),
13 | testCase(PolynomialMultipliedByPolynomialTests.allTests),
14 | testCase(PolynomialsExponentiatedTests.allTests),
15 | testCase(TermSortingTests.allTests),
16 | ]
17 | }
18 | #endif
19 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Extensions/Set_Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Set_Extension.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-02.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Set {
12 | /// Returns the union between this and `other` but `Element` being that of `other`.
13 | /// 1. Maps the set `other` to the same elements as this set:
14 | /// 2. Performs the union between these to sets
15 | /// 3. Returns the elements in the original set `other`, that exists in the union.
16 | public func unionTo(other: Set, transform: (O) -> (Element)) -> Set {
17 | return Set(union(Set(other.map(transform))).compactMap { element in other.first(where: { element == transform($0) }) })
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/EquationKit/MathematicalOperators/PolynomialEvaluationSubtitutionOfVariablesToConstantsOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialEvaluationSubtitutionOfVariablesToConstantsOperators.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-01.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Non special unicode char operators
12 | infix operator <--: BitwiseShiftPrecedence
13 | public func <-- (number: N, constants: [ConstantStruct]) -> NumberAndConstants {
14 | return NumberAndConstants(number: number, constants: constants)
15 | }
16 |
17 | // MARK: Special unicode char corresponding operators
18 | infix operator ↤: BitwiseShiftPrecedence
19 | public func ↤ (number: N, constants: [ConstantStruct]) -> NumberAndConstants {
20 | return number <-- constants
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol+Concrete.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol+Concrete.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public struct TermStruct: TermProtocol {
12 |
13 | public typealias NumberType = Exponentiation.NumberType
14 | public typealias ExponentiationType = Exponentiation
15 | public let coefficient: NumberType
16 | public let exponentiations: [ExponentiationType]
17 |
18 | public init?(exponentiations: [ExponentiationType], sorting: [SortingWithinTerm], coefficient: NumberType) {
19 | guard coefficient != 0 else { return nil }
20 | self.exponentiations = exponentiations.merged().sorted(by: sorting)
21 | self.coefficient = coefficient
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Exponentiation/ExponentiationProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExponentiationProtocol.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol ExponentiationProtocol: Algebraic, Comparable {
12 | var variable: VariableStruct { get }
13 | var exponent: NumberType { get }
14 | init(variable: VariableStruct, exponent: NumberType)
15 | }
16 |
17 | // MARK: - Convenience Initializers
18 | public extension ExponentiationProtocol {
19 | init(_ variable: VariableStruct, exponent: NumberType = .one) {
20 | self.init(variable: variable, exponent: exponent)
21 | }
22 |
23 | init(_ name: String, exponent: NumberType = .one) {
24 | self.init(VariableStruct(name), exponent: exponent)
25 | }
26 | }
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Sources/EquationKit/MathematicalOperators/PolynomialEvaluationOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialEvaluationOperators.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-01.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Non special unicode char operators
12 | public func == (polynomial: PolynomialType, evaluationOperand: EvaluationOperand) -> Bool {
13 | return polynomial.evaluate(constants: evaluationOperand.constants) == evaluationOperand.reference
14 | }
15 | public func != (polynomial: PolynomialType, evaluationOperand: EvaluationOperand) -> Bool {
16 | return !(polynomial == evaluationOperand)
17 | }
18 |
19 | // MARK: Special unicode char corresponding operators
20 | infix operator ≠: AssignmentPrecedence
21 | public func ≠ (polynomial: PolynomialType, evaluationProxy: EvaluationOperand) -> Bool {
22 | return polynomial != evaluationProxy
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/EquationKit/SortingOfTerms/TermSorting.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermSorting.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-21.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public struct TermSorting {
12 | public let betweenTerms: [SortingBetweenTerms]
13 | public let withinTerm: [SortingWithinTerm]
14 | public init(betweenTerms: [SortingBetweenTerms] = SortingBetweenTerms.defaultArray, withinTerm: [SortingWithinTerm] = SortingWithinTerm.defaultArray) {
15 | self.betweenTerms = betweenTerms
16 | self.withinTerm = withinTerm
17 | }
18 | }
19 |
20 | public extension TermSorting {
21 |
22 | init(betweenTerms: SortingBetweenTerms) {
23 | self.init(betweenTerms: [betweenTerms])
24 | }
25 |
26 | static var `default`: TermSorting {
27 | return TermSorting()
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Modulus/ModulusFunction.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModulusFunction.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public func mod(_ number: T, modulus: Modulus) -> T where T: BinaryInteger {
12 | var mod = number % modulus.number
13 | guard modulus.mode == .alwaysPositive else { return mod }
14 | if mod < 0 {
15 | mod = mod + modulus.number
16 | }
17 | guard mod >= 0 else { fatalError("NEGATIVE VALUE") }
18 | return mod
19 | }
20 |
21 | public func mod(_ number: F, modulus: Modulus) -> F where F: BinaryFloatingPoint {
22 | var mod = number.truncatingRemainder(dividingBy: modulus.number)
23 | guard modulus.mode == .alwaysPositive else { return mod }
24 | if mod < 0 {
25 | mod = mod + modulus.number
26 | }
27 | guard mod >= 0 else { fatalError("NEGATIVE VALUE") }
28 | return mod
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/EquationKit/MathematicalOperators/IntermediateOperandsFor_N-ary_Operators/CongruentEqualityOperand.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CongruentEqualityOperand.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-01.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public struct CongruentEqualityOperand {
12 | public let scalar: Number
13 | public let modulus: Modulus
14 | public let constants: Set>
15 |
16 | public init(scalar: Number, modulus: Number, constants: Set>) {
17 | self.scalar = scalar
18 | self.modulus = Modulus(modulus)
19 | self.constants = constants
20 | }
21 | }
22 |
23 | public extension CongruentEqualityOperand {
24 | public init(scalar: Number, modulusConstants: ModularEvaluationOperand) {
25 | self.init(scalar: scalar, modulus: modulusConstants.modulus, constants: modulusConstants.constants)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/EquationKit/NumberExpressible/Int+IntegerNumberExpressible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Int+IntegerNumberExpressible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-26.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Int: IntegerNumberExpressible {}
12 | public extension Int {
13 |
14 | static var zero: Int { return 0 }
15 | static var one: Int { return 1 }
16 |
17 | var shortFormat: String {
18 | return "\(self)"
19 | }
20 |
21 | var isNegative: Bool {
22 | return self < 0
23 | }
24 |
25 | var asInteger: Int {
26 | return self
27 | }
28 |
29 | var isPositive: Bool {
30 | return self > 0
31 | }
32 |
33 | func absolute() -> Int {
34 | return abs(self)
35 | }
36 |
37 | func negated() -> Int {
38 | return -self
39 | }
40 |
41 |
42 | func raised(to exponent: Int) -> Int {
43 | return Int(pow(Double(self), Double(exponent)))
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Exponentiation/ExponentiationProtocol+Substitionable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExponentiationProtocol+Substitionable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Substitionable
12 | public extension ExponentiationProtocol {
13 |
14 | var uniqueVariables: Set> {
15 | return variable.uniqueVariables
16 | }
17 |
18 | func substitute(constants: Set>, modulus: Modulus?) -> PolynomialType {
19 |
20 | return parse(
21 | substitutionable: variable,
22 | constants: constants,
23 | modulus: modulus,
24 | handleNumber: { base in
25 | base.raised(to: exponent)
26 | },
27 | handleAlgebraic: { poly in
28 | return poly.raised(to: self.exponent.asInteger)
29 | }
30 | )
31 | }
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Polynomial/PolynomialProtocol+Concrete.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialProtocol+Concrete.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public struct PolynomialStruct: PolynomialProtocol {
12 |
13 | public typealias NumberType = Term.NumberType
14 | public typealias TermType = Term
15 |
16 | public let constant: NumberType
17 | public let terms: [TermType]
18 |
19 | public init(terms: [TermType], sorting: TermSorting, constant: NumberType) {
20 | self.terms = terms.merged().sorted(by: sorting)
21 | self.constant = constant
22 | }
23 | }
24 |
25 | // MARK: - ExpressibleByIntegerLiteral
26 | extension PolynomialStruct: ExpressibleByIntegerLiteral where Term.NumberType == Double {
27 | public typealias IntegerLiteralType = Int
28 | public init(integerLiteral value: Int) {
29 | self.init(constant: NumberType(value))
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Extensions/Array_Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Array_Extension.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Array where Element: Hashable {
12 | public func containsDuplicates() -> Bool {
13 | return Set(self).count != count
14 | }
15 | }
16 |
17 | extension Array where Element: Equatable {
18 | func removed(element: Element) -> [Element] {
19 | guard contains(element) else { return self }
20 | var elements = self
21 | elements.removeAll { $0 == element }
22 | return elements
23 | }
24 | }
25 |
26 | public extension Array {
27 | func droppingFirst() -> [Element] {
28 | guard count > 1 else { return [] }
29 | return Array(dropFirst())
30 | }
31 |
32 | func droppingFirstNilIfEmpty() -> [Element]? {
33 | guard count > 1 else { return nil }
34 | return Array(dropFirst())
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Polynomial/PolynomialProtocol+Substitutionable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialProtocol+Substitutionable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Substitutionable
12 | public extension PolynomialProtocol {
13 |
14 | var uniqueVariables: Set> {
15 | return Set(terms.flatMap { Array($0.uniqueVariables) })
16 | }
17 |
18 | func substitute(constants: Set>, modulus: Modulus?) -> PolynomialType {
19 | return parseMany(
20 | substitutionables: terms,
21 | constants: constants,
22 | modulus: modulus,
23 | manyHandleAllNumbers: { values in
24 | values.reduce(self.constant, { $0 + $1 })
25 | },
26 | manyHandleMixedReduce: (initialResult: PolynomialType(constant: NumberType.zero), combine: {
27 | $0.adding(other: $1)
28 | })
29 | )
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol+Substitionable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol+Substitionable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Substitionable
12 | public extension TermProtocol {
13 |
14 | var uniqueVariables: Set> {
15 | return Set(exponentiations.map { $0.variable })
16 | }
17 |
18 | func substitute(constants: Set>, modulus: Modulus?) -> PolynomialType {
19 | return parseMany(
20 | substitutionables: exponentiations,
21 | constants: constants,
22 | modulus: modulus,
23 | manyHandleAllNumbers: { values in
24 | values.reduce(NumberType.one, { $0 * $1 }) * coefficient
25 | },
26 | manyHandleMixedReduce: (initialResult: PolynomialType(constant: coefficient), combine: {
27 | PolynomialType($0).multipliedBy(other: PolynomialType($1))
28 | })
29 | )
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Protocols/Algebraic.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Algebraic.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-17.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Shared protocol by all algebraic types.
12 | public protocol Atom {}
13 |
14 | public protocol Algebraic: Atom, Differentiatable, Substitutionable, Hashable, CustomStringConvertible {}
15 |
16 | public extension PolynomialProtocol {
17 |
18 | init(_ atom: Atom) {
19 | // if let constant = atom as? NumberType {
20 | // self.init(constant: constant)
21 | // } else
22 | if let variable = atom as? VariableStruct {
23 | self.init(variable: variable)
24 | } else if let exponentiation = atom as? ExponentiationType {
25 | self.init(exponentiation: exponentiation)
26 | } else if let term = atom as? TermType {
27 | self.init(term: term)
28 | } else if let polynomial = atom as? Self {
29 | self.init(polynomial: polynomial)
30 | } else {
31 | fatalError("incorrect implementation")
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportDoubleTests/Tests/ConstantSubstitutionTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConstantSubstitutionTests.swift
3 | // EquationKitDoubleTests
4 | //
5 | // Created by Alexander Cyon on 2018-09-02.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import EquationKit
12 | @testable import EquationKitDoubleSupport
13 |
14 | class ConstantSubstitutionTests: DoubleTestsBase {
15 |
16 | static var allTests = [
17 | ("testReplaceYWith2", testReplaceYWith2),
18 | ("testWeierstrass", testWeierstrass),
19 | ]
20 |
21 | func testReplaceYWith2() {
22 | let eq = x + y
23 | XCTAssertEqual(
24 | x + 2,
25 | eq.substitute() {[ y <- 2 ]}
26 | )
27 | }
28 |
29 | func testWeierstrass() {
30 | let 𝑥 = Variable("𝑥")
31 | let 𝑦 = Variable("𝑦")
32 | let 𝑥³ = 𝑥^^3
33 | let 𝑦² = 𝑦^^2
34 | let 𝑎 = Variable("𝑎")
35 | let 𝑏 = Variable("𝑏")
36 | let eq = 𝑦² - 𝑥³ - 𝑎*𝑥 - 𝑏
37 | XCTAssertEqual(eq.substitute() {[ 𝑎 <- 0, 𝑏 <- 7 ]}, 𝑦² - 𝑥³ - 7)
38 | }
39 |
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/Sources/EquationKit/NumberExpressible/Double+FloatingPointNumberExpressible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Double+FloatingPointNumberExpressible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-26.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Double: FloatingPointNumberExpressible {}
12 | public extension Double {
13 |
14 | static var zero: Double { return 0 }
15 | static var one: Double { return 1 }
16 | var shortFormat: String {
17 | let decimalsEqualToZero = truncatingRemainder(dividingBy: 1) == 0
18 | let format = decimalsEqualToZero ? "%.0f" : "%.2f"
19 | return String(format: format, self)
20 | }
21 |
22 | var asInteger: Int {
23 | return Int(exactly: self)!
24 | }
25 |
26 | var isNegative: Bool {
27 | return self < 0
28 | }
29 |
30 | var isPositive: Bool {
31 | return self > 0
32 | }
33 |
34 | func absolute() -> Double {
35 | return abs(self)
36 | }
37 |
38 | func negated() -> Double {
39 | return -self
40 | }
41 |
42 | func raised(to exponent: Double) -> Double {
43 | return pow(self, exponent)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/EquationKit/SortingOfTerms/Sorting.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Sorting.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-21.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol Sorting: Equatable {
12 | associatedtype TypeToSort
13 | typealias AreInIncreasingOrder = (TypeToSort, TypeToSort) -> (Bool)
14 | func areInIncreasingOrder(tieBreakers: [Self]?) -> AreInIncreasingOrder
15 | var comparing: (TypeToSort, TypeToSort) -> (ComparisonResult) { get }
16 | var targetComparisonResult: ComparisonResult { get }
17 | }
18 |
19 | public extension Sorting {
20 |
21 | func areInIncreasingOrder(tieBreakers: [Self]?) -> AreInIncreasingOrder {
22 | return {
23 | let comparison = self.comparing($0, $1)
24 | guard comparison != .orderedSame else {
25 | if let tieBreakers = tieBreakers, let tieBreaker = tieBreakers.removed(element: self).first {
26 | return tieBreaker.areInIncreasingOrder(tieBreakers: tieBreakers.droppingFirst())($0, $1)
27 | } else {
28 | return false
29 | }
30 | }
31 | return comparison == self.targetComparisonResult
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/EquationKit/NumberExpressible/NumberExpressible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NumberExpressible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-22.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol NumberExpressible: Numeric, Negatable, AbsoluteConvertible, Hashable, Comparable {
12 |
13 | static func + (lhs: Self, rhs: Self) -> Self
14 | static func * (lhs: Self, rhs: Self) -> Self
15 | static func - (lhs: Self, rhs: Self) -> Self
16 | static func / (lhs: Self, rhs: Self) -> Self
17 |
18 | var asInteger: Int { get }
19 |
20 | func raised(to exponent: Self) -> Self
21 | func mod(_ modulus: Self, mode: ModulusMode) -> Self
22 |
23 | static var zero: Self { get }
24 | static var one: Self { get }
25 |
26 | var isNegative: Bool { get }
27 | var isPositive: Bool { get }
28 | var shortFormat: String { get }
29 | }
30 |
31 | public extension NumberExpressible {
32 | var isZero: Bool {
33 | return self == .zero
34 | }
35 | }
36 |
37 | public extension NumberExpressible {
38 | func modIfNeeded(_ modulus: Modulus?) -> Self {
39 | guard let modulus = modulus else { return self }
40 | return mod(modulus.number, mode: modulus.mode)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/EquationKit/MathematicalOperators/IntermediateOperandsFor_N-ary_Operators/NumberAndConstants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NumberAndConstants.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-01.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public struct NumberAndConstants {
12 |
13 | public let number: Number
14 | public let constants: Set>
15 | public init(number: Number, constants: Set>) {
16 | self.number = number
17 | self.constants = constants
18 | }
19 |
20 | }
21 | public extension NumberAndConstants {
22 | public init(number: Number, constants: [ConstantStruct]) {
23 | guard !constants.containsDuplicates() else { fatalError("Constants array should not contain duplicates") }
24 | self.init(number: number, constants: Set(constants))
25 | }
26 | }
27 |
28 | public typealias EvaluationOperand = NumberAndConstants
29 | public extension EvaluationOperand {
30 | var reference: Number { return number }
31 | }
32 |
33 | public typealias ModularEvaluationOperand = NumberAndConstants
34 | public extension ModularEvaluationOperand {
35 | var modulus: Number { return number }
36 | }
37 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportBigIntTests/Tests/BigIntAdditionTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BigIntAdditionTests.swift
3 | // EquationKitBigIntTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-25.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 |
12 | @testable import EquationKit
13 | @testable import EquationKitBigIntSupport
14 | @testable import EquationKitBigIntSupport
15 | import BigInt
16 |
17 | class BigIntAdditionTests: XCTestCase {
18 |
19 | static var allTests = [
20 | ("testSimpleBigIntTests", testSimpleBigIntTests),
21 | ("testAddition", testAddition),
22 | ("testBigExp", testBigExp),
23 | ]
24 |
25 | func testSimpleBigIntTests() {
26 | let f = BigInt("F", radix: 16)!
27 | let c = BigInt("C", radix: 16)!
28 | XCTAssertEqual(f-c, 3)
29 | XCTAssertEqual(f+c, 27)
30 | }
31 |
32 | func testAddition() {
33 | XCTAssertEqual((x + y).evaluate() {[ x <- 1 << 65, y <- 1 << 66 ]}!.description, "110680464442257309696")
34 | }
35 |
36 | func testBigExp() {
37 | XCTAssertEqual((x⁹ + 1).evaluate() { x <- 1 << 65 }!.description, "126633165554229521438977290762059361297987250739820462036000284719563379254544315991201997343356439034674007770120263341747898897565056619503383631412169301973302667340133957633")
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/EquationKit/NamedVariables/NamedVariable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NamedVariable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol NamedVariable: NumberTypeSpecifying, CustomStringConvertible, Hashable, Comparable {
12 | var name: String { get }
13 | static func == (lhs: N, rhs: Self) -> Bool where N: NamedVariable, N.NumberType == Self.NumberType
14 | }
15 |
16 | public extension NamedVariable {
17 | static func == (lhs: N, rhs: Self) -> Bool where N: NamedVariable, N.NumberType == Self.NumberType {
18 | return lhs.name == rhs.name
19 | }
20 | }
21 |
22 | // MARK: - Equatable
23 | public extension NamedVariable {
24 | static func == (lhs: Self, rhs: Self) -> Bool {
25 | return lhs.name == rhs.name
26 | }
27 | }
28 |
29 | // MARK: - Comparable
30 | public extension NamedVariable {
31 | static func < (lhs: Self, rhs: Self) -> Bool {
32 | return lhs.name < rhs.name
33 | }
34 | }
35 |
36 | // MARK: - Hashable
37 | public extension NamedVariable {
38 | var hashValue: Int {
39 | return name.hashValue
40 | }
41 | }
42 |
43 | // MARK: - CustomStringConvertible
44 | public extension NamedVariable {
45 | var description: String {
46 | return name
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol+CustomStringConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol+CustomStringConvertible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - CustomStringConvertible
12 | public extension TermProtocol {
13 |
14 | func asString(sorting: SortingWithinTerm) -> String {
15 | return asString(sorting: [sorting])
16 | }
17 |
18 | func asString(sorting: [SortingWithinTerm] = SortingWithinTerm.defaultArray) -> String {
19 | let sorted = sortingExponentiations(by: sorting)
20 | return sorted.description
21 | }
22 |
23 | var description: String {
24 | var exponentiationsString: String {
25 | return exponentiations.map { $0.description }.joined()
26 | }
27 |
28 | var coefficientString: String {
29 | let absoluteCoefficient = coefficient.absolute()
30 | guard absoluteCoefficient != .one else { return "" }
31 | return "\(absoluteCoefficient.shortFormat)"
32 | }
33 |
34 | return "\(coefficientString)\(exponentiationsString)"
35 | }
36 | }
37 |
38 | // MARK: - CustomDebugStringConvertible
39 | public extension TermProtocol {
40 | var debugDescription: String {
41 | return "\(signString)\(description)"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Exponentiation/ExponentiationProtocol+CustomStringConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExponentiationProtocol+CustomStringConvertible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - CustomStringConvertible
12 | public extension ExponentiationProtocol {
13 | var description: String {
14 | guard exponent != 1 else { return variable.description }
15 | if exponent > 1 && exponent < 10 {
16 | let superscript: String
17 | if exponent == 2 {
18 | superscript = "²"
19 | } else if exponent == 3 {
20 | superscript = "³"
21 | } else if exponent == 4 {
22 | superscript = "⁴"
23 | } else if exponent == 5 {
24 | superscript = "⁵"
25 | } else if exponent == 6 {
26 | superscript = "⁶"
27 | } else if exponent == 7 {
28 | superscript = "⁷"
29 | } else if exponent == 8 {
30 | superscript = "⁸"
31 | } else if exponent == 9 {
32 | superscript = "⁹"
33 | } else { fatalError("forgot number") }
34 | return "\(variable)\(superscript)"
35 | } else {
36 | return "\(variable)^\(exponent.shortFormat)"
37 | }
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/Sources/EquationKitSupportBigInt/Operators/BigInt+IntegerNumberExpressible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BigInt+IntegerNumberExpressible.swift
3 | // EquationKitBigIntTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-26.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import EquationKit
11 |
12 | /// https://github.com/attaswift/BigInt
13 | import BigInt
14 |
15 |
16 | extension BigInt: IntegerNumberExpressible {
17 | public var asInteger: Int {
18 | guard bitWidth < 32 else { fatalError("overflow") }
19 | return Int(description)!
20 | }
21 | }
22 |
23 | public extension BigInt {
24 | var isNegative: Bool {
25 | return self < 0
26 | }
27 |
28 | var isPositive: Bool {
29 | return self > 0
30 | }
31 |
32 | func absolute() -> BigInt {
33 | return BigInt(sign: .plus, magnitude: magnitude)
34 | }
35 |
36 | func raised(to exponent: BigInt) -> BigInt {
37 | guard exponent.bitWidth <= Int.bitWidth else { fatalError("to big") }
38 | return power(Int(exponent))
39 | }
40 |
41 | static var zero: BigInt {
42 | return 0
43 | }
44 |
45 | static var one: BigInt {
46 | return 1
47 | }
48 |
49 | var shortFormat: String {
50 | return description
51 | }
52 |
53 | func negated() -> BigInt {
54 | return BigInt(sign: sign == .plus ? .minus : .plus, magnitude: magnitude)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Modulus/Modulus.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Modulus.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-03.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public struct Modulus {
12 | public let number: Number
13 | public let mode: ModulusMode
14 | public init(_ number: Number, mode: ModulusMode = .alwaysPositive) {
15 | self.number = number
16 | self.mode = mode
17 | }
18 | }
19 |
20 | extension Modulus: ExpressibleByIntegerLiteral where Number: InitializableByInteger {//where Number: IntegerNumberExpressible {
21 | public typealias IntegerLiteralType = Int
22 |
23 | public init(integerLiteral value: IntegerLiteralType) {
24 | self.init(Number(value))
25 | }
26 | }
27 |
28 | extension Modulus: ExpressibleByFloatLiteral where Number: InitializableByFloat {//where Number: FloatingPointNumberExpressible {
29 | public typealias FloatLiteralType = Float
30 |
31 | public init(floatLiteral value: FloatLiteralType) {
32 | self.init(Number(value))
33 | }
34 | }
35 |
36 | public protocol InitializableByInteger {
37 | init(_ int: Int)
38 | }
39 | public protocol InitializableByFloat {
40 | init(_ float: Float)
41 | }
42 | extension Int: InitializableByInteger {}
43 | extension Double: InitializableByInteger {}
44 | extension Int: InitializableByFloat {}
45 | extension Double: InitializableByFloat {}
46 |
--------------------------------------------------------------------------------
/Sources/EquationKit/MathematicalOperators/PolynomialCongruenceEvaluationOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialCongruenceEvaluationOperators.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-01.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Non special unicode char operators
12 | infix operator =%=: AssignmentPrecedence
13 | public func =%= (polynomial: PolynomialType, congruence: CongruentEqualityOperand) -> Bool {
14 | return polynomial.evaluate(constants: congruence.constants, modulus: congruence.modulus) == congruence.scalar
15 | }
16 |
17 | infix operator =!%=: AssignmentPrecedence
18 | public func =!%= (polynomial: PolynomialType, congruence: CongruentEqualityOperand) -> Bool {
19 | return !(polynomial ≡≡ congruence)
20 | }
21 |
22 | // MARK: Special unicode char corresponding operators
23 | infix operator ≡≡: AssignmentPrecedence
24 | public func ≡≡ (polynomial: PolynomialType, congruence: CongruentEqualityOperand) -> Bool {
25 | return polynomial =%= congruence
26 | }
27 |
28 | infix operator !≡: AssignmentPrecedence
29 | public func !≡ (polynomial: PolynomialType, congruence: CongruentEqualityOperand) -> Bool {
30 | return polynomial =!%= congruence
31 | }
32 |
33 | infix operator ≢: AssignmentPrecedence
34 | public func ≢ (polynomial: PolynomialType, congruence: CongruentEqualityOperand) -> Bool {
35 | return polynomial !≡ congruence
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Exponentiation/ExponentiationProtocol+Differentiatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExponentiationProtocol+Differentiatable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Differentiatable
12 | public extension ExponentiationProtocol {
13 |
14 | func differentiateWithRespectTo(_ variableToDifferentiate: VariableStruct) -> PolynomialType? {
15 |
16 | guard let _ = variable.differentiateWithRespectTo(variableToDifferentiate) else {
17 | return PolynomialType(exponentiation: self as! PolynomialType.ExponentiationType)
18 | }
19 |
20 | let exponentPriorToDifferentiation = self.exponent
21 | let exponent = exponentPriorToDifferentiation - 1
22 | guard exponent > 0 else {
23 | // actually this is never used.... but makes us able to distinguish between
24 | // doing `exponentiations.append(exponentiation)` and doing
25 | // nothing in differentiation in TermProtocol
26 | return PolynomialType(constant: NumberType.one)
27 | }
28 |
29 | let exponentiation = PolynomialType.ExponentiationType(variable, exponent: exponent)
30 | let term = PolynomialType.TermType(exponentiation: exponentiation, coefficient: exponentPriorToDifferentiation)!
31 | return PolynomialType(term: term)
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportDoubleTests/Tests/Concatenation/Multiplication/ConcatenationByMultiplicationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConcatenationByMultiplicationTests.swift
3 | // EquationKitTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-22.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 |
10 | import Foundation
11 | import XCTest
12 | @testable import EquationKit
13 | @testable import EquationKitDoubleSupport
14 |
15 | class ConcatenationByMultiplicationTests: DoubleTestsBase {
16 |
17 | static var allTests = [
18 | ("testX³", testX³),
19 | ("testVariableTimesVariableTimesVariable", testVariableTimesVariableTimesVariable),
20 | ]
21 |
22 | func testX³() {
23 |
24 | let eq = x*x*x
25 | XCTAssertEqual(eq, x³ + 0)
26 | XCTAssertEqual(eq.evaluate() { x <- 2 }!, 8)
27 | XCTAssertEqual(eq.evaluate() { x <- 3 }!, 27)
28 | XCTAssertEqual(eq.evaluate() { x <- 4 }!, 64)
29 | XCTAssertEqual(eq.evaluate() { x <- 5 }!, 125)
30 | }
31 |
32 | // Testing different ways of expressiong `x*y*z`
33 | func testVariableTimesVariableTimesVariable() {
34 | let xy = x*y
35 | let yx = y*x
36 | XCTAssertEqual(xy, yx)
37 | let yz = y*z
38 |
39 | let xy_z = xy*z
40 | let yx_z = yx*z
41 | XCTAssertEqual(xy_z, yx_z)
42 |
43 | let x_yz = x*yz
44 | XCTAssertEqual(x_yz, xy_z)
45 | XCTAssertEqual(x_yz, yx_z)
46 | XCTAssertEqual(x*y*z, x_yz)
47 | XCTAssertEqual(x*y*z, x_yz)
48 |
49 | XCTAssertEqual(Term(exponentiation: x³), Term(x, x, x))
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Sources/EquationKitSupportDouble/Variables/Double_Variables.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Double_Variables.swift
3 | // EquationKitDoubleTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-26.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import EquationKit
11 | import EquationKitDoubleOperators
12 |
13 | public let x = Variable("x")
14 | public let y = Variable("y")
15 | public let z = Variable("z")
16 |
17 | public let x² = Exponentiation(x, exponent: 2)
18 | public let x³ = Exponentiation(x, exponent: 3)
19 | public let x⁴ = Exponentiation(x, exponent: 4)
20 | public let x⁵ = Exponentiation(x, exponent: 5)
21 | public let x⁶ = Exponentiation(x, exponent: 6)
22 | public let x⁷ = Exponentiation(x, exponent: 7)
23 | public let x⁸ = Exponentiation(x, exponent: 8)
24 | public let x⁹ = Exponentiation(x, exponent: 9)
25 |
26 | public let y² = Exponentiation(y, exponent: 2)
27 | public let y³ = Exponentiation(y, exponent: 3)
28 | public let y⁴ = Exponentiation(y, exponent: 4)
29 | public let y⁵ = Exponentiation(y, exponent: 5)
30 | public let y⁶ = Exponentiation(y, exponent: 6)
31 | public let y⁷ = Exponentiation(y, exponent: 7)
32 | public let y⁸ = Exponentiation(y, exponent: 8)
33 | public let y⁹ = Exponentiation(y, exponent: 9)
34 |
35 | public let z² = Exponentiation(z, exponent: 2)
36 | public let z³ = Exponentiation(z, exponent: 3)
37 | public let z⁴ = Exponentiation(z, exponent: 4)
38 | public let z⁵ = Exponentiation(z, exponent: 5)
39 | public let z⁶ = Exponentiation(z, exponent: 6)
40 | public let z⁷ = Exponentiation(z, exponent: 7)
41 | public let z⁸ = Exponentiation(z, exponent: 8)
42 | public let z⁹ = Exponentiation(z, exponent: 9)
43 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol+Differentiatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol+Differentiatable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Differentiatable
12 | public extension TermProtocol {
13 |
14 | func differentiateWithRespectTo(_ variableToDifferentiate: VariableStruct) -> PolynomialType? {
15 | guard contains(variable: variableToDifferentiate) else { return nil }
16 |
17 | var exponentiations = [ExponentiationType]()
18 | var coefficient = self.coefficient
19 | for exponentiation in self.exponentiations {
20 | guard let differentiationResult = exponentiation.differentiateWithRespectTo(variableToDifferentiate) else { exponentiations.append(exponentiation); continue }
21 |
22 | guard let term = differentiationResult.terms.first else { continue }
23 | guard differentiationResult.terms.count == 1 else { fatalError("what? bad state...") }
24 |
25 | coefficient *= term.coefficient
26 | guard let exponentiation = term.exponentiations.first, term.exponentiations.count == 1 else { return nil }
27 | exponentiations.append(exponentiation as! ExponentiationType)
28 | }
29 |
30 | if exponentiations.count == 0 {
31 | return PolynomialType(constant: coefficient)
32 | } else {
33 | let term = Self(exponentiations: exponentiations, coefficient: coefficient)
34 | return PolynomialType(term: term as! PolynomialType.TermType)
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportDoubleTests/DoubleTestsBase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DoubleTestsBase.swift
3 | // EquationKitTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import EquationKit
12 | @testable import EquationKitDoubleSupport
13 |
14 | class DoubleTestsBase: XCTestCase {
15 |
16 | lazy var tx = Term(x)
17 | lazy var -tx = tx.negated()
18 |
19 | lazy var ty = Term(y)
20 | lazy var -ty = ty.negated()
21 |
22 | lazy var tz = Term(z)
23 | lazy var -tz = tz.negated()
24 |
25 | lazy var tx² = Term(exponentiation: x²)
26 | lazy var -tx² = tx².negated()
27 |
28 | lazy var ty² = Term(exponentiation: y²)
29 | lazy var -ty² = ty².negated()
30 |
31 | lazy var tz² = Term(exponentiation: z²)
32 | lazy var -tz² = tz².negated()
33 |
34 | lazy var tx³ = Term(exponentiation: x³)
35 | lazy var -tx³ = tx³.negated()
36 |
37 | lazy var ty³ = Term(exponentiation: y³)
38 | lazy var -ty³ = ty³.negated()
39 |
40 | lazy var tz³ = Term(exponentiation: z³)
41 | lazy var -tz³ = tz³.negated()
42 |
43 | lazy var tx⁴ = Term(x⁴)
44 |
45 | lazy var txyz = Term(x, y, z)
46 | lazy var -txyz = txyz.negated()
47 |
48 | lazy var txy = Term(x, y)
49 | lazy var -txy = txy.negated()
50 | lazy var txz = Term(x, z)
51 | lazy var -txz = txz
52 | lazy var tx²z³ = Term(x², z³)
53 | lazy var -tx²z³ = tx²z³.negated()
54 | lazy var tx²y²z² = Term(x², y², z²)
55 | lazy var -tx²y²z² = tx²y²z².negated()
56 | lazy var tx²y²z³ = Term(x²,y²,z³)
57 | lazy var -tx²y²z³ = tx²y²z³.negated()
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/Sources/EquationKit/NamedVariables/Constant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constant.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol ConstantProtocol: NamedVariable {
12 | var name: String { get }
13 | var value: NumberType { get }
14 | init(name: String, value: NumberType)
15 |
16 | func toVariable() -> VariableStruct
17 | }
18 |
19 | // MARK: - Default Implementation
20 | public extension ConstantProtocol {
21 | func toVariable() -> VariableStruct {
22 | return VariableStruct(name)
23 | }
24 | }
25 |
26 | // MARK: - CustomStringConvertible
27 | public extension ConstantProtocol {
28 | var description: String {
29 | return "<\(name)=\(value.shortFormat)>"
30 | }
31 | }
32 |
33 | // MARK: - Convenience Initializers
34 | public extension ConstantProtocol {
35 |
36 | init(_ variable: VariableStruct, value: NumberType) {
37 | self.init(name: variable.name, value: value)
38 | }
39 | }
40 |
41 | public extension ConstantProtocol where NumberType: FloatingPointNumberExpressible {
42 | init(_ variable: VariableStruct, value: Int) {
43 | self.init(variable, value: NumberType(Double(value)))
44 | }
45 | }
46 |
47 | // MARK: - ConstantStruct
48 | public struct ConstantStruct: ConstantProtocol {
49 | public typealias NumberType = Number
50 | public let name: String
51 | public let value: NumberType
52 | public init(name: String, value: NumberType) {
53 | self.name = name
54 | self.value = value
55 | }
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/Sources/EquationKitSupportBigInt/Variables/BigInt_Variables.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BigInt_Variables.swift
3 | // EquationKitBigIntTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-26.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import EquationKit
11 | import EquationKitBigIntOperators
12 |
13 | /// https://github.com/attaswift/BigInt
14 | import BigInt
15 |
16 | public let x = Variable("x")
17 | public let y = Variable("y")
18 | public let z = Variable("z")
19 | public let x² = Exponentiation(x, exponent: 2)
20 | public let x³ = Exponentiation(x, exponent: 3)
21 | public let x⁴ = Exponentiation(x, exponent: 4)
22 | public let x⁵ = Exponentiation(x, exponent: 5)
23 | public let x⁶ = Exponentiation(x, exponent: 6)
24 | public let x⁷ = Exponentiation(x, exponent: 7)
25 | public let x⁸ = Exponentiation(x, exponent: 8)
26 | public let x⁹ = Exponentiation(x, exponent: 9)
27 |
28 | public let y² = Exponentiation(y, exponent: 2)
29 | public let y³ = Exponentiation(y, exponent: 3)
30 | public let y⁴ = Exponentiation(y, exponent: 4)
31 | public let y⁵ = Exponentiation(y, exponent: 5)
32 | public let y⁶ = Exponentiation(y, exponent: 6)
33 | public let y⁷ = Exponentiation(y, exponent: 7)
34 | public let y⁸ = Exponentiation(y, exponent: 8)
35 | public let y⁹ = Exponentiation(y, exponent: 9)
36 |
37 | public let z² = Exponentiation(z, exponent: 2)
38 | public let z³ = Exponentiation(z, exponent: 3)
39 | public let z⁴ = Exponentiation(z, exponent: 4)
40 | public let z⁵ = Exponentiation(z, exponent: 5)
41 | public let z⁶ = Exponentiation(z, exponent: 6)
42 | public let z⁷ = Exponentiation(z, exponent: 7)
43 | public let z⁸ = Exponentiation(z, exponent: 8)
44 | public let z⁹ = Exponentiation(z, exponent: 9)
45 |
46 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Polynomial/PolynomialProtocol+Differentiatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialProtocol+Differentiatable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Differentiatable
12 | public extension PolynomialProtocol {
13 |
14 | func differentiateWithRespectTo(_ variableToDifferentiate: VariableStruct) -> PolynomialType? {
15 | guard contains(variable: variableToDifferentiate) else { return PolynomialType(constant: NumberType.zero) }
16 | var terms = [PolynomialType.TermType]()
17 | var constant: NumberType = .zero
18 | for term in self.terms {
19 | guard let differentiationResult = term.differentiateWithRespectTo(variableToDifferentiate) else { continue }
20 | if differentiationResult.terms.isEmpty && !differentiationResult.constant.isZero {
21 | constant += differentiationResult.constant
22 | } else if differentiationResult.terms.count == 1 && differentiationResult.constant.isZero, let term = differentiationResult.terms.first {
23 | terms.append(term)
24 | } else {
25 | fatalError("should not happen")
26 | }
27 |
28 | }
29 | return PolynomialType(terms: terms, constant: constant)
30 | }
31 | }
32 |
33 | // MARK: - Public Extensions
34 | public extension PolynomialProtocol {
35 | func contains(variable: VariableStruct) -> Bool {
36 | for term in terms {
37 | guard term.contains(variable: variable) else { continue }
38 | return true
39 | }
40 | return false
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Polynomial/PolynomialProtocol+CustomStringConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialProtocol+CustomStringConvertible.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - CustomStringConvertible
12 | public extension PolynomialProtocol {
13 |
14 | func sortingTerms(sorting: TermSorting) -> Self {
15 | return Self(terms: terms, sorting: sorting, constant: constant)
16 | }
17 |
18 | func asString(sorting betweenTerms: SortingBetweenTerms) -> String {
19 | return asString(sorting: TermSorting(betweenTerms: betweenTerms))
20 | }
21 |
22 | func asString(sorting: TermSorting) -> String {
23 | let sortedPolynomial = sortingTerms(sorting: sorting)
24 | return sortedPolynomial.description
25 | }
26 |
27 | var description: String {
28 | var constantString: String {
29 | guard constant != .zero else { return "" }
30 | let constantSignString = constant.isPositive ? "+" : "-"
31 | return " \(constantSignString) \(constant.absolute().shortFormat)"
32 | }
33 |
34 | var termsString: String {
35 | func termString(index: Int, term: TermType) -> String {
36 | let signStringIfNegative = term.isNegative ? term.signString : ""
37 | let signString = (index == 0 || index == terms.endIndex) ? "\(signStringIfNegative)" : " \(term.signString) "
38 | return "\(signString)\(term.description)"
39 |
40 | }
41 | return terms.enumerated().map { termString(index: $0, term: $1) }.joined()
42 | }
43 |
44 | return "\(termsString)\(constantString)"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Sources/EquationKitSupportDouble/Operators/Double_Operators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Double_Operators.swift
3 | // EquationKitTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-25.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import EquationKit
11 |
12 | public typealias Variable = VariableStruct
13 | public typealias Constant = ConstantStruct
14 | public typealias Polynomial = PolynomialType
15 |
16 | public typealias Exponentiation = ExponentiationStruct
17 | public typealias Term = TermStruct
18 |
19 | public func +(lhs: Atom, rhs: Atom) -> PolynomialType {
20 | return Polynomial(lhs).adding(other: Polynomial(rhs))
21 | }
22 |
23 | public func +(lhs: Atom, rhs: Double) -> PolynomialType {
24 | return Polynomial(lhs).adding(constant: rhs)
25 | }
26 |
27 | public func +(lhs: Double, rhs: Atom) -> PolynomialType {
28 | return Polynomial(rhs).adding(constant: lhs)
29 | }
30 |
31 | public func -(lhs: Atom, rhs: Atom) -> PolynomialType {
32 | return Polynomial(lhs).subtracting(other: Polynomial(rhs))
33 | }
34 |
35 | public func -(lhs: Atom, rhs: Double) -> PolynomialType {
36 | return Polynomial(lhs).subtracting(constant: rhs)
37 | }
38 |
39 | public func -(lhs: Double, rhs: Atom) -> PolynomialType {
40 | return Polynomial(rhs).negated().adding(constant: lhs)
41 | }
42 |
43 | public func *(lhs: Atom, rhs: Atom) -> PolynomialType {
44 | return Polynomial(lhs).multipliedBy(other: Polynomial(rhs))
45 | }
46 |
47 | public func *(lhs: Atom, rhs: Double) -> PolynomialType {
48 | return Polynomial(lhs).multipliedBy(constant: rhs)
49 | }
50 |
51 | public func *(lhs: Double, rhs: Atom) -> PolynomialType {
52 | return rhs * lhs
53 | }
54 |
55 | public func ^^(lhs: Atom, rhs: Int) -> PolynomialType {
56 | return Polynomial(lhs).raised(to: rhs)
57 | }
58 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Protocols/Substitutionable+Evaluate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Substitutionable+Evaluate.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-02.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public extension Substitutionable {
12 |
13 | func evaluate(constants: Set>, modulus: Modulus? = nil) -> NumberType? {
14 | return substitute(constants: constants, modulus: modulus).asNumber
15 | }
16 |
17 | func evaluate(constants: [ConstantStruct], modulus: Modulus? = nil) -> NumberType? {
18 | guard !constants.containsDuplicates() else { fatalError("cannot contain duplicates") }
19 | return evaluate(constants: Set(constants), modulus: modulus)
20 | }
21 |
22 | func evaluate(constants: ConstantStruct..., modulus: Modulus? = nil) -> NumberType? {
23 | return evaluate(constants: constants, modulus: modulus)
24 | }
25 |
26 | func evaluate(modulus: Modulus? = nil, makeConstants: () -> [ConstantStruct]) -> NumberType? {
27 | return evaluate(constants: makeConstants(), modulus: modulus)
28 | }
29 |
30 | func evaluate(modulus: Modulus? = nil, makeConstants: () -> ConstantStruct) -> NumberType? {
31 | return evaluate(constants: [makeConstants()], modulus: modulus)
32 | }
33 |
34 | func evaluate(constants: [VariableStruct: NumberType], modulus: Modulus? = nil) -> NumberType? {
35 | return evaluate(constants: constants.map { ConstantStruct($0, value: $1) }, modulus: modulus)
36 | }
37 |
38 | func evaluate(modulus: Modulus? = nil, makeConstants: () -> [(VariableStruct, NumberType)]) -> NumberType? {
39 | let array = makeConstants().map { ConstantStruct($0, value: $1) }
40 | return evaluate(constants: array, modulus: modulus)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/EquationKit/NamedVariables/Variable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Variable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol VariableProtocol: NamedVariable, Algebraic {
12 | init(_ name: String)
13 | }
14 |
15 | public struct VariableStruct: VariableProtocol {
16 | public typealias NumberType = Number
17 | public let name: String
18 |
19 | public init(_ name: String) {
20 | self.name = name
21 | }
22 | }
23 |
24 | // MARK: - Substitution
25 | public extension VariableProtocol {
26 | func substitute(constants: Set>, modulus: Modulus?) -> PolynomialType {
27 | guard let constant = constants.first(where: { $0 == self }) else { return PolynomialType(variable: self as! VariableStruct) }
28 | return PolynomialType(constant: constant.value)
29 | }
30 | }
31 |
32 |
33 | // MARK: - Solvable
34 | public extension VariableProtocol {
35 |
36 | var uniqueVariables: Set> {
37 | return Set([self as! VariableStruct])
38 | }
39 |
40 | func findRoots(constants: Set>) -> Set> {
41 | guard let constant = constants.first(where: { $0.toVariable() == self }) else { return Set() }
42 | return Set([ConstantStruct(name: self.name, value: constant.value)])
43 | }
44 | }
45 |
46 | // MARK: - Differentiatable
47 | public extension VariableProtocol {
48 | func differentiateWithRespectTo(_ variableToDifferentiate: VariableStruct) -> PolynomialType? {
49 | guard variableToDifferentiate == self else { return nil }
50 | // actually this is never used.... but makes us able to distinguish between
51 | // doing `exponentiations.append(exponentiation)` and doing
52 | // nothing in differentiation in TermProtocol
53 | return PolynomialType(constant: .one)
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/EquationKitSupportBigInt/Operators/BigInt_Operators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BigInt_Operators.swift
3 | // EquationKitBigIntTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-26.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import EquationKit
11 |
12 | /// https://github.com/attaswift/BigInt
13 | import BigInt
14 |
15 | public typealias Variable = VariableStruct
16 | public typealias Constant = ConstantStruct
17 | public typealias Polynomial = PolynomialType
18 |
19 | public typealias Exponentiation = ExponentiationStruct
20 | public typealias Term = TermStruct
21 |
22 | public func +(lhs: Atom, rhs: Atom) -> PolynomialType {
23 | return Polynomial(lhs).adding(other: Polynomial(rhs))
24 | }
25 |
26 | public func +(lhs: Atom, rhs: BigInt) -> PolynomialType {
27 | return Polynomial(lhs).adding(constant: rhs)
28 | }
29 |
30 | public func +(lhs: BigInt, rhs: Atom) -> PolynomialType {
31 | return Polynomial(rhs).adding(constant: lhs)
32 | }
33 |
34 | public func -(lhs: Atom, rhs: Atom) -> PolynomialType {
35 | return Polynomial(lhs).subtracting(other: Polynomial(rhs))
36 | }
37 |
38 | public func -(lhs: Atom, rhs: BigInt) -> PolynomialType {
39 | return Polynomial(lhs).subtracting(constant: rhs)
40 | }
41 |
42 | public func -(lhs: BigInt, rhs: Atom) -> PolynomialType {
43 | return Polynomial(rhs).negated().adding(constant: lhs)
44 | }
45 |
46 | public func *(lhs: Atom, rhs: Atom) -> PolynomialType {
47 | return Polynomial(lhs).multipliedBy(other: Polynomial(rhs))
48 | }
49 |
50 | public func *(lhs: Atom, rhs: BigInt) -> PolynomialType {
51 | return Polynomial(lhs).multipliedBy(constant: rhs)
52 | }
53 |
54 | public func *(lhs: BigInt, rhs: Atom) -> PolynomialType {
55 | return rhs * lhs
56 | }
57 |
58 | public func ^^(lhs: Atom, rhs: Int) -> PolynomialType {
59 | return Polynomial(lhs).raised(to: rhs)
60 | }
61 |
62 | public func ^^(lhs: BigInt, rhs: Int) -> BigInt {
63 | return lhs.power(rhs)
64 | }
65 |
66 | public func ^^(lhs: Int, rhs: Int) -> BigInt {
67 | return BigInt(lhs) ^^ rhs
68 | }
69 |
70 | public func -(lhs: BigInt, rhs: Int) -> BigInt {
71 | return lhs - BigInt(rhs)
72 | }
73 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Protocols/Solvable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Solvable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-26.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// *****************************************
12 | /// NOT IMPLEMENTED YET
13 | /// *****************************************
14 |
15 | public enum Solution: NumberTypeSpecifying {
16 | public typealias NumberType = Number
17 |
18 | case roots(Set>)
19 | case number(NumberType)
20 | }
21 |
22 | public protocol Solvable: Substitutionable {
23 | func solve(constants: Set>) -> Solution
24 |
25 | /// Might have a look at Sympys solver: https://github.com/sympy/sympy/blob/master/sympy/solvers/solvers.py#L450-L1349
26 | func findRoots(constants: Set>) -> Set>
27 | }
28 |
29 | public extension Solvable {
30 |
31 | func solve(constants: Set>) -> Solution {
32 | let variablesPassed = Set>(constants.map { $0.toVariable() })
33 |
34 | if variablesPassed.isSuperset(of: uniqueVariables) {
35 | return .number(evaluate(constants: constants)!)
36 | } else {
37 | return .roots(findRoots(constants: constants))
38 | }
39 | }
40 | }
41 |
42 | public extension Set where Element: ConstantProtocol {
43 | func toVariables() -> [VariableStruct: Element.NumberType] {
44 | let array: [(VariableStruct, Element.NumberType)] = self.map { ($0.toVariable(), $0.value) }
45 | let dictionary: [VariableStruct: Element.NumberType] = array.reduce(into: [:]) { $0[$1.0] = $1.1 }
46 | return dictionary
47 | }
48 | }
49 | public extension ExponentiationProtocol {
50 |
51 | func findRoots(constants: Set>) -> Set> {
52 | fatalError()
53 | }
54 | }
55 | // MARK: - Solvable
56 | public extension TermProtocol {
57 |
58 | func findRoots(constants: Set>) -> Set> {
59 | fatalError()
60 | }
61 | }
62 |
63 |
64 | // MARK: - Solvable
65 | public extension PolynomialProtocol {
66 |
67 | func findRoots(constants: Set>) -> Set> {
68 | fatalError()
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Sources/EquationKit/SortingOfTerms/SortingWithinTerm.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SortingWithinTerm.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-21.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public enum SortingWithinTerm: Sorting {
12 | public typealias TypeToSort = ExponentiationStruct
13 | case descendingExponent
14 | case variablesAlphabetically
15 |
16 | public static var defaultArray: [SortingWithinTerm] {
17 | return [.descendingExponent, .variablesAlphabetically]
18 | }
19 | }
20 |
21 | public extension SortingWithinTerm {
22 |
23 |
24 | var comparing: (TypeToSort, TypeToSort) -> (ComparisonResult) {
25 | switch self {
26 | case .descendingExponent: return { $0.exponent.compare(to: $1.exponent) }
27 | case .variablesAlphabetically: return { $0.variable.name.compare(to: $1.variable.name) }
28 | }
29 | }
30 |
31 | var targetComparisonResult: ComparisonResult {
32 | switch self {
33 | case .variablesAlphabetically: return .orderedAscending
34 | case .descendingExponent: return .orderedDescending
35 | }
36 | }
37 | }
38 |
39 |
40 | public extension Array where Element: ExponentiationProtocol {
41 |
42 | func sorted(by sorting: SortingWithinTerm) -> [Element] {
43 | return sorted(by: [sorting])
44 | }
45 |
46 | func sorted(by sorting: [SortingWithinTerm] = SortingWithinTerm.defaultArray) -> [Element] {
47 | guard let first = sorting.first else { return self }
48 |
49 | let areInIncreasingOrderClosure: (Element, Element) -> Bool = {
50 | guard
51 | let lhs = $0 as? ExponentiationStruct,
52 | let rhs = $1 as? ExponentiationStruct
53 | else {
54 | fatalError("what to do")
55 | }
56 |
57 | return first.areInIncreasingOrder(tieBreakers: sorting.droppingFirstNilIfEmpty())(lhs, rhs)
58 | }
59 |
60 | return sorted(by: areInIncreasingOrderClosure)
61 | }
62 |
63 | func merged() -> [Element] {
64 | var count: [VariableStruct: Element.NumberType] = [:]
65 | for exponentiation in self {
66 | count[exponentiation.variable] += exponentiation.exponent
67 | }
68 | return count.compactMap { Element.init(variable: $0.key, exponent: $0.value) }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Polynomial/PolynomialProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialProtocol.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol PolynomialProtocol:
12 | Algebraic,
13 | AbsoluteConvertible,
14 | Negatable
15 | where
16 | TermType.NumberType == Self.NumberType
17 | {
18 | associatedtype TermType: TermProtocol
19 | var constant: NumberType { get }
20 | var terms: [TermType] { get }
21 |
22 | init(terms: [TermType], sorting: TermSorting, constant: NumberType)
23 | init(term: TermType, constant: NumberType)
24 | init(constant: NumberType)
25 | }
26 |
27 | // MARK: - Typealias
28 | public extension PolynomialProtocol {
29 | typealias ExponentiationType = TermType.ExponentiationType
30 | }
31 |
32 | // MARK: - Convenience Initializers
33 | public extension PolynomialProtocol {
34 |
35 | init(polynomial: Self) {
36 | self.init(terms: polynomial.terms, constant: polynomial.constant)
37 | }
38 |
39 | init(terms: [TermType], sorting: TermSorting = .default, constant: NumberType = .zero) {
40 | self.init(terms: terms, sorting: sorting, constant: constant)
41 | }
42 |
43 | init(term: TermType, constant: NumberType = .zero) {
44 | self.init(terms: [term], constant: constant)
45 | }
46 |
47 | init(constant: NumberType) {
48 | self.init(terms: [], constant: constant)
49 | }
50 |
51 | init(exponentiation: ExponentiationType, constant: NumberType = .zero) {
52 | self.init(term: TermType(exponentiation: exponentiation), constant: constant)
53 | }
54 |
55 | init(variable: VariableStruct, constant: NumberType = .zero) {
56 | self.init(exponentiation: ExponentiationType(variable), constant: constant)
57 | }
58 | }
59 |
60 | // MARK: - Public Extensions
61 | public extension PolynomialProtocol {
62 | var highestExponent: NumberType? {
63 | guard !terms.isEmpty else { return nil }
64 | return terms.sorting(betweenTerms: .descendingExponent)[0].highestExponent
65 | }
66 |
67 | var asNumber: NumberType? {
68 | guard terms.isEmpty else { return nil }
69 | return constant
70 | }
71 | var isNumber: Bool {
72 | return asNumber != nil
73 | }
74 | }
75 |
76 | // MARK: - ExpressibleByArrayLiteral
77 | extension PolynomialStruct: ExpressibleByArrayLiteral {
78 | public init(arrayLiteral terms: TermType...) {
79 | self.init(terms: terms)
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Term/TermProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TermProtocol.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol TermProtocol:
12 | Algebraic,
13 | Negatable,
14 | AbsoluteConvertible,
15 | Comparable,
16 | CustomDebugStringConvertible
17 | where
18 | ExponentiationType.NumberType == Self.NumberType
19 | {
20 |
21 | associatedtype ExponentiationType: ExponentiationProtocol
22 |
23 | var coefficient: NumberType { get }
24 | var exponentiations: [ExponentiationType] { get }
25 |
26 | init?(exponentiations: [ExponentiationType], sorting: [SortingWithinTerm], coefficient: NumberType)
27 |
28 | }
29 |
30 | // MARK: - Convenience Initializers
31 | public extension TermProtocol {
32 | init?(exponentiations: [ExponentiationType], sorting: [SortingWithinTerm] = SortingWithinTerm.defaultArray, coefficient: NumberType = .one) {
33 | self.init(exponentiations: exponentiations, sorting: sorting, coefficient: coefficient)
34 | }
35 |
36 | init?(exponentiation: ExponentiationType, coefficient: NumberType) {
37 | self.init(exponentiations: [exponentiation], coefficient: coefficient)
38 | }
39 |
40 | init?(_ exponentiations: ExponentiationType..., coefficient: NumberType) {
41 | self.init(exponentiations: exponentiations, coefficient: coefficient)
42 | }
43 |
44 | init(exponentiation: ExponentiationType) {
45 | self.init(exponentiations: [exponentiation], coefficient: .one)!
46 | }
47 |
48 | init(_ exponentiations: ExponentiationType...) {
49 | self.init(exponentiations: exponentiations, coefficient: .one)!
50 | }
51 |
52 | init(_ variable: VariableStruct) {
53 | self.init(exponentiation: ExponentiationType(variable))
54 | }
55 |
56 | init(_ variables: [VariableStruct]) {
57 | self.init(exponentiations: variables.map { ExponentiationType($0) })!
58 | }
59 |
60 | init(_ variables: VariableStruct...) {
61 | self.init(variables)
62 | }
63 |
64 | }
65 |
66 | // MARK: - Public Extensions
67 | public extension TermProtocol {
68 | var isNegative: Bool {
69 | return coefficient.isNegative
70 | }
71 |
72 | func contains(variable: VariableStruct) -> Bool {
73 | return exponentiations.map { $0.variable }.contains(variable)
74 | }
75 |
76 | var highestExponent: NumberType {
77 | return exponentiations.sorted(by: .descendingExponent)[0].exponent
78 | }
79 | }
80 |
81 | // MARK: - Internal Extensions
82 | internal extension TermProtocol {
83 |
84 | var signString: String {
85 | return isNegative ? "-" : "+"
86 | }
87 |
88 | var variableNames: String {
89 | return exponentiations.map { $0.variable.name }.joined()
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Polynomial/PolynomialProtocol+Concatenation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialProtocol+Concatenation.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-08-24.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Appending
12 | public extension PolynomialProtocol {
13 |
14 | func adding(other: Self) -> Self {
15 | return Self(terms: terms + other.terms, constant: constant + other.constant)
16 | }
17 |
18 | func adding(constant: NumberType) -> Self {
19 | return Self.init(terms: terms, constant: self.constant + constant)
20 | }
21 |
22 | }
23 |
24 | // MARK: - Subtracting
25 | public extension PolynomialProtocol {
26 |
27 | func subtracting(other: Self) -> Self {
28 | return self.adding(other: other.negated())
29 | }
30 |
31 | func subtracting(constant: NumberType) -> Self {
32 | return Self(terms: terms, constant: self.constant - constant)
33 | }
34 |
35 |
36 | }
37 |
38 | // MARK: - Multiplying
39 | public extension PolynomialProtocol {
40 | func multipliedBy(other: Self) -> Self {
41 | var multipliedTerm = [TermType]()
42 | for lhsTerm in terms {
43 | for rhsTerm in other.terms {
44 | multipliedTerm.append(lhsTerm.multipliedBy(other: rhsTerm))
45 | }
46 | if other.constant != 0 {
47 | guard let multiplied = lhsTerm.multiplyingCoefficientBy(constant: other.constant) else { continue }
48 | multipliedTerm.append(multiplied)
49 | }
50 | }
51 | if constant != 0 {
52 | for rhsTerm in other.terms {
53 | guard let multiplied = rhsTerm.multiplyingCoefficientBy(constant: constant) else { continue }
54 | multipliedTerm.append(multiplied)
55 | }
56 | }
57 |
58 | return Self(terms: multipliedTerm, constant: constant * other.constant)
59 | }
60 |
61 | func multipliedBy(constant: NumberType) -> Self {
62 | guard let firstTerm = terms.first else { return Self(terms: [], constant: constant * constant) }
63 | guard let termMultiplied = TermType(exponentiations: firstTerm.exponentiations, coefficient: firstTerm.coefficient * constant) else {
64 | return Self(constant: .zero)
65 | }
66 | guard terms.count > 1 else { return Self(termMultiplied) }
67 | let rest = terms.dropFirst()
68 | return Self(terms: [termMultiplied] + rest, constant: constant)
69 | }
70 |
71 |
72 | }
73 |
74 | // MARK: - Exponentiating
75 | public extension PolynomialProtocol {
76 | func raised(to exponent: Int) -> Self {
77 |
78 | var polynomialExponentiated = Self(constant: 1)
79 |
80 | for _ in 0..: Sorting {
12 |
13 | public typealias TypeToSort = TermStruct>
14 |
15 | case descendingExponent
16 | case coefficient // positive higher than negative naturally
17 | case termsWithMostVariables
18 | case termsAlphabetically
19 | }
20 |
21 | public extension SortingBetweenTerms {
22 |
23 | static var defaultArray: [SortingBetweenTerms] {
24 | return [.descendingExponent, .termsWithMostVariables, .termsAlphabetically, .coefficient]
25 | }
26 | }
27 |
28 | public extension SortingBetweenTerms {
29 |
30 | var comparing: (TypeToSort, TypeToSort) -> (ComparisonResult) {
31 | switch self {
32 | case .descendingExponent: return { $0.highestExponent.compare(to: $1.highestExponent) }
33 | case .coefficient: return { $0.coefficient.compare(to: $1.coefficient) }
34 | case .termsWithMostVariables: return { $0.exponentiations.count.compare(to: $1.exponentiations.count) }
35 | case .termsAlphabetically: return { $0.variableNames.compare(to: $1.variableNames) }
36 | }
37 | }
38 |
39 | var targetComparisonResult: ComparisonResult {
40 | switch self {
41 | case .descendingExponent: return .orderedDescending
42 | case .coefficient: return .orderedDescending
43 | case .termsWithMostVariables: return .orderedDescending
44 | case .termsAlphabetically: return .orderedAscending
45 | }
46 | }
47 | }
48 |
49 | extension SortingBetweenTerms: CustomStringConvertible {}
50 | public extension SortingBetweenTerms {
51 | var description: String {
52 | switch self {
53 | case .descendingExponent: return "descendingExponent"
54 | case .coefficient: return "coefficient"
55 | case .termsWithMostVariables: return "termsWithMostVariables"
56 | case .termsAlphabetically: return "termsAlphabetically"
57 | }
58 | }
59 | }
60 |
61 | public extension Array where Element: TermProtocol {
62 |
63 | func merged() -> [Element] {
64 | var count: [[Element.ExponentiationType]: Element.NumberType] = [:]
65 | for term in self {
66 | count[term.exponentiations] += term.coefficient
67 | }
68 | return count.compactMap { Element.init(exponentiations: $0.key, coefficient: $0.value) }
69 | }
70 |
71 | func sorting(betweenTerms: SortingBetweenTerms) -> [Element] {
72 | return sorting(betweenTerms: [betweenTerms])
73 | }
74 |
75 | func sorting(betweenTerms: [SortingBetweenTerms] = SortingBetweenTerms.defaultArray) -> [Element] {
76 | return sorted(by: TermSorting(betweenTerms: betweenTerms))
77 | }
78 |
79 | func sorted(by sorting: TermSorting = TermSorting()) -> [Element] {
80 | guard let first = sorting.betweenTerms.first else { return self }
81 |
82 | let areInIncreasingOrderClosure: (Element, Element) -> Bool = {
83 | guard
84 | let lhs = $0 as? SortingBetweenTerms.TypeToSort,
85 | let rhs = $1 as? SortingBetweenTerms.TypeToSort
86 | else {
87 | fatalError("what to do")
88 | }
89 |
90 | return first.areInIncreasingOrder(tieBreakers: sorting.betweenTerms.droppingFirstNilIfEmpty())(lhs, rhs)
91 | }
92 |
93 | return sorted(by: areInIncreasingOrderClosure)
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportDoubleTests/Tests/ExploringRandomStuffTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExploringRandomStuffTests.swift
3 | // EquationKitTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-17.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import EquationKit
12 | @testable import EquationKitDoubleSupport
13 |
14 | class ExploringRandomStuffTests: DoubleTestsBase {
15 |
16 | static var allTests = [
17 | ("testDifferenceOfConsecutiveSquares", testDifferenceOfConsecutiveSquares),
18 | ("testDifferenceOfConsecutiveCubes", testDifferenceOfConsecutiveCubes),
19 | ("testDifferenceOfConsecutivePowersOfFour", testDifferenceOfConsecutivePowersOfFour),
20 | ("testDifferenceOfConsecutivePowersOfFour", testDifferenceOfConsecutivePowersOfFour),
21 | ]
22 |
23 | func testDifferenceOfConsecutiveSquares() {
24 | var lastSquareDiff: Double? = nil
25 | let equation = x² - y²
26 | for i in 0..<1000 {
27 | let squareDiff = equation.evaluate() {[ x <- Double(i+1), y <- Double(i) ]}!
28 | defer { lastSquareDiff = squareDiff }
29 | guard let lastSquareDiff = lastSquareDiff else { continue }
30 | XCTAssertEqual(squareDiff - lastSquareDiff, 2)
31 | }
32 | }
33 |
34 | func testDifferenceOfConsecutiveCubes() {
35 | var list = [Double]()
36 | let hexagonalRightmostDigitsPattern: [Double] = [1, 7, 9, 7, 1]
37 | let equation = x³ - y³
38 | for i in 0..<1000 {
39 | let difference = equation.evaluate() {[ x <- Double(i+1), y <- Double(i) ]}!
40 | let modRes = mod(difference, modulus: 10)
41 | list.append(modRes)
42 | if list.count == hexagonalRightmostDigitsPattern.count {
43 | XCTAssertEqual(list, hexagonalRightmostDigitsPattern)
44 | list = []
45 | }
46 | }
47 | }
48 |
49 | func testDifferenceOfConsecutivePowersOfFour() {
50 | continueAfterFailure = false
51 | var lastDiff: Double? = nil
52 |
53 | var diffsMod10 = [Double]()
54 | // Let `mod₁₀ { X }` denote `mod(x, 10)`:
55 |
56 | // `x⁴ⁿ - x⁴ⁿ⁻⁴`
57 | // Apparently `mod₁₀ { n⁴ - (n-1)⁴ }` have a cyclic property of size 5, repeating the following pattern:
58 | let diffsMod10Pattern: [Double] = [5, 5, 5, 9, 1]
59 |
60 | var diffDiffsMod10 = [Double]()
61 |
62 |
63 | // `mod₁₀ { (n⁴ - (n-1)⁴) - ((n-1)⁴ - (n-2)⁴) }` <=> `mod₁₀ { n⁴ - 2(n-1)⁴ + (n-2)⁴ }` have a cyclic property of size 5, repeating the following pattern:
64 | let diffDiffsMod10Pattern: [Double] = [4, 0, 0, 4, 2]
65 |
66 | let eq1 = x⁴ - y⁴
67 | let eq2 = 8*(x³+x) // (x-1)^^4 - (x-1)^^4/
68 |
69 | for i in 5..<1000 {
70 | let cx = Constant(x, value: i+1)
71 | let cy = Constant(y, value: i)
72 | let constants = [cx, cy]
73 |
74 | let difference = eq1.evaluate(constants: constants)!
75 |
76 | defer { lastDiff = difference }
77 | guard let lastDiff = lastDiff else { continue }
78 | let diffDiff = difference - lastDiff
79 |
80 | let diffMod10 = mod(difference, modulus: 10)
81 | diffsMod10.append(diffMod10)
82 | let diffDiffMod10 = mod(diffDiff, modulus: 10)
83 | diffDiffsMod10.append(diffDiffMod10)
84 |
85 | if diffsMod10.count == diffsMod10Pattern.count {
86 | XCTAssertEqual(diffsMod10, diffsMod10Pattern)
87 | diffsMod10 = []
88 | }
89 |
90 | if diffDiffsMod10.count == diffDiffsMod10Pattern.count {
91 | XCTAssertEqual(diffDiffsMod10, diffDiffsMod10Pattern)
92 | diffDiffsMod10 = []
93 | }
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportDoubleTests/Tests/PolynomialMultipliedByPolynomialTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialMultipliedByPolynomialTests.swift
3 | // EquationKitTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-15.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 |
12 | @testable import EquationKit
13 | @testable import EquationKitDoubleSupport
14 |
15 | class PolynomialMultipliedByPolynomialTests: DoubleTestsBase {
16 |
17 | static var allTests = [
18 | ("testGrade1Short", testGrade1Short),
19 | ("testGrade1Long", testGrade1Long),
20 | ("testConcatenation", testConcatenation),
21 | ("testFourRoots", testFourRoots),
22 | ]
23 |
24 | override func setUp() {
25 | super.setUp()
26 | continueAfterFailure = false
27 | }
28 |
29 | func testGrade1Short() {
30 | let eq = ((4*x) + 9) * ((8*x) + (5*y))
31 | XCTAssertEqual(eq, 32*x² + 20*x*y + 72*x + 45*y)
32 | }
33 |
34 | func testGrade1Long() {
35 | let eq = (3*x + 5*y - 17) * (7*x - 9*y + 23)
36 | XCTAssertEqual(eq, 21*x² + 8*x*y - 50*x - 45*y² + 268*y - 391)
37 | XCTAssertEqual(
38 | 0,
39 | eq.evaluate() {[
40 | x <- 4,
41 | y <- 1
42 | ]})
43 |
44 | let y' = eq.differentiateWithRespectTo(x)!
45 | XCTAssertEqual(42*x + 8*y - 50, y')
46 | XCTAssertEqual(
47 | 0,
48 | y'.evaluate() {[
49 | x <- 1,
50 | y <- 1
51 | ]}
52 | )
53 |
54 | let x' = eq.differentiateWithRespectTo(y)!
55 | XCTAssertEqual(8*x - 90*y + 268, x')
56 | XCTAssertEqual(
57 | 0,
58 | x'.evaluate() {[
59 | x <- 11.5,
60 | y <- 4
61 | ]}
62 | )
63 | }
64 |
65 |
66 | func testConcatenation() {
67 | let term = Term(x)
68 | let polynomial = Polynomial(variable: y)
69 | let eq1 = term + polynomial
70 | XCTAssertEqual(eq1, x+y)
71 | let exponentiation = Exponentiation(x, exponent: 2)
72 | let eq2 = exponentiation + polynomial
73 | XCTAssertEqual(eq2, x²+y)
74 |
75 | let eq3 = term - polynomial
76 | XCTAssertEqual(eq3, x-y)
77 | let eq4 = exponentiation - polynomial
78 | XCTAssertEqual(eq4, x²-y)
79 | }
80 |
81 | func testFourRoots() {
82 |
83 | let roots2Factorized = (x-2)*(x+3)
84 | let roots2Expanded = x² + x - 6
85 |
86 | XCTAssertEqual(roots2Factorized, roots2Expanded)
87 |
88 | let roots3FromRoots2FactorizedLHS = roots2Factorized * (x+7)
89 | let roots3FromRoots2FactorizedRHS = (x+7) * roots2Factorized
90 |
91 | let roots3ExpanedManual = x³ + 8*x² + x - 42
92 | XCTAssertEqual(roots3FromRoots2FactorizedLHS, roots3ExpanedManual)
93 | XCTAssertEqual(roots3FromRoots2FactorizedRHS, roots3ExpanedManual)
94 |
95 | let roots3FactorizedManual = (x-2)*(x+3)*(x+7)
96 | XCTAssertEqual(roots3ExpanedManual, roots3FactorizedManual)
97 |
98 | let roots4FromRoots3FactorizedLHS = roots3FromRoots2FactorizedLHS * (x-11)
99 | let roots4FromRoots3FactorizedRHS = (x-11) * roots3FromRoots2FactorizedLHS
100 |
101 | let eq = (x-2)*(x+3)*(x+7)*(x-11)
102 | XCTAssertEqual(eq, roots4FromRoots3FactorizedLHS)
103 | XCTAssertEqual(eq, roots4FromRoots3FactorizedRHS)
104 |
105 | XCTAssertEqual(eq, x⁴ - 3*x³ - 87*x² - 53*x + 462)
106 | let solutions = [
107 | eq.evaluate() { x <- 2 },
108 | eq.evaluate() { x <- -3 },
109 | eq.evaluate() { x <- -7 },
110 | eq.evaluate() { x <- 11 }
111 | ]
112 | solutions.forEach {
113 | XCTAssertEqual($0, 0)
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/Tests/EquationKitSupportDoubleTests/Tests/PolynomialsExponentiatedTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PolynomialsExponentiatedTests.swift
3 | // EquationKitTests
4 | //
5 | // Created by Alexander Cyon on 2018-08-17.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | import Foundation
12 | import XCTest
13 | @testable import EquationKit
14 | @testable import EquationKitDoubleSupport
15 |
16 | class PolynomialsExponentiatedTests: DoubleTestsBase {
17 |
18 | static var allTests = [
19 | ("test﹙𝑥+𝟙﹚²", test﹙𝑥+𝟙﹚²),
20 | ("test𝑥²ToPowerOf3", test𝑥²ToPowerOf3),
21 | ("test﹙𝑥+𝟙﹚³", test﹙𝑥+𝟙﹚³),
22 | ("testMultiplyWithZero", testMultiplyWithZero),
23 | ("test﹙𝑥-𝟙﹚²", test﹙𝑥-𝟙﹚²),
24 | ("test﹙𝑥-𝟙﹚³", test﹙𝑥-𝟙﹚³),
25 | ("test𝑥·𝑥²+𝑥²·𝑥-𝟚𝑥³", test𝑥·𝑥²+𝑥²·𝑥-𝟚𝑥³),
26 | ("test﹙𝑥-𝟙﹚⁹", test﹙𝑥-𝟙﹚⁹),
27 | ("testAbsolute", testAbsolute),
28 | ("testHighestExponent", testHighestExponent),
29 | ("testNegationOfTermsInsidePolynmoial", testNegationOfTermsInsidePolynmoial),
30 | ]
31 |
32 |
33 | func test﹙𝑥+𝟙﹚²() {
34 | let eq = (x + 1)^^2
35 | XCTAssertEqual(eq, (x + 1) * (x + 1))
36 | XCTAssertEqual(eq, x² + 2*x + 1)
37 | XCTAssertEqual(eq, (Double(1) + x)^^2)
38 | }
39 |
40 | func test𝑥²ToPowerOf3() {
41 | let eq = x²^^3
42 | XCTAssertEqual(eq, x^^6)
43 | XCTAssertEqual(eq, Polynomial(x⁶))
44 | }
45 |
46 | func test﹙𝑥+𝟙﹚³() {
47 | let eq = (x + 1)^^3
48 | XCTAssertEqual(eq, (x + 1) * (x + 1) * (x + 1))
49 | XCTAssertEqual(eq, x³ + 3*x² + 3*x + 1)
50 | }
51 |
52 | func testMultiplyWithZero() {
53 | let a = 0.0
54 | let b = 7.0
55 | let eq = y² - x³ + a*x + b
56 | XCTAssertEqual(eq, y² - x³ + 7)
57 | }
58 |
59 | func test﹙𝑥-𝟙﹚²() {
60 | let eq = (x - 1)^^2
61 | XCTAssertEqual(eq, (x - 1) * (x - 1))
62 | XCTAssertEqual(eq, x² - 2*x + 1)
63 | }
64 |
65 | func test﹙𝑥-𝟙﹚³() {
66 | let eq = (x - 1)^^3
67 | XCTAssertEqual(eq, (x - 1) * (x - 1) * (x - 1))
68 | XCTAssertEqual(eq, x³ - 3*x² + 3*x - 1)
69 | }
70 |
71 | func test𝑥·𝑥²+𝑥²·𝑥-𝟚𝑥³() {
72 | let eq = x*x² + x²*x - 2*x³
73 | XCTAssertEqual(eq.description, "")
74 | XCTAssertEqual(eq, 0)
75 | }
76 |
77 | func test﹙𝑥-𝟙﹚⁹() {
78 | let eq = (x - 1)^^9
79 | XCTAssertEqual(eq.asString(sorting: .descendingExponent), "x⁹ - 9x⁸ + 36x⁷ - 84x⁶ + 126x⁵ - 126x⁴ + 84x³ - 36x² + 9x - 1")
80 | XCTAssertEqual(eq, x⁹ - 9*x⁸ + 36*x⁷ - 84*x⁶ + 126*x⁵ - 126*x⁴ + 84*x³ - 36*x² + 9*x - 1)
81 | XCTAssertEqual(eq.evaluate() { x <- 1 }!, 0)
82 | XCTAssertEqual(eq.evaluate() { x <- 2 }!, 1)
83 | XCTAssertEqual(eq.evaluate() { x <- 3 }!, 512)
84 | XCTAssertEqual(eq.evaluate() { x <- 4 }!, 19683)
85 | }
86 |
87 | func testAbsolute() {
88 | let eq = y³ - x² - 2*x + y - 5
89 | let expectedAbsolute = y³ + x² + 2*x + y + 5
90 | XCTAssertEqual(eq.absolute(), expectedAbsolute)
91 | XCTAssertEqual(expectedAbsolute.evaluate() {[ x <- 2, y <- 3 ]}, 43)
92 | }
93 |
94 | func testHighestExponent() {
95 | let eq = x³ + x⁸ - y⁵ + 1337
96 | XCTAssertEqual(eq.highestExponent, 8)
97 | XCTAssertEqual((x + 1).highestExponent, 1)
98 | XCTAssertNil((x - x).highestExponent)
99 | }
100 |
101 | func testNegationOfTermsInsidePolynmoial() {
102 | let eq = 5*y² - (x³ + 3*x² + x)
103 | let expected = 5*y² - x³ - 3*x² - x
104 | func _test(_ poly: Polynomial) {
105 | XCTAssertEqual(poly.evaluate() {[ x <- 2, y <- 3 ]}, 23)
106 | }
107 | _test(eq)
108 | _test(expected)
109 | XCTAssertEqual(eq, expected)
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Sources/EquationKit/Protocols/Substitutionable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Substitutionable.swift
3 | // EquationKit
4 | //
5 | // Created by Alexander Cyon on 2018-09-02.
6 | // Copyright © 2018 Sajjon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol Substitutionable: NumberTypeSpecifying {
12 |
13 | var uniqueVariables: Set> { get }
14 |
15 | func substitute(constants: Set>, modulus: Modulus?) -> PolynomialType
16 | }
17 |
18 | public extension Substitutionable {
19 | func substitute(constants: Set>, modulus: Modulus? = nil) -> PolynomialType {
20 | return substitute(constants: constants, modulus: modulus)
21 | }
22 |
23 | func substitute(constants: [ConstantStruct], modulus: Modulus? = nil) -> PolynomialType {
24 | guard !constants.containsDuplicates() else { fatalError("cannot contain duplicates") }
25 | return substitute(constants: Set(constants), modulus: modulus)
26 | }
27 |
28 | func substitute(constants: ConstantStruct..., modulus: Modulus? = nil) -> PolynomialType