/** This class provides a method to compute symbolic derivatives of the * given function with respect to x. * * @author Adam Blank */ public class SymbolicDifferentiation { private static final String x = "x"; /** Checks if exp is a constant with respect to x */ public static boolean isConstant(String exp) { return EvaluatorUtilities.isNumber(exp) || exp.equals("n") || exp.equals("e"); } /** Computes the symbolic derivative of exp with respect to x */ public static String ddx(String exp) throws NotImplementedException { exp = exp.replaceAll(" ", ""); /* Remove the outermost parentheses */ if (exp.charAt(0) == '(') { exp = exp.substring(1, exp.length() - 1); } /* dx/dx = 1 */ if (exp.equals(x)) { return "1"; } /* dc/dx = 0 */ else if (EvaluatorUtilities.nextOperatorIndex(exp) == -1) { return "0"; } /* Split the string up by the op */ int opIndex = EvaluatorUtilities.nextOperatorIndex(exp); String left = exp.substring(0, opIndex); String right = exp.substring(opIndex + 1, exp.length()); char op = EvaluatorUtilities.nextOperator(exp); /* (d/dx)(f(x) + g(x)) = df/dx + dg/dx */ if (op == '+' || op == '-') { return String.format("(%s %s %s)", ddx(left), op, ddx(right)); } /* (d/dx)(f(x) * g(x)) = ((f(x) * dg/dx) + (df/dx * g(x))) */ else if (op == '*') { return String.format("((%s * %s) + (%s * %s))", left, ddx(right), right, ddx(left)); } else if (op == '^') { /* dc/dx = 0 */ if ((isConstant(left) && isConstant(right))) { return "0"; } /* (d/dx)(e^x) = e^x */ else if (left.equals("e") && right.equals(x)) { return "(e^x)"; } /* (d/dx)(x^n) = (n * (x ^ (n - 1))) */ else if (left.equals(x) && isConstant(right)) { return String.format("(%s * ((%s^(%s - 1))))", right, left, right); } /* Chain Rule: Let f(x) = x^C -> f(g(x)). * (d/dx)(f(g(x))) = ((df/dx)(g(x)) * (dg/dx)) */ else if (left.contains(x) && !right.contains(x)) { System.out.println(left + " | " + right); String df = ddx("(x^" + right + ")"); String dfOfg = df.replaceAll("x", left); return String.format("(%s * %s)", dfOfg, ddx(left)); } else { /* Note that most of the other cases are a single case that we could * write by implementing the chain rule. */ throw new NotImplementedException(); } } else { /* This would just involve implementing more rules... */ throw new NotImplementedException(); } } public static void main(String[] args) throws NotImplementedException { String[] exps = {"(2 * (x^n))", "(((2 * (x^n))*(e^x)) + (x*(2^n)))"}; for (int i = 0; i < exps.length; i++) { System.out.println("(d/dx)(" + exps[i] + ") = " + ddx(exps[i].replaceAll(" ", ""))); } } }