public static void svd_truncated_u(int m, int n, double[] a, ref double[] un, ref double[] sn, ref double[] v) //****************************************************************************80 // // Purpose: // // SVD_TRUNCATED_U gets the truncated SVD when N <= M // // Discussion: // // A(mxn) = U(mxm) * S(mxn) * V(nxn)' // = Un(mxn) * Sn(nxn) * V(nxn)' // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 14 September 2006 // // Author: // // John Burkardt // // Parameters: // // Input, int M, N, the number of rows and columns in the matrix A. // // Input, double A[M*N], the matrix whose singular value // decomposition we are investigating. // // Output, double UN[M*N], SN[N*N], V[N*N], the factors // that form the singular value decomposition of A. // { int i; int j; // // The correct size of E and SDIAG is min ( m+1, n). // double[] a_copy = new double[m * n]; double[] e = new double[m + n]; double[] sdiag = new double[m + n]; double[] work = new double[m]; // // Compute the eigenvalues and eigenvectors. // const int job = 21; // // The input matrix is destroyed by the routine. Since we need to keep // it around, we only pass a copy to the routine. // for (j = 0; j < n; j++) { for (i = 0; i < m; i++) { a_copy[i + j * m] = a[i + j * m]; } } int info = DSVDC.dsvdc(ref a_copy, m, m, n, ref sdiag, ref e, ref un, m, ref v, n, work, job); if (info != 0) { Console.WriteLine(""); Console.WriteLine("SVD_TRUNCATED_U - Failure!"); Console.WriteLine(" The SVD could not be calculated."); Console.WriteLine(" LINPACK routine DSVDC returned a nonzero"); Console.WriteLine(" value of the error flag, INFO = " + info + ""); return; } // // Make the NxN matrix S from the diagonal values in SDIAG. // for (j = 0; j < n; j++) { for (i = 0; i < n; i++) { if (i == j) { sn[i + j * n] = sdiag[i]; } else { sn[i + j * n] = 0.0; } } } }
public static void r8mat_svd_linpack(int m, int n, double[] a, ref double[] u, ref double[] s, ref double[] v) //****************************************************************************80 // // Purpose: // // R8MAT_SVD_LINPACK gets the SVD of a matrix using a call to LINPACK. // // Discussion: // // The singular value decomposition of a real MxN matrix A has the form: // // A = U * S * V' // // where // // U is MxM orthogonal, // S is MxN, and entirely zero except for the diagonal; // V is NxN orthogonal. // // Moreover, the nonzero entries of S are positive, and appear // in order, from largest magnitude to smallest. // // This routine calls the LINPACK routine DSVDC to compute the // factorization. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 14 September 2006 // // Author: // // John Burkardt // // Parameters: // // Input, int M, N, the number of rows and columns in the matrix A. // // Input, double A[M*N], the matrix whose singular value // decomposition we are investigating. // // Output, double U[M*M], S[M*N], V[N*N], the factors // that form the singular value decomposition of A. // { int i; int j; // // The correct size of E and SDIAG is min ( m+1, n). // double[] a_copy = new double[m * n]; double[] e = new double[m + n]; double[] sdiag = new double[m + n]; double[] work = new double[m]; // // Compute the eigenvalues and eigenvectors. // const int job = 11; // // The input matrix is destroyed by the routine. Since we need to keep // it around, we only pass a copy to the routine. // for (j = 0; j < n; j++) { for (i = 0; i < m; i++) { a_copy[i + j * m] = a[i + j * m]; } } int info = DSVDC.dsvdc(ref a_copy, m, m, n, ref sdiag, ref e, ref u, m, ref v, n, work, job); if (info != 0) { Console.WriteLine(""); Console.WriteLine("R8MAT_SVD_LINPACK - Failure!"); Console.WriteLine(" The SVD could not be calculated."); Console.WriteLine(" LINPACK routine DSVDC returned a nonzero"); Console.WriteLine(" value of the error flag, INFO = " + info + ""); return; } // // Make the MxN matrix S from the diagonal values in SDIAG. // for (j = 0; j < n; j++) { for (i = 0; i < m; i++) { if (i == j) { s[i + j * m] = sdiag[i]; } else { s[i + j * m] = 0.0; } } } // // Note that we do NOT need to transpose the V that comes out of LINPACK! // }
public static double[] svd_solve(int m, int n, double[] a, double[] b) //****************************************************************************80 // // Purpose: // // SVD_SOLVE solves a linear system in the least squares sense. // // Discussion: // // The vector X returned by this routine should always minimize the // Euclidean norm of the residual ||A*x-b||. // // If the matrix A does not have full column rank, then there are multiple // vectors that attain the minimum residual. In that case, the vector // X returned by this routine is the unique such minimizer that has the // the minimum possible Euclidean norm, that is, ||A*x-b|| and ||x|| // are both minimized. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 21 April 2012 // // Author: // // John Burkardt // // Reference: // // David Kahaner, Cleve Moler, Steven Nash, // Numerical Methods and Software, // Prentice Hall, 1989, // ISBN: 0-13-627258-4, // LC: TA345.K34. // // Parameters: // // Input, int M, the number of rows of A. // // Input, int N, the number of columns of A. // // Input, double A[M*N], the matrix. // // Input, double B[M], the right hand side. // // Output, double SVD_SOLVE[N], the least squares solution. // { int i; // // Get the SVD. // double[] a_copy = typeMethods.r8mat_copy_new(m, n, a); double[] sdiag = new double[Math.Max(m + 1, n)]; double[] e = new double[Math.Max(m + 1, n)]; double[] u = new double[m * m]; double[] v = new double[n * n]; double[] work = new double[m]; const int job = 11; int info = DSVDC.dsvdc(ref a_copy, m, m, n, ref sdiag, ref e, ref u, m, ref v, n, work, job); if (info != 0) { Console.WriteLine(""); Console.WriteLine("SVD_SOLVE - Failure!"); Console.WriteLine(" The SVD could not be calculated."); Console.WriteLine(" LINPACK routine DSVDC returned a nonzero"); Console.WriteLine(" value of the error flag, INFO = " + info + ""); return(null); } double[] ub = typeMethods.r8mat_mtv_new(m, m, u, b); // // For singular problems, there may be tiny but nonzero singular values // that should be ignored. This is a reasonable attempt to avoid such // problems, although in general, the user might wish to control the tolerance. // double smax = typeMethods.r8vec_max(n, sdiag); if (smax <= typeMethods.r8_epsilon()) { smax = 1.0; } double stol = typeMethods.r8_epsilon() * smax; double[] sub = new double[n]; for (i = 0; i < n; i++) { sub[i] = 0.0; if (i >= m) { continue; } if (stol <= sdiag[i]) { sub[i] = ub[i] / sdiag[i]; } } double[] x = typeMethods.r8mat_mv_new(n, n, v, sub); return(x); }
public static void singular_vectors(int m, int n, int basis_num, ref double[] a, ref double[] sval) //****************************************************************************80 // // Purpose: // // SINGULAR_VECTORS computes the desired singular values. // // Discussion: // // The LINPACK SVD routine DSVDC is used to compute the singular // value decomposition: // // A = U * S * V' // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 09 May 2005 // // Author: // // John Burkardt // // Parameters: // // Input, int M, the number of spatial dimensions. // // Input, int N, the number of data points. // // Input, int BASIS_NUM, the number of basis vectors to be extracted. // // Input/output, double A[M*N]; on input, the matrix whose // singular values are to be computed. On output, A(M,1:BASIS_NUM) // contains the first BASIS_NUM left singular vectors. // // Output, double SVAL[BASIS_NUM], the first BASIS_NUM // singular values. // { int i; Console.WriteLine(""); Console.WriteLine("SINGULAR_VECTORS"); Console.WriteLine(" For an MxN matrix A in general storage,"); Console.WriteLine(" The LINPACK routine DSVDC computes the"); Console.WriteLine(" singular value decomposition:"); Console.WriteLine(""); Console.WriteLine(" A = U * S * V'"); Console.WriteLine(""); // // Compute the eigenvalues and eigenvectors. // double[] s = new double[Math.Min(m + 1, n)]; double[] e = new double[n]; double[] u = a; double[] v = null; double[] work = new double[m]; const int job = 20; int info = DSVDC.dsvdc(ref a, m, m, n, ref s, ref e, ref u, m, ref v, n, work, job); if (info != 0) { Console.WriteLine(""); Console.WriteLine("SINGULAR_VECTORS - Warning:"); Console.WriteLine(" DSVDC returned nonzero INFO = " + info + ""); return; } for (i = 0; i < basis_num; i++) { sval[i] = s[i]; } Console.WriteLine(""); Console.WriteLine(" The leading singular values:"); Console.WriteLine(""); for (i = 0; i < basis_num; i++) { Console.WriteLine(" " + (i + 1).ToString(CultureInfo.InvariantCulture).PadLeft(4) + " " + sval[i].ToString(CultureInfo.InvariantCulture).PadLeft(16) + ""); } }
public static double[] r8mat_solve_svd(int m, int n, double[] a, double[] b) //****************************************************************************80 // // Purpose: // // R8MAT_SOLVE_SVD solves a linear system A*x=b using the SVD. // // Discussion: // // When the system is determined, the solution is the solution in the // ordinary sense, and A*x = b. // // When the system is overdetermined, the solution minimizes the // L2 norm of the residual ||A*x-b||. // // When the system is underdetermined, ||A*x-b|| should be zero, and // the solution is the solution of minimum L2 norm, ||x||. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 30 June 2012 // // Author: // // John Burkardt // // Parameters: // // Input, int M, N, the number of rows and columns // in the matrix A. // // Input, double A[M,*N], the matrix. // // Input, double B[M], the right hand side. // // Output, double R8MAT_SOLVE_SVD[N], the solution. // { int i; int j; // // Compute the SVD decomposition. // double[] a_copy = r8mat_copy_new(m, n, a); double[] sdiag = new double[Math.Max(m + 1, n)]; double[] e = new double[Math.Max(m + 1, n)]; double[] u = new double[m * m]; double[] v = new double[n * n]; double[] work = new double[m]; const int job = 11; int info = DSVDC.dsvdc(ref a_copy, m, m, n, ref sdiag, ref e, ref u, m, ref v, n, work, job); if (info != 0) { Console.WriteLine(""); Console.WriteLine("R8MAT_SOLVE_SVD - Fatal error!"); Console.WriteLine(" The SVD could not be calculated."); Console.WriteLine(" LINPACK routine DSVDC returned a nonzero"); Console.WriteLine(" value of the error flag, INFO = " + info + ""); return(null); } double[] s = new double [m * n]; for (j = 0; j < n; j++) { for (i = 0; i < m; i++) { s[i + j * m] = 0.0; } } for (i = 0; i < Math.Min(m, n); i++) { s[i + i * m] = sdiag[i]; } // // Compute the pseudo inverse. // double[] sp = new double [n * m]; for (j = 0; j < m; j++) { for (i = 0; i < n; i++) { sp[i + j * m] = 0.0; } } for (i = 0; i < Math.Min(m, n); i++) { if (s[i + i * m] != 0.0) { sp[i + i * n] = 1.0 / s[i + i * m]; } } double[] a_pseudo = new double[n * m]; for (j = 0; j < m; j++) { for (i = 0; i < n; i++) { a_pseudo[i + j * n] = 0.0; int k; for (k = 0; k < n; k++) { int l; for (l = 0; l < m; l++) { a_pseudo[i + j * n] += v[i + k * n] * sp[k + l * n] * u[j + l * m]; } } } } // // Compute x = A_pseudo * b. // double[] x = r8mat_mv_new(n, m, a_pseudo, b); return(x); }