using System; using System.Collections.Generic; using System.Globalization; using System.Linq; public class MathExpressionComparison { MathExpression leftSide; MathExpression rightSide; Func comparisonFunction; public MathExpressionComparison(MathExpression leftSide, MathExpression rightSide, Func comparisonFunction) { this.leftSide = leftSide; this.rightSide = rightSide; this.comparisonFunction = comparisonFunction; } public bool eval(float[] variables) { return comparisonFunction(leftSide.eval(variables), rightSide.eval(variables)); } } public class MathExpressionNode { Func function; MathExpressionNode[] childNodes; public MathExpressionNode(Func function, MathExpressionNode[] childNodes) { this.function = function; this.childNodes = childNodes; } public float eval(float[] variables) { var x = childNodes.Select(node => node.eval(variables)).ToArray(); return function(x, variables); } } public class MathExpression { private static Random random = new Random(); private static Dictionary expression_hierarchy = new Dictionary{ {'^', 4}, {'*', 3}, {'/', 3}, {'+', 1}, {'-', 1}, }; MathExpressionNode rootNode; public float eval(float[] variables) { return rootNode.eval(variables); } private static float negate(float[] children, float[] variables) { return -children[0]; } private static float mulitply(float[] children, float[] variables) { return children[0] * children[1]; } private static float power(float[] children, float[] variables) { return (float)Math.Pow(children[0], children[1]); } private static float divide(float[] children, float[] variables) { return children[0] / children[1]; } private static float add(float[] children, float[] variables) { return children[0] + children[1]; } private static float subtract(float[] children, float[] variables) { return children[0] - children[1]; } //private MathExpressionNode parse(Dictionary variableNames, string expression_string) { // var read_characters = 0; // var node = new MathExpressionNode(); // if (expression_string[0] == '(') { // var length = LSystemFileParser.countParenthesisEnd(expression_string, '(', ')'); // if (length == expression_string.Length - 2) { // return parse(variableNames, expression_string.Substring(1, length)); // } // var left_child_node = parse(variableNames, expression_string.Substring(1, length)); // read_characters += length + 2; // node.function = getFunction(expression_string[read_characters]); // read_characters += 1; // if (expression_string[read_characters] == '(') // } //} private static MathExpressionNode parse(Dictionary variableNames, string expression_string) { expression_string = expression_string.Trim(); var expression_pos = -1; var current_level = 1000; for (int i = 0; i < expression_string.Length; i++) { if (expression_string[i] == '(') { var length = LSystemFileParser.countParenthesisEnd(expression_string.Substring(i), '(', ')'); if (length == expression_string.Length - 2) { return parse(variableNames, expression_string.Substring(1, length)); } //skip parenthesis // if expression is covered in ( ) if (i == 0 && length == expression_string.Length - 2) { return parse(variableNames, expression_string.Substring(1, length)); } else { i += length + 1; continue; } } int new_level; if (expression_hierarchy.TryGetValue(expression_string[i], out new_level)) { if (i > 0 && !(i - 1 == expression_pos && expression_string[i] == '-')) { if (new_level <= current_level) { current_level = new_level; expression_pos = i; } } } } if (expression_pos > 0) { var left_node = parse(variableNames, expression_string.Substring(0, expression_pos)); var right_node = parse(variableNames, expression_string.Substring(expression_pos + 1)); MathExpressionNode[] child_nodes = { left_node, right_node }; switch (expression_string[expression_pos]) { case '*': return new MathExpressionNode(mulitply, child_nodes); break; case '/': return new MathExpressionNode(divide, child_nodes); break; case '+': return new MathExpressionNode(add, child_nodes); break; case '-': return new MathExpressionNode(subtract, child_nodes); break; case '^': return new MathExpressionNode(power, child_nodes); break; default: throw new Exception(String.Format("unknown operation {0} in {1}", expression_string[expression_pos], expression_string)); break; } } else if (expression_string[0] == '-') { MathExpressionNode[] a = { parse(variableNames, expression_string.Substring(1)) }; return new MathExpressionNode(negate, a); } else { int index; if (expression_string == "RANDOM") { return new MathExpressionNode((float[] children, float[] arguments) => (float)random.NextDouble(), new MathExpressionNode[0]); } if (variableNames.TryGetValue(expression_string.Trim(), out index)) { return new MathExpressionNode((float[] children, float[] arguments) => arguments[index], new MathExpressionNode[0]); } else { try { float value = float.Parse(expression_string, NumberStyles.Any, CultureInfo.InvariantCulture); return new MathExpressionNode((float[] children, float[] arguments) => value, new MathExpressionNode[0]); } catch (Exception) { throw new Exception(String.Format("can't parse ``{0}``. It's not a number nor a known variable", expression_string)); } } } } public MathExpression(Dictionary variableNames, string expression_string) { rootNode = parse(variableNames, expression_string); } } public class MathExpressionComparasionParser { private static bool le(float a, float b) { return a < b; } private static bool leq(float a, float b) { return a <= b; } private static bool eq(float a, float b) { return a == b; } public static MathExpressionComparison parse(Dictionary variableNames, string expression_string) { //var operations = new string[]{ "<=", ">=", "<", ">"}; if (expression_string.Contains("<=")) { var parts = expression_string.Split(new string[] { "<=" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray(); return new MathExpressionComparison(new MathExpression(variableNames, parts[0]), new MathExpression(variableNames, parts[1]), leq); } if (expression_string.Contains(">=")) { var parts = expression_string.Split(new string[] { ">=" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray(); return new MathExpressionComparison(new MathExpression(variableNames, parts[1]), new MathExpression(variableNames, parts[0]), leq); } if (expression_string.Contains("==")) { var parts = expression_string.Split(new string[] { "==" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray(); return new MathExpressionComparison(new MathExpression(variableNames, parts[1]), new MathExpression(variableNames, parts[0]), eq); } if (expression_string.Contains("<")) { var parts = expression_string.Split('<').Select(s => s.Trim()).ToArray(); return new MathExpressionComparison(new MathExpression(variableNames, parts[0]), new MathExpression(variableNames, parts[1]), le); } if (expression_string.Contains(">")) { var parts = expression_string.Split('>').Select(s => s.Trim()).ToArray(); return new MathExpressionComparison(new MathExpression(variableNames, parts[1]), new MathExpression(variableNames, parts[0]), le); } throw new Exception(String.Format("comparison operation not recognized in {}", expression_string)); } }