def bisection(f, a, b, tol=1e-6):
"""
Find a root of function f (i.e., f(x) = 0) within bracket [a, b] using bisection.
Parameters
----------
f : function
the function that we are finding a root for: f(x) = 0
a : float
left endpoint
b : float
right endpoint. note f(a) * f (b) must be < 0, otherwise function will return.
tol : float
tolerance for stopping criteria
Returns
-------
x : float
the root where f(x) = 0
"""
# check if this is a valid interval. if not return
# start while loop, continue while the bracket half-width is > tolerance
# compute midpoint
# evaluate function at midpoint
# check if midpoint is a root (within tolerance), if so return it
# update new bracket based on sign of f(midpoint)
# done with while loop, return midpoint as the root