/*
 * NewtonZeroFinder.java
 *
 * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
 *
 * This file is part of BEAST.
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership and licensing.
 *
 * BEAST is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 *  BEAST is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with BEAST; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

package dr.math.iterations;

import dr.math.functionEval.DrMath;
import dr.math.functionEval.FunctionDerivative;
import dr.math.interfaces.OneVariableFunction;
/**
 * Finds the zeroes of a function using Newton approximation.
 * Note: the zero of a function if the value at which the function's
 * value is zero.
 *
 * @author Didier H. Besset
 */
public class NewtonZeroFinder extends FunctionalIterator
{
	/**
	 * Derivative of the function for which the zero will be found.
	 */
	private OneVariableFunction df;
/**
* Constructor method.
* @param func the function for which the zero will be found.
* @param start the initial value for the search.
*/
public NewtonZeroFinder( OneVariableFunction func, double start)
{
	super( func);
	setStartingValue( start);
}
/**
* Constructor method.
* @param func the function for which the zero will be found.
* @param dFunc derivative of func.
* @param start the initial value for the search.
*/
public NewtonZeroFinder( OneVariableFunction func,
							OneVariableFunction dFunc, double start)
									throws IllegalArgumentException
{
	this( func, start);
	setDerivative( dFunc);
}
/**
* Evaluate the result of the current interation.
* @return the estimated precision of the result.
*/
public double evaluateIteration()
{
	double delta = f.value( result) / df.value( result);
	result -= delta;
	return relativePrecision( Math.abs( delta));
}
/**
* Initializes internal parameters to start the iterative process.
* Assigns default derivative if necessary.
*/
public void initializeIterations()
{
	if ( df == null)
		df = new FunctionDerivative( f);
	if ( Double.isNaN( result) )
		result = 0;
	int n = 0;
	while ( DrMath.equal( df.value( result), 0) )
	{
		if ( ++n > getMaximumIterations() )
			break;
		result += Math.random();
	}
}
/**
 * (c) Copyrights Didier BESSET, 1999, all rights reserved.
 * @param dFunc DhbInterfaces.OneVariableFunction
 * @exception java.lang.IllegalArgumentException
 *							if the derivative is not accurate.
 */
public void setDerivative( OneVariableFunction dFunc)
										throws IllegalArgumentException
{
	df = new FunctionDerivative( f);
	if ( !DrMath.equal( df.value( result), dFunc.value( result), 0.001) )
		throw new IllegalArgumentException
						( "Supplied derative function is inaccurate");
	df = dFunc;
}
/**
 * (c) Copyrights Didier BESSET, 1999, all rights reserved.
 */
public void setFunction( OneVariableFunction func)
{
	super.setFunction( func);
	df = null;
}
/**
* Defines the initial value for the search.
*/
public void setStartingValue( double start)
{
	result = start;
}
}