Esempio n. 1
0
        public AstBuilder(IFunctionRegistry functionRegistry, bool caseSensitive, IConstantRegistry compiledConstants = null)
        {
            if (functionRegistry == null)
            {
                throw new ArgumentNullException("functionRegistry");
            }

            this.functionRegistry      = functionRegistry;
            this.localConstantRegistry = compiledConstants ?? new ConstantRegistry(caseSensitive);
            this.caseSensitive         = caseSensitive;

            operationPrecedence.Add('(', 0);
            operationPrecedence.Add('&', 1);
            operationPrecedence.Add('|', 1);
            operationPrecedence.Add('<', 2);
            operationPrecedence.Add('>', 2);
            operationPrecedence.Add('≤', 2);
            operationPrecedence.Add('≥', 2);
            operationPrecedence.Add('≠', 2);
            operationPrecedence.Add('=', 2);
            operationPrecedence.Add('+', 3);
            operationPrecedence.Add('-', 3);
            operationPrecedence.Add('*', 4);
            operationPrecedence.Add('/', 4);
            operationPrecedence.Add('%', 4);
            operationPrecedence.Add('_', 6);
            operationPrecedence.Add('^', 5);
        }
Esempio n. 2
0
 public FormulaContext(IDictionary <string, double> variables,
                       IFunctionRegistry functionRegistry,
                       IConstantRegistry constantRegistry)
 {
     this.Variables        = variables;
     this.FunctionRegistry = functionRegistry;
     this.ConstantRegistry = constantRegistry;
 }
Esempio n. 3
0
 public Func <IDictionary <string, double>, double> BuildFormula(Operation operation,
                                                                 IFunctionRegistry functionRegistry,
                                                                 IConstantRegistry constantRegistry, IDictionary <string, double> vars)
 {
     return(adjustVariableCaseEnabled
       ? (Func <IDictionary <string, double>, double>)(variables =>
     {
         variables = EngineUtil.ConvertVariableNamesToLowerCase(variables);
         return Execute(operation, functionRegistry, constantRegistry, variables);
     })
       : (Func <IDictionary <string, double>, double>)(variables =>
     {
         return Execute(operation, functionRegistry, constantRegistry, variables);
     }));
 }
Esempio n. 4
0
        public Expression <TFunc> BuildExpressionTree <TFunc>(
            Operation operation,
            IFunctionRegistry functionRegistry,
            IConstantRegistry constantRegistry,
            IList <string> paramNames)
            where TFunc : Delegate
        {
            ParameterExpression[] parameters = paramNames
                                               .Select(param => Expression.Parameter(typeof(float), param))
                                               .ToArray();

            IDictionary <string, ParameterExpression> parametersDic = parameters.ToDictionary(parameter => parameter.Name);

            return(Expression.Lambda <TFunc>(
                       GenerateMethodBody(
                           operation,
                           functionRegistry,
                           constantRegistry,
                           parametersDic),
                       parameters
                       ));
        }
Esempio n. 5
0
        public Func <IDictionary <string, double>, double> BuildFormula(Operation operation,
                                                                        IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry)
        {
            Func <FormulaContext, double> func = BuildFormulaInternal(operation, functionRegistry);

            return(caseSensitive
                ? (Func <IDictionary <string, double>, double>)(variables =>
            {
                return func(new FormulaContext(variables, functionRegistry, constantRegistry));
            })
                : (Func <IDictionary <string, double>, double>)(variables =>
            {
                variables = EngineUtil.ConvertVariableNamesToLowerCase(variables);
                FormulaContext context = new FormulaContext(variables, functionRegistry, constantRegistry);
                return func(context);
            }));
        }
Esempio n. 6
0
 public double Execute(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry,
                       IDictionary <string, double> variables)
 {
     return(BuildFormula(operation, functionRegistry, constantRegistry)(variables));
 }
Esempio n. 7
0
 public double Execute(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry)
 {
     return(Execute(operation, functionRegistry, constantRegistry, new Dictionary <string, double>()));
 }
Esempio n. 8
0
        public double Execute(Operation operation,
                              IFunctionRegistry functionRegistry,
                              IConstantRegistry constantRegistry,
                              IDictionary <string, double> variables)
        {
            if (operation == null)
            {
                throw new ArgumentNullException("operation");
            }

            if (operation.GetType() == typeof(IntegerConstant))
            {
                IntegerConstant constant = (IntegerConstant)operation;
                return(constant.Value);
            }
            else if (operation.GetType() == typeof(FloatingPointConstant))
            {
                FloatingPointConstant constant = (FloatingPointConstant)operation;
                return(constant.Value);
            }
            else if (operation.GetType() == typeof(Variable))
            {
                Variable variable = (Variable)operation;

                double value;
                bool   variableFound = variables.TryGetValue(variable.Name, out value);

                if (variableFound)
                {
                    return(value);
                }
                else
                {
                    throw new VariableNotDefinedException(string.Format("The variable \"{0}\" used is not defined.", variable.Name));
                }
            }
            else if (operation.GetType() == typeof(Multiplication))
            {
                Multiplication multiplication = (Multiplication)operation;
                return(Execute(multiplication.Argument1, functionRegistry, constantRegistry, variables) * Execute(multiplication.Argument2, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Addition))
            {
                Addition addition = (Addition)operation;
                return(Execute(addition.Argument1, functionRegistry, constantRegistry, variables) + Execute(addition.Argument2, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Subtraction))
            {
                Subtraction addition = (Subtraction)operation;
                return(Execute(addition.Argument1, functionRegistry, constantRegistry, variables) - Execute(addition.Argument2, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Division))
            {
                Division division = (Division)operation;
                return(Execute(division.Dividend, functionRegistry, constantRegistry, variables) / Execute(division.Divisor, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Modulo))
            {
                Modulo division = (Modulo)operation;
                return(Execute(division.Dividend, functionRegistry, constantRegistry, variables) % Execute(division.Divisor, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Exponentiation))
            {
                Exponentiation exponentiation = (Exponentiation)operation;
                return(Math.Pow(Execute(exponentiation.Base, functionRegistry, constantRegistry, variables), Execute(exponentiation.Exponent, functionRegistry, constantRegistry, variables)));
            }
            else if (operation.GetType() == typeof(UnaryMinus))
            {
                UnaryMinus unaryMinus = (UnaryMinus)operation;
                return(-Execute(unaryMinus.Argument, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(And))
            {
                And and        = (And)operation;
                var operation1 = Execute(and.Argument1, functionRegistry, constantRegistry, variables) != 0;
                var operation2 = Execute(and.Argument2, functionRegistry, constantRegistry, variables) != 0;

                return((operation1 && operation2) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(Or))
            {
                Or  or         = (Or)operation;
                var operation1 = Execute(or.Argument1, functionRegistry, constantRegistry, variables) != 0;
                var operation2 = Execute(or.Argument2, functionRegistry, constantRegistry, variables) != 0;

                return((operation1 || operation2) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(LessThan))
            {
                LessThan lessThan = (LessThan)operation;
                return((Execute(lessThan.Argument1, functionRegistry, constantRegistry, variables) < Execute(lessThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(LessOrEqualThan))
            {
                LessOrEqualThan lessOrEqualThan = (LessOrEqualThan)operation;
                return((Execute(lessOrEqualThan.Argument1, functionRegistry, constantRegistry, variables) <= Execute(lessOrEqualThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(GreaterThan))
            {
                GreaterThan greaterThan = (GreaterThan)operation;
                return((Execute(greaterThan.Argument1, functionRegistry, constantRegistry, variables) > Execute(greaterThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(GreaterOrEqualThan))
            {
                GreaterOrEqualThan greaterOrEqualThan = (GreaterOrEqualThan)operation;
                return((Execute(greaterOrEqualThan.Argument1, functionRegistry, constantRegistry, variables) >= Execute(greaterOrEqualThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(Equal))
            {
                Equal equal = (Equal)operation;
                return((Execute(equal.Argument1, functionRegistry, constantRegistry, variables) == Execute(equal.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(NotEqual))
            {
                NotEqual notEqual = (NotEqual)operation;
                return((Execute(notEqual.Argument1, functionRegistry, constantRegistry, variables) != Execute(notEqual.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(Function))
            {
                Function function = (Function)operation;

                FunctionInfo functionInfo = functionRegistry.GetFunctionInfo(function.FunctionName);

                double[] arguments = new double[functionInfo.IsDynamicFunc ? function.Arguments.Count : functionInfo.NumberOfParameters];
                for (int i = 0; i < arguments.Length; i++)
                {
                    arguments[i] = Execute(function.Arguments[i], functionRegistry, constantRegistry, variables);
                }

                return(Invoke(functionInfo.Function, arguments));
            }
            else
            {
                throw new ArgumentException(string.Format("Unsupported operation \"{0}\".", operation.GetType().FullName), "operation");
            }
        }
Esempio n. 9
0
        public Operation Optimize(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry)
        {
            if (!operation.DependsOnVariables && operation.IsIdempotent && operation.GetType() != typeof(IntegerConstant) &&
                operation.GetType() != typeof(FloatingPointConstant))
            {
                double result = executor.Execute(operation, functionRegistry, constantRegistry);
                return(new FloatingPointConstant(result));
            }
            else
            {
                if (operation.GetType() == typeof(Addition))
                {
                    Addition addition = (Addition)operation;
                    addition.Argument1 = Optimize(addition.Argument1, functionRegistry, constantRegistry);
                    addition.Argument2 = Optimize(addition.Argument2, functionRegistry, constantRegistry);
                }
                else if (operation.GetType() == typeof(Subtraction))
                {
                    Subtraction substraction = (Subtraction)operation;
                    substraction.Argument1 = Optimize(substraction.Argument1, functionRegistry, constantRegistry);
                    substraction.Argument2 = Optimize(substraction.Argument2, functionRegistry, constantRegistry);
                }
                else if (operation.GetType() == typeof(Multiplication))
                {
                    Multiplication multiplication = (Multiplication)operation;
                    multiplication.Argument1 = Optimize(multiplication.Argument1, functionRegistry, constantRegistry);
                    multiplication.Argument2 = Optimize(multiplication.Argument2, functionRegistry, constantRegistry);

                    if ((multiplication.Argument1.GetType() == typeof(FloatingPointConstant) && ((FloatingPointConstant)multiplication.Argument1).Value == 0.0) ||
                        (multiplication.Argument2.GetType() == typeof(FloatingPointConstant) && ((FloatingPointConstant)multiplication.Argument2).Value == 0.0))
                    {
                        return(new FloatingPointConstant(0.0));
                    }
                }
                else if (operation.GetType() == typeof(Division))
                {
                    Division division = (Division)operation;
                    division.Dividend = Optimize(division.Dividend, functionRegistry, constantRegistry);
                    division.Divisor  = Optimize(division.Divisor, functionRegistry, constantRegistry);
                }
                else if (operation.GetType() == typeof(Exponentiation))
                {
                    Exponentiation division = (Exponentiation)operation;
                    division.Base     = Optimize(division.Base, functionRegistry, constantRegistry);
                    division.Exponent = Optimize(division.Exponent, functionRegistry, constantRegistry);
                }
                else if (operation.GetType() == typeof(Function))
                {
                    Function          function  = (Function)operation;
                    IList <Operation> arguments = function.Arguments.Select(a => Optimize(a, functionRegistry, constantRegistry)).ToList();
                    function.Arguments = arguments;
                }

                return(operation);
            }
        }
Esempio n. 10
0
        public Operation Optimize(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry)
        {
            if (!operation.DependsOnVariables && operation.GetType() != typeof(IntegerConstant) &&
                operation.GetType() != typeof(FloatingPointConstant))
            {
                double result = executor.Execute(operation, functionRegistry, constantRegistry);
                return(new FloatingPointConstant(result));
            }
            else
            {
                if (operation.GetType() == typeof(Addition))
                {
                    Addition addition = (Addition)operation;
                    addition.Argument1 = Optimize(addition.Argument1, functionRegistry, constantRegistry);
                    addition.Argument2 = Optimize(addition.Argument2, functionRegistry, constantRegistry);
                }
                else if (operation.GetType() == typeof(Subtraction))
                {
                    Subtraction substraction = (Subtraction)operation;
                    substraction.Argument1 = Optimize(substraction.Argument1, functionRegistry, constantRegistry);
                    substraction.Argument2 = Optimize(substraction.Argument2, functionRegistry, constantRegistry);
                }
                else if (operation.GetType() == typeof(Multiplication))
                {
                    Multiplication multiplication = (Multiplication)operation;
                    multiplication.Argument1 = Optimize(multiplication.Argument1, functionRegistry, constantRegistry);
                    multiplication.Argument2 = Optimize(multiplication.Argument2, functionRegistry, constantRegistry);
                }
                else if (operation.GetType() == typeof(Division))
                {
                    Division division = (Division)operation;
                    division.Dividend = Optimize(division.Dividend, functionRegistry, constantRegistry);
                    division.Divisor  = Optimize(division.Divisor, functionRegistry, constantRegistry);
                }
                else if (operation.GetType() == typeof(Exponentiation))
                {
                    Exponentiation division = (Exponentiation)operation;
                    division.Base     = Optimize(division.Base, functionRegistry, constantRegistry);
                    division.Exponent = Optimize(division.Exponent, functionRegistry, constantRegistry);
                }

                return(operation);
            }
        }
Esempio n. 11
0
        private Expression GenerateMethodBody(
            Operation operation,
            IFunctionRegistry functionRegistry,
            IConstantRegistry constantRegistry,
            IDictionary <string, ParameterExpression> parametersDic)
        {
            if (operation == null)
            {
                throw new ArgumentNullException("operation");
            }

            if (operation is FloatingPointConstant constant)
            {
                return(Expression.Constant(constant.Value, typeof(float)));
            }
            else if (operation is Variable variable)
            {
                if (parametersDic.TryGetValue(variable.Name, out ParameterExpression parameter))
                {
                    return(parameter);
                }
                else if (constantRegistry.IsConstantName(variable.Name))
                {
                    ConstantInfo ci = constantRegistry.GetConstantInfo(variable.Name);
                    return(Expression.Constant(ci.Value));
                }
                else
                {
                    throw new VariableNotDefinedException($"Undefined symbol: \"{variable.Name}\"");
                }
            }
            else if (operation is Multiplication multiplication)
            {
                Expression argument1 = GenerateMethodBody(multiplication.Argument1, functionRegistry, constantRegistry, parametersDic);
                Expression argument2 = GenerateMethodBody(multiplication.Argument2, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Multiply(argument1, argument2));
            }
            else if (operation is Addition addition)
            {
                Expression argument1 = GenerateMethodBody(addition.Argument1, functionRegistry, constantRegistry, parametersDic);
                Expression argument2 = GenerateMethodBody(addition.Argument2, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Add(argument1, argument2));
            }
            else if (operation is Substraction substraction)
            {
                Expression argument1 = GenerateMethodBody(substraction.Argument1, functionRegistry, constantRegistry, parametersDic);
                Expression argument2 = GenerateMethodBody(substraction.Argument2, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Subtract(argument1, argument2));
            }
            else if (operation is Division division)
            {
                Expression dividend = GenerateMethodBody(division.Dividend, functionRegistry, constantRegistry, parametersDic);
                Expression divisor  = GenerateMethodBody(division.Divisor, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Divide(dividend, divisor));
            }
            else if (operation is Modulo modulo)
            {
                Expression dividend = GenerateMethodBody(modulo.Dividend, functionRegistry, constantRegistry, parametersDic);
                Expression divisor  = GenerateMethodBody(modulo.Divisor, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Modulo(dividend, divisor));
            }
            else if (operation is Exponentiation exponentiation)
            {
                Expression @base    = GenerateMethodBody(exponentiation.Base, functionRegistry, constantRegistry, parametersDic);
                Expression exponent = GenerateMethodBody(exponentiation.Exponent, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Call(null, typeof(Mathf).GetRuntimeMethod("Pow", new Type[] { typeof(float), typeof(float) }), @base, exponent));
            }
            else if (operation is UnaryMinus unaryMinus)
            {
                Expression argument = GenerateMethodBody(unaryMinus.Argument, functionRegistry, constantRegistry, parametersDic);
                return(Expression.Negate(argument));
            }
            else if (operation is And and)
            {
                Expression argument1 = Expression.NotEqual(GenerateMethodBody(and.Argument1, functionRegistry, constantRegistry, parametersDic), Expression.Constant(0.0f));
                Expression argument2 = Expression.NotEqual(GenerateMethodBody(and.Argument2, functionRegistry, constantRegistry, parametersDic), Expression.Constant(0.0f));

                return(Expression.Condition(Expression.And(argument1, argument2),
                                            Expression.Constant(1.0f),
                                            Expression.Constant(0.0f)));
            }
            else if (operation is Or or)
            {
                Expression argument1 = Expression.NotEqual(GenerateMethodBody(or.Argument1, functionRegistry, constantRegistry, parametersDic), Expression.Constant(0.0f));
                Expression argument2 = Expression.NotEqual(GenerateMethodBody(or.Argument2, functionRegistry, constantRegistry, parametersDic), Expression.Constant(0.0f));

                return(Expression.Condition(Expression.Or(argument1, argument2),
                                            Expression.Constant(1.0f),
                                            Expression.Constant(0.0f)));
            }
            else if (operation is LessThan lessThan)
            {
                Expression argument1 = GenerateMethodBody(lessThan.Argument1, functionRegistry, constantRegistry, parametersDic);
                Expression argument2 = GenerateMethodBody(lessThan.Argument2, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Condition(Expression.LessThan(argument1, argument2),
                                            Expression.Constant(1.0f),
                                            Expression.Constant(0.0f)));
            }
            else if (operation is LessOrEqualThan lessOrEqualThan)
            {
                Expression argument1 = GenerateMethodBody(lessOrEqualThan.Argument1, functionRegistry, constantRegistry, parametersDic);
                Expression argument2 = GenerateMethodBody(lessOrEqualThan.Argument2, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Condition(Expression.LessThanOrEqual(argument1, argument2),
                                            Expression.Constant(1.0f),
                                            Expression.Constant(0.0f)));
            }
            else if (operation is GreaterThan greaterThan)
            {
                Expression argument1 = GenerateMethodBody(greaterThan.Argument1, functionRegistry, constantRegistry, parametersDic);
                Expression argument2 = GenerateMethodBody(greaterThan.Argument2, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Condition(Expression.GreaterThan(argument1, argument2),
                                            Expression.Constant(1.0f),
                                            Expression.Constant(0.0f)));
            }
            else if (operation is GreaterOrEqualThan greaterOrEqualThan)
            {
                Expression argument1 = GenerateMethodBody(greaterOrEqualThan.Argument1, functionRegistry, constantRegistry, parametersDic);
                Expression argument2 = GenerateMethodBody(greaterOrEqualThan.Argument2, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Condition(Expression.GreaterThanOrEqual(argument1, argument2),
                                            Expression.Constant(1.0f),
                                            Expression.Constant(0.0f)));
            }
            else if (operation is Equal equal)
            {
                Expression argument1 = GenerateMethodBody(equal.Argument1, functionRegistry, constantRegistry, parametersDic);
                Expression argument2 = GenerateMethodBody(equal.Argument2, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Condition(Expression.Equal(argument1, argument2),
                                            Expression.Constant(1.0f),
                                            Expression.Constant(0.0f)));
            }
            else if (operation is NotEqual notEqual)
            {
                Expression argument1 = GenerateMethodBody(notEqual.Argument1, functionRegistry, constantRegistry, parametersDic);
                Expression argument2 = GenerateMethodBody(notEqual.Argument2, functionRegistry, constantRegistry, parametersDic);

                return(Expression.Condition(Expression.NotEqual(argument1, argument2),
                                            Expression.Constant(1.0f),
                                            Expression.Constant(0.0f)));
            }
            else if (operation is Function function)
            {
                FunctionInfo functionInfo = functionRegistry.GetFunctionInfo(function.FunctionName);

                Type   funcType       = functionInfo.Function.GetType();
                Type[] parameterTypes = Enumerable.Repeat(typeof(float), functionInfo.NumberOfParameters).ToArray();

                Expression[] arguments = new Expression[functionInfo.NumberOfParameters];
                for (int i = 0; i < functionInfo.NumberOfParameters; i++)
                {
                    arguments[i] = GenerateMethodBody(function.Arguments[i], functionRegistry, constantRegistry, parametersDic);
                }

                ConstantExpression getFunctionInfo = Expression.Constant(functionInfo.Function, funcType);
                MethodInfo         invokeMethod    = funcType.GetRuntimeMethod("Invoke", parameterTypes);

                return(Expression.Call(
                           getFunctionInfo,
                           invokeMethod,
                           arguments));
            }
            else
            {
                throw new ArgumentException($"Unsupported operation \"{operation.GetType().FullName}\".", nameof(operation));
            }
        }