I am trying to improve my program that will allow all of the parameters in the compute_bisection function to be set by the user.
What I have tried:
My computer_bisection function:
def compute_bisection(f, a, b, n=10, tol_interval=1e-5, tol_f=1e-8):
'''This simple function applies up to n iterations of the bisection algorithm'''
# Let us first check the conditions to apply the bisection alg. are satisfied
if a >= b:
raise ValueError('The bisec. alg. requires a<b')
if f(a)*f(b) > 0:
raise ValueError('The bisec. alg. requires f(a) and f(b) are different signs')
# Now, perform the bisection algorithm
current_iter = 0
while current_iter < n:
c = (b+a)/2 # bisect the interval [a,b], i.e., compute mid-point
# Check if c is an (approx.) root
if np.abs(f(c)) < tol_f:
break
# Check if dividing [a,b] in half makes the interval too small to continue
if (b-a)/2 < tol_interval:
break
# Determine if a or b should be replaced with c
if f(a)*f(c) < 0:
b = c
else:
a = c
current_iter += 1
return (a, b, c)
My plot_bisection function :
def plot_bisection(f, a, b, n, x_min, x_max, grid_pts = 100, show_final_interval = False):
# Compute approximate root with bisec. alg.
(a_n, b_n, c) = compute_bisection(f, a, b, n)
############################################
# Everything below this line involves making plots of the results
############################################
fig = plt.figure(figsize=(10,5))
x = np.linspace(x_min,x_max,grid_pts)
# First, plot function and axes
plt.plot(x,f(x),'b',linewidth=2) #plot of function f
plt.axvline(0, linewidth=1, linestyle=':', c='k') #plot typical y-axis
plt.axhline(0, linewidth=1, linestyle=':', c='k') #plot typical x-axis
# Title information
title_str = 'Approx. root is ' + '{:.6}'.format(c) + '. Use this to update interval [a,b].'
plt.title(title_str, fontsize=14)
# Create a dict (dictionary) of properties of items used in annotations
bbox_pt = dict(boxstyle='round', fc='0.9')
bbox_text = dict(boxstyle="round", fc='b', color='r', alpha=0.25, linewidth=2)
arrowprops = dict(arrowstyle='->', facecolor='black', alpha=0.5, linewidth=2)
y_min, y_max = plt.ylim() #get min and max y-values from plot to offset annotations
y_range = y_max - y_min
x_range = x_max - x_min
# Now plot relevant points and annotate
# First annotate parts of the plot involving the points a and b
if show_final_interval:
plt.scatter(a_n,f(a_n),s=70,c='k')
plt.annotate(r'$(a_n,f(a_n))$', fontsize=12, xy=(a_n,f(a_n)), xytext=(a_n+0.2*x_range,f(a_n)-0.35*y_range),
bbox=bbox_pt, arrowprops=arrowprops)
plt.scatter(b_n,f(b_n),s=70,c='k')
plt.annotate(r'$(b_n,f(b_n))$', fontsize=12, xy=(b_n,f(b_n)), xytext=(b_n+0.2*x_range,f(b_n)-0.35*y_range),
bbox=bbox_pt, arrowprops=arrowprops)
else:
plt.scatter(a,f(a),s=70,c='k')
plt.annotate(r'$(a,f(a))$', fontsize=12, xy=(a,f(a)), xytext=(a+0.1*x_range,f(a)-0.25*y_range),
bbox=bbox_pt, arrowprops=arrowprops)
plt.scatter(b,f(b),s=70,c='k')
plt.annotate(r'$(b,f(b))$', fontsize=12, xy=(b,f(b)), xytext=(b+0.1*x_range,f(b)-0.25*y_range),
bbox=bbox_pt, arrowprops=arrowprops)
# Now annotate the part of the plot involving the approximate root c
plt.scatter(c,f(c),s=70,c='r')
plt.annotate('Approx. root\nfrom ' + str(n) + '\nstep(s) of bisec.\nalgorithm', fontsize=12, xy=(c,f(c)),
xytext=(c-0.2*x_range,f(c)+0.25*y_range), color='w',
bbox = bbox_text, arrowprops=arrowprops)
plt.annotate(r'$(c,f(c))$', fontsize=12, xy=(c,f(c)), xytext=(c+0.1*x_range,f(c)-0.25*y_range),
bbox=bbox_pt, arrowprops=arrowprops)