package org.geogebra.common.kernel.statistics; import org.apache.commons.math3.linear.RealMatrix; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.algos.AlgoDependentFunction; import org.geogebra.common.kernel.arithmetic.Evaluate2Var; import org.geogebra.common.kernel.arithmetic.FunctionNVar; //import org.geogebra.common.kernel.arithmetic.FunctionalNVar; import org.geogebra.common.kernel.arithmetic.MyDouble; 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.GeoFunctionNVar; import org.geogebra.common.kernel.geos.GeoFunctionable; import org.geogebra.common.kernel.geos.GeoList; import org.geogebra.common.kernel.kernelND.GeoPointND; import org.geogebra.common.plugin.Operation; /** * Represents set of functions in linear regression. Collects functions and * builds linear combinations of them. * * @author Zbynek */ public interface FunctionListND { /** * Linear combination of functions */ public class XY implements FunctionListND { private GeoFunctionable[] array; @Override public boolean set(int i, GeoElement geo) { if (!(geo instanceof GeoFunctionable)) { return false; } array[i] = (GeoFunctionable) geo; return true; } @Override public double evaluate(int c, GeoPointND point) { return array[c].getGeoFunction().value(point.getInhomX()); } @Override public double extractValueCoord(GeoPointND point) { return point.getInhomY(); } // Making GeoFunction fit(x)= p1*f(x)+p2*g(x)+p3*h(x)+... @Override public final CasEvaluableFunction makeFunction( CasEvaluableFunction template, GeoList functionlist, RealMatrix P) { double p; GeoFunction gf = null; GeoFunction product = new GeoFunction(template.getConstruction()); // First product: p = P.getEntry(0, 0); // parameter // Checks done in makeMatrixes... gf = array[0].getGeoFunction(); GeoFunction fitfunction2 = GeoFunction.mult((GeoFunction) template, p, gf); // p1*f(x) for (int i = 1; i < array.length; i++) { p = P.getEntry(i, 0); gf = array[i].getGeoFunction(); product = GeoFunction.mult(product, p, gf); // product= p*func fitfunction2 = GeoFunction.add(fitfunction2, fitfunction2, product, Operation.PLUS); // fit(x)=...+p*func } return fitfunction2; } @Override public CasEvaluableFunction getTemplate(Construction cons) { return new GeoFunction(cons); } @Override public void setSize(int size) { array = new GeoFunctionable[size]; } } /** * Linear combination of 2var functions */ public class XYZ implements FunctionListND { private Evaluate2Var[] array; @Override public boolean set(int i, GeoElement geo) { if (!(geo instanceof Evaluate2Var)) { return false; } array[i] = (Evaluate2Var) geo; return true; } @Override public double evaluate(int c, GeoPointND point) { return array[c].evaluate(point.getInhomX(), point.getInhomY()); } @Override public double extractValueCoord(GeoPointND point) { return point.getInhomZ(); } @Override public CasEvaluableFunction makeFunction(CasEvaluableFunction template, GeoList functionlist, RealMatrix P) { double p; Evaluate2Var gf = null; GeoFunctionNVar product = new GeoFunctionNVar( template.getConstruction()); // First product: p = P.getEntry(0, 0); // parameter // Checks done in makeMatrixes... gf = array[0]; GeoFunctionNVar fTemplate = (GeoFunctionNVar) template; mult(fTemplate, p, gf, Operation.MULTIPLY); // p1*f(x) for (int i = 1; i < array.length; i++) { p = P.getEntry(i, 0); gf = array[i]; mult(product, p, gf, Operation.MULTIPLY); // add(fTemplate, fTemplate, product, Operation.PLUS); // fit(x)=...+p*func } fTemplate.setDefined(true); return template; } private static void add(GeoFunctionNVar res, GeoFunctionNVar lt, GeoFunctionNVar rt, Operation op) { Kernel kernel1 = res.getKernel(); FunctionNVar fRes = GeoFunction.operationSymb(op, rt, lt) .deepCopy(kernel1); fRes.setExpression(AlgoDependentFunction .expandFunctionDerivativeNodes(fRes.getExpression(), true) .wrap()); res.setFunction(fRes); } private static void mult(GeoFunctionNVar res, double lt, Evaluate2Var rt, Operation op) { Kernel kernel1 = res.getKernel(); FunctionNVar fRes = GeoFunction .applyNumberSymb(op, rt, new MyDouble(kernel1, lt), false) .deepCopy(kernel1); fRes.setExpression(AlgoDependentFunction .expandFunctionDerivativeNodes(fRes.getExpression(), true) .wrap()); res.setFunction(fRes); } @Override public CasEvaluableFunction getTemplate(Construction cons) { return new GeoFunctionNVar(cons); } @Override public void setSize(int size) { array = new Evaluate2Var[size]; } } /** * @param i * index * @param geo * element * @return whether element has acceptable type */ boolean set(int i, GeoElement geo); /** * @param i * function index * @param point * point used for evaluation * @return function value */ double evaluate(int i, GeoPointND point); /** * Pick coord of the point that should be compared with value of the * regression function * * @param point * point * @return y or z coord of the point */ double extractValueCoord(GeoPointND point); /** * Multiply functions from functionlist by coefficients from matrix p and * return sum of the results * * @param fitfunction * template function * @param functionlist * list of functions * @param p * coefficient matrix * @return linear combination */ CasEvaluableFunction makeFunction(CasEvaluableFunction fitfunction, GeoList functionlist, RealMatrix p); /** * @param cons * construction * @return template function */ CasEvaluableFunction getTemplate(Construction cons); /** * @param functionsize * number of functions */ void setSize(int functionsize); }