mathnet/mathnet-symbolics

SymbolicExpression.Parse freeze for "29^11^7"

akolevmm opened this issue ยท 10 comments

Using C# nuget package MathNet.Symbolics, ver 0.20.0

Parsing this expression "29^11^7" leads to freeze.
Tried with
Infix.ParseOrUndefined("29^11^7");
and
SymbolicExpression.Parse("29^11^7")

When tried to put parenthesis it works fine
"(29^11)^7"

I think it's just trying to calculate:

"29^(11^7)"

that's very big number. So, put a parentheses is a good idea.

Yes. Exponentiation is right-associative, which means that it is evaluated right-to-left.

This is because (29^11)^7 can be written as 29^(11*7) while the other cannot be easily simplified.

I think large number detection can be done to avoid hangs. (Using power rules while calculating instead of expanding to a very big number)

Yes, it sounds reasonable.
The problem in my case with this expression is that it is entered by user and I don't have control over what he can enter.
Is there a way to handle this?

Evaluate asynchronously, show an activity indicator and provide a cancel button?

Evaluate asynchronously, show an activity indicator and provide a cancel button?

This is not possible, because my code is in web service invoked by other applications.

Setting a default timeout so that each request will not take too much time?

This is not an option too, because I have to return meaningful result in short time.
I have to somehow handle expressions like this without affecting the whole functionality.
For now my workaround is to run it in separate thread and wait for specified number of milliseconds, but I prefer to have better way to do it.

I guess we could have a global Control instance like in Numerics to control how a few operations like power behave on very large input (or expected very large output or expensive operation). Ugly, but usually good enough.

Any proposals on what good rules would be for power? Should the limitation be opt-in or opt-out?

Instead of a default timeout, there should be

  • no eager execution. the user needs to explicitly apply an Expression.simplify function
  • calculations should be done with CancellationToken support

Using a CancellationToken allows for scenarios with cancel buttons, web requests, as well as timeouts (via the CancellationTokenSource).

Example

let expression = 9Q ** (9Q ** 9Q);
expression ==> "9^(9^9)"
use cts = new CancellationTokenSource (TimeSpan.FromSeconds 5)
try
    Expression.simplifyAsync expression cts.Token
with
| :? TaskCanceledException as e => // ...