Pythonによる線形代数に関する計算

Numpyを利用した線形代数に関するさまざまな演算の実現方法を備忘録として以下に示す.

注意事項：
・この記事において $j$ は虚数を表す.
・numpyのimport文は省略して表記する.

### ベクトルの生成
```math
\vec{a}=(1,2,3)
```

```python:test.py
a = np.array([1,2,3])
```
### 行列の生成
```math
A=\left(
\begin{array}{ccc}
1+j & 2+2j & 3+3j\\
4+4j & 5+5j & 6+6j
\end{array}
\right)
```

```python:test.py
A = np.array([[1+1j,2+2j,3+3j],
              [4+4j,5+5j,6+6j]])
```

括弧に注意！

### 転置
```math
A^T=\left(
\begin{array}{cc}
1+j & 4+j \\
2+j & 5+j \\
3+j & 6+j
\end{array}
\right)
```

```python:test.py
# 前述の行列Aに対して
A_transpose = A.T
```

### 複素共役転置
```math
A^H=\left(
\begin{array}{cc}
1-j & 4-j \\
2-j & 5-j \\
3-j & 6-j
\end{array}
\right)
```

```python:test.py
# 前述の行列Aに対して
A_hermitian = np.conjugate(A.T)
```

### 行列の足し算
```math
A+A=\left(
\begin{array}{ccc}
1+j & 2+2j & 3+3j\\
4+4j & 5+5j & 6+6j
\end{array}
\right)+\left(
\begin{array}{ccc}
1+j & 2+2j & 3+3j\\
4+4j & 5+5j & 6+6j
\end{array}
\right)=\left(
\begin{array}{ccc}
2+2j & 4+4j & 6+6j\\
8+8j & 10+10j & 12+12j
\end{array}
\right)
```

```python:test.py
# 前述の行列Aに対して
A_plus = A + A
```
引き算も同様である.

### 行列の定数倍
```math
2A=2\left(
\begin{array}{ccc}
1+j & 2+2j & 3+3j\\
4+4j & 5+5j & 6+6j
\end{array}
\right)=\left(
\begin{array}{ccc}
2+2j & 4+4j & 6+6j\\
8+8j & 10+10j & 12+12j
\end{array}
\right)
```

```python:test.py
A_double = 2*A
```

### 行列の積 (ベクトルの場合は内積)
```math
AA^T=\left(
\begin{array}{ccc}
1+j & 2+2j & 3+3j\\
4+4j & 5+5j & 6+6j
\end{array}
\right)\left(
\begin{array}{cc}
1+j & 4+j \\
2+j & 5+j \\
3+j & 6+j
\end{array}
\right)=\left(
\begin{array}{cc}
0+28j & 0+64j \\
0+64j & 0+154j 
\end{array}
\right)
```

```python:test.py
# 前述の行列Aに対して
A_dot = np.dot(A, A.T)
```
ベクトルの内積もこの方法で算出できる.

### アダマール積 (要素ごとの積)
```math
A\circ A=\left(
\begin{array}{ccc}
1+j & 2+2j & 3+3j\\
4+4j & 5+5j & 6+6j
\end{array}
\right)\left(
\begin{array}{ccc}
1+j & 2+2j & 3+3j\\
4+4j & 5+5j & 6+6j
\end{array}
\right)=\left(
\begin{array}{ccc}
0+2j & 0+8j & 0+18j\\
0+32j & 0+50j & 0+72j
\end{array}
\right)
```

```python:test.py
# 前述の行列Aに対して
A_hadamard = A * A
```

### 逆行列の生成
```math
P=\left(
\begin{array}{cc}
1+j & 2+2j\\
3+3j & 4+4j 
\end{array}
\right)\text{に対し}P^{-1}=\left(
\begin{array}{cc}
-1+j & 0.5-0.5j\\
0.75-0.75j & -0.25+0.25j 
\end{array}
\right)
```

```python:test.py
P = np.array([[1+1j,2+2j],[3+3j,4+4j]])
P_inverse = np.linalg.inv(P)
```
ここでPとP_inverseの積を求めると確かに単位行列になる.

### 行列式
```math
\det{P}=\left|
\begin{array}{ccc}
1+j & 2+2j\\
3+3j & 4+4j
\end{array}
\right|=-4j
```

```python:test.py
# 前述の行列Pに対して
P_det = np.linalg.det(P)
```

### 固有値と固有ベクトル
$P\vec{x}=\lambda \vec{x}$ を満たすとき, $\lambda$ を $P$ の固有値, $\vec{x}$ を $P$ の固有値$\lambda$に対する固有ベクトルという.
ただし $\vec{x}$ は零ベクトル以外である.
行列 $P$ に対する固有値と固有ベクトルは次の通り.

```math
\lambda=-0.37-0.37j\text{ のとき, }\vec{x}=(0.82,-0.57) \\
\lambda=-5.37+5.37j\text{ のとき, }\vec{x}=(0.42,0.91)
```

```python:test.py
# 前述の行列Pに対して
eig_val, eig_vec = np.linalg.eig(P)
```
np.dot(P,eig_vec)と, eig_val*P を比較すると同じになっているであることが分かる.

### 行列の要素を取り出す方法
次の行列を考える.

```math
X=\left(
\begin{array}{cc}
1 & 2 \\
3 & 4
\end{array}
\right)
```

```python:test.py
X = np.array([[1,2],[3,4]]) # 行列 X の生成
a = X[0,0] # 1 が代入される
b = X[0,1] # 2 が代入される
c = X[1,0] # 3 が代入される
d = X[1,1] # 4 が代入される
e = X[:,0] # ベクトル array([1,3]) が代入される
f = X[:,1] # ベクトル array([2,4]) が代入される
g = X[0,:] # ベクトル array([1,2]) が代入される
h = X[1,:] # ベクトル array([3,4]) が代入される
i = X[:,:] # 行列 X がそのまま代入される
```
X[0]とかX[:]とかもあるが, 行か列か明示したほうがよい.

### ゼロ化
```math
Y=\left(
\begin{array}{ccc}
0 + 0j& 0+0j & 0+0j\\
0+0j & 0+0j & 0+0j
\end{array}
\right)
```

```python:test.py
Y = np.zeros((2,3), dtype = complex)
```
実数のみを扱う場合は省略してよい. 整数の場合は dtype = int にする.

### 単位行列
```math
I=\left(
\begin{array}{ccc}
1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1
\end{array}
\right)
```

```python:test.py
I = np.eye(3)
```
np.eye(2,3) といったような正方行列でないものも可能.

### 行列の結合
```math
U=\left(
\begin{array}{cc}
1 & 2 \\ 
3 & 4 
\end{array}
\right), V=\left(
\begin{array}{cc}
5 & 6 \\ 
7 & 8 
\end{array}
\right)\text{ のとき }\\
[U|V]=\left(
\begin{array}{cccc}
1 & 2 & 5 & 6 \\ 
3 & 4 & 7 & 8
\end{array}
\right),
```

```python:test.py
yoko = np.concatenate((U,V), axis=1)
```
縦に結合する場合は axis=0 とすればよい.