/// <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); }
/// <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); }
public void RandomUnitVector() { double epsilon = 0.0001; // unit vector should have length 1 Assert.AreEqual(1, V.Magnitude(ThinSvd.RandomUnitVector(10)), epsilon); // unit vector with single element should be [-1] or [+1] Assert.AreEqual(1, Math.Abs(ThinSvd.RandomUnitVector(1)[0]), epsilon); // two randomly generated unit vectors should not be equal Assert.AreNotEqual(ThinSvd.RandomUnitVector(10), ThinSvd.RandomUnitVector(10)); }
/// <summary> /// Computes a random unit vector. /// </summary> /// <param name="dimensions">The dimensions of the required vector.</param> /// <returns>The unit vector.</returns> public static double[] RandomUnitVector(int dimensions) { Random random = new Random(); double[] result = new double[dimensions]; for (int i = 0; i < dimensions; i++) { result[i] = 2 * random.NextDouble() - 1; } double magnitude = V.Magnitude(result); result = V.Scale(result, 1 / magnitude); return(result); }
public void VectorMagnitude() { Assert.AreEqual(Math.Sqrt(3), V.Magnitude(new double[] { 1, -1, 0, 1 })); }
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); }