[Pythonによる科学・技術計算]行列のノルム・条件数の定義のまとめ，数値線形代数


#はじめに

数値線形代数では行列の性質を表す一つの量である「**ノルム**」という用語が出てきます。**これを学ぶことは行列の固有値問題や線形方程式に関する性質を理解するうえで有益です。**

行列のノルムは，ざっくりいえば高校数学で学ぶ「ベクトル」のノルムを拡張したものです。
行列のノルムの定義にはいくつかの種類があります。本稿ではそれらを簡単にまとめます。また，行列のノルムを用いて，固有値問題や連立1次方程式の解の性質を議論するうえで有益となる「**条件数**」という量についても触れます。

これらの定義は初学者にとってはなんだかよくわからないものです。
そこで，定義を理解するために具体例も載せています。
**ノルムはpythonのnumpy.linalg.normメソッドを用いて計算可能です。条件数もnumpy.linalg.condメソッドで計算可能です。
これらのメソッドを用いたpythonによる計算結果も併記します。**


##どんな人向け？
● 数値線形代数の勉強がしたい方
● 行列の連立一次方程式を学ぶ予定の方
***

#内容
まずベクトルのノルムについてまとめます。次いで行列のノルムの定義を示します。最後に，行列のノルムを用いて「条件数」という量を導入します。

***

# (1) ベクトルのノルム

ベクトル$x$のノルム$||x||$としてよく用いられるものは

```math
||x||_p=(\sum_{i=1}^{n}|x_i|^p)^{1/p}
```

という量です。これは「**$p$-ノルム**」と呼ばれます。

##(1-1) p = 1のとき

```math
||x||_1=\sum_{i=1}^{n}|x_i|
```

この量を「**絶対和ノルム**」といいます。

例A-1: $x=(1,-2,4)$のとき，絶対和ノルムは，$||x||_1=(1+|-2|+4)=7$となります。Pythonでも試してみましょう。

```py3
import numpy as np
from numpy import linalg as LA

x=np.array([1,-2,4])
LA.norm(x,1) # ベクトル: 1-ノルム
```

==>7.0

手計算の結果と一致しています。


##(1-2) p = 2のとき
```math
||x||_2=\sqrt{\sum_{i=1}^{n}|x_i|^2}=\sqrt{x^Tx}
```

この量は「**ユークリッドノルム**」または「**2-ノルム**」と呼ばれます。ベクトルの大きさや距離を表すものとしてよく知られています。
ここで$x^T$はベクトル$x$の転置です。

例1-2: $x=(1,-2,4)$のとき，ユークリッドノルムは，$||x||_2=\sqrt{1+4+16}=4.58257...$となります。

Pythonで実行します。


```py3
import numpy as np
from numpy import linalg as LA

x=np.array([1,-2,4])
LA.norm(x,2) # ベクトル: 2-ノルム
```

==> 4.5825756949558398

手計算の結果と一致しています。



##(1-3) p = ∞のとき
```math
||x||_∞ = \max_{1\leq i \leq n}|x_i|
```

と定義され「**最大値ノルム**」または「**∞-ノルム**」と呼ばれます。$n$はベクトル$x$の成分の数です。

例1-3: $x=(1,-2,4)$のとき，最大値ノルムは，$||x||_∞ = \max_{i} |x_i|=4 $となります。


Pythonで実行します。


```py3
import numpy as np
from numpy import linalg as LA

x=np.array([1,-2,4])
LA.norm(x,np.inf) # ベクトル: ∞-ノルム

```

==> 4

手計算の結果と一致しています。


***

# (2) 行列のノルム

行列$A=(a_{ij})$のノルムは，任意のベクトル$x(\ne 0)$に対して

```math
||A||= \max_{x \ne 0} \frac{||Ax||}{||x||}
```

と表します。「**作用素ノルム**」とも呼ばれます。よく用いられる定義は，ベクトルノルムの場合と同様に

```math
||A||_p= \max_{x \ne 0} \frac{||Ax||_p}{||x||_p}
```

です。

**あらゆる$x (\ne 0)$ に対する右辺の$\frac{||Ax||_p}{||x||_p}$を計算したときに最大となる値が$||A||$です。**

#(2-0) 行列ノルムの性質

●すべての$A$とスカラー$α$に対して
$||α A||=α||A||$

● すべての$A$,$B$に対して，
$||A+B|| \le ||A||+||B||$

● すべての$A$,$B$に対して，
$||AB|| \le ||A|| \, ||B||$


##(2-1) p = 1のとき
```math
||A||_1= \max_{x \ne 0} \frac{||Ax||_1}{||x||_1}=\max_{1\le i \le n} \sum_{i=1}^{n}|a_{ij}|
```

となります。行列$A$の各列の成分の絶対和のうち最大のものとなります(**最大列和**)。


例2-1




```math
A =
\begin{pmatrix}
 1 & 2 & 3 \\
 -2 & 3 & -1 \\
 -3 & -1 & 5 \\
\end{pmatrix}
```

$||A||_1$を求めます。

第一列の要素の絶対値の和は

$1+|-2|+|-3|$=6

となります。同様に第二列，第三列の要素の絶対値の和はそれぞれ

$2+3+|-1|$=6，
$3+|-1|+5=9$

となります。

よって最大列和は第三列のものとなり，||A||_1=9$$となります。


Pythonで計算してみましょう。

```py3
import numpy as np
from numpy import linalg as LA

A=np.array([[1,2,3],[-2,3,-1],[-3,-1,5]])

LA.norm(A,1) # 行列 1-ノルム
```

==> 9

手計算の結果と一致しています。



##(2-2) p = 2のとき

```math
||A||_2= \max_{x \ne 0} \frac{||Ax||_2}{||x||_2}= \sqrt{\max_{x \ne 0} \frac{x^TA^TAx}{x^Tx})}
```

これを「**スペクトルノルム**」といいます。

$||A||_2$は$A^TA$の固有値の最大のものの平方根になることが知られています。



例2-2

```math
A =
\begin{pmatrix}
 1 & 2 & 3 \\
 -2 & 3 & -1 \\
 -3 & -1 & 5 \\
\end{pmatrix}
```


ここでは手計算は行わずPythonでの計算結果だけを示します。

```py3
import numpy as np
from numpy import linalg as LA

A=np.array([[1,2,3],[-2,3,-1],[-3,-1,5]])

LA.norm(A,2) # 行列 2-ノルム
```

==> 6.2520639091784211




##(2-3) p = ∞のとき

```math
||A||_∞= \max_{x \ne 0} \frac{||Ax||_∞}{||x||_∞}=\max_{1\le i \le n} \sum_{j=1}^{n}|a_{ij}|
```

となります。行列の行の成分の絶対和のうち最大のものになります(**最大行和**)。


例2-3

```math
A =
\begin{pmatrix}
 1 & 2 & 3 \\
 -2 & 3 & -1 \\
 -3 & -1 & 5 \\
\end{pmatrix}
```

このとき$||A||_∞$を求めます。

第一行の要素の絶対値の和は

$1+2+3$=6

となります。同様に第二行，第三行の要素の絶対値の和はそれぞれ

$|-2|+3+|-1|$=6，
$|-3|+|-1|+5=9$

となります。
これらの中で最大のものは第三行ですので，$||A||_∞=9$となります。





Pythonで計算してみましょう。

```py3
import numpy as np
from numpy import linalg as LA

A=np.array([[1,2,3],[-2,3,-1],[-3,-1,5]])

LA.norm(A,np.inf) # 行列 ∞-ノルム
```

==> 9

手計算の結果と一致しています。




##(2-4) 行列のスペクトル半径

固有値を$\lambda$，固有ベクトルを$x$とする固有方程式 $Ax=\lambda x$の両辺のノルムをとると，(2-0)から
$$||A|| \,||x||\ge||Ax||=||\lambda x||=|\lambda|\, ||x||$$
より，
$$||A||\ge |\lambda|$$
となります。

$∞$-ノルムを使うと，

```math
||A||_∞ = \max_{1 \le i \le n} \sum_{j=1}^{n}|a_{ij}| \ge \rho = \max_{k}|\lambda_k|
```
となります。

ここで$\rho$は行列Aの固有値の絶対値の中で最大の値で行列Aの「**スペクトル半径**」
と呼ばれており，**連立1次方程式の反復法による数値解法の収束性と密接に関係しています。**



##(2-5) その他，フロベニウスノルム

**フロベニウスノルム**$||A_F||$と呼ばれるノルムは以下の式で定義されます。

```math
||A||_F= \sqrt{\sum_{i=1}^{n} \sum_{j=1}^{n}a_{ij}^2}
```
これと$||A_2||$との間には

```math
\frac{1}{\sqrt{n}}||A||_F \le ||A||_2 \le ||A||_F
```
という大小関係があります。


例2-5

```math
A =
\begin{pmatrix}
 1 & 2 & 3 \\
 -2 & 3 & -1 \\
 -3 & -1 & 5 \\
\end{pmatrix}
```

のフロベニウスノルム$||A||_F$を求めます。


$||A||_F= \sqrt{1^2+2^2+3^2+(-2)^2+3^2+(-1)^2+(-3)^2+(-1)^2+5^2}=7.937253933193772..$





Pythonで計算してみましょう。**linalg.norm**の引数に"fro"をあたえます。

```py3
import numpy as np
from numpy import linalg as LA

A=np.array([[1,2,3],[-2,3,-1],[-3,-1,5]])

LA.norm(A,"fro") # 行列のフロベニウスノルム
```

==> 7.9372539331937721...

手計算の結果と一致しています。



# (3) 条件数

行列のノルムを用いて**条件数(condition number) cond(A)**が次のように定義されます。

$$cond(A)=||A|| \, ||A^-1||$$

cond(A)は$A$とその逆行列$||A||^-1$のそれぞれのノルムの積です。

行列ノルムに何を用いるのか明示する場合は

$$cond_p(A)=||A||_p \,||A^-1||_p$$
とします。$p=1,2,∞$がよく用いられます。


条件数は，

$$cond(A) \ge1$$

を満たします。
なぜなら$AA^-1=I$($I$は単位行列)より$||A||\,||A^-1|| \ge ||I|||$となりますが，単位行列$I$のノルムは1となるからです。

なお，$p=2$の場合，$cond_2(A)$は$A^TA$の最大固有値と最小固有値の比の平方根となります。


例3

```math
A =
\begin{pmatrix}
 1 & 2 & 3 \\
 -2 & 3 & -1 \\
 -3 & -1 & 5 \\
\end{pmatrix}
```

の条件数$cond_1(A)$をpythonで計算してみます。


```py3
import numpy as np
from numpy import linalg as LA

A=np.array([[1,2,3],[-2,3,-1],[-3,-1,5]])

LA.cond(A, 1) # 1-ノルムを用いた条件数
```

==> 4.684931506849316...





***

# 補遺: 条件数と連立一次方程式の誤差

**条件数は連立一次方程式 
$$Ax = b$$の係数行列$A$または右辺のベクトル$b$が少し変化したときに解ベクトル$x$がどのくらい変わるのかについての指標を与えてくれます。**以下でそれをみてみましょう。


連立1次方程式$Ax=b$において $A$が$\delta A$だけ変化したとき$x$が$\delta x$だけ変化したとすると，

```math
(A+\delta A)(x+\delta x)=b \\

\delta x = A^-1 \delta A (x+\delta x)\\

||\delta x|| \le ||A^-1|| \,||\delta A||\, ||x+\delta x||
```



となりますので，

```math
\frac{||x||}{||x+\delta x||} \le ||A|| \,||A^-1|| \frac{||\delta A||}{||A||} \\

=\frac{||x||}{||x+\delta x||} \le cond(A) \frac{||\delta A||}{||A||}
```


となります。
同様に$b$が$\delta b$だけ変化したときは

$$\frac{||\delta x||}{||x||} \le cond(A) \frac{||\delta b||}{||b||}$$
となることが示されます。

以上から，$x$の変化が$A$や$b$の変化のcond(A)倍され得ることを示しています。

条件数が小さく，1に近いときは$x$の相対変化は$A$や$b$の相対変化とほぼ等しくなります。しかし条件数が大きいと$A$や$b$の相対変化が小さくても$x$の相対は大きくなる可能性があります。このような事情を反映して，条件数が大きいときを「悪条件の問題(ill-conditioned)」，小さい時を「良条件の問題(well-conditioned)」といいます。このように，**行列の条件数を知ることによって連立方程式の数値誤差を評価することができます。**





#参考文献

[1] 川上一郎，[『数値計算 』](https://www.amazon.co.jp/%E6%95%B0%E5%80%A4%E8%A8%88%E7%AE%97-%E7%90%86%E5%B7%A5%E7%B3%BB%E3%81%AE%E6%95%B0%E5%AD%A6%E5%85%A5%E9%96%80%E3%82%B3%E3%83%BC%E3%82%B9-8-%E5%B7%9D%E4%B8%8A-%E4%B8%80%E9%83%8E/dp/4000077783),岩波書店,1989.

[2] 名取亮，[線形計算](https://www.amazon.co.jp/%E7%B7%9A%E5%BD%A2%E8%A8%88%E7%AE%97-%E3%81%99%E3%81%86%E3%81%8C%E3%81%8F%E3%81%B6%E3%81%A3%E3%81%8F%E3%81%99-%E5%90%8D%E5%8F%96-%E4%BA%AE/dp/4254114729), 朝倉書店，1993. 
[3] Qiita記事， [[Pythonによる科学・技術計算] 数値線形代数でヒンパンに出てくる行列の一覧](https://qiita.com/sci_Haru/items/7f7f8fc67d918388141a)


[4] [numpy.linalg.normのオンラインドキュメント](https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.linalg.norm.html)

[5] [numpy.linalg.normのオンラインドキュメント](https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.linalg.norm.html)