Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

➗ Library for parsing math expressions with rational numbers, finding their derivatives and compiling an optimal IL code

License

NotificationsYou must be signed in to change notification settings

KvanTTT/MathExpressions.NET

Repository files navigation

A library for parsing math expressions with rational numbers,finding their derivatives, and compiling an optimal IL code.

Libraries

  • ANTLR - Code generation from math expression grammar.
  • WolframAlpha.NET - Symbolic derivatives testing.
  • ILSpy - IL assembly disassembler. For compilation testing.
  • NUnit - General testing purposes.

Using

Simplification

varfunc=newMathFunc("(2 * x ^ 2 - 1 + 0 * a) ^ -1 * (2 * x ^ 2  - 1 * 1) ^ -1").Simplify();// func == (x ^ 2 * 2 + -1) ^ -2;

Differentiation

varfunc=newMathFunc("(2 * x ^ 2 - 1 + 0 * a) ^ -1 * (2 * x ^ 2  - 1 * 1) ^ -1").GetDerivative();// func == -((x ^ 2 * 2 + -1) ^ -3 * x * 8)

Compilation

Dynamic using

using(varmathAssembly=newMathAssembly("(2 * x ^ 2 - 1 + 0 * a) ^ -1 * (2 * x ^ 2  - 1 * 1) ^ -1","x")){varfuncResult=mathAssembly.Func(5);// funcResult == 0.00041649312786339027 (precision value is -1/2401)varfuncDerResult=mathAssembly.FuncDerivative(5);// funcDerResult == -0.00033999439009256349 (precision value is -40/117649)}

Static using (more faster and conventional)

You should compile assembly with MathExpressions.NET and add make referenceto this assembly your project.For function:(2 * x ^ 2 - 1 + 0 * a) ^ -1 * (2 * x ^ 2 - 1 * 1) ^ -1with the variable ofx, you'll get:

varfuncResult=MathFuncLib.MathFunc.Func(5);// funcResult == 0.00041649312786339027 (precision value is -1/2401)varfuncDerResult=MathFuncLib.MathFunc.FuncDerivative(5);// funcDerResult == -0.00033999439009256349 (precision value is -40/117649)

Undefined constants and functions

using(varmathAssembly=newMathAssembly("b(x) + 10 * x * a","x")){varb=newFunc<double,double>(x=>x*x);varfuncResult=mathAssembly.Func(5,2,b);// x = 5; a = 2; b = x ^ 2// funcResult == 5 ^ 2 + 10 * 5 * 2 = 125varfuncDerResult=mathAssembly.FuncDerivative(5,2,b);// x = 5; a = 2; b = x ^ 2// funcDerResult == (b(x + dx) - b(x)) / dx + 10 * a = 30}

Types of MathNodes

  • Calculated - Calculateddecimal constant.
  • Value - Calculated constant ofRational<long, long> format.Based onStephen M. McKamey implementation.
  • Constant - Undefined constant. It have name such asa,b etc.
  • Variable - It have name, such asx,y etc.
  • Function - This node present known (sin(x),log(x, 3),x + a) orunknown (a(x), b'(x)) function. It may have one or more children.

Steps of math expression processing

Parsing and AST building

Implemented withANTLR. The output of this step is athe tree structure of MathFuncNode types, which was described above.

Rational Numbers

Rational number representation

  • Taking of symbolic derivative. This is the recursive process ofreplacing simple nodes without children by constants (0 and 1),taking substitutions from the table for known functions (such as forsin(x)' = cos(x)),and replacing unknown functions with themselves with stroke (I meana(x)' = a'(x)).
    • Calculated' = Value' = Constant' = 0
    • Variable' = 1
    • KnownFunc(x)' = Derivatives[KnownFunc](x) * x'
    • UnknownFunc(x)' = UnknownFunc'(x) * x'
  • Simplification. This is similar to the previous process, but with another substitution rules, such as
    • a * 1 = a
    • a + 0 = a
    • a - a = 0
    • ...

It's worth mentioning that commutative functions (addition and multiplication)taken as a function with several nodes for more easy and flexible traversers.

For properly nodes comparison, sorting is using, as demonstrated on the image below:

Nodes sorting

Compilation

At this step simplified tree from the previous step transformedto the list of IL commands. There are implemented some optimizations:

Fast exponentiation (by squaring)

At this step expression with powers converts to optimized form withexponentiation by squaring algorithm.For example:a*a*a*a*a*a will be converted to(a^2)^2 * a^2.

Using the result of previously calculated nodes

If the result of the calculated value of any function is using more than one time,it can be stored to the local variable and it can be used at further code by such way:

if(!func.Calculated){EmitFunc(funcNode);func.Calculated=true;}elseIlInstructions.Add(newOpCodeArg(OpCodes.Ldloc,funcNode.Number));

Waste IL instruction removing

For generated IL code for math functions without loops, the following optimizations are available:IL Optimizations

Local vars count reducing

One local variable is used for every calculated function.But it can be also used for another calculated result. So, it is possible to reducethe number of local variables by such a way:

Local vars count reducing (before)Local vars count reducing (after)

Testing

WolframAlpha.NET

This lib for comparison of expected derivative from WolframAlpha API and actual derivative.

Assembly loading and unloading

.NET assembly has been generated on the compilation step. For dynamical assemblyloading and unloadingAppDomain is used withCreateInstanceFromAndUnwrap.

Comparison output of csc.exe compiler in release mode and my output

I compared generated IL code for example following function:

x ^ 3 + sin(3 * ln(x * 1)) + x ^ ln(2 * sin(3 * ln(x))) - 2 * x ^ 3

csc.exe .NET 4.5.1MathExpressions.NET
ldarg.0
ldc.r8 3
call float64 Math::Pow(float64, float64)
ldc.r8 3
ldarg.0
ldc.r8 1
mul
call float64 Math::Log(float64)
mul
call float64 Math::Sin(float64)
add
ldarg.0
ldc.r8 2
ldc.r8 3
ldarg.0
call float64Math::Log(float64)
mul
call float64 Math::Sin(float64)
mul
call float64 Math::Log(float64)
ldc.r8 2
ldarg.0
ldc.r83
call float64 Math::Pow(float64, float64)
mul
sub
call float64 Math::Pow(float64, float64)
add
ret
ldarg.0
ldc.r8 2
ldc.r8 3
ldarg.0
call float64 Math::Log(float64)
mul
call float64 Math::Sin(float64)
stloc.0
ldloc.0
mul
call float64 Math::Log(float64)
call float64 Math::Pow(float64,float64)
ldarg.0
ldarg.0
mul
ldarg.0
mul
sub
ldloc.0
add
ret








More detail explanation availableon Russian

About

➗ Library for parsing math expressions with rational numbers, finding their derivatives and compiling an optimal IL code

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp