public Characteristic(FormulaInfo formulaInfo, ReportDataProvider reportDataProvider) { if (formulaInfo == null) { throw new ArgumentNullException("formulaInfo"); } if (reportDataProvider == null) { throw new ArgumentNullException("reportDataProvider"); } _reportDataProvider = reportDataProvider; var formulaCore = formulaInfo.Coefficients .Aggregate(formulaInfo.Expression, (current, coeff) => current.Replace(coeff.Key, coeff.Value.ToString(CultureInfo.InvariantCulture))); _arguments = formulaInfo.Arguments; var preparedExpression = ToolsHelper.Parser.Parse(formulaCore); _compiledExpression = ToolsHelper.Compiler.Compile(preparedExpression); _compiledExpression = ToolsHelper.Optimizer.Optimize(_compiledExpression); }
public double Calculate(CompiledExpression compiledExpression, List<VariableValue> variableValues) { if (compiledExpression == null) throw new ArgumentNullException("compiledExpression"); if (variableValues == null) throw new ArgumentNullException("variableValues"); // List<double> calculationsStack = new List<double>(); // for (int i = 0; i < compiledExpression.CompiledExpressionItems.Count; i++) { CompiledExpressionItem item = compiledExpression.CompiledExpressionItems[i]; // switch (item.Kind) { case CompiledExpressionItemKind.Constant: { calculationsStack.Add(item.Constant); break; } case CompiledExpressionItemKind.Variable: { // TODO: Add dictionary optimizations. bool variableValueFound = false; foreach (VariableValue variableValue in variableValues) { if (item.VariableName == variableValue.VariableName) { variableValueFound = true; calculationsStack.Add(variableValue.Value); break; } } if (!variableValueFound) throw new MathProcessorException(String.Format("Variable {0} is not initialized.", item.VariableName)); break; } case CompiledExpressionItemKind.Operation: { Operation operation = operationsRegistry.GetOperationByName(item.OperationName); double[] parametersArray = new double[operation.OperandsCount]; // if (calculationsStack.Count - operation.OperandsCount < 0) throw new MathProcessorException("Stack is empty."); for (int j = 0; j < operation.OperandsCount; j++) { int index = calculationsStack.Count - operation.OperandsCount + j; parametersArray[j] = calculationsStack[index]; } // calculationsStack.RemoveRange(calculationsStack.Count - operation.OperandsCount, operation.OperandsCount); calculationsStack.Add(operation.Calculator.Calculate(parametersArray)); break; } default: { throw new InvalidOperationException("Unknown item kind."); } } } // if (calculationsStack.Count != 1) throw new MathProcessorException("Stack disbalance. Expression has invalid syntax."); return calculationsStack[0]; }
public CompiledExpression Optimize(CompiledExpression compiledExpression) { if (compiledExpression == null) throw new ArgumentNullException("compiledExpression"); // List<CompiledExpressionItem> optimizedExpression = new List<CompiledExpressionItem>(); // for (int i = 0; i < compiledExpression.CompiledExpressionItems.Count; i++) { CompiledExpressionItem item = compiledExpression.CompiledExpressionItems[i]; // switch (item.Kind) { case CompiledExpressionItemKind.Constant: { optimizedExpression.Add(item); break; } case CompiledExpressionItemKind.Variable: { optimizedExpression.Add(item); break; } case CompiledExpressionItemKind.Operation: { Operation operation = operationsRegistry.GetOperationByName(item.OperationName); // If all arguments are constants, we can optimize this. Otherwise, we can't bool noVariablesInArguments = true; for (int j = 0; (j < operation.OperandsCount) && noVariablesInArguments; j++) { int index = optimizedExpression.Count - operation.OperandsCount + j; if (index < 0) throw new MathProcessorException("Stack is empty."); // if (optimizedExpression[index].Kind != CompiledExpressionItemKind.Constant) noVariablesInArguments = false; } if (noVariablesInArguments) { double[] arguments = new double[operation.OperandsCount]; for (int j = optimizedExpression.Count - operation.OperandsCount, k = 0; j < optimizedExpression.Count; j++, k++) { arguments[k] = optimizedExpression[j].Constant; } // optimizedExpression.RemoveRange(optimizedExpression.Count - operation.OperandsCount, operation.OperandsCount); optimizedExpression.Add(new CompiledExpressionItem(CompiledExpressionItemKind.Constant, operation.Calculator.Calculate(arguments))); } else { optimizedExpression.Add(item); } break; } default: { throw new InvalidOperationException("Unknown item kind."); } } } return new CompiledExpression(optimizedExpression); }
public PreparedExpression Decompile(CompiledExpression compiledExpression) { if (compiledExpression == null) throw new ArgumentNullException("compiledExpression"); // List<DecompiledExpressionItem> decompilationStack = new List<DecompiledExpressionItem>(); // for (int i = 0; i < compiledExpression.CompiledExpressionItems.Count; i++) { CompiledExpressionItem item = compiledExpression.CompiledExpressionItems[i]; // switch (item.Kind) { case CompiledExpressionItemKind.Constant: { List<PreparedExpressionItem> items = new List<PreparedExpressionItem>(); items.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Constant, item.Constant)); decompilationStack.Add(new DecompiledExpressionItem(false, new PreparedExpression(items))); break; } case CompiledExpressionItemKind.Variable: { List<PreparedExpressionItem> items = new List<PreparedExpressionItem>(); items.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Variable, item.VariableName)); decompilationStack.Add(new DecompiledExpressionItem(false, new PreparedExpression(items))); break; } case CompiledExpressionItemKind.Operation: { Operation operation = operationsRegistry.GetOperationByName(item.OperationName); List<PreparedExpressionItem> resultExpression = new List<PreparedExpressionItem>(); // Begining to construct a new expression string if (operation.Kind == OperationKind.Function) { resultExpression.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Signature, operation.Signature[0])); resultExpression.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Delimiter, DelimiterKind.OpeningBrace)); } else if (operation.OperandsCount == 1) { // Unary operator resultExpression.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Signature, operation.Signature[0])); } // For each argument we have to determine, need there are braces or not for (int j = 0; j < operation.OperandsCount; j++) { int index = decompilationStack.Count - operation.OperandsCount + j; if (index < 0) throw new MathProcessorException("Stack is empty."); // DecompiledExpressionItem decompiledItem = decompilationStack[index]; bool applyBraces = false; if (operation.Kind != OperationKind.Function) { // First argument if (j == 0) { if (decompiledItem.IsComplex) if (decompiledItem.LastOperation.Kind != OperationKind.Function) { if (decompiledItem.LastOperation.OperandsCount == 1) applyBraces = true; else { if (operation.Priority < decompiledItem.LastOperation.Priority) applyBraces = true; else if (operation.Priority == decompiledItem.LastOperation.Priority) { if (operationsRegistry.GetAssociationByPriority(operation.Priority) == PriorityAssociation.RightAssociated) applyBraces = true; } } } } else // Last argument if (j == operation.OperandsCount - 1) if (decompiledItem.IsComplex) if (decompiledItem.LastOperation.Kind != OperationKind.Function) { if (decompiledItem.LastOperation.OperandsCount == 1) applyBraces = true; else { if (operation.Priority < decompiledItem.LastOperation.Priority) applyBraces = true; else if (operation.Priority == decompiledItem.LastOperation.Priority) { if (operationsRegistry.GetAssociationByPriority(operation.Priority) == PriorityAssociation.LeftAssociated) applyBraces = true; } } } } if (applyBraces) resultExpression.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Delimiter, DelimiterKind.OpeningBrace)); resultExpression.AddRange(decompiledItem.Expression.PreparedExpressionItems); if (applyBraces) resultExpression.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Delimiter, DelimiterKind.ClosingBrace)); // Appending delimiters between arguments if (j < operation.OperandsCount - 1) { if (operation.Kind == OperationKind.Function) { resultExpression.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Delimiter, DelimiterKind.Comma)); } else { resultExpression.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Signature, operation.Signature[j])); } } } decompilationStack.RemoveRange(decompilationStack.Count - operation.OperandsCount, operation.OperandsCount); // if (operation.Kind == OperationKind.Function) resultExpression.Add(new PreparedExpressionItem(PreparedExpressionItemKind.Delimiter, DelimiterKind.ClosingBrace)); // decompilationStack.Add(new DecompiledExpressionItem(true, new PreparedExpression(resultExpression), operation)); break; } default: { throw new InvalidOperationException("Unknown item kind."); } } } // if (decompilationStack.Count != 1) throw new MathProcessorException("Stack disbalance. Expression has invalid syntax."); return (decompilationStack[0].Expression); }
/// <summary> /// Checks a compiled expression for stack balance. /// </summary> private bool isCompiledExpressionStackBalanced(CompiledExpression compiledExpression) { if (compiledExpression == null) throw new ArgumentNullException("compiledExpression"); // int stackPointer = 0; // for (int i = 0; i < compiledExpression.CompiledExpressionItems.Count; i++) { CompiledExpressionItem item = compiledExpression.CompiledExpressionItems[i]; // switch (item.Kind) { case CompiledExpressionItemKind.Constant: { stackPointer++; break; } case CompiledExpressionItemKind.Variable: { stackPointer++; break; } case CompiledExpressionItemKind.Operation: { Operation operation = operationsRegistry.GetOperationByName(item.OperationName); stackPointer -= operation.OperandsCount - 1; break; } default: { throw new InvalidOperationException("Unknown item kind."); } } } // if (stackPointer != 1) return (false); return (true); }