Swiftpack.co - bradhowes/swift-math-parser as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by bradhowes.
bradhowes/swift-math-parser 2.1.2
Math expression parser built with Point•Free's swift-parsing package
⭐️ 29
🕓 1 week ago
iOS macOS watchOS tvOS
.package(url: "https://github.com/bradhowes/swift-math-parser.git", from: "2.1.2")

CI COV License: MIT

swift-math-parser

Basic math expression parser built with Point•Free's swift-parsing package (v0.10.0).

let parser = MathParser()
let evaluator = parser.parse('4 × sin(t × π) + 2 × sin(t × π)')
evaluator.eval("t", value: 0.0) // => 0.0
evaluator.eval("t", value: 0.25) // => 4.2426406871192848
evaluator.eval("t", value: 0.5) // => 6
evaluator.eval("t", value: 1.0) // => 0

The parser will return nil if it is unable to completely parse the expression.

By default, the expression parser and evaluator handle the following symbols and functions:

  • Constants: pi (π) and e
  • 1-argument functions: sin, cos, tan, log10, ln (loge), log2, exp, ceil, floor, round, sqrt ()
  • 2-argument functions: atan, hypot, pow [^1]
  • alternative math operator symbols: × for multiplication and ÷ for division (see example above for use of ×)

You can reference additional symbols or variables and functions by providing your own mapping functions. There are two places where this can be done:

  • MathParser.init
  • MathParser.Evaluator.eval

If a symbol or function does not exist during an eval call, the final result will be NaN. If a symbol is resolved during parsing, it will be replaced with the symbol's value. Otherwise, it will be resolved during a future eval call. Same for function calls -- if the function is known during parsing and all arguments have a known value, then it will be replaced with the function result. Otherwise, the function call will take place during an eval call.

Example:

let mySymbols = ["foo": 123.4]
let myFuncs: [String:(Double)->Double] = ["twice": {$0 + $0}]
let parser = MathParser(symbols: mySymbols.producer, unaryFunctions: myFuncs.producer)
let myEvalFuncs: [String:(Double)->Double] = ["power": {$0 * $0}]
let evaluator = parser.parse("power(twice(foo))")

# Expression parsed and `twice(foo)` resolved to `246.8` but `power` is still unknown
evaluator?.value // => nan

# Give evaluator way to resolve `power(246.8)`
evaluator?.eval(unaryFunctions: myEvalFuncs.producer) // => 60910.240000000005

Implied Multiplication

One of the original goals of this parser was to be able to accept a Wolfram Alpha math expression more or less as-is -- for instance the definition https://www.wolframalpha.com/input/?i=Sawsbuck+Winter+Form%E2%80%90like+curve -- without any editing. Here is the start of the textual representation from the above link:

x(t) = ((-2/9 sin(11/7 - 4 t) + 78/11 sin(t + 11/7) + 2/7 sin(2 t + 8/5) ...

Skipping over the assignment one can readily see that the representation includes implied multiplication between terms when there are no explicit math operators present (eg -2/9 x sin(11/7 - 4 x t)). There is support for this sort of operation in the parser that can be enabled by setting enableImpliedMultiplication when creating a new MathParser instance (it defaults to false). Note that when enabled, an expression such as 2^3 2^4 would be considered a valid expression, resolving to 2^3 * 2^4 = 128, and 4sin(t(pi)) would become 4 * sin(t * pi).

Here is the original example expression with implied multiplication:

let parser = MathParser(enableImpliedMultiplication: true)
let evaluator = parser.parse("4sin(t π) + 2sin(t π)")
evaluator.eval("t", value: 0.0) // => 0.0
evaluator.eval("t", value: 0.25) // => 4.2426406871192848
evaluator.eval("t", value: 0.5) // => 6
evaluator.eval("t", value: 1.0) // => 0

Note that t π cannot be since the parser treats the latter as one symbol and not two.

[^1]: Redundant since there is already the ^ operator.

GitHub

link
Stars: 29
Last commit: 1 week ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.

Release Notes

Time Bandits
1 week ago

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics