CompEcon Toolbox:

DemDdp01

Mine management model

Randall Romero Aguilar, PhD

This demo is based on the original Matlab demo accompanying the  Computational Economics and Finance 2001 textbook by Mario Miranda and Paul Fackler.

Last updated: 2020-Sep-09

## About

A mine operator must decide how much ore to extract from a mine that will be shut down and abandoned after $T$ years of operation. The price of extracted ore is $p$ dollars per ton, and the total cost of extracting $x$ tons of ore in any year, given that the mine contains $s$ tons at the beginning of the year, is $c(s, x)$ dollars. The mine currently contains $\bar{s}$ tons of ore. Assuming the amount of ore extracted in any year must be an integer number of tons, what extraction schedule maximizes profits?

## Initial tasks

```python
if 'google.colab' in str(get_ipython()):
    print("This notebook is running on Google Colab. Installing the compecon package.")
    !pip install compecon
```

```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from compecon import DDPmodel, getindex
```

## Model Parameters

Assuming a market price $p=1$, initial stock of ore $\bar{s}=100$, and annual discount factor $\delta = 0.9$

```python
price = 1
sbar  = 100
delta = 0.9
```

### State Space

This is a finite horizon, deterministic model with time $t$ measured in years. The state
variable $s \in \{0, 1, 2, \dots, \bar{s}\}$ is the amount of ore remaining in the mine at the beginning of the year, measured in tons.

```python
S = np.arange(sbar + 1)      # vector of states
n = S.size                   # number of states
```

### Action Space

The action variable $x \in \{0, 1, 2, \dots, s\}$ is the amount of ore extracted over the year, measured in tons.

```python
X = np.arange(sbar + 1)      # vector of actions
m = X.size                   # number of actions
```

### Reward Function

The reward function is $f(s, x) = px − c(s, x)$. The cost of extraction is $c(s, x) = \frac{x^2}{1+s}$.

Here, the reward is set to negative infinity if the extraction level exceeds the available stock in order to preclude the choice of an infeasible
action:

```python
f = np.full((m, n), -np.inf)
for c, s in enumerate(S):
    for r, x in enumerate(X):
        if x <= s:
            f[r, c] = price * x - (x ** 2) / (1 + s)
```

### State Transition Function

The state transition function is $g(s, x) = s − x$

Here, the routine `getindex` is used to find the index of the following period’s state.

```python
g = np.empty_like(f)
for r, x in enumerate(X):
    snext = S - x
    g[r] = getindex(snext, S)
```

## Model Structure

The value of the mine, given that it contains $s$ tons of ore at the beginning of year $t$, satisfies the Bellman equation

\begin{equation} V_t(s) = max_{x\in\{0,1,\dots,s\}} \left\{px−c(s, x) + \delta V_{t+1}(s−x)\right\} \end{equation}

subject to the terminal condition $V_{T+1}(s) = 0$

To solve and simulate this model, use the CompEcon class ```DDPmodel```.

```python
model = DDPmodel(f, g, delta)
model.solve()
```

By default, the `solve()` method uses Newton's algorithm. This and other default settings can be changed when solving the model. For example,
```python
model.solve(algorithm='funcit', print=True)
```
solves the model by function iteration, printing a summary of each iteration to screen.

In either case, `solve()` updates the model itself, storing the $n$ vector of values `.value`, the $n$ vector of optimal actions `.policy`, and the $n\times n$ controlled state `.transition` probability.

```python
solution = pd.DataFrame({
    'Stock': S,
    'Extraction': X[model.policy],
    'Value': model.value}).set_index('Stock')
```

## Analysis

### Simulate Model
The path followed by the stock level over time is computed by the `simulate()` method. Here, the simulation assumes an initial stock level of 100 and 15 years in duration.

```python
sinit = S.max()
nyrs = 15
t = np.arange(nyrs + 1)
spath, xpath = model.simulate(sinit, nyrs)

simul = pd.DataFrame({
    'Year': t,
    'Stock': S[spath],
    'Extraction': X[xpath]}).set_index('Year')
simul
```

### Plot Optimal Policy

```python
ax = solution['Extraction'].plot(title='Optimal Extraction Policy')
ax.set(ylabel='Extraction');
```

### Plot Value Function
The value of the firm is very nearly proportional to the stock level.

```python
ax = solution['Value'].plot(title='Optimal Value Function')
ax.set(ylabel='Value');
```

### Plot State and Extraction Path
As seen in this figure, the content of the mine is optimally exhausted in 15 years.

```python
ax = simul.plot(subplots=True, layout=[1,2], legend=None)
for i, lab in enumerate(simul.columns):
    ax[0, i].set(ylabel=lab);
```

notebooks/ddp/01 Mine management model.ipynb


```python
import sys
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import scipy as sp
import IPython
import sklearn
from sklearn import metrics
from sklearn import model_selection
from sklearn.linear_model import SGDRegressor
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import GridSearchCV
import sympy as sym

```

```python
data = pd.read_csv("/content/data_regression_full_1.csv")
```

```python
data.head()
```

      Speed
      Radius_big
      Radius_small
      Length
      Pressure_1
      Pressure_2
      Viscosity
      Kf_a
      Kf_b
      Kf_c
      Unnamed: 10
      Unnamed: 11
      Unnamed: 12
      Unnamed: 13

      0
      19.2
      2.0
      0.4
      1000.0
      40.0
      20.0
      0.001
      -5.0
      0
      20.0
      NaN
      NaN
      NaN
      NaN

      1
      12.8
      2.0
      1.2
      1000.0
      40.0
      20.0
      0.001
      -5.0
      0
      20.0
      NaN
      NaN
      NaN
      NaN

      2
      16.0
      2.0
      0.9
      1000.0
      40.0
      20.0
      0.001
      -5.0
      0
      20.0
      NaN
      NaN
      NaN
      NaN

      3
      14.0
      2.0
      1.1
      1000.0
      40.0
      20.0
      0.001
      -5.0
      0
      20.0
      NaN
      NaN
      NaN
      NaN

      4
      0.0
      2.0
      2.0
      1000.0
      40.0
      20.0
      0.001
      -5.0
      0
      20.0
      NaN
      NaN
      NaN
      NaN

```python
df = data.sample(frac=1) #Перемешивание выборки
```

```python
df.head()
```

      Speed
      Radius_big
      Radius_small
      Length
      Pressure_1
      Pressure_2
      Viscosity
      Kf_a
      Kf_b
      Kf_c
      Unnamed: 10
      Unnamed: 11
      Unnamed: 12
      Unnamed: 13

      5243
      76.2
      3.9
      0.8
      714.2
      133.6
      47.6
      0.006
      -5.2
      0
      79.8
      NaN
      NaN
      NaN
      NaN

      5058
      14.1
      1.6
      0.4
      351.7
      114.7
      88.4
      0.003
      -5.7
      0
      15.0
      NaN
      NaN
      NaN
      NaN

      4347
      38.3
      2.8
      1.1
      178.3
      22.6
      3.4
      0.005
      -5.6
      0
      45.2
      NaN
      NaN
      NaN
      NaN

      2531
      35.1
      4.4
      0.7
      477.3
      39.5
      9.2
      0.009
      -1.9
      0
      35.9
      NaN
      NaN
      NaN
      NaN

      3563
      7.3
      2.5
      0.6
      318.5
      19.2
      14.5
      0.003
      -1.2
      0
      7.6
      NaN
      NaN
      NaN
      NaN

```python
df.shape #Размер
```

    (6000, 14)

```python
df = df.drop(['Unnamed: 10', 'Unnamed: 11', 'Unnamed: 12', 'Unnamed: 13'], axis=1)
```

```python
X = df.drop(['Kf_a', 'Kf_b', 'Kf_c'], axis=1) #Параметры
X.head()
```

      Speed
      Radius_big
      Radius_small
      Length
      Pressure_1
      Pressure_2
      Viscosity

      5243
      76.2
      3.9
      0.8
      714.2
      133.6
      47.6
      0.006

      5058
      14.1
      1.6
      0.4
      351.7
      114.7
      88.4
      0.003

      4347
      38.3
      2.8
      1.1
      178.3
      22.6
      3.4
      0.005

      2531
      35.1
      4.4
      0.7
      477.3
      39.5
      9.2
      0.009

      3563
      7.3
      2.5
      0.6
      318.5
      19.2
      14.5
      0.003

```python
y = df.drop(['Speed', 'Radius_big', 'Radius_small', 'Length',\
             'Pressure_1', 'Pressure_2', 'Viscosity'], axis=1) #Коэффициенты
y.head()
```

      Kf_a
      Kf_b
      Kf_c

      5243
      -5.2
      0
      79.8

      5058
      -5.7
      0
      15.0

      4347
      -5.6
      0
      45.2

      2531
      -1.9
      0
      35.9

      3563
      -1.2
      0
      7.6

```python
n = len(X)
n_train = round(n * 0.85)

train_X = X.iloc[:n_train]
test_X = X.iloc[n_train:] #Разбитие на тренировочную и тестовую выборки

train_y, test_y = y.loc[train_X.index], y.loc[test_X.index]
```

```python
params = {'n_jobs': range(0,20)}
model = LinearRegression() #Линейная регрессия
rar = GridSearchCV(model, params) #Подбор гиперпараметров
rar.fit(train_X, train_y)
rar.best_params_

```

    {'n_jobs': 0}

```python
model_1 = LinearRegression().fit(train_X, train_y) #Тренировка
res = model_1.score(train_X, train_y)
res

```

    0.9476518272878293

```python
rslt_test = model_1.predict(test_X)
err_test = mean_absolute_error(test_y, rslt_test)
print('MAE, test: %f' % err_test) #Линейная регрессия совсем не справляется
```

    MAE, test: 175.963011

```python
params = {'n_estimators': range(1500, 1701, 100)} #Лучшие гиперпараметры
model = RandomForestRegressor()
rar = GridSearchCV(model, params)
rar.fit(train_X, train_y)
```

    GridSearchCV(estimator=RandomForestRegressor(),
                 param_grid={'n_estimators': range(1500, 1701, 100)})

```python
rar.best_params_
```

    {'n_estimators': 1500}

```python
momdel = RandomForestRegressor(max_features = 7, min_samples_leaf = 2, \
                               max_depth = 10, n_estimators=1500)
momdel.fit(train_X, train_y)
```

    RandomForestRegressor(max_depth=10, max_features=7, min_samples_leaf=2,
                          n_estimators=1500)

```python
rslt_test = momdel.predict(test_X)
err_test = mean_absolute_error(test_y, rslt_test)
print('MAE, test: %f' % err_test) #Случайный лес справляется лучше
```

    MAE, test: 72.351669


```
#default_exp example
from nbdev.showdoc import show_doc
```

# Example `.ipynb`

This notebook is an example of simple `markdown` cells being used as a descriptive page.

$$\begin{CD}
   A @>a>> B \\
     @VbVV @AAcA \\
   C @= D
\end{CD}$$

$$\begin{cases}
   a &\text{if } b \\
   c &\text{if } d
\end{cases}$$

$$\begin{align}
   a &=b+c \\
   d+e &=f
\end{align}$$


[ADS Entry](http://adsabs.harvard.edu/abs/1990ApJ...365L..55S)

```python
import sympy
sympy.init_printing()
```

One difficulty that I had with equation 1 is that is assumes that the pair production cross section decreases quadratically with the photon energy. The cross section for pair production can be found in equation 32 in [Weaver 1976](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.13.1563). The full calculation can be found in [Theory of Photons and Electrons by Jauch and Rohrlich (1955)](https://archive.org/details/TheoryOfPhotonsElectrons).

Equation 1

```python
sigma_T = sympy.Symbol('sigma_T')
epsilon = sympy.Symbol('epsilon')
n_gamma = sympy.Symbol('n_gamma')
mathscrE = sympy.Symbol(r'\mathscr{E}')
mathscrR = sympy.Symbol(r'\mathscr{R}')
tau = sympy.Symbol('tau')
hbar = sympy.Symbol('hbar', positive=True)
c = sympy.Symbol('c',positive=True)
m_e = sympy.Symbol('m_e', positive=True)
R = sympy.Symbol('R', positive=True)
alpha = sympy.Symbol('alpha')
compton_wavelength = hbar/(m_e*c)
_ = sigma_T*n_gamma*R/epsilon**2
_ = _.subs(n_gamma,mathscrE/epsilon/R**3)
_ = _.subs(R,mathscrR*compton_wavelength)
_ = _.subs(sigma_T,alpha**2*compton_wavelength**2)
eqn_1 = sympy.Eq(tau,_)
eqn_1
```

To derive equation 2, we begin with the Fermi distribution function for electrons

$n = \int_0^{\infty} \frac{p^2 dp}{\hbar^3} \left[1+\exp \left(\frac{\mu + \sqrt{p^2 c^2 + m_e^2 c^4}}{k T} \right)\right]^{-1} =$

Since the electrons are in equilibrium with photons, the chemical potential vanishes $\mu = 0$

$ = \int_0^{\infty} \frac{p^2 dp}{\hbar^3} \left[1+\exp \left(\frac{\sqrt{p^2 c^2 + m_e^2 c^4}}{k T} \right)\right]^{-1} \approx$

Since we are dealing with temperatures much smaller than the electron rest mass energy, the exponential term in the denominator is much larger than unity

$ \approx \int_0^{\infty} \frac{p^2 dp}{\hbar^3} \exp \left(-\frac{\sqrt{p^2 c^2 + m_e^2 c^4}}{k T} \right) \approx$

Most of the contribution to the integral comes from the $p \ll m_e c$, so

$ \approx \exp \left(-\frac{m_e c^2}{k T} \right) \int_0^{\infty} \frac{p^2 dp}{\hbar^3} \exp \left(-\frac{p^2}{m_e k T} \right) \approx \exp \left(-\frac{m_e c^2}{k T} \right) \left(\frac{m_e k T}{\hbar^2} \right)^{3/2}$

```python
k = sympy.Symbol('k')
T = sympy.Symbol('T')
lambda_e = sympy.Symbol('lambda_e')
mathscrT = sympy.Symbol(r'\mathscr{T}')
n_pm = sympy.Symbol(r'n_{\pm}')
_ = sympy.exp(-m_e*c**2/k/T)*(m_e*k*T/hbar**2)**sympy.Rational(3,2)
_ = _.subs(T,mathscrT*m_e*c**2/k)
_ = _.subs(hbar,sympy.solve(sympy.Eq(lambda_e,compton_wavelength),hbar)[0])
eqn_2 = sympy.Eq(n_pm,_)
eqn_2
```

Equation 3

```python
_ = sympy.Eq(mathscrE,R**3*(k*T)**4/(hbar*c)**3/(m_e*c**2))
_ = _.subs(T,mathscrT*m_e*c**2/k)
_ = _.subs(R, mathscrR*compton_wavelength)
eqn_3 = _
eqn_3
```

The energy density in the fireball is comparable to the pressure $p$. The total energy in the fireball is therefore $R^3 p$. In order to escape, a photon has to travel a distance $R$. If the mean free path is $l$, then the number of scatterings it takes for a photon to reach the same is $\left(R/l \right)^2$, and so the actual path the photon travels before escaping is larger $R^2/l$. The photon moves all the while at the speed of light, so the escape time is $\tau \approx \frac{R^2}{c l} \approx \frac{R}{c} \tau$. The luminosity is therefore

$L \approx \frac{p R^2 c}{\tau}$.

The ratio between the luminosity and mechanical power is

$\frac{L}{p dV/dt} \approx {p R^2 c}{p R^2 dR/dt} \frac{1}{\tau} \approx \frac{1}{\tau}$

Equation 5

```python
V = sympy.Symbol('V')
gamma = sympy.Symbol('gamma')
_ = V**(gamma-1)*T
_ = _.subs(gamma,sympy.Rational(4,3))
_ = _.subs(V,R**3)
_.simplify()
```

```python

```


```python
from sympy import *
import numpy as np

from numpy import concatenate
from scipy.linalg import block_diag

```

# Map python functions to MATAB syntax where possible

```python
def ones(*args):
    return np.ones(args, dtype=int)
def zeros(*args):
    return np.zeros(args, dtype=int)
def eye(n, m=None, k=0):
    if isinstance(n, tuple):
        m = n[1]
        n = n[0]
    return np.eye(n,m,k, dtype=int)

catr = lambda x: concatenate(x, 0)
catc = lambda x: concatenate(x, 1)
size = lambda x: np.shape(x)
```

# Generate the needed symbolic variables

```python
# shorten the number of variables for readability
T = 3
K = 2

C_k = list(symbols('C_1:%d'%(K+1)))
V_sk_max = list(symbols('V_s1:%d_max'%(K+1)))
R_sk_max = list(symbols('R_s1:%d_max'%(K+1)))
Delta = symbols('Delta')

sum_I_Mn = list(symbols('sum_I_Mn_1:%d'%(T+1)))

I_b = list(symbols('I_b_1:%d'%(T+1)))

I_out = []
I_in = []
V_s = []
L = []

for k in range(K):
    I_out += list(symbols('I_ou_%d_1:%d'%(k+1,T+1)))
    I_in += list(symbols('I_in_%d_1:%d'%(k+1,T+1)))
    V_s += list(symbols('V_s_%d_0:%d'%(k+1,T+1)))
    L += list(symbols('L_%d_1:%d'%(k+1,T+1)))

x = I_b + I_out + I_in + V_s + L
```

```python
sum_I_Mn = Matrix(sum_I_Mn)
I_b = Matrix(I_b)
I_in = Matrix(I_in)
I_out = Matrix(I_out)
V_s = Matrix(V_s)
L = Matrix(L)
x = Matrix(x)
x.T
```

$\displaystyle \left[\begin{array}{ccccccccccccccccccccccccccccc}I_{b 1} & I_{b 2} & I_{b 3} & I_{ou 1 1} & I_{ou 1 2} & I_{ou 1 3} & I_{ou 2 1} & I_{ou 2 2} & I_{ou 2 3} & I_{in 1 1} & I_{in 1 2} & I_{in 1 3} & I_{in 2 1} & I_{in 2 2} & I_{in 2 3} & V_{s 1 0} & V_{s 1 1} & V_{s 1 2} & V_{s 1 3} & V_{s 2 0} & V_{s 2 1} & V_{s 2 2} & V_{s 2 3} & L_{1 1} & L_{1 2} & L_{1 3} & L_{2 1} & L_{2 2} & L_{2 3}\end{array}\right]$

# constraint 1

```python
"""
% constraint : I_B + sum_k(I_sk_out - I_sk_in) - sum_n(I_Mn) = 0

% eq_lh = I_B + sum_k(I_sk_out - I_sk_in);
% eq_rh = sum_k(I_Mn, 2);

% in matrix form this should be:
% [I,   I,    I,    I,    I,    -I,   -I,   -I,   -I] *
% [I_b, I_1o, I_2o, I_3o, I_4o, I_1i, I_2i, I_3i, I_4i]^T
"""

I = eye(T, T);
A1 = eye(T, T);
A4 = zeros(T, (T+1)*K);
A5 = zeros(T, T*K);

for k in range(K):
    A2 = catc([A2,  eye(T, T)]) if k > 0 else eye(T, T);
    A3 = catc([A3, -eye(T, T)]) if k > 0 else -eye(T, T);

#        I_b, I_sk_out, I_sk_in,  V_sk, L_k
eq1_A = catc([A1,  A2,       A3,      A4,   A5]);
eq1_b = sum_I_Mn;

eq1_A * x
```

$\displaystyle \left[\begin{matrix}I_{b 1} - I_{in 1 1} - I_{in 2 1} + I_{ou 1 1} + I_{ou 2 1}\\I_{b 2} - I_{in 1 2} - I_{in 2 2} + I_{ou 1 2} + I_{ou 2 2}\\I_{b 3} - I_{in 1 3} - I_{in 2 3} + I_{ou 1 3} + I_{ou 2 3}\end{matrix}\right]$

```python
eq1_b
```

$\displaystyle \left[\begin{matrix}sum_{I Mn 1}\\sum_{I Mn 2}\\sum_{I Mn 3}\end{matrix}\right]$

This looks good and seems to **match the paper**. The equation given in the paper:

\begin{equation*}
I_B + \sum_{k \in K} \left( I_{S_k}^{out} - I_{S_k}^{in} \right) - \sum_{n \in N} I_{M_n} = \boldsymbol{0}
\end{equation*}

# constraint 2 implementation from paper in P1

```python
"""
% constraint : (A-I) * V_sk - D_k_out * I_sk_out - D_k_in * I_sk_in = 0

% eq_lh = (A-I) * V_sk - D_k_out * I_sk_out - D_k_in * I_sk_in;
% eq_rh = 0;

% should in matrix form be
% [0, A-I, -D_k_out, -D_k_in, 0] *
% [I_b, V_sk, I_sk_out, I_sk_in, L_k]^T
% where the non zero terms must actually be concat k times
"""

# part 1: (A-I) * V_sk
A11 = zeros(1, T);
A11[0,0] = 1;
A12 = zeros(1, 1);
A21 = eye(T);
A22 = zeros(T,1);

A1 = catc([A11, A12])
A2 = catc([A21, A22])
A_k = catr([A1, A2]);

# build block diagonalmatrix with k blocks on diagonal

A = block_diag(*[A_k for _ in range(K)])
Ia = eye(size(A));

# part 2: D_k_out * I_sk_out - D_k_in * I_sk_in
tmp = catr([ zeros(1,T), eye(T)]);

# stack K times

c1, c2 = symbols('c1 c2')

D_out = block_diag(*[c1 * tmp for _ in range(K)])
D_in = block_diag(*[c2 * tmp for _ in range(K)])

Z = zeros(D_out.shape[0], T)
Z_k = zeros(D_out.shape[0], K*T)

print((size(D_out), size(D_in), size((A-Ia))))
#         I_b,  I_sk_out, I_sk_in,  V_sk,    L_k
eq2_A = catc([ Z,    -D_out,   -D_in,    (A-Ia), Z_k]);

eq2_b = Matrix(zeros(T+1, 1));

-1 * (eq2_A * x)
```

    ((8, 6), (8, 6), (8, 8))

$\displaystyle \left[\begin{matrix}0\\I_{in 1 1} c_{2} + I_{ou 1 1} c_{1} - V_{s 1 0} + V_{s 1 1}\\I_{in 1 2} c_{2} + I_{ou 1 2} c_{1} - V_{s 1 1} + V_{s 1 2}\\I_{in 1 3} c_{2} + I_{ou 1 3} c_{1} - V_{s 1 2} + V_{s 1 3}\\0\\I_{in 2 1} c_{2} + I_{ou 2 1} c_{1} - V_{s 2 0} + V_{s 2 1}\\I_{in 2 2} c_{2} + I_{ou 2 2} c_{1} - V_{s 2 1} + V_{s 2 2}\\I_{in 2 3} c_{2} + I_{ou 2 3} c_{1} - V_{s 2 2} + V_{s 2 3}\end{matrix}\right]$

whith $c1 = R_{sk_{max}} + \Delta / C_k$ and $c2 = R_{sk_{max}} - \Delta / C_k$

This is the Matrix equation from P1, and **maches** the equation in the paper:

\begin{equation*}
v_{s_k}\left( t \right) = -\sum_{\tau=1}^t \left( \frac{\Delta}{C_k} \cdot i_{s_k}  \left( \tau \right) + R_{s_k} \cdot \left| i_{s_k} \left( \tau \right) \right| \right)
\end{equation*}

which is equal to:

\begin{equation*}
v_{s_k}\left( t \right) =  v_{s_k}\left( t-1 \right) - \left( \frac{\Delta}{C_k} \cdot i_{s_k}  \left( t \right) + R_{s_k} \cdot \left| i_{s_k} \left( t \right) \right| \right)
\end{equation*}

and by the steps given in the paper we get to:

\begin{equation*}
v_{s_k}\left( t \right) =  v_{s_k}\left( t-1 \right) - \left( c_1 i_{out_{k}} \left( t \right)  + c_2 i_{in_{k}} \left( t \right) \right)
\end{equation*}

the last equation however only seems to hold while $I_out < I_in$, which is omitted in the paper and might cause complications.

```python
eq2_b
```

```python
A * V_s
```

```python
D_out * I_out
```

```python
D_in * I_in
```

# constraint 3

```python
# constraint : E * V_sk = 0

# eq_lh = E * V_sk
# eq_rh = 0;

E_sub = zeros(1, T+1);
E_sub[0,0] = 1;
E_sub[0,-1] = -1;

# stack K times
for k in range(K):
    E = catc([E, E_sub]) if k > 0 else E_sub;

Z1 = zeros(1, T);
Z2 = zeros(1, K*T);

#         I_b,  I_sk_out,   I_sk_in, V_sk, L_k
eq3_A = catc([ Z1,   Z2,         Z2,       E,   Z2 ]);
eq3_b = Matrix([[0]]);

eq3_A * x
```

```python
eq3_b
```

This **matches** the given equation:

\begin{equation*}
v_{s_k}\left( 0 \right) = v_{s_k}\left( T \right)
\end{equation*}

# combine all constraints to one

```python
Aeq = catr([eq1_A, eq2_A, eq3_A]);

# test for debugging --> this must not fail
Aeq * x

```

```python
beq = Matrix(catr([eq1_b,eq2_b,eq3_b]))
beq
```

# inequality constraint 1

```python
"""
%% inequality constraint 1

% constraint : -L_k <= I_sk_out - I_sk_in <= L_k
% can be rewritten into:
%   (1): -L_k <= I_sk_out - I_sk_in
%   (2): I_sk_out - I_sk_in <= L_k      | switch sides
% can be rewritten into:
%   (1): -L_k <= I_sk_out - I_sk_in
%   (2):  L_k >= I_sk_out - I_sk_in     | * -1
% can be rewritten into:
%   (1): -L_k <=  I_sk_out - I_sk_in    | -I_sk_out | +I_sk_in
%   (2): -L_k <= -I_sk_out + I_sk_in    | +I_sk_out | -I_sk_in
%  which can be rewritten to:
%   (1): -I_sk_out + I_sk_in - L_k <= 0
%   (2):  I_sk_out - I_sk_in - L_k <= 0
% which in matrix algebra is:
"""

Z          = zeros(T*K, T);
Z_k        = zeros(T*K, K*(T+1));

I = eye(T)
E_I_sk_out = eye(T*K);
E_I_sk_in = eye(T*K);
E_L_k = eye(T*K);

#      I_b,  I_sk_out,    I_sk_in,   V_sk,  L_k
A_11 = catc([Z,   -E_I_sk_out,  E_I_sk_in, Z_k,  -E_L_k]);
b_11 = zeros(T*K, 1);

#      I_b,  I_sk_out,    I_sk_in,   V_sk,  L_k
A_12 = catc([Z,    E_I_sk_out, -E_I_sk_in, Z_k,  -E_L_k]);
b_12 = zeros(T*K, 1);

#  combine all inequality constraints
A = catr([A_11, A_12]);

b = catr([b_11, b_12]);
A = Matrix(A)
b = Matrix(b)

# A * x <= b

A * x
```

```python
b
```

This **matches** the equation given in the paper:

\begin{equation*}
-L_k \leq I_{S_k}^{out} - I_{S_k}^{in} \leq L_k
\end{equation*}

```python

```


# 微積分

## 極限

次のような無限数列を考える

$$
1, \frac{1}{2}, \frac{1}{3}, \frac{1}{4}, \cdots
$$

この数列の一般項は次の式で表される

$$
a_n = \frac{1}{n}
$$

この数列は $n$ が大きくなるにつれて 0 に近づいていく

このことを以下の式で表す

$$
\lim_{n\to\infty}\frac{1}{n} = 0
$$

この場合の $\frac{1}{n}$ が近づく値 0 を **極限**、または **極限値** と呼ぶ

全ての無限数列に極限が存在するわけではなく、例えば一般項 $a_n = n$ で表されるような無限数列は、$n$ が大きくなると無限に大きくなっていく

このような時、この数列は **発散する** という

$a_n = n$ で表される無限数列は正の方向に発散するが、$a_n = -n^2$ のように負の方向に発散する無限数列もある

上記のような発散は、以下のような式で表す

$$
\lim_{n\to\infty}n = \infty \\
\lim_{n\to\infty}(-n^2) = -\infty
$$

ここで注意すべきことは「$infty$ という数」があるわけではなく、発散することを表現するためにこの記号を使っているということである

$infty$ は数ではないため、この記号に対する演算は定義することができない

### 振動
一般項 $a_n = (-1)^nn$ で表される数列、

$$
-1, 2, -3, 4, \cdots
$$

を考える

この数列は収束せず、$n$ が大きくなるにつれて無限に大きくなるわけでも、無限に小さくなるわけでもない

このように発散も収束もしない数列の挙動は **振動** と呼ばれる

### 関数の極限
数列だけではなく、関数の極限についても同様に考えることが出来る

例えば $f(x) = \frac{1}{x}$ という関数を考えると、これは $x$ を限りなく大きくすると 0 に近づいていく

これは $\lim_{x\to\infty}\frac{1}{x} = 0$ という式で表されるが、以下のグラフを見ても明らかである

```julia
using Plots

f(x) = 1/x
plot(f; x_lims=(0, 5), y_lims=(0, 5))
```

同様に $f(x) = x$ は $\lim_{x\to\infty}x = \infty$ という極限で表され、$f(x) = -x^2$ は $\lim_{x\to\infty}(-x^2) = -\infty$ という極限で表される

```julia
f1(x) = x
p1 = plot(f1)

f2(x) = -x^2
p2 = plot(f2)

plot(p1, p2; x_lims=(0, 5), y_lims=(-10, 10), layout=(2, 1))
```

次に関数 $f(x) = x\sin x$ を考える

この関数は $x$ が大きくなるにつれて上下の振り幅が大きくなっていくが、無限に大きい $x$ については、いくらでも大きい値といくらでも小さな値の両方を取りうる

したがって、この関数は振動する、ということになる

```julia
f(x) = x * sin(x)
plot(f; x_lims=(-10, 90), y_lims=(-100, 100))
```

ここまで $x\rightarrow\infty$ の極限のみを考えてきたが、それ以外の極限を考えることもできる

例えば、関数 $f(x)=\frac{1}{x}$ は $x$ を無限に小さくしていくと 0 に近づく

これは次のような式で表される

$$
\lim_{x\to -\infty}\frac{1}{x} = 0
$$

```julia
f(x) = 1/x
plot(f; x_lims=(-5, 5), y_lims=(-5, 5))
```

また、特定の定数に近づけるときの極限というものも考えることが出来る

例えば、関数 $f(x) = x^2$ で $x$ が 1 の場合は $f(1) = 1^2 = 1$ となるため、次の式で表すことが出来る

$$
\lim_{x\to1}x^2 = 1
$$

上記は $x = 1$ が定義されている関数だったため、極限の計算は容易だった

一方、関数 $f(x) = \frac{x^2(x-1)}{x-1}$ は、$x = 1$ のときの計算は定義されていない（分母が 0 になってしまう）が、$x=1.01$ や $x=1.001$ などの計算は定義されており、$x$ が 1 に近づくほど $f(x)$ の値は 1 に近づくことが分かる

同様に $x=0.99$ や $x=0.999$ のように小さい方から 1 に近づけていっても $f(x)$ は 1 に近づく

以上より、$f(x) = \frac{x^2(x-1)}{x-1}$ の極限は以下の式で表すことが出来る

$$
\lim_{x\to1}\frac{x^2(x-1)}{x-1} = 1
$$

```julia
f(x) = (x^2 * (x - 1)) / (x - 1)
plot(f; x_lims=(-2, 2), y_lims=(0, 5))
```

### 極限の性質
$\lim_{x\to\alpha}f(x) = \alpha$, $\lim_{x\to\alpha}g(x) = \beta$ のとき（両式とも収束するとき）、次の式が成り立つ

$$
\begin{align}
\lim_{x\to\alpha}(f(x) + g(x)) &= \alpha + \beta \\
\lim_{x\to\alpha}(f(x)g(x)) &= \alpha\beta \\
\lim_{x\to\alpha}(\frac{f(x)}{g(x)}) &= \frac{\alpha}{\beta} \quad ただし \beta\neq0
\end{align}
$$

また、上式より以下の性質も成り立つ

$$
\begin{align}
\lim_{x\to\alpha}(f(x) - g(x)) &= \alpha - \beta \\
\lim_{x\to\alpha}kf(x) &= k\alpha \\
\lim_{x\to\alpha}(kf(x) + lg(x)) &= k\alpha + l\beta
\end{align}
$$

例として、次の極限を計算してみる

$$
\lim_{x\to\infty}\frac{3x^2 + 2x + 1}{x^2 + 2x + 3}
$$

これを計算するには、極限の性質と $\lim_{x\to\infty}\frac{1}{x} = 0$ であることを上手く利用する

$$
\begin{align}
\lim_{x\to\infty}\frac{3x^2 + 2x + 1}{x^2 + 2x + 3}
&= \lim_{x\to\infty}\frac{3 + \frac{2}{x} + \frac{1}{x^2}}{1 + \frac{2}{x} + \frac{3}{x^2}} \quad (分子・分母に x^2 を掛ける) \\
&= \frac{3 + 2\lim_{x\to\infty}\frac{1}{x} + \lim_{x\to\infty}\frac{1}{x^2}}{1 + 2\lim_{x\to\infty}\frac{1}{x} + 3\lim_{x\to\infty}\frac{1}{x^2}} \quad (極限の性質より) \\
&= \frac{3 + 2\cdot{0} + 0}{1 + 2\cdot{0} + 3\cdot{0}} \quad (\lim_{x\to\infty}\frac{1}{x} = 0 より) \\
&= 3
\end{align}
$$

### 関数の連続性
次のような関数を考える

$$
f(x) = \frac{x(x - 1)}{|x - 1|}
$$

この関数は $x = 1$ では定義されておらず、絶対値の定義より $x\gt{1}$ と $x\lt{1}$ で以下のように分けて定義される

$$
\begin{align}
f(x) &= \left\{
\begin{array}{ll}
\frac{x(x - 1)}{x - 1} & (x\gt{1}) \\
\frac{x(x - 1)}{-(x - 1)} & (x\lt{1})
\end{array}
\right.
\\
&= \left\{
\begin{array}{ll}
x & (x\gt{1}) \\
-x & (x\lt{1})
\end{array}
\right.
\end{align}
$$

したがって、この関数は $x$ を数直線上で右から 1 に近づけた場合と、左から 1 に近づけた場合で極限が異なる

$x$ を右から $a$ に近づけることを $x\rightarrow{a+0}$ で表し、左から $a$ に近づけることを $x\rightarrow{a-0}$ で表す

特に $a=0$ のときは、それぞれ $x\rightarrow+0$, $x\rightarrow-0$ と書く

以上より上記 $f(x)$ の場合は、以下のように記述される

$$
\begin{align}
\lim_{x\to1+0}\frac{x(x-1)}{|x-1|} &= \lim_{x\to1+0}\frac{x(x-1)}{x-1} \\
&= \lim_{x\to1+0}x = 1 \\
\\
\lim_{x\to1-0}\frac{x(x-1)}{|x-1|} &= \lim_{x\to1-0}\frac{x(x-1)}{-(x-1)} \\
&= \lim_{x\to1-0}-x = -1 \\
\end{align}
$$

```julia
f(x) = x * (x - 1) / abs(x - 1)

plot(f)
```

一般に $x\rightarrow{a+0}$ としたときの極限を右極限、$x\rightarrow{a-0}$ としたときの極限を左極限と呼ぶ

つまり $x\rightarrow{a}$ での右極限と左極限が一致する場合に、それを $x=a$ での極限と呼んでいたことになる

ここで連続関数の定義を行う

関数 $y = f(x)$ が $x=a$ で **連続** であるということは、次の式で定義される

$$
\lim_{x\to{a}}f(x) = f(a)
$$

つまりこれは $f(x)$ が $x=a$ で定義されていて、$x$ を右から $a$ に近づけても左から $a$ に近づけても、その極限は $f(a)$ になるという意味である

例外的に $a$ が $f(x)$ の端点である場合があり、例えば $f(x)$ の定義域が閉区間 $[p, q]$ で $a=p$ の場合、$a$ で連続であることは $\lim_{x\to{a+0}}f(x) = f(a)$ で表される

これは $a$ が定義域の下端であるために、左側から近づけることができないからである

ここまでで各点の連続性を定義できたため、関数全体での連続性を定義する

関数 $f(x)$ が連続であることは、定義域上のすべての点で連続であることをいう

この定義に従うと、全ての多項式関数は連続である

また、指数関数 $f(x) = a^x$ および対数関数 $f(x) = \log_ax$ も連続である（ただし、対数関数の定義域は $x\gt0$ であることに注意）

この、関数の連続性の定義は、日常言語の持つ「連続」の直感的イメージと異なることため注意が必要である

例えば前述の右極限・左極限の例として挙げた $f(x) = \frac{x(x-1)}{|x-1|}$ は連続関数である

なぜなら、この関数の定義域は $x\neq1$ であり、関数の連続性の定義から $x=1$ での連続性を考慮する必要がないためである

実際 $a\neq1$ のときは $\lim_{x\to{a}}\frac{x(x-1)}{|x-1|} = \frac{a(a-1)}{|a-1|}$ が成り立つ

一方で、以下の関数は連続ではない

$$
f(x) = \left\{
\begin{array}{ll}
\frac{x(x-1)}{|x-1|} & (x\neq1) \\
0 & (x=1)
\end{array}
\right.
$$

上記関数は $f(1) = 0$ が定義されているにも関わらず、$\lim_{x\to1}f(x)$ は定義されない（右極限と左極限が一致しない）ためである

#### 演習
次を計算せよ

1. $$
\lim_{x\to\infty}\frac{3x^3 + x}{x^3 + 2x^2}
$$
2. $$
\lim_{x\to\infty}\frac{x^2 + x}{x^3 + 2x^2}
$$
3. $$
\lim_{x\to\infty}\frac{2x^2 + x}{x + 3}
$$

#### 解答
1. $$
\begin{align}
\lim_{x\to\infty}\frac{3x^3 + x}{x^3 + 2x^2} &= \lim_{x\to\infty}\frac{3 + \frac{1}{x^3}}{1 + 2\frac{1}{x}} \\
&= 3
\end{align}
$$
2. $$
\begin{align}
\lim_{x\to\infty}\frac{x^2 + x}{x^3 + 2x^2} &= \lim_{x\to\infty}\frac{\frac{1}{x} + \frac{1}{x^3}}{1 + 2\frac{1}{x}} \\
&= 0
\end{align}
$$
3. $$
\begin{align}
\lim_{x\to\infty}\frac{2x^2 + x}{x + 3} &= \lim_{x\to\infty}\frac{2x + 1}{1 + 3\frac{1}{x}} \\
&= \infty \\
&\therefore 発散
\end{align}
$$

```julia
using SymPy

# x を記号計算の対象（シンボル）に
@vars x

f(x) = (3x^3 + x) / (x^3 + 2x^2)
# f(x) の x → ∞ 極限
limit(f, x, oo)
```

$\begin{equation*}3\end{equation*}$

```julia
f(x) = (x^2 + x) / (x^3 + 2x^2)
limit(f, x, oo)
```

$\begin{equation*}0\end{equation*}$

```julia
f(x) = (2x^2 + x) / (x + 3)
limit(f, x, oo)
```

$\begin{equation*}\infty\end{equation*}$

## 指数関数

$a$ の累乗 $a^n$ とは、$n$ が自然数（1以上の整数）のときには $a$ を $n$ 回掛けた数として定義されている

これは次の指数法則を満たす

$$
\begin{align}
a^m \times a^n &= a^{m+n} \\
(a^m)^n &= a^{mn} \\
(ab)^n &= a^nb^n
\end{align}
$$

$m$ と $n$ が自然数のときに限らず、指数法則を満たすようにすることで一般の実数 $x$ について $a^x$ を定義できる

このような $a^x$ を **べき乗** と呼ぶ

$a^m \times a^n &= a^{m+n}$ より、

$$
a^n \times a^0 = a^{n + 0} = a^n
$$

となるため、$a^0 = 1$ が成り立つ

また、自然数 $n$ に対して、

$$
a^n \times a^{-n} = a^{n + (-n)} = a^0 = 1
$$

となるため、$a^{-n} = \frac{1}{n}$ が成り立つ

次に、**平方根** という概念を導入する

実数 $a\geq0$ と自然数 $q$ に対して、$q$ 乗して $a$ になる数のうち、正の整数を

$$
\sqrt[q]{a}
$$

と記述し、これを平方根と呼ぶ

特に $q=2$ のときは $q$ を省略して記述する

例えば、

$$
\sqrt{4} = 2,\ \sqrt[3]{8} = 2,\ \sqrt[4]{81} = 3
$$

となる

平方根は整数にならないこともあり、例えば $\sqrt[3]3$ は $1.44224\cdots$ という無理数になる

次に整数を実数まで拡張し、実数 $x$ に対する $a^x$ という計算を考える

例えば $4^\frac{1}{2}$ について、指数法則を満たすようにすると、

$$
(4^\frac{1}{2})^2 = 4^{\frac{1}{2}\times2} = 4^1 = 4
$$

となるため、$4^\frac{1}{2} = 2$ であることが分かる

同様に、$27^\frac{1}{3}$ についても考えてみると、

$$
(27^\frac{1}{3})^3 = 27^{\frac{1}{3}\times3} = 27^1 = 27
$$

となるため、$27^\frac{1}{3} = 3$ であることが分かる

以上より、一般の有理数についてのべき乗は、平方根として定義できることが分かる

すなわち、整数 $p$ と自然数 $q$ に対して以下のように定義される

$$
a^\frac{p}{q} = (\sqrt[q]a)^p
$$

最後に、無理数の場合についても定義してみる

例えば、$2^\sqrt2$ という数を考えるときには、$\sqrt2$ に近づくような数列、

$$
1,\ 1.4,\ 1.41,\ 1.414,\ 1.4142,\ \cdots
$$

のような数列を考え、それに対応する、

$$
2^1,\ 2^{1.4},\ 2^{1.41},\ 2^{1.414},\ 2^{1.4142},\ \cdots
$$

という数列を考え、この極限値を $2^\sqrt2$ であると定義する

このように定義することで、すべての実数 $x$ に対して $a^x$ を定義できる

ここで $x$ の関数 $f(x)=a^x$ は、$a$ を底とする **指数関数** と呼ばれる

ただし、このとき $a\gt0$ である必要があるため注意が必要である

例えば $(-2)^\frac{1}{2}$ は2乗すると -2 になる数ということになるが、実数の範囲ではうまく定義できない

また、これまでの議論では指数関数を満たすようにべき乗の概念を拡張してきたため、任意の $x$, $y$, $a\gt0$ についても、同様の指数法則が成り立つ

$$
\begin{align}
a^x \times a^y &= a^{x+y} \\
(a^x)^y &= a^{xy} \\
(ab)^x &= a^xb^x
\end{align}
$$

### ネイピア数
指数関数の中でも次で定義される数が非常に重要な意味を持つ

$$
e = \lim_{n\to\infty}(1 + \frac{1}{n})^n
$$

この数は **自然対数の底** または **ネイピア数** と呼ばれ、次のような無理数である

$$
e = 2.71828182845\cdots
$$

この $e$ を用いた $f(x)=e^x$ という指数関数は、微分において非常に重要なものになるが、これについては後述する

$e^x$ は $\exp{x}$ と記述する場合もある

#### 演習
次の計算をせよ

1. $9^\frac{1}{2}$
2. $8^{-\frac{2}{3}}$
3. $25^{\sqrt3 - \frac{1}{2}} \times 5^{-1-2\sqrt3}$

#### 解答
1. $$
9^\frac{1}{2} = \sqrt9 = 3
$$
2. $$
8^{-\frac{2}{3}} = \frac{1}{8^\frac{2}{3}} = \frac{1}{(8^\frac{1}{3})^2} = \frac{1}{2^2} = \frac{1}{4}
$$
3. $$
\begin{align}
25^{\sqrt3 - \frac{1}{2}} \times 5^{-1-2\sqrt3} &= (5^2)^{\sqrt3 - \frac{1}{2}} \times 5^{-1-2\sqrt3} \\
&= 5^{2(\sqrt3 - \frac{1}{2})} \times 5^{-1-2\sqrt3} \\
&= 5^{2(\sqrt3 - \frac{1}{2}) + (-1-2\sqrt3)} \\
&= 5^{-2} \\
&= \frac{1}{25}
\end{align}
$$

```julia
9^(1/2)
```

    3.0

```julia
8^(-2/3)
```

    0.25

```julia
25^(sqrt(3) - 1/2) * 5^(-1 - 2*sqrt(3))
```

    0.04000000000000001

## 対数関数

$a\gt0$, $a\neq1$, $b\gt0$ について $a^x = b$ となるとき、以下のように定義する

$$
x = \log_ab
$$

つまり $\log_ab$ は「$a$ を何乗すると $b$ になるか」という数を表す

また、この $\log_ab$ を、$a$ を底とする $b$ の **対数** と呼ぶ

$a\gt0$, $b\gt0$ は、「指数関数は底が正の場合にのみ考えうる」ということに対応している

$a\neq1$ というのは、1 は何乗しても 1 になるため都合が悪いためである

定義により次の式は明らかに成り立つ

$$
\log_aa^p = p
$$

実際、$\log_aa^p$ は「$a$ を何乗すると $a^p$ になるか」を意味するため、この式は明らかである

この式の特別な場合として、$a^1=a$, $a^0=1$, $a^{-1}=\frac{1}{a}$ であることを考慮すると次が成り立つ

$$
\begin{align}
\log_aa &= 1 \\
\log_a1 &= 0 \\
\log_a\frac{1}{a} &= -1
\end{align}
$$

また、対数については以下の式が成り立つ

$$
\begin{align}
\log_apq &= \log_ap + \log_aq \\
\log_a\frac{p}{q} &= \log_ap - \log_aq \\
\log_ap^k &= k\log_ap
\end{align}
$$

### 底の変換法則
対数の底を変更して計算したい場合がよくある

$\log_ap$ が与えられた時、任意の $b\gt0$ について以下の式が成り立つ

$$
\log_ap = \frac{\log_bp}{\log_ba}
$$

これを **底の変換法則** と呼ぶ

### 自然対数
対数においても、自然対数の底 $e$ は特別な意味を持ち、特に対数の底を $e$ として $\log_ap$ の計算を行いたくなることが多い

この場合は $e$ を省略して $\log{p}$ や $\ln{p}$ と書くことが多い（化学数値計算では $\log{p}$ は $\log_{10}p$ を表すことが多いため、本稿では $\ln{p}$ という表記で統一する）

これを $p$ の **自然対数** と呼ぶ

#### 演習
次の計算をせよ

1. $$
\log_2{8}
$$
2. $$
\frac{\log_2{81}}{\log_2{3}}
$$
3. $$
\ln\frac{1}{e^2}
$$

#### 解答
1. $$
\log_2{8} = \log_2{2^3} = 3
$$
2. $$
\frac{\log_2{81}}{\log_2{3}} = \frac{\frac{\log_3{81}}{\log_3{2}}}{\frac{\log_3{3}}{\log_3{2}}} = \log_3{81} = 4
$$
3. $$
\ln\frac{1}{e^2} = \ln{e^{-2}} = -2
$$

```julia
log(2, 8)
```

    3.0

```julia
log(2, 81) / log(2, 3)
```

    4.0

```julia
log(exp(1), 1 / exp(2))
```

    -2.0

```julia

```