# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# ### Lab 06
#
# Labs in general are for you to solve short programming challenges in class. In contrast, homework assignments will involve more challenging and lengthy problems.
#
# Feel free to ask the TAs for help if there is anything you do not understand. The TAs will go through suggested solutions in the last 15 minutes of the lab - typically by solving them in a live demo. **Your midterm exams will be like this, so it is highly beneficial for you to attend these labs**.
#
# The second lab is to gain basic familiarity with root finding and optimization. 
#
# - You can import any Python library module you need
# - Do this lab without using the web to search for solutions

# **1**. Use the secant method to find the solution to $x^2 + 4x - 5 = 0$ starting from the (2,3) and running 5 iterations.

# +
# %matplotlib inline

import numpy as np
import matplotlib.pyplot as plt

# +
f = lambda x: x**2 + 4*x - 5

def secant(x0, x1, f):
    """Secant update."""
    
    y0 = f(x0)
    y1 = f(x1)
    m = (y1 - y0)/(x1 - x0)
    b = y1 - m*x1
    return -b/m

x0 = 2
x1 = 3

x = [x0, x1]
for i in range(5):
    x0, x1 = x1, secant(x0, x1, f)
    x.append(x1)
    
print(x[-1])
    
x = np.array(x)
y = f(x)
xp = np.linspace(-5, 5, 100)
plt.plot(xp, f(xp))
plt.scatter(x, y)
plt.scatter(x, np.zeros_like(x))
plt.axhline(0)
pass
# -

# **2**. Construct the companion matrix to find all solutions to $x^3 + 4x + 5 = 0$. 

A = np.array([
    [0,-4,-5],
    [1,0,0],
    [0,1,0]
])

x = np.linalg.eigvals(A)
x

# +
f = lambda x: x**3 + 4*x + 5

np.allclose(f(x), np.zeros_like(x))


# -

# **3**. Use the Newton-Raphson method to find the real cube root of 10 starting with an initial guess of 2..

def newton(x, f, fp, max_iter=5):
    "Newton-Raphson method"
    for i in range(max_iter):
        x = x - f(x)/fp(x)
    return x


# +
f = lambda x: x**3 - 10
fp = lambda x: 3*x**2

x0 = 2
x = newton(x0, f, fp)
x
# -

x**3

# **4**. The Lagrange basis functions are given by 
#
# $$
# l_j(x_j) = \prod_{0 \le m \le k, m \ne j} \frac{x - x_m}{x_j - x_m}
# $$
#
# Here, $x$ represents the points at which you want to interpolate, $x_j$ and $x_m$ are indices of the given points.
#
# Use this to fit and plot a quadratic to the 3 points (1,1), (3,7) and (4,11)

x = np.array([1,3,4])
y = np.array([1,7,11])

# +
xp = np.linspace(0, 5, 50)
L0 = ((xp-x[1])*(xp-x[2])) / ((x[0]-x[1])*(x[0]-x[2]))
L1 = ((xp-x[0])*(xp-x[2])) / ((x[1]-x[0])*(x[1]-x[2]))
L2 = ((xp-x[0])*(xp-x[1])) / ((x[2]-x[0])*(x[2]-x[1]))
yp = y[0]*L0 + y[1]*L1 + y[2]*L2

plt.scatter(x, y)
plt.plot(xp, yp)
pass
# -



StarcoderdataJupyterScriptsDedupFiltered