SymbolicDifferentiation.java 3.21 KB
/** 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(" ", "")));
        }

    }
}