| 1 | //$$svd.cpp                           singular value decomposition | 
|---|
| 2 |  | 
|---|
| 3 | // Copyright (C) 1991,2,3,4,5: R B Davies | 
|---|
| 4 | // Updated 17 July, 1995 | 
|---|
| 5 |  | 
|---|
| 6 | #define WANT_MATH | 
|---|
| 7 |  | 
|---|
| 8 | #include "include.h" | 
|---|
| 9 | #include "newmatap.h" | 
|---|
| 10 | #include "newmatrm.h" | 
|---|
| 11 | #include "precisio.h" | 
|---|
| 12 |  | 
|---|
| 13 | #ifdef use_namespace | 
|---|
| 14 | namespace NEWMAT { | 
|---|
| 15 | #endif | 
|---|
| 16 |  | 
|---|
| 17 | #ifdef DO_REPORT | 
|---|
| 18 | #define REPORT { static ExeCounter ExeCount(__LINE__,15); ++ExeCount; } | 
|---|
| 19 | #else | 
|---|
| 20 | #define REPORT {} | 
|---|
| 21 | #endif | 
|---|
| 22 |  | 
|---|
| 23 |  | 
|---|
| 24 | static Real pythag(Real f, Real g, Real& c, Real& s) | 
|---|
| 25 | // return z=sqrt(f*f+g*g), c=f/z, s=g/z | 
|---|
| 26 | // set c=1,s=0 if z==0 | 
|---|
| 27 | // avoid floating point overflow or divide by zero | 
|---|
| 28 | { | 
|---|
| 29 |    if (f==0 && g==0) { c=1.0; s=0.0; return 0.0; } | 
|---|
| 30 |    Real af = f>=0 ? f : -f; | 
|---|
| 31 |    Real ag = g>=0 ? g : -g; | 
|---|
| 32 |    if (ag<af) | 
|---|
| 33 |    { | 
|---|
| 34 |       REPORT | 
|---|
| 35 |       Real h = g/f; Real sq = sqrt(1.0+h*h); | 
|---|
| 36 |       if (f<0) sq = -sq;           // make return value non-negative | 
|---|
| 37 |       c = 1.0/sq; s = h/sq; return sq*f; | 
|---|
| 38 |    } | 
|---|
| 39 |    else | 
|---|
| 40 |    { | 
|---|
| 41 |       REPORT | 
|---|
| 42 |       Real h = f/g; Real sq = sqrt(1.0+h*h); | 
|---|
| 43 |       if (g<0) sq = -sq; | 
|---|
| 44 |       s = 1.0/sq; c = h/sq; return sq*g; | 
|---|
| 45 |    } | 
|---|
| 46 | } | 
|---|
| 47 |  | 
|---|
| 48 |  | 
|---|
| 49 | void SVD(const Matrix& A, DiagonalMatrix& Q, Matrix& U, Matrix& V, | 
|---|
| 50 |    bool withU, bool withV) | 
|---|
| 51 | // from Wilkinson and Reinsch: "Handbook of Automatic Computation" | 
|---|
| 52 | { | 
|---|
| 53 |    REPORT | 
|---|
| 54 |    Tracer trace("SVD"); | 
|---|
| 55 |    Real eps = FloatingPointPrecision::Epsilon(); | 
|---|
| 56 |    Real tol = FloatingPointPrecision::Minimum()/eps; | 
|---|
| 57 |  | 
|---|
| 58 |    int m = A.Nrows(); int n = A.Ncols(); | 
|---|
| 59 |    if (m<n) | 
|---|
| 60 |       Throw(ProgramException("Want no. Rows >= no. Cols", A)); | 
|---|
| 61 |    if (withV && &U == &V) | 
|---|
| 62 |       Throw(ProgramException("Need different matrices for U and V", U, V)); | 
|---|
| 63 |    U = A; Real g = 0.0; Real f,h; Real x = 0.0; int i; | 
|---|
| 64 |    RowVector E(n); RectMatrixRow EI(E,0); Q.ReSize(n); | 
|---|
| 65 |    RectMatrixCol UCI(U,0); RectMatrixRow URI(U,0,1,n-1); | 
|---|
| 66 |  | 
|---|
| 67 |    if (n) for (i=0;;) | 
|---|
| 68 |    { | 
|---|
| 69 |       EI.First() = g; Real ei = g; EI.Right(); Real s = UCI.SumSquare(); | 
|---|
| 70 |       if (s<tol) { REPORT Q.element(i) = 0.0; } | 
|---|
| 71 |       else | 
|---|
| 72 |       { | 
|---|
| 73 |          REPORT | 
|---|
| 74 |          f = UCI.First(); g = -sign(sqrt(s), f); h = f*g-s; UCI.First() = f-g; | 
|---|
| 75 |          Q.element(i) = g; RectMatrixCol UCJ = UCI; int j=n-i; | 
|---|
| 76 |          while (--j) { UCJ.Right(); UCJ.AddScaled(UCI, (UCI*UCJ)/h); } | 
|---|
| 77 |       } | 
|---|
| 78 |  | 
|---|
| 79 |       s = URI.SumSquare(); | 
|---|
| 80 |       if (s<tol) { REPORT g = 0.0; } | 
|---|
| 81 |       else | 
|---|
| 82 |       { | 
|---|
| 83 |          REPORT | 
|---|
| 84 |          f = URI.First(); g = -sign(sqrt(s), f); URI.First() = f-g; | 
|---|
| 85 |          EI.Divide(URI,f*g-s); RectMatrixRow URJ = URI; int j=m-i; | 
|---|
| 86 |          while (--j) { URJ.Down(); URJ.AddScaled(EI, URI*URJ); } | 
|---|
| 87 |       } | 
|---|
| 88 |  | 
|---|
| 89 |       Real y = fabs(Q.element(i)) + fabs(ei); if (x<y) { REPORT x = y; } | 
|---|
| 90 |       if (++i == n) { REPORT break; } | 
|---|
| 91 |       UCI.DownDiag(); URI.DownDiag(); | 
|---|
| 92 |    } | 
|---|
| 93 |  | 
|---|
| 94 |    if (withV) | 
|---|
| 95 |    { | 
|---|
| 96 |       REPORT | 
|---|
| 97 |       V.ReSize(n,n); V = 0.0; RectMatrixCol VCI(V,n-1,n-1,1); | 
|---|
| 98 |       if (n) { VCI.First() = 1.0; g=E.element(n-1); if (n!=1) URI.UpDiag(); } | 
|---|
| 99 |       for (i=n-2; i>=0; i--) | 
|---|
| 100 |       { | 
|---|
| 101 |          VCI.Left(); | 
|---|
| 102 |          if (g!=0.0) | 
|---|
| 103 |          { | 
|---|
| 104 |             VCI.Divide(URI, URI.First()*g); int j = n-i; | 
|---|
| 105 |             RectMatrixCol VCJ = VCI; | 
|---|
| 106 |             while (--j) { VCJ.Right(); VCJ.AddScaled( VCI, (URI*VCJ) ); } | 
|---|
| 107 |          } | 
|---|
| 108 |          VCI.Zero(); VCI.Up(); VCI.First() = 1.0; g=E.element(i); | 
|---|
| 109 |          if (i==0) break; | 
|---|
| 110 |          URI.UpDiag(); | 
|---|
| 111 |       } | 
|---|
| 112 |    } | 
|---|
| 113 |  | 
|---|
| 114 |    if (withU) | 
|---|
| 115 |    { | 
|---|
| 116 |       REPORT | 
|---|
| 117 |       for (i=n-1; i>=0; i--) | 
|---|
| 118 |       { | 
|---|
| 119 |          g = Q.element(i); URI.Reset(U,i,i+1,n-i-1); URI.Zero(); | 
|---|
| 120 |          if (g!=0.0) | 
|---|
| 121 |          { | 
|---|
| 122 |             h=UCI.First()*g; int j=n-i; RectMatrixCol UCJ = UCI; | 
|---|
| 123 |             while (--j) | 
|---|
| 124 |             { | 
|---|
| 125 |                UCJ.Right(); UCI.Down(); UCJ.Down(); Real s = UCI*UCJ; | 
|---|
| 126 |                UCI.Up(); UCJ.Up(); UCJ.AddScaled(UCI,s/h); | 
|---|
| 127 |             } | 
|---|
| 128 |             UCI.Divide(g); | 
|---|
| 129 |          } | 
|---|
| 130 |          else UCI.Zero(); | 
|---|
| 131 |          UCI.First() += 1.0; | 
|---|
| 132 |          if (i==0) break; | 
|---|
| 133 |          UCI.UpDiag(); | 
|---|
| 134 |       } | 
|---|
| 135 |    } | 
|---|
| 136 |  | 
|---|
| 137 |    eps *= x; | 
|---|
| 138 |    for (int k=n-1; k>=0; k--) | 
|---|
| 139 |    { | 
|---|
| 140 |       Real z = -FloatingPointPrecision::Maximum(); // to keep Gnu happy | 
|---|
| 141 |       Real y; int limit = 50; int l = 0; | 
|---|
| 142 |       while (limit--) | 
|---|
| 143 |       { | 
|---|
| 144 |          Real c, s; int i; int l1=k; bool tfc=false; | 
|---|
| 145 |          for (l=k; l>=0; l--) | 
|---|
| 146 |          { | 
|---|
| 147 | //          if (fabs(E.element(l))<=eps) goto test_f_convergence; | 
|---|
| 148 |             if (fabs(E.element(l))<=eps) { REPORT tfc=true; break; } | 
|---|
| 149 |             if (fabs(Q.element(l-1))<=eps) { REPORT l1=l; break; } | 
|---|
| 150 |             REPORT | 
|---|
| 151 |          } | 
|---|
| 152 |          if (!tfc) | 
|---|
| 153 |          { | 
|---|
| 154 |             REPORT | 
|---|
| 155 |             l=l1; l1=l-1; s = -1.0; c = 0.0; | 
|---|
| 156 |             for (i=l; i<=k; i++) | 
|---|
| 157 |             { | 
|---|
| 158 |                f = - s * E.element(i); E.element(i) *= c; | 
|---|
| 159 | //             if (fabs(f)<=eps) goto test_f_convergence; | 
|---|
| 160 |                if (fabs(f)<=eps) { REPORT break; } | 
|---|
| 161 |                g = Q.element(i); h = pythag(g,f,c,s); Q.element(i) = h; | 
|---|
| 162 |                if (withU) | 
|---|
| 163 |                { | 
|---|
| 164 |                   REPORT | 
|---|
| 165 |                   RectMatrixCol UCI(U,i); RectMatrixCol UCJ(U,l1); | 
|---|
| 166 |                   ComplexScale(UCJ, UCI, c, s); | 
|---|
| 167 |                } | 
|---|
| 168 |             } | 
|---|
| 169 |          } | 
|---|
| 170 | //       test_f_convergence: z = Q.element(k); if (l==k) goto convergence; | 
|---|
| 171 |          z = Q.element(k);  if (l==k) { REPORT break; } | 
|---|
| 172 |  | 
|---|
| 173 |          x = Q.element(l); y = Q.element(k-1); | 
|---|
| 174 |          g = E.element(k-1); h = E.element(k); | 
|---|
| 175 |          f = ((y-z)*(y+z) + (g-h)*(g+h)) / (2*h*y); | 
|---|
| 176 |          if (f>1)         { REPORT g = f * sqrt(1 + square(1/f)); } | 
|---|
| 177 |          else if (f<-1)   { REPORT g = -f * sqrt(1 + square(1/f)); } | 
|---|
| 178 |          else             { REPORT g = sqrt(f*f + 1); } | 
|---|
| 179 |             { REPORT f = ((x-z)*(x+z) + h*(y / ((f<0.0) ? f-g : f+g)-h)) / x; } | 
|---|
| 180 |  | 
|---|
| 181 |          c = 1.0; s = 1.0; | 
|---|
| 182 |          for (i=l+1; i<=k; i++) | 
|---|
| 183 |          { | 
|---|
| 184 |             g = E.element(i); y = Q.element(i); h = s*g; g *= c; | 
|---|
| 185 |             z = pythag(f,h,c,s); E.element(i-1) = z; | 
|---|
| 186 |             f = x*c + g*s; g = -x*s + g*c; h = y*s; y *= c; | 
|---|
| 187 |             if (withV) | 
|---|
| 188 |             { | 
|---|
| 189 |                REPORT | 
|---|
| 190 |                RectMatrixCol VCI(V,i); RectMatrixCol VCJ(V,i-1); | 
|---|
| 191 |                ComplexScale(VCI, VCJ, c, s); | 
|---|
| 192 |             } | 
|---|
| 193 |             z = pythag(f,h,c,s); Q.element(i-1) = z; | 
|---|
| 194 |             f = c*g + s*y; x = -s*g + c*y; | 
|---|
| 195 |             if (withU) | 
|---|
| 196 |             { | 
|---|
| 197 |                REPORT | 
|---|
| 198 |                RectMatrixCol UCI(U,i); RectMatrixCol UCJ(U,i-1); | 
|---|
| 199 |                ComplexScale(UCI, UCJ, c, s); | 
|---|
| 200 |             } | 
|---|
| 201 |          } | 
|---|
| 202 |          E.element(l) = 0.0; E.element(k) = f; Q.element(k) = x; | 
|---|
| 203 |       } | 
|---|
| 204 |       if (l!=k) { Throw(ConvergenceException(A)); } | 
|---|
| 205 | // convergence: | 
|---|
| 206 |       if (z < 0.0) | 
|---|
| 207 |       { | 
|---|
| 208 |          REPORT | 
|---|
| 209 |          Q.element(k) = -z; | 
|---|
| 210 |          if (withV) { RectMatrixCol VCI(V,k); VCI.Negate(); } | 
|---|
| 211 |       } | 
|---|
| 212 |    } | 
|---|
| 213 |    if (withU & withV) SortSV(Q, U, V); | 
|---|
| 214 |    else if (withU) SortSV(Q, U); | 
|---|
| 215 |    else if (withV) SortSV(Q, V); | 
|---|
| 216 |    else SortDescending(Q); | 
|---|
| 217 | } | 
|---|
| 218 |  | 
|---|
| 219 | void SVD(const Matrix& A, DiagonalMatrix& D) | 
|---|
| 220 | { REPORT Matrix U; SVD(A, D, U, U, false, false); } | 
|---|
| 221 |  | 
|---|
| 222 |  | 
|---|
| 223 |  | 
|---|
| 224 | #ifdef use_namespace | 
|---|
| 225 | } | 
|---|
| 226 | #endif | 
|---|
| 227 |  | 
|---|