248 lines
9.3 KiB
C#
248 lines
9.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
|
|
public class MathExpressionComparison
|
|
{
|
|
MathExpression leftSide;
|
|
MathExpression rightSide;
|
|
Func<float, float, bool> comparisonFunction;
|
|
|
|
public MathExpressionComparison(MathExpression leftSide, MathExpression rightSide, Func<float, float, bool> 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<float[], float[], float> function;
|
|
MathExpressionNode[] childNodes;
|
|
|
|
public MathExpressionNode(Func<float[], float[], float> 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 System.Random random = new System.Random();
|
|
|
|
private static Dictionary<char, int> expression_hierarchy = new Dictionary<char, int>{
|
|
{'^', 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<string, int> 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<string, int> 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<string, int> 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<string, int> 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));
|
|
}
|
|
}
|