/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.math.rootfinding;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.solvers.LaguerreSolver;
import org.apache.commons.math.complex.Complex;
import com.opengamma.analytics.math.MathException;
import com.opengamma.analytics.math.function.RealPolynomialFunction1D;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.CompareUtils;
/**
* Class that calculates the real roots of a polynomial using Laguerre's method. This class is a wrapper for the
* <a href="http://commons.apache.org/math/api-2.1/org/apache/commons/math/analysis/solvers/LaguerreSolver.html">Commons Math library implementation</a>
* of Laguerre's method.
*/
//TODO Have a complex and real root finder
public class LaguerrePolynomialRealRootFinder implements Polynomial1DRootFinder<Double> {
private static final LaguerreSolver ROOT_FINDER = new LaguerreSolver();
private static final Double[] EMPTY_ARRAY = new Double[0];
private static final double EPS = 1e-16;
/**
* {@inheritDoc}
* @throws MathException If there are no real roots; if the Commons method could not evaluate the function; if the Commons method could not converge.
*/
@Override
public Double[] getRoots(final RealPolynomialFunction1D function) {
ArgumentChecker.notNull(function, "function");
try {
final Complex[] roots = ROOT_FINDER.solveAll(function.getCoefficients(), 0);
final List<Double> realRoots = new ArrayList<>();
for (final Complex c : roots) {
if (CompareUtils.closeEquals(c.getImaginary(), 0, EPS)) {
realRoots.add(c.getReal());
}
}
if (realRoots.isEmpty()) {
throw new MathException("Could not find any real roots");
}
return realRoots.toArray(EMPTY_ARRAY);
} catch (final FunctionEvaluationException e) {
throw new MathException(e);
} catch (final org.apache.commons.math.ConvergenceException e) {
throw new MathException(e);
}
}
}