package org.geogebra.common.kernel.commands; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.algos.AlgoDependentGeoCopy; import org.geogebra.common.kernel.arithmetic.Command; import org.geogebra.common.kernel.arithmetic.FunctionVariable; import org.geogebra.common.kernel.cas.AlgoDerivative; import org.geogebra.common.kernel.geos.CasEvaluableFunction; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoFunctionNVar; import org.geogebra.common.kernel.geos.GeoNumberValue; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.kernel.kernelND.GeoElementND; import org.geogebra.common.main.MyError; /** * Derivative[ <GeoFunction> ] Derivative[ <GeoFunctionNVar>, <var> ] * Derivative[ <GeoCurveCartesian> ] */ public class CmdDerivative extends CommandProcessor { /** * Create new command processor * * @param kernel * kernel */ public CmdDerivative(Kernel kernel) { super(kernel); } @Override final public GeoElement[] process(Command c, EvalInfo info) throws MyError { int n = c.getArgumentNumber(); String label = c.getLabel(); GeoElement[] arg, arg2; switch (n) { case 1: arg = resArgs(c); if (arg[0] instanceof CasEvaluableFunction) { CasEvaluableFunction f = (CasEvaluableFunction) arg[0]; if (label == null) { label = getDerivLabel(f.toGeoElement(), 1); } GeoElement[] ret = { derivative(label, f, null, null, info) }; return ret; } throw argErr(app, c, arg[0]); case 2: boolean suppress = cons.isSuppressLabelsActive(); // we need to // reset this // later #2356 try { arg = resArgs(c); // Derivative[ f(x), 2] if ((arg[0].isGeoFunction() || arg[0].isGeoCurveCartesian()) && arg[1] instanceof GeoNumberValue) { double order = ((GeoNumberValue) arg[1]).getDouble(); // default for arg[1] not GeoNumeric (eg Segment) // don't want f''' for name boolean constant = false; if (arg[1].isGeoNumeric()) { if (arg[1].getParentAlgorithm() == null) { // Derivative[f,n] -> don't want f'' for name // Derivative[f,2] -> do want f'' for name constant = !arg[1].isLabelSet(); } else { // eg Derivative[f,n+2] -> don't want f'''' for name constant = false; } } CasEvaluableFunction f = (CasEvaluableFunction) arg[0]; if (label == null && constant) { int iorder = (int) Math.round(order); label = getDerivLabel(f.toGeoElement(), iorder); } GeoElement[] ret = { derivative(label, f, null, (GeoNumberValue) arg[1], info) }; return ret; } } catch (Throwable t) { t.printStackTrace(); } cons.setSuppressLabelCreation(suppress); // Derivative[ f(a,b), a ] try { arg2 = resArgsLocalNumVar(c, 1, 1); if (arg2[0] instanceof CasEvaluableFunction && arg2[1].isGeoNumeric()) { CasEvaluableFunction f = (CasEvaluableFunction) arg2[0]; FunctionVariable[] vars = f.getFunctionVariables(); String var = arg2[1].getLabelSimple(); // distinguish between Derivative[ f, a] and Derivative[ f, // p] for f(a,b) = a + b and slider 'p' boolean ok = false; if (vars != null) { for (int i = 0; i < vars.length; i++) { if (vars[i].getSetVarString().equals(var)) { ok = true; break; } } } if (ok) { GeoElement[] ret = { derivative(label, (CasEvaluableFunction) arg2[0], // function (GeoNumeric) arg2[1], null, info) }; // var return ret; } // else fall through } } catch (Throwable t) { t.printStackTrace(); } // Derivative[ f(x, y), x] arg = resArgs(c); if (arg[0] instanceof CasEvaluableFunction && arg[1].isGeoFunction()) { GeoNumeric var = new GeoNumeric(cons); var.setLocalVariableLabel( arg[1].toString(StringTemplate.defaultTemplate)); GeoElement[] ret = { derivative(label, (CasEvaluableFunction) arg[0], // function var, null, info) }; // var return ret; } // if we get here, the first argument must have been wrong throw argErr(app, c, arg[0]); case 3: // Derivative[ f(a,b), a, 2 ] try { arg = resArgsLocalNumVar(c, 1, 1); if (arg[0] instanceof CasEvaluableFunction && arg[1].isGeoNumeric() && arg[2] instanceof GeoNumberValue) { GeoElement[] ret = { derivative(label, (CasEvaluableFunction) arg[0], // function (GeoNumeric) arg[1], (GeoNumberValue) arg[2], info) }; // var return ret; } } catch (Throwable t) { t.printStackTrace(); } arg = resArgs(c); // Derivative[ f(x, y), x, 2] if (arg[0] instanceof GeoFunctionNVar && arg[1].isGeoFunction() && arg[2] instanceof GeoNumberValue) { GeoNumeric var = new GeoNumeric(cons); var.setLocalVariableLabel( arg[1].toString(StringTemplate.defaultTemplate)); GeoElement[] ret = { derivative(label, (GeoFunctionNVar) arg[0], // function var, (GeoNumberValue) arg[2], info) }; // var return ret; } // if we get here, the first argument must have been wrong throw argErr(app, c, arg[0]); default: throw argNumErr(app, c, n); } } /** * Returns eg f''_1' for third derivative of f when f''' is already used * * @param geo * function * @param order * derivative order * @return next free label for derivative */ static String getDerivLabel(GeoElementND geo, int order) { String label = null; if (geo.isLabelSet()) { StringBuilder labelBuilder = new StringBuilder( geo.getLabel(StringTemplate.defaultTemplate)); for (int i = 0; i < order; i++) { labelBuilder.append('\''); } label = labelBuilder.toString(); } else { if (geo.getParentAlgorithm() instanceof AlgoDependentGeoCopy) { return getDerivLabel(geo.getParentAlgorithm().getInput(0), order); } } return geo.getFreeLabel(label); } /** * Computes n-th derivative of f * * @param label * label for output * @param f * function * @param var * variable * @param n * derivative degree * @param info * evaluation flags * @return derivaive */ public GeoElement derivative(String label, CasEvaluableFunction f, GeoNumeric var, GeoNumberValue n, EvalInfo info) { AlgoDerivative algo = new AlgoDerivative(cons, label, f, var, n, info); return algo.getResult(); } }