public static int BalanceColumns(PZMath_matrix A, PZMath_vector D) { int N = A.ColumnCount; int j; if (D.Size != N) { PZMath_errno.ERROR ("PZMath_linalg::BalanceColumns(), length of D must match second dimension of A", PZMath_errno.PZMath_EINVAL); } D.SetAll(1.0); for (j = 0; j < N; j++) { PZMath_vector A_j = A.Column(j); double s = PZMath_blas.Dasum (A_j); double f = 1.0; if (s == 0.0 || !PZMath_sys.Finite(s)) { D[j] = f; continue; } while (s > 1.0) { s /= 2.0; f *= 2.0; } while (s < 0.5) { s *= 2.0; f /= 2.0; } D[j] = f; if (f != 1.0) PZMath_blas.Dscal(1.0/f, A_j); } 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; }
// These functions compute the inverse of a matrix A from its LU decomposition (LU,p), // storing the result in the matrix inverse. // The inverse is computed by solving the system A x = b for each column of the identity matrix. // It is preferable to avoid direct use of the inverse whenever possible, // as the linear solver functions can obtain the same result more efficiently and reliably // (consult any introductory textbook on numerical linear algebra for details). public static int LUInvert(PZMath_matrix LU, PZMath_permutation p, PZMath_matrix inverse) { int i; int n = LU.RowCount; int status = PZMath_errno.PZMath_SUCCESS; inverse.SetIdentity(); for (i = 0; i < n; i++) { PZMath_vector c = inverse.Column(i); int status_i = LUSVX(LU, p, c); if (status_i == PZMath_errno.PZMath_SUCCESS) status = status_i; } return status; }
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 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 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; }