package jnt.scimark2; /** LU matrix factorization. (Based on TNT implementation.) Decomposes a matrix A into a triangular lower triangular factor (L) and an upper triangular factor (U) such that A = L*U. By convnetion, the main diagonal of L consists of 1's so that L and U can be stored compactly in a NxN matrix. */ public class LU { /** Returns a <em>copy</em> of the compact LU factorization. (useful mainly for debugging.) @return the compact LU factorization. The U factor is stored in the upper triangular portion, and the L factor is stored in the lower triangular portion. The main diagonal of L consists (by convention) of ones, and is not explicitly stored. */ public static final double num_flops(int N) { // rougly 2/3*N^3 double Nd = (double) N; return (2.0 * Nd *Nd *Nd/ 3.0); } protected static double[] new_copy(double x[]) { int N = x.length; double T[] = new double[N]; for (int i=0; i<N; i++) T[i] = x[i]; return T; } protected static double[][] new_copy(double A[][]) { int M = A.length; int N = A[0].length; double T[][] = new double[M][N]; for (int i=0; i<M; i++) { double Ti[] = T[i]; double Ai[] = A[i]; for (int j=0; j<N; j++) Ti[j] = Ai[j]; } return T; } public static int[] new_copy(int x[]) { int N = x.length; int T[] = new int[N]; for (int i=0; i<N; i++) T[i] = x[i]; return T; } protected static final void insert_copy(double B[][], double A[][]) { int M = A.length; int N = A[0].length; int remainder = N & 3; // N mod 4; for (int i=0; i<M; i++) { double Bi[] = B[i]; double Ai[] = A[i]; for (int j=0; j<remainder; j++) Bi[j] = Ai[j]; for (int j=remainder; j<N; j+=4) { Bi[j] = Ai[j]; Bi[j+1] = Ai[j+1]; Bi[j+2] = Ai[j+2]; Bi[j+3] = Ai[j+3]; } } } public double[][] getLU() { return new_copy(LU_); } /** Returns a <em>copy</em> of the pivot vector. @return the pivot vector used in obtaining the LU factorzation. Subsequent solutions must permute the right-hand side by this vector. */ public int[] getPivot() { return new_copy(pivot_); } /** Initalize LU factorization from matrix. @param A (in) the matrix to associate with this factorization. */ public LU( double A[][] ) { int M = A.length; int N = A[0].length; //if ( LU_ == null || LU_.length != M || LU_[0].length != N) LU_ = new double[M][N]; insert_copy(LU_, A); //if (pivot_.length != M) pivot_ = new int[M]; factor(LU_, pivot_); } /** Solve a linear system, with pre-computed factorization. @param b (in) the right-hand side. @return solution vector. */ public double[] solve(double b[]) { double x[] = new_copy(b); solve(LU_, pivot_, x); return x; } /** LU factorization (in place). @param A (in/out) On input, the matrix to be factored. On output, the compact LU factorization. @param pivit (out) The pivot vector records the reordering of the rows of A during factorization. @return 0, if OK, nozero value, othewise. */ public static int factor(double A[][], int pivot[]) { int N = A.length; int M = A[0].length; int minMN = Math.min(M,N); for (int j=0; j<minMN; j++) { // find pivot in column j and test for singularity. int jp=j; double t = Math.abs(A[j][j]); for (int i=j+1; i<M; i++) { double ab = Math.abs(A[i][j]); if ( ab > t) { jp = i; t = ab; } } pivot[j] = jp; // jp now has the index of maximum element // of column j, below the diagonal if ( A[jp][j] == 0 ) return 1; // factorization failed because of zero pivot if (jp != j) { // swap rows j and jp double tA[] = A[j]; A[j] = A[jp]; A[jp] = tA; } if (j<M-1) // compute elements j+1:M of jth column { // note A(j,j), was A(jp,p) previously which was // guarranteed not to be zero (Label #1) // double recp = 1.0 / A[j][j]; for (int k=j+1; k<M; k++) A[k][j] *= recp; } if (j < minMN-1) { // rank-1 update to trailing submatrix: E = E - x*y; // // E is the region A(j+1:M, j+1:N) // x is the column vector A(j+1:M,j) // y is row vector A(j,j+1:N) for (int ii=j+1; ii<M; ii++) { double Aii[] = A[ii]; double Aj[] = A[j]; double AiiJ = Aii[j]; for (int jj=j+1; jj<N; jj++) Aii[jj] -= AiiJ * Aj[jj]; } } } return 0; } /** Solve a linear system, using a prefactored matrix in LU form. @param LU (in) the factored matrix in LU form. @param pivot (in) the pivot vector which lists the reordering used during the factorization stage. @param b (in/out) On input, the right-hand side. On output, the solution vector. */ public static void solve(double LU[][], int pvt[], double b[]) { int M = LU.length; int N = LU[0].length; int ii=0; for (int i=0; i<M; i++) { int ip = pvt[i]; double sum = b[ip]; b[ip] = b[i]; if (ii==0) for (int j=ii; j<i; j++) sum -= LU[i][j] * b[j]; else if (sum == 0.0) ii = i; b[i] = sum; } for (int i=N-1; i>=0; i--) { double sum = b[i]; for (int j=i+1; j<N; j++) sum -= LU[i][j] * b[j]; b[i] = sum / LU[i][i]; } } private double LU_[][]; private int pivot_[]; }