= -1; k--) { if (k == -1) { break; } if (fabs(e[k]) <= eps*(fabs(_S[k]) + fabs(_S[k+1]))) { e[k] = 0.0; break; } } if ( k == p-2 ) { mode = 4; } else { int ks(p-1); // start from ks == p-1 for ( ; ks >= k; ks--) { if (ks == k) { break; } double t = ( (ks != p) ? fabs(e[ks]) : 0.0) + ( (ks != k+1) ? fabs(e[ks-1]) : 0.0); if (fabs(_S[ks]) <= eps*t) { _S[ks] = 0.0; break; } } if (ks == k) { mode = 3; } else if (ks == p-1) { mode = 1; } else { mode = 2; k = ks; } } k++; // Perform the task indicated by the selected mode. switch ( mode ) { case 1: { // Deflate negligible _S[p] double f = e[p-2]; e[p-2] = 0.0; for (j = p-2; j >= k; j--) { double t = SiMath::triangle(_S[j],f); double cs = _S[j]/t; double sn = f/t; _S[j] = t; if (j != k) { f = -sn*e[j-1]; e[j-1] = cs*e[j-1]; } // update V if ( _computeV ) { for (i = 0; i < _n; i++) { t = cs*_V[i][j] + sn*_V[i][p-1]; _V[i][p-1] = -sn*_V[i][j] + cs*_V[i][p-1]; _V[i][j] = t; } } } } break; // end case 1 case 2: { // Split at negligible _S[k] double f = e[k-1]; e[k-1] = 0.0; for (j = k; j < p; j++) { double t = triangle(_S[j],f); double cs = _S[j]/t; double sn = f/t; _S[j] = t; f = -sn*e[j]; e[j] = cs*e[j]; if ( _computeU ) { for (i = 0; i < _m; i++) { t = cs*_U[i][j] + sn*_U[i][k-1]; _U[i][k-1] = -sn*_U[i][j] + cs*_U[i][k-1]; _U[i][j] = t; } } } } break; // end case 2 case 3: { // Perform one qr step. // Calculate the shift. double scale = max(max(max(max(fabs(_S[p-1]),fabs(_S[p-2])),fabs(e[p-2])),fabs(_S[k])),fabs(e[k])); double sp = _S[p-1]/scale; double spm1 = _S[p-2]/scale; double epm1 = e[p-2]/scale; double sk = _S[k]/scale; double ek = e[k]/scale; double b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0; double c = (sp*epm1)*(sp*epm1); double shift = 0.0; if ((b != 0.0) || (c != 0.0)) { shift = sqrt(b*b + c); if (b < 0.0) { shift = -shift; } shift = c/(b + shift); } double f = (sk + sp)*(sk - sp) + shift; double g = sk*ek; // Chase zeros. for (j = k; j < p-1; j++) { double t = SiMath::triangle(f,g); double cs = f/t; double sn = g/t; if (j != k) { e[j-1] = t; } f = cs*_S[j] + sn*e[j]; e[j] = cs*e[j] - sn*_S[j]; g = sn*_S[j+1]; _S[j+1] = cs*_S[j+1]; if ( _computeV ) { for (i = 0; i < _n; i++) { t = cs*_V[i][j] + sn*_V[i][j+1]; _V[i][j+1] = -sn*_V[i][j] + cs*_V[i][j+1]; _V[i][j] = t; } } t = SiMath::triangle(f,g); cs = f/t; sn = g/t; _S[j] = t; f = cs*e[j] + sn*_S[j+1]; _S[j+1] = -sn*e[j] + cs*_S[j+1]; g = sn*e[j+1]; e[j+1] = cs*e[j+1]; if ( _computeU && (j < _m-1) ) { for (i = 0; i < _m; i++) { t = cs*_U[i][j] + sn*_U[i][j+1]; _U[i][j+1] = -sn*_U[i][j] + cs*_U[i][j+1]; _U[i][j] = t; } } } e[p-2] = f; iter++; } break; // end case 3 // convergence step case 4: { // Make the singular values positive. if (_S[k] <= 0.0) { _S[k] = (_S[k] < 0.0 ) ? -_S[k] : 0.0; if ( _computeV ) { for (i = 0; i <= pp; i++) { _V[i][k] = -_V[i][k]; } } } // Order the singular values. while (k < pp) { if (_S[k] >= _S[k+1]) break; // swap values and columns if necessary _S.swap(k,k+1); if ( _computeV && (k < _n-1)) _V.swapColumns(k,k+1); if ( _computeU && (k < _m-1) ) _U.swapColumns(k,k+1); k++; } iter = 0; p--; } break; // end case 4 } } } Matrix SVD::getSingularMatrix() { unsigned int n = _S.size(); Matrix A(n,n,0.0); // set diagonal elements for (int i = 0; i < n; i++) { A[i][i] = _S[i]; } return A; } int SVD::rank() { double eps = pow(2.0,-52.0); double tol = max(_m,_n) * _S[0] * eps; int r = 0; for (int i = 0; i < _S.size(); i++) { if (_S[i] > tol) { r++; } } return r; } double SiMath::randD(double a, double b) { double d(a); d += (b-a) * ((double)rand()/RAND_MAX); return d; }