NOTE: v3.1.0 uses swift-parsing v0.12 which requires Xcode 14 and ideally Swift 5.8
(see What’s Changed for additional details).
If you need to use an older version, use the tagged 3.0.1 release instead.
The parser will return nil if it is unable to completely parse the expression. Alternatively, you can call the
parseResult to obtain a Swift Result enum that will have a MathParserError value when parsing fails. This
will contain a description of the parsing failure that comes from the swift-parsing library.
let evaluator = parser.parseResult("4 × sin(t × π")
print(evaluator)
failure(error: unexpected input
--> input:1:8
1 | 4 × sin(t × π
| ^ expected end of input)
By default, the expression parser and evaluator handle the following symbols and functions:
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
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.
You can get the unresolved symbol names from the Evaluator.unresolved attribute. It returns three collections for
unresolved variables, unary functions, and binary function names. You can also use the evalResult to attempt an
evaluation but also obtain a description of the failure when the evaluation fails.
Example:
let myVariables = ["foo": 123.4]
let myFuncs: [String:(Double)->Double] = ["twice": {$0 + $0}]
let parser = MathParser(variables: myVariables.producer, unaryFunctions: myFuncs.producer)
let evaluator = parser.parse("power(twice(foo))")
# Expression parsed and `twice(foo)` resolved to `246.8` but `power` is still unknown
evaluator?.value // => nan
evaluator?.unresolved.unaryFunctions // => ['power']'
# Give evaluator way to resolve `power(246.8)`
let myEvalFuncs: [String:(Double)->Double] = ["power": {$0 * $0}]
evaluator?.eval(unaryFunctions: myEvalFuncs.producer) // => 60910.240000000005
Instead of passing in a closure to access the dictionary of symbols, you can pass the dictionary itself:
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:
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/9xsin(11/7 - 4xt)). 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).
You can see the entire Wolfram example in the TestWolfram test case.
Here is the original example expression from the start of this README file with implied multiplication in use (all of the muliplication symbols
have been removed):
Note that with enableImpliedMultiplication enabled, tπ will be broken into t and π even though one could have a
symbol called tπ. This eager splitting of a symbol may cause unexpected multiplication. For instance, if you have a
symbol defined with the name pin, this will be split into pi and n because pi / π is a known symbol. The best
way to protect from this happening is to not enable enabledImpliedMultiplication but an alternative is to always
separate individual symbols with a space – or place one inside a pair of parentheses.
[^1]: Redundant since there is already the ^ operator.
swift-math-parser
Basic math expression parser built with Point•Free’s swift-parsing package (v0.12.0).
NOTE: v3.1.0 uses swift-parsing v0.12 which requires Xcode 14 and ideally Swift 5.8 (see What’s Changed for additional details). If you need to use an older version, use the tagged 3.0.1 release instead.
The parser will return
nil
if it is unable to completely parse the expression. Alternatively, you can call theparseResult
to obtain a SwiftResult
enum that will have aMathParserError
value when parsing fails. This will contain a description of the parsing failure that comes from the swift-parsing library.By default, the expression parser and evaluator handle the following symbols and functions:
pi
(π
) ande
sin
,cos
,tan
,log10
,ln
(loge
),log2
,exp
,ceil
,floor
,round
,sqrt
(√
)atan
,hypot
,pow
[^1]×
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
Evaluator.eval
If a symbol or function does not exist during an
eval
call, the final result will beNaN
. If a symbol is resolved during parsing, it will be replaced with the symbol’s value. Otherwise, it will be resolved during a futureeval
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 aneval
call.You can get the unresolved symbol names from the
Evaluator.unresolved
attribute. It returns three collections for unresolved variables, unary functions, and binary function names. You can also use theevalResult
to attempt an evaluation but also obtain a description of the failure when the evaluation fails.Example:
Instead of passing in a closure to access the dictionary of symbols, you can pass the dictionary itself:
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:
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
xsin(11/7 - 4
xt)
). There is support for this sort of operation in the parser that can be enabled by settingenableImpliedMultiplication
when creating a newMathParser
instance (it defaults tofalse
). Note that when enabled, an expression such as2^3 2^4
would be considered a valid expression, resolving to2^3 * 2^4 = 128
, and4sin(t(pi))
would become4 * sin(t * pi)
.You can see the entire Wolfram example in the TestWolfram test case.
Here is the original example expression from the start of this README file with implied multiplication in use (all of the muliplication symbols have been removed):
Note that with
enableImpliedMultiplication
enabled,tπ
will be broken intot
andπ
even though one could have a symbol calledtπ
. This eager splitting of a symbol may cause unexpected multiplication. For instance, if you have a symbol defined with the namepin
, this will be split intopi
andn
becausepi
/π
is a known symbol. The best way to protect from this happening is to not enableenabledImpliedMultiplication
but an alternative is to always separate individual symbols with a space – or place one inside a pair of parentheses.[^1]: Redundant since there is already the
^
operator.