Comments (12)
I will also add support to define constants in formulas declarative:
CalculationEngine engine = new CalculationEngine(CultureInfo.InvariantCulture, ExecutionMode.Compiled);
Func<double, double, double> formula = (Func<double, double, double>)engine.Formula("a+b+c")
.Parameter("b", DataType.FloatingPoint)
.Parameter("c", DataType.FloatingPoint)
.Constant("a", 1)
.Result(DataType.FloatingPoint)
.Build();
double result = formula(2.0, 2.0);
Assert.AreEqual(5.0, result);
from jace.
Hi Pieter,
What do u think about adding a local constant registry in AstBuilder? Something like this:
CalculationEngine.cs
private Operation BuildAbstractSyntaxTree(string formulaText, IDictionary<string, double> constants = null)
{
TokenReader tokenReader = new TokenReader(cultureInfo);
List<Token> tokens = tokenReader.Read(formulaText);
var localConstantsRegistry = new ConstantRegistry(false);
if (constants != null)
{
foreach (var localConst in constants)
localConstantsRegistry.RegisterConstant(localConst.Key, localConst.Value);
}
AstBuilder astBuilder = new AstBuilder(FunctionRegistry, adjustVariableCaseEnabled, localConstantsRegistry);
Operation operation = astBuilder.Build(tokens);
if (optimizerEnabled)
return optimizer.Optimize(operation, this.FunctionRegistry, this.ConstantRegistry);
else
return operation;
}
AstBuilder.cs (piece of public Operation Build(IList tokens))
case TokenType.Text:
if (functionRegistry.IsFunctionName((string)token.Value))
{
operatorStack.Push(token);
parameterCount.Push(1);
}
else
{
string tokenValue = (string)token.Value;
if (adjustVariableCaseEnabled)
{
tokenValue = tokenValue.ToLowerInvariant();
}
if (constantRegistry.IsConstantName(tokenValue)
{
resultStack.Push(new FloatingPointConstant(constantRegistry.GetConstantInfo(tokenValue).Value));
}
else
{
resultStack.Push(new Variable(tokenValue));
}
}
break;
CalculationEngineTest.cs
[TestMethod]
public void TestCalculationFormulaWithConstant()
{
CalculationEngine engine = new CalculationEngine(CultureInfo.InvariantCulture, ExecutionMode.Compiled);
var fn = engine.Build("a+b+c",new Dictionary<string,double> { { "a", 1 }});
double result = fn(new Dictionary<string, double> {{"b", 2}, {"c", 2}} );
Assert.AreEqual(5.0, result);
}
from jace.
I am open for the idea to add support for it, but just for my understanding: for which use cases would you require this feature?
from jace.
In my case it's almost a linear regression model. It has two types of variables: generated by the system and by the input. System variables almost never change but I need to keep track all changes. So it's easier to think of them as variables instead of constants in the expression.
Another point it is I'm caching by my side, because I have other types of expressions that are not math and Jace can not process.
from jace.
Another example would be a tax engine. The way of calculating is always the same, but each State has its aliquot. Then we can read the aliquots from a database and apply in the formula for each State.
I think always we have variables that change little and need to be tracked, this functionality will be applied.
from jace.
And just to challenge you: why could you not build a function and then provide the variables for calculation? (It would really like to understand your use case in depth)
from jace.
Yes, it is possible but I will lose performance or I need to do as I showed in the first post by string replacement and dealing with all complexity to identify variables boundaries.
var sw = new Stopwatch();
var calcEngine = new CalculationEngine();
var fn = calcEngine.Build("a*x+b");
sw.Start();
for (int i = 0; i < 10000000; i++)
{
fn(new Dictionary<string, double> {{"a", 2}, {"x", 3}, {"b", 4}});
}
sw.Stop();
sw.Reset(); // 4774ms
var fn1 = calcEngine.Build("2*x+4");
sw.Start();
for (int i = 0; i < 10000000; i++)
{
fn1(new Dictionary<string, double> { { "x", 3 } });
}
sw.Stop();
sw.Reset(); //2939ms
Thinking as Functional programming is like curry function. I've already had my "function body" defined or in this case my math expressions. But I want to create sub-formulas with some variables pre-defined and caching this new functions.
About my user case is a compliance engine. There are a many of predefined rules created by user and we have sensors generating input for that "acceptance tree". This predefined rules rarely, or never change. But the tolerance values may change slightly depending on the quality of the raw material.
Example:
Weight Acceptance Rule = "input - 1000 >= tolerance".
In this case my expression will never change but the tolerance value can change, or not, in a week for example.
It's like I said at the beginning, I can create the expression with all the values, except for the input of the sensor, but in this case would have to deal with the substitution by myself or I will always treating all variables as input losing performance.
Do you see any other way?
from jace.
You have convinced me 🙂 I agree with your use case. I will review your pull request this evening and add it as feature for Jace 1.0
from jace.
uow great news!
looking forward to this new release! 😄
from jace.
I have merged pull request #44 into the dev branch
from jace.
I have updated the wiki: https://github.com/pieterderycke/Jace/wiki/Compile-Time-constants
from jace.
This was released as part of Jace 1.0
from jace.
Related Issues (20)
- Can we make Random overrideable? HOT 3
- Bitwise operations
- Non base-10 numbers
- Matrix & display function itself
- Override operators HOT 2
- Feature Request: Option to set calc trigonomic functions with degrees (not radian) HOT 1
- Wrong precendence for unitary minus and exponential
- Invalid floating point numbers cause InvalidOperationException
- Problems with ambiguity of e
- Invalid scientific notation leads to IndexOutOfBoundsException instead of ParseException
- Upgrade to NetStandard 2.0 HOT 2
- Interpreter.BuildFormula does not work with constants
- Is this project still being updated? HOT 2
- Runtime Error : Could not load file or assembly System.Runtime HOT 2
- JaceOptions case sensitivity does not get applied to FunctionRegistry or ConstantRegistry on engine constructor HOT 4
- Bug in operators precedence HOT 17
- Request for dynamic variables
- PEMDAS HOT 2
- Introducing _sonic_, a maintained Jace.NET fork/successor HOT 1
- avg function not working HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jace.