Beispiel #1
0
        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));
        }