diff --git a/src/changes/changes.xml b/src/changes/changes.xml index a3c071f59..3a6977c90 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -52,6 +52,13 @@ If the output is not quite correct, check for invisible trailing spaces! + + Re-instated methods to find all complex roots of a polynomial (class + "LaguerreSolver" in package "o.a.c.m.analysis.solvers"). + + + Added accessors to the "Pair" class (package "o.a.c.m.util"). + Added new constructors in EigenDecomposition and deprecated two constructors with unused parameters. diff --git a/src/main/java/org/apache/commons/math3/analysis/solvers/LaguerreSolver.java b/src/main/java/org/apache/commons/math3/analysis/solvers/LaguerreSolver.java index be87db98a..d2e2f7e70 100644 --- a/src/main/java/org/apache/commons/math3/analysis/solvers/LaguerreSolver.java +++ b/src/main/java/org/apache/commons/math3/analysis/solvers/LaguerreSolver.java @@ -17,6 +17,8 @@ package org.apache.commons.math3.analysis.solvers; import org.apache.commons.math3.complex.Complex; +import org.apache.commons.math3.complex.ComplexUtils; +import org.apache.commons.math3.analysis.polynomials.PolynomialFunction; import org.apache.commons.math3.exception.NoBracketingException; import org.apache.commons.math3.exception.NullArgumentException; import org.apache.commons.math3.exception.NoDataException; @@ -144,11 +146,8 @@ public class LaguerreSolver extends AbstractPolynomialSolver { */ public double laguerre(double lo, double hi, double fLo, double fHi) { - double coefficients[] = getCoefficients(); - Complex c[] = new Complex[coefficients.length]; - for (int i = 0; i < coefficients.length; i++) { - c[i] = new Complex(coefficients[i], 0); - } + final Complex c[] = ComplexUtils.convertToComplex(getCoefficients()); + Complex initial = new Complex(0.5 * (lo + hi), 0); Complex z = complexSolver.solve(c, initial); if (complexSolver.isRoot(lo, hi, z)) { @@ -167,6 +166,58 @@ public class LaguerreSolver extends AbstractPolynomialSolver { } } + /** + * Find all complex roots for the polynomial with the given + * coefficients, starting from the given initial value. + *
+ * Note: This method is not part of the API of {@link BaseUnivariateSolver}. + * + * @param coefficients Polynomial coefficients. + * @param initial Start value. + * @return the point at which the function value is zero. + * @throws org.apache.commons.math3.exception.TooManyEvaluationsException + * if the maximum number of evaluations is exceeded. + * @throws NullArgumentException if the {@code coefficients} is + * {@code null}. + * @throws NoDataException if the {@code coefficients} array is empty. + */ + public Complex[] solveAllComplex(double[] coefficients, + double initial) { + setup(Integer.MAX_VALUE, + new PolynomialFunction(coefficients), + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, + initial); + return complexSolver.solveAll(ComplexUtils.convertToComplex(coefficients), + new Complex(initial, 0d)); + } + + /** + * Find a complex root for the polynomial with the given coefficients, + * starting from the given initial value. + *
+ * Note: This method is not part of the API of {@link BaseUnivariateSolver}. + * + * @param coefficients Polynomial coefficients. + * @param initial Start value. + * @return the point at which the function value is zero. + * @throws org.apache.commons.math3.exception.TooManyEvaluationsException + * if the maximum number of evaluations is exceeded. + * @throws NullArgumentException if the {@code coefficients} is + * {@code null}. + * @throws NoDataException if the {@code coefficients} array is empty. + */ + public Complex solveComplex(double[] coefficients, + double initial) { + setup(Integer.MAX_VALUE, + new PolynomialFunction(coefficients), + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, + initial); + return complexSolver.solve(ComplexUtils.convertToComplex(coefficients), + new Complex(initial, 0d)); + } + /** * Class for searching all (complex) roots. */ diff --git a/src/main/java/org/apache/commons/math3/complex/ComplexUtils.java b/src/main/java/org/apache/commons/math3/complex/ComplexUtils.java index a0f59d63f..678d399a7 100644 --- a/src/main/java/org/apache/commons/math3/complex/ComplexUtils.java +++ b/src/main/java/org/apache/commons/math3/complex/ComplexUtils.java @@ -32,9 +32,7 @@ public class ComplexUtils { /** * Default constructor. */ - private ComplexUtils() { - super(); - } + private ComplexUtils() {} /** * Creates a complex number from the given polar representation. @@ -58,7 +56,7 @@ public class ComplexUtils { * @param r the modulus of the complex number to create * @param theta the argument of the complex number to create * @return r·ei·theta - * @throws MathIllegalArgumentException if r is negative + * @throws MathIllegalArgumentException if {@code r} is negative. * @since 1.1 */ public static Complex polar2Complex(double r, double theta) { @@ -69,4 +67,21 @@ public class ComplexUtils { return new Complex(r * FastMath.cos(theta), r * FastMath.sin(theta)); } + /** + * Convert an array of primitive doubles to an array of {@code Complex} objects. + * + * @param real Array of numbers to be converted to their {@code Complex} + * equivalent. + * @return an array of {@code Complex} objects. + * + * @since 3.1 + */ + public static Complex[] convertToComplex(double[] real) { + final Complex c[] = new Complex[real.length]; + for (int i = 0; i < real.length; i++) { + c[i] = new Complex(real[i], 0); + } + + return c; + } } diff --git a/src/test/java/org/apache/commons/math3/analysis/solvers/LaguerreSolverTest.java b/src/test/java/org/apache/commons/math3/analysis/solvers/LaguerreSolverTest.java index 83282694d..369396773 100644 --- a/src/test/java/org/apache/commons/math3/analysis/solvers/LaguerreSolverTest.java +++ b/src/test/java/org/apache/commons/math3/analysis/solvers/LaguerreSolverTest.java @@ -19,7 +19,9 @@ package org.apache.commons.math3.analysis.solvers; import org.apache.commons.math3.analysis.polynomials.PolynomialFunction; import org.apache.commons.math3.exception.NumberIsTooLargeException; import org.apache.commons.math3.exception.NoBracketingException; +import org.apache.commons.math3.complex.Complex; import org.apache.commons.math3.util.FastMath; +import org.apache.commons.math3.TestUtils; import org.junit.Assert; import org.junit.Test; @@ -110,43 +112,26 @@ public final class LaguerreSolverTest { } /** - * Test of solver for the quintic function using solveAll(). - * XXX commented out because "solveAll" is not part of the API. + * Test of solver for the quintic function using + * {@link LaguerreSolver#solveAllComplex(double[],double) solveAllComplex}. */ - // public void testQuinticFunction2() { - // double initial = 0.0, tolerance; - // Complex expected, result[]; + @Test + public void testQuinticFunction2() { + // p(x) = x^5 + 4x^3 + x^2 + 4 = (x+1)(x^2-x+1)(x^2+4) + final double[] coefficients = { 4.0, 0.0, 1.0, 4.0, 0.0, 1.0 }; + final LaguerreSolver solver = new LaguerreSolver(); + final Complex[] result = solver.solveAllComplex(coefficients, 0); - // // p(x) = x^5 + 4x^3 + x^2 + 4 = (x+1)(x^2-x+1)(x^2+4) - // double coefficients[] = { 4.0, 0.0, 1.0, 4.0, 0.0, 1.0 }; - // LaguerreSolver solver = new LaguerreSolver(); - // result = solver.solveAll(coefficients, initial); - - // expected = new Complex(0.0, -2.0); - // tolerance = FastMath.max(solver.getAbsoluteAccuracy(), - // FastMath.abs(expected.abs() * solver.getRelativeAccuracy())); - // TestUtils.assertContains(result, expected, tolerance); - - // expected = new Complex(0.0, 2.0); - // tolerance = FastMath.max(solver.getAbsoluteAccuracy(), - // FastMath.abs(expected.abs() * solver.getRelativeAccuracy())); - // TestUtils.assertContains(result, expected, tolerance); - - // expected = new Complex(0.5, 0.5 * FastMath.sqrt(3.0)); - // tolerance = FastMath.max(solver.getAbsoluteAccuracy(), - // FastMath.abs(expected.abs() * solver.getRelativeAccuracy())); - // TestUtils.assertContains(result, expected, tolerance); - - // expected = new Complex(-1.0, 0.0); - // tolerance = FastMath.max(solver.getAbsoluteAccuracy(), - // FastMath.abs(expected.abs() * solver.getRelativeAccuracy())); - // TestUtils.assertContains(result, expected, tolerance); - - // expected = new Complex(0.5, -0.5 * FastMath.sqrt(3.0)); - // tolerance = FastMath.max(solver.getAbsoluteAccuracy(), - // FastMath.abs(expected.abs() * solver.getRelativeAccuracy())); - // TestUtils.assertContains(result, expected, tolerance); - // } + for (Complex expected : new Complex[] { new Complex(0, -2), + new Complex(0, 2), + new Complex(0.5, 0.5 * FastMath.sqrt(3)), + new Complex(-1, 0), + new Complex(0.5, -0.5 * FastMath.sqrt(3.0)) }) { + final double tolerance = FastMath.max(solver.getAbsoluteAccuracy(), + FastMath.abs(expected.abs() * solver.getRelativeAccuracy())); + TestUtils.assertContains(result, expected, tolerance); + } + } /** * Test of parameters for the solver. diff --git a/src/test/java/org/apache/commons/math3/complex/ComplexUtilsTest.java b/src/test/java/org/apache/commons/math3/complex/ComplexUtilsTest.java index af20d5585..4c71ba472 100644 --- a/src/test/java/org/apache/commons/math3/complex/ComplexUtilsTest.java +++ b/src/test/java/org/apache/commons/math3/complex/ComplexUtilsTest.java @@ -20,7 +20,7 @@ package org.apache.commons.math3.complex; import org.apache.commons.math3.TestUtils; import org.apache.commons.math3.util.FastMath; import org.junit.Test; - +import org.junit.Assert; /** * @version $Id$ @@ -100,4 +100,13 @@ public class ComplexUtilsTest { TestUtils.assertSame(negInfNegInf, ComplexUtils.polar2Complex(inf, 5*pi/4)); } + @Test + public void testConvertToComplex() { + final double[] real = new double[] { negInf, -123.45, 0, 1, 234.56, pi, inf }; + final Complex[] complex = ComplexUtils.convertToComplex(real); + + for (int i = 0; i < real.length; i++) { + Assert.assertEquals(real[i], complex[i].getReal(), 0d); + } + } }