public SimplificationReturnValue Simplify(string equation)
{
var retval = new SimplificationReturnValue { OriginalEquation = equation };
if (equation.Trim().StartsWith("-") || equation.Trim().StartsWith("+"))
equation = "0" + equation;
equation = equation.Replace("(+", "(0+");
equation = equation.Replace("(-", "(0-");
equation = equation.Replace("( +", "( 0+");
equation = equation.Replace("( -", "( 0-");
equation = equation.Replace(",-", ",0-");
equation = equation.Replace(", -", ", 0-");
equation = equation.Replace(",+", ",0+");
equation = equation.Replace(", +", ", 0+");
var tp = new TokenParser();
foreach (var cf in _customFunctions)
{
tp.RegisterCustomFunction(cf.Key);
}
tp.InputString = equation;
Token token = tp.GetToken();
_operatorStack.Clear();
_outputQueue.Clear();
while (token != null)
{
if (token.TokenName == TokenParser.Tokens.Sqrt)
{
string expression = token.TokenValue.Substring(4, token.TokenValue.Length - 4);
SimplificationReturnValue rv = EvaluateExpression(new NumberClass
{
Expression = expression,
NumberType = NumberClass.NumberTypes.Expression
});
token.TokenName = TokenParser.Tokens.Float;
switch (rv.ReturnType)
{
case SimplificationReturnValue.ReturnTypes.Integer:
token.TokenValue = Math.Sqrt(rv.IntValue).ToString();
break;
case SimplificationReturnValue.ReturnTypes.Float:
token.TokenValue = Math.Sqrt(rv.DoubleValue).ToString();
break;
}
}
if (token.TokenName == TokenParser.Tokens.Sin)
{
string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3);
SimplificationReturnValue rv =
EvaluateExpression(new NumberClass
{
Expression = expression,
NumberType = NumberClass.NumberTypes.Expression
});
token.TokenName = TokenParser.Tokens.Float;
switch (rv.ReturnType)
{
case SimplificationReturnValue.ReturnTypes.Integer:
token.TokenValue = Math.Sin(rv.IntValue).ToString();
break;
case SimplificationReturnValue.ReturnTypes.Float:
token.TokenValue = Math.Sin(rv.DoubleValue).ToString();
break;
}
}
if (token.TokenName == TokenParser.Tokens.Log)
{
string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3);
SimplificationReturnValue rv =
EvaluateExpression(new NumberClass
{
Expression = expression,
NumberType = NumberClass.NumberTypes.Expression
});
token.TokenName = TokenParser.Tokens.Float;
switch (rv.ReturnType)
{
case SimplificationReturnValue.ReturnTypes.Integer:
token.TokenValue = Math.Log(rv.IntValue, 10).ToString();
break;
case SimplificationReturnValue.ReturnTypes.Float:
token.TokenValue = Math.Log(rv.DoubleValue, 10).ToString();
break;
}
}
if (token.TokenName == TokenParser.Tokens.LogN)
{
string expression = token.TokenValue.Substring(4, token.TokenValue.Length - 4);
SimplificationReturnValue rv =
EvaluateExpression(new NumberClass
{
Expression = expression,
NumberType = NumberClass.NumberTypes.Expression
});
token.TokenName = TokenParser.Tokens.Float;
switch (rv.ReturnType)
{
case SimplificationReturnValue.ReturnTypes.Integer:
token.TokenValue = Math.Log(rv.IntValue).ToString();
break;
case SimplificationReturnValue.ReturnTypes.Float:
token.TokenValue = Math.Log(rv.DoubleValue).ToString();
break;
}
}
if (token.TokenName == TokenParser.Tokens.Tan)
{
string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3);
var rv =
EvaluateExpression(new NumberClass
{
Expression = expression,
NumberType = NumberClass.NumberTypes.Expression
});
token.TokenName = TokenParser.Tokens.Float;
switch (rv.ReturnType)
{
case SimplificationReturnValue.ReturnTypes.Integer:
token.TokenValue = Math.Tan(rv.IntValue).ToString();
break;
case SimplificationReturnValue.ReturnTypes.Float:
token.TokenValue = Math.Tan(rv.DoubleValue).ToString();
break;
}
}
if (token.TokenName == TokenParser.Tokens.Abs)
{
string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3);
var rv =
EvaluateExpression(new NumberClass
{
Expression = expression,
NumberType = NumberClass.NumberTypes.Expression
});
token.TokenName = TokenParser.Tokens.Float;
switch (rv.ReturnType)
{
case SimplificationReturnValue.ReturnTypes.Integer:
token.TokenValue = Math.Abs(rv.IntValue).ToString();
break;
case SimplificationReturnValue.ReturnTypes.Float:
token.TokenValue = Math.Abs(rv.DoubleValue).ToString();
break;
}
}
if (token.TokenName == TokenParser.Tokens.Cos)
{
string expression = token.TokenValue.Substring(3, token.TokenValue.Length - 3);
var rv =
EvaluateExpression(new NumberClass
{
Expression = expression,
NumberType = NumberClass.NumberTypes.Expression
});
token.TokenName = TokenParser.Tokens.Float;
switch (rv.ReturnType)
{
case SimplificationReturnValue.ReturnTypes.Integer:
token.TokenValue = Math.Cos(rv.IntValue).ToString();
break;
case SimplificationReturnValue.ReturnTypes.Float:
token.TokenValue = Math.Cos(rv.DoubleValue).ToString();
break;
}
}
if ((int)token.TokenName >= 100)
{
int ndx1 = token.TokenValue.IndexOf("(");
string fn = token.TokenValue.Substring(0, ndx1);
string origExpression = token.TokenValue.Substring(ndx1);
string[] expressions = origExpression.Replace(",", "),(").Split(',');
bool found = false;
foreach(var _f in _customFunctions)
{
if(_f.Key.Equals(fn))
{
found = true;
break;
}
}
if (found)
{
foreach (var ff in _customFunctions)
{
if (ff.Key.Equals(fn))
{
var p = new Parser();
foreach (var cfr in _customFunctions)
p.AddCustomFunction(cfr.Key, cfr.Value);
foreach (var vr in _variables)
p.AddVariable(vr.Key, vr.Value);
foreach (var vf in _functions)
p.AddFunction(vf.Name, vf.Arguments, vf.Expression);
var ex = new SimplificationReturnValue[expressions.Length];
for(var i = 0; i < expressions.Length; i++)
{
ex[i] = p.Simplify(expressions[i]);
}
object funcRetval = null;
if (ff.Value.Method.ReturnType == typeof(int))
{
var intParams = new object[ex.Length];
int ndx = 0;
foreach (var pp in ex)
{
if (pp.ReturnType == SimplificationReturnValue.ReturnTypes.Float)
intParams[ndx] = (int)pp.DoubleValue;
if (pp.ReturnType == SimplificationReturnValue.ReturnTypes.Integer)
intParams[ndx] = pp.IntValue;
ndx++;
}
funcRetval = ff.Value.DynamicInvoke(intParams);
}
if (ff.Value.Method.ReturnType == typeof(double))
{
var floatParams = new object[ex.Length];
int ndx = 0;
foreach (var pp in ex)
{
if (pp.ReturnType == SimplificationReturnValue.ReturnTypes.Float)
floatParams[ndx] = pp.DoubleValue;
if (pp.ReturnType == SimplificationReturnValue.ReturnTypes.Integer)
floatParams[ndx] = pp.IntValue;
ndx++;
}
funcRetval = ff.Value.DynamicInvoke(floatParams);
}
if (ff.Value.Method.ReturnType==typeof(object))
{
var ex2 = new SimplificationReturnValue[expressions.Length];
for(var i = 0; i < ex2.Length; i++)
ex2[i] = p.Simplify(expressions[i]);
funcRetval = ff.Value.DynamicInvoke(ex2);
}
//object funcRetval = ff.Value.DynamicInvoke(expressions.Select(p.Simplify).ToArray());
if (funcRetval is double)
{
token.TokenValue = ((double)funcRetval).ToString();
token.TokenName = TokenParser.Tokens.Float;
}
if (funcRetval is int)
{
token.TokenValue = ((int)funcRetval).ToString();
token.TokenName = TokenParser.Tokens.Integer;
}
if (funcRetval is SimplificationReturnValue)
{
var srv = (SimplificationReturnValue)funcRetval;
if (srv.ReturnType == SimplificationReturnValue.ReturnTypes.Integer)
{
token.TokenValue = srv.IntValue.ToString();
token.TokenName = TokenParser.Tokens.Integer;
}
if (srv.ReturnType == SimplificationReturnValue.ReturnTypes.Float)
{
token.TokenValue = srv.DoubleValue.ToString();
token.TokenName = TokenParser.Tokens.Float;
}
}
break;
}
}
}
if (!found)
{
throw new NoSuchFunctionException(StringResources.No_such_function_defined + ": " + fn);
}
}
if (token.TokenName == TokenParser.Tokens.Function)
{
int ndx1 = token.TokenValue.IndexOf("(");
string fn = token.TokenValue.Substring(0, ndx1).Remove(0, 4);
string origExpression = token.TokenValue.Substring(ndx1);
string[] expressions = origExpression.Replace(",", "),(").Split(',');
bool found = false;
FunctionClass fun = null;
foreach(var _f in _functions)
{
if(_f.Name.Equals(fn))
{
found = true;
break;
}
}
if (found)
{
foreach (var ff in _functions)
if (ff.Name.Equals(fn))
fun = ff;
}
if (!found)
{
throw new NoSuchFunctionException(StringResources.No_such_function_defined + ": " + fn);
}
var parser = new Parser();
foreach (var cfh in _customFunctions)
parser.AddCustomFunction(cfh.Key, cfh.Value);
foreach (var v in _variables)
{
if (v.Value.NumberType == NumberClass.NumberTypes.Float)
{
parser.AddVariable(v.Key, v.Value.FloatNumber);
}
if (v.Value.NumberType == NumberClass.NumberTypes.Integer)
{
parser.AddVariable(v.Key, v.Value.IntNumber);
}
if (v.Value.NumberType == NumberClass.NumberTypes.Expression)
{
parser.AddVariable(v.Key, v.Value.Expression);
}
}
foreach (var f in _functions)
{
parser.AddFunction(f.Name, f.Arguments, f.Expression);
}
var expressionList = new List<NumberClass>();
foreach (var expression in expressions)
{
SimplificationReturnValue simRetval = parser.Simplify(expression);
var numClass = new NumberClass();
if (simRetval.ReturnType == SimplificationReturnValue.ReturnTypes.Float)
{
numClass.FloatNumber = simRetval.DoubleValue;
numClass.NumberType = NumberClass.NumberTypes.Float;
}
if (simRetval.ReturnType == SimplificationReturnValue.ReturnTypes.Integer)
{
numClass.IntNumber = simRetval.IntValue;
numClass.NumberType = NumberClass.NumberTypes.Integer;
}
expressionList.Add(numClass);
}
if (fun != null)
{
var numClass = new NumberClass { NumberType = NumberClass.NumberTypes.Expression, Expression = fun.Expression };
SimplificationReturnValue sretval = parser.EvaluateFunction(numClass, fun, expressionList);
if (sretval != null && sretval.ReturnType == SimplificationReturnValue.ReturnTypes.Integer)
{
token.TokenName = TokenParser.Tokens.Integer;
token.TokenValue = sretval.IntValue.ToString();
}
if (sretval != null && sretval.ReturnType == SimplificationReturnValue.ReturnTypes.Float)
{
token.TokenName = TokenParser.Tokens.Float;
token.TokenValue = sretval.DoubleValue.ToString();
}
}
}
if (token.TokenName == TokenParser.Tokens.Variable)
{
if (_variables.ContainsKey(token.TokenValue))
{
var z = _variables[token.TokenValue];
if (z.NumberType == NumberClass.NumberTypes.Float)
{
token.TokenName = TokenParser.Tokens.Float;
token.TokenValue = z.FloatNumber.ToString();
}
else if (z.NumberType == NumberClass.NumberTypes.Integer)
{
token.TokenName = TokenParser.Tokens.Integer;
token.TokenValue = z.IntNumber.ToString();
}
}
else
{
throw new NoSuchVariableException(StringResources.Undefined_Variable + ": " + token.TokenValue);
}
}
if (token.TokenName == TokenParser.Tokens.Whitespace || token.TokenName == TokenParser.Tokens.Newline)
{
token = tp.GetToken();
continue;
}
if (token.TokenName == TokenParser.Tokens.Integer || token.TokenName == TokenParser.Tokens.Float)
{
var nc = new NumberClass();
switch (token.TokenName)
{
case TokenParser.Tokens.Float:
nc.NumberType = NumberClass.NumberTypes.Float;
nc.FloatNumber = double.Parse(token.TokenValue);
break;
case TokenParser.Tokens.Integer:
nc.NumberType = NumberClass.NumberTypes.Integer;
nc.IntNumber = int.Parse(token.TokenValue);
break;
}
_outputQueue.Enqueue(nc);
}
if (IsOperator(token.TokenName))
{
if (_operatorStack.Count > 0)
{
while (_operatorStack.Count > 0)
{
var op = _operatorStack.Peek(); //o2
if (op == "(" || op == ")")
break;
if ((GetPrecedence(token.TokenName) <= GetPrecedence(op) &&
IsLeftAssociative(token.TokenValue)) ||
!IsLeftAssociative(token.TokenValue) &&
GetPrecedence(token.TokenName) < GetPrecedence(op))
{
op = _operatorStack.Pop();
var nc = new NumberClass { NumberType = NumberClass.NumberTypes.Operator, Operator = op };
_outputQueue.Enqueue(nc);
}
else break;
}
}
_operatorStack.Push(token.TokenValue);
}
if (token.TokenName == TokenParser.Tokens.Lparen)
_operatorStack.Push(token.TokenValue);
if (token.TokenName == TokenParser.Tokens.Rparen)
{
if (_operatorStack.Count > 0)
{
var op = _operatorStack.Pop();
while (op != "(")
{
var nc = new NumberClass { Operator = op, NumberType = NumberClass.NumberTypes.Operator };
_outputQueue.Enqueue(nc);
if (_operatorStack.Count > 0)
op = _operatorStack.Pop();
else
{
throw new MismatchedParenthesisException();
}
}
}
else
{
throw new MismatchedParenthesisException();
}
}
token = tp.GetToken();
}
while (_operatorStack.Count > 0)
{
var op = _operatorStack.Pop();
if (op == "(" || op == ")")
{
throw new MismatchedParenthesisException();
}
var nc = new NumberClass { NumberType = NumberClass.NumberTypes.Operator, Operator = op };
_outputQueue.Enqueue(nc);
}
bool floatAnswer = false;
bool slashAnswer = false;
foreach(var v in _outputQueue)
{
if(v.NumberType == NumberClass.NumberTypes.Float)
{
floatAnswer = true;
}
if(v.Operator == "/")
{
slashAnswer = true;
}
}
if (floatAnswer || slashAnswer)
{
var dblStack = new Stack<double>();
foreach (var nc in _outputQueue)
{
if (nc.NumberType == NumberClass.NumberTypes.Integer)
dblStack.Push(nc.IntNumber);
if (nc.NumberType == NumberClass.NumberTypes.Float)
dblStack.Push(nc.FloatNumber);
if (nc.NumberType == NumberClass.NumberTypes.Operator)
{
double val = DoMath(nc.Operator, dblStack.Pop(), dblStack.Pop());
dblStack.Push(val);
}
}
if (dblStack.Count == 0)
throw new CouldNotParseExpressionException();
retval.DoubleValue = dblStack.Pop();
retval.ReturnType = SimplificationReturnValue.ReturnTypes.Float;
}
else
{
var intStack = new Stack<int>();
foreach (var nc in _outputQueue)
{
if (nc.NumberType == NumberClass.NumberTypes.Integer)
intStack.Push(nc.IntNumber);
if (nc.NumberType == NumberClass.NumberTypes.Float)
intStack.Push((int)nc.FloatNumber);
if (nc.NumberType == NumberClass.NumberTypes.Operator)
{
int val = DoMath(nc.Operator, intStack.Pop(), intStack.Pop());
intStack.Push(val);
}
}
if (intStack.Count == 0)
throw new CouldNotParseExpressionException();
retval.IntValue = intStack.Pop();
retval.ReturnType = SimplificationReturnValue.ReturnTypes.Integer;
}
return retval;
}