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); }
public FormulaContext(IDictionary <string, double> variables, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry) { this.Variables = variables; this.FunctionRegistry = functionRegistry; this.ConstantRegistry = constantRegistry; }
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); })); }
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 )); }
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); })); }
public double Execute(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry, IDictionary <string, double> variables) { return(BuildFormula(operation, functionRegistry, constantRegistry)(variables)); }
public double Execute(Operation operation, IFunctionRegistry functionRegistry, IConstantRegistry constantRegistry) { return(Execute(operation, functionRegistry, constantRegistry, new Dictionary <string, double>())); }
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"); } }
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); } }
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); } }
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)); } }