public class Matrix {
	public static final int NOT_FOUNT = -2147483646;
	private double[][] matrix;
	private int row, col;

	/**
	 * 0행렬 만들기
	 * 
	 * @param row
	 *            행 크기
	 * @param col
	 *            열 크기
	 * @return
	 */
	public static Matrix zeros(int row, int col) {
		Matrix temp = new Matrix(row, col);
		temp.setZeroMatrix();
		return temp;
	}

	/**
	 * i * i 크기의 0행렬
	 * 
	 * @param i
	 * @return
	 */
	public static Matrix zeros(int i) {
		return Matrix.zeros(i, i);
	}

	/**
	 * 1행렬 만들기
	 * 
	 * @param row
	 *            행 크기
	 * @param col
	 *            열 크기
	 * @return
	 */
	public static Matrix ones(int row, int col) {
		Matrix temp = new Matrix(row, col);
		temp.setOnesMatrix();
		return temp;
	}

	/**
	 * i * i 크기의 1행렬
	 * 
	 * @param i
	 * @return
	 */
	public static Matrix ones(int i) {
		return Matrix.ones(i, i);
	}

	/**
	 * i*i의 단위행렬
	 * 
	 * @param i
	 * @return
	 */
	public static Matrix unitMatrix(int i) {
		Matrix temp = new Matrix(i);
		temp.setUnitMatrix();
		return temp;
	}

	/**
	 * 행렬식을 계산한다.
	 * determinant()을 사용할것
	 * 
	 * @param target
	 * @return target의 행렬식
	 */
	@Deprecated 
	public static double determinant1(Matrix target) {
		// 라이프니츠 공식에 의한 행렬식 계산
		double det = 0;
		if (target.getRowSize() == target.getColSize()) {
			double[][] A = target.getMatrix();
			if (A.length == 1) {
				return A[0][0];
			} else {
				for (int i = 0; i < A[0].length; i++) {
					det += A[0][i] * target.cofactor(0, i);// 재귀
															// 호출
				}
			}
			return det;
		} else {
			System.out.println("행렬식을 구할수 없습니다.");
			return NOT_FOUNT;
		}

	}

	/**
	 * 가우스 소거법에 의한 행렬식 계산
	 * 
	 * @param target
	 * @return
	 */
	public static double determinant(Matrix target) {
		if (target.getRowSize() == target.getColSize()) {
			double[][] temp = new double[target.row][target.row];
			// temp=getMatrix()로 하면 레퍼런스로 되어서 본래 행렬이
			// 변경됨
			for (int i = 0; i < target.row; i++) {
				for (int j = 0; j < target.row; j++) {
					temp[i][j] = target.matrix[i][j];
				}
			}
			for (int n = 0; n < temp.length; n++) {
				if (temp[n][n] == 0) {
					for (int a = n; a < temp.length; a++) {
						if (temp[a][n] != 0) {
							for (int b = n; b < temp.length; b++) {
								temp[n][b] += temp[a][b];
							}
							break;
						}
					}
					if (temp[n][n] == 0) {
						System.out.println(n + "ss");
						return 0;
					}
				}
				for (int i = n + 1; i < temp.length; i++) {
					{
						for (int j = temp[0].length - 1; j >= n; j--) {
							temp[i][j] = temp[i][j] - temp[i][n] * temp[n][j]
									/ temp[n][n];// 수정필요
						}
					}
				}
				// new Matrix(temp).displayMatix();
				// //test
				// System.out.println("aaa");
			}
			double sum = 1;
			for (int i = 0; i < temp.length; i++) {
				sum *= temp[i][i];
			}
			// new Matrix(temp).displayMatix();
			return sum;
		} else {
			System.out.println("행렬식을 구할수 없습니다.");
			return NOT_FOUNT;
		}
	}

	/**
	 * 여행렬 구하기
	 * 
	 * @param target
	 * @param row
	 * @param col
	 * @return target의 row 행과 col 열을 제외한 여행렬
	 */
	public static double cofactor(Matrix target, int row, int col) {
		Matrix temp = target.minor(row, col);

		return temp.determinant() * Math.pow((-1), (row + col));
	}

	/**
	 * 소행렬 구하기
	 * 
	 * @param target
	 * @param removeRow
	 * @param removeCol
	 * @return target의 row 행과 col 열을 제외한 소행렬
	 */
	public Matrix minor(int removeRow, int removeCol) {
		int ar = 0, ac = 0;
		double temp[][] = new double[row - 1][col - 1];

		for (int r = 0; r < row; r++) {
			for (int c = 0; c < col; c++) {
				if (!(r == removeRow || c == removeCol)) {
					temp[ar][ac] = matrix[r][c];
					if (++ac >= col - 1) {
						if (++ar < row - 1)
							ac = 0;
					}
				}
			}
		}
		return new Matrix(temp);
	}

	/**
	 * 행렬의 합
	 * 
	 * @param A
	 * @param B
	 * @return
	 */
	public static Matrix plus(Matrix A, Matrix B) {
		double[][] temp = Matrix.zeros(A.row, A.col).getMatrix();
		double[][] tempA = A.getMatrix();
		double[][] tempB = B.getMatrix();
		if (equalSize(A, B)) {
			for (int i = 0; i < tempA.length; i++) {
				for (int k = 0; k < tempA[0].length; k++) {
					temp[i][k] = tempA[i][k] + tempB[i][k];
				}
			}
			return new Matrix(temp);
		}
		return new Matrix(temp);
	}

	/**
	 * 행렬의 차
	 * 
	 * @param A
	 * @param B
	 * @return
	 */
	public static Matrix minus(Matrix A, Matrix B) {
		double[][] temp = Matrix.zeros(A.row, A.col).getMatrix();
		double[][] tempA = A.getMatrix();
		double[][] tempB = B.getMatrix();
		if (equalSize(A, B)) {
			for (int i = 0; i < tempA.length; i++) {
				for (int k = 0; k < tempA[0].length; k++) {
					temp[i][k] = tempA[i][k] - tempB[i][k];
				}
			}
			return new Matrix(temp);
		}
		return new Matrix(temp);
	}

	/**
	 * 행렬의 모양 비교
	 * 
	 * @param A
	 * @param B
	 * @return
	 */
	public static boolean equalSize(Matrix A, Matrix B) {
		if (A.getRowSize() == B.getRowSize()
				&& A.getColSize() == B.getColSize()) {
			return true;
		} else {
			return false;
		}
	}

	Matrix(int i) // 행,열 의 크기가 같은 생성자
	{
		this.row = i;
		this.col = i;
		matrix = new double[i][i];
		for (int a = 0; a < i; a++) {
			for (int b = 0; b < i; b++) {
				matrix[a][b] = (int) (Math.random() * 10 * Math.pow(-1,
						(int) Math.random() * 10));
			}
		}
	}

	Matrix(int row, int col) // 행 열의 크기가 다른 생성자
	{
		this.row = row;
		this.col = col;
		matrix = new double[row][col];
		for (int i = 0; i < row; i++) {
			for (int k = 0; k < col; k++) {
				matrix[i][k] = (int) (Math.random() * 10 * Math.pow(-1,
						(int) Math.random() * 10));
			}
		}
	}

	public Matrix(double[][] temp) // 임의의 행렬을 입력받는 생성
	{
		this.matrix = temp;
		row = temp.length;
		col = temp[0].length;
	}

	/**
	 * 
	 * @return 행렬 원소중 Not a Number 인 원소가 있다면 true
	 */
	public boolean isNaN() {
		for (int i = 0; i < col; i++)
			for (int j = 0; j < row; j++)
				if (Double.isNaN(matrix[j][i]))
					return false;
		return true;
	}

	/**
	 * 자기 자신을 영행렬로 바꾸기
	 */
	public void setZeroMatrix() {
		for (int i = 0; i < row; i++) {
			for (int k = 0; k < col; k++) {
				matrix[i][k] = 0;
			}
		}
	}

	/**
	 * 자기 자신을 모두 1인 행렬로 바꿈
	 */
	public void setOnesMatrix() {
		for (int i = 0; i < row; i++) {
			for (int k = 0; k < col; k++) {
				matrix[i][k] = 1;
			}
		}
	}

	/**
	 * 자기자신을 단위행렬로
	 */
	public void setUnitMatrix() {
		setZeroMatrix();
		for (int i = 0; i < row; i++) {
			matrix[i][i] = 1;
		}
	}

	public void displayMatix() {
		System.out.println(this);
	}

	@Override
	public String toString() {
		String temp = "";
		for (int i = 0; i < row; i++) {
			for (int k = 0; k < col; k++) {
				if (matrix[i][k] == -0) {
					// 이 부분이 없으면 -0과 0이 동시에 나오게 된다
					matrix[i][k] = 0;
				}
				temp += Double.toString(matrix[i][k]);
				// C 의 printf와 유사
				if (k != col - 1) {
					temp += ",  ";
				}
			}
			temp += System.getProperty("line.separator");
		}
		return temp;
	}

	/**
	 * 여인수
	 * 
	 * @param row
	 * @param col
	 * @return
	 */
	public double cofactor(int row, int col) {
		return minor(row, col).determinant() * Math.pow((-1), row + col);
	}

	/**
	 * @param temp
	 *            행렬의 값을 temp로 바꿈
	 */
	public void setMatrix(double temp[][]) {
		// 행렬 내용 수정 temp와 matrix가 다를시 문제가 생길수 있음
		// length로 행과 열의 길이 파악
		this.row = temp.length;
		this.col = temp[0].length;
		this.matrix = temp;
	}

	/**
	 * 전치행렬
	 * 
	 * @return 이 행렬의 전치행렬
	 */
	public Matrix transpose() {
		Matrix tempM = new Matrix(col, row);
		double temp[][] = new double[col][row];
		for (int i = 0; i < row; i++) {
			for (int k = 0; k < col; k++) {
				temp[k][i] = matrix[i][k];
			}
		}
		tempM.setMatrix(temp);
		return tempM;
	}

	/**
	 * 행렬의 상수배
	 * 
	 * @param m
	 *            행렬에 곱할 수
	 * @return 현재 행렬의 m 배된 행렬
	 */
	public Matrix multiply(double m) {
		Matrix temp = new Matrix(row, col);
		for (int i = 0; i < row; i++) {
			for (int k = 0; k < col; k++) {
				temp.matrix[i][k] = this.matrix[i][k] * m;
			}
		}
		return temp;
	}

	/**
	 * 행렬의 곱
	 * 
	 * @param secMatrix
	 *            현재 행렬에 곱해질 행렬
	 * @return 현재 행렬X secMatrix
	 */
	public Matrix multiply(Matrix secMatrix) // 행렬*행렬
	{
		// Matrix temp;
		double[][] temp;
		// 곱하기 위해 앞쪽 행렬의 열과 뒷쪽행렬의 행이 같아야함
		if (this.col == secMatrix.row) {
			temp = Matrix.zeros(this.row, secMatrix.col).getMatrix();
			double[][] A = this.getMatrix();
			double[][] B = secMatrix.getMatrix();
			for (int i = 0; i < this.row; i++) {
				for (int j = 0; j < secMatrix.col; j++) {
					for (int a = 0; a < this.col; a++) {
						// System.out.println("i="+i+" k="+k+" a="+a);
						// //테스트
						temp[i][j] += A[i][a] * B[a][j];
					}
				}
			}
			return new Matrix(temp);
		} else {
			System.out.println("계산할 수 없습니다.");
			return Matrix.zeros(1);
		}

	}

	/**
	 * 역행렬
	 * invers()를 사용할것
	 * 
	 * @return 현재 행렬의 역행렬
	 */
	@Deprecated
	public Matrix invers1() {
		// 역행렬// 행렬의 크기가 8x8이 넘어가면 출력하는데 시간이 너무 오래걸린다.
		// 알고리즘의 최적화가 필요한듯 하다. ->invers() 알고리즘 변경
		Matrix temp = null;
		if (row == col) // 행==열인 행렬인지 확인
		{
			temp = Matrix.zeros(row);
			for (int i = 0; i < row; i++) {
				for (int j = 0; j < row; j++) {
					temp.matrix[i][j] = cofactor(i, j);
					// i행j열의 값 =여인수(i,j)
				}

			}
			temp = temp.transpose();// 전치
			double det = determinant1(this);
			// 원래 행렬의 행렬식계산
			if (det != 0) {
				return temp.multiply(1.0 / det);
				// 마지막으로 행렬식으로 나눠준다.
			} else {
				System.out.println("역행렬이 없습니다.");
				// 행렬식==0이면 역행렬이 없다.
				return Matrix.zeros(1);
			}

		} else {
			System.out.println("행과 열의 크기가 같지 않습니다.");
			return Matrix.zeros(1);
		}
	}

	/**
	 * 역행렬
* 가우스 조던 소거법 * invers1에 비하여 매우 빠르다 invers 는 9차 이상의 행렬에서 * 동작속도를 보장할수 없다. * 하지만 이것은 100차 행렬이 넘어가도 빠른속도로 계산이 가능하다. * 하지만 역행렬이 존재 하지 않는 행렬에서도 답이 나오므로 선행해서 걸러낼 필요가 * 있다. * 마지막에 원래 행렬과 만들어진 역행렬을 곱해서 단위행렬이 나오는지 검사 * * @return 현재 행렬의 역행렬. 역행렬을 만들수 없는 경우에는 null */ public Matrix invers() { double[][] temp = new double[row][row]; // temp=this.getMatrix()로 하면 레퍼런스로 되어서 본래 행렬이 // 변경됨 for (int i = 0; i < row; i++) { for (int j = 0; j < row; j++) { temp[i][j] = matrix[i][j]; } } double[][] comp = Matrix.unitMatrix(col).getMatrix(); for (int n = 0; n < col; n++) { if (temp[n][n] == 0) // { for (int k = n; k < col; k++) { if (temp[k][n] != 0) { for (int a = 0; a < col; a++) { comp[n][a] = comp[n][a] + comp[k][a]; temp[n][a] = temp[n][a] + temp[k][a]; } break; } } } double p = temp[n][n]; for (int a = 0; a < col; a++) { comp[n][a] /= p; temp[n][a] /= p; } for (int i = 0; i < col; i++) { if (i != n) { double p1 = temp[i][n]; for (int j = col - 1; j >= 0; j--) { comp[i][j] -= p1 * comp[n][j]; temp[i][j] -= p1 * temp[n][j]; } } } } Matrix tempReturn = new Matrix(comp); if (multiply(tempReturn).equals(Matrix.unitMatrix(row))) { // 만들어진 결과가 역행렬이 맞는지 확인 return tempReturn; } else { // 아닐경우 null리턴 System.out.println("경고)역행렬이 존재하않는 행렬일수 있습니다."); return null; } } /** * 왼쪽 나눗셈
* 선형방정식의 해를 구할때 씀 this*X=temp, X=this'*temp 일때 * X를 구할수있다. * * @param temp * @return */ public Matrix leftDivision(Matrix temp) { return this.invers().multiply(temp); } /** * 수반행렬 * * @return */ public Matrix adjoint() { double temp[][] = new double[row][col]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { temp[i][j] = cofactor(i, j); } } return new Matrix(temp); } /** * 행렬식 * * @return */ public double determinant() // 행렬식 { return Matrix.determinant(this); } public String size() // 전채 크기를 String로 리턴 배열로 리턴하려했으나 조금 문제가 있음 { return row + " " + col; } /** * * @return Matrix의 배열을 리턴 */ public double[][] getMatrix() { return matrix; } /** * * @return 행의 크기 */ public int getRowSize() { return this.row; } /** * * @return 열의 크기 */ public int getColSize() { return col; } /** * 행렬의 덧셈 * * @param A * 더해질 행렬 * @return 현재 행렬에 A 를 더한 행렬 */ public Matrix plus(Matrix A) { double[][] temp = Matrix.zeros(A.row, A.col).getMatrix(); if (equalSize(A, this)) { for (int i = 0; i < A.getRowSize(); i++) { for (int k = 0; k < A.getColSize(); k++) { temp[i][k] = A.matrix[i][k] + this.matrix[i][k]; } } return new Matrix(temp); } return new Matrix(temp); } /** * 행렬의 뺄셈 * * @param A * 더해질 뺄셈 * @return 현재 행렬에 A 를 뺀 행렬 */ public Matrix minus(Matrix A) { // 행렬 뺄셈 double[][] temp = Matrix.zeros(A.row, A.col).getMatrix(); if (equalSize(A, this)) { for (int i = 0; i < A.getRowSize(); i++) { for (int k = 0; k < A.getColSize(); k++) { temp[i][k] = A.matrix[i][k] - this.matrix[i][k]; } } return new Matrix(temp); } return new Matrix(temp); } /** * * @param m * 비교할 행렬 * @return 현재 행렬과 m이 같으면 true */ public boolean equals(Matrix m) { if (m.row == this.row && m.col == this.col) { for (int i = 1; i < row; i++) { for (int j = 1; j < col; j++) { if (Math.abs(m.matrix[i][j] - this.matrix[i][j]) >= 0.0000001) { // 컴퓨터로 계산한 값이기 때문에 두 값의 차가 // 0.0000001 보다 작으면 같다고 볼수 있다. // 행렬의 원소 자체가 매우 작으면 문제가 발생할수 // 있으나 이경우는 무시하기로한다 return false; } } } } return true; } }

'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 동적할당
: