아래는 위의 예시의 R코드입니다. 패키지 자체에 대한 함수로도 존재합니다.
# LU분해
# sol1)
A <- matrix(c(1,-2,0,
-1,3,-1,
0,-1,2),byrow = T,ncol=3)
E1 <- matrix(c(1,0,0,
1,1,0,
0,0,1),byrow = T,ncol=3)
E2 <- matrix(c(1,0,0,
0,1,0,
0,1,1),byrow = T,ncol=3)
U <- E2%*%E1%*%A
L <- solve(E1)%*%solve(E2)
L%*%U
# sol2)
#library(matlib)
LU(A)
> LU(A)
$P
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 0 0 1
$L
[,1] [,2] [,3]
[1,] 1 0 0
[2,] -1 1 0
[3,] 0 -1 1
$U
[,1] [,2] [,3]
[1,] 1 -2 0
[2,] 0 1 -1
[3,] 0 0 1
아래는 ex2)에 대한 R코드입니다.
B <- matrix(c(1,-2,0,
-1,3,-1,
0,-1,2),byrow = T,ncol=3)
E1 <- matrix(c(1,0,0,
1,1,0,
0,0,1),byrow = T,ncol=3)
E2 <- matrix(c(1,0,0,
0,1,0,
0,1,1),byrow = T,ncol=3)
U <- E2%*%E1%*%B
L <- solve(E1)%*%solve(E2)
#LY=B의 Y값
gaussianElimination(A=L,B = matrix(c(3,-6,5),byrow=T,ncol=1))
#UX =Y의 X값
gaussianElimination(A=U,B = matrix(c(2,-1,1),byrow=T,ncol=1))
추가적으로 LU분해 속도가 확실히 더 빠릅니다.
조건수 구하기 위한 특이값 R코드입니다.
# 행렬 생성####
A <- matrix(c(1, 2, 3, 4), nrow = 2, byrow = TRUE)
# SVD
svd_result <- svd(A)
> svd(A)
$d
[1] 5.4649857 0.3659662
$u
[,1] [,2]
[1,] -0.4045536 -0.9145143
[2,] -0.9145143 0.4045536
$v
[,1] [,2]
[1,] -0.5760484 0.8174156
[2,] -0.8174156 -0.5760484
# 특이값
singular_values <- svd_result$d
#실제로 특이값 식이 맞는지 확인
svd_result$u%*%(matrix(c(singular_values[1],0,0,singular_values[2]),byrow = T,ncol = 2))%*%t(svd_result$v)
> svd_result$u%*%(matrix(c(singular_values[1],0,0,singular_values[2]),byrow = T,ncol = 2))%*%t(svd_result$v)
[,1] [,2]
[1,] 1 2
[2,] 3 4
여기서 우리가 중요하게 볼 것은 특이값이므로,
> singular_values
[1] 5.4649857 0.3659662
> singular_values[1]*svd(A_inverse)$d[1]
[1] 14.93303
참고로 역행렬 조건수도 일반행렬 조건수와 동일합니다.
조건수가 1에 근접하면 오차에 민감한 변화가 작고 조건수가 크면 작은 오차에 민감한 변화가 큰데
이에 대한 대표적인 행렬들이 조건수가 1인 단위행렬과 조건수가 매우 큰 힐버트행렬입니다.
힐버트 행렬은 1,1 요소자리에서 부터 우측으로 가면서 각 요소자리 합-1분의 1만큼 요소를 가집니다.
#library(pracma)
B <- c(1,1,1 ,1) %>% as.matrix()
B_prime <- c(1,1,1 ,1+0.0001) %>% as.matrix()
H <- matrix(0.0001,ncol=4,nrow=4)
gaussianElimination(A=hilb(4),B = B)
gaussianElimination(A=hilb(4)+H,B=B)
gaussianElimination(A=hilb(4)+diag(0.0001,4),B=B)
#조건수 체크 : 대각행렬에 0.0001을 더한 조건수가 기존 조건수와 매우 달라짐.
> kappa(hilb(4))
[1] 20093.93
> kappa(hilb(4)+diag(0.0001,4))
[1] 9677.346
> kappa(hilb(4)+H)
[1] 20019.34
> gaussianElimination(A=hilb(4),B = B)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 -4
[2,] 0 1 0 0 60
[3,] 0 0 1 0 -180
[4,] 0 0 0 1 140
> gaussianElimination(A=hilb(4)+H,B=B)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 -3.99361
[2,] 0 1 0 0 59.90415
[3,] 0 0 1 0 -179.71246
[4,] 0 0 0 1 139.77636
> gaussianElimination(A=hilb(4)+diag(0.0001,4),B=B)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 -0.5889767
[2,] 0 1 0 0 21.1225671
[3,] 0 0 1 0 -85.7591250
[4,] 0 0 0 1 78.4565082
조건수가 커야 오차가 가우스소거법과 LU분해의 오차 차이가 확 크기 때문에
큰 행렬을 이용했다.
library(matlib)
set.seed(8457)
n <- 100
A <- matrix(rnorm(n * n), n, n)
b <- rnorm(n)
# 행렬의 조건수 계산
cond_A <- kappa(A)
paste0("행렬 A의 조건수:", cond_A)
# 가우스 소거법을 사용하여 해를 구함
x_gaussian <- gaussianElimination(A = A,B = b)[,101]
# LU 분해를 사용하여 Ax = b를 푸는 함수
solve_lu <- function(A, b) {
lu <- lu(A)
L <- lu$L
U <- lu$U
y <- forwardsolve(L, b) #LY = b
x <- backsolve(U, y) # UX = Y
x
}
# LU 분해를 사용하여 해를 구함
x_lu <- solve_lu(A, b)
# 실제 해 계산
x_true <- solve(A, b)
# 오차 계산
error_gaussian <- norm(x_true - x_gaussian, type = "2")
error_lu <- norm(x_true - x_lu, type = "2")
paste0("가우스 소거법에 의한 해의 오차:", error_gaussian)
paste0("LU 분해에 의한 해의 오차:", error_lu)
> paste0("가우스 소거법에 의한 해의 오차:", error_gaussian)
[1] "가우스 소거법에 의한 해의 오차:2.904426349253e-08"
> paste0("LU 분해에 의한 해의 오차:", error_lu)
[1] "LU 분해에 의한 해의 오차:6.55434647136738e-12"
행렬 수 200x200으로 가우스소거법을 진행하니 R이 터져버렸다.. (가우스 소거법의 문제점)
LU는 연산이 매우 간단하기에 빠르게 가능했고 이에 대한 오차도 작습니다.
##LU분해와 가우스소거법들의 오차검증이 제대로 확인되지 않았습니다.
그렇기에 아래의 오차내용은 무시해주세요.
##확실한 것은 LU분해가 행렬 사이즈가 클 수록 명백하게 가우스소거법보다 해를 찾아내는 속도가 빠른다는 점입니다.
'선형대수학' 카테고리의 다른 글
[R] Full column rank, Full row rank에서 해의 관계성 (1) | 2024.12.13 |
---|---|
LA-4) 연립방정식,역행렬,행렬식을 구하는 방법 [R] (0) | 2024.06.21 |
LA-2) 방정식 해의 존재 유무 판단(Augment matrix, rank) (2) | 2024.05.30 |
LA-1) 행렬식과 여인수,수반행렬 (0) | 2024.05.01 |
벡터의 정사영(Orthogonal projection)기출문제(2022 한양대 편입수학문제) (1) | 2024.04.26 |