From b453ec0047b5a87e36098b3519e085f03d917d81 Mon Sep 17 00:00:00 2001 From: Ben Culkin Date: Sat, 28 Mar 2020 12:02:32 -0400 Subject: Add DualExprParser This class parses DualExprs from prefix expressions --- .../main/java/bjc/utils/math/DualExprParser.java | 200 +++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 base/src/main/java/bjc/utils/math/DualExprParser.java (limited to 'base/src/main/java/bjc/utils/math/DualExprParser.java') diff --git a/base/src/main/java/bjc/utils/math/DualExprParser.java b/base/src/main/java/bjc/utils/math/DualExprParser.java new file mode 100644 index 0000000..71d62c7 --- /dev/null +++ b/base/src/main/java/bjc/utils/math/DualExprParser.java @@ -0,0 +1,200 @@ +/** + * + */ +package bjc.utils.math; + +import java.util.HashMap; +import java.util.Map; + +import bjc.utils.esodata.SimpleStack; +import bjc.utils.esodata.Stack; +import bjc.utils.esodata.Stack.StackUnderflowException; +import bjc.utils.exceptions.InvalidToken; +import bjc.utils.exceptions.NonConstantPower; +import bjc.utils.exceptions.OperandsRemaining; +import bjc.utils.math.DualExpr.ExprType; + +/** + * Create DualExprs from strings. + * + * @author Ben Culkin + * + */ +public class DualExprParser { + public static class Result { + public DualExpr expr; + public Map varMap; + + public Result() { + this.varMap = new HashMap<>(); + } + } + + /** + * Parses a dual expression from a postfix expression string. + * + * @param expr The string to parse the dual expression from. + * + * @param preVars Any pre-existing variables to use. + * + * @return Both the parsed expression, and a map of all the variables used + */ + public static Result parseExpression(String expr) { + return parseExpression(expr, null); + } + + /** + * Parses a dual expression from a postfix expression string. + * + * @param expr The string to parse the dual expression from. + * + * @param preVars Any pre-existing variables to use. + * + * @return Both the parsed expression, and a map of all the variables used + * + * @throws StackUnderflowException If the expression is not properly formatted. + */ + public static Result parseExpression(String expr, Map preVars) { + Result res = new Result(); + + if (preVars == null) { + } else { + res.varMap = preVars; + } + + Map vars = res.varMap; + + String[] tokens = expr.split(" "); + + Stack exprStack = new SimpleStack<>(); + + for (int idx = 0; idx < tokens.length; idx++) { + String token = tokens[idx]; + + switch (token) { + case "add": + case "+": { + DualExpr rhs = exprStack.pop(); + DualExpr lhs = exprStack.pop(); + + exprStack.push(new DualExpr(ExprType.ADDITION, lhs, rhs)); + break; + } + case "subtract": + case "-": { + DualExpr rhs = exprStack.pop(); + DualExpr lhs = exprStack.pop(); + + exprStack.push(new DualExpr(ExprType.SUBTRACTION, lhs, rhs)); + break; + } + case "multiply": + case "*": { + DualExpr rhs = exprStack.pop(); + DualExpr lhs = exprStack.pop(); + + exprStack.push(new DualExpr(ExprType.MULTIPLICATION, lhs, rhs)); + break; + } + case "divide": + case "/": { + DualExpr rhs = exprStack.pop(); + DualExpr lhs = exprStack.pop(); + + exprStack.push(new DualExpr(ExprType.DIVISION, lhs, rhs)); + break; + } + case "abs": { + DualExpr opr = exprStack.pop(); + + exprStack.push(new DualExpr(ExprType.ABSOLUTE, opr)); + break; + } + case "log": { + DualExpr opr = exprStack.pop(); + + exprStack.push(new DualExpr(ExprType.LOGARITHM, opr)); + break; + } + case "sin": { + DualExpr opr = exprStack.pop(); + + exprStack.push(new DualExpr(ExprType.SIN, opr)); + break; + } + case "cos": { + DualExpr opr = exprStack.pop(); + + exprStack.push(new DualExpr(ExprType.COS, opr)); + break; + } + case "exp": { + DualExpr opr = exprStack.pop(); + + exprStack.push(new DualExpr(ExprType.EXPONENTIAL, opr)); + break; + } + case "pow": { + DualExpr pow = exprStack.pop(); + DualExpr bod = exprStack.pop(); + + { + Dual val = pow.number; + if (val.dual != 0) + throw new NonConstantPower(); + } + + exprStack.push(new DualExpr(ExprType.POWER, bod, pow)); + break; + } + case "eval": { + DualExpr exp = exprStack.pop(); + + exprStack.push(new DualExpr(exp.evaluate())); + break; + } + case "dual": { + DualExpr dual = exprStack.pop(); + DualExpr real = exprStack.pop(); + + exprStack.push(new DualExpr(new Dual(real.evaluate().real, dual.evaluate().real))); + break; + } + default: + if (token.matches("[a-zA-Z][a-zA-Z0-9]*")) { + if (vars.containsKey(token)) { + exprStack.push(vars.get(token)); + } else { + Dual var = new Dual(); + DualExpr varExpr = new DualExpr(var); + + vars.put(token, varExpr); + + exprStack.push(varExpr); + } + } else { + try { + double d = Double.parseDouble(token); + + exprStack.push(new DualExpr(new Dual(d))); + } catch (NumberFormatException nfex) { + throw new InvalidToken(token); + } + } + + break; + } + } + + if (res.expr == null) { + res.expr = exprStack.pop(); + } + + if (exprStack.size() > 0) + throw new OperandsRemaining(String.format( + "After processing expression, not all values had been consumed.\n\tRemaining values are '%s'", + exprStack.toString())); + + return res; + } +} \ No newline at end of file -- cgit v1.2.3