import math
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt

# Newton-Raphson method
def newton_raphson(f,x,n):
    df = diff(f,t)
    res = x
    for i in range(n):
        res = res - (f(res))/(df(res))
    return res

#Secant method
def secant(f,x0,x1,n):
    res = [x0,x1]
    for i in range(n):
        res.append((res[0]*f(res[1]) - res[0]*f(res[1]))/(f(res[1])-f(res[0])))
        res.pop(0)
    return res[1]

#Bisection method
def bisection(f,x0,x1,n):
    bra = [x0,x1]
    for i in range(n):
        c = (bra[1]+bra[0])/2
        if np.sign(f(bra[0])) != np.sign(f(c)):
            bra = [bra[0],c]
        else:
            bra = [c,bra[1]]
    return bra


def dekker(f,x0,x1,n):
    if abs(f(x0)) < abs(f(x1)): #invariant; the better estimate shall be in the 0th position
        bra = [x1,x0]
    else:
        bra = [x0,x1]
    for i in range(n):
        m = (bra[1]+bra[0])/2
        s =(bra[0]*f(bra[1]) - bra[0]*f(bra[1]))/(f(bra[1])-f(bra[0]))
        if abs(bra[0]-m) < abs(bra[0]-s): #Choose whether to use bisection method of secant method for this iteration
            c = m
        else:
            c = s
        if np.sign(f(bra[0])) != np.sign(f(c)):
            bra = [c,bra[1]]
        else:
            bra = [c,bra[0]]
    return bra
