/*
GeoGebra - Dynamic Mathematics for Everyone
http://www.geogebra.org
This file is part of GeoGebra.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation.
*/
package org.geogebra.common.kernel.algos;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.arithmetic.VectorNDValue;
import org.geogebra.common.kernel.commands.Commands;
import org.geogebra.common.kernel.geos.CasEvaluableFunction;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.plugin.Operation;
/**
* Sum of functions, may take whole list or just several first elements
*/
public class AlgoFoldExpression extends AlgoElement {
@Override
public Commands getClassName() {
return op == Operation.PLUS ? Commands.Sum : Commands.Product;
}
private GeoElement expression; // input
private GeoNumeric to; // input
private GeoElement resultFun;
private Operation op;
private FoldComputer foldComputer;
private GeoNumeric from;
private GeoNumeric var;
/**
* Creates labeled function sum algo for truncated list (or whole list if
* truncate == null)
*
* @param cons
* construction
* @param label
* output label
* @param expression
* list
* @param var
* variable
* @param from
* min variable value
* @param truncate
* number of elements to take
* @param op
*/
public AlgoFoldExpression(Construction cons, String label,
GeoElement expression, GeoNumeric var, GeoNumeric from,
GeoNumeric truncate, Operation op) {
super(cons);
this.expression = expression;
this.var = var;
this.from = from;
this.to = truncate;
this.op = op;
this.foldComputer = getComputer(expression);
resultFun = foldComputer.getTemplate(cons,
expression.getGeoClassType());
if (op == Operation.MULTIPLY && resultFun instanceof VectorNDValue) {
((VectorNDValue) resultFun).setMode(Kernel.COORD_COMPLEX);
}
setInputOutput();
compute();
resultFun.setLabel(label);
}
private static FoldComputer getComputer(GeoElement expression) {
switch (expression.getGeoClassType()) {
case POINT:
case POINT3D:
case VECTOR:
case VECTOR3D:
return new PointNDFold();
case FUNCTION_NVAR:
return new FunctionNvarFold();
case FUNCTION:
return new FunctionFold();
case LIST:
return new ListFold();
}
return new NumberFold();
}
@Override
protected void setInputOutput() {
input = new GeoElement[4];
input[0] = expression;
input[1] = var;
input[2] = from;
input[3] = to;
setOutputLength(1);
setOutput(0, resultFun);
setDependencies(); // done by AlgoElement
}
/**
* Returns result
*
* @return sum of functions
*/
public GeoElement getResult() {
return resultFun;
}
@Override
public final void compute() {
// Sum[{x^2,x^3}]
var.setValue(from.getDouble());
updateLocalVar();
GeoElement fn = expression.copyInternal(cons);
if (fn instanceof CasEvaluableFunction) {
((GeoFunction) fn).replaceChildrenByValues(var);
}
foldComputer.setFrom(fn, kernel);
for (int i = (int) from.getDouble() + 1; i <= to.getDouble(); i++) {
var.setValue(i);
updateLocalVar();
fn = expression.copyInternal(cons);
if (fn instanceof CasEvaluableFunction) {
((GeoFunction) fn).replaceChildrenByValues(var);
}
foldComputer.add(fn, op);
}
foldComputer.finish();
}
private void updateLocalVar() {
// set local variable to given value
AlgoElement expressionParentAlgo = expression.getParentAlgorithm();
// update var's algorithms until we reach expression
if (expressionParentAlgo != null) {
// update all dependent algorithms of the local variable var
var.getAlgoUpdateSet().updateAllUntil(expressionParentAlgo);
this.setStopUpdateCascade(false);
expressionParentAlgo.update();
}
}
}