diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 573bd6fbb..30dd261ef 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -52,6 +52,11 @@ If the output is not quite correct, check for invisible trailing spaces! + + Added a NewtonRaphsonSolver taht use the new differentiation package + to define the function to solve. This class is intended to replace the + former NewtonSolver which is deprecated. + Added RandomDataGenerator to replace RandomDataImpl and deprecated RandomData interface and RandomDataImpl class. Deprecated diff --git a/src/main/java/org/apache/commons/math3/analysis/solvers/AbstractDifferentiableUnivariateSolver.java b/src/main/java/org/apache/commons/math3/analysis/solvers/AbstractDifferentiableUnivariateSolver.java index c6c29bbcd..64a744efa 100644 --- a/src/main/java/org/apache/commons/math3/analysis/solvers/AbstractDifferentiableUnivariateSolver.java +++ b/src/main/java/org/apache/commons/math3/analysis/solvers/AbstractDifferentiableUnivariateSolver.java @@ -26,7 +26,9 @@ import org.apache.commons.math3.analysis.UnivariateFunction; * * @since 3.0 * @version $Id$ + * @deprecated as of 3.1, replaced by {@link AbstractUnivariateDifferentiableSolver} */ +@Deprecated public abstract class AbstractDifferentiableUnivariateSolver extends BaseAbstractUnivariateSolver implements DifferentiableUnivariateSolver { diff --git a/src/main/java/org/apache/commons/math3/analysis/solvers/AbstractUnivariateDifferentiableSolver.java b/src/main/java/org/apache/commons/math3/analysis/solvers/AbstractUnivariateDifferentiableSolver.java new file mode 100644 index 000000000..6d3c8bca4 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/analysis/solvers/AbstractUnivariateDifferentiableSolver.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.math3.analysis.solvers; + +import org.apache.commons.math3.analysis.differentiation.DerivativeStructure; +import org.apache.commons.math3.analysis.differentiation.UnivariateDifferentiable; + +/** + * Provide a default implementation for several functions useful to generic + * solvers. + * + * @since 3.1 + * @version $Id$ + */ +public abstract class AbstractUnivariateDifferentiableSolver + extends BaseAbstractUnivariateSolver + implements UnivariateDifferentiableSolver { + + /** Function to solve. */ + private UnivariateDifferentiable function; + + /** + * Construct a solver with given absolute accuracy. + * + * @param absoluteAccuracy Maximum absolute error. + */ + protected AbstractUnivariateDifferentiableSolver(final double absoluteAccuracy) { + super(absoluteAccuracy); + } + + /** + * Construct a solver with given accuracies. + * + * @param relativeAccuracy Maximum relative error. + * @param absoluteAccuracy Maximum absolute error. + * @param functionValueAccuracy Maximum function value error. + */ + protected AbstractUnivariateDifferentiableSolver(final double relativeAccuracy, + final double absoluteAccuracy, + final double functionValueAccuracy) { + super(relativeAccuracy, absoluteAccuracy, functionValueAccuracy); + } + + /** + * Compute the objective function value. + * + * @param point Point at which the objective function must be evaluated. + * @return the objective function value and derivative at specified point. + * @throws org.apache.commons.math3.exception.TooManyEvaluationsException + * if the maximal number of evaluations is exceeded. + */ + protected DerivativeStructure computeObjectiveValueAndDerivative(double point) { + incrementEvaluationCount(); + return function.value(new DerivativeStructure(1, 1, 0, point)); + } + + /** + * {@inheritDoc} + */ + @Override + protected void setup(int maxEval, UnivariateDifferentiable f, + double min, double max, double startValue) { + super.setup(maxEval, f, min, max, startValue); + function = f; + } +} diff --git a/src/main/java/org/apache/commons/math3/analysis/solvers/BaseAbstractUnivariateSolver.java b/src/main/java/org/apache/commons/math3/analysis/solvers/BaseAbstractUnivariateSolver.java index a9b906662..961b798fd 100644 --- a/src/main/java/org/apache/commons/math3/analysis/solvers/BaseAbstractUnivariateSolver.java +++ b/src/main/java/org/apache/commons/math3/analysis/solvers/BaseAbstractUnivariateSolver.java @@ -287,7 +287,7 @@ public abstract class BaseAbstractUnivariateSolver {} diff --git a/src/main/java/org/apache/commons/math3/analysis/solvers/NewtonRaphsonSolver.java b/src/main/java/org/apache/commons/math3/analysis/solvers/NewtonRaphsonSolver.java new file mode 100644 index 000000000..e95591987 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/analysis/solvers/NewtonRaphsonSolver.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.math3.analysis.solvers; + +import org.apache.commons.math3.analysis.differentiation.DerivativeStructure; +import org.apache.commons.math3.analysis.differentiation.UnivariateDifferentiable; +import org.apache.commons.math3.util.FastMath; + +/** + * Implements + * Newton's Method for finding zeros of real univariate differentiable + * functions. + * + * @since 3.1 + * @version $Id$ + */ +public class NewtonRaphsonSolver extends AbstractUnivariateDifferentiableSolver { + /** Default absolute accuracy. */ + private static final double DEFAULT_ABSOLUTE_ACCURACY = 1e-6; + + /** + * Construct a solver. + */ + public NewtonRaphsonSolver() { + this(DEFAULT_ABSOLUTE_ACCURACY); + } + /** + * Construct a solver. + * + * @param absoluteAccuracy Absolute accuracy. + */ + public NewtonRaphsonSolver(double absoluteAccuracy) { + super(absoluteAccuracy); + } + + /** + * Find a zero near the midpoint of {@code min} and {@code max}. + * + * @param f Function to solve. + * @param min Lower bound for the interval. + * @param max Upper bound for the interval. + * @param maxEval Maximum number of evaluations. + * @return the value where the function is zero. + * @throws org.apache.commons.math3.exception.TooManyEvaluationsException + * if the maximum evaluation count is exceeded. + * @throws org.apache.commons.math3.exception.NumberIsTooLargeException + * if {@code min >= max}. + */ + @Override + public double solve(int maxEval, final UnivariateDifferentiable f, + final double min, final double max) { + return super.solve(maxEval, f, UnivariateSolverUtils.midpoint(min, max)); + } + + /** + * {@inheritDoc} + */ + @Override + protected double doSolve() { + final double startValue = getStartValue(); + final double absoluteAccuracy = getAbsoluteAccuracy(); + + double x0 = startValue; + double x1; + while (true) { + final DerivativeStructure y0 = computeObjectiveValueAndDerivative(x0); + x1 = x0 - (y0.getValue() / y0.getPartialDerivative(1)); + if (FastMath.abs(x1 - x0) <= absoluteAccuracy) { + return x1; + } + + x0 = x1; + } + } +} diff --git a/src/main/java/org/apache/commons/math3/analysis/solvers/NewtonSolver.java b/src/main/java/org/apache/commons/math3/analysis/solvers/NewtonSolver.java index 77f3d6722..0dd8111fb 100644 --- a/src/main/java/org/apache/commons/math3/analysis/solvers/NewtonSolver.java +++ b/src/main/java/org/apache/commons/math3/analysis/solvers/NewtonSolver.java @@ -26,8 +26,10 @@ import org.apache.commons.math3.util.FastMath; *

* The function should be continuous but not necessarily smooth.

* + * @deprecated as of 3.1, replaced by {@link NewtonRaphsonSolverTest} * @version $Id$ */ +@Deprecated public class NewtonSolver extends AbstractDifferentiableUnivariateSolver { /** Default absolute accuracy. */ private static final double DEFAULT_ABSOLUTE_ACCURACY = 1e-6; diff --git a/src/main/java/org/apache/commons/math3/analysis/solvers/UnivariateDifferentiableSolver.java b/src/main/java/org/apache/commons/math3/analysis/solvers/UnivariateDifferentiableSolver.java new file mode 100644 index 000000000..3d2f3bab3 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/analysis/solvers/UnivariateDifferentiableSolver.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math3.analysis.solvers; + +import org.apache.commons.math3.analysis.differentiation.UnivariateDifferentiable; + + +/** + * Interface for (univariate real) rootfinding algorithms. + * Implementations will search for only one zero in the given interval. + * + * @since 3.1 + * @version $Id$ + */ +public interface UnivariateDifferentiableSolver + extends BaseUnivariateSolver {} diff --git a/src/site/xdoc/userguide/analysis.xml b/src/site/xdoc/userguide/analysis.xml index f0e761dc6..1a456324e 100644 --- a/src/site/xdoc/userguide/analysis.xml +++ b/src/site/xdoc/userguide/analysis.xml @@ -94,11 +94,11 @@

- UnivariateSolver, - DifferentiableUnivariateSolver and + UnivariateSolver, + UnivariateDifferentiableSolver and PolynomialSolver provide means to find roots of univariate real-valued functions, - differentiable univariate real-valued functions, + differentiable univariate real-valued functions, and polynomial functions respectively. A root is the value where the function takes the value 0. Commons-Math includes implementations of the several root-finding algorithms: @@ -155,8 +155,8 @@ no - Newton's Method - differentiable univariate real-valued functions + Newton-Raphson's Method + differentiable univariate real-valued functions quadratic, non-guaranteed no no diff --git a/src/test/java/org/apache/commons/math3/analysis/solvers/BracketingNthOrderBrentSolverTest.java b/src/test/java/org/apache/commons/math3/analysis/solvers/BracketingNthOrderBrentSolverTest.java index 18eeb04af..866daacff 100644 --- a/src/test/java/org/apache/commons/math3/analysis/solvers/BracketingNthOrderBrentSolverTest.java +++ b/src/test/java/org/apache/commons/math3/analysis/solvers/BracketingNthOrderBrentSolverTest.java @@ -17,7 +17,6 @@ package org.apache.commons.math3.analysis.solvers; -import org.apache.commons.math3.analysis.DifferentiableUnivariateFunction; import org.apache.commons.math3.analysis.QuinticFunction; import org.apache.commons.math3.analysis.UnivariateFunction; import org.apache.commons.math3.analysis.differentiation.DerivativeStructure; @@ -150,37 +149,32 @@ public final class BracketingNthOrderBrentSolverTest extends BaseSecantSolverAbs private void compare(final UnivariateDifferentiable f, double root, double min, double max) { - DifferentiableUnivariateFunction df = new DifferentiableUnivariateFunction() { - public double value(double x) { - return f.value(x); - } - - public UnivariateFunction derivative() { - return new UnivariateFunction() { - public double value(double x) { - return f.value(new DerivativeStructure(1, 1, 0, x)).getPartialDerivative(1); - } - }; - } - }; - NewtonSolver newton = new NewtonSolver(1.0e-12); + NewtonRaphsonSolver newton = new NewtonRaphsonSolver(1.0e-12); BracketingNthOrderBrentSolver bracketing = new BracketingNthOrderBrentSolver(1.0e-12, 1.0e-12, 1.0e-18, 5); double resultN; try { - resultN = newton.solve(100, df, min, max); + resultN = newton.solve(100, f, min, max); } catch (TooManyEvaluationsException tmee) { resultN = Double.NaN; } double resultB; try { - resultB = bracketing.solve(100, df, min, max); + resultB = bracketing.solve(100, f, min, max); } catch (TooManyEvaluationsException tmee) { resultB = Double.NaN; } Assert.assertEquals(root, resultN, newton.getAbsoluteAccuracy()); Assert.assertEquals(root, resultB, bracketing.getAbsoluteAccuracy()); - Assert.assertTrue(bracketing.getEvaluations() < newton.getEvaluations()); + + // bracketing solver evaluates only function value, we set the weight to 1 + final int weightedBracketingEvaluations = bracketing.getEvaluations(); + + // Newton-Raphson solver evaluates both function value and derivative, we set the weight to 2 + final int weightedNewtonEvaluations = 2 * newton.getEvaluations(); + + Assert.assertTrue(weightedBracketingEvaluations < weightedNewtonEvaluations); + } private static abstract class TestFunction implements UnivariateDifferentiable { diff --git a/src/test/java/org/apache/commons/math3/analysis/solvers/NewtonRaphsonSolverTest.java b/src/test/java/org/apache/commons/math3/analysis/solvers/NewtonRaphsonSolverTest.java new file mode 100644 index 000000000..35fad5872 --- /dev/null +++ b/src/test/java/org/apache/commons/math3/analysis/solvers/NewtonRaphsonSolverTest.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math3.analysis.solvers; + +import org.apache.commons.math3.analysis.QuinticFunction; +import org.apache.commons.math3.analysis.differentiation.UnivariateDifferentiable; +import org.apache.commons.math3.analysis.function.Sin; +import org.apache.commons.math3.util.FastMath; +import org.junit.Assert; +import org.junit.Test; + + +/** + * @version $Id$ + */ +public final class NewtonRaphsonSolverTest { + /** + * + */ + @Test + public void testSinZero() { + UnivariateDifferentiable f = new Sin(); + double result; + + NewtonRaphsonSolver solver = new NewtonRaphsonSolver(); + result = solver.solve(100, f, 3, 4); + Assert.assertEquals(result, FastMath.PI, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, 1, 4); + Assert.assertEquals(result, FastMath.PI, solver.getAbsoluteAccuracy()); + + Assert.assertTrue(solver.getEvaluations() > 0); + } + + /** + * + */ + @Test + public void testQuinticZero() { + final UnivariateDifferentiable f = new QuinticFunction(); + double result; + + NewtonRaphsonSolver solver = new NewtonRaphsonSolver(); + result = solver.solve(100, f, -0.2, 0.2); + Assert.assertEquals(result, 0, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, -0.1, 0.3); + Assert.assertEquals(result, 0, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, -0.3, 0.45); + Assert.assertEquals(result, 0, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, 0.3, 0.7); + Assert.assertEquals(result, 0.5, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, 0.2, 0.6); + Assert.assertEquals(result, 0.5, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, 0.05, 0.95); + Assert.assertEquals(result, 0.5, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, 0.85, 1.25); + Assert.assertEquals(result, 1.0, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, 0.8, 1.2); + Assert.assertEquals(result, 1.0, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, 0.85, 1.75); + Assert.assertEquals(result, 1.0, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, 0.55, 1.45); + Assert.assertEquals(result, 1.0, solver.getAbsoluteAccuracy()); + + result = solver.solve(100, f, 0.85, 5); + Assert.assertEquals(result, 1.0, solver.getAbsoluteAccuracy()); + } +} diff --git a/src/test/java/org/apache/commons/math3/analysis/solvers/NewtonSolverTest.java b/src/test/java/org/apache/commons/math3/analysis/solvers/NewtonSolverTest.java index 6b82e9000..6c66f49f5 100644 --- a/src/test/java/org/apache/commons/math3/analysis/solvers/NewtonSolverTest.java +++ b/src/test/java/org/apache/commons/math3/analysis/solvers/NewtonSolverTest.java @@ -29,7 +29,9 @@ import org.junit.Test; /** * @version $Id$ + * @deprecated */ +@Deprecated public final class NewtonSolverTest { /** *