# Path: cxroots/IterativeMethods.py
# def secant(x1, x2, f, steptol=1e-12, roottol=1e-12, maxIter=30, callback=None):
#     """
#     Find an approximation to a point xf such that f(xf)=0 for a 
#     scalar function f using the secant method.  The method requires
#     two initial points x1 and x2, ideally close to a root,
#     and proceeds iteratively.
# 
#     Parameters
#     ----------
#     x1 : float or complex
#         An initial point for iteration, should be close to a 
#         root of f.
#     x2 : float or complex
#         An initial point for iteration, should be close to a 
#         root of f.  Should not equal x1.
#     f : function
#         Function of a single variable which we seek to find a root of.
#     steptol: float, optional
#         The routine ends if the step size, dx, between sucessive
#         iterations satisfies abs(dx) < steptol and attemptBest is False.
#     roottol: float, optional
#         The routine ends if abs(f(x)) < roottol and attemptBest is False.
#     maxIter : int, optional
#         The routine ends after maxIter iterations.
#     callback : function, optional
#         After each iteration callback(x, dx, f(x), iteration) will be 
#         called where 'x' is the current iteration of the estimated root, 
#         'dx' is the step size between the previous and current 'x' and 
#         'iteration' the number of iterations that have been taken.  If 
#         the callback function evaluates to True then the routine will end.
# 
#     Returns
#     -------
#     complex
#         The approximation to a root of f.
#     float
#         abs(f(x)) where x is the final approximation for the root of f.
#     """
#     # As in "Numerical Recipies 3rd Edition" pick the bound with the
#     # smallest function value as the most recent guess
#     y1, y2 = f(x1), f(x2)
#     if abs(y1) < abs(y2):
#         x1, x2 = x2, x1
#         y1, y2 = y2, y1
# 
#     for iteration in range(maxIter):
#         dx = -(x2 - x1) * y2 / (y2 - y1)
#         x1, x2 = x2, x2 + dx
#         y1, y2 = y2, f(x2)
# 
#         if callback is not None and callback(x2, dx, y2, iteration + 1):
#             break
# 
#         if abs(dx) < steptol or abs(y2) < roottol:
#             break
# 
#     return x2, abs(y2)


import pytest
from cxroots.IterativeMethods import secant
from numpy import pi, cos, sin



def test_secant():
    # example from Table 2.5 of "Numerical Analysis" by Richard L. Burden, J. Douglas Faires
    f = lambda x: cos(x) - x
    df = lambda x: -sin(x) - 1

    iterations = []
    callback = lambda x, dx, y, iteration: iterations.append(x)
    x, err = secant(0.5, pi / 4, f, callback=callback)
    iterations.append(x)

    correct_iterations = [
        0.7363841388,

# Path: cxroots/IterativeMethods.py
# def secant(x1, x2, f, steptol=1e-12, roottol=1e-12, maxIter=30, callback=None):
#     """
#     Find an approximation to a point xf such that f(xf)=0 for a 
#     scalar function f using the secant method.  The method requires
#     two initial points x1 and x2, ideally close to a root,
#     and proceeds iteratively.
# 
#     Parameters
#     ----------
#     x1 : float or complex
#         An initial point for iteration, should be close to a 
#         root of f.
#     x2 : float or complex
#         An initial point for iteration, should be close to a 
#         root of f.  Should not equal x1.
#     f : function
#         Function of a single variable which we seek to find a root of.
#     steptol: float, optional
#         The routine ends if the step size, dx, between sucessive
#         iterations satisfies abs(dx) < steptol and attemptBest is False.
#     roottol: float, optional
#         The routine ends if abs(f(x)) < roottol and attemptBest is False.
#     maxIter : int, optional
#         The routine ends after maxIter iterations.
#     callback : function, optional
#         After each iteration callback(x, dx, f(x), iteration) will be 
#         called where 'x' is the current iteration of the estimated root, 
#         'dx' is the step size between the previous and current 'x' and 
#         'iteration' the number of iterations that have been taken.  If 
#         the callback function evaluates to True then the routine will end.
# 
#     Returns
#     -------
#     complex
#         The approximation to a root of f.
#     float
#         abs(f(x)) where x is the final approximation for the root of f.
#     """
#     # As in "Numerical Recipies 3rd Edition" pick the bound with the
#     # smallest function value as the most recent guess
#     y1, y2 = f(x1), f(x2)
#     if abs(y1) < abs(y2):
#         x1, x2 = x2, x1
#         y1, y2 = y2, y1
# 
#     for iteration in range(maxIter):
#         dx = -(x2 - x1) * y2 / (y2 - y1)
#         x1, x2 = x2, x2 + dx
#         y1, y2 = y2, f(x2)
# 
#         if callback is not None and callback(x2, dx, y2, iteration + 1):
#             break
# 
#         if abs(dx) < steptol or abs(y2) < roottol:
#             break
# 
#     return x2, abs(y2)


# Path: cxroots/tests/test_secant.py
import pytest
from cxroots.IterativeMethods import secant
from numpy import pi, cos, sin




def test_secant():
    # example from Table 2.5 of "Numerical Analysis" by Richard L. Burden, J. Douglas Faires
    f = lambda x: cos(x) - x
    df = lambda x: -sin(x) - 1

    iterations = []
    callback = lambda x, dx, y, iteration: iterations.append(x)
    x, err = secant(0.5, pi / 4, f, callback=callback)
    iterations.append(x)

    correct_iterations = [
        0.7363841388,

        0.7390581392,