Quick start

The API is very simple to use. Let's begin from importing ILCalc's namespace:

using ILCalc;

Context creation

Now we can create new expression context. Note that at this step you should specify the expression type by providing an generic type parameter for the CalcContext class constructor. More info about supported types can be founded here. For this examples the System.Double type was chosen:

var calc = new CalcContext<double>("x");
We may specify the expression arguments to the constructor, or do it later, by the context's Arguments property.
For example, you may add another argument named "y":

calc.Arguments.Add("y");
Context is empty after creation, so let's import some built-it and user constants:

// built-in Pi, E, Inf and NaN constants:
calc.Constants.ImportBuiltIn( );

// user constants:
calc.Constants.Add("lambda0", 1.234);
calc.Constants.Add("epsilon", double.Epsilon);
Now let's import some suitable methods. There are different ways to specify importing methods:

// standard System.Math methods:
calc.Functions.ImportBuiltIn( );

// user methods as delegates:
calc.Functions.Add("Simple", Program.SimpleMethod);

// lambda expressions:
double val = 1.23;
calc.Functions.Add("Magic", () => val); // even with closure!
calc.Functions.Add("Triple", x => 3 * x);

// all suitable methods from whole class:
calc.Functions.Import(typeof(MyFunctionsClass));

// public method reflections:
calc.Functions.AddStatic("Some1",
    typeof(SomeClass).GetMethod("SomeStaticMethod"));

// even instance methods with targets:
var c = new SomeClass();
calc.Functions.AddInstance("Some2",
    typeof(SomeClass).GetMethod("SomeInstanceMethod"), c);
We can find a lot of Add( ) and Import( ) method overloads in FunctionCollection<T> / ConstantDictionary<T> classes.
Look for documentation for more detailed information about this methods.

Now it's time to set expression parse culture.
It's affects on parsing the decimal separator and arguments list separator symbols and number literals parsing.
Culture property can be set to null if you don't want to use any culture-sensitive features (defaults is '.' for decimal separator and ',' for arguments list separator).

calc.Culture = CultureInfo.InvariantCulture;
Expression context contains some properties for other options.
We can disable the ignore-case mode for the identifiers names, that is used by default:

calc.IgnoreCase = false;
Or can ask for performing overflow checks:

calc.OverflowCheck = false;
For the next article examples we will use the default values for this two properties.

Evaluation

Let's define simple arithmetical expression and evaluates it in different ways:

string expression = "4x + 2sin(pi/6) - lambda0";
As we may see, expression may contains a couple of number literals (remember that all of them are threated as literals of Double type that we specify at the context creation step), arithmetical operators (including implicit multiplication), an argument name "x", imported Math.Sin() method with name "sin" and constant "lambda0".

Quick interpreter

This is the best way to use ILCalc when you need to evaluate the specified expression only once:

double result = calc.Evaluate(expression, 1.0);  // = 1.0
Every Evaluate() call executes expression parsing, so this way is not efficient if you need to evaluate the same expression more than once with different argument value.

We should specify expression string and another one parameter, that would be threated as argument "х" value.
Specified parameters count (except expression) should be exactly the same, as the context's Arguments.Count, otherwise we will get an exception here.
Value of arguments should be provided to method in the same order as their names presented in ArgumentCollection class. For example:

calc.Arguments.AddRange("X", "Z", "Lambda");
calc.Evaluate(expression, 1, 2, 3);

// expression will get: X = 1,  Z = 2,  Lambda = 3

Interpret object

This is the best way when you need to evaluate expression more than once with giving some different argument values:

// create object:
var interpret = calc.CreateInterpret(expression);

// and separately invokes the evaluation:
double result = interpret.Evaluate(4.0);  // = 13.0
For this and following evaluation ways, we can use expression optimizer.
Optimizer options may be specified by context's Optimization property:

calc.Optimization =
    OptimizeModes.ConstantFolding |
    OptimizeModes.PowOptimize;

Evaluator object

This is the best way when you need for best performance during much many times expression evaluation.
Creation and usage looks exactly the same way, as Interpret<T> object, but backstage processes are different:

var eval = calc.CreateEvaluator(expression);

res = eval.Evaluate(3.0);  // = 9.0
Creation of Evaluator is much slower than creation of Interpret object cause it uses runtime MSIL code generation, but evaluation performance may be more than 10x better. So we should use this way when the best evaluation performance is needed and the startup time is not important.

Tabulator object

This is the best way when you need for extra performance in during expression evaluation with argument(s) in the specified range(s).
Argument range may be represented with ValueRange<T> class. Tabulator creation is the same, as Evaluator:

var tab = calc.CreateTabulator(expression);

// use it by specify begin, end, step values:
double[] table = tab.Tabulate(1.0, 5.0, 0.25);  // = { 1.0, 2.0, 3.0 ... }

// or via TabRange class:
var range = new TabRange<double>(1.0, 5.0, 1.0);
range.Count = 100; // set points count (recalculate step)

table = tab.Tabulate(range);  // = { 1.0, 1.16, 1.32, 1.48 ... }
Note, that you should specify at least one argument for Tabulator usage. As we can see, usage of Tabulator is nearly the same as the usage of Evaluator, except that argument ranges should be provided instead of argument values.

Validator

If needed to check the expression validity in this context, we can use the context's Validate() method like this:

try
{
    calc.Validate("2 / xyz");  // unresolved identifier "xyz" here
}
catch (SyntaxException err)
{
    // TODO: Show error message

    // we can get some error information here:
    //  err.Position   = 4
    //  err.Length     = 3
    //  err.Substring  = "xyz"
    //  err.Expression = "2 / xyz"
}
Expression validation doesn't causes any compilation or evaluation, preforming only validity check.

Last edited Sep 9, 2009 at 11:48 AM by Pelmen64, version 1

Comments

No comments yet.