1. 프로그램 개요
◆ 본 프로그램은 컴퓨터 연산의 기본이 되고 또한 통계학에서 많이 다루게 되는 행렬의
연산과 역행렬을 구하는 기능을 한다.
◆ 우선 Matrixmain클래스와 Matrix클래스 LUDecomposition클래스 이렇게 세개의
클래스로 구성되어 있다.
▶ Matrix클래스는 Matrix의 생성과 덧셈, 뺄셈, 곱, 행렬식값, 역행렬, 동치 판단의
기능이 있다.
▶ Matrixmain클래스는 생성된 Matrix의 행과 열, 원소값을 할당해주면 과제에 명시된
연산을 수행한다.
▶ LUDecomposition 클래스는 행렬을 상삼각과 하삼각 행렬로 분해를 한다.
이 프로그램 소스의 핵심 부분이며 역행렬을 구하는 방법중에 한가지이다.
◆ 작동 원리 : Matrixmain클래스에서 행렬의 행과 열, 원소값을 할당하면 Matrix클래스
에서 행렬을 생성한다. 연산에따라 덧셈 곱 뺄셈등 여러가지를 할수 있다.,
그리고 역행렬을 구할때는 LUDecomposition클래스에서 생성된 행렬을
하삼각 상삼각행렬로 분해후에 연산에 따라 역행렬을 만든다.
2. 프로그램 작성시 사용된 이론
◆다음과 같은 행렬이 있다고 할때
◆ 행렬의 덧셈
▶ 위 두행렬 사이에 n = n' , m = m' 이어야 덧셈이 가능하다.
▶ 덧셈의 공식은 다음과 같다.
▶ 결과 행렬을 C라고 할때 일반적인 식은 다음과 같다.
◆ 행렬의 뺄셈
▶ 위 두행렬 사이에 n = n' , m = m' 이어야 뺄셈이 가능하다.
▶ 뺄셈의 공식은 다음과 같다.
▶ 결과 행렬을 C라고 할때 일반적인 식은 다음과 같다.
▶ 결과 행렬을 C라고 할때 일반적인 식은 다음과 같다.
==================================================================================
Matrixmain클래스
==================================================================================
/*****
* author
* Date 4월 16일
* Matrixmain클래스 행렬값을 할당 해주고 계산 된 값들을 출력하는 클래스
*/
class Matrixmain
{
public static void main(String[] args) {
Matrix A = new Matrix(4,4); //행렬의 행과 열 할당
A.mat = new double[][]{{1,0,6,8},{0,1,5,4},
{0,0,-1,0},{0,0,0,-1}}; //행렬 원소 할당
result(A);
}
/*****
* 과제유형에 따른 행렬 계산
* @param A Matrix형 변수
*/
public static void result(Matrix A) {
LUDecomposition lu = new LUDecomposition(A); //LU분해
Matrix L = lu.getL(A); //lower triangle
Matrix U = lu.getU(A); //upper triangle
int pive = lu.piv(); //행변환에 따른 det부호
double detA = A.det(U,pive); //행렬식 계산
Matrix inverA = A.inverse(L,U,pive); //역행렬 계산
/***
* A*A+A-invA 계산과 행렬식값 출력
*/
Matrix A1 = A.times(A);
Matrix A2 = A1.add(A);
Matrix A3 = A2.subtract(inverA);
A3.printMatrix();
System.out.println("det(A) = "+detA);
}
}
==================================================================================
Matrix클래스
==================================================================================
/*****
* @author 박재철
* Date 4월 16일
* Matrix클래스 Matrix생성자를 생성하고 덧셈, 뺄셈, 역행렬등 행렬의 연산을
* 하는 클래스.
*/
class Matrix {
public int row; //생성할 행렬의 행
public int col; //생성할 행렬의 열
public double[][] mat; //행렬들의 값
/*****
* 행렬 생성하는 메소드
* @param row int형 변수
* @param col int형 변수
*/
public Matrix(int row, int col) {
this.row = row;
this.col = col;
this.mat = new double[row][col];
}
/*****
* 행렬의 덧셈을 하는 메소드
* @param B Matrix형 변수
* @return result 계산된 행렬
*/
public Matrix add(Matrix B) {
Matrix result = new Matrix(B.row,B.col);
if(this.row == B.row && this.col == B.col){ //행렬덧셈의 조건
for(int i=0; i<B.row; i++) {
for(int j=0; j<B.col;j++) {
result.mat[i][j]= this.mat[i][j]+
B.mat[i][j];
}
}
}else{
System.out.println("두 행렬은 덧셈이 불가능합니다.");
}
return result;
}
/*****
* 행렬의 뺄셈을 계산하는 메소드
* @param B Matrix 형 변수
* @return result 계산된 행렬
*/
public Matrix subtract(Matrix B){
Matrix result = new Matrix(B.row,B.col);
if(this.row == B.row && this.col == B.col){//행렬 뺄셈 조건
for(int i=0; i<B.row; i++) {
for(int j=0; j<B.col;j++) {
result.mat[i][j]=this.mat[i][j]-B.mat[i][j];
}
}
}else{
System.out.println("두 행렬은 뺄셈이 불가능합니다.");
}
return result;
}
/*****
* 행렬의 곱을 계산하는 메소드
* @param B Matrix형 변수
* @return result 계산된 행렬
*/
public Matrix times(Matrix B) {
Matrix result = new Matrix(B.row,B.col);
if(this.col == B.row){ //행렬 곱 조건
for(int i=0; i<this.row; i++) {
for(int j=0; j<this.col;j++) {
for(int k = 0; k < this.col; k++){
result.mat[i][j]=result.mat[i][j]
+this.mat[i][k]
*B.mat[k][j];
}
}
}
}else{
System.out.println("두 행렬은 곱셈이 불가능합니다.");
}
return result;
}
/*****
* 행렬을 출력하는 메소드
*/
public void printMatrix() {
for(int i=0; i<this.row; i++) {
for(int j=0; j<this.col;j++) {
System.out.print(this.mat[i][j]+" ");
}
System.out.println();
}
}
/*****
* 행렬식 값을 계산하는 메소드
* @param U Matrix형 변수
* @param piv int형 변수 : 행변환에 따른 행렬식값 부호
* @return piv*determin 행렬식 값
*/
public double det(Matrix U,int piv) {
double determin = 1;
for(int i=0; i<this.row; i++) {
determin *= U.mat[i][i]; //상삼각의 대각원소 곱
}
return piv*determin;
}
/*****
* 역행렬을 구하는 메소드
* @param L Matrix형 변수
* @param U Matrix형 변수
* @param piv int형 변수
* @return invers 역행렬
*/
public Matrix inverse(Matrix L, Matrix U, int piv) {
Matrix D = new Matrix(this.row,this.col);
Matrix invers = new Matrix(this.row,this.col);
if(this.det(U, piv) == 0) { //역행렬 존재 여부
System.out.println(" 역행렬이 존재 하지 않습니다.");
System.exit(0);
}
/*****
* A = LU 분해가 가능 한 행렬이면
* LUx = I 에서 Ux = D라 하면 LD =I이므로 D를 구하면
* Ux = D 에서 x가 A의 역행렬
* 2번의 수식을 참고
*/
for(int i=0; i<this.row ;i++) {
for(int j=0; j<this.col; j++){
if(i==j){
D.mat[i][i] = 1;
continue;
}
for(int k=j; k<=i-1; k++) {
if(i<j){
D.mat[i][j] = 0;
}else{
D.mat[i][j] += (-1/L.mat[i][i])*L.mat[i][k]
*D.mat[k][j];
}
}
}
}
for(int i=this.row-1; i >= 0; i--) {
for(int j=this.row-1; j >= 0; j--) {
for(int k=this.row-1; k >= i+1; k--){
if(i == this.row-1) {
invers.mat[this.row-1][j]=D.mat[this.row-1][j]
/U.mat[this.row-1][this.row-1];
}else{
invers.mat[i][j] += U.mat[i][k]*invers.mat[k][j];
}
}
invers.mat[i][j] = (1/U.mat[i][i])*
(D.mat[i][j]-invers.mat[i][j]);
}
}
return invers;
}
/*****
*행렬의 동치 여부를 검사
* @param B Matrix형 변수
* @return 행렬이 동치 인지 아닌지 boolean형 변수
*/
public boolean equals(Matrix B){
if(this.col != B.col || this.row != B.row)
return false;
else{
for(int i=0 ; i<this.row ; i++){
for(int j=0 ; j<this.col ; j++){
if(this.mat[i][j] != B.mat[i][j]){
return false;
}
}
}
}
return true;
}
}
==================================================================================
LUDecomposition클래스
==================================================================================
/*****
* @author
* Date 4월 16일
* LUDecomposition 클래스 행렬을 LU형태로 분해 시키는 클래스
*/
public class LUDecomposition
{
double[][] getL; //하삼각 행렬
double[][] getU; //상삼각 행렬
int pivsign = 1; //행변환에 따른 부호
public LUDecomposition(Matrix B) {
Matrix L = new Matrix(B.row,B.col);
getL = new double[B.row][B.col];
getU = new double[B.row][B.col];
int cnt = 0, replaceRow = 0;
double[][] m = new double[B.row][B.col];
for(int i=0; i<B.row-1; i++){
replaceRow = i+1;
cnt = 0;
/*****
* 대각원소가 0이면 pivoting이 필수 while부분은
* pivoting이 부분을 담당
*/
while(B.mat[i][i] == 0 && replaceRow < B.row) {
B = permutation(B,i,replaceRow);
cnt += 1;
replaceRow += cnt;
pivsign = -pivsign;
}
if(replaceRow == B.row){
continue;
}
//가우스 소거법에 의한 상삼각행렬 만들기
for(int j=i+1; j<B.col; j++) {
//가우스 소거법이용시 사용하는 계수들
m[i][j] = B.mat[j][i]/B.mat[i][i];
for(int k=i; k<B.col; k++) {
B.mat[j][k] = B.mat[j][k]- m[i][j]*B.mat[i][k];
//상삼각행렬을 만들때 이용한 계수를 사용하여 하삼각행렬 생성
if(i<j){
L.mat[j][i] = m[i][j];
}
L.mat[k][k] = 1;
}
}
}
//만들어진 LU행렬을 각각 배열 값으로 저장
for(int l=0; l<B.row; l++) {
for(int h=0; h<B.col;h++) {
getL[l][h] = L.mat[l][h];
getU[l][h] = B.mat[l][h];
}
}
}
/*****
* 치환 행렬 담당 하는 메소드
* @param B Matrix형 변수
* @param r int형 변수 : 대각원소가 0인행
* @param newr int 형 변수 : 위 행과 교체될 행
* @return 치환된 행렬
*/
public Matrix permutation(Matrix B ,int r, int newr) {
/****
* 치환 행렬 생성 부분 permutat가 치환 행렬이며 이 행렬과
* 곱셈 연산을 수행하면
* r행과 newr행의 교체가 이루어진다.
*/
Matrix permutat = new Matrix(B.row,B.col);
for(int i=0; i<B.row ; i++) {
for(int j=0; j<B.col ; j++) {
if(i == j) {
permutat.mat[i][j] = 1;
}
else {
permutat.mat[i][j] = 0;
}
}
}
permutat.mat[r][r] = permutat.mat[newr][newr] = 0;
permutat.mat[r][newr] = permutat.mat[newr][r] = 1;
Matrix C = permutat.times(B);
return C;
}
/****
* 하삼각행렬 반환 하는 메소드
* @param B Matrix형 변수
* @return L 하삼각행렬
*/
public Matrix getL(Matrix B) {
Matrix L = new Matrix(B.row,B.col);
for(int i=0; i<B.row; i++) {
for(int j=0; j<B.col;j++) {
L.mat[i][j] = getL[i][j];
}
}
return L;
}
/****
* 상삼각행렬 반환 하는 메소드
* @param B Matrix형 변수
* @return U 상삼각행렬
*/
public Matrix getU(Matrix B) {
Matrix U = new Matrix(B.row,B.col);
for(int i=0; i<B.row; i++) {
for(int j=0; j<B.col;j++) {
U.mat[i][j] = getU[i][j];
}
}
return U;
}
/*****
* 행변환에 따른 행렬식 부호결정하는 메소드
* @return pivsign 행렬식 부호
*/
public int piv() {
return pivsign;
}
}
==================================================================================
4. 프로그램 작성시 발생한 에러
◆ 프로그램 작성시에 Eclipse를 사용하여 별다른 에러는 발생하지 않았습니다.
다음과 같은 에러 외에는 발생하지 않았습니다.
Matrixmain.java:27: det(Matrix,int) in Matrix cannot be applied to (Matrix,double)
double detA = A.det(U,pive);
Matrixmain.java:29: inverse(Matrix,Matrix,int) in Matrix cannot be applied to (Matrix,Matrix,double)
Matrix inverA = A.inverse(L,U,pive);
2 errors
5. 출력 결과 및 R과비교
===== java ====== ====== R =======
A*A-A+invA = 1.0 0.0 0.0 0.0 1 0 0 0
0.0 1.0 0.0 0.0 0 1 0 0
0.0 0.0 1.0 0.0 0 0 1 0
0.0 0.0 0.0 1.0 0 0 0 1
================= ================
det(A) = 1.0 [1] 1
<R 코드>
x<- matrix(c(1,0,6,8,0,1,5,4,0,0,-1,0,0,0,0,-1),nrow = 4,byrow=T)
x%*%x - x +solve(x)
det(x)
6. 레포트 작성시 애로 사항 및 건의 사항
◆ 가장 어려웠던 부분은 역행렬을 구하는 부분입니다. 작년에 배운 수치해석을
기반으로 LU분해법을 사용하게 되었는데 생각보다 수식이 복잡하고 어려웠
습니다. 특히 분해후에 역행열을 구하는 과정도 꽤 복잡해서 고생을 좀 한거
같습니다.
7. 참고한 책과 웹사이트
◆ 저자 : Rcihard L.Burden / J. Douglas Faires
번역 : 유해영 심홍태 허정연
책이름 : 수치해석
출판사 : 사이텍미디어