Coder Social home page Coder Social logo

Comments (12)

pieterderycke avatar pieterderycke commented on July 28, 2024 1

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.

mrxrsd avatar mrxrsd commented on July 28, 2024

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.

pieterderycke avatar pieterderycke commented on July 28, 2024

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.

mrxrsd avatar mrxrsd commented on July 28, 2024

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.

mrxrsd avatar mrxrsd commented on July 28, 2024

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.

pieterderycke avatar pieterderycke commented on July 28, 2024

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.

mrxrsd avatar mrxrsd commented on July 28, 2024

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.

pieterderycke avatar pieterderycke commented on July 28, 2024

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.

mrxrsd avatar mrxrsd commented on July 28, 2024

uow great news!
looking forward to this new release! 😄

from jace.

pieterderycke avatar pieterderycke commented on July 28, 2024

I have merged pull request #44 into the dev branch

from jace.

pieterderycke avatar pieterderycke commented on July 28, 2024

I have updated the wiki: https://github.com/pieterderycke/Jace/wiki/Compile-Time-constants

from jace.

pieterderycke avatar pieterderycke commented on July 28, 2024

This was released as part of Jace 1.0

from jace.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.