-
Notifications
You must be signed in to change notification settings - Fork 77
Compilation
We will consider ways to improve the performance of computations via compiling functions.
Here we will consider a bunch of methods, which all are overloads of one: Compile.
This method compiles a given symbolic expression into a native delegate, which then
can be executed with a very high speed. This time, we first consider the way
you highly likely need it to be compiled.
Let us start with a simple example:
Entity expr = "sin(x)";
Func<float, float> mySin = expr.Compile<float, float>("x");
Console.WriteLine(mySin(4.2f));Output:
-0.87157565
The variable mySin has type Func<float, float>. Its type parameters accurately correspond
to the type parameters of method Compile. Let us consider a more complicated example:
Entity expr = "sqrt(sin(x) + 3)";
var f = expr.Compile<float, float>("x");
Console.WriteLine(f(4.2f));Output:
1.458912
The number 3, although integer, is upcasted to float automatically. But if only you passed
an integer as type params, sin will return an int as well. Example:
Entity expr = "sqrt(sin(x) + 3)";
var f = expr.Compile<int, int>("x");
Console.WriteLine(f(4));Output:
1
You can also pass multiple parameters, as well as multiple parameters of different types. Example:
Entity expr = "sin(x) + y";
var f = expr.Compile<float, double, float>("x", "y");
Console.WriteLine(f(4.3f, 7.8d));Output:
6.883834
The supported types are: int, long, float, double, Complex, BigInteger. Let us consider
an example, where int is upcasted to a Complex:
Entity expr = "x + y";
var f = expr.Compile<Complex, int, Complex>("x", "y");
Console.WriteLine(f(new(4, 5), 5));Output:
(9, 5)
You can pass up to 8 type parameters excluding the one for output.
Extensions include the same set of methods, but for string.
If needed to pass more than 8 parameters, or other types than the ones listed, or
custom rules for types, consider declaring your own CompilationProtocol.
Since the way AM compiles an expression is through Linq.Expression, it requires provided rules for constants to be converted into a constant, unary/binary/n-ary nodes to be converted into calls or operators.
That is why AM has class CompilationProtocol which defines a number of rules for every such
operation.
Its property ConstantConverter is responsible for converting a given constant
expression of type Entity into a Linq.Expression.
BinaryNodeConverter takes two arguments of type Linq.Expression and one argument of type
Entity. Although allowed, it is not recommended to rely on the third argument's value. Instead,
we encourage to use it as a type holder and switch over it when looking for a good node. For example,
that is a fragment of code for this ruleset:
...
return typeHolder switch
{
Sumf => Expression.Add(left, right),
Minusf => Expression.Subtract(left, right),
Mulf => Expression.Multiply(left, right),
Divf => Expression.Divide(left, right),
...Same way it is recommended to define UnaryNodeConverter and AnyArgumentConverter (the latter
for n-ary nodes).
Now, after you defined your own compilation protocol, you need to pass your delegate and parameters of the final function:
Entity expr = "x + y";
var f = expr.Compile<Func<float, float, float>>(
new(), typeof(float),
new[] { (typeof(float), Var("x")), (typeof(float), Var("y")) }
);
Console.WriteLine(f(4, 5));Here we use new() instead of an instance of CompilationProtocol, but instead of it a custom
protocol can be passed.
It is highly recommend to compile a given expression the way it is described above.
FastExpression is a special type. It contains instructions for every node and works as a stack
machine. When compiled into it, it translates a given expression into a number of instructions,
which are then sequentially executed.
It does not accept any arguments, as it unconditionally work with Complex. Example:
Entity expr = "x + y";
var f = expr.Compile("x", "y");
Console.WriteLine(f.Call(4, 5));Output:
(9, 0)
It is not as fast and flexible as Compile<>.
If you did not find what you were looking for, feel free to create an issue raising your problem.