/// <summary> /// singular value decomposition /// </summary> /// <param name="X">matrix X. The elements of X will not be altered.</param> /// <param name="U">(return value) left singular vectors of X as columns of matrix U. /// If this parameter is set, it must be not null. It might be an empty array. On return /// it will be set to a physical array accordingly.</param> /// <param name="V">right singular vectors of X as rows of matrix V. /// If this parameter is set, it must be not null. It might be an empty array. On return /// it will be set to a physical array accordingly.</param> /// <param name="small">if true: return only first min(M,N) columns of U and S will be /// of size [min(M,N),min(M,N)]</param> /// <param name="discardFiniteTest">if true: the matrix given will not be checked for infinte or NaN values. If such elements /// are contained nevertheless, this may result in failing convergence or error. In worst case /// the function may hang inside the Lapack lib. Use with care! </param> /// <returns>singluar values as diagonal matrix of same size as X</returns> /// <remarks>the right singular vectors V will be returned as reference array.</remarks> public static /*!HC:outClsS*/ ILArray <double> svd(/*!HC:inCls1*/ ILArray <double> X, ref /*!HC:outClsU*/ ILArray <double> U, ref /*!HC:outClsV*/ ILArray <double> V, bool small, bool discardFiniteTest) { if (!X.IsMatrix) { throw new ILArgumentSizeException("svd is defined for matrices only!"); } // early exit for small matrices if (X.Dimensions[1] < 4 && X.Dimensions[0] == X.Dimensions[1]) { switch (X.Dimensions[0]) { case 1: if (!Object.Equals(U, null)) { U = (/*!HC:outArrU*/ double )1.0; } if (!Object.Equals(V, null)) { V = (/*!HC:outArrV*/ double )1.0; } return(new /*!HC:outClsS*/ ILArray <double> (ILMath.abs(X))); //case 2: // return -1; //case 3: // return -1; } } if (!discardFiniteTest && !all(all(isfinite(X)))) { throw new ILArgumentException("svd: input must have only finite elements!"); } if (Lapack == null) { throw new ILMathException("No Lapack package available."); } // parameter evaluation int M = X.Dimensions[0]; int N = X.Dimensions[1]; int minMN = (M < N) ? M : N; int LDU = M; int LDVT = N; int LDA = M; /*!HC:outArrS*/ double [] dS = new /*!HC:outArrS*/ double [minMN]; char jobz = (small) ? 'S' : 'A'; /*!HC:outArrU*/ double [] dU = null; /*!HC:outArrV*/ double [] dVT = null; int info = 0; if (!Object.Equals(U, null) || !Object.Equals(V, null)) { // need to return U and VT if (small) { dU = new /*!HC:outArrU*/ double [M * minMN]; dVT = new /*!HC:outArrV*/ double [N * minMN]; } else { dU = new /*!HC:outArrU*/ double [M * M]; dVT = new /*!HC:outArrV*/ double [N * N]; } } else { jobz = 'N'; } // must create copy of input ! /*!HC:inArr1*/ double [] dInput = new /*!HC:inArr1*/ double [X.m_data.Length]; System.Array.Copy(X.m_data, dInput, X.m_data.Length); /*!HC:lapack_dgesdd*/ Lapack.dgesdd(jobz, M, N, dInput, LDA, dS, dU, LDU, dVT, LDVT, ref info); if (info < 0) { throw new ILArgumentException("ILMath.svd: the " + (-info).ToString() + "th argument was invalid."); } if (info > 0) { throw new ILArgumentException("svd was not converging!"); } /*!HC:outClsS*/ ILArray <double> ret = null; if (info == 0) { // success if (!Object.Equals(U, null) || !Object.Equals(V, null)) { if (small) { ret = /*!HC:outClsS*/ ILArray <double> .zeros(minMN, minMN); } else { ret = /*!HC:outClsS*/ ILArray <double> .zeros(M, N); } for (int i = 0; i < minMN; i++) { ret.SetValue(dS[i], i, i); } if (!Object.Equals(U, null)) { U = new /*!HC:outClsU*/ ILArray <double> (dU, M, dU.Length / M); } if (!Object.Equals(V, null)) { /*!HC:complxConj*/ V = new ILArray <double> (dVT, N, dVT.Length / N).T; } } else { ret = new /*!HC:outClsS*/ ILArray <double> (dS, minMN, 1); } } return(ret); }
/// <summary> /// singular value decomposition /// </summary> /// <param name="X">matrix X. The elements of X will not be altered.</param> /// <param name="U">(return value) left singular vectors of X as columns of matrix U. /// If this parameter is set, it must be not null. It might be an empty array. On return /// it will be set to a physical array accordingly.</param> /// <param name="V">right singular vectors of X as rows of matrix V. /// If this parameter is set, it must be not null. It might be an empty array. On return /// it will be set to a physical array accordingly.</param> /// <param name="small">if true: return only first min(M,N) columns of U and S will be /// of size [min(M,N),min(M,N)]</param> /// <param name="discardFiniteTest">if true: the matrix given will not be checked for infinte or NaN values. If such elements /// are contained nevertheless, this may result in failing convergence or error. In worst case /// the function may hang inside the Lapack lib. Use with care! </param> /// <returns>singluar values as diagonal matrix of same size as X</returns> /// <remarks>the right singular vectors V will be returned as reference array.</remarks> public static /*!HC:outClsS*/ ILArray<double> svd(/*!HC:inCls1*/ ILArray<double> X, ref /*!HC:outClsU*/ ILArray<double> U, ref /*!HC:outClsV*/ ILArray<double> V, bool small, bool discardFiniteTest) { if (!X.IsMatrix) throw new ILArgumentSizeException("svd is defined for matrices only!"); // early exit for small matrices if (X.Dimensions[1] < 4 && X.Dimensions[0] == X.Dimensions[1]) { switch (X.Dimensions[0]) { case 1: if (!Object.Equals(U,null)) U = (/*!HC:outArrU*/ double ) 1.0; if (!Object.Equals(V,null)) V = (/*!HC:outArrV*/ double ) 1.0; return new /*!HC:outClsS*/ ILArray<double> ( ILMath.abs(X)); //case 2: // return -1; //case 3: // return -1; } } if (!discardFiniteTest && !all(all(isfinite( X )))) throw new ILArgumentException("svd: input must have only finite elements!"); if (Lapack == null) throw new ILMathException("No Lapack package available."); // parameter evaluation int M = X.Dimensions[0]; int N = X.Dimensions[1]; int minMN = (M < N) ? M : N; int LDU = M; int LDVT = N; int LDA = M; /*!HC:outArrS*/ double [] dS = new /*!HC:outArrS*/ double [minMN]; char jobz = (small) ? 'S' : 'A'; /*!HC:outArrU*/ double [] dU = null; /*!HC:outArrV*/ double [] dVT = null; int info = 0; if (!Object.Equals(U, null) || !Object.Equals(V, null)) { // need to return U and VT if (small) { dU = new /*!HC:outArrU*/ double [M * minMN]; dVT = new /*!HC:outArrV*/ double [N * minMN]; } else { dU = new /*!HC:outArrU*/ double [M * M]; dVT = new /*!HC:outArrV*/ double [N * N]; } } else { jobz = 'N'; } if (X.IsReference) { X.Detach(); } // must create copy of input ! /*!HC:inArr1*/ double [] dInput = new /*!HC:inArr1*/ double [X.m_data.Length]; System.Array.Copy(X.m_data, dInput, X.m_data.Length); /*!HC:lapack_dgesdd*/ Lapack.dgesdd(jobz, M, N, dInput, LDA, dS, dU, LDU, dVT, LDVT, ref info); if (info < 0) throw new ILArgumentException ("ILMath.svd: the " + (-info).ToString() +"th argument was invalid."); if (info > 0) throw new ILArgumentException("svd was not converging!"); /*!HC:outClsS*/ ILArray<double> ret = null; if (info == 0) { // success if (!Object.Equals(U, null) || !Object.Equals(V, null)) { if (small) { ret = /*!HC:outClsS*/ ILArray<double> .zeros(minMN,minMN); } else { ret = /*!HC:outClsS*/ ILArray<double> .zeros(M, N); } for (int i = 0; i < minMN; i++) { ret.SetValue(dS[i],i,i); } if (!Object.Equals(U, null)) U = new /*!HC:outClsU*/ ILArray<double> (dU,M,dU.Length / M); if (!Object.Equals(V, null)) { /*!HC:complxConj*/ V = new ILArray<double> (dVT,N,dVT.Length / N).T; } } else { ret = new /*!HC:outClsS*/ ILArray<double> (dS,minMN,1); } } return ret; }