///<summary>Computes the algorithm.</summary> protected override void InternalCompute() { rows = matrix.RowLength; cols = matrix.ColumnLength; int mm=System.Math.Min(rows+1,cols); s = new ComplexDoubleVector(mm); // singular values #if MANAGED // Derived from LINPACK code. // Initialize. u=new ComplexDoubleMatrix(rows,rows); // left vectors v=new ComplexDoubleMatrix(cols,cols); // right vectors ComplexDoubleVector e=new ComplexDoubleVector(cols); ComplexDoubleVector work=new ComplexDoubleVector(rows); int i, iter, j, k, kase, l, lp1, ls=0, lu, m, nct, nctp1, ncu, nrt, nrtp1; double b, c, cs=0.0, el, emm1, f, g, scale, shift, sl, sm, sn=0.0, smm1, t1, test, ztest, xnorm, enorm; Complex t,r; ncu = rows; // reduce matrix to bidiagonal form, storing the diagonal elements // in s and the super-diagonal elements in e. int info = 0; nct = System.Math.Min(rows-1,cols); nrt = System.Math.Max(0,System.Math.Min(cols-2,rows)); lu = System.Math.Max(nct,nrt); for(l=0; l<lu; l++) { lp1 = l + 1; if (l < nct) { // compute the transformation for the l-th column and // place the l-th diagonal in s[l]. xnorm=dznrm2Column(matrix, l, l); s[l]=new Complex(xnorm,(double)0.0); if (dcabs1(s[l]) != 0.0) { if (dcabs1(matrix[l,l]) != 0.0) { s[l] = csign(s[l],matrix[l,l]); } zscalColumn(matrix, l, l, 1.0/s[l]); matrix[l,l] = Complex.One + matrix[l,l]; } s[l] = -s[l]; } for(j=lp1; j<cols; j++) { if (l < nct) { if (dcabs1(s[l]) != 0.0) { // apply the transformation. t = -zdotc(matrix, l, j, l)/matrix[l,l]; for(int ii=l; ii < matrix.RowLength; ii++) { matrix[ii,j]+=t*matrix[ii,l]; } } } //place the l-th row of matrix into e for the //subsequent calculation of the row transformation. e[j] = ComplexMath.Conjugate(matrix[l,j]); } if (computeVectors && l < nct) { // place the transformation in u for subsequent back multiplication. for(i=l; i < rows; i++) { u[i,l] = matrix[i,l]; } } if (l < nrt) { // compute the l-th row transformation and place the l-th super-diagonal in e(l). enorm=dznrm2Vector(e,lp1); e[l]=new Complex(enorm, 0.0); if (dcabs1(e[l]) != 0.0) { if (dcabs1(e[lp1]) != 0.0) { e[l] = csign(e[l],e[lp1]); } zscalVector(e, lp1, 1.0/e[l]); e[lp1] = Complex.One + e[lp1]; } e[l] = ComplexMath.Conjugate(-e[l]); if (lp1 < rows && dcabs1(e[l]) != 0.0) { // apply the transformation. for(i=lp1; i<rows; i++) { work[i] = Complex.Zero; } for(j=lp1; j<cols; j++) { for(int ii=lp1; ii < matrix.RowLength; ii++) { work[ii]+=e[j]*matrix[ii,j]; } } for(j=lp1; j<cols; j++) { Complex ww=ComplexMath.Conjugate(-e[j]/e[lp1]); for(int ii=lp1; ii < matrix.RowLength; ii++) { matrix[ii,j]+=ww*work[ii]; } } } if (computeVectors) { // place the transformation in v for subsequent back multiplication. for(i=lp1; i < cols; i++) { v[i,l] = e[i]; } } } } // set up the final bidiagonal matrix or order m. m = System.Math.Min(cols,rows+1); nctp1 = nct + 1; nrtp1 = nrt + 1; if (nct < cols) { s[nctp1-1] = matrix[nctp1-1,nctp1-1]; } if (rows < m) { s[m-1] = Complex.Zero; } if (nrtp1 < m) { e[nrtp1-1] = matrix[nrtp1-1,m-1]; } e[m-1] = Complex.Zero; // if required, generate u. if (computeVectors) { for(j=nctp1-1; j<ncu; j++) { for(i=0; i < rows; i++) { u[i,j] = Complex.Zero; } u[j,j] = Complex.One; } for(l=nct-1; l>=0; l--) { if (dcabs1(s[l]) != 0.0) { for(j=l+1; j < ncu; j++) { t = -zdotc(u, l, j, l)/u[l,l]; for(int ii=l; ii < u.RowLength; ii++) { u[ii,j]+=t*u[ii,l]; } } zscalColumn(u, l, l, -Complex.One); u[l,l] = Complex.One + u[l,l]; for(i=0; i<l; i++) { u[i,l] = Complex.Zero; } } else { for(i=0; i<rows; i++) { u[i,l] = Complex.Zero; } u[l,l] = Complex.One; } } } // if it is required, generate v. if (computeVectors) { for(l=cols-1; l>=0; l--) { lp1 = l + 1; if (l < nrt) { if (dcabs1(e[l]) != 0.0) { for(j=lp1; j < cols; j++) { t = -zdotc(v, l, j, lp1)/v[lp1,l]; for(int ii=l; ii < v.RowLength; ii++) { v[ii,j]+=t*v[ii,l]; } } } } for(i=0; i < cols; i++) { v[i,l] = Complex.Zero; } v[l,l] = Complex.One; } } // transform s and e so that they are double . for(i=0; i < m; i++) { if (dcabs1(s[i]) != 0.0) { t = new Complex(ComplexMath.Absolute(s[i]),0.0); r = s[i]/t; s[i] = t; if (i < m-1) { e[i] = e[i]/r; } if (computeVectors) { zscalColumn(u, i, 0, r); } } // ...exit if (i == m-1) { break; } if (dcabs1(e[i]) != 0.0) { t = new Complex(ComplexMath.Absolute(e[i]),0.0); r = t/e[i]; e[i] = t; s[i+1] = s[i+1]*r; if (computeVectors) { zscalColumn(v, i+1, 0, r); } } } // main iteration loop for the singular values. mm = m; iter = 0; while(m > 0) { // quit if all the singular values have been found. // if too many iterations have been performed, set // flag and return. if (iter >= MAXITER) { info = m; // ......exit break; } // this section of the program inspects for // negligible elements in the s and e arrays. on // completion the variables kase and l are set as follows. // kase = 1 if s[m] and e[l-1] are negligible and l < m // kase = 2 if s[l] is negligible and l < m // kase = 3 if e[l-1] is negligible, l < m, and // s[l, ..., s[m] are not negligible (qr step). // kase = 4 if e[m-1] is negligible (convergence). for(l=m-2; l>=0; l--) { test = ComplexMath.Absolute(s[l]) + ComplexMath.Absolute(s[l+1]); ztest = test + ComplexMath.Absolute(e[l]); if (ztest == test) { e[l] = Complex.Zero; break; } } if (l == m - 2) { kase = 4; } else { for(ls=m-1; ls > l; ls--) { test = 0.0; if (ls != m-1) { test = test + ComplexMath.Absolute(e[ls]); } if (ls != l + 1) { test = test + ComplexMath.Absolute(e[ls-1]); } ztest = test + ComplexMath.Absolute(s[ls]); if (ztest == test) { s[ls] = Complex.Zero; break; } } if (ls == l) { kase = 3; } else if (ls == m-1) { kase = 1; } else { kase = 2; l = ls; } } l = l + 1; // perform the task indicated by kase. switch(kase) { // deflate negligible s[m]. case 1: f = e[m-2].Real; e[m-2] = Complex.Zero; for(k=m-2; k>=0; k--) { t1 = s[k].Real; drotg(ref t1,ref f,ref cs,ref sn); s[k] = new Complex(t1, 0.0); if (k != l) { f = -sn*e[k-1].Real; e[k-1] = cs*e[k-1]; } if (computeVectors) { zdrot (v, k, m-1, cs, sn); } } break; // split at negligible s[l]. case 2: f = e[l-1].Real; e[l-1] = Complex.Zero; for(k=l; k <m; k++) { t1 = s[k].Real; drotg(ref t1, ref f, ref cs, ref sn); s[k] = new Complex(t1,0.0); f = -sn*e[k].Real; e[k] = cs*e[k]; if (computeVectors) { zdrot (u, k, l-1, cs, sn); } } break; // perform one qr step. case 3: // calculate the shift. scale=0.0; scale=System.Math.Max(scale,ComplexMath.Absolute(s[m-1])); scale=System.Math.Max(scale,ComplexMath.Absolute(s[m-2])); scale=System.Math.Max(scale,ComplexMath.Absolute(e[m-2])); scale=System.Math.Max(scale,ComplexMath.Absolute(s[l])); scale=System.Math.Max(scale,ComplexMath.Absolute(e[l])); sm = s[m-1].Real/scale; smm1 = s[m-2].Real/scale; emm1 = e[m-2].Real/scale; sl = s[l].Real/scale; el = e[l].Real/scale; b = ((smm1 + sm)*(smm1 - sm) + emm1*emm1)/2.0; c = (sm*emm1)*(sm*emm1); shift = 0.0; if (b != 0.0 || c != 0.0) { shift = System.Math.Sqrt(b*b+c); if (b < 0.0) { shift = -shift; } shift = c/(b + shift); } f = (sl + sm)*(sl - sm) + shift; g = sl*el; // chase zeros. for(k=l; k < m-1; k++) { drotg(ref f, ref g, ref cs, ref sn); if (k != l) { e[k-1] = new Complex(f,0.0); } f = cs*s[k].Real + sn*e[k].Real; e[k] = cs*e[k] - sn*s[k]; g = sn*s[k+1].Real; s[k+1] = cs*s[k+1]; if (computeVectors) { zdrot (v, k, k+1, cs, sn); } drotg(ref f, ref g, ref cs, ref sn); s[k] = new Complex(f,0.0); f = cs*e[k].Real + sn*s[k+1].Real; s[k+1] = -sn*e[k] + cs*s[k+1]; g = sn*e[k+1].Real; e[k+1] = cs*e[k+1]; if (computeVectors && k < rows) { zdrot(u, k, k+1, cs, sn); } } e[m-2] =new Complex(f,0.0); iter = iter + 1; break; // convergence. case 4: // make the singular value positive if (s[l].Real < 0.0) { s[l] = -s[l]; if (computeVectors) { zscalColumn(v, l, 0, -Complex.One); } } // order the singular value. while (l != mm-1) { if (s[l].Real >= s[l+1].Real) { break; } t = s[l]; s[l] = s[l+1]; s[l+1] = t; if (computeVectors && l < cols) { zswap(v,l,l+1); } if (computeVectors && l < rows) { zswap(u,l,l+1); } l = l + 1; } iter = 0; m = m - 1; break; } } // make matrix w from vector s // there is no constructor, creating diagonal matrix from vector // doing it ourselves mm=System.Math.Min(matrix.RowLength,matrix.ColumnLength); #else double[] d = new double[mm]; u = new ComplexDoubleMatrix(rows); v = new ComplexDoubleMatrix(cols); Complex[] a = new Complex[matrix.data.Length]; Array.Copy(matrix.data, a, matrix.data.Length); Lapack.Gesvd.Compute(rows, cols, a, d, u.data, v.data ); v.ConjugateTranspose(); for( int i = 0; i < d.Length; i++){ s[i] = d[i]; } #endif w=new ComplexDoubleMatrix(matrix.RowLength,matrix.ColumnLength); for(int ii=0; ii<matrix.RowLength; ii++) { for(int jj=0; jj<matrix.ColumnLength; jj++) { if(ii==jj) { w[ii,ii]=s[ii]; } } } double eps = System.Math.Pow(2.0,-52.0); double tol = System.Math.Max(matrix.RowLength,matrix.ColumnLength)*s[0].Real*eps; rank = 0; for (int h = 0; h < mm; h++) { if (s[h].Real > tol) { rank++; } } if( !computeVectors ) { u = null; v = null; } matrix = null; }
///<summary>Computes the algorithm.</summary> protected override void InternalCompute() { rows = matrix.RowLength; cols = matrix.ColumnLength; int mm = System.Math.Min(rows + 1, cols); s = new ComplexDoubleVector(mm); // singular values #if MANAGED // Derived from LINPACK code. // Initialize. u = new ComplexDoubleMatrix(rows, rows); // left vectors v = new ComplexDoubleMatrix(cols, cols); // right vectors ComplexDoubleVector e = new ComplexDoubleVector(cols); ComplexDoubleVector work = new ComplexDoubleVector(rows); int i, iter, j, k, kase, l, lp1, ls = 0, lu, m, nct, nctp1, ncu, nrt, nrtp1; double b, c, cs = 0.0, el, emm1, f, g, scale, shift, sl, sm, sn = 0.0, smm1, t1, test, ztest, xnorm, enorm; Complex t, r; ncu = rows; // reduce matrix to bidiagonal form, storing the diagonal elements // in s and the super-diagonal elements in e. int info = 0; nct = System.Math.Min(rows - 1, cols); nrt = System.Math.Max(0, System.Math.Min(cols - 2, rows)); lu = System.Math.Max(nct, nrt); for (l = 0; l < lu; l++) { lp1 = l + 1; if (l < nct) { // compute the transformation for the l-th column and // place the l-th diagonal in s[l]. xnorm = dznrm2Column(matrix, l, l); s[l] = new Complex(xnorm, (double)0.0); if (dcabs1(s[l]) != 0.0) { if (dcabs1(matrix[l, l]) != 0.0) { s[l] = csign(s[l], matrix[l, l]); } zscalColumn(matrix, l, l, 1.0 / s[l]); matrix[l, l] = Complex.One + matrix[l, l]; } s[l] = -s[l]; } for (j = lp1; j < cols; j++) { if (l < nct) { if (dcabs1(s[l]) != 0.0) { // apply the transformation. t = -zdotc(matrix, l, j, l) / matrix[l, l]; for (int ii = l; ii < matrix.RowLength; ii++) { matrix[ii, j] += t * matrix[ii, l]; } } } //place the l-th row of matrix into e for the //subsequent calculation of the row transformation. e[j] = ComplexMath.Conjugate(matrix[l, j]); } if (computeVectors && l < nct) { // place the transformation in u for subsequent back multiplication. for (i = l; i < rows; i++) { u[i, l] = matrix[i, l]; } } if (l < nrt) { // compute the l-th row transformation and place the l-th super-diagonal in e(l). enorm = dznrm2Vector(e, lp1); e[l] = new Complex(enorm, 0.0); if (dcabs1(e[l]) != 0.0) { if (dcabs1(e[lp1]) != 0.0) { e[l] = csign(e[l], e[lp1]); } zscalVector(e, lp1, 1.0 / e[l]); e[lp1] = Complex.One + e[lp1]; } e[l] = ComplexMath.Conjugate(-e[l]); if (lp1 < rows && dcabs1(e[l]) != 0.0) { // apply the transformation. for (i = lp1; i < rows; i++) { work[i] = Complex.Zero; } for (j = lp1; j < cols; j++) { for (int ii = lp1; ii < matrix.RowLength; ii++) { work[ii] += e[j] * matrix[ii, j]; } } for (j = lp1; j < cols; j++) { Complex ww = ComplexMath.Conjugate(-e[j] / e[lp1]); for (int ii = lp1; ii < matrix.RowLength; ii++) { matrix[ii, j] += ww * work[ii]; } } } if (computeVectors) { // place the transformation in v for subsequent back multiplication. for (i = lp1; i < cols; i++) { v[i, l] = e[i]; } } } } // set up the final bidiagonal matrix or order m. m = System.Math.Min(cols, rows + 1); nctp1 = nct + 1; nrtp1 = nrt + 1; if (nct < cols) { s[nctp1 - 1] = matrix[nctp1 - 1, nctp1 - 1]; } if (rows < m) { s[m - 1] = Complex.Zero; } if (nrtp1 < m) { e[nrtp1 - 1] = matrix[nrtp1 - 1, m - 1]; } e[m - 1] = Complex.Zero; // if required, generate u. if (computeVectors) { for (j = nctp1 - 1; j < ncu; j++) { for (i = 0; i < rows; i++) { u[i, j] = Complex.Zero; } u[j, j] = Complex.One; } for (l = nct - 1; l >= 0; l--) { if (dcabs1(s[l]) != 0.0) { for (j = l + 1; j < ncu; j++) { t = -zdotc(u, l, j, l) / u[l, l]; for (int ii = l; ii < u.RowLength; ii++) { u[ii, j] += t * u[ii, l]; } } zscalColumn(u, l, l, -Complex.One); u[l, l] = Complex.One + u[l, l]; for (i = 0; i < l; i++) { u[i, l] = Complex.Zero; } } else { for (i = 0; i < rows; i++) { u[i, l] = Complex.Zero; } u[l, l] = Complex.One; } } } // if it is required, generate v. if (computeVectors) { for (l = cols - 1; l >= 0; l--) { lp1 = l + 1; if (l < nrt) { if (dcabs1(e[l]) != 0.0) { for (j = lp1; j < cols; j++) { t = -zdotc(v, l, j, lp1) / v[lp1, l]; for (int ii = l; ii < v.RowLength; ii++) { v[ii, j] += t * v[ii, l]; } } } } for (i = 0; i < cols; i++) { v[i, l] = Complex.Zero; } v[l, l] = Complex.One; } } // transform s and e so that they are double . for (i = 0; i < m; i++) { if (dcabs1(s[i]) != 0.0) { t = new Complex(ComplexMath.Absolute(s[i]), 0.0); r = s[i] / t; s[i] = t; if (i < m - 1) { e[i] = e[i] / r; } if (computeVectors) { zscalColumn(u, i, 0, r); } } // ...exit if (i == m - 1) { break; } if (dcabs1(e[i]) != 0.0) { t = new Complex(ComplexMath.Absolute(e[i]), 0.0); r = t / e[i]; e[i] = t; s[i + 1] = s[i + 1] * r; if (computeVectors) { zscalColumn(v, i + 1, 0, r); } } } // main iteration loop for the singular values. mm = m; iter = 0; while (m > 0) { // quit if all the singular values have been found. // if too many iterations have been performed, set // flag and return. if (iter >= MAXITER) { info = m; // ......exit break; } // this section of the program inspects for // negligible elements in the s and e arrays. on // completion the variables kase and l are set as follows. // kase = 1 if s[m] and e[l-1] are negligible and l < m // kase = 2 if s[l] is negligible and l < m // kase = 3 if e[l-1] is negligible, l < m, and // s[l, ..., s[m] are not negligible (qr step). // kase = 4 if e[m-1] is negligible (convergence). for (l = m - 2; l >= 0; l--) { test = ComplexMath.Absolute(s[l]) + ComplexMath.Absolute(s[l + 1]); ztest = test + ComplexMath.Absolute(e[l]); if (ztest == test) { e[l] = Complex.Zero; break; } } if (l == m - 2) { kase = 4; } else { for (ls = m - 1; ls > l; ls--) { test = 0.0; if (ls != m - 1) { test = test + ComplexMath.Absolute(e[ls]); } if (ls != l + 1) { test = test + ComplexMath.Absolute(e[ls - 1]); } ztest = test + ComplexMath.Absolute(s[ls]); if (ztest == test) { s[ls] = Complex.Zero; break; } } if (ls == l) { kase = 3; } else if (ls == m - 1) { kase = 1; } else { kase = 2; l = ls; } } l = l + 1; // perform the task indicated by kase. switch (kase) { // deflate negligible s[m]. case 1: f = e[m - 2].Real; e[m - 2] = Complex.Zero; for (k = m - 2; k >= 0; k--) { t1 = s[k].Real; drotg(ref t1, ref f, ref cs, ref sn); s[k] = new Complex(t1, 0.0); if (k != l) { f = -sn * e[k - 1].Real; e[k - 1] = cs * e[k - 1]; } if (computeVectors) { zdrot(v, k, m - 1, cs, sn); } } break; // split at negligible s[l]. case 2: f = e[l - 1].Real; e[l - 1] = Complex.Zero; for (k = l; k < m; k++) { t1 = s[k].Real; drotg(ref t1, ref f, ref cs, ref sn); s[k] = new Complex(t1, 0.0); f = -sn * e[k].Real; e[k] = cs * e[k]; if (computeVectors) { zdrot(u, k, l - 1, cs, sn); } } break; // perform one qr step. case 3: // calculate the shift. scale = 0.0; scale = System.Math.Max(scale, ComplexMath.Absolute(s[m - 1])); scale = System.Math.Max(scale, ComplexMath.Absolute(s[m - 2])); scale = System.Math.Max(scale, ComplexMath.Absolute(e[m - 2])); scale = System.Math.Max(scale, ComplexMath.Absolute(s[l])); scale = System.Math.Max(scale, ComplexMath.Absolute(e[l])); sm = s[m - 1].Real / scale; smm1 = s[m - 2].Real / scale; emm1 = e[m - 2].Real / scale; sl = s[l].Real / scale; el = e[l].Real / scale; b = ((smm1 + sm) * (smm1 - sm) + emm1 * emm1) / 2.0; c = (sm * emm1) * (sm * emm1); shift = 0.0; if (b != 0.0 || c != 0.0) { shift = System.Math.Sqrt(b * b + c); if (b < 0.0) { shift = -shift; } shift = c / (b + shift); } f = (sl + sm) * (sl - sm) + shift; g = sl * el; // chase zeros. for (k = l; k < m - 1; k++) { drotg(ref f, ref g, ref cs, ref sn); if (k != l) { e[k - 1] = new Complex(f, 0.0); } f = cs * s[k].Real + sn * e[k].Real; e[k] = cs * e[k] - sn * s[k]; g = sn * s[k + 1].Real; s[k + 1] = cs * s[k + 1]; if (computeVectors) { zdrot(v, k, k + 1, cs, sn); } drotg(ref f, ref g, ref cs, ref sn); s[k] = new Complex(f, 0.0); f = cs * e[k].Real + sn * s[k + 1].Real; s[k + 1] = -sn * e[k] + cs * s[k + 1]; g = sn * e[k + 1].Real; e[k + 1] = cs * e[k + 1]; if (computeVectors && k < rows) { zdrot(u, k, k + 1, cs, sn); } } e[m - 2] = new Complex(f, 0.0); iter = iter + 1; break; // convergence. case 4: // make the singular value positive if (s[l].Real < 0.0) { s[l] = -s[l]; if (computeVectors) { zscalColumn(v, l, 0, -Complex.One); } } // order the singular value. while (l != mm - 1) { if (s[l].Real >= s[l + 1].Real) { break; } t = s[l]; s[l] = s[l + 1]; s[l + 1] = t; if (computeVectors && l < cols) { zswap(v, l, l + 1); } if (computeVectors && l < rows) { zswap(u, l, l + 1); } l = l + 1; } iter = 0; m = m - 1; break; } } // make matrix w from vector s // there is no constructor, creating diagonal matrix from vector // doing it ourselves mm = System.Math.Min(matrix.RowLength, matrix.ColumnLength); #else double[] d = new double[mm]; u = new ComplexDoubleMatrix(rows); v = new ComplexDoubleMatrix(cols); Complex[] a = new Complex[matrix.data.Length]; Array.Copy(matrix.data, a, matrix.data.Length); Lapack.Gesvd.Compute(rows, cols, a, d, u.data, v.data); v.ConjugateTranspose(); for (int i = 0; i < d.Length; i++) { s[i] = d[i]; } #endif w = new ComplexDoubleMatrix(matrix.RowLength, matrix.ColumnLength); for (int ii = 0; ii < matrix.RowLength; ii++) { for (int jj = 0; jj < matrix.ColumnLength; jj++) { if (ii == jj) { w[ii, ii] = s[ii]; } } } double eps = System.Math.Pow(2.0, -52.0); double tol = System.Math.Max(matrix.RowLength, matrix.ColumnLength) * s[0].Real * eps; rank = 0; for (int h = 0; h < mm; h++) { if (s[h].Real > tol) { rank++; } } if (!computeVectors) { u = null; v = null; } matrix = null; }