logo

줄리아에서 선형대수 패키지 사용하는 법 📂줄리아

줄리아에서 선형대수 패키지 사용하는 법

개요

줄리아매트랩 수준으로 선형대수를 잘 지원한다. 오히려 매트랩 이상으로 발전된, 직관적이고 미려한 문법을 보면 줄리아가 만들어진 시점부터 잘 설계된 느낌을 받을 수 있다1.

코드

julia> A = [    
           1 0 3
           0 5 1
           3 1 9
       ]        
3×3 Matrix{Int64}:
 1  0  3
 0  5  1
 3  1  9

보다시피 행렬을 정의하는 단계에서 이미 직관적이고 편하다. 이제 몇몇가지 상식적으로 있어야할 함수들에 대해 알아본다. 소제목에 관련 포스트를 링크하고 별도의 설명은 생략한다.

트레이스 tr()

julia> tr(A)
15

행렬식 det()

julia> det(A)
-1.000000000000003

역행렬 inv()

julia> inv(A)
3×3 Matrix{Float64}:
 -44.0  -3.0          15.0
  -3.0   6.10623e-16   1.0
  15.0   1.0          -5.0

julia> round.(Int64, inv(A))
3×3 Matrix{Int64}:
 -44  -3  15
  -3   0   1
  15   1  -5

대각행렬과 대각성분 diag(), diagm()

julia> diag(A)
3-element Vector{Int64}:
 1
 5
 9

julia> diagm([1,5,9])
3×3 Matrix{Int64}:
 1  0  0
 0  5  0
 0  0  9

norm()

julia> norm(A, 1)
23.0

고유값 eigvals()

julia> eigvals(A)
3-element Vector{Float64}:
 -0.020282065792505244
  4.846013411157458
 10.174268654635046

julia> eigvecs(A)
3×3 Matrix{Float64}:
 -0.944804    0.117887  0.305692
 -0.0640048  -0.981459  0.180669
  0.321322    0.151132  0.934832

julia> eigmax(A)
10.174268654635046

행렬분해 factorize()

julia> factorize(A)
BunchKaufman{Float64, Matrix{Float64}}
D factor:
3×3 Tridiagonal{Float64, Vector{Float64}}:
 -0.0227273  0.0       ⋅ 
  0.0        4.88889  0.0
   ⋅         0.0      9.0
U factor:
3×3 UnitUpperTriangular{Float64, Matrix{Float64}}:
 1.0  -0.0681818  0.333333
  ⋅    1.0        0.111111
  ⋅     ⋅         1.0
permutation:
3-element Vector{Int64}:
 1
 2
 3

julia> svd(A)
SVD{Float64, Float64, Matrix{Float64}}
U factor:
3×3 Matrix{Float64}:
 -0.305692   0.117887  -0.944804
 -0.180669  -0.981459  -0.0640048
 -0.934832   0.151132   0.321322
singular values:
3-element Vector{Float64}:
 10.174268654635044
  4.846013411157461
  0.02028206579250516
Vt factor:
3×3 Matrix{Float64}:
 -0.305692  -0.180669   -0.934832
  0.117887  -0.981459    0.151132
  0.944804   0.0640048  -0.321322

행렬대수 카테고리의 행렬분해를 참고하라. 행렬의 형태에 따라 적절한 분해법을 알아서 골라서 분해를 해준다. 물론 원한다면, 조건을 만족한다면 구체적인 분해 함수를 그냥 써도 된다.

행렬의 연산

julia> B = [
           1 0 1
           1 1 0
           2 1 1
       ]
3×3 Matrix{Int64}:
 1  0  1
 1  1  0
 2  1  1

julia> A + B
3×3 Matrix{Int64}:
 2  0   4
 1  6   1
 5  2  10

julia> A - B
3×3 Matrix{Int64}:
  0  0  2
 -1  4  1
  1  0  8

julia> A * B
3×3 Matrix{Int64}:
  7   3   4
  7   6   1
 22  10  12

julia> A .* B
3×3 Matrix{Int64}:
 1  0  3
 0  5  0
 6  1  9

julia> B / A
3×3 Matrix{Float64}:
 -29.0  -2.0  10.0
 -47.0  -3.0  16.0
 -76.0  -5.0  26.0

julia> B * inv(A)
3×3 Matrix{Float64}:
 -29.0  -2.0  10.0
 -47.0  -3.0  16.0
 -76.0  -5.0  26.0

julia> A / B
ERROR: SingularException(3)

우리가 생각하는 상식적인 연산들이 모두 통한다. 나눗셈은 당연히 곱셈의 역원인 역행렬을 곱하는 것과 같고, B처럼 역행렬이 존재하지 않는 경우 싱귤러익셉션을 레이즈한다.

블럭 행렬 []

다른 언어들과 비교하면 너무나 편하게 블럭 행렬을 만들 수 있다.

julia> [A B]
3×6 Matrix{Int64}:
 1  0  3  1  0  1
 0  5  1  1  1  0
 3  1  9  2  1  1

julia> [A;B]
6×3 Matrix{Int64}:
 1  0  3
 0  5  1
 3  1  9
 1  0  1
 1  1  0
 2  1  1

julia> [A,B]
2-element Vector{Matrix{Int64}}:
 [1 0 3; 0 5 1; 3 1 9]
 [1 0 1; 1 1 0; 2 1 1]

두 행렬 사이에 공백을 두면 가로로 행렬을 쌓고, 세미콜론을 두면 세로로 쌓는다. 쉼표는 행렬을 쌓는 것이 아니라 원래 배열에서 쓰던 문법 그대로 행렬의 배열이 된다.

전체 코드

복소행렬이나 내적에 관련된 내용은 생략했으나, 전체 코드에는 포함되어 있다.

using LinearAlgebra

A = [
    1 0 3
    0 5 1
    3 1 9
]
tr(A)
det(A)
inv(A)
round.(Int64, inv(A))
diag(A)
diagm([1,5,9])
norm(A, 1)

eigvals(A)
eigvecs(A)
eigmax(A)

factorize(A)
svd(A)

B = [
    1 0 1
    1 1 0
    2 1 1
]

det(B)
rank(B)
eigvals(B)
Symmetric(B) # |> issymmetric
transpose(B)
B'
C = [
    im im 1
    2  im 0
    im  1 2
]
C'

B'B

x = [1,2,3]
y = [0,1,2]
x'y

A + B
A - B
A * B
A .* B

B / A
B * inv(A)

[A B]
[A;B]
[A,B]

x' * y
y * x'

환경

  • OS: Windows
  • julia: v1.7.0