/************************************************************************* Tests whether A is HPD *************************************************************************/ private static bool ishpd(complex[,] a, int n) { bool result = new bool(); int j = 0; double ajj = 0; complex v = 0; double r = 0; complex[] t = new complex[0]; complex[] t2 = new complex[0]; complex[] t3 = new complex[0]; int i = 0; complex[,] a1 = new complex[0,0]; int i_ = 0; a = (complex[,])a.Clone(); t = new complex[n-1+1]; t2 = new complex[n-1+1]; t3 = new complex[n-1+1]; result = true; // // Compute the Cholesky factorization A = U'*U. // for(j=0; j<=n-1; j++) { // // Compute U(J,J) and test for non-positive-definiteness. // v = 0.0; for(i_=0; i_<=j-1;i_++) { v += math.conj(a[i_,j])*a[i_,j]; } ajj = (a[j,j]-v).x; if( (double)(ajj)<=(double)(0) ) { a[j,j] = ajj; result = false; return result; } ajj = Math.Sqrt(ajj); a[j,j] = ajj; // // Compute elements J+1:N-1 of row J. // if( j<n-1 ) { for(i_=0; i_<=j-1;i_++) { t2[i_] = math.conj(a[i_,j]); } for(i_=j+1; i_<=n-1;i_++) { t3[i_] = a[j,i_]; } for(i=j+1; i<=n-1; i++) { v = 0.0; for(i_=0; i_<=j-1;i_++) { v += a[i_,i]*t2[i_]; } t3[i] = t3[i]-v; } for(i_=j+1; i_<=n-1;i_++) { a[j,i_] = t3[i_]; } r = 1/ajj; for(i_=j+1; i_<=n-1;i_++) { a[j,i_] = r*a[j,i_]; } } } return result; }
/************************************************************************* Checks whether inverse is correct Returns True on success. *************************************************************************/ private static bool hpdmatrixcheckinverse(complex[,] a, complex[,] inva, bool isupper, int n, double threshold, int info, matinv.matinvreport rep) { bool result = new bool(); int i = 0; int j = 0; complex v = 0; int i_ = 0; a = (complex[,])a.Clone(); inva = (complex[,])inva.Clone(); for(i=0; i<=n-2; i++) { if( isupper ) { for(i_=i+1; i_<=n-1;i_++) { a[i_,i] = math.conj(a[i,i_]); } for(i_=i+1; i_<=n-1;i_++) { inva[i_,i] = math.conj(inva[i,i_]); } } else { for(i_=i+1; i_<=n-1;i_++) { a[i,i_] = math.conj(a[i_,i]); } for(i_=i+1; i_<=n-1;i_++) { inva[i,i_] = math.conj(inva[i_,i]); } } } result = true; if( info<=0 ) { result = false; } else { result = result & !((double)(rep.r1)<(double)(100*math.machineepsilon) | (double)(rep.r1)>(double)(1+1000*math.machineepsilon)); result = result & !((double)(rep.rinf)<(double)(100*math.machineepsilon) | (double)(rep.rinf)>(double)(1+1000*math.machineepsilon)); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { v = 0.0; for(i_=0; i_<=n-1;i_++) { v += a[i,i_]*inva[i_,j]; } if( i==j ) { v = v-1; } result = result & (double)(math.abscomplex(v))<=(double)(threshold); } } } return result; }
/************************************************************************* Estimate of a matrix condition number (infinity-norm). The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ public static double cmatrixrcondinf(complex[,] a, int n) { double result = 0; int i = 0; int j = 0; double v = 0; double nrm = 0; int[] pivots = new int[0]; a = (complex[,])a.Clone(); ap.assert(n>=1, "CMatrixRCondInf: N<1!"); nrm = 0; for(i=0; i<=n-1; i++) { v = 0; for(j=0; j<=n-1; j++) { v = v+math.abscomplex(a[i,j]); } nrm = Math.Max(nrm, v); } trfac.cmatrixlu(ref a, n, n, ref pivots); cmatrixrcondluinternal(a, n, false, true, nrm, ref v); result = v; return result; }
/************************************************************************* Calculation of the determinant of a general matrix Input parameters: A - matrix, array[0..N-1, 0..N-1] N - (optional) size of matrix A: * if given, only principal NxN submatrix is processed and overwritten. other elements are unchanged. * if not given, automatically determined from matrix size (A must be square matrix) Result: determinant of matrix A. -- ALGLIB -- Copyright 2005 by Bochkanov Sergey *************************************************************************/ public static complex cmatrixdet(complex[,] a, int n) { complex result = 0; int[] pivots = new int[0]; a = (complex[,])a.Clone(); ap.assert(n>=1, "CMatrixDet: N<1!"); ap.assert(ap.rows(a)>=n, "CMatrixDet: rows(A)<N!"); ap.assert(ap.cols(a)>=n, "CMatrixDet: cols(A)<N!"); ap.assert(apserv.apservisfinitecmatrix(a, n, n), "CMatrixDet: A contains infinite or NaN values!"); trfac.cmatrixlu(ref a, n, n, ref pivots); result = cmatrixludet(a, pivots, n); return result; }
/************************************************************************* Condition number estimate of a Hermitian positive definite matrix. The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). It should be noted that 1-norm and inf-norm of condition numbers of symmetric matrices are equal, so the algorithm doesn't take into account the differences between these types of norms. Input parameters: A - Hermitian positive definite matrix which is given by its upper or lower triangle depending on the value of IsUpper. Array with elements [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. Result: 1/LowerBound(cond(A)), if matrix A is positive definite, -1, if matrix A is not positive definite, and its condition number could not be found by this algorithm. NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ public static double hpdmatrixrcond(complex[,] a, int n, bool isupper) { double result = 0; int i = 0; int j = 0; int j1 = 0; int j2 = 0; double v = 0; double nrm = 0; double[] t = new double[0]; a = (complex[,])a.Clone(); t = new double[n]; for(i=0; i<=n-1; i++) { t[i] = 0; } for(i=0; i<=n-1; i++) { if( isupper ) { j1 = i; j2 = n-1; } else { j1 = 0; j2 = i; } for(j=j1; j<=j2; j++) { if( i==j ) { t[i] = t[i]+math.abscomplex(a[i,i]); } else { t[i] = t[i]+math.abscomplex(a[i,j]); t[j] = t[j]+math.abscomplex(a[i,j]); } } } nrm = 0; for(i=0; i<=n-1; i++) { nrm = Math.Max(nrm, t[i]); } if( trfac.hpdmatrixcholesky(ref a, n, isupper) ) { hpdmatrixrcondcholeskyinternal(a, n, isupper, true, nrm, ref v); result = v; } else { result = -1; } return result; }
/************************************************************************* Estimate of a matrix condition number (1-norm) The algorithm calculates a lower bound of the condition number. In this case, the algorithm does not return a lower bound of the condition number, but an inverse number (to avoid an overflow in case of a singular matrix). Input parameters: A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. Result: 1/LowerBound(cond(A)) NOTE: if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, 0.0 is returned in such cases. *************************************************************************/ public static double cmatrixrcond1(complex[,] a, int n) { double result = 0; int i = 0; int j = 0; double v = 0; double nrm = 0; int[] pivots = new int[0]; double[] t = new double[0]; a = (complex[,])a.Clone(); ap.assert(n>=1, "CMatrixRCond1: N<1!"); t = new double[n]; for(i=0; i<=n-1; i++) { t[i] = 0; } for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { t[j] = t[j]+math.abscomplex(a[i,j]); } } nrm = 0; for(i=0; i<=n-1; i++) { nrm = Math.Max(nrm, t[i]); } trfac.cmatrixlu(ref a, n, n, ref pivots); cmatrixrcondluinternal(a, n, true, true, nrm, ref v); result = v; return result; }
/************************************************************************* Finding the eigenvalues and eigenvectors of a Hermitian matrix The algorithm finds eigen pairs of a Hermitian matrix by reducing it to real tridiagonal form and using the QL/QR algorithm. Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasn’t changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). Note: eigenvectors of Hermitian matrix are defined up to multiplication by a complex number L, such that |L|=1. -- ALGLIB -- Copyright 2005, 23 March 2007 by Bochkanov Sergey *************************************************************************/ public static bool hmatrixevd(complex[,] a, int n, int zneeded, bool isupper, ref double[] d, ref complex[,] z) { bool result = new bool(); complex[] tau = new complex[0]; double[] e = new double[0]; double[] work = new double[0]; double[,] t = new double[0, 0]; complex[,] q = new complex[0, 0]; int i = 0; int k = 0; double v = 0; int i_ = 0; a = (complex[,])a.Clone(); d = new double[0]; z = new complex[0, 0]; alglib.ap.assert(zneeded == 0 || zneeded == 1, "HermitianEVD: incorrect ZNeeded"); // // Reduce to tridiagonal form // ortfac.hmatrixtd(ref a, n, isupper, ref tau, ref d, ref e); if (zneeded == 1) { ortfac.hmatrixtdunpackq(a, n, isupper, tau, ref q); zneeded = 2; } // // TDEVD // result = smatrixtdevd(ref d, e, n, zneeded, ref t); // // Eigenvectors are needed // Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T // if (result && zneeded != 0) { work = new double[n - 1 + 1]; z = new complex[n - 1 + 1, n - 1 + 1]; for (i = 0; i <= n - 1; i++) { // // Calculate real part // for (k = 0; k <= n - 1; k++) { work[k] = 0; } for (k = 0; k <= n - 1; k++) { v = q[i, k].x; for (i_ = 0; i_ <= n - 1; i_++) { work[i_] = work[i_] + v * t[k, i_]; } } for (k = 0; k <= n - 1; k++) { z[i, k].x = work[k]; } // // Calculate imaginary part // for (k = 0; k <= n - 1; k++) { work[k] = 0; } for (k = 0; k <= n - 1; k++) { v = q[i, k].y; for (i_ = 0; i_ <= n - 1; i_++) { work[i_] = work[i_] + v * t[k, i_]; } } for (k = 0; k <= n - 1; k++) { z[i, k].y = work[k]; } } } return result; }
/************************************************************************* Subroutine for finding the eigenvalues and eigenvectors of a Hermitian matrix with given indexes by using bisection and inverse iteration methods Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. IsUpperA - storage format of matrix A. I1, I2 - index interval for searching (from I1 to I2). 0 <= I1 <= I2 <= N-1. Output parameters: W - array of the eigenvalues found. Array whose index ranges within [0..I2-I1]. Z - if ZNeeded is equal to: * 0, Z hasn’t changed; * 1, Z contains eigenvectors. Array whose indexes range within [0..N-1, 0..I2-I1]. In that case, the eigenvectors are stored in the matrix columns. Result: True, if successful. W contains the eigenvalues, Z contains the eigenvectors (if needed). False, if the bisection method subroutine wasn't able to find the eigenvalues in the given interval or if the inverse iteration subroutine wasn't able to find all the corresponding eigenvectors. In that case, the eigenvalues and eigenvectors are not returned. Note: eigen vectors of Hermitian matrix are defined up to multiplication by a complex number L, such as |L|=1. -- ALGLIB -- Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. *************************************************************************/ public static bool hmatrixevdi(complex[,] a, int n, int zneeded, bool isupper, int i1, int i2, ref double[] w, ref complex[,] z) { bool result = new bool(); complex[,] q = new complex[0,0]; double[,] t = new double[0,0]; complex[] tau = new complex[0]; double[] e = new double[0]; double[] work = new double[0]; int i = 0; int k = 0; double v = 0; int m = 0; int i_ = 0; a = (complex[,])a.Clone(); w = new double[0]; z = new complex[0,0]; ap.assert(zneeded==0 | zneeded==1, "HermitianEigenValuesAndVectorsByIndexes: incorrect ZNeeded"); // // Reduce to tridiagonal form // ortfac.hmatrixtd(ref a, n, isupper, ref tau, ref w, ref e); if( zneeded==1 ) { ortfac.hmatrixtdunpackq(a, n, isupper, tau, ref q); zneeded = 2; } // // Bisection and inverse iteration // result = smatrixtdevdi(ref w, e, n, zneeded, i1, i2, ref t); // // Eigenvectors are needed // Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T // m = i2-i1+1; if( result & zneeded!=0 ) { work = new double[m-1+1]; z = new complex[n-1+1, m-1+1]; for(i=0; i<=n-1; i++) { // // Calculate real part // for(k=0; k<=m-1; k++) { work[k] = 0; } for(k=0; k<=n-1; k++) { v = q[i,k].x; for(i_=0; i_<=m-1;i_++) { work[i_] = work[i_] + v*t[k,i_]; } } for(k=0; k<=m-1; k++) { z[i,k].x = work[k]; } // // Calculate imaginary part // for(k=0; k<=m-1; k++) { work[k] = 0; } for(k=0; k<=n-1; k++) { v = q[i,k].y; for(i_=0; i_<=m-1;i_++) { work[i_] = work[i_] + v*t[k,i_]; } } for(k=0; k<=m-1; k++) { z[i,k].y = work[k]; } } } return result; }
/************************************************************************* Finding the eigenvalues and eigenvectors of a Hermitian matrix The algorithm finds eigen pairs of a Hermitian matrix by reducing it to real tridiagonal form and using the QL/QR algorithm. COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes one important improvement of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Generally, commercial ALGLIB is several times faster than open-source ! generic C edition, and many times faster than open-source C# edition. ! ! Multithreaded acceleration is NOT supported for this function. ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. Input parameters: A - Hermitian matrix which is given by its upper or lower triangular part. Array whose indexes range within [0..N-1, 0..N-1]. N - size of matrix A. IsUpper - storage format. ZNeeded - flag controlling whether the eigenvectors are needed or not. If ZNeeded is equal to: * 0, the eigenvectors are not returned; * 1, the eigenvectors are returned. Output parameters: D - eigenvalues in ascending order. Array whose index ranges within [0..N-1]. Z - if ZNeeded is equal to: * 0, Z hasn’t changed; * 1, Z contains the eigenvectors. Array whose indexes range within [0..N-1, 0..N-1]. The eigenvectors are stored in the matrix columns. Result: True, if the algorithm has converged. False, if the algorithm hasn't converged (rare case). Note: eigenvectors of Hermitian matrix are defined up to multiplication by a complex number L, such that |L|=1. -- ALGLIB -- Copyright 2005, 23 March 2007 by Bochkanov Sergey *************************************************************************/ public static bool hmatrixevd(complex[,] a, int n, int zneeded, bool isupper, ref double[] d, ref complex[,] z) { bool result = new bool(); complex[] tau = new complex[0]; double[] e = new double[0]; double[,] t = new double[0,0]; double[,] qz = new double[0,0]; complex[,] q = new complex[0,0]; int i = 0; int j = 0; a = (complex[,])a.Clone(); d = new double[0]; z = new complex[0,0]; alglib.ap.assert(zneeded==0 || zneeded==1, "HermitianEVD: incorrect ZNeeded"); // // Reduce to tridiagonal form // ortfac.hmatrixtd(ref a, n, isupper, ref tau, ref d, ref e); if( zneeded==1 ) { ortfac.hmatrixtdunpackq(a, n, isupper, tau, ref q); zneeded = 2; } // // TDEVD // result = smatrixtdevd(ref d, e, n, zneeded, ref t); // // Eigenvectors are needed // Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T // if( result && zneeded!=0 ) { z = new complex[n, n]; qz = new double[n, 2*n]; // // Calculate Re(Q)*T // for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { qz[i,j] = q[i,j].x; } } ablas.rmatrixgemm(n, n, n, 1.0, qz, 0, 0, 0, t, 0, 0, 0, 0.0, qz, 0, n); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { z[i,j].x = qz[i,n+j]; } } // // Calculate Im(Q)*T // for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { qz[i,j] = q[i,j].y; } } ablas.rmatrixgemm(n, n, n, 1.0, qz, 0, 0, 0, t, 0, 0, 0, 0.0, qz, 0, n); for(i=0; i<=n-1; i++) { for(j=0; j<=n-1; j++) { z[i,j].y = qz[i,n+j]; } } } return result; }
/************************************************************************* Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver without additional functions. Algorithm features: * O(N^3) complexity * matrix is represented by its upper or lower triangle * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1], right part OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or not positive definite X is filled by zeros in such cases. * -1 N<=0 was passed * 1 task was solved B - array[0..N-1]: * overwritten by solution * zeros, if A is exactly singular (diagonal of its LU decomposition has exact zeros). -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ public static void hpdmatrixsolvefast(complex[,] a, int n, bool isupper, complex[] b, ref int info) { int i = 0; a = (complex[,])a.Clone(); info = 0; info = 1; if( n<=0 ) { info = -1; return; } if( !trfac.hpdmatrixcholesky(ref a, n, isupper) ) { for(i=0; i<=n-1; i++) { b[i] = 0.0; } info = -3; return; } hpdbasiccholeskysolve(a, n, isupper, b); }
/************************************************************************* Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and N*M complex matrices X and B. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3+M*N^2) complexity * matrix is represented by its upper or lower triangle * no additional time consuming features like condition number estimation COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that Cholesky decomposition is harder ! to parallelize than, say, matrix-matrix product - this algorithm has ! several synchronization points which can not be avoided. However, ! parallelism starts to be profitable starting from N=500. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A IsUpper - what half of A is provided B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS Info - return code: * -3 A is is exactly singular or is not positive definite. B is filled by zeros in such cases. * -1 N<=0 was passed * 1 task is solved B - array[0..N-1]: * overwritten by solution * zeros, if problem was not solved -- ALGLIB -- Copyright 17.03.2015 by Bochkanov Sergey *************************************************************************/ public static void hpdmatrixsolvemfast(complex[,] a, int n, bool isupper, complex[,] b, int m, ref int info) { int i = 0; int j = 0; a = (complex[,])a.Clone(); info = 0; info = 1; if( n<=0 ) { info = -1; return; } if( !trfac.hpdmatrixcholesky(ref a, n, isupper) ) { for(i=0; i<=n-1; i++) { for(j=0; j<=m-1; j++) { b[i,j] = 0.0; } } info = -3; return; } if( isupper ) { ablas.cmatrixlefttrsm(n, m, a, 0, 0, true, false, 2, b, 0, 0); ablas.cmatrixlefttrsm(n, m, a, 0, 0, true, false, 0, b, 0, 0); } else { ablas.cmatrixlefttrsm(n, m, a, 0, 0, false, false, 0, b, 0, 0); ablas.cmatrixlefttrsm(n, m, a, 0, 0, false, false, 2, b, 0, 0); } }
/************************************************************************* Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex vectors x and b. "Fast-but-lightweight" version of the solver. Algorithm features: * O(N^3) complexity * no additional time consuming features, just triangular solver COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS: A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1], right part OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 27.01.2010 by Bochkanov Sergey *************************************************************************/ public static void cmatrixsolvefast(complex[,] a, int n, complex[] b, ref int info) { int i = 0; int j = 0; int[] p = new int[0]; a = (complex[,])a.Clone(); info = 0; if( n<=0 ) { info = -1; return; } trfac.cmatrixlu(ref a, n, n, ref p); for(i=0; i<=n-1; i++) { if( a[i,i]==0 ) { for(j=0; j<=n-1; j++) { b[j] = 0.0; } info = -3; return; } } cbasiclusolve(a, p, n, b); info = 1; }
/************************************************************************* Complex dense solver for A*X=B with N*N complex matrix A, N*M complex matrices X and B. "Fast-but-lightweight" version which provides just triangular solver - and no additional functions like iterative refinement or condition number estimation. Algorithm features: * O(N^3+M*N^2) complexity * no additional time consuming functions COMMERCIAL EDITION OF ALGLIB: ! Commercial version of ALGLIB includes two important improvements of ! this function, which can be used from C++ and C#: ! * Intel MKL support (lightweight Intel MKL is shipped with ALGLIB) ! * multicore support ! ! Intel MKL gives approximately constant (with respect to number of ! worker threads) acceleration factor which depends on CPU being used, ! problem size and "baseline" ALGLIB edition which is used for ! comparison. ! ! Say, on SSE2-capable CPU with N=1024, HPC ALGLIB will be: ! * about 2-3x faster than ALGLIB for C++ without MKL ! * about 7-10x faster than "pure C#" edition of ALGLIB ! Difference in performance will be more striking on newer CPU's with ! support for newer SIMD instructions. Generally, MKL accelerates any ! problem whose size is at least 128, with best efficiency achieved for ! N's larger than 512. ! ! Commercial edition of ALGLIB also supports multithreaded acceleration ! of this function. We should note that LU decomposition is harder to ! parallelize than, say, matrix-matrix product - this algorithm has ! many internal synchronization points which can not be avoided. However ! parallelism starts to be profitable starting from N=1024, achieving ! near-linear speedup for N=4096 or higher. ! ! In order to use multicore features you have to: ! * use commercial version of ALGLIB ! * call this function with "smp_" prefix, which indicates that ! multicore code will be used (for multicore support) ! ! We recommend you to read 'Working with commercial version' section of ! ALGLIB Reference Manual in order to find out how to use performance- ! related features provided by commercial edition of ALGLIB. INPUT PARAMETERS A - array[0..N-1,0..N-1], system matrix N - size of A B - array[0..N-1,0..M-1], right part M - right part size OUTPUT PARAMETERS: Info - return code: * -3 matrix is exactly singular (ill conditioned matrices are not recognized). * -1 N<=0 was passed * 1 task is solved B - array[N,M]: * info>0 => overwritten by solution * info=-3 => filled by zeros -- ALGLIB -- Copyright 16.03.2015 by Bochkanov Sergey *************************************************************************/ public static void cmatrixsolvemfast(complex[,] a, int n, complex[,] b, int m, ref int info) { complex v = 0; int i = 0; int j = 0; int k = 0; int[] p = new int[0]; a = (complex[,])a.Clone(); info = 0; // // Check for exact degeneracy // if( n<=0 || m<=0 ) { info = -1; return; } trfac.cmatrixlu(ref a, n, n, ref p); for(i=0; i<=n-1; i++) { if( a[i,i]==0 ) { for(j=0; j<=n-1; j++) { for(k=0; k<=m-1; k++) { b[j,k] = 0.0; } } info = -3; return; } } // // Solve with TRSM() // for(i=0; i<=n-1; i++) { if( p[i]!=i ) { for(j=0; j<=m-1; j++) { v = b[i,j]; b[i,j] = b[p[i],j]; b[p[i],j] = v; } } } ablas.cmatrixlefttrsm(n, m, a, 0, 0, false, true, 0, b, 0, 0); ablas.cmatrixlefttrsm(n, m, a, 0, 0, true, false, 0, b, 0, 0); info = 1; }