Is there any calculation engine for C# that can automatically recalculate dependent fields when a value changes?
Let me freestyle for a second, I'm imagining something like this..
Field<double> quantity = Field.Create<double>("Quantity");
F开发者_StackOverflow社区ield<double> unitCost = Field.Create<double>("Unit Cost");
Field<double> total = Field.Create<double>("Total");
total.Calculation((q,uc) => q * uc, quantity, value);
// would have signature something like this:
// void Calculation<TR,T1,T1>(Func<TR,T1,T2>, Field<T1>, Field<T2>)
This would set up fields that auto-propagate dependent values.
quantity.Value = 5.0;
unitCost.Value = 1.5;
Assert.That(total.Value, Is.EqualTo(7.5));
Obviously this is a simple example, the end uses would be much more akin to the calculations of a complex spreadsheet.
Thinking further it would be amazing if the field/cells would support change notification.
Have you seen http://ncalc.codeplex.com ?
It's extensible, fast (e.g. has its own cache) enables you to provide custom functions and varaibles at run time by handling EvaluateFunction/EvaluateParameter events. Example expressions it can parse:
Expression e = new Expression("Round(Pow(Pi, 2) + Pow([Pi2], 2) + X, 2)");
e.Parameters["Pi2"] = new Expression("Pi * Pi");
e.Parameters["X"] = 10;
e.EvaluateParameter += delegate(string name, ParameterArgs args)
{
if (name == "Pi")
args.Result = 3.14;
};
Debug.Assert(117.07 == e.Evaluate());
It also handles unicode & many data type natively. It comes with an antler file if you want to change the grammer. There is also a fork which supports MEF to load new functions.
It also supports logical operators, date/time's strings and if statements.
a solution
You could possibly do automatic recalculation by implementing INotifyPropertyChanged then doing something like
- set a field's expression this.Field.Expression = new Expression("Field1+Field2");
On notifypropertyupdated in the class
- for each field (with reflection) that is a Function
- if it's expression refers to the changed field then recalculate the variable.
- on recalculation you'd need to handle the EvaluateParameter event to use reflection to find the right field and extract its value (you could cache to avoid reflection if needed)
There are calculation engines for scalar parameters, and there are higher-level calculation engines for tables, typically used for applications like financial planning, fee and commission calculations, network and contract computations...
Let me explain this shortly. Consider following formulas for scalars:
1) z = f1(x,y)
2) p = f2(z,n)
3) q = f3(x,p)
...
and so on. Configuring such functions and dependency trees requires a calculation engine with scalar parameters. I would (also) recommend following link for such a calculation engine written in c# as a good starting point: http://www.codeproject.com/Articles/246374/A-Calculation-Engine-for-NET
As mentioned, there are also calculation engines with table functions that take tables as parameters. The main principle is but the same:
1) (T4, T5) = TableFunction1(T1, T2, T3)
2) (T7, T8) = TableFunction2(T2, T4)
...
and so on. Note that a table function can return multiple tables as outputs, as shown above.
There two key issues to be observed here:
a) The values of tables T7 and T8 depend on tables T2 and T4. Therefore, the tables T7 and T8 need to be updated by executing the function "TableFunction2" only if there is a change in one of the input parameters T2 or T4.
Similarly, T4 need to be updated only if T1, T2 or T3 is updated; dependency tree!
b) Separation of database from the calculation process: The calculation engine must work independent of any fixed data structure or database schema so that it can be integrated with any database and data structure.
You can find my related article where these principles are explained at:
Logical Architecture of a Rule-Based Calculation Framework http://finaquant.com/logical-architecture-of-a-rule-based-calculation-framework/1053
Now, a C#/.NET library for a calculation engine with tables as input and output parameters is being developed based on these principles.
Note to moderators: Please delete the link above if it is counted as self-promotion.
I asked a similar question here: Truly declarative language?
As far as I know not, only just heard about NCalc, I'll look into it. I have a project that does pretty much what you describe and then some like caching/ cache dropping on changes to values or model structure. Think f it as a crossover between a database and Excel. You can also define classes etc and link them together into large models with millions of objects in graphs, not just trees. Client server etc. Also there's a model editor where you create models in a UI so you can analyse how all the calculations build on each other.
Why exactly are you asking?
I would recommend to also give a look at Jace. Jace is a more modern calculation engine for the .NET framework. It is a lot faster then the above proposed NCalc. Furthermore it supports more platforms (.NET, WinRT, WP7 and WP8).
More information about Jace can be found on the GitHub page: https://github.com/pieterderycke/Jace
NuGet link: https://www.nuget.org/packages/Jace
One of problems with generic rule engine efficiency is recalculation of sums groups etc. Imagine that you want to calculates sum of VAT taxes. In your invoice event appeared that some product changed and vat changed from one to another. Now the simples solution is to recalculate all taxes. But we could imagine smart solution that we know that in given group we need to subtract vat amount and add it to another group. Another problem is cycles. We can have demand that our engine would calculate part of remaining to pay amount when we enter it into paid field. And in another case we would want to calculate paid field if we enter it into remaining to pay field. This could be done by virtual field "which field was entered by user" and if depending on it in the rule
精彩评论