
/** \ingroup PsimagLite */
/*@{*/

/*! \file RootFindingBisection.h
 *
 *  RootFindingBisection such as chemical potential
 *
 */
#ifndef ROOT_FIND_BISECT_H
#define ROOT_FIND_BISECT_H
#include "Fermi.h"
#include "Matrix.h"
#include "ProgressIndicator.h"

namespace PsimagLite
{
template <typename FunctionType>
class RootFindingBisection
{
	typedef typename FunctionType::RealType RealType;

public:

	RootFindingBisection(const FunctionType& function, RealType a = -100., RealType b = 100., SizeType maxIter = 100, RealType tolerance = 1.0e-3)
	    : function_(function)
	    , maxIter_(maxIter)
	    , tolerance_(tolerance)
	    , a_(a)
	    , b_(b)
	{
		RealType f1 = function_(a_) * function_(b_);
		if (f1 >= 0)
			throw RuntimeError(
			    "RootFindingBisection: condition not met\n");
	}

	RealType operator()() const
	{
		// INPUT: Function f, endpoint values a, b, tolerance TOL,
		//                maximum iterations NMAX
		// CONDITIONS: a < b, either f(a) < 0 and f(b) > 0 or
		//                           f(a) > 0 and f(b) < 0
		// OUTPUT: value which differs from a root of f(x)=0 by less
		// than TOL

		RealType a = a_;
		RealType b = b_;
		SizeType n = 0;
		RealType functionAtA = function_(a);
		while (n < maxIter_) {
			RealType c = (a + b) / 2; // new midpoint
			RealType tmp = function_(c);
			if (fabs(tmp) < tolerance_) { // solution found
				return c;
			}
			n++;
			if (sign(tmp) == sign(functionAtA)) {
				a = c;
				functionAtA = tmp;
			} else {
				b = c;
			}
		}

		String msg("RootFindBisection, too many iterations ");
		msg += "maximum = " + ttos(maxIter_) + " tolerance = ";
		msg += ttos(tolerance_) + " a = " + ttos(a_) + " b = " + ttos(b_) + "\n";
		throw std::runtime_error(msg);
	}

private:

	int sign(const RealType& x) const { return (x >= 0) ? 1 : -1; }

	const FunctionType& function_;
	SizeType maxIter_;
	RealType tolerance_;
	RealType a_, b_;
}; // RootFindingBisection
} // namespace PsimagLite

/*@}*/
#endif // ROOT_FIND_BISECT_H
