I am working on the file "SC2/U2_QuadWorldAll.ipynb".
The first task is:
Preguntas

El método de Midpoint y el del Trapecio se basan ambos en aproximaciones por polinomio de grado $1$. ¿Cuál considera usted mejor?. Hint: Considere la cantidad de evaluaciones de funciones, y el termino de error.
¿Cuál es la importancia del término $h$ en los Error term de cada método?
¿Cuál es la importancia del orden de la derivada $f^{(k)}(c)$ en los Error term de cada método?

<div id='ac' />

Análisis de Convergencia
Para entender bien el concepto de convergencia, es fundamental entender correctamente dos conceptos:

Grado de Precisión (Degree of Precision). Para un método de integración numérica, corresponde al mayor entero $k$ para el cual todos los polinomios de grado $k$ o menor, son integrados exactamente (sin error). Si recordamos los métodos ya estudiados, el término de error tiene la forma general:
$$
\text{Error term} = C \ h^p \ f^{(q)}(c) \ \ \ \ \text{con} \ \ C \ \text{constante} \ \ \text{y} \ \ p,q \in \mathbb{N}
$$
Dado que para cualquier polinomio de grado $\leq q-1$ se obtiene que $f^{(q)}=0$, entonces el grado de precisión de un tal método, viene determinado por el orden de la derivada, y es $q-1$.
Orden de convergencia. El orden de convergencia está derminada por la otra componente del Error term, esto es, por $h^p$. Recordar que $h$ debe ser pequeño ($h < 1$), y por lo tanto a mayor potencia $p$, menor será el orden del método. El orden de convergencia, nos dice cómo decrece el error a medida que se aumentan la cantidad de puntos de la malla.

A continuación compararemos gráficamente la convergencia de estos métodos:
Can you write Python code for it?

def get_error(quadrature_rule, myfun, Nrange, a, b, true_value):
    quad_error = []
    for N in Nrange:
        error = np.abs(true_value - quadrature_rule(myfun, N, a, b) )
        if error<1E-16:
            quad_error.append(1E-16)
        else:
            quad_error.append(error)
    return quad_error

def set_ylim(ymin, ymax):
    ymin = min(plt.ylim()[0], ymin)
    ymax = max(plt.ylim()[1], ymax)
    plt.ylim([ymin, ymax])
    return

def convergence(exp_data):
    Nrange     = exp_data[0]
    myfun      = exp_data[1]
    a          = exp_data[2]
    b          = exp_data[3]
    true_value = exp_data[4]
    #######################################################
    print('Printing numerical experiment details:')
    print('Nrange: ', Nrange)
    print(inspect.getsource(myfun).replace('\n', ''))
    print('a: ', a)
    print('b: ', b)
    print('true_value: ', true_value)
    #######################################################
    ms = 10
    f = np.vectorize(myfun) # So we can apply it to arrays without trouble
    e_mp = get_error(midpoint, myfun, Nrange, a, b, true_value)
    e_tr = get_error(trapezoid, myfun, Nrange, a, b, true_value)
    e_sp = get_error(simpsons, myfun, Nrange, a, b, true_value)
    e_gq = get_error(gaussianquad, myfun, Nrange, a, b, true_value)
    #plt.figure(figsize=(12,16))
    fig = plt.figure(figsize=(24,24))
    plt.rcParams.update({'font.size': 22})

    # First plot
    ax = plt.subplot(2,2,1)
    dd = 0.1*(b-a)
    x = np.linspace(a-dd, b+dd, 1000)
    plt.plot(x, f(x), 'k', label="f(x)", lw=2.0)
    x = np.linspace(a, b, 1000)
    plt.fill_between(x, f(x), 0, alpha=0.5, label=r"$\int_a^b f(x) dx$")
    plt.xlabel("x")
    plt.ylabel("f(x)")
    ymax = 1.05*plt.ylim()[1]
    plt.ylim([-ymax, ymax])
    plt.grid('on')
    plt.legend(loc="lower left")

    # Second plot
    ax = plt.subplot(2,2,2)
    plt.plot(Nrange, e_mp, 'sb', lw=2.0, ms=ms, label="Midpoint")
    plt.plot(Nrange, e_tr, 'or', lw=2.0, ms=ms, label="Trapezoid")
    plt.plot(Nrange, e_sp,...


I am working on the file "SC2/U2_QuadWorldAll.ipynb".
The first task is:
Test de Convergencia
Finalmente podemos testear la convergencia de nuestros métodos
Can you write Python code for it?


I am working on the file "SC2/U2_QuadWorldAll.ipynb".
The first task is:
Test de tiempos
Finalmente podemos testear los tiempos de nuestros métodos
Can you write Python code for it?


I am working on the file "SC2/U3_FEM1D.ipynb".
The first task is:
<div id='dir' />

Condiciones de Borde de Dirichlet
Si bien, el problema que ya resolvimos también tenía este tipo de condiciones de borde, volveremos a echarles un vistazo.
En esta ocasión resolveremos el siguiente problema:
\begin{align}
-\frac{d^2u(x)}{dx^2} = f(x) \ , \ x \in [0,1] \
\end{align}
\begin{align}
u(0) = u(1) = 0
\end{align}
Can you write Python code for it?

def DirichletSolver(f, N):
    x = np.linspace(0., 1., N)
    h = x[1]-x[0]
    K = (1./h)*(np.diag(-1*np.ones(N-1),-1)
               +np.diag( 2*np.ones(N), 0)
               +np.diag(-1*np.ones(N-1),+1))
    b = h*f(x)
    u = solve(K, b)
    return x, u

f1 = lambda x : np.e**x
u1 = lambda x : -np.e**x + (np.e - 1.)*x + 1.

f2 = lambda x : np.sin(x) - x
u2 = lambda x : np.sin(x) - x*np.sin(1.) +  (x**3 - x )/6.

# Example
f, u = f2, u2
N = 64
x, u_h = DirichletSolver(f, N)
SolutionPlot(x, u, u_h)

# Convergence
f, u = f2, u2

N_list = 64*2**np.arange(6)
h_list = []
error_list = []
for N in N_list:
    x, u_h = DirichletSolver(f, N)
    h = x[1]-x[0]
    h_list.append(h)
    error_list.append(Error(x, u, u_h) )

ErrorPlot(h_list, error_list)


I am working on the file "SC2/U3_FEM1D.ipynb".
The first task is:

Introducción
Al igual que en el anterior, en el siguiente notebook se estudiará la resolución numérica de ecuaciones diferenciales parciales elípticas. Sin ser necesaria la repetición de la introducción a las PDE, cabe destacar que en esta ocasión variaremos el método utilizado para resolverlas, siendo éste el método de elementos finitos (FEM), el cual es un método muy popular en la ingeniería.
A continuación veremos una breve explicación del método junto con aplicaciones prácticas al caso 1D y 2D.

Marco Teórico
El método de elementos finitos consiste, en palabras simples, en la discretización del dominio (cuerpo) sobre el cual queremos resolver la ecuación diferencial en cuestión. Esto lo logramos mediante la definición de numerosos subdominios no intersectantes entre sí llamados elementos finitos.
Al lograr expresar la ecuación diferencial que deseamos resolver en su forma débil o variacional (en forma de integral), se establecen condiciones de vínculo entre los elementos finitos de nuestro dominio, generándose un sistema de ecuaciones que debe ser resuelto numéricamente para obtener nuestra solución aproximada.
A modo de ejemplo, consideremos la siguiente ecuación en 1D:
\begin{align}
-\frac{d^2u(x)}{dx^2} + u(x) = f(x) \ , \ x \in [0,1] \
\end{align}
\begin{align}
u(0) = u(1) = 0
\end{align}
Multiplicando por $v(x)$ (con $v(0)=v(1)=0$) e integrando obtenemos:
\begin{align}
- \int_0^1 \frac{d^2u(x)}{dx^2}v(x)dx + \int_0^1 u(x)v(x)dx = \int_0^1  f(x)v(x)dx \
\end{align}
Si integramos por partes el primer término obtenemos:
\begin{align}
-\int_0^1 \frac{d^2u(x)}{dx^2}v(x)dx = -\left. \frac{du(x)}{dx}v(x)\right|^1_0 + \int_0^1 \frac{du(x)}{dx}v'(x)dx
\end{align}
Debido a nuestra definición de $v(x)$ podemos eliminar el término en donde esta función es evaluada en los bordes, por lo que nuestra ecuación en su forma variacional sería:
\begin{align}
\int_0^1 \frac{du(x)}{dx}\frac{dv(x)}{dx}dx + \int_0^1 u(x)v(x)dx = \int_0^1  f(x)v(x)dx
\end{align}
Lo que sigue es...
Can you write Python code for it?

f1 = lambda x: 0*x
P1 = {"f":f1, "a":0, "b":1}
u1 = lambda x: 0*x
P1_sol = {"u": u1}

f2 = lambda x: x**2 - x - 2
P2 = {"f":f2, "a":0, "b":1}
u2 = lambda x: x*(x-1)
P2_sol = {"u": u2}

f3 = lambda x: np.exp(-(x-.5)**2)
P3 = {"f":f3, "a":0, "b":1}
P3_sol = {"u": None}

f4 = lambda x: np.where(x<=.5, 0, 1)
P4 = {"f":f4, "a":0, "b":1}
P4_sol = {"u": None}

def FEM(P, u0, u1, N=5):
    # Parameters
    x = np.linspace(P["a"], P["b"], N+2)
    dx = x[1]-x[0]
    # Matrix K
    diag = (2./dx + 2.*dx/3.)*np.ones(N)
    udiag = (-1./dx + dx/6.)*np.ones(N)
    ldiag = udiag
    K = dia_matrix(([ldiag, diag, udiag], [-1, 0,+1]), shape=(N, N))
    # Right hand side
    b = dx*P["f"](x[1:-1])
    # Return the solution
    c = [u0] + list(spsolve(K, b)) + [u1]
    return x, c

P, P_sol = P2, P2_sol
x, c = FEM(P, 0, 0, N=15)
SolutionPlot(x, P_sol['u'], c)


I am working on the file "SC2/U3_ODE.ipynb".
The first task is:
<div id='conver' />

Convergencia
¡Esto es muy importante! Estudiémoslo...
Para hablar de convergencia, tenemos que tener en cuenta el orden de cada método. En palabras simples y resumidas podemos decir lo siguiente:

Euler es un método de primer orden $O(h)$, por lo que si $h$ se reduce a la mitad, el error también lo hace.
RK2 es un método de segundo orden $O(h^2)$, por lo que si $h$ se reduce a la mitad, el error se reduce a la cuarta parte.
RK4 es un método de cuarto orden $O(h^4)$, por lo que si $h$ se reduce a la mitad, el error se reduce 16 veces.

Para ver esto, consideremos el siguiente problema:
\begin{align}
\dot{y}(t)&=-3\,y(t)+6\,t+5\
y(0)&=3
\end{align}
cuya solución es $y(t)=2e^{-3t}+2t+1$.
Can you write Python code for it?

y0=3.0
time_test=0.5
def my_f(t,y):
    return np.array(-3*y+6*t+5)
y_sol = lambda t: 2.*np.exp(-3.*t)+2.*t+1

fig = plt.figure(figsize=(L/2,L/2))
fig.clf()
ax = fig.gca()
ax.axis("equal")
ax.grid(True)
ax.set_title("Convergence Analysis")

h_list = np.logspace(-5,-1,5)
for h in h_list:
    t_times = np.arange(0, time_test+h, h)
    y_output = np.zeros(t_times.size)
    y_output[0] = y0
    for i in range(1,t_times.size):
        y_output[i]=euler_ode(y_output[i-1],t_times[i-1],my_f,h)
    plt.loglog(h,abs(y_output[-1]-y_sol(t_times[-1])),'b.',ms=20,label='Euler',alpha=.5)
    y_output = np.zeros(t_times.size)
    y_output[0] = y0
    for i in range(1,t_times.size):
        y_output[i]=RK2_ode(y_output[i-1],t_times[i-1],my_f,h)
    plt.loglog(h,abs(y_output[-1]-y_sol(t_times[-1])),'rs',ms=20,label='RK2',alpha=.5)
    y_output = np.zeros(t_times.size)
    y_output[0] = y0
    for i in range(1,t_times.size):
        y_output[i]=RK4_ode(y_output[i-1],t_times[i-1],my_f,h)
    plt.loglog(h,abs(y_output[-1]-y_sol(t_times[-1])),'gd',ms=20,label='RK4',alpha=.5)
    if h==h_list[0]:
        plt.legend(numpoints=1, loc="lower right")
plt.loglog(h_list,h_list,'k-')
plt.loglog(h_list,np.power(h_list,2.),'k-')
plt.loglog(h_list,np.power(h_list,4.),'k-')


I am working on the file "SC2/U3_ODE.ipynb".
The first task is:

Problemas de segundo orden y más dimensiones
¿Por qué debemos estudiar problemas de dimensiones más altas?
¡Porque son geniales!
Van der pool
El ocsilador Van der Pol es un oscilador no conservativo con amortiguamiento no lineal. Su evolución en el tiempo sigue una ecuación diferencial de segundo orden:
$$\ddot{y}-\mu\,(1-y^2)\,\dot{y} + y = 0$$ con $y(0)=2\ $   y   $\dot{y}(0)=0$
$\mu$ es un parámetro escalar que indica la no linealidad y la fuerza del amortiguamiento.
$y_1(t)=y(t)$

$y_2(t)=\dot{y}(t)$

$\dot{y}_1=\dot{y} = y_2$

$\dot{y}_2=\ddot{y} = \mu (1-y^2) \dot{y} - y = \mu (1-y_1^2) y_2 - y_1$

Can you write Python code for it?

mu=10
def my_vdp(t,y,mu=mu):
    y1 = y[0]
    y2 = y[1]
    return np.array([y2, mu*(1-y1**2)*y2-y1])

def my_vdp_eig_jacobian(t,y,mu=mu):
    J=[[0,1],[-(2*mu*y[0]*y[1]+1), mu*(1-y[0]**2)]]
    lambs,vs= LA.eig(J)
    return lambs

def plotting_vdp(y01=2,y02=0,h=0.01,T=200,solver='euler'):
    y0=np.array([y01, y02])
    t_times = np.arange(0, T, h)
    y_output = np.zeros([t_times.size,2])
    y_output[0,:] = y0
    for i in range(1,t_times.size):
        #y_output[i,:]=euler_ode(y_output[i-1,:],t_times[i-1],my_vdp,h)
        if solver=='euler':
            y_output[i]=euler_ode(y_output[i-1],t_times[i-1],my_vdp,h)
        elif solver=='RK2':
            y_output[i]=RK2_ode(y_output[i-1],t_times[i-1],my_vdp,h)
        else:
            y_output[i]=RK4_ode(y_output[i-1],t_times[i-1],my_vdp,h)

    fig = plt.figure(figsize=(L,L/2))
    ax1 = fig.add_subplot(121)
    ax2 = fig.add_subplot(122)

    ax1.grid(True)
    ax1.set_title("Numerical Approximation")
    ax1.plot(t_times,y_output[:,0],'-')
    ax1.set(xlabel='t', ylabel='$y_1$')

    ax2.grid(True)
    ax2.set_title("Phase Portrait")
    ax2.plot(y_output[:,0],y_output[:,1],'-')
    ax2.set(xlabel='$y=y_1$', ylabel='$\dot{y}=y_2$')

interact(plotting_vdp,y01=(-3,3,0.1),y02=(-3,3,0.1),h=(0.001,1,0.01),T=(10,200,10),solver=['euler','RK2','RK4'])


I am working on the file "SC2/U3_ODE.ipynb".
The first task is:
Ejemplo en 1-D
Resolviendo $\dot{y}(t) = y(t)(1-y(t))$ para distintas condiciones iniciales $y_0$, tenemos:
Can you write Python code for it?

# Logistic Equation
def my_f_1D(t,y):
    return np.array(y*(1-y))

def plot_log_eq(h=0.15,solver='euler'):
    t_times = np.arange(0, 4, h)
    fig = plt.figure(figsize=(L/2,L/2))
    fig.clf()
    ax = fig.gca()
    ax.axis("equal")
    ax.grid(True)
    ax.set_title("Numerical Approximations and Direction Field")
    ax.axis([0, 4, -2, 2])

    for y0 in np.linspace(-1,5,40):
        y_output = np.zeros(t_times.size)
        y_output[0] = y0
        for i in range(1,t_times.size):
            if solver=='euler':
                y_output[i]=euler_ode(y_output[i-1],t_times[i-1],my_f_1D,h)
            elif solver=='RK2':
                y_output[i]=RK2_ode(y_output[i-1],t_times[i-1],my_f_1D,h)
            else:
                y_output[i]=RK4_ode(y_output[i-1],t_times[i-1],my_f_1D,h)
        plt.plot(t_times,y_output,'k-',alpha=0.5)
        plt.plot(t_times,y_output,'.')

    X,Y = np.meshgrid(np.arange(0,4,.2), np.arange(-2,2,.2))
    theta = np.arctan(my_f_1D(0,Y))
    U = np.cos(theta)
    V = np.sin(theta)
    plt.quiver(X,Y,U,V,alpha=0.5)
interact(plot_log_eq,h=(0.01,1,0.01),solver=['euler','RK2','RK4'])


I am working on the file "SC2/U3_ODE.ipynb".
The first task is:
Entonces, ¿cómo utilizamos la región de estabilidad?
Lo importante de este análisis es notar que no podemos definir $h$ a priori. Dados un método y $\lambda$ conocidos, debemos estudiar la región de estabilidad para determinar que valor de $h$ utilizar.
Can you write Python code for it?

def plot_log_eq_stability_region(y0=1.2, h=0.5, T=10):
    # How did I get this? Why do I need it?
    def my_f_1D_prime(y):
        return np.array(1-2*y)

    # Choosing which solver to use
    solvers = ('euler','RK2','RK4')
    solver = solvers[2]

    t_times = np.arange(0, T+h, h)
    y_output = np.zeros(t_times.size)
    y_output[0] = y0

    for i in range(1,t_times.size):
        if solver=='euler':
            y_output[i]=euler_ode(y_output[i-1],t_times[i-1],my_f_1D,h)
            c1,c2,c3='b','k','k'
        elif solver=='RK2':
            y_output[i]=RK2_ode(y_output[i-1],t_times[i-1],my_f_1D,h)
            c1,c2,c3='k','b','k'
        else:
            y_output[i]=RK4_ode(y_output[i-1],t_times[i-1],my_f_1D,h)
            c1,c2,c3='k','k','b'

    fig = plt.figure(figsize=(L,L))
    ax1 = fig.add_subplot(221)
    ax2 = fig.add_subplot(222)
    ax3 = fig.add_subplot(223)

    ax1.axis("equal")
    ax1.grid(True)
    ax1.set_title("Numerical Approximation")
    ax1.axis([0, T, -0.5, 2])
    ax1.plot(t_times,y_output,'-')
    ax1.plot(t_times,y_output,'.k')

    # The next code is to plot in logscale unstable numerical simulations
    y_all=h*my_f_1D_prime(y_output)
    y_pos=y_all>0
    y_neg=np.logical_not(y_pos)
    ax2.semilogy(t_times[y_pos],y_all[y_pos],'.r',ms=20)
    ax2.semilogy(t_times[y_neg],-y_all[y_neg],'.b',ms=20)
    ax2.grid("on")
    ax2.set_title("Numerical Approximation in log scale")

    zplot2(W1,ax3,line_color=c1)
    zplot2(W2,ax3,line_color=c2)
    zplot2(W4,ax3,line_color=c3)
    k_lambdah=h*my_f_1D_prime(y_output)
    ax3.plot(np.real(k_lambdah),np.imag(k_lambdah),'.r',ms=20)
    ax3.axis("equal")
    ax3.axis([-5, 2, -3.5, 3.5])
    ax3.grid("on")
    ax3.set_title("Stability Region and $k=\lambda\,h$")

#y0=1.2 # 1.2, 2.0, 4.0
#h=0.5  # 0.5, 0.1
#T=10
interact(plot_log_eq_stability_region,y0=(-2,5,0.1),h=(0.01,1,0.1), T=(1,20,1))


I am working on the file "SC2/U3_ODE.ipynb".
The first task is:
Modelo Lotka-Volterra (ecuaciones predador-presa), es decir, lobos comiendo conejos y conejos escondiendo y comiendo pasto infinito.
Se definen $y_1(t)$ como el número de conejos en el tiempo $t$ y $y_2(t)$ como el número de lobos en el tiempo $t$.
Todo esto está pasando en una isla, aunque estamos considerando la presencia de pasto infinito. Entonces, si no hay lobos, obtenemos $\dot{y1}(t)=y_1(t)$, en otras palabras, el número de conejos crece exponencialmente.
Ahora, si no hubiesen conejos, obtenemos $\dot{y_2}(t)=-y_2(t)$, debido a que la población de lobos decae exponencialmente. Pero, ¿qué pasa si tenemos ambas especies?
\begin{align}
\dot{y_1}(t)&=(1-y_2(t)/\mu_2)\,y_1(t)\
\dot{y_2}(t)&=-(1-y_1(t)/\mu_1)\,y_2(t)\
y_1(0)&=400\
y_2(0)&=100
\end{align}
donde $\mu_1$ y $\mu_2$ son constantes de normalización.
Can you write Python code for it?

mu1=300
mu2=200
def f_predprey(t,y,mu1=mu1,mu2=mu2):
    y1 = y[0]
    y2 = y[1]
    return np.array([(1-y2/mu2)*y1, -(1-y1/mu1)*y2])

def f_predprey_jacobian(t,y,mu1=mu1,mu2=mu2):
    J=[[1-y[1]/mu2,-y[0]/mu2],[y[1]/mu1, -(1-y[0]/mu1)]]
    lambs,vs= LA.eig(J)
    return lambs

y0=[400, 100]
h=0.03
T=30

# Choosing which solver to use
solvers = ('euler','RK2','RK4')
solver = solvers[0]

def plotting_predprey(y01=400,y02=100,h=0.03,T=30,solver='euler'):
    t_times = np.arange(0, T+h, h)
    y_output = np.zeros([2,t_times.size])
    y_output[:,0] = y0

    for i in range(1,t_times.size):
        if solver=='euler':
            y_output[:,i]=euler_ode(y_output[:,i-1],t_times[i-1],f_predprey,h)
            c1='b'
            c2='k'
            c3='k'
        elif solver=='RK2':
            y_output[:,i]=RK2_ode(y_output[:,i-1],t_times[i-1],f_predprey,h)
            c1='k'
            c2='b'
            c3='k'
        else:
            y_output[:,i]=RK4_ode(y_output[:,i-1],t_times[i-1],f_predprey,h)
            c1='k'
            c2='k'
            c3='b'

    fig = plt.figure(figsize=(L,L))
    ax1 = fig.add_subplot(221)
    ax2 = fig.add_subplot(222)
    ax3 = fig.add_subplot(223)

    ax1.grid(True)
    ax1.set_title('Numerical Approximation')
    ax1.plot(t_times,y_output[0,:],'-')
    ax1.plot(t_times,y_output[1,:],'r-')
    ax1.axis([0, T, 0, 600])

    zplot2(W1,ax2,line_color=c1)
    zplot2(W2,ax2,line_color=c2)
    zplot2(W4,ax2,line_color=c3)
    for i in range(1,t_times.size):
        k_lambdah=h*my_vdp_eig_jacobian(t_times[i],y_output[:,i])
        ax2.plot(np.real(k_lambdah[0]),np.imag(k_lambdah[0]),'.r',ms=10,alpha=.4)
        ax2.plot(np.real(k_lambdah[1]),np.imag(k_lambdah[1]),'sm',ms=10,alpha=.4)
    ax2.axis('equal')
    ax2.axis([-5, 2, -3.5, 3.5])
    ax2.grid('on')

    ax3.grid(True)
    ax3.set_title('Phase Portrait')
    ax3.plot(y_output[0,:],y_output[1,:],'-')
    ax3.set(xlabel='$y_1$', ylabel='$y_2$')
    ax3.axis([0, 800, 0,...


I am working on the file "SC2/U4_EDP_elipticas.ipynb".
The first task is:

Introducción
En el siguiente notebook se estudia la resolución numérica de ecuaciones diferenciales parciales elípticas. La resolución de estas tiene gran importancia, ya que aparecen repetidas veces en diferentes modelos físicos relacionados con los potenciales de energía. Por ejemplo, el potencial de carga eléctrica de acuerdo a las ecuaciones de Maxwell puede ser escrito como:
$$
\Delta u = -\frac{\rho}{\epsilon},
$$
con $u$ el potencial eléctrico, $\rho$ la densidad de carga, y $\epsilon$ el la permitividad eléctrica.
El método numérico que estudiaremos se basa en diferencias finitas, del mismo modo en que se hizo para resolver EDOs anteriormente, esto es, las derivadas son aproximadas por gradientes calculados numéricamente en base a los valores vecinos de cada punto. Sin embargo ahora las derivadas son parciales!, pero como veremos esto no es gran problema.

Marco Teórico
Si consideramos una función $u(x,y)$ dos veces diferenciable, entonces se define el operador Laplaciano como:
$$
\Delta u(x,y) = u_{xx}(x,y) + u_{yy}(x,y),
$$
si se considera además una función $f(x,y)$, entonces es posible definir:
$$
\Delta u(x,y) = u_{xx}(x,y) + u_{yy}(x,y) = f(x,y), \ \ \  \text{con } \ x,y \in \Omega \ \text{ y condiciones de borde en } \ \partial \Omega
$$
como la ecuación de Poisson, la cual es una de las más conocidas dentro de la clase _ Elípticas _. El caso particular donde $f(x,y) = 0$ se conoce como ecuación de Laplace.
Formulación numérica
Sea la ecuación de Laplace $\Delta u(x,y) = 0$ sobre un dominio rectangular $[x_a, x_b] \times [y_a, y_b]$, con condiciones de borde de Dirichlet:
\begin{align}
    u(x,y_a) &= g_1(x) \
    u(x,y_b) &= g_2(x) \
    u(x_a,y) &= g_3(y) \
    u(x_b,y) &= g_4(y) .
\end{align}
Para resolver este problema por diferencias finitas, es necesario discretizar el dominio $\Omega$ sobre el que se define la función. Tal discretización se puede ver gráficamente como se muestra a continuación:
Can you write Python code for it?

x = np.linspace(0., 1., 10)
y = np.linspace(0., 1., 10)
xgrid, ygrid = np.meshgrid(x, y, sparse=False)
plt.figure(figsize=(8,8))
plt.scatter(xgrid.ravel(), ygrid.ravel())
plt.plot((0,1),(0,0), 'g--' ,lw=2)
plt.plot((1,1),(0,1), 'g--' ,lw=2)
plt.plot((1,0),(1,1), 'g--' ,lw=2)
plt.plot((0,0),(1,0), 'g--' ,lw=2)
plt.title('Esquema de discretizacion uniforme')
plt.xlim(-0.1,1.1)
plt.ylim(-0.1,1.1)
plt.axis('equal')
plt.show()


I am working on the file "SC2/U4_EDP_elipticas.ipynb".
The first task is:
Ecuación de Helmholtz
Buscaremos resolver la ecuación de Helmholtz con condición de frontera de Dirichlet:
\begin{align}
\Delta u(x,y) -\lambda \, u(x,y)&= f(x,y) \ , \ (x, y) \in \Omega=[0,1]\times[0,1] \
u(x,0) &= b(x)\
u(x,1) &= t(x)\
u(0, y) &= l(y)\
u(1,y) &= r(y)
\end{align}
A continuación se definen tres problemas a resolver.
Can you write Python code for it?

# Problem 1
Lambda = 0.1
xmin, xmax = 0., 1.
ymin, ymax = 0., 1.
f  = lambda x,y : 0
bottom = lambda x : 0
top = lambda x : 0
left = lambda y : 1
right = lambda y: 1
P1 = {"Lambda":Lambda, "f":f, "b":bottom, "t":top, "l":left, "r":right,
      "xmin":xmin, "xmax":xmax, "ymin":ymin, "ymax":ymax}

# Problem 2
Lambda = 2.0
xmin, xmax = 0., 1.
ymin, ymax = 0., 1.
f  = lambda x,y : 0
bottom = lambda x : 0
top = lambda x : 0
left = lambda y : 1
right = lambda y: 1
P2 = {"Lambda":Lambda, "f":f, "b":bottom, "t":top, "l":left, "r":right,
      "xmin":xmin, "xmax":xmax, "ymin":ymin, "ymax":ymax}

# Problem 3
Lambda = 0.0
xmin, xmax = -1, 1.
ymin, ymax = -1, 1.
f  = lambda x,y : 0
bottom = lambda x : 0
top = lambda x : 0
left = lambda y : np.sin(np.pi*y)
right = lambda y: -np.sin(np.pi*y)
P3 = {"Lambda":Lambda, "f":f, "b":bottom, "t":top, "l":left, "r":right,
      "xmin":xmin, "xmax":xmax, "ymin":ymin, "ymax":ymax}

P_Helmholtz=[('P1', P1), ('P2', P2),('P3', P3)]


I am working on the file "SC2/U4_EDP_elipticas.ipynb".
The first task is:
La función solve_herlmotz() es la encargada de construir el sistema lineal correspondiente para al problema P a resolver.
Q: ¿Podría usted explicar esta construcción en base a lo visto en la formulación teórica?.
Can you write Python code for it?

def solve_helmholtz(P, Nx=30, Ny=30,flag_plot=False,elev=40,azim=230):
    # Discretize x and y
    x = np.linspace(P["xmin"], P["xmax"], Nx+1)
    y = np.linspace(P["ymin"], P["ymax"], Ny+1)
    L = P["Lambda"]

    # Define the discretization parameters
    dx = x[1]-x[0]
    dy = y[1]-y[0]

    # Create the matrix and the right hand size vector
    A = np.zeros([(Nx+1)*(Ny+1), (Nx+1)*(Ny+1)])
    b = np.zeros([(Nx+1)*(Ny+1), 1])

    # Define global indexing
    def index(i, j, nCols=(Ny+1)):
        return j + i*nCols

    # Fill up the matrix and right hand side vector
    for i in range(Nx+1):
        for j in range(Ny+1):
            k = index(i,j)
            if j==0: # y=ymin, bottom
                A[k,k] =  -1.5/dy
                A[k,index(i,j+1)] = 2.0/dy
                A[k,index(i,j+2)] =-0.5/dy
                b[k] = P["b"](x[i])
            elif i==Nx: # x=xmax, right
                A[k,k] =  1.
                b[k] = P["r"](y[j])
            elif j==Ny: # y=ymax, top
                A[k,k] =  1.5/dy
                A[k,index(i,j-1)] =  -2.0/dy
                A[k,index(i,j-2)] =  +0.5/dy
                b[k] = P["t"](x[i])
            elif i==0:  # x=xmin, left
                A[k,k] =  1.
                b[k] = P["l"](y[j])
            else:
                A[k, k] = -2./dx**2 - 2./dy**2 - L
                A[k,index(i+1,j)] =  1./dx**2
                A[k,index(i-1,j)] =  1./dx**2
                A[k,index(i,j-1)] =  1./dy**2
                A[k,index(i,j+1)] =  1./dy**2
                b[k] = P["f"](x[i], y[j])

    # Solve the linear system
    w = np.linalg.solve(A, b)

    if flag_plot:
        plot(x,y,w,elev,azim)
        return

    return x, y, w

elev_widget = IntSlider(min=0, max=180, step=10, value=40)
azim_widget = IntSlider(min=0, max=360, step=10, value=230)

interact(solve_helmholtz,P=P_Helmholtz,Nx=(5,50,5),Ny=(5,50,5),flag_plot=[True],elev=elev_widget,azim=azim_widget)


I am working on the file "SC2/U4_EDP_elipticas.ipynb".
The first task is:
La función solve_laplace() es la encargada de construir el sistema lineal correspondiente para al problema P a resolver.
Q: ¿Podría usted explicar esta construcción en base a lo visto en la formulación teórica?.
Can you write Python code for it?

def solve_laplace(P, Nx=30, Ny=30,flag_plot=False,elev=40,azim=230):
    # Discretize x and y
    x = np.linspace(P["xmin"], P["xmax"], Nx+1)
    y = np.linspace(P["ymin"], P["ymax"], Ny+1)

    # Define the discretization parameters
    dx = x[1]-x[0]
    dy = y[1]-y[0]

    # Create the matrix and the right hand size vector
    A = np.zeros([(Nx+1)*(Ny+1), (Nx+1)*(Ny+1)])
    b = np.zeros([(Nx+1)*(Ny+1), 1])

    # Define global indexing
    def index(i, j, nCols=(Ny+1)):
        return j + i*nCols

    # Fill up the matrix and right hand side vector
    for i in range(Nx+1):
        for j in range(Ny+1):
            k = index(i,j)
            if j==0: # y=ymin, bottom
                A[k,k] =  1.
                b[k] = P["b"](x[i])
            elif i==Nx: # x=xmax, right
                A[k,k] =  1.
                b[k] = P["r"](y[j])
            elif j==Ny: # y=ymax, top
                A[k,k] =  1.
                b[k] = P["t"](x[i])
            elif i==0:  # x=xmin, left
                A[k,k] =  1.
                b[k] = P["l"](y[j])
            else:
                A[k, k] = -2./dx**2 - 2./dy**2
                A[k,index(i+1,j)] =  1./dx**2
                A[k,index(i-1,j)] =  1./dx**2
                A[k,index(i,j-1)] =  1./dy**2
                A[k,index(i,j+1)] =  1./dy**2
                b[k] = P["f"](x[i], y[j])

    # Solve the linear system
    w = np.linalg.solve(A, b)

    if flag_plot:
        plot(x,y,w,elev,azim)
        return

    return x, y, w

elev_widget = IntSlider(min=0, max=180, step=10, value=40)
azim_widget = IntSlider(min=0, max=360, step=10, value=230)

interact(solve_laplace,P=P_Poisson,Nx=(5,50,5),Ny=(5,50,5),flag_plot=[True],elev=elev_widget,azim=azim_widget)


I am working on the file "SC2/U4_HeatEquation.ipynb".
The first task is:
<div id='heat1d:periodic' />

Ecuación de calor 1D: Condición de borde Periódica
Consideremos la siguiente EDP parabólica, para $ x \in [a,b]\ \ $ y $t \in [0,T_{max}] \ \ $:
\begin{align}
u_t(x,t) = D\, u_{xx}(x,t)
\end{align}
\begin{align}
u(x,0) = f(x)
\end{align}
\begin{align}
u(-x,t) = u(1-x,t)
\end{align}
La condición de frontera es periódica, esto es, estudiamos la evolución de la temperatura en un anillo,
por lo que consideramos que para $u(-x,t) = u(1-x,t)$
Can you write Python code for it?

f1 = lambda x: np.sin(2*np.pi*x)**2
P1 = {"xmin":0, "xmax":1, "tmin":0, "tmax":1.0, "D":1, "f":f1}

f2 = lambda x: 10*np.exp(-(x-.5)**2/0.01)
P2 = {"xmin":0, "xmax":1, "tmin":0, "tmax":1.0, "D":1, "f":f2}

f3 = lambda x: x
P3 = {"xmin":0, "xmax":1, "tmin":0, "tmax":1.0, "D":1, "f":f3}

P_Heat=[('P1', P1), ('P2', P2),('P3', P3)]

k_widget = IntSlider(min=0, max=30, step=1,value=0)
Nt_widget = IntSlider(min=50, max=5000, step=50, value=200)

def update_Nt_range(*args):
    k_widget.max = Nt_widget.value
Nt_widget.observe(update_Nt_range, 'value')

interact(plot_solution_heat_equation2,P=P_Heat,Nx=(5,50,5),Nt=Nt_widget,k=k_widget,solver=['forward_difference'],bc=['periodic'])


I am working on the file "SC2/U4_HeatEquation.ipynb".
The first task is:

EDP Parabólica: Ecuación de Calor
En esta sección estudiaremos una clase distinta (y muy común) de EDPs: Parabólicas, en partícular, la ecuación de calor:
$$
u_t(x,t) = D\, u_{xx}(x,t).
$$
Este corresponde a un modelo de difusión, que explica como una variable $u(x,t)$ a lo largo de una dimensión espacial $x$, se propaga desde regiones de mayores concentraciones hacia menores concentraciones, a lo largo del tiempo $t$, hasta alcanzar un estado estable.  En este sentido el coeficiente $D$ representa la capacidad de dufisividad, esto es, la fácilidad con la que puede propagarse a lo largo del medio.

Diferencias Finitas (Forward Difference)
Similar a como se hizo para solucionar numéricamente ODEs, se puede discretizar cada derivada parcial de la PDE con finite differences.  Sea la siguiente PDE (ecuación de calor) con sus condiciones de borde:
\begin{align}
u_t(x,t) &= D\, u_{xx}(x,t) \
u(x,0) &= f(x) \
u(a,t) &= l(t) \
u(b,t) &= r(t) \
\end{align}
Un primer enfoque es utilizar forward difference para aproximar la derivada temporal, y centered difference formula para la segunda derivada espacial, del siguiente modo:
\begin{align}
u_t(x,t) &\approx \frac{1}{k} \left( u(x, t+k) - u(x,t) \right) \
u_{xx}(x,t) &\approx \frac{1}{h^2} \left( u(x+h,t) - 2 u(x,t) + u(x-h, t)  \right),
\end{align}
siendo $k,h$ el time step y spatial step respectivamente. Si por simplicidad se denota $w_{i,j} = u(x_i, t_j)$, entonces la discretización de la ecuación queda del siguiente modo:
$$
\frac{1}{k} (w_{i,j+1} - w_{i,j}) \approx \frac{D}{h^2} ( w_{i+1,j}-2 w_{i,j} + w_{i-1,j} ),
$$
con error de aproximación del orden $O(k) + O(h^2)$.
(Idea) La idea del método es la siguiente; Dado que por la condiciones de borde y las condiciones iniciales, sabemos los valores de $w_{0,j}, w_{M,j}, w_{i,0} \ \ \forall i,j$, determinar sucesivamente los valores $w_{i,j}$ en los tiempos siguientes,
\begin{align}
t_1:  \ (w_{1,1}, w_{2,1}, &\ldots, w_{M-1,1}) \
t_2:  \ (w_{1,2}, w_{2,2}, &\ldots, w_{M-1,2}) \
 &...
Can you write Python code for it?

def heat_equation_forward_differences(P, Nx, Nt, bc='boundary'):
    """
    Solves the heat equation using forward differences
    """
    if bc=='dirichlet':
        x = np.linspace(P["xmin"], P["xmax"], Nx)
        t = np.linspace(P["tmin"], P["tmax"], Nt)
        dx = x[1]-x[0]
        dt = t[1]-t[0]
        S = P["D"]*dt/dx**2
        print("CFL condition: D*dt/dx^2 = ",S, " <= 0.5 ?")
        # Storage
        u = np.zeros((Nx, Nt))
        # Time Loop
        for i, ti in enumerate(t):
            if i==0:
                u[:,0] = P["f"](x)
            else:
                u[ 0,i] = P["l"](ti)
                u[-1,i] = P["r"](ti)
                u[1:-1, i] = S*u[:-2, i-1] + (1-2*S)*u[1:-1,i-1]+S*u[2:,i-1]
        return x, t, u

    elif bc=='periodic':
        x = np.linspace(P["xmin"], P["xmax"], Nx)
        t = np.linspace(P["tmin"], P["tmax"], Nt)
        dx = x[1]-x[0]
        dt = t[1]-t[0]
        S = P["D"]*dt/dx**2
        print("CFL condition: D*dt/dx^2 = ",S, " <= 0.5 ?")
        # Storage
        u = np.zeros((Nx, Nt))
        # Time Loop
        for i, ti in enumerate(t):
            if i==0:
                u[:,0] = P["f"](x)
            else:
                u[0, i] = S*u[-2, i-1] + (1-2*S)*u[0,i-1]+S*u[1,i-1]
                u[1:-1, i] = S*u[:-2, i-1] + (1-2*S)*u[1:-1,i-1]+S*u[2:,i-1]
                u[-1, i] = S*u[-2, i-1] + (1-2*S)*u[-1,i-1]+S*u[1,i-1]
        return x, t, u

def heat_equation_backward_differences(P, Nx, Nt, bc='dirichlet'):
    """
    Solves the heat equation using backward differences
    """
    if bc=='dirichlet':
        x = np.linspace(P["xmin"], P["xmax"], Nx)
        t = np.linspace(P["tmin"], P["tmax"], Nt)
        dx = x[1]-x[0]
        dt = t[1]-t[0]
        S = P["D"]*dt/dx**2
        print("CFL condition not required: D*dt/dx^2 = ",S)
        # Constructing the matrix
        A = np.diag(-S*np.ones(Nx-3),-1) + np.diag((1+2*S)*np.ones(Nx-2),0) + np.diag(-S*np.ones(Nx-3),+1)
        # Storage
        u = np.zeros((Nx, Nt))
        # Time Loop
        for...


I am working on the file "SC2/U4_HeatEquation.ipynb".
The first task is:
Experimentación
Can you write Python code for it?

f1 = lambda x: np.sin(2*np.pi*x)**2
l1 = lambda t: t
r1 = lambda t: t
P1 = {"xmin":0, "xmax":1, "tmin":0, "tmax":1.0, "D":1, "f":f1, "l":l1, "r":r1}

f2 = lambda x: 10*np.exp(-(x-.5)**2/0.01)
l2 = lambda t: 0
r2 = lambda t: 0
P2 = {"xmin":0, "xmax":1, "tmin":0, "tmax":1.0, "D":1, "f":f2, "l":l2, "r":r2}

f3 = lambda x: x
l3 = lambda t: 0
r3 = lambda t: 0
P3 = {"xmin":0, "xmax":1, "tmin":0, "tmax":1.0, "D":1, "f":f3, "l":l3, "r":r3}

P_Heat=[('P1', P1), ('P2', P2),('P3', P3)]

def plot_solution_heat_equation2(P, Nx=10, Nt=50, k=0, solver='forward_difference', bc='dirichlet'):
    if solver=='forward_difference':
        x, t, u = heat_equation_forward_differences(P, Nx, Nt, bc=bc)
        show2(x, t, u, k)
    else:
        x, t, u = heat_equation_backward_differences(P, Nx, Nt, bc=bc)
        show2(x, t, u, k)
    return

k_widget = IntSlider(min=0, max=30, step=1,value=0)
Nt_widget = IntSlider(min=50, max=5000, step=50, value=200)

def update_Nt_range(*args):
    k_widget.max = Nt_widget.value
Nt_widget.observe(update_Nt_range, 'value')

interact(plot_solution_heat_equation2,P=P_Heat,Nx=(5,50,5),Nt=Nt_widget,k=k_widget,solver=['forward_difference','backward_difference'],bc=['dirichlet'])


I am working on the file "SC2/U4_WaveEquation1D_Dirichlet.ipynb".
The first task is:

Ecuación de Onda 1D
Consideremos la siguiente EDP hiperbólica, para $ x \in [a,b] \ \ $ y $t \in [0,T_{max}] \ \ $:
\begin{align}
u_{tt}(x,t) &= c^2\, u_{xx}(x,t) \
u(x,0) &= f(x)\
u_t(x,0) &= g(x)\
u(a,t) &= l(t)\
u(b,t) &= r(t)
\end{align}
Utilizando diferencias finitas, la ecuación nos queda:
\begin{align}
u_{tt}(x,t) &= c^2\, u_{xx}(x,t) \
\dfrac{u_i^{t+1}-2u_i^t+u_i^{t-1}}{\Delta t^2} &= c^2\, \dfrac{u_{i+1}^t-2u_i^t+u_{i-1}^t}{\Delta x^2}
\end{align}
Nuestra incógnita sería $u_i^{t+1}$, la cual se puede calcular teniendo información de los dos tiempos anteriores. Por lo tanto, despejando llegamos a:
$$u_i^{t+1} = \dfrac{c^2 \Delta t^2}{\Delta x^2}\left(u_{i+1}^t + u_{i-1}^t\right) + 2\left(1 - \dfrac{c^2 \Delta t^2}{\Delta x^2}\right)u_i^t - u_i^{t-1}$$
Si bien esto se resuelve directamente a medida que avanzamos en el tiempo, en $t=1$ nos faltará el valor de $u_i^{-1}$, pero recordando que:
$$u_t = \dfrac{u_i^{t+1} - u_i^{t-1}}{2\Delta t}$$
se puede utilizar la condición incial para obtener:
\begin{align}
u_i^{t+1} &= \dfrac{c^2 \Delta t^2}{2 \Delta x^2}\left(u_{i+1}^t + u_{i-1}^t\right) + \left(1 - \dfrac{c^2 \Delta t^2}{\Delta x^2}\right)u_i^t + \Delta t u_t \
u_i^1 &= \dfrac{c^2 \Delta t^2}{2 \Delta x^2}\left(u_{i+1}^0 + u_{i-1}^0\right) + \left(1 - \dfrac{c^2 \Delta t^2}{\Delta x^2}\right)u_i^0  + \Delta t u_t(x_i,0)
\end{align}

Finite Differences con condición de borde de Dirichlet
Can you write Python code for it?

def Dirichlet(x,f,g,l,r,c2,dx,dt,N,M):

    sigma2 = c2 * dt**2 / dx**2

    print('sigma**2= ',sigma2)

    # The approximation for all time-steps
    w  = np.zeros((M+1,N))

    # Initial condition
    w[0,:]=f

    # Building A
    d=np.zeros(N-2)
    d[0]=2-2*sigma2
    d[1]=sigma2
    A=spla.toeplitz(d)

    ## First step
    tmp=np.zeros(N-2)
    tmp[0]=w[0,0]
    tmp[-1]=w[0,-1]
    w[1,1:-1]=0.5*(np.dot(A,w[0,1:-1]))+dt*g[1:-1]+0.5*sigma2*tmp

    ## All the rest of the steps
    for t in range(2,M+1):
        tmp[0]=l(dt*t)
        tmp[-1]=r(dt*t)
        w[t,1:-1]=np.dot(A,w[t-1,1:-1])-w[t-2,1:-1]+sigma2*tmp
        w[t,0]=l(dt*t)
        w[t,-1]=r(dt*t)
    return w

def l(t):
    return 0*t

def r(t):
    return 0*t

def plot(us,i=0):
    plt.plot(x,us[i])
    plt.ylim(-0.11,0.11)
    plt.title('Tiempo: '+str(i*dt))
    plt.grid()
    plt.show()

N=100
M=200
TMAX = 40
x = np.linspace(-20,20,N)
t = np.linspace(0,TMAX,M)

c = 1

dx = x[1]-x[0]
dt = t[1]-t[0]

# RECALL: CFL condition:
#  if c dt/dx<=1 => stability
#  else (c dt/dx>1) instability.

## Numerical Initial Conditions, notice these are numerical arrays!
# i.e. vectors not functions.
# u(x,0)=f(x)
f1 = 0.1*np.exp(-x**2)
f2 = 0.1*np.sin(2*x*np.pi/8)

# u_t(x,0)=f(x)
# SOLITON
g1 = (np.exp(-(x-0.2)**2) - np.exp(-(x+0.2)**2))/2
# ONDA QUE SE DIVIDE
g2 = np.zeros(N)

us1 = Dirichlet(x,f1,g1,l,r,c**2,dx,dt,N,M)

dp = 1
widgets.interact(plot,us=widgets.fixed(us1),i=(0,M,dp))

us2 = Dirichlet(x,f1,g2,l,r,c**2,dx,dt,N,M)

dp = 1
widgets.interact(plot,us=widgets.fixed(us2),i=(0,M,dp))

us3 = Dirichlet(x,f2,g2,l,r,c**2,dx,dt,N,M)

dp = 1
widgets.interact(plot,us=widgets.fixed(us3),i=(0,M,dp))


I am working on the file "SC3/01_MC_theorem_Halton_distance_matrix_and_RBF_interpolation.ipynb".
The first task is:
Defining a test function
Can you write Python code for it?

# The function to be interpolated
f=lambda x,y: 16*x*(1-x)*y*(1-y)

def showing_f(n=10, elev=40, azim=230):
    fig = plt.figure(figsize=(2*M,M))

    # Creating regular mesh
    Xr = np.linspace(0, 1, n)
    Xm, Ym = np.meshgrid(Xr,Xr)
    Z = f(Xm,Ym)

    # Wireframe
    plt.subplot(221,projection='3d')
    ax = fig.gca()
    ax.plot_wireframe(Xm, Ym, Z)
    ax.view_init(elev,azim)

    # imshow
    plt.subplot(222)
    #plt.imshow(Z,interpolation='none', extent=[0, 1, 0, 1])
    plt.contourf(Xm, Ym, Z, 20)
    plt.ylabel('$y$')
    plt.xlabel('$x$')
    plt.axis('equal')
    plt.xlim(0,1)
    plt.colorbar()

    # Contour plot
    plt.subplot(223)
    plt.contour(Xm, Ym, Z, 20)
    plt.axis('equal')
    plt.colorbar()

    # Surface
    plt.subplot(224,projection='3d')
    ax = fig.gca()
    surf = ax.plot_surface(Xm, Ym, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
                           linewidth=0, antialiased=False)
    fig.colorbar(surf)
    ax.view_init(elev,azim)

    plt.show()


I am working on the file "SC3/01_MC_theorem_Halton_distance_matrix_and_RBF_interpolation.ipynb".
The first task is:
Halton points vs pseudo-random points in 2D
Can you write Python code for it?

def plot_random_vs_Halton(n=100):
    # Number of points to be generated
    # n=1000
    # I am reseting the sequence everytime I generated just to get the same points
    sequencer.reset()
    xH=np.array(sequencer.get(n))
    np.random.seed(0)
    xR=np.random.rand(n,2)

    plt.figure(figsize=(2*M,M))

    plt.subplot(121)
    plt.scatter(xR[:,0], xR[:,1], s=100, c="r", alpha=1.0, marker='.',
                label="Random", edgecolors='None')
    plt.axis([0,1,0,1])
    plt.title(r'Pseudo-random points')
    plt.grid(True)

    plt.subplot(122)
    plt.scatter(xH[:,0], xH[:,1], s=100, c="b", alpha=1.0, marker='.',
                label="Halton")
    plt.axis([0,1,0,1])
    plt.title(r'Quasi-random points (Halton)')
    plt.grid(True)

    plt.show()

interact(plot_random_vs_Halton,n=(20,500,20))


I am working on the file "SC3/01_MC_theorem_Halton_distance_matrix_and_RBF_interpolation.ipynb".
The first task is:
Interpolation with Distance Matrix from Halton points
Can you write Python code for it?

def show_R(mH=10):
    fig= plt.figure(figsize=(2*M*mH/12,M*mH/12))
    ax = plt.gca()
    sequencer.reset()
    X=np.array(sequencer.get(mH))
    R=distance_matrix(X, X)
    plot_matrices_with_values(ax,R)

interact(show_R,mH=(2,20,1))


I am working on the file "SC3/01_MC_theorem_Halton_distance_matrix_and_RBF_interpolation.ipynb".
The first task is:
Mairhuber-Curtis Theorem
Can you write Python code for it?

# Initializing a R^2
sequencer = ghalton.Halton(2)
sequencer.reset()
xH=np.array(sequencer.get(9))
print(xH)

def show_MC_theorem(s_local=0):
    i=3
    j=4
    NC=40

    sequencer.reset()
    xH=np.array(sequencer.get(9))

    phi1= lambda s: (s-0.5)*(s-1)/((0-0.5)*(0-1))
    phi2= lambda s: (s-0)*(s-1)/((0.5-0)*(0.5-1))
    phi3= lambda s: (s-0)*(s-0.5)/((1-0)*(1-0.5))
    C1=lambda s: xH[i,:]*phi1(s)+np.array([0.45,0.55])*phi2(s)+xH[j,:]*phi3(s)
    C2=lambda s: xH[j,:]*phi1(s)+np.array([0.15,0.80])*phi2(s)+xH[i,:]*phi3(s)
    C1v=np.vectorize(C1,otypes=[np.ndarray])
    C2v=np.vectorize(C2,otypes=[np.ndarray])
    ss=np.linspace(0,1,NC).reshape((-1, 1))
    C1o=np.array(C1v(ss))
    C2o=np.array(C2v(ss))
    C1plot=np.zeros((NC,2))
    C2plot=np.zeros((NC,2))
    for k in np.arange(0,NC):
        C1plot[k,0]=C1o[k][0][0]
        C1plot[k,1]=C1o[k][0][1]
        C2plot[k,0]=C2o[k][0][0]
        C2plot[k,1]=C2o[k][0][1]

    plt.figure(figsize=(2*M,M))
    plt.subplot(121)
    plt.plot(C1plot[:,0],C1plot[:,1],'r--')
    plt.plot(C2plot[:,0],C2plot[:,1],'g--')
    plt.scatter(xH[:,0], xH[:,1], s=300, c="b", alpha=1.0, marker='.',
                label="Halton")
    plt.scatter(C1(s_local)[0], C1(s_local)[1], s=300, c="r", alpha=1.0, marker='d')
    plt.scatter(C2(s_local)[0], C2(s_local)[1], s=300, c="g", alpha=1.0, marker='d')
    plt.axis([0,1,0,1])
    plt.title(r'Quasi-random points (Halton)')
    plt.grid(True)

    xHm=np.copy(xH)
    xHm[i,:]=C1(s_local)
    xHm[j,:]=C2(s_local)
    R=distance_matrix(xHm, xH)
    det_s_local=np.linalg.det(R)

    plt.subplot(122)
    plt.title(r'det(R_fixed)='+str(det_s_local))
    det_s=np.zeros_like(ss)
    for k, s in enumerate(ss):
        xHm[i,:]=C1plot[k,:]
        xHm[j,:]=C2plot[k,:]
        R=distance_matrix(xHm, xH)
        det_s[k]=np.linalg.det(R)

    plt.plot(ss,det_s,'-')
    plt.plot(s_local,det_s_local,'dk',markersize=16)
    plt.grid(True)

    plt.show()

interact(show_MC_theorem,s_local=(0,1,0.1))


I am working on the file "SC3/01_MC_theorem_Halton_distance_matrix_and_RBF_interpolation.ipynb".
The first task is:
RBF interpolation
Can you write Python code for it?

# Some RBF's
linear_rbf   = lambda r,eps: r
gaussian_rbf = lambda r,eps: np.exp(-(eps*r)**2)
MQ_rbf       = lambda r,eps: np.sqrt(1+(eps*r)**2)
IMQ_rbf      = lambda r,eps: 1./np.sqrt(1+(eps*r)**2)
# The chosen one! But please try all of them!
rbf          = lambda r,eps: MQ_rbf(r,eps)

def eval_interp_rbf(C,X,x,y,eps):
    A=rbf(distance_matrix(X, np.array([[x,y]])),eps)
    return np.dot(C,A)

def showing_f_interpolated_rbf(n=10, mH=10, elev=40, azim=230, eps=1):
    fig = plt.figure(figsize=(2*M,M))

    # Creating regular mesh
    Xr = np.linspace(0, 1, n)
    Xm, Ym = np.meshgrid(Xr,Xr)
    Z = f(Xm,Ym)

    ########################################################
    ## Pseudo-random
    ## Building distance matrix and solving linear system
    np.random.seed(0)
    X=np.random.rand(mH,2)
    R=distance_matrix(X,X)
    A=rbf(R,eps)
    Zs=f(X[:,0],X[:,1])
    C=np.linalg.solve(A,Zs)
    # f interpolated with distance function
    fIR=np.vectorize(eval_interp_rbf, excluded=[0,1,4])

    # Contour plot - Original Data
    plt.subplot(231)
    plt.contour(Xm, Ym, fIR(C,X,Xm,Ym,eps), 20)
    plt.colorbar()
    plt.scatter(X[:,0], X[:,1], s=100, c="r", alpha=0.5, marker='.',
                label="Random", edgecolors='None')
    plt.title(r'$f(x,y)_{rbf}$ with Pseudo-random points')

    # Surface - Original Data
    plt.subplot(232,projection='3d')
    ax = fig.gca()
    surf = ax.plot_surface(Xm, Ym, fIR(C,X,Xm,Ym,eps), rstride=1, cstride=1, cmap=cm.coolwarm,
                           linewidth=0, antialiased=False)
    fig.colorbar(surf)
    ax.view_init(elev,azim)
    ax.set_zlim(0,1)
    plt.title(r'$f(x,y)_{rbf}$ with Pseudo-random points')

    # Contour plot - Original Data
    plt.subplot(233)
    plt.contourf(Xm, Ym, np.abs(f(Xm,Ym)-fIR(C,X,Xm,Ym,eps)), 20)
    #plt.imshow(np.abs(f(Xm,Ym)-fIR(C,X,Xm,Ym,eps)),interpolation='none', extent=[0, 1, 0, 1])
    plt.axis('equal')
    plt.xlim(0,1)
    plt.colorbar()
    plt.scatter(X[:,0], X[:,1], s=100, c="k", alpha=0.8, marker='.',
         ...


I am working on the file "SC3/01_MC_theorem_Halton_distance_matrix_and_RBF_interpolation.ipynb".
The first task is:
The interpolation with distance matrix itself
Can you write Python code for it?


I am working on the file "SC4/Chapter 1 - Intro IVP.ipynb".
The first task is:
Example 10, for completeness.
$$\begin{equation}
f(t)=
\begin{cases}
t\,\sin(t), & 0\leq t < 2, \
\dfrac{\sin(\pi\,t)}{t}, & 2 < t.
\end{cases}
\end{equation}$$
Can you write Python code for it?

t = np.linspace(0,4,100)

def f(t):
    if t<=2:
        return t*np.sin(t)
    else:
        return np.sin(np.pi*t)/t

fv=np.vectorize(f, otypes=[np.float64])

plt.figure()
plt.plot(t,fv(t),'b-',label='$f(t)$')
plt.plot(t[t<=2],fv(t[t<=2]),'r--',label=r'$f_r(t)$')
plt.plot(t[t>2],fv(t[t>2]),'r--')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid(True)
plt.show()


I am working on the file "SC4/Chapter 1 - Intro IVP.ipynb".
The first task is:
Example 11, for completeness.
Write a function that return $f(t)=\exp(-\alpha\,t^2)$ and $f'(t)=-2\,\alpha\,t\,\exp(-\alpha\,t^2)$.
Can you write Python code for it?

def f_and_fprime(t,alpha):
    f = lambda t: np.exp(-alpha*t**2)
    fp = lambda t: -2*alpha*t*f(t)
    return np.array([f(t),fp(t)])

print(f_and_fprime(t=1,alpha=1))


I am working on the file "SC4/Chapter 1 - Intro IVP.ipynb".
The first task is:
Example 2
Considers the following IVP:
$$\begin{align}
\dfrac{\mathrm{d}x}{\mathrm{d}t}(t) &= \sqrt{x(t)}\
x(0) &= 0,
\end{align}$$
Recall that $2^{-1074}$ is the smallest number greater than 0 that ``double precision'' can store. See:
- https://github.com/tclaudioe/Scientific-Computing/blob/master/SC1v2/02_floating_point_arithmetic.ipynb
Can you write Python code for it?

print(2**-1074,', ',2**-1075)

# Example 2, numerically.
def f_example_2(t,y):
    return np.sqrt(y)
# Initial condition
y0 = 0.0
# time where we want your solution
t = np.linspace(0, 1, 100)
sol_a = solve_ivp(f_example_2, [0,1], (y0,), t_eval=t)
sol_b = solve_ivp(f_example_2, [0,1], (y0+np.power(2.0,-1074),), t_eval=t)

plt.figure()
plt.plot(t, sol_a.y[0], 'b', label='y_a(t)')
plt.plot(t, sol_b.y[0], 'r', label='y_b(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid(True)
plt.show()


I am working on the file "SC4/Chapter 1 - Intro IVP.ipynb".
The first task is:
Example 4
See classnotes!
Can you write Python code for it?

def f_example_4(t,y,alpha):
    return alpha*(1/2-y/(1+y))

# Initial condition
y0=3
# time where we want your solution
t = np.linspace(0, 10, 100)

plt.figure(figsize=(10,8))
for j in np.arange(1,6):
    sol= odeint(f_example_4, y0, t, args=(4/j,), tfirst=True)
    plt.plot(t, sol, label=r'$\xi(t)$'+r', $\tau= $'+str(j))
    plt.axvline(x=j,color='k')
    plt.text(j,0.5,r'$\tau= $'+str(j))
plt.legend(loc='best')
plt.ylabel('Concentration')
plt.xlabel('t')
plt.ylim((0,3))
plt.grid(True)
plt.show()

def f_example_4b(t,y,alpha,phi_in):
    return phi_in-alpha*(y/(1+y))

# Initial condition
y0=3
# time where we want your solution
t = np.linspace(0, 1, 100)

plt.figure(figsize=(10,8))
sol= odeint(f_example_4b, y0, t, args=(4,5), tfirst=True)
plt.plot(t, sol, label=r'$\xi(t)$')
plt.legend(loc='best')
plt.ylabel('Concentration')
plt.xlabel('t')
plt.title(r'What happens then if $\phi_{in}\geq\alpha$?')
plt.grid(True)
plt.show()


I am working on the file "SC4/Chapter 1 - Intro IVP.ipynb".
The first task is:
Example 7, for completeness.
Plotting:
$$\begin{align}
f(t) &= \dfrac{t^2}{\pi^2+t^2}\,\sin(5\,t),\quad 0 \leq t \leq 4\,\pi
\end{align}$$
Can you write Python code for it?

t = np.linspace(0,4*np.pi,100)

f = lambda t: (t**2/(np.pi**2+t**2))*np.sin(t)

plt.figure()
plt.plot(t,f(t),'b-',label='f(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid(True)
plt.show()


I am working on the file "SC4/Chapter 1 - Intro IVP.ipynb".
The first task is:
Hints:
I strongly suggest to review the following jupyter notebook:
- [Intro to ODE] https://github.com/tclaudioe/Scientific-Computing/blob/master/SC1v2/11_ODE.ipynb
1.2 Ordinary differential equations
A differential equation, in this case a scalar initial value problem (IVP), can be defined as follows:
$$\begin{align}
    \dfrac{\mathrm{d}x}{\mathrm{d}t}(t) &= f(t,x(t)),\
    x(0) &= x_0.
\end{align}$$
For a known function $f(t,x)$ and $x_0$.
Particularly one could integrate both sides of the first equation as follows,
$$\begin{align}
    \int_0^{h} \dfrac{\mathrm{d}x}{\mathrm{d}t}(t)\,\mathrm{d}t & = \int_0^{h} f(t,x(t))\,\mathrm{d}t,\
    x(h)-x(0) &= \int_0^{h} f(t,x(t))\,\mathrm{d}t,
\end{align}$$
where the Fundamental Theorem of Calculus was used.
Now, we solve for the unknow value $x(h)$:
$$\begin{align}
    x(h) &= x_0 + \int_0^{h} f(t,x(t))\,\mathrm{d}t.
\end{align}$$
Up to this point, we have not made any approximation.
From this point, one can derive several numerical method, depending how you approximate the integral.
For instance, if we consider $h=\Delta t$ and we use a Reimann sum from the left (only one interval from $0$ to $\Delta t$), we obtain the method called Forward Euler.
But if we do the same but with the Reimann sum from the right, we obtain backward Euler.
Another two options that are easy to see are the midpoint rule and the trapezoidal rule.
Notice that in some cases mentioned, you would need a non-linear equation (or a system in higher dimension) for each time step.
Example 1
Considers the following IVP:
$$\begin{align}
\dfrac{\mathrm{d}x}{\mathrm{d}t}(t) &= -\alpha\,x(t),\
x(0) &= x_0,
\end{align}$$
for which we know the solution:
$$\begin{align}
x(t) &= x_0\,\exp(-\alpha\,t)
\end{align}$$
Can you write Python code for it?

# Warning: In general, we will use \dot{y}=f(t,y), y(0)=y_0,
# so don't get mixed up with the notation from the textbook.

def f_example_1_interact(alpha_input=1,T_max=5,p=2):
    # Example 1, numerically.
    def f_example_1(t, y, alpha):
        return -alpha*y

    # Initial condition
    y0=1
    # time where we want your solution
    t = np.linspace(0, T_max, 100)

    sol = solve_ivp(f_example_1, [0,T_max], (y0,), t_eval=t, args=(alpha_input,))

    plt.figure()
    plt.plot(t, sol.y[0], 'b', label='y(t)')
    for i in np.arange(1,np.ceil(T_max/(np.log(p)/alpha_input))):
        plt.axvline(x=i*np.log(p)/alpha_input)
        print('t: ',i*np.log(p)/alpha_input,', exp(t): ',np.exp(-alpha_input*i*np.log(p)/alpha_input))
    plt.legend(loc='best')
    plt.xlabel('t')
    plt.ylabel(r'$\exp(-\alpha\,t)$')
    plt.title('What are the red lines?')
    plt.grid(True)
    plt.show()
interact(f_example_1_interact,alpha_input=(0.1,10,0.1),T_max=(0.1,100,0.1),p=(2,10,1))


I am working on the file "SC4/Chapter 2 - Compartment models.ipynb".
The first task is:
2.1 Simple compartment models
Example 1:
Can you write Python code for it?

# Example 1, numerically.
def f_example_1(t,y,c,k1,k2):
    X = y[0]
    Y = y[1]

    Xp = c(t)-k1*X
    Yp = k1*X-k2*Y

    return np.array([Xp,Yp])

# Initial condition
y0 = np.array([500, 600])
a  = 1200
t1 = 12*60
t2 = 19*60
tau = 30
c  = lambda t: a*(np.exp(-((np.mod(t,24*60)-t1)**2)/(2*tau**2)) \
                +np.exp(-((np.mod(t,24*60)-t2)**2)/(2*tau**2))) \
                /(np.sqrt(2*np.pi*tau**2))

T_digest = 80
T_metabolic = 240
k1 = 1/T_digest
k2 = 1/T_metabolic

T = 2*24*60

# time where we want your solution
t = np.linspace(0, T, 100)
sol = solve_ivp(f_example_1, [0,T], y0, t_eval=t, args=(c,k1,k2))

plt.figure()
plt.plot(t, sol.y[0], 'b', label='X(t): Energy in gastric channel')
plt.plot(t, sol.y[1], 'r', label='Y(t): Energy in blood')
plt.legend(loc='right', bbox_to_anchor=(2, 0.5))
plt.xlabel('t')
plt.ylabel('kcal')
plt.grid(True)
plt.show()

print(t1,t2)

plt.figure()
T = 5*24*60
t = np.linspace(0, T, 1000)
plt.plot(t,c(t),'b')
plt.grid(True)
plt.plot()


I am working on the file "SC4/Chapter 2 - Compartment models.ipynb".
The first task is:
2.2 Subcompartment models
Example 5
Can you write Python code for it?

# Volumnes
Vol_ch = 50./1000
Vol_t  = 0.3/1000

# Initial conditions in chamber
Lac_ch_0 = 0.3
Glc_ch_0 = 1.6
O2_ch_0  = 0.6
CO2_ch_0 = 0.1
x0 = np.array([Lac_ch_0,Glc_ch_0,O2_ch_0,CO2_ch_0])

# Initial conditions in tissue
Lac_t_0  = 0.8
Glc_t_0  = 0.5
O2_t_0   = 0.14
CO2_t_0  = 0.2
ATP_t_0  = 6.2
ADP_t_0  = 0.8
y0 = np.array([Lac_t_0,Glc_t_0,O2_t_0,CO2_t_0,ATP_t_0,ADP_t_0])

# Maximum rates
T1 = 5e-5
T2 = 3e-5
V1 = 1e-4
V2 = 1e-4

# Affinities
M1 = 0.5
M2 = 0.5
K1 = 0.5
K2 = 0.22
mu1 = 0.1
mu2 = 0.1

#Fick's constants
lambda3 = 3e-3
lambda4 = 8e-3

# Constants defining the activity
t0  = 3. # min
tau = 10./60 # min

# Activity levels
a0      = 1e-5
delta_a = 1e-2

def f_example_5(t,z):
    x = z[:4]
    y = z[4:]

    Phi = np.zeros(4)
    Phi[0] = T1*((x[0]/(x[0]+M1))-(y[0]/(y[0]+M1)))
    Phi[1] = T2*((x[1]/(x[1]+M1))-(y[1]/(y[1]+M1)))
    Phi[2] = lambda3*(x[2]-y[2])
    Phi[3] = lambda4*(x[3]-y[3])

    p = y[5]/y[4]
    Psi1 = V1*(p/(p+mu1))*(y[1]/(y[1]+K1))
    rho1 = np.array([2.,-1,0,0,2,-2])*Psi1

    Psi2 = V2*(p/(p+mu2))*(y[1]*y[2]/(y[1]*y[2]+K2**2))
    rho2 = np.array([0.,-1,-6,6,32,-32])*Psi2

    a = a0+delta_a*(np.heaviside(t-(t0), 1)-np.heaviside(t-(t0+tau), 1))
    rho3 = np.array([0.,0,0,0,-1,1])*a

    dxdt = -Phi/Vol_ch

    dydt = np.zeros(6)
    dydt[:4] = Phi
    dydt += rho1+rho2+rho3
    dydt /=Vol_t
    return np.concatenate((dxdt,dydt), axis=0)

# Initial condition
z0 = np.concatenate((x0,y0), axis=0)

T = 10
# time where we want your solution
t = np.linspace(0, T, 100)

sol = solve_ivp(f_example_5, [0,T], z0, t_eval=t)

plt.figure(figsize=(10,10))

plt.subplot(221)
plt.plot(t, sol.y[4], 'b-', label='Lac_t(t)')
plt.plot(t, sol.y[5], 'b--', label='Glc_t(t)')
plt.legend(loc='best')
plt.axvline(x=t0,color='k',alpha=0.5)
plt.axvline(x=t0+tau,color='k',alpha=0.5)
plt.xlabel('t [min]')
plt.ylabel('concentration [mmol/l]')
plt.ylim([0.2,1])
plt.grid(True)

plt.subplot(222)
plt.plot(t, sol.y[6], 'b-', label='O2_t(t)')
plt.plot(t, sol.y[7], 'b--',...


I am working on the file "SC4/Chapter 2 - Compartment models.ipynb".
The first task is:
2.2.- Interacting population models
2.2.1.- Predator-prey models
Example 3
Can you write Python code for it?

# Example 1, numerically.
def f_example_3(t,y,eta,gamma,eps):
    X = y[0]
    Y = y[1]

    Xp = eta*X*(1-Y/(eta/gamma))
    Yp = -eps*Y*(1-X/(eps/delta))

    return np.array([Xp,Yp])

# Initial condition

eta = 8-1/2
eps = 1/5
gamma = 1/100
delta = eps*gamma/(20*eta)

X_eq = eps/delta
Y_eq = eta/gamma

y0 = np.array([0.9*X_eq, 1.2*Y_eq])

T = 15

# time where we want your solution
t = np.linspace(0, T, 100)
sol = solve_ivp(f_example_3,[0,T], y0, t_eval=t, args=(eta,gamma,eps))

X_output = sol.y[0]
Y_output = sol.y[1]

fig, ax1 = plt.subplots()
color = 'tab:blue'
ax1.set_xlabel('time [years]')
ax1.set_ylabel('Prey population', color=color)
ax1.plot(t, X_output, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax2 = ax1.twinx()  # instantiate a second axes that shares the same x-axis
color = 'tab:green'
ax2.set_ylabel('Predator population', color=color)  # we already handled the x-label with ax1
ax2.plot(t, Y_output, color=color)
ax2.tick_params(axis='y', labelcolor=color)
fig.tight_layout()  # otherwise the right y-label is slightly clipped
plt.show()

plt.figure()
plt.plot(t,X_output,'b')
plt.plot(t,Y_output,'r')
plt.grid(True)
plt.show()

plt.figure()
plt.plot(X_output,Y_output,'k')
plt.xlabel('prey')
plt.ylabel('predator')
plt.plot(X_eq,Y_eq,'b.',markersize=20)
plt.plot(y0[0],y0[1],'r.',markersize=20)
plt.text(X_eq,Y_eq,'  equilibrium state')
plt.text(y0[0],y0[1],'  initial state')
plt.show()

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(X_output, Y_output, t,'b')
ax.view_init(elev=40,azim=230)
plt.xlabel('prey')
plt.ylabel('predator')
ax.set_zlabel('t')
plt.show()


I am working on the file "SC4/Chapter 2 - Compartment models.ipynb".
The first task is:
2.2.3.- Endemic diseases
Can you write Python code for it?

# Example 1, numerically.
def f_SIR_endemic(t,y,alpha,beta,sigma,N):
    S = y[0]
    I = y[1]
    R = y[2]

    Sp = -alpha*I*S+sigma*N-sigma*S
    Ip = alpha*I*S-beta*I-sigma*I
    Rp = beta*I-sigma*R

    return np.array([Sp,Ip,Rp])

# Initial condition
N = 1e6
alpha = 1e-6
beta = 1/3
sigma = 1/50

S0 = 9e5
I0 = 1e5
y0 = np.array([S0, I0, N-S0-I0])

T = 150

# time where we want your solution
t = np.linspace(0, T, 100)
sol = solve_ivp(f_SIR_endemic, [0,T], y0, t_eval=t, args=(alpha,beta,sigma,N))

plt.figure()
plt.plot(t, sol.y[0], 'b', label='S(t)')
plt.plot(t, sol.y[1], 'r', label='I(t)')
plt.plot(t, sol.y[2], 'g', label='R(t)')
plt.legend(loc='right', bbox_to_anchor=(2, 0.5))
plt.xlabel('t')
plt.ylabel('number of individuals')
plt.grid(True)
plt.show()


I am working on the file "SC4/Chapter 2 - Compartment models.ipynb".
The first task is:
Logistic growth with harvesting
Can you write Python code for it?

def f_logistic_growth_harvesting(t,y,r,K,h):
    X = y
    Xp = r*(1-X/K)*X-h
    return Xp

# Initial condition
r = 1
K = 1000
h = 100
print(K*r/4,h)

T = 8

Xplus = K/2*(1+np.sqrt(1-4*h/(K*r)))
Xminus = K/2*(1-np.sqrt(1-4*h/(K*r)))
print(Xplus,Xminus)

# time where we want your solution
t = np.linspace(0, T, 100)

plt.figure()
N=20
y0s = np.zeros(N+1)
y0s[0] = Xminus-0.5
y0s[1:] = np.linspace(Xminus,1200,N)
for y0 in y0s:
    sol = solve_ivp(f_logistic_growth_harvesting, [0,T], (y0,), t_eval=t, args=(r,K,h))
    plt.plot(t, sol.y[0], 'b')

plt.plot(t, sol.y[0]*0+Xplus, 'r')
plt.plot(t, sol.y[0]*0+Xminus, 'r')
plt.plot(t, sol.y[0]*0, 'r--')
plt.xlabel('t')
plt.ylabel('population size')
plt.grid(True)
plt.show()

plt.figure()
f = lambda X: -(r/K)*X**2+r*X-h
Xs = np.linspace(0,Xplus+200,100)
plt.plot(Xs, f(Xs), 'b')
plt.plot(Xs, f(Xs)*0, 'r')
plt.axvline(x=Xminus,color='k',label='$X_-$')
plt.axvline(x=Xplus,color='g',label='$X_+$')
plt.xlabel('X')
plt.legend(loc='right', bbox_to_anchor=(1.3, 0.5))
plt.grid(True)
plt.show()


I am working on the file "SC4/Chapter 8 - Markov processes.ipynb".
The first task is:
8.2 Stochastic predator-prey model
Can you write Python code for it?

def plot_S_Pred_Prey(seed=0):
    Nj       = 200 # number of X adult pair at t = t(j)
    Mj       = 50  # number of Y adult pair at t = t(j)
    p_mean   = 10  # mean number of X offsprings/adult pair
    p_std    = 3   # std of the number of the X offspring/adult pair
    beta     = 0.3 # Survival probability of X in the absence of Y
    Mstar    = 50  # number of Y that halves the survival prob. of X
    q_mean   = 4   # mean number of Y offspring/adult pair
    q_std    = 2   # std of the number of the Y offsrping/adult pair
    gamma    = 0.6 # Survival prob. of Y in adundance of X
    Nstar    = 400 # Number of X pairs at which the survival prob. of Y is halved

    nrounds  = 40  # Number of generations allowed

    N = np.full(nrounds,np.nan)
    N[0] = Nj
    M = np.full(nrounds,np.nan)
    M[0] = Mj
    Surv = np.full((nrounds-1,2),np.nan)

    np.random.seed(seed)

    for j in np.arange(1,nrounds):
        # Draw the number of offsprings of species X
        Pj = Nj*p_mean+np.sqrt(Nj)*p_std*np.random.randn()
        # Survival probability of the offspring of species X
        s = beta/(1+(Mj/Mstar)**2)
        Nj = s*Pj+np.sqrt(s*Pj*(1-s))*np.random.randn()
        N[j] = 0.5*Nj
        # Draw the number of offsprings of species Y
        Qj = Mj*q_mean+np.sqrt(Mj)*q_std*np.random.randn()
        # Survival probability of the offspring of species Y
        r = gamma*(1-1/(1+(Nj/Nstar)**2))
        Mj = r*Qj+np.sqrt(r*Qj*(1-r))*np.random.randn()
        M[j] = 0.5*Mj
        # Saving the survival probabilities for later analysis
        Surv[j-1,:]=[s,r]

    s=Surv[:,0]
    r=Surv[:,1]

    smean = np.sum(s)/(nrounds-1)
    rmean = np.sum(r)/(nrounds-1)
    Surv_c = Surv-np.array([smean,rmean])
    covSurv = np.dot(Surv_c.T,Surv_c)/(nrounds-1)
    corrcoeff = covSurv[0,1]/np.sqrt(covSurv[0,0]*covSurv[1,1])

    fig,  ((ax1,ax2),(ax3,ax4))   = plt.subplots(2, 2, figsize=(10,10))

    ax4.plot(N,'r.-')
    ax4.plot(M,'b.-')
    ax4.grid(True)

    s=Surv[:,0]
    r=Surv[:,1]
   ...


I am working on the file "SC4/Chapter 8 - Markov processes.ipynb".
The first task is:
Second algorithm: Power iteration. Warning: For the case of the Knight, this algorithm shows an interesting behavior and that seems to be related there are two eigenvalues with the magnitud equal to 1, one of the is actually equal to 1 but the other is equally to -1. This does not happen for the case of the King.
Can you write Python code for it?

def plot_P_n(nj, I, M):
    # Defining initial distribution
    (i0,j0)=(0,1)
    pcurr = np.zeros(64)
    pcurr[I[i0,j0]] = 1
    for j in np.arange(nj):
        pcurr = np.dot(M,pcurr)
    pcurrM = np.reshape(pcurr,(8,8),order='F')
    fig,  (ax1)   = plt.subplots(1, 1, figsize=(10,10))
    plot_matrices_with_values2(ax1,np.log10(pcurrM),True)
    # print(pcurr)
interact(lambda nj=0: plot_P_n(nj, I=I, M=M), nj = (0,2000,1))


I am working on the file "SC4/Chapter 8 - Markov processes.ipynb".
The first task is:
Third algorithm: Eigenvalues and eigenvectors. We need to look for the eigenvector associated to the eigenvalue equal to 1.
Can you write Python code for it?

w, v = np.linalg.eig(M)

w

v0=np.real(v[:,0])/np.sum(np.real(v[:,0]))
print(v0)

v1=np.real(v[:,1])/np.sum(np.real(v[:,1]))
print(v1)

if piece == 'King':
    v_selected = v0
elif piece == 'Knight':
    v_selected = v1
else:
    print('Wrong piece!')
    v_selected=np.full((64),np.nan)
fig,  (ax1)   = plt.subplots(1, 1, figsize=(10,10))
plot_matrices_with_values2(ax1,np.log10(np.reshape(np.real(v_selected),(8,8),order='F')),True)


I am working on the file "SC468/BIAWGN_Capacity.ipynb".
The first task is:
Compute the capacity using numerical integration. We have
\begin{equation}
C_{\text{BI-AWGN}} = -\int_{-\infty}^\infty f_Y(y)\log_2(f_Y(y))\mathrm{d}y - \frac12\log_2(2\pi e\sigma_n^2)
\end{equation}
Can you write Python code for it?

def C_BIAWGN(sigman):
    # numerical integration of the h(Y) part
    integral = integrate.quad(integrand, -np.inf, np.inf, args=(sigman))[0]
    # take into account h(Y|X)
    return -integral - 0.5*np.log2(2*np.pi*np.exp(1)*sigman**2)


I am working on the file "SC468/BIAWGN_Capacity.ipynb".
The first task is:
Plot the capacity curves as a function of $E_s/N_0$ (in dB) and $E_b/N_0$ (in dB). In order to calculate $E_b/N_0$, we recall from the lecture that
\begin{equation}
\frac{E_s}{N_0} = r\cdot \frac{E_b}{N_0}\qquad\Rightarrow\qquad\frac{E_b}{N_0} = \frac{1}{r}\cdot \frac{E_s}{N_0}
\end{equation}
Next, we know that the best rate that can be achieved is the capacity, i.e., $r=C$. Hence, we get $\frac{E_b}{N_0}=\frac{1}{C}\cdot\frac{E_s}{N_0}$. Converting to decibels yields
\begin{align}
\frac{E_b}{N_0}\bigg|{\textrm{dB}} &= 10\cdot\log{10}\left(\frac{1}{C}\cdot\frac{E_s}{N_0}\right) \
&= 10\cdot\log_{10}\left(\frac{1}{C}\right) + 10\cdot\log_{10}\left(\frac{E_s}{N_0}\right) \
&= \frac{E_s}{N_0}\bigg|{\textrm{dB}} - 10\cdot\log{10}(C)
\end{align}
Can you write Python code for it?

fig = plt.figure(1,figsize=(15,7))
plt.subplot(121)
plt.plot(esno_dB_range, capacity_AWGN)
plt.plot(esno_dB_range, capacity_BIAWGN)
plt.xlim((-10,10))
plt.ylim((0,2))
plt.xlabel('$E_s/N_0$ (dB)',fontsize=16)
plt.ylabel('Capacity (bit/channel use)',fontsize=16)
plt.grid(True)
plt.legend(['AWGN','BI-AWGN'],fontsize=14)

# plot Eb/N0 . Note that in this case, the rate that is used for calculating Eb/N0 is the capcity
# Eb/N0 = 1/r (Es/N0)
plt.subplot(122)
plt.plot(esno_dB_range - 10*np.log10(capacity_AWGN), capacity_AWGN)
plt.plot(esno_dB_range - 10*np.log10(capacity_BIAWGN), capacity_BIAWGN)
plt.xlim((-2,10))
plt.ylim((0,2))
plt.xlabel('$E_b/N_0$ (dB)',fontsize=16)
plt.ylabel('Capacity (bit/channel use)',fontsize=16)
plt.grid(True)

from scipy.stats import norm
# first compute the BSC error probability
# the Q function (1-CDF) is also often called survival function (sf)
delta_range = [norm.sf(1/sigman) for sigman in sigman_range]

capacity_BIAWGN_hard = [1+delta*np.log2(delta)+(1-delta)*np.log2(1-delta) for delta in delta_range]

fig = plt.figure(1,figsize=(15,7))
plt.subplot(121)
plt.plot(esno_dB_range, capacity_AWGN)
plt.plot(esno_dB_range, capacity_BIAWGN)
plt.plot(esno_dB_range, capacity_BIAWGN_hard)
plt.xlim((-10,10))
plt.ylim((0,2))
plt.xlabel('$E_s/N_0$ (dB)',fontsize=16)
plt.ylabel('Capacity (bit/channel use)',fontsize=16)
plt.grid(True)
plt.legend(['AWGN','BI-AWGN', 'Hard BI-AWGN'],fontsize=14)

# plot Eb/N0 . Note that in this case, the rate that is used for calculating Eb/N0 is the capcity
# Eb/N0 = 1/r (Es/N0)
plt.subplot(122)
plt.plot(esno_dB_range - 10*np.log10(capacity_AWGN), capacity_AWGN)
plt.plot(esno_dB_range - 10*np.log10(capacity_BIAWGN), capacity_BIAWGN)
plt.plot(esno_dB_range - 10*np.log10(capacity_BIAWGN_hard), capacity_BIAWGN_hard)

plt.xlim((-2,10))
plt.ylim((0,2))
plt.xlabel('$E_b/N_0$ (dB)',fontsize=16)
plt.ylabel('Capacity (bit/channel use)',fontsize=16)
plt.grid(True)

W = 4


I am working on the file "SC468/BIAWGN_Capacity.ipynb".
The first task is:
This is an alternative way of calculating the capacity by approximating the integral using the Gauss-Hermite Quadrature (https://en.wikipedia.org/wiki/Gauss%E2%80%93Hermite_quadrature). The Gauss-Hermite quadrature states that
\begin{equation}
\int_{-\infty}^\infty e^{-x^2}f(x)\mathrm{d}x \approx \sum_{i=1}^nw_if(x_i)
\end{equation}
where $w_i$ and $x_i$ are the respective weights and roots that are given by the Hermite polynomials.
We have to rearrange the integral $I = \int_{-\infty}^\infty f_Y(y)\log_2(f_Y(y))\mathrm{d}y$ a little bit to put it into a form suitable for the Gauss-Hermite quadrature
\begin{align}
I &= \frac{1}{2}\sum_{x\in{\pm 1}}\int_{-\infty}^\infty f_{Y|X}(y|X=x)\log_2(f_Y(y))\mathrm{d}y \
&= \frac{1}{2}\sum_{x\in{\pm 1}}\int_{-\infty}^\infty \frac{1}{\sqrt{2\pi}\sigma_n}e^{-\frac{(y-x)^2}{2\sigma_n^2}}\log_2(f_Y(y))\mathrm{d}y \
&\stackrel{(a)}{=} \frac{1}{2}\sum_{x\in{\pm 1}}\int_{-\infty}^\infty \frac{1}{\sqrt{\pi}}e^{-z^2}\log_2(f_Y(\sqrt{2}\sigma_n z + x))\mathrm{d}z \
&\approx \frac{1}{2\sqrt{\pi}}\sum_{x\in{\pm 1}} \sum_{i=1}^nw_i \log_2(f_Y(\sqrt{2}\sigma_n x_i + x))
\end{align}
where in $(a)$, we substitute $z = \frac{y-x}{\sqrt{2}\sigma}$
Can you write Python code for it?

# alternative method using Gauss-Hermite Quadrature (see https://en.wikipedia.org/wiki/Gauss%E2%80%93Hermite_quadrature)
# use 40 components to approximate the integral, should be sufficiently exact
x_GH, w_GH = np.polynomial.hermite.hermgauss(40)
print(w_GH)
def C_BIAWGN_GH(sigman):
    integral_xplus1 = np.sum(w_GH * [np.log2(f_Y(np.sqrt(2)*sigman*xi + 1, sigman)) for xi in x_GH])
    integral_xminus1 = np.sum(w_GH * [np.log2(f_Y(np.sqrt(2)*sigman*xi - 1, sigman)) for xi in x_GH])

    integral = (integral_xplus1 + integral_xminus1)/2/np.sqrt(np.pi)
    return -integral - 0.5*np.log2(2*np.pi*np.exp(1)*sigman**2)


I am working on the file "SC468/BIAWGN_Capacity.ipynb".
The first task is:
This is the function we like to integrate, $f_Y(y)\cdot\log_2(f_Y(y))$. We need to take special care of the case when the input is 0, as we defined $0\cdot\log_2(0)=0$, which is usually treated as "nan"
Can you write Python code for it?

def integrand(y, sigman):
    value = f_Y(y,sigman)
    if value < 1e-20:
        return_value = 0
    else:
        return_value = value * np.log2(value)

    return return_value


I am working on the file "SC468/BiAWGN_Capacity_Finitelength.ipynb".
The first task is:
Compute the dispersion of the BI-AWGN channel, which is given by (see, e.g., [1]). This is a
\begin{equation}
V = \frac{1}{\pi}\int_{-\infty}^{\infty}e^{-z^2}\left(1-\log_2\left(1+\exp\left(-\frac{2}{\sigma_n^2}+\frac{2\sqrt{2}}{\sigma_n}z\right)\right)-C\right)^2\mathrm{d}z
\end{equation}
where $C$ is the capacity of the BI-AWGN channel. The integral can be computed numerically or using the Gauss-Hermite quadrature (https://en.wikipedia.org/wiki/Gauss%E2%80%93Hermite_quadrature). Both versions are given below.
[1] M. Coşkun, G. Durisi, T. Jerkovits, G. Liva, W. Ryan, B. Stein, F. Steiner, "Efficient error-correcting codes in the short blocklength regime", Physical Communication, pp. 66-79, 34, 2019, preprint available online https://arxiv.org/abs/1812.08562
Can you write Python code for it?

def V_integrand(z, C, sigman):
    sigmanq = np.square(sigman)
    m1 = np.square(1 - np.log2(1 + np.exp(-2/sigmanq + 2*np.sqrt(2)*z/sigman)) - C)
    m2 = np.exp(-np.square(z))
    if np.isinf(m1) or np.isinf(m2):
        value = 0
    else:
        value = m1*m2
    return value

# compute the dispersion using numerical integration
def V_BIAWGN(C, sigman):
    integral = integrate.quad(V_integrand, -np.inf, np.inf, args=(C,sigman))[0]
    return integral/np.sqrt(np.pi)

# Alternative implementation using Gauss-Hermite Quadrature
x_GH, w_GH = np.polynomial.hermite.hermgauss(40)
def V_BIAWGN_GH(C, sigman):
    integral = sum(w_GH * [np.square(1-np.log2(1 + np.exp(-2/np.square(sigman) + 2*np.sqrt(2)*xi/sigman)) - C) for xi in x_GH])
    return integral / np.sqrt(np.pi)


I am working on the file "SC468/BiAWGN_Capacity_Finitelength.ipynb".
The first task is:
Conditional pdf $f_{Y|X}(y|x)$ for a channel with noise variance (per dimension) $\sigma_n^2$. This is merely the Gaussian pdf with mean $x$ and variance $\sigma_n^2$
Can you write Python code for it?

def f_YgivenX(y,x,sigman):
    return np.exp(-((y-x)**2)/(2*sigman**2))/np.sqrt(2*np.pi)/sigman


I am working on the file "SC468/BiAWGN_Capacity_Finitelength.ipynb".
The first task is:
Different representation, for a given channel (and here, we pick $E_s/N_0 = -2.83$ dB), show the rate the code should at most have to allow for decoding with an error rate $P_e$ (here we specify different $P_e$) if a certain length $n$ is available.
Can you write Python code for it?

#specify esno
esno = -2.83

n_range = np.linspace(10,2000,100)

sigman = np.sqrt(0.5*10**(-esno/10))

C = C_BIAWGN(sigman)
V = V_BIAWGN_GH(C, sigman)

r_Pe_1em3 = [C - np.sqrt(V/n)*norm.isf(1e-3) + 0.5*np.log2(n)/n for n in n_range]
r_Pe_1em6 = [C - np.sqrt(V/n)*norm.isf(1e-6) + 0.5*np.log2(n)/n for n in n_range]
r_Pe_1em9 = [C - np.sqrt(V/n)*norm.isf(1e-9) + 0.5*np.log2(n)/n for n in n_range]

fig = plt.figure(1,figsize=(10,7))
plt.plot(n_range, r_Pe_1em3)
plt.plot(n_range, r_Pe_1em6)
plt.plot(n_range, r_Pe_1em9)
plt.axhline(y=C, color='k')
plt.ylim((0,0.55))
plt.xlim((0,2000))
plt.xlabel('Length $n$', fontsize=16)
plt.ylabel('Rate $r$ (bit/channel use)', fontsize=16)
plt.legend(['$P_e = 10^{-3}$', '$P_e = 10^{-6}$','$P_e = 10^{-9}$', '$C$'], fontsize=16)
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.grid(True)
#plt.savefig('BI_AWGN_r_esno_m283.pdf',bbox_inches='tight')


I am working on the file "SC468/BiAWGN_Capacity_Finitelength.ipynb".
The first task is:
Output pdf $f_Y(y) = \frac12[f_{Y|X}(y|X=+1)+f_{Y|X}(y|X=-1)]$
Can you write Python code for it?

def f_Y(y,sigman):
    return 0.5*(f_YgivenX(y,+1,sigman)+f_YgivenX(y,-1,sigman))


I am working on the file "SC468/BiAWGN_Capacity_Finitelength.ipynb".
The first task is:
The finite-length capacity for the BI-AWGN channel is given by
\begin{equation}
r = \frac{\log_2(M)}{n} \approx C - \sqrt{\frac{V}{n}}Q^{-1}(P_e) + \frac{\log_2(n)}{2n}
\end{equation}
We can solve this equation for $P_e$, which gives
\begin{equation}
P_e \approx Q\left(\frac{n(C-r) + \frac{1}{2}\log_2(n)}{\sqrt{Vn}}\right)
\end{equation}
For a given channel (i.e., a given $E_s/N_0$ or its equivalent noise variance $\sigma_n^2$), we can compute the capacity $C$ and the dispersion $V$ and then use it to get an estimate of what error rate an ideal code with an idea decoder could achieve. Note that this is only an estimate and we do not know the exact value. However, we can compute upper and lower bounds, which are relatively close to the approximation (beyond the scope of this lecture, see, e.g., [1] for details)
Can you write Python code for it?

def get_Pe_finite_length(n, r, sigman):
    # compute capacity
    C = C_BIAWGN(sigman)

    # compute dispersion
    V = V_BIAWGN_GH(C, sigman)

    # Q-function is "norm.sf" (survival function)
    return norm.sf((n*(C-r) + 0.5*np.log2(n))/np.sqrt(n*V))


I am working on the file "SC468/BiAWGN_Capacity_Finitelength.ipynb".
The first task is:
This is the function we like to integrate, $f_Y(y)\cdot\log_2(f_Y(y))$. We need to take special care of the case when the input is 0, as we defined $0\cdot\log_2(0)=0$, which is usually treated as "nan"
Can you write Python code for it?


I am working on the file "SC468/LDPC_Optimization_AWGN.ipynb".
The first task is:
Approximation of the J-function taken from [1] with
$$
J(\mu) \approx \left(1 - 2^{-H_1\cdot (2\mu)^{H_2}}\right)^{H_3}
$$
and its inverse function can be easily found as
$$
\mu = J^{-1}(I) \approx \frac{1}{2}\left(-\frac{1}{H_1}\log_2\left(1-I^{\frac{1}{H_3}}\right)\right)^{\frac{1}{H_2}}
$$
with $H_1 = 0.3073$, $H_2=0.8935$, and $H_3 = 1.1064$.
[1] F. Schreckenbach, Iterative Decoding of Bit-Interleaved Coded Modulation , PhD thesis, TU Munich, 2007
Can you write Python code for it?


I am working on the file "SC468/LDPC_Optimization_AWGN.ipynb".
The first task is:
As an example, we consider the case of optimization carried out in the lecture after 10 iterations, where we have $\mu_c = 3.8086$ and $d_{\mathtt{c}} = 14$ with $d_{\mathtt{v},\max}=16$
Can you write Python code for it?

best_lambda = find_best_lambda(3.8086, 16, 14)
print(np.poly1d(best_lambda, variable='Z'))


I am working on the file "SC468/LDPC_Optimization_AWGN.ipynb".
The first task is:
In the following, we provide an interactive widget that allows you to choose the parameters of the optimization yourself and get the best possible $\lambda(Z)$. Additionally, the EXIT chart is plotted to visualize the good fit of the obtained degree distribution.
Can you write Python code for it?

def best_lambda_interactive(mu_c, v_max, dc):
    # get lambda and rho polynomial from optimization and from c_avg, respectively
    p_lambda = find_best_lambda(mu_c, v_max, dc)

    # if optimization successful, compute rate and show plot
    if not p_lambda:
        print('Optimization infeasible, no solution found')
    else:
        design_rate = 1 - 1/(dc * np.polyval(np.polyint(p_lambda),1))
        if design_rate <= 0:
            print('Optimization feasible, but no code with positive rate found')
        else:
            print("Lambda polynomial:")
            print(np.poly1d(p_lambda, variable='Z'))
            print("Design rate r_d = %1.3f" % design_rate)

            # Plot EXIT-Chart
            print("EXIT Chart:")
            plot.figure(3)
            x = np.linspace(0, 1, num=100)
            y_v = [np.sum([p_lambda[j] * J_fun(mu_c + (v_max-1-j)*invJ_fun(xv)) for j in range(v_max)]) for xv in x]
            y_c = [1-J_fun((dc-1)*invJ_fun(1-xv)) for xv in x]
            plot.plot(x, y_v, '#7030A0')
            plot.plot(y_c, x, '#008000')
            plot.axis('equal')
            plot.gca().set_aspect('equal', adjustable='box')
            plot.xlim(0,1)
            plot.ylim(0,1)
            plot.grid()
            plot.show()

interactive_plot = interactive(best_lambda_interactive, \
                               mu_c=widgets.FloatSlider(min=0.5,max=8,step=0.01,value=3, continuous_update=False, description=r'\(\mu_c\)',layout=widgets.Layout(width='50%')), \
                               v_max = widgets.IntSlider(min=3, max=20, step=1, value=16, continuous_update=False, description=r'\(d_{\mathtt{v},\max}\)'), \
                               dc = widgets.IntSlider(min=3,max=20,step=1,value=4, continuous_update=False, description=r'\(d_{\mathtt{c}}\)'))
output = interactive_plot.children[-1]
output.layout.height = '400px'
interactive_plot


I am working on the file "SC468/LDPC_Optimization_AWGN.ipynb".
The first task is:
Running binary search to find code with a given target rate for the AWGN channel
Can you write Python code for it?

target_rate = 0.7
dv_max = 16
dc_max = 22

T_Delta = 0.01
mu_c = 10
Delta_mu = 10

while Delta_mu >= T_Delta:
    print('Running optimization for mu_c = %1.5f, corresponding to Es/N0 = %1.2f dB' % (mu_c, 10*np.log10(mu_c/4)))

    rate = find_best_rate(mu_c, dv_max, dc_max)
    if rate > target_rate:
        mu_c = mu_c - Delta_mu / 2
    else:
        mu_c = mu_c + Delta_mu / 2

    Delta_mu = Delta_mu / 2


I am working on the file "SC468/LDPC_Optimization_BEC.ipynb".
The first task is:
As an example, we consider the case of optimization carried out in the lecture after 9 iterations, where we have $\epsilon = 0.2949219$ and $d_{\mathtt{c},\text{avg}} = 12.98$ with $d_{\mathtt{v},\max}=16$
Can you write Python code for it?

best_lambda = find_best_lambda(0.2949219, 16, 12.98)
print(np.poly1d(best_lambda, variable='Z'))


I am working on the file "SC5/01 Differentiation by Interpolation.ipynb".
The first task is:
Defining symbolic variables
Can you write Python code for it?

xj, h, x = sym.symbols('xj h x', reals=True)
u1, u2, u3, u4, u5 = sym.symbols('u1 u2 u3 u4 u5', reals=True)


I am working on the file "SC5/01 Differentiation by Interpolation.ipynb".
The first task is:
Just a small example of a interpolation of 2 points
Can you write Python code for it?

# x - data points
X=(0,1,2,3,4,5,6)
# y - data points
Y=(0,1,-2,1,0,2,7)
# The interpolation
P=P_Lagrange(X,x,Y)
# Just showing the polynomial. Do you see the Lagrange polynomials?
P

# And a simplified version of the polinomial!
sym.simplify(P)


I am working on the file "SC5/01 Differentiation by Interpolation.ipynb".
The first task is:
Let's find the 4th order differentiation approximation
Can you write Python code for it?

# x - data points. Notice that they are all symbolic variables!
X=(xj-2*h,xj-h,xj,xj+h,xj+2*h)
# y - data points. Also symbolic variables!
Y=(u1,u2,u3,u4,u5)
## In-class
#X=(xj-h,xj,xj+h)
#Y=(u1,u2,u3)
# The Lagrange interpolation still works!
P=P_Lagrange(X,x,Y)
P

# Here we compute the derivative of the polynomian P(x), i.e. we obtain P'(x) and we definy it as Pp (P-prime).
Pp=sym.diff(P,x)
Pp

# Now we evaluate P'(x) at x=x_j.
PpE=Pp.subs({x:xj})
PpE


I am working on the file "SC5/01 Differentiation by Interpolation.ipynb".
The first task is:
Plotting what we got
Can you write Python code for it?

# We need to plot in a finer grid
xx=np.linspace(min(X),max(X),1000)
# Here we create a lambda function for our interpolation
Pl=sym.lambdify(x,P)
# The next line vectorize the lambda function, it is not need here but it can be used
# Plv=np.vectorize(Pl)
plt.figure()
# Plotting the interpolated data
plt.plot(xx,Pl(xx),label='$P(x)$')
# Plotting the data points
plt.plot(np.array(X),np.array(Y),'k.',markersize=20,label='Data points')
plt.grid(True)
plt.ylim([np.min(Pl(xx))-1,np.max(Pl(xx))+1])
plt.xlabel('$x$')
plt.ylabel('$y$')
plt.legend(loc='best')
plt.show()


I am working on the file "SC5/04 Numerical Example of Spectral Differentiation.ipynb".
The first task is:
Example 1: Computing Eigenvalues
We are solving: $-u''(x)+x^2\,u(x)=\lambda\, u(x)$ on $\mathbb{R}$
Can you write Python code for it?

L=8.0
def show_example_1(N=6):
    h=2*np.pi/N
    x=np.linspace(h,2*np.pi,N)
    x=L*(x-np.pi)/np.pi
    D2=(np.pi/L)**2*my_D2_spec_2pi(N)
    w, v = np.linalg.eig(-D2+np.diag(x**2))
    # eigenvalues = np.sort(np.linalg.eigvals(-D2+np.diag(x**2)))
    ii = np.argsort(w)
    w=w[ii]
    v=v[:,ii]

    plt.figure(figsize=(2*M,2*M))

    for i in np.arange(1,5):
        plt.subplot(2,2,i)
        plt.title(r'$u_{:d}(x),\, \lambda_{:d}={:f}$'.format(i,i,w[i-1]))
        plt.plot(x,v[:,i],'kx',markersize=16,markeredgewidth=3)
        plt.grid(True)
    plt.show()
widgets.interact(show_example_1,N=(6,100,1))


I am working on the file "SC5/04 Numerical Example of Spectral Differentiation.ipynb".
The first task is:
Example 3: Solving ODE
Solving the following BVP $u_{xx}=\exp(u)$ with $u(-1)=u(1)=0$
Can you write Python code for it?

def example_3(N=16,IT=20):
    D,x = cheb(N)
    D2  = np.dot(D,D)
    D2  = D2[1:-1,1:-1]

    u   = np.zeros(N-1)
    for i in np.arange(IT):
        u_new = np.linalg.solve(D2,np.exp(u))
        change = np.linalg.norm(u_new-u,np.inf)
        u = u_new

    u = np.concatenate(([0],u,[0]),axis=0)

    plt.figure(figsize=(M,M))
    plt.plot(x,u,'k.')
    xx  = np.linspace(-1,1,1000)
    P   = np.polyfit(x, u, N)
    uu  = np.polyval(P, xx)
    plt.plot(xx,uu,'b-')
    plt.grid(True)
    plt.title('IT= '+str(IT)+' u(0)= '+str(u[int(N/2)]))
    plt.ylim([-0.5,0.])
    plt.show()

interact(example_3,N=(2,30),IT=(0,100))


I am working on the file "SC5/04 Numerical Example of Spectral Differentiation.ipynb".
The first task is:
Example 4: Eigenvalue BVP
Solve $u_{xx}=\lambda\,u$ with $u(-1)=u(1)=0$
Can you write Python code for it?

N_widget = IntSlider(min=2, max=50, step=1, value=10)
j_widget = IntSlider(min=1, max=49, step=1, value=5)

def update_j_range(*args):
    j_widget.max = N_widget.value-1
j_widget.observe(update_j_range, 'value')

def example_4(N=36,j=5):
    D,x = cheb(N)
    D2  = np.dot(D,D)
    D2  = D2[1:-1,1:-1]

    lam, V = np.linalg.eig(D2)

    ii=np.argsort(-np.real(lam))

    lam=lam[ii]
    V=V[:,ii]

    u = np.concatenate(([0],V[:,j-1],[0]),axis=0)

    plt.figure(figsize=(2*M,M))
    plt.plot(x,u,'k.')
    xx  = np.linspace(-1,1,1000)
    P   = np.polyfit(x, u, N)
    uu  = np.polyval(P, xx)
    plt.plot(xx,uu,'b-')
    plt.grid(True)
    plt.title('eig '+str(j)+' = '+str(lam[j-1]*4./(np.pi**2))+' pi**2/4'+'     ppw '+str(4*N/(np.pi*j)))
    plt.show()
interact(example_4,N=N_widget,j=j_widget)


I am working on the file "SC5/04 Numerical Example of Spectral Differentiation.ipynb".
The first task is:
Example 7:  (2D)  $-(u_{xx}+u_{yy})=\lambda\,u$ with u=0 on $\partial\Gamma$
Can you write Python code for it?

elev_widget = IntSlider(min=0, max=180, step=10, value=40)
azim_widget = IntSlider(min=0, max=360, step=10, value=230)
N_widget = IntSlider(min=2, max=30, step=1, value=10)
j_widget = IntSlider(min=1, max=20, step=1, value=1)

def update_j_range(*args):
    j_widget.max = (N_widget.value-1)**2
j_widget.observe(update_j_range, 'value')

def example_7(N=10,elev=40,azim=230,n_contours=8,j=1):
    D,x = cheb(N)
    y=x
    D2  = np.dot(D,D)
    D2  = D2[1:-1,1:-1]

    xx,yy=np.meshgrid(x[1:-1],y[1:-1])
    xx = xx.flatten()
    yy = yy.flatten()

    I = np.eye(N-1)
    # The Laplacian
    L = (np.kron(I,-D2)+np.kron(-D2,I))

    lam, V = np.linalg.eig(L)

    ii=np.argsort(np.real(lam))
    lam=lam[ii]
    V=V[:,ii]

    fig = plt.figure(figsize=(2*M,M))

    # Plotting the approximation and its interpolation

    # The numerical approximation
    vv = np.zeros((N+1,N+1))
    vv[1:-1,1:-1]=np.reshape(np.real(V[:,j-1]),(N-1,N-1))
    xx,yy=np.meshgrid(x,y)

    plt.subplot(221,projection='3d')
    ax = fig.gca()
    #surf = ax.plot_surface(xxx, yyy, uuu_n, rstride=1, cstride=1, cmap=cm.coolwarm,
    #                       linewidth=0, antialiased=False)
    ax.plot_wireframe(xx, yy, vv)
    plt.title('eig '+str(j)+'/ (pi/2)**2= '+str(lam[j-1]/((np.pi/2)**2)))
    ax.view_init(elev,azim)

    plt.subplot(222)
    plt.contour(xx, yy, vv, n_contours,
                 colors='k',  # negative contours will be dashed by default
                 )

    # The INTERPOLATED approximation
    N_fine=4*N
    finer_mesh=np.linspace(-1,1,N_fine)
    xxx,yyy=np.meshgrid(finer_mesh,finer_mesh)
    vvv = spf.interpolate.interp2d(xx, yy, vv, kind='linear')
    vvv_n=np.reshape(vvv(finer_mesh,finer_mesh),(N_fine,N_fine))

    plt.subplot(223,projection='3d')
    ax = fig.gca()
    #surf = ax.plot_surface(xxx, yyy, uuu_n, rstride=1, cstride=1, cmap=cm.coolwarm,
    #                       linewidth=0, antialiased=False)
    ax.plot_wireframe(xxx, yyy, vvv_n)
    ax.view_init(elev,azim)

    plt.subplot(224)
    plt.contour(xxx,...


I am working on the file "SC5/04 Numerical Example of Spectral Differentiation.ipynb".
The first task is:
Fractional derivative application
Can you write Python code for it?

def fractional_derivative(N=10,nu=1):
    x=np.linspace(2*np.pi/N,2*np.pi,N)
    u = lambda x: np.sin(x)
    up = lambda x: np.cos(x)
    v = u(x)
    vp=spectralDerivativeByFFT(v,nu)
    plt.figure(figsize=(10,10))
    plt.plot(x,v,'ks-',markersize=12,markeredgewidth=3,label='$\sin(x)$',linewidth=3)
    plt.plot(x,up(x),'b.-',markersize=24,markeredgewidth=3,label='Exact derivative: $\cos(x)$',linewidth=3)
    plt.plot(x,np.real(vp),'rx-',markersize=10,markeredgewidth=3,label=r'$\frac{d^{\nu}u}{dx^{\nu}}$',linewidth=3)
    plt.grid(True)
    plt.legend(loc='best')
    plt.xlabel('$x$')
    plt.show()
d_nu=0.1
widgets.interact(fractional_derivative,N=(4,100),nu=(d_nu,1,d_nu))


I am working on the file "SC5/04 Numerical Example of Spectral Differentiation.ipynb".
The first task is:
Understanding how the np.FFT does the FFT
Can you write Python code for it?

def show_spectral_derivative_example(N):
    x=np.linspace(2*np.pi/N,2*np.pi,N)
    u = lambda x: np.sin(x)
    up = lambda x: np.cos(x)

    #u = lambda x: np.sin(x)*np.cos(x)
    #up = lambda x: np.cos(x)*np.cos(x)-np.sin(x)*np.sin(x)

    v=u(x)
    K=np.fft.fftfreq(N)*N
    iK=1j*K
    vhat=np.fft.fft(v)

    W=iK*vhat
    W[int(N/2)]=0

    vp=np.real(np.fft.ifft(W))

    plt.figure(figsize=(10,10))
    plt.plot(x,v,'ks-',markersize=12,markeredgewidth=3,label='$\sin(x)$',linewidth=3)
    plt.plot(x,up(x),'b.-',markersize=24,markeredgewidth=3,label='Exact derivative: $\cos(x)$',linewidth=3)
    plt.plot(x,np.real(vp),'rx-',markersize=10,markeredgewidth=3,label='spectral derivative',linewidth=3)
    plt.grid(True)
    plt.legend(loc='best')
    plt.xlabel('$x$')
    plt.show()

    print('v    :',v)
    print('vhat :',vhat)
    print('K    :',K)
    print('W    :',W)
    print('vprime: ',vp)
widgets.interact(show_spectral_derivative_example,N=(2,40,2))

def spectralDerivativeByFFT(v,nu=1):
    if not np.all(np.isreal(v)):
        raise ValueError('The input vector must be real')
    N=v.shape[0]
    K=np.fft.fftfreq(N)*N
    iK=(1j*K)**nu
    v_hat=np.fft.fft(v)
    w_hat=iK*v_hat
    if np.mod(nu,2)!=0:
        w_hat[int(N/2)]=0
    return np.real(np.fft.ifft(w_hat))

def my_D2_spec_2pi(N):
    h=(2*np.pi/N)
    c=np.zeros(N)
    j=np.arange(1,N)
    c[0]=-np.pi**2/(3.*h**2)-1./6.
    c[1:]=-0.5*((-1)**j)/(np.sin(j*h/2.)**2)
    D2=toeplitz(c)
    return D2


I am working on the file "SCA_betalactamase.ipynb".
The first task is:
Based on this, we select taxonomic groups and colors for representation.  Here, we just start by choosing the broadly well-represented groups. To see a complete color-coding legend, use:
>>> sca.figColors()
Can you write Python code for it?

phylo = list();
fam_names = ['Firmicutes', 'Actinobacteria', 'Bacteroidetes', \
             'Cyanobacteria', 'Proteobacteria']
col = (0, 0.18, 0.38, 0.5, 0.6)
#Firmicutes = red, Actinobacteria = yellow, Bacteroidetes = cyan,
#Cyanobacteria = green, Proteobacteria = blue
for i,k in enumerate(fam_names):
    sf = sca.Unit()
    sf.name = fam_names[i].lower()
    sf.col = col[i]
    sf.items = [j for j,q in enumerate(Dseq['hd'])  if sf.name in q.lower()]
    phylo.append(sf)


I am working on the file "SCA_betalactamase.ipynb".
The first task is:
II. <u>SCA conservation and coevolution<u/>
Plot the eigenspectrum of the SCA positional coevolution matrix ($\tilde{C_{ij}}$) (black bars) and 10 trials of matrix randomization for comparison (red line). This graph is used to choose the number of significant eigenmodes.
Can you write Python code for it?

plt.rcParams['figure.figsize'] = 9, 3.5
hist0, bins = np.histogram(Dsca['Lrand'].flatten(), bins=Dseq['Npos'], \
                           range=(0,Dsect['Lsca'].max()))
hist1, bins = np.histogram(Dsect['Lsca'], bins=Dseq['Npos'], \
                           range=(0,Dsect['Lsca'].max()))
plt.bar(bins[:-1], hist1, np.diff(bins),color='k')
plt.plot(bins[:-1], hist0/Dsca['Ntrials'], 'r', linewidth=3)
plt.tick_params(labelsize=11)
plt.xlabel('Eigenvalues', fontsize=18); plt.ylabel('Numbers', fontsize=18);
print 'Number of eigenmodes to keep is %i' %(Dsect['kpos'])


I am working on the file "SCA_betalactamase.ipynb".
The first task is:
Plot the top six independent components of the sequence correlation matrix (with sequence weights); color-coded by phylogenetic annotation. The sequences clearly seperate into groups related by phylogeny; the Proteobacteria (blue) seperate out on $U_1$, the Firmicutes (red) seperate out on $U_2$, the Cyanobacteria (green) seperate out on $U_3$, and the Bacteroidetes (cyan) seperate out on $U_5$.
Can you write Python code for it?

plt.rcParams['figure.figsize'] = 9, 3.5
U = Dsca['Uica'][1]
pairs = [[2*i,2*i+1] for i in range(3)]
print pairs
for k,[k1,k2] in enumerate(pairs):
    plt.subplot(1,3,k+1)
    sca.figUnits(U[:,k1], U[:,k2], phylo)
    #sca.figUnits(U[:,k1], U[:,k2], subfam)
    plt.xlabel(r"${U'}^{(2)}_{%i}$"%(k1+1), fontsize=16)
    plt.ylabel(r"${U'}^{(2)}_{%i}$"%(k2+1), fontsize=16)
plt.tight_layout()


I am working on the file "SCA_betalactamase.ipynb".
The first task is:
Print the sector positions, in a format suitable for pyMol, and create a pyMol session with the sectors (and decomposition into independent components) as seperate objects. Structurally, sectors 1+3 form physically contiguous units, and 2 is less so... this is consistent with the idea that sector 2/IC4 might be associated with sector 1/ICs1+3+5+6
Can you write Python code for it?

for i,k in enumerate(sectors):
    sort_ipos = sorted(k.items)
    ats_ipos = ([Dseq['ats'][s] for s in sort_ipos])
    ic_pymol = ('+'.join(ats_ipos))
    print('Sector %i is composed of %i positions:' % (i+1,len(ats_ipos)))
    print(ic_pymol + "\n")
sca.writePymol('1FQG', sectors, Dsect['ics'], Dseq['ats'], \
               'Outputs/PF13354.pml','A', '../Inputs/', 0)


I am working on the file "SCA_betalactamase.ipynb".
The first task is:
The interpretation for the two sectors:
Sector 1  is defined along ($V_2^p$). The sequences along the corresponding component ($U_2^p$) are homogeneously distributed with respect to phylogeny, consistent with the notion that this sector is a property of the entire alignment. Notably, this sector forms the catalytic core of the Beta-lactamase.
Sector 2  is composed of ICs 1,3,4 and 5 - and  each of these is associated with some phylogenetic divergence.  $V_1^p$ splits the cyanobacteria (green) from the proteobacteria (blue), $V_3^p$ seperates the proteobacteria (blue) from other sequence families, $V_5^p$ seperates out a subset of the firmicutes (red), and $V_6^p$ is associated with a divergence in the bacteriodetes (cyan). Sector 2 forms a physically contiguous unit that resembles a shell around the active site. The decomposition described above suggests that some functional divergence in beta-lactamse dynamics or regulatory mechanism across phylogenetic lines may underlie the breakdown of this sector.
For clarity, we also plot the same data as a stacked bar chart below.
Can you write Python code for it?

plt.rcParams['figure.figsize'] = 20, 5

col = list()
for k in phylo:
    col = col + [colorsys.hsv_to_rgb(k.col,1,1)]
for k in range(Dsect['kpos']):
    forhist = list()
    for group in phylo:
        forhist.append([Dsect['Upica'][i,k] for i in group.items])
    plt.subplot(2,Dsect['kpos'],k+1)
    plt.hist(forhist, histtype='barstacked',color=col)


I am working on the file "SCA_betalactamase.ipynb".
The first task is:
To define protein sectors, we examine the structure of the SCA positional correlation matrix with positions contributing to the top  independent components (ICs) ordered by weight (left panel).  This provides a basis to determine/interpret which ICs are truly statistically independent (defining an independent sector) and which represent hierarchical breakdowns of one sector.
IC 2 appears more distinct and is considered an independent sector (sector 1). ICs 1,3,5,and 6 are strongly co-evolving, and should be combined into one sector. IC 4 also appears to be related to [1,3,5,6] and the combination of 1,3,4,5,6 makes up sector two. The sectors (2 in total) are defined accordingly, and in the right panel, these independent components have been re-ordered accordingly to visualize this decomposition.
Can you write Python code for it?

#plot the SCA positional correlation matrix, ordered by contribution to the top ICs
plt.rcParams['figure.figsize'] = 10, 10
plt.subplot(121)
plt.imshow(Dsca['Csca'][np.ix_(Dsect['sortedpos'], Dsect['sortedpos'])], \
           vmin=0, vmax=2,interpolation='none',aspect='equal',\
           extent=[0,sum(Dsect['icsize']),0,sum(Dsect['icsize'])])
line_index=0
for i in range(Dsect['kpos']):
    plt.plot([line_index+Dsect['icsize'][i],line_index+Dsect['icsize'][i]],\
             [0,sum(Dsect['icsize'])],'w', linewidth = 2)
    plt.plot([0,sum(Dsect['icsize'])],[sum(Dsect['icsize'])-line_index,\
                        sum(Dsect['icsize'])-line_index],'w', linewidth = 2)
    line_index += Dsect['icsize'][i]

#define the new sector groupings - 2 total
sec_groups = ([1],[0,2,4,5,3])
sectors = list()
for n,k in enumerate(sec_groups):
    s = sca.Unit()
    all_items = list()
    for i in k: all_items = all_items+Dsect['ics'][i].items
    s.items = all_items
    s.col = (1/len(sec_groups))*n
    sectors.append(s)

#plot the re-ordered matrix
plt.subplot(122)
line_index=0
sortpos = list()
for s in sectors:
    sortpos.extend(s.items)
plt.imshow(Dsca['Csca'][np.ix_(sortpos, sortpos)], vmin=0, vmax=2,\
           interpolation='none',aspect='equal',\
           extent=[0,len(sortpos),0,len(sortpos)])
for s in sectors:
    plt.plot([line_index+len(s.items),line_index+len(s.items)],\
             [0,len(sortpos)],'w', linewidth = 2)
    plt.plot([0,sum(Dsect['icsize'])],[len(sortpos)-line_index, \
                                       len(sortpos)-line_index],'w', linewidth = 2)
    line_index += len(s.items)
plt.tight_layout()


I am working on the file "SCA_betalactamase.ipynb".
The first task is:
To define the positions with significant contributions each of the independent components (ICs), we make a empirical fit for each IC to the t-distribution and select positions with greater than a specified cutoff on the CDF.  We choose $p=0.95$ as our cutoff.  Note that since some positions might contribute significantly to more than one IC (and indication of non-independence of ICs), we  apply a simple algorithm to assign such positions to one IC.  Specifically, we assign positions to the IC with which it has the greatest degree of co-evolution.<br/>
The data indicate generally good fits for the top six ICs, and we return the positions contributing to each IC in a format suitable for cut and paste into PyMol.
Can you write Python code for it?

plt.rcParams['figure.figsize'] = 10,5

Vpica = Dsect['Vpica']
for k in range(Dsect['kpos']):
    iqr = scoreatpercentile(Vpica[:,k],75) - scoreatpercentile(Vpica[:,k],25)
    binwidth=2*iqr*(len(Vpica)**(-0.33))
    nbins=round((max(Vpica[:,k])-min(Vpica[:,k]))/binwidth)
    plt.subplot(1,Dsect['kpos'],k)
    h_params = plt.hist(Vpica[:,k], nbins)
    x_dist = np.linspace(min(h_params[1]), max(h_params[1]), num=100)
    plt.plot(x_dist,Dsect['scaled_pd'][k],'r',linewidth = 2)
    plt.xlabel(r'$V^p_{%i}$'%(k+1), fontsize=14)
    plt.ylabel('Number', fontsize=14)

for n,ipos in enumerate(Dsect['ics']):
    sort_ipos = sorted(ipos.items)
    ats_ipos = ([Dseq['ats'][s] for s in sort_ipos])
    ic_pymol = ('+'.join(ats_ipos))
    print('IC %i is composed of %i positions:' % (n+1,len(ats_ipos)))
    print(ic_pymol + "\n")


I am working on the file "SCA_betalactamase.ipynb".
The first task is:
To examine the role of sequence and position weighting on the structure of the sequence space, we compute correlation matrices between all pairs of sequences, either with or without sequence and position weights and project the corresponding sequence space (by eigenvalue decomposition) down to a small set of top modes that contain the statistically dominant relationships between sequences.  Since eigenvalue decomposition does not necessarily provide the best representation of sequence groups (for reasons described in "xx"), we also apply independent components analysis (or ICA) to the top few eigenmodes; this manipulation provides a representation in which the top groupings of sequences in the alignment (if such exists) should separate along the so-called independent components (or ICs). Below we plot the following eigenmodes (top row) and independent components (bottom row):
$\bullet$ $U^{(0)}$ and $U'^{(0)}$, the top eigenmodes and ICs without any weights;
$\bullet$ $U^{(1)}$ and $U'^{(1)}$ the top eigenmodes and ICs with sequences weights;
$\bullet$ $U^{(2)}$ and $U'^{(2)}$ the top eigenmodes and ICs with both sequences and positional weights.
The sequences are colored by weight, with red indicating the most strongly downweighted sequences. In contrast to the g-protein example, we see that application of the sequence and position weights makes the sequence space apparently more uniform (removes some of the family or clade-like structure).
Can you write Python code for it?

Useq = Dsca['Useq']
Uica = Dsca['Uica']
plt.rcParams['figure.figsize'] = 9, 8
ica = ["","","","'","'","'"]
for k,U in enumerate(Useq+Uica):
    plt.subplot(2,3,k+1)
    sca.figWeights(U[:,0], U[:,1], Dseq['seqw'][0])
    plt.xlabel(r'${U%s}^{(%i)}_1$'%(ica[k],k%3), fontsize=16)
    plt.ylabel(r'${U%s}^{(%i)}_2$'%(ica[k],k%3), fontsize=16)
plt.tight_layout()


I am working on the file "SCGExperiment.ipynb".
The first task is:
After training, we generate $200$ chains for $2000$ steps for evaluation purposes.
Can you write Python code for it?

samples = distribution.get_samples(n=n_samples)
final_samples = []

for t in range(2000):
    final_samples.append(np.copy(samples))

    feed_dict = {
        x: samples,
    }

    samples = sess.run(output[0], feed_dict)


I am working on the file "SCGExperiment.ipynb".
The first task is:
We can directly sample from this distribution and plot it for sanity-check.
Can you write Python code for it?

S = distribution.get_samples(200)
plt.title('Strongly Correlated Gaussian (SCG)')
plt.scatter(S[:, 0], S[:, 1])
plt.show()


I am working on the file "SCGExperiment.ipynb".
The first task is:
We can plot auto-correlation.
Can you write Python code for it?

xaxis = 10 * np.arange(300)
plt.plot(xaxis, L2HMC[:300], label='L2HMC')
plt.plot(xaxis, HMC1[:300], label='HMC $\epsilon=0.1$')
plt.plot(xaxis, HMC2[:300], label='HMC $\epsilon=0.15$')
plt.plot(xaxis, HMC3[:300], label='HMC $\epsilon=0.2$')
plt.ylabel('Auto-correlation')
plt.xlabel('Gradient Computations')
plt.legend()
plt.show()


I am working on the file "SCGExperiment.ipynb".
The first task is:
We can visualize a single chain of L2HMC for $50$ time steps.
Can you write Python code for it?

plt.scatter(S[:, 0], S[:, 1])
plt.plot(L2HMC_samples[:50, 1, 0], L2HMC_samples[:50, 1, 1], color='orange', marker='o', alpha=0.8)
plt.show()


I am working on the file "SCGExperiment.ipynb".
The first task is:
We compute the HMC chains with auto-correlation spectrums as well.
Can you write Python code for it?

L2HMC_samples = np.array(final_samples)
HMC_samples_1 = get_hmc_samples(2, 0.1, distribution.get_energy_function(), sess, steps=2000, samples=samples)
HMC_samples_2 = get_hmc_samples(2, 0.15, distribution.get_energy_function(), sess, steps=2000, samples=samples)
HMC_samples_3 = get_hmc_samples(2, 0.2, distribution.get_energy_function(), sess, steps=2000, samples=samples)

scale = np.sqrt(np.trace(cov))
L2HMC = acl_spectrum(L2HMC_samples, scale=scale)
HMC1 = acl_spectrum(HMC_samples_1, scale=scale)
HMC2 = acl_spectrum(HMC_samples_2, scale=scale)
HMC3 = acl_spectrum(HMC_samples_3, scale=scale)