public GeoElement[] processFunctionNVar(ExpressionNode funNode, FunctionNVar fun) { fun.initFunction(); String label = fun.getLabel(); GeoElement[] ret = new GeoElement[1]; GeoElement[] vars = fun.getGeoElementVariables(); boolean isIndependent = (vars == null || vars.length == 0); if (isIndependent) { ret[0] = kernel.FunctionNVar(label, fun); } else { ret[0] = kernel.DependentFunctionNVar(label, fun); } return ret; }
/** * Evaluates this function using the given CAS command. Caching is used for symbolic CAS * evaluations. * * @param ggbCasCmd the GeoGebraCAS command needs to include % in all places where the function f * should be substituted, e.g. "Derivative(%,x)" * @param symbolic true for symbolic evaluation, false to use values of GeoElement variables * @return resulting function */ public final FunctionNVar evalCasCommand(String ggbCasCmd, boolean symbolic) { // remember expression and its CAS string boolean useCaching = true; // for multi-variate functions we need to ensure value form, // i.e. f(x,m)=x^2+m, g(x)=f(x,2), Derivative[g] gets sent as Derivative[x^2+2] instead of // Derivative[f(x,2)] // see http://www.geogebra.org/trac/ticket/1466 symbolic = symbolic && !expression.containsObjectType(GeoFunctionNVar.class); // make sure to use temporary variable names // e.g. a in Derivative[a*x^2,x] needs to be renamed temporarily when a exists in GeoGebra // see http://www.geogebra.org/trac/ticket/929 boolean oldTempVariableValue = kernel.isUseTempVariablePrefix(); kernel.setUseTempVariablePrefix(true); // did expression change since last time? if (casEvalExpression != expression) { casEvalExpression = expression; if (symbolic) { casEvalStringSymbolic = expression.getCASstring(ExpressionNode.STRING_TYPE_GEOGEBRA, true); } // caching should only be done if the expression doesn't contain // other functions // e.g. this is important for f(x) = x^2, g(x,y) = f(x) + y, // Derivative(g(x,y), x) // where we cannot cache the derivative of g because g may have // changed useCaching = symbolic && !expression.containsObjectType(CasEvaluableFunction.class); } // build command string for CAS String expString = symbolic ? casEvalStringSymbolic : expression.getCASstring(ExpressionNode.STRING_TYPE_GEOGEBRA, false); // set back kernel kernel.setUseTempVariablePrefix(oldTempVariableValue); // substitute % by expString in ggbCasCmd String casString = ggbCasCmd.replaceAll("%", expString); FunctionNVar resultFun = null; // eval with CAS try { if (useCaching) { // check if result is in cache resultFun = lookupCasEvalMap(casString); if (resultFun != null) { // System.out.println("caching worked: " + casString + " -> " + resultFun); return resultFun; } } // evaluate expression by CAS String result = symbolic ? kernel.evaluateGeoGebraCAS(casString) : // symbolic kernel.evaluateCachedGeoGebraCAS(casString); // value string // System.out.println("evaluateGeoGebraCAS: " + casString + " -> " + result); // parse CAS result back into GeoGebra sb.setLength(0); sb.append("f("); // this name is never used, just needed for parsing sb.append(getVarString()); sb.append(") = "); sb.append(result); // parse result if (getVarNumber() == 1) { resultFun = kernel.getParser().parseFunction(sb.toString()); } else { resultFun = kernel.getParser().parseFunctionNVar(sb.toString()); } resultFun.initFunction(); } catch (Error err) { err.printStackTrace(); resultFun = null; } catch (Exception e) { e.printStackTrace(); resultFun = null; } catch (Throwable e) { resultFun = null; } // cache result if (useCaching && resultFun != null) { getCasEvalMap().put(casString, resultFun); } // System.out.println("NO caching: " + casString + " -> " + resultFun); return resultFun; }