線性代數

tags: Numerical Methods

對於數值分析領域的研究者來說,線性代數是一個非常好的工具。它不僅可以協助我們將繁雜的數學式進行化簡(例如方程組轉換成矩陣的形式,並利用 Cramer's Rule 求解),同時也能夠利用線性代數的各種性質推廣數值分析上重要的內涵。

Symbolics套件與變數設定

在安裝完套件後,我們可以先對符號進行定義,也就是將其令為變數(variables)

using Symbolics
@variables a b c d e f g h i j k l m n;

不過,為什麼要進行上面的步驟呢?我們來做個實驗,如果在 kernel 上面打上 p 會出現什麼呢?

UndefVarError: p not defined

Stacktrace:
 [1] top-level scope
   @ :0
 [2] eval
   @ .\boot.jl:373 [inlined]
 [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
   @ Base .\loading.jl:1196

很明顯的,因為我們還未定義 p 在這個程式裡面的意義,因此

Julia 不會知道這個 p 是一個變數。設定完成之後,我們可以隨意打上我們剛剛設定的那些符號,它就會顯示為數學符號(也就是
LATEX
)的形式了。

a

它就會跑出

a

向量(vector)

給定兩個欄向量(column vector)

M1
N1

a = [m₁; m₂; m₃]
b = [n₁; n₂; n₃]
a |> display
b |> display

a=[m1m2m3],b=[n1n2n3]

內積(inner product)

若將兩向量進行內積,就會得到一個純量,即

a' * b |> display

ab=[m1m2m3][n1n2n3]=m1n1+m2n2+m3n3

上述的結果也可以透過逐元的方式計算:

sum(m1 .* n1) |> display

正交(orthogonal)

如果說兩個向量的內積為

0,則我們說這兩個向量相互垂直(orthogonal),或稱為正交的。

u = [3; 2; 1]
v = [-2; 3; 0]
u'v |> display

## 0

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

範數(norm)

而向量的範數是一個計算向量長度的方式,其計算方式為

m=MM

m1_norm = sqrt(m1' * m1)

會得到

m12+m22+m32

若其長度為

1,則我們稱該向量為標準化向量。

m1_normalized = m1 ./ m1_norm
m1_normalized_norm = sqrt(m1_normalized' * m1_normalized)

m1_normalized |> display
m1_normalized_norm |> display

會得到標準化過後的向量為

[m1m12+m22+m32m2m12+m22+m32m3m12+m22+m32]

其長度為

m12(m12+m22+m32)2+m22(m12+m22+m32)2+m32(m12+m22+m32)2

經過化簡可得其長度為

1

simplify.(expand.(m1_normalized_norm))

m12+m22+m32(m12+m22+m32)2=1

而在計量經濟學中,我們最常使用的性質是標準正交(orthonormal):若兩個向量相互垂直且均經過標準化,則稱這兩個向量具有標準正交的性質。

外積(outer product)

若將兩向量進行外積,就會得到一個張量(tensor),即

a * b' |> display

a×b=[m1m2m3][n1n2n3]=[m1n1m1n2m1n3m2n1m2n2m2n3m3n1m3n2m3n3]

矩陣(matrix)

根據維基百科的定義,數學上,一個

m×n的矩陣是一個由
m
列(row)
n
行(column)元素排列成的矩形陣列,如果用英文表達,就是一個
m
by
n
的矩陣。矩陣裡的元素可以是數字、符號或數學式。[1]我們來看看下面的例子:

## 2 x 2 的矩陣
A = [a b; c d]

## 2 x 3 的矩陣
B = [a b c
     d e f]

## 3 x 2 的矩陣
C = [a b; c d; e f]

A |> display
B |> display
C |> display

它便會顯示

[abcd][abcdef][abcdef]

矩陣的符號表示

我們會以大寫(或粗體)的字母表示矩陣,例如

A;利用小寫的字母代表矩陣內的元素,例如
a
。注意到,在矩陣中為了清楚定義是哪一個元素,我們會利用以下的方式進行註記。
Ai,j

其中下標(subscript)

i 代表行,
j
代表列。如果我們要找到上面設定的矩陣
B
中第二列第三個元素,也就是
f
,要怎麼輸入呢?

@show B[2, 3]

顯示

f

矩陣的四則運算

如果我們要將兩個矩陣進行相加,我們可寫成:

[a b
c d] + [e f
        g h]

其計算結果很直觀地可以猜想到是

[a+eb+fc+gd+h]

而有趣地是,在

Julia 中,我們可以將兩個不同維度(dimension)的矩陣進行相加總,不過必須利用**逐元(element-wise)**的方式進行運算。[2]例如

[a b
c d] .+ [e
        g]

結果會是

[a+eb+ec+gd+g]

接著我們來看一下乘積。首先定義兩個矩陣,

A1
A2

A1 = [a b; c d]
A2 = [e f; g h]

如果我們要計算兩個矩陣相乘,即

A1A2;或是在矩陣前方乘上一個純量(scalar),也就是
cA1
,我們可以這麼做:

A12 = A1 * A2 # 兩個矩陣相乘
A3 = 3 * A1 # 純量乘上矩陣

結果就是

A1A2=[ae+bgaf+bhce+dgcf+dh]3A1=[3a3b3c3d]

同樣地,我們也可以運用

Julia 中逐元的性質對矩陣進行乘積。例如

A3 = A1 .* A2 # 進行逐元乘積

A3 會等於
[aebfcgdh]

注意到,如果我們對

A1
A2
的乘積進行交換,其結果在數學上與在
Julia
上均是不成立的,這部分就留給讀者自行證明。

A21 = A2 * A1

會得到

A2A1=[ae+cfbe+dfag+chbg+dh]

值得一提的是,給定兩個矩陣,其中

X1 為一個
p×q
的矩陣,
X2
則是一個
s×t
的矩陣。而只有在
q=s
時,兩個矩陣才能進行乘積,並得到一個新的矩陣
X3
,且為一
p×t
的矩陣。

行列式

行列式(determinant),記作

det(A)
|A|
,是一個在方陣上計算得到的純量。[3]如果要進行計算的話,首先要引入套件 LinearAlgebra,接著利用指令 det() 計算行列式。

using LinearAlgebra

A |> display
@show det(A)

結果會是

[abcd]det(A)=adbc

如果考慮以下矩陣

D

[abcdefghi]

則其行列式為

det(D)=c(dheg)+a(eifh)b(difg)

其實到了高維的矩陣,可以看到行列式的計算變得複雜,因此我們可以利用 expand.() 的指令,將計算過程展開,了解其背後的運作、計算過程與原理。

@show expand.(det(D))

## b*f*g + a*e*i + c*d*h - b*d*i - c*e*g - a*f*h

有關乘法,我們要注意一件事:

AB=AC 並不隱含
B=C

a1 = [1 2; 2 4]
b1 = [2 1; 1 3]
c1 = [4 3; 0 2]

@show a1 * b1
@show a1 * c1

## a1 * b1 = [4 7; 8 14]
## a1 * c1 = [4 7; 8 14]

另外給定

A
B
C
三個矩陣,如果
A(BC)=(AB)C
,那麼我們就稱其符合結合律。

A*(B*C) |> display
(A*B)*C |> display

輸出的結果如下:

[a(a2+bc+ce)+b(ad+ce+ef)a(ab+bd+cf)+b(bd+de+f2)c(a2+bc+ce)+d(ad+ce+ef)c(ab+bd+cf)+d(bd+de+f2)][a(a2+bd)+c(ab+be)+e(ac+bf)b(a2+bd)+d(ab+be)+f(ac+bf)a(ac+d2)+c(bc+de)+e(c2+df)b(ac+d2)+d(bc+de)+f(c2+df)]
但基本上由上面的結果我們很難看出兩者到底是不是相同的,因此我們可利用 simplify.() 的指令,配合上面使用過的 expand.(),將其進行展開後化簡成最易讀的形式。

simplify.(expand.(A*(B*C))) |> display
simplify.(expand.((A*B)*C)) |> display

[a3+ab(c+d)+bef+ce(a+b)b(a2+f2)+b2d+abd+bde+acfd2a+a2c+c2(b+e)+cde+defc2f+d2(b+e)+f2d+abc+bcd][a3+ab(c+d)+bef+ce(a+b)b(a2+f2)+b2d+abd+bde+acfd2a+a2c+c2(b+e)+cde+defc2f+d2(b+e)+f2d+abc+bcd]

單位矩陣(identity matrix)

單位矩陣就是一個

n×n 的方陣,其主對角線(main diagonal)上的元素均為
1
,其餘元素為
0
。以一個
4×4
的單位矩陣
I4
為例,其可寫作

[1001]

注意到,如果我們將單位矩陣與其他矩陣相乘,其是具有交換律的,且結果會等於被乘矩陣,即

AI=A=IA

Imat = [1 0; 0 1]

A * Imat |> display
Imat * A |> display

[abcd][abcd]

對角矩陣(diagonal matrix)

若一個矩陣主對角線之外的元素皆為

0,那麼我們就稱其為對角矩陣。例如

d = [a 0 0; 0 b 0; 0 0 c]

[a000b000c]

如果兩個對角矩陣相乘,其結果也會是一個對角矩陣。

D1 = [1 0 0; 0 2 0; 0 0 3]
D2 = [4 0 0; 0 5 0; 0 0 6]
D1D2 = D1 * D2

D1 |> display
D2 |> display
D1D2 |> display

結果會是

[40001000018]

三角矩陣(triangular matrix)

其分為上三角與下三角矩陣,前者的對角線左下方元素為

0,後者則是對角線右上方元素為
0

UT = [a b c; 0 d e; 0 0 f]
LT = [a 0 0; b c 0; d e f]

UT |> display
LT |> display

得到上三角矩陣

[abc0de00f]
與下三角矩陣
[a00bc0def]

同樣地,我們將三角矩陣相乘的結果仍會是三角矩陣。

UT * UT |> display

[a2ab+bdac+be+cf0d2de+ef00f2]

轉置矩陣(transpose of matrix)

簡單來說,轉置矩陣就是將行、列進行交換。下面定義

M
N
兩個矩陣,並對
M
取轉置矩陣,在數學上我們記做
M
M

@variables m₁₁ m₁₂ m₁₃ m₂₁ m₂₂ m₂₃ m₁ m₂ m₃
 
M = [ m₁₁ m₁₂ m₁₃
      m₂₁ m₂₂ m₂₃ ]

@variables n₁₁ n₁₂ n₁₃ n₂₁ n₂₂ n₂₃ n₃₁ n₃₂ n₁ n₂ n₃

N = [ n₁₁ n₁₂
      n₂₁ n₂₂
      n₃₁ n₃₂ ]

M |> display
M' |> display

[m11m12m13m21m22m23][m11m21m12m22m13m23]

而轉置矩陣有下列的性質。如果將矩陣進行轉置,再對其進行一次轉置,我們會得到原本的矩陣:

(M)=M

如果我們將兩個矩陣相加再轉置,可以寫成兩個矩陣先進行轉置後再進行相加

(M+N)=M+N

而兩個矩陣先進行相乘再轉至,其結果為

(MN)=NM

道理很簡單,我們令

M 為一個
m×n
的矩陣,
N
為一個
n×m
的矩陣,兩者相乘的結果會是
m×m
的結果。而如果將
M
轉置,會得到一個
n×m
的矩陣,將
N
進行轉置則會得到一個
m×n
的矩陣,故若為
MN
,其結果會是一個
n×n
的矩陣;如果是
NM
,則會是
m×m
的矩陣。

(M*N)' |> display
N'M' |> display
M'N' |> display

[m11n11+m12n21+m13n31m21n11+m22n21+m23n31m11n12+m12n22+m13n32m21n12+m22n22+m23n32][m11n11+m12n21+m13n31m21n11+m22n21+m23n31m11n12+m12n22+m13n32m21n12+m22n22+m23n32][m11n11+m21n12m11n21+m21n22m11n31+m21n32m12n11+m22n12m12n21+m22n22m12n31+m22n32m13n11+m23n12m13n21+m23n22m13n31+m23n32]

對稱矩陣與反對稱矩陣

若一個矩陣之轉置矩陣仍是其自己本身,那麼其便符合對稱矩陣的性質,即

A=A

S = [a b c; b d e; c e f]
S |> display
S' |> display

[abcbdecef][abcbdecef]

而反對稱矩陣則是其轉置矩陣與自身的加法反元素相等,即

A=A

SS = [0 b c; -b 0 e; -c -e 0]
SS |> display
SS' |> display

[0bcb0ece0][0bcb0ece0]

注意到,如果一個矩陣的轉置矩陣乘上該矩陣,結果會是一個對稱矩陣,即

AA

A' * A |> display
B' * B |> display

[a2+c2ab+cdab+cdb2+d2][a2+d2ab+deac+dfab+deb2+e2bc+efac+dfbc+efc2+f2]

反矩陣(inverse matrix)

給定一個

n 階方陣
A
,若存在一
n
階方陣
B
,使得
AB=BA=In
,其中
In
n
階單位矩陣,則稱
A
是可逆的,且
B
A
的逆矩陣,記作
A1
。但並非所有矩陣都可以取反矩陣,如果其行列式等於
0
時,便不能取反矩陣。原因是因為如果矩陣
A
可逆,則
A1=adj(A)det(A)
,其中
adj(A)
為矩陣
A
的伴隨矩陣(adjugate matrix),故若行列式的值為
0
,此等式就會無意義。根據上述性質,可得出以下小結論:若矩陣
A
可逆,則

AA1=I=A1A

A * inv(A)

得到

[10c(true+bcad+bca)a+dcad+bcadd+bca+cbd+bcaa]

經過化簡可以得到

simplify.(expand.(A * inv(A))) |> display
simplify.(expand.(inv(A) * A)) |> display

兩者結果均是

I=[1001]

而反矩陣有以下性質:

(AB)1=B1A1(A)1=(A1)

simplify.(expand.(inv(A'))) |> display
simplify.(expand.(inv(A)')) |> display

輸出結果均為

[dadbccadbcbadbcaadbc]

那我們要怎麼手刻反矩陣呢?根據上面的定義,

AA1=I

其實可以把反矩陣令為一個未知矩陣

X,因此可以寫成
AX=I

而利用反斜線(backslash)的運算符,我們可以計算出反矩陣,即

X = A\I

結果會是

[1+bcad+bcaabd+bcaacad+bca1d+bca]

經過化簡與檢查,確定該算法可得出反矩陣:

simplify.(expand.(inv(A))) |> display
simplify.(expand.(A \ I_mat)) |> display

[dadbcbadbccadbcaadbc]


  1. 參考自維基百科──矩陣 ↩︎

  2. 注意到在數學上這件事是不成立的。 ↩︎

  3. 參考自維基百科──行列式 ↩︎