How to improve performance on evaluating multiple mathematical expressions?

144 views Asked by At

I'm developing an application that works like an excel sheet: the user types a few values, and a lot of consequent calculation is done, in Blazor.

Right now I'm following this sequence (simplified code can be found at the end of question):

  1. Retrieve all expressions from DB into a List.
    The expressions can be written by the user, in another section. For example, the user can insert that BMI formula is "= @Weight / @Height ^2"
  2. Each property call "RetrieveValue(propertyName)"
  3. Substitute refferences in expression for it's value
    That means, if the expression is "= @Weight / @Height ^ 2", I'll replace '@Weight' and '@Height' for either user-typed values, or for values from other expressions
  4. Evaluate using FLEE (fast lightweight expression evalutor)
    I'd then send the expression "100 / 170 ^2" to be compiled and return it's value to the property

But it's taking too much time (around 300 evaluations taking 40 seconds), so I'm not sure this is the best method. I'm already storing an expression final form and it's result, so I don't have to evaluate again if it has already been evaluated.

What changes can I do to improve performance?

  1.     Expressions = expressionsLibrary.ToList();
    
  2.     public string? BMI
        {
            get
            {
                return RetrieveValue("BMI");
            }
            set
            {
                return;
            }
        }
    
  3.     public string RetrieveValue(string propertyName)
        {
            // Retrieve property expression from list
            var result = Expressions.FirstOrDefault(e => d.Name == propertyName) ?? null;
            object value = result.Value;
    
            // Check for null
            if (result is null)
            {
                return null;
            }
            else if (!(result.Value is null) && result.ValueTrim().StartsWith('='))
            {
                // Replace refferences for numeric valuess
                var replaced = ReplaceRefferences(result.Value)GetAwaiter().GetResult();
    
                // If I didn't evaluate this expression yet, or it has changed
                if (string.IsNullOrEmpty(result.ReplacedValue) || resultado.ReplacedValue != replaced)
                {
                    var index = Expressions.IndexOf(result);
    
                    // Updates expression in list
                    Expressions[index].ReplacedValue = replaced;
    
                    // Evaluate
                    value = Eval(replaced);
    
                    // Updates value in list
                    Expressions[index].EvaluatedValue = value;
                }
                else
                {
                    value = result.EvaluatedValue;
                }
            }
    
            return Convert.ToString(value);
        }
    
  4.     private string Eval(String expression)
        {
            cExpressionContext context = new ExpressionContext();
    
            context.ParserOptions.RecreateParser();
    
            // Allow the expression to use all static public methods of System.Math
            context.Imports.AddType(typeof(Math));
    
            Flee.PublicTypes.IDynamicExpression eDynamic = context.CompileDynamic(expression);
    
            return Convert.ToString(eDynamic.Evaluate());
        }
    

I'm already storing an expression final form and it's result, so I don't have to evaluate again if it has already been evaluated. It works well with a few expressions per call (10 or so)

0

There are 0 answers