/*## ## class NFull ## ## This class contains the factor, determ, inverse, conditon, and solve ## for full matrices. It also contains the Singular Value Decompostion, ## QR-decomposition, and Cholesky updating routines. ## This class has methods to compute the transpose of a matrix and several ## matrix-matrix and matrix-vector multiplication routines. ## ##*/ package edu.rice.linpack.Matrix.NMatrix; import edu.rice.linpack.LNumber.*; import edu.rice.linpack.util.*; public class NFull extends NMatrix { public NFull() { super(); cons(); } public NFull(int i, int j) { cons(i,j); } public NFull(LNumber[][] f) { cons(f); } /*## ## This is the copy constructor. ##*/ public NFull(NFull F) { cons(F); } /*## ## This is the constructor that allows for the manipulation of a ## subsection of a matrix by creating a new NFull from the subsection. ##*/ public NFull(int ni, int nj, LNumber[][] f, int strow, int stcol) { rows = ni; cols = nj; Mat = new LNumber[rows][cols]; for(int i=0;i=i1 && k=ml) B.setElem(k,j,Mat[i][j]); else { LNumber T = newOfType(); T.setZero(); B.setElem(k,j,T); } } } } return B; } /*## ## These routines set the pivot array of an NFull. ## This is necessary for qrPDecompose. ##*/ public void setPivot(int i, int p) { pivot[i] = p; } public void setPivots(int[] p) { int q = Math.min(p.length,cols); for(int i=0;i= 2 Return the first min(rows,cols) singluar ## vectors in U. ## B == 0 Do not compute the right singular ## vectors. ## B == 1 Return the right singular vectors ## in V. ## ## On Return: ## ## S LNumber[MM], where MM = Math.min(rows+1,cols). ## The first min(rows,cols) entries of S contain the ## singular values of this NFull arranged in ## descending order of magnitude. ## ## E LNumber[cols] ## E ordinarily contains zeros. However see the ## discussion of info for exceptions. ## ## U LNumber[rows][k], where if job(A) == 1 then k == rows ## else k == Min(rows,cols). ## U contains the NFull of right singular vectors. ## U is not referenced if job(A) == 0. ## ## V LNumber[cols][cols] ## V contains the NFull of right singular vectors. ## V is not referenced if job == 0. ## ## info int ## The singular values (and their corresponding ## singular vectors) S(info),S(info+1),...,S(M-1) ## are correct (here M=min(rows,cols)). Thus if ## info == 0, all the singular values and their ## vectors are correct. In any event, the matrix ## B = U.transpose()*this*V is the bidiagonal matrix ## with the elements of S on its diagonal and the ## elements of E on its super-diagonal. Thus the ## singular values of this and B are the same. ##*/ public int svDecompose(LNumber[] S, LNumber[] E, NFull U, NFull V, int job) { LNumber[] W = new LNumber[rows]; int info = 0; /*## ## This is the maximum number of iterations. ##*/ int MAXIT = 30; /*## ## Determine what is to be computed ##*/ boolean wantU = false; boolean wantV = false; int jobu = (job%100)/10; int NCU = rows; if(jobu > 1) NCU = Math.min(cols,rows); if(jobu != 0) wantU = true; if(job%10 != 0) wantV = true; /*## ## Reduce Mat to bidiagonal form, storing the diagonal elements ## in S and the super-diagonal elements in E. ##*/ int NCT = Math.min(rows-1,cols); int NRT = Math.max(0,Math.min(cols-2,rows)); int lu = Math.max(NCT,NRT); for(int q=0;q0) { /*## ## If too many iterations have been performed, return error flag. ##*/ if(iter >= MAXIT) return M; else { /*## ## qgetter determines what to do next by searching for negligible ## elements in S and E. ##*/ int q = qgetter(M-2,S,E); if(q == M-2) { /*## ## E[M-2] is negligible (convergence). ##*/ q++; /*## ## Make the singular value positive. ##*/ if(S[q].lessThan(0)) { S[q].negateTo(); if(wantV) V.scal(cols,-1,1,0,q); } /*## ## Order the singular value. ##*/ boolean notDone = true; while(q < MM-1 && notDone) { if(S[q].lessThan(S[q+1])) { NUtil.swapElems(S,q,q+1); if(wantV && q < cols-1) V.swap(cols,1,0,q,V,1,0,q+1); if(wantU && q < rows-1) U.swap(rows,1,0,q,U,1,0,q+1); q++; } else notDone = false; } iter = 0; M--; } else { /*## ## If there is not convergence, findNextStep helps qgetter ## determine what to do next. ##*/ int qs = this.findNextStep(q,M,S,E); if(qs == q) { /*## ## E[q-1] is negligible, q < M, and S[q], ... , S[M-1] are ## not negligible (qr step). ## Perform one qr shift. ##*/ q++; /*## ## Calculate the shift. ##*/ NTrig Tg = this.fggetter(q,M,S,E); /*## ## Chase zeros. ##*/ for(int k=q;k=q;k--) { // S[k] should only be real - is this a prob? Tg.setA(S[k].realPt()); NUtil.rotg(Tg); S[k] = Tg.getA(); if(k != q) { // Need it here, too Tg.setB(((Tg.getSin()).mult(E[k-1].realPt())).negateTo()); E[k-1].multTo(Tg.getCos()); } if(wantV) V.rot(cols,1,0,k,V,1,0,MMOne+1,Tg); } } else { /*## ## S[q] is negligible and q < M. ## Split at negligible S[q]. ##*/ q = qs; NTrig Tg = new NTrig(); // Real part of E[q] wanted here, too Tg.setB(E[q].realPt()); E[q].setZero(); q++; for(int k=q;k 0) { for(int q=NCT-1;q>=0;q--) { if(!S[q].equals(0)) { for(int j=q+1;j=0;q--) { int qp = q+1; if((q < NRT) && (!E[q].equals(0))) { for(int j=qp;j= 0;q--) { LNumber Test = (S[q].modulus()).add(S[q+1].modulus()); LNumber ZTest = Test.add(E[q].modulus()); if(ZTest.equals(Test)) { E[q].setZero(); return q; } } return -1; } private int findNextStep(int q, int M, LNumber[] S, LNumber[] E) { for(int qs=M-1;qs>q;qs--) { LNumber Test = E[qs].modulus(); if(qs == M-1) Test.setZero(); if(qs != q+1) Test.addTo(E[qs-1].modulus()); LNumber Ztest = Test.add(S[qs].modulus()); if(Ztest.equals(Test)) { S[qs].setZero(); return qs; } } return q; } private NTrig fggetter(int q, int M, LNumber[] S, LNumber[] E) { NTrig Tg = new NTrig(); LNumber scale = NUtil.mMax(S[M-1],S[M-2],E[M-2],S[q],E[q]); // These are all supposed to be dreal LNumber SM = (S[M-1].realPt()).div(scale); LNumber SMM = (S[M-2].realPt()).div(scale); LNumber EMM = (E[M-2].realPt()).div(scale); LNumber Sq = (S[q].realPt()).div(scale); LNumber Eq = (E[q].realPt()).div(scale); // It isn't a problem until here LNumber B = (((SMM.add(SM)).mult(SMM.sub(SM))).add(EMM.square())).div(2); LNumber C = (SM.mult(EMM)).square(); LNumber shift = C.Clone(); shift.setZero(); if(!(B.equals(0) && C.equals(0))) { shift = ((B.square()).add(C)).sqrt(); if(!B.greaterOrEqual(0)) shift.negateTo(); shift = C.div(B.add(shift)); } Tg.setA(((Sq.add(SM)).mult(Sq.sub(SM))).sub(shift)); Tg.setB(Sq.mult(Eq)); return Tg; } /*## ## qrDecompose uses Householder transformations to compute the ## QR factorization of an n by p NFull. Column pivoting ## based on the 2-norms of the reduced columns may be ## performed at the user's option. ## ## On Entry: ## ## this NFull - Mat[L][p], where L >= n ## NFull contains the NFull whose decomposition is to ## be computed. ## ## ## n int ## n is the number of rows of NFull.Mat to be used in ## the calculation ## ## p int ## p is the number of columns of NFull.Mat to be used ## in the calculation ## ## pivot int[p] ## pivot contains ints that control the selection ## of the pivot columns. The k-th column NFull.Mat[0][k] ## is placed in one of three classes according to the ## value of pivot[k]: ## ## if pivot[k] > 0, then NFull.getColumn(k,0) is an ## initial column. ## ## if pivot[k] == 0, then NFull.getColumn(k,0) is a ## free column. ## ## if pivot[k] < 0, then NFull.getColumn(k,0) is a ## final column. ## ## Before the decomposition is computed, initial columns ## are moved to the beginning of NFull.Mat and final ## columns to the end. Both initial and final columns ## are frozen in place during the computation and only ## free columns are moved. At the k-th stage of the ## reduction, if NFull.getColumn(k,0) is occupied by a ## free column it is interchanged with the free column of ## largest reduced norm. pivot is not referenced if ## job == 0. ## ## ## On Return ## ## this NFull.Mat contains in its upper triangle the upper ## triangular matrix R of the QR factorization. ## Below its diagonal NFull.Mat contains information ## from which the orthogonal part of the decomposition ## can be recovered. Note that if pivoting has ## been requested, the decomposition is not that ## of the original NFull.Mat, but that of NFull.Mat ## with its columns permuted as described by pivot. ## ## QRaux LNumber[p] ## QRaux contains further information required to recover ## the orthogonal part of the decomposition. ## ## pivot pivot[k-1] contains the index of the column of the ## original matrix that has been interchanged into ## the k-th column, if pivoting was requested. ##*/ public void qrPDecompose(LNumber[] QRaux) { Pul P = new Pul(0,-1); this.qrPivot(P); this.qrDecom(P, QRaux); } private void qrPivot(Pul P) { this.swaperSki(P); P.pu = cols-1; for(int j=P.pu;j>=0;j--) { if(pivot[j] < 0) { pivot[j] = -pivot[j]; if(j != P.pu) { this.swap(rows,1,0,P.pu,this,1,0,j); NUtil.swapElems(pivot,P.pu,j); } P.pu--; } } } void swaperSki(Pul P) { for(int j=0;j 0); if(pivot[j] < 0) pivot[j] = -j-1; else pivot[j] = j+1; if(swapj) this.swap2(j,P); } } void swap2(int j, Pul P) { if(j != P.pl) this.swap(rows,1,0,P.pl,this,1,0,j); pivot[j] = pivot[P.pl]; pivot[P.pl] = j+1; P.pl++; } public void qrDecompose(LNumber[] QRaux) { Pul P = new Pul(0,-1); qrDecom(P,QRaux); } private void qrDecom(Pul P, LNumber[] QRaux) { LNumber[] Work = new LNumber[cols]; for(int j=P.pl;j<=P.pu;j++) { QRaux[j] = this.nrm2(rows,1,0,j); Work[j] = QRaux[j].Clone(); } int qup = Math.min(rows,cols); for(int q=0;q= P.pl && q= P.pl && j <= P.pu) { if(!QRaux[j].equals(0)) { // In this area are 3 dreals that I do not use LNumber TT = (((Mat[q][j].modulus()).div(QRaux[j].realPt())) .square()).subFrom(1); if(!TT.greaterThan(0)) TT.setZero(); T = TT.Clone(); TT = ((TT.mult(((QRaux[j].realPt()).div(Work[j].realPt())) .square())).div(2)).add(1); if(!TT.equals(1)) { //System.out.println("FUNKY SQRT"); QRaux[j].multTo(T.sqrt()); } else { QRaux[j] = this.nrm2(rows-q-1,1,q+1,j); Work[j] = QRaux[j].Clone(); } } } } QRaux[q] = Mat[q][q]; Mat[q][q] = normxq.negate(); } } } } /*## ## The following qr*** routines apply the output of qrDecompose to ## compute coordinate transformations, projections, and least squares ## solutions. ## for k < Min(n,p), let XK be the matrix ## ## XK = (this.getColumn(pivot(0)-1,0), ## this.getColumn(pivot(1)-1,0), ## ... ,this.getColumn(pivot(k)-1,0)); ## ## formed from columns pivot[0], ... , pivot[k] of the original ## n X p matrix NFull.Mat that was input to qrDecompose (if no ## pivoting was done, XK consists of the first k+1 columns of ## NFull.Mat in their original order). qrDecompose produces a ## factored orthogonal matrix Q and an upper triang. matrix R s.t. ## ## XK = Q * (R) ## (0) ## ## this information is contained in coded form in NFull.Mat and QRaux ## ## On Entry ## ## this NFull.Mat[n][p] ## NFull.Mat contains the output of qrDecompose ## ## n int ## n is the number of rows of the matrix XK. It must ## have the same value as n in qrDecompose. ## ## k int ## k is the number of columns of the matrix XK. k ## must not be greater than min(n,p), where p is the ## same as in qrDecompose. ## ## QRaux LNumber[p] ## QRaux contains the auxiliary output from qrDecompose. ## ## Y LNumber[n] ## Y contains the vector that is to be manipulated ## by qr***. ## ## On Return from its respective function ## ## qrQy: ## Qy LNumber[n] ## Qy contains Q*Y ## ## qrQty: ## Qty LNumber[n] ## Qty contains Q.transpose()*Y ## ## qrQB: ## B LNumber[k] ## B contains the solution of the least squares problem ## ## minimize norm2(Y - XK*B), ## ## (Note that if pivoting was requested in qrDecompose, ## the j-th component of B will be associated with column ## pivot[j-1]-1 of the original NFull.Mat that was input ## into qrDecompose.) ## ## info int ## info is zero unless R is exactly singular in the ## computation of B. In this case, info is the index plus ## one of the first zero diagonal element of R and B is ## left unaltered. ## ## qrQRSD: ## Rsd LNumber[n] ## Rsd contains the least squares residual Y - XK*B, ## Rsd is also the orthogonal projection of Y onto the ## orthogonal complement of the column space of XK. ## ## qrXB: ## Xb LNumber[n] ## Xb contains the least squares approximation XK*B, ## Xb is also the orthogonal projection of Y onto the ## column space of NFull.Mat. ##*/ public void qrQy(LNumber[] QRaux, LNumber[] Y, LNumber[] Qy) { int k = Math.min(rows,cols); int ju = Math.min(k,rows-1) - 1; if(ju < 0) Qy[0] = Y[0].Clone(); else { NUtil.copy(rows,Y,1,0,Qy,1,0); for(int j=ju;j>=0;j--) this.qrsolver(j,Qy,QRaux); } } public void qrQty(LNumber[] QRaux, LNumber[] Y,LNumber[] Qty) { int k = Math.min(rows,cols); int ju = Math.min(k,rows-1) - 1; if(ju < 0) Qty[0] = Y[0].Clone(); else { NUtil.copy(rows,Y,1,0,Qty,1,0); for(int j=0;j<=ju;j++) this.qrsolver(j,Qty,QRaux); } } public int qrB(LNumber[] QRaux, LNumber[] Y, LNumber[] Qty, LNumber[] B) { int k = Math.min(cols,rows); int ju = Math.min(k,rows-1) - 1; qrQty(QRaux,Y,Qty); if(ju < 0) { if(Mat[0][0].equals(0)) return 1; else B[0] = Y[0].div(Mat[0][0]); } else { NUtil.copy(k,Qty,1,0,B,1,0); for(int j=k-1;j>=0;j--) { if(Mat[j][j].equals(0)) return j+1; else { B[j].divTo(Mat[j][j]); if(j > 0) this.axpy(j,B[j].negate(),1,0,j,B,1,0); } } } return 0; } public void qrXB(LNumber[] QRaux, LNumber[] Y, LNumber[] Qty, LNumber[] Xb) { int k = Math.min(cols,rows); int ju = Math.min(k,rows-1) - 1; qrQty(QRaux,Y,Qty); if(ju < 0) Xb[0] = Y[0].Clone(); else { NUtil.copy(k,Qty,1,0,Xb,1,0); for(int i=k;i=0;j--) this.qrsolver(j,Xb,QRaux); } } public void qrRSD(LNumber[] QRaux, LNumber[] Y, LNumber[] Qty, LNumber[] Rsd) { int k = Math.min(cols,rows); int ju = Math.min(k,rows-1) - 1; qrQty(QRaux,Y,Qty); if(ju < 0) { Rsd[0] = Y[0].Clone(); Rsd[0].setZero(); } else { int kp = k+1; if(k < rows) NUtil.copy(rows-k,Qty,1,k,Rsd,1,k); for(int i=0;i=0;j--) this.qrsolver(j,Rsd,QRaux); } } private void qrsolver(int j, LNumber[] R, LNumber[] QRaux) { if(!QRaux[j].equals(0)) { LNumber Temp = Mat[j][j].Clone(); Mat[j][j] = QRaux[j]; LNumber T = (dot(rows-j,1,j,j,R,1,j).div(Mat[j][j])).negateTo(); this.axpy(rows-j,T,1,j,j,R,1,j); Mat[j][j] = Temp; } } public void chUpdate(LNumber[] X,LNumber[][] Z,LNumber[] Y, LNumber[] Rho, LNumber[] C, LNumber[] S) { // Update the matrix // for(int j=0;j=0;i--) { LNumber scale = alpha.add(S[i].modulus()); LNumber A = alpha.div(scale); LNumber B = S[i].div(scale); norm = (A.square().add(B.square())).sqrt(); C[i] = A.div(norm); S[i] = B.div(norm); alpha = scale.mult(norm); } for(int j=0;j=0;i--) { T = (C[i].mult(XX)).add(S[i].mult(Mat[i][j])); Mat[i][j] = (C[i].mult(Mat[i][j])).sub(S[i].mult(XX)); XX = T; } } for(int j=0;j=k;j--) { for(int i=0;i<=j;i++) Mat[i][j+1] = Mat[i][j].Clone(); Mat[j+1][j+1].setZero(); } for(int i=0;i 1) { for(int k=0;k < nm; k++) { int kp = k+1; /*## ## Find L the pivot index ##*/ int L = this.i_amax(cols-k,1,k,k) + k; pivot[k] = L+1; /*## ## Zero pivot implies this column already triangularized ##*/ if(!(Mat[L][k].abs()).equals(0)) { /*## ## Interchange if necessary ##*/ if(L != k) this.swapElem(L,k,k,k); /*## ## Compute multipliers ##*/ T = (Mat[k][k].inv()).negateTo(); this.scal(nm-k,T,1,kp,k); /*## ## Row elimination with column indexing ##*/ for(int j=kp;j=0;k--) { if(k < cols-1) { Z[k].addTo(dot(cols-k-1,1,k+1,k,Z,1,k+1)); } if((Z[k].abs()).greaterThan(1)) { LNumber S = (Z[k].abs()).invTo(); NUtil.scal(cols,S,Z,1); } int L = pivot[k] - 1; NUtil.swapElems(Z,L,k); } LNumber S = (NUtil.asum(cols,Z,1)).invTo(); NUtil.scal(cols,S,Z,1); } LNumber solveUZ(LNumber[] Z, LNumber ynorm) { for(int k=cols-1;k>=0;k--) { if((Z[k].abs()).greaterThan(Mat[k][k].abs())) { LNumber S = (Mat[k][k].abs()).div(Z[k].abs()); NUtil.scal(cols,S,Z,1); ynorm.multTo(S); } if(!Mat[k][k].equals(0)) Z[k].divTo(Mat[k][k]); else Z[k].setOne(); this.axpy(k,Z[k].negate(),1,0,k,Z,1,0); } LNumber S = (NUtil.asum(cols,Z,1)).invTo(); NUtil.scal(cols,S,Z,1); ynorm.multTo(S); return ynorm; } /*## ## this.solve solves the single precision system ## A * X = B or A.transpose() * X = B ## using the factors computed by this.condition or this.factor. ## ## On Entry ## ## this.Mat LNumber[n][n] ## The output from this.condition or this.factor. ## ## n int ## The order of this.Mat. ## ## pivot int(n) ## The pivot vector from this.condition or this.factor. ## ## B LNumber[n] ## The right hand side vector. ## ## Job int ## = 0 To solve A*X = B , ## = non-zero To solve A.transpose() * X = B ## ## On Return ## ## B The solution vector X. ## ## Error condition ## ## A division by zero will occur if the input factor contains a ## zero on the diagonal. Technically this indicates singularity ## but it is often caused by improper arguments or improper ## setting of n. It will not occur if the subroutines are ## called correctly and if this.condition has set ## LLNumber.getLNumber > 0 or this.factor threw an exception ## ## To compute A.inverse() * C where C is a FMatrix ## with p columns ## ## this.condition(); ## if (FRcond.Rcond > threshold) { ## for(int j=0;j=0;k--) { B[k].addTo(dot(nm-k,1,k+1,k,B,1,k+1)); int L = pivot[k] - 1; if(L != k) NUtil.swapElems(B,L,k); } } return; } /*## ## Solve U*X = Y ## This function is used by NPoFull ##*/ void solveUX(LNumber[] B) { for(int k=cols-1;k>=0;k--) { B[k].divTo(Mat[k][k]); this.axpy(k,B[k].negate(),1,0,k,B,1,0); } } /*## ## Solve U.transpose() * Y = B ## This function is used by NPoFull ##*/ void solveTransAX (LNumber[] B){ for(int k=0;k 0 or this.factor has set info == 0. ##*/ public void inverse() { /*## ## Compute Inverse of U ##*/ this.invertU(); /*## ## Form inverse(U)*inverse(L) ##*/ if(cols > 1) this.invUinvL(); } void invertU () { for(int k=0;k=0;k--) { int kp = k+1; for(int i=kp;i