Ejemplo n.º 1
0
        /// <summary>
        /// Computes a single singular vector for the given matrix, corresponding to the largest singular value.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="epsilon">The error margin.</param>
        /// <param name="max_iterations">The maximum number of iterations.</param>
        /// <returns>A singular vector, with dimension equal to number of columns of the matrix.</returns>
        public static double[] Decompose1D(double[,] matrix, double epsilon, int max_iterations)
        {
            int    n          = matrix.GetLength(1);
            int    iterations = 0;
            double mag;

            double[] lastIteration;
            double[] currIteration = RandomUnitVector(n);
            double[,] b = M.MultiplyGeneral(M.Transpose(matrix), matrix);
            do
            {
                lastIteration = V.Copy(currIteration);
                currIteration = M.MultiplyVector(b, lastIteration);
                currIteration = V.Scale(currIteration, 100);
                mag           = V.Magnitude(currIteration);
                if (mag > epsilon)
                {
                    currIteration = V.Scale(currIteration, 1 / mag);
                }

                iterations++;
            }while (V.Dot(lastIteration, currIteration) < 1 - epsilon && iterations < max_iterations);

            return(currIteration);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Computes the SVD for the given matrix, with singular values arranged from greatest to least.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="epsilon">The error margin.</param>
        /// <param name="max_iterations">The maximum number of iterations.</param>
        /// <returns>The SVD.</returns>
        public static (double[, ] U, double[] S, double[, ] V) Decompose(double[,] matrix, double epsilon, int max_iterations)
        {
            int m         = matrix.GetLength(0);
            int n         = matrix.GetLength(1);
            int numValues = Math.Min(m, n);

            // sigmas is be a diagonal matrix, hence only a vector is needed
            double[] sigmas = new double[numValues];
            double[,] us = new double[m, numValues];
            double[,] vs = new double[n, numValues];

            // keep track of progress
            double[,] remaining = M.Copy(matrix);

            // for each singular value
            for (int i = 0; i < numValues; i++)
            {
                // compute the v singular vector
                double[] v = Decompose1D(remaining, epsilon, max_iterations);
                double[] u = M.MultiplyVector(matrix, v);

                // compute the contribution of this pair of singular vectors
                double[,] contrib = V.OuterProduct(u, v);

                // extract the singular value
                double s = V.Magnitude(u);

                // v and u should be unit vectors
                if (s < epsilon)
                {
                    u = V.Zero(m);
                    v = V.Zero(n);
                }
                else
                {
                    u = V.Scale(u, 1 / s);
                }

                // save u, v and s into the result
                for (int j = 0; j < u.Length; j++)
                {
                    us[j, i] = u[j];
                }

                for (int j = 0; j < v.Length; j++)
                {
                    vs[j, i] = v[j];
                }

                sigmas[i] = s;

                // remove the contribution of this pair and compute the rest
                remaining = M.Subtract(remaining, contrib);
            }

            return(U : us, S : sigmas, V : vs);
        }
Ejemplo n.º 3
0
 public void MatrixMultiply()
 {
     double[,] lhs = new double[, ] {
         { 1, 2 }, { 3, 4 }, { 5, 6 }
     };
     double[,] rhs = new double[, ] {
         { 7, 8, 9 }, { 10, 11, 12 }
     };
     double[,] expected = new double[, ] {
         { 27, 30, 33 }, { 61, 68, 75 }, { 95, 106, 117 }
     };
     double[,] got = M.MultiplyGeneral(lhs, rhs);
     Assert.AreEqual(expected, got);
 }
Ejemplo n.º 4
0
        public void CheckSvd(double[,] testMatrix)
        {
            double epsilon = 1E-5;

            double[,] u;
            double[,] v;
            double[] s;
            (u, s, v) = ThinSvd.Decompose(testMatrix, 1E-8, 1000);

            for (int i = 1; i < s.Length; i++)
            {
                // singular values should be arranged from greatest to smallest
                Assert.GreaterOrEqual(s[i - 1], s[i]);
            }

            for (int i = 0; i < u.GetLength(1); i++)
            {
                double[] extracted = new double[u.GetLength(0)];
                // extract a column of u
                for (int j = 0; j < extracted.Length; j++)
                {
                    extracted[j] = u[j, i];
                }

                if (s[i] > epsilon)
                {
                    // if the singular value is non-zero, then the basis vector in u should be a unit vector
                    Assert.AreEqual(1, V.Magnitude(extracted), epsilon);
                }
                else
                {
                    // if the singular value is zero, then the basis vector in u should be zeroed out
                    Assert.AreEqual(0, V.Magnitude(extracted), epsilon);
                }
            }

            for (int i = 0; i < v.GetLength(1); i++)
            {
                double[] extracted = new double[v.GetLength(0)];
                // extract column of v
                for (int j = 0; j < extracted.Length; j++)
                {
                    extracted[j] = v[j, i];
                }

                if (s[i] > epsilon)
                {
                    // if the singular value is non-zero, then the basis vector in v should be a unit vector
                    Assert.AreEqual(1, V.Magnitude(extracted), epsilon);
                }
                else
                {
                    // if the singular value is zero, then the basis vector in v should be zeroed out
                    Assert.AreEqual(0, V.Magnitude(extracted), epsilon);
                }
            }

            // convert singular values to a diagonal matrix
            double[,] expanded = new double[s.Length, s.Length];
            for (int i = 0; i < s.Length; i++)
            {
                expanded[i, i] = s[i];
            }


            // matrix = U * S * V^t, definition of Singular Vector Decomposition
            AssertMatrixEqual(testMatrix,
                              M.MultiplyGeneral(M.MultiplyGeneral(u, expanded), M.Transpose(v)), epsilon);
            AssertMatrixEqual(testMatrix,
                              M.MultiplyGeneral(u, M.MultiplyGeneral(expanded, M.Transpose(v))), epsilon);
        }