/// <summary> /// Return the rightmost column of U. /// Does not check to see whether or not the matrix actually was rank-deficient. /// </summary> /// <returns></returns> public Vector LeftNullvector() { Vector ret = new Vector(m_); int col = Netlib.min(m_, n_) - 1; for (int i = 0; i < m_; ++i) { ret[i] = U_[i, col]; } return(ret); }
/// <summary> /// Return the determinant of M.\ This is computed from M = Q R as follows:. /// |M| = |Q| |R| /// |R| is the product of the diagonal elements. /// |Q| is (-1)^n as it is a product of Householder reflections. /// So det = -prod(-r_ii). /// </summary> /// <returns></returns> public float Determinant() { int m = Netlib.min((int)qrdc_out_.Columns, (int)qrdc_out_.Rows); float det = qrdc_out_[0, 0]; for (int i = 1; i < m; ++i) { det *= -qrdc_out_[i, i]; } return(det); }
private unsafe void init(MatrixFixed M, float zero_out_tol) { m_ = M.Rows; n_ = M.Columns; U_ = new MatrixFixed(m_, n_); W_ = new DiagMatrix(n_); Winverse_ = new DiagMatrix(n_); V_ = new MatrixFixed(n_, n_); //assert(m_ > 0); //assert(n_ > 0); int n = M.Rows; int p = M.Columns; int mm = Netlib.min(n + 1, p); // Copy source matrix into fortran storage // SVD is slow, don't worry about the cost of this transpose. Vector X = Vector.fortran_copy(M); // Make workspace vectors Vector work = new Vector(n); work.Fill(0); Vector uspace = new Vector(n * p); uspace.Fill(0); Vector vspace = new Vector(p * p); vspace.Fill(0); Vector wspace = new Vector(mm); wspace.Fill(0); // complex fortran routine actually _wants_ complex W! Vector espace = new Vector(p); espace.Fill(0); // Call Linpack SVD int info = 0; int job = 21; fixed(float *data = X.Datablock()) { fixed(float *data2 = wspace.Datablock()) { fixed(float *data3 = espace.Datablock()) { fixed(float *data4 = uspace.Datablock()) { fixed(float *data5 = vspace.Datablock()) { fixed(float *data6 = work.Datablock()) { Netlib.dsvdc_(data, &n, &n, &p, data2, data3, data4, &n, data5, &p, data6, &job, &info); } } } } } } // Error return? if (info != 0) { // If info is non-zero, it contains the number of singular values // for this the SVD algorithm failed to converge. The condition is // not bogus. Even if the returned singular values are sensible, // the singular vectors can be utterly wrong. // It is possible the failure was due to NaNs or infinities in the // matrix. Check for that now. M.assert_finite(); // If we get here it might be because // 1. The scalar type has such // extreme precision that too few iterations were performed to // converge to within machine precision (that is the svdc criterion). // One solution to that is to increase the maximum number of // iterations in the netlib code. // // 2. The LINPACK dsvdc_ code expects correct IEEE rounding behaviour, // which some platforms (notably x86 processors) // have trouble doing. For example, gcc can output // code in -O2 and static-linked code that causes this problem. // One solution to this is to persuade gcc to output slightly different code // by adding and -fPIC option to the command line for v3p\netlib\dsvdc.c. If // that doesn't work try adding -ffloat-store, which should fix the problem // at the expense of being significantly slower for big problems. Note that // if this is the cause, vxl/vnl/tests/test_svd should have failed. // // You may be able to diagnose the problem here by printing a warning message. Debug.WriteLine("__FILE__ : suspicious return value (" + Convert.ToString(info) + ") from SVDC" + "__FILE__ : M is " + Convert.ToString(M.Rows) + "x" + Convert.ToString(M.Columns)); valid_ = false; } else { valid_ = true; } // Copy fortran outputs into our storage int ctr = 0; for (int j = 0; j < p; ++j) { for (int i = 0; i < n; ++i) { U_[i, j] = uspace[ctr]; ctr++; } } for (int j = 0; j < mm; ++j) { W_[j, j] = Math.Abs(wspace[j]); // we get rid of complexness here. } for (int j = mm; j < n_; ++j) { W_[j, j] = 0; } ctr = 0; for (int j = 0; j < p; ++j) { for (int i = 0; i < p; ++i) { V_[i, j] = vspace[ctr]; ctr++; } } //if (test_heavily) { // Test that recomposed matrix == M //float recomposition_residual = Math.Abs((Recompose() - M).FrobeniusNorm()); //float n2 = Math.Abs(M.FrobeniusNorm()); //float thresh = m_ * (float)(eps) * n2; //if (recomposition_residual > thresh) { //std::cerr << "VNL::SVD<T>::SVD<T>() -- Warning, recomposition_residual = " //<< recomposition_residual << std::endl //<< "FrobeniusNorm(M) = " << n << std::endl //<< "eps*FrobeniusNorm(M) = " << thresh << std::endl //<< "Press return to continue\n"; //char x; //std::cin.get(&x, 1, '\n'); } } if (zero_out_tol >= 0) { // Zero out small sv's and update rank count. ZeroOutAbsolute((float)(+zero_out_tol)); } else { // negative tolerance implies relative to max elt. ZeroOutRelative((float)(-zero_out_tol)); } }