Esempio n. 1
0
        /// <summary>
        /// cholesky factorization
        /// </summary>
        /// <param name="A">hermitian matrix A. A must be a symmetric matrix.
        /// Therefore the upper triangular part of A must be
        /// <param name="throwException">throw an ILArgumentException if A
        /// is found not to be positive definite.</param>
        /// the (complex conjugate) of the lower triangular part. No check
        /// is made for that! <br/>
        /// The elements of A will not be altered.</param>
        /// <returns>cholesky factorization</returns>
        /// <remarks><para>if <paramref name="throwException"/> is true and
        /// A is found not to be positive definite, an ILArgumentException
        /// will be thrown and the operation will be canceled.</para>
        /// <para> If <paramref name="throwException"/> is false, check the
        /// return value's dimension to determine the success of the
        /// operation (unless you are sure, A was positive definite).
        /// If A was found not pos.def. the matrix returned
        /// will be of dimension [k x k] and the result of the cholesky
        /// factorization of A[0:k-1;0:k-1]. Here k is the first leading
        /// minor of A which was found to be not positive definite.  </para>
        /// The factorization is carried out by use of the LAPACK functions
        /// DPOTRF, ZPOTRF, SPOTRF or CPOTRF respectively. </remarks>
        public static ILArray <complex> chol(
            ILArray <complex> A, bool throwException)
        {
            if (!A.IsMatrix)
            {
                throw new ILArgumentSizeException("chol is defined for matrices only!");
            }
            int n = A.Dimensions[0], info = 0;

            if (A.Dimensions[1] != n)
            {
                throw new ILArgumentException("chol: input matrix must be square!");
            }
            ILArray <complex> ret = A.copyUpperTriangle(n);

            Lapack.zpotrf('U', n, ret.m_data, n, ref info);
            if (info < 0)
            {
                throw new ILArgumentException("chol: illegal parameter error.");
            }
            else if (info > 0)
            {
                // not pos.definite
                if (!throwException)
                {
                    if (info > 1)
                    {
                        int newDim = info - 1;
                        ret = A.copyUpperTriangle(newDim);
                        Lapack.zpotrf('U', newDim, ret.m_data, newDim, ref info);
                        if (info != 0)
                        {
                            throw new ILArgumentException("chol: the original matrix given was not pos. definit. An attempt to decompose the submatrix of order " + (newDim + 1).ToString() + " failed.");
                        }
                        return(ret);
                    }
                    else
                    {
                        return(ILArray <complex> .empty(0, 0));
                    }
                }
                else
                {
                    throw new ILArgumentException("chol: the matrix given is not positive definite!");
                }
            }
            return(ret);
        }
Esempio n. 2
0
 /// <summary>
 /// upper triangular part of matrix
 /// </summary>
 /// <typeparam name="T">inner type of matrix</typeparam>
 /// <param name="A">original matrix, size [m x n]</param>
 /// <returns>physical array of size [m x n], holding upper triangular part of A</returns>
 /// <exception cref="ILNumerics.Exceptions.ILArgumentException"> if A has more than 2 dimensions.</exception>
 public static ILArray <T> triu <T>(ILArray <T> A)
 {
     if (A.Dimensions.NumberOfDimensions > 2)
     {
         throw  new ILArgumentException("triu: input argument must be matrix!");
     }
     return(A.copyUpperTriangle(A.Dimensions[0]));
 }
Esempio n. 3
0
// DO NOT EDIT INSIDE THIS REGION !! CHANGES WILL BE LOST !! 
        /// <summary>
        /// cholesky factorization 
        /// </summary>
        /// <param name="A">hermitian matrix A. A must be a symmetric matrix. 
        /// Therefore the upper triangular part of A must be 
        /// <param name="throwException">throw an ILArgumentException if A 
        /// is found not to be positive definite.</param>
        /// the (complex conjugate) of the lower triangular part. No check 
        /// is made for that! <br/> 
        /// The elements of A will not be altered.</param>
        /// <returns>cholesky factorization</returns>
        /// <remarks><para>if <paramref name="throwException"/> is true and 
        /// A is found not to be positive definite, an ILArgumentException 
        /// will be thrown and the operation will be canceled.</para>
        /// <para> If <paramref name="throwException"/> is false, check the
        /// return value's dimension to determine the success of the 
        /// operation (unless you are sure, A was positive definite). 
        /// If A was found not pos.def. the matrix returned 
        /// will be of dimension [k x k] and the result of the cholesky 
        /// factorization of A[0:k-1;0:k-1]. Here k is the first leading 
        /// minor of A which was found to be not positive definite.  </para>
        /// The factorization is carried out by use of the LAPACK functions 
        /// DPOTRF, ZPOTRF, SPOTRF or CPOTRF respectively. </remarks>
        public static  ILArray<complex> chol(
                      ILArray<complex> A, bool throwException) {
            if (!A.IsMatrix)
                throw new ILArgumentSizeException("chol is defined for matrices only!");
            int n = A.Dimensions[0], info = 0; 
            if (A.Dimensions[1] != n) 
                throw new ILArgumentException("chol: input matrix must be square!");
            ILArray<complex> ret = A.copyUpperTriangle(n);
            Lapack.zpotrf ('U', n, ret.m_data, n, ref info); 
            if (info < 0 ) {
                throw new ILArgumentException("chol: illegal parameter error.");
            } else if (info > 0) {
                // not pos.definite 
                if (! throwException) {
                    if (info > 1) {
                        int newDim = info - 1;
                        ret = A.copyUpperTriangle(newDim); 
                         Lapack.zpotrf ('U',newDim,ret.m_data, newDim, ref info);
                        if (info != 0) 
                            throw new ILArgumentException("chol: the original matrix given was not pos. definit. An attempt to decompose the submatrix of order " + (newDim + 1).ToString() + " failed."); 
                        return ret; 
                    } else {
                        return  ILArray<complex> .empty(0,0); 
                    } 
                } else {
                    throw new ILArgumentException("chol: the matrix given is not positive definite!"); 
                }
            }
            return ret; 
        }
Esempio n. 4
0
 /// <summary>
 /// find some eigenvalues and -vectors of symmetric (hermitian) matrix
 /// </summary>
 /// <param name="A">input matrix, Size [n x n], symmetric (hermitian for complex A) </param> 
 /// <param name="V">output: n eigenvectors as columns. Size [n x n]. If V is null on input, the eigenvectors will not be computed and V is not changed. </param>
 /// <param name="rangeStart">The eigenvalues will be returned by increasing size. This will determine the number of the first eigenvalue to be returned.</param>
 /// <param name="rangeEnd">Determine the number of the last eigenvalue to be returned.</param>
 /// <returns>diagonal matrix of size [n,n] with eigenvalues of A on the main diagonal.</returns>
 /// <remarks><para>For computation the Lapack functions dsyevr, ssyevr, chesvr and zheesv are used. </para>
 /// <para>Since A is symmetric, the eigenvalues will always be real. Therefore the return value will be of the same inner type as A.</para></remarks>
 /// <exception cref="ILNumerics.Exceptions.ILArgumentException">if A is not square or <paramref name="rangeEnd"/> &lt; <paramref name="rangeStart"/> or if either one is &lt;= 0.</exception>
 public static /*!HC:HCCls1*/ ILArray<double> eigSymm (/*!HC:HCCls1*/ ILArray<double> A, ref /*!HC:HCCls1*/ ILArray<double> V, /*!HC:HCArrReal*/ double rangeStart, /*!HC:HCArrReal*/ double rangeEnd) {
     if (A.IsEmpty) {
         V = /*!HC:HCCls1*/ ILArray<double> .empty(A.Dimensions); 
         return /*!HC:HCCls1*/ ILArray<double> .empty(A.Dimensions); 
     }
     int n = A.Dimensions[0]; 
     if (n != A.Dimensions[1])
         throw new ILArgumentException("eigSymm: input matrix A must be square and symmetric/hermitian.");
     /*!HC:HCCls1*/ ILArray<double> ret = null; 
     int m = 0,ldz = 0,info = 0; 
     if (rangeStart > rangeEnd) 
         throw new ILArgumentException("eigSymm: invalid range of eigenvalues requested");
     /*!HC:HCCls1*/ ILArray<double> tmpA = A.copyUpperTriangle(n); 
     /*!HC:HCClsReal*/ ILArray<double> w = new /*!HC:HCClsReal*/ ILArray<double> (new /*!HC:HCArrReal*/ double [n],1,n); 
     /*!HC:HCArr1*/ double [] z; 
     char jobz;
     if (object.Equals(V,null)) {
         z = new /*!HC:HCArr1*/ double [1]; 
         jobz = 'N';             
         ldz = 1; 
     } else {
         z = new /*!HC:HCArr1*/ double [n * n];
         jobz = 'V';
         ldz = n; 
     } 
     int [] isuppz = new int[2 * n];
     /*!HC:lapack_???evr*/ Lapack.dsyevr (jobz,'V','U',n,tmpA.m_data,n,rangeStart,rangeEnd,0,0,0, ref m,w.m_data,z,ldz,isuppz,ref info);
     ret = ILMath.diag(/*!HC:HCClsConv3*/ /**/ (w)); 
     if (jobz == 'V') {
         V =  new  /*!HC:HCCls1*/ ILArray<double> (z,n,n);
         V = V[null,ILMath.vector(0,m-1)]; 
     }
Esempio n. 5
0
 /// <summary>
 /// find all eigenvalues of symmetric (hermitian) matrix
 /// </summary>
 /// <param name="A">input matrix, Size [n x n], symmetric (hermitian for complex A) </param> 
 /// <returns>array of size [n,1] with eigenvalues of A.</returns>
 /// <remarks><para>For computation the Lapack functions dsyevr, ssyevr, chesvr and zheesv are used. </para>
 /// <para>Since A is symmetric, the eigenvalues will always be real. Therefore the return value will be of the same inner type as A.</para></remarks>
 /// <exception cref="ILNumerics.Exceptions.ILArgumentException">if A is not square.</exception>
 public static /*!HC:HCCls1*/ ILArray<double> eigSymm (/*!HC:HCCls1*/ ILArray<double> A) {
     if (A.IsEmpty) {
         return /*!HC:HCCls1*/ ILArray<double> .empty(A.Dimensions); 
     }
     int n = A.Dimensions[0]; 
     if (n != A.Dimensions[1])
         throw new ILArgumentException("eigSymm: input matrix A must be square and symmetric/hermitian.");
     /*!HC:HCCls1*/ ILArray<double> ret = null; 
     int m = 0,info = 0; 
     /*!HC:HCCls1*/ ILArray<double> tmpA = A.copyUpperTriangle(n); 
     /*!HC:HCClsReal*/ ILArray<double> w = new /*!HC:HCClsReal*/ ILArray<double> (new /*!HC:HCArrReal*/ double [n],1,n); 
     /*!HC:HCArr1*/ double [] z = new /*!HC:HCArr1*/ double [1]; ; 
     int [] isuppz = new int[2 * n];
     /*!HC:lapack_???evr*/ Lapack.dsyevr ('N','A','U',n,tmpA.m_data,n,0,0,0,0,0,ref m,w.m_data,z,1,isuppz,ref info);
     ret = /*!HC:HCClsConv3*/ /**/ (w); 
     return ret; 
 }
 /// <summary>
 /// find all eigenvalues and -vectors of symmetric (hermitian) matrix
 /// </summary>
 /// <param name="A">input matrix, Size [n x n], symmetric (hermitian for complex A) </param> 
 /// <param name="V">output: n eigenvectors as columns. Size [n x n]. If V is null on input, the eigenvectors will not be computed and V is not changed. </param>
 /// <returns>diagonal matrix of size [n,n] with eigenvalues of A on the main diagonal.</returns>
 /// <remarks><para>For computation the Lapack functions dsyevr, ssyevr, chesvr and zheesv are used. </para>
 /// <para>Since A is symmetric, the eigenvalues will always be real. Therefore the return value will be of the same inner type as A.</para></remarks>
 /// <exception cref="ILNumerics.Exceptions.ILArgumentException">if A is not square.</exception>
 public static /*!HC:HCCls1*/ ILArray<double> eigSymm (/*!HC:HCCls1*/ ILArray<double> A, ref /*!HC:HCCls1*/ ILArray<double> V) {
     if (A.IsEmpty) {
         V = /*!HC:HCCls1*/ ILArray<double> .empty(A.Dimensions); 
         return /*!HC:HCCls1*/ ILArray<double> .empty(A.Dimensions); 
     }
     int n = A.Dimensions[0]; 
     if (n != A.Dimensions[1])
         throw new ILArgumentException("eigSymm: input matrix A must be square and symmetric/hermitian.");
     /*!HC:HCCls1*/ ILArray<double> ret = null; 
     int m = 0,ldz = 0,info = 0; 
     /*!HC:HCCls1*/ ILArray<double> tmpA = A.copyUpperTriangle(n); 
     /*!HC:HCClsReal*/ ILArray<double> w = new /*!HC:HCClsReal*/ ILArray<double> (new /*!HC:HCArrReal*/ double [n],n,1); 
     /*!HC:HCArr1*/ double [] z; 
     char jobz;
     if (object.Equals(V,null)) {
         z = new /*!HC:HCArr1*/ double [1]; 
         jobz = 'N';
         ldz = 1; 
     } else {
         z = new /*!HC:HCArr1*/ double [n * n];
         jobz = 'V';
         ldz = n; 
     } 
     int [] isuppz = new int[2 * n];
     /*!HC:lapack_???evr*/ Lapack.dsyevr (jobz,'A','U',n,tmpA.m_data,n,1,n,0,0,0,ref m,w.m_data,z,ldz,isuppz,ref info);
     if (info != 0) 
         throw new ILException("eigSymm: error returned from lapack: " + info); 
     if (jobz == 'V') {
         V =  new  /*!HC:HCCls1*/ ILArray<double> (z,n,n);
         V = V[null,ILMath.vector(0,m-1)]; 
         ret = ILMath.diag(/*!HC:HCClsConv3*/ /**/ (w)); 
     } else {
         ret = /*!HC:HCClsConv3*/ /**/ (w);
     }
     return ret; 
 }
 /// <summary>
 /// find some eigenvalues and -vectors of symmetric (hermitian) matrix
 /// </summary>
 /// <param name="A">input matrix, Size [n x n], symmetric (hermitian for complex A) </param> 
 /// <param name="V">output: n eigenvectors as columns. Size [n x n]. If V is null on input, the eigenvectors will not be computed and V is not changed. </param>
 /// <param name="rangeStart">specify the lowest limit for the range of eigenvalues to be queried.</param>
 /// <param name="rangeEnd">specify the upper limit for the range of eigenvalues to be queried.</param>
 /// <returns>diagonal matrix of size [n,n] with eigenvalues of A on the main diagonal.</returns>
 /// <remarks><para>For computation the Lapack functions dsyevr, ssyevr, chesvr and zheesv are used. </para>
 /// <para>Since A is symmetric, the eigenvalues will always be real. Therefore the return value will be of the same inner type as A.</para></remarks>
 /// <exception cref="ILNumerics.Exceptions.ILArgumentException">if A is not square or <paramref name="rangeEnd"/> &lt; <paramref name="rangeStart"/></exception>
 public static /*!HC:HCCls1*/ ILArray<double> eigSymm (/*!HC:HCCls1*/ ILArray<double> A, ref /*!HC:HCCls1*/ ILArray<double> V, int rangeStart, int rangeEnd) {
     if (A.IsEmpty) {
         V = /*!HC:HCCls1*/ ILArray<double> .empty(A.Dimensions); 
         return /*!HC:HCCls1*/ ILArray<double> .empty(A.Dimensions); 
     }
     int n = A.Dimensions[0]; 
     if (n != A.Dimensions[1])
         throw new ILArgumentException("eigSymm: input matrix A must be square and symmetric/hermitian.");
     /*!HC:HCCls1*/ ILArray<double> ret = null; 
     int m = 0,ldz = 0,info = 0; 
     if (rangeEnd < rangeStart || rangeStart < 1) 
         throw new ILArgumentException("eigSymm: invalid range of eigenvalues requested");
     /*!HC:HCCls1*/ ILArray<double> tmpA = A.copyUpperTriangle(n); 
     /*!HC:HCClsReal*/ ILArray<double> w = new /*!HC:HCClsReal*/ ILArray<double> (new /*!HC:HCArrReal*/ double [n],1,n); 
     /*!HC:HCArr1*/ double [] z; 
     char jobz;
     if (object.Equals(V,null)) {
         z = new /*!HC:HCArr1*/ double [1]; 
         jobz = 'N';
         ldz = 1; 
     } else {
         z = new /*!HC:HCArr1*/ double [n * n];
         jobz = 'V';
         ldz = n; 
     } 
     int [] isuppz = new int[2 * n];
     /*!HC:lapack_???evr*/ Lapack.dsyevr (jobz,'I','U',n,tmpA.m_data,n,0,0,rangeStart,rangeEnd,0,ref m,w.m_data,z,ldz,isuppz,ref info);
     ret = ILMath.diag(/*!HC:HCClsConv3*/ /**/ (w)); 
     if (jobz == 'V') {
         V =  new  /*!HC:HCCls1*/ ILArray<double> (z,n,n);
         V = V[null,ILMath.vector(0,m-1)]; 
     }
     return ret; 
 }
Esempio n. 6
0
 /// <summary>
 /// Solve linear equation system
 /// </summary>
 /// <param name="A">Matrix A. Size [n x q]</param>
 /// <param name="B">'rigth hand side' B. Size [n x m]</param>
 /// <param name="props">Matrix properties. If defined, no checks are made for the structure of A. If the matrix A was found to be (close to or) singular, the 'MatrixProperties.Singular' flag in props will be set. This flag should be tested on return, in order to verify the reliability of the solution.</param>
 /// <returns>the solution x solving multiply(A,x) = B. Size [n x m]</returns>
 /// <remarks><para>depending on the <paramref name="props"/> parameter the equation system will be solved differently for special structures of A:
 /// <list type="bullet">
 /// <item>If A is square (q == n) and an <b>upper or lower triangular</b> matrix, the system will directly be solved via backward- or forward substitution. Therefore the Lapack function ?trtrs will be used, whenever the memory layout of A is suitable. This may be the case even for reference ILArray's! 
 /// <example><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix 
 /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
 /// // now construct a right side and solve the equations: 
 /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T; 
 /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved beeing reference arrays! ]]></example></item>
 /// <item><para>if A is square and symmetric or hermitian, A will be decomposed into a triangular equation system using cholesky factorization and Lapack. The system is than solved using performant Lapack routines.</para>
 /// <para>if during the cholesky factorization A was found to be <b>not positive definite</b> - the corresponding flag in props will be cleaned and <c>null</c> will be returned.</para></item>
 /// <item>otherwise if A is square only, it will be decomposed into upper and lower triangular matrices using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
 /// <item>otherwise, if A is of size [q x n] and q != n, the system is solved using QR decomposition. A may be rank deficient. The solution is computed by use of the Lapack routine '?gelsy' and may be a reference array.</item>
 /// </list></para>
 /// <para>Compatibility with Matlab<sup>(R)</sup>: If A is square, the algorithm used follows the same logic as Matlab up to Rel 14, with the exception of Hessenberg matrices wich are solved via LU factorization here. The un-squared case is handled differently. A direct Lapack driver function (?gelsy) is used here. Therefore the solutions might differ! However, the solution will of course fullfill the equation A * x = B without round off errrors. </para>
 /// <para>For specifiying the rank of A in the unsquare case (q != n), the eps member from <see cref="ILNumerics.Settings.ILSettings"/> class is used.</para></remarks>
 public static  ILArray<complex> linsolve( ILArray<complex> A,  ILArray<complex> B, ref MatrixProperties props) {
     if (object.Equals(A,null)) 
         throw new ILArgumentException("linsolve: input argument A must not be null!"); 
     if (object.Equals(B,null))
         throw new ILArgumentException("linsolve: input argument B must not be null!"); 
     if (A.IsEmpty || B.IsEmpty)
         return  ILArray<complex> .empty(A.Dimensions); 
     if (A.Dimensions[0] != B.Dimensions[0])
         throw new ILArgumentException("linsolve: number of rows for matrix A must match number of rows for RHS!");
     int info = 0, m = A.Dimensions[0]; 
     ILArray<complex> ret; 
     if (m == A.Dimensions[1]) {
         props |= MatrixProperties.Square; 
         if ((props & MatrixProperties.LowerTriangular) != 0) {
             ret = solveLowerTriangularSystem(A,B,ref info); 
             if (info > 0)
                 props |= MatrixProperties.Singular; 
             return ret;
         } 
         if ((props & MatrixProperties.UpperTriangular) != 0) {
             ret = solveUpperTriangularSystem(A,B, ref info); 
             if (info > 0)
                 props |= MatrixProperties.Singular; 
            return ret; 
         } 
         if ((props & MatrixProperties.Hermitian) != 0) {
             ILArray<complex> cholFact = A.copyUpperTriangle(m);
             Lapack.zpotrf ('U', m, cholFact.m_data, m, ref info); 
             if (info > 0) {
                 props ^= MatrixProperties.Hermitian; 
                 return null; 
             }  else {
                 // solve 
                 ret = ( ILArray<complex> )B.Clone(); 
                 Lapack.zpotrs ('U',m,B.Dimensions[1],cholFact.m_data,m,ret.m_data,m,ref info);   
                 return ret; 
             } 
         } else {
             // attempt complete (expensive) LU factorization 
             ILArray<complex> L = ( ILArray<complex> )A.Clone();  
             int [] pivInd = new int[m]; 
             Lapack.zgetrf (m, m, L.m_data, m, pivInd ,ref info); 
             if (info > 0)
                 props |= MatrixProperties.Singular; 
             ret = ( ILArray<complex> )B.Clone(); 
             Lapack.zgetrs ('N',m,B.Dimensions[1],L.m_data,m,pivInd,ret.m_data,m,ref info); 
             if (info < 0) 
                 throw new ILArgumentException("linsolve: failed to solve via lapack dgetrs");
             return ret; 
         }
     } else {
         // under- / overdetermined system
         int n = A.Dimensions[1], rank = 0, minMN = (m < n)? m:n, maxMN = (m > n)? m:n;
         int nrhs = B.Dimensions[1];
         if (B.Dimensions[0] != m) 
             throw new ILArgumentException("linsolve: right hand side matrix B must match input A!"); 
         ILArray<complex> tmpA = ( ILArray<complex> )A.Clone();
         if (m < n) {
             ret = new  ILArray<complex> (new  complex [n * nrhs],n,nrhs);
             ret["0:"+(m-1)+";:"] = B;
         } else {
             ret = ( ILArray<complex> )B.Clone();
         }
         int [] JPVT = new int [n]; 
         Lapack.zgelsy (m, n, B.Dimensions[1], tmpA.m_data, m, ret.m_data, 
                             maxMN, JPVT,  ILMath.MachineParameterDouble.eps ,
                             ref rank, ref info); 
         if (n < m) {
             ret = ret[ILMath.vector(0,n-1),null];
         }
         if (rank < minMN)
             props |= MatrixProperties.RankDeficient; 
         return ret; 
     }
 }
Esempio n. 7
0
        /// <summary>
        /// Solve linear equation system
        /// </summary>
        /// <param name="A">Matrix A. Size [n x q]</param>
        /// <param name="B">'rigth hand side' B. Size [n x m]</param>
        /// <param name="props">Matrix properties. If defined, no checks are made for the structure of A. If the matrix A was found to be (close to or) singular, the 'MatrixProperties.Singular' flag in props will be set. This flag should be tested on return, in order to verify the reliability of the solution.</param>
        /// <returns>the solution x solving multiply(A,x) = B. Size [n x m]</returns>
        /// <remarks><para>depending on the <paramref name="props"/> parameter the equation system will be solved differently for special structures of A:
        /// <list type="bullet">
        /// <item>If A is square (q == n) and an <b>upper or lower triangular</b> matrix, the system will directly be solved via backward- or forward substitution. Therefore the Lapack function ?trtrs will be used, whenever the memory layout of A is suitable. This may be the case even for reference ILArray's!
        /// <example><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix
        /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
        /// // now construct a right side and solve the equations:
        /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T;
        /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved beeing reference arrays! ]]></example></item>
        /// <item><para>if A is square and symmetric or hermitian, A will be decomposed into a triangular equation system using cholesky factorization and Lapack. The system is than solved using performant Lapack routines.</para>
        /// <para>if during the cholesky factorization A was found to be <b>not positive definite</b> - the corresponding flag in props will be cleaned and <c>null</c> will be returned.</para></item>
        /// <item>otherwise if A is square only, it will be decomposed into upper and lower triangular matrices using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
        /// <item>otherwise, if A is of size [q x n] and q != n, the system is solved using QR decomposition. A may be rank deficient. The solution is computed by use of the Lapack routine '?gelsy' and may be a reference array.</item>
        /// </list></para>
        /// <para>Compatibility with Matlab<sup>(R)</sup>: If A is square, the algorithm used follows the same logic as Matlab up to Rel 14, with the exception of Hessenberg matrices wich are solved via LU factorization here. The un-squared case is handled differently. A direct Lapack driver function (?gelsy) is used here. Therefore the solutions might differ! However, the solution will of course fullfill the equation A * x = B without round off errrors. </para>
        /// <para>For specifiying the rank of A in the unsquare case (q != n), the eps member from <see cref="ILNumerics.Settings.ILSettings"/> class is used.</para></remarks>
        public static ILArray <complex> linsolve(ILArray <complex> A, ILArray <complex> B, ref MatrixProperties props)
        {
            if (object.Equals(A, null))
            {
                throw new ILArgumentException("linsolve: input argument A must not be null!");
            }
            if (object.Equals(B, null))
            {
                throw new ILArgumentException("linsolve: input argument B must not be null!");
            }
            if (A.IsEmpty || B.IsEmpty)
            {
                return(ILArray <complex> .empty(A.Dimensions));
            }
            if (A.Dimensions[0] != B.Dimensions[0])
            {
                throw new ILArgumentException("linsolve: number of rows for matrix A must match number of rows for RHS!");
            }
            int info = 0, m = A.Dimensions[0];
            ILArray <complex> ret;

            if (m == A.Dimensions[1])
            {
                props |= MatrixProperties.Square;
                if ((props & MatrixProperties.LowerTriangular) != 0)
                {
                    ret = solveLowerTriangularSystem(A, B, ref info);
                    if (info > 0)
                    {
                        props |= MatrixProperties.Singular;
                    }
                    return(ret);
                }
                if ((props & MatrixProperties.UpperTriangular) != 0)
                {
                    ret = solveUpperTriangularSystem(A, B, ref info);
                    if (info > 0)
                    {
                        props |= MatrixProperties.Singular;
                    }
                    return(ret);
                }
                if ((props & MatrixProperties.Hermitian) != 0)
                {
                    ILArray <complex> cholFact = A.copyUpperTriangle(m);
                    Lapack.zpotrf('U', m, cholFact.m_data, m, ref info);
                    if (info > 0)
                    {
                        props ^= MatrixProperties.Hermitian;
                        return(null);
                    }
                    else
                    {
                        // solve
                        ret = (ILArray <complex>)B.Clone();
                        Lapack.zpotrs('U', m, B.Dimensions[1], cholFact.m_data, m, ret.m_data, m, ref info);
                        return(ret);
                    }
                }
                else
                {
                    // attempt complete (expensive) LU factorization
                    ILArray <complex> L      = (ILArray <complex>)A.Clone();
                    int []            pivInd = new int[m];
                    Lapack.zgetrf(m, m, L.m_data, m, pivInd, ref info);
                    if (info > 0)
                    {
                        props |= MatrixProperties.Singular;
                    }
                    ret = (ILArray <complex>)B.Clone();
                    Lapack.zgetrs('N', m, B.Dimensions[1], L.m_data, m, pivInd, ret.m_data, m, ref info);
                    if (info < 0)
                    {
                        throw new ILArgumentException("linsolve: failed to solve via lapack dgetrs");
                    }
                    return(ret);
                }
            }
            else
            {
                // under- / overdetermined system
                int n = A.Dimensions[1], rank = 0, minMN = (m < n)? m:n, maxMN = (m > n)? m:n;
                int nrhs = B.Dimensions[1];
                if (B.Dimensions[0] != m)
                {
                    throw new ILArgumentException("linsolve: right hand side matrix B must match input A!");
                }
                ILArray <complex> tmpA = (ILArray <complex>)A.Clone();
                if (m < n)
                {
                    ret = new  ILArray <complex> (new  complex [n * nrhs], n, nrhs);
                    ret["0:" + (m - 1) + ";:"] = B;
                }
                else
                {
                    ret = (ILArray <complex>)B.Clone();
                }
                int [] JPVT = new int [n];
                Lapack.zgelsy(m, n, B.Dimensions[1], tmpA.m_data, m, ret.m_data,
                              maxMN, JPVT, ILMath.MachineParameterDouble.eps,
                              ref rank, ref info);
                if (n < m)
                {
                    ret = ret[ILMath.vector(0, n - 1), null];
                }
                if (rank < minMN)
                {
                    props |= MatrixProperties.RankDeficient;
                }
                return(ret);
            }
        }