Esempio n. 1
0
        /// <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 ILArray <float> svd(ILArray <fcomplex> X, ref ILArray <fcomplex> U, ref ILArray <fcomplex> 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 = ( fcomplex )1.0;
                    }
                    if (!Object.Equals(V, null))
                    {
                        V = ( fcomplex )1.0;
                    }
                    return(new  ILArray <float> (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;

            float [] dS   = new  float [minMN];
            char     jobz = (small) ? 'S' : 'A';

            fcomplex [] dU   = null;
            fcomplex [] dVT  = null;
            int         info = 0;

            if (!Object.Equals(U, null) || !Object.Equals(V, null))
            {
                // need to return U and VT
                if (small)
                {
                    dU  = new  fcomplex  [M * minMN];
                    dVT = new  fcomplex [N * minMN];
                }
                else
                {
                    dU  = new  fcomplex [M * M];
                    dVT = new  fcomplex [N * N];
                }
            }
            else
            {
                jobz = 'N';
            }

            if (X.IsReference)
            {
                X.Detach();
            }
            // must create copy of input !
            fcomplex [] dInput = new  fcomplex [X.m_data.Length];
            System.Array.Copy(X.m_data, dInput, X.m_data.Length);
            Lapack.cgesdd(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!");
            }
            ILArray <float> ret = null;

            if (info == 0)
            {
                // success
                if (!Object.Equals(U, null) || !Object.Equals(V, null))
                {
                    if (small)
                    {
                        ret = ILArray <float> .zeros(minMN, minMN);
                    }
                    else
                    {
                        ret = ILArray <float> .zeros(M, N);
                    }
                    for (int i = 0; i < minMN; i++)
                    {
                        ret.SetValue(dS[i], i, i);
                    }
                    if (!Object.Equals(U, null))
                    {
                        U = new  ILArray <fcomplex> (dU, M, dU.Length / M);
                    }
                    if (!Object.Equals(V, null))
                    {
                        V = conj(new  ILArray <fcomplex> (dVT, N, dVT.Length / N).T);
                    }
                }
                else
                {
                    ret = new  ILArray <float> (dS, minMN, 1);
                }
            }
            return(ret);
        }