public static double HouseholderTransform(PZMath_vector v) { /* replace v[0:n-1] with a householder vector (v[0:n-1]) and coefficient tau that annihilate v[1:n-1] */ int n = v.Size; if (n == 1) { return 0.0; /* tau = 0 */ } else { double alpha, beta, tau ; PZMath_vector x = v.SubVector(1, n - 1); double xnorm = PZMath_blas.Dnrm2(x); if (xnorm == 0) { return 0.0; /* tau = 0 */ } alpha = v[0]; beta = - (alpha >= 0.0 ? +1.0 : -1.0) * PZMath_sys.Hypot (alpha, xnorm) ; tau = (beta - alpha) / beta ; PZMath_blas.Dscal(1.0 / (alpha - beta), x); v[0] = beta; return tau; } }
public static int HouseholderHV(double tau, PZMath_vector v, PZMath_vector w) { /* applies a householder transformation v to vector w */ int N = v.Size; if (tau == 0) return PZMath_errno.PZMath_SUCCESS; { /* compute d = v'w */ double d0 = w[0]; double d1, d; PZMath_vector v1 = v.SubVector(1, N - 1); PZMath_vector w1 = w.SubVector(1, N - 1); PZMath_blas.Ddot(v1, w1, out d1); d = d0 + d1; /* compute w = w - tau (v) (v'w) */ { double w0 = w[0]; w[0] = w0 - tau * d; } PZMath_blas.Daxpy(-tau * d, v1, w1); } return PZMath_errno.PZMath_SUCCESS; }
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; }
/* Modified algorithm which is better for M>>N */ public static int SVDecompMod(PZMath_matrix A, PZMath_matrix X, PZMath_matrix V, PZMath_vector S, PZMath_vector work) { int i, j; int M = A.RowCount; int N = A.ColumnCount; if (M < N) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecompMod(), svd of MxN matrix, M<N, is not implemented", PZMath_errno.PZMath_EUNIMPL); } else if (V.RowCount != N) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecompMod(), 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::SVDDecompMod(), matrix V must be square", PZMath_errno.PZMath_ENOTSQR); } else if (X.RowCount != N) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecompMod(), square matrix X must match second dimension of matrix A", PZMath_errno.PZMath_EBADLEN); } else if (X.RowCount != X.ColumnCount) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecompMod(), matrix X must be square", PZMath_errno.PZMath_ENOTSQR); } else if (S.Size != N) { PZMath_errno.ERROR ("PZMath_linalg::SVDDecompMod(), 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::SVDDecompMod(), length of workspace must match second dimension of matrix A", PZMath_errno.PZMath_EBADLEN); } 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; } /* Convert A into an upper triangular matrix R */ for (i = 0; i < N; i++) { PZMath_vector c = A.Column(i); PZMath_vector v = c.SubVector(i, M - i); double tau_i = PZMath_linalg.HouseholderTransform(v); /* Apply the transformation to the remaining columns */ if (i + 1 < N) { PZMath_matrix m =A.Submatrix(i, i + 1, M - i, N - (i + 1)); PZMath_linalg.HouseholderHM(tau_i, v, m); } S[i] = tau_i; } /* Copy the upper triangular part of A into X */ for (i = 0; i < N; i++) { for (j = 0; j < i; j++) { X[i, j] = 0.0; } { double Aii = A[i, i]; X[i, i] = Aii; } for (j = i + 1; j < N; j++) { double Aij = A[i, j]; X[i, j] = Aij; } } /* Convert A into an orthogonal matrix L */ for (j = N; j > 0 && (j -- > 0);) { /* Householder column transformation to accumulate L */ double tj = S[j]; PZMath_matrix m = A.Submatrix(j, j, M - j, N - j); PZMath_linalg.HouseholderHM1(tj, m); } /* unpack R into X V S */ PZMath_linalg.SVDecomp(X, V, S, work); /* Multiply L by X, to obtain U = L X, stored in U */ { PZMath_vector sum = work.SubVector(0, N); for (i = 0; i < M; i++) { PZMath_vector L_i = A.Row(i); sum.SetZero(); for (j = 0; j < N; j++) { double Lij = L_i[j]; PZMath_vector X_j = X.Row(j); PZMath_blas.Daxpy(Lij, X_j, sum); } L_i.MemCopyFrom(sum); } } return PZMath_errno.PZMath_SUCCESS; }
public static int QR_QTvec(PZMath_matrix QR, PZMath_vector tau, PZMath_vector v) { int M = QR.RowCount; int N = QR.ColumnCount; 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 (v.Size != M) { PZMath_errno.ERROR("vector size must be N", PZMath_errno.PZMath_EBADLEN); } else { int i; /* compute Q^T v */ for (i = 0; i < System.Math.Min(M, N); i++) { PZMath_vector c = QR.Column(i); PZMath_vector h = c.SubVector(i, M - i); PZMath_vector w = v.SubVector(i, M - i); double ti = tau[i]; HouseholderHV(ti, h, w); } return PZMath_errno.PZMath_SUCCESS; } return 0; }