001public class Matrix {
002    public static final int NOT_FOUNT = -2147483646;
003    private double[][] matrix;
004    private int row, col;
005 
006    /**
007     * 0행렬 만들기
008     *
009     * @param row
010     *            행 크기
011     * @param col
012     *            열 크기
013     * @return
014     */
015    public static Matrix zeros(int row, int col) {
016        Matrix temp = new Matrix(row, col);
017        temp.setZeroMatrix();
018        return temp;
019    }
020 
021    /**
022     * i * i 크기의 0행렬
023     *
024     * @param i
025     * @return
026     */
027    public static Matrix zeros(int i) {
028        return Matrix.zeros(i, i);
029    }
030 
031    /**
032     * 1행렬 만들기
033     *
034     * @param row
035     *            행 크기
036     * @param col
037     *            열 크기
038     * @return
039     */
040    public static Matrix ones(int row, int col) {
041        Matrix temp = new Matrix(row, col);
042        temp.setOnesMatrix();
043        return temp;
044    }
045 
046    /**
047     * i * i 크기의 1행렬
048     *
049     * @param i
050     * @return
051     */
052    public static Matrix ones(int i) {
053        return Matrix.ones(i, i);
054    }
055 
056    /**
057     * i*i의 단위행렬
058     *
059     * @param i
060     * @return
061     */
062    public static Matrix unitMatrix(int i) {
063        Matrix temp = new Matrix(i);
064        temp.setUnitMatrix();
065        return temp;
066    }
067 
068    /**
069     * 행렬식을 계산한다.
070     * determinant()을 사용할것
071     *
072     * @param target
073     * @return target의 행렬식
074     */
075    @Deprecated
076    public static double determinant1(Matrix target) {
077        // 라이프니츠 공식에 의한 행렬식 계산
078        double det = 0;
079        if (target.getRowSize() == target.getColSize()) {
080            double[][] A = target.getMatrix();
081            if (A.length == 1) {
082                return A[0][0];
083            } else {
084                for (int i = 0; i < A[0].length; i++) {
085                    det += A[0][i] * target.cofactor(0, i);// 재귀
086                                                            // 호출
087                }
088            }
089            return det;
090        } else {
091            System.out.println("행렬식을 구할수 없습니다.");
092            return NOT_FOUNT;
093        }
094 
095    }
096 
097    /**
098     * 가우스 소거법에 의한 행렬식 계산
099     *
100     * @param target
101     * @return
102     */
103    public static double determinant(Matrix target) {
104        if (target.getRowSize() == target.getColSize()) {
105            double[][] temp = new double[target.row][target.row];
106            // temp=getMatrix()로 하면 레퍼런스로 되어서 본래 행렬이
107            // 변경됨
108            for (int i = 0; i < target.row; i++) {
109                for (int j = 0; j < target.row; j++) {
110                    temp[i][j] = target.matrix[i][j];
111                }
112            }
113            for (int n = 0; n < temp.length; n++) {
114                if (temp[n][n] == 0) {
115                    for (int a = n; a < temp.length; a++) {
116                        if (temp[a][n] != 0) {
117                            for (int b = n; b < temp.length; b++) {
118                                temp[n][b] += temp[a][b];
119                            }
120                            break;
121                        }
122                    }
123                    if (temp[n][n] == 0) {
124                        System.out.println(n + "ss");
125                        return 0;
126                    }
127                }
128                for (int i = n + 1; i < temp.length; i++) {
129                    {
130                        for (int j = temp[0].length - 1; j >= n; j--) {
131                            temp[i][j] = temp[i][j] - temp[i][n] * temp[n][j]
132                                    / temp[n][n];// 수정필요
133                        }
134                    }
135                }
136                // new Matrix(temp).displayMatix();
137                // //test
138                // System.out.println("aaa");
139            }
140            double sum = 1;
141            for (int i = 0; i < temp.length; i++) {
142                sum *= temp[i][i];
143            }
144            // new Matrix(temp).displayMatix();
145            return sum;
146        } else {
147            System.out.println("행렬식을 구할수 없습니다.");
148            return NOT_FOUNT;
149        }
150    }
151 
152    /**
153     * 여행렬 구하기
154     *
155     * @param target
156     * @param row
157     * @param col
158     * @return target의 row 행과 col 열을 제외한 여행렬
159     */
160    public static double cofactor(Matrix target, int row, int col) {
161        Matrix temp = target.minor(row, col);
162 
163        return temp.determinant() * Math.pow((-1), (row + col));
164    }
165 
166    /**
167     * 소행렬 구하기
168     *
169     * @param target
170     * @param removeRow
171     * @param removeCol
172     * @return target의 row 행과 col 열을 제외한 소행렬
173     */
174    public Matrix minor(int removeRow, int removeCol) {
175        int ar = 0, ac = 0;
176        double temp[][] = new double[row - 1][col - 1];
177 
178        for (int r = 0; r < row; r++) {
179            for (int c = 0; c < col; c++) {
180                if (!(r == removeRow || c == removeCol)) {
181                    temp[ar][ac] = matrix[r][c];
182                    if (++ac >= col - 1) {
183                        if (++ar < row - 1)
184                            ac = 0;
185                    }
186                }
187            }
188        }
189        return new Matrix(temp);
190    }
191 
192    /**
193     * 행렬의 합
194     *
195     * @param A
196     * @param B
197     * @return
198     */
199    public static Matrix plus(Matrix A, Matrix B) {
200        double[][] temp = Matrix.zeros(A.row, A.col).getMatrix();
201        double[][] tempA = A.getMatrix();
202        double[][] tempB = B.getMatrix();
203        if (equalSize(A, B)) {
204            for (int i = 0; i < tempA.length; i++) {
205                for (int k = 0; k < tempA[0].length; k++) {
206                    temp[i][k] = tempA[i][k] + tempB[i][k];
207                }
208            }
209            return new Matrix(temp);
210        }
211        return new Matrix(temp);
212    }
213 
214    /**
215     * 행렬의 차
216     *
217     * @param A
218     * @param B
219     * @return
220     */
221    public static Matrix minus(Matrix A, Matrix B) {
222        double[][] temp = Matrix.zeros(A.row, A.col).getMatrix();
223        double[][] tempA = A.getMatrix();
224        double[][] tempB = B.getMatrix();
225        if (equalSize(A, B)) {
226            for (int i = 0; i < tempA.length; i++) {
227                for (int k = 0; k < tempA[0].length; k++) {
228                    temp[i][k] = tempA[i][k] - tempB[i][k];
229                }
230            }
231            return new Matrix(temp);
232        }
233        return new Matrix(temp);
234    }
235 
236    /**
237     * 행렬의 모양 비교
238     *
239     * @param A
240     * @param B
241     * @return
242     */
243    public static boolean equalSize(Matrix A, Matrix B) {
244        if (A.getRowSize() == B.getRowSize()
245                && A.getColSize() == B.getColSize()) {
246            return true;
247        } else {
248            return false;
249        }
250    }
251 
252    Matrix(int i) // 행,열 의 크기가 같은 생성자
253    {
254        this.row = i;
255        this.col = i;
256        matrix = new double[i][i];
257        for (int a = 0; a < i; a++) {
258            for (int b = 0; b < i; b++) {
259                matrix[a][b] = (int) (Math.random() * 10 * Math.pow(-1,
260                        (int) Math.random() * 10));
261            }
262        }
263    }
264 
265    Matrix(int row, int col) // 행 열의 크기가 다른 생성자
266    {
267        this.row = row;
268        this.col = col;
269        matrix = new double[row][col];
270        for (int i = 0; i < row; i++) {
271            for (int k = 0; k < col; k++) {
272                matrix[i][k] = (int) (Math.random() * 10 * Math.pow(-1,
273                        (int) Math.random() * 10));
274            }
275        }
276    }
277 
278    public Matrix(double[][] temp) // 임의의 행렬을 입력받는 생성
279    {
280        this.matrix = temp;
281        row = temp.length;
282        col = temp[0].length;
283    }
284 
285    /**
286     *
287     * @return 행렬 원소중 Not a Number 인 원소가 있다면 true
288     */
289    public boolean isNaN() {
290        for (int i = 0; i < col; i++)
291            for (int j = 0; j < row; j++)
292                if (Double.isNaN(matrix[j][i]))
293                    return false;
294        return true;
295    }
296 
297    /**
298     * 자기 자신을 영행렬로 바꾸기
299     */
300    public void setZeroMatrix() {
301        for (int i = 0; i < row; i++) {
302            for (int k = 0; k < col; k++) {
303                matrix[i][k] = 0;
304            }
305        }
306    }
307 
308    /**
309     * 자기 자신을 모두 1인 행렬로 바꿈
310     */
311    public void setOnesMatrix() {
312        for (int i = 0; i < row; i++) {
313            for (int k = 0; k < col; k++) {
314                matrix[i][k] = 1;
315            }
316        }
317    }
318 
319    /**
320     * 자기자신을 단위행렬로
321     */
322    public void setUnitMatrix() {
323        setZeroMatrix();
324        for (int i = 0; i < row; i++) {
325            matrix[i][i] = 1;
326        }
327    }
328 
329    public void displayMatix() {
330        System.out.println(this);
331    }
332 
333    @Override
334    public String toString() {
335        String temp = "";
336        for (int i = 0; i < row; i++) {
337            for (int k = 0; k < col; k++) {
338                if (matrix[i][k] == -0) {
339                    // 이 부분이 없으면 -0과 0이 동시에 나오게 된다
340                    matrix[i][k] = 0;
341                }
342                temp += Double.toString(matrix[i][k]);
343                // C 의 printf와 유사
344                if (k != col - 1) {
345                    temp += ",  ";
346                }
347            }
348            temp += System.getProperty("line.separator");
349        }
350        return temp;
351    }
352 
353    /**
354     * 여인수
355     *
356     * @param row
357     * @param col
358     * @return
359     */
360    public double cofactor(int row, int col) {
361        return minor(row, col).determinant() * Math.pow((-1), row + col);
362    }
363 
364    /**
365     * @param temp
366     *            행렬의 값을 temp로 바꿈
367     */
368    public void setMatrix(double temp[][]) {
369        // 행렬 내용 수정 temp와 matrix가 다를시 문제가 생길수 있음
370        // length로 행과 열의 길이 파악
371        this.row = temp.length;
372        this.col = temp[0].length;
373        this.matrix = temp;
374    }
375 
376    /**
377     * 전치행렬
378     *
379     * @return 이 행렬의 전치행렬
380     */
381    public Matrix transpose() {
382        Matrix tempM = new Matrix(col, row);
383        double temp[][] = new double[col][row];
384        for (int i = 0; i < row; i++) {
385            for (int k = 0; k < col; k++) {
386                temp[k][i] = matrix[i][k];
387            }
388        }
389        tempM.setMatrix(temp);
390        return tempM;
391    }
392 
393    /**
394     * 행렬의 상수배
395     *
396     * @param m
397     *            행렬에 곱할 수
398     * @return 현재 행렬의 m 배된 행렬
399     */
400    public Matrix multiply(double m) {
401        Matrix temp = new Matrix(row, col);
402        for (int i = 0; i < row; i++) {
403            for (int k = 0; k < col; k++) {
404                temp.matrix[i][k] = this.matrix[i][k] * m;
405            }
406        }
407        return temp;
408    }
409 
410    /**
411     * 행렬의 곱
412     *
413     * @param secMatrix
414     *            현재 행렬에 곱해질 행렬
415     * @return 현재 행렬X secMatrix
416     */
417    public Matrix multiply(Matrix secMatrix) // 행렬*행렬
418    {
419        // Matrix temp;
420        double[][] temp;
421        // 곱하기 위해 앞쪽 행렬의 열과 뒷쪽행렬의 행이 같아야함
422        if (this.col == secMatrix.row) {
423            temp = Matrix.zeros(this.row, secMatrix.col).getMatrix();
424            double[][] A = this.getMatrix();
425            double[][] B = secMatrix.getMatrix();
426            for (int i = 0; i < this.row; i++) {
427                for (int j = 0; j < secMatrix.col; j++) {
428                    for (int a = 0; a < this.col; a++) {
429                        // System.out.println("i="+i+" k="+k+" a="+a);
430                        // //테스트
431                        temp[i][j] += A[i][a] * B[a][j];
432                    }
433                }
434            }
435            return new Matrix(temp);
436        } else {
437            System.out.println("계산할 수 없습니다.");
438            return Matrix.zeros(1);
439        }
440 
441    }
442 
443    /**
444     * 역행렬
445     * invers()를 사용할것
446     *
447     * @return 현재 행렬의 역행렬
448     */
449    @Deprecated
450    public Matrix invers1() {
451        // 역행렬// 행렬의 크기가 8x8이 넘어가면 출력하는데 시간이 너무 오래걸린다.
452        // 알고리즘의 최적화가 필요한듯 하다. ->invers() 알고리즘 변경
453        Matrix temp = null;
454        if (row == col) // 행==열인 행렬인지 확인
455        {
456            temp = Matrix.zeros(row);
457            for (int i = 0; i < row; i++) {
458                for (int j = 0; j < row; j++) {
459                    temp.matrix[i][j] = cofactor(i, j);
460                    // i행j열의 값 =여인수(i,j)
461                }
462 
463            }
464            temp = temp.transpose();// 전치
465            double det = determinant1(this);
466            // 원래 행렬의 행렬식계산
467            if (det != 0) {
468                return temp.multiply(1.0 / det);
469                // 마지막으로 행렬식으로 나눠준다.
470            } else {
471                System.out.println("역행렬이 없습니다.");
472                // 행렬식==0이면 역행렬이 없다.
473                return Matrix.zeros(1);
474            }
475 
476        } else {
477            System.out.println("행과 열의 크기가 같지 않습니다.");
478            return Matrix.zeros(1);
479        }
480    }
481 
482    /**
483     * 역행렬<br>
484 
485 
486 
487     * 가우스 조던 소거법
488     * invers1에 비하여 매우 빠르다 invers 는 9차 이상의 행렬에서
489     * 동작속도를 보장할수 없다.
490     * 하지만 이것은 100차 행렬이 넘어가도 빠른속도로 계산이 가능하다.
491     * 하지만 역행렬이 존재 하지 않는 행렬에서도 답이 나오므로 선행해서 걸러낼 필요가
492     * 있다.
493     * 마지막에 원래 행렬과 만들어진 역행렬을 곱해서 단위행렬이 나오는지 검사
494     *
495     * @return 현재 행렬의 역행렬. 역행렬을 만들수 없는 경우에는 null
496     */
497    public Matrix invers() {
498 
499        double[][] temp = new double[row][row];
500        // temp=this.getMatrix()로 하면 레퍼런스로 되어서 본래 행렬이
501        // 변경됨
502        for (int i = 0; i < row; i++) {
503            for (int j = 0; j < row; j++) {
504                temp[i][j] = matrix[i][j];
505            }
506        }
507        double[][] comp = Matrix.unitMatrix(col).getMatrix();
508        for (int n = 0; n < col; n++) {
509            if (temp[n][n] == 0) //
510            {
511                for (int k = n; k < col; k++) {
512                    if (temp[k][n] != 0) {
513                        for (int a = 0; a < col; a++) {
514                            comp[n][a] = comp[n][a] + comp[k][a];
515                            temp[n][a] = temp[n][a] + temp[k][a];
516                        }
517                        break;
518                    }
519                }
520            }
521            double p = temp[n][n];
522            for (int a = 0; a < col; a++) {
523                comp[n][a] /= p;
524                temp[n][a] /= p;
525            }
526            for (int i = 0; i < col; i++) {
527                if (i != n) {
528                    double p1 = temp[i][n];
529                    for (int j = col - 1; j >= 0; j--) {
530                        comp[i][j] -= p1 * comp[n][j];
531                        temp[i][j] -= p1 * temp[n][j];
532                    }
533                }
534            }
535 
536        }
537        Matrix tempReturn = new Matrix(comp);
538        if (multiply(tempReturn).equals(Matrix.unitMatrix(row))) {
539            // 만들어진 결과가 역행렬이 맞는지 확인
540            return tempReturn;
541        } else { // 아닐경우 null리턴
542            System.out.println("경고)역행렬이 존재하않는 행렬일수 있습니다.");
543            return null;
544        }
545 
546    }
547 
548    /**
549     * 왼쪽 나눗셈<br>
550 
551 
552 
553     * 선형방정식의 해를 구할때 씀 this*X=temp, X=this'*temp 일때
554     * X를 구할수있다.
555     *
556     * @param temp
557     * @return
558     */
559    public Matrix leftDivision(Matrix temp) {
560 
561        return this.invers().multiply(temp);
562    }
563 
564    /**
565     * 수반행렬
566     *
567     * @return
568     */
569    public Matrix adjoint() {
570        double temp[][] = new double[row][col];
571        for (int i = 0; i < row; i++) {
572            for (int j = 0; j < col; j++) {
573                temp[i][j] = cofactor(i, j);
574            }
575        }
576        return new Matrix(temp);
577    }
578 
579    /**
580     * 행렬식
581     *
582     * @return
583     */
584    public double determinant() // 행렬식
585    {
586        return Matrix.determinant(this);
587    }
588 
589    public String size()
590    // 전채 크기를 String로 리턴 배열로 리턴하려했으나 조금 문제가 있음
591    {
592        return row + " " + col;
593    }
594 
595    /**
596     *
597     * @return Matrix의 배열을 리턴
598     */
599    public double[][] getMatrix() {
600        return matrix;
601    }
602 
603    /**
604     *
605     * @return 행의 크기
606     */
607    public int getRowSize() {
608        return this.row;
609    }
610 
611    /**
612     *
613     * @return 열의 크기
614     */
615    public int getColSize() {
616        return col;
617    }
618 
619    /**
620     * 행렬의 덧셈
621     *
622     * @param A
623     *            더해질 행렬
624     * @return 현재 행렬에 A 를 더한 행렬
625     */
626 
627    public Matrix plus(Matrix A) {
628 
629        double[][] temp = Matrix.zeros(A.row, A.col).getMatrix();
630        if (equalSize(A, this)) {
631            for (int i = 0; i < A.getRowSize(); i++) {
632                for (int k = 0; k < A.getColSize(); k++) {
633                    temp[i][k] = A.matrix[i][k] + this.matrix[i][k];
634                }
635            }
636            return new Matrix(temp);
637        }
638        return new Matrix(temp);
639    }
640 
641    /**
642     * 행렬의 뺄셈
643     *
644     * @param A
645     *            더해질 뺄셈
646     * @return 현재 행렬에 A 를 뺀 행렬
647     */
648    public Matrix minus(Matrix A) {
649        // 행렬 뺄셈
650        double[][] temp = Matrix.zeros(A.row, A.col).getMatrix();
651        if (equalSize(A, this)) {
652            for (int i = 0; i < A.getRowSize(); i++) {
653                for (int k = 0; k < A.getColSize(); k++) {
654                    temp[i][k] = A.matrix[i][k] - this.matrix[i][k];
655                }
656            }
657            return new Matrix(temp);
658        }
659        return new Matrix(temp);
660    }
661 
662    /**
663     *
664     * @param m
665     *            비교할 행렬
666     * @return 현재 행렬과 m이 같으면 true
667     */
668    public boolean equals(Matrix m) {
669        if (m.row == this.row && m.col == this.col) {
670            for (int i = 1; i < row; i++) {
671                for (int j = 1; j < col; j++) {
672                    if (Math.abs(m.matrix[i][j] - this.matrix[i][j]) >= 0.0000001) {
673                        // 컴퓨터로 계산한 값이기 때문에 두 값의 차가
674                        // 0.0000001 보다 작으면 같다고 볼수 있다.
675                        // 행렬의 원소 자체가 매우 작으면 문제가 발생할수
676                        // 있으나 이경우는 무시하기로한다
677                        return false;
678                    }
679                }
680            }
681        }
682        return true;
683    }
684}

'Programming > Algorithm' 카테고리의 다른 글

힙 정렬 - Heap Sort  (0) 2011.04.17
빠른 정렬 - QuickSort  (0) 2011.04.16
최대 힙 최소 힙  (0) 2011.04.16
색종이 만들기  (0) 2011.04.16
Convex Hull Divide and Conquer for JAVA  (0) 2011.04.16
Posted by 동적할당
: