public static int SVDecomp(PZMath_matrix A, PZMath_matrix V, PZMath_vector S, PZMath_vector work) { int a, b, i, j; int M = A.RowCount; int N = A.ColumnCount; int K = System.Math.Min(M, N); if (M < N) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecomp(),svd of MxN matrix, M<N, is not implemented", PZMath_errno.PZMath_EUNIMPL); } else if (V.RowCount != N) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecomp(), square matrix V must match second dimension of matrix A", PZMath_errno.PZMath_EBADLEN); } else if (V.RowCount != V.ColumnCount) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecomp(),matrix V must be square", PZMath_errno.PZMath_ENOTSQR); } else if (S.Size != N) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecomp(),length of vector S must match second dimension of matrix A", PZMath_errno.PZMath_EBADLEN); } else if (work.Size != N) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecomp(),length of workspace must match second dimension of matrix A", PZMath_errno.PZMath_EBADLEN); } /* Handle the case of N = 1 (SVD of a column vector) */ if (N == 1) { PZMath_vector column = A.Column(0); double norm = PZMath_blas.Dnrm2(column); S[0] = norm; V[0, 0] = 1.0; if (norm != 0.0) { PZMath_blas.Dscal(1.0 / norm, column); } return PZMath_errno.PZMath_SUCCESS; } { PZMath_vector f = work.SubVector(0, K - 1); /* bidiagonalize matrix A, unpack A into U S V */ PZMath_linalg.BidiagDecomp (A, S, f); PZMath_linalg.BidiagUnpack2 (A, S, f, V); /* apply reduction steps to B=(S,Sd) */ ChopSmallElements (S, f); /* Progressively reduce the matrix until it is diagonal */ b = N - 1; while (b > 0) { double fbm1 = f[b - 1]; if (fbm1 == 0.0 || PZMath_sys.Isnan (fbm1)) { b--; continue; } /* Find the largest unreduced block (a,b) starting from b and working backwards */ a = b - 1; while (a > 0) { double fam1 = f[a - 1]; if (fam1 == 0.0 || PZMath_sys.Isnan (fam1)) { break; } a--; } { int n_block = b - a + 1; PZMath_vector S_block = S.SubVector(a, n_block); PZMath_vector f_block = f.SubVector (a, n_block - 1); PZMath_matrix U_block = A.Submatrix(0, a, A.RowCount, n_block); PZMath_matrix V_block = V.Submatrix(0, a, V.RowCount, n_block); QRStep (S_block, f_block, U_block, V_block); /* remove any small off-diagonal elements */ ChopSmallElements (S_block, f_block); } } } /* Make singular values positive by reflections if necessary */ for (j = 0; j < K; j++) { double Sj = S[j]; if (Sj < 0.0) { for (i = 0; i < N; i++) { double Vij = V[i, j]; V[i, j] = -Vij; } S[j] = -Sj; } } /* Sort singular values into decreasing order */ for (i = 0; i < K; i++) { double S_max = S[i]; int i_max = i; for (j = i + 1; j < K; j++) { double Sj = S[j]; if (Sj > S_max) { S_max = Sj; i_max = j; } } if (i_max != i) { /* swap eigenvalues */ S.Swap(i, i_max); /* swap eigenvectors */ A.SwapColumns(i, i_max); V.SwapColumns(i, i_max); } } return PZMath_errno.PZMath_SUCCESS; }
public static int QRPTDecomp(PZMath_matrix A, PZMath_vector tau, PZMath_permutation p, out int signum, PZMath_vector norm) { int M = A.RowCount; int N = A.ColumnCount; signum = 0; if (tau.Size != System.Math.Min(M, N)) { PZMath_errno.ERROR("size of tau must be MIN(M,N)", PZMath_errno.PZMath_EBADLEN); } else if (p.Size != N) { PZMath_errno.ERROR("permutation size must be N", PZMath_errno.PZMath_EBADLEN); } else if (norm.Size != N) { PZMath_errno.ERROR("norm size must be N", PZMath_errno.PZMath_EBADLEN); } else { int i; signum = 1; p.Init(); /* set to identity */ /* Compute column norms and store in workspace */ for (i = 0; i < N; i++) { PZMath_vector c = A.Column(i); double x = PZMath_blas.Dnrm2(c); norm[i] = x; } for (i = 0; i < System.Math.Min(M, N); i++) { /* Bring the column of largest norm into the pivot position */ double max_norm = norm[i]; int j; int kmax = i; for (j = i + 1; j < N; j++) { double x = norm[j]; if (x > max_norm) { max_norm = x; kmax = j; } } if (kmax != i) { A.SwapColumns(i, kmax); p.Swap(i, kmax); norm.Swap(i, kmax); signum = - signum; } /* Compute the Householder transformation to reduce the j-th column of the matrix to a multiple of the j-th unit vector */ { PZMath_vector c_full = A.Column(i); PZMath_vector c = c_full.SubVector(i, M - i); double tau_i = HouseholderTransform(c); tau[i] = tau_i; /* Apply the transformation to the remaining columns */ if (i + 1 < N) { PZMath_matrix m = A.Submatrix(i, i + 1, M - i, N - (i + 1)); HouseholderHM (tau_i, c, m); } } /* Update the norms of the remaining columns too */ if (i + 1 < M) { for (j = i + 1; j < N; j++) { double x = norm[j]; if (x > 0.0) { double y = 0; double temp= A[i, j] / x; if (System.Math.Abs(temp) >= 1) y = 0.0; else y = x * System.Math.Sqrt(1 - temp * temp); /* recompute norm to prevent loss of accuracy */ if (System.Math.Abs(y / x) < System.Math.Sqrt(20.0) * PZMath_machine.PZMath_SQRT_DBL_EPSILON) { PZMath_vector c_full = A.Column(j); PZMath_vector c = c_full.SubVector(i + 1, M - (i + 1)); y = PZMath_blas.Dnrm2(c); } norm[j] = y; } } } } } return PZMath_errno.PZMath_SUCCESS; }
public static void SVD2(PZMath_vector d, PZMath_vector f, PZMath_matrix U, PZMath_matrix V) { int i; double c, s, a11, a12, a21, a22; int M = U.RowCount; int N = V.RowCount; double d0 = d[0]; double f0 = f[0]; double d1 = d[1]; if (d0 == 0.0) { /* Eliminate off-diagonal element in [0,f0;0,d1] to make [d,0;0,0] */ CreateGivens (f0, d1, out c, out s); /* compute B <= G^T B X, where X = [0,1;1,0] */ d[0] = c * f0 - s * d1; f[0] = s * f0 + c * d1; d[1] = 0.0; /* Compute U <= U G */ for (i = 0; i < M; i++) { double Uip = U[i, 0]; double Uiq = U[i, 1]; U[i, 0] = c * Uip - s * Uiq; U[i, 1] = s * Uip + c * Uiq; } /* Compute V <= V X */ V.SwapColumns(0, 1); return; } else if (d1 == 0.0) { /* Eliminate off-diagonal element in [d0,f0;0,0] */ CreateGivens (d0, f0, out c, out s); /* compute B <= B G */ d[0] = d0 * c - f0 * s; f[0] = 0.0; /* Compute V <= V G */ for (i = 0; i < N; i++) { double Vip = V[i, 0]; double Viq = V[i, 1]; V[i, 0] = c * Vip - s * Viq; V[i, 1] = s * Vip + c * Viq; } return; } else { /* Make columns orthogonal, A = [d0, f0; 0, d1] * G */ CreateSchur (d0, f0, d1, out c, out s); /* compute B <= B G */ a11 = c * d0 - s * f0; a21 = - s * d1; a12 = s * d0 + c * f0; a22 = c * d1; /* Compute V <= V G */ for (i = 0; i < N; i++) { double Vip = V[i, 0]; double Viq = V[i, 1]; V[i, 0] = c * Vip - s * Viq; V[i, 1] = s * Vip + c * Viq; } /* Eliminate off-diagonal elements, bring column with largest norm to first column */ if (PZMath_sys.Hypot (a11, a21) < PZMath_sys.Hypot (a12,a22)) { double t1, t2; /* B <= B X */ t1 = a11; a11 = a12; a12 = t1; t2 = a21; a21 = a22; a22 = t2; /* V <= V X */ V.SwapColumns(0, 1); } CreateGivens (a11, a21, out c, out s); /* compute B <= G^T B */ d[0] = c * a11 - s * a21; f[0] = c * a12 - s * a22; d[1] = s * a12 + c * a22; /* Compute U <= U G */ for (i = 0; i < M; i++) { double Uip = U[i, 0]; double Uiq = U[i, 1]; U[i, 0] = c * Uip - s * Uiq; U[i, 1] = s * Uip + c * Uiq; } return; } }