Skip to content

Commit c5007c7

Browse files
committed
Update README.md
1 parent fb36d35 commit c5007c7

File tree

1 file changed

+129
-2
lines changed

1 file changed

+129
-2
lines changed

README.md

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,131 @@
1-
Math-Functions
1+
MathExpressions.NET
22
==============
33

4-
A library for parsing math expressions with rational numbers, finding their derivatives and compiling an optimal IL code.
4+
A library for parsing math expressions with rational numbers, finding their derivatives and compiling an optimal IL code.
5+
6+
##Libraries##
7+
* [GOLD Parsing System](http://goldparser.org/) - Code generation from math expression grammar.
8+
* [WolframAlpha.NET](https://github.com/Genbox/WolframAlpha.NET) - Symbolic derivatives testing.
9+
* ILSpy - IL assembly dissambler. For compilation tesing.
10+
* NUnit - General testing purposes.
11+
12+
##Using##
13+
14+
* Simplification
15+
16+
```csharp
17+
var func = new MathFunc("(2 * x ^ 2 - 1 + 0 * a) ^ -1 * (2 * x ^ 2 - 1 * 1) ^ -1").Simplify();
18+
// func == (x ^ 2 * 2 + -1) ^ -2;
19+
```
20+
21+
* Differentiation
22+
23+
```csharp
24+
var func = new MathFunc("(2 * x ^ 2 - 1 + 0 * a) ^ -1 * (2 * x ^ 2 - 1 * 1) ^ -1").GetDerivative();
25+
// func == -((x ^ 2 * 2 + -1) ^ -3 * x * 8)
26+
```
27+
28+
* Compilation
29+
30+
* Dynamic using
31+
```csharp
32+
using (var mathAssembly = new MathAssembly("(2 * x ^ 2 - 1 + 0 * a) ^ -1 * (2 * x ^ 2 - 1 * 1) ^ -1", "x"))
33+
{
34+
var funcResult = mathAssembly.Func(5);
35+
// funcResult == 0.00041649312786339027 (precision value is -1/2401)
36+
var funcDerResult = mathAssembly.FuncDerivative(5);
37+
// funcDerResult == -0.00033999439009256349 (precision value is -40/117649)
38+
}
39+
```
40+
41+
* Static using (more faster and conventional)
42+
43+
You sholud compile assembly with MathExpressions.NET and add reference to this assembly your project.
44+
For function: (2 * x ^ 2 - 1 + 0 * a) ^ -1 * (2 * x ^ 2 - 1 * 1) ^ -1 with variable of x, you'll get:
45+
```csharp
46+
var funcResult = MathFuncLib.MathFunc.Func(5);
47+
// funcResult == 0.00041649312786339027 (precision value is -1/2401)
48+
var funcDerResult = MathFuncLib.MathFunc.FuncDerivative(5);
49+
// funcDerResult == -0.00033999439009256349 (precision value is -40/117649)
50+
```
51+
52+
* Undefined constants and functions
53+
54+
```csharp
55+
using (var mathAssembly = new MathAssembly("b(x) + 10 * x * a", "x"))
56+
{
57+
var b = new Func<double, double>(x => x * x);
58+
var funcResult = mathAssembly.Func(5, 2, b); // x = 5; a = 2; b = x ^ 2
59+
// funcResult == 5 ^ 2 + 10 * 5 * 2 = 125
60+
var funcDerResult = mathAssembly.FuncDerivative(5, 2, b); // x = 5; a = 2; b = x ^ 2
61+
// funcDerResult == (b(x + dx) - b(x)) / dx + 10 * a = 30
62+
}
63+
```
64+
65+
## Types of MathNodes ##
66+
67+
* **Calculated** - Calculated *decimal* constant.
68+
* **Value** - Calculated constant of *Rational<long, long>* format. Based on [Stephen M. McKamey implementation](http://exif-utils.googlecode.com/svn/trunk/ExifUtils/ExifUtils/Rational.cs).
69+
* **Constant** - Undefined constant. It have name such as *a*, *b* etc.
70+
* **Variable** - It have name, such as *x*, *y* etc.
71+
* **Function** - This node present known (*sin(x)*, *log(x, 3)*, x + a) or unknown (a(x), b'(x)) function. It may have one or more childs.
72+
73+
## Steps of math expression processing ##
74+
75+
* **Parsing and AST building**. Implemented with LALR [GOLD Parsing System](http://goldparser.org/). Output of this step is tree structure of MathFuncNode types, which was described above.
76+
* **Rational Numbers**.
77+
![Rational number representation](http://habr.habrastorage.org/post_images/fc7/c73/526/fc7c73526dc83f8c341aa43f23d2b931.png)
78+
* **Taking of symbolic derivative**. This is the recursive process of replacing simple nodes without childs by constants (0 and 1), taking substitutions from table for known functions (such as for sin(x)' = cos(x)), and replacing unknown functions with themselves with stroke (I mean a(x)' = a'(x)). List of derivatives at first time loaded from [app.config](https://github.com/KvanTTT/Math-Functions/blob/master/MathFunctions.GUI/app.config) but further can be changed in runtime and saved.
79+
* Calculated' = Value' = Constant' = 0
80+
* Variable' = 1
81+
* KnownFunc(x)' = Derivatives\[KnownFunc\](x) * x'
82+
* UnknownFunc(x)' = UnknownFunc'(x) * x'
83+
* **Simplification**. This is similar to previous process, but with another substitution rools, such as
84+
* a * 1 = a
85+
* a + 0 = a
86+
* a - a = 0
87+
* ...
88+
89+
Worth mentioning that commutative functions (addition and multiplication) taken as function with several nodes for more easy and flexible travers.
90+
91+
For properly nodes comparsion, sorting is using, as demonstated on image below:
92+
![Nodes sorting](http://habrastorage.org/files/b78/215/c09/b78215c09a0441b8b96ab5a552da9250.png)
93+
94+
* **Compilation**. At this step simplified tree from previous step transformed to list of IL commands. There are implemented some optimizations:
95+
* **Fast exponentiation (by squaring)**
96+
At this step expression with powers converts to optimized form with [exponentiation by squaring algorithm](http://en.wikipedia.org/wiki/Exponentiation_by_squaring). For example: a*a*a*a*a*a will be converted to (a^2)^2 * a^2.
97+
* **Using result of previously calculated nodes**
98+
If result of 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:
99+
```csharp
100+
if (!func.Calculated)
101+
{
102+
EmitFunc(funcNode);
103+
func.Calculated = true;
104+
}
105+
else
106+
IlInstructions.Add(new OpCodeArg(OpCodes.Ldloc, funcNode.Number));
107+
```
108+
* **Waste IL instruction removing**
109+
For generated IL code for math functions without loops, following optimizations are available:
110+
![IL Optimizations](http://habrastorage.org/files/f2b/cc4/866/f2bcc48663a94d0c84c867583aefffc3.png)
111+
* **Local vars count reducing**
112+
One local variable is used for every calculated function. But it can be also used for another calculated result. So, it is posiible to reduce number of local variables by such way:
113+
![Local vars count reducing](http://habrastorage.org/files/ab0/a27/c29/ab0a27c29a3843af9e32b867b78cf4de.png)
114+
115+
## Testing ##
116+
117+
* **WolframAlpha.NET**
118+
This lib for comparsion of expected derivative from WolframAlpha API and actual derivative.
119+
* **Assembly loading and unloading**
120+
.NET assembly has been generated on compilation step. For dynamical assembly loading and unloading ```AppDomain``` is used with ```CreateInstanceFromAndUnwrap```.
121+
* **Comparsion output of csc.exe compiler in release mode and my output.**
122+
123+
I compared generated IL code for example following function:
124+
125+
```x ^ 3 + sin(3 * ln(x * 1)) + x ^ ln(2 * sin(3 * ln(x))) - 2 * x ^ 3```
126+
127+
**csc.exe .NET 4.5.1** | **MathExpressions.NET**
128+
----------------------------------------------------------|--------------------------------------------------
129+
ldarg.0<br/>ldc.r8 3<br/>call float64 Math::Pow(float64, float64)<br/>ldc.r8 3<br/>ldarg.0<br/>ldc.r8 1<br/>mul<br/>call float64 Math::Log(float64)<br/>mul<br/>call float64 Math::Sin(float64)<br/>add<br/>ldarg.0<br/>ldc.r8 2<br/>ldc.r8 3<br/>ldarg.0<br/>call float64Math::Log(float64)<br/>mul<br/>call float64 Math::Sin(float64)<br/>mul<br/>call float64 Math::Log(float64)<br/>ldc.r8 2<br/>ldarg.0<br/>ldc.r83<br/>call float64 Math::Pow(float64, float64)<br/>mul<br/>sub<br/>call float64 Math::Pow(float64, float64)<br/>add<br/>ret | ldarg.0<br/>ldc.r8 2<br/>ldc.r8 3<br/>ldarg.0<br/>call float64 Math::Log(float64)<br/>mul<br/>call float64 Math::Sin(float64)<br/>stloc.0<br/>ldloc.0<br/>mul<br/>call float64 Math::Log(float64)<br/>call float64 Math::Pow(float64,float64)<br/>ldarg.0<br/>ldarg.0<br/>mul<br/>ldarg.0<br/>mul<br/>sub<br/>ldloc.0<br/>add<br/>ret<br/><br/><br/><br/><br/><br/><br/><br/><br/>
130+
131+
More detail explanation available [on Russian](http://habrahabr.ru/post/150043/)

0 commit comments

Comments
 (0)