diff --git a/src/NativeWrappers/ATLAS/blas.c b/src/NativeWrappers/ATLAS/blas.c new file mode 100644 index 00000000..42df66e0 --- /dev/null +++ b/src/NativeWrappers/ATLAS/blas.c @@ -0,0 +1,101 @@ +#include "wrapper_common.h" +#include "blas.h" + +#if GCC +extern "C" { +#endif +DLLEXPORT void s_axpy(const int n, const float alpha, const float x[], float y[]){ + cblas_saxpy(n, alpha, x, 1, y, 1); +} + +DLLEXPORT void d_axpy(const int n, const double alpha, const double x[], double y[]){ + cblas_daxpy(n, alpha, x, 1, y, 1); +} + +DLLEXPORT void c_axpy(const int n, const Complex8 alpha, const Complex8 x[], Complex8 y[]){ + cblas_caxpy(n, &alpha, x, 1, y, 1); +} + +DLLEXPORT void z_axpy(const int n, const Complex16 alpha, const Complex16 x[], Complex16 y[]){ + cblas_zaxpy(n, &alpha, x, 1, y, 1); +} + +DLLEXPORT void s_scale(const int n, const float alpha, float x[]){ + cblas_sscal(n, alpha, x, 1); +} + +DLLEXPORT void d_scale(const int n, const double alpha, double x[]){ + cblas_dscal(n, alpha, x, 1); +} + +DLLEXPORT void c_scale(const int n, const Complex8 alpha, Complex8 x[]){ + cblas_cscal(n, &alpha, x, 1); +} + +DLLEXPORT void z_scale(const int n, const Complex16 alpha, Complex16 x[]){ + cblas_zscal(n, &alpha, x, 1); +} + +DLLEXPORT float s_dot_product(const int n, const float x[], const float y[]){ + return cblas_sdot(n, x, 1, y, 1); +} + +DLLEXPORT double d_dot_product(const int n, const double x[], const double y[]){ + return cblas_ddot(n, x, 1, y, 1); +} + +DLLEXPORT Complex8 c_dot_product(const int n, const Complex8 x[], const Complex8 y[]){ + Complex8 ret; + cblas_cdotu_sub(n, x, 1, y, 1, &ret); + return ret; +} + +DLLEXPORT Complex16 z_dot_product(const int n, const Complex16 x[], const Complex16 y[]){ + Complex16 ret; + cblas_zdotu_sub(n, x, 1, y, 1, &ret); + return ret; +} + +DLLEXPORT void s_matrix_multiply(const enum CBLAS_TRANSPOSE transA, const enum CBLAS_TRANSPOSE transB, const int m, const int n, const int k, const float alpha, const float x[], const float y[], const float beta, float c[]){ + int lda = transA == CblasNoTrans ? m : k; + int ldb = transB == CblasNoTrans ? k : n; + + cblas_sgemm(CblasColMajor, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m); +} + +DLLEXPORT void d_matrix_multiply(const enum CBLAS_TRANSPOSE transA, const enum CBLAS_TRANSPOSE transB, const int m, const int n, const int k, const double alpha, const double x[], const double y[], const double beta, double c[]){ + int lda = transA == CblasNoTrans ? m : k; + int ldb = transB == CblasNoTrans ? k : n; + + cblas_dgemm(CblasColMajor, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m); +} + +DLLEXPORT void c_matrix_multiply(const enum CBLAS_TRANSPOSE transA, const enum CBLAS_TRANSPOSE transB, const int m, const int n, const int k, const Complex8 alpha, const Complex8 x[], const Complex8 y[], const Complex8 beta, Complex8 c[]){ + int lda = transA == CblasNoTrans ? m : k; + int ldb = transB == CblasNoTrans ? k : n; + + cblas_cgemm(CblasColMajor, transA, transB, m, n, k, &alpha, x, lda, y, ldb, &beta, c, m); +} + +DLLEXPORT void z_matrix_multiply(const enum CBLAS_TRANSPOSE transA, const enum CBLAS_TRANSPOSE transB, const int m, const int n, const int k, const Complex16 alpha, const Complex16 x[], const Complex16 y[], const Complex16 beta, Complex16 c[]){ + int lda = transA == CblasNoTrans ? m : k; + int ldb = transB == CblasNoTrans ? k : n; + + cblas_zgemm(CblasColMajor, transA, transB, m, n, k, &alpha, x, lda, y, ldb, &beta, c, m); +} + +/*char getTransChar(enum TRANSPOSE trans){ + char cTrans; + switch( trans ){ + case CblasNoTrans : cTrans = 'N'; + break; + case CblasTrans : cTrans = 'T'; + break; + case CblasConjTrans : cTrans = 'C'; + break; + } + return cTrans; +}*/ +#if GCC +} +#endif \ No newline at end of file diff --git a/src/NativeWrappers/ATLAS/lapack.cpp b/src/NativeWrappers/ATLAS/lapack.cpp index a34ba6b8..31ac6358 100644 --- a/src/NativeWrappers/ATLAS/lapack.cpp +++ b/src/NativeWrappers/ATLAS/lapack.cpp @@ -1,64 +1,525 @@ -#include "common.h" +#include "lapack_common.h" +#include "wrapper_common.h" #include "blas.h" +#include +extern "C" { #include "clapack.h" + // to get atlas to link + float _sqrtf(float x) {return sqrt(x);} +} -extern "C" { +template +inline int lu_factor(int m, T a[], int ipiv[], + int (*getrf) (CBLAS_ORDER, const int, const int, K*, const int, int*)) +{ + int info = getrf(CblasColMajor, m, m, a, m, ipiv); + shift_ipiv_down(m, ipiv); + return info; +}; - DLLEXPORT int s_cholesky_factor(int n, float a[]){ - int info = clapack_spotrf(CblasColMajor, CblasLower, n, a, n); - for (int i = 0; i < n; ++i) - { - int index = i * n; - for (int j = 0; j < n && i > j; ++j) - { - a[index + j] = 0; - } - } +template +inline int lu_inverse(int n, T a[], + int (*getrf) (CBLAS_ORDER, const int, const int, K*, const int, int*), + int (*getri) (CBLAS_ORDER, const int, K*, const int, const int*)) +{ + int* ipiv = new int[n]; + int info = getrf(CblasColMajor, n, n, a, n, ipiv); + + if (info != 0){ + delete[] ipiv; return info; } - DLLEXPORT int d_cholesky_factor(int n, double* a){ - int info = clapack_dpotrf(CblasColMajor, CblasLower, n, a, n); - for (int i = 0; i < n; ++i) + info = getri(CblasColMajor, n, a, n, ipiv); + delete[] ipiv; + return info; +}; + +template +inline int lu_inverse_factored(int n, T a[], int ipiv[], + int (*getri) (CBLAS_ORDER, const int, K*, const int, const int*)) +{ + shift_ipiv_up(n, ipiv); + int info = getri(CblasColMajor,n, a, n, ipiv); + shift_ipiv_down(n, ipiv); + return info; +} + +template +inline int lu_solve_factored(int n, int nrhs, T a[], int ipiv[], T b[], + int (*getrs) (CBLAS_ORDER, CBLAS_TRANSPOSE, const int, const int, const K*, const int, const int*, K*, const int)) +{ + shift_ipiv_up(n, ipiv); + int info = getrs(CblasColMajor, CblasNoTrans, n, nrhs, a, n, ipiv, b, n); + shift_ipiv_down(n, ipiv); + return info; +} + +template +inline int lu_solve(int n, int nrhs, T a[], T b[], + int (*getrf) (CBLAS_ORDER, const int, const int, K*, const int, int*), + int (*getrs) (CBLAS_ORDER, CBLAS_TRANSPOSE, const int, const int, const K*, const int, const int*, K*, const int)) +{ + T* clone = Clone(n, n, a); + int* ipiv = new int[n]; + int info = getrf(CblasColMajor, n, n, clone, n, ipiv); + + if (info != 0){ + delete[] ipiv; + delete[] clone; + return info; + } + + info = getrs(CblasColMajor, CblasNoTrans, n, nrhs, clone, n, ipiv, b, n); + delete[] ipiv; + delete[] clone; + return info; +} + +template +inline int cholesky_factor(int n, T* a, int (*potrf) (CBLAS_ORDER, CBLAS_UPLO, const int, K*, const int)) +{ + int info = potrf(CblasColMajor, CblasLower, n, a, n); + T zero = T(); + for (int i = 0; i < n; ++i) + { + int index = i * n; + for (int j = 0; j < n && i > j; ++j) { - int index = i * n; - for (int j = 0; j < n && i > j; ++j) - { - a[index + j] = 0; - } + a[index + j] = zero; } + } + return info; +} + +template +inline int cholesky_solve(int n, int nrhs, T a[], T b[], + int (*potrf) (CBLAS_ORDER, CBLAS_UPLO, const int, K*, const int), + int (*potrs) (CBLAS_ORDER, CBLAS_UPLO, const int, const int, const K*, const int, K*, const int)) +{ + T* clone = Clone(n, n, a); + int info = potrf(CblasColMajor, CblasLower, n, clone, n); + + if (info != 0){ + delete[] clone; return info; } - DLLEXPORT int c_cholesky_factor(int n, Complex8 a[]){ - int info = clapack_cpotrf(CblasColMajor, CblasLower, n, a, n); - Complex8 zero; - zero.real = 0.0; - zero.real = 0.0; - for (int i = 0; i < n; ++i) + info = potrs(CblasColMajor, CblasLower, n, nrhs, clone, n, b, n); + delete[] clone; + return info; +} + +template +inline int cholesky_solve_factored(int n, int nrhs, T a[], T b[], + int (*potrs) (CBLAS_ORDER, CBLAS_UPLO, const int, const int, const K*, const int, K*, const int)) +{ + return potrs(CblasColMajor, CblasLower, n, nrhs, a, n, b, n); +} + +template +inline int qr_factor(int m, int n, T r[], T tau[], T q[], T work[], int len, + int (*geqrf) (const int, const int, K*, const int, T*), + int (*orgqr) (const int, const int, const int, K*, const int, const K*)) +{ + int info = geqrf(m, n, r, m, tau); + + for (int i = 0; i < m; ++i) + { + for (int j = 0; j < m && j < n; ++j) { - int index = i * n; - for (int j = 0; j < n && i > j; ++j) + if (i > j) { - a[index + j] = zero; + q[j * m + i] = r[j * m + i]; } } - return info; } - DLLEXPORT int z_cholesky_factor(int n, Complex16 a[]){ - int info = clapack_zpotrf(CblasColMajor, CblasLower, n, a, n); - Complex16 zero; - zero.real = 0.0; - zero.real = 0.0; - for (int i = 0; i < n; ++i) + //compute the q elements explicitly + if (m <= n) + { + info = orgqr(m, m, m, q, m, tau); + } + else + { + info = orgqr(m, m, n, q, m, tau); + } + + return info; +} + +template +inline int qr_thin_factor(int m, int n, T q[], T tau[], T r[], T work[], int len, + void (*geqrf) (const int*, const int*, T*, const int*, T*, T*, const int*, int*), + void (*orgqr) (const int*, const int*, const int*, T*, const int*, const T*, T*, const int*, int*)) +{ + int info = 0; + geqrf(&m, &n, q, &m, tau, work, &len, &info); + + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < n; ++j) { - int index = i * n; - for (int j = 0; j < n && i > j; ++j) - { - a[index + j] = zero; + if( i <= j) { + r[j * n + i] = q[j * m + i]; } } - return info; } + + orgqr(&m, &n, &n, q, &m, tau, work, &len, &info); + + return info; +} + +template +inline int qr_solve(int m, int n, int bn, T a[], T b[], T x[], T work[], int len, + void (*gels) (const char*, const int*, const int*, const int*, T*, + const int*, T* b, const int*, T*, const int*, int*)) +{ + T* clone_a = new T[m*n]; + std::memcpy(clone_a, a, m*n*sizeof(T)); + + T* clone_b = new T[m*bn]; + std::memcpy(clone_b, b, m*bn*sizeof(T)); + + char N = 'N'; + int info = 0; + gels(&N, &m, &n, &bn, clone_a, &m, clone_b, &m, work, &len, &info); + copyBtoX(n, n, bn, clone_b, x); + + delete[] clone_a; + delete[] clone_b; + return info; +} + +template +inline int qr_solve_factored(int m, int n, int bn, T r[], T b[], T tau[], T x[], T work[], int len, + void (*ormqr) (const char*, const char*, const int*, const int*, const int*, + const T*, const int*, const T*, T*, const int*, T*, const int*, int* info), + void (*trsm) (const CBLAS_ORDER, const CBLAS_SIDE, const CBLAS_UPLO, const CBLAS_TRANSPOSE, const CBLAS_DIAG, + const int, const int, const T, const T*, const int, T*, const int)) +{ + T* clone_b = new T[m*bn]; + std::memcpy(clone_b, b, m*bn*sizeof(T)); + + char side ='L'; + char tran = 'T'; + int info = 0; + ormqr(&side, &tran, &m, &bn, &n, r, &m, tau, clone_b, &m, work, &len, &info); + trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, 1.0, r, m, clone_b, m); + copyBtoX(n, n, bn, clone_b, x); + + delete[] clone_b; + return info; +} + +template +inline int complex_qr_solve_factored(int m, int n, int bn, T r[], T b[], T tau[], T x[], T work[], int len, + void (*unmqr) (const char*, const char*, const int*, const int*, const int*, + const T*, const int*, const T*, T*, const int*, T*, const int*, int* info), + void (*trsm) (const CBLAS_ORDER, const CBLAS_SIDE, const CBLAS_UPLO, const CBLAS_TRANSPOSE, const CBLAS_DIAG, + const int, const int, const void*, const void*, const int, void*, const int ldb)) +{ + T* clone_b = new T[m*bn]; + std::memcpy(clone_b, b, m*bn*sizeof(T)); + + char side ='L'; + char tran = 'C'; + int info = 0; + unmqr(&side, &tran, &m, &bn, &n, r, &m, tau, clone_b, &m, work, &len, &info); + + T one = {1.0f, 0.0f}; + trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, &one, r, m, clone_b, m); + copyBtoX(n, n, bn, clone_b, x); + + delete[] clone_b; + return info; +} + +template +inline int svd_factor(bool compute_vectors, int m, int n, T a[], T s[], T u[], T v[], T work[], int len, + void (*gesvd) (const char*, const char*, const int*, const int*, T*, const int*, + T*, T*, const int*, T*, const int*, T*, const int*, int*)) +{ + int info = 0; + char job = compute_vectors ? 'A' : 'N'; + gesvd(&job, &job, &m, &n, a, &m, s, u, &m, v, &n, work, &len, &info); + return info; +} + + +template +inline int complex_svd_factor(bool compute_vectors, int m, int n, T a[], T s[], T u[], T v[], T work[], int len, + void (*gesvd) (const char*, const char*, const int*, const int*, T*, const int*, + R*, T*, const int*, T*, const int*, T*, const int*, R*, int*)) +{ + int info = 0; + int dim_s = std::min(m,n); + R* rwork = new R[5 * dim_s]; + R* s_local = new R[dim_s]; + char job = compute_vectors ? 'A' : 'N'; + gesvd(&job, &job, &m, &n, a, &m, s_local, u, &m, v, &n, work, &len, rwork, &info); + + for(int index = 0; index < dim_s; ++index){ + T value = {s_local[index], 0.0f}; + s[index] = value; + } + + delete[] rwork; + delete[] s_local; + return info; +} + +extern "C" { + DLLEXPORT int s_lu_factor(int m, float a[], int ipiv[]) { + return lu_factor(m, a, ipiv, clapack_sgetrf); + } + + DLLEXPORT int d_lu_factor(int m, double a[], int ipiv[]) { + return lu_factor(m, a, ipiv, clapack_dgetrf); + } + + DLLEXPORT int c_lu_factor(int m, Complex8 a[], int ipiv[]) { + return lu_factor(m, a, ipiv, clapack_cgetrf); + } + + DLLEXPORT int z_lu_factor(int m, Complex16 a[], int ipiv[]) { + return lu_factor(m, a, ipiv, clapack_zgetrf); + } + + DLLEXPORT int s_lu_inverse(int n, float a[]) + { + return lu_inverse(n, a, clapack_sgetrf, clapack_sgetri); + } + + DLLEXPORT int d_lu_inverse(int n, double a[]) + { + return lu_inverse(n, a, clapack_dgetrf, clapack_dgetri); + } + + DLLEXPORT int c_lu_inverse(int n, Complex8 a[]) + { + return lu_inverse(n, a, clapack_cgetrf, clapack_cgetri); + } + + DLLEXPORT int z_lu_inverse(int n, Complex16 a[]) + { + return lu_inverse(n, a, clapack_zgetrf, clapack_zgetri); + } + + DLLEXPORT int s_lu_inverse_factored(int n, float a[], int ipiv[], float work[], int lwork) + { + return lu_inverse_factored(n, a, ipiv, clapack_sgetri); + } + + DLLEXPORT int d_lu_inverse_factored(int n, double a[], int ipiv[], double work[], int lwork) + { + return lu_inverse_factored(n, a, ipiv, clapack_dgetri); + } + + DLLEXPORT int c_lu_inverse_factored(int n, Complex8 a[], int ipiv[], Complex8 work[], int lwork) + { + return lu_inverse_factored(n, a, ipiv, clapack_cgetri); + } + + DLLEXPORT int z_lu_inverse_factored(int n, Complex16 a[], int ipiv[], Complex16 work[], int lwork) + { + return lu_inverse_factored(n, a, ipiv, clapack_zgetri); + } + + DLLEXPORT int s_lu_solve_factored(int n, int nrhs, float a[], int ipiv[], float b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, clapack_sgetrs); + } + + DLLEXPORT int d_lu_solve_factored(int n, int nrhs, double a[], int ipiv[], double b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, clapack_dgetrs); + } + + DLLEXPORT int c_lu_solve_factored(int n, int nrhs, Complex8 a[], int ipiv[], Complex8 b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, clapack_cgetrs); + } + + DLLEXPORT int z_lu_solve_factored(int n, int nrhs, Complex16 a[], int ipiv[], Complex16 b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, clapack_zgetrs); + } + + DLLEXPORT int s_lu_solve(int n, int nrhs, float a[], float b[]) + { + return lu_solve(n, nrhs, a, b, clapack_sgetrf, clapack_sgetrs); + } + + DLLEXPORT int d_lu_solve(int n, int nrhs, double a[], double b[]) + { + return lu_solve(n, nrhs, a, b, clapack_dgetrf, clapack_dgetrs); + } + + DLLEXPORT int c_lu_solve(int n, int nrhs, Complex8 a[], Complex8 b[]) + { + return lu_solve(n, nrhs, a, b, clapack_cgetrf, clapack_cgetrs); + } + + DLLEXPORT int z_lu_solve(int n, int nrhs, Complex16 a[], Complex16 b[]) + { + return lu_solve(n, nrhs, a, b, clapack_zgetrf, clapack_zgetrs); + } + + DLLEXPORT int s_cholesky_factor(int n, float a[]){ + return cholesky_factor(n, a, clapack_spotrf); + } + + DLLEXPORT int d_cholesky_factor(int n, double* a){ + return cholesky_factor(n, a, clapack_dpotrf); + } + + DLLEXPORT int c_cholesky_factor(int n, Complex8 a[]){ + return cholesky_factor(n, a, clapack_cpotrf); + } + + DLLEXPORT int z_cholesky_factor(int n, Complex16 a[]){ + return cholesky_factor(n, a, clapack_zpotrf); + } + + DLLEXPORT int s_cholesky_solve(int n, int nrhs, float a[], float b[]) + { + return cholesky_solve(n, nrhs, a, b, clapack_spotrf, clapack_spotrs); + } + + DLLEXPORT int d_cholesky_solve(int n, int nrhs, double a[], double b[]) + { + return cholesky_solve(n, nrhs, a, b, clapack_dpotrf, clapack_dpotrs); + } + + DLLEXPORT int c_cholesky_solve(int n, int nrhs, Complex8 a[], Complex8 b[]) + { + return cholesky_solve(n, nrhs, a, b, clapack_cpotrf, clapack_cpotrs); + } + + DLLEXPORT int z_cholesky_solve(int n, int nrhs, Complex16 a[], Complex16 b[]) + { + return cholesky_solve(n, nrhs, a, b, clapack_zpotrf, clapack_zpotrs); + } + + DLLEXPORT int s_cholesky_solve_factored(int n, int nrhs, float a[], float b[]) + { + return cholesky_solve_factored(n, nrhs, a, b, clapack_spotrs); + } + + DLLEXPORT int d_cholesky_solve_factored(int n, int nrhs, double a[], double b[]) + { + return cholesky_solve_factored(n, nrhs, a, b, clapack_dpotrs); + } + + DLLEXPORT int c_cholesky_solve_factored(int n, int nrhs, Complex8 a[], Complex8 b[]) + { + return cholesky_solve_factored(n, nrhs, a, b, clapack_cpotrs); + } + + DLLEXPORT int z_cholesky_solve_factored(int n, int nrhs, Complex16 a[], Complex16 b[]) + { + return cholesky_solve_factored(n, nrhs, a, b, clapack_zpotrs); + } + + /*DLLEXPORT int s_qr_factor(int m, int n, float r[], float tau[], float q[], float work[], int len) + { + return qr_factor(m, n, r, tau, q, work, len, clapack_sgeqrf, clapack_sorgqr); + } + + DLLEXPORT int s_qr_thin_factor(int m, int n, float q[], float tau[], float r[], float work[], int len) + { + return qr_thin_factor(m, n, q, tau, r, work, len, clapack_sgeqrf, clapack_sorgqr); + } + + DLLEXPORT int d_qr_factor(int m, int n, double r[], double tau[], double q[], double work[], int len) + { + return qr_factor(m, n, r, tau, q, work, len, clapack_dgeqrf, clapack_dorgqr); + } + + DLLEXPORT int d_qr_thin_factor(int m, int n, double q[], double tau[], double r[], double work[], int len) + { + return qr_thin_factor(m, n, q, tau, r, work, len, clapack_dgeqrf, clapack_dorgqr); + } + + DLLEXPORT int c_qr_factor(int m, int n, Complex8 r[], Complex8 tau[], Complex8 q[], Complex8 work[], int len) + { + return qr_factor(m, n, r, tau, q, work, len, clapack_cgeqrf, clapack_cungqr); + } + + DLLEXPORT int c_qr_thin_factor(int m, int n, Complex8 q[], Complex8 tau[], Complex8 r[], Complex8 work[], int len) + { + return qr_thin_factor(m, n, q, tau, r, work, len, clapack_cgeqrf, clapack_cungqr); + } + + DLLEXPORT int z_qr_factor(int m, int n, Complex16 r[], Complex16 tau[], Complex16 q[]) + { + return qr_factor(m, n, r, tau, q, work, len, clapack_zgeqrf, clapack_zungqr); + } + + DLLEXPORT int z_qr_thin_factor(int m, int n, Complex16 q[], Complex16 tau[], Complex16 r[]) + { + return qr_thin_factor(m, n, q, tau, r, work, len, clapack_zgeqrf, clapack_zungqr); + } + + DLLEXPORT int s_qr_solve(int m, int n, int bn, float a[], float b[], float x[], float work[], int len) + { + return qr_solve(m, n, bn, a, b, x, work, len, sgels); + } + + DLLEXPORT int d_qr_solve(int m, int n, int bn, double a[], double b[], double x[], double work[], int len) + { + return qr_solve(m, n, bn, a, b, x, work, len, dgels); + } + + DLLEXPORT int c_qr_solve(int m, int n, int bn, Complex8 a[], Complex8 b[], Complex8 x[], Complex8 work[], int len) + { + return qr_solve(m, n, bn, a, b, x, work, len, cgels); + } + + DLLEXPORT int z_qr_solve(int m, int n, int bn, Complex16 a[], Complex16 b[], Complex16 x[], Complex16 work[], int len) + { + return qr_solve(m, n, bn, a, b, x, work, len, zgels); + } + + DLLEXPORT int s_qr_solve_factored(int m, int n, int bn, float r[], float b[], float tau[], float x[], float work[], int len) + { + return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, sormqr, cblas_strsm); + } + + DLLEXPORT int d_qr_solve_factored(int m, int n, int bn, double r[], double b[], double tau[], double x[], double work[], int len) + { + return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, dormqr, cblas_dtrsm); + } + + DLLEXPORT int c_qr_solve_factored(int m, int n, int bn, Complex8 r[], Complex8 b[], Complex8 tau[], Complex8 x[], Complex8 work[], int len) + { + return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, cunmqr, cblas_ctrsm); + } + + DLLEXPORT int z_qr_solve_factored(int m, int n, int bn, Complex16 r[], Complex16 b[], Complex16 tau[], Complex16 x[], Complex16 work[], int len) + { + return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, zunmqr, cblas_ztrsm); + } + + DLLEXPORT int s_svd_factor(bool compute_vectors, int m, int n, float a[], float s[], float u[], float v[], float work[], int len) + { + return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, sgesvd); + } + + DLLEXPORT int d_svd_factor(bool compute_vectors, int m, int n, double a[], double s[], double u[], double v[], double work[], int len) + { + return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, dgesvd); + } + + DLLEXPORT int c_svd_factor(bool compute_vectors, int m, int n, Complex8 a[], Complex8 s[], Complex8 u[], Complex8 v[], Complex8 work[], int len) + { + return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, cgesvd); + } + + DLLEXPORT int z_svd_factor(bool compute_vectors, int m, int n, Complex16 a[], Complex16 s[], Complex16 u[], Complex16 v[], Complex16 work[], int len) + { + return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, zgesvd); + }*/ } \ No newline at end of file diff --git a/src/NativeWrappers/Common/lapack_common.h b/src/NativeWrappers/Common/lapack_common.h index ab2aa46a..46677a4b 100644 --- a/src/NativeWrappers/Common/lapack_common.h +++ b/src/NativeWrappers/Common/lapack_common.h @@ -18,8 +18,7 @@ inline void shift_ipiv_up(int m, int ipiv[]){ } template -inline T* Clone(const int m, const int n, const T* a) -{ +inline T* Clone(const int m, const int n, const T* a){ T* clone = new T[m*n]; memcpy(clone, a, m*n*sizeof(T)); return clone; diff --git a/src/NativeWrappers/Common/resource.rc b/src/NativeWrappers/Common/resource.rc index 41b5a5ff..5609b91a 100644 --- a/src/NativeWrappers/Common/resource.rc +++ b/src/NativeWrappers/Common/resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,2,1,0 - PRODUCTVERSION 1,2,1,0 + FILEVERSION 1,3,0,0 + PRODUCTVERSION 1,3,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -70,12 +70,12 @@ BEGIN VALUE "Comments", "http://numerics.mathdotnet.com/" VALUE "CompanyName", "Math.NET" VALUE "FileDescription", "MathNET Numerics Native Wrapper" - VALUE "FileVersion", "1.2.1.0" + VALUE "FileVersion", "1.3.0.0" VALUE "InternalName", "Math.NET" VALUE "LegalCopyright", "Copyright (C) Math.NET 2009-2013" VALUE "OriginalFilename", "MathNet.Numerics" VALUE "ProductName", "Math.NET Numerics" - VALUE "ProductVersion", "1.2.1.0" + VALUE "ProductVersion", "1.3.0.0" END END BLOCK "VarFileInfo" diff --git a/src/NativeWrappers/Linux/build.sh b/src/NativeWrappers/Linux/build.sh index c30ad1bd..20421612 100755 --- a/src/NativeWrappers/Linux/build.sh +++ b/src/NativeWrappers/Linux/build.sh @@ -1,6 +1,11 @@ export INTEL=/opt/intel export MKL=$INTEL/mkl +export OPENMP=$INTEL/composerxe/lib -g++ --shared -fPIC -o ./x64/MathNet.Numerics.MKL.so -I$MKL/include -I../Common ../MKL/vector_functions.c ../MKL/blas.c ../MKL/lapack.cpp $INTEL/lib/intel64/libiomp5.a $MKL/lib/intel64/libmkl_intel_lp64.a $MKL/lib/intel64/libmkl_intel_thread.a $MKL/lib/intel64/libmkl_core.a +g++ -DGCC -m64 --shared -fPIC -o ../../../../MKL/Linux/x64/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common ../MKL/vector_functions.c ../MKL/blas.c ../MKL/lapack.cpp -Wl,--start-group $MKL/lib/intel64/libmkl_intel_lp64.a $MKL/lib/intel64/libmkl_intel_thread.a $MKL/lib/intel64/libmkl_core.a -Wl,--end-group -L$OPENMP/intel64 -liomp5 -lpthread -lm -g++ -m32 --shared -fPIC -o ./x86/MathNet.Numerics.MKL.so -I$MKL/include -I../Common ../MKL/vector_functions.c ../MKL/blas.c ../MKL/lapack.cpp $INTEL/lib/ia32/libiomp5.a $MKL/lib/ia32/libmkl_intel.a $MKL/lib/ia32/libmkl_intel_thread.a $MKL/lib/ia32/libmkl_core.a +cp $OPENMP/intel64/libiomp5.so ../../../../MKL/Linux/x64/ + +g++ -DGCC -m32 --shared -fPIC -o ../../../../MKL/Linux/x86/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common ../MKL/vector_functions.c ../MKL/blas.c ../MKL/lapack.cpp -Wl,--start-group $MKL/lib/ia32/libmkl_intel.a $MKL/lib/ia32/libmkl_intel_thread.a $MKL/lib/ia32/libmkl_core.a -Wl,--end-group -L$OPENMP/ia32 -liomp5 -lpthread -lm + +cp $OPENMP/ia32/libiomp5.so ../../../../MKL/Linux/x86/ diff --git a/src/NativeWrappers/MKL/blas.c b/src/NativeWrappers/MKL/blas.c index 4eb75f1f..88c054f2 100644 --- a/src/NativeWrappers/MKL/blas.c +++ b/src/NativeWrappers/MKL/blas.c @@ -1,6 +1,9 @@ #include "mkl_cblas.h" #include "wrapper_common.h" +#if GCC +extern "C" { +#endif DLLEXPORT void s_axpy(const MKL_INT n, const float alpha, const float x[], float y[]){ cblas_saxpy(n, alpha, x, 1, y, 1); } @@ -80,3 +83,7 @@ DLLEXPORT void z_matrix_multiply(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, cblas_zgemm(CblasColMajor, transA, transB, m, n, k, &alpha, x, lda, y, ldb, &beta, c, m); } + +#if GCC +} +#endif diff --git a/src/NativeWrappers/MKL/lapack.cpp b/src/NativeWrappers/MKL/lapack.cpp index 47eccbad..cb1fc691 100644 --- a/src/NativeWrappers/MKL/lapack.cpp +++ b/src/NativeWrappers/MKL/lapack.cpp @@ -1,570 +1,751 @@ -#include "mkl_lapack.h" +#include +#include +#define MKL_Complex8 std::complex +#define MKL_Complex16 std::complex + +#include "mkl_lapack.h" #include "mkl_cblas.h" #include "lapack_common.h" #include "wrapper_common.h" -#include +#include "mkl_lapacke.h" -template -inline MKL_INT lu_factor(MKL_INT m, T a[], MKL_INT ipiv[], - void (*getrf) (const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*, MKL_INT*)) +template +inline MKL_INT lu_factor(MKL_INT m, T a[], MKL_INT ipiv[], + void (*getrf)(const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*, MKL_INT*)) { + std::complex x = 5; MKL_INT info = 0; - getrf(&m, &m, a, &m, ipiv, &info); - shift_ipiv_down(m, ipiv); - return info; + getrf(&m, &m, a, &m, ipiv, &info); + shift_ipiv_down(m, ipiv); + return info; }; -template -inline MKL_INT lu_inverse(MKL_INT n, T a[], T work[], MKL_INT lwork, - void (*getrf) (const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*, MKL_INT*), - void (*getri) (const MKL_INT*, T*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) +template +inline MKL_INT lu_inverse(MKL_INT n, T a[], T work[], MKL_INT lwork, + void (*getrf)(const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*, MKL_INT*), + void (*getri)(const MKL_INT*, T*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) { - MKL_INT* ipiv = new MKL_INT[n]; - MKL_INT info = 0; - getrf(&n, &n, a, &n, ipiv, &info); - - if (info != 0){ - delete[] ipiv; - return info; - } - - getri(&n, a, &n, ipiv, work, &lwork, &info); - delete[] ipiv; - return info; + MKL_INT* ipiv = new MKL_INT[n]; + MKL_INT info = 0; + getrf(&n, &n, a, &n, ipiv, &info); + + if (info != 0) + { + delete[] ipiv; + return info; + } + + getri(&n, a, &n, ipiv, work, &lwork, &info); + delete[] ipiv; + return info; }; -template +template inline MKL_INT lu_inverse_factored(MKL_INT n, T a[], MKL_INT ipiv[], T work[], MKL_INT lwork, - void (*getri) (const MKL_INT*, T*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) + void (*getri)(const MKL_INT*, T*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) { - shift_ipiv_up(n, ipiv); - MKL_INT info = 0; - getri(&n, a, &n, ipiv, work, &lwork, &info); - shift_ipiv_down(n, ipiv); - return info; + shift_ipiv_up(n, ipiv); + MKL_INT info = 0; + getri(&n, a, &n, ipiv, work, &lwork, &info); + shift_ipiv_down(n, ipiv); + return info; } -template +template inline MKL_INT lu_solve_factored(MKL_INT n, MKL_INT nrhs, T a[], MKL_INT ipiv[], T b[], - void (*getrs) (const char*, const MKL_INT*, const MKL_INT*, const T*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) + void (*getrs)(const char*, const MKL_INT*, const MKL_INT*, const T*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) { - shift_ipiv_up(n, ipiv); - MKL_INT info = 0; - char trans ='N'; - getrs(&trans, &n, &nrhs, a, &n, ipiv, b, &n, &info); - shift_ipiv_down(n, ipiv); - return info; + shift_ipiv_up(n, ipiv); + MKL_INT info = 0; + char trans ='N'; + getrs(&trans, &n, &nrhs, a, &n, ipiv, b, &n, &info); + shift_ipiv_down(n, ipiv); + return info; } -template -inline MKL_INT lu_solve(MKL_INT n, MKL_INT nrhs, T a[], T b[], - void (*getrf) (const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*, MKL_INT*), - void (*getrs) (const char*, const MKL_INT*, const MKL_INT*, const T*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) +template +inline MKL_INT lu_solve(MKL_INT n, MKL_INT nrhs, T a[], T b[], + void (*getrf)(const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*, MKL_INT*), + void (*getrs)(const char*, const MKL_INT*, const MKL_INT*, const T*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) { - T* clone = Clone(n, n, a); - MKL_INT* ipiv = new MKL_INT[n]; - MKL_INT info = 0; - getrf(&n, &n, clone, &n, ipiv, &info); - - if (info != 0){ - delete[] ipiv; - delete[] clone; - return info; - } - - char trans ='N'; - getrs(&trans, &n, &nrhs, clone, &n, ipiv, b, &n, &info); - delete[] ipiv; - delete[] clone; - return info; + T* clone = Clone(n, n, a); + MKL_INT* ipiv = new MKL_INT[n]; + MKL_INT info = 0; + getrf(&n, &n, clone, &n, ipiv, &info); + + if (info != 0) + { + delete[] ipiv; + delete[] clone; + return info; + } + + char trans ='N'; + getrs(&trans, &n, &nrhs, clone, &n, ipiv, b, &n, &info); + delete[] ipiv; + delete[] clone; + return info; } -template +template inline MKL_INT cholesky_factor(MKL_INT n, T* a, - void (*potrf) (const char*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) + void (*potrf)(const char*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) { - char uplo = 'L'; - MKL_INT info = 0; - potrf(&uplo, &n, a, &n, &info); - T zero = T(); - for (MKL_INT i = 0; i < n; ++i) - { - MKL_INT index = i * n; - for (MKL_INT j = 0; j < n && i > j; ++j) - { - a[index + j] = zero; - } - } - return info; + char uplo = 'L'; + MKL_INT info = 0; + potrf(&uplo, &n, a, &n, &info); + T zero = T(); + + for (MKL_INT i = 0; i < n; ++i) + { + MKL_INT index = i * n; + + for (MKL_INT j = 0; j < n && i > j; ++j) + { + a[index + j] = zero; + } + } + + return info; } -template +template inline MKL_INT cholesky_solve(MKL_INT n, MKL_INT nrhs, T a[], T b[], - void (*potrf) (const char*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*), - void (*potrs) (const char*, const MKL_INT*, const MKL_INT*, const T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) + void (*potrf)(const char*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*), + void (*potrs)(const char*, const MKL_INT*, const MKL_INT*, const T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) { - T* clone = Clone(n, n, a); - char uplo = 'L'; - MKL_INT info = 0; - potrf(&uplo, &n, clone, &n, &info); - - if (info != 0){ - delete[] clone; - return info; - } - - potrs(&uplo, &n, &nrhs, clone, &n, b, &n, &info); - delete[] clone; - return info; + T* clone = Clone(n, n, a); + char uplo = 'L'; + MKL_INT info = 0; + potrf(&uplo, &n, clone, &n, &info); + + if (info != 0) + { + delete[] clone; + return info; + } + + potrs(&uplo, &n, &nrhs, clone, &n, b, &n, &info); + delete[] clone; + return info; } -template +template inline MKL_INT cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, T a[], T b[], - void (*potrs) (const char*, const MKL_INT*, const MKL_INT*, const T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) + void (*potrs)(const char*, const MKL_INT*, const MKL_INT*, const T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) { - char uplo = 'L'; - MKL_INT info = 0; - potrs(&uplo, &n, &nrhs, a, &n, b, &n, &info); - return info; + char uplo = 'L'; + MKL_INT info = 0; + potrs(&uplo, &n, &nrhs, a, &n, b, &n, &info); + return info; } -template +template inline MKL_INT qr_factor(MKL_INT m, MKL_INT n, T r[], T tau[], T q[], T work[], MKL_INT len, - void (*geqrf) (const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, T*, T*, const MKL_INT*, MKL_INT*), - void (*orgqr) (const MKL_INT*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, const T*, T*, const MKL_INT*, MKL_INT*)) + void (*geqrf)(const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, T*, T*, const MKL_INT*, MKL_INT*), + void (*orgqr)(const MKL_INT*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, const T*, T*, const MKL_INT*, MKL_INT*)) { - MKL_INT info = 0; - geqrf(&m, &n, r, &m, tau, work, &len, &info); - - for (MKL_INT i = 0; i < m; ++i) - { - for (MKL_INT j = 0; j < m && j < n; ++j) - { - if (i > j) - { - q[j * m + i] = r[j * m + i]; - } - } - } - - //compute the q elements explicitly - if (m <= n) - { - orgqr(&m, &m, &m, q, &m, tau, work, &len, &info); - } - else - { - orgqr(&m, &m, &n, q, &m, tau, work, &len, &info); - } - - return info; + MKL_INT info = 0; + geqrf(&m, &n, r, &m, tau, work, &len, &info); + + for (MKL_INT i = 0; i < m; ++i) + { + for (MKL_INT j = 0; j < m && j < n; ++j) + { + if (i > j) + { + q[j * m + i] = r[j * m + i]; + } + } + } + + //compute the q elements explicitly + if (m <= n) + { + orgqr(&m, &m, &m, q, &m, tau, work, &len, &info); + } + else + { + orgqr(&m, &m, &n, q, &m, tau, work, &len, &info); + } + + return info; } -template +template inline MKL_INT qr_thin_factor(MKL_INT m, MKL_INT n, T q[], T tau[], T r[], T work[], MKL_INT len, - void (*geqrf) (const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, T*, T*, const MKL_INT*, MKL_INT*), - void (*orgqr) (const MKL_INT*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, const T*, T*, const MKL_INT*, MKL_INT*)) + void (*geqrf)(const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, T*, T*, const MKL_INT*, MKL_INT*), + void (*orgqr)(const MKL_INT*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, const T*, T*, const MKL_INT*, MKL_INT*)) { - MKL_INT info = 0; - geqrf(&m, &n, q, &m, tau, work, &len, &info); - - for (MKL_INT i = 0; i < n; ++i) - { - for (MKL_INT j = 0; j < n; ++j) - { - if( i <= j) { - r[j * n + i] = q[j * m + i]; - } - } - } - - orgqr(&m, &n, &n, q, &m, tau, work, &len, &info); - - return info; + MKL_INT info = 0; + geqrf(&m, &n, q, &m, tau, work, &len, &info); + + for (MKL_INT i = 0; i < n; ++i) + { + for (MKL_INT j = 0; j < n; ++j) + { + if (i <= j) + { + r[j * n + i] = q[j * m + i]; + } + } + } + + orgqr(&m, &n, &n, q, &m, tau, work, &len, &info); + return info; } -template +template inline MKL_INT qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, T a[], T b[], T x[], T work[], MKL_INT len, - void (*gels) (const char*, const MKL_INT*, const MKL_INT*, const MKL_INT*, T*, - const MKL_INT*, T* b, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) + void (*gels)(const char*, const MKL_INT*, const MKL_INT*, const MKL_INT*, T*, + const MKL_INT*, T* b, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) { - T* clone_a = Clone(m, n, a); - T* clone_b = Clone(m, bn, b); - - char N = 'N'; - MKL_INT info = 0; - gels(&N, &m, &n, &bn, clone_a, &m, clone_b, &m, work, &len, &info); - - for (MKL_INT i = 0; i < n; ++i) - { - for (MKL_INT j = 0; j < bn; ++j) - { - x[j * n + i] = clone_b[j * m + i]; - } - } - - delete[] clone_a; - delete[] clone_b; - return info; + T* clone_a = Clone(m, n, a); + T* clone_b = Clone(m, bn, b); + char N = 'N'; + MKL_INT info = 0; + gels(&N, &m, &n, &bn, clone_a, &m, clone_b, &m, work, &len, &info); + copyBtoX(m, n, bn, clone_b, x); + delete[] clone_a; + delete[] clone_b; + return info; } -template +template inline MKL_INT qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, T r[], T b[], T tau[], T x[], T work[], MKL_INT len, - void (*ormqr) (const char*, const char*, const MKL_INT*, const MKL_INT*, const MKL_INT*, - const T*, const MKL_INT*, const T*, T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT* info), - void (*trsm) (const CBLAS_ORDER, const CBLAS_SIDE, const CBLAS_UPLO, const CBLAS_TRANSPOSE, const CBLAS_DIAG, - const MKL_INT, const MKL_INT, const T, const T*, const MKL_INT, T*, const MKL_INT)) + void (*ormqr)(const char*, const char*, const MKL_INT*, const MKL_INT*, const MKL_INT*, + const T*, const MKL_INT*, const T*, T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT* info), + void (*trsm)(const CBLAS_ORDER, const CBLAS_SIDE, const CBLAS_UPLO, const CBLAS_TRANSPOSE, const CBLAS_DIAG, + const MKL_INT, const MKL_INT, const T, const T*, const MKL_INT, T*, const MKL_INT)) { - T* clone_b = Clone(m, bn, b); - char side ='L'; - char tran = 'T'; - MKL_INT info = 0; - ormqr(&side, &tran, &m, &bn, &n, r, &m, tau, clone_b, &m, work, &len, &info); - trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, 1.0, r, m, clone_b, m); - for (MKL_INT i = 0; i < n; ++i) - { - for (MKL_INT j = 0; j < bn; ++j) - { - x[j * n + i] = clone_b[j * m + i]; - } - } - - delete[] clone_b; - return info; + T* clone_b = Clone(m, bn, b); + char side ='L'; + char tran = 'T'; + MKL_INT info = 0; + ormqr(&side, &tran, &m, &bn, &n, r, &m, tau, clone_b, &m, work, &len, &info); + trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, 1.0, r, m, clone_b, m); + copyBtoX(m, n, bn, clone_b, x); + delete[] clone_b; + return info; } -template +template inline MKL_INT complex_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, T r[], T b[], T tau[], T x[], T work[], MKL_INT len, - void (*unmqr) (const char*, const char*, const MKL_INT*, const MKL_INT*, const MKL_INT*, - const T*, const MKL_INT*, const T*, T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT* info), - void (*trsm) (const CBLAS_ORDER, const CBLAS_SIDE, const CBLAS_UPLO, const CBLAS_TRANSPOSE, const CBLAS_DIAG, - const MKL_INT, const MKL_INT, const void*, const void*, const MKL_INT, void*, const MKL_INT ldb)) + void (*unmqr)(const char*, const char*, const MKL_INT*, const MKL_INT*, const MKL_INT*, + const T*, const MKL_INT*, const T*, T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT* info), + void (*trsm)(const CBLAS_ORDER, const CBLAS_SIDE, const CBLAS_UPLO, const CBLAS_TRANSPOSE, const CBLAS_DIAG, + const MKL_INT, const MKL_INT, const void*, const void*, const MKL_INT, void*, const MKL_INT ldb)) { - T* clone_b = Clone(m, bn, b); - char side ='L'; - char tran = 'C'; - MKL_INT info = 0; - unmqr(&side, &tran, &m, &bn, &n, r, &m, tau, clone_b, &m, work, &len, &info); - - T one = {1.0f, 0.0f}; - trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, &one, r, m, clone_b, m); - for (MKL_INT i = 0; i < n; ++i) - { - for (MKL_INT j = 0; j < bn; ++j) - { - x[j * n + i] = clone_b[j * m + i]; - } - } - - delete[] clone_b; - return info; + T* clone_b = Clone(m, bn, b); + char side ='L'; + char tran = 'C'; + MKL_INT info = 0; + unmqr(&side, &tran, &m, &bn, &n, r, &m, tau, clone_b, &m, work, &len, &info); + T one = 1.0f; + trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, &one, r, m, clone_b, m); + copyBtoX(m, n, bn, clone_b, x); + delete[] clone_b; + return info; } -template +template inline MKL_INT svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, T a[], T s[], T u[], T v[], T work[], MKL_INT len, - void (*gesvd) (const char*, const char*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, - T*, T*, const MKL_INT*, T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) + void (*gesvd)(const char*, const char*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, + T*, T*, const MKL_INT*, T*, const MKL_INT*, T*, const MKL_INT*, MKL_INT*)) { - MKL_INT info = 0; - char job = compute_vectors ? 'A' : 'N'; - gesvd(&job, &job, &m, &n, a, &m, s, u, &m, v, &n, work, &len, &info); - return info; + MKL_INT info = 0; + char job = compute_vectors ? 'A' : 'N'; + gesvd(&job, &job, &m, &n, a, &m, s, u, &m, v, &n, work, &len, &info); + return info; } -template +template inline MKL_INT complex_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, T a[], T s[], T u[], T v[], T work[], MKL_INT len, - void (*gesvd) (const char*, const char*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, - R*, T*, const MKL_INT*, T*, const MKL_INT*, T*, const MKL_INT*, R*, MKL_INT*)) + void (*gesvd)(const char*, const char*, const MKL_INT*, const MKL_INT*, T*, const MKL_INT*, + R*, T*, const MKL_INT*, T*, const MKL_INT*, T*, const MKL_INT*, R*, MKL_INT*)) { - MKL_INT info = 0; - MKL_INT dim_s = std::min(m,n); - R* rwork = new R[5 * dim_s]; - R* s_local = new R[dim_s]; - char job = compute_vectors ? 'A' : 'N'; - gesvd(&job, &job, &m, &n, a, &m, s_local, u, &m, v, &n, work, &len, rwork, &info); - - for(MKL_INT index = 0; index < dim_s; ++index){ - T value = {s_local[index], 0.0f}; - s[index] = value; - } - - delete[] rwork; - delete[] s_local; - return info; + MKL_INT info = 0; + MKL_INT dim_s = std::min(m,n); + R* rwork = new R[5 * dim_s]; + R* s_local = new R[dim_s]; + char job = compute_vectors ? 'A' : 'N'; + gesvd(&job, &job, &m, &n, a, &m, s_local, u, &m, v, &n, work, &len, rwork, &info); + + for (MKL_INT index = 0; index < dim_s; ++index) + { + s[index] = s_local[index]; + } + + delete[] rwork; + delete[] s_local; + return info; } -extern "C" { - - DLLEXPORT float s_matrix_norm(char norm, MKL_INT m, MKL_INT n, float a[], float work[]) - { - return slange(&norm, &m, &n, a, &m, work); - } - - DLLEXPORT double d_matrix_norm(char norm, MKL_INT m, MKL_INT n, double a[], double work[]) - { - return dlange(&norm, &m, &n, a, &m, work); - } - - DLLEXPORT float c_matrix_norm(char norm, MKL_INT m, MKL_INT n, MKL_Complex8 a[], float work[]) - { - return clange(&norm, &m, &n, a, &m, work); - } - - DLLEXPORT double z_matrix_norm(char norm, MKL_INT m, MKL_INT n, MKL_Complex16 a[], double work[]) - { - return zlange(&norm, &m, &n, a, &m, work); - } - - DLLEXPORT MKL_INT s_lu_factor(MKL_INT m, float a[], MKL_INT ipiv[]) { - return lu_factor(m, a, ipiv, sgetrf); - } - - DLLEXPORT MKL_INT d_lu_factor(MKL_INT m, double a[], MKL_INT ipiv[]) { - return lu_factor(m, a, ipiv, dgetrf); - } - - DLLEXPORT MKL_INT c_lu_factor(MKL_INT m, MKL_Complex8 a[], MKL_INT ipiv[]) { - return lu_factor(m, a, ipiv, cgetrf); - } - - DLLEXPORT MKL_INT z_lu_factor(MKL_INT m, MKL_Complex16 a[], MKL_INT ipiv[]) { - return lu_factor(m, a, ipiv, zgetrf); - } - - DLLEXPORT MKL_INT s_lu_inverse(MKL_INT n, float a[], float work[], MKL_INT lwork) - { - return lu_inverse(n, a, work, lwork, sgetrf, sgetri); - } - - DLLEXPORT MKL_INT d_lu_inverse(MKL_INT n, double a[], double work[], MKL_INT lwork) - { - return lu_inverse(n, a, work, lwork, dgetrf, dgetri); - } - - DLLEXPORT MKL_INT c_lu_inverse(MKL_INT n, MKL_Complex8 a[], MKL_Complex8 work[], MKL_INT lwork) - { - return lu_inverse(n, a, work, lwork, cgetrf, cgetri); - } - - DLLEXPORT MKL_INT z_lu_inverse(MKL_INT n, MKL_Complex16 a[], MKL_Complex16 work[], MKL_INT lwork) - { - return lu_inverse(n, a, work, lwork, zgetrf, zgetri); - } - - DLLEXPORT MKL_INT s_lu_inverse_factored(MKL_INT n, float a[], MKL_INT ipiv[], float work[], MKL_INT lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, sgetri); - } - - DLLEXPORT MKL_INT d_lu_inverse_factored(MKL_INT n, double a[], MKL_INT ipiv[], double work[], MKL_INT lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, dgetri); - } - - DLLEXPORT MKL_INT c_lu_inverse_factored(MKL_INT n, MKL_Complex8 a[], MKL_INT ipiv[], MKL_Complex8 work[], MKL_INT lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, cgetri); - } - - DLLEXPORT MKL_INT z_lu_inverse_factored(MKL_INT n, MKL_Complex16 a[], MKL_INT ipiv[], MKL_Complex16 work[], MKL_INT lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, zgetri); - } - - DLLEXPORT MKL_INT s_lu_solve_factored(MKL_INT n, MKL_INT nrhs, float a[], MKL_INT ipiv[], float b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, sgetrs); - } - - DLLEXPORT MKL_INT d_lu_solve_factored(MKL_INT n, MKL_INT nrhs, double a[], MKL_INT ipiv[], double b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, dgetrs); - } - - DLLEXPORT MKL_INT c_lu_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_INT ipiv[], MKL_Complex8 b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, cgetrs); - } - - DLLEXPORT MKL_INT z_lu_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_INT ipiv[], MKL_Complex16 b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, zgetrs); - } - - DLLEXPORT MKL_INT s_lu_solve(MKL_INT n, MKL_INT nrhs, float a[], float b[]) - { - return lu_solve(n, nrhs, a, b, sgetrf, sgetrs); - } - - DLLEXPORT MKL_INT d_lu_solve(MKL_INT n, MKL_INT nrhs, double a[], double b[]) - { - return lu_solve(n, nrhs, a, b, dgetrf, dgetrs); - } - - DLLEXPORT MKL_INT c_lu_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_Complex8 b[]) - { - return lu_solve(n, nrhs, a, b, cgetrf, cgetrs); - } - - DLLEXPORT MKL_INT z_lu_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_Complex16 b[]) - { - return lu_solve(n, nrhs, a, b, zgetrf, zgetrs); - } - - DLLEXPORT MKL_INT s_cholesky_factor(MKL_INT n, float a[]){ - return cholesky_factor(n, a, spotrf); - } - - DLLEXPORT MKL_INT d_cholesky_factor(MKL_INT n, double* a){ - return cholesky_factor(n, a, dpotrf); - } - - DLLEXPORT MKL_INT c_cholesky_factor(MKL_INT n, MKL_Complex8 a[]){ - return cholesky_factor(n, a, cpotrf); - } - - DLLEXPORT MKL_INT z_cholesky_factor(MKL_INT n, MKL_Complex16 a[]){ - return cholesky_factor(n, a, zpotrf); - } - - DLLEXPORT MKL_INT s_cholesky_solve(MKL_INT n, MKL_INT nrhs, float a[], float b[]) - { - return cholesky_solve(n, nrhs, a, b, spotrf, spotrs); - } - - DLLEXPORT MKL_INT d_cholesky_solve(MKL_INT n, MKL_INT nrhs, double a[], double b[]) - { - return cholesky_solve(n, nrhs, a, b, dpotrf, dpotrs); - } - - DLLEXPORT MKL_INT c_cholesky_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_Complex8 b[]) - { - return cholesky_solve(n, nrhs, a, b, cpotrf, cpotrs); - } - - DLLEXPORT MKL_INT z_cholesky_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_Complex16 b[]) - { - return cholesky_solve(n, nrhs, a, b, zpotrf, zpotrs); - } - - DLLEXPORT MKL_INT s_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, float a[], float b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, spotrs); - } - - DLLEXPORT MKL_INT d_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, double a[], double b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, dpotrs); - } - - DLLEXPORT MKL_INT c_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_Complex8 b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, cpotrs); - } - - DLLEXPORT MKL_INT z_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_Complex16 b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, zpotrs); - } - - DLLEXPORT MKL_INT s_qr_factor(MKL_INT m, MKL_INT n, float r[], float tau[], float q[], float work[], MKL_INT len) - { - return qr_factor(m, n, r, tau, q, work, len, sgeqrf, sorgqr); - } - - DLLEXPORT MKL_INT s_qr_thin_factor(MKL_INT m, MKL_INT n, float q[], float tau[], float r[], float work[], MKL_INT len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, sgeqrf, sorgqr); - } - - DLLEXPORT MKL_INT d_qr_factor(MKL_INT m, MKL_INT n, double r[], double tau[], double q[], double work[], MKL_INT len) - { - return qr_factor(m, n, r, tau, q, work, len, dgeqrf, dorgqr); - } - - DLLEXPORT MKL_INT d_qr_thin_factor(MKL_INT m, MKL_INT n, double q[], double tau[], double r[], double work[], MKL_INT len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, dgeqrf, dorgqr); - } - - DLLEXPORT MKL_INT c_qr_factor(MKL_INT m, MKL_INT n, MKL_Complex8 r[], MKL_Complex8 tau[], MKL_Complex8 q[], MKL_Complex8 work[], MKL_INT len) - { - return qr_factor(m, n, r, tau, q, work, len, cgeqrf, cungqr); - } +template +inline MKL_INT eigen_factor(MKL_INT n, T a[], T vectors[], MKL_Complex16 values[], T d[], + MKL_INT(*gees)(MKL_INT, char, char, int(*)(const T*, const T*), MKL_INT, T* a, + MKL_INT, MKL_INT*, T*, T*, T*, MKL_INT), + MKL_INT(*trevc)(MKL_INT, char, char, lapack_logical*, MKL_INT, const T*, + MKL_INT, T*, MKL_INT, T*, MKL_INT, MKL_INT, MKL_INT*)) +{ + T* clone_a = Clone(n, n, a); + T* wr = new T[n]; + T* wi = new T[n]; + + MKL_INT sdim; + MKL_INT info = gees(LAPACK_COL_MAJOR, 'V', 'N', nullptr, n, clone_a, n, &sdim, wr, wi, vectors, n); + if (info != 0) + { + delete[] clone_a; + delete[] wr; + delete[] wi; + return info; + } + + MKL_INT m; + info = trevc(LAPACK_COL_MAJOR, 'R', 'B', nullptr, n, clone_a, n, nullptr, n, vectors, n, n, &m); + if (info != 0) + { + delete[] clone_a; + delete[] wr; + delete[] wi; + return info; + } + + for (MKL_INT index = 0; index < n; ++index) + { + values[index] = MKL_Complex16(wr[index], wi[index]); + } + + for (MKL_INT i = 0; i < n; ++i) + { + MKL_INT in = i * n; + d[in + i] = wr[i]; + + if (wi[i] > 0) + { + d[in + n + i] = wi[i]; + } + else if (wi[i] < 0) + { + d[in - n + i] = wi[i]; + } + } + + delete[] clone_a; + delete[] wr; + delete[] wi; + return info; +} - DLLEXPORT MKL_INT c_qr_thin_factor(MKL_INT m, MKL_INT n, MKL_Complex8 q[], MKL_Complex8 tau[], MKL_Complex8 r[], MKL_Complex8 work[], MKL_INT len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, cgeqrf, cungqr); - } +template +inline MKL_INT eigen_complex_factor(MKL_INT n, T a[], T vectors[], MKL_Complex16 values[], T d[], + MKL_INT(*gees)(MKL_INT, char, char, int(*)(const T*), MKL_INT, T* a, + MKL_INT, MKL_INT*, T*, T*, MKL_INT), + MKL_INT(*trevc)(MKL_INT, char, char, const lapack_logical*, MKL_INT, T*, + MKL_INT, T*, MKL_INT, T*, MKL_INT, MKL_INT, MKL_INT*)) +{ + T* clone_a = Clone(n, n, a); + T* w = new T[n]; - DLLEXPORT MKL_INT z_qr_factor(MKL_INT m, MKL_INT n, MKL_Complex16 r[], MKL_Complex16 tau[], MKL_Complex16 q[], MKL_Complex16 work[], MKL_INT len) + MKL_INT sdim; + MKL_INT info = gees(LAPACK_COL_MAJOR, 'V', 'N', nullptr, n, clone_a, n, &sdim, w, vectors, n); + if (info != 0) { - return qr_factor(m, n, r, tau, q, work, len, zgeqrf, zungqr); + delete[] clone_a; + delete[] w; + return info; } - DLLEXPORT MKL_INT z_qr_thin_factor(MKL_INT m, MKL_INT n, MKL_Complex16 q[], MKL_Complex16 tau[], MKL_Complex16 r[], MKL_Complex16 work[], MKL_INT len) + MKL_INT m; + info = trevc(LAPACK_COL_MAJOR, 'R', 'B', nullptr, n, clone_a, n, nullptr, n, vectors, n, n, &m); + if (info != 0) { - return qr_thin_factor(m, n, q, tau, r, work, len, zgeqrf, zungqr); + delete[] clone_a; + delete[] w; + return info; } - DLLEXPORT MKL_INT s_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, float a[], float b[], float x[], float work[], MKL_INT len) + for (MKL_INT i = 0; i < n; ++i) { - return qr_solve(m, n, bn, a, b, x, work, len, sgels); + values[i] = w[i]; + d[i * n + i] = w[i]; } - DLLEXPORT MKL_INT d_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, double a[], double b[], double x[], double work[], MKL_INT len) - { - return qr_solve(m, n, bn, a, b, x, work, len, dgels); - } + delete[] clone_a; + delete[] w; + return info; +} - DLLEXPORT MKL_INT c_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex8 a[], MKL_Complex8 b[], MKL_Complex8 x[], MKL_Complex8 work[], MKL_INT len) - { - return qr_solve(m, n, bn, a, b, x, work, len, cgels); - } +template +inline MKL_INT sym_eigen_factor(MKL_INT n, T a[], T vectors[], MKL_Complex16 values[], T d[], + MKL_INT(*syev)(int, char, char, int, T*, int, R*)) +{ + T* clone_a = Clone(n, n, a); + R* w = new R[n]; - DLLEXPORT MKL_INT z_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex16 a[], MKL_Complex16 b[], MKL_Complex16 x[], MKL_Complex16 work[], MKL_INT len) + MKL_INT info = syev(LAPACK_COL_MAJOR, 'V', 'U', n, clone_a, n, w); + if (info != 0) { - return qr_solve(m, n, bn, a, b, x, work, len, zgels); + delete[] clone_a; + delete[] w; + return info; } - DLLEXPORT MKL_INT s_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, float r[], float b[], float tau[], float x[], float work[], MKL_INT len) - { - return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, sormqr, cblas_strsm); - } + memcpy(vectors, clone_a, n*n*sizeof(T)); - DLLEXPORT MKL_INT d_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, double r[], double b[], double tau[], double x[], double work[], MKL_INT len) + for (MKL_INT index = 0; index < n; ++index) { - return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, dormqr, cblas_dtrsm); + values[index] = MKL_Complex16(w[index]); } + + for (MKL_INT j = 0; j < n; j++) + { + MKL_INT jn = j*n; - DLLEXPORT MKL_INT c_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex8 r[], MKL_Complex8 b[], MKL_Complex8 tau[], MKL_Complex8 x[], MKL_Complex8 work[], MKL_INT len) - { - return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, cunmqr, cblas_ctrsm); - } + for (MKL_INT i = 0; i < n; ++i) + { + if (i == j) + { + d[jn + i] = w[i]; + } + } + } - DLLEXPORT MKL_INT z_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex16 r[], MKL_Complex16 b[], MKL_Complex16 tau[], MKL_Complex16 x[], MKL_Complex16 work[], MKL_INT len) - { - return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, zunmqr, cblas_ztrsm); - } + delete[] clone_a; + delete[] w; + return info; +} - DLLEXPORT MKL_INT s_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, float a[], float s[], float u[], float v[], float work[], MKL_INT len) - { - return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, sgesvd); - } +extern "C" { - DLLEXPORT MKL_INT d_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, double a[], double s[], double u[], double v[], double work[], MKL_INT len) - { - return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, dgesvd); - } + DLLEXPORT float s_matrix_norm(char norm, MKL_INT m, MKL_INT n, float a[], float work[]) + { + return slange(&norm, &m, &n, a, &m, work); + } + + DLLEXPORT double d_matrix_norm(char norm, MKL_INT m, MKL_INT n, double a[], double work[]) + { + return dlange(&norm, &m, &n, a, &m, work); + } + + DLLEXPORT float c_matrix_norm(char norm, MKL_INT m, MKL_INT n, MKL_Complex8 a[], float work[]) + { + return clange(&norm, &m, &n, a, &m, work); + } + + DLLEXPORT double z_matrix_norm(char norm, MKL_INT m, MKL_INT n, MKL_Complex16 a[], double work[]) + { + return zlange(&norm, &m, &n, a, &m, work); + } + + DLLEXPORT MKL_INT s_lu_factor(MKL_INT m, float a[], MKL_INT ipiv[]) + { + return lu_factor(m, a, ipiv, sgetrf); + } + + DLLEXPORT MKL_INT d_lu_factor(MKL_INT m, double a[], MKL_INT ipiv[]) + { + return lu_factor(m, a, ipiv, dgetrf); + } + + DLLEXPORT MKL_INT c_lu_factor(MKL_INT m, MKL_Complex8 a[], MKL_INT ipiv[]) + { + return lu_factor(m, a, ipiv, cgetrf); + } + + DLLEXPORT MKL_INT z_lu_factor(MKL_INT m, MKL_Complex16 a[], MKL_INT ipiv[]) + { + return lu_factor(m, a, ipiv, zgetrf); + } + + DLLEXPORT MKL_INT s_lu_inverse(MKL_INT n, float a[], float work[], MKL_INT lwork) + { + return lu_inverse(n, a, work, lwork, sgetrf, sgetri); + } + + DLLEXPORT MKL_INT d_lu_inverse(MKL_INT n, double a[], double work[], MKL_INT lwork) + { + return lu_inverse(n, a, work, lwork, dgetrf, dgetri); + } + + DLLEXPORT MKL_INT c_lu_inverse(MKL_INT n, MKL_Complex8 a[], MKL_Complex8 work[], MKL_INT lwork) + { + return lu_inverse(n, a, work, lwork, cgetrf, cgetri); + } + + DLLEXPORT MKL_INT z_lu_inverse(MKL_INT n, MKL_Complex16 a[], MKL_Complex16 work[], MKL_INT lwork) + { + return lu_inverse(n, a, work, lwork, zgetrf, zgetri); + } + + DLLEXPORT MKL_INT s_lu_inverse_factored(MKL_INT n, float a[], MKL_INT ipiv[], float work[], MKL_INT lwork) + { + return lu_inverse_factored(n, a, ipiv, work, lwork, sgetri); + } + + DLLEXPORT MKL_INT d_lu_inverse_factored(MKL_INT n, double a[], MKL_INT ipiv[], double work[], MKL_INT lwork) + { + return lu_inverse_factored(n, a, ipiv, work, lwork, dgetri); + } + + DLLEXPORT MKL_INT c_lu_inverse_factored(MKL_INT n, MKL_Complex8 a[], MKL_INT ipiv[], MKL_Complex8 work[], MKL_INT lwork) + { + return lu_inverse_factored(n, a, ipiv, work, lwork, cgetri); + } + + DLLEXPORT MKL_INT z_lu_inverse_factored(MKL_INT n, MKL_Complex16 a[], MKL_INT ipiv[], MKL_Complex16 work[], MKL_INT lwork) + { + return lu_inverse_factored(n, a, ipiv, work, lwork, zgetri); + } + + DLLEXPORT MKL_INT s_lu_solve_factored(MKL_INT n, MKL_INT nrhs, float a[], MKL_INT ipiv[], float b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, sgetrs); + } + + DLLEXPORT MKL_INT d_lu_solve_factored(MKL_INT n, MKL_INT nrhs, double a[], MKL_INT ipiv[], double b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, dgetrs); + } + + DLLEXPORT MKL_INT c_lu_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_INT ipiv[], MKL_Complex8 b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, cgetrs); + } + + DLLEXPORT MKL_INT z_lu_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_INT ipiv[], MKL_Complex16 b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, zgetrs); + } + + DLLEXPORT MKL_INT s_lu_solve(MKL_INT n, MKL_INT nrhs, float a[], float b[]) + { + return lu_solve(n, nrhs, a, b, sgetrf, sgetrs); + } + + DLLEXPORT MKL_INT d_lu_solve(MKL_INT n, MKL_INT nrhs, double a[], double b[]) + { + return lu_solve(n, nrhs, a, b, dgetrf, dgetrs); + } + + DLLEXPORT MKL_INT c_lu_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_Complex8 b[]) + { + return lu_solve(n, nrhs, a, b, cgetrf, cgetrs); + } + + DLLEXPORT MKL_INT z_lu_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_Complex16 b[]) + { + return lu_solve(n, nrhs, a, b, zgetrf, zgetrs); + } + + DLLEXPORT MKL_INT s_cholesky_factor(MKL_INT n, float a[]) + { + return cholesky_factor(n, a, spotrf); + } + + DLLEXPORT MKL_INT d_cholesky_factor(MKL_INT n, double* a) + { + return cholesky_factor(n, a, dpotrf); + } + + DLLEXPORT MKL_INT c_cholesky_factor(MKL_INT n, MKL_Complex8 a[]) + { + return cholesky_factor(n, a, cpotrf); + } + + DLLEXPORT MKL_INT z_cholesky_factor(MKL_INT n, MKL_Complex16 a[]) + { + return cholesky_factor(n, a, zpotrf); + } + + DLLEXPORT MKL_INT s_cholesky_solve(MKL_INT n, MKL_INT nrhs, float a[], float b[]) + { + return cholesky_solve(n, nrhs, a, b, spotrf, spotrs); + } + + DLLEXPORT MKL_INT d_cholesky_solve(MKL_INT n, MKL_INT nrhs, double a[], double b[]) + { + return cholesky_solve(n, nrhs, a, b, dpotrf, dpotrs); + } + + DLLEXPORT MKL_INT c_cholesky_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_Complex8 b[]) + { + return cholesky_solve(n, nrhs, a, b, cpotrf, cpotrs); + } + + DLLEXPORT MKL_INT z_cholesky_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_Complex16 b[]) + { + return cholesky_solve(n, nrhs, a, b, zpotrf, zpotrs); + } + + DLLEXPORT MKL_INT s_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, float a[], float b[]) + { + return cholesky_solve_factored(n, nrhs, a, b, spotrs); + } + + DLLEXPORT MKL_INT d_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, double a[], double b[]) + { + return cholesky_solve_factored(n, nrhs, a, b, dpotrs); + } + + DLLEXPORT MKL_INT c_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_Complex8 b[]) + { + return cholesky_solve_factored(n, nrhs, a, b, cpotrs); + } + + DLLEXPORT MKL_INT z_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_Complex16 b[]) + { + return cholesky_solve_factored(n, nrhs, a, b, zpotrs); + } + + DLLEXPORT MKL_INT s_qr_factor(MKL_INT m, MKL_INT n, float r[], float tau[], float q[], float work[], MKL_INT len) + { + return qr_factor(m, n, r, tau, q, work, len, sgeqrf, sorgqr); + } + + DLLEXPORT MKL_INT s_qr_thin_factor(MKL_INT m, MKL_INT n, float q[], float tau[], float r[], float work[], MKL_INT len) + { + return qr_thin_factor(m, n, q, tau, r, work, len, sgeqrf, sorgqr); + } + + DLLEXPORT MKL_INT d_qr_factor(MKL_INT m, MKL_INT n, double r[], double tau[], double q[], double work[], MKL_INT len) + { + return qr_factor(m, n, r, tau, q, work, len, dgeqrf, dorgqr); + } + + DLLEXPORT MKL_INT d_qr_thin_factor(MKL_INT m, MKL_INT n, double q[], double tau[], double r[], double work[], MKL_INT len) + { + return qr_thin_factor(m, n, q, tau, r, work, len, dgeqrf, dorgqr); + } + + DLLEXPORT MKL_INT c_qr_factor(MKL_INT m, MKL_INT n, MKL_Complex8 r[], MKL_Complex8 tau[], MKL_Complex8 q[], MKL_Complex8 work[], MKL_INT len) + { + return qr_factor(m, n, r, tau, q, work, len, cgeqrf, cungqr); + } + + DLLEXPORT MKL_INT c_qr_thin_factor(MKL_INT m, MKL_INT n, MKL_Complex8 q[], MKL_Complex8 tau[], MKL_Complex8 r[], MKL_Complex8 work[], MKL_INT len) + { + return qr_thin_factor(m, n, q, tau, r, work, len, cgeqrf, cungqr); + } + + DLLEXPORT MKL_INT z_qr_factor(MKL_INT m, MKL_INT n, MKL_Complex16 r[], MKL_Complex16 tau[], MKL_Complex16 q[], MKL_Complex16 work[], MKL_INT len) + { + return qr_factor(m, n, r, tau, q, work, len, zgeqrf, zungqr); + } + + DLLEXPORT MKL_INT z_qr_thin_factor(MKL_INT m, MKL_INT n, MKL_Complex16 q[], MKL_Complex16 tau[], MKL_Complex16 r[], MKL_Complex16 work[], MKL_INT len) + { + return qr_thin_factor(m, n, q, tau, r, work, len, zgeqrf, zungqr); + } + + DLLEXPORT MKL_INT s_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, float a[], float b[], float x[], float work[], MKL_INT len) + { + return qr_solve(m, n, bn, a, b, x, work, len, sgels); + } + + DLLEXPORT MKL_INT d_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, double a[], double b[], double x[], double work[], MKL_INT len) + { + return qr_solve(m, n, bn, a, b, x, work, len, dgels); + } + + DLLEXPORT MKL_INT c_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex8 a[], MKL_Complex8 b[], MKL_Complex8 x[], MKL_Complex8 work[], MKL_INT len) + { + return qr_solve(m, n, bn, a, b, x, work, len, cgels); + } + + DLLEXPORT MKL_INT z_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex16 a[], MKL_Complex16 b[], MKL_Complex16 x[], MKL_Complex16 work[], MKL_INT len) + { + return qr_solve(m, n, bn, a, b, x, work, len, zgels); + } + + DLLEXPORT MKL_INT s_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, float r[], float b[], float tau[], float x[], float work[], MKL_INT len) + { + return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, sormqr, cblas_strsm); + } + + DLLEXPORT MKL_INT d_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, double r[], double b[], double tau[], double x[], double work[], MKL_INT len) + { + return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, dormqr, cblas_dtrsm); + } + + DLLEXPORT MKL_INT c_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex8 r[], MKL_Complex8 b[], MKL_Complex8 tau[], MKL_Complex8 x[], MKL_Complex8 work[], MKL_INT len) + { + return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, cunmqr, cblas_ctrsm); + } + + DLLEXPORT MKL_INT z_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex16 r[], MKL_Complex16 b[], MKL_Complex16 tau[], MKL_Complex16 x[], MKL_Complex16 work[], MKL_INT len) + { + return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, zunmqr, cblas_ztrsm); + } + + DLLEXPORT MKL_INT s_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, float a[], float s[], float u[], float v[], float work[], MKL_INT len) + { + return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, sgesvd); + } + + DLLEXPORT MKL_INT d_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, double a[], double s[], double u[], double v[], double work[], MKL_INT len) + { + return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, dgesvd); + } + + DLLEXPORT MKL_INT c_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, MKL_Complex8 a[], MKL_Complex8 s[], MKL_Complex8 u[], MKL_Complex8 v[], MKL_Complex8 work[], MKL_INT len) + { + return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, cgesvd); + } + + DLLEXPORT MKL_INT z_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, MKL_Complex16 a[], MKL_Complex16 s[], MKL_Complex16 u[], MKL_Complex16 v[], MKL_Complex16 work[], MKL_INT len) + { + return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, zgesvd); + } + + DLLEXPORT MKL_INT s_eigen(bool isSymmetric, MKL_INT n, float a[], float vectors[], MKL_Complex16 values[], float d[]) + { + if (isSymmetric) + { + return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_ssyev); + } + else + { + return eigen_factor(n, a, vectors, values, d, LAPACKE_sgees, LAPACKE_strevc); + } + } + + DLLEXPORT MKL_INT d_eigen(bool isSymmetric, MKL_INT n, double a[], double vectors[], MKL_Complex16 values[], double d[]) + { + if (isSymmetric) + { + return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_dsyev); + } + else + { + return eigen_factor(n, a, vectors, values, d, LAPACKE_dgees, LAPACKE_dtrevc); + } + } + + DLLEXPORT MKL_INT c_eigen(bool isSymmetric, MKL_INT n, MKL_Complex8 a[], MKL_Complex8 vectors[], MKL_Complex16 values[], MKL_Complex8 d[]) + { + if (isSymmetric) + { + return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_cheev); + } + else + { + return -1; + //return eigen_factor(n, a, vectors, values, d, LAPACKE_zgees, LAPACKE_ztrevc); + } + } - DLLEXPORT MKL_INT c_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, MKL_Complex8 a[], MKL_Complex8 s[], MKL_Complex8 u[], MKL_Complex8 v[], MKL_Complex8 work[], MKL_INT len) - { - return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, cgesvd); - } - - DLLEXPORT MKL_INT z_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, MKL_Complex16 a[], MKL_Complex16 s[], MKL_Complex16 u[], MKL_Complex16 v[], MKL_Complex16 work[], MKL_INT len) - { - return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, zgesvd); - } + DLLEXPORT MKL_INT z_eigen(bool isSymmetric, MKL_INT n, MKL_Complex16 a[], MKL_Complex16 vectors[], MKL_Complex16 values[], MKL_Complex16 d[]) + { + if (isSymmetric) + { + return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_zheev); + } + else + { + return eigen_complex_factor(n, a, vectors, values, d, LAPACKE_zgees, LAPACKE_ztrevc); + } + } } \ No newline at end of file diff --git a/src/NativeWrappers/MKL/vector_functions.c b/src/NativeWrappers/MKL/vector_functions.c index 7e379a8f..df05d487 100644 --- a/src/NativeWrappers/MKL/vector_functions.c +++ b/src/NativeWrappers/MKL/vector_functions.c @@ -1,7 +1,9 @@ #include "mkl_vml.h" #include "wrapper_common.h" - +#if GCC +extern "C" { +#endif DLLEXPORT void s_vector_add( const int n, const float x[], const float y[], float result[] ){ vsAdd( n, x, y, result ); } @@ -65,3 +67,6 @@ DLLEXPORT void z_vector_multiply( const int n, const MKL_Complex16 x[], const MK DLLEXPORT void z_vector_divide( const int n, const MKL_Complex16 x[], const MKL_Complex16 y[], MKL_Complex16 result[] ){ vzDiv( n, x, y, result ); } +#if GCC +} +#endif diff --git a/src/NativeWrappers/Windows/ATLASWrapper/ATLASWrapper.vcxproj b/src/NativeWrappers/Windows/ATLASWrapper/ATLASWrapper.vcxproj new file mode 100644 index 00000000..53ab828a --- /dev/null +++ b/src/NativeWrappers/Windows/ATLASWrapper/ATLASWrapper.vcxproj @@ -0,0 +1,160 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220} + Win32Proj + ATLASWrapper + + + + DynamicLibrary + true + v110 + Unicode + + + DynamicLibrary + true + v110 + Unicode + + + DynamicLibrary + false + v110 + true + Unicode + + + DynamicLibrary + false + v110 + true + Unicode + + + + + + + + + + + + + + + + + + + true + D:\Source\ATLAS\include;..\..\Common;$(IncludePath) + $(SolutionDir)..\..\..\..\ATLAS\Windows\x86\ + + + true + D:\Source\ATLAS\include;..\..\Common;$(IncludePath) + $(SolutionDir)..\..\..\..\ATLAS\Windows\x64\ + + + false + D:\Source\ATLAS\include;..\..\Common;$(IncludePath) + $(SolutionDir)..\..\..\..\ATLAS\Windows\x86\ + + + false + D:\Source\ATLAS\include;..\..\Common;$(IncludePath) + $(SolutionDir)..\..\..\..\ATLAS\Windows\x64\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;ATLASWRAPPER_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + libptcblas.a;libatlas.a;libptlapack.a;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;ATLASWRAPPER_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + libptcblas.a;libatlas.a;libptlapack.a;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;ATLASWRAPPER_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + libptcblas.a;libatlas.a;libptlapack.a;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;ATLASWRAPPER_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + libptcblas.a;libatlas.a;libptlapack.a;%(AdditionalDependencies) + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/NativeWrappers/Windows/ATLASWrapper/ATLASWrapper.vcxproj.filters b/src/NativeWrappers/Windows/ATLASWrapper/ATLASWrapper.vcxproj.filters new file mode 100644 index 00000000..d6464ae4 --- /dev/null +++ b/src/NativeWrappers/Windows/ATLASWrapper/ATLASWrapper.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Resource Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj b/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj index 11b8e4d2..c76b97f6 100644 --- a/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj +++ b/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj @@ -241,6 +241,7 @@ Level3 ProgramDatabase Default + /Qvec-report:1 %(AdditionalOptions) libiomp5md.lib;mkl_intel_c.lib;mkl_intel_thread.lib;mkl_core.lib;%(AdditionalDependencies) @@ -271,6 +272,7 @@ Level3 ProgramDatabase Default + /Qvec-report:1 %(AdditionalOptions) libiomp5md.lib;mkl_intel_lp64.lib;mkl_intel_thread.lib;mkl_core.lib;%(AdditionalDependencies) @@ -292,9 +294,6 @@ - - - diff --git a/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters b/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters index 90fe534e..0a96af4e 100644 --- a/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters +++ b/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters @@ -28,11 +28,6 @@ Source Files - - - Header Files - - Resource Files diff --git a/src/NativeWrappers/Windows/NativeWrappers.sln b/src/NativeWrappers/Windows/NativeWrappers.sln index a19c473e..a514d628 100644 --- a/src/NativeWrappers/Windows/NativeWrappers.sln +++ b/src/NativeWrappers/Windows/NativeWrappers.sln @@ -12,22 +12,40 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{5A0892 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MKLWrapper", "MKL\MKLWrapper.vcxproj", "{C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ATLASWrapper", "ATLASWrapper\ATLASWrapper.vcxproj", "{2362B8AC-C52B-45E4-A1BF-C682A4DB4220}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Mixed Platforms = Debug|Mixed Platforms Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 + Release|Mixed Platforms = Release|Mixed Platforms Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Debug|Win32.ActiveCfg = Debug|Win32 {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Debug|Win32.Build.0 = Debug|Win32 {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Debug|x64.ActiveCfg = Debug|x64 {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Debug|x64.Build.0 = Debug|x64 + {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Release|Mixed Platforms.Build.0 = Release|Win32 {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Release|Win32.ActiveCfg = Release|Win32 {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Release|Win32.Build.0 = Release|Win32 {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Release|x64.ActiveCfg = Release|x64 {C0B0DBA9-7FB0-4C87-BDB1-3EED19DC2B8F}.Release|x64.Build.0 = Release|x64 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Debug|Win32.ActiveCfg = Debug|Win32 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Debug|Win32.Build.0 = Debug|Win32 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Debug|x64.ActiveCfg = Debug|Win32 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Release|Mixed Platforms.Build.0 = Release|Win32 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Release|Win32.ActiveCfg = Release|Win32 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Release|Win32.Build.0 = Release|Win32 + {2362B8AC-C52B-45E4-A1BF-C682A4DB4220}.Release|x64.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProvider.cs b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProvider.cs index 8a3fc253..4138835f 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProvider.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProvider.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -93,5 +93,49 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// The requested of the matrix. /// Complex MatrixNorm(Norm norm, int rows, int columns, Complex[] matrix, double[] work); + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + void EigenDecomp(bool isSymmetric, int order, float[] matrix, float[] matrixEv, Complex[] vectorEv, float[] matrixD); + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + void EigenDecomp(bool isSymmetric, int order, double[] matrix, double[] matrixEv, Complex[] vectorEv, double[] matrixD); + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + void EigenDecomp(bool isSymmetric, int order, Complex32[] matrix, Complex32[] matrixEv, Complex[] vectorEv, Complex32[] matrixD); + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + void EigenDecomp(bool isSymmetric, int order, Complex[] matrix, Complex[] matrixEv, Complex[] vectorEv, Complex[] matrixD); } } diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs index 1e254853..ace87e43 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs @@ -3,7 +3,7 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -24,14 +24,14 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using MathNet.Numerics.LinearAlgebra.Generic.Factorization; - namespace MathNet.Numerics.Algorithms.LinearAlgebra { using System; using System.Numerics; using Properties; using Threading; + using Numerics.LinearAlgebra.Complex.Factorization; + using Numerics.LinearAlgebra.Generic.Factorization; /// /// The managed linear algebra provider. @@ -108,7 +108,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (var index = 0; index < x.Length; index++) { - result[index] = y[index] + (alpha * x[index]); + result[index] = y[index] + (alpha*x[index]); } } } @@ -152,7 +152,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (var index = 0; index < x.Length; index++) { - result[index] = alpha * x[index]; + result[index] = alpha*x[index]; } } } @@ -185,7 +185,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var dot = Complex.Zero; for (var index = 0; index < y.Length; index++) { - dot += y[index] * x[index]; + dot += y[index]*x[index]; } return dot; @@ -339,7 +339,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (var index = 0; index < x.Length; index++) { - result[index] = x[index] * y[index]; + result[index] = x[index]*y[index]; } } } @@ -390,7 +390,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (var index = 0; index < x.Length; index++) { - result[index] = x[index] / y[index]; + result[index] = x[index]/y[index]; } } } @@ -416,7 +416,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var s = 0.0; for (var i = 0; i < rows; i++) { - s += matrix[(j * rows) + i].Magnitude; + s += matrix[(j*rows) + i].Magnitude; } ret = Math.Max(ret, s); @@ -429,7 +429,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (var j = 0; j < columns; j++) { - ret = Math.Max(matrix[(j * rows) + i].Magnitude, ret); + ret = Math.Max(matrix[(j*rows) + i].Magnitude, ret); } } @@ -440,7 +440,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var s = 0.0; for (var j = 0; j < columns; j++) { - s += matrix[(j * rows) + i].Magnitude; + s += matrix[(j*rows) + i].Magnitude; } ret = Math.Max(ret, s); @@ -448,12 +448,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra break; case Norm.FrobeniusNorm: - var aat = new Complex[rows * rows]; + var aat = new Complex[rows*rows]; MatrixMultiplyWithUpdate(Transpose.DontTranspose, Transpose.ConjugateTranspose, 1.0, matrix, rows, columns, matrix, rows, columns, 0.0, aat); for (var i = 0; i < rows; i++) { - ret += aat[(i * rows) + i].Magnitude; + ret += aat[(i*rows) + i].Magnitude; } ret = Math.Sqrt(ret); @@ -510,12 +510,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("result"); } - if (rowsX * columnsX != x.Length) + if (rowsX*columnsX != x.Length) { throw new ArgumentException("x.Length != xRows * xColumns"); } - if (rowsY * columnsY != y.Length) + if (rowsY*columnsY != y.Length) { throw new ArgumentException("y.Length != yRows * yColumns"); } @@ -525,7 +525,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException("xColumns != yRows"); } - if (rowsX * columnsY != result.Length) + if (rowsX*columnsY != result.Length) { throw new ArgumentException("xRows * yColumns != result.Length"); } @@ -536,7 +536,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra Complex[] xdata; if (ReferenceEquals(x, result)) { - xdata = (Complex[])x.Clone(); + xdata = (Complex[]) x.Clone(); } else { @@ -546,7 +546,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra Complex[] ydata; if (ReferenceEquals(y, result)) { - ydata = (Complex[])y.Clone(); + ydata = (Complex[]) y.Clone(); } else { @@ -587,14 +587,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("b"); } - if ((int)transposeA > 111 && (int)transposeB > 111) + if ((int) transposeA > 111 && (int) transposeB > 111) { if (rowsA != columnsB) { throw new ArgumentOutOfRangeException(); } - if (columnsA * rowsB != c.Length) + if (columnsA*rowsB != c.Length) { throw new ArgumentOutOfRangeException(); } @@ -603,14 +603,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra n = rowsB; k = rowsA; } - else if ((int)transposeA > 111) + else if ((int) transposeA > 111) { if (rowsA != rowsB) { throw new ArgumentOutOfRangeException(); } - if (columnsA * columnsB != c.Length) + if (columnsA*columnsB != c.Length) { throw new ArgumentOutOfRangeException(); } @@ -619,14 +619,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra n = columnsB; k = rowsA; } - else if ((int)transposeB > 111) + else if ((int) transposeB > 111) { if (columnsA != columnsB) { throw new ArgumentOutOfRangeException(); } - if (rowsA * rowsB != c.Length) + if (rowsA*rowsB != c.Length) { throw new ArgumentOutOfRangeException(); } @@ -642,7 +642,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentOutOfRangeException(); } - if (rowsA * columnsB != c.Length) + if (rowsA*columnsB != c.Length) { throw new ArgumentOutOfRangeException(); } @@ -664,7 +664,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra Complex[] adata; if (ReferenceEquals(a, c)) { - adata = (Complex[])a.Clone(); + adata = (Complex[]) a.Clone(); } else { @@ -674,7 +674,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra Complex[] bdata; if (ReferenceEquals(b, c)) { - bdata = (Complex[])b.Clone(); + bdata = (Complex[]) b.Clone(); } else { @@ -720,13 +720,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// The constant number of columns of matrix op(B) and of the matrix C. /// The constant number of columns of matrix op(A) and the rows of the matrix op(B). /// Indicates if this is the first recursion. - private static void CacheObliviousMatrixMultiply(Transpose transposeA, Transpose transposeB, Complex alpha, Complex[] matrixA, int shiftArow, int shiftAcol, Complex[] matrixB, int shiftBrow, int shiftBcol, Complex[] result, int shiftCrow, int shiftCcol, int m, int n, int k, int constM, int constN, int constK, bool first) + static void CacheObliviousMatrixMultiply(Transpose transposeA, Transpose transposeB, Complex alpha, Complex[] matrixA, int shiftArow, int shiftAcol, Complex[] matrixB, int shiftBrow, int shiftBcol, Complex[] result, int shiftCrow, int shiftCcol, int m, int n, int k, int constM, int constN, int constK, bool first) { if (m + n <= Control.ParallelizeOrder) { - if ((int)transposeA > 111 && (int)transposeB > 111) + if ((int) transposeA > 111 && (int) transposeB > 111) { - if ((int)transposeA > 112 && (int)transposeB > 112) + if ((int) transposeA > 112 && (int) transposeB > 112) { for (var m1 = 0; m1 < m; m1++) { @@ -738,15 +738,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = Complex.Zero; for (var k1 = 0; k1 < k; ++k1) { - sum += matrixA[(matArowPos * constK) + k1 + shiftAcol].Conjugate() * - matrixB[((k1 + shiftBrow) * constN) + matBcolPos].Conjugate(); + sum += matrixA[(matArowPos*constK) + k1 + shiftAcol].Conjugate()* + matrixB[((k1 + shiftBrow)*constN) + matBcolPos].Conjugate(); } - result[((n1 + shiftCcol) * constM) + matCrowPos] += alpha * sum; + result[((n1 + shiftCcol)*constM) + matCrowPos] += alpha*sum; } } } - else if ((int)transposeA > 112) + else if ((int) transposeA > 112) { for (var m1 = 0; m1 < m; m1++) { @@ -758,15 +758,15 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = Complex.Zero; for (var k1 = 0; k1 < k; ++k1) { - sum += matrixA[(matArowPos * constK) + k1 + shiftAcol].Conjugate() * - matrixB[((k1 + shiftBrow) * constN) + matBcolPos]; + sum += matrixA[(matArowPos*constK) + k1 + shiftAcol].Conjugate()* + matrixB[((k1 + shiftBrow)*constN) + matBcolPos]; } - result[((n1 + shiftCcol) * constM) + matCrowPos] += alpha * sum; + result[((n1 + shiftCcol)*constM) + matCrowPos] += alpha*sum; } } } - else if ((int)transposeB > 112) + else if ((int) transposeB > 112) { for (var m1 = 0; m1 < m; m1++) { @@ -778,11 +778,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = Complex.Zero; for (var k1 = 0; k1 < k; ++k1) { - sum += matrixA[(matArowPos * constK) + k1 + shiftAcol] * - matrixB[((k1 + shiftBrow) * constN) + matBcolPos].Conjugate(); + sum += matrixA[(matArowPos*constK) + k1 + shiftAcol]* + matrixB[((k1 + shiftBrow)*constN) + matBcolPos].Conjugate(); } - result[((n1 + shiftCcol) * constM) + matCrowPos] += alpha * sum; + result[((n1 + shiftCcol)*constM) + matCrowPos] += alpha*sum; } } } @@ -798,18 +798,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = Complex.Zero; for (var k1 = 0; k1 < k; ++k1) { - sum += matrixA[(matArowPos * constK) + k1 + shiftAcol] * - matrixB[((k1 + shiftBrow) * constN) + matBcolPos]; + sum += matrixA[(matArowPos*constK) + k1 + shiftAcol]* + matrixB[((k1 + shiftBrow)*constN) + matBcolPos]; } - result[((n1 + shiftCcol) * constM) + matCrowPos] += alpha * sum; + result[((n1 + shiftCcol)*constM) + matCrowPos] += alpha*sum; } - } + } } } - else if ((int)transposeA > 111) + else if ((int) transposeA > 111) { - if ((int)transposeA > 112) + if ((int) transposeA > 112) { for (var m1 = 0; m1 < m; m1++) { @@ -821,11 +821,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = Complex.Zero; for (var k1 = 0; k1 < k; ++k1) { - sum += matrixA[(matArowPos * constK) + k1 + shiftAcol].Conjugate() * - matrixB[(matBcolPos * constK) + k1 + shiftBrow]; + sum += matrixA[(matArowPos*constK) + k1 + shiftAcol].Conjugate()* + matrixB[(matBcolPos*constK) + k1 + shiftBrow]; } - result[((n1 + shiftCcol) * constM) + matCrowPos] += alpha * sum; + result[((n1 + shiftCcol)*constM) + matCrowPos] += alpha*sum; } } } @@ -841,18 +841,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = Complex.Zero; for (var k1 = 0; k1 < k; ++k1) { - sum += matrixA[(matArowPos * constK) + k1 + shiftAcol] * - matrixB[(matBcolPos * constK) + k1 + shiftBrow]; + sum += matrixA[(matArowPos*constK) + k1 + shiftAcol]* + matrixB[(matBcolPos*constK) + k1 + shiftBrow]; } - result[((n1 + shiftCcol) * constM) + matCrowPos] += alpha * sum; + result[((n1 + shiftCcol)*constM) + matCrowPos] += alpha*sum; } } } } - else if ((int)transposeB > 111) + else if ((int) transposeB > 111) { - if ((int)transposeB > 112) + if ((int) transposeB > 112) { for (var m1 = 0; m1 < m; m1++) { @@ -864,11 +864,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = Complex.Zero; for (var k1 = 0; k1 < k; ++k1) { - sum += matrixA[((k1 + shiftAcol) * constM) + matArowPos] * - matrixB[((k1 + shiftBrow) * constN) + matBcolPos].Conjugate(); + sum += matrixA[((k1 + shiftAcol)*constM) + matArowPos]* + matrixB[((k1 + shiftBrow)*constN) + matBcolPos].Conjugate(); } - result[((n1 + shiftCcol) * constM) + matCrowPos] += alpha * sum; + result[((n1 + shiftCcol)*constM) + matCrowPos] += alpha*sum; } } } @@ -884,11 +884,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = Complex.Zero; for (var k1 = 0; k1 < k; ++k1) { - sum += matrixA[((k1 + shiftAcol) * constM) + matArowPos] * - matrixB[((k1 + shiftBrow) * constN) + matBcolPos]; + sum += matrixA[((k1 + shiftAcol)*constM) + matArowPos]* + matrixB[((k1 + shiftBrow)*constN) + matBcolPos]; } - result[((n1 + shiftCcol) * constM) + matCrowPos] += alpha * sum; + result[((n1 + shiftCcol)*constM) + matCrowPos] += alpha*sum; } } } @@ -905,11 +905,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = Complex.Zero; for (var k1 = 0; k1 < k; ++k1) { - sum += matrixA[((k1 + shiftAcol) * constM) + matArowPos] * - matrixB[(matBcolPos * constK) + k1 + shiftBrow]; + sum += matrixA[((k1 + shiftAcol)*constM) + matArowPos]* + matrixB[(matBcolPos*constK) + k1 + shiftBrow]; } - result[((n1 + shiftCcol) * constM) + matCrowPos] += alpha * sum; + result[((n1 + shiftCcol)*constM) + matCrowPos] += alpha*sum; } } } @@ -917,7 +917,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra else { // divide and conquer - int m2 = m / 2, n2 = n / 2, k2 = k / 2; + int m2 = m/2, n2 = n/2, k2 = k/2; if (first) { @@ -971,7 +971,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("ipiv"); } - if (data.Length != order * order) + if (data.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "data"); } @@ -992,7 +992,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // Outer loop. for (var j = 0; j < order; j++) { - var indexj = j * order; + var indexj = j*order; var indexjj = indexj + j; // Make a copy of the j-th column to localize references. @@ -1009,7 +1009,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var s = Complex.Zero; for (var k = 0; k < kmax; k++) { - s += data[(k * order) + i] * vecLUcolj[k]; + s += data[(k*order) + i]*vecLUcolj[k]; } data[indexj + i] = vecLUcolj[i] -= s; @@ -1029,7 +1029,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (var k = 0; k < order; k++) { - var indexk = k * order; + var indexk = k*order; var indexkp = indexk + p; var indexkj = indexk + j; var temp = data[indexkp]; @@ -1064,7 +1064,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -1093,7 +1093,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -1106,7 +1106,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var inverse = new Complex[a.Length]; for (var i = 0; i < order; i++) { - inverse[i + (order * i)] = Complex.One; + inverse[i + (order*i)] = Complex.One; } LUSolveFactored(order, a, order, ipiv, inverse); @@ -1162,12 +1162,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("b"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (b.Length != order * columnsOfB) + if (b.Length != order*columnsOfB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -1210,7 +1210,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("b"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -1220,7 +1220,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (b.Length != order * columnsOfB) + if (b.Length != order*columnsOfB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -1241,7 +1241,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var p = ipiv[i]; for (var j = 0; j < columnsOfB; j++) { - var indexk = j * order; + var indexk = j*order; var indexkp = indexk + p; var indexkj = indexk + i; var temp = b[indexkp]; @@ -1253,13 +1253,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // Solve L*Y = P*B for (var k = 0; k < order; k++) { - var korder = k * order; + var korder = k*order; for (var i = k + 1; i < order; i++) { for (var j = 0; j < columnsOfB; j++) { - var index = j * order; - b[i + index] -= b[k + index] * a[i + korder]; + var index = j*order; + b[i + index] -= b[k + index]*a[i + korder]; } } } @@ -1267,19 +1267,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // Solve U*X = Y; for (var k = order - 1; k >= 0; k--) { - var korder = k + (k * order); + var korder = k + (k*order); for (var j = 0; j < columnsOfB; j++) { - b[k + (j * order)] /= a[korder]; + b[k + (j*order)] /= a[korder]; } - korder = k * order; + korder = k*order; for (var i = 0; i < k; i++) { for (var j = 0; j < columnsOfB; j++) { - var index = j * order; - b[i + index] -= b[k + index] * a[i + korder]; + var index = j*order; + b[i + index] -= b[k + index]*a[i + korder]; } } } @@ -1305,20 +1305,20 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra for (var ij = 0; ij < order; ij++) { // "Pivot" element - var tmpVal = a[(ij * order) + ij]; + var tmpVal = a[(ij*order) + ij]; if (tmpVal.Real > 0.0) { tmpVal = tmpVal.SquareRoot(); - a[(ij * order) + ij] = tmpVal; + a[(ij*order) + ij] = tmpVal; tmpColumn[ij] = tmpVal; // Calculate multipliers and copy to local column // Current column, below the diagonal for (var i = ij + 1; i < order; i++) { - a[(ij * order) + i] /= tmpVal; - tmpColumn[i] = a[(ij * order) + i]; + a[(ij*order) + i] /= tmpVal; + tmpColumn[i] = a[(ij*order) + i]; } // Remaining columns, below the diagonal @@ -1331,7 +1331,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra for (var i = ij + 1; i < order; i++) { - a[(i * order) + ij] = 0.0; + a[(i*order) + ij] = 0.0; } } } @@ -1345,14 +1345,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// Total columns /// Multipliers calculated previously /// Number of available processors - private static void DoCholeskyStep(Complex[] data, int rowDim, int firstCol, int colLimit, Complex[] multipliers, int availableCores) + static void DoCholeskyStep(Complex[] data, int rowDim, int firstCol, int colLimit, Complex[] multipliers, int availableCores) { var tmpColCount = colLimit - firstCol; if ((availableCores > 1) && (tmpColCount > Control.ParallelizeElements)) { - var tmpSplit = firstCol + (tmpColCount / 3); - var tmpCores = availableCores / 2; + var tmpSplit = firstCol + (tmpColCount/3); + var tmpCores = availableCores/2; CommonParallel.Invoke( () => DoCholeskyStep(data, rowDim, firstCol, tmpSplit, multipliers, tmpCores), @@ -1365,7 +1365,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var tmpVal = multipliers[j]; for (var i = j; i < rowDim; i++) { - data[(j * rowDim) + i] -= multipliers[i] * tmpVal.Conjugate(); + data[(j*rowDim) + i] -= multipliers[i]*tmpVal.Conjugate(); } } } @@ -1391,7 +1391,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -1427,7 +1427,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -1453,9 +1453,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// The number of rows and columns in A. /// On entry the B matrix; on exit the X matrix. /// The column to solve for. - private static void DoCholeskySolve(Complex[] a, int orderA, Complex[] b, int index) + static void DoCholeskySolve(Complex[] a, int orderA, Complex[] b, int index) { - var cindex = index * orderA; + var cindex = index*orderA; // Solve L*Y = B; Complex sum; @@ -1464,23 +1464,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra sum = b[cindex + i]; for (var k = i - 1; k >= 0; k--) { - sum -= a[(k * orderA) + i] * b[cindex + k]; + sum -= a[(k*orderA) + i]*b[cindex + k]; } - b[cindex + i] = sum / a[(i * orderA) + i]; + b[cindex + i] = sum/a[(i*orderA) + i]; } // Solve L'*X = Y; for (var i = orderA - 1; i >= 0; i--) { sum = b[cindex + i]; - var iindex = i * orderA; + var iindex = i*orderA; for (var k = i + 1; k < orderA; k++) { - sum -= a[iindex + k].Conjugate() * b[cindex + k]; + sum -= a[iindex + k].Conjugate()*b[cindex + k]; } - b[cindex + i] = sum / a[iindex + i]; + b[cindex + i] = sum/a[iindex + i]; } } @@ -1508,7 +1508,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("q"); } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -1518,12 +1518,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (q.Length != rowsR * rowsR) + if (q.Length != rowsR*rowsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - var work = columnsR > rowsR ? new Complex[rowsR * rowsR] : new Complex[rowsR * columnsR]; + var work = columnsR > rowsR ? new Complex[rowsR*rowsR] : new Complex[rowsR*columnsR]; QRFactor(r, rowsR, columnsR, q, tau, work); } @@ -1559,7 +1559,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("q"); } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -1569,24 +1569,24 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (q.Length != rowsR * rowsR) + if (q.Length != rowsR*rowsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } if (columnsR > rowsR) { - if (work.Length < rowsR * rowsR) + if (work.Length < rowsR*rowsR) { - work[0] = rowsR * rowsR; + work[0] = rowsR*rowsR; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } } else { - if (work.Length < rowsR * columnsR) + if (work.Length < rowsR*columnsR) { - work[0] = rowsR * columnsR; + work[0] = rowsR*columnsR; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } } @@ -1611,7 +1611,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra ComputeQR(work, i, q, i, rowsR, i, rowsR, Control.NumberOfParallelWorkerThreads); } - work[0] = columnsR > rowsR ? rowsR * rowsR : rowsR * columnsR; + work[0] = columnsR > rowsR ? rowsR*rowsR : rowsR*columnsR; } /// @@ -1638,7 +1638,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("a"); } - if (a.Length != rowsA * columnsA) + if (a.Length != rowsA*columnsA) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "a"); } @@ -1648,12 +1648,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (r.Length != columnsA * columnsA) + if (r.Length != columnsA*columnsA) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - var work = new Complex[rowsA * columnsA]; + var work = new Complex[rowsA*columnsA]; ThinQRFactor(a, rowsA, columnsA, r, tau, work); } @@ -1689,7 +1689,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("q"); } - if (a.Length != rowsA * columnsA) + if (a.Length != rowsA*columnsA) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "a"); } @@ -1699,14 +1699,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (r.Length != columnsA * columnsA) + if (r.Length != columnsA*columnsA) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - if (work.Length < rowsA * columnsA) + if (work.Length < rowsA*columnsA) { - work[0] = rowsA * columnsA; + work[0] = rowsA*columnsA; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -1720,8 +1720,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra //copy R for (var j = 0; j < columnsA; j++) { - var rIndex = j * columnsA; - var aIndex = j * rowsA; + var rIndex = j*columnsA; + var aIndex = j*rowsA; for (var i = 0; i < columnsA; i++) { r[rIndex + i] = a[aIndex + i]; @@ -1732,7 +1732,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra Array.Clear(a, 0, a.Length); for (var i = 0; i < columnsA; i++) { - a[i * rowsA + i] = Complex.One; + a[i*rowsA + i] = Complex.One; } for (var i = minmn - 1; i >= 0; i--) @@ -1740,7 +1740,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra ComputeQR(work, i, a, i, rowsA, i, columnsA, Control.NumberOfParallelWorkerThreads); } - work[0] = rowsA * columnsA; + work[0] = rowsA*columnsA; } @@ -1757,7 +1757,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// The first column /// The last column /// Number of available CPUs - private static void ComputeQR(Complex[] work, int workIndex, Complex[] a, int rowStart, int rowCount, int columnStart, int columnCount, int availableCores) + static void ComputeQR(Complex[] work, int workIndex, Complex[] a, int rowStart, int rowCount, int columnStart, int columnCount, int availableCores) { if (rowStart > rowCount || columnStart > columnCount) { @@ -1768,8 +1768,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if ((availableCores > 1) && (tmpColCount > 200)) { - var tmpSplit = columnStart + (tmpColCount / 2); - var tmpCores = availableCores / 2; + var tmpSplit = columnStart + (tmpColCount/2); + var tmpCores = availableCores/2; CommonParallel.Invoke( () => ComputeQR(work, workIndex, a, rowStart, rowCount, columnStart, tmpSplit, tmpCores), @@ -1782,12 +1782,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var scale = Complex.Zero; for (var i = rowStart; i < rowCount; i++) { - scale += work[(workIndex * rowCount) + i - rowStart] * a[(j * rowCount) + i]; + scale += work[(workIndex*rowCount) + i - rowStart]*a[(j*rowCount) + i]; } for (var i = rowStart; i < rowCount; i++) { - a[(j * rowCount) + i] -= work[(workIndex * rowCount) + i - rowStart].Conjugate() * scale; + a[(j*rowCount) + i] -= work[(workIndex*rowCount) + i - rowStart].Conjugate()*scale; } } } @@ -1801,9 +1801,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// The number of rows in matrix /// The first row /// Column index - private static void GenerateColumn(Complex[] work, Complex[] a, int rowCount, int row, int column) + static void GenerateColumn(Complex[] work, Complex[] a, int rowCount, int row, int column) { - var tmp = column * rowCount; + var tmp = column*rowCount; var index = tmp + row; CommonParallel.For(row, rowCount, (u, v) => @@ -1820,7 +1820,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra for (var i = 0; i < rowCount - row; ++i) { var index1 = tmp + i; - norm += work[index1].Magnitude * work[index1].Magnitude; + norm += work[index1].Magnitude*work[index1].Magnitude; } norm = norm.SquareRoot(); @@ -1833,7 +1833,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (work[tmp].Magnitude != 0.0) { - norm = norm.Magnitude * (work[tmp] / work[tmp].Magnitude); + norm = norm.Magnitude*(work[tmp]/work[tmp].Magnitude); } a[index] = -norm; @@ -1871,7 +1871,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra /// Rows must be greater or equal to columns. public virtual void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full) { - var work = new Complex[rows * columns]; + var work = new Complex[rows*columns]; QRSolve(a, rows, columns, b, columnsB, x, work, method); } @@ -1911,12 +1911,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("work"); } - if (a.Length != rows * columns) + if (a.Length != rows*columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (b.Length != rows * columnsB) + if (b.Length != rows*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -1926,14 +1926,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.RowsLessThanColumns); } - if (x.Length != columns * columnsB) + if (x.Length != columns*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "x"); } - if (work.Length < rows * columns) + if (work.Length < rows*columns) { - work[0] = rows * columns; + work[0] = rows*columns; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -1942,18 +1942,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (method == QRMethod.Full) { - var q = new Complex[rows * rows]; + var q = new Complex[rows*rows]; QRFactor(clone, rows, columns, q, work); QRSolveFactored(q, clone, rows, columns, null, b, columnsB, x, method); } else { - var r = new Complex[columns * columns]; + var r = new Complex[columns*columns]; ThinQRFactor(clone, rows, columns, r, work); QRSolveFactored(clone, r, rows, columns, null, b, columnsB, x, method); } - work[0] = rows * columns; + work[0] = rows*columns; } /// @@ -2141,12 +2141,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("vt"); } - if (u.Length != rowsA * rowsA) + if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - if (vt.Length != columnsA * columnsA) + if (vt.Length != columnsA*columnsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } @@ -2201,12 +2201,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("work"); } - if (u.Length != rowsA * rowsA) + if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - if (vt.Length != columnsA * columnsA) + if (vt.Length != columnsA*columnsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } @@ -2257,24 +2257,24 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var sum = 0.0; for (i = l; i < rowsA; i++) { - sum += a[(l * rowsA) + i].Magnitude * a[(l * rowsA) + i].Magnitude; + sum += a[(l*rowsA) + i].Magnitude*a[(l*rowsA) + i].Magnitude; } stemp[l] = Math.Sqrt(sum); if (stemp[l] != 0.0) { - if (a[(l * rowsA) + l] != 0.0) + if (a[(l*rowsA) + l] != 0.0) { - stemp[l] = stemp[l].Magnitude * (a[(l * rowsA) + l] / a[(l * rowsA) + l].Magnitude); + stemp[l] = stemp[l].Magnitude*(a[(l*rowsA) + l]/a[(l*rowsA) + l].Magnitude); } // A part of column "l" of Matrix A from row "l" to end multiply by 1.0 / s[l] for (i = l; i < rowsA; i++) { - a[(l * rowsA) + i] = a[(l * rowsA) + i] * (1.0 / stemp[l]); + a[(l*rowsA) + i] = a[(l*rowsA) + i]*(1.0/stemp[l]); } - a[(l * rowsA) + l] = 1.0 + a[(l * rowsA) + l]; + a[(l*rowsA) + l] = 1.0 + a[(l*rowsA) + l]; } stemp[l] = -stemp[l]; @@ -2290,21 +2290,21 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra t = 0.0; for (i = l; i < rowsA; i++) { - t += a[(l * rowsA) + i].Conjugate() * a[(j * rowsA) + i]; + t += a[(l*rowsA) + i].Conjugate()*a[(j*rowsA) + i]; } - t = -t / a[(l * rowsA) + l]; + t = -t/a[(l*rowsA) + l]; for (var ii = l; ii < rowsA; ii++) { - a[(j * rowsA) + ii] += t * a[(l * rowsA) + ii]; + a[(j*rowsA) + ii] += t*a[(l*rowsA) + ii]; } } } // Place the l-th row of matrix into "e" for the // subsequent calculation of the row transformation. - e[j] = a[(j * rowsA) + l].Conjugate(); + e[j] = a[(j*rowsA) + l].Conjugate(); } if (computeVectors && l < nct) @@ -2312,7 +2312,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // Place the transformation in "u" for subsequent back multiplication. for (i = l; i < rowsA; i++) { - u[(l * rowsA) + i] = a[(l * rowsA) + i]; + u[(l*rowsA) + i] = a[(l*rowsA) + i]; } } @@ -2325,7 +2325,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var enorm = 0.0; for (i = lp1; i < e.Length; i++) { - enorm += e[i].Magnitude * e[i].Magnitude; + enorm += e[i].Magnitude*e[i].Magnitude; } e[l] = Math.Sqrt(enorm); @@ -2333,13 +2333,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if (e[lp1] != 0.0) { - e[l] = e[l].Magnitude * (e[lp1] / e[lp1].Magnitude); + e[l] = e[l].Magnitude*(e[lp1]/e[lp1].Magnitude); } // Scale vector "e" from "lp1" by 1.0 / e[l] for (i = lp1; i < e.Length; i++) { - e[i] = e[i] * (1.0 / e[l]); + e[i] = e[i]*(1.0/e[l]); } e[lp1] = 1.0 + e[lp1]; @@ -2359,16 +2359,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (var ii = lp1; ii < rowsA; ii++) { - work[ii] += e[j] * a[(j * rowsA) + ii]; + work[ii] += e[j]*a[(j*rowsA) + ii]; } } for (j = lp1; j < columnsA; j++) { - var ww = (-e[j] / e[lp1]).Conjugate(); + var ww = (-e[j]/e[lp1]).Conjugate(); for (var ii = lp1; ii < rowsA; ii++) { - a[(j * rowsA) + ii] += ww * work[ii]; + a[(j*rowsA) + ii] += ww*work[ii]; } } } @@ -2381,7 +2381,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // Place the transformation in v for subsequent back multiplication. for (i = lp1; i < columnsA; i++) { - v[(l * columnsA) + i] = e[i]; + v[(l*columnsA) + i] = e[i]; } } @@ -2391,7 +2391,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var nrtp1 = nrt + 1; if (nct < columnsA) { - stemp[nctp1 - 1] = a[((nctp1 - 1) * rowsA) + (nctp1 - 1)]; + stemp[nctp1 - 1] = a[((nctp1 - 1)*rowsA) + (nctp1 - 1)]; } if (rowsA < m) @@ -2401,7 +2401,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (nrtp1 < m) { - e[nrtp1 - 1] = a[((m - 1) * rowsA) + (nrtp1 - 1)]; + e[nrtp1 - 1] = a[((m - 1)*rowsA) + (nrtp1 - 1)]; } e[m - 1] = 0.0; @@ -2413,10 +2413,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (i = 0; i < rowsA; i++) { - u[(j * rowsA) + i] = 0.0; + u[(j*rowsA) + i] = 0.0; } - u[(j * rowsA) + j] = 1.0; + u[(j*rowsA) + j] = 1.0; } for (l = nct - 1; l >= 0; l--) @@ -2428,36 +2428,36 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra t = 0.0; for (i = l; i < rowsA; i++) { - t += u[(l * rowsA) + i].Conjugate() * u[(j * rowsA) + i]; + t += u[(l*rowsA) + i].Conjugate()*u[(j*rowsA) + i]; } - t = -t / u[(l * rowsA) + l]; + t = -t/u[(l*rowsA) + l]; for (var ii = l; ii < rowsA; ii++) { - u[(j * rowsA) + ii] += t * u[(l * rowsA) + ii]; + u[(j*rowsA) + ii] += t*u[(l*rowsA) + ii]; } } // A part of column "l" of matrix A from row "l" to end multiply by -1.0 for (i = l; i < rowsA; i++) { - u[(l * rowsA) + i] = u[(l * rowsA) + i] * -1.0; + u[(l*rowsA) + i] = u[(l*rowsA) + i]*-1.0; } - u[(l * rowsA) + l] = 1.0 + u[(l * rowsA) + l]; + u[(l*rowsA) + l] = 1.0 + u[(l*rowsA) + l]; for (i = 0; i < l; i++) { - u[(l * rowsA) + i] = 0.0; + u[(l*rowsA) + i] = 0.0; } } else { for (i = 0; i < rowsA; i++) { - u[(l * rowsA) + i] = 0.0; + u[(l*rowsA) + i] = 0.0; } - u[(l * rowsA) + l] = 1.0; + u[(l*rowsA) + l] = 1.0; } } } @@ -2477,13 +2477,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra t = 0.0; for (i = lp1; i < columnsA; i++) { - t += v[(l * columnsA) + i].Conjugate() * v[(j * columnsA) + i]; + t += v[(l*columnsA) + i].Conjugate()*v[(j*columnsA) + i]; } - t = -t / v[(l * columnsA) + lp1]; + t = -t/v[(l*columnsA) + lp1]; for (var ii = l; ii < columnsA; ii++) { - v[(j * columnsA) + ii] += t * v[(l * columnsA) + ii]; + v[(j*columnsA) + ii] += t*v[(l*columnsA) + ii]; } } } @@ -2491,10 +2491,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra for (i = 0; i < columnsA; i++) { - v[(l * columnsA) + i] = 0.0; + v[(l*columnsA) + i] = 0.0; } - v[(l * columnsA) + l] = 1.0; + v[(l*columnsA) + l] = 1.0; } } @@ -2505,11 +2505,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (stemp[i] != 0.0) { t = stemp[i].Magnitude; - r = stemp[i] / t; + r = stemp[i]/t; stemp[i] = t; if (i < m - 1) { - e[i] = e[i] / r; + e[i] = e[i]/r; } if (computeVectors) @@ -2517,7 +2517,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // A part of column "i" of matrix U from row 0 to end multiply by r for (j = 0; j < rowsA; j++) { - u[(i * rowsA) + j] = u[(i * rowsA) + j] * r; + u[(i*rowsA) + j] = u[(i*rowsA) + j]*r; } } } @@ -2534,9 +2534,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } t = e[i].Magnitude; - r = t / e[i]; + r = t/e[i]; e[i] = t; - stemp[i + 1] = stemp[i + 1] * r; + stemp[i + 1] = stemp[i + 1]*r; if (!computeVectors) { continue; @@ -2545,7 +2545,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // A part of column "i+1" of matrix VT from row 0 to end multiply by r for (j = 0; j < columnsA; j++) { - v[((i + 1) * columnsA) + j] = v[((i + 1) * columnsA) + j] * r; + v[((i + 1)*columnsA) + j] = v[((i + 1)*columnsA) + j]*r; } } @@ -2632,7 +2632,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra double f; switch (kase) { - // Deflate negligible s[m]. + // Deflate negligible s[m]. case 1: f = e[m - 2].Real; e[m - 2] = 0.0; @@ -2645,8 +2645,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra stemp[k] = t1; if (k != l) { - f = -sn * e[k - 1].Real; - e[k - 1] = cs * e[k - 1]; + f = -sn*e[k - 1].Real; + e[k - 1] = cs*e[k - 1]; } if (computeVectors) @@ -2654,16 +2654,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // Rotate for (i = 0; i < columnsA; i++) { - var z = (cs * v[(k * columnsA) + i]) + (sn * v[((m - 1) * columnsA) + i]); - v[((m - 1) * columnsA) + i] = (cs * v[((m - 1) * columnsA) + i]) - (sn * v[(k * columnsA) + i]); - v[(k * columnsA) + i] = z; + var z = (cs*v[(k*columnsA) + i]) + (sn*v[((m - 1)*columnsA) + i]); + v[((m - 1)*columnsA) + i] = (cs*v[((m - 1)*columnsA) + i]) - (sn*v[(k*columnsA) + i]); + v[(k*columnsA) + i] = z; } } } break; - // Split at negligible s[l]. + // Split at negligible s[l]. case 2: f = e[l - 1].Real; e[l - 1] = 0.0; @@ -2672,23 +2672,23 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra t1 = stemp[k].Real; Drotg(ref t1, ref f, ref cs, ref sn); stemp[k] = t1; - f = -sn * e[k].Real; - e[k] = cs * e[k]; + f = -sn*e[k].Real; + e[k] = cs*e[k]; if (computeVectors) { // Rotate for (i = 0; i < rowsA; i++) { - var z = (cs * u[(k * rowsA) + i]) + (sn * u[((l - 1) * rowsA) + i]); - u[((l - 1) * rowsA) + i] = (cs * u[((l - 1) * rowsA) + i]) - (sn * u[(k * rowsA) + i]); - u[(k * rowsA) + i] = z; + var z = (cs*u[(k*rowsA) + i]) + (sn*u[((l - 1)*rowsA) + i]); + u[((l - 1)*rowsA) + i] = (cs*u[((l - 1)*rowsA) + i]) - (sn*u[(k*rowsA) + i]); + u[(k*rowsA) + i] = z; } } } break; - // Perform one qr step. + // Perform one qr step. case 3: // calculate the shift. var scale = 0.0; @@ -2697,27 +2697,27 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra scale = Math.Max(scale, e[m - 2].Magnitude); scale = Math.Max(scale, stemp[l].Magnitude); scale = Math.Max(scale, e[l].Magnitude); - var sm = stemp[m - 1].Real / scale; - var smm1 = stemp[m - 2].Real / scale; - var emm1 = e[m - 2].Real / scale; - var sl = stemp[l].Real / scale; - var el = e[l].Real / scale; - var b = (((smm1 + sm) * (smm1 - sm)) + (emm1 * emm1)) / 2.0; - var c = (sm * emm1) * (sm * emm1); + var sm = stemp[m - 1].Real/scale; + var smm1 = stemp[m - 2].Real/scale; + var emm1 = e[m - 2].Real/scale; + var sl = stemp[l].Real/scale; + var el = e[l].Real/scale; + var b = (((smm1 + sm)*(smm1 - sm)) + (emm1*emm1))/2.0; + var c = (sm*emm1)*(sm*emm1); var shift = 0.0; if (b != 0.0 || c != 0.0) { - shift = Math.Sqrt((b * b) + c); + shift = Math.Sqrt((b*b) + c); if (b < 0.0) { shift = -shift; } - shift = c / (b + shift); + shift = c/(b + shift); } - f = ((sl + sm) * (sl - sm)) + shift; - var g = sl * el; + f = ((sl + sm)*(sl - sm)) + shift; + var g = sl*el; // Chase zeros for (k = l; k < m - 1; k++) @@ -2728,33 +2728,33 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra e[k - 1] = f; } - f = (cs * stemp[k].Real) + (sn * e[k].Real); - e[k] = (cs * e[k]) - (sn * stemp[k]); - g = sn * stemp[k + 1].Real; - stemp[k + 1] = cs * stemp[k + 1]; + f = (cs*stemp[k].Real) + (sn*e[k].Real); + e[k] = (cs*e[k]) - (sn*stemp[k]); + g = sn*stemp[k + 1].Real; + stemp[k + 1] = cs*stemp[k + 1]; if (computeVectors) { for (i = 0; i < columnsA; i++) { - var z = (cs * v[(k * columnsA) + i]) + (sn * v[((k + 1) * columnsA) + i]); - v[((k + 1) * columnsA) + i] = (cs * v[((k + 1) * columnsA) + i]) - (sn * v[(k * columnsA) + i]); - v[(k * columnsA) + i] = z; + var z = (cs*v[(k*columnsA) + i]) + (sn*v[((k + 1)*columnsA) + i]); + v[((k + 1)*columnsA) + i] = (cs*v[((k + 1)*columnsA) + i]) - (sn*v[(k*columnsA) + i]); + v[(k*columnsA) + i] = z; } } Drotg(ref f, ref g, ref cs, ref sn); stemp[k] = f; - f = (cs * e[k].Real) + (sn * stemp[k + 1].Real); - stemp[k + 1] = -(sn * e[k]) + (cs * stemp[k + 1]); - g = sn * e[k + 1].Real; - e[k + 1] = cs * e[k + 1]; + f = (cs*e[k].Real) + (sn*stemp[k + 1].Real); + stemp[k + 1] = -(sn*e[k]) + (cs*stemp[k + 1]); + g = sn*e[k + 1].Real; + e[k + 1] = cs*e[k + 1]; if (computeVectors && k < rowsA) { for (i = 0; i < rowsA; i++) { - var z = (cs * u[(k * rowsA) + i]) + (sn * u[((k + 1) * rowsA) + i]); - u[((k + 1) * rowsA) + i] = (cs * u[((k + 1) * rowsA) + i]) - (sn * u[(k * rowsA) + i]); - u[(k * rowsA) + i] = z; + var z = (cs*u[(k*rowsA) + i]) + (sn*u[((k + 1)*rowsA) + i]); + u[((k + 1)*rowsA) + i] = (cs*u[((k + 1)*rowsA) + i]) - (sn*u[(k*rowsA) + i]); + u[(k*rowsA) + i] = z; } } } @@ -2763,7 +2763,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra iter = iter + 1; break; - // Convergence + // Convergence case 4: // Make the singular value positive @@ -2775,7 +2775,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // A part of column "l" of matrix VT from row 0 to end multiply by -1 for (i = 0; i < columnsA; i++) { - v[(l * columnsA) + i] = v[(l * columnsA) + i] * -1.0; + v[(l*columnsA) + i] = v[(l*columnsA) + i]*-1.0; } } } @@ -2796,9 +2796,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // Swap columns l, l + 1 for (i = 0; i < columnsA; i++) { - var z = v[(l * columnsA) + i]; - v[(l * columnsA) + i] = v[((l + 1) * columnsA) + i]; - v[((l + 1) * columnsA) + i] = z; + var z = v[(l*columnsA) + i]; + v[(l*columnsA) + i] = v[((l + 1)*columnsA) + i]; + v[((l + 1)*columnsA) + i] = z; } } @@ -2807,9 +2807,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // Swap columns l, l + 1 for (i = 0; i < rowsA; i++) { - var z = u[(l * rowsA) + i]; - u[(l * rowsA) + i] = u[((l + 1) * rowsA) + i]; - u[((l + 1) * rowsA) + i] = z; + var z = u[(l*rowsA) + i]; + u[(l*rowsA) + i] = u[((l + 1)*rowsA) + i]; + u[((l + 1)*rowsA) + i] = z; } } @@ -2829,7 +2829,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (j = 0; j < columnsA; j++) { - vt[(j * columnsA) + i] = v[(i * columnsA) + j].Conjugate(); + vt[(j*columnsA) + i] = v[(i*columnsA) + j].Conjugate(); } } } @@ -2841,7 +2841,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra // On return the first element of the work array stores the min size of the work array could have been // work[0] = Math.Max(3 * Math.Min(aRows, aColumns) + Math.Max(aRows, aColumns), 5 * Math.Min(aRows, aColumns)); - work[0] = rowsA; + work[0] = rowsA; } /// @@ -2870,25 +2870,25 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("x"); } - if (b.Length != rowsA * columnsB) + if (b.Length != rowsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - if (x.Length != columnsA * columnsB) + if (x.Length != columnsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } var work = new Complex[rowsA]; var s = new Complex[Math.Min(rowsA, columnsA)]; - var u = new Complex[rowsA * rowsA]; - var vt = new Complex[columnsA * columnsA]; + var u = new Complex[rowsA*rowsA]; + var vt = new Complex[columnsA*columnsA]; var clone = new Complex[a.Length]; a.Copy(clone); SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); - SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); + SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } /// @@ -2929,12 +2929,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentNullException("x"); } - if (u.Length != rowsA * rowsA) + if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - if (vt.Length != columnsA * columnsA) + if (vt.Length != columnsA*columnsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } @@ -2944,12 +2944,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - if (b.Length != rowsA * columnsB) + if (b.Length != rowsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - if (x.Length != columnsA * columnsB) + if (x.Length != columnsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -2966,7 +2966,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { for (var i = 0; i < rowsA; i++) { - value += u[(j * rowsA) + i].Conjugate() * b[(k * rowsA) + i]; + value += u[(j*rowsA) + i].Conjugate()*b[(k*rowsA) + i]; } value /= s[j]; @@ -2980,12 +2980,92 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra var value = Complex.Zero; for (var i = 0; i < columnsA; i++) { - value += vt[(j * columnsA) + i].Conjugate() * tmp[i]; + value += vt[(j*columnsA) + i].Conjugate()*tmp[i]; } - x[(k * columnsA) + j] = value; + x[(k*columnsA) + j] = value; + } + } + } + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + public virtual void EigenDecomp(bool isSymmetric, int order, Complex[] matrix, Complex[] matrixEv, Complex[] vectorEv, Complex[] matrixD) + { + if (matrix == null) + { + throw new ArgumentNullException("matrix"); + } + + if (matrix.Length != order * order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrix"); + } + + if (matrixEv == null) + { + throw new ArgumentNullException("matrixEv"); + } + + if (matrixEv.Length != order * order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixEv"); + } + + if (vectorEv == null) + { + throw new ArgumentNullException("vectorEv"); + } + + if (vectorEv.Length != order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order), "vectorEv"); + } + + if (matrixD == null) + { + throw new ArgumentNullException("matrixD"); + } + + if (matrixD.Length != order * order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); + } + var matrixCopy = new Complex[matrix.Length]; + Array.Copy(matrix, matrixCopy, matrix.Length); + + if (isSymmetric) + { + var tau = new Complex[order]; + var d = new double[order]; + var e = new double[order]; + + DenseEvd.SymmetricTridiagonalize(matrixCopy, d, e, tau, order); + DenseEvd.SymmetricDiagonalize(matrixEv, d, e, order); + DenseEvd.SymmetricUntridiagonalize(matrixEv, matrixCopy, tau, order); + + for (var i = 0; i < order; i++) + { + vectorEv[i] = new Complex(d[i], e[i]); } } + else + { + DenseEvd.NonsymmetricReduceToHessenberg(matrixEv, matrixCopy, order); + DenseEvd.NonsymmetricReduceHessenberToRealSchur(vectorEv, matrixEv, matrixCopy, order); + } + + for (var i = 0; i < order; i ++) + { + matrixD[i * order + i] = vectorEv[i]; + } } } } diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs index 06421f48..038ce62d 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs @@ -3,7 +3,7 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -24,14 +24,15 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using System.Numerics; -using MathNet.Numerics.LinearAlgebra.Generic.Factorization; - namespace MathNet.Numerics.Algorithms.LinearAlgebra { using System; using Properties; using Threading; + using System.Numerics; + using Numerics.LinearAlgebra.Complex32.Factorization; + using Numerics.LinearAlgebra.Generic.Factorization; + using Numerics.LinearAlgebra.Complex32; /// /// The managed linear algebra provider. @@ -2984,5 +2985,87 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } } } + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + public virtual void EigenDecomp(bool isSymmetric, int order, Complex32[] matrix, Complex32[] matrixEv, Complex[] vectorEv, Complex32[] matrixD) + { + if (matrix == null) + { + throw new ArgumentNullException("matrix"); + } + + if (matrix.Length != order * order ) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrix"); + } + + if (matrixEv == null) + { + throw new ArgumentNullException("matrixEv"); + } + + if (matrixEv.Length != order * order ) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixEv"); + } + + if (vectorEv == null) + { + throw new ArgumentNullException("vectorEv"); + } + + if (vectorEv.Length != order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order), "vectorEv"); + } + + if (matrixD == null) + { + throw new ArgumentNullException("matrixD"); + } + + if (matrixD.Length != order * order ) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); + } + + var matrixCopy = new Complex32[matrix.Length]; + Array.Copy(matrix, matrixCopy, matrix.Length); + var v = new DenseVector(order); + if (isSymmetric) + { + var tau = new Complex32[order]; + var d = new float[order]; + var e = new float[order]; + + DenseEvd.SymmetricTridiagonalize(matrixCopy, d, e, tau, order); + DenseEvd.SymmetricDiagonalize(matrixEv, d, e, order); + DenseEvd.SymmetricUntridiagonalize(matrixEv, matrixCopy, tau, order); + + for (var i = 0; i < order; i++) + { + vectorEv[i] = new Complex(d[i], e[i]); + matrixD[i * order + i] = new Complex32(d[i], e[i]); + } + } + else + { + DenseEvd.NonsymmetricReduceToHessenberg(matrixEv, matrixCopy, order); + DenseEvd.NonsymmetricReduceHessenberToRealSchur(v.Values, matrixEv, matrixCopy, order); + for (var i = 0; i < order; i++) + { + vectorEv[i] = new Complex(v[i].Real, v[i].Imaginary); + matrixD[i * order + i] = v[i]; + } + } + } } } diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs index 5f8c9b01..a6f28baa 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs @@ -3,7 +3,7 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -24,11 +24,11 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using MathNet.Numerics.LinearAlgebra.Generic.Factorization; - namespace MathNet.Numerics.Algorithms.LinearAlgebra { using System; + using System.Numerics; + using Numerics.LinearAlgebra.Generic.Factorization; using Properties; using Threading; @@ -2933,5 +2933,98 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } } } + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + public virtual void EigenDecomp(bool isSymmetric, int order, double[] matrix, double[] matrixEv, Complex[] vectorEv, double[] matrixD) + { + if (matrix == null) + { + throw new ArgumentNullException("matrix"); + } + + if (matrix.Length != order * order ) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrix"); + } + + if (matrixEv == null) + { + throw new ArgumentNullException("matrixEv"); + } + + if (matrixEv.Length != order * order ) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixEv"); + } + + if (vectorEv == null) + { + throw new ArgumentNullException("vectorEv"); + } + + if (vectorEv.Length != order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order), "vectorEv"); + } + + if (matrixD == null) + { + throw new ArgumentNullException("matrixD"); + } + + if (matrixD.Length != order * order ) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); + } + + var d = new double[order]; + var e = new double[order]; + + if (isSymmetric) + { + Buffer.BlockCopy(matrix, 0, matrixEv, 0, matrix.Length * Constants.SizeOfDouble); + var om1 = order - 1; + for (var i = 0; i < order; i++) + { + d[i] = matrixEv[i*order + om1]; + } + + Numerics.LinearAlgebra.Double.Factorization.DenseEvd.SymmetricTridiagonalize(matrixEv, d, e, order); + Numerics.LinearAlgebra.Double.Factorization.DenseEvd.SymmetricDiagonalize(matrixEv, d, e, order); + } + else + { + var matrixH = new double[matrix.Length]; + Buffer.BlockCopy(matrix, 0, matrixH, 0, matrix.Length * Constants.SizeOfDouble); + Numerics.LinearAlgebra.Double.Factorization.DenseEvd.NonsymmetricReduceToHessenberg(matrixEv, matrixH, order); + Numerics.LinearAlgebra.Double.Factorization.DenseEvd.NonsymmetricReduceHessenberToRealSchur(matrixEv, matrixH, d, e, order); + } + + for (var i = 0; i < order; i++) + { + vectorEv[i] = new Complex(d[i], e[i]); + + var io = i * order; + matrixD[io + i] = d[i]; + + if (e[i] > 0) + { + matrixD[io + order + i] = e[i]; + matrixD[(i+1) * order + i] = e[i]; + } + else if (e[i] < 0) + { + matrixD[io - order + i] = e[i]; + } + } + } } } diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs index 46402b52..dc32bdd4 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs @@ -3,7 +3,7 @@ // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without @@ -24,11 +24,11 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using MathNet.Numerics.LinearAlgebra.Generic.Factorization; - namespace MathNet.Numerics.Algorithms.LinearAlgebra { using System; + using System.Numerics; + using Numerics.LinearAlgebra.Generic.Factorization; using Properties; using Threading; @@ -2936,5 +2936,97 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } } } + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + public virtual void EigenDecomp(bool isSymmetric, int order, float[] matrix, float[] matrixEv, Complex[] vectorEv, float[] matrixD) + { + if (matrix == null) + { + throw new ArgumentNullException("matrix"); + } + + if (matrix.Length != order * order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrix"); + } + + if (matrixEv == null) + { + throw new ArgumentNullException("matrixEv"); + } + + if (matrixEv.Length != order * order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixEv"); + } + + if (vectorEv == null) + { + throw new ArgumentNullException("vectorEv"); + } + + if (vectorEv.Length != order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order), "vectorEv"); + } + + if (matrixD == null) + { + throw new ArgumentNullException("matrixD"); + } + + if (matrixD.Length != order * order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); + } + + var d = new float[order]; + var e = new float[order]; + + if (isSymmetric) + { + Buffer.BlockCopy(matrix, 0, matrixEv, 0, matrix.Length * Constants.SizeOfFloat); + var om1 = order - 1; + for (var i = 0; i < order; i++) + { + d[i] = matrixEv[i * order + om1]; + } + + Numerics.LinearAlgebra.Single.Factorization.DenseEvd.SymmetricTridiagonalize(matrixEv, d, e, order); + Numerics.LinearAlgebra.Single.Factorization.DenseEvd.SymmetricDiagonalize(matrixEv, d, e, order); + } + else + { + var matrixH = new float[matrix.Length]; + Buffer.BlockCopy(matrix, 0, matrixH, 0, matrix.Length * Constants.SizeOfFloat); + Numerics.LinearAlgebra.Single.Factorization.DenseEvd.NonsymmetricReduceToHessenberg(matrixEv, matrixH, order); + Numerics.LinearAlgebra.Single.Factorization.DenseEvd.NonsymmetricReduceHessenberToRealSchur(matrixEv, matrixH, d, e, order); + } + + for (var i = 0; i < order; i++) + { + vectorEv[i] = new Complex(d[i], e[i]); + + var io = i * order; + matrixD[io + i] = d[i]; + + if (e[i] > 0) + { + matrixD[io + order + i] = e[i]; + } + else if (e[i] < 0) + { + matrixD[io - order + i] = e[i]; + } + } + } } } diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs index feaf09cb..20752b09 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2011 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs index f1455621..9ef81835 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2011 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -28,14 +28,13 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using MathNet.Numerics.LinearAlgebra.Generic.Factorization; - namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { using System; using System.Security; + using Numerics.LinearAlgebra.Generic.Factorization; using Properties; - + /// /// Intel's Math Kernel Library (MKL) linear algebra provider. /// @@ -68,7 +67,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl return SafeNativeMethods.c_dot_product(x.Length, x, y); } - + /// /// Adds a scaled vector to another: result = y + alpha*x. /// @@ -121,8 +120,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl if (x == null) { throw new ArgumentNullException("x"); - } - + } + if (!ReferenceEquals(x, result)) { Array.Copy(x, 0, result, 0, x.Length); @@ -190,9 +189,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl var k = transposeA == Transpose.DontTranspose ? columnsA : rowsA; var l = transposeB == Transpose.DontTranspose ? rowsB : columnsB; - if (c.Length != m * n) + if (c.Length != m*n) { - throw new ArgumentException(Resources.ArgumentMatrixDimensions); + throw new ArgumentException(Resources.ArgumentMatrixDimensions); } if (k != l) @@ -225,7 +224,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (data.Length != order * order) + if (data.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "data"); } @@ -234,7 +233,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - + SafeNativeMethods.c_lu_factor(order, data, ipiv); } @@ -252,13 +251,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } var work = new Complex32[order]; - SafeNativeMethods.c_lu_inverse(order, a, work, work.Length); + SafeNativeMethods.c_lu_inverse(order, a, work, work.Length); } /// @@ -281,7 +280,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -292,7 +291,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl } var work = new Complex32[order]; - SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv, work, order); + SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv, work, order); } /// @@ -312,7 +311,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -327,7 +326,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } - SafeNativeMethods.c_lu_inverse(order, a, work, work.Length); + SafeNativeMethods.c_lu_inverse(order, a, work, work.Length); } /// @@ -353,7 +352,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -373,7 +372,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } - SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv, work, order); + SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv, work, order); } /// @@ -392,22 +391,22 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - + if (ReferenceEquals(a, b)) { throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_lu_solve(order, columnsOfB, a, b); + SafeNativeMethods.c_lu_solve(order, columnsOfB, a, b); } /// @@ -432,7 +431,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -442,7 +441,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -452,7 +451,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_lu_solve_factored(order, columnsOfB, a, ipiv, b); + SafeNativeMethods.c_lu_solve_factored(order, columnsOfB, a, ipiv, b); } /// @@ -475,7 +474,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -510,7 +509,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -520,7 +519,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_cholesky_solve(orderA, columnsB, a, b); + SafeNativeMethods.c_cholesky_solve(orderA, columnsB, a, b); } /// @@ -544,7 +543,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -554,7 +553,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_cholesky_solve_factored(orderA, columnsB, a, b); + SafeNativeMethods.c_cholesky_solve_factored(orderA, columnsB, a, b); } /// @@ -582,7 +581,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -592,12 +591,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (q.Length != rowsR * rowsR) + if (q.Length != rowsR*rowsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - var work = new Complex32[columnsR * Control.BlockSize]; + var work = new Complex32[columnsR*Control.BlockSize]; SafeNativeMethods.c_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } @@ -634,7 +633,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("work"); } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -644,14 +643,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (q.Length != rowsR * rowsR) + if (q.Length != rowsR*rowsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - if (work.Length < columnsR * Control.BlockSize) + if (work.Length < columnsR*Control.BlockSize) { - work[0] = columnsR * Control.BlockSize; + work[0] = columnsR*Control.BlockSize; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -672,7 +671,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl [SecuritySafeCritical] public override void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full) { - var work = new Complex32[columns * Control.BlockSize]; + var work = new Complex32[columns*Control.BlockSize]; QRSolve(a, rows, columns, b, columnsB, x, work, method); } @@ -713,17 +712,17 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("work"); } - if (a.Length != rows * columns) + if (a.Length != rows*columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (b.Length != rows * columnsB) + if (b.Length != rows*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - if (x.Length != columns * columnsB) + if (x.Length != columns*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "x"); } @@ -735,7 +734,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl if (work.Length < 1) { - work[0] = rows * Control.BlockSize; + work[0] = rows*Control.BlockSize; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -759,7 +758,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl [SecuritySafeCritical] public override void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsR, int columnsR, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full) { - var work = new Complex32[columnsR * Control.BlockSize]; + var work = new Complex32[columnsR*Control.BlockSize]; QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); } @@ -821,29 +820,29 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl columnsQ = rowsR = columnsR = columnsA; } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR*columnsR), "r"); } - if (q.Length != rowsQ * columnsQ) + if (q.Length != rowsQ*columnsQ) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ*columnsQ), "q"); } - if (b.Length != rowsA * columnsB) + if (b.Length != rowsA*columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA*columnsB), "b"); } - if (x.Length != columnsA * columnsB) + if (x.Length != columnsA*columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA*columnsB), "x"); } if (work.Length < 1) { - work[0] = rowsA * Control.BlockSize; + work[0] = rowsA*Control.BlockSize; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -895,12 +894,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("vt"); } - if (u.Length != rowsA * rowsA) + if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - if (vt.Length != columnsA * columnsA) + if (vt.Length != columnsA*columnsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } @@ -910,7 +909,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - var work = new Complex32[(2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; + var work = new Complex32[(2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); } @@ -940,20 +939,20 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("x"); } - if (b.Length != rowsA * columnsB) + if (b.Length != rowsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - if (x.Length != columnsA * columnsB) + if (x.Length != columnsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - var work = new Complex32[(2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; + var work = new Complex32[(2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; var s = new Complex32[Math.Min(rowsA, columnsA)]; - var u = new Complex32[rowsA * rowsA]; - var vt = new Complex32[columnsA * columnsA]; + var u = new Complex32[rowsA*rowsA]; + var vt = new Complex32[columnsA*columnsA]; var clone = new Complex32[a.Length]; a.Copy(clone); @@ -1005,12 +1004,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("work"); } - if (u.Length != rowsA * rowsA) + if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - if (vt.Length != columnsA * columnsA) + if (vt.Length != columnsA*columnsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } @@ -1025,9 +1024,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); } - if (work.Length < (2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)) + if (work.Length < (2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)) { - work[0] = (2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA); + work[0] = (2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA); throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -1060,7 +1059,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); @@ -1095,12 +1094,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + SafeNativeMethods.c_vector_subtract(x.Length, x, y, result); } @@ -1130,12 +1129,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + SafeNativeMethods.c_vector_multiply(x.Length, x, y, result); } @@ -1165,12 +1164,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + SafeNativeMethods.c_vector_divide(x.Length, x, y, result); } } diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs index cf43e799..359a9422 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2011 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -28,14 +28,14 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using MathNet.Numerics.LinearAlgebra.Generic.Factorization; - namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { using System; + using System.Numerics; using System.Security; + using Numerics.LinearAlgebra.Generic.Factorization; using Properties; - + /// /// Intel's Math Kernel Library (MKL) linear algebra provider. /// @@ -121,8 +121,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl if (x == null) { throw new ArgumentNullException("x"); - } - + } + if (!ReferenceEquals(x, result)) { Array.Copy(x, 0, result, 0, x.Length); @@ -190,9 +190,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl var k = transposeA == Transpose.DontTranspose ? columnsA : rowsA; var l = transposeB == Transpose.DontTranspose ? rowsB : columnsB; - if (c.Length != m * n) + if (c.Length != m*n) { - throw new ArgumentException(Resources.ArgumentMatrixDimensions); + throw new ArgumentException(Resources.ArgumentMatrixDimensions); } if (k != l) @@ -225,7 +225,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (data.Length != order * order) + if (data.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "data"); } @@ -234,7 +234,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - + SafeNativeMethods.d_lu_factor(order, data, ipiv); } @@ -252,13 +252,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } var work = new double[order]; - SafeNativeMethods.d_lu_inverse(order, a, work, work.Length); + SafeNativeMethods.d_lu_inverse(order, a, work, work.Length); } /// @@ -281,7 +281,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -292,7 +292,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl } var work = new double[order]; - SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv, work, order); + SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv, work, order); } /// @@ -312,7 +312,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -327,7 +327,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } - SafeNativeMethods.d_lu_inverse(order, a, work, work.Length); + SafeNativeMethods.d_lu_inverse(order, a, work, work.Length); } /// @@ -353,7 +353,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -373,7 +373,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } - SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv, work, order); + SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv, work, order); } /// @@ -392,22 +392,22 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - + if (ReferenceEquals(a, b)) { throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_lu_solve(order, columnsOfB, a, b); + SafeNativeMethods.d_lu_solve(order, columnsOfB, a, b); } /// @@ -432,7 +432,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -442,7 +442,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -452,7 +452,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_lu_solve_factored(order, columnsOfB, a, ipiv, b); + SafeNativeMethods.d_lu_solve_factored(order, columnsOfB, a, ipiv, b); } /// @@ -475,7 +475,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -510,7 +510,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -520,7 +520,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_cholesky_solve(orderA, columnsB, a, b); + SafeNativeMethods.d_cholesky_solve(orderA, columnsB, a, b); } /// @@ -544,7 +544,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -554,7 +554,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_cholesky_solve_factored(orderA, columnsB, a, b); + SafeNativeMethods.d_cholesky_solve_factored(orderA, columnsB, a, b); } /// @@ -582,7 +582,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -592,12 +592,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (q.Length != rowsR * rowsR) + if (q.Length != rowsR*rowsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - var work = new double[columnsR * Control.BlockSize]; + var work = new double[columnsR*Control.BlockSize]; SafeNativeMethods.d_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } @@ -634,7 +634,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("work"); } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -644,14 +644,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (q.Length != rowsR * rowsR) + if (q.Length != rowsR*rowsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - if (work.Length < columnsR * Control.BlockSize) + if (work.Length < columnsR*Control.BlockSize) { - work[0] = columnsR * Control.BlockSize; + work[0] = columnsR*Control.BlockSize; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -683,7 +683,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (q.Length != rowsA * columnsA) + if (q.Length != rowsA*columnsA) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); } @@ -698,9 +698,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - var work = new double[columnsA * Control.BlockSize]; + var work = new double[columnsA*Control.BlockSize]; SafeNativeMethods.d_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); - } @@ -776,7 +775,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl [SecuritySafeCritical] public override void QRSolve(double[] a, int rows, int columns, double[] b, int columnsB, double[] x, QRMethod method = QRMethod.Full) { - var work = new double[columns * Control.BlockSize]; + var work = new double[columns*Control.BlockSize]; QRSolve(a, rows, columns, b, columnsB, x, work, method); } @@ -817,17 +816,17 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("work"); } - if (a.Length != rows * columns) + if (a.Length != rows*columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (b.Length != rows * columnsB) + if (b.Length != rows*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - if (x.Length != columns * columnsB) + if (x.Length != columns*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "x"); } @@ -839,7 +838,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl if (work.Length < 1) { - work[0] = rows * Control.BlockSize; + work[0] = rows*Control.BlockSize; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -863,7 +862,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl [SecuritySafeCritical] public override void QRSolveFactored(double[] q, double[] r, int rowsR, int columnsR, double[] tau, double[] b, int columnsB, double[] x, QRMethod method = QRMethod.Full) { - var work = new double[columnsR * Control.BlockSize]; + var work = new double[columnsR*Control.BlockSize]; QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); } @@ -914,7 +913,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl } int rowsQ, columnsQ, rowsR, columnsR; - if( method == QRMethod.Full) + if (method == QRMethod.Full) { rowsQ = columnsQ = rowsR = rowsA; columnsR = columnsA; @@ -925,29 +924,29 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl columnsQ = rowsR = columnsR = columnsA; } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR*columnsR), "r"); } - if (q.Length != rowsQ * columnsQ) + if (q.Length != rowsQ*columnsQ) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ*columnsQ), "q"); } - if (b.Length != rowsA * columnsB) + if (b.Length != rowsA*columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA*columnsB), "b"); } - if (x.Length != columnsA * columnsB) + if (x.Length != columnsA*columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA*columnsB), "x"); } if (work.Length < 1) { - work[0] = rowsA * Control.BlockSize; + work[0] = rowsA*Control.BlockSize; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -999,12 +998,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("vt"); } - if (u.Length != rowsA * rowsA) + if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - if (vt.Length != columnsA * columnsA) + if (vt.Length != columnsA*columnsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } @@ -1014,7 +1013,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - var work = new double[Math.Max((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5 * Math.Min(rowsA, columnsA))]; + var work = new double[Math.Max((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5*Math.Min(rowsA, columnsA))]; SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); } @@ -1044,20 +1043,20 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("x"); } - if (b.Length != rowsA * columnsB) + if (b.Length != rowsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - if (x.Length != columnsA * columnsB) + if (x.Length != columnsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - var work = new double[Math.Max((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5 * Math.Min(rowsA, columnsA))]; + var work = new double[Math.Max((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5*Math.Min(rowsA, columnsA))]; var s = new double[Math.Min(rowsA, columnsA)]; - var u = new double[rowsA * rowsA]; - var vt = new double[columnsA * columnsA]; + var u = new double[rowsA*rowsA]; + var vt = new double[columnsA*columnsA]; var clone = new double[a.Length]; a.Copy(clone); @@ -1109,12 +1108,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("work"); } - if (u.Length != rowsA * rowsA) + if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - if (vt.Length != columnsA * columnsA) + if (vt.Length != columnsA*columnsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } @@ -1129,9 +1128,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); } - if (work.Length < Math.Max((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5 * Math.Min(rowsA, columnsA))) + if (work.Length < Math.Max((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5*Math.Min(rowsA, columnsA))) { - work[0] = Math.Max((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5 * Math.Min(rowsA, columnsA)); + work[0] = Math.Max((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5*Math.Min(rowsA, columnsA)); throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -1164,7 +1163,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); @@ -1199,12 +1198,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + SafeNativeMethods.d_vector_subtract(x.Length, x, y, result); } @@ -1234,12 +1233,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + SafeNativeMethods.d_vector_multiply(x.Length, x, y, result); } @@ -1269,13 +1268,67 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + SafeNativeMethods.d_vector_divide(x.Length, x, y, result); } + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + public override void EigenDecomp(bool isSymmetric, int order, double[] matrix, double[] matrixEv, Complex[] vectorEv, double[] matrixD) + { + if (matrix == null) + { + throw new ArgumentNullException("matrix"); + } + + if (matrix.Length != order*order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrix"); + } + + if (matrixEv == null) + { + throw new ArgumentNullException("matrixEv"); + } + + if (matrixEv.Length != order*order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixEv"); + } + + if (vectorEv == null) + { + throw new ArgumentNullException("vectorEv"); + } + + if (vectorEv.Length != order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order), "vectorEv"); + } + + if (matrixD == null) + { + throw new ArgumentNullException("matrixD"); + } + + if (matrixD.Length != order*order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixD"); + } + + SafeNativeMethods.d_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + } } } diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.float.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.float.cs index b32d698e..42aa1937 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.float.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.float.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2011 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -28,18 +28,14 @@ // OTHER DEALINGS IN THE SOFTWARE. // -/* This file is automatically generated - do not modify it. - Last generated on UTC 2011-04-17 06:45:23Z -*/ - -using MathNet.Numerics.LinearAlgebra.Generic.Factorization; - namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { using System; + using System.Numerics; using System.Security; + using Numerics.LinearAlgebra.Generic.Factorization; using Properties; - + /// /// Intel's Math Kernel Library (MKL) linear algebra provider. /// @@ -72,7 +68,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl return SafeNativeMethods.s_dot_product(x.Length, x, y); } - + /// /// Adds a scaled vector to another: result = y + alpha*x. /// @@ -125,8 +121,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl if (x == null) { throw new ArgumentNullException("x"); - } - + } + if (!ReferenceEquals(x, result)) { Array.Copy(x, 0, result, 0, x.Length); @@ -194,9 +190,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl var k = transposeA == Transpose.DontTranspose ? columnsA : rowsA; var l = transposeB == Transpose.DontTranspose ? rowsB : columnsB; - if (c.Length != m * n) + if (c.Length != m*n) { - throw new ArgumentException(Resources.ArgumentMatrixDimensions); + throw new ArgumentException(Resources.ArgumentMatrixDimensions); } if (k != l) @@ -229,7 +225,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (data.Length != order * order) + if (data.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "data"); } @@ -238,7 +234,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - + SafeNativeMethods.s_lu_factor(order, data, ipiv); } @@ -256,13 +252,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } var work = new float[order]; - SafeNativeMethods.s_lu_inverse(order, a, work, work.Length); + SafeNativeMethods.s_lu_inverse(order, a, work, work.Length); } /// @@ -285,7 +281,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -316,7 +312,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -331,7 +327,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } - SafeNativeMethods.s_lu_inverse(order, a, work, work.Length); + SafeNativeMethods.s_lu_inverse(order, a, work, work.Length); } /// @@ -357,7 +353,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -396,22 +392,22 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("a"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - + if (ReferenceEquals(a, b)) { throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_lu_solve(order, columnsOfB, a, b); + SafeNativeMethods.s_lu_solve(order, columnsOfB, a, b); } /// @@ -436,7 +432,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -446,7 +442,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -456,7 +452,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_lu_solve_factored(order, columnsOfB, a, ipiv, b); + SafeNativeMethods.s_lu_solve_factored(order, columnsOfB, a, ipiv, b); } /// @@ -479,7 +475,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -514,7 +510,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -524,7 +520,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_cholesky_solve(orderA, columnsB, a, b); + SafeNativeMethods.s_cholesky_solve(orderA, columnsB, a, b); } /// @@ -548,7 +544,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -558,7 +554,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_cholesky_solve_factored(orderA, columnsB, a, b); + SafeNativeMethods.s_cholesky_solve_factored(orderA, columnsB, a, b); } /// @@ -586,7 +582,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -596,12 +592,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (q.Length != rowsR * rowsR) + if (q.Length != rowsR*rowsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - var work = new float[columnsR * Control.BlockSize]; + var work = new float[columnsR*Control.BlockSize]; SafeNativeMethods.s_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } @@ -638,7 +634,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("work"); } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -648,14 +644,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); } - if (q.Length != rowsR * rowsR) + if (q.Length != rowsR*rowsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - if (work.Length < columnsR * Control.BlockSize) + if (work.Length < columnsR*Control.BlockSize) { - work[0] = columnsR * Control.BlockSize; + work[0] = columnsR*Control.BlockSize; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -676,7 +672,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl [SecuritySafeCritical] public override void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, QRMethod method = QRMethod.Full) { - var work = new float[columns * Control.BlockSize]; + var work = new float[columns*Control.BlockSize]; QRSolve(a, rows, columns, b, columnsB, x, work, method); } @@ -717,17 +713,17 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("work"); } - if (a.Length != rows * columns) + if (a.Length != rows*columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (b.Length != rows * columnsB) + if (b.Length != rows*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - if (x.Length != columns * columnsB) + if (x.Length != columns*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "x"); } @@ -739,7 +735,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl if (work.Length < 1) { - work[0] = rows * Control.BlockSize; + work[0] = rows*Control.BlockSize; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -763,7 +759,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl [SecuritySafeCritical] public override void QRSolveFactored(float[] q, float[] r, int rowsR, int columnsR, float[] tau, float[] b, int columnsB, float[] x, QRMethod method = QRMethod.Full) { - var work = new float[columnsR * Control.BlockSize]; + var work = new float[columnsR*Control.BlockSize]; QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); } @@ -825,29 +821,29 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl columnsQ = rowsR = columnsR = columnsA; } - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR*columnsR), "r"); } - if (q.Length != rowsQ * columnsQ) + if (q.Length != rowsQ*columnsQ) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ*columnsQ), "q"); } - if (b.Length != rowsA * columnsB) + if (b.Length != rowsA*columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA*columnsB), "b"); } - if (x.Length != columnsA * columnsB) + if (x.Length != columnsA*columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA*columnsB), "x"); } if (work.Length < 1) { - work[0] = rowsA * Control.BlockSize; + work[0] = rowsA*Control.BlockSize; throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -899,12 +895,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("vt"); } - if (u.Length != rowsA * rowsA) + if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - if (vt.Length != columnsA * columnsA) + if (vt.Length != columnsA*columnsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } @@ -914,7 +910,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - var work = new float[Math.Max(((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5 * Math.Min(rowsA, columnsA))]; + var work = new float[Math.Max(((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5*Math.Min(rowsA, columnsA))]; SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); } @@ -944,20 +940,20 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("x"); } - if (b.Length != rowsA * columnsB) + if (b.Length != rowsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - if (x.Length != columnsA * columnsB) + if (x.Length != columnsA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - var work = new float[Math.Max(((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5 * Math.Min(rowsA, columnsA))]; + var work = new float[Math.Max(((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5*Math.Min(rowsA, columnsA))]; var s = new float[Math.Min(rowsA, columnsA)]; - var u = new float[rowsA * rowsA]; - var vt = new float[columnsA * columnsA]; + var u = new float[rowsA*rowsA]; + var vt = new float[columnsA*columnsA]; var clone = new float[a.Length]; a.Copy(clone); @@ -1009,12 +1005,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentNullException("work"); } - if (u.Length != rowsA * rowsA) + if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); } - if (vt.Length != columnsA * columnsA) + if (vt.Length != columnsA*columnsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); } @@ -1029,9 +1025,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); } - if (work.Length < Math.Max(((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5 * Math.Min(rowsA, columnsA))) + if (work.Length < Math.Max(((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5*Math.Min(rowsA, columnsA))) { - work[0] = Math.Max(((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5 * Math.Min(rowsA, columnsA)); + work[0] = Math.Max(((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5*Math.Min(rowsA, columnsA)); throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); } @@ -1064,7 +1060,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); @@ -1099,12 +1095,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + SafeNativeMethods.s_vector_subtract(x.Length, x, y, result); } @@ -1134,12 +1130,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + SafeNativeMethods.s_vector_multiply(x.Length, x, y, result); } @@ -1169,13 +1165,67 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + if (x.Length != result.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } - + SafeNativeMethods.s_vector_divide(x.Length, x, y, result); } + + /// + /// Computes the eigenvalues and eigenvectors of a matrix. + /// + /// Wether the matrix is symmetric or not. + /// The order of the matrix. + /// The matrix to decompose. The lenth of the array must be order * order. + /// On output, the matrix contains the eigen vectors. The lenth of the array must be order * order. + /// On output, the eigen values (λ) of matrix in ascending value. The length of the arry must . + /// On output, the block diagonal eigenvalue matrix. The lenth of the array must be order * order. + public override void EigenDecomp(bool isSymmetric, int order, float[] matrix, float[] matrixEv, Complex[] vectorEv, float[] matrixD) + { + if (matrix == null) + { + throw new ArgumentNullException("matrix"); + } + + if (matrix.Length != order*order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrix"); + } + + if (matrixEv == null) + { + throw new ArgumentNullException("matrixEv"); + } + + if (matrixEv.Length != order*order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixEv"); + } + + if (vectorEv == null) + { + throw new ArgumentNullException("vectorEv"); + } + + if (vectorEv.Length != order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order), "vectorEv"); + } + + if (matrixD == null) + { + throw new ArgumentNullException("matrixD"); + } + + if (matrixD.Length != order*order) + { + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixD"); + } + + SafeNativeMethods.s_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + } } } diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/SafeNativeMethods.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/SafeNativeMethods.cs index 87f5b8fe..135c97f3 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/SafeNativeMethods.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/SafeNativeMethods.cs @@ -2,7 +2,7 @@ // Math.NET Numerics, part of the Math.NET Project // http://mathnet.opensourcedotnet.info // -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -266,6 +266,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl [DllImport(DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] internal static extern int z_svd_factor(bool computeVectors, int m, int n, [In, Out] Complex[] a, [In, Out] Complex[] s, [In, Out] Complex[] u, [In, Out] Complex[] v, [In, Out] Complex[] work, int len); + [DllImport(DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] + internal static extern int s_eigen(bool isSymmetric, int n, [In] float[] a, [In, Out] float[] vectors, [In, Out] Complex[] values, [In, Out] float[] d); + + [DllImport(DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] + internal static extern int d_eigen(bool isSymmetric, int n, [In] double[] a, [In, Out] double[] vectors, [In, Out] Complex[] values, [In, Out] double[] d); + + [DllImport(DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] + internal static extern int c_eigen(bool isSymmetric, int n, [In] Complex32[] a, [In, Out] Complex32[] vectors, [In, Out] Complex[] values, [In, Out] Complex32[] d); + + [DllImport(DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] + internal static extern int z_eigen(bool isSymmetric, int n, [In] Complex[] a, [In, Out] Complex[] vectors, [In, Out] Complex[] values, [In, Out] Complex[] d); + #endregion LAPACK #region Vector Functions diff --git a/src/Numerics/LinearAlgebra/Complex/Factorization/DenseEvd.cs b/src/Numerics/LinearAlgebra/Complex/Factorization/DenseEvd.cs index afa8bfcc..8a2c1b0f 100644 --- a/src/Numerics/LinearAlgebra/Complex/Factorization/DenseEvd.cs +++ b/src/Numerics/LinearAlgebra/Complex/Factorization/DenseEvd.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -27,13 +27,13 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // + namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization { using System; - using System.Numerics; using Generic; using Properties; - + /// /// Eigenvalues and eigenvectors of a complex matrix. /// @@ -72,45 +72,23 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization var order = matrix.RowCount; - // Initialize matricies for eigenvalues and eigenvectors + // Initialize matrices for eigenvalues and eigenvectors MatrixEv = DenseMatrix.Identity(order); MatrixD = matrix.CreateMatrix(order, order); VectorEv = new DenseVector(order); - + IsSymmetric = true; - for (var i = 0; i < order & IsSymmetric; i++) + for (var i = 0; IsSymmetric && i < order; i++) { - for (var j = 0; j < order & IsSymmetric; j++) + for (var j = 0; IsSymmetric && j < order; j++) { IsSymmetric &= matrix.At(i, j) == matrix.At(j, i).Conjugate(); } } - if (IsSymmetric) - { - var matrixCopy = matrix.ToArray(); - var tau = new Complex[order]; - var d = new double[order]; - var e = new double[order]; - - SymmetricTridiagonalize(matrixCopy, d, e, tau, order); - SymmetricDiagonalize(((DenseMatrix)MatrixEv).Values, d, e, order); - SymmetricUntridiagonalize(((DenseMatrix)MatrixEv).Values, matrixCopy, tau, order); - - for (var i = 0; i < order; i++) - { - VectorEv[i] = new Complex(d[i], e[i]); - } - } - else - { - var matrixH = matrix.ToArray(); - NonsymmetricReduceToHessenberg(((DenseMatrix)MatrixEv).Values, matrixH, order); - NonsymmetricReduceHessenberToRealSchur(((DenseVector)VectorEv).Values, ((DenseMatrix)MatrixEv).Values, matrixH, order); - } - - MatrixD.SetDiagonal(VectorEv); + Control.LinearAlgebraProvider.EigenDecomp(IsSymmetric, order, matrix.Values, ((DenseMatrix) MatrixEv).Values, + ((DenseVector) VectorEv).Values, ((DenseMatrix) MatrixD).Values); } /// @@ -125,14 +103,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization /// Smith, Boyle, Dongarra, Garbow, Ikebe, Klema, Moler, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricTridiagonalize(Complex[,] matrixA, double[] d, double[] e, Complex[] tau, int order) + internal static void SymmetricTridiagonalize(System.Numerics.Complex[] matrixA, double[] d, double[] e, System.Numerics.Complex[] tau, int order) { double hh; - tau[order - 1] = Complex.One; + tau[order - 1] = System.Numerics.Complex.One; for (var i = 0; i < order; i++) { - d[i] = matrixA[i, i].Real; + d[i] = matrixA[i*order + i].Real; } // Householder reduction to tridiagonal form. @@ -144,95 +122,96 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization for (var k = 0; k < i; k++) { - scale = scale + Math.Abs(matrixA[i, k].Real) + Math.Abs(matrixA[i, k].Imaginary); + scale = scale + Math.Abs(matrixA[k*order + i].Real) + Math.Abs(matrixA[k*order + i].Imaginary); } if (scale == 0.0) { - tau[i - 1] = Complex.One; + tau[i - 1] = System.Numerics.Complex.One; e[i] = 0.0; } else { for (var k = 0; k < i; k++) { - matrixA[i, k] /= scale; - h += matrixA[i, k].MagnitudeSquared(); + matrixA[k*order + i] /= scale; + h += matrixA[k*order + i].MagnitudeSquared(); } - Complex g = Math.Sqrt(h); - e[i] = scale * g.Real; + System.Numerics.Complex g = Math.Sqrt(h); + e[i] = scale*g.Real; - Complex temp; - var f = matrixA[i, i - 1]; + System.Numerics.Complex temp; + var im1Oi = (i - 1)*order + i; + var f = matrixA[im1Oi]; if (f.Magnitude != 0) { - temp = -(matrixA[i, i - 1].Conjugate() * tau[i].Conjugate()) / f.Magnitude; - h += f.Magnitude * g.Real; - g = 1.0 + (g / f.Magnitude); - matrixA[i, i - 1] *= g; + temp = -(matrixA[im1Oi].Conjugate()*tau[i].Conjugate())/f.Magnitude; + h += f.Magnitude*g.Real; + g = 1.0 + (g/f.Magnitude); + matrixA[im1Oi] *= g; } else { temp = -tau[i].Conjugate(); - matrixA[i, i - 1] = g; + matrixA[im1Oi] = g; } if ((f.Magnitude == 0) || (i != 1)) { - f = Complex.Zero; + f = System.Numerics.Complex.Zero; for (var j = 0; j < i; j++) { - var tmp = Complex.Zero; - + var tmp = System.Numerics.Complex.Zero; + var jO = j*order; // Form element of A*U. for (var k = 0; k <= j; k++) { - tmp += matrixA[j, k] * matrixA[i, k].Conjugate(); + tmp += matrixA[k*order + j]*matrixA[k*order + i].Conjugate(); } for (var k = j + 1; k <= i - 1; k++) { - tmp += matrixA[k, j].Conjugate() * matrixA[i, k].Conjugate(); + tmp += matrixA[jO + k].Conjugate()*matrixA[k*order + i].Conjugate(); } // Form element of P - tau[j] = tmp / h; - f += (tmp / h) * matrixA[i, j]; + tau[j] = tmp/h; + f += (tmp/h)*matrixA[jO + i]; } - hh = f.Real / (h + h); + hh = f.Real/(h + h); // Form the reduced A. for (var j = 0; j < i; j++) { - f = matrixA[i, j].Conjugate(); - g = tau[j] - (hh * f); + f = matrixA[j*order + i].Conjugate(); + g = tau[j] - (hh*f); tau[j] = g.Conjugate(); for (var k = 0; k <= j; k++) { - matrixA[j, k] -= (f * tau[k]) + (g * matrixA[i, k]); + matrixA[k*order + j] -= (f*tau[k]) + (g*matrixA[k*order + i]); } } } for (var k = 0; k < i; k++) { - matrixA[i, k] *= scale; + matrixA[k*order + i] *= scale; } tau[i - 1] = temp.Conjugate(); } hh = d[i]; - d[i] = matrixA[i, i].Real; - matrixA[i, i] = new Complex(hh, scale * Math.Sqrt(h)); + d[i] = matrixA[i*order + i].Real; + matrixA[i*order + i] = new System.Numerics.Complex(hh, scale*Math.Sqrt(h)); } hh = d[0]; - d[0] = matrixA[0, 0].Real; - matrixA[0, 0] = hh; + d[0] = matrixA[0].Real; + matrixA[0] = hh; e[0] = 0.0; } @@ -247,7 +226,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization /// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricDiagonalize(Complex[] dataEv, double[] d, double[] e, int order) + internal static void SymmetricDiagonalize(System.Numerics.Complex[] dataEv, double[] d, double[] e, int order) { const int Maxiter = 1000; @@ -268,7 +247,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization var m = l; while (m < order) { - if (Math.Abs(e[m]) <= eps * tst1) + if (Math.Abs(e[m]) <= eps*tst1) { break; } @@ -287,15 +266,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization // Compute implicit shift var g = d[l]; - var p = (d[l + 1] - g) / (2.0 * e[l]); + var p = (d[l + 1] - g)/(2.0*e[l]); var r = SpecialFunctions.Hypotenuse(p, 1.0); if (p < 0) { r = -r; } - d[l] = e[l] / (p + r); - d[l + 1] = e[l] * (p + r); + d[l] = e[l]/(p + r); + d[l + 1] = e[l]*(p + r); var dl1 = d[l + 1]; var h = g - d[l]; @@ -319,27 +298,27 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization c3 = c2; c2 = c; s2 = s; - g = c * e[i]; - h = c * p; + g = c*e[i]; + h = c*p; r = SpecialFunctions.Hypotenuse(p, e[i]); - e[i + 1] = s * r; - s = e[i] / r; - c = p / r; - p = (c * d[i]) - (s * g); - d[i + 1] = h + (s * ((c * g) + (s * d[i]))); + e[i + 1] = s*r; + s = e[i]/r; + c = p/r; + p = (c*d[i]) - (s*g); + d[i + 1] = h + (s*((c*g) + (s*d[i]))); // Accumulate transformation. for (var k = 0; k < order; k++) { - h = dataEv[((i + 1) * order) + k].Real; - dataEv[((i + 1) * order) + k] = (s * dataEv[(i * order) + k].Real) + (c * h); - dataEv[(i * order) + k] = (c * dataEv[(i * order) + k].Real) - (s * h); + h = dataEv[((i + 1)*order) + k].Real; + dataEv[((i + 1)*order) + k] = (s*dataEv[(i*order) + k].Real) + (c*h); + dataEv[(i*order) + k] = (c*dataEv[(i*order) + k].Real) - (s*h); } } - p = (-s) * s2 * c3 * el1 * e[l] / dl1; - e[l] = s * p; - d[l] = c * p; + p = (-s)*s2*c3*el1*e[l]/dl1; + e[l] = s*p; + d[l] = c*p; // Check for convergence. If too many iterations have been performed, // throw exception that Convergence Failed @@ -347,8 +326,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization { throw new ArgumentException(Resources.ConvergenceFailed); } - } - while (Math.Abs(e[l]) > eps * tst1); + } while (Math.Abs(e[l]) > eps*tst1); } d[l] = d[l] + f; @@ -375,9 +353,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization d[i] = p; for (var j = 0; j < order; j++) { - p = dataEv[(i * order) + j].Real; - dataEv[(i * order) + j] = dataEv[(k * order) + j]; - dataEv[(k * order) + j] = p; + p = dataEv[(i*order) + j].Real; + dataEv[(i*order) + j] = dataEv[(k*order) + j]; + dataEv[(k*order) + j] = p; } } } @@ -394,35 +372,35 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization /// by Smith, Boyle, Dongarra, Garbow, Ikebe, Klema, Moler, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricUntridiagonalize(Complex[] dataEv, Complex[,] matrixA, Complex[] tau, int order) + internal static void SymmetricUntridiagonalize(System.Numerics.Complex[] dataEv, System.Numerics.Complex[] matrixA, System.Numerics.Complex[] tau, int order) { for (var i = 0; i < order; i++) { for (var j = 0; j < order; j++) { - dataEv[(j * order) + i] = dataEv[(j * order) + i].Real * tau[i].Conjugate(); + dataEv[(j*order) + i] = dataEv[(j*order) + i].Real*tau[i].Conjugate(); } } // Recover and apply the Householder matrices. for (var i = 1; i < order; i++) { - var h = matrixA[i, i].Imaginary; + var h = matrixA[i*order + i].Imaginary; if (h != 0) { for (var j = 0; j < order; j++) { - var s = Complex.Zero; + var s = System.Numerics.Complex.Zero; for (var k = 0; k < i; k++) { - s += dataEv[(j * order) + k] * matrixA[i, k]; + s += dataEv[(j*order) + k]*matrixA[k*order + i]; } - s = (s / h) / h; + s = (s/h)/h; for (var k = 0; k < i; k++) { - dataEv[(j * order) + k] -= s * matrixA[i, k].Conjugate(); + dataEv[(j*order) + k] -= s*matrixA[k*order + i].Conjugate(); } } } @@ -439,17 +417,18 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization /// by Martin and Wilkinson, Handbook for Auto. Comp., /// Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutines in EISPACK. - private static void NonsymmetricReduceToHessenberg(Complex[] dataEv, Complex[,] matrixH, int order) + internal static void NonsymmetricReduceToHessenberg(System.Numerics.Complex[] dataEv, System.Numerics.Complex[] matrixH, int order) { - var ort = new Complex[order]; + var ort = new System.Numerics.Complex[order]; for (var m = 1; m < order - 1; m++) { // Scale column. var scale = 0.0; + var mm1O = (m - 1)*order; for (var i = m; i < order; i++) { - scale += Math.Abs(matrixH[i, m - 1].Real) + Math.Abs(matrixH[i, m - 1].Imaginary); + scale += Math.Abs(matrixH[mm1O + i].Real) + Math.Abs(matrixH[mm1O + i].Imaginary); } if (scale != 0.0) @@ -458,57 +437,58 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization var h = 0.0; for (var i = order - 1; i >= m; i--) { - ort[i] = matrixH[i, m - 1] / scale; + ort[i] = matrixH[mm1O + i]/scale; h += ort[i].MagnitudeSquared(); } var g = Math.Sqrt(h); if (ort[m].Magnitude != 0) { - h = h + (ort[m].Magnitude * g); + h = h + (ort[m].Magnitude*g); g /= ort[m].Magnitude; - ort[m] = (1.0 + g) * ort[m]; + ort[m] = (1.0 + g)*ort[m]; } else { ort[m] = g; - matrixH[m, m - 1] = scale; + matrixH[mm1O + m] = scale; } // Apply Householder similarity transformation // H = (I-u*u'/h)*H*(I-u*u')/h) for (var j = m; j < order; j++) { - var f = Complex.Zero; + var f = System.Numerics.Complex.Zero; + var jO = j*order; for (var i = order - 1; i >= m; i--) { - f += ort[i].Conjugate() * matrixH[i, j]; + f += ort[i].Conjugate()*matrixH[jO + i]; } - f = f / h; + f = f/h; for (var i = m; i < order; i++) { - matrixH[i, j] -= f * ort[i]; + matrixH[jO + i] -= f*ort[i]; } } for (var i = 0; i < order; i++) { - var f = Complex.Zero; + var f = System.Numerics.Complex.Zero; for (var j = order - 1; j >= m; j--) { - f += ort[j] * matrixH[i, j]; + f += ort[j]*matrixH[j*order + i]; } - f = f / h; + f = f/h; for (var j = m; j < order; j++) { - matrixH[i, j] -= f * ort[j].Conjugate(); + matrixH[j*order + i] -= f*ort[j].Conjugate(); } } - ort[m] = scale * ort[m]; - matrixH[m, m - 1] *= -g; + ort[m] = scale*ort[m]; + matrixH[mm1O + m] *= -g; } } @@ -517,59 +497,65 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization { for (var j = 0; j < order; j++) { - dataEv[(j * order) + i] = i == j ? Complex.One : Complex.Zero; + dataEv[(j*order) + i] = i == j ? System.Numerics.Complex.One : System.Numerics.Complex.Zero; } } for (var m = order - 2; m >= 1; m--) { - if (matrixH[m, m - 1] != Complex.Zero && ort[m] != Complex.Zero) + var mm1O = (m - 1)*order; + var mm1Om = mm1O + m; + if (matrixH[mm1Om] != System.Numerics.Complex.Zero && ort[m] != System.Numerics.Complex.Zero) { - var norm = (matrixH[m, m - 1].Real * ort[m].Real) + (matrixH[m, m - 1].Imaginary * ort[m].Imaginary); + var norm = (matrixH[mm1Om].Real*ort[m].Real) + (matrixH[mm1Om].Imaginary*ort[m].Imaginary); for (var i = m + 1; i < order; i++) { - ort[i] = matrixH[i, m - 1]; + ort[i] = matrixH[mm1O + i]; } for (var j = m; j < order; j++) { - var g = Complex.Zero; + var g = System.Numerics.Complex.Zero; for (var i = m; i < order; i++) { - g += ort[i].Conjugate() * dataEv[(j * order) + i]; + g += ort[i].Conjugate()*dataEv[(j*order) + i]; } // Double division avoids possible underflow g /= norm; for (var i = m; i < order; i++) { - dataEv[(j * order) + i] += g * ort[i]; + dataEv[(j*order) + i] += g*ort[i]; } } } } - + // Create real subdiagonal elements. for (var i = 1; i < order; i++) { - if (matrixH[i, i - 1].Imaginary != 0.0) + var im1 = i - 1; + var im1O = im1*order; + var im1Oi = im1O + i; + var iO = i*order; + if (matrixH[im1Oi].Imaginary != 0.0) { - var y = matrixH[i, i - 1] / matrixH[i, i - 1].Magnitude; - matrixH[i, i - 1] = matrixH[i, i - 1].Magnitude; + var y = matrixH[im1Oi]/matrixH[im1Oi].Magnitude; + matrixH[im1Oi] = matrixH[im1Oi].Magnitude; for (var j = i; j < order; j++) { - matrixH[i, j] *= y.Conjugate(); + matrixH[j*order + i] *= y.Conjugate(); } for (var j = 0; j <= Math.Min(i + 1, order - 1); j++) { - matrixH[j, i] *= y; + matrixH[iO + j] *= y; } for (var j = 0; j < order; j++) { - dataEv[(i * order) + j] *= y; + dataEv[(i*order) + j] *= y; } } } @@ -586,14 +572,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization /// by Martin and Wilkinson, Handbook for Auto. Comp., /// Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void NonsymmetricReduceHessenberToRealSchur(Complex[] vectorV, Complex[] dataEv, Complex[,] matrixH, int order) + internal static void NonsymmetricReduceHessenberToRealSchur(System.Numerics.Complex[] vectorV, System.Numerics.Complex[] dataEv, System.Numerics.Complex[] matrixH, int order) { // Initialize var n = order - 1; var eps = Precision.DoubleMachinePrecision; double norm; - Complex x, y, z, exshift = Complex.Zero; + System.Numerics.Complex x, y, z, exshift = System.Numerics.Complex.Zero; // Outer loop over eigenvalue index var iter = 0; @@ -603,8 +589,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization var l = n; while (l > 0) { - var tst1 = Math.Abs(matrixH[l - 1, l - 1].Real) + Math.Abs(matrixH[l - 1, l - 1].Imaginary) + Math.Abs(matrixH[l, l].Real) + Math.Abs(matrixH[l, l].Imaginary); - if (Math.Abs(matrixH[l, l - 1].Real) < eps * tst1) + var lm1 = l - 1; + var lm1O = lm1*order; + var lO = l*order; + var tst1 = Math.Abs(matrixH[lm1O + lm1].Real) + Math.Abs(matrixH[lm1O + lm1].Imaginary) + Math.Abs(matrixH[lO + l].Real) + Math.Abs(matrixH[lO + l].Imaginary); + if (Math.Abs(matrixH[lm1O + l].Real) < eps*tst1) { break; } @@ -612,46 +601,50 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization l--; } + var nm1 = n - 1; + var nm1O = nm1*order; + var nO = n*order; + var nOn = nO + n; // Check for convergence // One root found if (l == n) { - matrixH[n, n] += exshift; - vectorV[n] = matrixH[n, n]; + matrixH[nOn] += exshift; + vectorV[n] = matrixH[nOn]; n--; iter = 0; } else { // Form shift - Complex s; + System.Numerics.Complex s; if (iter != 10 && iter != 20) { - s = matrixH[n, n]; - x = matrixH[n - 1, n] * matrixH[n, n - 1].Real; + s = matrixH[nOn]; + x = matrixH[nO + nm1]*matrixH[nm1O + n].Real; if (x.Real != 0.0 || x.Imaginary != 0.0) { - y = (matrixH[n - 1, n - 1] - s) / 2.0; - z = ((y * y) + x).SquareRoot(); - if ((y.Real * z.Real) + (y.Imaginary * z.Imaginary) < 0.0) + y = (matrixH[nm1O + nm1] - s)/2.0; + z = ((y*y) + x).SquareRoot(); + if ((y.Real*z.Real) + (y.Imaginary*z.Imaginary) < 0.0) { z *= -1.0; } - x /= y + z; + x /= y + z; s = s - x; } } else { // Form exceptional shift - s = Math.Abs(matrixH[n, n - 1].Real) + Math.Abs(matrixH[n - 1, n - 2].Real); + s = Math.Abs(matrixH[nm1O + n].Real) + Math.Abs(matrixH[(n - 2)*order + nm1].Real); } for (var i = 0; i <= n; i++) { - matrixH[i, i] -= s; + matrixH[i*order + i] -= s; } exshift += s; @@ -660,31 +653,35 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization // Reduce to triangle (rows) for (var i = l + 1; i <= n; i++) { - s = matrixH[i, i - 1].Real; - norm = SpecialFunctions.Hypotenuse(matrixH[i - 1, i - 1].Magnitude, s.Real); - x = matrixH[i - 1, i - 1] / norm; + var im1 = i - 1; + var im1O = im1*order; + var im1Oim1 = im1O + im1; + s = matrixH[im1O + i].Real; + norm = SpecialFunctions.Hypotenuse(matrixH[im1Oim1].Magnitude, s.Real); + x = matrixH[im1Oim1]/norm; vectorV[i - 1] = x; - matrixH[i - 1, i - 1] = norm; - matrixH[i, i - 1] = new Complex(0.0, s.Real / norm); + matrixH[im1Oim1] = norm; + matrixH[im1O + i] = new System.Numerics.Complex(0.0, s.Real/norm); for (var j = i; j < order; j++) { - y = matrixH[i - 1, j]; - z = matrixH[i, j]; - matrixH[i - 1, j] = (x.Conjugate() * y) + (matrixH[i, i - 1].Imaginary * z); - matrixH[i, j] = (x * z) - (matrixH[i, i - 1].Imaginary * y); + var jO = j*order; + y = matrixH[jO + im1]; + z = matrixH[jO + i]; + matrixH[jO + im1] = (x.Conjugate()*y) + (matrixH[im1O + i].Imaginary*z); + matrixH[jO + i] = (x*z) - (matrixH[im1O + i].Imaginary*y); } } - s = matrixH[n, n]; + s = matrixH[nOn]; if (s.Imaginary != 0.0) { - s /= matrixH[n, n].Magnitude; - matrixH[n, n] = matrixH[n, n].Magnitude; + s /= matrixH[nOn].Magnitude; + matrixH[nOn] = matrixH[nOn].Magnitude; for (var j = n + 1; j < order; j++) { - matrixH[n, j] *= s.Conjugate(); + matrixH[j*order + n] *= s.Conjugate(); } } @@ -692,29 +689,34 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization for (var j = l + 1; j <= n; j++) { x = vectorV[j - 1]; + var jO = j*order; + var jm1 = j - 1; + var jm1O = jm1*order; + var jm1Oj = jm1O + j; for (var i = 0; i <= j; i++) { - z = matrixH[i, j]; + var jm1Oi = jm1O + i; + z = matrixH[jO + i]; if (i != j) { - y = matrixH[i, j - 1]; - matrixH[i, j - 1] = (x * y) + (matrixH[j, j - 1].Imaginary * z); + y = matrixH[jm1Oi]; + matrixH[jm1Oi] = (x*y) + (matrixH[jm1O + j].Imaginary*z); } else { - y = matrixH[i, j - 1].Real; - matrixH[i, j - 1] = new Complex((x.Real * y.Real) - (x.Imaginary * y.Imaginary) + (matrixH[j, j - 1].Imaginary * z.Real), matrixH[i, j - 1].Imaginary); + y = matrixH[jm1Oi].Real; + matrixH[jm1Oi] = new System.Numerics.Complex((x.Real*y.Real) - (x.Imaginary*y.Imaginary) + (matrixH[jm1O + j].Imaginary*z.Real), matrixH[jm1Oi].Imaginary); } - matrixH[i, j] = (x.Conjugate() * z) - (matrixH[j, j - 1].Imaginary * y); + matrixH[jO + i] = (x.Conjugate()*z) - (matrixH[jm1O + j].Imaginary*y); } for (var i = 0; i < order; i++) { - y = dataEv[((j - 1) * order) + i]; - z = dataEv[(j * order) + i]; - dataEv[((j - 1) * order) + i] = (x * y) + (matrixH[j, j - 1].Imaginary * z); - dataEv[(j * order) + i] = (x.Conjugate() * z) - (matrixH[j, j - 1].Imaginary * y); + y = dataEv[((j - 1)*order) + i]; + z = dataEv[(j*order) + i]; + dataEv[jm1O + i] = (x*y) + (matrixH[jm1Oj].Imaginary*z); + dataEv[jO + i] = (x.Conjugate()*z) - (matrixH[jm1Oj].Imaginary*y); } } @@ -722,12 +724,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization { for (var i = 0; i <= n; i++) { - matrixH[i, n] *= s; + matrixH[nO + i] *= s; } for (var i = 0; i < order; i++) { - dataEv[(n * order) + i] *= s; + dataEv[nO + i] *= s; } } } @@ -740,7 +742,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization { for (var j = i; j < order; j++) { - norm = Math.Max(norm, Math.Abs(matrixH[i, j].Real) + Math.Abs(matrixH[i, j].Imaginary)); + norm = Math.Max(norm, Math.Abs(matrixH[j*order + i].Real) + Math.Abs(matrixH[j*order + i].Imaginary)); } } @@ -756,32 +758,34 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization for (n = order - 1; n > 0; n--) { + var nO = n*order; + var nOn = nO + n; x = vectorV[n]; - matrixH[n, n] = 1.0; + matrixH[nOn] = 1.0; for (var i = n - 1; i >= 0; i--) { z = 0.0; for (var j = i + 1; j <= n; j++) { - z += matrixH[i, j] * matrixH[j, n]; + z += matrixH[j*order + i]*matrixH[nO + j]; } y = x - vectorV[i]; if (y.Real == 0.0 && y.Imaginary == 0.0) { - y = eps * norm; + y = eps*norm; } - matrixH[i, n] = z / y; + matrixH[nO + i] = z/y; // Overflow control - var tr = Math.Abs(matrixH[i, n].Real) + Math.Abs(matrixH[i, n].Imaginary); - if ((eps * tr) * tr > 1) + var tr = Math.Abs(matrixH[nO + i].Real) + Math.Abs(matrixH[nO + i].Imaginary); + if ((eps*tr)*tr > 1) { for (var j = i; j <= n; j++) { - matrixH[j, n] = matrixH[j, n] / tr; + matrixH[nO + j] = matrixH[nO + j]/tr; } } } @@ -790,25 +794,26 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization // Back transformation to get eigenvectors of original matrix for (var j = order - 1; j > 0; j--) { + var jO = j*order; for (var i = 0; i < order; i++) { - z = Complex.Zero; + z = System.Numerics.Complex.Zero; for (var k = 0; k <= j; k++) { - z += dataEv[(k * order) + i] * matrixH[k, j]; + z += dataEv[(k*order) + i]*matrixH[jO + k]; } - dataEv[(j * order) + i] = z; + dataEv[jO + i] = z; } } } - + /// /// Solves a system of linear equations, AX = B, with A SVD factorized. /// /// The right hand side , B. /// The left hand side , X. - public override void Solve(Matrix input, Matrix result) + public override void Solve(Matrix input, Matrix result) { // Check for proper arguments. if (input == null) @@ -842,18 +847,18 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization if (IsSymmetric) { var order = VectorEv.Count; - var tmp = new Complex[order]; + var tmp = new System.Numerics.Complex[order]; for (var k = 0; k < order; k++) { for (var j = 0; j < order; j++) { - Complex value = 0.0; + System.Numerics.Complex value = 0.0; if (j < order) { for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(j * order) + i].Conjugate() * input.At(i, k); + value += ((DenseMatrix) MatrixEv).Values[(j*order) + i].Conjugate()*input.At(i, k); } value /= VectorEv[j].Real; @@ -864,10 +869,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization for (var j = 0; j < order; j++) { - Complex value = 0.0; + System.Numerics.Complex value = 0.0; for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(i * order) + j] * tmp[i]; + value += ((DenseMatrix) MatrixEv).Values[(i*order) + j]*tmp[i]; } result.At(j, k, value); @@ -876,7 +881,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization } else { - throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); } } @@ -885,7 +890,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization /// /// The right hand side vector, b. /// The left hand side , x. - public override void Solve(Vector input, Vector result) + public override void Solve(Vector input, Vector result) { if (input == null) { @@ -914,8 +919,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization { // Symmetric case -> x = V * inv(λ) * VH * b; var order = VectorEv.Count; - var tmp = new Complex[order]; - Complex value; + var tmp = new System.Numerics.Complex[order]; + System.Numerics.Complex value; for (var j = 0; j < order; j++) { @@ -924,7 +929,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization { for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(j * order) + i].Conjugate() * input[i]; + value += ((DenseMatrix) MatrixEv).Values[(j*order) + i].Conjugate()*input[i]; } value /= VectorEv[j].Real; @@ -936,9 +941,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization for (var j = 0; j < order; j++) { value = 0; - for (int i = 0; i < order; i++) + for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(i * order) + j] * tmp[i]; + value += ((DenseMatrix) MatrixEv).Values[(i*order) + j]*tmp[i]; } result[j] = value; @@ -950,4 +955,4 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization } } } -} \ No newline at end of file +} diff --git a/src/Numerics/LinearAlgebra/Complex/Factorization/UserEvd.cs b/src/Numerics/LinearAlgebra/Complex/Factorization/UserEvd.cs index 2cc06d32..b8d6bed5 100644 --- a/src/Numerics/LinearAlgebra/Complex/Factorization/UserEvd.cs +++ b/src/Numerics/LinearAlgebra/Complex/Factorization/UserEvd.cs @@ -79,9 +79,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization IsSymmetric = true; - for (var i = 0; i < order & IsSymmetric; i++) + for (var i = 0; IsSymmetric && i < order; i++) { - for (var j = 0; j < order & IsSymmetric; j++) + for (var j = 0; IsSymmetric && j < order; j++) { IsSymmetric &= matrix.At(i, j) == matrix.At(j, i).Conjugate(); } diff --git a/src/Numerics/LinearAlgebra/Complex32/Factorization/DenseEvd.cs b/src/Numerics/LinearAlgebra/Complex32/Factorization/DenseEvd.cs index 7237f7d7..880a326a 100644 --- a/src/Numerics/LinearAlgebra/Complex32/Factorization/DenseEvd.cs +++ b/src/Numerics/LinearAlgebra/Complex32/Factorization/DenseEvd.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -27,12 +27,12 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // + + namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization { using System; - using System.Numerics; using Generic; - using Numerics; using Properties; /// @@ -73,48 +73,23 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization var order = matrix.RowCount; - // Initialize matricies for eigenvalues and eigenvectors + // Initialize matrices for eigenvalues and eigenvectors MatrixEv = DenseMatrix.Identity(order); MatrixD = matrix.CreateMatrix(order, order); - VectorEv = new LinearAlgebra.Complex.DenseVector(order); - + VectorEv = new Complex.DenseVector(order); + IsSymmetric = true; - for (var i = 0; i < order & IsSymmetric; i++) + for (var i = 0; IsSymmetric && i < order; i++) { - for (var j = 0; j < order & IsSymmetric; j++) + for (var j = 0; IsSymmetric && j < order; j++) { IsSymmetric &= matrix.At(i, j) == matrix.At(j, i).Conjugate(); } } - if (IsSymmetric) - { - var matrixCopy = matrix.ToArray(); - var tau = new Complex32[order]; - var d = new float[order]; - var e = new float[order]; - - SymmetricTridiagonalize(matrixCopy, d, e, tau, order); - SymmetricDiagonalize(((DenseMatrix)MatrixEv).Values, d, e, order); - SymmetricUntridiagonalize(((DenseMatrix)MatrixEv).Values, matrixCopy, tau, order); - - for (var i = 0; i < order; i++) - { - VectorEv[i] = new Complex(d[i], e[i]); - } - } - else - { - var matrixH = matrix.ToArray(); - NonsymmetricReduceToHessenberg(((DenseMatrix)MatrixEv).Values, matrixH, order); - NonsymmetricReduceHessenberToRealSchur(((LinearAlgebra.Complex.DenseVector)VectorEv).Values, ((DenseMatrix)MatrixEv).Values, matrixH, order); - } - - for (var i = 0; i < VectorEv.Count; i++) - { - MatrixD.At(i, i, (Complex32)VectorEv[i]); - } + Control.LinearAlgebraProvider.EigenDecomp(IsSymmetric, order, matrix.Values, ((DenseMatrix) MatrixEv).Values, + ((Complex.DenseVector) VectorEv).Values, ((DenseMatrix) MatrixD).Values); } /// @@ -129,14 +104,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization /// Smith, Boyle, Dongarra, Garbow, Ikebe, Klema, Moler, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricTridiagonalize(Complex32[,] matrixA, float[] d, float[] e, Complex32[] tau, int order) + internal static void SymmetricTridiagonalize(Numerics.Complex32[] matrixA, float[] d, float[] e, Numerics.Complex32[] tau, int order) { float hh; - tau[order - 1] = Complex32.One; + tau[order - 1] = Numerics.Complex32.One; for (var i = 0; i < order; i++) { - d[i] = matrixA[i, i].Real; + d[i] = matrixA[i*order + i].Real; } // Householder reduction to tridiagonal form. @@ -148,95 +123,96 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization for (var k = 0; k < i; k++) { - scale = scale + Math.Abs(matrixA[i, k].Real) + Math.Abs(matrixA[i, k].Imaginary); + scale = scale + Math.Abs(matrixA[k*order + i].Real) + Math.Abs(matrixA[k*order + i].Imaginary); } if (scale == 0.0f) { - tau[i - 1] = Complex32.One; + tau[i - 1] = Numerics.Complex32.One; e[i] = 0.0f; } else { for (var k = 0; k < i; k++) { - matrixA[i, k] /= scale; - h += matrixA[i, k].MagnitudeSquared; + matrixA[k*order + i] /= scale; + h += matrixA[k*order + i].MagnitudeSquared; } - Complex32 g = (float)Math.Sqrt(h); - e[i] = scale * g.Real; + Numerics.Complex32 g = (float) Math.Sqrt(h); + e[i] = scale*g.Real; - Complex32 temp; - var f = matrixA[i, i - 1]; - if (f.Magnitude != 0) + Numerics.Complex32 temp; + var im1Oi = (i - 1)*order + i; + var f = matrixA[im1Oi]; + if (f.Magnitude != 0.0f) { - temp = -(matrixA[i, i - 1].Conjugate() * tau[i].Conjugate()) / f.Magnitude; - h += f.Magnitude * g.Real; - g = 1.0f + (g / f.Magnitude); - matrixA[i, i - 1] *= g; + temp = -(matrixA[im1Oi].Conjugate()*tau[i].Conjugate())/f.Magnitude; + h += f.Magnitude*g.Real; + g = 1.0f + (g/f.Magnitude); + matrixA[im1Oi] *= g; } else { temp = -tau[i].Conjugate(); - matrixA[i, i - 1] = g; + matrixA[im1Oi] = g; } - if ((f.Magnitude == 0) || (i != 1)) + if ((f.Magnitude == 0.0f) || (i != 1)) { - f = Complex32.Zero; + f = Numerics.Complex32.Zero; for (var j = 0; j < i; j++) { - var tmp = Complex32.Zero; - + var tmp = Numerics.Complex32.Zero; + var jO = j*order; // Form element of A*U. for (var k = 0; k <= j; k++) { - tmp += matrixA[j, k] * matrixA[i, k].Conjugate(); + tmp += matrixA[k*order + j]*matrixA[k*order + i].Conjugate(); } for (var k = j + 1; k <= i - 1; k++) { - tmp += matrixA[k, j].Conjugate() * matrixA[i, k].Conjugate(); + tmp += matrixA[jO + k].Conjugate()*matrixA[k*order + i].Conjugate(); } // Form element of P - tau[j] = tmp / h; - f += (tmp / h) * matrixA[i, j]; + tau[j] = tmp/h; + f += (tmp/h)*matrixA[jO + i]; } - hh = f.Real / (h + h); + hh = f.Real/(h + h); // Form the reduced A. for (var j = 0; j < i; j++) { - f = matrixA[i, j].Conjugate(); - g = tau[j] - (hh * f); + f = matrixA[j*order + i].Conjugate(); + g = tau[j] - (hh*f); tau[j] = g.Conjugate(); for (var k = 0; k <= j; k++) { - matrixA[j, k] -= (f * tau[k]) + (g * matrixA[i, k]); + matrixA[k*order + j] -= (f*tau[k]) + (g*matrixA[k*order + i]); } } } for (var k = 0; k < i; k++) { - matrixA[i, k] *= scale; + matrixA[k*order + i] *= scale; } tau[i - 1] = temp.Conjugate(); } hh = d[i]; - d[i] = matrixA[i, i].Real; - matrixA[i, i] = new Complex32(hh, scale * (float)Math.Sqrt(h)); + d[i] = matrixA[i*order + i].Real; + matrixA[i*order + i] = new Numerics.Complex32(hh, scale*(float) Math.Sqrt(h)); } hh = d[0]; - d[0] = matrixA[0, 0].Real; - matrixA[0, 0] = hh; + d[0] = matrixA[0].Real; + matrixA[0] = hh; e[0] = 0.0f; } @@ -251,7 +227,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization /// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricDiagonalize(Complex32[] dataEv, float[] d, float[] e, int order) + internal static void SymmetricDiagonalize(Numerics.Complex32[] dataEv, float[] d, float[] e, int order) { const int Maxiter = 1000; @@ -272,7 +248,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization var m = l; while (m < order) { - if (Math.Abs(e[m]) <= eps * tst1) + if (Math.Abs(e[m]) <= eps*tst1) { break; } @@ -291,15 +267,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization // Compute implicit shift var g = d[l]; - var p = (d[l + 1] - g) / (2.0f * e[l]); + var p = (d[l + 1] - g)/(2.0f*e[l]); var r = SpecialFunctions.Hypotenuse(p, 1.0f); if (p < 0) { r = -r; } - d[l] = e[l] / (p + r); - d[l + 1] = e[l] * (p + r); + d[l] = e[l]/(p + r); + d[l + 1] = e[l]*(p + r); var dl1 = d[l + 1]; var h = g - d[l]; @@ -323,27 +299,27 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization c3 = c2; c2 = c; s2 = s; - g = c * e[i]; - h = c * p; + g = c*e[i]; + h = c*p; r = SpecialFunctions.Hypotenuse(p, e[i]); - e[i + 1] = s * r; - s = e[i] / r; - c = p / r; - p = (c * d[i]) - (s * g); - d[i + 1] = h + (s * ((c * g) + (s * d[i]))); + e[i + 1] = s*r; + s = e[i]/r; + c = p/r; + p = (c*d[i]) - (s*g); + d[i + 1] = h + (s*((c*g) + (s*d[i]))); // Accumulate transformation. for (var k = 0; k < order; k++) { - h = dataEv[((i + 1) * order) + k].Real; - dataEv[((i + 1) * order) + k] = (s * dataEv[(i * order) + k].Real) + (c * h); - dataEv[(i * order) + k] = (c * dataEv[(i * order) + k].Real) - (s * h); + h = dataEv[((i + 1)*order) + k].Real; + dataEv[((i + 1)*order) + k] = (s*dataEv[(i*order) + k].Real) + (c*h); + dataEv[(i*order) + k] = (c*dataEv[(i*order) + k].Real) - (s*h); } } - p = (-s) * s2 * c3 * el1 * e[l] / dl1; - e[l] = s * p; - d[l] = c * p; + p = (-s)*s2*c3*el1*e[l]/dl1; + e[l] = s*p; + d[l] = c*p; // Check for convergence. If too many iterations have been performed, // throw exception that Convergence Failed @@ -351,8 +327,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization { throw new ArgumentException(Resources.ConvergenceFailed); } - } - while (Math.Abs(e[l]) > eps * tst1); + } while (Math.Abs(e[l]) > eps*tst1); } d[l] = d[l] + f; @@ -379,9 +354,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization d[i] = p; for (var j = 0; j < order; j++) { - p = dataEv[(i * order) + j].Real; - dataEv[(i * order) + j] = dataEv[(k * order) + j]; - dataEv[(k * order) + j] = p; + p = dataEv[(i*order) + j].Real; + dataEv[(i*order) + j] = dataEv[(k*order) + j]; + dataEv[(k*order) + j] = p; } } } @@ -398,35 +373,35 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization /// by Smith, Boyle, Dongarra, Garbow, Ikebe, Klema, Moler, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricUntridiagonalize(Complex32[] dataEv, Complex32[,] matrixA, Complex32[] tau, int order) + internal static void SymmetricUntridiagonalize(Numerics.Complex32[] dataEv, Numerics.Complex32[] matrixA, Numerics.Complex32[] tau, int order) { for (var i = 0; i < order; i++) { for (var j = 0; j < order; j++) { - dataEv[(j * order) + i] = dataEv[(j * order) + i].Real * tau[i].Conjugate(); + dataEv[(j*order) + i] = dataEv[(j*order) + i].Real*tau[i].Conjugate(); } } // Recover and apply the Householder matrices. for (var i = 1; i < order; i++) { - var h = matrixA[i, i].Imaginary; + var h = matrixA[i*order + i].Imaginary; if (h != 0) { for (var j = 0; j < order; j++) { - var s = Complex32.Zero; + var s = Numerics.Complex32.Zero; for (var k = 0; k < i; k++) { - s += dataEv[(j * order) + k] * matrixA[i, k]; + s += dataEv[(j*order) + k]*matrixA[k*order + i]; } - s = (s / h) / h; + s = (s/h)/h; for (var k = 0; k < i; k++) { - dataEv[(j * order) + k] -= s * matrixA[i, k].Conjugate(); + dataEv[(j*order) + k] -= s*matrixA[k*order + i].Conjugate(); } } } @@ -443,17 +418,18 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization /// by Martin and Wilkinson, Handbook for Auto. Comp., /// Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutines in EISPACK. - private static void NonsymmetricReduceToHessenberg(Complex32[] dataEv, Complex32[,] matrixH, int order) + internal static void NonsymmetricReduceToHessenberg(Numerics.Complex32[] dataEv, Numerics.Complex32[] matrixH, int order) { - var ort = new Complex32[order]; + var ort = new Numerics.Complex32[order]; for (var m = 1; m < order - 1; m++) { // Scale column. var scale = 0.0f; + var mm1O = (m - 1)*order; for (var i = m; i < order; i++) { - scale += Math.Abs(matrixH[i, m - 1].Real) + Math.Abs(matrixH[i, m - 1].Imaginary); + scale += Math.Abs(matrixH[mm1O + i].Real) + Math.Abs(matrixH[mm1O + i].Imaginary); } if (scale != 0.0f) @@ -462,57 +438,58 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization var h = 0.0f; for (var i = order - 1; i >= m; i--) { - ort[i] = matrixH[i, m - 1] / scale; + ort[i] = matrixH[mm1O + i]/scale; h += ort[i].MagnitudeSquared; } - var g = (float)Math.Sqrt(h); + var g = (float) Math.Sqrt(h); if (ort[m].Magnitude != 0) { - h = h + (ort[m].Magnitude * g); + h = h + (ort[m].Magnitude*g); g /= ort[m].Magnitude; - ort[m] = (1.0f + g) * ort[m]; + ort[m] = (1.0f + g)*ort[m]; } else { ort[m] = g; - matrixH[m, m - 1] = scale; + matrixH[mm1O + m] = scale; } // Apply Householder similarity transformation // H = (I-u*u'/h)*H*(I-u*u')/h) for (var j = m; j < order; j++) { - var f = Complex32.Zero; + var f = Numerics.Complex32.Zero; + var jO = j*order; for (var i = order - 1; i >= m; i--) { - f += ort[i].Conjugate() * matrixH[i, j]; + f += ort[i].Conjugate()*matrixH[jO + i]; } - f = f / h; + f = f/h; for (var i = m; i < order; i++) { - matrixH[i, j] -= f * ort[i]; + matrixH[jO + i] -= f*ort[i]; } } for (var i = 0; i < order; i++) { - var f = Complex32.Zero; + var f = Numerics.Complex32.Zero; for (var j = order - 1; j >= m; j--) { - f += ort[j] * matrixH[i, j]; + f += ort[j]*matrixH[j*order + i]; } - f = f / h; + f = f/h; for (var j = m; j < order; j++) { - matrixH[i, j] -= f * ort[j].Conjugate(); + matrixH[j*order + i] -= f*ort[j].Conjugate(); } } - ort[m] = scale * ort[m]; - matrixH[m, m - 1] *= -g; + ort[m] = scale*ort[m]; + matrixH[mm1O + m] *= -g; } } @@ -521,59 +498,65 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization { for (var j = 0; j < order; j++) { - dataEv[(j * order) + i] = i == j ? Complex32.One : Complex32.Zero; + dataEv[(j*order) + i] = i == j ? Numerics.Complex32.One : Numerics.Complex32.Zero; } } for (var m = order - 2; m >= 1; m--) { - if (matrixH[m, m - 1] != Complex32.Zero && ort[m] != Complex32.Zero) + var mm1O = (m - 1)*order; + var mm1Om = mm1O + m; + if (matrixH[mm1Om] != Numerics.Complex32.Zero && ort[m] != Numerics.Complex32.Zero) { - var norm = (matrixH[m, m - 1].Real * ort[m].Real) + (matrixH[m, m - 1].Imaginary * ort[m].Imaginary); + var norm = (matrixH[mm1Om].Real*ort[m].Real) + (matrixH[mm1Om].Imaginary*ort[m].Imaginary); for (var i = m + 1; i < order; i++) { - ort[i] = matrixH[i, m - 1]; + ort[i] = matrixH[mm1O + i]; } for (var j = m; j < order; j++) { - var g = Complex32.Zero; + var g = Numerics.Complex32.Zero; for (var i = m; i < order; i++) { - g += ort[i].Conjugate() * dataEv[(j * order) + i]; + g += ort[i].Conjugate()*dataEv[(j*order) + i]; } // Double division avoids possible underflow g /= norm; for (var i = m; i < order; i++) { - dataEv[(j * order) + i] += g * ort[i]; + dataEv[(j*order) + i] += g*ort[i]; } } } } - + // Create real subdiagonal elements. for (var i = 1; i < order; i++) { - if (matrixH[i, i - 1].Imaginary != 0.0f) + var im1 = i - 1; + var im1O = im1*order; + var im1Oi = im1O + i; + var iO = i*order; + if (matrixH[im1Oi].Imaginary != 0.0f) { - var y = matrixH[i, i - 1] / matrixH[i, i - 1].Magnitude; - matrixH[i, i - 1] = matrixH[i, i - 1].Magnitude; + var y = matrixH[im1Oi]/matrixH[im1Oi].Magnitude; + matrixH[im1Oi] = matrixH[im1Oi].Magnitude; for (var j = i; j < order; j++) { - matrixH[i, j] *= y.Conjugate(); + matrixH[j*order + i] *= y.Conjugate(); } for (var j = 0; j <= Math.Min(i + 1, order - 1); j++) { - matrixH[j, i] *= y; + matrixH[iO + j] *= y; } for (var j = 0; j < order; j++) { - dataEv[(i * order) + j] *= y; + dataEv[(i*order) + j] *= y; } } } @@ -590,14 +573,14 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization /// by Martin and Wilkinson, Handbook for Auto. Comp., /// Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void NonsymmetricReduceHessenberToRealSchur(Complex[] vectorV, Complex32[] dataEv, Complex32[,] matrixH, int order) + internal static void NonsymmetricReduceHessenberToRealSchur(Numerics.Complex32[] vectorV, Numerics.Complex32[] dataEv, Numerics.Complex32[] matrixH, int order) { // Initialize var n = order - 1; - var eps = (float)Precision.SingleMachinePrecision; + var eps = (float) Precision.SingleMachinePrecision; float norm; - Complex32 x, y, z, exshift = Complex32.Zero; + Numerics.Complex32 x, y, z, exshift = Numerics.Complex32.Zero; // Outer loop over eigenvalue index var iter = 0; @@ -607,8 +590,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization var l = n; while (l > 0) { - var tst1 = Math.Abs(matrixH[l - 1, l - 1].Real) + Math.Abs(matrixH[l - 1, l - 1].Imaginary) + Math.Abs(matrixH[l, l].Real) + Math.Abs(matrixH[l, l].Imaginary); - if (Math.Abs(matrixH[l, l - 1].Real) < eps * tst1) + var lm1 = l - 1; + var lm1O = lm1*order; + var lO = l*order; + var tst1 = Math.Abs(matrixH[lm1O + lm1].Real) + Math.Abs(matrixH[lm1O + lm1].Imaginary) + Math.Abs(matrixH[lO + l].Real) + Math.Abs(matrixH[lO + l].Imaginary); + if (Math.Abs(matrixH[lm1O + l].Real) < eps*tst1) { break; } @@ -616,46 +602,50 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization l--; } + var nm1 = n - 1; + var nm1O = nm1*order; + var nO = n*order; + var nOn = nO + n; // Check for convergence // One root found if (l == n) { - matrixH[n, n] += exshift; - vectorV[n] = matrixH[n, n].ToComplex(); + matrixH[nOn] += exshift; + vectorV[n] = matrixH[nOn]; n--; iter = 0; } else { // Form shift - Complex32 s; + Numerics.Complex32 s; if (iter != 10 && iter != 20) { - s = matrixH[n, n]; - x = matrixH[n - 1, n] * matrixH[n, n - 1].Real; + s = matrixH[nOn]; + x = matrixH[nO + nm1]*matrixH[nm1O + n].Real; if (x.Real != 0.0f || x.Imaginary != 0.0f) { - y = (matrixH[n - 1, n - 1] - s) / 2.0f; - z = ((y * y) + x).SquareRoot(); - if ((y.Real * z.Real) + (y.Imaginary * z.Imaginary) < 0.0f) + y = (matrixH[nm1O + nm1] - s)/2.0f; + z = ((y*y) + x).SquareRoot(); + if ((y.Real*z.Real) + (y.Imaginary*z.Imaginary) < 0.0) { z *= -1.0f; } - x /= y + z; + x /= y + z; s = s - x; } } else { // Form exceptional shift - s = Math.Abs(matrixH[n, n - 1].Real) + Math.Abs(matrixH[n - 1, n - 2].Real); + s = Math.Abs(matrixH[nm1O + n].Real) + Math.Abs(matrixH[(n - 2)*order + nm1].Real); } for (var i = 0; i <= n; i++) { - matrixH[i, i] -= s; + matrixH[i*order + i] -= s; } exshift += s; @@ -664,61 +654,70 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization // Reduce to triangle (rows) for (var i = l + 1; i <= n; i++) { - s = matrixH[i, i - 1].Real; - norm = SpecialFunctions.Hypotenuse(matrixH[i - 1, i - 1].Magnitude, s.Real); - x = matrixH[i - 1, i - 1] / norm; - vectorV[i - 1] = x.ToComplex(); - matrixH[i - 1, i - 1] = norm; - matrixH[i, i - 1] = new Complex32(0.0f, s.Real / norm); + var im1 = i - 1; + var im1O = im1*order; + var im1Oim1 = im1O + im1; + s = matrixH[im1O + i].Real; + norm = SpecialFunctions.Hypotenuse(matrixH[im1Oim1].Magnitude, s.Real); + x = matrixH[im1Oim1]/norm; + vectorV[i - 1] = x; + matrixH[im1Oim1] = norm; + matrixH[im1O + i] = new Numerics.Complex32(0.0f, s.Real/norm); for (var j = i; j < order; j++) { - y = matrixH[i - 1, j]; - z = matrixH[i, j]; - matrixH[i - 1, j] = (x.Conjugate() * y) + (matrixH[i, i - 1].Imaginary * z); - matrixH[i, j] = (x * z) - (matrixH[i, i - 1].Imaginary * y); + var jO = j*order; + y = matrixH[jO + im1]; + z = matrixH[jO + i]; + matrixH[jO + im1] = (x.Conjugate()*y) + (matrixH[im1O + i].Imaginary*z); + matrixH[jO + i] = (x*z) - (matrixH[im1O + i].Imaginary*y); } } - s = matrixH[n, n]; + s = matrixH[nOn]; if (s.Imaginary != 0.0f) { - s /= matrixH[n, n].Magnitude; - matrixH[n, n] = matrixH[n, n].Magnitude; + s /= matrixH[nOn].Magnitude; + matrixH[nOn] = matrixH[nOn].Magnitude; for (var j = n + 1; j < order; j++) { - matrixH[n, j] *= s.Conjugate(); + matrixH[j*order + n] *= s.Conjugate(); } } // Inverse operation (columns). for (var j = l + 1; j <= n; j++) { - x = (Complex32)vectorV[j - 1]; + x = vectorV[j - 1]; + var jO = j*order; + var jm1 = j - 1; + var jm1O = jm1*order; + var jm1Oj = jm1O + j; for (var i = 0; i <= j; i++) { - z = matrixH[i, j]; + var jm1Oi = jm1O + i; + z = matrixH[jO + i]; if (i != j) { - y = matrixH[i, j - 1]; - matrixH[i, j - 1] = (x * y) + (matrixH[j, j - 1].Imaginary * z); + y = matrixH[jm1Oi]; + matrixH[jm1Oi] = (x*y) + (matrixH[jm1O + j].Imaginary*z); } else { - y = matrixH[i, j - 1].Real; - matrixH[i, j - 1] = new Complex32((x.Real * y.Real) - (x.Imaginary * y.Imaginary) + (matrixH[j, j - 1].Imaginary * z.Real), matrixH[i, j - 1].Imaginary); + y = matrixH[jm1Oi].Real; + matrixH[jm1Oi] = new Numerics.Complex32((x.Real*y.Real) - (x.Imaginary*y.Imaginary) + (matrixH[jm1O + j].Imaginary*z.Real), matrixH[jm1Oi].Imaginary); } - matrixH[i, j] = (x.Conjugate() * z) - (matrixH[j, j - 1].Imaginary * y); + matrixH[jO + i] = (x.Conjugate()*z) - (matrixH[jm1O + j].Imaginary*y); } for (var i = 0; i < order; i++) { - y = dataEv[((j - 1) * order) + i]; - z = dataEv[(j * order) + i]; - dataEv[((j - 1) * order) + i] = (x * y) + (matrixH[j, j - 1].Imaginary * z); - dataEv[(j * order) + i] = (x.Conjugate() * z) - (matrixH[j, j - 1].Imaginary * y); + y = dataEv[((j - 1)*order) + i]; + z = dataEv[(j*order) + i]; + dataEv[jm1O + i] = (x*y) + (matrixH[jm1Oj].Imaginary*z); + dataEv[jO + i] = (x.Conjugate()*z) - (matrixH[jm1Oj].Imaginary*y); } } @@ -726,12 +725,12 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization { for (var i = 0; i <= n; i++) { - matrixH[i, n] *= s; + matrixH[nO + i] *= s; } for (var i = 0; i < order; i++) { - dataEv[(n * order) + i] *= s; + dataEv[nO + i] *= s; } } } @@ -744,7 +743,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization { for (var j = i; j < order; j++) { - norm = Math.Max(norm, Math.Abs(matrixH[i, j].Real) + Math.Abs(matrixH[i, j].Imaginary)); + norm = Math.Max(norm, Math.Abs(matrixH[j*order + i].Real) + Math.Abs(matrixH[j*order + i].Imaginary)); } } @@ -753,39 +752,41 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization return; } - if (norm == 0.0f) + if (norm == 0.0) { return; } for (n = order - 1; n > 0; n--) { - x = (Complex32)vectorV[n]; - matrixH[n, n] = 1.0f; + var nO = n*order; + var nOn = nO + n; + x = vectorV[n]; + matrixH[nOn] = 1.0f; for (var i = n - 1; i >= 0; i--) { z = 0.0f; for (var j = i + 1; j <= n; j++) { - z += matrixH[i, j] * matrixH[j, n]; + z += matrixH[j*order + i]*matrixH[nO + j]; } - y = x - (Complex32)vectorV[i]; + y = x - vectorV[i]; if (y.Real == 0.0f && y.Imaginary == 0.0f) { - y = eps * norm; + y = eps*norm; } - matrixH[i, n] = z / y; + matrixH[nO + i] = z/y; // Overflow control - var tr = Math.Abs(matrixH[i, n].Real) + Math.Abs(matrixH[i, n].Imaginary); - if ((eps * tr) * tr > 1) + var tr = Math.Abs(matrixH[nO + i].Real) + Math.Abs(matrixH[nO + i].Imaginary); + if ((eps*tr)*tr > 1) { for (var j = i; j <= n; j++) { - matrixH[j, n] = matrixH[j, n] / tr; + matrixH[nO + j] = matrixH[nO + j]/tr; } } } @@ -794,25 +795,26 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization // Back transformation to get eigenvectors of original matrix for (var j = order - 1; j > 0; j--) { + var jO = j*order; for (var i = 0; i < order; i++) { - z = Complex32.Zero; + z = Numerics.Complex32.Zero; for (var k = 0; k <= j; k++) { - z += dataEv[(k * order) + i] * matrixH[k, j]; + z += dataEv[(k*order) + i]*matrixH[jO + k]; } - dataEv[(j * order) + i] = z; + dataEv[jO + i] = z; } } } - + /// /// Solves a system of linear equations, AX = B, with A SVD factorized. /// /// The right hand side , B. /// The left hand side , X. - public override void Solve(Matrix input, Matrix result) + public override void Solve(Matrix input, Matrix result) { // Check for proper arguments. if (input == null) @@ -846,21 +848,21 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization if (IsSymmetric) { var order = VectorEv.Count; - var tmp = new Complex32[order]; + var tmp = new Numerics.Complex32[order]; for (var k = 0; k < order; k++) { for (var j = 0; j < order; j++) { - Complex32 value = 0.0f; + Numerics.Complex32 value = 0.0f; if (j < order) { for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(j * order) + i].Conjugate() * input.At(i, k); + value += ((DenseMatrix) MatrixEv).Values[(j*order) + i].Conjugate()*input.At(i, k); } - value /= (float)VectorEv[j].Real; + value /= (float) VectorEv[j].Real; } tmp[j] = value; @@ -868,10 +870,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization for (var j = 0; j < order; j++) { - Complex32 value = 0.0f; + Numerics.Complex32 value = 0.0f; for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(i * order) + j] * tmp[i]; + value += ((DenseMatrix) MatrixEv).Values[(i*order) + j]*tmp[i]; } result.At(j, k, value); @@ -880,7 +882,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization } else { - throw new ArgumentException(Resources.ArgumentMatrixSymmetric); + throw new ArgumentException(Resources.ArgumentMatrixSymmetric); } } @@ -889,7 +891,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization /// /// The right hand side vector, b. /// The left hand side , x. - public override void Solve(Vector input, Vector result) + public override void Solve(Vector input, Vector result) { if (input == null) { @@ -918,8 +920,8 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization { // Symmetric case -> x = V * inv(λ) * VH * b; var order = VectorEv.Count; - var tmp = new Complex32[order]; - Complex32 value; + var tmp = new Numerics.Complex32[order]; + Numerics.Complex32 value; for (var j = 0; j < order; j++) { @@ -928,10 +930,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization { for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(j * order) + i].Conjugate() * input[i]; + value += ((DenseMatrix) MatrixEv).Values[(j*order) + i].Conjugate()*input[i]; } - value /= (float)VectorEv[j].Real; + value /= (float) VectorEv[j].Real; } tmp[j] = value; @@ -940,9 +942,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization for (var j = 0; j < order; j++) { value = 0; - for (int i = 0; i < order; i++) + for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(i * order) + j] * tmp[i]; + value += ((DenseMatrix) MatrixEv).Values[(i*order) + j]*tmp[i]; } result[j] = value; @@ -954,4 +956,4 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization } } } -} \ No newline at end of file +} diff --git a/src/Numerics/LinearAlgebra/Complex32/Factorization/UserEvd.cs b/src/Numerics/LinearAlgebra/Complex32/Factorization/UserEvd.cs index c39b6118..d91773ac 100644 --- a/src/Numerics/LinearAlgebra/Complex32/Factorization/UserEvd.cs +++ b/src/Numerics/LinearAlgebra/Complex32/Factorization/UserEvd.cs @@ -80,9 +80,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization IsSymmetric = true; - for (var i = 0; i < order & IsSymmetric; i++) + for (var i = 0; IsSymmetric && i < order; i++) { - for (var j = 0; j < order & IsSymmetric; j++) + for (var j = 0; IsSymmetric && j < order; j++) { IsSymmetric &= matrix.At(i, j) == matrix.At(j, i).Conjugate(); } diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/DenseEvd.cs b/src/Numerics/LinearAlgebra/Double/Factorization/DenseEvd.cs index 6479df99..100e4292 100644 --- a/src/Numerics/LinearAlgebra/Double/Factorization/DenseEvd.cs +++ b/src/Numerics/LinearAlgebra/Double/Factorization/DenseEvd.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -27,6 +27,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // + namespace MathNet.Numerics.LinearAlgebra.Double.Factorization { using System; @@ -72,58 +73,23 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization var order = matrix.RowCount; - // Initialize matricies for eigenvalues and eigenvectors + // Initialize matrices for eigenvalues and eigenvectors MatrixEv = matrix.CreateMatrix(order, order); MatrixD = matrix.CreateMatrix(order, order); VectorEv = new LinearAlgebra.Complex.DenseVector(order); - + IsSymmetric = true; - for (var i = 0; i < order & IsSymmetric; i++) + for (var i = 0; IsSymmetric && i < order; i++) { - for (var j = 0; j < order & IsSymmetric; j++) + for (var j = 0; IsSymmetric && j < order; j++) { IsSymmetric &= matrix.At(i, j) == matrix.At(j, i); } } - var d = new double[order]; - var e = new double[order]; - - if (IsSymmetric) - { - matrix.CopyTo(MatrixEv); - d = MatrixEv.Row(order - 1).ToArray(); - - SymmetricTridiagonalize(((DenseMatrix)MatrixEv).Values, d, e, order); - SymmetricDiagonalize(((DenseMatrix)MatrixEv).Values, d, e, order); - } - else - { - var matrixH = matrix.ToArray(); - - NonsymmetricReduceToHessenberg(((DenseMatrix)MatrixEv).Values, matrixH, order); - NonsymmetricReduceHessenberToRealSchur(((DenseMatrix)MatrixEv).Values, matrixH, d, e, order); - } - - for (var i = 0; i < order; i++) - { - MatrixD.At(i, i, d[i]); - - if (e[i] > 0) - { - MatrixD.At(i, i + 1, e[i]); - } - else if (e[i] < 0) - { - MatrixD.At(i, i - 1, e[i]); - } - } - - for (var i = 0; i < order; i++) - { - VectorEv[i] = new Complex(d[i], e[i]); - } + Control.LinearAlgebraProvider.EigenDecomp(IsSymmetric, order, matrix.Values, ((DenseMatrix) MatrixEv).Values, + ((LinearAlgebra.Complex.DenseVector)VectorEv).Values, ((DenseMatrix)MatrixD).Values); } /// @@ -137,7 +103,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization /// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricTridiagonalize(double[] a, double[] d, double[] e, int order) + internal static void SymmetricTridiagonalize(double[] a, double[] d, double[] e, int order) { // Householder reduction to tridiagonal form. for (var i = order - 1; i > 0; i--) @@ -156,9 +122,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization e[i] = d[i - 1]; for (var j = 0; j < i; j++) { - d[j] = a[(j * order) + i - 1]; - a[(j * order) + i] = 0.0; - a[(i * order) + j] = 0.0; + d[j] = a[(j*order) + i - 1]; + a[(j*order) + i] = 0.0; + a[(i*order) + j] = 0.0; } } else @@ -167,7 +133,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization for (var k = 0; k < i; k++) { d[k] /= scale; - h += d[k] * d[k]; + h += d[k]*d[k]; } var f = d[i - 1]; @@ -177,8 +143,8 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization g = -g; } - e[i] = scale * g; - h = h - (f * g); + e[i] = scale*g; + h = h - (f*g); d[i - 1] = f - g; for (var j = 0; j < i; j++) @@ -190,13 +156,13 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization for (var j = 0; j < i; j++) { f = d[j]; - a[(i * order) + j] = f; - g = e[j] + (a[(j * order) + j] * f); + a[(i*order) + j] = f; + g = e[j] + (a[(j*order) + j]*f); for (var k = j + 1; k <= i - 1; k++) { - g += a[(j * order) + k] * d[k]; - e[k] += a[(j * order) + k] * f; + g += a[(j*order) + k]*d[k]; + e[k] += a[(j*order) + k]*f; } e[j] = g; @@ -207,14 +173,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization for (var j = 0; j < i; j++) { e[j] /= h; - f += e[j] * d[j]; + f += e[j]*d[j]; } - var hh = f / (h + h); + var hh = f/(h + h); for (var j = 0; j < i; j++) { - e[j] -= hh * d[j]; + e[j] -= hh*d[j]; } for (var j = 0; j < i; j++) @@ -224,11 +190,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization for (var k = j; k <= i - 1; k++) { - a[(j * order) + k] -= (f * e[k]) + (g * d[k]); + a[(j*order) + k] -= (f*e[k]) + (g*d[k]); } - d[j] = a[(j * order) + i - 1]; - a[(j * order) + i] = 0.0; + d[j] = a[(j*order) + i - 1]; + a[(j*order) + i] = 0.0; } } @@ -238,14 +204,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization // Accumulate transformations. for (var i = 0; i < order - 1; i++) { - a[(i * order) + order - 1] = a[(i * order) + i]; - a[(i * order) + i] = 1.0; + a[(i*order) + order - 1] = a[(i*order) + i]; + a[(i*order) + i] = 1.0; var h = d[i + 1]; if (h != 0.0) { for (var k = 0; k <= i; k++) { - d[k] = a[((i + 1) * order) + k] / h; + d[k] = a[((i + 1)*order) + k]/h; } for (var j = 0; j <= i; j++) @@ -253,29 +219,29 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization var g = 0.0; for (var k = 0; k <= i; k++) { - g += a[((i + 1) * order) + k] * a[(j * order) + k]; + g += a[((i + 1)*order) + k]*a[(j*order) + k]; } for (var k = 0; k <= i; k++) { - a[(j * order) + k] -= g * d[k]; + a[(j*order) + k] -= g*d[k]; } } } for (var k = 0; k <= i; k++) { - a[((i + 1) * order) + k] = 0.0; + a[((i + 1)*order) + k] = 0.0; } } for (var j = 0; j < order; j++) { - d[j] = a[(j * order) + order - 1]; - a[(j * order) + order - 1] = 0.0; + d[j] = a[(j*order) + order - 1]; + a[(j*order) + order - 1] = 0.0; } - a[(order * order) - 1] = 1.0; + a[(order*order) - 1] = 1.0; e[0] = 0.0; } @@ -290,9 +256,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization /// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricDiagonalize(double[] a, double[] d, double[] e, int order) + internal static void SymmetricDiagonalize(double[] a, double[] d, double[] e, int order) { - const int Maxiter = 1000; + const int maxiter = 1000; for (var i = 1; i < order; i++) { @@ -311,7 +277,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization var m = l; while (m < order) { - if (Math.Abs(e[m]) <= eps * tst1) + if (Math.Abs(e[m]) <= eps*tst1) { break; } @@ -330,15 +296,15 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization // Compute implicit shift var g = d[l]; - var p = (d[l + 1] - g) / (2.0 * e[l]); + var p = (d[l + 1] - g)/(2.0*e[l]); var r = SpecialFunctions.Hypotenuse(p, 1.0); if (p < 0) { r = -r; } - d[l] = e[l] / (p + r); - d[l + 1] = e[l] * (p + r); + d[l] = e[l]/(p + r); + d[l + 1] = e[l]*(p + r); var dl1 = d[l + 1]; var h = g - d[l]; @@ -362,36 +328,35 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization c3 = c2; c2 = c; s2 = s; - g = c * e[i]; - h = c * p; + g = c*e[i]; + h = c*p; r = SpecialFunctions.Hypotenuse(p, e[i]); - e[i + 1] = s * r; - s = e[i] / r; - c = p / r; - p = (c * d[i]) - (s * g); - d[i + 1] = h + (s * ((c * g) + (s * d[i]))); + e[i + 1] = s*r; + s = e[i]/r; + c = p/r; + p = (c*d[i]) - (s*g); + d[i + 1] = h + (s*((c*g) + (s*d[i]))); // Accumulate transformation. for (var k = 0; k < order; k++) { - h = a[((i + 1) * order) + k]; - a[((i + 1) * order) + k] = (s * a[(i * order) + k]) + (c * h); - a[(i * order) + k] = (c * a[(i * order) + k]) - (s * h); + h = a[((i + 1)*order) + k]; + a[((i + 1)*order) + k] = (s*a[(i*order) + k]) + (c*h); + a[(i*order) + k] = (c*a[(i*order) + k]) - (s*h); } } - p = (-s) * s2 * c3 * el1 * e[l] / dl1; - e[l] = s * p; - d[l] = c * p; + p = (-s)*s2*c3*el1*e[l]/dl1; + e[l] = s*p; + d[l] = c*p; // Check for convergence. If too many iterations have been performed, // throw exception that Convergence Failed - if (iter >= Maxiter) + if (iter >= maxiter) { throw new ArgumentException(Resources.ConvergenceFailed); } - } - while (Math.Abs(e[l]) > eps * tst1); + } while (Math.Abs(e[l]) > eps*tst1); } d[l] = d[l] + f; @@ -418,9 +383,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization d[i] = p; for (var j = 0; j < order; j++) { - p = a[(i * order) + j]; - a[(i * order) + j] = a[(k * order) + j]; - a[(k * order) + j] = p; + p = a[(i*order) + j]; + a[(i*order) + j] = a[(k*order) + j]; + a[(k*order) + j] = p; } } } @@ -436,27 +401,29 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization /// by Martin and Wilkinson, Handbook for Auto. Comp., /// Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutines in EISPACK. - private static void NonsymmetricReduceToHessenberg(double[] a, double[,] matrixH, int order) + internal static void NonsymmetricReduceToHessenberg(double[] a, double[] matrixH, int order) { var ort = new double[order]; - - for (var m = 1; m < order - 1; m++) + var high = order - 1; + for (var m = 1; m <= high - 1; m++) { + var mm1 = m - 1; + var mm1O = mm1*order; // Scale column. var scale = 0.0; - for (var i = m; i < order; i++) + for (var i = m; i <= high; i++) { - scale = scale + Math.Abs(matrixH[i, m - 1]); + scale += Math.Abs(matrixH[mm1O + i]); } if (scale != 0.0) { // Compute Householder transformation. var h = 0.0; - for (var i = order - 1; i >= m; i--) + for (var i = high; i >= m; i--) { - ort[i] = matrixH[i, m - 1] / scale; - h += ort[i] * ort[i]; + ort[i] = matrixH[mm1O + i]/scale; + h += ort[i]*ort[i]; } var g = Math.Sqrt(h); @@ -465,43 +432,45 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization g = -g; } - h = h - (ort[m] * g); + h = h - (ort[m]*g); ort[m] = ort[m] - g; // Apply Householder similarity transformation // H = (I-u*u'/h)*H*(I-u*u')/h) for (var j = m; j < order; j++) { + var jO = j*order; var f = 0.0; for (var i = order - 1; i >= m; i--) { - f += ort[i] * matrixH[i, j]; + f += ort[i]*matrixH[jO + i]; } - f = f / h; - for (var i = m; i < order; i++) + f = f/h; + + for (var i = m; i <= high; i++) { - matrixH[i, j] -= f * ort[i]; + matrixH[jO + i] -= f*ort[i]; } } - for (var i = 0; i < order; i++) + for (var i = 0; i <= high; i++) { var f = 0.0; - for (var j = order - 1; j >= m; j--) + for (var j = high; j >= m; j--) { - f += ort[j] * matrixH[i, j]; + f += ort[j]*matrixH[j*order + i]; } + f = f/h; - f = f / h; - for (var j = m; j < order; j++) + for (var j = m; j <= high; j++) { - matrixH[i, j] -= f * ort[j]; + matrixH[j*order + i] -= f*ort[j]; } } - ort[m] = scale * ort[m]; - matrixH[m, m - 1] = scale * g; + ort[m] = scale*ort[m]; + matrixH[mm1O + m] = scale*g; } } @@ -510,32 +479,37 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization { for (var j = 0; j < order; j++) { - a[(j * order) + i] = i == j ? 1.0 : 0.0; + a[(j*order) + i] = i == j ? 1.0 : 0.0; } } - for (var m = order - 2; m >= 1; m--) + for (var m = high - 1; m >= 1; m--) { - if (matrixH[m, m - 1] != 0.0) + var mm1 = m - 1; + var mm1O = mm1*order; + var mm1Om = mm1O + m; + if (matrixH[mm1Om] != 0.0) { - for (var i = m + 1; i < order; i++) + for (var i = m + 1; i <= high; i++) { - ort[i] = matrixH[i, m - 1]; + ort[i] = matrixH[mm1O + i]; } - for (var j = m; j < order; j++) + for (var j = m; j <= high; j++) { var g = 0.0; - for (var i = m; i < order; i++) + var jO = j*order; + for (var i = m; i <= high; i++) { - g += ort[i] * a[(j * order) + i]; + g += ort[i]*a[jO + i]; } // Double division avoids possible underflow - g = (g / ort[m]) / matrixH[m, m - 1]; - for (var i = m; i < order; i++) + g = (g/ort[m])/matrixH[mm1Om]; + + for (var i = m; i <= high; i++) { - a[(j * order) + i] += g * ort[i]; + a[jO + i] += g*ort[i]; } } } @@ -554,13 +528,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization /// by Martin and Wilkinson, Handbook for Auto. Comp., /// Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void NonsymmetricReduceHessenberToRealSchur(double[] a, double[,] matrixH, double[] d, double[] e, int order) + internal static void NonsymmetricReduceHessenberToRealSchur(double[] a, double[] matrixH, double[] d, double[] e, int order) { // Initialize var n = order - 1; - var eps = Precision.DoubleMachinePrecision; + var eps = Math.Pow(2.0, -52.0); var exshift = 0.0; - double p = 0, q = 0, r = 0, s = 0, z = 0, w, x, y; + double p = 0, q = 0, r = 0, s = 0, z = 0; + double w, x, y; // Store roots isolated by balanc and compute matrix norm var norm = 0.0; @@ -568,7 +543,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization { for (var j = Math.Max(i - 1, 0); j < order; j++) { - norm = norm + Math.Abs(matrixH[i, j]); + norm = norm + Math.Abs(matrixH[j*order + i]); } } @@ -580,14 +555,16 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization var l = n; while (l > 0) { - s = Math.Abs(matrixH[l - 1, l - 1]) + Math.Abs(matrixH[l, l]); + var lm1 = l - 1; + var lm1O = lm1*order; + s = Math.Abs(matrixH[lm1O + lm1]) + Math.Abs(matrixH[l*order + l]); if (s == 0.0) { s = norm; } - if (Math.Abs(matrixH[l, l - 1]) < eps * s) + if (Math.Abs(matrixH[lm1O + l]) < eps*s) { break; } @@ -599,8 +576,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization // One root found if (l == n) { - matrixH[n, n] = matrixH[n, n] + exshift; - d[n] = matrixH[n, n]; + var index = n*order + n; + matrixH[index] += exshift; + d[n] = matrixH[index]; e[n] = 0.0; n--; iter = 0; @@ -609,13 +587,19 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization } else if (l == n - 1) { - w = matrixH[n, n - 1] * matrixH[n - 1, n]; - p = (matrixH[n - 1, n - 1] - matrixH[n, n]) / 2.0; - q = (p * p) + w; + var nO = n*order; + var nm1 = n - 1; + var nm1O = nm1*order; + var nOn = nO + n; + + w = matrixH[nm1O + n]*matrixH[nO + nm1]; + p = (matrixH[nm1O + nm1] - matrixH[nOn])/2.0; + q = (p*p) + w; z = Math.Sqrt(Math.Abs(q)); - matrixH[n, n] = matrixH[n, n] + exshift; - matrixH[n - 1, n - 1] = matrixH[n - 1, n - 1] + exshift; - x = matrixH[n, n]; + + matrixH[nOn] += exshift; + matrixH[nm1O + nm1] += exshift; + x = matrixH[nOn]; // Real pair if (q >= 0) @@ -629,46 +613,50 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization z = p - z; } - d[n - 1] = x + z; + d[nm1] = x + z; - d[n] = d[n - 1]; + d[n] = d[nm1]; if (z != 0.0) { - d[n] = x - (w / z); + d[n] = x - (w/z); } e[n - 1] = 0.0; e[n] = 0.0; - x = matrixH[n, n - 1]; + x = matrixH[nm1O + n]; s = Math.Abs(x) + Math.Abs(z); - p = x / s; - q = z / s; - r = Math.Sqrt((p * p) + (q * q)); - p = p / r; - q = q / r; + p = x/s; + q = z/s; + r = Math.Sqrt((p*p) + (q*q)); + p = p/r; + q = q/r; // Row modification for (var j = n - 1; j < order; j++) { - z = matrixH[n - 1, j]; - matrixH[n - 1, j] = (q * z) + (p * matrixH[n, j]); - matrixH[n, j] = (q * matrixH[n, j]) - (p * z); + var jO = j*order; + var jOn = jO + n; + z = matrixH[jO + nm1]; + matrixH[jO + nm1] = (q*z) + (p*matrixH[jOn]); + matrixH[jOn] = (q*matrixH[jOn]) - (p*z); } // Column modification for (var i = 0; i <= n; i++) { - z = matrixH[i, n - 1]; - matrixH[i, n - 1] = (q * z) + (p * matrixH[i, n]); - matrixH[i, n] = (q * matrixH[i, n]) - (p * z); + var nOi = nO + i; + z = matrixH[nm1O + i]; + matrixH[nm1O + i] = (q*z) + (p*matrixH[nOi]); + matrixH[nOi] = (q*matrixH[nOi]) - (p*z); } // Accumulate transformations for (var i = 0; i < order; i++) { - z = a[((n - 1) * order) + i]; - a[((n - 1) * order) + i] = (q * z) + (p * a[(n * order) + i]); - a[(n * order) + i] = (q * a[(n * order) + i]) - (p * z); + var nOi = nO + i; + z = a[nm1O + i]; + a[nm1O + i] = (q*z) + (p*a[nOi]); + a[nOi] = (q*a[nOi]) - (p*z); } // Complex pair @@ -688,14 +676,19 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization } else { + var nO = n*order; + var nm1 = n - 1; + var nm1O = nm1*order; + var nOn = nO + n; + // Form shift - x = matrixH[n, n]; + x = matrixH[nOn]; y = 0.0; w = 0.0; if (l < n) { - y = matrixH[n - 1, n - 1]; - w = matrixH[n, n - 1] * matrixH[n - 1, n]; + y = matrixH[nm1O + nm1]; + w = matrixH[nm1O + n]*matrixH[nO + nm1]; } // Wilkinson's original ad hoc shift @@ -704,19 +697,19 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization exshift += x; for (var i = 0; i <= n; i++) { - matrixH[i, i] -= x; + matrixH[i*order + i] -= x; } - s = Math.Abs(matrixH[n, n - 1]) + Math.Abs(matrixH[n - 1, n - 2]); - x = y = 0.75 * s; - w = (-0.4375) * s * s; + s = Math.Abs(matrixH[nm1O + n]) + Math.Abs(matrixH[(n - 2)*order + nm1]); + x = y = 0.75*s; + w = (-0.4375)*s*s; } // MATLAB's new ad hoc shift if (iter == 30) { - s = (y - x) / 2.0; - s = (s * s) + w; + s = (y - x)/2.0; + s = (s*s) + w; if (s > 0) { s = Math.Sqrt(s); @@ -725,10 +718,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization s = -s; } - s = x - (w / (((y - x) / 2.0) + s)); + s = x - (w/(((y - x)/2.0) + s)); for (var i = 0; i <= n; i++) { - matrixH[i, i] -= s; + matrixH[i*order + i] -= s; } exshift += s; @@ -736,29 +729,39 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization } } - iter = iter + 1; // (Could check iteration count here.) + iter = iter + 1; + if (iter >= 30*order) + { + throw new ArgumentException(Resources.ConvergenceFailed); + } // Look for two consecutive small sub-diagonal elements var m = n - 2; while (m >= l) { - z = matrixH[m, m]; + var mp1 = m + 1; + var mm1 = m - 1; + var mO = m*order; + var mp1O = mp1*order; + var mm1O = mm1*order; + + z = matrixH[mO + m]; r = x - z; s = y - z; - p = (((r * s) - w) / matrixH[m + 1, m]) + matrixH[m, m + 1]; - q = matrixH[m + 1, m + 1] - z - r - s; - r = matrixH[m + 2, m + 1]; + p = (((r*s) - w)/matrixH[mO + mp1]) + matrixH[mp1O + m]; + q = matrixH[mp1O + mp1] - z - r - s; + r = matrixH[mp1O + (m + 2)]; s = Math.Abs(p) + Math.Abs(q) + Math.Abs(r); - p = p / s; - q = q / s; - r = r / s; + p = p/s; + q = q/s; + r = r/s; if (m == l) { break; } - if (Math.Abs(matrixH[m, m - 1]) * (Math.Abs(q) + Math.Abs(r)) < eps * (Math.Abs(p) * (Math.Abs(matrixH[m - 1, m - 1]) + Math.Abs(z) + Math.Abs(matrixH[m + 1, m + 1])))) + if (Math.Abs(matrixH[mm1O + m])*(Math.Abs(q) + Math.Abs(r)) < eps*(Math.Abs(p)*(Math.Abs(matrixH[mm1O + mm1]) + Math.Abs(z) + Math.Abs(matrixH[mp1O + mp1])))) { break; } @@ -766,40 +769,45 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization m--; } - for (var i = m + 2; i <= n; i++) + var mp2 = m + 2; + for (var i = mp2; i <= n; i++) { - matrixH[i, i - 2] = 0.0; - if (i > m + 2) + matrixH[(i - 2)*order + i] = 0.0; + if (i > mp2) { - matrixH[i, i - 3] = 0.0; + matrixH[(i - 3)*order + i] = 0.0; } } // Double QR step involving rows l:n and columns m:n for (var k = m; k <= n - 1; k++) { - bool notlast = k != n - 1; - + var notlast = k != n - 1; + var kO = k*order; + var km1 = k - 1; + var kp1 = k + 1; + var kp2 = k + 2; + var kp1O = kp1*order; + var kp2O = kp2*order; + var km1O = km1*order; if (k != m) { - p = matrixH[k, k - 1]; - q = matrixH[k + 1, k - 1]; - r = notlast ? matrixH[k + 2, k - 1] : 0.0; + p = matrixH[km1O + k]; + q = matrixH[km1O + kp1]; + r = notlast ? matrixH[km1O + kp2] : 0.0; x = Math.Abs(p) + Math.Abs(q) + Math.Abs(r); - if (x != 0.0) + if (x == 0.0) { - p = p / x; - q = q / x; - r = r / x; + continue; } - } - if (x == 0.0) - { - break; + p = p/x; + q = q/x; + r = r/x; } - s = Math.Sqrt((p * p) + (q * q) + (r * r)); + s = Math.Sqrt((p*p) + (q*q) + (r*r)); + if (p < 0) { s = -s; @@ -809,63 +817,66 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization { if (k != m) { - matrixH[k, k - 1] = (-s) * x; + matrixH[km1O + k] = (-s)*x; } else if (l != m) { - matrixH[k, k - 1] = -matrixH[k, k - 1]; + matrixH[km1O + k] = -matrixH[km1O + k]; } p = p + s; - x = p / s; - y = q / s; - z = r / s; - q = q / p; - r = r / p; + x = p/s; + y = q/s; + z = r/s; + q = q/p; + r = r/p; // Row modification for (var j = k; j < order; j++) { - p = matrixH[k, j] + (q * matrixH[k + 1, j]); - + var jO = j*order; + var jOk = jO + k; + var jOkp1 = jO + kp1; + var jOkp2 = jO + kp2; + p = matrixH[jOk] + (q*matrixH[jOkp1]); if (notlast) { - p = p + (r * matrixH[k + 2, j]); - matrixH[k + 2, j] = matrixH[k + 2, j] - (p * z); + p = p + (r*matrixH[jOkp2]); + matrixH[jOkp2] -= (p*z); } - matrixH[k, j] = matrixH[k, j] - (p * x); - matrixH[k + 1, j] = matrixH[k + 1, j] - (p * y); + matrixH[jOk] -= (p*x); + matrixH[jOkp1] -= (p*y); } // Column modification for (var i = 0; i <= Math.Min(n, k + 3); i++) { - p = (x * matrixH[i, k]) + (y * matrixH[i, k + 1]); + p = (x*matrixH[kO + i]) + (y*matrixH[kp1O + i]); if (notlast) { - p = p + (z * matrixH[i, k + 2]); - matrixH[i, k + 2] = matrixH[i, k + 2] - (p * r); + p = p + (z*matrixH[kp2O + i]); + matrixH[kp2O + i] -= (p*r); } - matrixH[i, k] = matrixH[i, k] - p; - matrixH[i, k + 1] = matrixH[i, k + 1] - (p * q); + matrixH[kO + i] -= p; + matrixH[kp1O + i] -= (p*q); } // Accumulate transformations for (var i = 0; i < order; i++) { - p = (x * a[(k * order) + i]) + (y * a[((k + 1) * order) + i]); + p = (x*a[kO + i]) + (y*a[kp1O + i]); if (notlast) { - p = p + (z * a[((k + 2) * order) + i]); - a[((k + 2) * order) + i] -= p * r; + p = p + (z*a[kp2O + i]); + a[kp2O + i] -= p*r; } - a[(k * order) + i] -= p; - a[((k + 1) * order) + i] -= p * q; + a[kO + i] -= p; + a[kp1O + i] -= p*q; } } // (s != 0) } // k loop @@ -880,23 +891,31 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization for (n = order - 1; n >= 0; n--) { - double t; + var nO = n*order; + var nm1 = n - 1; + var nm1O = nm1*order; p = d[n]; q = e[n]; + // Real vector + double t; if (q == 0.0) { var l = n; - matrixH[n, n] = 1.0; + matrixH[nO + n] = 1.0; for (var i = n - 1; i >= 0; i--) { - w = matrixH[i, i] - p; + var ip1 = i + 1; + var iO = i*order; + var ip1O = ip1*order; + + w = matrixH[iO + i] - p; r = 0.0; for (var j = l; j <= n; j++) { - r = r + (matrixH[i, j] * matrixH[j, n]); + r = r + (matrixH[j*order + i]*matrixH[nO + j]); } if (e[i] < 0.0) @@ -911,39 +930,39 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization { if (w != 0.0) { - matrixH[i, n] = (-r) / w; + matrixH[nO + i] = (-r)/w; } else { - matrixH[i, n] = (-r) / (eps * norm); + matrixH[nO + i] = (-r)/(eps*norm); } // Solve real equations } else { - x = matrixH[i, i + 1]; - y = matrixH[i + 1, i]; - q = ((d[i] - p) * (d[i] - p)) + (e[i] * e[i]); - t = ((x * s) - (z * r)) / q; - matrixH[i, n] = t; + x = matrixH[ip1O + i]; + y = matrixH[iO + ip1]; + q = ((d[i] - p)*(d[i] - p)) + (e[i]*e[i]); + t = ((x*s) - (z*r))/q; + matrixH[nO + i] = t; if (Math.Abs(x) > Math.Abs(z)) { - matrixH[i + 1, n] = (-r - (w * t)) / x; + matrixH[nO + ip1] = (-r - (w*t))/x; } else { - matrixH[i + 1, n] = (-s - (y * t)) / z; + matrixH[nO + ip1] = (-s - (y*t))/z; } } // Overflow control - t = Math.Abs(matrixH[i, n]); - if ((eps * t) * t > 1) + t = Math.Abs(matrixH[nO + i]); + if ((eps*t)*t > 1) { for (var j = i; j <= n; j++) { - matrixH[j, n] = matrixH[j, n] / t; + matrixH[nO + j] /= t; } } } @@ -956,31 +975,36 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization var l = n - 1; // Last vector component imaginary so matrix is triangular - if (Math.Abs(matrixH[n, n - 1]) > Math.Abs(matrixH[n - 1, n])) + if (Math.Abs(matrixH[nm1O + n]) > Math.Abs(matrixH[nO + nm1])) { - matrixH[n - 1, n - 1] = q / matrixH[n, n - 1]; - matrixH[n - 1, n] = (-(matrixH[n, n] - p)) / matrixH[n, n - 1]; + matrixH[nm1O + nm1] = q/matrixH[nm1O + n]; + matrixH[nO + nm1] = (-(matrixH[nO + n] - p))/matrixH[nm1O + n]; } else { - var res = Cdiv(0.0, -matrixH[n - 1, n], matrixH[n - 1, n - 1] - p, q); - matrixH[n - 1, n - 1] = res.Real; - matrixH[n - 1, n] = res.Imaginary; + var res = Cdiv(0.0, -matrixH[nO + nm1], matrixH[nm1O + nm1] - p, q); + matrixH[nm1O + nm1] = res.Real; + matrixH[nO + nm1] = res.Imaginary; } - matrixH[n, n - 1] = 0.0; - matrixH[n, n] = 1.0; + matrixH[nm1O + n] = 0.0; + matrixH[nO + n] = 1.0; for (var i = n - 2; i >= 0; i--) { - double ra = 0.0; - double sa = 0.0; + var ip1 = i + 1; + var iO = i*order; + var ip1O = ip1*order; + var ra = 0.0; + var sa = 0.0; for (var j = l; j <= n; j++) { - ra = ra + (matrixH[i, j] * matrixH[j, n - 1]); - sa = sa + (matrixH[i, j] * matrixH[j, n]); + var jO = j*order; + var jOi = jO + i; + ra = ra + (matrixH[jOi]*matrixH[nm1O + j]); + sa = sa + (matrixH[jOi]*matrixH[nO + j]); } - w = matrixH[i, i] - p; + w = matrixH[iO + i] - p; if (e[i] < 0.0) { @@ -994,46 +1018,46 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization if (e[i] == 0.0) { var res = Cdiv(-ra, -sa, w, q); - matrixH[i, n - 1] = res.Real; - matrixH[i, n] = res.Imaginary; + matrixH[nm1O + i] = res.Real; + matrixH[nO + i] = res.Imaginary; } else { // Solve complex equations - x = matrixH[i, i + 1]; - y = matrixH[i + 1, i]; + x = matrixH[ip1O + i]; + y = matrixH[iO + ip1]; - double vr = ((d[i] - p) * (d[i] - p)) + (e[i] * e[i]) - (q * q); - double vi = (d[i] - p) * 2.0 * q; + var vr = ((d[i] - p)*(d[i] - p)) + (e[i]*e[i]) - (q*q); + var vi = (d[i] - p)*2.0*q; if ((vr == 0.0) && (vi == 0.0)) { - vr = eps * norm * (Math.Abs(w) + Math.Abs(q) + Math.Abs(x) + Math.Abs(y) + Math.Abs(z)); + vr = eps*norm*(Math.Abs(w) + Math.Abs(q) + Math.Abs(x) + Math.Abs(y) + Math.Abs(z)); } - var res = Cdiv((x * r) - (z * ra) + (q * sa), (x * s) - (z * sa) - (q * ra), vr, vi); - matrixH[i, n - 1] = res.Real; - matrixH[i, n] = res.Imaginary; + var res = Cdiv((x*r) - (z*ra) + (q*sa), (x*s) - (z*sa) - (q*ra), vr, vi); + matrixH[nm1O + i] = res.Real; + matrixH[nO + i] = res.Imaginary; if (Math.Abs(x) > (Math.Abs(z) + Math.Abs(q))) { - matrixH[i + 1, n - 1] = (-ra - (w * matrixH[i, n - 1]) + (q * matrixH[i, n])) / x; - matrixH[i + 1, n] = (-sa - (w * matrixH[i, n]) - (q * matrixH[i, n - 1])) / x; + matrixH[nm1O + ip1] = (-ra - (w*matrixH[nm1O + i]) + (q*matrixH[nO + i]))/x; + matrixH[nO + ip1] = (-sa - (w*matrixH[nO + i]) - (q*matrixH[nm1O + i]))/x; } else { - res = Cdiv(-r - (y * matrixH[i, n - 1]), -s - (y * matrixH[i, n]), z, q); - matrixH[i + 1, n - 1] = res.Real; - matrixH[i + 1, n] = res.Imaginary; + res = Cdiv(-r - (y*matrixH[nm1O + i]), -s - (y*matrixH[nO + i]), z, q); + matrixH[nm1O + ip1] = res.Real; + matrixH[nO + ip1] = res.Imaginary; } } // Overflow control - t = Math.Max(Math.Abs(matrixH[i, n - 1]), Math.Abs(matrixH[i, n])); - if ((eps * t) * t > 1) + t = Math.Max(Math.Abs(matrixH[nm1O + i]), Math.Abs(matrixH[nO + i])); + if ((eps*t)*t > 1) { for (var j = i; j <= n; j++) { - matrixH[j, n - 1] = matrixH[j, n - 1] / t; - matrixH[j, n] = matrixH[j, n] / t; + matrixH[nm1O + j] /= t; + matrixH[nO + j] /= t; } } } @@ -1044,15 +1068,16 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization // Back transformation to get eigenvectors of original matrix for (var j = order - 1; j >= 0; j--) { + var jO = j*order; for (var i = 0; i < order; i++) { z = 0.0; for (var k = 0; k <= j; k++) { - z = z + (a[(k * order) + i] * matrixH[k, j]); + z = z + (a[k*order + i]*matrixH[jO + k]); } - a[(j * order) + i] = z; + a[jO + i] = z; } } } @@ -1065,14 +1090,14 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization /// Real part of Y /// Imaginary part of Y /// Division result as a number. - private static Complex Cdiv(double xreal, double ximag, double yreal, double yimag) + static System.Numerics.Complex Cdiv(double xreal, double ximag, double yreal, double yimag) { if (Math.Abs(yimag) < Math.Abs(yreal)) { - return new Complex((xreal + (ximag * (yimag / yreal))) / (yreal + (yimag * (yimag / yreal))), (ximag - (xreal * (yimag / yreal))) / (yreal + (yimag * (yimag / yreal)))); + return new System.Numerics.Complex((xreal + (ximag*(yimag/yreal)))/(yreal + (yimag*(yimag/yreal))), (ximag - (xreal*(yimag/yreal)))/(yreal + (yimag*(yimag/yreal)))); } - return new Complex((ximag + (xreal * (yreal / yimag))) / (yimag + (yreal * (yreal / yimag))), (-xreal + (ximag * (yreal / yimag))) / (yimag + (yreal * (yreal / yimag)))); + return new System.Numerics.Complex((ximag + (xreal*(yreal/yimag)))/(yimag + (yreal*(yreal/yimag))), (-xreal + (ximag*(yreal/yimag)))/(yimag + (yreal*(yreal/yimag)))); } /// @@ -1125,7 +1150,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization { for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(j * order) + i] * input.At(i, k); + value += ((DenseMatrix) MatrixEv).Values[(j*order) + i]*input.At(i, k); } value /= VectorEv[j].Real; @@ -1139,7 +1164,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization double value = 0; for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(i * order) + j] * tmp[i]; + value += ((DenseMatrix) MatrixEv).Values[(i*order) + j]*tmp[i]; } result.At(j, k, value); @@ -1196,7 +1221,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization { for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(j * order) + i] * input[i]; + value += ((DenseMatrix) MatrixEv).Values[(j*order) + i]*input[i]; } value /= VectorEv[j].Real; @@ -1208,9 +1233,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization for (var j = 0; j < order; j++) { value = 0; - for (int i = 0; i < order; i++) + for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(i * order) + j] * tmp[i]; + value += ((DenseMatrix) MatrixEv).Values[(i*order) + j]*tmp[i]; } result[j] = value; @@ -1222,4 +1247,4 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization } } } -} \ No newline at end of file +} diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/UserEvd.cs b/src/Numerics/LinearAlgebra/Double/Factorization/UserEvd.cs index 6a8b7fb7..3f0a5315 100644 --- a/src/Numerics/LinearAlgebra/Double/Factorization/UserEvd.cs +++ b/src/Numerics/LinearAlgebra/Double/Factorization/UserEvd.cs @@ -79,9 +79,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization IsSymmetric = true; - for (var i = 0; i < order & IsSymmetric; i++) + for (var i = 0; IsSymmetric && i < order; i++) { - for (var j = 0; j < order & IsSymmetric; j++) + for (var j = 0; IsSymmetric && j < order; j++) { IsSymmetric &= matrix.At(i, j) == matrix.At(j, i); } diff --git a/src/Numerics/LinearAlgebra/Single/Factorization/DenseEvd.cs b/src/Numerics/LinearAlgebra/Single/Factorization/DenseEvd.cs index 2f99ab41..3e86aa98 100644 --- a/src/Numerics/LinearAlgebra/Single/Factorization/DenseEvd.cs +++ b/src/Numerics/LinearAlgebra/Single/Factorization/DenseEvd.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -27,12 +27,12 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // + namespace MathNet.Numerics.LinearAlgebra.Single.Factorization { using System; using System.Numerics; using Generic; - using Numerics; using Properties; /// @@ -73,58 +73,23 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization var order = matrix.RowCount; - // Initialize matricies for eigenvalues and eigenvectors + // Initialize matrices for eigenvalues and eigenvectors MatrixEv = matrix.CreateMatrix(order, order); MatrixD = matrix.CreateMatrix(order, order); VectorEv = new LinearAlgebra.Complex.DenseVector(order); - + IsSymmetric = true; - for (var i = 0; i < order & IsSymmetric; i++) + for (var i = 0; IsSymmetric && i < order; i++) { - for (var j = 0; j < order & IsSymmetric; j++) + for (var j = 0; IsSymmetric && j < order; j++) { IsSymmetric &= matrix.At(i, j) == matrix.At(j, i); } } - var d = new float[order]; - var e = new float[order]; - - if (IsSymmetric) - { - matrix.CopyTo(MatrixEv); - d = MatrixEv.Row(order - 1).ToArray(); - - SymmetricTridiagonalize(((DenseMatrix)MatrixEv).Values, d, e, order); - SymmetricDiagonalize(((DenseMatrix)MatrixEv).Values, d, e, order); - } - else - { - var matrixH = matrix.ToArray(); - - NonsymmetricReduceToHessenberg(((DenseMatrix)MatrixEv).Values, matrixH, order); - NonsymmetricReduceHessenberToRealSchur(((DenseMatrix)MatrixEv).Values, matrixH, d, e, order); - } - - for (var i = 0; i < order; i++) - { - MatrixD.At(i, i, d[i]); - - if (e[i] > 0) - { - MatrixD.At(i, i + 1, e[i]); - } - else if (e[i] < 0) - { - MatrixD.At(i, i - 1, e[i]); - } - } - - for (var i = 0; i < order; i++) - { - VectorEv[i] = new Complex(d[i], e[i]); - } + Control.LinearAlgebraProvider.EigenDecomp(IsSymmetric, order, matrix.Values, ((DenseMatrix) MatrixEv).Values, + ((LinearAlgebra.Complex.DenseVector) VectorEv).Values, ((DenseMatrix) MatrixD).Values); } /// @@ -138,7 +103,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization /// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricTridiagonalize(float[] a, float[] d, float[] e, int order) + internal static void SymmetricTridiagonalize(float[] a, float[] d, float[] e, int order) { // Householder reduction to tridiagonal form. for (var i = order - 1; i > 0; i--) @@ -157,9 +122,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization e[i] = d[i - 1]; for (var j = 0; j < i; j++) { - d[j] = a[(j * order) + i - 1]; - a[(j * order) + i] = 0.0f; - a[(i * order) + j] = 0.0f; + d[j] = a[(j*order) + i - 1]; + a[(j*order) + i] = 0.0f; + a[(i*order) + j] = 0.0f; } } else @@ -168,18 +133,18 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization for (var k = 0; k < i; k++) { d[k] /= scale; - h += d[k] * d[k]; + h += d[k]*d[k]; } var f = d[i - 1]; - var g = (float)Math.Sqrt(h); + var g = (float) Math.Sqrt(h); if (f > 0) { g = -g; } - e[i] = scale * g; - h = h - (f * g); + e[i] = scale*g; + h = h - (f*g); d[i - 1] = f - g; for (var j = 0; j < i; j++) @@ -191,13 +156,13 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization for (var j = 0; j < i; j++) { f = d[j]; - a[(i * order) + j] = f; - g = e[j] + (a[(j * order) + j] * f); + a[(i*order) + j] = f; + g = e[j] + (a[(j*order) + j]*f); for (var k = j + 1; k <= i - 1; k++) { - g += a[(j * order) + k] * d[k]; - e[k] += a[(j * order) + k] * f; + g += a[(j*order) + k]*d[k]; + e[k] += a[(j*order) + k]*f; } e[j] = g; @@ -208,14 +173,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization for (var j = 0; j < i; j++) { e[j] /= h; - f += e[j] * d[j]; + f += e[j]*d[j]; } - var hh = f / (h + h); + var hh = f/(h + h); for (var j = 0; j < i; j++) { - e[j] -= hh * d[j]; + e[j] -= hh*d[j]; } for (var j = 0; j < i; j++) @@ -225,11 +190,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization for (var k = j; k <= i - 1; k++) { - a[(j * order) + k] -= (f * e[k]) + (g * d[k]); + a[(j*order) + k] -= (f*e[k]) + (g*d[k]); } - d[j] = a[(j * order) + i - 1]; - a[(j * order) + i] = 0.0f; + d[j] = a[(j*order) + i - 1]; + a[(j*order) + i] = 0.0f; } } @@ -239,14 +204,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization // Accumulate transformations. for (var i = 0; i < order - 1; i++) { - a[(i * order) + order - 1] = a[(i * order) + i]; - a[(i * order) + i] = 1.0f; + a[(i*order) + order - 1] = a[(i*order) + i]; + a[(i*order) + i] = 1.0f; var h = d[i + 1]; if (h != 0.0f) { for (var k = 0; k <= i; k++) { - d[k] = a[((i + 1) * order) + k] / h; + d[k] = a[((i + 1)*order) + k]/h; } for (var j = 0; j <= i; j++) @@ -254,29 +219,29 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization var g = 0.0f; for (var k = 0; k <= i; k++) { - g += a[((i + 1) * order) + k] * a[(j * order) + k]; + g += a[((i + 1)*order) + k]*a[(j*order) + k]; } for (var k = 0; k <= i; k++) { - a[(j * order) + k] -= g * d[k]; + a[(j*order) + k] -= g*d[k]; } } } for (var k = 0; k <= i; k++) { - a[((i + 1) * order) + k] = 0.0f; + a[((i + 1)*order) + k] = 0.0f; } } for (var j = 0; j < order; j++) { - d[j] = a[(j * order) + order - 1]; - a[(j * order) + order - 1] = 0.0f; + d[j] = a[(j*order) + order - 1]; + a[(j*order) + order - 1] = 0.0f; } - a[(order * order) - 1] = 1.0f; + a[(order*order) - 1] = 1.0f; e[0] = 0.0f; } @@ -291,7 +256,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization /// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void SymmetricDiagonalize(float[] a, float[] d, float[] e, int order) + internal static void SymmetricDiagonalize(float[] a, float[] d, float[] e, int order) { const int Maxiter = 1000; @@ -304,7 +269,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization var f = 0.0f; var tst1 = 0.0f; - var eps = Precision.DoubleMachinePrecision; + var eps = Precision.SingleMachinePrecision; for (var l = 0; l < order; l++) { // Find small subdiagonal element @@ -312,7 +277,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization var m = l; while (m < order) { - if (Math.Abs(e[m]) <= eps * tst1) + if (Math.Abs(e[m]) <= eps*tst1) { break; } @@ -331,15 +296,15 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization // Compute implicit shift var g = d[l]; - var p = (d[l + 1] - g) / (2.0f * e[l]); + var p = (d[l + 1] - g)/(2.0f*e[l]); var r = SpecialFunctions.Hypotenuse(p, 1.0f); if (p < 0) { r = -r; } - d[l] = e[l] / (p + r); - d[l + 1] = e[l] * (p + r); + d[l] = e[l]/(p + r); + d[l + 1] = e[l]*(p + r); var dl1 = d[l + 1]; var h = g - d[l]; @@ -363,27 +328,27 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization c3 = c2; c2 = c; s2 = s; - g = c * e[i]; - h = c * p; + g = c*e[i]; + h = c*p; r = SpecialFunctions.Hypotenuse(p, e[i]); - e[i + 1] = s * r; - s = e[i] / r; - c = p / r; - p = (c * d[i]) - (s * g); - d[i + 1] = h + (s * ((c * g) + (s * d[i]))); + e[i + 1] = s*r; + s = e[i]/r; + c = p/r; + p = (c*d[i]) - (s*g); + d[i + 1] = h + (s*((c*g) + (s*d[i]))); // Accumulate transformation. for (var k = 0; k < order; k++) { - h = a[((i + 1) * order) + k]; - a[((i + 1) * order) + k] = (s * a[(i * order) + k]) + (c * h); - a[(i * order) + k] = (c * a[(i * order) + k]) - (s * h); + h = a[((i + 1)*order) + k]; + a[((i + 1)*order) + k] = (s*a[(i*order) + k]) + (c*h); + a[(i*order) + k] = (c*a[(i*order) + k]) - (s*h); } } - p = (-s) * s2 * c3 * el1 * e[l] / dl1; - e[l] = s * p; - d[l] = c * p; + p = (-s)*s2*c3*el1*e[l]/dl1; + e[l] = s*p; + d[l] = c*p; // Check for convergence. If too many iterations have been performed, // throw exception that Convergence Failed @@ -391,8 +356,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization { throw new ArgumentException(Resources.ConvergenceFailed); } - } - while (Math.Abs(e[l]) > eps * tst1); + } while (Math.Abs(e[l]) > eps*tst1); } d[l] = d[l] + f; @@ -419,9 +383,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization d[i] = p; for (var j = 0; j < order; j++) { - p = a[(i * order) + j]; - a[(i * order) + j] = a[(k * order) + j]; - a[(k * order) + j] = p; + p = a[(i*order) + j]; + a[(i*order) + j] = a[(k*order) + j]; + a[(k*order) + j] = p; } } } @@ -437,72 +401,76 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization /// by Martin and Wilkinson, Handbook for Auto. Comp., /// Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutines in EISPACK. - private static void NonsymmetricReduceToHessenberg(float[] a, float[,] matrixH, int order) + internal static void NonsymmetricReduceToHessenberg(float[] a, float[] matrixH, int order) { var ort = new float[order]; - - for (var m = 1; m < order - 1; m++) + var high = order - 1; + for (var m = 1; m <= high - 1; m++) { + var mm1 = m - 1; + var mm1O = mm1*order; // Scale column. var scale = 0.0f; - for (var i = m; i < order; i++) + for (var i = m; i <= high; i++) { - scale = scale + Math.Abs(matrixH[i, m - 1]); + scale += Math.Abs(matrixH[mm1O + i]); } if (scale != 0.0f) { // Compute Householder transformation. var h = 0.0f; - for (var i = order - 1; i >= m; i--) + for (var i = high; i >= m; i--) { - ort[i] = matrixH[i, m - 1] / scale; - h += ort[i] * ort[i]; + ort[i] = matrixH[mm1O + i]/scale; + h += ort[i]*ort[i]; } - var g = (float)Math.Sqrt(h); + var g = (float) Math.Sqrt(h); if (ort[m] > 0) { g = -g; } - h = h - (ort[m] * g); + h = h - (ort[m]*g); ort[m] = ort[m] - g; // Apply Householder similarity transformation // H = (I-u*u'/h)*H*(I-u*u')/h) for (var j = m; j < order; j++) { + var jO = j*order; var f = 0.0f; for (var i = order - 1; i >= m; i--) { - f += ort[i] * matrixH[i, j]; + f += ort[i]*matrixH[jO + i]; } - f = f / h; - for (var i = m; i < order; i++) + f = f/h; + + for (var i = m; i <= high; i++) { - matrixH[i, j] -= f * ort[i]; + matrixH[jO + i] -= f*ort[i]; } } - for (var i = 0; i < order; i++) + for (var i = 0; i <= high; i++) { var f = 0.0f; - for (var j = order - 1; j >= m; j--) + for (var j = high; j >= m; j--) { - f += ort[j] * matrixH[i, j]; + f += ort[j]*matrixH[j*order + i]; } + f = f/h; - f = f / h; - for (var j = m; j < order; j++) + for (var j = m; j <= high; j++) { - matrixH[i, j] -= f * ort[j]; + matrixH[j*order + i] -= f*ort[j]; } } - ort[m] = scale * ort[m]; - matrixH[m, m - 1] = scale * g; + ort[m] = scale*ort[m]; + matrixH[mm1O + m] = scale*g; } } @@ -511,32 +479,37 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization { for (var j = 0; j < order; j++) { - a[(j * order) + i] = i == j ? 1.0f : 0.0f; + a[(j*order) + i] = i == j ? 1.0f : 0.0f; } } - for (var m = order - 2; m >= 1; m--) + for (var m = high - 1; m >= 1; m--) { - if (matrixH[m, m - 1] != 0.0f) + var mm1 = m - 1; + var mm1O = mm1*order; + var mm1Om = mm1O + m; + if (matrixH[mm1Om] != 0.0) { - for (var i = m + 1; i < order; i++) + for (var i = m + 1; i <= high; i++) { - ort[i] = matrixH[i, m - 1]; + ort[i] = matrixH[mm1O + i]; } - for (var j = m; j < order; j++) + for (var j = m; j <= high; j++) { var g = 0.0f; - for (var i = m; i < order; i++) + var jO = j*order; + for (var i = m; i <= high; i++) { - g += ort[i] * a[(j * order) + i]; + g += ort[i]*a[jO + i]; } // Double division avoids possible underflow - g = (g / ort[m]) / matrixH[m, m - 1]; - for (var i = m; i < order; i++) + g = (g/ort[m])/matrixH[mm1Om]; + + for (var i = m; i <= high; i++) { - a[(j * order) + i] += g * ort[i]; + a[jO + i] += g*ort[i]; } } } @@ -555,13 +528,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization /// by Martin and Wilkinson, Handbook for Auto. Comp., /// Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK. - private static void NonsymmetricReduceHessenberToRealSchur(float[] a, float[,] matrixH, float[] d, float[] e, int order) + internal static void NonsymmetricReduceHessenberToRealSchur(float[] a, float[] matrixH, float[] d, float[] e, int order) { // Initialize var n = order - 1; - var eps = (float)Precision.SingleMachinePrecision; + var eps = (float) Precision.SingleMachinePrecision; var exshift = 0.0f; - float p = 0, q = 0, r = 0, s = 0, z = 0, w, x, y; + float p = 0, q = 0, r = 0, s = 0, z = 0; + float w, x, y; // Store roots isolated by balanc and compute matrix norm var norm = 0.0f; @@ -569,7 +543,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization { for (var j = Math.Max(i - 1, 0); j < order; j++) { - norm = norm + Math.Abs(matrixH[i, j]); + norm = norm + Math.Abs(matrixH[j*order + i]); } } @@ -581,14 +555,16 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization var l = n; while (l > 0) { - s = Math.Abs(matrixH[l - 1, l - 1]) + Math.Abs(matrixH[l, l]); + var lm1 = l - 1; + var lm1O = lm1*order; + s = Math.Abs(matrixH[lm1O + lm1]) + Math.Abs(matrixH[l*order + l]); - if (s == 0.0f) + if (s == 0.0) { s = norm; } - if (Math.Abs(matrixH[l, l - 1]) < eps * s) + if (Math.Abs(matrixH[lm1O + l]) < eps*s) { break; } @@ -600,8 +576,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization // One root found if (l == n) { - matrixH[n, n] = matrixH[n, n] + exshift; - d[n] = matrixH[n, n]; + var index = n*order + n; + matrixH[index] += exshift; + d[n] = matrixH[index]; e[n] = 0.0f; n--; iter = 0; @@ -610,13 +587,19 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization } else if (l == n - 1) { - w = matrixH[n, n - 1] * matrixH[n - 1, n]; - p = (matrixH[n - 1, n - 1] - matrixH[n, n]) / 2.0f; - q = (p * p) + w; - z = (float)Math.Sqrt(Math.Abs(q)); - matrixH[n, n] = matrixH[n, n] + exshift; - matrixH[n - 1, n - 1] = matrixH[n - 1, n - 1] + exshift; - x = matrixH[n, n]; + var nO = n*order; + var nm1 = n - 1; + var nm1O = nm1*order; + var nOn = nO + n; + + w = matrixH[nm1O + n]*matrixH[nO + nm1]; + p = (matrixH[nm1O + nm1] - matrixH[nOn])/2.0f; + q = (p*p) + w; + z = (float) Math.Sqrt(Math.Abs(q)); + + matrixH[nOn] += exshift; + matrixH[nm1O + nm1] += exshift; + x = matrixH[nOn]; // Real pair if (q >= 0) @@ -630,46 +613,50 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization z = p - z; } - d[n - 1] = x + z; + d[nm1] = x + z; - d[n] = d[n - 1]; - if (z != 0.0f) + d[n] = d[nm1]; + if (z != 0.0) { - d[n] = x - (w / z); + d[n] = x - (w/z); } e[n - 1] = 0.0f; e[n] = 0.0f; - x = matrixH[n, n - 1]; + x = matrixH[nm1O + n]; s = Math.Abs(x) + Math.Abs(z); - p = x / s; - q = z / s; - r = (float)Math.Sqrt((p * p) + (q * q)); - p = p / r; - q = q / r; + p = x/s; + q = z/s; + r = (float) Math.Sqrt((p*p) + (q*q)); + p = p/r; + q = q/r; // Row modification for (var j = n - 1; j < order; j++) { - z = matrixH[n - 1, j]; - matrixH[n - 1, j] = (q * z) + (p * matrixH[n, j]); - matrixH[n, j] = (q * matrixH[n, j]) - (p * z); + var jO = j*order; + var jOn = jO + n; + z = matrixH[jO + nm1]; + matrixH[jO + nm1] = (q*z) + (p*matrixH[jOn]); + matrixH[jOn] = (q*matrixH[jOn]) - (p*z); } // Column modification for (var i = 0; i <= n; i++) { - z = matrixH[i, n - 1]; - matrixH[i, n - 1] = (q * z) + (p * matrixH[i, n]); - matrixH[i, n] = (q * matrixH[i, n]) - (p * z); + var nOi = nO + i; + z = matrixH[nm1O + i]; + matrixH[nm1O + i] = (q*z) + (p*matrixH[nOi]); + matrixH[nOi] = (q*matrixH[nOi]) - (p*z); } // Accumulate transformations for (var i = 0; i < order; i++) { - z = a[((n - 1) * order) + i]; - a[((n - 1) * order) + i] = (q * z) + (p * a[(n * order) + i]); - a[(n * order) + i] = (q * a[(n * order) + i]) - (p * z); + var nOi = nO + i; + z = a[nm1O + i]; + a[nm1O + i] = (q*z) + (p*a[nOi]); + a[nOi] = (q*a[nOi]) - (p*z); } // Complex pair @@ -689,14 +676,19 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization } else { + var nO = n*order; + var nm1 = n - 1; + var nm1O = nm1*order; + var nOn = nO + n; + // Form shift - x = matrixH[n, n]; + x = matrixH[nOn]; y = 0.0f; w = 0.0f; if (l < n) { - y = matrixH[n - 1, n - 1]; - w = matrixH[n, n - 1] * matrixH[n - 1, n]; + y = matrixH[nm1O + nm1]; + w = matrixH[nm1O + n]*matrixH[nO + nm1]; } // Wilkinson's original ad hoc shift @@ -705,31 +697,31 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization exshift += x; for (var i = 0; i <= n; i++) { - matrixH[i, i] -= x; + matrixH[i*order + i] -= x; } - s = Math.Abs(matrixH[n, n - 1]) + Math.Abs(matrixH[n - 1, n - 2]); - x = y = 0.75f * s; - w = (-0.4375f) * s * s; + s = Math.Abs(matrixH[nm1O + n]) + Math.Abs(matrixH[(n - 2)*order + nm1]); + x = y = 0.75f*s; + w = (-0.4375f)*s*s; } // MATLAB's new ad hoc shift if (iter == 30) { - s = (y - x) / 2.0f; - s = (s * s) + w; + s = (y - x)/2.0f; + s = (s*s) + w; if (s > 0) { - s = (float)Math.Sqrt(s); + s = (float) Math.Sqrt(s); if (y < x) { s = -s; } - s = x - (w / (((y - x) / 2.0f) + s)); + s = x - (w/(((y - x)/2.0f) + s)); for (var i = 0; i <= n; i++) { - matrixH[i, i] -= s; + matrixH[i*order + i] -= s; } exshift += s; @@ -737,29 +729,39 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization } } - iter = iter + 1; // (Could check iteration count here.) + iter = iter + 1; + if (iter >= 30*order) + { + throw new ArgumentException(Resources.ConvergenceFailed); + } // Look for two consecutive small sub-diagonal elements var m = n - 2; while (m >= l) { - z = matrixH[m, m]; + var mp1 = m + 1; + var mm1 = m - 1; + var mO = m*order; + var mp1O = mp1*order; + var mm1O = mm1*order; + + z = matrixH[mO + m]; r = x - z; s = y - z; - p = (((r * s) - w) / matrixH[m + 1, m]) + matrixH[m, m + 1]; - q = matrixH[m + 1, m + 1] - z - r - s; - r = matrixH[m + 2, m + 1]; + p = (((r*s) - w)/matrixH[mO + mp1]) + matrixH[mp1O + m]; + q = matrixH[mp1O + mp1] - z - r - s; + r = matrixH[mp1O + (m + 2)]; s = Math.Abs(p) + Math.Abs(q) + Math.Abs(r); - p = p / s; - q = q / s; - r = r / s; + p = p/s; + q = q/s; + r = r/s; if (m == l) { break; } - if (Math.Abs(matrixH[m, m - 1]) * (Math.Abs(q) + Math.Abs(r)) < eps * (Math.Abs(p) * (Math.Abs(matrixH[m - 1, m - 1]) + Math.Abs(z) + Math.Abs(matrixH[m + 1, m + 1])))) + if (Math.Abs(matrixH[mm1O + m])*(Math.Abs(q) + Math.Abs(r)) < eps*(Math.Abs(p)*(Math.Abs(matrixH[mm1O + mm1]) + Math.Abs(z) + Math.Abs(matrixH[mp1O + mp1])))) { break; } @@ -767,40 +769,45 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization m--; } - for (var i = m + 2; i <= n; i++) + var mp2 = m + 2; + for (var i = mp2; i <= n; i++) { - matrixH[i, i - 2] = 0.0f; - if (i > m + 2) + matrixH[(i - 2)*order + i] = 0.0f; + if (i > mp2) { - matrixH[i, i - 3] = 0.0f; + matrixH[(i - 3)*order + i] = 0.0f; } } // Double QR step involving rows l:n and columns m:n for (var k = m; k <= n - 1; k++) { - bool notlast = k != n - 1; - + var notlast = k != n - 1; + var kO = k*order; + var km1 = k - 1; + var kp1 = k + 1; + var kp2 = k + 2; + var kp1O = kp1*order; + var kp2O = kp2*order; + var km1O = km1*order; if (k != m) { - p = matrixH[k, k - 1]; - q = matrixH[k + 1, k - 1]; - r = notlast ? matrixH[k + 2, k - 1] : 0.0f; + p = matrixH[km1O + k]; + q = matrixH[km1O + kp1]; + r = notlast ? matrixH[km1O + kp2] : 0.0f; x = Math.Abs(p) + Math.Abs(q) + Math.Abs(r); - if (x != 0.0f) + if (x == 0.0f) { - p = p / x; - q = q / x; - r = r / x; + continue; } - } - if (x == 0.0f) - { - break; + p = p/x; + q = q/x; + r = r/x; } - s = (float)Math.Sqrt((p * p) + (q * q) + (r * r)); + s = (float) Math.Sqrt((p*p) + (q*q) + (r*r)); + if (p < 0) { s = -s; @@ -810,63 +817,66 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization { if (k != m) { - matrixH[k, k - 1] = (-s) * x; + matrixH[km1O + k] = (-s)*x; } else if (l != m) { - matrixH[k, k - 1] = -matrixH[k, k - 1]; + matrixH[km1O + k] = -matrixH[km1O + k]; } p = p + s; - x = p / s; - y = q / s; - z = r / s; - q = q / p; - r = r / p; + x = p/s; + y = q/s; + z = r/s; + q = q/p; + r = r/p; // Row modification for (var j = k; j < order; j++) { - p = matrixH[k, j] + (q * matrixH[k + 1, j]); - + var jO = j*order; + var jOk = jO + k; + var jOkp1 = jO + kp1; + var jOkp2 = jO + kp2; + p = matrixH[jOk] + (q*matrixH[jOkp1]); if (notlast) { - p = p + (r * matrixH[k + 2, j]); - matrixH[k + 2, j] = matrixH[k + 2, j] - (p * z); + p = p + (r*matrixH[jOkp2]); + matrixH[jOkp2] -= (p*z); } - matrixH[k, j] = matrixH[k, j] - (p * x); - matrixH[k + 1, j] = matrixH[k + 1, j] - (p * y); + matrixH[jOk] -= (p*x); + matrixH[jOkp1] -= (p*y); } // Column modification for (var i = 0; i <= Math.Min(n, k + 3); i++) { - p = (x * matrixH[i, k]) + (y * matrixH[i, k + 1]); + p = (x*matrixH[kO + i]) + (y*matrixH[kp1O + i]); if (notlast) { - p = p + (z * matrixH[i, k + 2]); - matrixH[i, k + 2] = matrixH[i, k + 2] - (p * r); + p = p + (z*matrixH[kp2O + i]); + matrixH[kp2O + i] -= (p*r); } - matrixH[i, k] = matrixH[i, k] - p; - matrixH[i, k + 1] = matrixH[i, k + 1] - (p * q); + matrixH[kO + i] -= p; + matrixH[kp1O + i] -= (p*q); } // Accumulate transformations for (var i = 0; i < order; i++) { - p = (x * a[(k * order) + i]) + (y * a[((k + 1) * order) + i]); + p = (x*a[kO + i]) + (y*a[kp1O + i]); if (notlast) { - p = p + (z * a[((k + 2) * order) + i]); - a[((k + 2) * order) + i] -= p * r; + p = p + (z*a[kp2O + i]); + a[kp2O + i] -= p*r; } - a[(k * order) + i] -= p; - a[((k + 1) * order) + i] -= p * q; + a[kO + i] -= p; + a[kp1O + i] -= p*q; } } // (s != 0) } // k loop @@ -881,26 +891,34 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization for (n = order - 1; n >= 0; n--) { - float t; + var nO = n*order; + var nm1 = n - 1; + var nm1O = nm1*order; p = d[n]; q = e[n]; + // Real vector + float t; if (q == 0.0f) { var l = n; - matrixH[n, n] = 1.0f; + matrixH[nO + n] = 1.0f; for (var i = n - 1; i >= 0; i--) { - w = matrixH[i, i] - p; + var ip1 = i + 1; + var iO = i*order; + var ip1O = ip1*order; + + w = matrixH[iO + i] - p; r = 0.0f; for (var j = l; j <= n; j++) { - r = r + (matrixH[i, j] * matrixH[j, n]); + r = r + (matrixH[j*order + i]*matrixH[nO + j]); } - if (e[i] < 0.0f) + if (e[i] < 0.0) { z = w; s = r; @@ -912,39 +930,39 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization { if (w != 0.0f) { - matrixH[i, n] = (-r) / w; + matrixH[nO + i] = (-r)/w; } else { - matrixH[i, n] = (-r) / (eps * norm); + matrixH[nO + i] = (-r)/(eps*norm); } // Solve real equations } else { - x = matrixH[i, i + 1]; - y = matrixH[i + 1, i]; - q = ((d[i] - p) * (d[i] - p)) + (e[i] * e[i]); - t = ((x * s) - (z * r)) / q; - matrixH[i, n] = t; + x = matrixH[ip1O + i]; + y = matrixH[iO + ip1]; + q = ((d[i] - p)*(d[i] - p)) + (e[i]*e[i]); + t = ((x*s) - (z*r))/q; + matrixH[nO + i] = t; if (Math.Abs(x) > Math.Abs(z)) { - matrixH[i + 1, n] = (-r - (w * t)) / x; + matrixH[nO + ip1] = (-r - (w*t))/x; } else { - matrixH[i + 1, n] = (-s - (y * t)) / z; + matrixH[nO + ip1] = (-s - (y*t))/z; } } // Overflow control - t = Math.Abs(matrixH[i, n]); - if ((eps * t) * t > 1) + t = Math.Abs(matrixH[nO + i]); + if ((eps*t)*t > 1) { for (var j = i; j <= n; j++) { - matrixH[j, n] = matrixH[j, n] / t; + matrixH[nO + j] /= t; } } } @@ -957,33 +975,38 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization var l = n - 1; // Last vector component imaginary so matrix is triangular - if (Math.Abs(matrixH[n, n - 1]) > Math.Abs(matrixH[n - 1, n])) + if (Math.Abs(matrixH[nm1O + n]) > Math.Abs(matrixH[nO + nm1])) { - matrixH[n - 1, n - 1] = q / matrixH[n, n - 1]; - matrixH[n - 1, n] = (-(matrixH[n, n] - p)) / matrixH[n, n - 1]; + matrixH[nm1O + nm1] = q/matrixH[nm1O + n]; + matrixH[nO + nm1] = (-(matrixH[nO + n] - p))/matrixH[nm1O + n]; } else { - var res = Cdiv(0.0f, -matrixH[n - 1, n], matrixH[n - 1, n - 1] - p, q); - matrixH[n - 1, n - 1] = res.Real; - matrixH[n - 1, n] = res.Imaginary; + var res = Cdiv(0.0f, -matrixH[nO + nm1], matrixH[nm1O + nm1] - p, q); + matrixH[nm1O + nm1] = res.Real; + matrixH[nO + nm1] = res.Imaginary; } - matrixH[n, n - 1] = 0.0f; - matrixH[n, n] = 1.0f; + matrixH[nm1O + n] = 0.0f; + matrixH[nO + n] = 1.0f; for (var i = n - 2; i >= 0; i--) { - float ra = 0.0f; - float sa = 0.0f; + var ip1 = i + 1; + var iO = i*order; + var ip1O = ip1*order; + var ra = 0.0f; + var sa = 0.0f; for (var j = l; j <= n; j++) { - ra = ra + (matrixH[i, j] * matrixH[j, n - 1]); - sa = sa + (matrixH[i, j] * matrixH[j, n]); + var jO = j*order; + var jOi = jO + i; + ra = ra + (matrixH[jOi]*matrixH[nm1O + j]); + sa = sa + (matrixH[jOi]*matrixH[nO + j]); } - w = matrixH[i, i] - p; + w = matrixH[iO + i] - p; - if (e[i] < 0.0f) + if (e[i] < 0.0) { z = w; r = ra; @@ -992,49 +1015,49 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization else { l = i; - if (e[i] == 0.0f) + if (e[i] == 0.0) { var res = Cdiv(-ra, -sa, w, q); - matrixH[i, n - 1] = res.Real; - matrixH[i, n] = res.Imaginary; + matrixH[nm1O + i] = res.Real; + matrixH[nO + i] = res.Imaginary; } else { // Solve complex equations - x = matrixH[i, i + 1]; - y = matrixH[i + 1, i]; + x = matrixH[ip1O + i]; + y = matrixH[iO + ip1]; - float vr = ((d[i] - p) * (d[i] - p)) + (e[i] * e[i]) - (q * q); - float vi = (d[i] - p) * 2.0f * q; + var vr = ((d[i] - p)*(d[i] - p)) + (e[i]*e[i]) - (q*q); + var vi = (d[i] - p)*2.0f*q; if ((vr == 0.0f) && (vi == 0.0f)) { - vr = eps * norm * (Math.Abs(w) + Math.Abs(q) + Math.Abs(x) + Math.Abs(y) + Math.Abs(z)); + vr = eps*norm*(float) (Math.Abs(w) + Math.Abs(q) + Math.Abs(x) + Math.Abs(y) + Math.Abs(z)); } - var res = Cdiv((x * r) - (z * ra) + (q * sa), (x * s) - (z * sa) - (q * ra), vr, vi); - matrixH[i, n - 1] = res.Real; - matrixH[i, n] = res.Imaginary; + var res = Cdiv((x*r) - (z*ra) + (q*sa), (x*s) - (z*sa) - (q*ra), vr, vi); + matrixH[nm1O + i] = res.Real; + matrixH[nO + i] = res.Imaginary; if (Math.Abs(x) > (Math.Abs(z) + Math.Abs(q))) { - matrixH[i + 1, n - 1] = (-ra - (w * matrixH[i, n - 1]) + (q * matrixH[i, n])) / x; - matrixH[i + 1, n] = (-sa - (w * matrixH[i, n]) - (q * matrixH[i, n - 1])) / x; + matrixH[nm1O + ip1] = (-ra - (w*matrixH[nm1O + i]) + (q*matrixH[nO + i]))/x; + matrixH[nO + ip1] = (-sa - (w*matrixH[nO + i]) - (q*matrixH[nm1O + i]))/x; } else { - res = Cdiv(-r - (y * matrixH[i, n - 1]), -s - (y * matrixH[i, n]), z, q); - matrixH[i + 1, n - 1] = res.Real; - matrixH[i + 1, n] = res.Imaginary; + res = Cdiv(-r - (y*matrixH[nm1O + i]), -s - (y*matrixH[nO + i]), z, q); + matrixH[nm1O + ip1] = res.Real; + matrixH[nO + ip1] = res.Imaginary; } } // Overflow control - t = Math.Max(Math.Abs(matrixH[i, n - 1]), Math.Abs(matrixH[i, n])); - if ((eps * t) * t > 1) + t = Math.Max(Math.Abs(matrixH[nm1O + i]), Math.Abs(matrixH[nO + i])); + if ((eps*t)*t > 1) { for (var j = i; j <= n; j++) { - matrixH[j, n - 1] = matrixH[j, n - 1] / t; - matrixH[j, n] = matrixH[j, n] / t; + matrixH[nm1O + j] /= t; + matrixH[nO + j] /= t; } } } @@ -1045,15 +1068,16 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization // Back transformation to get eigenvectors of original matrix for (var j = order - 1; j >= 0; j--) { + var jO = j*order; for (var i = 0; i < order; i++) { z = 0.0f; for (var k = 0; k <= j; k++) { - z = z + (a[(k * order) + i] * matrixH[k, j]); + z = z + (a[k*order + i]*matrixH[jO + k]); } - a[(j * order) + i] = z; + a[jO + i] = z; } } } @@ -1066,14 +1090,14 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization /// Real part of Y /// Imaginary part of Y /// Division result as a number. - private static Complex32 Cdiv(float xreal, float ximag, float yreal, float yimag) + static Numerics.Complex32 Cdiv(float xreal, float ximag, float yreal, float yimag) { if (Math.Abs(yimag) < Math.Abs(yreal)) { - return new Complex32((xreal + (ximag * (yimag / yreal))) / (yreal + (yimag * (yimag / yreal))), (ximag - (xreal * (yimag / yreal))) / (yreal + (yimag * (yimag / yreal)))); + return new Numerics.Complex32((xreal + (ximag*(yimag/yreal)))/(yreal + (yimag*(yimag/yreal))), (ximag - (xreal*(yimag/yreal)))/(yreal + (yimag*(yimag/yreal)))); } - return new Complex32((ximag + (xreal * (yreal / yimag))) / (yimag + (yreal * (yreal / yimag))), (-xreal + (ximag * (yreal / yimag))) / (yimag + (yreal * (yreal / yimag)))); + return new Numerics.Complex32((ximag + (xreal*(yreal/yimag)))/(yimag + (yreal*(yreal/yimag))), (-xreal + (ximag*(yreal/yimag)))/(yimag + (yreal*(yreal/yimag)))); } /// @@ -1126,10 +1150,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization { for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(j * order) + i] * input.At(i, k); + value += ((DenseMatrix) MatrixEv).Values[(j*order) + i]*input.At(i, k); } - value /= (float)VectorEv[j].Real; + value /= (float) VectorEv[j].Real; } tmp[j] = value; @@ -1140,7 +1164,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization float value = 0; for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(i * order) + j] * tmp[i]; + value += ((DenseMatrix) MatrixEv).Values[(i*order) + j]*tmp[i]; } result.At(j, k, value); @@ -1197,10 +1221,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization { for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(j * order) + i] * input[i]; + value += ((DenseMatrix) MatrixEv).Values[(j*order) + i]*input[i]; } - value /= (float)VectorEv[j].Real; + value /= (float) VectorEv[j].Real; } tmp[j] = value; @@ -1209,9 +1233,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization for (var j = 0; j < order; j++) { value = 0; - for (int i = 0; i < order; i++) + for (var i = 0; i < order; i++) { - value += ((DenseMatrix)MatrixEv).Values[(i * order) + j] * tmp[i]; + value += ((DenseMatrix) MatrixEv).Values[(i*order) + j]*tmp[i]; } result[j] = value; @@ -1223,4 +1247,4 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization } } } -} \ No newline at end of file +} diff --git a/src/Numerics/LinearAlgebra/Single/Factorization/UserEvd.cs b/src/Numerics/LinearAlgebra/Single/Factorization/UserEvd.cs index e49125df..3053bae0 100644 --- a/src/Numerics/LinearAlgebra/Single/Factorization/UserEvd.cs +++ b/src/Numerics/LinearAlgebra/Single/Factorization/UserEvd.cs @@ -80,9 +80,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization IsSymmetric = true; - for (var i = 0; i < order & IsSymmetric; i++) + for (var i = 0; IsSymmetric && i < order; i++) { - for (var j = 0; j < order & IsSymmetric; j++) + for (var j = 0; IsSymmetric && j < order; j++) { IsSymmetric &= matrix.At(i, j) == matrix.At(j, i); } diff --git a/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs index 0db5efc5..97eda0fd 100644 --- a/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs +++ b/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs @@ -248,7 +248,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32 var matrix = _matrices["Square3x3"]; var work = new float[18]; var norm = Control.LinearAlgebraProvider.MatrixNorm(Norm.FrobeniusNorm, matrix.RowCount, matrix.ColumnCount, matrix.Values, work); - AssertHelpers.AlmostEqual(10.777754868246f, norm, 8); + AssertHelpers.AlmostEqual(10.777754868246f, norm, 6); } /// diff --git a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs index ac0d765d..d6b6ae38 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/EvdTests.cs @@ -30,7 +30,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization using System.Numerics; using LinearAlgebra.Complex; using LinearAlgebra.Complex.Factorization; - using LinearAlgebra.Generic.Factorization; using NUnit.Framework; /// diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs index 8bfb356a..69c753b9 100644 --- a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/EvdTests.cs @@ -30,7 +30,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization using System.Numerics; using LinearAlgebra.Complex32; using LinearAlgebra.Complex32.Factorization; - using LinearAlgebra.Generic.Factorization; using NUnit.Framework; using Complex32 = Numerics.Complex32; @@ -115,8 +114,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization /// /// Can factorize a symmetric random square matrix. /// Matrix order. - [Test, Ignore] - public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) + [Test] + public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10)] int order) { var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianDenseMatrix(order); MatrixHelpers.ForceConjugateSymmetric(matrixA); @@ -201,13 +200,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b). /// /// Matrix order. - [Test, Ignore] + [Test] [TestCase(1)] [TestCase(2)] [TestCase(5)] [TestCase(10)] [TestCase(50)] - [TestCase(100)] public void CanSolveForRandomVectorAndSymmetricMatrix(int order) { var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianDenseMatrix(order); @@ -249,7 +247,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization [TestCase(5)] [TestCase(10)] [TestCase(50)] - [TestCase(100)] public void CanSolveForRandomMatrixAndSymmetricMatrix(int order) { var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianDenseMatrix(order); @@ -292,13 +289,12 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization /// Can solve a system of linear equations for a random vector and symmetric matrix (Ax=b) into a result vector. /// /// Matrix order. - [Test, Ignore] + [Test] [TestCase(1)] [TestCase(2)] [TestCase(5)] [TestCase(10)] [TestCase(50)] - [TestCase(100)] public void CanSolveForRandomVectorAndSymmetricMatrixWhenResultVectorGiven(int order) { var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteHermitianDenseMatrix(order); diff --git a/src/UnitTests/LinearAlgebraTests/Double/Factorization/EvdTests.cs b/src/UnitTests/LinearAlgebraTests/Double/Factorization/EvdTests.cs index 098cb512..4354c101 100644 --- a/src/UnitTests/LinearAlgebraTests/Double/Factorization/EvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Double/Factorization/EvdTests.cs @@ -24,8 +24,6 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using MathNet.Numerics.LinearAlgebra.Generic; - namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization { using System; @@ -128,7 +126,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization var factorEvd = matrixA.Evd(); var eigenVectors = factorEvd.EigenVectors(); var d = factorEvd.D(); - + Assert.AreEqual(order, eigenVectors.RowCount); Assert.AreEqual(order, eigenVectors.ColumnCount); diff --git a/src/UnitTests/LinearAlgebraTests/Single/Factorization/EvdTests.cs b/src/UnitTests/LinearAlgebraTests/Single/Factorization/EvdTests.cs index 61f0825e..e098f6ff 100644 --- a/src/UnitTests/LinearAlgebraTests/Single/Factorization/EvdTests.cs +++ b/src/UnitTests/LinearAlgebraTests/Single/Factorization/EvdTests.cs @@ -77,7 +77,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization /// Can factorize a random square matrix. /// /// Matrix order. - [Test, Ignore] + [Test] public void CanFactorizeRandomMatrix([Values(1, 2, 5, 10, 50, 100)] int order) { var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); @@ -108,8 +108,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization /// Can factorize a symmetric random square matrix. /// /// Matrix order. - [Test, Ignore] - public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10, 50, 100)] int order) + [Test] + public void CanFactorizeRandomSymmetricMatrix([Values(1, 2, 5, 10, 50)] int order) { var matrixA = MatrixLoader.GenerateRandomPositiveDefiniteDenseMatrix(order); MatrixHelpers.ForceSymmetric(matrixA); @@ -169,7 +169,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization matrixA[i - 1, i] = 1; matrixA[i + 1, i] = 1; } - var factorEvd = matrixA.Evd(); Assert.AreEqual(factorEvd.Determinant, 0);