public static int BidiagDecomp(PZMath_matrix A, PZMath_vector tau_U, PZMath_vector tau_V) { if (A.RowCount < A.ColumnCount) PZMath_errno.ERROR ("PZMath_linalg::BidiagDecomp(), bidiagonal decomposition requires M>=N", PZMath_errno.PZMath_EBADLEN); else if (tau_U.Size != A.ColumnCount) PZMath_errno.ERROR ("PZMath_linalg::BidiagDecomp(),size of tau_U must be N", PZMath_errno.PZMath_EBADLEN); else if (tau_V.Size + 1 != A.ColumnCount) PZMath_errno.ERROR ("PZMath_linalg::BidiagDecomp(),size of tau_V must be (N - 1)", PZMath_errno.PZMath_EBADLEN); else { int M = A.RowCount; int N = A.ColumnCount; int i; for (i = 0 ; i < N; i++) { /* Apply Householder transformation to current column */ { 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); } tau_U[i] = tau_i; } /* Apply Householder transformation to current row */ if (i + 1 < N) { PZMath_vector r = A.Row(i); PZMath_vector v = r.SubVector(i + 1, N - (i + 1)); double tau_i = PZMath_linalg.HouseholderTransform (v); /* Apply the transformation to the remaining rows */ if (i + 1 < M) { PZMath_matrix m = A.Submatrix(i+1, i+1, M - (i+1), N - (i+1)); PZMath_linalg.HouseholderMH(tau_i, v, m); } tau_V[i] = tau_i; } } } 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 CholeskyDecomp(PZMath_matrix A) { int M = A.RowCount; int N = A.ColumnCount; if (M != N) { PZMath_errno.ERROR("PZMath_linalg::CholeskyDecomp()::cholesky decomposition requires square matrix", PZMath_errno.PZMath_ENOTSQR); } int i, j, k; int status = 0; /* Do the first 2 rows explicitly. It is simple, and faster. And * one can return if the matrix has only 1 or 2 rows. */ double A_00 = A[0, 0]; double L_00 = QuietSqrt(A_00); if (A_00 <= 0) { status = PZMath_errno.PZMath_EDOM; } A[0, 0] = L_00; if (M > 1) { double A_10 = A[1, 0]; double A_11 = A[1, 1]; double L_10 = A_10 / L_00; double diag = A_11 - L_10 * L_10; double L_11 = QuietSqrt(diag); if (diag <= 0) { status = PZMath_errno.PZMath_EDOM; } A[1, 0] = L_10; A[1, 1] = L_11; } for (k = 2; k < M; k++) { double A_kk = A[k, k]; for (i = 0; i < k; i++) { double sum = 0; double A_ki = A[k, i]; double A_ii = A[i, i]; PZMath_vector ci = A.Row(i); PZMath_vector ck = A.Row(k); if (i > 0) { PZMath_vector di = ci.SubVector(0, i); PZMath_vector dk = ck.SubVector(0, i); PZMath_blas.Ddot(di, dk, out sum); } A_ki = (A_ki - sum) / A_ii; A[k, i] = A_ki; } { PZMath_vector ck = A.Row(k); PZMath_vector dk = ck.SubVector(0, k); double sum = PZMath_blas.Dnrm2(dk); double diag = A_kk - sum * sum; double L_kk = QuietSqrt(diag); if (diag <= 0) { status = PZMath_errno.PZMath_EDOM; } A[k, k] = L_kk; } } /* Now copy the transposed lower triangle to the upper triangle, * the diagonal is common. */ for (i = 1; i < M; i++) { for (j = 0; j < i; j++) { double A_ij = A[i, j]; A[j, i] = A_ij; } } if (status == PZMath_errno.PZMath_EDOM) { PZMath_errno.ERROR("PZMath_linalg::CholeskyDecomp()::matrix must be positive definite", PZMath_errno.PZMath_EDOM); } return PZMath_errno.PZMath_SUCCESS; }
public static int BidiagUnpack2(PZMath_matrix A, PZMath_vector tau_U, PZMath_vector tau_V, PZMath_matrix V) { int M = A.RowCount; int N = A.ColumnCount; int K = System.Math.Min(M, N); if (M < N) { PZMath_errno.ERROR ("PZMath_linalg::BidiagUnpack2(),matrix A must have M >= N", PZMath_errno.PZMath_EBADLEN); } else if (tau_U.Size != K) { PZMath_errno.ERROR ("PZMath_linalg::BidiagUnpack2(),size of tau must be MIN(M,N)", PZMath_errno.PZMath_EBADLEN); } else if (tau_V.Size + 1 != K) { PZMath_errno.ERROR ("PZMath_linalg::BidiagUnpack2(),size of tau must be MIN(M,N) - 1", PZMath_errno.PZMath_EBADLEN); } else if (V.RowCount != N || V.ColumnCount != N) { PZMath_errno.ERROR ("PZMath_linalg::BidiagUnpack2(),size of V must be N x N", PZMath_errno.PZMath_EBADLEN); } else { int i, j; /* Initialize V to the identity */ V.SetIdentity(); for (i = N - 1; i > 0 && (i -- > 0);) { /* Householder row transformation to accumulate V */ PZMath_vector r = A.Row(i); PZMath_vector h = r.SubVector(i + 1, N - (i+1)); double ti = tau_V[i]; PZMath_matrix m = V.Submatrix(i + 1, i + 1, N-(i+1), N-(i+1)); PZMath_linalg.HouseholderHM (ti, h, m); } /* Copy superdiagonal into tau_v */ for (i = 0; i < N - 1; i++) { double Aij = A[i, i+1]; tau_V[i] = Aij; } /* Allow U to be unpacked into the same memory as A, copy diagonal into tau_U */ for (j = N; j > 0 && (j -- > 0);) { /* Householder column transformation to accumulate U */ double tj = tau_U[j]; double Ajj = A[j, j]; PZMath_matrix m = A.Submatrix (j, j, M-j, N-j); tau_U[j] = Ajj; PZMath_linalg.HouseholderHM1(tj, m); } } return PZMath_errno.PZMath_SUCCESS;; }