Skip to content

Sajjon/EquationKit

EquationKit

Write equations in pure Swift, differentiate and/or evaluate them.

let polynomial = (3*x + 5*y - 17) * (7*x - 9*y + 23)
print(polynomial) // 21x² + 8xy - 50x - 45y² + 268y - 391)
let number = polynomial.evaluate() {[ x <- 4, y <- 1 ]}
print(number) // 0

let y= polynomial.differentiateWithRespectTo(x)
print(y') // 42x + 8y - 50
y.evaluate() {[ x <- 1, y <- 1 ]} // 0

let x= polynomial.differentiateWithRespectTo(y)
print(x') // 8x - 90y + 268
 x.evaluate() {[ x <- 11.5,  y <- 4 ]} // 0

Installation

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/Sajjon/EquationKit", from: "0.1.0")
]

Usage

Generics

EquationKit is fully generic and supports any number type conforming to the protocol NumberExpressible, Swift Foundation's Int and Double both conforms to said protocol. By conforming to NumberExpressible you can use EquationKit with e.g. excellent attaswift/BigInt.

You need only to import EquationKitBigIntSupport

We would like to use operator overloading, making it possible to write x + y, x - 2, x*z² - y³ etc. Supporting operator overloading using generic func + <N: NumberExpressible>(lhs: Variable, rhs: N) -> PolynomialStruct<N> results in Swift compiler taking too long time to compile polynomials having over 3 terms (using Xcode 10 beta 6 at least). Thus EquationKit does not come bundled with any operator support at all. Instead, you chose your Number type yourself. If you don't need BigInt then Double is probably what you want, just import EquationKitDoubleSupport and you are good to go! It contains around 10 operators which are all 3 lines of code each.

Variables

You write powers using the custom operator x^^2, but for powers between 2 and 9 you can use the unicode superscript symbols instead, like so:

let x = Variable("x")
let y = Variable("y")
let x² = Exponentiation(x, exponent: 2)
let x³ = Exponentiation(x, exponent: 3)
let x= Exponentiation(x, exponent: 4)
let x= Exponentiation(x, exponent: 5)
let x= Exponentiation(x, exponent: 6)
let x= Exponentiation(x, exponent: 7)
let x= Exponentiation(x, exponent: 8)
let x= Exponentiation(x, exponent: 9)

let y² = Exponentiation(y, exponent: 2)

Advanced operators

You can use some of the advanced mathematical operators provided in the folder MathematicalOperators to precisely express the mathematical constraints you might have.

Variable to Constant (evaluation)

Let's have a look at one of the simplest scenario:

Using the special Unicode char (single character for := often used in literature for assignment of value.) we can write evaluations as:

𝑦² - 𝑥³.evaluate() {[ x  1, y  2 ]} 

Instead of:

𝑦² - 𝑥³.evaluate() {[ x <- 1, y <- 2 ]} 

Complex examples

Below is the example of how EllipticCurveKit uses EquationKit to express requirements on the elliptic curve parameters. Elliptic curves on the Weierstraß form requires this congruence inequality to hold:

$$𝟜𝑎³ + 𝟚𝟟𝑏² ≢ 𝟘 mod 𝑝$$

Thanks to EquationKit we can express said inequality almost identically to pure math in Swift:

𝟜𝑎³ + 𝟚𝟟𝑏²  0 % 𝑝 

But that is not enough since we also need to evaluate said inequality (polynomial) using the arguments passed in the initializer. We can of course write

(𝟜𝑎³ + 𝟚𝟟𝑏²).evaluate(modulus: 𝑝) {[ 𝑎  a, 𝑏  b ]} != 0

But a slightly more "mathy" syntax would be:

𝟜𝑎³ + 𝟚𝟟𝑏²  𝟘 % 𝑝  [ 𝑎  a, 𝑏  b ]

Which evaluates the polynomial 𝟜𝑎³ + 𝟚𝟟𝑏² given a and b and performs modulo 𝑝 and compares it to 0. We could, of course, add support for this syntax as well:

// This syntax is not yet supported, but can easily be added
[a𝑎, b𝑏]  𝟜𝑎³ + 𝟚𝟟𝑏²  𝟘 % 𝑝

We can of course also write this without using any special unicode char, like so:

4*a^^3 + 27*b^^2 =!%= 0 % p <-- [ a  constA, b  constB ]

where =!%= replaces .

Please give feedback on the choice of operators, by submitting an issue.

let 𝑎 = Variable("𝑎")
let 𝑏 = Variable("𝑏")
let 𝑎³ = Exponentiation(𝑎, exponent: 3)
let 𝑏² = Exponentiation(𝑏, exponent: 2)

let 𝟜𝑎³ = 4*𝑎³
let 𝟚𝟟𝑏² = 27*𝑏²
let 𝟘: BigInt = 0

///
/// Elliptic Curve on Short Weierstraß form (`𝑆`)
/// - Covers all elliptic curves char≠𝟚,𝟛
/// - Mixed Jacobian coordinates have been the speed leader for a long time.
///
///
/// # Equation
///      𝑆: 𝑦² = 𝑥³ + 𝑎𝑥 + 𝑏
/// - Requires: `𝟜𝑎³ + 𝟚𝟟𝑏² ≠ 𝟘 in 𝔽_𝑝 (mod 𝑝)`
///
struct ShortWeierstraßCurve {
    /// Try to initialize an elliptic curve on the ShortWeierstraß form using parameters for `a`, `b` in the given Galois field (mod 𝑝).
    public init(a: BigInt, b: BigInt, field 𝑝: BigInt) throws {
        guard 
            𝟜𝑎³ + 𝟚𝟟𝑏²  𝟘 % 𝑝  [ 𝑎  a, 𝑏  b ]
        else { throw EllipticCurveError.invalidCurveParameters }
        self.a = a
        self.b = b
        self.field = 𝑝
    }
}

Supported

  • Single and multivariate equations (no limitation to how many variables, go crazy!)
  • Differentiate any single or multivariate equation with respect to some of its variables
  • Multiply equations with equations
  • Modulus
  • BigInt support

Limitations

Not supported, but on roadmap

  • Substitution (3*(4*x + 5)^^2 - 2*(4x+5) - 1).substitute() { z <~ (4*x + 5) } // 3*z²-2*z-1
  • Division
  • Finding roots (solving)

Not supported and not on the roadmap

  • Variables in exponents, such as 2^x
  • log/ln functions
  • Trigonometric functions (sin, cos, tan etc.)
  • Complex numbers