```python
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

import numpy as np
import pandas as pd
import scipy
import math

from collections import Counter

from warnings import filterwarnings
filterwarnings('ignore')
```

# Необходимые сведения из высшей математики (линейная алгебра, математический анализ, теория вероятности, статистика)

Курс "Модели и методы интеллектуального анализа данных"

Чернышов Юрий

к.ф.-м.н., доцент кафедры ИТЗИ УрГУПС (Екатеринбург)

yuchernyshov@usurt.ru

# Оглавление

Линейная алгебра

Векторы

Матрицы

Математический анализ

Функции одной переменной

Производные

Функции нескольких переменных

Частные производные.

Градиент. Градиентные методы

Теория вероятностей

Определение вероятности

Формула Байеса

Математическая статистика

Центральная предельная теорема

Уровни значимости, p-value

Задачи

Линейная алгебра

Математический анализ

Теория вероятности и математическая статистика

Литература

Математические объекты и методы играют важнейшую роль в исследовании данных. Далее описаны некоторые основные базовые понятия и методы из линейной алгебры, математического анализа и теории вероятности, которые используются при работе с данными. При этом математические понятия разбираются в контексте их использования в языке Python (библиотеки numpy, pandas, scipy). Для более глубокого изучения рекомендуется обратиться к соответствующим книгам из списка литературы.

# Линейная алгебра

Алгебра - раздел высшей математики, который изучает различные пространства, операции в этих пространствах и их свойства. Примеры пространств:
- пространство действительных чисел $R=(-\infty, \infty)$,
- пространство векторов,
- пространство матриц.

Линейная алгебра изучает векторные пространства.

В библиотеке numpy есть специальный модуль линейной алгебры linalg.

```python
np.info(np.linalg)
```

    Core Linear Algebra Tools
    -------------------------
    Linear algebra basics:

    - norm            Vector or matrix norm
    - inv             Inverse of a square matrix
    - solve           Solve a linear system of equations
    - det             Determinant of a square matrix
    - lstsq           Solve linear least-squares problem
    - pinv            Pseudo-inverse (Moore-Penrose) calculated using a singular
                      value decomposition
    - matrix_power    Integer power of a square matrix

    Eigenvalues and decompositions:

    - eig             Eigenvalues and vectors of a square matrix
    - eigh            Eigenvalues and eigenvectors of a Hermitian matrix
    - eigvals         Eigenvalues of a square matrix
    - eigvalsh        Eigenvalues of a Hermitian matrix
    - qr              QR decomposition of a matrix
    - svd             Singular value decomposition of a matrix
    - cholesky        Cholesky decomposition of a matrix

    Tensor operations:

    - tensorsolve     Solve a linear tensor equation
    - tensorinv       Calculate an inverse of a tensor

    Exceptions:

    - LinAlgError     Indicates a failed linear algebra operation

Как видно из описаний модуль numpy.linalg содержит функции для работы с векторами и матрицами, решения уравнений, работы с тензорами и другие возможности.

Назад к Оглавлению

## Векторы

Скаляр - это число. Вектор - это набор чисел. Векторы можно складывать и вычитать, умножать на число (скаляр). Также для векторов определены два вида умножения - скалярное ($\vec{a} \cdot \vec{b}$) и векторное ($\vec{a} \times \vec{b}$) произведения векторов.

$$
\vec{a}=(a_1, a_2, a_3), \vec{b}=(b_1, b_2, b_3)
$$

$$
\vec{a}\pm\vec{b} = (a_1 \pm b_1, a_2 \pm b_2, a_3 \pm b_3)
$$

$$
k \vec{a} = (ka_1, ka_2, ka_3)
$$

$$
\vec{a} \cdot \vec{b} = a_1 b_1 + a_2 b_2 + a_3 b_3
$$

$$
\vec{a} \cdot \vec{b} = \left| \vec{a} \right| \left| \vec{b} \right| \cos (\alpha),~\alpha - угол~между~векторами~\vec{a}~и~\vec{b}.
$$

$$
\vec{a} \times \vec{b} = \left| \vec{a} \right| \left| \vec{b} \right| \sin (\alpha),~\alpha - угол~между~векторами~\vec{a}~и~\vec{b}.
$$

Для работы с векторами в Python можно использовать обычные списки, либо массивы numpy (в которых оптимизирована работа с большими векторами). Также в библиотеке pandas есть специальный тип pandas.Series для задания вектора.

#### Список python

```python
рост_вес = [180, 80]
рост_вес[0]*рост_вес[1]
```

    14400

#### Массив numpy.array

```python
a = np.array([180,80], dtype='int32')
print(a**2)
```

    [32400  6400]

При работе с большими числами важно обращать внимание на то, чтобы размера памяти для хранения элементов массива было достаточно. В частности, при очень больших значениях элементов массива типа элемента 'int32' не хватает.

```python
print(a**5)
a = np.array([180,80], dtype='int64')
print(a**5)
```

    [  -21761024 -1018167296]
    [188956800000   3276800000]

#### Скалярное произведение в numpy

```python
a = np.array([1, 2])
b = np.array([3, 4])
a.dot(b)
```

    11

#### Объект pandas.Series

```python
ds = pd.Series(np.array([1,2,3]))
display(ds)
print("Сумма элементов: {}".format(ds.sum()))
```

    0    1
    1    2
    2    3
    dtype: int32

    Сумма элементов: 6

Графически вектор - это направленный отрезок прямой, имеющий начало $A$ и конец $B$. Обозначение: $\vec{AB}$ или просто $\vec{a}$.

Вектор задается координатами начала $(x_0, y_0)$ и конца $(x_1, y_1)$, при этом также задается направление вектора.

Начало любого вектора можно перенести в точку $(0,0)$, при этом координаты конца вектора будут $(x_1-x_0,y_1-y_0)$.

```python
plt.xlim(-1, 5); plt.ylim(-1, 6)
a_begin = np.array ([1, 3]); a_end = np.array ([4, 5])
b_begin = np.array ([a_begin[0]-a_begin[0], a_begin[1]-a_begin[1]]); b_end = np.array ([a_end[0]-a_begin[0], a_end[1]-a_begin[1]])
plt.annotate (u'$\\vec{a}$', xy=a_begin, xytext=a_end, arrowprops={'arrowstyle': '<|-',})
plt.annotate (u'$\\vec{b}$', xy=b_begin, xytext=b_end, arrowprops={'arrowstyle': '<|-',})
plt.grid(True)
plt.xticks(range(6))
plt.yticks(range(7))
plt.show()
```

#### Сложение и вычитание векторов

Сложение и вычитание двух векторов $\vec{a}=(a_1,a_2)$ и $\vec{b}=(b_1,b_2)$.

$$
\vec{a} \pm \vec{b}=\vec{c}
$$

$$
\vec{c}=(a_1 \pm b_1, a_2 \pm b_2)
$$

```python
plt.xlim(-1, 7)
plt.ylim(-1, 6)
a = np.array ([1, 3])
b = np.array ([5, 2])
c = a + b
plt.annotate ('', xy=(0, 0), xytext=a, arrowprops={'arrowstyle': '<|-', 'color':'b'})
plt.annotate ('', xy=(0, 0), xytext=b, arrowprops={'arrowstyle': '<|-', 'color':'r'})
plt.annotate ('', xy=a, xytext=a+b, arrowprops={'arrowstyle': '<|-', 'color':'r'})
plt.annotate ('', xy=(0, 0), xytext=c, arrowprops={'arrowstyle': '<|-', 'color':'g'})
plt.annotate("$\\vec{a}$", xy=(0,2) ,xytext=(0,2), arrowprops={'color':'b'})
plt.annotate("$\\vec{b}$", xy=(3,0) ,xytext=(3,0), arrowprops={'color':'r'})
plt.annotate("$\\vec{c}=\\vec{a}+\\vec{b}$", xy=(4,3) ,xytext=(4,3) , arrowprops={'color':'g'})
plt.grid(True)
plt.xticks(range(7))
plt.yticks(range(7))
plt.show()
```

#### Умножение векторов

Умножение вектора $\vec{a}=(x_1,y_1)$  на число $k$:
$$
k \vec{a} = (kx_1, ky_1)
$$

```python
plt.xlim(-1, 7)
plt.ylim(-1, 3)
a = np.array ([3, 1])
b = a * 2
plt.annotate ('', xy=a, xytext=(0, 0), arrowprops={'arrowstyle': 'fancy', 'color':'b'})
plt.annotate ('', xy=(0, 0), xytext=b, arrowprops={'arrowstyle': '<|-', 'color':'r'})
plt.annotate("$\\vec{a}$", xy=(0,1) ,xytext=(0,1), arrowprops={'color':'b'})
plt.annotate("$\\vec{b} = 2\\vec{a}$", xy=(6,1.5) ,xytext=(6,1.5), arrowprops={'color':'r'})
plt.grid(True)
plt.xticks(range(7))
plt.yticks(range(4))
plt.show()
```

#### Скалярное произведение векторов

Скалярное произведение векторов задается формулой $\vec{a}\cdot\vec{b}=|\vec{a}||\vec{b}|\cos \alpha$, где $\alpha$ - угол между векторами $\vec{a}$ и $\vec{b}$. Кроме того, если заданы декартовы координаты векторов $\vec{a}=(a_1, a_2, a_3)$ и $\vec{b}=(b_1, b_2, b_3)$, то скалярное произведение векторов можно представить в виде $\vec{a}\cdot\vec{b}=a_1 b_1 + a_2 b_2 +a_3 b_3$. Геометрически на плоскости скалярное произведение вектора $\vec{a}=(a_1, a_2)$ на вектор $\vec{a}=(b_1, b_2)$ это модуль (длина) проекции вектора $\vec{a}$ на вектор $\vec{b}$ (или, учитывая переместительное свойство скалярного произведения, вектора $\vec{b}$ на вектор $\vec{a}$).

```python
a = np.array ([3, 3])
b = np.array ([4, 1])
plt.xlim(-1, 7)
plt.ylim(-1, 4)
plt.annotate ('', xy=a, xytext=(0, 0), arrowprops={'arrowstyle': '-|>', 'color':'b'})
plt.annotate ('', xy=b, xytext=(0, 0), arrowprops={'arrowstyle': '-|>', 'color':'r'})
plt.annotate("$\\vec{a}$", xy=(0,1), xytext=(0,1))
plt.annotate("$\\vec{b}$", xy=(4,0), xytext=(4,0))
N = a*np.dot(a,b)/np.linalg.norm(a)/np.linalg.norm(b); plt.plot([N[0], b[0]],[N[1], b[1]], c='g');
plt.scatter(N[0],N[1], c='g')
M = b*np.dot(a,b)/np.linalg.norm(a)/np.linalg.norm(b); plt.plot([M[0], a[0]],[M[1], a[1]], c='b');
plt.scatter(M[0],M[1], c='b')
plt.grid(True)
plt.xticks(range(7))
plt.yticks(range(4))
plt.show()
```

Назад к Оглавлению

## Матрицы

Матрица - двумерная таблица.

В python матрица реализуется как список списков при использовании встроенных в Python списков, либо с использованием встроенных средств библиотек numpy или pandas.

Пример создания матрицы с помощью списка списков:

```python
A = [[int(i+j) for i in range(3)] for j in range(4)]
print(A)
for row in A:
    print(" ".join([str(elem) for elem in row]))
print(A[1][1])
```

    [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]
    0 1 2
    1 2 3
    2 3 4
    3 4 5
    2

Пример создания двумерного массива с помощью функции numpy.array. Скачала создается одномерный массов чисел, затем из него создается матрица с помощью функции reshape().

```python
B = np.array([i for i in range(1,13)])
print(B, B[4])
B = B.reshape(3,4)
print(B, B[1,0])
type(B)
```

    [ 1  2  3  4  5  6  7  8  9 10 11 12] 5
    [[ 1  2  3  4]
     [ 5  6  7  8]
     [ 9 10 11 12]] 5

    numpy.ndarray

Пример создания матрицы с помощью функции numpy.matrix.

```python
C = np.mat([[1,2],[3,4]])
print(C, type(C))
```

    [[1 2]
     [3 4]] <class 'numpy.matrixlib.defmatrix.matrix'>

Пример создания объекта pandas.DataFrame

```python
df = pd.DataFrame(np.array([1,2,3,4]).reshape(2,2))
display(df)
```

      0
      1

      0
      1
      2

      1
      3
      4

#### Вычисление определителя матрицы

```python
A = np.array([[1,2,3],[0,2,1],[5,4,2]])
np.linalg.det(A)
```

    -19.999999999999996

#### Операции над матрицами: сложение, вычитание, умножение, транспонирование.

Пусть заданы матрицы
$$
A = \left(
\begin{array}{lll}
a_{11} & a_{12} & a_{13} \\
a_{21} & a_{22} & a_{23} \\
a_{31} & a_{32} & a_{33}
\end{array}
\right),
~~
B = \left(
\begin{array}{lll}
b_{11} & b_{12} & b_{13} \\
b_{21} & b_{22} & b_{23} \\
b_{31} & b_{32} & b_{33}
\end{array}
\right),
~~
$$

Умножение матрицы A на число k
$$
k A = \left(
\begin{array}{lll}
ka_{11} & ka_{12} & ka_{13} \\
ka_{21} & ka_{22} & ka_{23} \\
ka_{31} & ka_{32} & ka_{33}
\end{array}
\right)
$$

Сумма матриц A+B
$$
A\pm = \left(
\begin{array}{lll}
a_{11} \pm b_{11} & a_{11} \pm b_{12} & a_{11} \pm b_{13} \\
a_{21} \pm b_{21} & a_{21} \pm b_{22} & a_{21} \pm b_{23} \\
a_{31} \pm b_{31} & a_{31} \pm b_{32} & a_{31} \pm b_{33}
\end{array}
\right)
$$

Произведение матриц A и B

$$
AB =
\left(
\begin{array}{lll}
a_{11} & a_{12} & a_{13} \\
a_{21} & a_{22} & a_{23} \\
a_{31} & a_{32} & a_{33}
\end{array}
\right)
\left(
\begin{array}{lll}
b_{11} & b_{12} & b_{13} \\
b_{21} & b_{22} & b_{23} \\
b_{31} & b_{32} & b_{33}
\end{array}
\right)
=
$$

$$
=
\left(
\begin{array}{lll}
a_{11}b_{11}+a_{12}b_{21}+a_{13}b_{31} & a_{11}b_{12}+a_{12}b_{22}+a_{13}b_{32} & a_{11}b_{13}+a_{12}b_{23}+a_{13}b_{33} \\
a_{21}b_{11}+a_{22}b_{21}+a_{23}b_{31} & a_{21}b_{12}+a_{22}b_{22}+a_{33}b_{32} & a_{21}b_{13}+a_{22}b_{23}+a_{23}b_{33} \\
a_{31}b_{11}+a_{32}b_{21}+a_{33}b_{31} & a_{31}b_{12}+a_{32}b_{22}+a_{33}b_{32} & a_{31}b_{13}+a_{32}b_{23}+a_{33}b_{33}
\end{array}
\right)
$$

Транспонированная матрица $A^T$ определяется следующим образом:

$$
A^T = \left(
\begin{array}{lll}
a_{11} & a_{12} & a_{13} \\
a_{21} & a_{22} & a_{23} \\
a_{31} & a_{32} & a_{33}
\end{array}
\right)^T
=
\left(
\begin{array}{lll}
a_{11} & a_{12} & a_{31} \\
a_{12} & a_{22} & a_{32} \\
a_{13} & a_{23} & a_{33}
\end{array}
\right)
$$

```python
A = np.array([[1,2],[3,4]])
B = np.array([[1,2],[3,4]])
print("Сложение матриц")
print(np.add(A,B))
print("Вычитание матриц")
print(np.subtract(A,B))
print("Произведение матриц")
print(np.dot(A,B))
print("Обратная матрица")
print(A.T)
```

    Сложение матриц
    [[2 4]
     [6 8]]
    Вычитание матриц
    [[0 0]
     [0 0]]
    Произведение матриц
    [[ 7 10]
     [15 22]]
    Обратная матрица
    [[1 3]
     [2 4]]

Матрица, обратная к матрице $A$, обозначается $A^{-1}$ и обладает следующим свойством: $A A^{-1} = E$, где $E$ - единичная матрица (элементы на главной диагонали равны 1, остальные элементы равны нулю). Вычисление обратной матрицы

```python
A = np.array([np.random.choice([0,1,2,3]) for _ in range(25)]).reshape(-1,5)
print(A)
invA = np.linalg.inv(A)
print(invA)
I = np.dot(A, invA)
print("I=")
for row in I:
    print("   ".join([str(round(i,2)) for i in row]))
```

    [[0 3 3 2 2]
     [0 1 0 2 1]
     [2 1 0 1 0]
     [1 1 2 3 1]
     [3 2 1 1 2]]
    [[-0.14893617 -0.21276596  0.14893617  0.12765957  0.19148936]
     [ 0.40425532  0.14893617  0.59574468 -0.4893617  -0.23404255]
     [ 0.12765957 -0.53191489 -0.12765957  0.31914894 -0.0212766 ]
     [-0.10638298  0.27659574  0.10638298  0.23404255 -0.14893617]
     [-0.19148936  0.29787234 -0.80851064  0.0212766   0.53191489]]
    I=
    1.0   0.0   0.0   0.0   0.0
    0.0   1.0   0.0   0.0   0.0
    -0.0   0.0   1.0   0.0   0.0
    0.0   0.0   0.0   1.0   0.0
    0.0   0.0   0.0   0.0   1.0

#### Ранг матрицы

Рангом матрицы называется порядок наибольшего минора матрицы, определитель которого отличен от нуля.

```python
A = np.array([[1,2,3],[0,2,1],[5,4,2]])
np.linalg.matrix_rank(A)
```

    3

#### Собственные векторы матрицы. Собственные числа.

Собственные векторы матрицы A это векторы, которые при применении линейного преобразования с помощью матрицы A изменяются только в масштабе, но не в направлении.
$$
A \vec{v} = \lambda \vec{v}
$$

```python
A = np.array([[1,2],[3,4]])
```

```python
np.linalg.eig(A)
```

    (array([-0.37228132,  5.37228132]), array([[-0.82456484, -0.41597356],
            [ 0.56576746, -0.90937671]]))

#### След матрицы

След матрицы это сумма элементов, стоящих на главной диагонали

```python
A = np.array(range(1,10)).reshape(-1,3)
print(A)
print(np.diagonal(A))
print(np.trace(A))
```

    [[1 2 3]
     [4 5 6]
     [7 8 9]]
    [1 5 9]
    15

#### Практические задачи с применением матриц.

Матрицы используются для линейных преобразований пространства. Например, если задан вектор, то его умножение на матрицу приведет к изменению этого вектора - растяжению, повороту относительно начала координат.

```python
plt.xlim(-1, 6)
plt.ylim(-1, 6)
M1 = np.array([1, 2]); M2 = np.array([3, 1])
A = np.array([[1,0],[0,2]])
M3 = M1.dot(A); M4 = M2.dot(A);
plt.plot([M1[0], M2[0]],[M1[1], M2[1]], c='r')
plt.annotate(u'', xy=(0, 0), xytext = M1, arrowprops = {'arrowstyle': '<|-', 'color': 'r'})
plt.annotate(u'', xy=(0, 0), xytext = M2, arrowprops = {'arrowstyle': '<|-', 'color': 'r'})
plt.plot([M3[0], M4[0]],[M3[1], M4[1]], c='g')
plt.annotate(u'', xy=(0, 0), xytext = M3, arrowprops = {'arrowstyle': '<|-', 'color': 'g'})
plt.annotate(u'', xy=(0, 0), xytext = M4, arrowprops = {'arrowstyle': '<|-', 'color': 'g'})
plt.grid(True)
plt.show()
```

```python
print(M1, M2, M3, M4)
print(A)
```

    [1 2] [3 1] [1 4] [3 2]
    [[1 0]
     [0 2]]

Матрицы используют для решения систем линейных алгебраических уравнений (матодом Крамера, методом обратной матрицы).

Например, решим систему линейных уравнений методом Крамера

$$
\left\{
\begin{array}{l}
x+2y=5,\\
3x+4y=6
\end{array}
\right.
$$

Эту систему уравнений можно представить в матричном виде

$$
A\vec{X}=\vec{B},
~~
A= \left(
\begin{array}{cc}
1 & 2 \\ 3 &4
\end{array}
\right),
~~
\vec{X}=\left( \begin{array}{c} x\\ y \end{array} \right),
~~
\vec{B}=\left( \begin{array}{c} 5\\ 6 \end{array} \right).
$$

```python
A = np.array([1,2,3,4]).reshape(2,2)
B = np.array([5,6])
D1 = np.linalg.det(np.array([5,2,6,4]).reshape(2,2))
D2 = np.linalg.det(np.array([1,5,3,6]).reshape(2,2))
D  = np.linalg.det(np.array([1,2,3,4]).reshape(2,2))
x = D1/D; y = D2/D
print("Корни уравнений: {} и {}".format(x,y))
```

    Корни уравнений: -4.0 и 4.5

Решим эту же систему методом обратной матрицы по формуле
$$
\vec{X} = A^{-1} \vec{B}.
$$

```python
X = np.linalg.inv(A).dot(B)
print(X)
```

    [-4.   4.5]

Назад к Оглавлению

# Математический анализ

Математический анализ изучает функции одной и нескольких переменных и их свойства, используя понятие непрерывности, которое определяется через последовательности. Для непрерывных функций вводится важнейший математический инструмент - производная. Также в математическом анализе изучаются интегралы, ряды.

## Функции

Основными объектами исследований в задачах математического анализа являются функции.

Простейшие функции - элементарные. Это - степенная функция $y=x^n$, показательная функция $y=a^x$ (важным частным случаем которой является экспоненциальная функция $y=e^x$, где $e$ - экспонента), тригонометрические функции, логарифмические функции.

```python
plt.rcParams['figure.figsize']=(15,10)
xs = np.linspace(-2, 2, 150)
titles = ["$y=x^2$", "$y=\sqrt{x}$", "$y=e^x$",
          "y=sin(x)", "y=cos(x)", "y=tan(x)",
          "y=ln(x)", "y=arcsin(x)", "y=sinh(x)"
         ]
functions = [xs**2, xs**(1/2), np.exp(xs), np.sin(xs), np.cos(xs), np.tan(xs), np.log(xs), np.arcsin(xs), np.sinh(xs)]
fig, ax = plt.subplots(3,3)
for pos in range(9):
    ax[pos%3][pos//3].plot(xs, functions[pos]); ax[pos%3][pos//3].set_title(titles[pos])
plt.show()
```

## Производные

Производной функции называется предел отношения приращения функции $\Delta f = f(x + \Delta x)-f(x)$  к приращению аргумента этой функции $\Delta x$ при $\Delta x \to 0$.

$$f'(x)=\frac{df}{dx}=\lim_{\Delta x \to \infty}\frac{f(x+\Delta x)-f(x)}{\Delta x}$$

Производная $f'(x)$ характеризует скорость изменения функции.

```python
plt.rcParams['figure.figsize']=(10,5)
fig, ax = plt.subplots(2)
ax[0].plot([x for x in range(-5,6)], [x**2 for x in range(-5,6)], color='b')
ax[1].plot([x for x in range(-5,6)], [2*x for x in range(-5,6)], color='r')
for i in [0,1]: ax[i].grid(True)
plt.show()
```

Видим на рисунке, что для тех $x$, для которых $f'(x)<0$, функция $f(x)$ убывает (причем, чем меньше $f'(x)$, тем быстрее убывает $f(x)$), а для $x$ при которых $f'(x)>0$, функция $f(x)$ возрастает (причем чем больше $f'(x)$, тем быстрее возрастает $f(x)$). В точке $x_*$ в которой $f'(x_*)=0$ находится экстремум - минимум функции $f(x)$.

Геометрический смысл производной - производная $y'(x_0)$ функции $y(x)$ в точке $x_0$ равна тангенсу угла графика наклона касательной прямой к функции $y(x)$ в точке $x_0$.

```python
xs = np.linspace(-2,2,10)
ys = xs**2
plt.plot(xs,ys)
plt.grid(True)
plt.scatter(2,4,c='r')
plt.plot([2,1],[4,0])
plt.show()
```

## Функции нескольких переменных

Функции нескольких переменных зависят от нескольких переменных. Например, функция $F(x,y,z)=x^2+y^2+z^2$ зависит от переменных $x$, $y$, $z$. По каждой из этих переменных можно взять производную, такие производные называются частными.

$$F(x,y)=x^3+y^3$$

```python
from sympy import *
x, y = symbols('x y')
r1 = diff(x**3 + y**3, x)
r2 = diff(x**3 + y**3, x)
print(type(r1))
print(r1,r2)
```

    <class 'sympy.core.mul.Mul'>
    3*x**2 3*x**2

Назад к Оглавлению

## Градиент. Градиентные методы

Вектор, составленный из частных производных функции $F(x,y$ называется градиентом. Важное свойство вектора градиента - он указывает в направлении наискорейшего возрастания функции.

$$\nabla F(x,y)=(F_x,F_y)$$

С использованием метода градииента работают методы поиска экстремума (максимума или минимума) функций нескольких переменных. Суть метода:
- выбирается начальная точка
- их этой точки делается шаг длины $h$ в направлении вектора градиента (если ищется максимум) или антиградиента (если ищется минимум)
- далее процедура повторяется из новой точки

```python
def grad_step(f, xp, yp, h):
    fx = (f(xp + h,yp  )   - f(xp,yp))/h
    fy = (f(xp  ,  yp + h) - f(xp,yp))/h
    L = math.sqrt(fx**2+fy**2)
    xn = xp - h*fx/L
    yn = yp - h*fy/L
    return xn, yn
```

Зададим функцию $y(x)=(x-1)^2+2(y-2)^2$. Это парабалоид оси которого направлены вверх. Очевидно он имеет минимум в точке $(x=1, y=2)$ равный $0$.

```python
def f(x,y):
    return (x-1)**2 + 2*(y-2)**2
```

```python
u, v = np.mgrid[-10:10, -1:10]
x = u
y = v
z = (u-1)**2+2*(v-2)**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(x, y, z)
#ax.scatter(1, 2, 0, c='r', s=100)
plt.show()
```

```python
s=[]
xt, yt = 5, 5
for _ in range(100):
    xt, yt = grad_step(f, xt, yt, 0.2)
    s.append((xt,yt))
plt.scatter([i[0] for i in s],[i[1] for i in s])
plt.grid(True)
plt.xticks(range(-1,10))
plt.show()
```

```python
s[-5:]
```

    [(0.8999999999999999, 1.758377005960798),
     (0.9, 1.958377005960798),
     (0.8999999999999999, 1.758377005960798),
     (0.9, 1.958377005960798),
     (0.8999999999999999, 1.758377005960798)]

Видим, что из за величины шага $h=1$ метод начал колебаться около искомой точки, не имея возможности к ней приблизиться. Попробуем взять более близкую к месту колебаний точку и уменьшить шаг.

```python
s=[]
xt, yt = -3, -4
for _ in range(100):
    xt, yt = grad_step(f, xt, yt, 0.2)
    s.append((xt,yt))
plt.scatter([i[0] for i in s], [i[1] for i in s])
plt.grid(True)
plt.show()
```

```python
s[-5:]
```

    [(0.9000000001520045, 1.7408429736519178),
     (0.9000000000564985, 1.9408429736519177),
     (0.8999999999181675, 1.7408429736519178),
     (0.8999999999695837, 1.9408429736519177),
     (0.900000000044055, 1.7408429736519178)]

Видимо, что с уменьшением шага ($h=0.01$) и выбором более близкого к искомому решению начального приближения ($x_0=1.1$ и $y_0=1$) удалось получить более точное решение с точностью $\epsilon=10^{-3}$.

```python
x = np.linspace(-5,5,100)
y = np.linspace(-5,5,100)
z = [[f(i,j) for i in x] for j in y]

plt.xticks([i for i in range(100) if not i%10]+[len(x)-1],
           [round(x[i]) for i in range(100) if not i%10]+[x[-1]],
           rotation=20)

plt.yticks([i for i in range(100) if not i%10]+[len(y)-1],
           [round(y[i]) for i in range(100) if not i%10]+[y[-1]],
           rotation=20)

plt.contour(z)
plt.grid(True)
plt.scatter([(i[0]+5)*10 for i in s], [(i[1]+5)*10 for i in s])

plt.show()
```

На контурном графике видно, что градиентный метод, начав из точки $(-3, -4)$ и двигаясь в направлении вектора антиградиента с постоянным шагом $h=0.2$, приближается к точке минимума $(-1,-2)$.

Назад к Оглавлению

## Стохастический градиентный спуск

Метод стохастического градиентного спуска отличается от рассмотренного пакетного градиентного спуска тем, что при вычислении шага выбирается одно произвольное направление (одна произвольно выбранная координата). На большщих данных это приводит к существенной экономии в ресурсах при вычислении.

```python
def stohastic_grad_step(f, xp, yp, h):
    i = np.random.choice([0,1])
    if i==0:
        f_step = (f(xp + h,yp  )   - f(xp,yp))/h
    else:
        f_step = (f(xp  ,  yp + h) - f(xp,yp))/h
    L = math.sqrt(f_step**2 + f_step**2)
    xn = xp - h*f_step/L
    yn = yp - h*f_step/L
    return xn, yn
```

Зададим функцию $y(x)=(x-1)^2+2(y-2)^2$. Это парабалоид оси которого направлены вверх. Очевидно он имеет минимум в точке $(x=1, y=2)$ равный $0$.

```python
def f(x,y):
    return (x-1)**2 + 2*(y-2)**2
```

```python
u, v = np.mgrid[-10:10, -1:10]
x = u
y = v
z = (u-1)**2 + 2*(v-2)**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(x, y, z)
ax.scatter(1, 2, 0, c='r', s=100)
plt.show()
```

```python
s=[]
xt, yt = -3, -4
for _ in range(300):
    xt, yt = stohastic_grad_step(f, xt, yt, 0.2)
    s.append((xt,yt))
plt.scatter([i[0] for i in s], [i[1] for i in s])
plt.grid(True)
plt.show()
```

```python
x = np.linspace(-5,5,100)
y = np.linspace(-5,5,100)
z = [[f(i,j) for i in x] for j in y]

plt.xticks([i for i in range(100) if not i%10]+[len(x)-1],
           [round(x[i]) for i in range(100) if not i%10]+[x[-1]],
           rotation=20)

plt.yticks([i for i in range(100) if not i%10]+[len(y)-1],
           [round(y[i]) for i in range(100) if not i%10]+[y[-1]],
           rotation=20)

plt.contour(z)
plt.grid(True)
plt.scatter([(i[0]+5)*10 for i in s], [(i[1]+5)*10 for i in s])

plt.show()
```

Назад к Оглавлению

```python
from matplotlib import animation, rc
from IPython.display import HTML, display_html

num = 10

# nice figure settings
fig, ax = plt.subplots()

y_true_value = np.array([[1]*num, [2]*num])

level_x = np.linspace(0, 2, num)
level_y = np.linspace(0, 3, num)

X, Y = np.meshgrid(level_x, level_y)
Z = (X - y_true_value[0])**2 + (Y - y_true_value[1])**2

ax.set_xlim(-0.02, 2)
ax.set_ylim(-0.02, 3)

ax.scatter(*y_true_value, c='red')

contour = ax.contour(X, Y, Z, 10)
ax.clabel(contour, inline=1, fontsize=10)

plt.show()
```

```python
xs = np.array([0])
ys = np.array([0])
trajectory = []

line, = ax.plot([], [], lw=2)

# start animation with empty trajectory
def init():
    line.set_data([], [])
    return (line,)

# one animation step (make one GD step)
def animate(i):
    xt = xs[-1] - 0.1*1
    yt = ys[-1] - 0.1*1
    np.append(xs, xt)
    np.append(ys, yt)
    trajectory.append([xt, yt])
    line.set_data(*zip(*trajectory))
    return (line,)

anim = animation.FuncAnimation(fig, animate, init_func=init,
                               frames=100, interval=20, blit=True)
```

```python
try:
    display_html(HTML(anim.to_html5_video()))
except (RuntimeError, KeyError):
    # In case the build-in renderers are unaviable, fall back to
    # a custom one, that doesn't require external libraries
    anim.save('test.gif', writer='pillow')
```

```python

```

Назад к Оглавлению

# Теория вероятности

## Определение вероятности

Упрощенно вероятность наступления какого-либо события задается с помощью фоотношения $P=\frac{m}{n}$, где $m$ - число благоприятных случаев, $n$ - общее число случаев. Например, вероятность выпадения четного числа при бросании игрального шестигранного кубика равна $P=\frac{3}{6}=\frac{1}{2}$, поскольку $m=3$ (выпадение 2, 4 или 6), а $n=6$. $P$ принимает значения от 0 до 1. Значение $1$ соответствует достоверному событию, $0$ - невозможному событию.

## Зависимые и независимые события. Условная вероятность.

Пусть $A$ и $B$ - события, $P(A)$ и $P(B)$ - вероятности этих событий. События $A$ и $B$ называются независимыми, если $P(AB)=P(A)P(B)$.

$P(A|B)$ - вероятность наступления события $A$ при условии наступления события $B$. Для зависимых событий $A$ и $B$ выполняется $P(AB)=P(A)P(B|A)$.

## Теорема Байеса

Пусть $H_i,~i\in [0,n]$ независимые события, составляющие полную группу событий (т.е. $\sum_{i=1}^{n}{H_i}=1$). Также $H_i$ называют гипотезами. Справедлива следующая формула Байеса
$$
P(H_i|A) = \frac{P(H_i) P (A|H_i)}{\sum_{i=1}^{n}{P(H_i) P (A|H_i)}}.
$$

```python

```

Например, пусть есть события: $S$ - сообщение является спамом, $R$ - сообщение содержит слово Rolex. Тогда условные вероятности:
- $P(S|R)$ - вероятность того, что сообщение является спамом в том случае, если оно содержит слово Rolex
- $P(R|S)$ - доля спам сообщений, содержащих слово Rolex

Формула Байеса для вычисления того, что сообщение является спамом в том случае, если содержит слово Rolex:

$$
P(S|R) = \frac{P(S) P(R|S)}{P(\overline{S}) P(R|\overline{S})+P(S) P(R|S)}
$$

```python

```

Назад к Оглавлению

## Случайные величины

Случайная величина принимает в результате определенное значение (заранее неизвестно какое). Примеры: в результате бросания игрального кубика возможно выпадение числа от 1 до 6, в результате выстрела по мишени возможно отклонение от центра мишени.

Различают дискретные и непрерывные случайные величины. Для дискретных случайных величин все возможные значения могут быть заранее перечислены (как в примере с бросанием кубика). Для непрерывных случайных величин заранее перечислить значения нельзя, они непрерывно заполняют некоторый промежуток (как в примере со стрельбой по мишени).

## Числовые характеристики случайных величин

- Математическое ожидание

Дискретная случайная величина: $M[X]=\sum_{i=1}^{n}{p_i x_i}$

Непрерывная случайная величина: $M[X]=\int_{-\infty}^{\infty}{xf(x) dx}$

- Дисперсия.

Дискретная случайная величина: $D[X]=\sum_{i=1}^{n}{p_i (x_i-M[X])^2}$

Непрерывная случайная величина: $M[X]=\int_{-\infty}^{\infty}{x(f(x)-M[X])^2 dx}$

- Ковариация двух случайных величин
$K_{xy} = M[(X-M[X])(Y-M[Y])]$

- Коррелция двух случайных величин
$r_{xy} = \frac{K_{xy}}{D[X]D[Y]}$

Для вычисления характеристик случайных величин в библиотеке numpy есть соответствующие функции.

```python
x = np.random.randn(1,10)
y = np.random.randn(1,10)
```

```python
print(x.mean())
print(np.var(x))
print(np.median(x))
print(x.std())
print(np.corrcoef(x,y))

```

    0.05050911370569235
    1.7270207966730493
    -0.2004098768967763
    1.3141616326285932
    [[1.         0.05765124]
     [0.05765124 1.        ]]

Назад к Оглавлению

# Математическая статистика

Задача математической статистики - описать случайную величину (ее основные свойства) по имеющимся выборкам значений. Эти выборки могут быть получены, например, в результате проведения эксперимента.

Описание наборов чисел. Сам по себе числовой ряд характеризует себя, для него можно вычислить основные характеристики - минимальное и максимальное значения, среднее арифметическое, моду (самое часто встречающееся значение), медиану (значение, которое разделяет числовой ряд пополам).

```python
m = np.array([np.random.randint(1,100) for _ in range(10)])
```

```python
print(m)
print(m.min())
print(m.max())
print(m.mean())
print(m.var())
print(m.std())
```

    [92 80 88 43 46 50 57 55 91 65]
    43
    92
    66.7
    336.40999999999997
    18.34148303709381

При большом размере выборки работать одновременно со всеми числами становится затруднительно, поэтому используют статистики (статистические показатели), при помощи которых передают существенные характеристики ряда.

```python
from collections import Counter
m = np.array([np.random.randint(1,10) for _ in range(1000)])
c = Counter(m)
plt.bar(c.keys(),c.values())
plt.show()
```

## Центральная предельная теорема

При бесконечном повторении опытов выборка независимо распределенных случайных величин (i.i.d.) сходится к нормальному закону распределения.

```python
def f_bernulli(n,p):
    result = 0
    for i in range(n):
        if np.random.random()<p:
            result += 1
    return result
```

```python
cols = 10
p = 0.5
n = 10

fig, ax = plt.subplots(1, cols, figsize=(20,3))

for i in range(cols):
    num = (i+1)*10
    probs = [f_bernulli(n,p) for _ in range(num)]

    c = Counter(probs)

    ax[i].bar(c.keys(), c.values())
    ax[i].set_xticks(list(c.keys()))

plt.show()
```

Назад к Оглавлению

## Уровни значимости, p-value

```python

```

```python

```

```python

```

Назад к Оглавлению

# Задачи

## Линейная алгебра

Назад к Оглавлению

## Математический анализ

Назад к Оглавлению

## Теория вероятности и математическая статистика

#### Задача  (условную вероятность)
Предположим, что в некоторой популяции до 60 лет доживает 50%, а до 80 лет — 20%. Какова вероятность (от 0 до 1), что случайно выбранный шестидесятилетний представитель популяции доживёт до восьмидесяти? Запишите ответ с точностью до одного знака после десятичной точки.

```python
0.2/0.5
```

    0.4

#### Задача (формула полной вероятности)

В супермаркете 60% яблок из Турции и 40% яблок из Индии. 10% турецких и 15% индийских яблок — червивые. Какова вероятность, что яблоко, купленное в этом магазине, окажется червивым? Запишите ответ от 0 до 1 с двумя знаками после десятичной точки.

```python
0.6*0.1+0.4*0.15
```

    0.12

#### Задача (формула полной вероятности)

Представьте, что вы купили яблоко в магазине из предыдущей задачи, и оно оказалось червивым. Какова вероятность того, что оно из Турции, а не из Индии?

```python
0.6*0.1/(0.6*0.1+0.4*0.15)
```

    0.5

#### Задача (формула Байеса)

1% женщин больны раком груди. У 80% женщин, больных раком груди, маммограмма верно выявляет наличие заболевания; кроме того, она даёт ложный положительный результат (то есть, неверно показывает наличие рака) для 9.6% здоровых женщин.

У какого процента женщин, маммограмма которых дала положительный результат, есть рак груди? Запишите ответ  с точностью до одного знака после десятичной точки (знак процента не нужен).

```python
0.01*0.8/(0.01*0.8+0.99*0.096)
```

    0.07763975155279504

#### Задача (условная вероятность)

Какова вероятность того, что при независимом подбрасывании двух симметричных шестигранных кубиков хотя бы на одном из них выпадет больше трёх очков? Запишите точный ответ в виде десятичной дроби.

```python
1/2+1/4
```

    0.75

```python
3**5 * np.exp(-3) / np.math.factorial(5)
```

    0.10081881344492448

Метеостанция, находящаяся в ботаническом саду Сиднея, регистрирует количество выпадающих осадков с 1885 года. Среднее годовое количество осадков за период с 1885 по 2015 включительно составляет 1197.69 мм, выборочная дисперсия — 116182.2.

Считая, что годовое количество осадков — случайная величина, не меняющаяся во времени и имеющая нормальное распределение, постройте интервал, который с вероятностью 99.7% будет содержать количество осадков, которые выпадут в 2016 году. Чему равна его верхняя граница? Округлите ответ до двух знаков после десятичной точки.

```python
m = 1197.69
d = 116182.2
np.sqrt(d)
```

    340.8551011793721

```python
m+3*np.sqrt(d)
```

    2220.2553035381166

Оцените значение параметра $\sigma_n$ — среднеквадратического отклонения нормального распределения, которым, согласно центральной предельной теореме, можно аппроксимировать распределение среднего количества осадков за год из предыдущей задачи. Округлите ответ до двух знаков после десятичной точки.

```python
n = 2015-1885+1
n
```

    131

```python
np.sqrt(d/n)
```

    29.780648463402596

Постройте приближённый 99.7% доверительный интервал для среднего количества осадков за год. Чему равен верхний доверительный предел? Округлите ответ до двух знаков после десятичной точки.

```python
m+3*np.sqrt(d/n)
```

    1287.0319453902077

Для продвижения вашего продукта рекламный отдел предлагает использовать новый видеоролик. На фокус-группе вы показываете 40 испытуемым новый и старый видеоролики и спрашиваете, какой из них им нравится больше; 62.5% испытуемых выбирают новый. Используя центральную предельную теорему и правило двух сигм, постройте 95% доверительный интервал для доли членов целевой аудитории, предпочитающих новый видеоролик. Выберите вывод, соответствующий построенному интервалу.

```python
40*0.625
```

    25.0

```python
25/40
```

    0.625

```python
np.sqrt(1/39*(25*(1-0.625)**2 + 15*(-0.625)**2))
```

    0.49029033784546006

Назад к Оглавлению

# Список литературы

1. Фихтенгольц Г.М.	Основы математического анализа, Том 1-3	Москва, 1968
2. Вентцель Е.С. Теория вероятностей 4-е изд., стереотип. - М.: Наука, Физматгиз, 1969 - 576 с.
3. Курош А.Г. Курс высшей алгебры Москва: Издательство «Наука», 1966

Назад к Оглавлению


# Linear Shell solution

## Init symbols for *sympy*

```python
from sympy import *
from geom_util import *
from sympy.vector import CoordSys3D
import matplotlib.pyplot as plt
import sys
sys.path.append("../")

%matplotlib inline

%reload_ext autoreload
%autoreload 2
%aimport geom_util
```

```python
# Any tweaks that normally go in .matplotlibrc, etc., should explicitly go here
%config InlineBackend.figure_format='retina'
plt.rcParams['figure.figsize'] = (12, 12)

plt.rc('text', usetex=True)

plt.rc('font', family='serif')

init_printing()
```

```python
N = CoordSys3D('N')
alpha1, alpha2, alpha3 = symbols("alpha_1 alpha_2 alpha_3", real = True, positive=True)
A,K,rho = symbols("A K rho")
```

### Tymoshenko theory

$u_1 \left( \alpha_1, \alpha_2, \alpha_3 \right)=u\left( \alpha_1 \right)+\alpha_3\gamma \left( \alpha_1 \right) $

$u_2 \left( \alpha_1, \alpha_2, \alpha_3 \right)=0 $

$u_3 \left( \alpha_1, \alpha_2, \alpha_3 \right)=w\left( \alpha_1 \right) $

$ \left(
\begin{array}{c}
u_1 \\
\frac { \partial u_1 } { \partial \alpha_1} \\
\frac { \partial u_1 } { \partial \alpha_2} \\
\frac { \partial u_1 } { \partial \alpha_3} \\
u_2 \\
\frac { \partial u_2 } { \partial \alpha_1} \\
\frac { \partial u_2 } { \partial \alpha_2} \\
\frac { \partial u_2 } { \partial \alpha_3} \\
u_3 \\
\frac { \partial u_3 } { \partial \alpha_1} \\
\frac { \partial u_3 } { \partial \alpha_2} \\
\frac { \partial u_3 } { \partial \alpha_3} \\
\end{array}
\right) = T \cdot
\left(
\begin{array}{c}
u \\
\frac { \partial u } { \partial \alpha_1} \\
\gamma \\
\frac { \partial \gamma } { \partial \alpha_1} \\
w \\
\frac { \partial w } { \partial \alpha_1} \\
\end{array}
\right) $

```python
T=zeros(12,6)
T[0,0]=1
T[0,2]=alpha3
T[1,1]=1
T[1,3]=alpha3
T[3,2]=1

T[8,4]=1
T[9,5]=1
T
```

```python
B=Matrix([[0, 1/(A*(K*alpha3 + 1)), 0, 0, 0, 0, 0, 0, K/(K*alpha3 + 1), 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1/(A*(K*alpha3 + 1)), 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [-K/(K*alpha3 + 1), 0, 0, 0, 0, 0, 0, 0, 0, 1/(A*(K*alpha3 + 1)), 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]])
B
```

```python
E=zeros(6,9)
E[0,0]=1
E[1,4]=1
E[2,8]=1
E[3,1]=1
E[3,3]=1
E[4,2]=1
E[4,6]=1
E[5,5]=1
E[5,7]=1
E
```

```python
simplify(E*B*T)
```

```python
mu = Symbol('mu')
la = Symbol('lambda')
C_tensor = getIsotropicStiffnessTensor(mu, la)
C = convertStiffnessTensorToMatrix(C_tensor)
C
```

```python
S=T.T*B.T*E.T*C*E*B*T*A*(1+alpha3*K)
S=simplify(S)
S
```

```python
h=Symbol('h')
S_in = integrate(S,(alpha3, -h/2, h/2))
S_in
```

```python
E,nu=symbols('E nu')
lambda_elastic=E*nu/((1+nu)*(1-2*nu))
mu_elastic=E/(2*(1+nu))
S_ins=simplify(S_in.subs(A,1).subs(la,lambda_elastic).subs(mu,mu_elastic))
S_ins
```

```python

a11=E/(1-nu**2)
a44=5*E/(12*(1+nu))

AM=Matrix([[a11,0],[0,a44]])
strainT=Matrix([[1,alpha3,0],[0,0,1]])
AT=strainT.T*AM*strainT
integrate(AT,(alpha3, -h/2, h/2))
```

```python
M=Matrix([[rho, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, rho, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, rho, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
M=T.T*M*T*A*(1+alpha3*K)
M
```

```python
M_in = integrate(M,(alpha3, -h/2, h/2))
M_in
```

## Cartesian coordinates

```python
import fem.geometry as g
import fem.model as m
import fem.material as mat
import fem.shell.shellsolver as s
import fem.shell.mesh1D as me
import plot

stiffness_matrix_func = lambdify([A, K, mu, la, h], S_in, "numpy")
mass_matrix_func = lambdify([A, K, rho, h], M_in, "numpy")

def stiffness_matrix(material, geometry, x1, x2, x3):
    A,K = geometry.get_A_and_K(x1,x2,x3)
    return stiffness_matrix_func(A, K, material.mu(), material.lam(), thickness)

def mass_matrix(material, geometry, x1, x2, x3):
    A,K = geometry.get_A_and_K(x1,x2,x3)
    return mass_matrix_func(A, K, material.rho, thickness)

def generate_layers(thickness, layers_count, material):
    layer_top = thickness / 2
    layer_thickness = thickness / layers_count
    layers = set()
    for i in range(layers_count):
        layer = m.Layer(layer_top - layer_thickness, layer_top, material, i)
        layers.add(layer)
        layer_top -= layer_thickness
    return layers

def solve(geometry, thickness, linear, N_width):
    layers_count = 1
    layers = generate_layers(thickness, layers_count, mat.IsotropicMaterial.steel())
    model = m.Model(geometry, layers, m.Model.FIXED_BOTTOM_LEFT_RIGHT_POINTS)
    mesh = me.Mesh1D.generate(width, layers, N_width, m.Model.FIXED_BOTTOM_LEFT_RIGHT_POINTS)
    lam, vec = s.solve(model, mesh, stiffness_matrix, mass_matrix)

    return lam, vec, mesh, geometry

width = 2
curvature = 0.8
thickness = 0.05

corrugation_amplitude = 0.05
corrugation_frequency = 20

geometry = g.General(width, curvature, corrugation_amplitude, corrugation_frequency)

N_width = 600

lam, vec, mesh, geometry = solve(geometry, thickness, False, N_width)
results = s.convert_to_results(lam, vec, mesh, geometry)

results_index = 0

plot.plot_init_and_deformed_geometry_in_cartesian(results[results_index], 0, width, -thickness / 2, thickness / 2, 0, geometry.to_cartesian_coordinates)
to_print = 20
if (len(results) < to_print):
    to_print = len(results)

for i in range(to_print):
    print(results[i].rad_per_sec_to_Hz(results[i].freq))

```