# 1. Human capital accumulation

## Question 1
First we will define each variable and parameters with Sympy.symbols.

```python
# import packages
import numpy as np
import sympy as sm
sm.init_printing(use_unicode=True) # for pretty printing
```

```python
# Define parameters and variables as symbols
rho = sm.symbols("rho")
beta = sm.symbols("beta")
gamma = sm.symbols("gamma")
w = sm.symbols("w")
b = sm.symbols("b")
Delta = sm.symbols("Delta")
h_2 = sm.symbols("h_2")
l_2 = sm.symbols("l_2")
c_2 = sm.symbols("c_2")
l_1 = sm.symbols("l_1")
h_1 = sm.symbols("h_1")
```

The utility the worker receives from consumption depends on the variable $l_t$. If the value is [1], consumption will be $w*h_2*l_2$, and for the value [0], $(1-l_2)*b$. Hence we define the function as the following:
$c_2 = (w*h_2*l_2)+(1-l_2)*b$

```python
# Define consumption function according to the pres-ented formula
# Includes, wage w, unemployment benefit b, human capital for period 2 h_2 and labor supply for period 2 l_2
# Returns the consumption
def consumption_2(w, h_2, l_2, b):
    return (w*h_2*l_2)+(1-l_2)*b
```

Next we will try to define the utility function.

```python
# Define utility function according to the presented formula
utility = c_2 ** (1-rho)/(1-rho) - gamma * l_2
utility
```

Then we will use sympy to substitute the consumption function into the utility function

```python
# Set consumption equal to the variables and parameters
consumption2 = w*h_2*l_2+(1-l_2)*b
consumption2
```

```python
# Use sympy.subs to substitute consumption_2 into the utility function.
utility_subs = utility.subs(c_2,consumption2)
utility_subs
```

This is the final utility function, which we will define below.

```python
# Define final utility function.
def utility_2(gamma, w, b, rho, h, l):
    return ((1-l)*b+(h*l*w))**(1-rho)/(1-rho)-gamma*l
```

Next we will try to solve the model visually.

```python
# Import the following packages
%matplotlib inline
import matplotlib.pyplot as plt
```

Next we will use  np.argmax to solve the model for period 2 by using the given vector for $h_2$ and an empty vector (100,2), "choices2".

```python
# Vectors
choices2 = np.empty((100,2))
h2_vec = np.linspace(0.1,1.5,100)

# Parameters
rho = 2
beta = 0.96
gamma = 0.1
w = 2
b = 1
Delta = 0.1

# loop over each value of h for l=0 and l=1 for the utility function to fill up choices2
for index, value in enumerate(h2_vec):
    choices2[index, 0] = utility_2(gamma, w, b, rho, value, 0)
    choices2[index, 1] = utility_2(gamma, w, b, rho, value, 1)
```

Now we can find the solutions for labor supply $l_2$, consumption $c_2$ and value $v_2$.

```python
# Find the argument, which maximise the value of l2 given choices2
l2_sol = np.argmax(choices2, axis=1)
# Insert the above sol into consumption.
c2_sol = consumption_2(w, b ,l2_sol,h2_vec)
# Max choises2 to find v2
v2_sol = np.max(choices2, axis=1)
```

At last we can show the solution in the below subplots.

```python
# Begin plot
fig = plt.figure(figsize=(18,10))

# Add the three subplots
ax = fig.add_subplot(3,3,1)
ax.plot(h2_vec,l2_sol)
ax.grid()
ax.set_xlabel('$h_2$')
ax.set_ylabel('$l_2$')
ax.set_title('Labor supply function in period 2');

ax = fig.add_subplot(3,3,2)
ax.plot(h2_vec,c2_sol, color='green')
ax.grid()
ax.set_xlabel('$h_2$')
ax.set_ylabel('$c_2$')
ax.set_title('Consumption function in period 2');

ax = fig.add_subplot(3,3,3)
ax.plot(h2_vec,v2_sol, color='orange')
ax.grid()
ax.set_xlabel('$h_2$')
ax.set_ylabel('$v_2$')
ax.set_title('Value function in period 2');
```

We see how there is a kink at a certain value of $h_2$, approx. 0.55. At this value, the worker gets more utility from working than living of unemployment benefits. Hence, the worker's consumtion and value increases.

# Question 2
Now the worker has a chance of accumulating human capital.

```python
# Define consumption and utility function (same as period 2)
def consumption_1(w, h_1, l_1, b):
    return (w*h_1*l_1)+(1-l_1)*b

def utility_1(gamma, w, b, rho, h_1, l_1):
    return ((1-l_1)*b+(h_1*l_1*w))**(1-rho)/(1-rho)-gamma*l_1
```

Next we will create a value function, which inputs consits of the possibilities for the worker to accumulate human capital

```python
def v1(gamma, b, w, rho, Delta, beta, h_1, l_1, v2_interp):
    #  h2 value, if no acc
    h2_no_acc = h_1 + l_1

    # b2 value, if no acc
    v2_no_acc = v2_interp([h2_no_acc])[0]

    # h2 value, if acc
    h2_acc = h_1 + l_1 + Delta

    # v2 value if acc
    v2_acc = v2_interp([h2_acc])[0]

    # expected v2 value
    v2 = 0.5 * v2_no_acc + 0.5 * v2_acc

    # return the total value
    return utility_1(gamma, rho, b, w, h_1, l_1) + beta * v2
```

Construct interpolar

```python
from scipy import interpolate

# Constructing interpolar
v2_interp = interpolate.RegularGridInterpolator([h2_vec], v2_sol,
                                                bounds_error=False,fill_value=None)
```

Similar to how we did in Question 1, we create a empty array and loop over each value of $h$

```python
# Vectors
choices1 = np.empty((100,2))

# loop over each value of h for l=0 and l=1 to fill up choices 1
for index, value in enumerate(h2_vec):
    choices1[index, 0] = v1(gamma, b, w, rho, Delta, beta, value, 0, v2_interp)
    choices1[index, 1] = v1(gamma, b, w, rho, Delta, beta, value, 1, v2_interp)

```

Now we can find the following solutions.

```python
# Find the argument, which maximise the value of l1 given choices1
l1_sol = np.argmax(choices1, axis=1)

# Insert the above sol into consumption.
c1_sol = consumption_1(w,b,l1_sol,h2_vec)

# Max choises1 to find v1
v1_sol = np.max(choices1, axis=1)
```

```python
# Begin plotting
fig = plt.figure(figsize=(18,10))

# Add subplots
ax = fig.add_subplot(3,3,1)
ax.plot(h2_vec,l1_sol)
ax.grid()
ax.set_xlabel('$h_1$')
ax.set_ylabel('$l_1$')
ax.set_title('Labor supply in period 1');

ax = fig.add_subplot(3,3,2)
ax.plot(h2_vec,c1_sol, color ='green')
ax.grid()
ax.set_xlabel('$h_1$')
ax.set_ylabel('$c_1$')
ax.set_title('Consumption in period 1');

ax = fig.add_subplot(3,3,3)
ax.plot(h2_vec,v1_sol, color = 'orange')
ax.grid()
ax.set_xlabel('$h_1$')
ax.set_ylabel('$v_1$')
ax.set_title('Value function in period 1');
```

We see that when the worker has a chance of accumulating human capital, the kink happens at a smaller $h$ value, approx. 0.35.

# Question 3
In this question we will explore if the worker will still prefer working even though $b>w$. In order for us to do so, we will research if the worker chooses $l_t$ = [1] for a certain value of $h_t$. For your convenience this will be done only for period 2.

The method is similar to the previous questions.

```python
# Import packages
import matplotlib.pyplot as plt
import ipywidgets as widgets
from ipywidgets import interactive

# Define interactive figure
def interactive_fig_w(w_t):

    # Find solution with the method similar to previous questions.
    choices_w = np.empty((100,2))

    for index, value in enumerate(h2_vec):
        choices_w[index, 0] = utility_2(gamma, w_t, b, rho, value, 0)
        choices_w[index, 1] = utility_2(gamma, w_t, b, rho, value, 1)

    lw_sol = np.argmax(choices_w, axis=1)

    # Plot figure

    plt.plot(h2_vec,lw_sol)
    plt.title('Labor supply in period 2')
    plt.xlabel('$h_2$')
    plt.ylabel('$l_2$')
    plt.axis([0,1.6,-0.1,1.1])
    plt.show()

interactive_plot_w = interactive(interactive_fig_w,
                               w_t=widgets.FloatSlider(description="$w$",
                                                       min=0.0,
                                                       max=1.0,
                                                       step=0.01,
                                                       value=0.9,
                                                       continuous_update=True)
                              )

interactive_plot_w
```

    interactive(children=(FloatSlider(value=0.9, description='$w$', max=1.0, step=0.01), Output()), _dom_classes=(…

What the above figure tells us is that when the wage is $w = 0.75$ or above, the worker gets more utility from working than relying on unemployment benefits $b = 1$. So yes, the worker will still work ($l_1 = 1$), when the worker's wage is below the unemployment benefits.

# 2. AS-AD model

```python
# Create dictionary for parameters and their values
par = {}

par['alpha'] = 5.76
par['h'] = 0.5
par['b'] = 0.5
par['phi'] = 0
par['gamma'] = 0.075
```

# Question 1
First we will define the following variables and parameters as symbols.

```python
# Defining variables and parameters as symbols
alpha = sm.symbols("alpha")
b = sm.symbols("b")
h = sm.symbols("h")
phi = sm.symbols("phi")
gamma = sm.symbols("gamma")

y_t = sm.symbols("y_t")
y_t_1 = sm.symbols("y_{t-1}")
s_t = sm.symbols("s_t")
s_t_1 = sm.symbols("s_{t-1}")
v_t = sm.symbols("v_t")
pi_t = sm.symbols("pi_t")
pi_t_1 = sm.symbols("\pi_{t-1}")
```

Then we are able to construct the following equations for the SRAS curve and the AD curve.

```python
# Constructing SRAS and AD curve
SRAS = sm.Eq(pi_t,pi_t_1 + gamma * y_t  - phi * gamma * y_t_1 + s_t - phi * s_t_1)
AD = sm.Eq(pi_t, 1/(h * alpha) * (v_t - (1 + b * alpha) * y_t))
SRAS, AD
```

To solve the model, we will have to set the two curves equal to eachother.

```python
SRAS_AD = sm.Eq(
                pi_t_1 + gamma * y_t  - phi * gamma * y_t_1 + s_t - phi * s_t_1,
                1/(h * alpha) * (v_t - (1 + b * alpha) * y_t))
SRAS_AD
```

Then we can solve for $y_t$

```python
# Solve the equation for y_t
yt_sol = sm.solve(SRAS_AD,y_t)[0]
print(f'The solution for output y_t is:')
yt_sol
```

Then insert the above solution into the AD-curve to find $\pi_t$

```python
# Sub yt_sol into the AD equation.
pit_sol = 1/(h * alpha) * (v_t - (1 + b * alpha) * yt_sol)
print(f'The solution for inflaton pi_t is:')
pit_sol
```

To find the equilibrium values for  output, $y_t$, and inflation, $\pi_t$,given the parameters ($\alpha$, $h$, $b$, $\alpha$, $\gamma$) and $y_{t-1}$ , $\pi_{t-1}$, $v_t$, $s_t$, and $s_{t-1}$, we will substitute the given parameters into the solution.

```python
yt_val = yt_sol.subs({alpha: par['alpha'],
                      h: par['h'],
                      b: par['b'],
                      phi: par['phi'],
                      gamma: par['gamma']})
print(f'The equilibrium for output y_t given the above parameters is:')
yt_val
```

```python
pit_val = pit_sol.subs({alpha: par['alpha'],
                      h: par['h'],
                      b: par['b'],
                      phi: par['phi'],
                      gamma: par['gamma']})
print(f'The equilibrium for inflation pi_t given the above parameters is:')
pit_val
```

# Question 2
We will first the initial values of $y_{t-1} = \pi_{t-1} = v_t = s_t = s_{t-1} = 0$. Next we will transform the sympy equations to lambda functions to calculate numerical values for $y_t$ and $\pi_t$

```python
# Create dict for var and set initials value to 0

var = {}

var['pi_t_1_val'] = 0
var['v_t_val'] = 0
var['y_t_1_val'] = 0
var['s_t_val'] = 0
var['s_t_1_val'] = 0

# Transform the sympy equations into lambda functions

_yt_sol_func = sm.lambdify((alpha, h, b, phi, gamma, pi_t_1, v_t, y_t_1, s_t, s_t_1),yt_sol)

def yt_sol_func(pi_t_1, v_t, y_t_1, s_t, s_t_1,
                    alpha = par['alpha'],
                    h = par['h'],
                    b= par['b'],
                    phi= par['phi'],
                    gamma= par['gamma']):

    return _yt_sol_func(alpha, h, b, phi, gamma, pi_t_1, v_t, y_t_1, s_t, s_t_1)

# Calculate the numerical values
yt_sol_val = yt_sol_func(
                         pi_t_1 = var['pi_t_1_val'],
                         v_t = var['v_t_val'],
                         y_t_1 = var['y_t_1_val'],
                         s_t = var['s_t_val'],
                         s_t_1 = var['s_t_1_val']
                        )

f"The initial equilibrium value of y_t given the parameters and variables is  {yt_sol_val:.3f}"
```

    'The initial equilibrium value of y_t given the parameters and variables is  0.000'

```python
# Transform the sympy equations into lambda functions
_pi_sol_func = sm.lambdify((alpha, h, b, phi, gamma, pi_t_1, v_t, y_t_1, s_t, s_t_1, y_t),pit_sol)

def pi_sol_func(pi_t_1, v_t, y_t_1, s_t, s_t_1, y_t,
                    alpha = par['alpha'],
                    h = par['h'],
                    b= par['b'],
                    phi= par['phi'],
                    gamma= par['gamma']):

    return _pi_sol_func(alpha, h, b, phi, gamma, pi_t_1, v_t, y_t_1, s_t, s_t_1, y_t)

pi_sol_val = pi_sol_func(
                         pi_t_1 = var['pi_t_1_val'],
                         v_t = var['v_t_val'],
                         y_t_1 = var['y_t_1_val'],
                         s_t = var['s_t_val'],
                         s_t_1 = var['s_t_1_val'],
                         y_t = yt_sol_val)
f"The initial equilibrium value of pi_t given the parameters and variables is  {pi_sol_val:.3f}"
```

    'The initial equilibrium value of pi_t given the parameters and variables is  0.000'

Now we will try to illustrate the AD_curve and SRAS_curve in a AS-AD diagram. We will also create a slider to simulate the changing value of $v_t$

```python
# First define the two curves as functions.
def AD_curve(alpha, h, b, v_t, y_t):
    return 1/(h * alpha) * (v_t - (1 + b * alpha) * y_t)

def SRAS_curve(gamma, phi, pi_t_1, y_t_1, s_t, s_t_1, y_t):
    return pi_t_1 + gamma * y_t  - phi * gamma * y_t_1 + s_t - phi * s_t_1
```

Creating the plot

```python
# Define interactive figure
def interactive_fig(v_t_val):

    # Range for output, y_t
    y = np.linspace(-0.1, 0.1, 100)

    # Plot the optimal values for y_t and pi_t
    y_opt_val = yt_sol_func(
                         pi_t_1 = var['pi_t_1_val'],
                         v_t = v_t_val,
                         y_t_1 = var['y_t_1_val'],
                         s_t = var['s_t_val'],
                         s_t_1 = var['s_t_1_val'],
                        )

    pi_opt_val = pi_sol_func(
                         pi_t_1 = var['pi_t_1_val'],
                         v_t = v_t_val,
                         y_t_1 = var['y_t_1_val'],
                         s_t = var['s_t_val'],
                         s_t_1 = var['s_t_1_val'],
                         y_t = y
                        )

    # xlabel, ylabel and title
    plt.xlabel(r'$y_t$', )
    plt.ylabel(r'$\pi_{t}$', fontsize = 15)
    plt.title(r'Equilibrium for AD and SRAS', fontsize = 15)

    # Shorten
    AD_c = AD_curve(
                alpha = par["alpha"],
                h = par['h'],
                b = par['b'],
                v_t = v_t_val,
                y_t = y
               )
    SRAS_c = SRAS_curve(
                gamma = par["gamma"],
                phi = par['phi'],
                pi_t_1 = var['pi_t_1_val'],
                y_t_1 = var['y_t_1_val'],
                s_t = var['s_t_val'],
                s_t_1 = var['s_t_1_val'],
                y_t = y
                )
    # Plot the two curves
    plt.plot(y, AD_c, label = "AD-Curve")
    plt.plot(y, SRAS_c, label = "SRAS_Curve")

    # Create a dashed lines to show optimal values for y_t and pi_t
    plt.axvline(y_opt_val,
                linestyle = 'dashed',
                color = "red",
                label = '$y^*$')

    plt.axhline(pi_opt_val,
                linestyle = 'dashed',
                color = "green",
                label = '$\pi^*$')

    plt.legend()

    plt.axis([-0.15,0.15,-0.18,0.18])

    # Create arrow, which points at the equilibrium
    plt.annotate('Equilibrium', xy=(y_opt_val, pi_opt_val), xytext=(y_opt_val-0.10, pi_opt_val-0.05),
            arrowprops=dict(facecolor='black', shrink=0.01))

    plt.show()

# create slider and plot
interactive_plot = interactive(interactive_fig,
                               v_t_val=widgets.FloatSlider(description="$v_t$",
                                                       min=0.0,
                                                       max=0.1,
                                                       step=0.1,
                                                       value=0,
                                                       continuous_update=True)
                              )

interactive_plot
```

    interactive(children=(FloatSlider(value=0.0, description='$v_t$', max=0.1), Output()), _dom_classes=('widget-i…

We see how the $v_t$ shock moves the AD-curve up and how output increases.

# Question 3
For this question we will begin by setting the initial values to 0. Then create an array for the two shock variables and filling them up with the autoregressive parameters to simulate the economy.

```python
par['delta'] = 0.80
par['omega'] = 0.15
```

```python
# Initial values
y_1 = 0
pi_0 = 0
s_0 = 0
v_0 = 0
x_0 = 0.1
x_t = 0
c_t = 0

# Set periods to 100
period = 100

# Create array and fill in value for initial period
v_t = [ par["delta"] * v_0 + x_0 ]
s_t = [ par["omega"] * s_0 + c_t ]

# Fill up arrays for each period
for i in range(0, period):
    v_t.append(par['delta'] * v_t[i] + x_t)
    s_t.append(par['omega'] * s_t[i] + c_t)
```

Next we want to find all the numeric solutions for $y_t$ and $\pi_t$. We will create an empty array for $y_t$ and $\pi_t$ and then fill it up with the solutions from the simulation.

```python
# Create arrays
y_vals = [0]
pi_vals = [0]

# Loop over each period  and append the solution to the array.
for i in range(1, period):

    # y
    y_vals_i = yt_sol_func(
        v_t=v_t[i],
        s_t=s_t[i],
        pi_t_1=pi_vals[i-1],
        y_t_1=y_vals[i-1],
        s_t_1=s_t[i-1]
        )
    y_vals.append(y_vals_i)
    # Pi
    pi_vals_i = pi_sol_func(
        v_t=v_t[i],
        s_t=s_t[i],
        y_t=y_vals[i],
        pi_t_1=pi_vals[i-1],
        y_t_1=y_vals[i-1],
        s_t_1=s_t[i-1]
        )
    pi_vals.append(pi_vals_i)
```

Now we will illustrate this shock to the economy. First we will define functions for the AD curve and the SRAS curve. For the first period, the function will take the initial input.

```python
# Define functions, which returns the initial numeric solution for the first period and otherwise returns
# the value for the simulated periods to come.
def AD_curves_func(y_t,period,
             h = par['h'],
             b = par['b'],
             alpha = par['alpha'],
             v_t = v_t):
    if period == 0:
        return 1 / (h * alpha) * (v_0 - (1 + b * alpha) * y_t)
    else:
        return 1 / (h * alpha) * (v_t[period - 1] - (1 + b * alpha) * y_t)

def SRAS_curves_func(y_t,period,
               gamma = par['gamma'],
               phi = par['phi'],
               s_t = s_t):

    if period == 0:
        return pi_0 + gamma * y_t - phi * y_1 + s_t[period] - phi * s_0
    else:
        y_values = [0]
        pi_values = [0]
        for i in range(1,period):
            y_val_i = yt_sol_func(
            v_t=v_t[i],
            s_t=s_t[i],
            pi_t_1=pi_vals[i-1],
            y_t_1=y_vals[i-1],
            s_t_1=s_t[i-1]
        )
            y_values.append(y_val_i)
            pi_val_i = pi_sol_func(
            v_t = v_t[i],
            s_t = s_t[i],
            y_t = y_vals[i],
            pi_t_1 = pi_vals[i-1],
            y_t_1 = y_vals[i-1],
            s_t_1 = s_t[i-1])
            pi_values.append(pi_val_i)

        return pi_values[period-1] + gamma * y_t - phi * gamma * y_values[period - 1] + s_t[period] - phi * s_t[period-1]

```

```python
#  Constructing graph

def simulate_economy(vt,st):

    # range for output, y

    y = np.linspace(-0.05,0.05,100)

    # Create AD-curves
    AD_0 = AD_curves_func(y, 0, v_t = v_t)
    AD_1 = AD_curves_func(y, 1, v_t = v_t)
    AD_2 = AD_curves_func(y, 2, v_t = v_t)
    AD_5 = AD_curves_func(y, 5, v_t = v_t)
    AD_10 = AD_curves_func(y, 10, v_t = v_t)
    AD_100 = AD_curves_func(y, 100, v_t = v_t)

    # Create SRAS-curves
    SRAS_0 = SRAS_curves_func(y, 0, s_t = s_t)
    SRAS_1 = SRAS_curves_func(y, 1, s_t = s_t)
    SRAS_2 = SRAS_curves_func(y, 2, s_t = s_t)
    SRAS_5 = SRAS_curves_func(y, 5, s_t = s_t)
    SRAS_10 = SRAS_curves_func(y, 10, s_t = s_t)
    SRAS_100 = SRAS_curves_func(y, 10 , s_t = s_t)

    # Plot the figure
    plt.figure(figsize=(12,6))

    # Plot AD curves
    plt.plot(y,AD_0,label=('$AD_0$'),linewidth=5,color='#1843ce')
    plt.plot(y,AD_1,label='$AD_1$',color='#1863ce')
    plt.plot(y,AD_2,label='$AD_2$',color='#1879ce')
    plt.plot(y,AD_5,label='$AD_5$',color='#189dce')
    plt.plot(y,AD_10,label='$AD_{10}$',color='#18b5ce')
    plt.plot(y,AD_100,label='$AD_{100}$',color='#38c0e2')

    # Plot SRAS curves
    plt.plot(y,SRAS_0,label='$SRAS_0$',linewidth=5,color='#961618')
    plt.plot(y,SRAS_1,label='$SRAS_1$',color='#ba1a1c')
    plt.plot(y,SRAS_2,label='$SRAS_2$',color='#d62022')
    plt.plot(y,SRAS_5,label='$SRAS_{5}$',color='#f92527')
    plt.plot(y,SRAS_10,label='$SRAS_{10}$',color='#f94345')
    plt.plot(y,SRAS_100,label='$SRAS_{100}$',color='#fc585a')

    # label, title
    plt.title('AD and SRAS', fontsize = 15)
    plt.xlabel('$y_t$', fontsize = 15)
    plt.ylabel('$\pi_t$', fontsize = 15)

    # d. Create a dashed lines to show optimal values for y_t and pi_t
    plt.axvline(yt_sol_val, linestyle='dashed', label='$y^*$')
    plt.axhline(pi_sol_val, linestyle='dashed', label='$\pi^*$')

    plt.legend()

    # Creates an arrow, which point at the way the AD-curve transition back to equilibrium.
    plt.annotate('', xy=(0, 0), xytext=(0.0, 0.035),
            arrowprops=dict(facecolor='black', shrink=0.01))

simulate_economy(v_t,s_t)
```

# Question 4
For this question we choose a random seed numer, 189, to generate $x_t$ and $c_t$.

```python
par['sigma_x'] = 3.492
par['sigma_c'] = 0.2
```

```python
# Choose 1000 periods and set seed number to 189, then generate x_t and c_t
period = 1000
seed = 189
np.random.seed(seed)
x_t = np.random.normal(0,par['sigma_x'],period)
c_t = np.random.normal(0,par['sigma_c'],period)
```

Next we will create an empty array for the two shock variables and fill them up as done previously.

```python
# Create empty vectors
v_vec = [0]
s_vec = [0]

# Loop over each x_t and c_t
for i in range(1, period):
    v_i = par["delta"] * v_vec[i-1] + x_t[i]
    v_vec.append(v_i)
    s_i = par["omega"] * s_vec[i-1] + c_t[i]
    s_vec.append(s_i)
```

Next we want to find the new numeric solution to arrays for $y_t$ and $\pi_t$

```python
#
y_vec = [0]
pi_vec = [0]

# Loop over each period and find the numeric solutions.
for i in range(1, period):

    y_val_i = yt_sol_func(
        v_t=v_vec[i],
        s_t=s_vec[i],
        pi_t_1=pi_vec[i-1],
        y_t_1=y_vec[i-1],
        s_t_1=s_vec[i-1]
        )

    y_vec.append(y_val_i)

    pi_val_i = pi_sol_func(
        pi_t_1=pi_vec[i-1],
        v_t=v_vec[i],
        y_t_1=y_vec[i-1],
        s_t=s_vec[i],
        s_t_1=s_vec[i-1],
        y_t=y_vec[i],
        )
    pi_vec.append(pi_val_i)
```

Now we can find the mean, variance, correlation etc.

```python
# Variance for y
y_variance = np.var(y_vec)
f'1, The variance of y_t is: {y_variance:.3f}'
```

    '1, The variance of y_t is: 1.993'

```python
# Variance for pi
pi_variance = np.var(pi_vec)
f'2. The variance of pi_t is: {pi_variance:.3f}'
```

    '2. The variance of pi_t is: 1.206'

```python
# Correlation between y and pi
y_pi_corr = np.corrcoef(y_vec,pi_vec)
f'3. The correlation between y_t and pi_t is: {y_pi_corr[1,0]:.3f}'
```

    '3. The correlation between y_t and pi_t is: -0.234'

```python
# Auto-correlation between y_t_1 and y_t
autocoef_y = np.corrcoef(np.array([y_vec[:-1],y_vec[1:]]))
f'4. The auto-correlation between y_t and y_t_1 is: {autocoef_y[1,0]:.3f}'
```

    '4. The auto-correlation between y_t and y_t_1 is: 0.791'

```python
# Auto-correlation between pi_t_1 and pi_t
autocoef_pi = np.corrcoef(np.array([pi_vec[:-1],pi_vec[1:]]))
f'5. The auto-correlation between pi_t and pi_t_1 is: {autocoef_pi[1,0]:.3f}'
```

    '5. The auto-correlation between pi_t and pi_t_1 is: 0.980'

# Question 5
For this question, we will begin by resetting the variables by setting them equal to their initial values. Then we will define a function, which first create two empty arrays and then loop over each period to fill them up with the numeric solutions. The function will return the correlation coeffecient between $y_t$ and $\pi_t$

```python
# Set variables to their initial values
s_0 = 0
v_0 = 0
x_0 = 0.1
x_t = 0
c_t = 0

# Define function
def corr_sim(corr):

    # Create arrays
    y_sim_vec = [0]
    pi_sim_vec = [0]

    # Loop over each period and find numerical solutions.
    for i in range (1, period):

        y_sim = yt_sol_func(
        v_t=v_vec[i],
        s_t=s_vec[i],
        pi_t_1=pi_sim_vec[i-1],
        y_t_1=y_sim_vec[i-1],
        s_t_1=s_vec[i-1],
        phi = corr
        )
        y_sim_vec.append(y_sim)

        pi_sim = pi_sol_func(
        pi_t_1=pi_sim_vec[i-1],
        v_t=v_vec[i],
        y_t_1=y_sim_vec[i-1],
        s_t=s_vec[i],
        s_t_1=s_vec[i-1],
        y_t=y_sim_vec[i],
        phi = corr
        )
        pi_sim_vec.append(pi_sim)

    # Return the correlation coeffecient
    return np.corrcoef(y_sim_vec,pi_sim_vec)[1,0]
```

Now we will plot how the correlation increases for increasing values of $\phi$.

```python
# Create vec for phi
phi_vec = np.linspace(0,1,100)

# Create empty vec for correlation and loop over each correlation between y_t and pi_t
correlation_vec = np.empty(100)
for i, val in enumerate(phi_vec):
    correlation_vec[i] = corr_sim(val)

# plot
plt.figure(figsize=(8,5))
plt.plot(phi_vec,correlation_vec)
plt.title('Correlation between $y_t$ and $\pi_t$')
plt.xlabel('$\phi$')
plt.ylabel('Correlation coef between $y_t$ and $\pi_t$')
plt.grid(True)
```

We see from the above plot how the correlation increases for increasing values of $\phi$
Now we will make use of scipy.optimize to find the value of $\phi$, which ensure that the correlation coef between $y_t$ and $pi_t$ is 0.31

```python
# import optimize
from scipy import optimize
# Set x_0 = 0
x_0 = 0

# Create a lambda function
obj = lambda corr: (corr_sim(corr)-0.31)**2

# minimize_scalar with the bounded method
result = optimize.minimize_scalar(obj,x_0,method='bounded',bounds=[0.5,1])
print(f'"The optimal value of phi is {result.x:.3} to ensure the correlation coef between y_t and pi_t is 0.31')
```

    "The optimal value of phi is 0.979 to ensure the correlation coef between y_t and pi_t is 0.31

# Quesiton 6
Unfortunately, we ran into some issues when trying to solve the last question.
We tried to enforce the similar method as in the previous question, but was unable to do it correctly.
Anyways, we notice that the $var(y_t)$, $corr(y_t,\pi_t$) and $corr(y_{t-1},y_t)$ somewhat matches the US economy, while the others does not.

# 3. Exchange economy

```python
# a. parameters
N = 50000
mu = np.array([3,2,1])
Sigma = np.array([[0.25, 0, 0], [0, 0.25, 0], [0, 0, 0.25]])
gamma = 0.8
zeta = 1

# b. random draws
seed = 1986
np.random.seed(seed)

# preferences
alphas = np.exp(np.random.multivariate_normal(mu, Sigma, size=N))
betas = alphas/np.reshape(np.sum(alphas,axis=1),(N,1))

# endowments
e1 = np.random.exponential(zeta,size=N)
e2 = np.random.exponential(zeta,size=N)
e3 = np.random.exponential(zeta,size=N)
```

# Question 1
As the utility function is presented as a Cobb-douglas, we know that $beta_j$ is the budget share for each good.

```python
# Create arrays for each agent's preferences of the three goods
beta1=betas[:,0]
beta2=betas[:,1]
beta3=betas[:,2]
```

```python
# Create figure
fig = plt.figure(figsize=(15,10))

# Add a subplot for each good
ax1 = fig.add_subplot(2,3,1)
ax1.hist(beta1, bins=200, color ="#f7d56f")
ax1.set_title('Good #1')
ax1.set_xlabel('$\\beta_1$')
ax1.set_ylabel('Number of agents')
plt.axis([0, 1, 0, 1300])

ax2 = fig.add_subplot(2,3,2)
ax2.hist(beta2, bins=200, color ="#6ab2f2")
ax2.set_title('Good #2')
ax2.set_xlabel('$\\beta_2$')
plt.axis([0, 1, 0, 1300])

ax3 = fig.add_subplot(2,3,3)
ax3.hist(beta3, bins=200, color ="#66f47e")
ax3.set_title('Good #3')
ax3.set_xlabel('$\\beta_3$')
plt.axis([0, 1, 0, 1300])

plt.show()
```

# Question 2
We will begin by defining the demand function for each of the three goods.

```python
# The function takes the two price vectors p1, p2 and three endowments e1, e2, e3 and the betas.
# The income is defined as price times endowments
# The function returns the demand for each good

def demand_good_1_func(p1,p2,e1,e2,e3,betas):
    I = p1*e1+p2*e2+e3
    return beta1*I/p1

def demand_good_2_func(p1,p2,e1,e2,e3,betas):
    I = p1 * e1 + p2 * e2 + e3
    return beta2*I/p2

def demand_good_3_func(p1,p2,e1,e2,e3,betas):
    I = p1 * e1 + p2 * e2 + e3
    return beta3*I
```

Then we will define the excess demand functions for each good.

```python
def excess_demand_good_1_func(p1,p2,e1,e2,e3,betas):

    # a. demand - Sum of all demand for good 1
    demand = np.sum(demand_good_1_func(p1,p2,e1,e2,e3,betas))

    # b. supply - Sum of all endowments
    supply = np.sum(e1)

    # c. excess demand - Demand less the supply
    excess_demand = demand-supply

    return excess_demand

def excess_demand_good_2_func(p1,p2,e1,e2,e3,betas):

    # a. demand - Sum of all demand for good 2
    demand = np.sum(demand_good_2_func(p1,p2,e1,e2,e3,betas))

    # b. upply - Sum of all endowments
    supply = np.sum(e2)

    # c. excess demand - Demand less the supply
    excess_demand = demand-supply

    return excess_demand

def excess_demand_good_3_func(p1,p2,e1,e2,e3,betas):

    # a. demand - Sum of all demand for good 3
    demand = np.sum(demand_good_3_func(p1,p2,e1,e2,e3,betas))

    # b. Sum of all endowments
    supply = np.sum(e3)

    # c. excess demand - Demand less the supply
    excess_demand = demand-supply

    return excess_demand
```

Next we will first define the two price vectors for p1 and p2, which we define as a linear vector from [0.5,10]. Then we will make use of np.meshgrid to return grids from the price vectors.
We will then create three empty grids for each excess grid and then fill them up with each value in the price vectors given the demand excess functions.

```python
# choose a size for the vectors
Num = 100

# Create shape tuple
shape_tuple = (Num,Num)

# Create price vectors
p1_vec = np.linspace(0.5,10,Num)
p2_vec = np.linspace(0.5,10,Num)

# Create meshgrid from price vectors
p1_grid, p2_grid = np.meshgrid(p1_vec, p2_vec)

# Define three empty excess grids
excess1 = np.empty((shape_tuple))
excess2 = np.empty((shape_tuple))
excess3 = np.empty((shape_tuple))

# Iterate over each value in the price vector to fill up the excess grids
for i, p1 in enumerate(p1_vec):
    for j, p2 in enumerate(p2_vec):
        excess1[i,j]=excess_demand_good_1_func(p1,p2,e1,e2,e3,betas)
        excess2[i,j]=excess_demand_good_2_func(p1,p2,e1,e2,e3,betas)
        excess3[i,j]=excess_demand_good_3_func(p1,p2,e1,e2,e3,betas)

```

```python
# Import packages
%matplotlib inline
import matplotlib.pyplot as plt # baseline modul
from mpl_toolkits.mplot3d import Axes3D # for 3d figures
from matplotlib import cm # for color
```

```python

fig = plt.figure(figsize=(15,5)) # create the figure

# For each good, plot the price meshes and the excess demand.

ax1 = fig.add_subplot(1,3,1,projection='3d') # create a 3d axis in the figure
ax1.plot_surface(p1_grid,p2_grid,excess1,cmap=cm.jet) # create surface plot in the axis
ax1.invert_xaxis()
ax1.set_title('Excess demand of good 1')
ax1.set_xlabel('$p_2$')
ax1.set_ylabel('$p_1$')
ax1.set_zlabel('$z_1$')
ax1.xaxis.pane.fill = False
ax1.yaxis.pane.fill = False
ax1.zaxis.pane.fill = False

ax2 = fig.add_subplot(1,3,2,projection='3d') # create a 3d axis in the figure
ax2.plot_surface(p1_grid,p2_grid,excess2,cmap=cm.jet)
ax2.invert_xaxis()
ax2.set_title('Excess demand of good 2')
ax2.set_xlabel('$p_2$')
ax2.set_ylabel('$p_1$')
ax2.set_zlabel('$z_2$');
ax2.xaxis.pane.fill = False
ax2.yaxis.pane.fill = False
ax2.zaxis.pane.fill = False

ax3 = fig.add_subplot(1,3,3,projection='3d') # create a 3d axis in the figure
ax3.plot_surface(p1_grid,p2_grid,excess3,cmap=cm.jet)
ax3.invert_xaxis()
ax3.set_title('Excess demand of good 3')
ax3.set_xlabel('$p_2$')
ax3.set_ylabel('$p_1$')
ax3.set_zlabel('$z_3$')
ax3.xaxis.pane.fill = False
ax3.yaxis.pane.fill = False
ax3.zaxis.pane.fill = False;
```

# Question 3
We will begin this question by defining a function for the tâtonnement process, which takes p1, p2, e1, e2, e3, betas, kappa (Which adjust the aggresivivity), eps (the tolerance), maxiter (Max iterations).

```python
def find_equilibrium(p1,p2,e1,e2,e3,betas,kappa=0.9,eps=1e-8,maxiter=3000):

    t = 0
    while True:

        # a. excess demand for good 1 and good 2
        Z1 = excess_demand_good_1_func(p1,p2,e1,e2,e3,betas)
        Z2 = excess_demand_good_2_func(p1,p2,e1,e2,e3,betas)

        # b: If the excess demand for good 1 or good 2 is lower (or maxiter has been reached) than the tolerance
        #  then break.
        if  np.abs(Z1) < eps and np.abs(Z2) < eps or t >= maxiter:
            print(f'{t:3d}: p1 = {p1:12.8f} -> excess demand -> {Z1:14.8f} p2 = {p2:12.8f} -> excess demand -> {Z2:14.8f}')
            break

        # c. If not, then set the prices as below
        p1 = p1 + kappa*Z1/betas.size
        p2 = p2 + kappa*Z2/betas.size

        # d. return
        if t < 5 or t%25 == 0:
            print(f'{t:3d}: p1 = {p1:12.8f} -> excess demand -> {Z1:14.8f} p2 = {p2:12.8f} -> excess demand -> {Z2:14.8f}')
        elif t == 5:
            print('   ...')

        t += 1

    return p1, p2
```

Now we guess on the prices and run the function.

```python
p1 = 3
p2 = 3
kappa = 0.8
eps = 1e-8
p1, p2 = find_equilibrium(p1,p2,e1,e2,e3,betas,kappa=kappa,eps=eps)
```

      0: p1 =   3.13242998 -> excess demand -> 24830.62081187 p2 =   2.89503410 -> excess demand -> -19681.10609181
      1: p1 =   3.24953265 -> excess demand -> 21956.75110613 p2 =   2.79653311 -> excess demand -> -18468.93528892
      2: p1 =   3.35382488 -> excess demand -> 19554.79244949 p2 =   2.70436429 -> excess demand -> -17281.65490885
      3: p1 =   3.44723557 -> excess demand -> 17514.50532486 p2 =   2.61840426 -> excess demand -> -16117.50536588
      4: p1 =   3.53129068 -> excess demand -> 15760.33324137 p2 =   2.53852765 -> excess demand -> -14976.86431327
       ...
     25: p1 =   4.32935739 -> excess demand ->  3668.14907331 p2 =   1.88994781 -> excess demand ->  -737.37747432
     50: p1 =   4.69763396 -> excess demand ->  2299.14161154 p2 =   1.95010213 -> excess demand ->   778.99889458
     75: p1 =   4.96884180 -> excess demand ->  1824.74465940 p2 =   2.04851523 -> excess demand ->   679.27508163
    100: p1 =   5.18816891 -> excess demand ->  1494.51036578 p2 =   2.13043481 -> excess demand ->   558.86386466
    125: p1 =   5.36929385 -> excess demand ->  1243.02199491 p2 =   2.19816371 -> excess demand ->   464.74526696
    150: p1 =   5.52082611 -> excess demand ->  1045.38867190 p2 =   2.25480861 -> excess demand ->   390.71295581
    175: p1 =   5.64883988 -> excess demand ->   886.71796026 p2 =   2.30264612 -> excess demand ->   331.31089719
    200: p1 =   5.75780927 -> excess demand ->   757.22505816 p2 =   2.34335602 -> excess demand ->   282.85957009
    225: p1 =   5.85113097 -> excess demand ->   650.16880321 p2 =   2.37821255 -> excess demand ->   242.82156882
    250: p1 =   5.93144568 -> excess demand ->   560.73558333 p2 =   2.40820553 -> excess demand ->   209.38689340
    275: p1 =   6.00084623 -> excess demand ->   485.38651202 p2 =   2.43411891 -> excess demand ->   181.22623081
    300: p1 =   6.06101767 -> excess demand ->   421.45595138 p2 =   2.45658349 -> excess demand ->   157.33916882
    325: p1 =   6.11333460 -> excess demand ->   366.89448568 p2 =   2.47611363 -> excess demand ->   136.95713969
    350: p1 =   6.15893085 -> excess demand ->   320.09870835 p2 =   2.49313343 -> excess demand ->   119.47922356
    375: p1 =   6.19875040 -> excess demand ->   279.79517965 p2 =   2.50799584 -> excess demand ->   104.42842920
    400: p1 =   6.23358544 -> excess demand ->   244.95929392 p2 =   2.52099698 -> excess demand ->    91.42115569
    425: p1 =   6.26410534 -> excess demand ->   214.75728406 p2 =   2.53238699 -> excess demand ->    80.14538099
    450: p1 =   6.29087897 -> excess demand ->   188.50394327 p2 =   2.54237843 -> excess demand ->    70.34477323
    475: p1 =   6.31439229 -> excess demand ->   165.63125967 p2 =   2.55115281 -> excess demand ->    61.80691099
    500: p1 =   6.33506222 -> excess demand ->   145.66477716 p2 =   2.55886586 -> excess demand ->    54.35441059
    525: p1 =   6.35324786 -> excess demand ->   128.20552356 p2 =   2.56565168 -> excess demand ->    47.83814661
    550: p1 =   6.36925947 -> excess demand ->   112.91601469 p2 =   2.57162612 -> excess demand ->    42.13200407
    575: p1 =   6.38336596 -> excess demand ->    99.50928598 p2 =   2.57688956 -> excess demand ->    37.12876764
    600: p1 =   6.39580094 -> excess demand ->    87.74020338 p2 =   2.58152924 -> excess demand ->    32.73686646
    625: p1 =   6.40676783 -> excess demand ->    77.39851106 p2 =   2.58562108 -> excess demand ->    28.87777051
    650: p1 =   6.41644411 -> excess demand ->    68.30321767 p2 =   2.58923132 -> excess demand ->    25.48388912
    675: p1 =   6.42498488 -> excess demand ->    60.29802549 p2 =   2.59241785 -> excess demand ->    22.49686034
    700: p1 =   6.43252588 -> excess demand ->    53.24757962 p2 =   2.59523134 -> excess demand ->    19.86614766
    725: p1 =   6.43918608 -> excess demand ->    47.03436835 p2 =   2.59771618 -> excess demand ->    17.54788068
    750: p1 =   6.44506987 -> excess demand ->    41.55614478 p2 =   2.59991133 -> excess demand ->    15.50389093
    775: p1 =   6.45026893 -> excess demand ->    36.72376936 p2 =   2.60185101 -> excess demand ->    13.70090532
    800: p1 =   6.45486387 -> excess demand ->    32.45939446 p2 =   2.60356528 -> excess demand ->    12.10986759
    825: p1 =   6.45892559 -> excess demand ->    28.69492934 p2 =   2.60508061 -> excess demand ->    10.70536464
    850: p1 =   6.46251652 -> excess demand ->    25.37073606 p2 =   2.60642029 -> excess demand ->     9.46513932
    875: p1 =   6.46569167 -> excess demand ->    22.43451708 p2 =   2.60760485 -> excess demand ->     8.36967481
    900: p1 =   6.46849952 -> excess demand ->    19.84036280 p2 =   2.60865238 -> excess demand ->     7.40183888
    925: p1 =   6.47098281 -> excess demand ->    17.54793309 p2 =   2.60957882 -> excess demand ->     6.54657822
    950: p1 =   6.47317928 -> excess demand ->    15.52175195 p2 =   2.61039825 -> excess demand ->     5.79065504
    975: p1 =   6.47512222 -> excess demand ->    13.73059782 p2 =   2.61112309 -> excess demand ->     5.12241938
    1000: p1 =   6.47684100 -> excess demand ->    12.14697534 p2 =   2.61176431 -> excess demand ->     4.53161194
    1025: p1 =   6.47836160 -> excess demand ->    10.74665649 p2 =   2.61233160 -> excess demand ->     4.00919277
    1050: p1 =   6.47970694 -> excess demand ->     9.50828140 p2 =   2.61283349 -> excess demand ->     3.54719219
    1075: p1 =   6.48089728 -> excess demand ->     8.41301014 p2 =   2.61327757 -> excess demand ->     3.13858092
    1100: p1 =   6.48195053 -> excess demand ->     7.44421877 p2 =   2.61367049 -> excess demand ->     2.77715653
    1125: p1 =   6.48288251 -> excess demand ->     6.58723343 p2 =   2.61401818 -> excess demand ->     2.45744428
    1150: p1 =   6.48370721 -> excess demand ->     5.82909747 p2 =   2.61432584 -> excess demand ->     2.17461013
    1175: p1 =   6.48443701 -> excess demand ->     5.15836733 p2 =   2.61459810 -> excess demand ->     1.92438463
    1200: p1 =   6.48508284 -> excess demand ->     4.56493326 p2 =   2.61483904 -> excess demand ->     1.70299599
    1225: p1 =   6.48565438 -> excess demand ->     4.03986196 p2 =   2.61505226 -> excess demand ->     1.50711138
    1250: p1 =   6.48616019 -> excess demand ->     3.57525812 p2 =   2.61524095 -> excess demand ->     1.33378520
    1275: p1 =   6.48660783 -> excess demand ->     3.16414260 p2 =   2.61540795 -> excess demand ->     1.18041372
    1300: p1 =   6.48700400 -> excess demand ->     2.80034519 p2 =   2.61555574 -> excess demand ->     1.04469500
    1325: p1 =   6.48735462 -> excess demand ->     2.47841012 p2 =   2.61568655 -> excess demand ->     0.92459362
    1350: p1 =   6.48766493 -> excess demand ->     2.19351275 p2 =   2.61580231 -> excess demand ->     0.81830966
    1375: p1 =   6.48793958 -> excess demand ->     1.94138610 p2 =   2.61590477 -> excess demand ->     0.72425125
    1400: p1 =   6.48818266 -> excess demand ->     1.71825606 p2 =   2.61599545 -> excess demand ->     0.64101038
    1425: p1 =   6.48839780 -> excess demand ->     1.52078417 p2 =   2.61607571 -> excess demand ->     0.56734159
    1450: p1 =   6.48858822 -> excess demand ->     1.34601712 p2 =   2.61614675 -> excess demand ->     0.50214310
    1475: p1 =   6.48875675 -> excess demand ->     1.19134215 p2 =   2.61620963 -> excess demand ->     0.44444018
    1500: p1 =   6.48890592 -> excess demand ->     1.05444763 p2 =   2.61626527 -> excess demand ->     0.39337044
    1525: p1 =   6.48903795 -> excess demand ->     0.93328828 p2 =   2.61631453 -> excess demand ->     0.34817087
    1550: p1 =   6.48915481 -> excess demand ->     0.82605438 p2 =   2.61635812 -> excess demand ->     0.30816633
    1575: p1 =   6.48925824 -> excess demand ->     0.73114456 p2 =   2.61639671 -> excess demand ->     0.27275941
    1600: p1 =   6.48934979 -> excess demand ->     0.64714181 p2 =   2.61643086 -> excess demand ->     0.24142146
    1625: p1 =   6.48943082 -> excess demand ->     0.57279216 p2 =   2.61646109 -> excess demand ->     0.21368470
    1650: p1 =   6.48950254 -> excess demand ->     0.50698594 p2 =   2.61648785 -> excess demand ->     0.18913515
    1675: p1 =   6.48956602 -> excess demand ->     0.44874112 p2 =   2.61651153 -> excess demand ->     0.16740643
    1700: p1 =   6.48962221 -> excess demand ->     0.39718861 p2 =   2.61653249 -> excess demand ->     0.14817435
    1725: p1 =   6.48967194 -> excess demand ->     0.35155929 p2 =   2.61655104 -> excess demand ->     0.13115196
    1750: p1 =   6.48971596 -> excess demand ->     0.31117244 p2 =   2.61656747 -> excess demand ->     0.11608532
    1775: p1 =   6.48975493 -> excess demand ->     0.27542563 p2 =   2.61658200 -> excess demand ->     0.10274969
    1800: p1 =   6.48978941 -> excess demand ->     0.24378567 p2 =   2.61659487 -> excess demand ->     0.09094615
    1825: p1 =   6.48981994 -> excess demand ->     0.21578066 p2 =   2.61660625 -> excess demand ->     0.08049866
    1850: p1 =   6.48984696 -> excess demand ->     0.19099295 p2 =   2.61661633 -> excess demand ->     0.07125141
    1875: p1 =   6.48987087 -> excess demand ->     0.16905288 p2 =   2.61662526 -> excess demand ->     0.06306649
    1900: p1 =   6.48989204 -> excess demand ->     0.14963327 p2 =   2.61663315 -> excess demand ->     0.05582185
    1925: p1 =   6.48991077 -> excess demand ->     0.13244455 p2 =   2.61664014 -> excess demand ->     0.04940947
    1950: p1 =   6.48992736 -> excess demand ->     0.11723042 p2 =   2.61664633 -> excess demand ->     0.04373371
    1975: p1 =   6.48994204 -> excess demand ->     0.10376402 p2 =   2.61665180 -> excess demand ->     0.03870997
    2000: p1 =   6.48995503 -> excess demand ->     0.09184457 p2 =   2.61665665 -> excess demand ->     0.03426332
    2025: p1 =   6.48996653 -> excess demand ->     0.08129435 p2 =   2.61666094 -> excess demand ->     0.03032748
    2050: p1 =   6.48997671 -> excess demand ->     0.07195607 p2 =   2.61666474 -> excess demand ->     0.02684377
    2075: p1 =   6.48998572 -> excess demand ->     0.06369050 p2 =   2.61666810 -> excess demand ->     0.02376023
    2100: p1 =   6.48999369 -> excess demand ->     0.05637441 p2 =   2.61667108 -> excess demand ->     0.02103091
    2125: p1 =   6.49000075 -> excess demand ->     0.04989873 p2 =   2.61667371 -> excess demand ->     0.01861511
    2150: p1 =   6.49000700 -> excess demand ->     0.04416692 p2 =   2.61667604 -> excess demand ->     0.01647681
    2175: p1 =   6.49001253 -> excess demand ->     0.03909352 p2 =   2.61667810 -> excess demand ->     0.01458414
    2200: p1 =   6.49001743 -> excess demand ->     0.03460290 p2 =   2.61667993 -> excess demand ->     0.01290888
    2225: p1 =   6.49002176 -> excess demand ->     0.03062812 p2 =   2.61668155 -> excess demand ->     0.01142606
    2250: p1 =   6.49002559 -> excess demand ->     0.02710992 p2 =   2.61668298 -> excess demand ->     0.01011357
    2275: p1 =   6.49002899 -> excess demand ->     0.02399586 p2 =   2.61668424 -> excess demand ->     0.00895184
    2300: p1 =   6.49003199 -> excess demand ->     0.02123950 p2 =   2.61668536 -> excess demand ->     0.00792356
    2325: p1 =   6.49003465 -> excess demand ->     0.01879976 p2 =   2.61668636 -> excess demand ->     0.00701340
    2350: p1 =   6.49003701 -> excess demand ->     0.01664027 p2 =   2.61668723 -> excess demand ->     0.00620778
    2375: p1 =   6.49003909 -> excess demand ->     0.01472884 p2 =   2.61668801 -> excess demand ->     0.00549471
    2400: p1 =   6.49004093 -> excess demand ->     0.01303697 p2 =   2.61668870 -> excess demand ->     0.00486354
    2425: p1 =   6.49004257 -> excess demand ->     0.01153945 p2 =   2.61668931 -> excess demand ->     0.00430488
    2450: p1 =   6.49004401 -> excess demand ->     0.01021394 p2 =   2.61668985 -> excess demand ->     0.00381039
    2475: p1 =   6.49004529 -> excess demand ->     0.00904069 p2 =   2.61669032 -> excess demand ->     0.00337270
    2500: p1 =   6.49004642 -> excess demand ->     0.00800221 p2 =   2.61669075 -> excess demand ->     0.00298528
    2525: p1 =   6.49004742 -> excess demand ->     0.00708301 p2 =   2.61669112 -> excess demand ->     0.00264237
    2550: p1 =   6.49004831 -> excess demand ->     0.00626941 p2 =   2.61669145 -> excess demand ->     0.00233885
    2575: p1 =   6.49004910 -> excess demand ->     0.00554926 p2 =   2.61669174 -> excess demand ->     0.00207019
    2600: p1 =   6.49004979 -> excess demand ->     0.00491183 p2 =   2.61669200 -> excess demand ->     0.00183239
    2625: p1 =   6.49005041 -> excess demand ->     0.00434762 p2 =   2.61669223 -> excess demand ->     0.00162191
    2650: p1 =   6.49005095 -> excess demand ->     0.00384822 p2 =   2.61669244 -> excess demand ->     0.00143561
    2675: p1 =   6.49005143 -> excess demand ->     0.00340618 p2 =   2.61669262 -> excess demand ->     0.00127070
    2700: p1 =   6.49005186 -> excess demand ->     0.00301492 p2 =   2.61669277 -> excess demand ->     0.00112474
    2725: p1 =   6.49005224 -> excess demand ->     0.00266861 p2 =   2.61669292 -> excess demand ->     0.00099554
    2750: p1 =   6.49005257 -> excess demand ->     0.00236207 p2 =   2.61669304 -> excess demand ->     0.00088119
    2775: p1 =   6.49005287 -> excess demand ->     0.00209075 p2 =   2.61669315 -> excess demand ->     0.00077997
    2800: p1 =   6.49005313 -> excess demand ->     0.00185059 p2 =   2.61669325 -> excess demand ->     0.00069038
    2825: p1 =   6.49005336 -> excess demand ->     0.00163802 p2 =   2.61669333 -> excess demand ->     0.00061107
    2850: p1 =   6.49005357 -> excess demand ->     0.00144986 p2 =   2.61669341 -> excess demand ->     0.00054088
    2875: p1 =   6.49005375 -> excess demand ->     0.00128332 p2 =   2.61669348 -> excess demand ->     0.00047875
    2900: p1 =   6.49005391 -> excess demand ->     0.00113591 p2 =   2.61669354 -> excess demand ->     0.00042376
    2925: p1 =   6.49005405 -> excess demand ->     0.00100543 p2 =   2.61669359 -> excess demand ->     0.00037508
    2950: p1 =   6.49005418 -> excess demand ->     0.00088994 p2 =   2.61669364 -> excess demand ->     0.00033200
    2975: p1 =   6.49005429 -> excess demand ->     0.00078771 p2 =   2.61669368 -> excess demand ->     0.00029386
    3000: p1 =   6.49005438 -> excess demand ->     0.00069723 p2 =   2.61669372 -> excess demand ->     0.00026011

The Walras-equilibrium prices, $(p_1,p_2)$, where both excess demands are (approximately) zero have been found to be:

```python
f'(p_1,p_2) = ({p1:.3f},{p2:.3f})'
```

    '(p_1,p_2) = (6.490,2.617)'

At last we will ensure that the excess demand is almost zero.

```python
Z1 = excess_demand_good_1_func(p1,p2,e1,e2,e3,betas)
Z2 = excess_demand_good_2_func(p1,p2,e1,e2,e3,betas)
Z3 = excess_demand_good_3_func(p1,p2,e1,e2,e3,betas)
f'Z1: {Z1:.2f}, Z2: {Z2:.2f}, Z3: {Z3:.2f}'
```

    'Z1: 0.00, Z2: 0.00, Z3: -0.01'

# Question 4
We define the utility function as presented in the text.

```python
# The function takes the two prices, p1, p2 and the endowments, e1, e2, e3, betas and gamma.
# The income with the new prices
# The demand for each good given the new prices
# return the utility

def utility_func(p1, p2, e1, e2, e3, betas, gamma):

    I = p1 * e1 + p2 * e2 + e3
    x1 = beta1*I/p1
    x2 = beta2*I/p2
    x3 = beta3*I

    return (x1 ** beta1 * x2 ** beta2 * x3 ** beta3)**gamma
```

Next we calculate the mean and variance for the utility of the agents

```python
utility_vec = utility_func(p1, p2, e1, e2, e3, betas, gamma)

# Calculate mean
utility_mean = np.mean(utility_vec)

# Calculate variance
utility_var = np.var(utility_vec)

f'The distribution has the mean of {utility_mean:.3f} and the variance of {utility_var:.3f}'

```

    'The distribution has the mean of 1.010 and the variance of 0.317'

Now we will plot the distribution of utility in a histogram

```python
# Plotting the figure
fig = plt.figure(dpi=120)

ax = fig.add_subplot(1,1,1)
ax.hist(utility_vec,bins=500,density=True, alpha = 0.4, label='beta1')
ax.set_title('Distribution of utilities')
ax.set_xlabel('Utility')
ax.set_ylabel('Number of agents')
ax.set_xlim([0,6])
ax.text(3, 0.5, f'$\mu_u$: {utility_mean:.3f},  $\sigma^2_u$: {utility_var:.3f}');
```

# Question 5
We start this question by creating a new empty array for each good and then filling it up with the mean value of each endowment.

```python
# Create empty array and fill up with mean value of endowment
e1_equal = np.zeros(N)+np.mean(e1)
e2_equal = np.zeros(N)+np.mean(e2)
e3_equal = np.zeros(N)+np.mean(e3)
```

Then we can run our find_equilibrium function one more time with the endowment arrays.

```python
# Guess on prices
p1 = 3
p2 = 3

# Run function
p1, p2 = find_equilibrium(p1,p2,e1_equal,e2_equal,e3_equal,betas,kappa=kappa,eps=eps)
```

      0: p1 =   3.13240299 -> excess demand -> 24825.55975897 p2 =   2.89504860 -> excess demand -> -19678.38813939
      1: p1 =   3.24947755 -> excess demand -> 21951.48082735 p2 =   2.79656676 -> excess demand -> -18465.34392437
      2: p1 =   3.35374115 -> excess demand -> 19549.42451647 p2 =   2.70442119 -> excess demand -> -17277.29411287
      3: p1 =   3.44712313 -> excess demand -> 17509.12132286 p2 =   2.61848798 -> excess demand -> -16112.47732727
      4: p1 =   3.53114976 -> excess demand -> 15754.99444829 p2 =   2.53864120 -> excess demand -> -14971.27125771
       ...
     25: p1 =   4.32881196 -> excess demand ->  3665.82708308 p2 =   1.89065163 -> excess demand ->  -734.78080912
     50: p1 =   4.69682912 -> excess demand ->  2297.33952155 p2 =   1.95095356 -> excess demand ->   779.53750330
     75: p1 =   4.96780468 -> excess demand ->  1823.05317155 p2 =   2.04941887 -> excess demand ->   679.57023695
    100: p1 =   5.18691322 -> excess demand ->  1492.91876997 p2 =   2.13136828 -> excess demand ->   559.02987191
    125: p1 =   5.36783268 -> excess demand ->  1241.52683984 p2 =   2.19911271 -> excess demand ->   464.82072065
    150: p1 =   5.51917205 -> excess demand ->  1043.98617748 p2 =   2.25576291 -> excess demand ->   390.72314748
    175: p1 =   5.64700501 -> excess demand ->   885.40419047 p2 =   2.30359834 -> excess demand ->   331.27379011
    200: p1 =   5.75580516 -> excess demand ->   755.99602954 p2 =   2.34430079 -> excess demand ->   282.78830357
    225: p1 =   5.84896863 -> excess demand ->   649.02053716 p2 =   2.37914604 -> excess demand ->   242.72594953
    250: p1 =   5.92913560 -> excess demand ->   559.66413687 p2 =   2.40912503 -> excess demand ->   209.27434732
    275: p1 =   5.99839840 -> excess demand ->   484.38799846 p2 =   2.43502256 -> excess demand ->   181.10243703
    300: p1 =   6.05844153 -> excess demand ->   420.52655557 p2 =   2.45747012 -> excess demand ->   157.20849654
    325: p1 =   6.11063911 -> excess demand ->   366.03047617 p2 =   2.47698256 -> excess demand ->   136.82295853
    350: p1 =   6.15612449 -> excess demand ->   319.29644750 p2 =   2.49398437 -> excess demand ->   119.34412945
    375: p1 =   6.19584114 -> excess demand ->   279.05113221 p2 =   2.50882883 -> excess demand ->   104.29441254
    400: p1 =   6.23058082 -> excess demand ->   244.27003433 p2 =   2.52181226 -> excess demand ->    91.28972878
    425: p1 =   6.26101242 -> excess demand ->   214.11950259 p2 =   2.53318500 -> excess demand ->    80.01767626
    450: p1 =   6.28770439 -> excess demand ->   187.91445113 p2 =   2.54315972 -> excess demand ->    70.22161994
    475: p1 =   6.31114228 -> excess demand ->   165.08699297 p2 =   2.55191803 -> excess demand ->    61.68889594
    500: p1 =   6.33174261 -> excess demand ->   145.16279991 p2 =   2.55961573 -> excess demand ->    54.24192648
    525: p1 =   6.34986409 -> excess demand ->   127.74302968 p2 =   2.56638695 -> excess demand ->    47.73143108
    550: p1 =   6.36581661 -> excess demand ->   112.49032901 p2 =   2.57234756 -> excess demand ->    42.03117126
    575: p1 =   6.37986874 -> excess demand ->    99.11786447 p2 =   2.57759797 -> excess demand ->    37.03383396
    600: p1 =   6.39225377 -> excess demand ->    87.38063248 p2 =   2.58222540 -> excess demand ->    32.64777158
    625: p1 =   6.40317479 -> excess demand ->    77.06850625 p2 =   2.58630575 -> excess demand ->    28.79439463
    650: p1 =   6.41280900 -> excess demand ->    68.00062145 p2 =   2.58990526 -> excess demand ->    25.40606713
    675: p1 =   6.42131120 -> excess demand ->    60.02080470 p2 =   2.59308179 -> excess demand ->    22.42439343
    700: p1 =   6.42881688 -> excess demand ->    52.99382226 p2 =   2.59588598 -> excess demand ->    19.79881281
    725: p1 =   6.43544477 -> excess demand ->    46.80227995 p2 =   2.59836219 -> excess demand ->    17.48543844
    750: p1 =   6.44129902 -> excess demand ->    41.34404447 p2 =   2.60054934 -> excess demand ->    15.44609178
    775: p1 =   6.44647110 -> excess demand ->    36.53008556 p2 =   2.60248161 -> excess demand ->    13.64749474
    800: p1 =   6.45104140 -> excess demand ->    32.28266044 p2 =   2.60418905 -> excess demand ->    12.06059022
    825: p1 =   6.45508065 -> excess demand ->    28.53377851 p2 =   2.60569808 -> excess demand ->    10.65996752
    850: p1 =   6.45865110 -> excess demand ->    25.22389729 p2 =   2.60703197 -> excess demand ->     9.42337443
    875: p1 =   6.46180759 -> excess demand ->    22.30080988 p2 =   2.60821120 -> excess demand ->     8.33130112
    900: p1 =   6.46459846 -> excess demand ->    19.71869251 p2 =   2.60925383 -> excess demand ->     7.36662376
    925: p1 =   6.46706631 -> excess demand ->    17.43728612 p2 =   2.61017578 -> excess demand ->     6.51429858
    950: p1 =   6.46924874 -> excess demand ->    15.42119109 p2 =   2.61099110 -> excess demand ->     5.76109802
    975: p1 =   6.47117891 -> excess demand ->    13.63925765 p2 =   2.61171218 -> excess demand ->     5.09538288
    1000: p1 =   6.47288611 -> excess demand ->    12.06405771 p2 =   2.61234996 -> excess demand ->     4.50690482
    1025: p1 =   6.47439620 -> excess demand ->    10.67142625 p2 =   2.61291410 -> excess demand ->     3.98663493
    1050: p1 =   6.47573200 -> excess demand ->     9.44006218 p2 =   2.61341312 -> excess demand ->     3.52661449
    1075: p1 =   6.47691369 -> excess demand ->     8.35118038 p2 =   2.61385458 -> excess demand ->     3.11982498
    1100: p1 =   6.47795911 -> excess demand ->     7.38820788 p2 =   2.61424512 -> excess demand ->     2.76007444
    1125: p1 =   6.47888399 -> excess demand ->     6.53651815 p2 =   2.61459064 -> excess demand ->     2.44189824
    1150: p1 =   6.47970227 -> excess demand ->     5.78319844 p2 =   2.61489633 -> excess demand ->     2.16047206
    1175: p1 =   6.48042626 -> excess demand ->     5.11684578 p2 =   2.61516680 -> excess demand ->     1.91153572
    1200: p1 =   6.48106683 -> excess demand ->     4.52738798 p2 =   2.61540610 -> excess demand ->     1.69132625
    1225: p1 =   6.48163362 -> excess demand ->     4.00592640 p2 =   2.61561784 -> excess demand ->     1.49651914
    1250: p1 =   6.48213513 -> excess demand ->     3.54459764 p2 =   2.61580519 -> excess demand ->     1.32417666
    1275: p1 =   6.48257889 -> excess demand ->     3.13645198 p2 =   2.61597097 -> excess demand ->     1.17170246
    1300: p1 =   6.48297156 -> excess demand ->     2.77534624 p2 =   2.61611766 -> excess demand ->     1.03680150
    1325: p1 =   6.48331902 -> excess demand ->     2.45584946 p2 =   2.61624746 -> excess demand ->     0.91744484
    1350: p1 =   6.48362648 -> excess demand ->     2.17315978 p2 =   2.61636233 -> excess demand ->     0.81183857
    1375: p1 =   6.48389856 -> excess demand ->     1.92303109 p2 =   2.61646396 -> excess demand ->     0.71839640
    1400: p1 =   6.48413931 -> excess demand ->     1.70170837 p2 =   2.61655391 -> excess demand ->     0.63571554
    1425: p1 =   6.48435236 -> excess demand ->     1.50587065 p2 =   2.61663350 -> excess demand ->     0.56255530
    1450: p1 =   6.48454090 -> excess demand ->     1.33258058 p2 =   2.61670393 -> excess demand ->     0.49781836
    1475: p1 =   6.48470774 -> excess demand ->     1.17923997 p2 =   2.61676625 -> excess demand ->     0.44053408
    1500: p1 =   6.48485538 -> excess demand ->     1.04355049 p2 =   2.61682141 -> excess demand ->     0.38984385
    1525: p1 =   6.48498603 -> excess demand ->     0.92347897 p2 =   2.61687022 -> excess demand ->     0.34498813
    1550: p1 =   6.48510165 -> excess demand ->     0.81722673 p2 =   2.61691341 -> excess demand ->     0.30529496
    1575: p1 =   6.48520396 -> excess demand ->     0.72320246 p2 =   2.61695163 -> excess demand ->     0.27016986
    1600: p1 =   6.48529451 -> excess demand ->     0.63999827 p2 =   2.61698546 -> excess demand ->     0.23908688
    1625: p1 =   6.48537464 -> excess demand ->     0.56636850 p2 =   2.61701539 -> excess demand ->     0.21158067
    1650: p1 =   6.48544555 -> excess demand ->     0.50121103 p2 =   2.61704188 -> excess demand ->     0.18723950
    1675: p1 =   6.48550830 -> excess demand ->     0.44355067 p2 =   2.61706532 -> excess demand ->     0.16569906
    1700: p1 =   6.48556383 -> excess demand ->     0.39252455 p2 =   2.61708607 -> excess demand ->     0.14663701
    1725: p1 =   6.48561298 -> excess demand ->     0.34736916 p2 =   2.61710443 -> excess demand ->     0.12976811
    1750: p1 =   6.48565647 -> excess demand ->     0.30740891 p2 =   2.61712068 -> excess demand ->     0.11483999
    1775: p1 =   6.48569496 -> excess demand ->     0.27204598 p2 =   2.61713506 -> excess demand ->     0.10162931
    1800: p1 =   6.48572902 -> excess demand ->     0.24075136 p2 =   2.61714778 -> excess demand ->     0.08993845
    1825: p1 =   6.48575916 -> excess demand ->     0.21305696 p2 =   2.61715904 -> excess demand ->     0.07959254
    1850: p1 =   6.48578584 -> excess demand ->     0.18854854 p2 =   2.61716900 -> excess demand ->     0.07043683
    1875: p1 =   6.48580944 -> excess demand ->     0.16685953 p2 =   2.61717782 -> excess demand ->     0.06233438
    1900: p1 =   6.48583033 -> excess demand ->     0.14766556 p2 =   2.61718563 -> excess demand ->     0.05516401
    1925: p1 =   6.48584882 -> excess demand ->     0.13067959 p2 =   2.61719253 -> excess demand ->     0.04881849
    1950: p1 =   6.48586518 -> excess demand ->     0.11564759 p2 =   2.61719865 -> excess demand ->     0.04320292
    1975: p1 =   6.48587966 -> excess demand ->     0.10234477 p2 =   2.61720406 -> excess demand ->     0.03823334
    2000: p1 =   6.48589248 -> excess demand ->     0.09057220 p2 =   2.61720884 -> excess demand ->     0.03383541
    2025: p1 =   6.48590382 -> excess demand ->     0.08015385 p2 =   2.61721308 -> excess demand ->     0.02994339
    2050: p1 =   6.48591385 -> excess demand ->     0.07093394 p2 =   2.61721683 -> excess demand ->     0.02649907
    2075: p1 =   6.48592273 -> excess demand ->     0.06277459 p2 =   2.61722015 -> excess demand ->     0.02345095
    2100: p1 =   6.48593059 -> excess demand ->     0.05555381 p2 =   2.61722308 -> excess demand ->     0.02075345
    2125: p1 =   6.48593755 -> excess demand ->     0.04916363 p2 =   2.61722568 -> excess demand ->     0.01836625
    2150: p1 =   6.48594370 -> excess demand ->     0.04350850 p2 =   2.61722798 -> excess demand ->     0.01625364
    2175: p1 =   6.48594915 -> excess demand ->     0.03850387 p2 =   2.61723001 -> excess demand ->     0.01438404
    2200: p1 =   6.48595397 -> excess demand ->     0.03407491 p2 =   2.61723182 -> excess demand ->     0.01272950
    2225: p1 =   6.48595824 -> excess demand ->     0.03015540 p2 =   2.61723341 -> excess demand ->     0.01126527
    2250: p1 =   6.48596201 -> excess demand ->     0.02668675 p2 =   2.61723482 -> excess demand ->     0.00996947
    2275: p1 =   6.48596535 -> excess demand ->     0.02361708 p2 =   2.61723607 -> excess demand ->     0.00882272
    2300: p1 =   6.48596831 -> excess demand ->     0.02090051 p2 =   2.61723717 -> excess demand ->     0.00780788
    2325: p1 =   6.48597093 -> excess demand ->     0.01849641 p2 =   2.61723815 -> excess demand ->     0.00690978
    2350: p1 =   6.48597324 -> excess demand ->     0.01636885 p2 =   2.61723902 -> excess demand ->     0.00611497
    2375: p1 =   6.48597529 -> excess demand ->     0.01448601 p2 =   2.61723978 -> excess demand ->     0.00541160
    2400: p1 =   6.48597711 -> excess demand ->     0.01281975 p2 =   2.61724046 -> excess demand ->     0.00478912
    2425: p1 =   6.48597871 -> excess demand ->     0.01134515 p2 =   2.61724106 -> excess demand ->     0.00423825
    2450: p1 =   6.48598013 -> excess demand ->     0.01004017 p2 =   2.61724159 -> excess demand ->     0.00375075
    2475: p1 =   6.48598139 -> excess demand ->     0.00888530 p2 =   2.61724206 -> excess demand ->     0.00331932
    2500: p1 =   6.48598250 -> excess demand ->     0.00786327 p2 =   2.61724247 -> excess demand ->     0.00293751
    2525: p1 =   6.48598349 -> excess demand ->     0.00695879 p2 =   2.61724284 -> excess demand ->     0.00259962
    2550: p1 =   6.48598436 -> excess demand ->     0.00615835 p2 =   2.61724317 -> excess demand ->     0.00230060
    2575: p1 =   6.48598513 -> excess demand ->     0.00544999 p2 =   2.61724346 -> excess demand ->     0.00203597
    2600: p1 =   6.48598581 -> excess demand ->     0.00482310 p2 =   2.61724371 -> excess demand ->     0.00180179
    2625: p1 =   6.48598641 -> excess demand ->     0.00426832 p2 =   2.61724394 -> excess demand ->     0.00159453
    2650: p1 =   6.48598695 -> excess demand ->     0.00377736 p2 =   2.61724414 -> excess demand ->     0.00141112
    2675: p1 =   6.48598742 -> excess demand ->     0.00334287 p2 =   2.61724431 -> excess demand ->     0.00124881
    2700: p1 =   6.48598784 -> excess demand ->     0.00295835 p2 =   2.61724447 -> excess demand ->     0.00110516
    2725: p1 =   6.48598821 -> excess demand ->     0.00261807 p2 =   2.61724461 -> excess demand ->     0.00097804
    2750: p1 =   6.48598854 -> excess demand ->     0.00231693 p2 =   2.61724473 -> excess demand ->     0.00086554
    2775: p1 =   6.48598883 -> excess demand ->     0.00205042 p2 =   2.61724484 -> excess demand ->     0.00076598
    2800: p1 =   6.48598909 -> excess demand ->     0.00181457 p2 =   2.61724493 -> excess demand ->     0.00067788
    2825: p1 =   6.48598931 -> excess demand ->     0.00160585 p2 =   2.61724502 -> excess demand ->     0.00059990
    2850: p1 =   6.48598951 -> excess demand ->     0.00142114 p2 =   2.61724509 -> excess demand ->     0.00053090
    2875: p1 =   6.48598969 -> excess demand ->     0.00125767 p2 =   2.61724516 -> excess demand ->     0.00046983
    2900: p1 =   6.48598985 -> excess demand ->     0.00111301 p2 =   2.61724522 -> excess demand ->     0.00041579
    2925: p1 =   6.48598999 -> excess demand ->     0.00098498 p2 =   2.61724527 -> excess demand ->     0.00036796
    2950: p1 =   6.48599011 -> excess demand ->     0.00087169 p2 =   2.61724532 -> excess demand ->     0.00032564
    2975: p1 =   6.48599022 -> excess demand ->     0.00077142 p2 =   2.61724536 -> excess demand ->     0.00028818
    3000: p1 =   6.48599031 -> excess demand ->     0.00068269 p2 =   2.61724539 -> excess demand ->     0.00025503

The Walras-equilibrium prices, $(p_1,p_2)$, where both excess demands are (approximately) zero have been found to be:

```python
f'(p_1,p_2) = ({p1:.3f},{p2:.3f})'
```

    '(p_1,p_2) = (6.486,2.617)'

We see that there is a small change in p1, but beside that th equilibrium prices are almost identical.

At last we will create an interactive figure for changing values of gamma, which will show how the two distributions behave and how their mean and variance are affected.

```python
def utility_fig(gamma):

    # Define old utility vector and calculate mean and variance
    utility_vec = utility_func(p1, p2, e1, e2, e3, betas, gamma)
    utility_mean = np.mean(utility_vec)
    utility_var = np.var(utility_vec)

     # Define new utility vector and calculate mean and variance
    utility_vec_equal= utility_func(p1, p2, e1_equal, e1_equal, e1_equal, betas, gamma)
    utility_mean_equal = np.mean(utility_vec_equal)
    utility_var_equal = np.var(utility_vec_equal)

    # Plot the figures
    fig = plt.figure(figsize=(15,10))

    ax1 = fig.add_subplot(2,2,1)
    ax1.hist(utility_vec, bins=500, color ="#6ab2f2")
    ax1.set_title('Distribution of utilities')
    ax1.set_xlabel('Utility')
    ax1.set_ylabel('Number of agents')
    plt.axis([-0.1, 5, 0, 1600])

    ax2 = fig.add_subplot(2,2,2)
    ax2.hist(utility_vec_equal, bins=500, color ="#f7d56f")
    ax2.set_title('Distribution of utilities with equal endowments')
    ax2.set_xlabel('Utility')
    ax2.set_ylabel('Number of agents')

    # Plot text with mean and variance
    plt.text(-4, 900, f'$\mu$: {utility_mean:.3f} $\sigma^2$: {utility_var:.3f}')
    plt.text(2.0, 900, f'$\mu$: {utility_mean_equal:.3f} $\sigma^2$: {utility_var_equal:.3f}')
    plt.axis([-0.1, 5, 0, 1600])

    plt.show()
# Create slider
interactive_plot = interactive(utility_fig,
                               gamma=widgets.FloatSlider(description="$\gamma$",
                                                       min=0.0,
                                                       max=2.0,
                                                       step=0.1,
                                                       value=0.8,
                                                       continuous_update=True)
                              )

interactive_plot
```

    interactive(children=(FloatSlider(value=0.8, description='$\\gamma$', max=2.0), Output()), _dom_classes=('widg…

First of all we notice how concentrated around the mean the utitilty is for the second plot, due to the variance being much smaller. We also notice how the utility is never below 1. When we increase the value of gamma, we notice how the variance of the first plot increases by a much higher ratio than the second plot. Having the same equal endowments means the change in utility is only due to small changes in preferences.


# Coordinates and Vectors
This notebook will take you through the basics of the cartesian co-ordinates system, and the way we can use vectors to represent positions in space.

## Introduction: Examples of Coordinates and Changes
Coordinates you have covered before, these are pairs of numbers which represent the location of things on a grid.

Below is an example of a variety of coordinates with objects placed at them, stolen shamelessly from a Bing search.

This part is familitar, but when it comes to calculating the steps that any one object would need to cover to get to any other, things can get long winded.

There is a standardised formula. This is simply the co-ordinates subtracted, in the form of: Destination - Origin

A simple conceptual derivation is below

When you want to go from one location to another, there is a journey involved. This journey takes the same form as the two locations. Our journey represented mathematically would look like:
\begin{equation}
\begin{pmatrix}x_{origin}  & y_{origin} \end{pmatrix} + \vec{journey} =  \begin{pmatrix} x_{target}  & y_{target} \end{pmatrix}
\end{equation}

When we rearrange to find the journey then we'd have something which looked like:
\begin{equation}
\begin{pmatrix} x_{target}  & y_{target} \end{pmatrix} - \begin{pmatrix}x_{origin}  & y_{origin} \end{pmatrix}  =  \vec{journey}
\end{equation}

The prescriptive equation then (using what we know about co-ordinates) is:
\begin{equation}
 \vec{journey}  =\begin{pmatrix} x_{target} - x_{origin} & y_{target} - y_{origin} \end{pmatrix}
\end{equation}

Path for worm to heart is
\begin{equation}
 \begin{pmatrix} 3  & 1 \end{pmatrix} - \begin{pmatrix}5  & 2 \end{pmatrix}  =  \begin{pmatrix} -2  & -1 \end{pmatrix}
\end{equation}
Or in the other direction , heart to worm is

\begin{equation}
\begin{pmatrix}5  & 2 \end{pmatrix}  -  \begin{pmatrix} 3  & 1 \end{pmatrix} =  \begin{pmatrix} 2  & 1 \end{pmatrix}
\end{equation}

Path between the worm and the heart is (2, 1) or (-2,-1) depending on your direction.

## Python Exposure: Numpy Arrays
These can be represented in python too, and made a lot simpler to work with for us. What we need is a structure which understands that it has two parts, and when adding or subtracting one from the other, it needs to add the two first parts together and the two second parts together, not just add the lot. For example

```python
(1, 2) + (1, 1)
```

    (1, 2, 1, 1)

Using () brackets, the + sign just stuck them together into one big list. the same will occur if you use square brackets []

Thankfully, someone has already though of us needing this, and created something which will do the heavy lifting for us, along with lots of other features that we don't need right now. This is gathered into a library called numpy (Number Python). The structure we are looking for is called an array.

```python
import numpy as np # abbreviated 'cause we're lazy
worm = np.array([5, 2])
heart = np.array([3, 1])

print(worm - heart)
print(heart - worm)
```

    [2 1]
    [-2 -1]

Note: In python taking an object, like `np` and using the `.` operator, pulls out a particular part of it. Here we are extracting the definition for the array structure and using it to make one.

As you can see, when using two numpy arrays, python understands that its supposed to add the relevant parts together, not just sum the lot.

### Exercise 1.1: Calculating Journeys
Now, Using numpy, calculate the following journeys:

1. Cricket -> Dog
1. Sun -> Strawberry
1. Cricket -> Sun

We've already imported numpy above, so you will be able to access the array generators with the np.array([x,y]) syntax as before

```python
## Put your Exercise attempt in here.

### Below is an empty list, which you can use to store your answers,
### remember: if you dont use the output directly you must wrap the numbers in np.array
answers = [ , , ]
## This should check your results
sum(answers) == np.array([9,-5])
```

### Excercise 1.2: Multi Stage Journeys
There is a useful feature of complex journeys with co-ordinates. Which will hopefully become clear when doing the 2 tasks below.

1. Calculate the overall movement to make the following journey::  sun -> worm -> cricket -> strawberry

1. And the movement to take the simpler journey :::::::::::::::::::::::::  sun -> strawberry

## Extension: 3 Dimensional Co-ordinates.

We are familiar with using 2 dimensional co-ordinates to describe flat surfaces. This works because they have two directions they can travel in. Left-Right and Up-Down. In reality though, there is another dimension, In-Out of the page. Since it's very difficult to show a 3D image on a 2D surface, we have to make do with some side-on views to try to make sense of it all.

### Exercise 2.1: Reading 3d Co-ordinates
Using the diagram above, define the position of the 3rd point (R). First two are included for reference.

```python
## Generate the Coordinates for R
pos_P = np.array([-3,0,0]) # Note the array is 3 elements long now
pos_Q = np.array([6,-2,0])

## Define Position for R here
```

### Exercise 2.2: 3-d Journeys
We can define the journey between two points in 3 dimensions the same as before.

What is the journey from point P to point Q below

```python
## Define your calculation here
sum(pos_P - pos_Q)

## This should check the answer
sum(answer) == -7
```

    -7

```python

```


# Introduction

The quantum Fourier transform and quantum phase estimation provide the foundation for many quantum algorithms, including the quantum matrix inversion, which is extensively used in quantum machine learning. It is therefore worthwhile developing a good understanding of these building blocks before moving on to more complex algorithms.

We must emphasize that starting with this notebook, the algorithms presented are coherent quantum protocols. By that, we mean that the input and output of an algorithm is a quantum state that we do not have classical information about. The protocol itself might use measurements: in this sense, they are not fully coherent, since we gain some, but incomplete classical information about the quantum system. We might also perform post-selection, which means that a gate is controlled by the classical output of a measurement. In some cases, we entirely discard a calculation based on a measurement output.

Why does it matter that we begin and end up with quantum states? Can't we just use state preparation starting from classical data and then perform tomography on the final state? We could do that, but state preparation and tomography are resource-intensive, and they are likely to destroy any quantum advantage.

An additional problem is that the quantum Fourier transformation and other quantum algorithms similar in complexity require a very large number of gates on a large number of high-quality qubits. This is why the practical relevance of these algorithms is not immediate, but since they are the core of many quantum machine learning protocols, it is essential that we take a look at them.

```python
import numpy as np
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit import execute
from qiskit import Aer
π = np.pi
```

# Quantum Fourier Transform

The quantum Fourier transform is a quantum algorithm for the discrete Fourier transform over the amplitudes of a wavefunction. The exposition here follows the introduction in [[1](#1)]. A similar approach can be found in the [Qiskit tutorials](https://github.com/Qiskit/qiskit-tutorials/blob/master/community/algorithms/shor_algorithm.ipynb).

The classical discrete Fourier transform acts on a vector $\vec{x}=\begin{bmatrix}x_0\\ \vdots\\ x_{N-1}\end{bmatrix}$ and maps it to the vector $\vec{y}=\begin{bmatrix}y_0\\ \vdots\\ y_{N-1}\end{bmatrix}$, where $y_k = \frac{1}{\sqrt{N}}\sum_{j=0}^{N-1}x_je^{ \boldsymbol{2\pi i} \frac{jk}{N}}$.

The quantum Fourier transform acts on an amplitude-encoded variant of this vector, the quantum state $|x\rangle=\sum_{i=0}^{N-1} x_i |i \rangle$ and maps it to the quantum state $|y\rangle=\sum_{k=0}^{N-1} y_k |k \rangle$, where
$y_k = \frac{1}{\sqrt{N}}\sum_{j=0}^{N-1}x_je^{\boldsymbol{2\pi i} \frac{jk}{N}}$. Since the transformed state is also in the superposition of the computational basis, in essence, only the amplitudes are transformed.

To derive a circuit for a power of two $N=2^n$, consider the transform acts on the state $| x \rangle = | x_1...x_n \rangle$ where $x_1$ is the most significant bit, unlike the usual convention followed in the course. We will rewrite a number $y$ in the fractional binary notation  as $j = 0.j_1...j_n = \sum_{k=1}^n j_k/2^k$. For example $0.8125_d = 0.1101_b = \sum_{k=1}^4 j_k/2^k = 1/2 + 1/4 + 0/8 + 1/16$, where the subscripts $d$ stands for decimal and $b$ for binary. The action of the unitary $U$ describing the transform can be expanded as
\begin{aligned}
U |x \rangle = U |x_1 x_2 \cdots x_n \rangle& = \frac{1}{\sqrt{N}} \sum_{k=0}^{2^n-1} e^{\boldsymbol{2\pi i} xk / 2^n} |k \rangle \\
& = \frac{1}{\sqrt{N}} \sum_{k_1=0}^{1}\ldots\sum_{k_n=0}^{1} e^{\boldsymbol{2\pi i} x\left(\sum_{l=1}^n k_l2^{-l}\right) } \vert k_1 ... k_n \rangle \\
& = \frac{1}{\sqrt{N}} \sum_{k_1=0}^{1}\ldots\sum_{k_n=0}^{1} \bigotimes_{l=1}^n e^{\boldsymbol{2\pi i} x k_l2^{-l}} | k_1 ... k_n \rangle \\
& = \frac{1}{\sqrt{N}} \bigotimes_{l=1}^n \sum_{k_l=0}^{1}  e^{\boldsymbol{2\pi i} x k_l2^{-l}} | k_1 ... k_n \rangle \\
& = \frac{1}{\sqrt{N}} \bigotimes_{l=1}^n  \left(|0\rangle + e^{\boldsymbol{2\pi i} x 2^{-l} } |1\rangle \right) \\
& = \frac{1}{\sqrt{N}} \left(|0\rangle + e^{\boldsymbol{2\pi i} 0.x_n} |1\rangle\right) \otimes...\otimes  \left(\vert0\rangle + e^{\boldsymbol{2\pi i} 0.x_1.x_2...x_{n-1}.x_n} |1\rangle\right)
\end{aligned}

This form of the QFT is useful for deriving a circuit, since only the last qubit depends on the the
values of all the other input qubits. The remaining qubits depend less and less on the input qubits. The simple structure also allows to decompose the unitary as Hadamard gates and rotations. On three qubits, we can define the circuit as follows:

```python
q = QuantumRegister(3, 'q')
c = ClassicalRegister(1, 'c')
qft = QuantumCircuit(q, c)
qft.h(q[0])
qft.cu1(π/2, q[1], q[0])
qft.h(q[1])
qft.cu1(π/4, q[2], q[0])
qft.cu1(π/2, q[2], q[1])
qft.h(q[2])
```

We can plot it to make the qubit dependencies more apparent:

```python
from qiskit.tools.visualization import circuit_drawer
circuit_drawer(qft)
```

The conditional rotations dominate the complexity, which scales as $O(N^2)$.

# Quantum phase estimation

The goal of a quantum phase estimation algorithm is, given a unitary operator $U$ and an eigenvector $|\psi\rangle$ of $U$, to estimate $\theta$ in  $U|\psi \rangle =e^{2 i \pi \theta}|\psi \rangle$. Since $U$ is unitary, all of its eigenvalues have an absolute value of 1. By convention, $\theta$ is taken to be in $[0,1]$ and is called the *phase* of $U$ associated to $|\psi\rangle$.

The eigenvector $|\psi\rangle$ is encoded in one set of quantum registers. An additional set of $n$ qubits forms an ancilla register. At the end of the procedure, this ancilla register should contain an approximation of the [binary fraction](https://www.electronics-tutorials.ws/binary/binary-fractions.html) associated to $\theta$, with n-bits precision. A critical element is the ability to perform the controlled unitary $C-U^{2^k}$ -- it is usually assumed to be provided to the phase estimation protocol.

First, the uniform superposition is prepared in the ancilla register via the application of Hadamard gates $H$. These qubits will act as controls for the unitary operators at different time steps. Our goal is to create a superposition of $U$ as the unitary is applied for different durations. Since the eigenvalues are always situated on the complex unit circle, these differently evolved components in the superposition help reveal the eigenstructure. Given that the ancilla register we have a superposition of all possible time steps between $0$ and $2^{n-1}$, we will end up with a superposition of all possible evolutions to encode binary representations of the eigenvalues. At the end of this procedure, we have the state
\begin{aligned}
& \frac {1}{2^{\frac {n}{2}}} (|0\rangle+{e^{2 i \pi \theta \cdot 2^{n-1}}}|1\rangle ) \otimes \cdots (|0\rangle+{e^{2 i \pi \theta \cdot 2^{1}}}|1\rangle ) \otimes (|0\rangle+{e^{2i \pi \theta \cdot 2^{0}}}|1\rangle ) = \\
&\frac {1}{2^{\frac {n}{2}}}\sum _{k=0}^{2^{n}-1}e^{2 i \pi \theta k}|k\rangle
\end{aligned}
in the ancilla. To write the ancilla in this form, we exploit that the controlled unitary operations when applied, introduce a global phase, and it is this global phase that we see in the ancilla. This phenomenon is also known as the phase kickback.

As a final step, we apply an inverse Fourier transform on the ancilla. Measuring out in the computational basis, we get the phase in the ancilla register:

\begin{align}
\frac {1}{2^{\frac {n}{2}}}\sum _{k=0}^{2^{n}-1}e^{2i \pi \theta k}|k\rangle \otimes | \psi \rangle \xrightarrow{\mathcal{QFT}_n^{-1}} | \tilde{\theta} \rangle \otimes | \psi \rangle
\end{align}

where $\tilde{\theta}$ is the n-bits approximation of the binary fraction representing $\theta$.

The circuit for phase estimation is the following:

As a toy example, let's take the $2\times 2$ unitary matrix $\begin{bmatrix}e^{0} & 0 \\0 & e^{i \pi}\end{bmatrix}=\begin{bmatrix}1 & 0 \\0 & -1\end{bmatrix}$, which has the eigenvectors $|0\rangle$ and $|1\rangle$, and phases $\theta_0=0$ and $\theta_1=\frac{1}{2}$. Therefore, the $C-U^{2^k}$ gate is a controlled-$Z$ gate for $k=0$ and the identity for $k\geq 1$.

Starting with $|\psi\rangle=|0\rangle$ in the main register, we prepare the superposition in the ancilla:

```python
q = QuantumRegister(3, 'q')
c = ClassicalRegister(2, 'c')

qpe = QuantumCircuit(q, c)
qpe.h(q[0])
qpe.h(q[1])
```

Next we perform the controlled unitary operations:

```python
# Controlled-U0
qpe.cz(q[1], q[2])
# Controlled-U1
# nothing: identity
```

We apply quantum inverse Fourier transformation to write the phase to the ancilla register:

```python
qpe.swap(q[0], q[1])
qpe.h(q[1])
qpe.cu1(-π / 2, q[0], q[1])
qpe.h(q[0])
qpe.swap(q[0], q[1])
```

We will get the result from the two first registers

```python
qpe.measure(q[0], c[0])
qpe.measure(q[1], c[1])
```

We can plot the circuit:

```python
circuit_drawer(qpe)
```

Let's now test our circuit:

```python
backend = Aer.get_backend('qasm_simulator')
job = execute(qpe, backend, shots=1000)
result = job.result()
result.get_counts(qpe)
```

As expected the result is $|2 \cdot \theta_0\rangle=|2\cdot 0\rangle=|00\rangle$

Let's now run the circuit for the eigenvector $|1\rangle$:

```python
qpe = QuantumCircuit(q, c)
qpe.h(q[0])
qpe.h(q[1])
qpe.x(q[2]) # create |1> in the main register

qpe.cz(q[1], q[2])

qpe.swap(q[0], q[1])
qpe.h(q[1])
qpe.cu1(-π / 2, q[0], q[1])
qpe.h(q[0])
qpe.swap(q[0], q[1])

qpe.measure(q[0], c[0])
qpe.measure(q[1], c[1])
```

```python
backend = Aer.get_backend('qasm_simulator')
job = execute(qpe, backend, shots=1000)
result = job.result()
result.get_counts(qpe)
```

The result should be $|10\rangle$. Indeed, $10 \rightarrow 1\cdot 2^{-1} + 0 \cdot 2^0=\frac{1}{2}=\theta_1$

# References
[1] M. Nielsen, I. Chuang. (2000). *Quantum Computation and Quantum Information*. Cambridge University Press.


# Example usage of functions in plot_helpers

```python
%matplotlib notebook
import matplotlib.pyplot as plt
from plot_helpers import plot_vec, plot_vecs, plot_line, plot_plane, autoscale_arrows
import numpy as np
from sympy import *
```

## Plots in the plane

```python
fig = plt.figure()

# plot vectors:
u = Matrix([1,1])
v = Matrix([1,-2])
plot_vecs(u,v)
# same as:
# plot_vec(u)
# plot_vec(v)

# line plot as point + direction form:
plot_line(u,[0,1])

# line plot using normal + constant:
nvec = Matrix([1,1])
d = 1
plot_plane(nvec,d)    # n_x*x + n_y*y = d

# manual set of plot limits
ax = plt.gca()
ax.set_xlim([-10,10])
ax.set_ylim([-10,10])

# automatic scale (ensure all vectors fit in plot)
# autoscale_arrows()
```

    <IPython.core.display.Javascript object>

    (-10, 10)

## Three-dimensional plots

```python
fig = plt.figure()

# plot vectors:
u = Matrix([1,1,1])
v = Matrix([1,-2,0])

plot_vecs(u,v)
# same as:
# plot_vec(u)
# plot_vec(v)

# line plot as point + direction form:
plot_line(u,[0,0,1])
plot_line(v,[0,0,1],color='r')

# plane plot using normal + constant:
plot_plane(u,2)
plot_plane(u,4)
plot_plane(u,8,xrange=[-2,2],yrange=[-2,2])

ax = plt.gca()
ax.set_xlim([-10,10])
ax.set_ylim([-10,10])
ax.set_zlim([-10,10])

# autoscale_arrows()
```

    <IPython.core.display.Javascript object>

    (-10, 10)

```python

```


### Introduction to Scientific Python
# LIF Neuron Exercise

*Please execute the cell bellow in order to initialize the notebook environment*

```python
# show figures inline and do not autosave notebook
%matplotlib inline
%autosave 0

import matplotlib.pyplot as plt    # import matplotlib
import math                        # import basic math functions
import random                      # import basic random number generator functions
from __future__ import division    # enable division by integers
```

    Autosave disabled

## Leaky Integrate-and-Fire Neuron

In this notebook we'll implement a *Leaky Integrate-and-Fire (LIF)* neuron with stochastic pre-synaptic input current, and visualize its key statistical properties.

This neuron model is defined by a *membrane equation* and a *reset condition*:
\begin{align}
&\tau_m\,\frac{d}{dt}\,V(t) = E_{L} - V(t) + R\,I(t) &\text{if }\quad V(t) \leq V_{th}\\
\\
&V(t) = V_{r} &\text{otherwise}\\
\\
\end{align}
where $V(t)$ is the membrane potential, $\tau_m$ is the membrane time constant, $E_{L}$ is the leak potential, $I(t)$ is the pre-synaptic input current, $V_{th}$ is the firing threshold, and $V_{r}$ is the reset voltage.

We'll extract and visualize the mean, standard deviation and histogram of the following quantities:

* Pre-synaptic input current $I(t)$
* Membrane potential $V(t)$
* Output firing frequency $\lambda(t)$

The problem will be split in several steps:

* Discrete time integration of $V(t)$ under sinusoidal pre-synaptic input, and without spikes
* Stochastic pre-synaptic input
* Visualizing ensemble statistics
* Introducing output spikes

**EXERCISE 1**

Initialize the main simulation variables.

**INSTRUCTIONS**
* Modify the code below to print the main simulation parameters

```python
# t_max = 150e-3   # second
# dt = 1e-3        # second
# tau = 20e-3      # second
# el = -60e-3      # milivolt
# vr = -70e-3      # milivolt
# vth = -50e-3     # milivolt
# r = 100e6        # ohm
# i_mean = 25e-11  # ampere

# print t_max, dt, tau, el, vr, vth, r, i_mean
```

```python
# exercise 1
```

**EXPECTED OUTPUT**
0.15 0.001 0.02 -0.06 -0.07 -0.05 100000000.0 2.5e-10
### ODE integration without spikes

The numerical integration of the membrane equation can be performed in discrete time, with a sufficiently small $\Delta t$. We start by writting the membrane equation. without taking the limit $\Delta t \to 0$ in the definition of the time derivative $d/dt\,V(t)$:

\begin{align*}
\tau_m\,\frac{V\left(t+\Delta t\right)-V\left(t\right)}{\Delta t} &= E_{L} - V(t) + R\,I(t)
\end{align*}

The value of membrane potential $V\left(t+\Delta t\right)$ can be expressed in terms of its previous value $V(t)$ by simple algebraic manipulation. For *small enough* values of $\Delta t$ this provides a good approximation of the continuous time integration.

**EXERCISE 2**

Compute the values of $V(t)$ between $t=0$ and $t=0.01$ with $V(0)=E_L$ and pre-synaptic input given by:

$$
I(t)=I_{mean}\left(1+\sin\left(\frac{2 \pi}{0.01}\,t\right)\right)
$$

**INSTRUCTIONS**
* Express $V\left(t+\Delta t\right)$ in terms of $V(t)$
* Initialize the membrane potential variable `v` to `el`
* Loop in the time variable `t` from `t=0` to `t=0.01` with time step `dt`
* At each time step
    * Compute the current value of `i`
    * Update the value of `v`
    * Print `v`
* Use `math.pi` and `math.sin` for evaluating $\pi$ and $\sin(\,)$, respectively

```python
# exercise 2
```

**EXPECTED OUTPUT**
-0.05875
-0.0568277684346
-0.0545475593675
-0.0523813607538
-0.0507775611507
-0.0499886830932
-0.0499739805039
-0.0504141021241
-0.0508322176632
-0.0507753383454
-0.0507753383454
**EXERCISE 3**

Plot the values of $V(t)$ between $t=0$ and $t=t_{max}$ under the same conditions.

**INSTRUCTIONS**
* Update end time of loop to `t_max`
* Replace printing command with plotting command (with keyword `'ko'`)

```python
# exercise 3
```

**EXPECTED OUTPUT**

## Stochastic pre-synaptic input

From the standpoint of neurons, their pre-synaptic input is random. We'll improve the pre-synaptic input model by introducing random input with similar statistical properties:

\begin{align}
I(t)=I_{mean}\left(1+0.1\sqrt{\frac{t_{max}}{\Delta t}}\,\xi(t)\right)\qquad\text{with }\xi(t)\sim U(-1,1)
\end{align}
where $U(-1,1)$ is the uniform distribution with support $x\in[-1,1]$.

A random pre-synaptic input $I(t)$ results in a random time course $V(t)$.

**EXERCISE 4**

Plot the values of $V(t)$ between $t=0$ and $t=t_{max}$ with random input $I(t)$.

Initialize the (pseudo) random number generator to a fixed value (`0` for example) in order to obtain the same random input across executions of the code. The function `random.seed()` initializes the random number generator, and `random.random()` generates samples from the uniform distribution between `0` and `1`.

**INSTRUCTIONS**
* Use the function `random.seed()`to initialize the random number generator to `0`
* Use the function `random.random()` to generate the input at each timestep
* Repeat the execution several times to verify that $V(t)$ has a random time course

```python
# exercise 4
```

**EXPECTED OUTPUT**

## Ensemble statistics

Multiple runs of the previous exercise may give the impression of periodic regularity in the evolution of $V(t)$. We'll collect the sample mean over $N$ realizations of $V(t)$  with random input in order to test such hypothesis. The sample mean, sample variance and sample autocovariance at times $\left\{t_k, t_j\right\}\in[0,t_{max}]$, and for $N$ realizations of $V(t)$ are given by:

\begin{align}
\left\langle V(t_k)\right\rangle &= \frac{1}{N}\sum_{n=1}^N V(t_k)_n & & \text{sample mean}\\
\left\langle (V(t_k)-\left\langle V(t_k)\right\rangle)^2\right\rangle &= \frac{1}{N-1} \sum_{n=1}^N \left(V(t_k)_n-\left\langle V(t_k)\right\rangle\right)^2 & & \text{sample variance} \\
\left\langle \left(V(t_k)-\left\langle V(t_k)\right\rangle\right)\left(V(t_j)-\left\langle V(t_j)\right\rangle\right)\right\rangle
&= \frac{1}{N-1} \sum_{n=1}^N \left(V(t_k)_n-\left\langle V(t_k)\right\rangle\right)\left(V(t_j)_n-\left\langle V(t_j)\right\rangle\right) & & \text{sample autocovariance}
\end{align}

**EXERCISE 5**

Plot multiple realizations of $V(t)$.

**INSTRUCTIONS**
* Create a list to store the value of $V(t)$ for each realization.
* At each timestep loop over `N=50` realizations of random input
* Plot the realizations at each time step with keyword `'kx'` and parameter `alpha=0.1`

```python
# exercise 5
```

**EXPECTED OUTPUT**

**EXERCISE 6**

Plot the sample mean $\left\langle V(t)\right\rangle$ over `N=50` realizations.

**INSTRUCTIONS**
* Plot the sample mean at each timestep with keyword `'m.'` and parameter `alpha=0.5`

```python
# exercise 6
```

**EXPECTED OUTPUT**

**EXERCISE 7**

Add sample standard deviation $\sigma(t_k)\equiv\sqrt{\text{Var}\left(t_k\right)}$ to the plot.

**INSTRUCTIONS**
* After collecting the sample mean, iterate a second time to compute the sample variance $\sigma(t_k)$
* Plot $\left\langle V(t)\right\rangle\pm\sigma(t_k)$ with keyword `'m.'` and parameter `alpha=0.5`.

```python
# exercise 7
```

**EXPECTED OUTPUT**

Another important statistic is the sample histogram at time $t_k\in[0,t_{max}]$, which for $N$ realizations $V\left(t_k\right)$ and $J$ bins is given by:

\begin{align}
N = \sum_{j=1}^{J} m_j
\end{align}

where $m_j$ is a function that counts the number of samples $V\left(t_k\right)$ that fall into bin $j$.

**EXERCISE 8**

Plot an histogram of $J=50$ bins of $V(t)$ for $t=t_{max}/10$ and $t=t_{max}$ for $N=10000$ realizations.

The function `plt.hist(data, nbins)` plots an histogram of `nbins` bins of the list 'data' and returns the lists `pdf`, `bins`, `patches`.

`pdf, bins, patches = plt.hist(data, bins)`

The parameters `histtype='stepfilled'` and `linewidth=0` may improve the plots.

**INSTRUCTIONS**
* Plot the 1st histogram after running up to $t=t_{max}/10$
* Plot the 2nd histogram at $t=t_{max}$
* Add labels to identify the time of each histogram
* Plot each histogram with parameters `histtype='stepfilled'` and `linewidth=0`

```python
# exercise 8
```

**EXPECTED OUTPUT**

## Output Spikes

Introduce the *reset condition*: $V(t) = V_{r} \text{if }\quad V(t)\geq V_{th}$

**EXERCISE 9**

Insert the reset condition, and collect the spike times of each realization in a dictionary variable `spikes`, with $N=500$.

**INSTRUCTIONS**
* Reset $V(t)$ to $V_r$ if $V(t)\geq V_{th}$ and collect the spike time
* Plot each realization with keyword `'kx'` and parameter `alpha=0.03`
* Plot the sample mean with keyword `'m.'` and parameter `alpha=0.5`
* Create a new figure and plot the spike times with keyword `'k|'` and parameter `alpha=0.2`
* Create a new figure and plot and the mean spiking activity

```python
# exercise 9
```

**EXPECTED OUTPUT**

**EXERCISE 10**

Investigate the effect of refractory period $t_{ref}$ on the evolution of output rate $\lambda(t)$.

**INSTRUCTIONS**
* Add refractory period $t_{ref}=10$ ms after each spike, during which $V(t)$ is clamped to $V_r$
* Experiment increasingly higher values of refractory period $t_{ref}$

```python
# exercise 10
```

**EXPECTED OUTPUT**

**EXERCISE 11**

Below is a proposed implementation for Exercise 7 from above. Rewrite this code, but break it up into functions. Specifically, write and use function to:
* `I(n)`: returns the current, $I(t)$, at a given time $t$, a list of $n$ floats
* `mean(x)`: returns the mean of `x`, a list of floats
* `std(x)`: returns the standard deviation of `x`, a list of floats
* `ode_step(v, i)`: returns the voltage at the next time step, $V(t+\Delta t)$, given the voltage at the current time step, $V(t)$, and the current, $I(t)$, all lists of floats

```python
# exercise 11
```

**EXPECTED OUTPUT**

**EXERCISE 12**

Rewrite the code from Exercise 11, but now use the tools from NumPy. For example:
* Use `np.array` instead of Python list for voltage, $V(t)$, and time, $t$
* Use the NumPy functions for statistical function, (e.g. `np.mean`) and mathematical (e.g. `np.sqrt`) operations
* Plot mean $\pm$ std using `plt.fill_between` with parameters `color='m'` and `alpha=0.5`

```python
# exercise 12
```

**EXPECTED OUTPUT**

**EXERCISE 13**

**Stretch exercise: this problem is open-ended and will take some extra thought on your part**

Extend your solution from Exercise 9 to model a simple network. In Exercise 9 you modeled an ensemble of spiking neurons that evolved independently of each other. The only step you need to turn this into a network is to allow spikes from one neuron to influece the voltage of other neurons. One simple way of achieve this provide a "kick" to the voltage of "post-synaptic" neurons whenever a "post-synaptic" neuron spikes. The size of this kick represent the strength of the synapses between the neurons. Remember to include both positive and negative "synapses" so that your network activity does not explode!


## Task 19 - Motor Control
### Introduction to modeling and simulation of human movement
https://github.com/BMClab/bmc/blob/master/courses/ModSim2018.md

Desiree Miraldo

* Task (for Lecture 19):

Solve problemas 1 and 2 of the notebook [Optimization (Marcos Duarte)](http://nbviewer.jupyter.org/github/BMClab/bmc/blob/master/notebooks/Optimization.ipynb).

```python
# import Python libraries
import numpy as np
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import sympy as sym
from sympy.plotting import plot
import pandas as pd
from IPython.display import display
from IPython.core.display import Math
```

## Exercises

1. Find the extrema in the function $f(x)=x^3-7.5x^2+18x-10$ analytically and determine if they are minimum or maximum.
2. Find the minimum in the $f(x)=x^3-7.5x^2+18x-10$ using the gradient descent algorithm.
2. Regarding the distribution problem for the elbow muscles presented in this text:
    a. Test different initial values for the optimization.
    b. Test other values for the elbow angle where the results are likely to change.

3. In an experiment to estimate forces of the elbow flexors, through inverse dynamics it was found an elbow flexor moment of 10 Nm.
Consider the following data for maximum force (F0), moment arm (r), and pcsa (A) of the brachialis, brachioradialis, and biceps brachii muscles: F0 (N): 1000, 250, 700; r (cm): 2, 5, 4; A (cm$^2$): 33, 8, 23, respectively (data from Robertson et al. (2013)).
    a. Use static optimization to estimate the muscle forces.
    b. Test the robustness of the results using different initial values for the muscle forces.
    c. Compare the results for different cost functions.

#### Exercises 1: Find the extrema in the function $f(x)=x^3-7.5x^2+18x-10$ analytically and determine if they are minimum or maximum.

```python
x = sym.symbols('x')
f = x**3 - 7.5*x**2 + 18*x - 10
fdiff = sym.expand(sym.diff(f, x))
roots = sym.solve(fdiff, x)
display(Math(sym.latex('Roots:') + sym.latex(roots)))
```

$$Roots:\left [ 2.0, \quad 3.0\right ]$$

```python
f  = lambda x: x**3 - 7.5*x**2 + 18*x - 10

print('f(x = {:.1f}) = {:.2f}'.format(roots[0],f(roots[0])))
print('f(x = {:.1f}) = {:.2f}'.format(roots[1],f(roots[1])))
```

    f(x = 2.0) = 4.00
    f(x = 3.0) = 3.50

#### Exercises 2: Find the minimum in the $f(x)=x^3-7.5x^2+18x-10$ using the gradient descent algorithm.

```python
# From https://en.wikipedia.org/wiki/Gradient_descent
# The local minimum of $f(x)=x^3-7.5x^2+18x-10$

cur_x = 6               # The algorithm starts at x=6
gamma = 0.01            # step size multiplier
precision = 0.00001
step_size = 1           # initial step size
max_iters = 10000       # maximum number of iterations
iters = 0               # iteration counter

f  = lambda x: x**3 - 7.5*x**2 + 18*x - 10  # lambda function for f(x)
df = lambda x: 3*x**2 - 15*x + 18    # lambda function for the gradient of f(x)

while (step_size > precision) and (iters < max_iters):
    prev_x = cur_x
    cur_x -= gamma*df(prev_x)
    step_size = abs(cur_x - prev_x)
    iters+=1

print('True local minimum at {} with function value {}.'.format(3, f(3)))
print('Local minimum by gradient descent at {} with function value {}.'.format(cur_x, f(cur_x)))

from scipy.optimize import minimize
import numpy as np

minimize(f, 6, args=(), method='CG', jac=None, tol=precision, callback=None,
         options={'gtol': 1e-05, 'norm': np.inf, 'eps': 1.4901161193847656e-08,
                  'maxiter': max_iters, 'disp': True, 'return_all': False})
```

    True local minimum at 3 with function value 3.5.
    Local minimum by gradient descent at 3.000323195755751 with function value 3.5000001567170003.
    Optimization terminated successfully.
             Current function value: -4150663493044532703920128.000000
             Iterations: 3
             Function evaluations: 93
             Gradient evaluations: 31

         fun: array([ -4.15066349e+24])
         jac: array([ 0.])
     message: 'Optimization terminated successfully.'
        nfev: 93
         nit: 3
        njev: 31
      status: 0
     success: True
           x: array([ -1.60708619e+08])

```python

```