public void solve_for_diagonal() { int count = 3; double[][] value = new double[count][]; double[] output = new double[count]; for (int i = 0; i < count; i++) { value[i] = new double[3]; double x = i + 1; double y = 2 * (i + 1) - 1; value[i][0] = x; value[i][1] = y; value[i][2] = System.Math.Pow(x, 2); output[i] = 4 * x - y + 3; } var target = new JaggedSingularValueDecomposition(value, computeLeftSingularVectors: true, computeRightSingularVectors: true); { double[][] expected = value; double[][] actual = Matrix.Multiply(Matrix.Multiply(target.LeftSingularVectors, target.DiagonalMatrix), target.RightSingularVectors.Transpose()); // Checking the decomposition Assert.IsTrue(Matrix.IsEqual(actual, expected, 1e-8)); } { double[][] expected = value.Inverse(); double[][] actual = Matrix.Multiply(Matrix.Multiply( target.RightSingularVectors.Transpose().Inverse(), target.DiagonalMatrix.Inverse()), target.LeftSingularVectors.Inverse() ); // Checking the invers decomposition Assert.IsTrue(Matrix.IsEqual(actual, expected, 1e-8)); } { double[][] solution = target.SolveForDiagonal(output); double[][] expected = Jagged.Diagonal(output); double[][] actual = value.Dot(solution); Assert.IsTrue(Matrix.IsEqual(actual, expected, 1e-8)); } }
/// <summary> /// Solves a set of equation systems of type <c>A * X = B</c> where B is a diagonal matrix. /// </summary> /// <param name="diagonal">Diagonal fo the right hand side matrix with as many rows as <c>A</c>.</param> /// <returns>Matrix <c>X</c> so that <c>L * U * X = B</c>.</returns> /// public Single[][] SolveForDiagonal(Single[] diagonal) { if (diagonal == null) { throw new ArgumentNullException("diagonal"); } return(Solve(Jagged.Diagonal(diagonal))); }
/// <summary>Least squares solution of <c>A * X = I</c></summary> public Double[][] Inverse() { if (!this.FullRank) { throw new InvalidOperationException("Matrix is rank deficient."); } return(Solve(Jagged.Diagonal(n, n, (Double)1))); }
/// <summary> /// Reverts a set of projected data into it's original form. Complete reverse /// transformation is not always possible and is not even guaranteed to exist. /// </summary> /// /// <remarks> /// <para> /// This method works using a closed-form MDS approach as suggested by /// Kwok and Tsang. It is currently a direct implementation of the algorithm /// without any kind of optimization. /// </para> /// <para> /// Reference: /// - http://cmp.felk.cvut.cz/cmp/software/stprtool/manual/kernels/preimage/list/rbfpreimg3.html /// </para> /// </remarks> /// /// <param name="data">The kpca-transformed data.</param> /// <param name="neighbors">The number of nearest neighbors to use while constructing the pre-image.</param> /// public double[][] Revert(double[][] data, int neighbors = 10) { if (data == null) { throw new ArgumentNullException("data"); } if (sourceCentered == null) { throw new InvalidOperationException("The analysis must have been computed first."); } if (neighbors < 2) { throw new ArgumentOutOfRangeException("neighbors", "At least two neighbors are necessary."); } // Verify if the current kernel supports // distance calculation in feature space. var distance = kernel as IReverseDistance; if (distance == null) { throw new NotSupportedException( "Current kernel does not support distance calculation in feature space."); } int rows = data.Rows(); var result = this.result; double[][] reversion = Jagged.Zeros(rows, sourceCentered.Columns()); // number of neighbors cannot exceed the number of training vectors. int nn = System.Math.Min(neighbors, sourceCentered.Rows()); // For each point to be reversed for (int p = 0; p < rows; p++) { // 1. Get the point in feature space double[] y = data.GetRow(p); // 2. Select nn nearest neighbors of the feature space double[][] X = sourceCentered; double[] d2 = new double[result.GetLength(0)]; int[] inx = new int[result.GetLength(0)]; // 2.1 Calculate distances for (int i = 0; i < X.GetLength(0); i++) { inx[i] = i; d2[i] = distance.ReverseDistance(y, result.GetRow(i).First(y.Length)); if (Double.IsNaN(d2[i])) { d2[i] = Double.PositiveInfinity; } } // 2.2 Order them Array.Sort(d2, inx); // 2.3 Select nn neighbors int def = 0; for (int i = 0; i < d2.Length && i < nn; i++, def++) { if (Double.IsInfinity(d2[i])) { break; } } inx = inx.First(def); X = X.Get(inx).Transpose(); // X is in input space d2 = d2.First(def); // distances in input space // 3. Perform SVD // [U,L,V] = svd(X*H); // TODO: If X has more columns than rows, the SV decomposition should be // computed on the transpose of X and the left and right vectors should // be swapped. This should be fixed after more unit tests are elaborated. var svd = new JaggedSingularValueDecomposition(X, computeLeftSingularVectors: true, computeRightSingularVectors: true, autoTranspose: false); double[][] U = svd.LeftSingularVectors; double[][] L = Jagged.Diagonal(def, svd.Diagonal); double[][] V = svd.RightSingularVectors; // 4. Compute projections // Z = L*V'; double[][] Z = Matrix.DotWithTransposed(L, V); // 5. Calculate distances // d02 = sum(Z.^2)'; double[] d02 = Matrix.Sum(Elementwise.Pow(Z, 2), 0); // 6. Get the pre-image using // z = -0.5*inv(Z')*(d2-d02) double[][] inv = Matrix.PseudoInverse(Z.Transpose()); double[] w = (-0.5).Multiply(inv).Dot(d2.Subtract(d02)); double[] z = w.First(U.Columns()); // 8. Project the pre-image on the original basis using // x = U*z + sum(X,2)/nn; double[] x = (U.Dot(z)).Add(Matrix.Sum(X.Transpose(), 0).Multiply(1.0 / nn)); // 9. Store the computed pre-image. for (int i = 0; i < reversion.Columns(); i++) { reversion[p][i] = x[i]; } } // if the data has been standardized or centered, // we need to revert those operations as well if (this.Method == PrincipalComponentMethod.Standardize) { // multiply by standard deviation and add the mean reversion.Multiply(StandardDeviations, dimension: 0, result: reversion) .Add(Means, dimension: 0, result: reversion); } else if (this.Method == PrincipalComponentMethod.Center) { // only add the mean reversion.Add(Means, dimension: 0, result: reversion); } return(reversion); }