summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/math/DualExprParser.java
diff options
context:
space:
mode:
authorBen Culkin <scorpress@gmail.com>2020-03-28 12:02:32 -0400
committerBen Culkin <scorpress@gmail.com>2020-03-28 12:02:32 -0400
commitb453ec0047b5a87e36098b3519e085f03d917d81 (patch)
tree881e8f129d87decc34524cf467df8d743e27166b /base/src/main/java/bjc/utils/math/DualExprParser.java
parent373464d30d87bd8702fe27b920ed1406a0833ef3 (diff)
Add DualExprParser
This class parses DualExprs from prefix expressions
Diffstat (limited to 'base/src/main/java/bjc/utils/math/DualExprParser.java')
-rw-r--r--base/src/main/java/bjc/utils/math/DualExprParser.java200
1 files changed, 200 insertions, 0 deletions
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<String, DualExpr> 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<String, DualExpr> preVars) {
+ Result res = new Result();
+
+ if (preVars == null) {
+ } else {
+ res.varMap = preVars;
+ }
+
+ Map<String, DualExpr> vars = res.varMap;
+
+ String[] tokens = expr.split(" ");
+
+ Stack<DualExpr> 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