필립 클라인의 저서 코딩 더 매트릭스 7장 차원
- 여부분공간을 이해합니다.
- 선형함수의 가역조건을 차원 원리에 적용해 봅니다.
- Kernel-Image 정리와 rank-nullity 정리를 이해합니다.
- 가역함수의 조건을 바탕으로 행렬의 가역조건을 이해합니다.
- 소멸자의 정의를 알고 , 임을 이해합니다.
- 차원 관련 프로시저를 작성해 봅니다.
여부분공간 Complementary subspace
벡터공간 와 부분공간 , 에 대해 이면 와 를 여부분공간이라 합니다. 예를 들어 다음 직선과 평면들은 의 여부분공간입니다.
두 그림은 같은 평면에 대해 여부분공간인 직선이 여러개임을 보여주기도 합니다.
임의의 벡터공간 와 의 임의의 부분공간 에 대해 를 만족하는 의 부분공간 가 존재합니다. 를 의 기저라 하겠습니다. Superset basis에 의하면 의 기저를 포함하는 의 기저가 존재하므로 의 기저를 과 같이 쓸 수 있습니다. 이 때 이라 하겠습니다. 내 임의의 벡터 는 다음과 같이 나타낼 수 있습니다.
와 의 직합을 정의할 수 있다면 는 의 임의의 벡터이고 이는 를 만족하는 의 부분공간 가 있음을 보여줍니다. 어떤 벡터 가 와 에 모두 속한다고 할 때 를 다음과 같이 쓸 수 있습니다.
위 식을 변형하면 다음이 성립합니다.
는 의 기저이므로 일차독립입니다. 위 식은 자명한 선형결합에 대해서만 성립하므로 는 영벡터이고 이는 와 가 영벡터만 공유함을 의미합니다. 따라서 를 정의할 수 있고 를 만족하는 부분공간 가 존재합니다.
차원과 선형함수
선형함수 가 가역이기 위한 필요충분조건은 가 전단사함수여야 한다는 것이었습니다. 단사함수이기 위한 필요충분조건은 가 자명한 경우입니다. (참고) 전사함수일 필요충분조건은 인 경우입니다. 차원 원리를 식 에 적용하면 입니다. 따라서 가 전사함수일 필요충분조건은 인 경우라 할 수 있습니다.
Kernel-Image 정리
이번 섹션에서는 아래 식을 도출하기 위해 긴 증명과정을 따라가 보겠습니다.
반드시 가역적이지는 않은 함수 가 있습니다.
함수 를 바탕으로 가역적인 서브함수 를 정의해 보겠습니다. 가 전사함수가 되도록 를 선택합니다. 선택한 원소들 은 의 기저라 하겠습니다.
다음에 은 의 원상이라 하고 을 만족하는 내의 임의의 벡터들 을 선택하겠습니다. 이제 이라 하겠습니다.
함수 는 라고 정의합니다. 선택한 서브함수 는 전단사함수입니다. 따라서 , 입니다.
함수 에서 가역 서브함수 를 구성하는 것은 서브함수의 정의역을 원래 선형함수 의 커널에 연관시켜 다음 식을 이끌어 냅니다.
위 식이 성립하기 위해서는 이 정의되어야 하고 내의 모든 벡터가 의 원소 로 표현될 수 있어야 합니다.
의 원소 중 을 만족하는 원소는 영벡터뿐이므로 와 는 영벡터만을 공유합니다. 따라서 를 정의할 수 있습니다. 내의 임의의 벡터 에 대해 라 하면 는 전사함수이므로 를 만족하는 가 존재합니다. 이고 으로 다시 쓸 수 있습니다. 라 하면 이므로 입니다. 이므로 임의의 벡터 를 의 원소로서 표현할 수 있습니다. 따라서 가 성립합니다.
에서 의 기저와 의 기저의 합집합은 의 기저이므로 식이 성립합니다. 여기서 의 는 의 원상이고 는 전단사함수이므로 입니다. 따라서 라 할 수 있습니다. 이를 Kernel-Image 정리라 합니다.
Kernel-Image 정리를 도출하는 동안 이용했던 서브함수 를 통해 가역적인 함수의 성질을 다시 한번 정리할 수 있습니다. 선형함수가 가역적이려면 , 이어야 합니다. 가역함수 는 이었습니다. 따라서 선형함수 가 가역적이려면 이고 이어야 합니다.
rank-nullity 정리
선형함수는 행렬곱셈으로 표현할 수 있었습니다. 예를 들어 행렬 에 대해 을 라 하면 이므로 다음과 같이 바꿔 쓸 수 있습니다.
위 식에서 는 의 열공간에 대한 선형결합이므로 입니다. 행렬 의 영공간의 차원 를 라 합니다. 의 열의 개수를 이라 하면 다음을 얻습니다.
행렬의 가역성
함수가 가역함수일 조건들을 행렬의 가역성에 대응할 수 있습니다. , 행렬 에 대해 라 할 때,
- 단사함수일 조건
- 전사함수일 조건
첫번째 조건 은 행렬의 열벡터들에 의한 선형결합이 0이 되는 경우는 자명한 선형결합 뿐임을 뜻하고 이는 열벡터들이 일차독립이어야 함을 뜻합니다.
가역행렬의 전치행렬은 가역행렬입니다. 가역행렬 가 있다고 할 때 는 정방행렬이고 열벡터들은 일차독립입니다. 의 열벡터들의 랭크는 의 행랭크입니다. 행렬의 행랭크와 열랭크는 같고 는 정방행렬이므로 의 행들은 일차독립입니다. 따라서 가 정방행렬이고 열벡터들이 일차독립이므로 가역행렬의 전치행렬은 가역적이라고 할 수 있습니다.
소멸자 Annihilator
벡터공간을 어떤 벡터들의 생성으로서 또는 동차선형시스템의 해집합으로서 표현할 수 있습니다. 예를 들어 평면 은 으로 표현할 수 있습니다. 아핀공간 역시 아핀hull 로서 또는 선형시스템의 해집합으로서 표현할 수 있습니다. 벡터공간 또는 아핀공간을 해집합 또는 생성으로서 표현하는 것은 이번 섹션인 소멸자와 연관됩니다.
의 부분공간 에 대해 의 소멸자는 로 표현되고 다음과 같습니다.
평면을 해집합으로 표현한 의 해는 소멸자 를 찾는 것과 같습니다.
한편 소멸자를 찾는 것은 영공간의 생성자를 찾는 것과 같습니다. 은 에 대한 생성자들이라 하고 행렬 가 다음과 같다고 하겠습니다.
의 벡터 가 에 있을 필요충분조건은 모든 벡터 에 대해 인 경우입니다. 의 소멸자 가 이므로 입니다.
Annihilator Dimension 정리
, 가 의 부분공간일때 가 성립하고 이를 Annihilator Dimension 정리라 합니다. 가 행렬이고 행공간을 라 하면 rank-nullity 정리에 의해 이 성립하고 , 이므로 는 참입니다.
Annihilator 정리
어떤 알고리즘 X가 있습니다. X의 입력값으로 의 생성자들이 주어지면 의 생성자들이 출력됩니다. X에 의 생성자들이 입력되면 의 생성자들이 출력될 것입니다. 그렇다면 는 무엇일까요?
의 기저를 , 의 기저를 이라 하겠습니다. 이 성립하고 에 대해 모두 식이 성립합니다. 따라서 은 의 부분공간입니다. 한편 Annihilator Dimension 정리에 의해 이고 입니다. 두 식을 연립하면 를 얻습니다. 차원정리에 의해 가 성립합니다.
차원 관련 프로시저
- morphing 정리를 직접 구현한 프로시저
morph
.solve
모듈은 소스파일에서 다운로드 받을 수 있습니다.
from solver import solve
from matutil import coldict2mat
from vecutil import list2vec
def is_superfluous(L, i):
if len(L) == 1:
return False
M = coldict2mat(L[0:i] + L[i + 1:])
u = solve(M, L[i])
return (L[i] - M * u).is_almost_zero()
def is_independent(L):
for i in range(len(L)):
if is_superfluous(L, i):
return False
return True
def exchange(S, A, z):
for i in range(len(S)):
if not is_independent(A + [S[i]]):
continue
M = S[0:i] + [z] + S[i+1:]
for v in S:
if not is_superfluous([v] + M, 0):
break
else:
return S[i]
def morph(S, B):
res = []
A = []
for z in B:
w = exchange(S, A, z)
A.append(z)
S.append(z)
S = [ s for s in S if s != w ]
res.append((z, w))
return res
S = [ list2vec(v) for v in [ [2,4,0], [1,0,3], [0,4,4], [1,1,1] ] ]
B = [ list2vec(v) for v in [ [1,0,0], [0,1,0], [0,0,1] ] ]
for (z,w) in morph(S, B):
print("injecting", z)
print("ejecting", w)
>>>
injecting
0 1 2
------
1 0 0
ejecting
0 1 2
------
2 4 0
injecting
0 1 2
------
0 1 0
ejecting
0 1 2
------
1 0 3
injecting
0 1 2
------
0 0 1
ejecting
0 1 2
------
0 4 4
Morphing 정리는 교환정리를 기반으로 증명되므로 프로시저 exchange
를 사용합니다.
- 랭크를 찾는 프로시저
my_rank
def subset_basis(T):
subset = []
for v in T:
if not is_superfluous([v] + subset, 0):
subset = [v] + subset
return subset
def my_rank(L):
return len(subset_basis(L))
assert my_rank([ list2vec(v) for v in [ [1,2,3], [4,5,6], [1.1,1.1,1.1] ] ]) == 2
assert my_rank([ list2vec(v) for v in [ [1,3,0,0], [2,0,5,1], [0,0,1,0], [0,0,7,-1] ] ]) == 4
assert my_rank([ list2vec(v) for v in [ [one,0,one,0], [0,one,0,0], [one,one,one,one], [0,0,0,one] ] ]) == 3
랭크는 기저의 크기이므로 프로시저 subset_basis
로 기저벡터들을 찾은 뒤 갯수만 반환합니다.
- 프로시저
direct_sum_decompose
. 입력 벡터 를 두 벡터공간의 기저들의 선형결합으로 표현합니다. 이 때 입니다.
def direct_sum_decompose(U_basis, V_basis, w):
U_len = len(U_basis)
V_len = len(V_basis)
M = coldict2mat({ i: (U_basis + V_basis)[i] for i in range(U_len + V_len) })
x = solve(M, w)
u = sum([ x[i] * U_basis[i] for i in range(U_len)])
v = sum([ x[j] * V_basis[i] for i, j in zip(range(V_len), range(U_len, U_len + V_len))])
return (u, v)
U_basis = [ list2vec(v) for v in [ [2,1,0,0,6,0], [11,5,0,0,1,0], [3,1.5,0,0,7.5,0] ] ]
V_basis = [ list2vec(v) for v in [ [0,0,7,0,0,1], [0,0,15,0,0,2] ] ]
w = list2vec([ 2,5,0,0,1,0 ])
(u,v) = direct_sum_decompose(U_basis, V_basis, w)
print(u,v)
w = list2vec([ 0,0,3,0,0,-4 ])
(u,v) = direct_sum_decompose(U_basis, V_basis, w)
print(u,v)
w = list2vec([ 1,2,0,0,2,1 ])
(u,v) = direct_sum_decompose(U_basis, V_basis, w)
print(u,v)
w = list2vec([ -6,2,4,0,4,5 ])
(u,v) = direct_sum_decompose(U_basis, V_basis, w)
print(u,v)
>>>
0 1 2 3 4 5
------------
2 5 0 0 1 0
0 1 2 3 4 5
------------
0 0 0 0 0 0
0 1 2 3 4 5
------------
0 0 0 0 0 0
0 1 2 3 4 5
-------------
0 0 3 0 0 -4
0 1 2 3 4 5
------------
1 2 0 0 2 0
0 1 2 3 4 5
------------
0 0 0 0 0 1
0 1 2 3 4 5
-------------
-6 2 0 0 4 0
0 1 2 3 4 5
------------
0 0 4 0 0 5
- 행렬의 가역성을 이용한 프로시저
is_invertible
from matutil import mat2coldict, listlist2mat
from GF2 import one
def is_invertible(M):
L = [ v for k, v in mat2coldict(M).items() ]
if len(M.D[0]) != len(M.D[1]):
return False
return is_independent(L)
assert is_invertible(listlist2mat([ [1,2,3], [3,1,1] ])) == False
assert is_invertible(listlist2mat([ [1,0,1,0], [0,2,1,0], [0,0,3,1], [0,0,0,4] ])) == True
assert is_invertible(listlist2mat([ [1,0], [0,1], [2,1] ])) == False
assert is_invertible(listlist2mat([ [one,0,one], [0,one,one], [one,one,0] ])) == False
assert is_invertible(listlist2mat([ [one,one], [0,one] ])) == True
행렬의 가역성 조건에 맞춰 행렬이 정방행렬인지, 열벡터들이 일차독립인지 확인합니다.
- GF(2) 상에서 역행렬을 찾는 프로시저
find_matrix_inverse
from GF2 import one
from solver import solve
from matutil import coldict2mat
from vec import Vec
def find_matrix_inverse(A):
coldict = {}
for r in A.D[0]:
coldict[r] = solve(A, Vec(A.D[0], { r: one }))
return coldict2mat(coldict)
A = listlist2mat([ [one,one,one,one], [one,one,one,0], [0,one,0,one], [0,0,one,0] ])
print(find_matrix_inverse(A) * A)
>>>
0 1 2 3
---------
0 | 1 0 0 0
1 | 0 1 0 0
2 | 0 0 1 0
3 | 0 0 0 1
행렬-벡터 곱셈에 따라 , , ..., 를 만족하는 벡터 을 찾은 뒤 을 열벡터로 갖는 행렬을 반환합니다.
- 상삼각행렬의 역행렬을 찾는 프로시저
find_triangular_matrix_inverse
from vec import Vec
from vecutil import zero_vec
from matutil import mat2rowdict, coldict2mat, listlist2mat
def triangular_solve(rowlist, v):
D = rowlist[0].D
label_list = sorted(list(D))
u = zero_vec(D)
for i in reversed(range(len(rowlist))):
c = label_list[i]
row = rowlist[i]
u[c] = (v[i] - row * u) / row[c]
return u
def find_triangular_matrix_inverse(A):
rowdict = mat2rowdict(A)
rowlist = [ rowdict[k] for k in sorted(list(rowdict.keys())) ]
inverse_coldict = {}
for r in A.D[0]:
inverse_coldict[r] = triangular_solve(rowlist, Vec(A.D[0], { r: 1 }))
return coldict2mat(inverse_coldict)
A = listlist2mat([ [1,.5, .2, 4], [0, 1, .3, .9], [0, 0, 1, .1], [0, 0, 0, 1] ])
print(find_triangular_matrix_inverse(A))
print(find_triangular_matrix_inverse(A) * A)
>>>
0 1 2 3
--------------------
0 | 1 -0.5 -0.05 -3.54
1 | 0 1 -0.3 -0.87
2 | 0 0 1 -0.1
3 | 0 0 0 1
0 1 2 3
---------
0 | 1 0 0 0
1 | 0 1 0 0
2 | 0 0 1 0
3 | 0 0 0 1
입력된 행렬이 상삼각행렬이라면 solve
모듈없이 역행렬을 찾을 수 있습니다. 후진대입법을 이용해 행렬-벡터 곱셈의 해를 찾고 그것들을 열벡터로 갖는 행렬을 반환합니다.