#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Aug 13 14:59:32 2024

@author: sam
"""

import numpy as np

roots = []
#define list of roots

'''functions'''
def bracket(f,a,b,N):
    x = np.linspace(a,b,N)
    for i in range(len(x)-1):
        if f(x[i])*f(x[i+1])<0:
            roots.append([x[i],x[i+1]])
#revised bracket method adapted in findallzeros function (also found in Lab2_Q4)

def secant(f,a,b,tol):
    n = 0
    while abs(a-b) >= tol and n < 100:
        c = (b*f(a)-a*f(b))/(f(a)-f(b))
        b = a
        a = c
        n += 1
    return c
#revised secant method adapted in findallzeros function (also found in lab2_Q4)



def findallzeros(f,a,b,tol):
    #findallzeros function that takes a function f, end points a and b, and a tolerance tol
    
    x = np.linspace(a,b,100)
    #split range of x into 100
    
    for i in range(len(x)-1):
    #iterate from 0 - 99
    
        if f(x[i])*f(x[i+1])<0:
        #checks for change in sign between two x points
        
            roots.append([x[i],x[i+1]])
            #if so, add those two points to the list as a pair
            
    for i in range(len(roots)):
    #iterate through the number of roots found from bracketing procedure
    
        [a,b] = roots[i][:]
        #set a and b to be a list of two elements, equal to the ith pair of roots
        
        n = 0
        while abs(a-b) >= tol and n < 100:
        #stops when within tolerance or exceeds runtime
        
            c = (b*f(a)-a*f(b))/(f(a)-f(b))
            #secant method
            
            b = a
            a = c
            #changing variables
            
            n += 1
            #increase runtime cutoff
            
        roots[i] = c
        #assigns ith bracketed pair of roots to c, an estimation of the root from the secant method
        
    return roots
    #returns list of roots