From: Giovanni Mascellani Subject: [PATCH] patch/flanagan_nonfree This patch substitutes non free code from Michael Flanagan with equivalent code from Apache Commons Math. Signed-off-by: Giovanni Mascellani --- geogebra/io/MyI2GHandler.java | 28 +++++----- geogebra/kernel/AlgoIntegralDefinite.java | 55 +++++------------- geogebra/kernel/AlgoRootInterval.java | 19 ++++-- geogebra/kernel/AlgoRootNewton.java | 60 +++++++++++--------- geogebra/kernel/AlgoRootsPolynomial.java | 6 ++- geogebra/kernel/EquationSolver.java | 53 +++++++++++++----- geogebra/kernel/GeoVec2D.java | 47 ++++++++-------- geogebra/kernel/arithmetic/Function.java | 8 +++ geogebra/kernel/arithmetic/PolyFunction.java | 4 + geogebra/kernel/integration/EllipticArcLength.java | 2 - geogebra/kernel/roots/RealRootAdapter.java | 22 +++++++ geogebra/kernel/roots/RealRootDerivAdapter.java | 36 ++++++++++++ geogebra/kernel/roots/RealRootDerivFunction.java | 2 + geogebra/kernel/roots/RealRootFunction.java | 5 ++ 14 files changed, 220 insertions(+), 127 deletions(-) diff --git a/geogebra/io/MyI2GHandler.java b/geogebra/io/MyI2GHandler.java index b62a9d8..ba24ad9 100644 --- a/geogebra/io/MyI2GHandler.java +++ b/geogebra/io/MyI2GHandler.java @@ -27,13 +27,13 @@ import geogebra.kernel.GeoVector; import geogebra.kernel.Kernel; import geogebra.kernel.arithmetic.Command; import geogebra.kernel.arithmetic.ExpressionNode; -import geogebra.kernel.complex.Complex; import geogebra.kernel.parser.Parser; import geogebra.main.Application; import geogebra.main.MyError; import java.util.LinkedHashMap; +import org.apache.commons.math.complex.Complex; import org.xml.sax.SAXException; /** @@ -326,7 +326,7 @@ debug("startElements", eName); break; } for (coord = 0; coord < coords.length; coord++) { - if (Complex.isNaN(coords[coord])) { + if (coords[coord].isNaN()) { break; } } @@ -366,8 +366,8 @@ debug("textElements", str); coords[coord] = new Complex(Double.parseDouble(str), 0); } else if (Double.isNaN(coords[coord].getReal())) { coords[coord] = new Complex(Double.parseDouble(str), Double.NaN); - } else if (Double.isNaN(coords[coord].getImag())) { - coords[coord].setImag(Double.parseDouble(str)); + } else if (Double.isNaN(coords[coord].getImaginary())) { + coords[coord] = new Complex(coords[coord].getReal(), Double.parseDouble(str)); } else { Application.debug("more than 2 specified for "); } @@ -397,7 +397,7 @@ debug("endElements", eName); break; case MODE_COORDINATES : - if (Complex.isNaN(coords[coords.length - 1])) { + if (coords[coords.length - 1].isNaN()) { String tag = ""; if (cmdName.equals("homogeneous_coordinates")) { tag = " or "; @@ -406,12 +406,12 @@ debug("endElements", eName); } else { GeoVec3D v = (GeoVec3D) geo; if (coords.length == 3) { - if (!coords[2].isReal()) { - coords[0] = Complex.over(coords[0], coords[2], new Complex()); - coords[1] = Complex.over(coords[1], coords[2], new Complex()); - coords[2] = Complex.over(coords[2], coords[2], new Complex()); + if (coords[2].getImaginary() != 0.0) { + coords[0] = coords[0].divide(coords[2]); + coords[1] = coords[1].divide(coords[2]); + coords[2] = coords[2].divide(coords[2]); } - if (coords[0].isReal() && coords[1].isReal() && coords[2].isReal()) { + if (coords[0].getImaginary() == 0.0 && coords[1].getImaginary() == 0.0 && coords[2].getImaginary() == 0.0) { v.setCoords(coords[0].getReal(), coords[1].getReal(), coords[2].getReal()); } else { Application.debug("could not import complex coordinates"); @@ -434,12 +434,12 @@ debug("endElements", eName); break; case MODE_COORDINATES_COMPLEX : - if (coord < coords.length && Complex.isNaN(coords[coord])) { + if (coord < coords.length && coords[coord].isNaN()) { if (Double.isNaN(coords[coord].getReal())) { - coords[coord] = new Complex(); + coords[coord] = new Complex(0, 0); Application.debug("no specified for "); - } else if (Double.isNaN(coords[coord].getImag())) { - coords[coord].setImag(0); + } else if (Double.isNaN(coords[coord].getImaginary())) { + coords[coord] = new Complex(coords[coord].getReal(), 0); Application.debug("only 1 specified for "); } } diff --git a/geogebra/kernel/AlgoIntegralDefinite.java b/geogebra/kernel/AlgoIntegralDefinite.java index bf7e8ce..db64bba 100644 --- a/geogebra/kernel/AlgoIntegralDefinite.java +++ b/geogebra/kernel/AlgoIntegralDefinite.java @@ -12,8 +12,12 @@ the Free Software Foundation. package geogebra.kernel; +import org.apache.commons.math.ConvergenceException; +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.integration.LegendreGaussIntegrator; + import geogebra.kernel.arithmetic.NumberValue; -import geogebra.kernel.integration.GaussQuadIntegration; +import geogebra.kernel.roots.RealRootAdapter; import geogebra.kernel.roots.RealRootFunction; /** @@ -33,11 +37,9 @@ public class AlgoIntegralDefinite extends AlgoElement { private GeoFunction symbIntegral; // for numerical adaptive GaussQuad integration - private static final int FIRST_ORDER = 5; - private static final int SECOND_ORDER = 7; - private static GaussQuadIntegration firstGauss, secondGauss; - private static int adaptiveGaussQuadCounter = 0; - private static final int MAX_GAUSS_QUAD_CALLS = 500; + private static final int ORDER = 5; + private static final int MAX_ITER = 100; + private static LegendreGaussIntegrator gauss; public AlgoIntegralDefinite( Construction cons, @@ -167,44 +169,17 @@ public class AlgoIntegralDefinite extends AlgoElement { * quadrature approach. */ public static double adaptiveGaussQuad(RealRootFunction fun, double a, double b) { - adaptiveGaussQuadCounter = 0; - double result = doAdaptiveGaussQuad(fun, a, b); - - //System.out.println("calls: " + adaptiveGaussQuadCounter); - return result; - } - - private static double doAdaptiveGaussQuad(RealRootFunction fun, double a, double b) { - if (++adaptiveGaussQuadCounter > MAX_GAUSS_QUAD_CALLS) { - return Double.NaN; - } - // init GaussQuad classes for numerical integration - if (firstGauss == null) { - firstGauss = new GaussQuadIntegration(FIRST_ORDER); - secondGauss = new GaussQuadIntegration(SECOND_ORDER); + if (gauss == null) { + gauss = new LegendreGaussIntegrator(ORDER, MAX_ITER); } // integrate using gauss quadrature - double firstSum = firstGauss.integrate(fun, a, b); - if (Double.isNaN(firstSum)) return Double.NaN; - double secondSum = secondGauss.integrate(fun, a, b); - if (Double.isNaN(secondSum)) return Double.NaN; - - // check if both results are equal - boolean equal = Kernel.isEqual(firstSum, secondSum, Kernel.STANDARD_PRECISION); - - if (equal) { - // success - return secondSum; - } else { - double mid = (a + b) / 2; - double left = doAdaptiveGaussQuad(fun, a, mid); - if (Double.isNaN(left)) - return Double.NaN; - else - return left + doAdaptiveGaussQuad(fun, mid, b); - } + try { + return gauss.integrate(new RealRootAdapter(fun), a, b); + } catch (Exception e) { + return Double.NaN; + } } final public String toString() { diff --git a/geogebra/kernel/AlgoRootInterval.java b/geogebra/kernel/AlgoRootInterval.java index d9479db..e103fb3 100644 --- a/geogebra/kernel/AlgoRootInterval.java +++ b/geogebra/kernel/AlgoRootInterval.java @@ -12,9 +12,13 @@ the Free Software Foundation. package geogebra.kernel; +import org.apache.commons.math.analysis.solvers.BrentSolver; +import org.apache.commons.math.analysis.solvers.UnivariateRealSolver; +import org.apache.commons.math.analysis.solvers.UnivariateRealSolverFactory; + import geogebra.kernel.arithmetic.Function; import geogebra.kernel.arithmetic.NumberValue; -import geogebra.kernel.roots.RealRoot; +import geogebra.kernel.roots.RealRootAdapter; import geogebra.kernel.roots.RealRootUtil; import geogebra.main.Application; @@ -32,7 +36,6 @@ public class AlgoRootInterval extends AlgoElement { private GeoPoint rootPoint; // output private GeoElement aGeo, bGeo; - private RealRoot rootFinder; public AlgoRootInterval( Construction cons, @@ -47,8 +50,6 @@ public class AlgoRootInterval extends AlgoElement { aGeo = a.toGeoElement(); bGeo = b.toGeoElement(); - rootFinder = new RealRoot(); - // output rootPoint = new GeoPoint(cons); setInputOutput(); // for AlgoElement @@ -87,16 +88,18 @@ public class AlgoRootInterval extends AlgoElement { double root = Double.NaN; Function fun = f.getFunction(); + UnivariateRealSolverFactory fact = UnivariateRealSolverFactory.newInstance(); + UnivariateRealSolver rootFinder = fact.newBrentSolver(); try { // Brent's method - root = rootFinder.brent(fun, a.getDouble(), b.getDouble()); + root = rootFinder.solve(new RealRootAdapter(fun), a.getDouble(), b.getDouble()); //root = rootFinder.falsePosition(fun, a.getDouble(), b.getDouble()); - } catch (IllegalArgumentException e) { + } catch (Exception e) { try { // Brent's failed because we left our function's domain // Let's search for a valid domain and try again double [] borders = RealRootUtil.getDefinedInterval(fun, a.getDouble(), b.getDouble()); - root = rootFinder.brent(fun, borders[0], borders[1]); + root = rootFinder.solve(new RealRootAdapter(fun), borders[0], borders[1]); } catch (Exception ex) { root = Double.NaN; } @@ -105,6 +108,7 @@ public class AlgoRootInterval extends AlgoElement { if (Math.abs(fun.evaluate(root)) < Kernel.MIN_PRECISION) return root; + /* // Brent's failed, try false position (regula falsi) method double aVal = fun.evaluate(a.getDouble()); double bVal = fun.evaluate(b.getDouble()); @@ -114,6 +118,7 @@ public class AlgoRootInterval extends AlgoElement { if (Math.abs(fun.evaluate(root)) < Kernel.MIN_PRECISION) return root; } + */ return Double.NaN; } diff --git a/geogebra/kernel/AlgoRootNewton.java b/geogebra/kernel/AlgoRootNewton.java index 188f672..b499f5c 100644 --- a/geogebra/kernel/AlgoRootNewton.java +++ b/geogebra/kernel/AlgoRootNewton.java @@ -12,9 +12,15 @@ the Free Software Foundation. package geogebra.kernel; +import org.apache.commons.math.ConvergenceException; +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.solvers.UnivariateRealSolver; +import org.apache.commons.math.analysis.solvers.UnivariateRealSolverFactory; + import geogebra.kernel.arithmetic.Function; import geogebra.kernel.arithmetic.NumberValue; -import geogebra.kernel.roots.RealRoot; +import geogebra.kernel.roots.RealRootAdapter; +import geogebra.kernel.roots.RealRootDerivAdapter; import geogebra.kernel.roots.RealRootDerivFunction; import geogebra.kernel.roots.RealRootUtil; @@ -33,7 +39,7 @@ public class AlgoRootNewton extends AlgoElement { private GeoPoint rootPoint; // output private GeoElement startGeo; - private RealRoot rootFinder; + private UnivariateRealSolver rootFinderBrent, rootFinderNewton; public AlgoRootNewton( Construction cons, @@ -45,8 +51,6 @@ public class AlgoRootNewton extends AlgoElement { this.start = start; startGeo = start.toGeoElement(); - rootFinder = new RealRoot(); - // output rootPoint = new GeoPoint(cons); setInputOutput(); // for AlgoElement @@ -57,7 +61,6 @@ public class AlgoRootNewton extends AlgoElement { AlgoRootNewton(Construction cons) { super(cons); - rootFinder = new RealRoot(); } protected String getClassName() { @@ -93,35 +96,40 @@ public class AlgoRootNewton extends AlgoElement { final double calcRoot(Function fun, double start) { double root = Double.NaN; - + double [] borders = getDomain(fun, start); + // for Newton's method we need the derivative of our function fun RealRootDerivFunction derivFun = fun.getRealRootDerivFunction(); - // no derivative found: let's use REGULA FALSI - if (derivFun == null) { - double [] borders = getDomain(fun, start); - try { - root = rootFinder.brent(fun, borders[0], borders[1]); - } catch (Exception e) { - root = Double.NaN; + // derivative found: let's use Newton's method + if (derivFun != null) { + if (rootFinderNewton == null) { + UnivariateRealSolverFactory fact = UnivariateRealSolverFactory.newInstance(); + rootFinderNewton = fact.newNewtonSolver(); } - } - else { - // NEWTON's METHOD + try { - root = rootFinder.newtonRaphson(derivFun, start); + root = rootFinderNewton.solve(new RealRootDerivAdapter(derivFun), borders[0], borders[1], start); } - catch (IllegalArgumentException e) { - // BISECTION with NEWTON's METHOD - try { - // Newton's method failed because we left our function's domain - // Let's search for a valid domain and try again using a restricted method - double [] borders = getDomain(fun, start); - root = rootFinder.bisectNewtonRaphson(derivFun, borders[0], borders[1]); - } catch (Exception ex) { - } + catch (Exception e) { + e.printStackTrace(); + root = Double.NaN; } } + + // if Newton didn't know the answer, let's ask Brent + if (Double.isNaN(root)) { + if (rootFinderBrent == null) { + UnivariateRealSolverFactory fact = UnivariateRealSolverFactory.newInstance(); + rootFinderBrent = fact.newBrentSolver(); + } + + try { + root = rootFinderBrent.solve(new RealRootAdapter(fun), borders[0], borders[1]); + } catch (Exception e) { + root = Double.NaN; + } + } // check what we got if (Math.abs(fun.evaluate(root)) < Kernel.MIN_PRECISION ) diff --git a/geogebra/kernel/AlgoRootsPolynomial.java b/geogebra/kernel/AlgoRootsPolynomial.java index cac5380..7af3d07 100644 --- a/geogebra/kernel/AlgoRootsPolynomial.java +++ b/geogebra/kernel/AlgoRootsPolynomial.java @@ -20,8 +20,10 @@ import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; +import org.apache.commons.math.analysis.solvers.UnivariateRealSolver; + /** - * Finds all real roots of a polynomial. + * Finds all real roots of a polynomial using Brent's method. * TODO: extend for rational functions * * @author Markus Hohenwarter @@ -52,6 +54,8 @@ public class AlgoRootsPolynomial extends AlgoIntersect { // used for AlgoExtremumPolynomial, see setRootPoints() private Function diffFunction; // used for intersection of f and g private GeoPoint tempPoint; + + private UnivariateRealSolver rootFinder; /** * Computes all roots of f diff --git a/geogebra/kernel/EquationSolver.java b/geogebra/kernel/EquationSolver.java index a3ad579..0466abc 100644 --- a/geogebra/kernel/EquationSolver.java +++ b/geogebra/kernel/EquationSolver.java @@ -12,25 +12,28 @@ the Free Software Foundation. package geogebra.kernel; +import org.apache.commons.math.ConvergenceException; +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.solvers.LaguerreSolver; +import org.apache.commons.math.analysis.solvers.UnivariateRealSolver; +import org.apache.commons.math.analysis.solvers.UnivariateRealSolverFactory; +import org.apache.commons.math.complex.Complex; import java.util.Arrays; import geogebra.kernel.arithmetic.PolyFunction; -import geogebra.kernel.complex.Complex; -import geogebra.kernel.complex.ComplexPoly; -import geogebra.kernel.roots.RealRoot; +import geogebra.kernel.roots.RealRootAdapter; public class EquationSolver { private static final double LAGUERRE_EPS = 1E-5; private double epsilon = Kernel.STANDARD_PRECISION; - - private RealRoot rootPolisher; - //private ExtremumFinder extrFinder; + + private LaguerreSolver laguerreSolver; + private UnivariateRealSolver rootFinderBrent, rootFinderNewton; public EquationSolver(Kernel kernel) { // we need someone to polish our roots - rootPolisher = new RealRoot(); //extrFinder = kernel.getExtremumFinder(); } @@ -391,8 +394,15 @@ public class EquationSolver { */ // calc roots with Laguerre method - ComplexPoly poly = new ComplexPoly(eqn); - Complex [] complexRoots = poly.roots(false, new Complex(LAGUERRE_START, 0)); // don't polish here + Complex[] complexRoots = null; + try { + if (laguerreSolver == null) { + laguerreSolver = new LaguerreSolver(); + } + complexRoots = laguerreSolver.solveAll(eqn, LAGUERRE_START); + } catch (Exception e) { + System.err.println("EquationSolver.LaguerreSolver: "+e.getLocalizedMessage()); + } // sort complexRoots by real part into laguerreRoots double [] laguerreRoots = new double[complexRoots.length]; @@ -419,14 +429,23 @@ public class EquationSolver { boolean bounded = f_left * f_right < 0.0; try { - if (bounded) { + if (bounded) { + if (rootFinderBrent == null) { + UnivariateRealSolverFactory fact = UnivariateRealSolverFactory.newInstance(); + rootFinderBrent = fact.newBrentSolver(); + } + // small f'(root): don't go too fare from our laguerre root ! - root = rootPolisher.bisectNewtonRaphson(polyFunc, left, right); + root = rootFinderBrent.solve(new RealRootAdapter(polyFunc), left, right); //System.out.println("Polish bisectNewtonRaphson: " + root); } else { + if (rootFinderNewton == null) { + UnivariateRealSolverFactory fact = UnivariateRealSolverFactory.newInstance(); + rootFinderNewton = fact.newNewtonSolver(); + } // the root is not bounded: give Mr. Newton a chance - root = rootPolisher.newtonRaphson(polyFunc, root); + root = rootFinderNewton.solve(new RealRootAdapter(polyFunc), left, right, root); //System.out.println("Polish newtonRaphson: " + root); } } @@ -435,10 +454,16 @@ public class EquationSolver { // polishing failed: maybe we have an extremum here // try to find a local extremum try { - root = rootPolisher.bisectNewtonRaphson(derivFunc, left, right); + if (rootFinderBrent == null) { + UnivariateRealSolverFactory fact = UnivariateRealSolverFactory.newInstance(); + rootFinderBrent = fact.newBrentSolver(); + } + + root = rootFinderBrent.solve(new RealRootAdapter(derivFunc), left, right); //System.out.println(" find extremum successfull: " + root); } catch (Exception ex) { - System.err.println(ex.getMessage()); + + //System.err.println(ex.getMessage()); } } diff --git a/geogebra/kernel/GeoVec2D.java b/geogebra/kernel/GeoVec2D.java index f30afd1..2f19282 100644 --- a/geogebra/kernel/GeoVec2D.java +++ b/geogebra/kernel/GeoVec2D.java @@ -25,10 +25,11 @@ import geogebra.kernel.arithmetic.MyList; import geogebra.kernel.arithmetic.NumberValue; import geogebra.kernel.arithmetic.ValidExpression; import geogebra.kernel.arithmetic.VectorValue; -import geogebra.kernel.complex.Complex; import java.util.HashSet; +import org.apache.commons.math.complex.Complex; + /** * * @author Markus @@ -410,12 +411,12 @@ implements VectorValue { //c.x = (x1 * x2 + y1 * y2)/(x2 * x2 + y2 * b.y); //c.y = (y1 * x2 - x1 * y2)/(x2 * x2 + y2 * b.y); - Complex out = new Complex(); + Complex out; - Complex.over(new Complex(a.x, a.y), new Complex(b.x, b.y), out); + out = new Complex(a.x, a.y).divide(new Complex(b.x, b.y)); c.x = out.getReal(); - c.y = out.getImag(); + c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } @@ -431,12 +432,12 @@ implements VectorValue { //c.y = ( - x1 * y2)/(x2 * x2 + y2 * b.y); - Complex out = new Complex(); + Complex out; - Complex.over(a.getDouble(), new Complex(b.x, b.y), out); + out = new Complex(a.getDouble(), 0).divide(new Complex(b.x, b.y)); c.x = out.getReal(); - c.y = out.getImag(); + c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } @@ -452,62 +453,62 @@ implements VectorValue { /** c = a ^ b Michael Borcherds 2009-03-10 */ final public static void complexPower(GeoVec2D a, NumberValue b, GeoVec2D c) { - Complex out = new Complex(); + Complex out; - out = Complex.pow(new Complex(a.x, a.y), b.getDouble()); + out = new Complex(a.x, a.y).pow(new Complex(b.getDouble(), 0)); c.x = out.getReal(); - c.y = out.getImag(); + c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** c = a ^ b Michael Borcherds 2009-03-10 */ final public static void complexPower(NumberValue a, GeoVec2D b, GeoVec2D c) { - Complex out = new Complex(); + Complex out; - out = Complex.pow(new Complex(a.getDouble(), 0.0), new Complex(b.x, b.y)); + out = new Complex(a.getDouble(), 0.0).pow(new Complex(b.x, b.y)); c.x = out.getReal(); - c.y = out.getImag(); + c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** c = e ^ a Michael Borcherds 2009-03-10 */ final public static void complexExp(GeoVec2D a, GeoVec2D c) { - Complex out = new Complex(); + Complex out; - out = Complex.exp(new Complex(a.x, a.y)); + out = new Complex(a.x, a.y).exp(); c.x = out.getReal(); - c.y = out.getImag(); + c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** c = natural log(a) Michael Borcherds 2009-03-10 */ final public static void complexLog(GeoVec2D a, GeoVec2D c) { - Complex out = new Complex(); + Complex out; - out = Complex.log(new Complex(a.x, a.y)); + out = new Complex(a.x, a.y).log(); c.x = out.getReal(); - c.y = out.getImag(); + c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** c = natural log(a) Michael Borcherds 2009-03-10 */ final public static double complexAbs(GeoVec2D a) { - return Complex.abs(new Complex(a.x, a.y)); + return new Complex(a.x, a.y).abs(); } /** c = a ^ b Michael Borcherds 2009-03-14 */ final public static void complexPower(GeoVec2D a, GeoVec2D b, GeoVec2D c) { - Complex out = new Complex(); + Complex out; - out = Complex.pow(new Complex(a.x, a.y), new Complex(b.x, b.y)); + out = new Complex(a.x, a.y).pow(new Complex(b.x, b.y)); c.x = out.getReal(); - c.y = out.getImag(); + c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } diff --git a/geogebra/kernel/arithmetic/Function.java b/geogebra/kernel/arithmetic/Function.java index 9e094b5..7c16b17 100644 --- a/geogebra/kernel/arithmetic/Function.java +++ b/geogebra/kernel/arithmetic/Function.java @@ -256,6 +256,10 @@ implements ExpressionValue, RealRootFunction, Functional { } } + public double evaluateDerivative(double x) { + return getDerivative(1).evaluate(x); + } + /** * Returns this function's value at position x. * (Note: use this method if isBooleanFunction() returns true. @@ -1249,6 +1253,10 @@ implements ExpressionValue, RealRootFunction, Functional { public double evaluate(double x) { return fun.evaluate(x); } + + public double evaluateDerivative(double x) { + return derivative.evaluate(x); + } } public final boolean includesDivisionByVariable() { diff --git a/geogebra/kernel/arithmetic/PolyFunction.java b/geogebra/kernel/arithmetic/PolyFunction.java index 98c1884..6df2802 100644 --- a/geogebra/kernel/arithmetic/PolyFunction.java +++ b/geogebra/kernel/arithmetic/PolyFunction.java @@ -87,6 +87,10 @@ public class PolyFunction implements RealRootFunction, RealRootDerivFunction { return deriv; } + final public double evaluateDerivative(double x) { + return evaluateDerivFunc(x)[1]; + } + /** * Evaluates polynomial and its derivative */ diff --git a/geogebra/kernel/integration/EllipticArcLength.java b/geogebra/kernel/integration/EllipticArcLength.java index d6aec8f..e80c66d 100644 --- a/geogebra/kernel/integration/EllipticArcLength.java +++ b/geogebra/kernel/integration/EllipticArcLength.java @@ -24,12 +24,10 @@ public class EllipticArcLength { private double [] halfAxes; private RealRootFunction arcLengthFunction; - private GaussQuadIntegration gauss; public EllipticArcLength(GeoConic ellipse) { halfAxes = ellipse.getHalfAxes(); arcLengthFunction = new EllipticArcLengthFunction(); - gauss = new GaussQuadIntegration(5); } /** diff --git a/geogebra/kernel/roots/RealRootAdapter.java b/geogebra/kernel/roots/RealRootAdapter.java new file mode 100644 index 0000000..e6241c3 --- /dev/null +++ b/geogebra/kernel/roots/RealRootAdapter.java @@ -0,0 +1,22 @@ +package geogebra.kernel.roots; + +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.UnivariateRealFunction; + +public class RealRootAdapter implements UnivariateRealFunction { + + private RealRootFunction fun; + + public RealRootAdapter(RealRootFunction fun) { + this.fun = fun; + } + + public double value(double x) throws FunctionEvaluationException { + double res = this.fun.evaluate(x); + if (Double.isInfinite(res) || Double.isNaN(res)) + throw new FunctionEvaluationException(res); + else + return res; + } + +} diff --git a/geogebra/kernel/roots/RealRootDerivAdapter.java b/geogebra/kernel/roots/RealRootDerivAdapter.java new file mode 100644 index 0000000..65c8725 --- /dev/null +++ b/geogebra/kernel/roots/RealRootDerivAdapter.java @@ -0,0 +1,36 @@ +package geogebra.kernel.roots; + +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.analysis.DifferentiableUnivariateRealFunction; +import org.apache.commons.math.analysis.UnivariateRealFunction; + +public class RealRootDerivAdapter implements + DifferentiableUnivariateRealFunction { + + private RealRootDerivFunction derivFun; + + public RealRootDerivAdapter(RealRootDerivFunction derivFun) { + this.derivFun = derivFun; + } + + public UnivariateRealFunction derivative() { + return new UnivariateRealFunction() { + public double value(double x) throws FunctionEvaluationException { + double res = derivFun.evaluateDerivative(x); + if (Double.isInfinite(res) || Double.isNaN(res)) + throw new FunctionEvaluationException(x); + else + return res; + } + }; + } + + public double value(double x) throws FunctionEvaluationException { + double res = derivFun.evaluate(x); + if (Double.isInfinite(res) || Double.isNaN(res)) + throw new FunctionEvaluationException(x); + else + return res; + } + +} diff --git a/geogebra/kernel/roots/RealRootDerivFunction.java b/geogebra/kernel/roots/RealRootDerivFunction.java index 055f023..ba4c964 100644 --- a/geogebra/kernel/roots/RealRootDerivFunction.java +++ b/geogebra/kernel/roots/RealRootDerivFunction.java @@ -7,4 +7,6 @@ public interface RealRootDerivFunction extends RealRootFunction { * @param x */ public double [] evaluateDerivFunc(double x); + + public double evaluateDerivative(double x); } diff --git a/geogebra/kernel/roots/RealRootFunction.java b/geogebra/kernel/roots/RealRootFunction.java new file mode 100644 index 0000000..65c8438 --- /dev/null +++ b/geogebra/kernel/roots/RealRootFunction.java @@ -0,0 +1,5 @@ +package geogebra.kernel.roots; + +public interface RealRootFunction { + public double evaluate(double x); +} -- tg: (6d6be1c..) patch/flanagan_nonfree (depends on: master)