Search code examples
pythonfor-loopnumerical-analysisfixed-point-iteration

How to Make Python Print something at nth Iteration within a For Loop?


I want to preface my question by saying that I am very new to Python and have only started using it for a specific class in grad school.

I have written a script to find the root of a function using iterative methods such as the Fixed-point, Bisection, and Newton-Raphson methods. The python code for my algorithms are as follows:

Fixed-Point Method:

def fixedpoint(func, g_func,x0,tol, MAXIT):
    
    def g(x):
        return eval(g_func)
    
    print(f"Seeking root of {func}.")
    print("FIXED POINT ITERATION:")
    iterated_x = g(x0)
    for i in range(0, MAXIT):
        iterated_x = g(iterated_x)
        print("Iteration", i + 1, iterated_x)
        condition = abs(g(iterated_x) - (iterated_x)) 
        if condition < tol:
            print(f"The root converges to {iterated_x} after {i+1} iterations.")
            break
        if i == MAXIT and condition >= tol:
            print("ERROR: The root did not converge after maximum iterations.")

fixedpoint('x**2 - 4*x + 2', '(x**2+2)/4', 0.75, 10**(-4), 100)
fixedpoint('math.exp(-x) + x - 7 ', '7 - math.exp(-x)', 0.75, 10**(-4), 100)

Bisection Method:

def bisection(func,a, b, tol, MAXIT):
    
    def f(x):
        return eval(func)
    
    print(f"Seeking root of {func}")
    print("BISECTION METHOD:")
    if f(a)*f(b) <0:
        for i in range(0, MAXIT):
            c = (a+b)/2
            if f(a)*f(c) < 0:
                a = a
                b = c
                print(f"Iteration", i + 1, f(c))
            elif f(b)*f(c) < 0:
                b = b
                a = c
                print(f"Iteration", i + 1, f(c))
            if f(c) == 0 or abs(f(c)) < tol:
                print ("Exact Solution Found")
                print(f"Iteration", i + 1, c)
                print("The root converges to", c, "after", i + 1, "iterations.")
                break
            elif i == MAXIT and abs(f(c)) > tol:
                print("Bisection method fails.")
                
    return None

bisection('x**2 - 4*x + 2',0.5, 1, 10**(-4), 100)
bisection('math.exp(-x) + x - 7',6, 8, 10**(-4), 100)

Newton-Raphson Method:

def newtonraphson(func, deriv, x0, tol, MAXIT):
    
    def f(x):
        return eval(func)

    def ddx(x):
        return eval(deriv)
        
    
    print(f"Seeking root of {func}.")
    print("NEWTON-RAPHSON METHOD:")
    
    for i in range(1, MAXIT):
        iterated_x = x0 - (f(x0)/ddx(x0))
        x0 = iterated_x
        print(f"Iteration", i, x0)

        if f(x0) < tol:
            print(f"The root converges to {x0} after {i} iterations.")
            break
        elif i==MAXIT and f(x0) > tol:
            print("After maximum iterations, root was not found.")

newtonraphson('x**2-4*x+2', '2*x-4', 0.75,10**(-4), 100)
newtonraphson('math.exp(-x) + x - 7', '-(math.exp(-x)) + 1', 0.75,10**(-4), 100)

While my script is successfully able to find the roots for the equations I am interested in, I am stuck with a simpler problem. Basically, I want to tell my program that if after maximum iterations, my tolerance condition is not fulfilled, print "Method Failed".

However, my code does not print the statement I want it to when I experiment with functions that don't coverage when maximum iterations is set at 100 and tolerance is set to 0.0001.

Is my syntax right for the fail print statement?

Do conditions like "if i==MAXIT and f(x0) > tol" make sense in the context of the function I have written?

I would appreciate any and all advice for this issue as I am trying hard to improve at Python.

Thank you.


Solution

  • A good way to achieve this in Python is to use the for\else construct. Essentially, if you hang an "else" clause off of your for loop, it will execute if the loop doesn't terminate early due to a break statement. It's very useful for loops that are searching for something, and root finding definitely fits that mold. So your fixed point iteration loop would look like:

    for i in range(0, MAXIT):
        iterated_x = g(iterated_x)
        condition = abs(g(iterated_x) - (iterated_x)) 
        if condition < tol:
            print(f"The root converges to {iterated_x} after {i+1} iterations.")
            break
    else:
        print("ERROR: The root did not converge after maximum iterations.")
    

    One advantage of doing it this way is that it doesn't matter if you change your success criteria in the loop--the else clause runs if you don't declare success with the break statement no matter how success is defined.