logo

그램-슈미트 직교화 📂선형대수

그램-슈미트 직교화

정리

모든 유한차원 내적공간은 정규직교기저를 갖는다.

설명

존재성 증명이라는 게 대개 그렇듯 길지도 않고 별것도 아닌것 같아보이지만 엄청나게 중요한 정리다. 선형대수학을 지탱하는 수많은 논리가 바로 이 정규직교기저가 존재한다는데에 의존하고 있기 때문이다.

증명

내적공간 $(V, \left\langle \cdot , \cdot \right\rangle)$ 을 생성하는 기저 중 하나를 $\left\{ \mathbf{x}_{1} , \cdots , \mathbf{x}_{n} \right\}$ 이라고 잡자. 새로운 벡터

$$ \mathbf{v}_{1} := {{ \mathbf{x}_{1} } \over { \left\| \mathbf{x}_{1} \right\| }} $$

$$ {\color{blue} \mathbf{v}_{2}} := {{ {\color{red} \mathbf{x}_{2} - ( \mathbf{x}_{2} \cdot \mathbf{v}_{1} ) \mathbf{v}_{1} } } \over { \left\| \mathbf{x}_{2} - ( \mathbf{x}_{2} \cdot \mathbf{v}_{1} ) \mathbf{v}_{1} \right\| }} = {{ \mathbf{x}_{2} - \text{Proj} ( \mathbf{x}_{1} ) } \over { \left\| \mathbf{x}_{2} - \text{Proj} ( \mathbf{x}_{1} ) \right\| }} $$

을 정의하자.

20180120\_134426.png

그림에서 나타낸 바와 같이 $\mathbf{v}_{1} \perp \mathbf{v}_{2}$ 가 성립한다. 위와 같은 프로세스는

$$ \mathbf{v}_{k} := {{ \mathbf{x}_{k} - \text{Proj} ( \mathbf{x}_{k-1} ) } \over { \left\| \mathbf{x}_{k} - \text{Proj} ( \mathbf{x}_{k-1} ) \right\| }} $$ 에 대해서 반복할 수 있으므로, 직교기저 $\left\{ \mathbf{v}_{1} , \cdots , \mathbf{v}_{n} \right\}$ 을 찾을 수 있다. 정의에 따라 $\mathbf{v}_{1} , \cdots , \mathbf{v}_{n}$ 들은 모두 그 크기가 $1$ 이므로 $\left\{ \mathbf{v}_{1} , \cdots , \mathbf{v}_{n} \right\}$ 는 정규직교벡터다.


사실 정규화는 그저 크기가 1이 되도록 놈을 나눠주면 그만이고, 핵심적인 것은 사영을 이용해 직교벡터를 찾는 것이다.

코드

그램-슈미트 직교화 정리의 증명은 그 자체로 알고리즘이나 마찬가지다. 실제로 주어진 랜덤행렬 X에 대해 정규직교화를 거친 행렬 V는 각 행벡터간의 내적이 $0$ 이고 크기가 $1$ 이라는 것을 확인할 수 있다.

julia> X = randn(3, 3)
3×3 Matrix{Float64}:
  0.0582107   0.414695  0.730785
 -0.740409   -0.885193  0.302674
  1.25107     0.840262  0.176503

julia> V = gram_schmidt(X)
3×3 Matrix{Float64}:
  0.0400097   0.739513  0.671952
 -0.508902   -0.563652  0.650626
  0.859894   -0.367989  0.353788

julia> V[1,:]'V[2,:], V[1,:]'V[3,:], V[2,:]'V[3,:]
(0.0, -8.326672684688674e-17, 1.1102230246251565e-16)

julia> norm(V[1,:]), norm(V[2,:]), norm(V[3,:])
(1.0, 0.9999999999999999, 1.0)

다음은 그램-슈미트 직교정규화를 행렬에서 수행하는 줄리아 코드다.

using LinearAlgebra

function gram_schmidt(A)
    U = deepcopy(A)
    for i in axes(A, 1)
        for j in 1:(i-1)
            U[:, i] -= (U[:, i]'U[:, j])*U[:, j]/norm(U[:, j])
        end
        U[:, i] /= norm(U[:, i])
    end
    return U
end

X = randn(3, 3)
V = gram_schmidt(X)

V[1,:]'V[2,:], V[1,:]'V[3,:], V[2,:]'V[3,:]
norm(V[1,:]), norm(V[2,:]), norm(V[3,:])

랴푸노프 스펙트럼

랴푸노프 스펙트럼을 계산할 땐 다음과 같이 정규직교 행렬 U와 함께 유닛 볼의 축이 얼마나 바뀌는지를 측정하는 그냥 직교 행렬 V를 동시에 계산하는 함수가 필요하다.

using LinearAlgebra

function gram_schmidt(J)
    N = size(J, 1)
    U, V = deepcopy(J), deepcopy(J)
    U[:,1] = V[:,1] / norm(V[:,1])
    for j in 2:N
        for jp in 1:(j-1)
            V[:,j] -= (J[:,j]'U[:,jp])*U[:,jp]
        end
        U[:,j] = V[:,j] / norm(V[:,j])
    end
    return U, V
end

같이보기