package org.geogebra.common.kernel.statistics; /* 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. */ import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.algos.AlgoPolynomialFromCoordinates; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoFunction; import org.geogebra.common.kernel.geos.GeoList; import org.geogebra.common.kernel.geos.GeoNumberValue; /** * Fits a polynomial with given degree to list of points. Adapted from * AlgoFitLine and AlgoPolynomialFromCoordinates (Borcherds) * * @author Hans-Petter Ulven * @version 24.04.08 * * 27.01.09: Extended FitPoly to more than 4th degree ToDo: Put in a * max degree limit, after some testing... */ public class AlgoFitPoly extends AlgoElement { private GeoList geolist; // input private GeoNumberValue degree; // input private GeoFunction geofunction; // output private final RegressionMath regMath; /** * @param cons * construction * @param geolist * points * @param degree * degree */ public AlgoFitPoly(Construction cons, GeoList geolist, GeoNumberValue degree) { super(cons); regMath = new RegressionMath(); this.geolist = geolist; this.degree = degree; geofunction = new GeoFunction(cons); setInputOutput(); compute(); } @Override public Commands getClassName() { return Commands.FitPoly; } @Override protected void setInputOutput() { input = new GeoElement[2]; input[0] = geolist; input[1] = degree.toGeoElement(); setOnlyOutput(geofunction); setDependencies(); } /** * @return fit polynomial */ public GeoFunction getFitPoly() { return geofunction; } @Override public final void compute() { int size = geolist.size(); int par; boolean regok = true; double[] cof = null; par = (int) Math.round(degree.getDouble()); if (!geolist.isDefined() || (size < 2) || (par >= size)) { geofunction.setUndefined(); return; } if (par == size - 1) { AlgoPolynomialFromCoordinates.setFromPoints(geofunction, geolist); return; } // if error in parameters : switch (par) { case RegressionMath.LINEAR: // moved up linear case from default regok = regMath.doLinear(geolist); if (regok) { cof = new double[2]; cof[0] = regMath.getP1(); cof[1] = regMath.getP2(); } // else: -> break; case RegressionMath.QUAD: regok = regMath.doQuad(geolist); if (regok) { cof = new double[3]; cof[0] = regMath.getP1(); cof[1] = regMath.getP2(); cof[2] = regMath.getP3(); } // else: -> break; case RegressionMath.CUBIC: regok = regMath.doCubic(geolist); if (regok) { cof = new double[4]; cof[0] = regMath.getP1(); cof[1] = regMath.getP2(); cof[2] = regMath.getP3(); cof[3] = regMath.getP4(); } // else: -> break; case RegressionMath.QUART: regok = regMath.doQuart(geolist); if (regok) { cof = new double[5]; cof[0] = regMath.getP1(); cof[1] = regMath.getP2(); cof[2] = regMath.getP3(); cof[3] = regMath.getP4(); cof[4] = regMath.getP5(); } // else: -> break; default: if ((par > 4) && (par < 300)) { // ToDo: test speed for max limit! regok = regMath.doPolyN(geolist, par); if (regok) { cof = new double[par + 1]; cof = regMath.getPar(); } // else: -> } else { regok = false; // 24.04.08: Only 1<=degree } // if }// switch // System.out.println("Used: "+(System.currentTimeMillis()-ms)); if (!regok) { geofunction.setUndefined(); return; } // if error in regression geofunction.setFunction(AlgoPolynomialFromCoordinates .buildPolyFunctionExpression(cons.getKernel(), cof)); geofunction.setDefined(true); }// compute() }// class AlgoFitPoly