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 the given ExpressionValue and returns the result in MathPiper syntax. * * @param resolveVariables: states whether variables from the GeoGebra kernel should be used. Note * that this changes the given ExpressionValue. */ public synchronized String toMaximaString(ValidExpression ve, boolean resolveVariables) { // resolve global variables if (resolveVariables) { casParser.resolveVariablesForCAS(ve); } // convert to Maxima String String MaximaStr = doToMaximaString(ve, resolveVariables); // handle assignments String veLabel = ve.getLabel(); if (veLabel != null) { StringBuilder sb = new StringBuilder(); if (ve instanceof FunctionNVar) { // function, e.g. f(x) := 2*x FunctionNVar fun = (FunctionNVar) ve; sb.append(veLabel); sb.append("("); sb.append(fun.getVarString()); sb.append(") := "); // evaluate right hand side: // import for e.g. g(x) := Eval(D(x) x^2) // sb.append("Eval("); sb.append(MaximaStr); // sb.append(")"); MaximaStr = sb.toString(); } else { // assignment, e.g. a := 5 MaximaStr = veLabel + " := " + MaximaStr; } } // TODO: remove // System.out.println("CASmaxima.toMaxima: " + MaximaStr); return MaximaStr; }
public GeoElement[] processExpressionNode(ExpressionNode n) throws MyError { // command is leaf: process command if (n.isLeaf()) { ExpressionValue leaf = n.getLeft(); if (leaf instanceof Command) { Command c = (Command) leaf; c.setLabels(n.getLabels()); return cmdDispatcher.processCommand(c, true); } else if (leaf instanceof Equation) { Equation eqn = (Equation) leaf; eqn.setLabels(n.getLabels()); return processEquation(eqn); } else if (leaf instanceof Function) { Function fun = (Function) leaf; fun.setLabels(n.getLabels()); return processFunction(n, fun); } else if (leaf instanceof FunctionNVar) { FunctionNVar fun = (FunctionNVar) leaf; fun.setLabels(n.getLabels()); return processFunctionNVar(n, fun); } } // ELSE: resolve variables and evaluate expressionnode n.resolveVariables(); eval = n.evaluate(); boolean dollarLabelFound = false; ExpressionNode myNode = n; if (myNode.isLeaf()) myNode = myNode.getLeftTree(); // leaf (no new label specified): just return the existing GeoElement if (eval.isGeoElement() && n.getLabel() == null && !(n.operation.equals(Operation.ELEMENT_OF))) { // take care of spreadsheet $ names: don't loose the wrapper ExpressionNode here // check if we have a Variable switch (myNode.getOperation()) { case $VAR_COL: case $VAR_ROW: case $VAR_ROW_COL: // don't do anything here: we need to keep the wrapper ExpressionNode // and must not return the GeoElement here dollarLabelFound = true; break; default: // return the GeoElement GeoElement[] ret = {(GeoElement) eval}; return ret; } } if (eval.isBooleanValue()) return processBoolean(n, eval); else if (eval.isNumberValue()) return processNumber(n, eval); else if (eval.isVectorValue()) return processPointVector(n, eval); else if (eval.isVector3DValue()) return processPointVector3D(n, eval); else if (eval.isTextValue()) return processText(n, eval); else if (eval instanceof MyList) { return processList(n, (MyList) eval); } else if (eval instanceof Function) { return processFunction(n, (Function) eval); } else if (eval instanceof FunctionNVar) { return processFunctionNVar(n, (FunctionNVar) eval); } // we have to process list in case list=matrix1(1), but not when list=list2 else if (eval instanceof GeoList && myNode.hasOperations()) { Application.debug("should work"); return processList(n, ((GeoList) eval).getMyList()); } else if (eval.isGeoElement()) { // e.g. B1 = A1 where A1 is a GeoElement and B1 does not exist yet // create a copy of A1 if (n.getLabel() != null || dollarLabelFound) { return processGeoCopy(n.getLabel(), n); } } // REMOVED due to issue 131: http://code.google.com/p/geogebra/issues/detail?id=131 // // expressions like 2 a (where a:x + y = 1) // // A1=b doesn't work for these objects // else if (eval instanceof GeoLine) { // if (((GeoLine)eval).getParentAlgorithm() instanceof AlgoDependentLine) { // GeoElement[] ret = {(GeoElement) eval }; // return ret; // } // // } // if we get here, nothing worked Application.debug("Unhandled ExpressionNode: " + eval + ", " + eval.getClass()); return null; }
/** * 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; }