Beispiel #1
0
        internal static int ComputeSVD(GMatrix mat, GMatrix U, GMatrix
			 W, GMatrix V)
        {
            int i;
            int j;
            int k;
            int nr;
            int nc;
            int si;
            int converged;
            int rank;
            double cs;
            double sn;
            double r;
            double mag;
            double scale;
            double t;
            int eLength;
            int sLength;
            int vecLength;
            GMatrix tmp = new GMatrix(mat.nRow, mat.nCol);
            GMatrix u = new GMatrix(mat.nRow, mat.nCol);
            GMatrix v = new GMatrix(mat.nRow, mat.nCol);
            GMatrix m = new GMatrix(mat);
            // compute the number of singular values
            if (m.nRow >= m.nCol)
            {
                sLength = m.nCol;
                eLength = m.nCol - 1;
            }
            else
            {
                sLength = m.nRow;
                eLength = m.nRow;
            }
            if (m.nRow > m.nCol)
            {
                vecLength = m.nRow;
            }
            else
            {
                vecLength = m.nCol;
            }
            double[] vec = new double[vecLength];
            double[] single_values = new double[sLength];
            double[] e = new double[eLength];
            rank = 0;
            U.SetIdentity();
            V.SetIdentity();
            nr = m.nRow;
            nc = m.nCol;
            // householder reduction
            for (si = 0; si < sLength; si++)
            {
                // for each singular value
                if (nr > 1)
                {
                    // zero out column
                    // compute reflector
                    mag = 0.0;
                    for (i = 0; i < nr; i++)
                    {
                        mag += m.values[i + si][si] * m.values[i + si][si];
                    }
                    mag = Math.Sqrt(mag);
                    if (m.values[si][si] == 0.0)
                    {
                        vec[0] = mag;
                    }
                    else
                    {
                        vec[0] = m.values[si][si] + D_sign(mag, m.values[si][si]);
                    }
                    for (i = 1; i < nr; i++)
                    {
                        vec[i] = m.values[si + i][si];
                    }
                    scale = 0.0;
                    for (i = 0; i < nr; i++)
                    {
                        scale += vec[i] * vec[i];
                    }
                    scale = 2.0 / scale;
                    for (j = si; j < m.nRow; j++)
                    {
                        for (k = si; k < m.nRow; k++)
                        {
                            u.values[j][k] = -scale * vec[j - si] * vec[k - si];
                        }
                    }
                    for (i = si; i < m.nRow; i++)
                    {
                        u.values[i][i] += 1.0;
                    }
                    // compute s
                    t = 0.0;
                    for (i = si; i < m.nRow; i++)
                    {
                        t += u.values[si][i] * m.values[i][si];
                    }
                    m.values[si][si] = t;
                    // apply reflector
                    for (j = si; j < m.nRow; j++)
                    {
                        for (k = si + 1; k < m.nCol; k++)
                        {
                            tmp.values[j][k] = 0.0;
                            for (i = si; i < m.nCol; i++)
                            {
                                tmp.values[j][k] += u.values[j][i] * m.values[i][k];
                            }
                        }
                    }
                    for (j = si; j < m.nRow; j++)
                    {
                        for (k = si + 1; k < m.nCol; k++)
                        {
                            m.values[j][k] = tmp.values[j][k];
                        }
                    }
                    // update U matrix
                    for (j = si; j < m.nRow; j++)
                    {
                        for (k = 0; k < m.nCol; k++)
                        {
                            tmp.values[j][k] = 0.0;
                            for (i = si; i < m.nCol; i++)
                            {
                                tmp.values[j][k] += u.values[j][i] * U.values[i][k];
                            }
                        }
                    }
                    for (j = si; j < m.nRow; j++)
                    {
                        for (k = 0; k < m.nCol; k++)
                        {
                            U.values[j][k] = tmp.values[j][k];
                        }
                    }
                    nr--;
                }
                if (nc > 2)
                {
                    // zero out row
                    mag = 0.0;
                    for (i = 1; i < nc; i++)
                    {
                        mag += m.values[si][si + i] * m.values[si][si + i];
                    }
                    // generate the reflection vector, compute the first entry and
                    // copy the rest from the row to be zeroed
                    mag = Math.Sqrt(mag);
                    if (m.values[si][si + 1] == 0.0)
                    {
                        vec[0] = mag;
                    }
                    else
                    {
                        vec[0] = m.values[si][si + 1] + D_sign(mag, m.values[si][si + 1]);
                    }
                    for (i = 1; i < nc - 1; i++)
                    {
                        vec[i] = m.values[si][si + i + 1];
                    }
                    // use reflection vector to compute v matrix
                    scale = 0.0;
                    for (i = 0; i < nc - 1; i++)
                    {
                        scale += vec[i] * vec[i];
                    }
                    scale = 2.0 / scale;
                    for (j = si + 1; j < nc; j++)
                    {
                        for (k = si + 1; k < m.nCol; k++)
                        {
                            v.values[j][k] = -scale * vec[j - si - 1] * vec[k - si - 1];
                        }
                    }
                    for (i = si + 1; i < m.nCol; i++)
                    {
                        v.values[i][i] += 1.0;
                    }
                    t = 0.0;
                    for (i = si; i < m.nCol; i++)
                    {
                        t += v.values[i][si + 1] * m.values[si][i];
                    }
                    m.values[si][si + 1] = t;
                    // apply reflector
                    for (j = si + 1; j < m.nRow; j++)
                    {
                        for (k = si + 1; k < m.nCol; k++)
                        {
                            tmp.values[j][k] = 0.0;
                            for (i = si + 1; i < m.nCol; i++)
                            {
                                tmp.values[j][k] += v.values[i][k] * m.values[j][i];
                            }
                        }
                    }
                    for (j = si + 1; j < m.nRow; j++)
                    {
                        for (k = si + 1; k < m.nCol; k++)
                        {
                            m.values[j][k] = tmp.values[j][k];
                        }
                    }
                    // update V matrix
                    for (j = 0; j < m.nRow; j++)
                    {
                        for (k = si + 1; k < m.nCol; k++)
                        {
                            tmp.values[j][k] = 0.0;
                            for (i = si + 1; i < m.nCol; i++)
                            {
                                tmp.values[j][k] += v.values[i][k] * V.values[j][i];
                            }
                        }
                    }
                    for (j = 0; j < m.nRow; j++)
                    {
                        for (k = si + 1; k < m.nCol; k++)
                        {
                            V.values[j][k] = tmp.values[j][k];
                        }
                    }
                    nc--;
                }
            }
            for (i = 0; i < sLength; i++)
            {
                single_values[i] = m.values[i][i];
            }
            for (i = 0; i < eLength; i++)
            {
                e[i] = m.values[i][i + 1];
            }
            // Fix ArrayIndexOutOfBounds for 2x2 matrices, which partially
            // addresses bug 4348562 for J3D 1.2.1.
            //
            // Does *not* fix the following problems reported in 4348562,
            // which will wait for J3D 1.3:
            //
            //   1) no output of W
            //   2) wrong transposition of U
            //   3) wrong results for 4x4 matrices
            //   4) slow performance
            if (m.nRow == 2 && m.nCol == 2)
            {
                double[] cosl = new double[1];
                double[] cosr = new double[1];
                double[] sinl = new double[1];
                double[] sinr = new double[1];
                Compute_2X2(single_values[0], e[0], single_values[1], single_values, sinl, cosl,
                    sinr, cosr, 0);
                Update_u(0, U, cosl, sinl);
                Update_v(0, V, cosr, sinr);
                return 2;
            }
            // compute_qr causes ArrayIndexOutOfBounds for 2x2 matrices
            Compute_qr(0, e.Length - 1, single_values, e, U, V);
            // compute rank = number of non zero singular values
            rank = single_values.Length;
            // sort by order of size of single values
            // and check for zero's
            return rank;
        }
Beispiel #2
0
        private static void Print_svd(double[] s, double[] e, GMatrix u, GMatrix
			 v)
        {
            int i;
            GMatrix mtmp = new GMatrix(u.nCol, v.nRow);
            System.Console.Out.WriteLine(" \ns = ");
            for (i = 0; i < s.Length; i++)
            {
                System.Console.Out.WriteLine(" " + s[i]);
            }
            System.Console.Out.WriteLine(" \ne = ");
            for (i = 0; i < e.Length; i++)
            {
                System.Console.Out.WriteLine(" " + e[i]);
            }
            System.Console.Out.WriteLine(" \nu  = \n" + u.ToString());
            System.Console.Out.WriteLine(" \nv  = \n" + v.ToString());
            mtmp.SetIdentity();
            for (i = 0; i < s.Length; i++)
            {
                mtmp.values[i][i] = s[i];
            }
            for (i = 0; i < e.Length; i++)
            {
                mtmp.values[i][i + 1] = e[i];
            }
            System.Console.Out.WriteLine(" \nm  = \n" + mtmp.ToString());
            mtmp.MulTransposeLeft(u, mtmp);
            mtmp.MulTransposeRight(mtmp, v);
            System.Console.Out.WriteLine(" \n u.transpose*m*v.transpose  = \n" + mtmp.ToString
                ());
        }
Beispiel #3
0
 /// <summary>
 /// Finds the singular value decomposition (SVD) of this matrix
 /// such that this = U*W*transpose(V); and returns the rank of
 /// this matrix; the values of U,W,V are all overwritten.
 /// </summary>
 /// <remarks>
 /// Finds the singular value decomposition (SVD) of this matrix
 /// such that this = U*W*transpose(V); and returns the rank of
 /// this matrix; the values of U,W,V are all overwritten.  Note
 /// that the matrix V is output as V, and
 /// not transpose(V).  If this matrix is mxn, then U is mxm, W
 /// is a diagonal matrix that is mxn, and V is nxn.  Using the
 /// notation W = diag(w), then the inverse of this matrix is:
 /// inverse(this) = V*diag(1/w)*tranpose(U), where diag(1/w)
 /// is the same matrix as W except that the reciprocal of each
 /// of the diagonal components is used.
 /// </remarks>
 /// <param name="U">The computed U matrix in the equation this = U*W*transpose(V)</param>
 /// <param name="W">The computed W matrix in the equation this = U*W*transpose(V)</param>
 /// <param name="V">The computed V matrix in the equation this = U*W*transpose(V)</param>
 /// <returns>The rank of this matrix.</returns>
 public int Svd(GMatrix U, GMatrix W, GMatrix V)
 {
     // check for consistancy in dimensions
     if (nCol != V.nCol || nCol != V.nRow)
     {
         throw new MismatchedSizeException("GMatrix.SVD: dimension mismatch with V matrix");
     }
     if (nRow != U.nRow || nRow != U.nCol)
     {
         throw new MismatchedSizeException("GMatrix.SVD: dimension mismatch with U matrix");
     }
     if (nRow != W.nRow || nCol != W.nCol)
     {
         throw new MismatchedSizeException("GMatrix.SVD: dimension mismatch with W matrix");
     }
     // Fix ArrayIndexOutOfBounds for 2x2 matrices, which partially
     // addresses bug 4348562 for J3D 1.2.1.
     //
     // Does *not* fix the following problems reported in 4348562,
     // which will wait for J3D 1.3:
     //
     //   1) no output of W
     //   2) wrong transposition of U
     //   3) wrong results for 4x4 matrices
     //   4) slow performance
     if (nRow == 2 && nCol == 2)
     {
         if (values[1][0] == 0.0)
         {
             U.SetIdentity();
             V.SetIdentity();
             if (values[0][1] == 0.0)
             {
                 return 2;
             }
             double[] sinl = new double[1];
             double[] sinr = new double[1];
             double[] cosl = new double[1];
             double[] cosr = new double[1];
             double[] single_values = new double[2];
             single_values[0] = values[0][0];
             single_values[1] = values[1][1];
             Compute_2X2(values[0][0], values[0][1], values[1][1], single_values, sinl, cosl,
                 sinr, cosr, 0);
             Update_u(0, U, cosl, sinl);
             Update_v(0, V, cosr, sinr);
             return 2;
         }
     }
     // else call computeSVD() and check for 2x2 there
     return ComputeSVD(this, U, W, V);
 }