示例#1
0
        public static Array <float> PseudoInv(Array <float> a)
        {
            // https://en.wikipedia.org/wiki/Moore–Penrose_pseudoinverse
            // http://vene.ro/blog/inverses-pseudoinverses-numerical-issues-speed-symmetry.html

            // https://software.intel.com/en-us/forums/intel-math-kernel-library/topic/296030
            // dgelss can do the job with one input your matrix, the other the unit matrix
            // http://icl.cs.utk.edu/lapack-forum/viewtopic.php?f=2&t=160

            var m = a.Shape[0];
            var n = a.Shape[1];

            /* Compute SVD */
            var k      = Math.Min(m, n);
            var s      = new float[k];
            var u      = NN.Zeros <float>(m, m);
            var vt     = NN.Zeros <float>(n, n);
            var copy   = (float[])a.Values.Clone(); // if (jobu != 'O' && jobv != 'O') a is destroyed by dgesdv (https://software.intel.com/en-us/node/521150)
            var superb = new float[k - 1];

            Lapack.gesvd('A', 'A', m, n, copy, n, s, u.Values, m, vt.Values, n, superb);

            var invSigma = NN.Zeros <float>(n, m);

            invSigma[Range(0, k), Range(0, k)] = NN.Diag(1 / NN.Array(s));

            var pseudoInv = vt.T.Dot(invSigma).Dot(u.T);

            return(pseudoInv);
        }
示例#2
0
        public void TestInverse2x2b()
        {
            const int n = 2;

            float[,] a = new float[n, n] {
                { 1, 2 },
                { 3, 4 }
            };
            float[,] aInv = (float[, ])a.Clone();
            Lapack.Inverse(aInv, n);

            float[,] eye = new float[n, n];
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    for (int k = 0; k < n; k++)
                    {
                        eye[i, j] += a[i, k] * aInv[k, j];
                    }
                }
            }
            AssertArray.AreAlmostEqual(1f, eye[0, 0]);
            AssertArray.AreAlmostEqual(0f, eye[0, 1]);
            AssertArray.AreAlmostEqual(0f, eye[1, 0]);
            AssertArray.AreAlmostEqual(1f, eye[1, 1]);
        }
        }                                       // private constructor for singleton pattern

        /// <summary>
        /// See https://software.intel.com/content/www/us/en/develop/documentation/mkl-developer-reference-fortran/top/lapack-routines/lapack-least-squares-and-eigenvalue-problem-routines/lapack-least-squares-and-eigenvalue-problem-driver-routines/nonsymmetric-eigenvalue-problems-lapack-driver-routines/geev.html
        /// </summary>
        public void Dgeev(string jobVl, string jobVr, int n, ref double[] a, int offsetA, int ldA, ref double[] wr, int offsetWr,
                          ref double[] wi, int offsetWi, ref double[] vl, int offsetVl, int ldVl, ref double[] vr, int offsetVr, int ldVr,
                          ref double[] work, int offsetWork, int lWork, ref int info)
        {
            Lapack.Dgeev(jobVl, jobVr, ref n, ref a[offsetA], ref ldA, ref wr[offsetWr], ref wi[offsetWi], ref vl[offsetVl],
                         ref ldVl, ref vr[offsetVr], ref ldVr, ref work[offsetWork], ref lWork, ref info);
        }
示例#4
0
        public PositiveDefiniteMatrix SetToInverse(PositiveDefiniteMatrix A)
        {
#if LAPACK
            this.SetTo(A);
            Lapack.SymmetricInverseInPlace(this);
            return(this);
#else
            return(SetToInverse(A, new LowerTriangularMatrix(rows, cols)));
#endif
        }
示例#5
0
        public void TestSolve()
        {
            /* Solve the equations A*X = B */
            // https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/dgesv_ex.c.htm
            const int N = 5;
            const int NRHS = 3;
            const int LDA = N;
            const int LDB = NRHS;
            int       n = N, nrhs = NRHS, lda = LDA, ldb = LDB;

            /* Local arrays */
            int[]    ipiv = new int[N];
            double[] a    = new double[N * N] {
                6.80, -6.05, -0.45, 8.32, -9.67,
                -2.11, -3.30, 2.58, 2.71, -5.14,
                5.66, 5.36, -2.70, 4.35, -7.26,
                5.97, -4.44, 0.27, -7.17, 6.08,
                8.23, 1.08, 9.04, 2.14, -6.87
            };
            double[] b = new double[N * NRHS] {
                4.02, -1.56, 9.81,
                6.19, 4.00, -4.09,
                -8.22, -8.67, -4.57,
                -7.57, 1.75, -8.61,
                -3.03, 2.86, 8.99
            };
            /* Solve the equations A*X = B */
            Lapack.gesv(n, nrhs, a, lda, ipiv, b, ldb);

            // Solution
            var solution = NN.Array(new[] {
                -0.80, -0.39, 0.96,
                -0.70, -0.55, 0.22,
                0.59, 0.84, 1.90,
                1.32, -0.10, 5.36,
                0.57, 0.11, 4.04,
            }).Reshape(n, nrhs);

            AssertArray.AreAlmostEqual(solution, NN.Array(b).Reshape(N, NRHS), 1e-2, 1e-2);

            // Details of LU factorization
            var luFactorization = NN.Array(new[]
            {
                8.23, 1.08, 9.04, 2.14, -6.87,
                0.83, -6.94, -7.92, 6.55, -3.99,
                0.69, -0.67, -14.18, 7.24, -5.19,
                0.73, 0.75, 0.02, -13.82, 14.19,
                -0.26, 0.44, -0.59, -0.34, -3.43,
            }).Reshape(n, n);

            AssertArray.AreAlmostEqual(luFactorization, NN.Array(a).Reshape(n, n), 1e-2, 1e-2);

            // Pivot indices
            AssertArray.AreEqual(new[] { 5, 5, 3, 4, 5 }, ipiv);
        }
示例#6
0
        public void TestDeterminant2x2c()
        {
            const int n = 2;
            var       A = new float[n * n] {
                1, 2,
                3, 4
            };
            var result = Lapack.Determinant(A, n);

            AssertArray.AreAlmostEqual(result, -2f);
        }
示例#7
0
        /// <summary>
        /// Gets the Cholesky decomposition of the matrix (L*L' = A), replacing its contents.
        /// </summary>
        /// <param name="isPosDef">True if <c>this</c> is positive definite, otherwise false.</param>
        /// <returns>The Cholesky decomposition L.  If <c>this</c> is positive semidefinite,
        /// then L will satisfy L*L' = A.
        /// Otherwise, L will only approximately satisfy L*L' = A.</returns>
        /// <remarks>
        /// <c>this</c> must be symmetric, but need not be positive definite.
        /// </remarks>
        public LowerTriangularMatrix CholeskyInPlace(out bool isPosDef)
        {
            LowerTriangularMatrix L = new LowerTriangularMatrix(rows, cols, data);

#if LAPACK
            isPosDef = Lapack.CholeskyInPlace(this);
#else
            isPosDef = L.SetToCholesky(this);
#endif
            return(L);
        }
示例#8
0
        public void TestDeterminantUpper()
        {
            const int n = 4;

            float[] A = new float[n * n] {
                1, 2, 4, 7,
                0, 3, 5, 8,
                0, 0, 6, 9,
                0, 0, 0, 10
            };

            var result = Lapack.Determinant(A, n);

            Assert.AreEqual(result, 180f);
        }
示例#9
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);
        }
示例#10
0
        /// <summary>
        /// Decompose matrix A into uper and lower triangular part. Returns permutation matrix also.
        /// </summary>
        /// <param name="A">general input matrix. Size [m x n]</param>
        /// <param name="U">[output] reference to upper triangular matrix. Size [min(m,n) x n]. Must not be null.</param>
        /// <param name="P">[output] reference to permutation matrix. Size [min(m,n) x min(m,n)]. Must not be null.</param>
        /// <returns>lower triangular matrix L of size [m x min(m,n)]</returns>
        /// <remarks>A is decomposed into L and U, so that the equation
        /// <code>ILMath.multiply(L,U) == ILMath.multiply(P,A)</code>
        /// will hold except for round off error.
        /// <para>L and U will be true lower triangular matrices.</para>
        /// <example> <code>
        /// //Let's construct a matrix X:
        /// ILArray&lt;double&gt; X = new ILArray&lt;double&gt;(new double[]{1, 2, 3, 4, 4, 4, 5, 6, 7},3,3).T;
        /// // now X.ToString() will give something like:
        /// // {&lt;Double&gt; 63238509 [3x3] Ref(2)
        /// //(:,:)
        /// // 1,00000  2,00000  3,00000
        /// // 4,00000  4,00000  4,00000
        /// // 5,00000  6,00000  7,00000
        /// //}
        /// // construct references on U and P and call the decomposition
        /// ILArray&lt;double&gt; U = new ILArray&lt;double&gt;.empty();
        /// ILArray&lt;double&gt; P = new ILArray&lt;double&gt;.empty();
        /// ILArray&lt;double&gt; L = ILMath.lu(X, ref U, ref P);
        ///
        /// // L.ToString() is now:
        /// // {&lt;Double&gt; 19634871 [3x3] Phys.
        /// //(:,:)
        /// // 1,00000   0,00000   0,00000
        /// // 0,80000   1,00000   0,00000
        /// // 0,20000  -1,00000   1,00000
        /// //}
        /// // U is now:
        /// //{&lt;Double&gt; 22584602 [3x3] Phys.
        /// //(:,:)
        /// // 5,00000  6,00000  7,00000
        /// // 0,00000  -0,80000  -1,60000
        /// // 0,00000  0,00000  0,00000
        /// //}
        /// // and P is:
        /// //{&lt;Double&gt; 2192437 [3x3] Phys.
        /// //(:,:)
        /// // 0,00000  0,00000  1,00000
        /// // 0,00000  1,00000  0,00000
        /// // 1,00000  0,00000  0,00000
        /// //}
        /// </code>
        /// In order to reflect the pivoting done during the decomposition inside ?getrf, the matrix P may be used on A:
        /// <code>
        /// (ILMath.multiply(P,A) - ILMath.multiply(L,U)).ToString();
        /// // will give:
        /// //{&lt;Double&gt; 59192235 [3x3] Phys.
        /// //(:,:)
        /// // 0,00000  0,00000  0,00000
        /// // 0,00000  0,00000  0,00000
        /// // 0,00000  0,00000  0,00000
        /// //}
        /// </code>
        /// </example>
        /// <para>lu uses the Lapack function ?getrf.</para>
        /// <para>All of the matrices U,L,P returned will be solid ILArrays.</para>
        /// </remarks>
        /// <seealso cref="ILNumerics.BuiltInFunctions.ILMath.lu(ILArray&lt;double&gt;)"/>
        /// <seealso cref="ILNumerics.BuiltInFunctions.ILMath.lu(ILArray&lt;double&gt;, ref ILArray&lt;double&gt;)"/>
        /// <exception cref="ILNumerics.Exceptions.ILArgumentException"> if input A is not a matrix.</exception>
        public static ILArray <complex> lu(ILArray <complex> A, ref ILArray <complex> U, ref ILArray <complex> P)
        {
            if (!A.IsMatrix)
            {
                throw new ILArgumentSizeException("lu is defined for matrices only!");
            }
            int m = A.Dimensions[0], n = A.Dimensions[1], info = 0, minMN = (m < n)? m : n;
            ILArray <complex> L = (ILArray <complex>)A.Clone();

            int [] pivInd       = ILMemoryPool.Pool.New <int>(minMN);
            Lapack.zgetrf(m, n, L.m_data, m, pivInd, ref info);
            if (info < 0)
            {
                ILMemoryPool.Pool.RegisterObject(pivInd);
                throw new ILArgumentException("lu: illegal parameter error.");
                //} else if (info > 0) {
                //    // singular diagonal entry found
            }
            else
            {
                // completed successfuly
                if (!Object.Equals(U, null))
                {
                    if (!Object.Equals(P, null))
                    {
                        pivInd = perm2indicesForward(pivInd);
                        U      = copyUpperTriangle(L, minMN, n);
                        L      = copyLowerTriangle(L, m, minMN, new complex(1.0, 0.0));
                        P      = ILArray <complex> .zeros(minMN, minMN);

                        // construct permutation matrix P
                        for (int r = 0; r < m; r++)
                        {
                            P[r, pivInd[r]] = new complex(1.0, 0.0);
                        }
                    }
                    else
                    {
                        pivInd = perm2indicesBackward(pivInd);
                        U      = copyUpperTriangle(L, minMN, n);
                        L      = copyLowerTrianglePerm(L, m, minMN, new complex(1.0, 0.0), pivInd);
                    }
                }
            }
            ILMemoryPool.Pool.RegisterObject(pivInd);
            return(L);
        }
示例#11
0
        public static (matrix, vector) Eigens(MatrixExpression a)
        {
            var v = a.Evaluate();

            if (v.Rows != v.Cols)
            {
                ThrowHelper.ThrowIncorrectDimensionsForOperation();
            }
            if (a is MatrixInput)
            {
                v = Copy(v);
            }
            var w = new vector(v.Rows);

            ThrowHelper.Check(Lapack.syev(Layout.ColMajor, 'V', UpLoChar.Lower, v.Rows, v.Array, v.Rows, w.Array));
            return(v, w);
        }
示例#12
0
        public static Array <float> PowerMethod(Array <float> a)
        {
            // https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_pseudoinverse

            // init A(0) = (A*A + dI)-1.A*
            var d      = 1e-6f;
            var result = a.T.Dot(a) + d * NN.Eye(a.Shape[1]);

            Lapack.Inverse(result.Values, result.Shape[0]);
            result = result.Dot(a.T);

            // iterate: A(i+1) = 2A(i) - A(i).A.A(i)
            for (int i = 0; i < 2; i++)
            {
                result = 2 * result - result.Dot(a).Dot(result);
            }
            return(result);
        }
示例#13
0
// DO NOT EDIT INSIDE THIS REGION !! CHANGES WILL BE LOST !!
        /// <summary>
        /// QR decomposition - raw Lapack output
        /// </summary>
        /// <param name="A">general input matrix A</param>
        /// <returns>orthonormal / unitary matrix Q and upper triangular
        /// matrix R packed into single matrix. This is the output of the
        /// lapack function ?geqrf.</returns>
        /// <remarks><para>Input matrix A will not be altered. </para>
        /// <para>The matrix returned is the direct output of the lapack
        /// function [d,s,c,z]geqrf respectively. This mean that it contains
        /// the decomposition factors Q and R, but they are cmbined into a
        /// single matrix for performance reasons. If you need one of the factors,
        /// you would use the overloaded function
        /// <see cref="ILNumerics.BuiltInFunctions.ILMath.qr(ILArray&lt;double&gt;,ref ILArray&lt;double&gt;)"/>
        /// instead, which returns those factors seperately.</para></remarks>
        public static ILArray <complex> qr(ILArray <complex> A)
        {
            if (!A.IsMatrix)
            {
                throw new ILArgumentException("qr decomposition: A must be a matrix");
            }
            int m = A.Dimensions[0], n = A.Dimensions[1];
            ILArray <complex> ret = (ILArray <complex>)A.Clone();

            complex [] tau        = new  complex [(m < n)?m:n];
            int        info       = 0;

            Lapack.zgeqrf(m, n, ret.m_data, m, tau, ref info);
            if (info < 0)
            {
                throw new ILArgumentException("qr: an error occoured during decomposition");
            }
            return(ret);
        }
示例#14
0
        /// <summary>
        /// QR decomposition - raw Lapack output
        /// </summary>
        /// <param name="A">general input matrix A</param>
        /// <returns>orthonormal / unitary matrix Q and upper triangular
        /// matrix R packed into single matrix. This is the output of the
        /// lapack function ?geqrf.</returns>
        /// <remarks><para>Input matrix A will not be altered. </para>
        /// <para>The matrix returned is the direct output of the lapack
        /// function [d,s,c,z]geqrf respectively. This mean that it contains
        /// the decomposition factors Q and R, but they are cmbined into a
        /// single matrix for performance reasons. If you need one of the factors,
        /// you would use the overloaded function
        /// <see cref="ILNumerics.BuiltInFunctions.ILMath.qr(ILArray&lt;double&gt;,ref ILArray&lt;double&gt;)"/>
        /// instead, which returns those factors seperately.</para></remarks>
        public static /*!HC:inCls1*/ ILArray <double> qr(/*!HC:inCls1*/ ILArray <double> A)
        {
            if (!A.IsMatrix)
            {
                throw new ILArgumentException("qr decomposition: A must be a matrix");
            }
            int m = A.Dimensions[0], n = A.Dimensions[1];
            /*!HC:inCls1*/ ILArray <double> ret = (/*!HC:inCls1*/ ILArray <double>)A.Clone();

            /*!HC:inArr1*/ double [] tau        = new /*!HC:inArr1*/ double [(m < n)?m:n];
            int info = 0;

            /*!HC:lapack_*geqrf*/ Lapack.dgeqrf(m, n, ret.m_data, m, tau, ref info);
            if (info < 0)
            {
                throw new ILArgumentException("qr: an error occoured during decomposition");
            }
            return(ret);
        }
示例#15
0
        static void Main(string[] args)
        {
            var x = new float[] { 1.0f, 1.0f, 1.0f };

            WriteLine("Level1 BLAS sasum call test.");
            WriteLine(Blas1.sasum(x.Length, x, 1));

            WriteLine("Level1 BLAS scopy call test.");
            Blas1.scopy(x.Length, x, 1, out var y, 1);
            for (var i = 0; i < y.Length; i++)
            {
                Write(y[i] + " ");
            }
            WriteLine("\n");

            WriteLine("Level2 BLAS dgemv call test.");
            var ad = new double[] { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
            var xd = new double[] { 1.0, 1.0, 1.0 };
            var yd = new double[] { 0.0, 0.0, 0.0 };

            Blas2.dgemv(CBlasLayout.RowMajor, CBlasTranspose.NoTrans, 3, 3, 1.0, ad, 3, xd, 1, 1.0, yd, 1);
            for (var i = 0; i < yd.Length; i++)
            {
                Write(yd[i] + " ");
            }
            WriteLine("\n");

            WriteLine("LAPACK General Matrix call test.");
            var ag = new double[] { 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0 };
            var bg = new double[] { 6.0, 7.0, 12.0, 15.0 };

            Lapack.dgetrf(LapackLayout.RowMajor, 4, 4, ag, 4, out var ipiv);
            Lapack.dgetrs(LapackLayout.RowMajor, LapackTranspose.N, 4, 1, ag, 4, ipiv, bg, 1);
            for (var i = 0; i < bg.Length; i++)
            {
                Write(bg[i] + " ");
            }
            WriteLine();

            WriteLine("Please press Enter key...");
            ReadLine();
        }
示例#16
0
        /// <summary>
        /// Determinant of square matrix
        /// </summary>
        /// <param name="A">square input matrix</param>
        /// <returns>determinant of A</returns>
        /// <remarks><para>The determinant is computed by decomposing A into upper and lower triangular part. Therefore LAPACK function ?getrf is used. <br />
        /// Due to the properties of determinants, det(a) is the same as det(L) * det(U),where det(L) can easily be extracted from the permutation indices returned from LU decomposition. det(U) - with U beeing an upper triangular matrix - equals the product of the diagonal elements.</para>
        /// <para>For scalar A, a plain copy of A is returned.</para></remarks>
        /// <example>Creating a nonsingular 4x4 (double) matrix and it's determinant
        /// <code>ILArray&lt;double&gt; A = ILMath.counter(1.0,1.0,4,4);
        ///A[1] = 0.0;  // make A nonsingular
        ///A[14] = 0.0; //(same as: A[2,3] = 0.0;)
        /// // A is now:
        /// //&lt;Double&gt; [4,4]
        /// //(:,:) 1e+001 *
        /// // 0,10000   0,50000   0,90000   1,30000
        /// // 0,00000   0,60000   1,00000   1,40000
        /// // 0,30000   0,70000   1,10000   0,00000
        /// // 0,40000   0,80000   1,20000   1,60000
        ///
        ///ILMath.det(A) gives:
        /// //&lt;Double&gt; -360
        ///</code></example>
        ///<exception cref="ILNumerics.Exceptions.ILArgumentException">if A is empty or not a square matrix</exception>
        public static /*!HC:inCls1*/ ILArray <double> det(/*!HC:inCls1*/ ILArray <double> A)
        {
            if (A.IsScalar)
            {
                return(A.C);
            }
            if (A.IsEmpty)
            {
                throw new ILArgumentException("det: A must be a matrix");
            }
            int m = A.Dimensions[0];

            if (m != A.Dimensions[1])
            {
                throw new ILArgumentException("det: matrix A must be square");
            }

            /*!HC:inCls1*/ ILArray <double> L = A.C;

            int [] pivInd = new int[m];
            int    info   = 0;

            /*!HC:lapack_*getrf*/ Lapack.dgetrf(m, m, L.m_data, m, pivInd, ref info);
            if (info < 0)
            {
                throw new ILArgumentException("det: illegal parameter error.");
            }
            // determine pivoting: number of exchanges
            /*!HC:inArr1*/ double retA = /*!HC:unityVal*/ 1.0;

            for (int i = 0; i < m;)
            {
                retA *= L.m_data[i * m + i];
                if (pivInd[i] != ++i)
                {
                    retA *= /*!HC:negUnityValNoCmplx*/ -1.0;
                }
            }
            L.Dispose();
            return(new /*!HC:inCls1*/ ILArray <double> (retA));
        }
示例#17
0
        /// <summary>
        /// Determinant of square matrix
        /// </summary>
        /// <param name="A">square input matrix</param>
        /// <returns>determinant of A</returns>
        /// <remarks><para>The determinant is computed by decomposing A into upper and lower triangular part. Therefore LAPACK function ?getrf is used. <br />
        /// Due to the properties of determinants, det(a) is the same as det(L) * det(U),where det(L) can easily be extracted from the permutation indices returned from LU decomposition. det(U) - with U beeing an upper triangular matrix - equals the product of the diagonal elements.</para>
        /// <para>For scalar A, a plain copy of A is returned.</para></remarks>
        /// <example>Creating a nonsingular 4x4 (double) matrix and it's determinant
        /// <code>ILArray&lt;double&gt; A = ILMath.counter(1.0,1.0,4,4);
        ///A[1] = 0.0;  // make A nonsingular
        ///A[14] = 0.0; //(same as: A[2,3] = 0.0;)
        /// // A is now:
        /// //&lt;Double&gt; [4,4]
        /// //(:,:) 1e+001 *
        /// // 0,10000   0,50000   0,90000   1,30000
        /// // 0,00000   0,60000   1,00000   1,40000
        /// // 0,30000   0,70000   1,10000   0,00000
        /// // 0,40000   0,80000   1,20000   1,60000
        ///
        ///ILMath.det(A) gives:
        /// //&lt;Double&gt; -360
        ///</code></example>
        ///<exception cref="ILNumerics.Exceptions.ILArgumentException">if A is empty or not a square matrix</exception>
        public static ILArray <complex> det(ILArray <complex> A)
        {
            if (A.IsScalar)
            {
                return(A.C);
            }
            if (A.IsEmpty)
            {
                throw new ILArgumentException("det: A must be a matrix");
            }
            int m = A.Dimensions[0];

            if (m != A.Dimensions[1])
            {
                throw new ILArgumentException("det: matrix A must be square");
            }

            ILArray <complex> L = A.C;

            int [] pivInd = new int[m];
            int    info   = 0;

            Lapack.zgetrf(m, m, L.m_data, m, pivInd, ref info);
            if (info < 0)
            {
                throw new ILArgumentException("det: illegal parameter error.");
            }
            // determine pivoting: number of exchanges
            complex retA = new complex(1.0, 0.0);

            for (int i = 0; i < m;)
            {
                retA *= L.m_data[i * m + i];
                if (pivInd[i] != ++i)
                {
                    retA *= -1.0;
                }
            }
            L.Dispose();
            return(new  ILArray <complex> (retA));
        }
示例#18
0
        public static double Det(MatrixExpression a)
        {
            var m = a.Evaluate();

            if (a is MatrixInput)
            {
                m = Copy(m);
            }
            var ipiv = Pool.Int.Rent(m.Rows);

            ThrowHelper.Check(Lapack.getrf(Layout.ColMajor, m.Rows, m.Rows, m.Array, m.Rows, ipiv));
            Pool.Int.Return(ipiv);
            double r = m[0, 0];

            for (int i = 1; i < m.Rows; i++)
            {
                r *= m[i, i];
            }
            m.Dispose();
            return(-r);
        }
示例#19
0
        public static double[] LsFit(double[] x, double[] y, int order)
        {
            //Least squares fit to x, y data
            int m = Math.Min(x.Length, y.Length);
            int n = order + 1;
            int i, j, r;

            if (m < 1)
            {
                throw new Exception("Invalid number of elements for Ls");
            }

            double[] a = new double[m * n];
            double[] b = new double[Math.Max(m, n)];

            for (i = 0; i < m; ++i)
            {
                r    = n * i;
                a[r] = 1.0;
                b[i] = y[i];
                for (j = 1; j < n; ++j)
                {
                    a[r + j] = x[i] * a[r + j - 1];
                }
            }

            int info = Lapack.LAPACKE_dgels(Lapack.LAPACK_ROW_MAJOR, 'N', m, n, 1, a, n, b, 1);

            if (info != 0)
            {
                throw new Exception(string.Format("LAPACKE_dgels returned {0}", info));
            }
            double[] c = new double[n];
            for (i = 0; i < n; ++i)
            {
                c[i] = b[i];
            }

            return(c);
        }
示例#20
0
        public static double[] LsSolve(double[] a, int rows, int cols, double[] b)
        {
            //Least squares solution of X * A = B, X returned. a is row * col matrix, b is column vector
            int i;

            double[] b1 = new double[b.Length];
            Array.Copy(b, b1, b.Length);

            int info = Lapack.LAPACKE_dgels(Lapack.LAPACK_ROW_MAJOR, 'N', rows, cols, 1, a, cols, b1, 1);

            if (info != 0)
            {
                throw new Exception(string.Format("LAPACKE_dgels returned {0}", info));
            }
            double[] c = new double[cols];
            for (i = 0; i < cols; ++i)
            {
                c[i] = b1[i];
            }

            return(c);
        }
示例#21
0
// DO NOT EDIT INSIDE THIS REGION !! CHANGES WILL BE LOST !!


        /// <summary>
        /// GEneral Matrix Multiply this array
        /// </summary>
        /// <overloads>General Matrix Multiply for double, float, complex and fcomplex arrays</overloads>
        /// <param name="A"><![CDATA[ILArray<>]]> matrix A</param>
        /// <param name="B"><![CDATA[ILArray<>]]> matrix B</param>
        /// <returns><![CDATA[ILArray<double>]]> new array - result of matrix multiplication</returns>
        /// <remarks>Both arrays must be matrices. The matrix will be multiplied only
        /// if dimensions match accordingly. Therefore B's number of rows must
        /// equal A's number of columns. An Exception will be thrown otherwise.
        /// The multiplication will carried out on BLAS libraries, if availiable and the
        /// storage memory structure meets BLAS's requirements. If not it will be done inside .NET's
        /// framework 'by hand'. This is especially true for referencing storages with
        /// irregular dimensions. However, even GEMM on those reference storages linking into
        /// a physical storage can (an will) be carried out via BLAS dll's, if the spacing
        /// into dimensions matches the requirements of BLAS. Those are:
        /// <list>
        /// <item>the elements of one dimension will be adjecently layed out, and</item>
        /// <item>the elements of the second dimension must be regular (evenly) spaced</item>
        /// </list>
        /// <para>For reference arrays where the spacing between adjecent elements do not meet the
        /// requirements above, the matrix multiplication will be made without optimization and
        /// therefore suffer from low performance in relation to solid arrays. See <a href="http://ilnumerics.net?site=5142">online documentation: referencing for ILNumerics.Net</a></para>
        /// </remarks>
        /// <exception cref="ILNumerics.Exceptions.ILArgumentSizeException">if at least one arrays is not a matrix</exception>
        /// <exception cref="ILNumerics.Exceptions.ILDimensionMismatchException">if the size of both matrices do not match</exception>
        public static ILArray <complex> multiply(ILArray <complex> A, ILArray <complex> B)
        {
            ILArray <complex> ret = null;

            if (A.Dimensions.NumberOfDimensions != 2 ||
                B.Dimensions.NumberOfDimensions != 2)
            {
                throw new ILArgumentSizeException("Matrix multiply: arguments must be 2-d.");
            }
            if (A.Dimensions[1] != B.Dimensions[0])
            {
                throw new ILDimensionMismatchException("Matrix multiply: inner matrix dimensions must match.");
            }
            // decide wich method to use
            // test auf Regelmigkeit der Dimensionen
            int  spacingA0;
            int  spacingA1;
            int  spacingB0;
            int  spacingB1;
            char transA, transB;

            complex [] retArr = null;
            isSuitableForLapack(A, B, out spacingA0, out spacingA1, out spacingB0, out spacingB1, out transA, out transB);
            if (A.m_dimensions.NumberOfElements > ILAtlasMinimumElementSize ||
                B.m_dimensions.NumberOfElements > ILAtlasMinimumElementSize)
            {
                // do BLAS GEMM
                retArr = new  complex [A.m_dimensions[0] * B.m_dimensions[1]];
                if (((spacingA0 == 1 && spacingA1 > int.MinValue) || (spacingA1 == 1 && spacingA0 > int.MinValue)) &&
                    ((spacingB0 == 1 && spacingB1 > int.MinValue) || (spacingB1 == 1 && spacingB0 > int.MinValue)))
                {
                    ret = new  ILArray <complex> (retArr, new ILDimension(A.m_dimensions[0], B.m_dimensions[1]));
                    if (transA == 't')
                    {
                        spacingA1 = spacingA0;
                    }
                    if (transB == 't')
                    {
                        spacingB1 = spacingB0;
                    }
                    unsafe
                    {
                        fixed(complex *ptrC = retArr)
                        fixed(complex * pA = A.m_data)
                        fixed(complex * pB = B.m_data)
                        {
                            complex *ptrA = pA + A.getBaseIndex(0);
                            complex *ptrB = pB + B.getBaseIndex(0);

                            if (transA == 't')
                            {
                                spacingA1 = spacingA0;
                            }
                            if (transB == 't')
                            {
                                spacingB1 = spacingB0;
                            }
                            Lapack.zgemm(transA, transB, A.m_dimensions[0], B.m_dimensions[1],
                                         A.m_dimensions[1], ( complex )1.0, (IntPtr)ptrA, spacingA1,
                                         (IntPtr)ptrB, spacingB1, ( complex )1.0, retArr, A.m_dimensions[0]);
                        }
                    }
                    return(ret);
                }
            }
            // do GEMM by hand
            retArr = new  complex [A.m_dimensions[0] * B.m_dimensions[1]];
            ret    = new  ILArray <complex> (retArr, A.m_dimensions[0], B.m_dimensions[1]);
            unsafe {
                int in2Len1 = B.m_dimensions[1];
                int in1Len0 = A.m_dimensions[0];
                int in1Len1 = A.m_dimensions[1];
                fixed(complex *ptrC = retArr)
                {
                    complex *pC = ptrC;

                    for (int c = 0; c < in2Len1; c++)
                    {
                        for (int r = 0; r < in1Len0; r++)
                        {
                            for (int n = 0; n < in1Len1; n++)
                            {
                                *pC += A.GetValue(r, n) * B.GetValue(n, c);
                            }
                            pC++;
                        }
                    }
                }
            }
            return(ret);
        }
示例#22
0
        private static void Main()
        {
            CompareTimeDot(10);
            CompareTimeDot(100);
            CompareTimeDot(100000);

            CompareTimeLU();

            void CompareTimeDot(int size)
            {
                var sw = new Stopwatch();

                (var x, var y) = GenerateVector();
                WriteLine($"Calc dot product by raw C# : size = {size}");
                sw.Reset();
                var res = 0.0;

                for (var i = 0; i < LoopDot; i++)
                {
                    sw.Start();
                    res = Dot(x, y);
                    sw.Stop();
                }
                WriteLine($"Result : {res}\tTime : {sw.Elapsed / (double) LoopDot}");

                WriteLine($"Calc dot product by BLAS : size = {size}");
                sw.Reset();
                for (var i = 0; i < LoopDot; i++)
                {
                    sw.Start();
                    res = Blas1.dot(size, x, 1, y, 1);
                    sw.Stop();
                }
                WriteLine($"Result : {res}\tTime : {sw.Elapsed / (double) LoopDot}\n");

                (double[] x, double[] y) GenerateVector()
                {
                    x = new double[size];
                    y = new double[size];
                    for (var i = 0; i < size; i++)
                    {
                        x[i] = 1.0;
                        y[i] = 1.0;
                    }
                    return(x, y);
                }
            }

            void CompareTimeLU()
            {
                const int    M     = 49;
                const int    N     = M * M;
                const double h     = 1.0 / (M + 1);
                const double Heat  = 4.0;
                var          aBase = new double[N * N];
                var          bBase = new double[N];
                var          ipiv  = new int[N];

                for (var i = 1; i <= M; i++)
                {
                    for (var j = 1; j <= M; j++)
                    {
                        var k = (j - 1) * M + i - 1;
                        aBase[k * N + k] = 4.0 / (h * h);
                        if (i > 1)
                        {
                            var kl = k - 1;
                            aBase[kl * N + k] = -1.0 / (h * h);
                        }
                        if (i < M)
                        {
                            var kr = k + 1;
                            aBase[kr * N + k] = -1.0 / (h * h);
                        }
                        if (j > 1)
                        {
                            var kd = k - M;
                            aBase[kd * N + k] = -1.0 / (h * h);
                        }
                        if (j < M)
                        {
                            var ku = k + M;
                            aBase[ku * N + k] = -1.0 / (h * h);
                        }
                        bBase[k] = Heat;
                    }
                }

                var sw = new Stopwatch();

                WriteLine("Calc Poisson eq by raw C#");
                sw.Reset();
                var res = new double[bBase.Length];

                for (var i = 0; i < LoopLU; i++)
                {
                    Blas1.copy(aBase.Length, aBase, 1, out var a, 1);
                    Blas1.copy(bBase.Length, bBase, 1, out var b, 1);
                    sw.Start();
                    Decomp(N, N, a, ipiv);
                    Solve(N, N, a, b, ipiv);
                    sw.Stop();
                    if (i == LoopLU - 1)
                    {
                        Blas1.copy(b.Length, b, 1, res, 1);
                    }
                }
                WriteLine($"Result : {res[((M + 1) / 2 - 1) * M + M + 1]}\tTime : {sw.Elapsed / (double) LoopLU}");

                WriteLine("Calc Poisson eq by LAPACK");
                sw.Reset();
                for (var i = 0; i < LoopLU; i++)
                {
                    Blas1.copy(aBase.Length, aBase, 1, out var a, 1);
                    Blas1.copy(bBase.Length, bBase, 1, out var b, 1);
                    sw.Start();
                    Lapack.getrf(LapackLayout.RowMajor, N, N, a, N, ipiv);
                    Lapack.getrs(LapackLayout.RowMajor, LapackTranspose.NoTrans, N, 1, a, N, ipiv, b, 1);
                    sw.Stop();
                    if (i == LoopLU - 1)
                    {
                        Blas1.copy(b.Length, b, 1, res, 1);
                    }
                }
                WriteLine($"Result : {res[((M + 1) / 2 - 1) * M + M + 1]}\tTime : {sw.Elapsed / (double) LoopLU}");
            }
        }
 /// <summary>
 /// See https://software.intel.com/en-us/mkl-developer-reference-fortran-potri#64544865-D81B-4811-84AA-D218A680AA3D
 /// </summary>
 public void Dpotri(string uplo, int n, double[] a, int offsetA, int ldA, ref int info)
 => Lapack.Dpotri(uplo, ref n, ref a[offsetA], ref ldA, ref info);
 /// <summary>
 /// See https://software.intel.com/en-us/mkl-developer-reference-fortran-ormqr#BE4B1C37-0E36-48EB-B44A-A40CACE43821
 /// </summary>
 public void Dormqr(string side, string transQ, int m, int n, int k, double[] a, int offsetA, int ldA, double[] tau,
                    int offsetTau, double[] c, int offsetC, int ldC, double[] work, int offsetWork, int lWork, ref int info)
 => Lapack.Dormqr(side, transQ, ref m, ref n, ref k, ref a[offsetA], ref ldA, ref tau[offsetTau],
                  ref c[offsetC], ref ldC, ref work[offsetWork], ref lWork, ref info);
 /// <summary>
 /// See https://software.intel.com/en-us/mkl-developer-reference-fortran-orgqr#8CE6CEB0-18AA-4CF6-80F4-D47C9A754019
 /// </summary>
 public void Dorgqr(int m, int n, int k, double[] a, int offsetA, int ldA, double[] tau, int offsetTau,
                    double[] work, int offsetWork, int lWork, ref int info)
 => Lapack.Dorgqr(ref m, ref n, ref k, ref a[offsetA], ref ldA, ref tau[offsetTau],
                  ref work[offsetWork], ref lWork, ref info);
 /// <summary>
 /// See https://software.intel.com/en-us/mkl-developer-reference-fortran-getrs#C286AE91-D0E0-44FB-94B4-5C262C037CAF
 /// </summary>
 public void Dgetrs(string transA, int n, int nRhs, double[] a, int offsetA, int ldA, int[] ipiv, int offsetIpiv,
                    double[] b, int offsetB, int ldB, ref int info)
 => Lapack.Dgetrs(transA, ref n, ref nRhs, ref a[offsetA], ref ldA, ref ipiv[offsetIpiv],
                  ref b[offsetB], ref ldB, ref info);
 /// <summary>
 /// See https://software.intel.com/en-us/mkl-developer-reference-fortran-getri#626EB2AE-CA6A-4233-A6FA-04F54EF7A6E6
 /// </summary>
 public void Dgetri(int n, double[] a, int offsetA, int ldA, int[] ipiv, int offsetIpiv,
                    double[] work, int offsetWork, int lWork, ref int info)
 => Lapack.Dgetri(ref n, ref a[offsetA], ref ldA, ref ipiv[offsetIpiv], ref work[offsetWork], ref lWork, ref info);
 /// <summary>
 /// See https://software.intel.com/en-us/mkl-developer-reference-fortran-getrf#42740A2C-4898-4EFA-88B9-94CA6EAAC4DB
 /// </summary>
 public void Dgetrf(int m, int n, double[] a, int offsetA, int ldA, int[] ipiv, int offsetIpiv, ref int info)
 => Lapack.Dgetrf(ref m, ref n, ref a[offsetA], ref ldA, ref ipiv[offsetIpiv], ref info);
 /// <summary>
 /// See https://software.intel.com/en-us/mkl-developer-reference-fortran-pptrs#B8D4E277-E28A-42BD-8496-9A72A66EACC3
 /// </summary>
 public void Dpptrs(string uplo, int n, int nRhs, double[] a, int offsetA, double[] b, int offsetB, int ldB, ref int info)
 => Lapack.Dpptrs(uplo, ref n, ref nRhs, ref a[offsetA], ref b[offsetB], ref ldB, ref info);
 /// <summary>
 /// See https://software.intel.com/en-us/mkl-developer-reference-fortran-pptrf#A2934477-60D2-40B4-B07D-2AD982989C47
 /// </summary>
 public void Dpptrf(string uplo, int n, double[] a, int offsetA, ref int info)
 => Lapack.Dpptrf(uplo, ref n, ref a[offsetA], ref info);