mirror of
https://github.com/0xJ1M/MathsEngine.git
synced 2026-06-05 01:00:06 +00:00
Refactor
This commit is contained in:
74
MathEngine/MathEngine/Evaluator/Evaluator.cs
Normal file
74
MathEngine/MathEngine/Evaluator/Evaluator.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using MathEngine.Parser.Parser;
|
||||
using MathEngine.Parser.Tokeniser;
|
||||
|
||||
namespace MathEngine.Parser.Evaluator
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal class Evaluator
|
||||
{
|
||||
public static TreeNode? Evaluate(TreeNode rootNode)
|
||||
{
|
||||
if (rootNode == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else // To evaluate we go anti-clockwise around the tree
|
||||
{
|
||||
TreeNode? Root, LeftBranch, RightBranch;
|
||||
if (rootNode.NodeValue.Token_Type == Token.Type.Numeric)
|
||||
return rootNode;
|
||||
else
|
||||
{ //For now these can't be null, this will need to be updated in the future
|
||||
LeftBranch = Evaluate_Tree_Branch(rootNode.GetChildNode(0));
|
||||
RightBranch = Evaluate_Tree_Branch(rootNode.GetChildNode(1));
|
||||
Root = Evaluate_Operator(rootNode.NodeValue, LeftBranch, RightBranch);
|
||||
return Root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates branches of a given tree
|
||||
/// </summary>
|
||||
/// <param name="Branch">The TreeNode branch to evaluate</param>
|
||||
/// <returns>Returns the Evaluation of the Branch</returns>
|
||||
private static TreeNode Evaluate_Tree_Branch(TreeNode Branch)
|
||||
{
|
||||
TreeNode Root, LeftBranch, RightBranch;
|
||||
if (Branch.NodeValue.Token_Type == Token.Type.Numeric)
|
||||
return Branch;
|
||||
else
|
||||
{
|
||||
LeftBranch = Evaluate_Tree_Branch(Branch.GetChildNode(0));
|
||||
RightBranch = Evaluate_Tree_Branch(Branch.GetChildNode(1));
|
||||
// We finally combine the computed branches with the operator that links them and return the result
|
||||
Root = Evaluate_Operator(Branch.NodeValue, LeftBranch, RightBranch);
|
||||
return Root;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evlautes a binary node where the root node is an operator and given two branches the left and the right
|
||||
/// </summary>
|
||||
/// <param name="Operator_Token"></param>
|
||||
/// <param name="Left_Branch"></param>
|
||||
/// <param name="Right_Branch"></param>
|
||||
/// <returns>Returns the evaluated value of the operator as a TreeNode</returns>
|
||||
private static TreeNode Evaluate_Operator(Token Operator_Token, TreeNode Left_Branch, TreeNode Right_Branch)
|
||||
{
|
||||
decimal lhs = decimal.Parse(Left_Branch.NodeValue.TokenValue);
|
||||
decimal rhs = decimal.Parse(Right_Branch.NodeValue.TokenValue);
|
||||
return Operator_Token.Token_Type switch
|
||||
{
|
||||
Token.Type.Addition => new TreeNode(new Token((lhs + rhs).ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0)),
|
||||
Token.Type.Subtraction => new TreeNode(new Token((lhs - rhs).ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0)),
|
||||
Token.Type.Multiplication => new TreeNode(new Token(((decimal)(lhs * rhs)).ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0)),
|
||||
Token.Type.Division => new TreeNode(new Token(((decimal)(lhs / rhs)).ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0)),
|
||||
_ => throw new Exception("Potentially invalid token?"),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using MathEngine.Parser.Tokeniser;
|
||||
using MathEngine.Parser.Tokeniser;
|
||||
namespace MathEngine.Parser.Parser
|
||||
{
|
||||
/// <summary>
|
||||
@@ -11,6 +10,7 @@ namespace MathEngine.Parser.Parser
|
||||
/// The root node of the expression tree;
|
||||
/// </summary>
|
||||
private readonly TreeNode rootNode;
|
||||
private TreeNode? evaluated_expression;
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new instance of the MathEngine.Parser.Parser.Node class with a given Token
|
||||
@@ -21,7 +21,7 @@ namespace MathEngine.Parser.Parser
|
||||
{
|
||||
List<Token> tokens = Tokeniser.Tokeniser.Tokenise(Expression);
|
||||
Stack<Token> rpnForm = Parser.Parse(tokens);
|
||||
rootNode = GenerateExpressionTree(rpnForm);
|
||||
rootNode = TreeGenerator.TreeFromRPN(rpnForm);
|
||||
}
|
||||
|
||||
private ExpressionTree(TreeNode rootNode)
|
||||
@@ -29,141 +29,13 @@ namespace MathEngine.Parser.Parser
|
||||
this.rootNode = rootNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a binary TreeNode, that is a node with a root value and two children
|
||||
/// </summary>
|
||||
/// <param name="CurrentToken">The token to be the root node of the TreeNode</param>
|
||||
/// <param name="LeftToken">TreeNode that is the left branch of the current node</param>
|
||||
/// <param name="RightToken">TreeNode that is the right branch of the current node</param>
|
||||
/// <returns>A TreeNode with CurrentToken as the root value and LeftBranch and RightBranch as Children</returns>
|
||||
private static TreeNode CreateBinaryNode(Token CurrentToken, TreeNode LeftBranch, TreeNode RightBranch)
|
||||
{
|
||||
TreeNode root = new(CurrentToken);
|
||||
root.AddChildNode(LeftBranch);
|
||||
root.AddChildNode(RightBranch);
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a unary TreeNode, that is a node with a root value and two children
|
||||
/// </summary>
|
||||
/// <param name="CurrentToken">The token to be the root node of the TreeNode</param>
|
||||
/// <param name="LeftToken">TreeNode that is the child of the current node</param>
|
||||
/// <returns>A TreeNode with CurrentToken as the root value and ChildNode as the sole child node</returns>
|
||||
private static TreeNode CreateUnaryNode(Token CurrentToken, TreeNode ChildNode)
|
||||
{
|
||||
TreeNode root = new(CurrentToken);
|
||||
root.AddChildNode(ChildNode);
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the full expression tree given an RPN expression stack
|
||||
/// </summary>
|
||||
/// <param name="rpnExpression">RPN expression stack to generate an expression tree from</param>
|
||||
/// <returns>An expression Tree that represents the Mathematical expression given by rpnExpression</returns>
|
||||
private static TreeNode GenerateExpressionTree(Stack<Token> rpnExpression)
|
||||
{
|
||||
Stack<TreeNode> OutputStack = new(rpnExpression.Count);
|
||||
TreeNode Node;
|
||||
Token CurrentToken;
|
||||
while (rpnExpression.Count != 0)
|
||||
{
|
||||
CurrentToken = rpnExpression.Pop();
|
||||
switch (CurrentToken.Token_Type)
|
||||
{
|
||||
case Token.Type.Numeric:
|
||||
Node = new TreeNode(CurrentToken);
|
||||
OutputStack.Push(Node);
|
||||
break;
|
||||
// We need to preserve "Left handness" of the ExpressionTree
|
||||
// i.e 7/8 gives a root node of / with Cnode(0) = 7 and Cnod(1) = 8 etc.
|
||||
// This should preserve non commutativity
|
||||
case Token.Type.Addition:
|
||||
case Token.Type.Subtraction:
|
||||
case Token.Type.Multiplication:
|
||||
case Token.Type.Division:
|
||||
case Token.Type.Exponentiation:
|
||||
TreeNode Right = OutputStack.Pop();
|
||||
TreeNode Left = OutputStack.Pop();
|
||||
Node = CreateBinaryNode(CurrentToken, Left, Right);
|
||||
OutputStack.Push(Node);
|
||||
break;
|
||||
case Token.Type.UnaryPlus:
|
||||
case Token.Type.UnaryMinus:
|
||||
Node = CreateUnaryNode(CurrentToken, OutputStack.Pop());
|
||||
OutputStack.Push(Node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return OutputStack.Pop();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates branches of a given tree
|
||||
/// </summary>
|
||||
/// <param name="Branch">The TreeNode branch to evaluate</param>
|
||||
/// <returns>Returns the Evaluation of the Branch</returns>
|
||||
private static TreeNode Evaluate_Tree_Branch(TreeNode Branch)
|
||||
{
|
||||
TreeNode Root, LeftBranch, RightBranch;
|
||||
if (Branch.NodeValue.Token_Type == Token.Type.Numeric)
|
||||
return Branch;
|
||||
else
|
||||
{
|
||||
LeftBranch = Evaluate_Tree_Branch(Branch.GetChildNode(0));
|
||||
RightBranch = Evaluate_Tree_Branch(Branch.GetChildNode(1));
|
||||
// We finally combine the computed branches with the operator that links them and return the result
|
||||
Root = Evaluate_Operator(Branch.NodeValue, LeftBranch, RightBranch);
|
||||
return Root;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evlautes a binary node where the root node is an operator and given two branches the left and the right
|
||||
/// </summary>
|
||||
/// <param name="Operator_Token"></param>
|
||||
/// <param name="Left_Branch"></param>
|
||||
/// <param name="Right_Branch"></param>
|
||||
/// <returns>Returns the evaluated value of the operator as a TreeNode</returns>
|
||||
private static TreeNode Evaluate_Operator(Token Operator_Token, TreeNode Left_Branch, TreeNode Right_Branch)
|
||||
{
|
||||
decimal lhs = decimal.Parse(Left_Branch.NodeValue.TokenValue);
|
||||
decimal rhs = decimal.Parse(Right_Branch.NodeValue.TokenValue);
|
||||
return Operator_Token.Token_Type switch
|
||||
{
|
||||
Token.Type.Addition => new TreeNode(new Token((lhs + rhs).ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0)),
|
||||
Token.Type.Subtraction => new TreeNode(new Token((lhs - rhs).ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0)),
|
||||
Token.Type.Multiplication => new TreeNode(new Token(((decimal)(lhs * rhs)).ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0)),
|
||||
Token.Type.Division => new TreeNode(new Token(((decimal)(lhs / rhs)).ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0)),
|
||||
_ => throw new Exception("Potentially invalid token?"),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the current instance of ExpressionTree
|
||||
/// </summary>
|
||||
/// <returns>Returns an update of the current instance which the expression Evaluated</returns>
|
||||
public ExpressionTree? Evaluate()
|
||||
public ExpressionTree Evaluate()
|
||||
{
|
||||
if (rootNode == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else // To evaluate we go anti-clockwise around the tree
|
||||
{
|
||||
TreeNode? Root, LeftBranch, RightBranch;
|
||||
if (rootNode.NodeValue.Token_Type == Token.Type.Numeric)
|
||||
return this;
|
||||
else
|
||||
{ //For now these can't be null, this will need to be updated in the future
|
||||
LeftBranch = Evaluate_Tree_Branch(rootNode.GetChildNode(0));
|
||||
RightBranch = Evaluate_Tree_Branch(rootNode.GetChildNode(1));
|
||||
Root = Evaluate_Operator(rootNode.NodeValue, LeftBranch, RightBranch);
|
||||
return new ExpressionTree(Root);
|
||||
}
|
||||
}
|
||||
return new(Evaluator.Evaluator.Evaluate(rootNode));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
81
MathEngine/MathEngine/Parser/Parser/TreeGenerator.cs
Normal file
81
MathEngine/MathEngine/Parser/Parser/TreeGenerator.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using MathEngine.Parser.Tokeniser;
|
||||
|
||||
namespace MathEngine.Parser.Parser
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for converting from RPN form to an expression tree
|
||||
/// </summary>
|
||||
internal class TreeGenerator
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates a binary TreeNode, that is a node with a root value and two children
|
||||
/// </summary>
|
||||
/// <param name="CurrentToken">The token to be the root node of the TreeNode</param>
|
||||
/// <param name="LeftToken">TreeNode that is the left branch of the current node</param>
|
||||
/// <param name="RightToken">TreeNode that is the right branch of the current node</param>
|
||||
/// <returns>A TreeNode with CurrentToken as the root value and LeftBranch and RightBranch as Children</returns>
|
||||
private static TreeNode CreateBinaryNode(Token CurrentToken, TreeNode LeftBranch, TreeNode RightBranch)
|
||||
{
|
||||
TreeNode root = new(CurrentToken);
|
||||
root.AddChildNode(LeftBranch);
|
||||
root.AddChildNode(RightBranch);
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a unary TreeNode, that is a node with a root value and two children
|
||||
/// </summary>
|
||||
/// <param name="CurrentToken">The token to be the root node of the TreeNode</param>
|
||||
/// <param name="LeftToken">TreeNode that is the child of the current node</param>
|
||||
/// <returns>A TreeNode with CurrentToken as the root value and ChildNode as the sole child node</returns>
|
||||
private static TreeNode CreateUnaryNode(Token CurrentToken, TreeNode ChildNode)
|
||||
{
|
||||
TreeNode root = new(CurrentToken);
|
||||
root.AddChildNode(ChildNode);
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the full expression tree given an RPN expression stack
|
||||
/// </summary>
|
||||
/// <param name="rpnExpression">RPN expression stack to generate an expression tree from</param>
|
||||
/// <returns>An expression Tree that represents the Mathematical expression given by rpnExpression</returns>
|
||||
public static TreeNode TreeFromRPN(Stack<Token> rpnExpression)
|
||||
{
|
||||
Stack<TreeNode> OutputStack = new(rpnExpression.Count);
|
||||
TreeNode Node;
|
||||
Token CurrentToken;
|
||||
while (rpnExpression.Count != 0)
|
||||
{
|
||||
CurrentToken = rpnExpression.Pop();
|
||||
switch (CurrentToken.Token_Type)
|
||||
{
|
||||
case Token.Type.Numeric:
|
||||
Node = new TreeNode(CurrentToken);
|
||||
OutputStack.Push(Node);
|
||||
break;
|
||||
// We need to preserve "Left handness" of the ExpressionTree
|
||||
// i.e 7/8 gives a root node of / with Cnode(0) = 7 and Cnod(1) = 8 etc.
|
||||
// This should preserve non commutativity
|
||||
case Token.Type.Addition:
|
||||
case Token.Type.Subtraction:
|
||||
case Token.Type.Multiplication:
|
||||
case Token.Type.Division:
|
||||
case Token.Type.Exponentiation:
|
||||
TreeNode Right = OutputStack.Pop();
|
||||
TreeNode Left = OutputStack.Pop();
|
||||
Node = CreateBinaryNode(CurrentToken, Left, Right);
|
||||
OutputStack.Push(Node);
|
||||
break;
|
||||
case Token.Type.UnaryPlus:
|
||||
case Token.Type.UnaryMinus:
|
||||
Node = CreateUnaryNode(CurrentToken, OutputStack.Pop());
|
||||
OutputStack.Push(Node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return OutputStack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user