2010-01-02 3 views
9

Java에서 역행렬을 계산하려고합니다.Java 역행렬 계산

나는 adjoint 방법을 사용하고있다. (adjoint 행렬의 첫 번째 계산을하고,이 행렬을 조인하고 마지막으로 행렬식의 역함수에 곱한다.)

매트릭스가 너무 크지 않을 때 작동합니다. 필자는 12x12 크기의 행렬에 대해 결과가 신속하게 제공되는지 확인했습니다. 그러나 행렬이 12x12보다 클 때 계산을 완료하는 데 필요한 시간이 기하 급수적으로 증가합니다.

반전해야하는 행렬은 19x19이고 너무 많은 시간이 걸립니다. 더 많은 시간을 소비하는 방법은 행렬식의 계산에 사용되는 방법입니다.

내가 사용하는 코드는 다음과 같습니다

public static double determinant(double[][] input) { 
    int rows = nRows(input);  //number of rows in the matrix 
    int columns = nColumns(input); //number of columns in the matrix 
    double determinant = 0; 

    if ((rows== 1) && (columns == 1)) return input[0][0]; 

    int sign = 1;  
    for (int column = 0; column < columns; column++) { 
    double[][] submatrix = getSubmatrix(input, rows, columns,column); 
    determinant = determinant + sign*input[0][column]*determinant(submatrix); 
    sign*=-1; 
    } 
    return determinant; 
} 

사람이보다 효율적으로 큰 행렬의 행렬식을 계산하는 방법을 알고 있나요? 그렇지 않다면 다른 알고리즘을 사용하여 큰 행렬의 역함수를 계산하는 방법을 아는 사람이 있습니까?

감사합니다.

+0

@duffymo : 답변 해 주셔서 감사합니다. 당신이 옳습니다, 기하 급수적으로 말이 아닙니다. 행렬 크기 12x12에서 행렬식을 계산하는 데 걸리는 시간이 눈에 띄게 증가한다는 것을 의미합니다. 나는 Jama를 사용해 봤지만, 제대로 작동하지 않는다. (나는 Java에서 꽤 새로운 것이다.) LU 분해에 대해서도 살펴볼 것입니다. 감사합니다. . – dedalo

+0

알고리즘이 실제로 지수 함수이기 때문에 "기하 급수적으로"정확하지 않지만, 역행렬 또는 행렬식 계산이 * 지수 *를 요구하지 않는다는 점에서 Duffymo 또한 정확합니다. – JaakkoK

+0

감사합니다. 나는 Jama를보고 클래스 Matrix에서 'det'이라는 메서드를 찾았습니다.이 메서드는이를 빠르게 계산합니다.나는 또한 행렬 L과 U (A = L * U)를 계산하고 det (A) = det (L) * det (U)를 계산하는 방법을 찾았다. – dedalo

답변

14

지수가? 아니, 매트릭스 반전은 O (N^3)라고 생각합니다.

행렬 방정식을 풀려면 LU decomposition을 사용하는 것이 좋습니다. 행렬식을 사용할 때이를 결정할 필요는 없습니다.

아직 도움이되는 패키지를 살펴보십시오. JAMA이 떠오른다.

12x12 또는 19x19는 큰 matricies가 아닙니다. 자유도가 수십 또는 수백이되는 수천의 문제를 해결하는 것이 일반적입니다.

다음은 JAMA 사용 방법의 실제 예입니다.

package linearalgebra; 

import Jama.LUDecomposition; 
import Jama.Matrix; 

public class JamaDemo 
{ 
    public static void main(String[] args) 
    { 
     double [][] values = {{1, 1, 2}, {2, 4, -3}, {3, 6, -5}}; // each array is a row in the matrix 
     double [] rhs = { 9, 1, 0 }; // rhs vector 
     double [] answer = { 1, 2, 3 }; // this is the answer that you should get. 

     Matrix a = new Matrix(values); 
     a.print(10, 2); 
     LUDecomposition luDecomposition = new LUDecomposition(a); 
     luDecomposition.getL().print(10, 2); // lower matrix 
     luDecomposition.getU().print(10, 2); // upper matrix 

     Matrix b = new Matrix(rhs, rhs.length); 
     Matrix x = luDecomposition.solve(b); // solve Ax = b for the unknown vector x 
     x.print(10, 2); // print the solution 
     Matrix residual = a.times(x).minus(b); // calculate the residual error 
     double rnorm = residual.normInf(); // get the max error (yes, it's very small) 
     System.out.println("residual: " + rnorm); 
    } 
} 

여기 quant_dev의 권고에 따라, 아파치 코 몬즈 수학을 사용하여 해결했다 동일한 문제입니다 :

package linearalgebra; 

import org.apache.commons.math.linear.Array2DRowRealMatrix; 
import org.apache.commons.math.linear.ArrayRealVector; 
import org.apache.commons.math.linear.DecompositionSolver; 
import org.apache.commons.math.linear.LUDecompositionImpl; 
import org.apache.commons.math.linear.RealMatrix; 
import org.apache.commons.math.linear.RealVector; 

public class LinearAlgebraDemo 
{ 
    public static void main(String[] args) 
    { 
     double [][] values = {{1, 1, 2}, {2, 4, -3}, {3, 6, -5}}; 
     double [] rhs = { 9, 1, 0 }; 

     RealMatrix a = new Array2DRowRealMatrix(values); 
     System.out.println("a matrix: " + a); 
     DecompositionSolver solver = new LUDecompositionImpl(a).getSolver(); 

     RealVector b = new ArrayRealVector(rhs); 
     RealVector x = solver.solve(b); 
     System.out.println("solution x: " + x);; 
     RealVector residual = a.operate(x).subtract(b); 
     double rnorm = residual.getLInfNorm(); 
     System.out.println("residual: " + rnorm); 
    } 
} 

를 상황에 이러한 적응 컴파일하고 실행하면 당신은 당신의 CLASSPATH에서 JAMA의 JAR을 가지고 있습니다.

+0

답변 해 주셔서 감사합니다. 당신이 옳습니다, 기하 급수적으로 말이 아닙니다. 행렬 크기 12x12에서 행렬식을 계산하는 데 걸리는 시간이 눈에 띄게 증가한다는 것을 의미합니다. 나는 Jama를 사용해 봤지만, 제대로 작동하지 않는다. (나는 Java에서 꽤 새로운 것이다.) LU 분해에 대해서도 살펴볼 것입니다. 감사합니다. – dedalo

+1

실험실에서 수십억 개의 자유도가있는 매트릭스를 잠시 동안 풀어 냈습니다. 수백 또는 수천 개의 프로세서에서 자연스럽게 – notJim

+1

한 달 동안 한 가지 문제가 발생했습니다. 다중 프로세서가 일반적으로 사용되기 전에는 유닉스 워크 스테이션에서 실행되었습니다. 결과가 추락하여 다시 시작해야하는 경우 너무 많은 시간을 낭비하지 않도록 일주일에 한 번 결과를 검사해야했습니다. – duffymo

3

매트릭스 반전은 계산적으로 매우 집중적입니다. duffymo는 LU가 좋은 알고리즘이라고 답했고 다른 변종 (QR 등)이 있습니다.

불행히도 무거운 계산을 없앨 수는 없으며 최적화 된 라이브러리를 사용하지 않는 경우 bottelneck은 getSubmatrix 메소드입니다.

또한 특수 매트릭스 구조 (밴드 매트릭 시티, 대칭, 대각선, 희소성)는 계산시 고려해 보면 성능에 큰 영향을 미칩니다. 귀하의 마일리지는 다를 수 있습니다 ...

3

이런 식으로 역행렬을 계산하고 싶지는 않습니다. 자, 역 자체의 계산은 피하는 것이 좋습니다. 왜냐하면 LU와 같은 인수 분해를 사용하는 것이 거의 항상 바람직하기 때문입니다.

재귀 계산을 사용한 행렬식의 계산은 수치 적으로 외설적 인 일입니다. 더 나은 선택은 LU 인수 분해를 사용하여 행렬식을 계산하는 것입니다.그러나 LU 팩터를 계산하는 데 신경을 써야한다면 왜 역행을 계산할 것입니까? LU 요소를 계산하여 이미 어려운 작업을 수행했습니다.

일단 LU 계수가 있으면이를 사용하여 앞뒤 대체를 할 수 있습니다.

19x19 크기의 매트릭스가 크다면, 내가 생각하는 것과 비슷하지 않을 수도 있습니다.

1

게임에서 Matlab을 이길 수 없습니다. 그들은 또한 정밀도에 대해주의를 기울이고있다. 당신이 2.0과 2.00001을 피벗으로 가지고 있다면 - 조심해! 귀하의 대답은 매우 부정확하게 끝날 수도 있습니다. 또한 Python의 구현을 확인하십시오 (numpy/scipy 어딘가에 있습니다 ...)

2

결정자를 계산하는 알고리즘은 실제로 지수 함수입니다. 기본적인 문제는 당신이 정의로부터 계산하고 있고, 직선적 인 정의가 지수 적으로 계산할 하위 결정자를 유도한다는 것입니다. 행렬식을 변환하기 전에 행렬식을 먼저 변환해야합니다. 동적 프로그래밍에 대해 설명하려고 생각했지만 하위 문제의 수가 기하 급수적으로 늘어남에 따라 동적 프로그래밍으로는이 문제를 해결할 수 없습니다.

다른 사람이 권장하는대로 LU 분해가 좋은 선택입니다. 행렬 계산을 처음 사용하는 경우 처음에는 이해하기가 더 쉬울 수 있으므로 가우스 제거를 사용하여 행렬식과 역원을 계산할 수도 있습니다.

매트릭스 반전에서 기억해야 할 것은 부동 소수점 숫자를 다루기 때문에 숫자 안정성입니다. 좋은 알고리즘은 호출 될 때 적절한 피벗을 선택하기 위해 행 및/또는 열의 순열을 포함합니다. 적어도 가우시안 제거에서는 각 단계에서 절대 값이 가장 큰 요소가 피벗으로 선택되도록 열을 바꾸기를 원합니다. 이것이 가장 안정된 선택입니다.

9

Apache Commons Math 2.0을 사용하는 것이 좋습니다. JAMA는 죽은 프로젝트입니다. ACM 2.0은 실제로 선형 대수학을 JAMA에서 가져 와서 더 발전 시켰습니다.

+0

몰랐는데, quant_dev. 정보 주셔서 감사합니다. – duffymo

1

정확한 해결책이 필요합니까? 근사 해법 (Gauss-Seidel은 매우 실행 가능하고 구현하기 쉽다)이 당신을 위해 잘 작동 할 것이고, 매우 빨리 수렴 할 것이다. 19x19는 꽤 작은 행렬입니다. Gauss-Seidel 코드는 눈 깜짝 할 사이에 128x128 행렬을 풀 수 있다고 생각합니다. (그러나 그 말은 인용하지 마십시오.

2

la4j (Java 용 선형 대수) 라이브러리는 행렬 반전을 지원합니다. ACM 라이브러리는 수년에 걸쳐 업데이트했습니다

Matrix a = new Basic2DMatrix(new double[][]{ 
    { 1.0, 2.0, 3.0 }, 
    { 4.0, 5.0, 6.0 }, 
    { 7.0, 8.0. 9.0 } 
}); 

Matrix b = a.invert(Matrices.DEFAULT_INVERTOR); // uses Gaussian Elimination 
1

때문에, 여기 매트릭스 반전을위한 최신 정의에 부합하는 구현은 다음과 같습니다 여기에 간단한 예입니다.

import org.apache.commons.math3.linear.Array2DRowRealMatrix; 
import org.apache.commons.math3.linear.ArrayRealVector; 
import org.apache.commons.math3.linear.DecompositionSolver; 
import org.apache.commons.math3.linear.LUDecomposition; 
import org.apache.commons.math3.linear.RealMatrix; 
import org.apache.commons.math3.linear.RealVector; 

public class LinearAlgebraDemo 
{ 
    public static void main(String[] args) 
    { 
     double [][] values = {{1, 1, 2}, {2, 4, -3}, {3, 6, -5}}; 
     double [][] rhs = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; 

     // Solving AB = I for given A 
     RealMatrix A = new Array2DRowRealMatrix(values); 
     System.out.println("Input A: " + A); 
     DecompositionSolver solver = new LUDecomposition(A).getSolver(); 

     RealMatrix I = new Array2DRowRealMatrix(rhs); 
     RealMatrix B = solver.solve(I); 
     System.out.println("Inverse B: " + B); 
    } 
} 
+0

이 에러는 AWT-EventQueue-0 org.apache.commons.math3.linear.SingularMatrixException : 행렬의 예외는 행렬이 같은 크기를 사용해야한다는 것을 의미합니다. – zygimantus

-1

LU 분해는 희소 행렬에 대해 잘 작동합니다. 가우스 요르단은 그렇지 않을 수도 있습니다. Dodgson 방법을 시도 할 수도 있지만 0으로 나누면주의해야합니다.

+0

큰 비 - 희소 매트릭스의 경우 역변환이 필요했고, LU 분해가 실제로 엉망이었습니다. 조건 번호는 1e-20에서 1e-500으로 변경되었습니다. 나는 나를 얕보는 사용자가이 분야에 대한 나의 전문성을 가지고 있는지 의심 스럽다. –