Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GaussianProcessTuning/ILNumerics.2.14.4735.573/Functions/builtin/slash.cs @ 9102

Last change on this file since 9102 was 9102, checked in by gkronber, 12 years ago

#1967: ILNumerics source for experimentation

File size: 72.7 KB
Line 
1///
2///    This file is part of ILNumerics Community Edition.
3///
4///    ILNumerics Community Edition - high performance computing for applications.
5///    Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
6///
7///    ILNumerics Community Edition is free software: you can redistribute it and/or modify
8///    it under the terms of the GNU General Public License version 3 as published by
9///    the Free Software Foundation.
10///
11///    ILNumerics Community Edition is distributed in the hope that it will be useful,
12///    but WITHOUT ANY WARRANTY; without even the implied warranty of
13///    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14///    GNU General Public License for more details.
15///
16///    You should have received a copy of the GNU General Public License
17///    along with ILNumerics Community Edition. See the file License.txt in the root
18///    of your distribution package. If not, see <http://www.gnu.org/licenses/>.
19///
20///    In addition this software uses the following components and/or licenses:
21///
22///    =================================================================================
23///    The Open Toolkit Library License
24///   
25///    Copyright (c) 2006 - 2009 the Open Toolkit library.
26///   
27///    Permission is hereby granted, free of charge, to any person obtaining a copy
28///    of this software and associated documentation files (the "Software"), to deal
29///    in the Software without restriction, including without limitation the rights to
30///    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
31///    the Software, and to permit persons to whom the Software is furnished to do
32///    so, subject to the following conditions:
33///
34///    The above copyright notice and this permission notice shall be included in all
35///    copies or substantial portions of the Software.
36///
37///    =================================================================================
38///   
39
40using System;
41using System.Collections.Generic;
42using System.Text;
43using ILNumerics.Storage;
44using ILNumerics.Misc;
45using ILNumerics.Exceptions;
46
47
48
49namespace ILNumerics {
50    public partial class ILMath {
51
52
53       
54        /// <summary>
55        /// Solve linear equation system
56        /// </summary>
57        /// <param name="A">Matrix A. Size [n x q]</param>
58        /// <param name="B">Right hand side B. Size [n x m]</param>
59        /// <returns>Solution x solving the equation system: multiply(A, x) = B. Size [n x m]</returns>
60        /// <remarks><para>Depending on the structure and properties of A, the equation system will be solved in different ways:
61        /// <list type="bullet">
62        /// <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!
63        /// <example><code><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix
64        /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
65        /// // now construct a right side and solve the equations:
66        /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T;
67        /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved being reference arrays! ]]></code></example></item>
68        /// <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>
69        /// <para>If during the cholesky factorization A was found to be <b>not positive definite</b> - the cholesky factorization is canceled. </para></item>
70        /// <item>otherwise, if A is square only, it will be decomposed into upper and lower triangular martices using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
71        /// <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>
72        /// </list></para>
73        /// <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>
74        /// <para>For specifiying the rank of A in the unsquare case (q != n), <see cref="ILNumerics.ILMath.eps"/> is used.</para></remarks>
75        public static ILRetArray< double > linsolve(ILInArray< double > A, ILInArray< double > B) {
76            if (object.Equals(A,null) || object.Equals(B,null))
77                throw new ILArgumentException("parameter must not be null!");
78            using (ILScope.Enter(A, B)) {
79                MatrixProperties props = MatrixProperties.None;
80                if (A.Size[0] == A.Size[1]) {
81                    props |= MatrixProperties.Square;
82                    if (ILMath.istriup(A)) {
83                        props |= MatrixProperties.UpperTriangular;
84                        return linsolve(A, B, ref props);
85                    }
86                    if (ILMath.istrilow(A)) {
87                        props |= MatrixProperties.LowerTriangular;
88                        return linsolve(A, B, ref props);
89                    }
90                    if (ILMath.ishermitian(A)) {
91                        // give cholesky a try
92                        props |= MatrixProperties.Hermitian;
93                        props |= MatrixProperties.PositivDefinite;
94                        ILArray< double> ret = linsolve(A, B, ref props);
95                        if (!object.Equals(ret, null)) {
96                            return ret;
97                        } else {
98                            props ^= MatrixProperties.PositivDefinite;
99                        }
100                    }
101                }
102                return linsolve(A, B, ref props);
103            }
104        }
105
106        /// <summary>
107        /// Solve linear equation system
108        /// </summary>
109        /// <param name="A">Matrix A. Size [n x q]</param>
110        /// <param name="B">Right hand side B. Size [n x m]</param>
111        /// <param name="props">Matrix properties. If defined, no checks are made for the structure of A. If the
112        /// matrix A was found to be (close to or) singular, the 'MatrixProperties.Singular' flag in props will be set.
113        /// This flag should be tested on return, in order to verify the reliability of the solution.</param>
114        /// <returns>The solution x solving multiply(A,x) = B. Size [n x m]</returns>
115        /// <remarks><para>Depending on the <paramref name="props"/> parameter the equation system will be solved
116        /// differently for special structures of A:
117        /// <list type="bullet">
118        /// <item>If A is square (q == n) and an <b>upper or lower triangular</b> matrix, the system will directly
119        /// be solved via backward- or forward substitution. Therefore the Lapack function ?trtrs will be used,
120        /// whenever the memory layout of A is suitable. This may be the case even for reference ILArray's!
121        /// <example><code><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix
122        /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
123        /// // now construct a right side and solve the equations:
124        /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T;
125        /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved being reference arrays! ]]></code></example></item>
126        /// <item><para>If A is square and symmetric or hermitian, A will be decomposed into a triangular equation
127        /// system using cholesky factorization and Lapack. The system is than solved using performant Lapack routines.</para>
128        /// <para>If during the cholesky factorization A was found to be <b>not positive definite</b> - the
129        /// corresponding flag in props will be cleaned and <c>null</c> will be returned.</para></item>
130        /// <item>Otherwise if A is square only, it will be decomposed into upper and lower triangular matrices
131        /// using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
132        /// <item>Otherwise, if A is of size [q x n] and q != n, the system is solved using QR decomposition.
133        /// A may be rank deficient. The solution is computed by use of the Lapack routine '?gelsy' and may be a
134        /// reference array.</item>
135        /// </list></para>
136        /// <para>Compatibility with Matlab<sup>(R)</sup>: If A is square, the algorithm used follows the same
137        /// logic as Matlab up to Rel 14, with the exception of Hessenberg matrices wich are solved via LU
138        /// factorization here. The un-squared case is handled differently. A direct Lapack driver function
139        /// (?gelsy) is used here. Therefore the solutions might differ! However, the solution will of course
140        /// fullfill the equation A * x = B without round off errrors. </para>
141        /// <para>For specifiying the rank of A in the unsquare case (q != n),
142        /// <see cref="ILNumerics.ILMath.eps"/> is used.</para></remarks>
143        public static ILRetArray< double > linsolve(ILInArray< double > A, ILInArray< double > B, ref MatrixProperties props) {
144            if (object.Equals(A,null))
145                throw new ILArgumentException("input argument A must not be null!");
146            if (object.Equals(B,null))
147                throw new ILArgumentException("input argument B must not be null!");
148            using (ILScope.Enter(A, B)) {
149                if (A.IsEmpty || B.IsEmpty)
150                    return empty< double>(A.Size);
151                if (A.Size[0] != B.Size[0])
152                    throw new ILArgumentException("number of rows for matrix A must match number of rows for RHS!");
153                int info = 0, m = A.Size[0];
154                ILArray< double> ret = empty<double>(ILSize.Empty00);
155                if (m == A.Size[1]) {
156                    props |= MatrixProperties.Square;
157                    if ((props & MatrixProperties.LowerTriangular) != 0) {
158                        ret.a = solveLowerTriangularSystem(A, B, ref info);
159                        if (info > 0)
160                            props |= MatrixProperties.Singular;
161                        return ret;
162                    }
163                    if ((props & MatrixProperties.UpperTriangular) != 0) {
164                        ret.a = solveUpperTriangularSystem(A, B, ref info);
165                        if (info > 0)
166                            props |= MatrixProperties.Singular;
167                        return ret;
168                    }
169                    if ((props & MatrixProperties.Hermitian) != 0) {
170                        ILDenseStorage< double> cholFact = A.Storage.copyUpperTriangle(m);
171                        /*!HC:lapack_*potrf*/
172                        Lapack.dpotrf('U', m, cholFact.GetArrayForWrite(), m, ref info);
173                        if (info > 0) {
174                            props ^= MatrixProperties.Hermitian;
175                            cholFact.Dispose();
176                            return null;
177                        } else {
178                            // solve
179                            ret.a = B.C;
180                            /*!HC:lapack_*potrs*/
181                            Lapack.dpotrs('U', m, B.Size[1], cholFact.GetArrayForWrite(), m, ret.GetArrayForWrite(), m, ref info);
182                            cholFact.Dispose();
183                            return ret;
184                        }
185                    } else {
186                        // attempt complete (expensive) LU factorization
187                        ILArray< double> L = A.C;
188                        int[] pivInd = ILMemoryPool.Pool.New<int>(m);
189                        /*!HC:lapack_*getrf*/
190                        Lapack.dgetrf(m, m, L.GetArrayForWrite(), m, pivInd, ref info);
191                        if (info > 0)
192                            props |= MatrixProperties.Singular;
193                        ret.a = B.C;
194                        /*!HC:lapack_*getrs*/
195                        Lapack.dgetrs('N', m, B.Size[1], L.GetArrayForWrite(), m, pivInd, ret.GetArrayForWrite(), m, ref info);
196                        if (info < 0)
197                            throw new ILArgumentException("failed to solve via lapack dgetrs");
198                        return ret;
199                    }
200                } else {
201                    // under- / overdetermined system
202                    int n = A.Size[1], rank = 0, minMN = (m < n) ? m : n, maxMN = (m > n) ? m : n;
203                    int nrhs = B.Size[1];
204                    if (B.Size[0] != m)
205                        throw new ILArgumentException("right hand side matrix B must match input A!");
206                    ILArray</*!HCinArr1*/ double> tmpA = A.C;
207                    if (m < n) {
208                        ret.a = zeros< double>(n, nrhs);
209                        ret[r(0, m - 1), full] = B.C;
210                    } else {
211                        ret.a = B.C;
212                    }
213                    int[] JPVT = new int[n];
214                    /*!HC:Lapack.?gelsy*/
215                    Lapack.dgelsy(m, n, B.Size[1], tmpA.GetArrayForWrite(), m, ret.GetArrayForWrite(),
216                        maxMN, JPVT,  ILMath.MachineParameterDouble.eps,
217                        ref rank, ref info);
218                    if (n < m) {
219                        ret.a = ret[r(0, n - 1), full];
220                    }
221                    if (rank < minMN)
222                        props |= MatrixProperties.RankDeficient;
223                    return ret;
224                }
225            }
226        }
227       
228        /// <summary>
229        /// Solve system of linear equations A*x = b, with A being a upper triangular matrix
230        /// </summary>
231        /// <param name="A">Input matrix of size [n x n], must be upper triangular. No check is made for that!</param>
232        /// <param name="B">Solution vector or matrix. Size [n x m]</param>
233        /// <param name="singularityDetect">[Output] This value gives the row of A, where a singularity has been detected (if any). If A is not singular, this will be a negative value.</param>
234        /// <returns>Solution x solving A * x = b.</returns>
235        /// <remarks><para>The solution will be determined via backward substitution</para>
236        /// <para>Make sure, A and b are of correct size, since no checks are made for that!</para>
237        /// <para>This function is used by ILMath.linsolve. There should be rare need for you to call this function directly.</para>
238        /// <para>Elements of A below the main diagonal will not be accessed.</para>
239        /// <para>If A has been found to be singular, the array returned will contain NaN values for corresponding elements!</para></remarks>
240        internal static ILRetArray< double > solveUpperTriangularSystem (ILInArray< double > A, ILInArray< double > B, ref int singularityDetect) {
241            System.Diagnostics.Debug.Assert(B.Size[1] >= 0);
242            System.Diagnostics.Debug.Assert(B.Size[0] == A.Size[1]);
243            System.Diagnostics.Debug.Assert(A.Size[0] == A.Size[1]);
244            using (ILScope.Enter(A, B)) {
245                singularityDetect = -1;
246                int n = A.Size[0];
247                int m = B.Size[1];
248                int info = 0;
249                ILArray< double> ret = B.C;
250               
251                double[] retArr = ret.GetArrayForWrite();
252                // solve using Lapack
253                unsafe {
254                    fixed ( double* ptrA = A.GetArrayForRead())
255                    fixed ( double* ptrB = ret.GetArrayForWrite()) {
256                        /*!HC:lapack.?trtrs*/
257                        Lapack.dtrtrs('U', 'N', 'N', A.Size[0], B.Size[1], (IntPtr)ptrA, A.Size[0], (IntPtr)ptrB, B.Size[0], ref info);
258                    }
259                }
260                if (info < 0)
261                    throw new ILArgumentException("error inside Lapack function ?trtrs for argument: " + (-info));
262                if (info > 0) {
263                    singularityDetect = info - 1;
264                    for (m = 0; m < ret.Size[1]; m++) {
265                        info = m * n + singularityDetect;
266                        for (int i = singularityDetect; i < n; i++) {
267                            retArr[info++] =  double.NaN;
268                        }
269                    }
270                } else {
271                    singularityDetect = -1;
272                }
273                return ret;
274            }
275        }
276
277        /// <summary>
278        /// Solve system of linear equations A*x = b, with A being a lower triangular matrix
279        /// </summary>
280        /// <param name="A">Input matrix of size [n x n], must be lower triangular. No check is made for that!</param>
281        /// <param name="B">Solution vector. Size [n x 1]</param>
282        /// <param name="singularityDetect">[Output] This value gives the row of A, where a singularity has been detected (if any). If A is not singular, this will be a negative value.</param>
283        /// <returns>Solution x solving A * x = b.</returns>
284        /// <remarks><para>The solution will be determined via forward substitution</para>
285        /// <para>Make sure, A and b are of correct size, since no checks are made for that!</para>
286        /// <para>This function is used by ILMath.linsolve. There should be rare need for you to call this function directly.</para>
287        /// <para>Elements of A above the main diagonal will not be accessed.</para>
288        /// <para>If A has been found to be singular, the array returned will contain NaN values for corresponding elements!</para></remarks>
289        internal static ILRetArray< double> solveLowerTriangularSystem( ILInArray< double> A, ILInArray< double> B, ref int singularityDetect ) {
290            System.Diagnostics.Debug.Assert(B.Size[1] >= 0);
291            System.Diagnostics.Debug.Assert(B.Size[0] == A.Size[1]);
292            System.Diagnostics.Debug.Assert(A.Size[0] == A.Size[1]);
293            using (ILScope.Enter(A, B)) {
294                singularityDetect = -1;
295                int n = A.Size[0];
296                int m = B.Size[1];
297                int info = 0;
298                ILArray< double> ret = B.C;
299               
300                double[] retArr = ret.GetArrayForWrite();
301                // solve using Lapack
302                unsafe {
303                    fixed ( double* ptrA = A.GetArrayForRead())
304                    fixed ( double* ptrB = ret.GetArrayForWrite()) {
305                        /*!HC:lapack.?trtrs*/
306                        Lapack.dtrtrs('L', 'N', 'N', A.Size[0], B.Size[1], (IntPtr)ptrA, A.Size[0], (IntPtr)ptrB, B.Size[0], ref info);
307                    }
308                }
309                if (info < 0)
310                    throw new ILArgumentException("error inside Lapack function ?trtrs for argument: " + (-info));
311                if (info > 0) {
312                    singularityDetect = info - 1;
313                    for (m = 0; m < ret.Size[1]; m++) {
314                        info = m * n + singularityDetect;
315                        for (int i = singularityDetect; i < n; i++) {
316                            retArr[info++] =  double.NaN;
317                        }
318                    }
319                } else {
320                    singularityDetect = -1;
321                }
322                return ret;
323            }
324        }
325
326
327#region HYCALPER AUTO GENERATED CODE
328
329       
330        /// <summary>
331        /// Solve linear equation system
332        /// </summary>
333        /// <param name="A">Matrix A. Size [n x q]</param>
334        /// <param name="B">Right hand side B. Size [n x m]</param>
335        /// <returns>Solution x solving the equation system: multiply(A, x) = B. Size [n x m]</returns>
336        /// <remarks><para>Depending on the structure and properties of A, the equation system will be solved in different ways:
337        /// <list type="bullet">
338        /// <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!
339        /// <example><code><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix
340        /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
341        /// // now construct a right side and solve the equations:
342        /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T;
343        /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved being reference arrays! ]]></code></example></item>
344        /// <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>
345        /// <para>If during the cholesky factorization A was found to be <b>not positive definite</b> - the cholesky factorization is canceled. </para></item>
346        /// <item>otherwise, if A is square only, it will be decomposed into upper and lower triangular martices using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
347        /// <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>
348        /// </list></para>
349        /// <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>
350        /// <para>For specifiying the rank of A in the unsquare case (q != n), <see cref="ILNumerics.ILMath.eps"/> is used.</para></remarks>
351        public static ILRetArray< float > linsolve(ILInArray< float > A, ILInArray< float > B) {
352            if (object.Equals(A,null) || object.Equals(B,null))
353                throw new ILArgumentException("parameter must not be null!");
354            using (ILScope.Enter(A, B)) {
355                MatrixProperties props = MatrixProperties.None;
356                if (A.Size[0] == A.Size[1]) {
357                    props |= MatrixProperties.Square;
358                    if (ILMath.istriup(A)) {
359                        props |= MatrixProperties.UpperTriangular;
360                        return linsolve(A, B, ref props);
361                    }
362                    if (ILMath.istrilow(A)) {
363                        props |= MatrixProperties.LowerTriangular;
364                        return linsolve(A, B, ref props);
365                    }
366                    if (ILMath.ishermitian(A)) {
367                        // give cholesky a try
368                        props |= MatrixProperties.Hermitian;
369                        props |= MatrixProperties.PositivDefinite;
370                        ILArray< float> ret = linsolve(A, B, ref props);
371                        if (!object.Equals(ret, null)) {
372                            return ret;
373                        } else {
374                            props ^= MatrixProperties.PositivDefinite;
375                        }
376                    }
377                }
378                return linsolve(A, B, ref props);
379            }
380        }
381
382        /// <summary>
383        /// Solve linear equation system
384        /// </summary>
385        /// <param name="A">Matrix A. Size [n x q]</param>
386        /// <param name="B">Right hand side B. Size [n x m]</param>
387        /// <param name="props">Matrix properties. If defined, no checks are made for the structure of A. If the
388        /// matrix A was found to be (close to or) singular, the 'MatrixProperties.Singular' flag in props will be set.
389        /// This flag should be tested on return, in order to verify the reliability of the solution.</param>
390        /// <returns>The solution x solving multiply(A,x) = B. Size [n x m]</returns>
391        /// <remarks><para>Depending on the <paramref name="props"/> parameter the equation system will be solved
392        /// differently for special structures of A:
393        /// <list type="bullet">
394        /// <item>If A is square (q == n) and an <b>upper or lower triangular</b> matrix, the system will directly
395        /// be solved via backward- or forward substitution. Therefore the Lapack function ?trtrs will be used,
396        /// whenever the memory layout of A is suitable. This may be the case even for reference ILArray's!
397        /// <example><code><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix
398        /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
399        /// // now construct a right side and solve the equations:
400        /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T;
401        /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved being reference arrays! ]]></code></example></item>
402        /// <item><para>If A is square and symmetric or hermitian, A will be decomposed into a triangular equation
403        /// system using cholesky factorization and Lapack. The system is than solved using performant Lapack routines.</para>
404        /// <para>If during the cholesky factorization A was found to be <b>not positive definite</b> - the
405        /// corresponding flag in props will be cleaned and <c>null</c> will be returned.</para></item>
406        /// <item>Otherwise if A is square only, it will be decomposed into upper and lower triangular matrices
407        /// using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
408        /// <item>Otherwise, if A is of size [q x n] and q != n, the system is solved using QR decomposition.
409        /// A may be rank deficient. The solution is computed by use of the Lapack routine '?gelsy' and may be a
410        /// reference array.</item>
411        /// </list></para>
412        /// <para>Compatibility with Matlab<sup>(R)</sup>: If A is square, the algorithm used follows the same
413        /// logic as Matlab up to Rel 14, with the exception of Hessenberg matrices wich are solved via LU
414        /// factorization here. The un-squared case is handled differently. A direct Lapack driver function
415        /// (?gelsy) is used here. Therefore the solutions might differ! However, the solution will of course
416        /// fullfill the equation A * x = B without round off errrors. </para>
417        /// <para>For specifiying the rank of A in the unsquare case (q != n),
418        /// <see cref="ILNumerics.ILMath.eps"/> is used.</para></remarks>
419        public static ILRetArray< float > linsolve(ILInArray< float > A, ILInArray< float > B, ref MatrixProperties props) {
420            if (object.Equals(A,null))
421                throw new ILArgumentException("input argument A must not be null!");
422            if (object.Equals(B,null))
423                throw new ILArgumentException("input argument B must not be null!");
424            using (ILScope.Enter(A, B)) {
425                if (A.IsEmpty || B.IsEmpty)
426                    return empty< float>(A.Size);
427                if (A.Size[0] != B.Size[0])
428                    throw new ILArgumentException("number of rows for matrix A must match number of rows for RHS!");
429                int info = 0, m = A.Size[0];
430                ILArray< float> ret = empty<float>(ILSize.Empty00);
431                if (m == A.Size[1]) {
432                    props |= MatrixProperties.Square;
433                    if ((props & MatrixProperties.LowerTriangular) != 0) {
434                        ret.a = solveLowerTriangularSystem(A, B, ref info);
435                        if (info > 0)
436                            props |= MatrixProperties.Singular;
437                        return ret;
438                    }
439                    if ((props & MatrixProperties.UpperTriangular) != 0) {
440                        ret.a = solveUpperTriangularSystem(A, B, ref info);
441                        if (info > 0)
442                            props |= MatrixProperties.Singular;
443                        return ret;
444                    }
445                    if ((props & MatrixProperties.Hermitian) != 0) {
446                        ILDenseStorage< float> cholFact = A.Storage.copyUpperTriangle(m);
447                       
448                        Lapack.spotrf('U', m, cholFact.GetArrayForWrite(), m, ref info);
449                        if (info > 0) {
450                            props ^= MatrixProperties.Hermitian;
451                            cholFact.Dispose();
452                            return null;
453                        } else {
454                            // solve
455                            ret.a = B.C;
456                           
457                            Lapack.spotrs('U', m, B.Size[1], cholFact.GetArrayForWrite(), m, ret.GetArrayForWrite(), m, ref info);
458                            cholFact.Dispose();
459                            return ret;
460                        }
461                    } else {
462                        // attempt complete (expensive) LU factorization
463                        ILArray< float> L = A.C;
464                        int[] pivInd = ILMemoryPool.Pool.New<int>(m);
465                       
466                        Lapack.sgetrf(m, m, L.GetArrayForWrite(), m, pivInd, ref info);
467                        if (info > 0)
468                            props |= MatrixProperties.Singular;
469                        ret.a = B.C;
470                       
471                        Lapack.sgetrs('N', m, B.Size[1], L.GetArrayForWrite(), m, pivInd, ret.GetArrayForWrite(), m, ref info);
472                        if (info < 0)
473                            throw new ILArgumentException("failed to solve via lapack dgetrs");
474                        return ret;
475                    }
476                } else {
477                    // under- / overdetermined system
478                    int n = A.Size[1], rank = 0, minMN = (m < n) ? m : n, maxMN = (m > n) ? m : n;
479                    int nrhs = B.Size[1];
480                    if (B.Size[0] != m)
481                        throw new ILArgumentException("right hand side matrix B must match input A!");
482                    ILArray< float> tmpA = A.C;
483                    if (m < n) {
484                        ret.a = zeros< float>(n, nrhs);
485                        ret[r(0, m - 1), full] = B.C;
486                    } else {
487                        ret.a = B.C;
488                    }
489                    int[] JPVT = new int[n];
490                   
491                    Lapack.sgelsy(m, n, B.Size[1], tmpA.GetArrayForWrite(), m, ret.GetArrayForWrite(),
492                        maxMN, JPVT,  ILMath.MachineParameterSingle.eps,
493                        ref rank, ref info);
494                    if (n < m) {
495                        ret.a = ret[r(0, n - 1), full];
496                    }
497                    if (rank < minMN)
498                        props |= MatrixProperties.RankDeficient;
499                    return ret;
500                }
501            }
502        }
503       
504        /// <summary>
505        /// Solve system of linear equations A*x = b, with A being a upper triangular matrix
506        /// </summary>
507        /// <param name="A">Input matrix of size [n x n], must be upper triangular. No check is made for that!</param>
508        /// <param name="B">Solution vector or matrix. Size [n x m]</param>
509        /// <param name="singularityDetect">[Output] This value gives the row of A, where a singularity has been detected (if any). If A is not singular, this will be a negative value.</param>
510        /// <returns>Solution x solving A * x = b.</returns>
511        /// <remarks><para>The solution will be determined via backward substitution</para>
512        /// <para>Make sure, A and b are of correct size, since no checks are made for that!</para>
513        /// <para>This function is used by ILMath.linsolve. There should be rare need for you to call this function directly.</para>
514        /// <para>Elements of A below the main diagonal will not be accessed.</para>
515        /// <para>If A has been found to be singular, the array returned will contain NaN values for corresponding elements!</para></remarks>
516        internal static ILRetArray< float > solveUpperTriangularSystem (ILInArray< float > A, ILInArray< float > B, ref int singularityDetect) {
517            System.Diagnostics.Debug.Assert(B.Size[1] >= 0);
518            System.Diagnostics.Debug.Assert(B.Size[0] == A.Size[1]);
519            System.Diagnostics.Debug.Assert(A.Size[0] == A.Size[1]);
520            using (ILScope.Enter(A, B)) {
521                singularityDetect = -1;
522                int n = A.Size[0];
523                int m = B.Size[1];
524                int info = 0;
525                ILArray< float> ret = B.C;
526               
527                float[] retArr = ret.GetArrayForWrite();
528                // solve using Lapack
529                unsafe {
530                    fixed ( float* ptrA = A.GetArrayForRead())
531                    fixed ( float* ptrB = ret.GetArrayForWrite()) {
532                       
533                        Lapack.strtrs('U', 'N', 'N', A.Size[0], B.Size[1], (IntPtr)ptrA, A.Size[0], (IntPtr)ptrB, B.Size[0], ref info);
534                    }
535                }
536                if (info < 0)
537                    throw new ILArgumentException("error inside Lapack function ?trtrs for argument: " + (-info));
538                if (info > 0) {
539                    singularityDetect = info - 1;
540                    for (m = 0; m < ret.Size[1]; m++) {
541                        info = m * n + singularityDetect;
542                        for (int i = singularityDetect; i < n; i++) {
543                            retArr[info++] =  float.NaN;
544                        }
545                    }
546                } else {
547                    singularityDetect = -1;
548                }
549                return ret;
550            }
551        }
552
553        /// <summary>
554        /// Solve system of linear equations A*x = b, with A being a lower triangular matrix
555        /// </summary>
556        /// <param name="A">Input matrix of size [n x n], must be lower triangular. No check is made for that!</param>
557        /// <param name="B">Solution vector. Size [n x 1]</param>
558        /// <param name="singularityDetect">[Output] This value gives the row of A, where a singularity has been detected (if any). If A is not singular, this will be a negative value.</param>
559        /// <returns>Solution x solving A * x = b.</returns>
560        /// <remarks><para>The solution will be determined via forward substitution</para>
561        /// <para>Make sure, A and b are of correct size, since no checks are made for that!</para>
562        /// <para>This function is used by ILMath.linsolve. There should be rare need for you to call this function directly.</para>
563        /// <para>Elements of A above the main diagonal will not be accessed.</para>
564        /// <para>If A has been found to be singular, the array returned will contain NaN values for corresponding elements!</para></remarks>
565        internal static ILRetArray< float> solveLowerTriangularSystem( ILInArray< float> A, ILInArray< float> B, ref int singularityDetect ) {
566            System.Diagnostics.Debug.Assert(B.Size[1] >= 0);
567            System.Diagnostics.Debug.Assert(B.Size[0] == A.Size[1]);
568            System.Diagnostics.Debug.Assert(A.Size[0] == A.Size[1]);
569            using (ILScope.Enter(A, B)) {
570                singularityDetect = -1;
571                int n = A.Size[0];
572                int m = B.Size[1];
573                int info = 0;
574                ILArray< float> ret = B.C;
575               
576                float[] retArr = ret.GetArrayForWrite();
577                // solve using Lapack
578                unsafe {
579                    fixed ( float* ptrA = A.GetArrayForRead())
580                    fixed ( float* ptrB = ret.GetArrayForWrite()) {
581                       
582                        Lapack.strtrs('L', 'N', 'N', A.Size[0], B.Size[1], (IntPtr)ptrA, A.Size[0], (IntPtr)ptrB, B.Size[0], ref info);
583                    }
584                }
585                if (info < 0)
586                    throw new ILArgumentException("error inside Lapack function ?trtrs for argument: " + (-info));
587                if (info > 0) {
588                    singularityDetect = info - 1;
589                    for (m = 0; m < ret.Size[1]; m++) {
590                        info = m * n + singularityDetect;
591                        for (int i = singularityDetect; i < n; i++) {
592                            retArr[info++] =  float.NaN;
593                        }
594                    }
595                } else {
596                    singularityDetect = -1;
597                }
598                return ret;
599            }
600        }
601
602       
603        /// <summary>
604        /// Solve linear equation system
605        /// </summary>
606        /// <param name="A">Matrix A. Size [n x q]</param>
607        /// <param name="B">Right hand side B. Size [n x m]</param>
608        /// <returns>Solution x solving the equation system: multiply(A, x) = B. Size [n x m]</returns>
609        /// <remarks><para>Depending on the structure and properties of A, the equation system will be solved in different ways:
610        /// <list type="bullet">
611        /// <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!
612        /// <example><code><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix
613        /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
614        /// // now construct a right side and solve the equations:
615        /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T;
616        /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved being reference arrays! ]]></code></example></item>
617        /// <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>
618        /// <para>If during the cholesky factorization A was found to be <b>not positive definite</b> - the cholesky factorization is canceled. </para></item>
619        /// <item>otherwise, if A is square only, it will be decomposed into upper and lower triangular martices using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
620        /// <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>
621        /// </list></para>
622        /// <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>
623        /// <para>For specifiying the rank of A in the unsquare case (q != n), <see cref="ILNumerics.ILMath.eps"/> is used.</para></remarks>
624        public static ILRetArray< fcomplex > linsolve(ILInArray< fcomplex > A, ILInArray< fcomplex > B) {
625            if (object.Equals(A,null) || object.Equals(B,null))
626                throw new ILArgumentException("parameter must not be null!");
627            using (ILScope.Enter(A, B)) {
628                MatrixProperties props = MatrixProperties.None;
629                if (A.Size[0] == A.Size[1]) {
630                    props |= MatrixProperties.Square;
631                    if (ILMath.istriup(A)) {
632                        props |= MatrixProperties.UpperTriangular;
633                        return linsolve(A, B, ref props);
634                    }
635                    if (ILMath.istrilow(A)) {
636                        props |= MatrixProperties.LowerTriangular;
637                        return linsolve(A, B, ref props);
638                    }
639                    if (ILMath.ishermitian(A)) {
640                        // give cholesky a try
641                        props |= MatrixProperties.Hermitian;
642                        props |= MatrixProperties.PositivDefinite;
643                        ILArray< fcomplex> ret = linsolve(A, B, ref props);
644                        if (!object.Equals(ret, null)) {
645                            return ret;
646                        } else {
647                            props ^= MatrixProperties.PositivDefinite;
648                        }
649                    }
650                }
651                return linsolve(A, B, ref props);
652            }
653        }
654
655        /// <summary>
656        /// Solve linear equation system
657        /// </summary>
658        /// <param name="A">Matrix A. Size [n x q]</param>
659        /// <param name="B">Right hand side B. Size [n x m]</param>
660        /// <param name="props">Matrix properties. If defined, no checks are made for the structure of A. If the
661        /// matrix A was found to be (close to or) singular, the 'MatrixProperties.Singular' flag in props will be set.
662        /// This flag should be tested on return, in order to verify the reliability of the solution.</param>
663        /// <returns>The solution x solving multiply(A,x) = B. Size [n x m]</returns>
664        /// <remarks><para>Depending on the <paramref name="props"/> parameter the equation system will be solved
665        /// differently for special structures of A:
666        /// <list type="bullet">
667        /// <item>If A is square (q == n) and an <b>upper or lower triangular</b> matrix, the system will directly
668        /// be solved via backward- or forward substitution. Therefore the Lapack function ?trtrs will be used,
669        /// whenever the memory layout of A is suitable. This may be the case even for reference ILArray's!
670        /// <example><code><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix
671        /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
672        /// // now construct a right side and solve the equations:
673        /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T;
674        /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved being reference arrays! ]]></code></example></item>
675        /// <item><para>If A is square and symmetric or hermitian, A will be decomposed into a triangular equation
676        /// system using cholesky factorization and Lapack. The system is than solved using performant Lapack routines.</para>
677        /// <para>If during the cholesky factorization A was found to be <b>not positive definite</b> - the
678        /// corresponding flag in props will be cleaned and <c>null</c> will be returned.</para></item>
679        /// <item>Otherwise if A is square only, it will be decomposed into upper and lower triangular matrices
680        /// using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
681        /// <item>Otherwise, if A is of size [q x n] and q != n, the system is solved using QR decomposition.
682        /// A may be rank deficient. The solution is computed by use of the Lapack routine '?gelsy' and may be a
683        /// reference array.</item>
684        /// </list></para>
685        /// <para>Compatibility with Matlab<sup>(R)</sup>: If A is square, the algorithm used follows the same
686        /// logic as Matlab up to Rel 14, with the exception of Hessenberg matrices wich are solved via LU
687        /// factorization here. The un-squared case is handled differently. A direct Lapack driver function
688        /// (?gelsy) is used here. Therefore the solutions might differ! However, the solution will of course
689        /// fullfill the equation A * x = B without round off errrors. </para>
690        /// <para>For specifiying the rank of A in the unsquare case (q != n),
691        /// <see cref="ILNumerics.ILMath.eps"/> is used.</para></remarks>
692        public static ILRetArray< fcomplex > linsolve(ILInArray< fcomplex > A, ILInArray< fcomplex > B, ref MatrixProperties props) {
693            if (object.Equals(A,null))
694                throw new ILArgumentException("input argument A must not be null!");
695            if (object.Equals(B,null))
696                throw new ILArgumentException("input argument B must not be null!");
697            using (ILScope.Enter(A, B)) {
698                if (A.IsEmpty || B.IsEmpty)
699                    return empty< fcomplex>(A.Size);
700                if (A.Size[0] != B.Size[0])
701                    throw new ILArgumentException("number of rows for matrix A must match number of rows for RHS!");
702                int info = 0, m = A.Size[0];
703                ILArray< fcomplex> ret = empty<fcomplex>(ILSize.Empty00);
704                if (m == A.Size[1]) {
705                    props |= MatrixProperties.Square;
706                    if ((props & MatrixProperties.LowerTriangular) != 0) {
707                        ret.a = solveLowerTriangularSystem(A, B, ref info);
708                        if (info > 0)
709                            props |= MatrixProperties.Singular;
710                        return ret;
711                    }
712                    if ((props & MatrixProperties.UpperTriangular) != 0) {
713                        ret.a = solveUpperTriangularSystem(A, B, ref info);
714                        if (info > 0)
715                            props |= MatrixProperties.Singular;
716                        return ret;
717                    }
718                    if ((props & MatrixProperties.Hermitian) != 0) {
719                        ILDenseStorage< fcomplex> cholFact = A.Storage.copyUpperTriangle(m);
720                       
721                        Lapack.cpotrf('U', m, cholFact.GetArrayForWrite(), m, ref info);
722                        if (info > 0) {
723                            props ^= MatrixProperties.Hermitian;
724                            cholFact.Dispose();
725                            return null;
726                        } else {
727                            // solve
728                            ret.a = B.C;
729                           
730                            Lapack.cpotrs('U', m, B.Size[1], cholFact.GetArrayForWrite(), m, ret.GetArrayForWrite(), m, ref info);
731                            cholFact.Dispose();
732                            return ret;
733                        }
734                    } else {
735                        // attempt complete (expensive) LU factorization
736                        ILArray< fcomplex> L = A.C;
737                        int[] pivInd = ILMemoryPool.Pool.New<int>(m);
738                       
739                        Lapack.cgetrf(m, m, L.GetArrayForWrite(), m, pivInd, ref info);
740                        if (info > 0)
741                            props |= MatrixProperties.Singular;
742                        ret.a = B.C;
743                       
744                        Lapack.cgetrs('N', m, B.Size[1], L.GetArrayForWrite(), m, pivInd, ret.GetArrayForWrite(), m, ref info);
745                        if (info < 0)
746                            throw new ILArgumentException("failed to solve via lapack dgetrs");
747                        return ret;
748                    }
749                } else {
750                    // under- / overdetermined system
751                    int n = A.Size[1], rank = 0, minMN = (m < n) ? m : n, maxMN = (m > n) ? m : n;
752                    int nrhs = B.Size[1];
753                    if (B.Size[0] != m)
754                        throw new ILArgumentException("right hand side matrix B must match input A!");
755                    ILArray< fcomplex> tmpA = A.C;
756                    if (m < n) {
757                        ret.a = zeros< fcomplex>(n, nrhs);
758                        ret[r(0, m - 1), full] = B.C;
759                    } else {
760                        ret.a = B.C;
761                    }
762                    int[] JPVT = new int[n];
763                   
764                    Lapack.cgelsy(m, n, B.Size[1], tmpA.GetArrayForWrite(), m, ret.GetArrayForWrite(),
765                        maxMN, JPVT,  ILMath.MachineParameterSingle.eps,
766                        ref rank, ref info);
767                    if (n < m) {
768                        ret.a = ret[r(0, n - 1), full];
769                    }
770                    if (rank < minMN)
771                        props |= MatrixProperties.RankDeficient;
772                    return ret;
773                }
774            }
775        }
776       
777        /// <summary>
778        /// Solve system of linear equations A*x = b, with A being a upper triangular matrix
779        /// </summary>
780        /// <param name="A">Input matrix of size [n x n], must be upper triangular. No check is made for that!</param>
781        /// <param name="B">Solution vector or matrix. Size [n x m]</param>
782        /// <param name="singularityDetect">[Output] This value gives the row of A, where a singularity has been detected (if any). If A is not singular, this will be a negative value.</param>
783        /// <returns>Solution x solving A * x = b.</returns>
784        /// <remarks><para>The solution will be determined via backward substitution</para>
785        /// <para>Make sure, A and b are of correct size, since no checks are made for that!</para>
786        /// <para>This function is used by ILMath.linsolve. There should be rare need for you to call this function directly.</para>
787        /// <para>Elements of A below the main diagonal will not be accessed.</para>
788        /// <para>If A has been found to be singular, the array returned will contain NaN values for corresponding elements!</para></remarks>
789        internal static ILRetArray< fcomplex > solveUpperTriangularSystem (ILInArray< fcomplex > A, ILInArray< fcomplex > B, ref int singularityDetect) {
790            System.Diagnostics.Debug.Assert(B.Size[1] >= 0);
791            System.Diagnostics.Debug.Assert(B.Size[0] == A.Size[1]);
792            System.Diagnostics.Debug.Assert(A.Size[0] == A.Size[1]);
793            using (ILScope.Enter(A, B)) {
794                singularityDetect = -1;
795                int n = A.Size[0];
796                int m = B.Size[1];
797                int info = 0;
798                ILArray< fcomplex> ret = B.C;
799               
800                fcomplex[] retArr = ret.GetArrayForWrite();
801                // solve using Lapack
802                unsafe {
803                    fixed ( fcomplex* ptrA = A.GetArrayForRead())
804                    fixed ( fcomplex* ptrB = ret.GetArrayForWrite()) {
805                       
806                        Lapack.ctrtrs('U', 'N', 'N', A.Size[0], B.Size[1], (IntPtr)ptrA, A.Size[0], (IntPtr)ptrB, B.Size[0], ref info);
807                    }
808                }
809                if (info < 0)
810                    throw new ILArgumentException("error inside Lapack function ?trtrs for argument: " + (-info));
811                if (info > 0) {
812                    singularityDetect = info - 1;
813                    for (m = 0; m < ret.Size[1]; m++) {
814                        info = m * n + singularityDetect;
815                        for (int i = singularityDetect; i < n; i++) {
816                            retArr[info++] =  new fcomplex(float.NaN,float.NaN);
817                        }
818                    }
819                } else {
820                    singularityDetect = -1;
821                }
822                return ret;
823            }
824        }
825
826        /// <summary>
827        /// Solve system of linear equations A*x = b, with A being a lower triangular matrix
828        /// </summary>
829        /// <param name="A">Input matrix of size [n x n], must be lower triangular. No check is made for that!</param>
830        /// <param name="B">Solution vector. Size [n x 1]</param>
831        /// <param name="singularityDetect">[Output] This value gives the row of A, where a singularity has been detected (if any). If A is not singular, this will be a negative value.</param>
832        /// <returns>Solution x solving A * x = b.</returns>
833        /// <remarks><para>The solution will be determined via forward substitution</para>
834        /// <para>Make sure, A and b are of correct size, since no checks are made for that!</para>
835        /// <para>This function is used by ILMath.linsolve. There should be rare need for you to call this function directly.</para>
836        /// <para>Elements of A above the main diagonal will not be accessed.</para>
837        /// <para>If A has been found to be singular, the array returned will contain NaN values for corresponding elements!</para></remarks>
838        internal static ILRetArray< fcomplex> solveLowerTriangularSystem( ILInArray< fcomplex> A, ILInArray< fcomplex> B, ref int singularityDetect ) {
839            System.Diagnostics.Debug.Assert(B.Size[1] >= 0);
840            System.Diagnostics.Debug.Assert(B.Size[0] == A.Size[1]);
841            System.Diagnostics.Debug.Assert(A.Size[0] == A.Size[1]);
842            using (ILScope.Enter(A, B)) {
843                singularityDetect = -1;
844                int n = A.Size[0];
845                int m = B.Size[1];
846                int info = 0;
847                ILArray< fcomplex> ret = B.C;
848               
849                fcomplex[] retArr = ret.GetArrayForWrite();
850                // solve using Lapack
851                unsafe {
852                    fixed ( fcomplex* ptrA = A.GetArrayForRead())
853                    fixed ( fcomplex* ptrB = ret.GetArrayForWrite()) {
854                       
855                        Lapack.ctrtrs('L', 'N', 'N', A.Size[0], B.Size[1], (IntPtr)ptrA, A.Size[0], (IntPtr)ptrB, B.Size[0], ref info);
856                    }
857                }
858                if (info < 0)
859                    throw new ILArgumentException("error inside Lapack function ?trtrs for argument: " + (-info));
860                if (info > 0) {
861                    singularityDetect = info - 1;
862                    for (m = 0; m < ret.Size[1]; m++) {
863                        info = m * n + singularityDetect;
864                        for (int i = singularityDetect; i < n; i++) {
865                            retArr[info++] =  new fcomplex(float.NaN,float.NaN);
866                        }
867                    }
868                } else {
869                    singularityDetect = -1;
870                }
871                return ret;
872            }
873        }
874
875       
876        /// <summary>
877        /// Solve linear equation system
878        /// </summary>
879        /// <param name="A">Matrix A. Size [n x q]</param>
880        /// <param name="B">Right hand side B. Size [n x m]</param>
881        /// <returns>Solution x solving the equation system: multiply(A, x) = B. Size [n x m]</returns>
882        /// <remarks><para>Depending on the structure and properties of A, the equation system will be solved in different ways:
883        /// <list type="bullet">
884        /// <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!
885        /// <example><code><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix
886        /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
887        /// // now construct a right side and solve the equations:
888        /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T;
889        /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved being reference arrays! ]]></code></example></item>
890        /// <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>
891        /// <para>If during the cholesky factorization A was found to be <b>not positive definite</b> - the cholesky factorization is canceled. </para></item>
892        /// <item>otherwise, if A is square only, it will be decomposed into upper and lower triangular martices using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
893        /// <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>
894        /// </list></para>
895        /// <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>
896        /// <para>For specifiying the rank of A in the unsquare case (q != n), <see cref="ILNumerics.ILMath.eps"/> is used.</para></remarks>
897        public static ILRetArray< complex > linsolve(ILInArray< complex > A, ILInArray< complex > B) {
898            if (object.Equals(A,null) || object.Equals(B,null))
899                throw new ILArgumentException("parameter must not be null!");
900            using (ILScope.Enter(A, B)) {
901                MatrixProperties props = MatrixProperties.None;
902                if (A.Size[0] == A.Size[1]) {
903                    props |= MatrixProperties.Square;
904                    if (ILMath.istriup(A)) {
905                        props |= MatrixProperties.UpperTriangular;
906                        return linsolve(A, B, ref props);
907                    }
908                    if (ILMath.istrilow(A)) {
909                        props |= MatrixProperties.LowerTriangular;
910                        return linsolve(A, B, ref props);
911                    }
912                    if (ILMath.ishermitian(A)) {
913                        // give cholesky a try
914                        props |= MatrixProperties.Hermitian;
915                        props |= MatrixProperties.PositivDefinite;
916                        ILArray< complex> ret = linsolve(A, B, ref props);
917                        if (!object.Equals(ret, null)) {
918                            return ret;
919                        } else {
920                            props ^= MatrixProperties.PositivDefinite;
921                        }
922                    }
923                }
924                return linsolve(A, B, ref props);
925            }
926        }
927
928        /// <summary>
929        /// Solve linear equation system
930        /// </summary>
931        /// <param name="A">Matrix A. Size [n x q]</param>
932        /// <param name="B">Right hand side B. Size [n x m]</param>
933        /// <param name="props">Matrix properties. If defined, no checks are made for the structure of A. If the
934        /// matrix A was found to be (close to or) singular, the 'MatrixProperties.Singular' flag in props will be set.
935        /// This flag should be tested on return, in order to verify the reliability of the solution.</param>
936        /// <returns>The solution x solving multiply(A,x) = B. Size [n x m]</returns>
937        /// <remarks><para>Depending on the <paramref name="props"/> parameter the equation system will be solved
938        /// differently for special structures of A:
939        /// <list type="bullet">
940        /// <item>If A is square (q == n) and an <b>upper or lower triangular</b> matrix, the system will directly
941        /// be solved via backward- or forward substitution. Therefore the Lapack function ?trtrs will be used,
942        /// whenever the memory layout of A is suitable. This may be the case even for reference ILArray's!
943        /// <example><code><![CDATA[ILArray<double> A = ILMath.randn(4); // construct 4 x 4 matrix
944        /// A = A.T; // A is a reference array now! The transpose is fast and does not consume much memory
945        /// // now construct a right side and solve the equations:
946        /// ILArray<double> B = new ILArray<double> (1.0,2.0,3.0).T;
947        /// ILMath.linsolve(A,B); // ... will be carried out via Lapack, even for all arrays involved being reference arrays! ]]></code></example></item>
948        /// <item><para>If A is square and symmetric or hermitian, A will be decomposed into a triangular equation
949        /// system using cholesky factorization and Lapack. The system is than solved using performant Lapack routines.</para>
950        /// <para>If during the cholesky factorization A was found to be <b>not positive definite</b> - the
951        /// corresponding flag in props will be cleaned and <c>null</c> will be returned.</para></item>
952        /// <item>Otherwise if A is square only, it will be decomposed into upper and lower triangular matrices
953        /// using LU decomposition and Lapack. The triangular system is than solved using performant Lapack routines.</item>
954        /// <item>Otherwise, if A is of size [q x n] and q != n, the system is solved using QR decomposition.
955        /// A may be rank deficient. The solution is computed by use of the Lapack routine '?gelsy' and may be a
956        /// reference array.</item>
957        /// </list></para>
958        /// <para>Compatibility with Matlab<sup>(R)</sup>: If A is square, the algorithm used follows the same
959        /// logic as Matlab up to Rel 14, with the exception of Hessenberg matrices wich are solved via LU
960        /// factorization here. The un-squared case is handled differently. A direct Lapack driver function
961        /// (?gelsy) is used here. Therefore the solutions might differ! However, the solution will of course
962        /// fullfill the equation A * x = B without round off errrors. </para>
963        /// <para>For specifiying the rank of A in the unsquare case (q != n),
964        /// <see cref="ILNumerics.ILMath.eps"/> is used.</para></remarks>
965        public static ILRetArray< complex > linsolve(ILInArray< complex > A, ILInArray< complex > B, ref MatrixProperties props) {
966            if (object.Equals(A,null))
967                throw new ILArgumentException("input argument A must not be null!");
968            if (object.Equals(B,null))
969                throw new ILArgumentException("input argument B must not be null!");
970            using (ILScope.Enter(A, B)) {
971                if (A.IsEmpty || B.IsEmpty)
972                    return empty< complex>(A.Size);
973                if (A.Size[0] != B.Size[0])
974                    throw new ILArgumentException("number of rows for matrix A must match number of rows for RHS!");
975                int info = 0, m = A.Size[0];
976                ILArray< complex> ret = empty<complex>(ILSize.Empty00);
977                if (m == A.Size[1]) {
978                    props |= MatrixProperties.Square;
979                    if ((props & MatrixProperties.LowerTriangular) != 0) {
980                        ret.a = solveLowerTriangularSystem(A, B, ref info);
981                        if (info > 0)
982                            props |= MatrixProperties.Singular;
983                        return ret;
984                    }
985                    if ((props & MatrixProperties.UpperTriangular) != 0) {
986                        ret.a = solveUpperTriangularSystem(A, B, ref info);
987                        if (info > 0)
988                            props |= MatrixProperties.Singular;
989                        return ret;
990                    }
991                    if ((props & MatrixProperties.Hermitian) != 0) {
992                        ILDenseStorage< complex> cholFact = A.Storage.copyUpperTriangle(m);
993                       
994                        Lapack.zpotrf('U', m, cholFact.GetArrayForWrite(), m, ref info);
995                        if (info > 0) {
996                            props ^= MatrixProperties.Hermitian;
997                            cholFact.Dispose();
998                            return null;
999                        } else {
1000                            // solve
1001                            ret.a = B.C;
1002                           
1003                            Lapack.zpotrs('U', m, B.Size[1], cholFact.GetArrayForWrite(), m, ret.GetArrayForWrite(), m, ref info);
1004                            cholFact.Dispose();
1005                            return ret;
1006                        }
1007                    } else {
1008                        // attempt complete (expensive) LU factorization
1009                        ILArray< complex> L = A.C;
1010                        int[] pivInd = ILMemoryPool.Pool.New<int>(m);
1011                       
1012                        Lapack.zgetrf(m, m, L.GetArrayForWrite(), m, pivInd, ref info);
1013                        if (info > 0)
1014                            props |= MatrixProperties.Singular;
1015                        ret.a = B.C;
1016                       
1017                        Lapack.zgetrs('N', m, B.Size[1], L.GetArrayForWrite(), m, pivInd, ret.GetArrayForWrite(), m, ref info);
1018                        if (info < 0)
1019                            throw new ILArgumentException("failed to solve via lapack dgetrs");
1020                        return ret;
1021                    }
1022                } else {
1023                    // under- / overdetermined system
1024                    int n = A.Size[1], rank = 0, minMN = (m < n) ? m : n, maxMN = (m > n) ? m : n;
1025                    int nrhs = B.Size[1];
1026                    if (B.Size[0] != m)
1027                        throw new ILArgumentException("right hand side matrix B must match input A!");
1028                    ILArray< complex> tmpA = A.C;
1029                    if (m < n) {
1030                        ret.a = zeros< complex>(n, nrhs);
1031                        ret[r(0, m - 1), full] = B.C;
1032                    } else {
1033                        ret.a = B.C;
1034                    }
1035                    int[] JPVT = new int[n];
1036                   
1037                    Lapack.zgelsy(m, n, B.Size[1], tmpA.GetArrayForWrite(), m, ret.GetArrayForWrite(),
1038                        maxMN, JPVT,  ILMath.MachineParameterDouble.eps,
1039                        ref rank, ref info);
1040                    if (n < m) {
1041                        ret.a = ret[r(0, n - 1), full];
1042                    }
1043                    if (rank < minMN)
1044                        props |= MatrixProperties.RankDeficient;
1045                    return ret;
1046                }
1047            }
1048        }
1049       
1050        /// <summary>
1051        /// Solve system of linear equations A*x = b, with A being a upper triangular matrix
1052        /// </summary>
1053        /// <param name="A">Input matrix of size [n x n], must be upper triangular. No check is made for that!</param>
1054        /// <param name="B">Solution vector or matrix. Size [n x m]</param>
1055        /// <param name="singularityDetect">[Output] This value gives the row of A, where a singularity has been detected (if any). If A is not singular, this will be a negative value.</param>
1056        /// <returns>Solution x solving A * x = b.</returns>
1057        /// <remarks><para>The solution will be determined via backward substitution</para>
1058        /// <para>Make sure, A and b are of correct size, since no checks are made for that!</para>
1059        /// <para>This function is used by ILMath.linsolve. There should be rare need for you to call this function directly.</para>
1060        /// <para>Elements of A below the main diagonal will not be accessed.</para>
1061        /// <para>If A has been found to be singular, the array returned will contain NaN values for corresponding elements!</para></remarks>
1062        internal static ILRetArray< complex > solveUpperTriangularSystem (ILInArray< complex > A, ILInArray< complex > B, ref int singularityDetect) {
1063            System.Diagnostics.Debug.Assert(B.Size[1] >= 0);
1064            System.Diagnostics.Debug.Assert(B.Size[0] == A.Size[1]);
1065            System.Diagnostics.Debug.Assert(A.Size[0] == A.Size[1]);
1066            using (ILScope.Enter(A, B)) {
1067                singularityDetect = -1;
1068                int n = A.Size[0];
1069                int m = B.Size[1];
1070                int info = 0;
1071                ILArray< complex> ret = B.C;
1072               
1073                complex[] retArr = ret.GetArrayForWrite();
1074                // solve using Lapack
1075                unsafe {
1076                    fixed ( complex* ptrA = A.GetArrayForRead())
1077                    fixed ( complex* ptrB = ret.GetArrayForWrite()) {
1078                       
1079                        Lapack.ztrtrs('U', 'N', 'N', A.Size[0], B.Size[1], (IntPtr)ptrA, A.Size[0], (IntPtr)ptrB, B.Size[0], ref info);
1080                    }
1081                }
1082                if (info < 0)
1083                    throw new ILArgumentException("error inside Lapack function ?trtrs for argument: " + (-info));
1084                if (info > 0) {
1085                    singularityDetect = info - 1;
1086                    for (m = 0; m < ret.Size[1]; m++) {
1087                        info = m * n + singularityDetect;
1088                        for (int i = singularityDetect; i < n; i++) {
1089                            retArr[info++] =  new complex(double.NaN,double.NaN);
1090                        }
1091                    }
1092                } else {
1093                    singularityDetect = -1;
1094                }
1095                return ret;
1096            }
1097        }
1098
1099        /// <summary>
1100        /// Solve system of linear equations A*x = b, with A being a lower triangular matrix
1101        /// </summary>
1102        /// <param name="A">Input matrix of size [n x n], must be lower triangular. No check is made for that!</param>
1103        /// <param name="B">Solution vector. Size [n x 1]</param>
1104        /// <param name="singularityDetect">[Output] This value gives the row of A, where a singularity has been detected (if any). If A is not singular, this will be a negative value.</param>
1105        /// <returns>Solution x solving A * x = b.</returns>
1106        /// <remarks><para>The solution will be determined via forward substitution</para>
1107        /// <para>Make sure, A and b are of correct size, since no checks are made for that!</para>
1108        /// <para>This function is used by ILMath.linsolve. There should be rare need for you to call this function directly.</para>
1109        /// <para>Elements of A above the main diagonal will not be accessed.</para>
1110        /// <para>If A has been found to be singular, the array returned will contain NaN values for corresponding elements!</para></remarks>
1111        internal static ILRetArray< complex> solveLowerTriangularSystem( ILInArray< complex> A, ILInArray< complex> B, ref int singularityDetect ) {
1112            System.Diagnostics.Debug.Assert(B.Size[1] >= 0);
1113            System.Diagnostics.Debug.Assert(B.Size[0] == A.Size[1]);
1114            System.Diagnostics.Debug.Assert(A.Size[0] == A.Size[1]);
1115            using (ILScope.Enter(A, B)) {
1116                singularityDetect = -1;
1117                int n = A.Size[0];
1118                int m = B.Size[1];
1119                int info = 0;
1120                ILArray< complex> ret = B.C;
1121               
1122                complex[] retArr = ret.GetArrayForWrite();
1123                // solve using Lapack
1124                unsafe {
1125                    fixed ( complex* ptrA = A.GetArrayForRead())
1126                    fixed ( complex* ptrB = ret.GetArrayForWrite()) {
1127                       
1128                        Lapack.ztrtrs('L', 'N', 'N', A.Size[0], B.Size[1], (IntPtr)ptrA, A.Size[0], (IntPtr)ptrB, B.Size[0], ref info);
1129                    }
1130                }
1131                if (info < 0)
1132                    throw new ILArgumentException("error inside Lapack function ?trtrs for argument: " + (-info));
1133                if (info > 0) {
1134                    singularityDetect = info - 1;
1135                    for (m = 0; m < ret.Size[1]; m++) {
1136                        info = m * n + singularityDetect;
1137                        for (int i = singularityDetect; i < n; i++) {
1138                            retArr[info++] =  new complex(double.NaN,double.NaN);
1139                        }
1140                    }
1141                } else {
1142                    singularityDetect = -1;
1143                }
1144                return ret;
1145            }
1146        }
1147
1148
1149#endregion HYCALPER AUTO GENERATED CODE
1150
1151    }
1152}
Note: See TracBrowser for help on using the repository browser.