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;
  }
Beispiel #4
0
  /**
   * 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;
  }