From 06008b1c88455bfd727029dc17321942e6273cbf Mon Sep 17 00:00:00 2001 From: Marcus Cuda Date: Fri, 3 Jul 2015 20:18:30 +0300 Subject: [PATCH 1/4] first take on removing work arrays and using LAPACKE in the MKL provider - native side --- .gitignore | 1 + src/NativeProviders/MKL/lapack.cpp | 1247 +++++++++-------- src/NativeProviders/MKL/lapack.h | 17 + .../Windows/MKL/MKLWrapper.vcxproj.filters | 4 +- src/Numerics/Exceptions.cs | 106 ++ src/Numerics/Properties/Resources.Designer.cs | 270 ++-- src/Numerics/Properties/Resources.resx | 15 + .../Mkl/MklLinearAlgebraProvider.Complex.cs | 477 ++----- .../Mkl/MklLinearAlgebraProvider.Complex32.cs | 478 ++----- .../Mkl/MklLinearAlgebraProvider.Double.cs | 481 ++----- .../Mkl/MklLinearAlgebraProvider.Single.cs | 472 ++----- .../Mkl/MklLinearAlgebraProvider.cs | 11 + .../LinearAlgebra/Mkl/SafeNativeMethods.cs | 64 +- .../Complex/LinearAlgebraProviderTests.cs | 16 +- src/UnitTests/UnitTests-MKL.csproj | 326 ++++- 15 files changed, 1847 insertions(+), 2138 deletions(-) create mode 100644 src/NativeProviders/MKL/lapack.h diff --git a/.gitignore b/.gitignore index fb3d351c..9ea7abe9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ coverage.* *.psess *.vsp *.vspx +*.lnt # Caches _ReSharper* diff --git a/src/NativeProviders/MKL/lapack.cpp b/src/NativeProviders/MKL/lapack.cpp index a1945bce..aa500dae 100644 --- a/src/NativeProviders/MKL/lapack.cpp +++ b/src/NativeProviders/MKL/lapack.cpp @@ -1,670 +1,729 @@ #include #include +#include "wrapper_common.h" -#define MKL_Complex8 std::complex -#define MKL_Complex16 std::complex - -#include "mkl_lapack.h" -#include "mkl_cblas.h" +#include "lapack.h" #include "lapack_common.h" -#include "wrapper_common.h" -#include "mkl_lapacke.h" -#include "mkl.h" -#include "mkl_trans.h" + +struct ptrfree +{ + void operator()(void* x) { PTRFREE(x); } +}; + +template using ptr = std::unique_ptr < T, ptrfree >; + +template +inline ptr array_new(const int size, int alignment = ALIGNMENT) { + auto ret = static_cast(PTRALLOC(size * sizeof(T), alignment)); + + if (!ret) + { + throw new std::bad_alloc(); + } + + return ptr(ret); +} + +template +inline ptr array_clone(const int size, const T* array){ + auto clone = array_new(size); + memcpy(clone.get(), array, size * sizeof(T)); + return clone; +} template -inline MKL_INT lu_factor(MKL_INT m, T a[], MKL_INT ipiv[], GETRF getrf) +inline lapack_int lu_factor(lapack_int m, T a[], lapack_int ipiv[], GETRF getrf) { - MKL_INT info = 0; - getrf(&m, &m, a, &m, ipiv, &info); - shift_ipiv_down(m, ipiv); - return info; + auto info = getrf(LAPACK_COL_MAJOR, m, m, a, m, ipiv); + shift_ipiv_down(m, ipiv); + return info; } template -inline MKL_INT lu_inverse(MKL_INT n, T a[], T work[], MKL_INT lwork, GETRF getrf, GETRI getri) +inline lapack_int lu_inverse(lapack_int n, T a[], GETRF getrf, GETRI getri) { - 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; + try + { + auto ipiv = array_new(n); + auto info = getrf(LAPACK_COL_MAJOR, n, n, a, n, ipiv.get()); + + if (info != 0) + { + return info; + } + + info = getri(LAPACK_COL_MAJOR, n, a, n, ipiv.get()); + return info; + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } } template -inline MKL_INT lu_inverse_factored(MKL_INT n, T a[], MKL_INT ipiv[], T work[], MKL_INT lwork, GETRI getri) +inline lapack_int lu_inverse_factored(lapack_int n, T a[], lapack_int ipiv[], GETRI getri) { - 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); + auto info = getri(LAPACK_COL_MAJOR, n, a, n, ipiv); + shift_ipiv_down(n, ipiv); + return info; } template -inline MKL_INT lu_solve_factored(MKL_INT n, MKL_INT nrhs, T a[], MKL_INT ipiv[], T b[], GETRS getrs) +inline lapack_int lu_solve_factored(lapack_int n, lapack_int nrhs, T a[], lapack_int ipiv[], T b[], GETRS getrs) { - 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); + auto info = getrs(LAPACK_COL_MAJOR, 'N', n, nrhs, a, n, ipiv, b, n); + shift_ipiv_down(n, ipiv); + return info; } template -inline MKL_INT lu_solve(MKL_INT n, MKL_INT nrhs, T a[], T b[], GETRF getrf, GETRS getrs) +inline lapack_int lu_solve(lapack_int n, lapack_int nrhs, T a[], T b[], GETRF getrf, GETRS getrs) { - 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; + try + { + auto clone = array_clone(n * n, a); + auto ipiv = array_new(n); + auto info = getrf(LAPACK_COL_MAJOR, n, n, clone.get(), n, ipiv.get()); + + if (info != 0) + { + return info; + } + + return getrs(LAPACK_COL_MAJOR, 'N', n, nrhs, clone.get(), n, ipiv.get(), b, n); + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } } template -inline MKL_INT cholesky_factor(MKL_INT n, T* a, POTRF potrf) +inline lapack_int cholesky_factor(lapack_int n, T* a, POTRF potrf) { - 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; + auto info = potrf(LAPACK_COL_MAJOR, 'L', n, a, n); + auto zero = T(); + + for (auto i = 0; i < n; ++i) + { + auto index = i * n; + + for (auto j = 0; j < n && i > j; ++j) + { + a[index + j] = zero; + } + } + + return info; } template -inline MKL_INT cholesky_solve(MKL_INT n, MKL_INT nrhs, T a[], T b[], POTRF potrf, POTRS potrs) +inline lapack_int cholesky_solve(lapack_int n, lapack_int nrhs, T a[], T b[], POTRF potrf, POTRS potrs) { - 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; -} + try + { + auto clone = array_clone(n * n, a); + auto info = potrf(LAPACK_COL_MAJOR, 'L', n, clone.get(), n); -template -inline MKL_INT cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, T a[], T b[], POTRS potrs) -{ - char uplo = 'L'; - MKL_INT info = 0; - potrs(&uplo, &n, &nrhs, a, &n, b, &n, &info); - return info; + if (info != 0) + { + return info; + } + + return potrs(LAPACK_COL_MAJOR, 'L', n, nrhs, clone.get(), n, b, n); + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } } + template -inline MKL_INT qr_factor(MKL_INT m, MKL_INT n, T r[], T tau[], T q[], T work[], MKL_INT len, GEQRF geqrf, ORGQR orgqr) +inline lapack_int qr_factor(lapack_int m, lapack_int n, T r[], T tau[], T q[], GEQRF geqrf, ORGQR orgqr) { - 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; + auto info = geqrf(LAPACK_COL_MAJOR, m, n, r, m, tau); + + for (auto i = 0; i < m; ++i) + { + for (auto j = 0; j < m && j < n; ++j) + { + if (i > j) + { + q[j * m + i] = r[j * m + i]; + } + } + } + + if (info != 0) + { + return info; + } + + //compute the q elements explicitly + if (m <= n) + { + info = orgqr(LAPACK_COL_MAJOR, m, m, m, q, m, tau); + } + else + { + info = orgqr(LAPACK_COL_MAJOR, m, m, n, q, m, tau); + } + + return info; } template -inline MKL_INT qr_thin_factor(MKL_INT m, MKL_INT n, T q[], T tau[], T r[], T work[], MKL_INT len, GEQRF geqrf, ORGQR orgqr) +inline lapack_int qr_thin_factor(lapack_int m, lapack_int n, T q[], T tau[], T r[], GEQRF geqrf, ORGQR orgqr) { - 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; + auto info = geqrf(LAPACK_COL_MAJOR, m, n, q, m, tau); + + for (auto i = 0; i < n; ++i) + { + for (auto j = 0; j < n; ++j) + { + if (i <= j) + { + r[j * n + i] = q[j * m + i]; + } + } + } + + if (info != 0) + { + return info; + } + + info = orgqr(LAPACK_COL_MAJOR, m, n, n, q, m, tau); + return info; } 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, GELS gels) +inline lapack_int qr_solve(lapack_int m, lapack_int n, lapack_int bn, T a[], T b[], T x[], GELS gels) { - 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; + try{ + auto clone_a = array_clone(m * n, a); + auto clone_b = array_clone(m * bn, b); + auto info = gels(LAPACK_COL_MAJOR, 'N', m, n, bn, clone_a.get(), m, clone_b.get(), m); + + if (info != 0) + { + return info; + } + + copyBtoX(m, n, bn, clone_b.get(), x); + return info; + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } + } 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, ORMQR ormqr, TRSM trsm) +inline lapack_int qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, T r[], T b[], T tau[], T x[], ORMQR ormqr, TRSM trsm) { - 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; + try + { + auto clone_b = array_clone(m * bn, b); + auto info = ormqr(LAPACK_COL_MAJOR, 'L', 'T', m, bn, n, r, m, tau, clone_b.get(), m); + + if (info != 0) + { + return info; + } + + trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, 1.0, r, m, clone_b.get(), m); + copyBtoX(m, n, bn, clone_b.get(), x); + return info; + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } + } 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, UNMQR unmqr, TRSM trsm) +inline lapack_int complex_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, T r[], T b[], T tau[], T x[], UNMQR unmqr, TRSM trsm) { - 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; + try + { + auto clone_b = array_clone(m * bn, b); + auto info = unmqr(LAPACK_COL_MAJOR, 'L', 'C', m, bn, n, r, m, tau, clone_b.get(), m); + + if (info != 0) + { + return info; + } + + T one = 1.0f; + trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, &one, r, m, clone_b.get(), m); + copyBtoX(m, n, bn, clone_b.get(), x); + return info; + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } } 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, GESVD gesvd) +inline lapack_int svd_factor(bool compute_vectors, lapack_int m, lapack_int n, T a[], T s[], T u[], T v[], GESVD gesvd) { - 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; + try + { + auto job = compute_vectors ? 'A' : 'N'; + auto dim_s = std::min(m, n); + auto superb = array_new(std::max(2, dim_s) - 1); + return gesvd(LAPACK_COL_MAJOR, job, job, m, n, a, m, s, u, m, v, n, superb.get()); + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } } 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, GESVD gesvd) +inline lapack_int complex_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, T a[], T s[], T u[], T v[], GESVD gesvd) { - 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; + try + { + auto dim_s = std::min(m, n); + auto s_local = array_new(dim_s); + auto superb = array_new(std::max(2, dim_s) - 1); + auto job = compute_vectors ? 'A' : 'N'; + auto info = gesvd(LAPACK_COL_MAJOR, job, job, m, n, a, m, s_local.get(), u, m, v, n, superb.get()); + + for (auto index = 0; index < dim_s; ++index) + { + s[index] = s_local.get()[index]; + } + + return info; + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } } template -inline MKL_INT eigen_factor(MKL_INT n, T a[], T vectors[], R values[], T d[], GEES gees, TREVC trevc) +inline lapack_int eigen_factor(lapack_int n, T a[], T vectors[], R values[], T d[], GEES gees, TREVC trevc) { - 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] = R(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; + try + { + auto clone_a = array_clone(n * n, a); + auto wr = array_new(n); + auto wi = array_new(n); + + lapack_int sdim; + lapack_int info = gees(LAPACK_COL_MAJOR, 'V', 'N', nullptr, n, clone_a.get(), n, &sdim, wr.get(), wi.get(), vectors, n); + if (info != 0) + { + return info; + } + + lapack_int m; + info = trevc(LAPACK_COL_MAJOR, 'R', 'B', nullptr, n, clone_a.get(), n, nullptr, n, vectors, n, n, &m); + if (info != 0) + { + return info; + } + + for (auto index = 0; index < n; ++index) + { + values[index] = R(wr.get()[index], wi.get()[index]); + } + + for (auto i = 0; i < n; ++i) + { + auto in = i * n; + d[in + i] = wr.get()[i]; + + if (wi.get()[i] > 0) + { + d[in + n + i] = wi.get()[i]; + } + else if (wi.get()[i] < 0) + { + d[in - n + i] = wi.get()[i]; + } + } + return info; + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } } template -inline MKL_INT eigen_complex_factor(MKL_INT n, T a[], T vectors[], MKL_Complex16 values[], T d[], GEES gees, TREVC trevc) +inline lapack_int eigen_complex_factor(lapack_int n, T a[], T vectors[], std::complex values[], T d[], GEES gees, TREVC trevc) { - T* clone_a = Clone(n, n, a); - T* w = new T[n]; - - MKL_INT sdim; - MKL_INT info = gees(LAPACK_COL_MAJOR, 'V', 'N', nullptr, n, clone_a, n, &sdim, w, vectors, n); - if (info != 0) + try { - delete[] clone_a; - delete[] w; + auto clone_a = array_clone(n * n, a); + auto w = array_new(n); + + lapack_int sdim; + lapack_int info = gees(LAPACK_COL_MAJOR, 'V', 'N', nullptr, n, clone_a.get(), n, &sdim, w.get(), vectors, n); + if (info != 0) + { + return info; + } + + lapack_int m; + info = trevc(LAPACK_COL_MAJOR, 'R', 'B', nullptr, n, clone_a.get(), n, nullptr, n, vectors, n, n, &m); + if (info != 0) + { + return info; + } + + for (auto i = 0; i < n; ++i) + { + values[i] = w.get()[i]; + d[i * n + i] = w.get()[i]; + } + return info; } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } +} - MKL_INT m; - info = trevc(LAPACK_COL_MAJOR, 'R', 'B', nullptr, n, clone_a, n, nullptr, n, vectors, n, n, &m); - if (info != 0) +template +inline lapack_int sym_eigen_factor(lapack_int n, T a[], T vectors[], std::complex values[], T d[], SYEV syev) +{ + try { - delete[] clone_a; - delete[] w; + auto clone_a = array_clone(n * n, a); + auto w = array_new(n); + + lapack_int info = syev(LAPACK_COL_MAJOR, 'V', 'U', n, clone_a.get(), n, w.get()); + if (info != 0) + { + return info; + } + + memcpy(vectors, clone_a.get(), n*n*sizeof(T)); + + for (auto index = 0; index < n; ++index) + { + values[index] = std::complex(w.get()[index]); + } + + for (auto j = 0; j < n; ++j) + { + auto jn = j*n; + + for (auto i = 0; i < n; ++i) + { + if (i == j) + { + d[jn + i] = w.get()[i]; + } + } + } + return info; } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } +} + +extern "C" { - for (MKL_INT i = 0; i < n; ++i) + DLLEXPORT float s_matrix_norm(char norm, lapack_int m, lapack_int n, float a[]) { - values[i] = w[i]; - d[i * n + i] = w[i]; + return LAPACKE_slange(LAPACK_COL_MAJOR, norm, m, n, a, m); } - delete[] clone_a; - delete[] w; - return info; -} + DLLEXPORT double d_matrix_norm(char norm, lapack_int m, lapack_int n, double a[]) + { + return LAPACKE_dlange(LAPACK_COL_MAJOR, norm, m, n, a, m); + } -template -inline MKL_INT sym_eigen_factor(MKL_INT n, T a[], T vectors[], MKL_Complex16 values[], T d[], SYEV syev) -{ - T* clone_a = Clone(n, n, a); - R* w = new R[n]; + DLLEXPORT float c_matrix_norm(char norm, lapack_int m, lapack_int n, std::complex a[]) + { + return LAPACKE_clange(LAPACK_COL_MAJOR, norm, m, n, a, m); + } - MKL_INT info = syev(LAPACK_COL_MAJOR, 'V', 'U', n, clone_a, n, w); - if (info != 0) + DLLEXPORT double z_matrix_norm(char norm, lapack_int m, lapack_int n, std::complex a[]) { - delete[] clone_a; - delete[] w; - return info; + return LAPACKE_zlange(LAPACK_COL_MAJOR, norm, m, n, a, m); } - - memcpy(vectors, clone_a, n*n*sizeof(T)); - for (MKL_INT index = 0; index < n; ++index) + DLLEXPORT lapack_int s_lu_factor(lapack_int m, float a[], lapack_int ipiv[]) { - values[index] = MKL_Complex16(w[index]); + return lu_factor(m, a, ipiv, LAPACKE_sgetrf); } - - for (MKL_INT j = 0; j < n; ++j) - { - MKL_INT jn = j*n; - for (MKL_INT i = 0; i < n; ++i) - { - if (i == j) - { - d[jn + i] = w[i]; - } - } - } + DLLEXPORT lapack_int d_lu_factor(lapack_int m, double a[], lapack_int ipiv[]) + { + return lu_factor(m, a, ipiv, LAPACKE_dgetrf); + } - delete[] clone_a; - delete[] w; - return info; -} + DLLEXPORT lapack_int c_lu_factor(lapack_int m, std::complex a[], lapack_int ipiv[]) + { + return lu_factor(m, a, ipiv, LAPACKE_cgetrf); + } -extern "C" { + DLLEXPORT lapack_int z_lu_factor(lapack_int m, std::complex a[], lapack_int ipiv[]) + { + return lu_factor(m, a, ipiv, LAPACKE_zgetrf); + } + + DLLEXPORT lapack_int s_lu_inverse(lapack_int n, float a[], float work[], lapack_int lwork) + { + return lu_inverse(n, a, LAPACKE_sgetrf, LAPACKE_sgetri); + } + + DLLEXPORT lapack_int d_lu_inverse(lapack_int n, double a[], double work[], lapack_int lwork) + { + return lu_inverse(n, a, LAPACKE_dgetrf, LAPACKE_dgetri); + } + + DLLEXPORT lapack_int c_lu_inverse(lapack_int n, std::complex a[], std::complex work[], lapack_int lwork) + { + return lu_inverse(n, a, LAPACKE_cgetrf, LAPACKE_cgetri); + } + + DLLEXPORT lapack_int z_lu_inverse(lapack_int n, std::complex a[], std::complex work[], lapack_int lwork) + { + return lu_inverse(n, a, LAPACKE_zgetrf, LAPACKE_zgetri); + } + + DLLEXPORT lapack_int s_lu_inverse_factored(lapack_int n, float a[], lapack_int ipiv[], float work[], lapack_int lwork) + { + return lu_inverse_factored(n, a, ipiv, LAPACKE_sgetri); + } + + DLLEXPORT lapack_int d_lu_inverse_factored(lapack_int n, double a[], lapack_int ipiv[], double work[], lapack_int lwork) + { + return lu_inverse_factored(n, a, ipiv, LAPACKE_dgetri); + } + + DLLEXPORT lapack_int c_lu_inverse_factored(lapack_int n, std::complex a[], lapack_int ipiv[], std::complex work[], lapack_int lwork) + { + return lu_inverse_factored(n, a, ipiv, LAPACKE_cgetri); + } + + DLLEXPORT lapack_int z_lu_inverse_factored(lapack_int n, std::complex a[], lapack_int ipiv[], std::complex work[], lapack_int lwork) + { + return lu_inverse_factored(n, a, ipiv, LAPACKE_zgetri); + } + + DLLEXPORT lapack_int s_lu_solve_factored(lapack_int n, lapack_int nrhs, float a[], lapack_int ipiv[], float b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACKE_sgetrs); + } + + DLLEXPORT lapack_int d_lu_solve_factored(lapack_int n, lapack_int nrhs, double a[], lapack_int ipiv[], double b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACKE_dgetrs); + } + + DLLEXPORT lapack_int c_lu_solve_factored(lapack_int n, lapack_int nrhs, std::complex a[], lapack_int ipiv[], std::complex b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACKE_cgetrs); + } + + DLLEXPORT lapack_int z_lu_solve_factored(lapack_int n, lapack_int nrhs, std::complex a[], lapack_int ipiv[], std::complex b[]) + { + return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACKE_zgetrs); + } + + DLLEXPORT lapack_int s_lu_solve(lapack_int n, lapack_int nrhs, float a[], float b[]) + { + return lu_solve(n, nrhs, a, b, LAPACKE_sgetrf, LAPACKE_sgetrs); + } + + DLLEXPORT lapack_int d_lu_solve(lapack_int n, lapack_int nrhs, double a[], double b[]) + { + return lu_solve(n, nrhs, a, b, LAPACKE_dgetrf, LAPACKE_dgetrs); + } + + DLLEXPORT lapack_int c_lu_solve(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + { + return lu_solve(n, nrhs, a, b, LAPACKE_cgetrf, LAPACKE_cgetrs); + } + + DLLEXPORT lapack_int z_lu_solve(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + { + return lu_solve(n, nrhs, a, b, LAPACKE_zgetrf, LAPACKE_zgetrs); + } + + DLLEXPORT lapack_int s_cholesky_factor(lapack_int n, float a[]) + { + return cholesky_factor(n, a, LAPACKE_spotrf); + } + + DLLEXPORT lapack_int d_cholesky_factor(lapack_int n, double* a) + { + return cholesky_factor(n, a, LAPACKE_dpotrf); + } + + DLLEXPORT lapack_int c_cholesky_factor(lapack_int n, std::complex a[]) + { + return cholesky_factor(n, a, LAPACKE_cpotrf); + } + + DLLEXPORT lapack_int z_cholesky_factor(lapack_int n, std::complex a[]) + { + return cholesky_factor(n, a, LAPACKE_zpotrf); + } + + DLLEXPORT lapack_int s_cholesky_solve(lapack_int n, lapack_int nrhs, float a[], float b[]) + { + return cholesky_solve(n, nrhs, a, b, LAPACKE_spotrf, LAPACKE_spotrs); + } + + DLLEXPORT lapack_int d_cholesky_solve(lapack_int n, lapack_int nrhs, double a[], double b[]) + { + return cholesky_solve(n, nrhs, a, b, LAPACKE_dpotrf, LAPACKE_dpotrs); + } + + DLLEXPORT lapack_int c_cholesky_solve(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + { + return cholesky_solve(n, nrhs, a, b, LAPACKE_cpotrf, LAPACKE_cpotrs); + } + + DLLEXPORT lapack_int z_cholesky_solve(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + { + return cholesky_solve(n, nrhs, a, b, LAPACKE_zpotrf, LAPACKE_zpotrs); + } - 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[]) - { + DLLEXPORT lapack_int s_cholesky_solve_factored(lapack_int n, lapack_int nrhs, float a[], float b[]) + { + return LAPACKE_spotrs(LAPACK_COL_MAJOR, 'L', n, nrhs, a, n, b, n); + } + + DLLEXPORT lapack_int d_cholesky_solve_factored(lapack_int n, lapack_int nrhs, double a[], double b[]) + { + return LAPACKE_dpotrs(LAPACK_COL_MAJOR, 'L', n, nrhs, a, n, b, n); + } + + DLLEXPORT lapack_int c_cholesky_solve_factored(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + { + return LAPACKE_cpotrs(LAPACK_COL_MAJOR, 'L', n, nrhs, a, n, b, n); + } + + DLLEXPORT lapack_int z_cholesky_solve_factored(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + { + return LAPACKE_zpotrs(LAPACK_COL_MAJOR, 'L', n, nrhs, a, n, b, n); + } + + DLLEXPORT lapack_int s_qr_factor(lapack_int m, lapack_int n, float r[], float tau[], float q[]) + { + return qr_factor(m, n, r, tau, q, LAPACKE_sgeqrf, LAPACKE_sorgqr); + } + + DLLEXPORT lapack_int s_qr_thin_factor(lapack_int m, lapack_int n, float q[], float tau[], float r[]) + { + return qr_thin_factor(m, n, q, tau, r, LAPACKE_sgeqrf, LAPACKE_sorgqr); + } + + DLLEXPORT lapack_int d_qr_factor(lapack_int m, lapack_int n, double r[], double tau[], double q[]) + { + return qr_factor(m, n, r, tau, q, LAPACKE_dgeqrf, LAPACKE_dorgqr); + } + + DLLEXPORT lapack_int d_qr_thin_factor(lapack_int m, lapack_int n, double q[], double tau[], double r[]) + { + return qr_thin_factor(m, n, q, tau, r, LAPACKE_dgeqrf, LAPACKE_dorgqr); + } + + DLLEXPORT lapack_int c_qr_factor(lapack_int m, lapack_int n, std::complex r[], std::complex tau[], std::complex q[]) + { + return qr_factor(m, n, r, tau, q, LAPACKE_cgeqrf, LAPACKE_cungqr); + } + + DLLEXPORT lapack_int c_qr_thin_factor(lapack_int m, lapack_int n, std::complex q[], std::complex tau[], std::complex r[]) + { + return qr_thin_factor(m, n, q, tau, r, LAPACKE_cgeqrf, LAPACKE_cungqr); + } + + DLLEXPORT lapack_int z_qr_factor(lapack_int m, lapack_int n, std::complex r[], std::complex tau[], std::complex q[]) + { + return qr_factor(m, n, r, tau, q, LAPACKE_zgeqrf, LAPACKE_zungqr); + } + + DLLEXPORT lapack_int z_qr_thin_factor(lapack_int m, lapack_int n, std::complex q[], std::complex tau[], std::complex r[]) + { + return qr_thin_factor(m, n, q, tau, r, LAPACKE_zgeqrf, LAPACKE_zungqr); + } + + DLLEXPORT lapack_int s_qr_solve(lapack_int m, lapack_int n, lapack_int bn, float a[], float b[], float x[]) + { + return qr_solve(m, n, bn, a, b, x, LAPACKE_sgels); + } + + DLLEXPORT lapack_int d_qr_solve(lapack_int m, lapack_int n, lapack_int bn, double a[], double b[], double x[]) + { + return qr_solve(m, n, bn, a, b, x, LAPACKE_dgels); + } + + DLLEXPORT lapack_int c_qr_solve(lapack_int m, lapack_int n, lapack_int bn, std::complex a[], std::complex b[], std::complex x[]) + { + return qr_solve(m, n, bn, a, b, x, LAPACKE_cgels); + } + + DLLEXPORT lapack_int z_qr_solve(lapack_int m, lapack_int n, lapack_int bn, std::complex a[], std::complex b[], std::complex x[]) + { + return qr_solve(m, n, bn, a, b, x, LAPACKE_zgels); + } + + DLLEXPORT lapack_int s_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, float r[], float b[], float tau[], float x[]) + { + return qr_solve_factored(m, n, bn, r, b, tau, x, LAPACKE_sormqr, cblas_strsm); + } + + DLLEXPORT lapack_int d_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, double r[], double b[], double tau[], double x[]) + { + return qr_solve_factored(m, n, bn, r, b, tau, x, LAPACKE_dormqr, cblas_dtrsm); + } + + DLLEXPORT lapack_int c_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, std::complex r[], std::complex b[], std::complex tau[], std::complex x[]) + { + return complex_qr_solve_factored(m, n, bn, r, b, tau, x, LAPACKE_cunmqr, cblas_ctrsm); + } + + DLLEXPORT lapack_int z_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, std::complex r[], std::complex b[], std::complex tau[], std::complex x[]) + { + return complex_qr_solve_factored(m, n, bn, r, b, tau, x, LAPACKE_zunmqr, cblas_ztrsm); + } + + DLLEXPORT lapack_int s_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, float a[], float s[], float u[], float v[]) + { + return svd_factor(compute_vectors, m, n, a, s, u, v, LAPACKE_sgesvd); + } + + DLLEXPORT lapack_int d_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, double a[], double s[], double u[], double v[]) + { + return svd_factor(compute_vectors, m, n, a, s, u, v, LAPACKE_dgesvd); + } + + DLLEXPORT lapack_int c_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, std::complex a[], std::complex s[], std::complex u[], std::complex v[]) + { + return complex_svd_factor, float>(compute_vectors, m, n, a, s, u, v, LAPACKE_cgesvd); + } + + DLLEXPORT lapack_int z_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, std::complex a[], std::complex s[], std::complex u[], std::complex v[]) + { + return complex_svd_factor, double>(compute_vectors, m, n, a, s, u, v, LAPACKE_zgesvd); + } + + DLLEXPORT lapack_int s_eigen(bool isSymmetric, lapack_int n, float a[], float vectors[], std::complex values[], float d[]) + { if (isSymmetric) { return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_ssyev); @@ -673,22 +732,22 @@ extern "C" { { 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) - { + DLLEXPORT lapack_int d_eigen(bool isSymmetric, lapack_int n, double a[], double vectors[], std::complex values[], double d[]) + { + if (isSymmetric) + { return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_dsyev); - } - else - { + } + 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[]) - { + DLLEXPORT lapack_int c_eigen(bool isSymmetric, lapack_int n, std::complex a[], std::complex vectors[], std::complex values[], std::complex d[]) + { if (isSymmetric) { return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_cheev); @@ -697,10 +756,10 @@ extern "C" { { return eigen_complex_factor(n, a, vectors, values, d, LAPACKE_cgees, LAPACKE_ctrevc); } - } - - DLLEXPORT MKL_INT z_eigen(bool isSymmetric, MKL_INT n, MKL_Complex16 a[], MKL_Complex16 vectors[], MKL_Complex16 values[], MKL_Complex16 d[]) - { + } + + DLLEXPORT lapack_int z_eigen(bool isSymmetric, lapack_int n, std::complex a[], std::complex vectors[], std::complex values[], std::complex d[]) + { if (isSymmetric) { return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_zheev); @@ -709,5 +768,5 @@ extern "C" { { return eigen_complex_factor(n, a, vectors, values, d, LAPACKE_zgees, LAPACKE_ztrevc); } - } + } } diff --git a/src/NativeProviders/MKL/lapack.h b/src/NativeProviders/MKL/lapack.h new file mode 100644 index 00000000..dce0c23a --- /dev/null +++ b/src/NativeProviders/MKL/lapack.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#define MKL_Complex8 std::complex +#define MKL_Complex16 std::complex + +#include "mkl.h" + +const int INSUFFICIENT_MEMORY = -999999; +const int ALIGNMENT = 64; + +//#define PTRALLOC( size, alignment ) LAPACKE_malloc( size ) +//#define PTRFREE( p ) LAPACKE_free( p ) + +#define PTRALLOC( size, alignment ) mkl_malloc( size, alignment ) +#define PTRFREE( p ) mkl_free( p ) + diff --git a/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters b/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters index 09081f53..c543369a 100644 --- a/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters +++ b/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters @@ -9,7 +9,7 @@ {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 @@ -36,7 +36,7 @@ - Resource Files + Source Files\Resource Files diff --git a/src/Numerics/Exceptions.cs b/src/Numerics/Exceptions.cs index ddee11f5..5d17b7be 100644 --- a/src/Numerics/Exceptions.cs +++ b/src/Numerics/Exceptions.cs @@ -53,6 +53,112 @@ namespace MathNet.Numerics : base(info, context) { } +#endif + } + + /// + /// An error occured calling native provider function. + /// + [Serializable] + public abstract class NativeInterfaceException : Exception + { + protected NativeInterfaceException() + { + } + + protected NativeInterfaceException(string message) + : base(message) + { + } + + protected NativeInterfaceException(string message, Exception innerException) + : base(message, innerException) + { + } +#if !PORTABLE + protected NativeInterfaceException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } +#endif + } + + /// + /// An error occured calling native provider function. + /// + [Serializable] + public class InvalidParameterException : NativeInterfaceException + { + public InvalidParameterException() + : base(Resources.InvalidParameter) + { + } + + public InvalidParameterException(int parameter) + : base(string.Format(Resources.InvalidParameterWithNumber, parameter)) + { + } + + public InvalidParameterException(int parameter, Exception innerException) + : base(string.Format(Resources.InvalidParameterWithNumber, parameter), innerException) + { + } +#if !PORTABLE + protected InvalidParameterException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } +#endif + } + + /// + /// Native provider was unable to allocate sufficent memory. + /// + [Serializable] + public class MemoryAllocationException : NativeInterfaceException + { + public MemoryAllocationException() + : base(Resources.MemoryAllocation) + { + } + + public MemoryAllocationException(Exception innerException) + : base(Resources.MemoryAllocation, innerException) + { + } +#if !PORTABLE + protected MemoryAllocationException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } +#endif + } + + /// + /// Native provider failed LU inversion do to a singular U matrix. + /// + [Serializable] + public class SingularUMatrixException : NativeInterfaceException + { + public SingularUMatrixException() + : base(Resources.SingularUMatrix) + { + } + + public SingularUMatrixException(int element) + : base(string.Format(Resources.SingularUMatrixWithElement, element)) + { + } + + public SingularUMatrixException(int element, Exception innerException) + : base(string.Format(Resources.SingularUMatrixWithElement, element), innerException) + { + } +#if !PORTABLE + protected SingularUMatrixException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { + } #endif } } diff --git a/src/Numerics/Properties/Resources.Designer.cs b/src/Numerics/Properties/Resources.Designer.cs index 301c0a64..8b9820ea 100644 --- a/src/Numerics/Properties/Resources.Designer.cs +++ b/src/Numerics/Properties/Resources.Designer.cs @@ -8,12 +8,10 @@ // //------------------------------------------------------------------------------ -using System.Reflection; - namespace MathNet.Numerics.Properties { using System; - - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -25,38 +23,29 @@ namespace MathNet.Numerics.Properties { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Resources.ResourceManager ResourceManager { get { -#if NET45REFLECTION - if (object.ReferenceEquals(resourceMan, null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MathNet.Numerics.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); - resourceMan = temp; - } -#else - if (object.ReferenceEquals(resourceMan, null)) - { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MathNet.Numerics.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } -#endif return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. @@ -70,7 +59,7 @@ namespace MathNet.Numerics.Properties { resourceCulture = value; } } - + /// /// Looks up a localized string similar to The accuracy couldn't be reached with the specified number of iterations.. /// @@ -79,7 +68,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("AccuracyNotReached", resourceCulture); } } - + /// /// Looks up a localized string similar to The array arguments must have the same length.. /// @@ -88,7 +77,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentArraysSameLength", resourceCulture); } } - + /// /// Looks up a localized string similar to The given array is the wrong length. Should be {0}.. /// @@ -97,7 +86,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentArrayWrongLength", resourceCulture); } } - + /// /// Looks up a localized string similar to The argument must be between 0 and 1.. /// @@ -106,7 +95,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentBetween0And1", resourceCulture); } } - + /// /// Looks up a localized string similar to Value cannot be in the range -1 < x < 1.. /// @@ -115,7 +104,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentCannotBeBetweenOneAndNegativeOne", resourceCulture); } } - + /// /// Looks up a localized string similar to Value must be even.. /// @@ -124,7 +113,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentEven", resourceCulture); } } - + /// /// Looks up a localized string similar to The histogram does not contain the value.. /// @@ -133,7 +122,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentHistogramContainsNot", resourceCulture); } } - + /// /// Looks up a localized string similar to Value is expected to be between {0} and {1} (including {0} and {1}).. /// @@ -142,7 +131,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentInIntervalXYInclusive", resourceCulture); } } - + /// /// Looks up a localized string similar to At least one item of {0} is a null reference (Nothing in Visual Basic).. /// @@ -151,7 +140,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentItemNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Value must be greater than or equal to one.. /// @@ -160,7 +149,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentLessThanOne", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix dimensions must agree.. /// @@ -169,7 +158,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixDimensions", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix dimensions must agree: {0}.. /// @@ -178,7 +167,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixDimensions1", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix dimensions must agree: op1 is {0}, op2 is {1}.. /// @@ -187,7 +176,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixDimensions2", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix dimensions must agree: op1 is {0}, op2 is {1}, op3 is {2}.. /// @@ -196,7 +185,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixDimensions3", resourceCulture); } } - + /// /// Looks up a localized string similar to The requested matrix does not exist.. /// @@ -205,7 +194,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixDoesNotExist", resourceCulture); } } - + /// /// Looks up a localized string similar to The matrix indices must not be out of range of the given matrix.. /// @@ -214,7 +203,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixIndexOutOfRange", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must not be rank deficient.. /// @@ -223,7 +212,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixNotRankDeficient", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must not be singular.. /// @@ -232,7 +221,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixNotSingular", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must be positive definite.. /// @@ -241,7 +230,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixPositiveDefinite", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix column dimensions must agree.. /// @@ -250,7 +239,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixSameColumnDimension", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix row dimensions must agree.. /// @@ -259,7 +248,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixSameRowDimension", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must have exactly one column.. /// @@ -268,7 +257,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixSingleColumn", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must have exactly one column and row, thus have only one cell.. /// @@ -277,7 +266,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixSingleColumnRow", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must have exactly one row.. /// @@ -286,7 +275,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixSingleRow", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must be square.. /// @@ -295,7 +284,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixSquare", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must be symmetric.. /// @@ -304,7 +293,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixSymmetric", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must be symmetric positive definite.. /// @@ -313,7 +302,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMatrixSymmetricPositiveDefinite", resourceCulture); } } - + /// /// Looks up a localized string similar to In the specified range, the minimum is greater than maximum.. /// @@ -322,7 +311,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMinValueGreaterThanMaxValue", resourceCulture); } } - + /// /// Looks up a localized string similar to Value must be positive.. /// @@ -331,7 +320,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentMustBePositive", resourceCulture); } } - + /// /// Looks up a localized string similar to Value must neither be infinite nor NaN.. /// @@ -340,7 +329,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentNotInfinityNaN", resourceCulture); } } - + /// /// Looks up a localized string similar to Value must not be negative (zero is ok).. /// @@ -349,7 +338,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentNotNegative", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} is a null reference (Nothing in Visual Basic).. /// @@ -358,7 +347,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentNull", resourceCulture); } } - + /// /// Looks up a localized string similar to Value must be odd.. /// @@ -367,7 +356,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentOdd", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} must be greater than {1}.. /// @@ -376,7 +365,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentOutOfRangeGreater", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} must be greater than or equal to {1}.. /// @@ -385,7 +374,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentOutOfRangeGreaterEqual", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} must be smaller than {1}.. /// @@ -412,7 +401,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentParameterSetInvalid", resourceCulture); } } - + /// /// Looks up a localized string similar to The given expression does not represent a complex number.. /// @@ -421,7 +410,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentParseComplexNumber", resourceCulture); } } - + /// /// Looks up a localized string similar to Value must be positive (and not zero).. /// @@ -430,7 +419,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentPositive", resourceCulture); } } - + /// /// Looks up a localized string similar to Size must be a Power of Two.. /// @@ -439,7 +428,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentPowerOfTwo", resourceCulture); } } - + /// /// Looks up a localized string similar to Size must be a Power of Two in every dimension.. /// @@ -448,7 +437,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentPowerOfTwoEveryDimension", resourceCulture); } } - + /// /// Looks up a localized string similar to The range between {0} and {1} must be less than or equal to {2}.. /// @@ -457,7 +446,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentRangeLessEqual", resourceCulture); } } - + /// /// Looks up a localized string similar to Arguments must be different objects.. /// @@ -466,7 +455,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentReferenceDifferent", resourceCulture); } } - + /// /// Looks up a localized string similar to Array must have exactly one dimension (and not be null).. /// @@ -475,7 +464,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentSingleDimensionArray", resourceCulture); } } - + /// /// Looks up a localized string similar to Value is too large.. /// @@ -484,7 +473,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentTooLarge", resourceCulture); } } - + /// /// Looks up a localized string similar to Value is too large for the current iteration limit.. /// @@ -493,7 +482,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentTooLargeForIterationLimit", resourceCulture); } } - + /// /// Looks up a localized string similar to Type mismatch.. /// @@ -502,7 +491,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentTypeMismatch", resourceCulture); } } - + /// /// Looks up a localized string similar to The upper bound must be strictly larger than the lower bound.. /// @@ -511,7 +500,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentUpperBoundMustBeLargerThanLowerBound", resourceCulture); } } - + /// /// Looks up a localized string similar to The upper bound must be at least as large as the lower bound.. /// @@ -520,7 +509,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentUpperBoundMustBeLargerThanOrEqualToLowerBound", resourceCulture); } } - + /// /// Looks up a localized string similar to Array length must be a multiple of {0}.. /// @@ -529,7 +518,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentVectorLengthsMultipleOf", resourceCulture); } } - + /// /// Looks up a localized string similar to All vectors must have the same dimensionality.. /// @@ -538,7 +527,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentVectorsSameLength", resourceCulture); } } - + /// /// Looks up a localized string similar to The vector must have 3 dimensions.. /// @@ -547,7 +536,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArgumentVectorThreeDimensional", resourceCulture); } } - + /// /// Looks up a localized string similar to The given array is too small. It must be at least {0} long.. /// @@ -556,7 +545,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ArrayTooSmall", resourceCulture); } } - + /// /// Looks up a localized string similar to Big endian files are not supported.. /// @@ -565,7 +554,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("BigEndianNotSupported", resourceCulture); } } - + /// /// Looks up a localized string similar to The supplied collection is empty.. /// @@ -574,7 +563,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("CollectionEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to Complex matrices are not supported.. /// @@ -583,7 +572,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ComplexMatricesNotSupported", resourceCulture); } } - + /// /// Looks up a localized string similar to An algorithm failed to converge.. /// @@ -592,7 +581,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ConvergenceFailed", resourceCulture); } } - + /// /// Looks up a localized string similar to This feature is not implemented yet (but is planned).. /// @@ -601,7 +590,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("FeaturePlannedButNotImplementedYet", resourceCulture); } } - + /// /// Looks up a localized string similar to The given file doesn't exist.. /// @@ -610,7 +599,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("FileDoesNotExist", resourceCulture); } } - + /// /// Looks up a localized string similar to Sample points should be sorted in strictly ascending order. /// @@ -619,7 +608,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("Interpolation_Initialize_SamplePointsNotStrictlyAscendingOrder", resourceCulture); } } - + /// /// Looks up a localized string similar to All sample points should be unique.. /// @@ -628,7 +617,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("Interpolation_Initialize_SamplePointsNotUnique", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid parameterization for the distribution.. /// @@ -637,7 +626,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("InvalidDistributionParameters", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid Left Boundary Condition.. /// @@ -646,7 +635,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("InvalidLeftBoundaryCondition", resourceCulture); } } - + /// /// Looks up a localized string similar to The operation could not be performed because the accumulator is empty.. /// @@ -655,7 +644,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("InvalidOperationAccumulatorEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to The operation could not be performed because the histogram is empty.. /// @@ -664,7 +653,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("InvalidOperationHistogramEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to Not enough points in the distribution.. /// @@ -673,7 +662,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("InvalidOperationHistogramNotEnoughPoints", resourceCulture); } } - + /// /// Looks up a localized string similar to No Samples Provided. Preparation Required.. /// @@ -682,7 +671,25 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("InvalidOperationNoSamplesProvided", resourceCulture); } } - + + /// + /// Looks up a localized string similar to An invalid parameter was passed to a native method.. + /// + public static string InvalidParameter { + get { + return ResourceManager.GetString("InvalidParameter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An invalid parameter was passed to a native method, parameter number : {0}. + /// + public static string InvalidParameterWithNumber { + get { + return ResourceManager.GetString("InvalidParameterWithNumber", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid Right Boundary Condition.. /// @@ -691,7 +698,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("InvalidRightBoundaryCondition", resourceCulture); } } - + /// /// Looks up a localized string similar to Lag must be positive. /// @@ -700,7 +707,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("LagMustBePositive", resourceCulture); } } - + /// /// Looks up a localized string similar to Lag must be smaller than the sample size. /// @@ -709,7 +716,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("LagMustBeSmallerThanTheSampleSize", resourceCulture); } } - + /// /// Looks up a localized string similar to ddd MMM dd HH:mm:ss yyyy. /// @@ -718,7 +725,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("MatlabDateHeaderFormat", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrices can not be empty and must have at least one row and column.. /// @@ -727,7 +734,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("MatrixCanNotBeEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to The number of columns of a matrix must be positive.. /// @@ -736,7 +743,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("MatrixColumnsMustBePositive", resourceCulture); } } - + /// /// Looks up a localized string similar to Matrix must be in sparse storage format. /// @@ -745,7 +752,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("MatrixMustBeSparse", resourceCulture); } } - + /// /// Looks up a localized string similar to The number of rows of a matrix must be positive.. /// @@ -754,7 +761,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("MatrixRowsMustBePositive", resourceCulture); } } - + /// /// Looks up a localized string similar to The number of rows or columns of a matrix must be positive.. /// @@ -763,7 +770,16 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("MatrixRowsOrColumnsMustBePositive", resourceCulture); } } - + + /// + /// Looks up a localized string similar to Unable to allocate native memory.. + /// + public static string MemoryAllocation { + get { + return ResourceManager.GetString("MemoryAllocation", resourceCulture); + } + } + /// /// Looks up a localized string similar to Only 1 and 2 dimensional arrays are supported.. /// @@ -772,7 +788,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("MoreThan2D", resourceCulture); } } - + /// /// Looks up a localized string similar to Data must contain at least {0} values.. /// @@ -781,7 +797,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("MustContainAtLeast", resourceCulture); } } - + /// /// Looks up a localized string similar to Name cannot contain a space. name: {0}. /// @@ -790,7 +806,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("NameCannotContainASpace", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} is not a supported type.. /// @@ -799,7 +815,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("NotSupportedType", resourceCulture); } } - + /// /// Looks up a localized string similar to Algorithm experience a numerical break down ///. @@ -809,7 +825,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("NumericalBreakdown", resourceCulture); } } - + /// /// Looks up a localized string similar to The two arguments can't be compared (maybe they are part of a partial ordering?). /// @@ -818,7 +834,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("PartialOrderException", resourceCulture); } } - + /// /// Looks up a localized string similar to The integer array does not represent a valid permutation.. /// @@ -827,7 +843,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("PermutationAsIntArrayInvalid", resourceCulture); } } - + /// /// Looks up a localized string similar to The sampler's proposal distribution is not upper bounding the target density.. /// @@ -836,7 +852,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("ProposalDistributionNoUpperBound", resourceCulture); } } - + /// /// Looks up a localized string similar to The algorithm has failed, exceeded the number of iterations allowed or there is no root within the provided bounds.. /// @@ -845,7 +861,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("RootFindingFailed", resourceCulture); } } - + /// /// Looks up a localized string similar to The algorithm has failed, exceeded the number of iterations allowed or there is no root within the provided bounds. Consider to use RobustNewtonRaphson instead.. /// @@ -854,7 +870,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("RootFindingFailedRecommendRobustNewtonRaphson", resourceCulture); } } - + /// /// Looks up a localized string similar to The lower and upper bounds must bracket a single root.. /// @@ -863,7 +879,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("RootMustBeBracketedByBounds", resourceCulture); } } - + /// /// Looks up a localized string similar to The algorithm ended without root in the range.. /// @@ -872,7 +888,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("RootNotFound", resourceCulture); } } - + /// /// Looks up a localized string similar to The number of rows must greater than or equal to the number of columns.. /// @@ -881,7 +897,25 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("RowsLessThanColumns", resourceCulture); } } - + + /// + /// Looks up a localized string similar to U is singular, and the inversion could not be completed.. + /// + public static string SingularUMatrix { + get { + return ResourceManager.GetString("SingularUMatrix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to U is singular, and the inversion could not be completed. The {0}-th diagonal element of the factor U is zero.. + /// + public static string SingularUMatrixWithElement { + get { + return ResourceManager.GetString("SingularUMatrixWithElement", resourceCulture); + } + } + /// /// Looks up a localized string similar to The singular vectors were not computed.. /// @@ -890,7 +924,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("SingularVectorsNotComputed", resourceCulture); } } - + /// /// Looks up a localized string similar to This special case is not supported yet (but is planned).. /// @@ -899,7 +933,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("SpecialCasePlannedButNotImplementedYet", resourceCulture); } } - + /// /// Looks up a localized string similar to The given stop criterion already exist in the collection.. /// @@ -908,7 +942,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("StopCriterionDuplicate", resourceCulture); } } - + /// /// Looks up a localized string similar to There is no stop criterion in the collection.. /// @@ -917,7 +951,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("StopCriterionMissing", resourceCulture); } } - + /// /// Looks up a localized string similar to String parameter cannot be empty or null.. /// @@ -926,7 +960,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("StringNullOrEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to We only support sparse matrix with less than int.MaxValue elements.. /// @@ -935,7 +969,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("TooManyElements", resourceCulture); } } - + /// /// Looks up a localized string similar to The moment of the distribution is undefined.. /// @@ -944,7 +978,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("UndefinedMoment", resourceCulture); } } - + /// /// Looks up a localized string similar to A user defined provider has not been specified.. /// @@ -953,7 +987,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("UserDefinedProviderNotSpecified", resourceCulture); } } - + /// /// Looks up a localized string similar to User work buffers are not supported by this provider.. /// @@ -962,7 +996,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("UserWorkBufferNotSupported", resourceCulture); } } - + /// /// Looks up a localized string similar to Vectors can not be empty and must have at least one element.. /// @@ -971,7 +1005,7 @@ namespace MathNet.Numerics.Properties { return ResourceManager.GetString("VectorCanNotBeEmpty", resourceCulture); } } - + /// /// Looks up a localized string similar to The given work array is too small. Check work[0] for the corret size.. /// diff --git a/src/Numerics/Properties/Resources.resx b/src/Numerics/Properties/Resources.resx index 6713e906..d87f9a72 100644 --- a/src/Numerics/Properties/Resources.resx +++ b/src/Numerics/Properties/Resources.resx @@ -421,4 +421,19 @@ User work buffers are not supported by this provider. + + An invalid parameter was passed to a native method. + + + An invalid parameter was passed to a native method, parameter number : {0} + + + Unable to allocate native memory. + + + U is singular, and the inversion could not be completed. + + + U is singular, and the inversion could not be completed. The {0}-th diagonal element of the factor U is zero. + \ No newline at end of file diff --git a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs index 126f6285..34e245da 100644 --- a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs +++ b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs @@ -76,8 +76,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, rows * columns), "matrix"); } - var work = new double[rows]; - return SafeNativeMethods.z_matrix_norm((byte)norm, rows, columns, matrix, work); + return SafeNativeMethods.z_matrix_norm((byte)norm, rows, columns, matrix); } /// @@ -274,7 +273,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - SafeNativeMethods.z_lu_factor(order, data, ipiv); + var info = SafeNativeMethods.z_lu_factor(order, data, ipiv); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -296,77 +300,22 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - var work = new Complex[order]; - SafeNativeMethods.z_lu_inverse(order, a, work, work.Length); - } + var info = SafeNativeMethods.z_lu_inverse(order, a); - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(Complex[] a, int order, int[] ipiv) - { - if (a == null) + if (info == (int)MklError.MemoryAllocation) { - throw new ArgumentNullException("a"); + throw new MemoryAllocationException(); } - if (ipiv == null) + if (info < 0) { - throw new ArgumentNullException("ipiv"); + throw new InvalidParameterException(Math.Abs(info)); } - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - var work = new Complex[order]; - SafeNativeMethods.z_lu_inverse_factored(order, a, ipiv, work, order); - } - - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(Complex[] a, int order, Complex[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (work.Length < order) + if (info > 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new SingularUMatrixException(info); } - - SafeNativeMethods.z_lu_inverse(order, a, work, work.Length); } /// @@ -375,12 +324,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// The LU factored N by N matrix. Contains the inverse On exit. /// The order of the square matrix . /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is equivalent to the GETRI LAPACK routine. [SecuritySafeCritical] - public override void LUInverseFactored(Complex[] a, int order, int[] ipiv, Complex[] work) + public override void LUInverseFactored(Complex[] a, int order, int[] ipiv) { if (a == null) { @@ -402,17 +348,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } + var info = SafeNativeMethods.z_lu_inverse_factored(order, a, ipiv); - if (work.Length < order) + if (info < 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - SafeNativeMethods.z_lu_inverse_factored(order, a, ipiv, work, order); + if (info > 0) + { + throw new SingularUMatrixException(info); + } } /// @@ -446,7 +392,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.z_lu_solve(order, columnsOfB, a, b); + var info = SafeNativeMethods.z_lu_solve(order, columnsOfB, a, b); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -491,7 +447,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.z_lu_solve_factored(order, columnsOfB, a, ipiv, b); + var info = SafeNativeMethods.z_lu_solve_factored(order, columnsOfB, a, ipiv, b); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -521,6 +487,11 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl var info = SafeNativeMethods.z_cholesky_factor(order, a); + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + if (info > 0) { throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite); @@ -559,7 +530,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.z_cholesky_solve(orderA, columnsB, a, b); + var info = SafeNativeMethods.z_cholesky_solve(orderA, columnsB, a, b); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -593,51 +574,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.z_cholesky_solve_factored(orderA, columnsB, a, b); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void QRFactor(Complex[] r, int rowsR, int columnsR, Complex[] q, Complex[] tau) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); - } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } + var info = SafeNativeMethods.z_cholesky_solve_factored(orderA, columnsB, a, b); - if (q.Length != rowsR*rowsR) + if (info < 0) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); + throw new InvalidParameterException(Math.Abs(info)); } - - var work = new Complex[columnsR*Control.BlockSize]; - SafeNativeMethods.z_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -647,16 +589,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// it is overwritten with the R matrix of the QR factorization. /// The number of rows in the A matrix. /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// A min(m,n) vector. On exit, contains additional information /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is similar to the GEQRF and ORGQR LAPACK routines. [SecuritySafeCritical] - public override void QRFactor(Complex[] r, int rowsR, int columnsR, Complex[] q, Complex[] tau, Complex[] work) + public override void QRFactor(Complex[] r, int rowsR, int columnsR, Complex[] q, Complex[] tau) { if (r == null) { @@ -668,11 +607,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); @@ -688,13 +622,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - if (work.Length < columnsR*Control.BlockSize) + var info = SafeNativeMethods.z_qr_factor(rowsR, columnsR, r, tau, q); + + if (info < 0) { - work[0] = columnsR*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.z_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -737,66 +670,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - var work = new Complex[columnsA * Control.BlockSize]; - SafeNativeMethods.z_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); - } + var info = SafeNativeMethods.z_qr_thin_factor(rowsA, columnsA, q, tau, r); - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void ThinQRFactor(Complex[] q, int rowsA, int columnsA, Complex[] r, Complex[] tau, Complex[] work) - { - if (r == null) + if (info < 0) { - throw new ArgumentNullException("r"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (q.Length != rowsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA*columnsA) - { - throw new ArgumentException( - string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } - - if (work.Length < columnsA*Control.BlockSize) - { - work[0] = columnsA*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - - SafeNativeMethods.z_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); } /// @@ -812,27 +691,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// Rows must be greater or equal to columns. [SecuritySafeCritical] public override void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full) - { - var work = new Complex[columns*Control.BlockSize]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x, Complex[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -849,22 +707,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("x"); } - if (work == null) - { - 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"); } @@ -874,56 +727,40 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < 1) + var info = SafeNativeMethods.z_qr_solve(rows, columns, columnsB, a, b, x); + + if (info == (int)MklError.MemoryAllocation) { - work[0] = rows*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new MemoryAllocationException(); } - SafeNativeMethods.z_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length); - } + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolveFactored(Complex[] q, Complex[] r, int rowsR, int columnsR, Complex[] tau, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full) - { - var work = new Complex[columnsR*Control.BlockSize]; - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); + if (info > 0) + { + throw new ArgumentException(Resources.ArgumentMatrixNotRankDeficient, "a"); + } } /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. + /// The Q matrix obtained by calling . /// The R matrix obtained by calling . /// The number of rows in the A matrix. /// The number of columns in the A matrix. /// Contains additional information on Q. Only used for the native solver /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. + /// The B matrix. /// The number of columns of B. /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. [SecuritySafeCritical] - public override void QRSolveFactored(Complex[] q, Complex[] r, int rowsA, int columnsA, Complex[] tau, Complex[] b, int columnsB, Complex[] x, Complex[] work, QRMethod method = QRMethod.Full) + public override void QRSolveFactored(Complex[] q, Complex[] r, int rowsA, int columnsA, Complex[] tau, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full) { if (r == null) { @@ -945,11 +782,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - int rowsQ, columnsQ, rowsR, columnsR; if (method == QRMethod.Full) { @@ -962,35 +794,39 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl columnsQ = rowsR = columnsR = columnsA; } - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR*columnsR), "r"); - } - - if (q.Length != rowsQ*columnsQ) + if (r.Length != rowsR * columnsR) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ*columnsQ), "q"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r"); } - if (b.Length != rowsA*columnsB) + if (q.Length != rowsQ * columnsQ) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA*columnsB), "b"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q"); } - if (x.Length != columnsA*columnsB) + if (b.Length != rowsA * columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA*columnsB), "x"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b"); } - if (work.Length < 1) + if (x.Length != columnsA * columnsB) { - work[0] = rowsA*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); } if (method == QRMethod.Full) { - SafeNativeMethods.z_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length); + var info = SafeNativeMethods.z_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } else { @@ -1000,61 +836,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl } } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - var work = new Complex[(2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -1091,14 +872,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - var work = new Complex[(2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; var s = new Complex[Math.Min(rowsA, 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); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -1114,12 +894,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// The work array. For real matrices, the work array should be at least - /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). - /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) + public override void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt) { if (a == null) { @@ -1141,11 +918,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("vt"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); @@ -1161,18 +933,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - if (work.Length == 0) + var info = SafeNativeMethods.z_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt); + + if (info == (int) MklError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); + throw new MemoryAllocationException(); } - if (work.Length < (2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)) + if (info < 0) { - work[0] = (2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA); - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (SafeNativeMethods.z_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt, work, work.Length) > 0) + if (info > 0) { throw new NonConvergenceException(); } @@ -1369,7 +1142,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); } - if (SafeNativeMethods.z_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD) > 0) + var info = SafeNativeMethods.z_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + + if (info > 0) { throw new NonConvergenceException(); } diff --git a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs index 715522f6..180b7f3b 100644 --- a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs +++ b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs @@ -76,8 +76,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, rows * columns), "matrix"); } - var work = new float[rows]; - return SafeNativeMethods.c_matrix_norm((byte)norm, rows, columns, matrix, work); + return SafeNativeMethods.c_matrix_norm((byte)norm, rows, columns, matrix); } /// @@ -274,7 +273,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - SafeNativeMethods.c_lu_factor(order, data, ipiv); + var info = SafeNativeMethods.c_lu_factor(order, data, ipiv); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -296,77 +300,22 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - var work = new Complex32[order]; - SafeNativeMethods.c_lu_inverse(order, a, work, work.Length); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(Complex32[] a, int order, int[] ipiv) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } + var info = SafeNativeMethods.c_lu_inverse(order, a); - if (a.Length != order*order) + if (info == (int)MklError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + throw new MemoryAllocationException(); } - if (ipiv.Length != order) + if (info < 0) { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); + throw new InvalidParameterException(Math.Abs(info)); } - var work = new Complex32[order]; - SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv, work, order); - } - - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(Complex32[] a, int order, Complex32[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (work.Length < order) + if (info > 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new SingularUMatrixException(info); } - - SafeNativeMethods.c_lu_inverse(order, a, work, work.Length); } /// @@ -375,12 +324,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// The LU factored N by N matrix. Contains the inverse On exit. /// The order of the square matrix . /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is equivalent to the GETRI LAPACK routine. [SecuritySafeCritical] - public override void LUInverseFactored(Complex32[] a, int order, int[] ipiv, Complex32[] work) + public override void LUInverseFactored(Complex32[] a, int order, int[] ipiv) { if (a == null) { @@ -402,17 +348,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } + var info = SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv); - if (work.Length < order) + if (info < 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv, work, order); + if (info > 0) + { + throw new SingularUMatrixException(info); + } } /// @@ -446,7 +392,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_lu_solve(order, columnsOfB, a, b); + var info = SafeNativeMethods.c_lu_solve(order, columnsOfB, a, b); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -491,7 +447,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_lu_solve_factored(order, columnsOfB, a, ipiv, b); + var info = SafeNativeMethods.c_lu_solve_factored(order, columnsOfB, a, ipiv, b); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -521,6 +482,11 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl var info = SafeNativeMethods.c_cholesky_factor(order, a); + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + if (info > 0) { throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite); @@ -559,7 +525,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_cholesky_solve(orderA, columnsB, a, b); + var info = SafeNativeMethods.c_cholesky_solve(orderA, columnsB, a, b); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -593,51 +569,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_cholesky_solve_factored(orderA, columnsB, a, b); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void QRFactor(Complex32[] r, int rowsR, int columnsR, Complex32[] q, Complex32[] tau) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } + var info = SafeNativeMethods.c_cholesky_solve_factored(orderA, columnsB, a, b); - if (r.Length != rowsR*columnsR) + if (info < 0) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (q.Length != rowsR*rowsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); - } - - var work = new Complex32[columnsR*Control.BlockSize]; - SafeNativeMethods.c_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -647,16 +584,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// it is overwritten with the R matrix of the QR factorization. /// The number of rows in the A matrix. /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// A min(m,n) vector. On exit, contains additional information /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is similar to the GEQRF and ORGQR LAPACK routines. [SecuritySafeCritical] - public override void QRFactor(Complex32[] r, int rowsR, int columnsR, Complex32[] q, Complex32[] tau, Complex32[] work) + public override void QRFactor(Complex32[] r, int rowsR, int columnsR, Complex32[] q, Complex32[] tau) { if (r == null) { @@ -668,11 +602,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); @@ -688,13 +617,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - if (work.Length < columnsR*Control.BlockSize) + var info = SafeNativeMethods.c_qr_factor(rowsR, columnsR, r, tau, q); + + if (info < 0) { - work[0] = columnsR*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.c_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -737,66 +665,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - var work = new Complex32[columnsA * Control.BlockSize]; - SafeNativeMethods.c_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); - } - - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void ThinQRFactor(Complex32[] q, int rowsA, int columnsA, Complex32[] r, Complex32[] tau, Complex32[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (q.Length != rowsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA*columnsA) - { - throw new ArgumentException( - string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } + var info = SafeNativeMethods.c_qr_thin_factor(rowsA, columnsA, q, tau, r); - if (work.Length < columnsA*Control.BlockSize) + if (info < 0) { - work[0] = columnsA*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.c_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); } /// @@ -812,27 +686,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// Rows must be greater or equal to columns. [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]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x, Complex32[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -849,22 +702,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("x"); } - if (work == null) - { - 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"); } @@ -874,56 +722,40 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < 1) + var info = SafeNativeMethods.c_qr_solve(rows, columns, columnsB, a, b, x); + + if (info == (int)MklError.MemoryAllocation) { - work[0] = rows*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new MemoryAllocationException(); } - SafeNativeMethods.c_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length); - } + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [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]; - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); + if (info > 0) + { + throw new ArgumentException(Resources.ArgumentMatrixNotRankDeficient, "a"); + } } /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. + /// The Q matrix obtained by calling . /// The R matrix obtained by calling . /// The number of rows in the A matrix. /// The number of columns in the A matrix. /// Contains additional information on Q. Only used for the native solver /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. + /// The B matrix. /// The number of columns of B. /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. [SecuritySafeCritical] - public override void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsA, int columnsA, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x, Complex32[] work, QRMethod method = QRMethod.Full) + public override void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsA, int columnsA, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full) { if (r == null) { @@ -945,11 +777,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - int rowsQ, columnsQ, rowsR, columnsR; if (method == QRMethod.Full) { @@ -962,35 +789,39 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl columnsQ = rowsR = columnsR = columnsA; } - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR*columnsR), "r"); - } - - if (q.Length != rowsQ*columnsQ) + if (r.Length != rowsR * columnsR) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ*columnsQ), "q"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r"); } - if (b.Length != rowsA*columnsB) + if (q.Length != rowsQ * columnsQ) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA*columnsB), "b"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q"); } - if (x.Length != columnsA*columnsB) + if (b.Length != rowsA * columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA*columnsB), "x"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b"); } - if (work.Length < 1) + if (x.Length != columnsA * columnsB) { - work[0] = rowsA*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); } if (method == QRMethod.Full) { - SafeNativeMethods.c_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length); + var info = SafeNativeMethods.c_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } else { @@ -1000,61 +831,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl } } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - var work = new Complex32[(2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -1091,14 +867,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - 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 clone = new Complex32[a.Length]; a.Copy(clone); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -1114,12 +889,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// The work array. For real matrices, the work array should be at least - /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). - /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) + public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt) { if (a == null) { @@ -1141,17 +913,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("vt"); } - if (work == null) - { - 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"); } @@ -1161,18 +928,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - if (work.Length == 0) + var info = SafeNativeMethods.c_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt); + + if (info == (int)MklError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); + throw new MemoryAllocationException(); } - if (work.Length < (2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)) + if (info < 0) { - work[0] = (2*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA); - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (SafeNativeMethods.c_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt, work, work.Length) > 0) + if (info > 0) { throw new NonConvergenceException(); } @@ -1366,10 +1134,22 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl if (matrixD.Length != order * order) { - throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); } - if (SafeNativeMethods.c_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD) > 0) + var info = SafeNativeMethods.c_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + + if (info > 0) { throw new NonConvergenceException(); } diff --git a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Double.cs b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Double.cs index 8054efc4..b4cd6b74 100644 --- a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Double.cs +++ b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Double.cs @@ -76,8 +76,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, rows * columns), "matrix"); } - var work = new double[rows]; - return SafeNativeMethods.d_matrix_norm((byte)norm, rows, columns, matrix, work); + return SafeNativeMethods.d_matrix_norm((byte)norm, rows, columns, matrix); } /// @@ -274,7 +273,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - SafeNativeMethods.d_lu_factor(order, data, ipiv); + var info = SafeNativeMethods.d_lu_factor(order, data, ipiv); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -296,77 +300,22 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - var work = new double[order]; - SafeNativeMethods.d_lu_inverse(order, a, work, work.Length); - } + var info = SafeNativeMethods.d_lu_inverse(order, a); - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(double[] a, int order, int[] ipiv) - { - if (a == null) + if (info == (int)MklError.MemoryAllocation) { - throw new ArgumentNullException("a"); + throw new MemoryAllocationException(); } - if (ipiv == null) + if (info < 0) { - throw new ArgumentNullException("ipiv"); + throw new InvalidParameterException(Math.Abs(info)); } - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - var work = new double[order]; - SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv, work, order); - } - - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(double[] a, int order, double[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (work.Length < order) + if (info > 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new SingularUMatrixException(info); } - - SafeNativeMethods.d_lu_inverse(order, a, work, work.Length); } /// @@ -375,12 +324,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// The LU factored N by N matrix. Contains the inverse On exit. /// The order of the square matrix . /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is equivalent to the GETRI LAPACK routine. [SecuritySafeCritical] - public override void LUInverseFactored(double[] a, int order, int[] ipiv, double[] work) + public override void LUInverseFactored(double[] a, int order, int[] ipiv) { if (a == null) { @@ -402,17 +348,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } + var info = SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv); - if (work.Length < order) + if (info < 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv, work, order); + if (info > 0) + { + throw new SingularUMatrixException(info); + } } /// @@ -446,7 +392,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_lu_solve(order, columnsOfB, a, b); + var info = SafeNativeMethods.d_lu_solve(order, columnsOfB, a, b); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -491,7 +447,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_lu_solve_factored(order, columnsOfB, a, ipiv, b); + var info = SafeNativeMethods.d_lu_solve_factored(order, columnsOfB, a, ipiv, b); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -521,6 +482,16 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl var info = SafeNativeMethods.d_cholesky_factor(order, a); + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + if (info > 0) { throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite); @@ -559,7 +530,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_cholesky_solve(orderA, columnsB, a, b); + var info = SafeNativeMethods.d_cholesky_solve(orderA, columnsB, a, b); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -593,51 +574,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_cholesky_solve_factored(orderA, columnsB, a, b); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void QRFactor(double[] r, int rowsR, int columnsR, double[] q, double[] tau) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); - } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } + var info = SafeNativeMethods.d_cholesky_solve_factored(orderA, columnsB, a, b); - if (q.Length != rowsR*rowsR) + if (info < 0) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); + throw new InvalidParameterException(Math.Abs(info)); } - - var work = new double[columnsR*Control.BlockSize]; - SafeNativeMethods.d_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -647,16 +589,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// it is overwritten with the R matrix of the QR factorization. /// The number of rows in the A matrix. /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// A min(m,n) vector. On exit, contains additional information /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is similar to the GEQRF and ORGQR LAPACK routines. [SecuritySafeCritical] - public override void QRFactor(double[] r, int rowsR, int columnsR, double[] q, double[] tau, double[] work) + public override void QRFactor(double[] r, int rowsR, int columnsR, double[] q, double[] tau) { if (r == null) { @@ -668,11 +607,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); @@ -688,13 +622,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - if (work.Length < columnsR*Control.BlockSize) + var info = SafeNativeMethods.d_qr_factor(rowsR, columnsR, r, tau, q); + + if (info < 0) { - work[0] = columnsR*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.d_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -737,66 +670,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - var work = new double[columnsA*Control.BlockSize]; - SafeNativeMethods.d_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); - } + var info = SafeNativeMethods.d_qr_thin_factor(rowsA, columnsA, q, tau, r); - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void ThinQRFactor(double[] q, int rowsA, int columnsA, double[] r, double[] tau, double[] work) - { - if (r == null) + if (info < 0) { - throw new ArgumentNullException("r"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (q.Length != rowsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA*columnsA) - { - throw new ArgumentException( - string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } - - if (work.Length < columnsA*Control.BlockSize) - { - work[0] = columnsA*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - - SafeNativeMethods.d_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); } /// @@ -812,27 +691,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// Rows must be greater or equal to columns. [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]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolve(double[] a, int rows, int columns, double[] b, int columnsB, double[] x, double[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -849,22 +707,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("x"); } - if (work == null) - { - 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"); } @@ -874,56 +727,40 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < 1) + var info = SafeNativeMethods.d_qr_solve(rows, columns, columnsB, a, b, x); + + if (info == (int)MklError.MemoryAllocation) { - work[0] = rows*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new MemoryAllocationException(); } - SafeNativeMethods.d_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length); - } + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [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]; - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); + if (info > 0) + { + throw new ArgumentException(Resources.ArgumentMatrixNotRankDeficient, "a"); + } } /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. + /// The Q matrix obtained by calling . /// The R matrix obtained by calling . /// The number of rows in the A matrix. /// The number of columns in the A matrix. /// Contains additional information on Q. Only used for the native solver /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. + /// The B matrix. /// The number of columns of B. /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. [SecuritySafeCritical] - public override void QRSolveFactored(double[] q, double[] r, int rowsA, int columnsA, double[] tau, double[] b, int columnsB, double[] x, double[] work, QRMethod method = QRMethod.Full) + public override void QRSolveFactored(double[] q, double[] r, int rowsA, int columnsA, double[] tau, double[] b, int columnsB, double[] x, QRMethod method = QRMethod.Full) { if (r == null) { @@ -945,11 +782,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - int rowsQ, columnsQ, rowsR, columnsR; if (method == QRMethod.Full) { @@ -962,35 +794,39 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl columnsQ = rowsR = columnsR = columnsA; } - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR*columnsR), "r"); - } - - if (q.Length != rowsQ*columnsQ) + if (r.Length != rowsR * columnsR) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ*columnsQ), "q"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r"); } - if (b.Length != rowsA*columnsB) + if (q.Length != rowsQ * columnsQ) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA*columnsB), "b"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q"); } - if (x.Length != columnsA*columnsB) + if (b.Length != rowsA * columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA*columnsB), "x"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b"); } - if (work.Length < 1) + if (x.Length != columnsA * columnsB) { - work[0] = rowsA*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); } if (method == QRMethod.Full) { - SafeNativeMethods.d_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length); + var info = SafeNativeMethods.d_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } else { @@ -1000,61 +836,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl } } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - 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))]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -1091,14 +872,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl 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 s = new double[Math.Min(rowsA, columnsA)]; var u = new double[rowsA*rowsA]; var vt = new double[columnsA*columnsA]; var clone = new double[a.Length]; a.Copy(clone); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -1114,12 +894,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// The work array. For real matrices, the work array should be at least - /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). - /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt, double[] work) + public override void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt) { if (a == null) { @@ -1141,17 +918,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("vt"); } - if (work == null) - { - 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"); } @@ -1161,18 +933,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - if (work.Length == 0) + var info = SafeNativeMethods.d_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt); + + if (info == (int)MklError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); + throw new MemoryAllocationException(); } - if (work.Length < Math.Max((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5*Math.Min(rowsA, columnsA))) + if (info < 0) { - work[0] = Math.Max((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5*Math.Min(rowsA, columnsA)); - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (SafeNativeMethods.d_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt, work, work.Length) > 0) + if (info > 0) { throw new NonConvergenceException(); } @@ -1369,7 +1142,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixD"); } - if (SafeNativeMethods.d_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD) > 0) + var info = SafeNativeMethods.d_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + + if (info > 0) { throw new NonConvergenceException(); } diff --git a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Single.cs b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Single.cs index 46222bfa..18ba703c 100644 --- a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Single.cs +++ b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Single.cs @@ -76,8 +76,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArrayTooSmall, rows * columns), "matrix"); } - var work = new float[rows]; - return SafeNativeMethods.s_matrix_norm((byte)norm, rows, columns, matrix, work); + return SafeNativeMethods.s_matrix_norm((byte)norm, rows, columns, matrix); } /// @@ -274,7 +273,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - SafeNativeMethods.s_lu_factor(order, data, ipiv); + var info = SafeNativeMethods.s_lu_factor(order, data, ipiv); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -296,77 +300,22 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - var work = new float[order]; - SafeNativeMethods.s_lu_inverse(order, a, work, work.Length); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(float[] a, int order, int[] ipiv) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - var work = new float[order]; - SafeNativeMethods.s_lu_inverse_factored(order, a, ipiv, work, order); - } - - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(float[] a, int order, float[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } + var info = SafeNativeMethods.s_lu_inverse(order, a); - if (a.Length != order*order) + if (info == (int)MklError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + throw new MemoryAllocationException(); } - if (work == null) + if (info < 0) { - throw new ArgumentNullException("work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (work.Length < order) + if (info > 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new SingularUMatrixException(info); } - - SafeNativeMethods.s_lu_inverse(order, a, work, work.Length); } /// @@ -375,12 +324,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// The LU factored N by N matrix. Contains the inverse On exit. /// The order of the square matrix . /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is equivalent to the GETRI LAPACK routine. [SecuritySafeCritical] - public override void LUInverseFactored(float[] a, int order, int[] ipiv, float[] work) + public override void LUInverseFactored(float[] a, int order, int[] ipiv) { if (a == null) { @@ -402,17 +348,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } + var info = SafeNativeMethods.s_lu_inverse_factored(order, a, ipiv); - if (work.Length < order) + if (info < 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - SafeNativeMethods.s_lu_inverse_factored(order, a, ipiv, work, order); + if (info > 0) + { + throw new SingularUMatrixException(info); + } } /// @@ -446,7 +392,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_lu_solve(order, columnsOfB, a, b); + var info = SafeNativeMethods.s_lu_solve(order, columnsOfB, a, b); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -491,7 +447,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_lu_solve_factored(order, columnsOfB, a, ipiv, b); + var info = SafeNativeMethods.s_lu_solve_factored(order, columnsOfB, a, ipiv, b); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -521,6 +482,11 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl var info = SafeNativeMethods.s_cholesky_factor(order, a); + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + if (info > 0) { throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite); @@ -559,7 +525,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_cholesky_solve(orderA, columnsB, a, b); + var info = SafeNativeMethods.s_cholesky_solve(orderA, columnsB, a, b); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -593,51 +569,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_cholesky_solve_factored(orderA, columnsB, a, b); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void QRFactor(float[] r, int rowsR, int columnsR, float[] q, float[] tau) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } + var info = SafeNativeMethods.s_cholesky_solve_factored(orderA, columnsB, a, b); - if (r.Length != rowsR*columnsR) + if (info < 0) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (q.Length != rowsR*rowsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); - } - - var work = new float[columnsR*Control.BlockSize]; - SafeNativeMethods.s_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -647,16 +584,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// it is overwritten with the R matrix of the QR factorization. /// The number of rows in the A matrix. /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// A min(m,n) vector. On exit, contains additional information /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is similar to the GEQRF and ORGQR LAPACK routines. [SecuritySafeCritical] - public override void QRFactor(float[] r, int rowsR, int columnsR, float[] q, float[] tau, float[] work) + public override void QRFactor(float[] r, int rowsR, int columnsR, float[] q, float[] tau) { if (r == null) { @@ -668,11 +602,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); @@ -688,13 +617,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - if (work.Length < columnsR*Control.BlockSize) + var info = SafeNativeMethods.s_qr_factor(rowsR, columnsR, r, tau, q); + + if (info < 0) { - work[0] = columnsR*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.s_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -737,66 +665,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - var work = new float[columnsA * Control.BlockSize]; - SafeNativeMethods.s_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); - } + var info = SafeNativeMethods.s_qr_thin_factor(rowsA, columnsA, q, tau, r); - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void ThinQRFactor(float[] q, int rowsA, int columnsA, float[] r, float[] tau, float[] work) - { - if (r == null) + if (info < 0) { - throw new ArgumentNullException("r"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (q.Length != rowsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA*columnsA) - { - throw new ArgumentException( - string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } - - if (work.Length < columnsA*Control.BlockSize) - { - work[0] = columnsA*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - - SafeNativeMethods.s_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); } /// @@ -812,27 +686,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// Rows must be greater or equal to columns. [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]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, float[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -849,22 +702,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("x"); } - if (work == null) - { - 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"); } @@ -874,56 +722,40 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < 1) + var info = SafeNativeMethods.s_qr_solve(rows, columns, columnsB, a, b, x); + + if (info == (int)MklError.MemoryAllocation) { - work[0] = rows*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new MemoryAllocationException(); } - SafeNativeMethods.s_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length); - } + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [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]; - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); + if (info > 0) + { + throw new ArgumentException(Resources.ArgumentMatrixNotRankDeficient, "a"); + } } /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. + /// The Q matrix obtained by calling . /// The R matrix obtained by calling . /// The number of rows in the A matrix. /// The number of columns in the A matrix. /// Contains additional information on Q. Only used for the native solver /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. + /// The B matrix. /// The number of columns of B. /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. [SecuritySafeCritical] - public override void QRSolveFactored(float[] q, float[] r, int rowsA, int columnsA, float[] tau, float[] b, int columnsB, float[] x, float[] work, QRMethod method = QRMethod.Full) + public override void QRSolveFactored(float[] q, float[] r, int rowsA, int columnsA, float[] tau, float[] b, int columnsB, float[] x, QRMethod method = QRMethod.Full) { if (r == null) { @@ -945,11 +777,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - int rowsQ, columnsQ, rowsR, columnsR; if (method == QRMethod.Full) { @@ -962,35 +789,39 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl columnsQ = rowsR = columnsR = columnsA; } - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR*columnsR), "r"); - } - - if (q.Length != rowsQ*columnsQ) + if (r.Length != rowsR * columnsR) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ*columnsQ), "q"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r"); } - if (b.Length != rowsA*columnsB) + if (q.Length != rowsQ * columnsQ) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA*columnsB), "b"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q"); } - if (x.Length != columnsA*columnsB) + if (b.Length != rowsA * columnsB) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA*columnsB), "x"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b"); } - if (work.Length < 1) + if (x.Length != columnsA * columnsB) { - work[0] = rowsA*Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); } if (method == QRMethod.Full) { - SafeNativeMethods.s_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length); + var info = SafeNativeMethods.s_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } else { @@ -1000,61 +831,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl } } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - 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))]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -1091,14 +867,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl 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 s = new float[Math.Min(rowsA, columnsA)]; var u = new float[rowsA*rowsA]; var vt = new float[columnsA*columnsA]; var clone = new float[a.Length]; a.Copy(clone); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -1114,12 +889,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// The work array. For real matrices, the work array should be at least - /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). - /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt, float[] work) + public override void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt) { if (a == null) { @@ -1141,11 +913,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentNullException("vt"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); @@ -1161,18 +928,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - if (work.Length == 0) + var info = SafeNativeMethods.s_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt); + + if (info == (int)MklError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); + throw new MemoryAllocationException(); } - if (work.Length < Math.Max(((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5*Math.Min(rowsA, columnsA))) + if (info < 0) { - work[0] = Math.Max(((3*Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5*Math.Min(rowsA, columnsA)); - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (SafeNativeMethods.s_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt, work, work.Length) > 0) + if (info > 0) { throw new NonConvergenceException(); } @@ -1369,7 +1137,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixD"); } - if (SafeNativeMethods.s_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD) > 0) + var info = SafeNativeMethods.s_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + + if (info == (int)MklError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + + if (info > 0) { throw new NonConvergenceException(); } diff --git a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs index 780d3fa8..5aa12c7a 100644 --- a/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs @@ -34,6 +34,17 @@ using System; namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl { + /// + /// Error codes return from the MKL provider. + /// + public enum MklError : int + { + /// + /// Unable to allocate memory. + /// + MemoryAllocation = -999999 + } + /// /// Consistency vs. performance trade-off between runs on different machines. /// diff --git a/src/Numerics/Providers/LinearAlgebra/Mkl/SafeNativeMethods.cs b/src/Numerics/Providers/LinearAlgebra/Mkl/SafeNativeMethods.cs index 1bd150f9..6fc00840 100644 --- a/src/Numerics/Providers/LinearAlgebra/Mkl/SafeNativeMethods.cs +++ b/src/Numerics/Providers/LinearAlgebra/Mkl/SafeNativeMethods.cs @@ -134,16 +134,16 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl #region LAPACK [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern float s_matrix_norm(byte norm, int rows, int columns, [In] float[] a, [In, Out] float[] work); + internal static extern float s_matrix_norm(byte norm, int rows, int columns, [In] float[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern double d_matrix_norm(byte norm, int rows, int columns, [In] double[] a, [In, Out] double[] work); + internal static extern double d_matrix_norm(byte norm, int rows, int columns, [In] double[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern float c_matrix_norm(byte norm, int rows, int columns, [In] Complex32[] a, [In, Out] float[] work); + internal static extern float c_matrix_norm(byte norm, int rows, int columns, [In] Complex32[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern double z_matrix_norm(byte norm, int rows, int columns, [In] Complex[] a, [In, Out] double[] work); + internal static extern double z_matrix_norm(byte norm, int rows, int columns, [In] Complex[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] internal static extern int s_cholesky_factor(int n, [In, Out] float[] a); @@ -170,28 +170,28 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl internal static extern int z_lu_factor(int n, [In, Out] Complex[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_lu_inverse(int n, [In, Out] float[] a, [In, Out] float[] work, int lwork); + internal static extern int s_lu_inverse(int n, [In, Out] float[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_lu_inverse(int n, [In, Out] double[] a, [In, Out] double[] work, int lwork); + internal static extern int d_lu_inverse(int n, [In, Out] double[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_lu_inverse(int n, [In, Out] Complex32[] a, [In, Out] Complex32[] work, int lwork); + internal static extern int c_lu_inverse(int n, [In, Out] Complex32[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_lu_inverse(int n, [In, Out] Complex[] a, [In, Out] Complex[] work, int lwork); + internal static extern int z_lu_inverse(int n, [In, Out] Complex[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_lu_inverse_factored(int n, [In, Out] float[] a, [In, Out] int[] ipiv, [In, Out] float[] work, int lwork); + internal static extern int s_lu_inverse_factored(int n, [In, Out] float[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_lu_inverse_factored(int n, [In, Out] double[] a, [In, Out] int[] ipiv, [In, Out] double[] work, int lwork); + internal static extern int d_lu_inverse_factored(int n, [In, Out] double[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_lu_inverse_factored(int n, [In, Out] Complex32[] a, [In, Out] int[] ipiv, [In, Out] Complex32[] work, int lwork); + internal static extern int c_lu_inverse_factored(int n, [In, Out] Complex32[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_lu_inverse_factored(int n, [In, Out] Complex[] a, [In, Out] int[] ipiv, [In, Out] Complex[] work, int lwork); + internal static extern int z_lu_inverse_factored(int n, [In, Out] Complex[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] internal static extern int s_lu_solve_factored(int n, int nrhs, float[] a, [In, Out] int[] ipiv, [In, Out] float[] b); @@ -242,64 +242,64 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl internal static extern int z_cholesky_solve_factored(int n, int nrhs, Complex[] a, [In, Out] Complex[] b); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_qr_factor(int m, int n, [In, Out] float[] r, [In, Out] float[] tau, [In, Out] float[] q, [In, Out] float[] work, int len); + internal static extern int s_qr_factor(int m, int n, [In, Out] float[] r, [In, Out] float[] tau, [In, Out] float[] q); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_qr_factor(int m, int n, [In, Out] double[] r, [In, Out] double[] tau, [In, Out] double[] q, [In, Out] double[] work, int len); + internal static extern int d_qr_factor(int m, int n, [In, Out] double[] r, [In, Out] double[] tau, [In, Out] double[] q); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_qr_factor(int m, int n, [In, Out] Complex32[] r, [In, Out] Complex32[] tau, [In, Out] Complex32[] q, [In, Out] Complex32[] work, int len); + internal static extern int c_qr_factor(int m, int n, [In, Out] Complex32[] r, [In, Out] Complex32[] tau, [In, Out] Complex32[] q); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_qr_factor(int m, int n, [In, Out] Complex[] r, [In, Out] Complex[] tau, [In, Out] Complex[] q, [In, Out] Complex[] work, int len); + internal static extern int z_qr_factor(int m, int n, [In, Out] Complex[] r, [In, Out] Complex[] tau, [In, Out] Complex[] q); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_qr_thin_factor(int m, int n, [In, Out] float[] q, [In, Out] float[] tau, [In, Out] float[] r, [In, Out] float[] work, int len); + internal static extern int s_qr_thin_factor(int m, int n, [In, Out] float[] q, [In, Out] float[] tau, [In, Out] float[] r); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_qr_thin_factor(int m, int n, [In, Out] double[] q, [In, Out] double[] tau, [In, Out] double[] r, [In, Out] double[] work, int len); + internal static extern int d_qr_thin_factor(int m, int n, [In, Out] double[] q, [In, Out] double[] tau, [In, Out] double[] r); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_qr_thin_factor(int m, int n, [In, Out] Complex32[] q, [In, Out] Complex32[] tau, [In, Out] Complex32[] r, [In, Out] Complex32[] work, int len); + internal static extern int c_qr_thin_factor(int m, int n, [In, Out] Complex32[] q, [In, Out] Complex32[] tau, [In, Out] Complex32[] r); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_qr_thin_factor(int m, int n, [In, Out] Complex[] q, [In, Out] Complex[] tau, [In, Out] Complex[] r, [In, Out] Complex[] work, int len); + internal static extern int z_qr_thin_factor(int m, int n, [In, Out] Complex[] q, [In, Out] Complex[] tau, [In, Out] Complex[] r); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_qr_solve(int m, int n, int bn, float[] r, float[] b, [In, Out] float[] x, [In, Out] float[] work, int len); + internal static extern int s_qr_solve(int m, int n, int bn, float[] r, float[] b, [In, Out] float[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_qr_solve(int m, int n, int bn, double[] r, double[] b, [In, Out] double[] x, [In, Out] double[] work, int len); + internal static extern int d_qr_solve(int m, int n, int bn, double[] r, double[] b, [In, Out] double[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_qr_solve(int m, int n, int bn, Complex32[] r, Complex32[] b, [In, Out] Complex32[] x, [In, Out] Complex32[] work, int len); + internal static extern int c_qr_solve(int m, int n, int bn, Complex32[] r, Complex32[] b, [In, Out] Complex32[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_qr_solve(int m, int n, int bn, Complex[] r, Complex[] b, [In, Out] Complex[] x, [In, Out] Complex[] work, int len); + internal static extern int z_qr_solve(int m, int n, int bn, Complex[] r, Complex[] b, [In, Out] Complex[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_qr_solve_factored(int m, int n, int bn, float[] r, float[] b, float[] tau, [In, Out] float[] x, [In, Out] float[] work, int len); + internal static extern int s_qr_solve_factored(int m, int n, int bn, float[] r, float[] b, float[] tau, [In, Out] float[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_qr_solve_factored(int m, int n, int bn, double[] r, double[] b, double[] tau, [In, Out] double[] x, [In, Out] double[] work, int len); + internal static extern int d_qr_solve_factored(int m, int n, int bn, double[] r, double[] b, double[] tau, [In, Out] double[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_qr_solve_factored(int m, int n, int bn, Complex32[] r, Complex32[] b, Complex32[] tau, [In, Out] Complex32[] x, [In, Out] Complex32[] work, int len); + internal static extern int c_qr_solve_factored(int m, int n, int bn, Complex32[] r, Complex32[] b, Complex32[] tau, [In, Out] Complex32[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_qr_solve_factored(int m, int n, int bn, Complex[] r, Complex[] b, Complex[] tau, [In, Out] Complex[] x, [In, Out] Complex[] work, int len); + internal static extern int z_qr_solve_factored(int m, int n, int bn, Complex[] r, Complex[] b, Complex[] tau, [In, Out] Complex[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] float[] a, [In, Out] float[] s, [In, Out] float[] u, [In, Out] float[] v, [In, Out] float[] work, int len); + internal static extern int s_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] float[] a, [In, Out] float[] s, [In, Out] float[] u, [In, Out] float[] v); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] double[] a, [In, Out] double[] s, [In, Out] double[] u, [In, Out] double[] v, [In, Out] double[] work, int len); + internal static extern int d_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] double[] a, [In, Out] double[] s, [In, Out] double[] u, [In, Out] double[] v); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] Complex32[] a, [In, Out] Complex32[] s, [In, Out] Complex32[] u, [In, Out] Complex32[] v, [In, Out] Complex32[] work, int len); + internal static extern int c_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] Complex32[] a, [In, Out] Complex32[] s, [In, Out] Complex32[] u, [In, Out] Complex32[] v); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_svd_factor([MarshalAs(UnmanagedType.U1)] 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); + internal static extern int z_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] Complex[] a, [In, Out] Complex[] s, [In, Out] Complex[] u, [In, Out] Complex[] v); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] internal static extern int s_eigen([MarshalAs(UnmanagedType.U1)] bool isSymmetric, int n, [In] float[] a, [In, Out] float[] vectors, [In, Out] Complex[] values, [In, Out] float[] d); diff --git a/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs index d17a75cd..3998ae08 100644 --- a/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs +++ b/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs @@ -433,6 +433,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13); } +#if ! MKL /// /// Can compute the inverse of a matrix using LU factorization /// with a work array. @@ -461,7 +462,9 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727, 13); AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13); } +#endif +#if ! MKL /// /// Can compute the inverse of a matrix using LU factorization /// using a previously factored matrix with a work array. @@ -494,6 +497,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727, 13); AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13); } +#endif /// /// Can solve Ax=b using LU factorization. @@ -692,6 +696,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex } } +#if ! MKL /// /// Can compute QR factorization of a square matrix using a work array. /// @@ -775,6 +780,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex } } } +#endif /// /// Can compute thin QR factorization of a square matrix. @@ -830,6 +836,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex } } +#if ! MKL /// /// Can compute thin QR factorization of a square matrix using a work array. /// @@ -884,6 +891,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex } } } +#endif /// /// Can solve Ax=b using QR factorization with a square A matrix. @@ -936,6 +944,8 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } + +#if ! MKL /// /// Can solve Ax=b using QR factorization with a square A matrix /// using a work array. @@ -1021,7 +1031,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); } - +#endif /// /// Can solve Ax=b using QR factorization with a tall A matrix /// using a factored A matrix. @@ -1050,6 +1060,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } +#if ! MKL /// /// Can solve Ax=b using QR factorization with a square A matrix /// using a factored A matrix with a work array. @@ -1109,6 +1120,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } +#endif /// /// Can solve Ax=b using thin QR factorization with a square A matrix. @@ -1162,6 +1174,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } +#if ! MKL /// /// Can solve Ax=b using thin QR factorization with a square A matrix /// using a work array. @@ -1217,6 +1230,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } +#endif /// /// Can solve Ax=b using thin QR factorization with a square A matrix diff --git a/src/UnitTests/UnitTests-MKL.csproj b/src/UnitTests/UnitTests-MKL.csproj index df1bc55f..f0972c67 100644 --- a/src/UnitTests/UnitTests-MKL.csproj +++ b/src/UnitTests/UnitTests-MKL.csproj @@ -52,8 +52,324 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -348,4 +664,10 @@ + + + + + + \ No newline at end of file From c6720b630f267bb274f5621182ae1953a4244d08 Mon Sep 17 00:00:00 2001 From: Kuan Bartel Date: Wed, 15 Jul 2015 01:37:07 +0900 Subject: [PATCH 2/4] Updated OpenBLAS LA provider to remove work arrays to match the MKL LA provider changes. Changed MKLWrapper and OpenBLASWrapper projects to use shared blas.c and lapack.cpp files. Each project has individual blas.h and lapack.h header files. --- src/NativeProviders/Common/blas.c | 89 +++ .../{MKL => Common}/lapack.cpp | 116 ++- src/NativeProviders/Common/lapack_common.h | 25 + src/NativeProviders/MKL/blas.c | 89 --- src/NativeProviders/MKL/blas.h | 7 + src/NativeProviders/MKL/lapack.h | 27 +- src/NativeProviders/OpenBLAS/blas.c | 89 --- src/NativeProviders/OpenBLAS/blas.h | 7 + src/NativeProviders/OpenBLAS/complex.h | 39 - src/NativeProviders/OpenBLAS/lapack.cpp | 712 ------------------ src/NativeProviders/OpenBLAS/lapack.h | 9 + .../Windows/MKL/MKLWrapper.vcxproj | 7 +- .../Windows/MKL/MKLWrapper.vcxproj.filters | 21 +- .../Windows/OpenBLAS/OpenBLASWrapper.vcxproj | 8 +- .../OpenBLAS/OpenBLASWrapper.vcxproj.filters | 18 +- src/Numerics/Control.cs | 2 + .../OpenBlasLinearAlgebraProvider.Complex.cs | 493 ++++-------- ...OpenBlasLinearAlgebraProvider.Complex32.cs | 486 ++++-------- .../OpenBlasLinearAlgebraProvider.Double.cs | 505 ++++--------- .../OpenBlasLinearAlgebraProvider.Single.cs | 500 ++++-------- .../OpenBlas/OpenBlasLinearAlgebraProvider.cs | 11 + .../OpenBlas/SafeNativeMethods.cs | 100 +-- 22 files changed, 860 insertions(+), 2500 deletions(-) create mode 100644 src/NativeProviders/Common/blas.c rename src/NativeProviders/{MKL => Common}/lapack.cpp (80%) delete mode 100644 src/NativeProviders/MKL/blas.c create mode 100644 src/NativeProviders/MKL/blas.h delete mode 100644 src/NativeProviders/OpenBLAS/blas.c create mode 100644 src/NativeProviders/OpenBLAS/blas.h delete mode 100644 src/NativeProviders/OpenBLAS/complex.h delete mode 100644 src/NativeProviders/OpenBLAS/lapack.cpp create mode 100644 src/NativeProviders/OpenBLAS/lapack.h diff --git a/src/NativeProviders/Common/blas.c b/src/NativeProviders/Common/blas.c new file mode 100644 index 00000000..4cbcef1f --- /dev/null +++ b/src/NativeProviders/Common/blas.c @@ -0,0 +1,89 @@ +#include "wrapper_common.h" +#include "blas.h" + +#if __cplusplus +extern "C" { +#endif +DLLEXPORT void s_axpy(const blas_int n, const float alpha, const float x[], float y[]){ + cblas_saxpy(n, alpha, x, 1, y, 1); +} + +DLLEXPORT void d_axpy(const blas_int n, const double alpha, const double x[], double y[]){ + cblas_daxpy(n, alpha, x, 1, y, 1); +} + +DLLEXPORT void c_axpy(const blas_int n, const blas_complex_float alpha, const blas_complex_float x[], blas_complex_float y[]){ + cblas_caxpy(n, (float*)&alpha, (float*)x, 1, (float*)y, 1); +} + +DLLEXPORT void z_axpy(const blas_int n, const blas_complex_double alpha, const blas_complex_double x[], blas_complex_double y[]){ + cblas_zaxpy(n, (double*)&alpha, (double*)x, 1, (double*)y, 1); +} + +DLLEXPORT void s_scale(const blas_int n, const float alpha, float x[]){ + cblas_sscal(n, alpha, x, 1); +} + +DLLEXPORT void d_scale(const blas_int n, const double alpha, double x[]){ + cblas_dscal(n, alpha, x, 1); +} + +DLLEXPORT void c_scale(const blas_int n, const blas_complex_float alpha, blas_complex_float x[]){ + cblas_cscal(n, (float*)&alpha, (float*)x, 1); +} + +DLLEXPORT void z_scale(const blas_int n, const blas_complex_double alpha, blas_complex_double x[]){ + cblas_zscal(n, (double*)&alpha, (double*)x, 1); +} + +DLLEXPORT float s_dot_product(const blas_int n, const float x[], const float y[]){ + return cblas_sdot(n, x, 1, y, 1); +} + +DLLEXPORT double d_dot_product(const blas_int n, const double x[], const double y[]){ + return cblas_ddot(n, x, 1, y, 1); +} + +DLLEXPORT blas_complex_float c_dot_product(const blas_int n, const blas_complex_float x[], const blas_complex_float y[]){ + blas_complex_float ret; + cblas_cdotu_sub(n, (float*)x, 1, (float*)y, 1, &ret); + return ret; +} + +DLLEXPORT blas_complex_double z_dot_product(const blas_int n, const blas_complex_double x[], const blas_complex_double y[]){ + blas_complex_double ret; + cblas_zdotu_sub(n, (double*)x, 1, (double*)y, 1, &ret); + return ret; +} + +DLLEXPORT void s_matrix_multiply(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const blas_int m, const blas_int n, const blas_int k, const float alpha, const float x[], const float y[], const float beta, float c[]){ + blas_int lda = transA == CblasNoTrans ? m : k; + blas_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(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const blas_int m, const blas_int n, const blas_int k, const double alpha, const double x[], const double y[], const double beta, double c[]){ + blas_int lda = transA == CblasNoTrans ? m : k; + blas_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(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const blas_int m, const blas_int n, const blas_int k, const blas_complex_float alpha, const blas_complex_float x[], const blas_complex_float y[], const blas_complex_float beta, blas_complex_float c[]){ + blas_int lda = transA == CblasNoTrans ? m : k; + blas_int ldb = transB == CblasNoTrans ? k : n; + + cblas_cgemm(CblasColMajor, transA, transB, m, n, k, (float*)&alpha, (float*)x, lda, (float*)y, ldb, (float*)&beta, (float*)c, m); +} + +DLLEXPORT void z_matrix_multiply(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const blas_int m, const blas_int n, const blas_int k, const blas_complex_double alpha, const blas_complex_double x[], const blas_complex_double y[], const blas_complex_double beta, blas_complex_double c[]){ + blas_int lda = transA == CblasNoTrans ? m : k; + blas_int ldb = transB == CblasNoTrans ? k : n; + + cblas_zgemm(CblasColMajor, transA, transB, m, n, k, (double*)&alpha, (double*)x, lda, (double*)y, ldb, (double*)&beta, (double*)c, m); +} + +#if __cplusplus +} +#endif diff --git a/src/NativeProviders/MKL/lapack.cpp b/src/NativeProviders/Common/lapack.cpp similarity index 80% rename from src/NativeProviders/MKL/lapack.cpp rename to src/NativeProviders/Common/lapack.cpp index aa500dae..b0955923 100644 --- a/src/NativeProviders/MKL/lapack.cpp +++ b/src/NativeProviders/Common/lapack.cpp @@ -1,35 +1,8 @@ -#include -#include #include "wrapper_common.h" #include "lapack.h" #include "lapack_common.h" - -struct ptrfree -{ - void operator()(void* x) { PTRFREE(x); } -}; - -template using ptr = std::unique_ptr < T, ptrfree >; - -template -inline ptr array_new(const int size, int alignment = ALIGNMENT) { - auto ret = static_cast(PTRALLOC(size * sizeof(T), alignment)); - - if (!ret) - { - throw new std::bad_alloc(); - } - - return ptr(ret); -} - -template -inline ptr array_clone(const int size, const T* array){ - auto clone = array_new(size); - memcpy(clone.get(), array, size * sizeof(T)); - return clone; -} +#include template inline lapack_int lu_factor(lapack_int m, T a[], lapack_int ipiv[], GETRF getrf) @@ -204,7 +177,8 @@ inline lapack_int qr_thin_factor(lapack_int m, lapack_int n, T q[], T tau[], T r template inline lapack_int qr_solve(lapack_int m, lapack_int n, lapack_int bn, T a[], T b[], T x[], GELS gels) { - try{ + try + { auto clone_a = array_clone(m * n, a); auto clone_b = array_clone(m * bn, b); auto info = gels(LAPACK_COL_MAJOR, 'N', m, n, bn, clone_a.get(), m, clone_b.get(), m); @@ -221,7 +195,6 @@ inline lapack_int qr_solve(lapack_int m, lapack_int n, lapack_int bn, T a[], T b { return INSUFFICIENT_MEMORY; } - } template @@ -245,10 +218,9 @@ inline lapack_int qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, T { return INSUFFICIENT_MEMORY; } - } -template +template inline lapack_int complex_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, T r[], T b[], T tau[], T x[], UNMQR unmqr, TRSM trsm) { try @@ -262,7 +234,7 @@ inline lapack_int complex_qr_solve_factored(lapack_int m, lapack_int n, lapack_i } T one = 1.0f; - trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, &one, r, m, clone_b.get(), m); + trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, reinterpret_cast(&one), reinterpret_cast(r), m, reinterpret_cast(clone_b.get()), m); copyBtoX(m, n, bn, clone_b.get(), x); return info; } @@ -363,7 +335,7 @@ inline lapack_int eigen_factor(lapack_int n, T a[], T vectors[], R values[], T d } template -inline lapack_int eigen_complex_factor(lapack_int n, T a[], T vectors[], std::complex values[], T d[], GEES gees, TREVC trevc) +inline lapack_int eigen_complex_factor(lapack_int n, T a[], T vectors[], lapack_complex_double values[], T d[], GEES gees, TREVC trevc) { try { @@ -399,7 +371,7 @@ inline lapack_int eigen_complex_factor(lapack_int n, T a[], T vectors[], std::co } template -inline lapack_int sym_eigen_factor(lapack_int n, T a[], T vectors[], std::complex values[], T d[], SYEV syev) +inline lapack_int sym_eigen_factor(lapack_int n, T a[], T vectors[], lapack_complex_double values[], T d[], SYEV syev) { try { @@ -416,7 +388,7 @@ inline lapack_int sym_eigen_factor(lapack_int n, T a[], T vectors[], std::comple for (auto index = 0; index < n; ++index) { - values[index] = std::complex(w.get()[index]); + values[index] = lapack_complex_double(w.get()[index]); } for (auto j = 0; j < n; ++j) @@ -452,12 +424,12 @@ extern "C" { return LAPACKE_dlange(LAPACK_COL_MAJOR, norm, m, n, a, m); } - DLLEXPORT float c_matrix_norm(char norm, lapack_int m, lapack_int n, std::complex a[]) + DLLEXPORT float c_matrix_norm(char norm, lapack_int m, lapack_int n, lapack_complex_float a[]) { return LAPACKE_clange(LAPACK_COL_MAJOR, norm, m, n, a, m); } - DLLEXPORT double z_matrix_norm(char norm, lapack_int m, lapack_int n, std::complex a[]) + DLLEXPORT double z_matrix_norm(char norm, lapack_int m, lapack_int n, lapack_complex_double a[]) { return LAPACKE_zlange(LAPACK_COL_MAJOR, norm, m, n, a, m); } @@ -472,12 +444,12 @@ extern "C" { return lu_factor(m, a, ipiv, LAPACKE_dgetrf); } - DLLEXPORT lapack_int c_lu_factor(lapack_int m, std::complex a[], lapack_int ipiv[]) + DLLEXPORT lapack_int c_lu_factor(lapack_int m, lapack_complex_float a[], lapack_int ipiv[]) { return lu_factor(m, a, ipiv, LAPACKE_cgetrf); } - DLLEXPORT lapack_int z_lu_factor(lapack_int m, std::complex a[], lapack_int ipiv[]) + DLLEXPORT lapack_int z_lu_factor(lapack_int m, lapack_complex_double a[], lapack_int ipiv[]) { return lu_factor(m, a, ipiv, LAPACKE_zgetrf); } @@ -492,12 +464,12 @@ extern "C" { return lu_inverse(n, a, LAPACKE_dgetrf, LAPACKE_dgetri); } - DLLEXPORT lapack_int c_lu_inverse(lapack_int n, std::complex a[], std::complex work[], lapack_int lwork) + DLLEXPORT lapack_int c_lu_inverse(lapack_int n, lapack_complex_float a[], lapack_complex_float work[], lapack_int lwork) { return lu_inverse(n, a, LAPACKE_cgetrf, LAPACKE_cgetri); } - DLLEXPORT lapack_int z_lu_inverse(lapack_int n, std::complex a[], std::complex work[], lapack_int lwork) + DLLEXPORT lapack_int z_lu_inverse(lapack_int n, lapack_complex_double a[], lapack_complex_double work[], lapack_int lwork) { return lu_inverse(n, a, LAPACKE_zgetrf, LAPACKE_zgetri); } @@ -512,12 +484,12 @@ extern "C" { return lu_inverse_factored(n, a, ipiv, LAPACKE_dgetri); } - DLLEXPORT lapack_int c_lu_inverse_factored(lapack_int n, std::complex a[], lapack_int ipiv[], std::complex work[], lapack_int lwork) + DLLEXPORT lapack_int c_lu_inverse_factored(lapack_int n, lapack_complex_float a[], lapack_int ipiv[], lapack_complex_float work[], lapack_int lwork) { return lu_inverse_factored(n, a, ipiv, LAPACKE_cgetri); } - DLLEXPORT lapack_int z_lu_inverse_factored(lapack_int n, std::complex a[], lapack_int ipiv[], std::complex work[], lapack_int lwork) + DLLEXPORT lapack_int z_lu_inverse_factored(lapack_int n, lapack_complex_double a[], lapack_int ipiv[], lapack_complex_double work[], lapack_int lwork) { return lu_inverse_factored(n, a, ipiv, LAPACKE_zgetri); } @@ -532,12 +504,12 @@ extern "C" { return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACKE_dgetrs); } - DLLEXPORT lapack_int c_lu_solve_factored(lapack_int n, lapack_int nrhs, std::complex a[], lapack_int ipiv[], std::complex b[]) + DLLEXPORT lapack_int c_lu_solve_factored(lapack_int n, lapack_int nrhs, lapack_complex_float a[], lapack_int ipiv[], lapack_complex_float b[]) { return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACKE_cgetrs); } - DLLEXPORT lapack_int z_lu_solve_factored(lapack_int n, lapack_int nrhs, std::complex a[], lapack_int ipiv[], std::complex b[]) + DLLEXPORT lapack_int z_lu_solve_factored(lapack_int n, lapack_int nrhs, lapack_complex_double a[], lapack_int ipiv[], lapack_complex_double b[]) { return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACKE_zgetrs); } @@ -552,12 +524,12 @@ extern "C" { return lu_solve(n, nrhs, a, b, LAPACKE_dgetrf, LAPACKE_dgetrs); } - DLLEXPORT lapack_int c_lu_solve(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + DLLEXPORT lapack_int c_lu_solve(lapack_int n, lapack_int nrhs, lapack_complex_float a[], lapack_complex_float b[]) { return lu_solve(n, nrhs, a, b, LAPACKE_cgetrf, LAPACKE_cgetrs); } - DLLEXPORT lapack_int z_lu_solve(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + DLLEXPORT lapack_int z_lu_solve(lapack_int n, lapack_int nrhs, lapack_complex_double a[], lapack_complex_double b[]) { return lu_solve(n, nrhs, a, b, LAPACKE_zgetrf, LAPACKE_zgetrs); } @@ -572,12 +544,12 @@ extern "C" { return cholesky_factor(n, a, LAPACKE_dpotrf); } - DLLEXPORT lapack_int c_cholesky_factor(lapack_int n, std::complex a[]) + DLLEXPORT lapack_int c_cholesky_factor(lapack_int n, lapack_complex_float a[]) { return cholesky_factor(n, a, LAPACKE_cpotrf); } - DLLEXPORT lapack_int z_cholesky_factor(lapack_int n, std::complex a[]) + DLLEXPORT lapack_int z_cholesky_factor(lapack_int n, lapack_complex_double a[]) { return cholesky_factor(n, a, LAPACKE_zpotrf); } @@ -592,12 +564,12 @@ extern "C" { return cholesky_solve(n, nrhs, a, b, LAPACKE_dpotrf, LAPACKE_dpotrs); } - DLLEXPORT lapack_int c_cholesky_solve(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + DLLEXPORT lapack_int c_cholesky_solve(lapack_int n, lapack_int nrhs, lapack_complex_float a[], lapack_complex_float b[]) { return cholesky_solve(n, nrhs, a, b, LAPACKE_cpotrf, LAPACKE_cpotrs); } - DLLEXPORT lapack_int z_cholesky_solve(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + DLLEXPORT lapack_int z_cholesky_solve(lapack_int n, lapack_int nrhs, lapack_complex_double a[], lapack_complex_double b[]) { return cholesky_solve(n, nrhs, a, b, LAPACKE_zpotrf, LAPACKE_zpotrs); } @@ -612,12 +584,12 @@ extern "C" { return LAPACKE_dpotrs(LAPACK_COL_MAJOR, 'L', n, nrhs, a, n, b, n); } - DLLEXPORT lapack_int c_cholesky_solve_factored(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + DLLEXPORT lapack_int c_cholesky_solve_factored(lapack_int n, lapack_int nrhs, lapack_complex_float a[], lapack_complex_float b[]) { return LAPACKE_cpotrs(LAPACK_COL_MAJOR, 'L', n, nrhs, a, n, b, n); } - DLLEXPORT lapack_int z_cholesky_solve_factored(lapack_int n, lapack_int nrhs, std::complex a[], std::complex b[]) + DLLEXPORT lapack_int z_cholesky_solve_factored(lapack_int n, lapack_int nrhs, lapack_complex_double a[], lapack_complex_double b[]) { return LAPACKE_zpotrs(LAPACK_COL_MAJOR, 'L', n, nrhs, a, n, b, n); } @@ -642,22 +614,22 @@ extern "C" { return qr_thin_factor(m, n, q, tau, r, LAPACKE_dgeqrf, LAPACKE_dorgqr); } - DLLEXPORT lapack_int c_qr_factor(lapack_int m, lapack_int n, std::complex r[], std::complex tau[], std::complex q[]) + DLLEXPORT lapack_int c_qr_factor(lapack_int m, lapack_int n, lapack_complex_float r[], lapack_complex_float tau[], lapack_complex_float q[]) { return qr_factor(m, n, r, tau, q, LAPACKE_cgeqrf, LAPACKE_cungqr); } - DLLEXPORT lapack_int c_qr_thin_factor(lapack_int m, lapack_int n, std::complex q[], std::complex tau[], std::complex r[]) + DLLEXPORT lapack_int c_qr_thin_factor(lapack_int m, lapack_int n, lapack_complex_float q[], lapack_complex_float tau[], lapack_complex_float r[]) { return qr_thin_factor(m, n, q, tau, r, LAPACKE_cgeqrf, LAPACKE_cungqr); } - DLLEXPORT lapack_int z_qr_factor(lapack_int m, lapack_int n, std::complex r[], std::complex tau[], std::complex q[]) + DLLEXPORT lapack_int z_qr_factor(lapack_int m, lapack_int n, lapack_complex_double r[], lapack_complex_double tau[], lapack_complex_double q[]) { return qr_factor(m, n, r, tau, q, LAPACKE_zgeqrf, LAPACKE_zungqr); } - DLLEXPORT lapack_int z_qr_thin_factor(lapack_int m, lapack_int n, std::complex q[], std::complex tau[], std::complex r[]) + DLLEXPORT lapack_int z_qr_thin_factor(lapack_int m, lapack_int n, lapack_complex_double q[], lapack_complex_double tau[], lapack_complex_double r[]) { return qr_thin_factor(m, n, q, tau, r, LAPACKE_zgeqrf, LAPACKE_zungqr); } @@ -672,12 +644,12 @@ extern "C" { return qr_solve(m, n, bn, a, b, x, LAPACKE_dgels); } - DLLEXPORT lapack_int c_qr_solve(lapack_int m, lapack_int n, lapack_int bn, std::complex a[], std::complex b[], std::complex x[]) + DLLEXPORT lapack_int c_qr_solve(lapack_int m, lapack_int n, lapack_int bn, lapack_complex_float a[], lapack_complex_float b[], lapack_complex_float x[]) { return qr_solve(m, n, bn, a, b, x, LAPACKE_cgels); } - DLLEXPORT lapack_int z_qr_solve(lapack_int m, lapack_int n, lapack_int bn, std::complex a[], std::complex b[], std::complex x[]) + DLLEXPORT lapack_int z_qr_solve(lapack_int m, lapack_int n, lapack_int bn, lapack_complex_double a[], lapack_complex_double b[], lapack_complex_double x[]) { return qr_solve(m, n, bn, a, b, x, LAPACKE_zgels); } @@ -692,14 +664,14 @@ extern "C" { return qr_solve_factored(m, n, bn, r, b, tau, x, LAPACKE_dormqr, cblas_dtrsm); } - DLLEXPORT lapack_int c_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, std::complex r[], std::complex b[], std::complex tau[], std::complex x[]) + DLLEXPORT lapack_int c_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, lapack_complex_float r[], lapack_complex_float b[], lapack_complex_float tau[], lapack_complex_float x[]) { - return complex_qr_solve_factored(m, n, bn, r, b, tau, x, LAPACKE_cunmqr, cblas_ctrsm); + return complex_qr_solve_factored(m, n, bn, r, b, tau, x, LAPACKE_cunmqr, cblas_ctrsm); } - DLLEXPORT lapack_int z_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, std::complex r[], std::complex b[], std::complex tau[], std::complex x[]) + DLLEXPORT lapack_int z_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, lapack_complex_double r[], lapack_complex_double b[], lapack_complex_double tau[], lapack_complex_double x[]) { - return complex_qr_solve_factored(m, n, bn, r, b, tau, x, LAPACKE_zunmqr, cblas_ztrsm); + return complex_qr_solve_factored(m, n, bn, r, b, tau, x, LAPACKE_zunmqr, cblas_ztrsm); } DLLEXPORT lapack_int s_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, float a[], float s[], float u[], float v[]) @@ -712,17 +684,17 @@ extern "C" { return svd_factor(compute_vectors, m, n, a, s, u, v, LAPACKE_dgesvd); } - DLLEXPORT lapack_int c_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, std::complex a[], std::complex s[], std::complex u[], std::complex v[]) + DLLEXPORT lapack_int c_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, lapack_complex_float a[], lapack_complex_float s[], lapack_complex_float u[], lapack_complex_float v[]) { - return complex_svd_factor, float>(compute_vectors, m, n, a, s, u, v, LAPACKE_cgesvd); + return complex_svd_factor(compute_vectors, m, n, a, s, u, v, LAPACKE_cgesvd); } - DLLEXPORT lapack_int z_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, std::complex a[], std::complex s[], std::complex u[], std::complex v[]) + DLLEXPORT lapack_int z_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, lapack_complex_double a[], lapack_complex_double s[], lapack_complex_double u[], lapack_complex_double v[]) { - return complex_svd_factor, double>(compute_vectors, m, n, a, s, u, v, LAPACKE_zgesvd); + return complex_svd_factor(compute_vectors, m, n, a, s, u, v, LAPACKE_zgesvd); } - DLLEXPORT lapack_int s_eigen(bool isSymmetric, lapack_int n, float a[], float vectors[], std::complex values[], float d[]) + DLLEXPORT lapack_int s_eigen(bool isSymmetric, lapack_int n, float a[], float vectors[], lapack_complex_double values[], float d[]) { if (isSymmetric) { @@ -734,7 +706,7 @@ extern "C" { } } - DLLEXPORT lapack_int d_eigen(bool isSymmetric, lapack_int n, double a[], double vectors[], std::complex values[], double d[]) + DLLEXPORT lapack_int d_eigen(bool isSymmetric, lapack_int n, double a[], double vectors[], lapack_complex_double values[], double d[]) { if (isSymmetric) { @@ -746,7 +718,7 @@ extern "C" { } } - DLLEXPORT lapack_int c_eigen(bool isSymmetric, lapack_int n, std::complex a[], std::complex vectors[], std::complex values[], std::complex d[]) + DLLEXPORT lapack_int c_eigen(bool isSymmetric, lapack_int n, lapack_complex_float a[], lapack_complex_float vectors[], lapack_complex_double values[], lapack_complex_float d[]) { if (isSymmetric) { @@ -758,7 +730,7 @@ extern "C" { } } - DLLEXPORT lapack_int z_eigen(bool isSymmetric, lapack_int n, std::complex a[], std::complex vectors[], std::complex values[], std::complex d[]) + DLLEXPORT lapack_int z_eigen(bool isSymmetric, lapack_int n, lapack_complex_double a[], lapack_complex_double vectors[], lapack_complex_double values[], lapack_complex_double d[]) { if (isSymmetric) { diff --git a/src/NativeProviders/Common/lapack_common.h b/src/NativeProviders/Common/lapack_common.h index 46677a4b..5441d599 100644 --- a/src/NativeProviders/Common/lapack_common.h +++ b/src/NativeProviders/Common/lapack_common.h @@ -35,4 +35,29 @@ inline void copyBtoX (int m, int n, int bn, T b[], T x[]){ } } +#ifndef LAPACK_MEMORY +#define LAPACK_MEMORY + +#include + +const int INSUFFICIENT_MEMORY = -999999; +const int ALIGNMENT = 64; + +template using array_ptr = std::unique_ptr; + +template +inline array_ptr array_new(const int size, int alignment = ALIGNMENT) +{ + return array_ptr(new T[size]); +} + #endif + +template +inline array_ptr array_clone(const int size, const T* array) { + auto clone = array_new(size); + memcpy(clone.get(), array, size * sizeof(T)); + return clone; +} + +#endif \ No newline at end of file diff --git a/src/NativeProviders/MKL/blas.c b/src/NativeProviders/MKL/blas.c deleted file mode 100644 index 45fa4c55..00000000 --- a/src/NativeProviders/MKL/blas.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "mkl_cblas.h" -#include "wrapper_common.h" - -#if __cplusplus -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); -} - -DLLEXPORT void d_axpy(const MKL_INT n, const double alpha, const double x[], double y[]){ - cblas_daxpy(n, alpha, x, 1, y, 1); -} - -DLLEXPORT void c_axpy(const MKL_INT n, const MKL_Complex8 alpha, const MKL_Complex8 x[], MKL_Complex8 y[]){ - cblas_caxpy(n, &alpha, x, 1, y, 1); -} - -DLLEXPORT void z_axpy(const MKL_INT n, const MKL_Complex16 alpha, const MKL_Complex16 x[], MKL_Complex16 y[]){ - cblas_zaxpy(n, &alpha, x, 1, y, 1); -} - -DLLEXPORT void s_scale(const MKL_INT n, const float alpha, float x[]){ - cblas_sscal(n, alpha, x, 1); -} - -DLLEXPORT void d_scale(const MKL_INT n, const double alpha, double x[]){ - cblas_dscal(n, alpha, x, 1); -} - -DLLEXPORT void c_scale(const MKL_INT n, const MKL_Complex8 alpha, MKL_Complex8 x[]){ - cblas_cscal(n, &alpha, x, 1); -} - -DLLEXPORT void z_scale(const MKL_INT n, const MKL_Complex16 alpha, MKL_Complex16 x[]){ - cblas_zscal(n, &alpha, x, 1); -} - -DLLEXPORT float s_dot_product(const MKL_INT n, const float x[], const float y[]){ - return cblas_sdot(n, x, 1, y, 1); -} - -DLLEXPORT double d_dot_product(const MKL_INT n, const double x[], const double y[]){ - return cblas_ddot(n, x, 1, y, 1); -} - -DLLEXPORT MKL_Complex8 c_dot_product(const MKL_INT n, const MKL_Complex8 x[], const MKL_Complex8 y[]){ - MKL_Complex8 ret; - cblas_cdotu_sub(n, x, 1, y, 1, &ret); - return ret; -} - -DLLEXPORT MKL_Complex16 z_dot_product(const MKL_INT n, const MKL_Complex16 x[], const MKL_Complex16 y[]){ - MKL_Complex16 ret; - cblas_zdotu_sub(n, x, 1, y, 1, &ret); - return ret; -} - -DLLEXPORT void s_matrix_multiply(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const MKL_INT m, const MKL_INT n, const MKL_INT k, const float alpha, const float x[], const float y[], const float beta, float c[]){ - MKL_INT lda = transA == CblasNoTrans ? m : k; - MKL_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(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const MKL_INT m, const MKL_INT n, const MKL_INT k, const double alpha, const double x[], const double y[], const double beta, double c[]){ - MKL_INT lda = transA == CblasNoTrans ? m : k; - MKL_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(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const MKL_INT m, const MKL_INT n, const MKL_INT k, const MKL_Complex8 alpha, const MKL_Complex8 x[], const MKL_Complex8 y[], const MKL_Complex8 beta, MKL_Complex8 c[]){ - MKL_INT lda = transA == CblasNoTrans ? m : k; - MKL_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(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const MKL_INT m, const MKL_INT n, const MKL_INT k, const MKL_Complex16 alpha, const MKL_Complex16 x[], const MKL_Complex16 y[], const MKL_Complex16 beta, MKL_Complex16 c[]){ - MKL_INT lda = transA == CblasNoTrans ? m : k; - MKL_INT ldb = transB == CblasNoTrans ? k : n; - - cblas_zgemm(CblasColMajor, transA, transB, m, n, k, &alpha, x, lda, y, ldb, &beta, c, m); -} - -#if __cplusplus -} -#endif diff --git a/src/NativeProviders/MKL/blas.h b/src/NativeProviders/MKL/blas.h new file mode 100644 index 00000000..555d466c --- /dev/null +++ b/src/NativeProviders/MKL/blas.h @@ -0,0 +1,7 @@ +#pragma once + +#include "mkl_cblas.h" + +#define blas_int MKL_INT +#define blas_complex_float MKL_Complex8 +#define blas_complex_double MKL_Complex16 diff --git a/src/NativeProviders/MKL/lapack.h b/src/NativeProviders/MKL/lapack.h index dce0c23a..b57ca9ee 100644 --- a/src/NativeProviders/MKL/lapack.h +++ b/src/NativeProviders/MKL/lapack.h @@ -1,17 +1,34 @@ #pragma once -#include +#include #define MKL_Complex8 std::complex #define MKL_Complex16 std::complex #include "mkl.h" +#define LAPACK_MEMORY +#include + const int INSUFFICIENT_MEMORY = -999999; const int ALIGNMENT = 64; -//#define PTRALLOC( size, alignment ) LAPACKE_malloc( size ) -//#define PTRFREE( p ) LAPACKE_free( p ) +struct array_free +{ + void operator()(void* x) { mkl_free(x); } +}; + +template using array_ptr = std::unique_ptr; + +template +inline array_ptr array_new(const int size, int alignment = ALIGNMENT) +{ + auto ret = static_cast(mkl_malloc(size * sizeof(T), alignment)); + + if (!ret) + { + throw new std::bad_alloc(); + } -#define PTRALLOC( size, alignment ) mkl_malloc( size, alignment ) -#define PTRFREE( p ) mkl_free( p ) + return array_ptr(ret); +} diff --git a/src/NativeProviders/OpenBLAS/blas.c b/src/NativeProviders/OpenBLAS/blas.c deleted file mode 100644 index 3bf9290e..00000000 --- a/src/NativeProviders/OpenBLAS/blas.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "cblas.h" -#include "wrapper_common.h" - -#if __cplusplus -extern "C" { -#endif -DLLEXPORT void s_axpy(const blasint n, const float alpha, const float x[], float y[]){ - cblas_saxpy(n, alpha, x, 1, y, 1); -} - -DLLEXPORT void d_axpy(const blasint n, const double alpha, const double x[], double y[]){ - cblas_daxpy(n, alpha, x, 1, y, 1); -} - -DLLEXPORT void c_axpy(const blasint n, const openblas_complex_float alpha, const openblas_complex_float x[], openblas_complex_float y[]){ - cblas_caxpy(n, (float*)&alpha, (float*)x, 1, (float*)y, 1); -} - -DLLEXPORT void z_axpy(const blasint n, const openblas_complex_double alpha, const openblas_complex_double x[], openblas_complex_double y[]){ - cblas_zaxpy(n, (double*)&alpha, (double*)x, 1, (double*)y, 1); -} - -DLLEXPORT void s_scale(const blasint n, const float alpha, float x[]){ - cblas_sscal(n, alpha, x, 1); -} - -DLLEXPORT void d_scale(const blasint n, const double alpha, double x[]){ - cblas_dscal(n, alpha, x, 1); -} - -DLLEXPORT void c_scale(const blasint n, const openblas_complex_float alpha, openblas_complex_float x[]){ - cblas_cscal(n, (float*)&alpha, (float*)x, 1); -} - -DLLEXPORT void z_scale(const blasint n, const openblas_complex_double alpha, openblas_complex_double x[]){ - cblas_zscal(n, (double*)&alpha, (double*)x, 1); -} - -DLLEXPORT float s_dot_product(const blasint n, const float x[], const float y[]){ - return cblas_sdot(n, x, 1, y, 1); -} - -DLLEXPORT double d_dot_product(const blasint n, const double x[], const double y[]){ - return cblas_ddot(n, x, 1, y, 1); -} - -DLLEXPORT openblas_complex_float c_dot_product(const blasint n, const openblas_complex_float x[], const openblas_complex_float y[]){ - openblas_complex_float ret; - cblas_cdotu_sub(n, (float*)x, 1, (float*)y, 1, &ret); - return ret; -} - -DLLEXPORT openblas_complex_double z_dot_product(const blasint n, const openblas_complex_double x[], const openblas_complex_double y[]){ - openblas_complex_double ret; - cblas_zdotu_sub(n, (double*)x, 1, (double*)y, 1, &ret); - return ret; -} - -DLLEXPORT void s_matrix_multiply(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const blasint m, const blasint n, const blasint k, const float alpha, const float x[], const float y[], const float beta, float c[]){ - blasint lda = transA == CblasNoTrans ? m : k; - blasint 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(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const blasint m, const blasint n, const blasint k, const double alpha, const double x[], const double y[], const double beta, double c[]){ - blasint lda = transA == CblasNoTrans ? m : k; - blasint 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(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const blasint m, const blasint n, const blasint k, const openblas_complex_float alpha, const openblas_complex_float x[], const openblas_complex_float y[], const openblas_complex_float beta, openblas_complex_float c[]){ - blasint lda = transA == CblasNoTrans ? m : k; - blasint ldb = transB == CblasNoTrans ? k : n; - - cblas_cgemm(CblasColMajor, transA, transB, m, n, k, (float*)&alpha, (float*)x, lda, (float*)y, ldb, (float*)&beta, (float*)c, m); -} - -DLLEXPORT void z_matrix_multiply(CBLAS_TRANSPOSE transA, CBLAS_TRANSPOSE transB, const blasint m, const blasint n, const blasint k, const openblas_complex_double alpha, const openblas_complex_double x[], const openblas_complex_double y[], const openblas_complex_double beta, openblas_complex_double c[]){ - blasint lda = transA == CblasNoTrans ? m : k; - blasint ldb = transB == CblasNoTrans ? k : n; - - cblas_zgemm(CblasColMajor, transA, transB, m, n, k, (double*)&alpha, (double*)x, lda, (double*)y, ldb, (double*)&beta, (double*)c, m); -} - -#if __cplusplus -} -#endif diff --git a/src/NativeProviders/OpenBLAS/blas.h b/src/NativeProviders/OpenBLAS/blas.h new file mode 100644 index 00000000..c5c0a7e0 --- /dev/null +++ b/src/NativeProviders/OpenBLAS/blas.h @@ -0,0 +1,7 @@ +#pragma once + +#include "cblas.h" + +#define blas_int blasint +#define blas_complex_float openblas_complex_float +#define blas_complex_double openblas_complex_double diff --git a/src/NativeProviders/OpenBLAS/complex.h b/src/NativeProviders/OpenBLAS/complex.h deleted file mode 100644 index d107e400..00000000 --- a/src/NativeProviders/OpenBLAS/complex.h +++ /dev/null @@ -1,39 +0,0 @@ -template -struct complex -{ - _T real, imag; - - complex(_T _real = 0, _T _imag = 0) - { - real = _real; - imag = _imag; - } - - complex(const complex<_T>& right) - { - real = right.real; - imag = right.imag; - } - - complex& operator=(const complex& right) - { - real = right.real; - imag = right.imag; - return *this; - } - - complex& operator=(const _T& right) - { - real = right; - imag = 0; - return *this; - } - - template inline - complex& operator=(const complex<_Other>& right) - { - real = (_T)right.real; - imag = (_T)right.imag; - return *this; - } -}; \ No newline at end of file diff --git a/src/NativeProviders/OpenBLAS/lapack.cpp b/src/NativeProviders/OpenBLAS/lapack.cpp deleted file mode 100644 index fee9abec..00000000 --- a/src/NativeProviders/OpenBLAS/lapack.cpp +++ /dev/null @@ -1,712 +0,0 @@ -#include "cblas.h" - -#include "complex.h" -#define LAPACK_COMPLEX_CUSTOM -#define lapack_complex_float complex -#define lapack_complex_double complex - -#include "lapacke.h" -#include "lapack_common.h" -#include "wrapper_common.h" -#include - -template -inline lapack_int lu_factor(lapack_int m, T a[], lapack_int ipiv[], GETRF getrf) -{ - lapack_int info = 0; - getrf(&m, &m, a, &m, ipiv, &info); - shift_ipiv_down(m, ipiv); - return info; -}; - -template -inline lapack_int lu_inverse(lapack_int n, T a[], T work[], lapack_int lwork, GETRF getrf, GETRI getri) -{ - lapack_int* ipiv = new lapack_int[n]; - lapack_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 -inline lapack_int lu_inverse_factored(lapack_int n, T a[], lapack_int ipiv[], T work[], lapack_int lwork, GETRI getri) -{ - shift_ipiv_up(n, ipiv); - lapack_int info = 0; - getri(&n, a, &n, ipiv, work, &lwork, &info); - shift_ipiv_down(n, ipiv); - return info; -} - -template -inline lapack_int lu_solve_factored(lapack_int n, lapack_int nrhs, T a[], lapack_int ipiv[], T b[], GETRS getrs) -{ - shift_ipiv_up(n, ipiv); - lapack_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 lapack_int lu_solve(lapack_int n, lapack_int nrhs, T a[], T b[], GETRF getrf, GETRS getrs) -{ - T* clone = Clone(n, n, a); - lapack_int* ipiv = new lapack_int[n]; - lapack_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 -inline lapack_int cholesky_factor(lapack_int n, T* a, POTRF potrf) -{ - char uplo = 'L'; - lapack_int info = 0; - potrf(&uplo, &n, a, &n, &info); - T zero = T(); - - for (lapack_int i = 0; i < n; ++i) - { - lapack_int index = i * n; - - for (lapack_int j = 0; j < n && i > j; ++j) - { - a[index + j] = zero; - } - } - - return info; -} - -template -inline lapack_int cholesky_solve(lapack_int n, lapack_int nrhs, T a[], T b[], POTRF potrf, POTRS potrs) -{ - T* clone = Clone(n, n, a); - char uplo = 'L'; - lapack_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 -inline lapack_int cholesky_solve_factored(lapack_int n, lapack_int nrhs, T a[], T b[], POTRS potrs) -{ - char uplo = 'L'; - lapack_int info = 0; - potrs(&uplo, &n, &nrhs, a, &n, b, &n, &info); - return info; -} - -template -inline lapack_int qr_factor(lapack_int m, lapack_int n, T r[], T tau[], T q[], T work[], lapack_int len, GEQRF geqrf, ORGQR orgqr) -{ - lapack_int info = 0; - geqrf(&m, &n, r, &m, tau, work, &len, &info); - - for (lapack_int i = 0; i < m; ++i) - { - for (lapack_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 -inline lapack_int qr_thin_factor(lapack_int m, lapack_int n, T q[], T tau[], T r[], T work[], lapack_int len, GEQRF geqrf, ORGQR orgqr) -{ - lapack_int info = 0; - geqrf(&m, &n, q, &m, tau, work, &len, &info); - - for (lapack_int i = 0; i < n; ++i) - { - for (lapack_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 -inline lapack_int qr_solve(lapack_int m, lapack_int n, lapack_int bn, T a[], T b[], T x[], T work[], lapack_int len, GELS gels) -{ - T* clone_a = Clone(m, n, a); - T* clone_b = Clone(m, bn, b); - char N = 'N'; - lapack_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 -inline lapack_int qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, T r[], T b[], T tau[], T x[], T work[], lapack_int len, ORMQR ormqr, TRSM trsm) -{ - T* clone_b = Clone(m, bn, b); - char side ='L'; - char tran = 'T'; - lapack_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 -inline lapack_int complex_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, T r[], T b[], T tau[], T x[], T work[], lapack_int len, UNMQR unmqr, TRSM trsm) -{ - T* clone_b = Clone(m, bn, b); - char side ='L'; - char tran = 'C'; - lapack_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, reinterpret_cast(&one), reinterpret_cast(r), m, reinterpret_cast(clone_b), m); - copyBtoX(m, n, bn, clone_b, x); - delete[] clone_b; - return info; -} - -template -inline lapack_int svd_factor(bool compute_vectors, lapack_int m, lapack_int n, T a[], T s[], T u[], T v[], T work[], lapack_int len, GESVD gesvd) -{ - lapack_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 lapack_int complex_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, T a[], T s[], T u[], T v[], T work[], lapack_int len, GESVD gesvd) -{ - lapack_int info = 0; - lapack_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 (lapack_int index = 0; index < dim_s; ++index) - { - s[index] = s_local[index]; - } - - delete[] rwork; - delete[] s_local; - return info; -} - -template -inline lapack_int eigen_factor(lapack_int n, T a[], T vectors[], R values[], T d[], GEES gees, TREVC trevc) -{ - T* clone_a = Clone(n, n, a); - T* wr = new T[n]; - T* wi = new T[n]; - - lapack_int sdim; - lapack_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; - } - - lapack_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 (lapack_int index = 0; index < n; ++index) - { - values[index] = R(wr[index], wi[index]); - } - - for (lapack_int i = 0; i < n; ++i) - { - lapack_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; -} - -template -inline lapack_int eigen_complex_factor(lapack_int n, T a[], T vectors[], lapack_complex_double values[], T d[], GEES gees, TREVC trevc) -{ - T* clone_a = Clone(n, n, a); - T* w = new T[n]; - - lapack_int sdim; - lapack_int info = gees(LAPACK_COL_MAJOR, 'V', 'N', nullptr, n, clone_a, n, &sdim, w, vectors, n); - if (info != 0) - { - delete[] clone_a; - delete[] w; - return info; - } - - lapack_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[] w; - return info; - } - - for (lapack_int i = 0; i < n; ++i) - { - values[i] = w[i]; - d[i * n + i] = w[i]; - } - - delete[] clone_a; - delete[] w; - return info; -} - -template -inline lapack_int sym_eigen_factor(lapack_int n, T a[], T vectors[], lapack_complex_double values[], T d[], SYEV syev) -{ - T* clone_a = Clone(n, n, a); - R* w = new R[n]; - - lapack_int info = syev(LAPACK_COL_MAJOR, 'V', 'U', n, clone_a, n, w); - if (info != 0) - { - delete[] clone_a; - delete[] w; - return info; - } - - memcpy(vectors, clone_a, n*n*sizeof(T)); - - for (lapack_int index = 0; index < n; ++index) - { - values[index] = lapack_complex_double(w[index]); - } - - for (lapack_int j = 0; j < n; ++j) - { - lapack_int jn = j*n; - - for (lapack_int i = 0; i < n; ++i) - { - if (i == j) - { - d[jn + i] = w[i]; - } - } - } - - delete[] clone_a; - delete[] w; - return info; -} - -extern "C" { - - DLLEXPORT float s_matrix_norm(char norm, lapack_int m, lapack_int n, float a[], float work[]) - { - return LAPACKE_slange_work(CblasColMajor, norm, m, n, a, m, work); - } - - DLLEXPORT double d_matrix_norm(char norm, lapack_int m, lapack_int n, double a[], double work[]) - { - return LAPACKE_dlange_work(CblasColMajor, norm, m, n, a, m, work); - } - - DLLEXPORT float c_matrix_norm(char norm, lapack_int m, lapack_int n, lapack_complex_float a[], float work[]) - { - return LAPACKE_clange_work(CblasColMajor, norm, m, n, a, m, work); - } - - DLLEXPORT double z_matrix_norm(char norm, lapack_int m, lapack_int n, lapack_complex_double a[], double work[]) - { - return LAPACKE_zlange_work(CblasColMajor, norm, m, n, a, m, work); - } - - DLLEXPORT lapack_int s_lu_factor(lapack_int m, float a[], lapack_int ipiv[]) - { - return lu_factor(m, a, ipiv, LAPACK_sgetrf); - } - - DLLEXPORT lapack_int d_lu_factor(lapack_int m, double a[], lapack_int ipiv[]) - { - return lu_factor(m, a, ipiv, LAPACK_dgetrf); - } - - DLLEXPORT lapack_int c_lu_factor(lapack_int m, lapack_complex_float a[], lapack_int ipiv[]) - { - return lu_factor(m, a, ipiv, LAPACK_cgetrf); - } - - DLLEXPORT lapack_int z_lu_factor(lapack_int m, lapack_complex_double a[], lapack_int ipiv[]) - { - return lu_factor(m, a, ipiv, LAPACK_zgetrf); - } - - DLLEXPORT lapack_int s_lu_inverse(lapack_int n, float a[], float work[], lapack_int lwork) - { - return lu_inverse(n, a, work, lwork, LAPACK_sgetrf, LAPACK_sgetri); - } - - DLLEXPORT lapack_int d_lu_inverse(lapack_int n, double a[], double work[], lapack_int lwork) - { - return lu_inverse(n, a, work, lwork, LAPACK_dgetrf, LAPACK_dgetri); - } - - DLLEXPORT lapack_int c_lu_inverse(lapack_int n, lapack_complex_float a[], lapack_complex_float work[], lapack_int lwork) - { - return lu_inverse(n, a, work, lwork, LAPACK_cgetrf, LAPACK_cgetri); - } - - DLLEXPORT lapack_int z_lu_inverse(lapack_int n, lapack_complex_double a[], lapack_complex_double work[], lapack_int lwork) - { - return lu_inverse(n, a, work, lwork, LAPACK_zgetrf, LAPACK_zgetri); - } - - DLLEXPORT lapack_int s_lu_inverse_factored(lapack_int n, float a[], lapack_int ipiv[], float work[], lapack_int lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, LAPACK_sgetri); - } - - DLLEXPORT lapack_int d_lu_inverse_factored(lapack_int n, double a[], lapack_int ipiv[], double work[], lapack_int lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, LAPACK_dgetri); - } - - DLLEXPORT lapack_int c_lu_inverse_factored(lapack_int n, lapack_complex_float a[], lapack_int ipiv[], lapack_complex_float work[], lapack_int lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, LAPACK_cgetri); - } - - DLLEXPORT lapack_int z_lu_inverse_factored(lapack_int n, lapack_complex_double a[], lapack_int ipiv[], lapack_complex_double work[], lapack_int lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, LAPACK_zgetri); - } - - DLLEXPORT lapack_int s_lu_solve_factored(lapack_int n, lapack_int nrhs, float a[], lapack_int ipiv[], float b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACK_sgetrs); - } - - DLLEXPORT lapack_int d_lu_solve_factored(lapack_int n, lapack_int nrhs, double a[], lapack_int ipiv[], double b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACK_dgetrs); - } - - DLLEXPORT lapack_int c_lu_solve_factored(lapack_int n, lapack_int nrhs, lapack_complex_float a[], lapack_int ipiv[], lapack_complex_float b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACK_cgetrs); - } - - DLLEXPORT lapack_int z_lu_solve_factored(lapack_int n, lapack_int nrhs, lapack_complex_double a[], lapack_int ipiv[], lapack_complex_double b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, LAPACK_zgetrs); - } - - DLLEXPORT lapack_int s_lu_solve(lapack_int n, lapack_int nrhs, float a[], float b[]) - { - return lu_solve(n, nrhs, a, b, LAPACK_sgetrf, LAPACK_sgetrs); - } - - DLLEXPORT lapack_int d_lu_solve(lapack_int n, lapack_int nrhs, double a[], double b[]) - { - return lu_solve(n, nrhs, a, b, LAPACK_dgetrf, LAPACK_dgetrs); - } - - DLLEXPORT lapack_int c_lu_solve(lapack_int n, lapack_int nrhs, lapack_complex_float a[], lapack_complex_float b[]) - { - return lu_solve(n, nrhs, a, b, LAPACK_cgetrf, LAPACK_cgetrs); - } - - DLLEXPORT lapack_int z_lu_solve(lapack_int n, lapack_int nrhs, lapack_complex_double a[], lapack_complex_double b[]) - { - return lu_solve(n, nrhs, a, b, LAPACK_zgetrf, LAPACK_zgetrs); - } - - DLLEXPORT lapack_int s_cholesky_factor(lapack_int n, float a[]) - { - return cholesky_factor(n, a, LAPACK_spotrf); - } - - DLLEXPORT lapack_int d_cholesky_factor(lapack_int n, double* a) - { - return cholesky_factor(n, a, LAPACK_dpotrf); - } - - DLLEXPORT lapack_int c_cholesky_factor(lapack_int n, lapack_complex_float a[]) - { - return cholesky_factor(n, a, LAPACK_cpotrf); - } - - DLLEXPORT lapack_int z_cholesky_factor(lapack_int n, lapack_complex_double a[]) - { - return cholesky_factor(n, a, LAPACK_zpotrf); - } - - DLLEXPORT lapack_int s_cholesky_solve(lapack_int n, lapack_int nrhs, float a[], float b[]) - { - return cholesky_solve(n, nrhs, a, b, LAPACK_spotrf, LAPACK_spotrs); - } - - DLLEXPORT lapack_int d_cholesky_solve(lapack_int n, lapack_int nrhs, double a[], double b[]) - { - return cholesky_solve(n, nrhs, a, b, LAPACK_dpotrf, LAPACK_dpotrs); - } - - DLLEXPORT lapack_int c_cholesky_solve(lapack_int n, lapack_int nrhs, lapack_complex_float a[], lapack_complex_float b[]) - { - return cholesky_solve(n, nrhs, a, b, LAPACK_cpotrf, LAPACK_cpotrs); - } - - DLLEXPORT lapack_int z_cholesky_solve(lapack_int n, lapack_int nrhs, lapack_complex_double a[], lapack_complex_double b[]) - { - return cholesky_solve(n, nrhs, a, b, LAPACK_zpotrf, LAPACK_zpotrs); - } - - DLLEXPORT lapack_int s_cholesky_solve_factored(lapack_int n, lapack_int nrhs, float a[], float b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, LAPACK_spotrs); - } - - DLLEXPORT lapack_int d_cholesky_solve_factored(lapack_int n, lapack_int nrhs, double a[], double b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, LAPACK_dpotrs); - } - - DLLEXPORT lapack_int c_cholesky_solve_factored(lapack_int n, lapack_int nrhs, lapack_complex_float a[], lapack_complex_float b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, LAPACK_cpotrs); - } - - DLLEXPORT lapack_int z_cholesky_solve_factored(lapack_int n, lapack_int nrhs, lapack_complex_double a[], lapack_complex_double b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, LAPACK_zpotrs); - } - - DLLEXPORT lapack_int s_qr_factor(lapack_int m, lapack_int n, float r[], float tau[], float q[], float work[], lapack_int len) - { - return qr_factor(m, n, r, tau, q, work, len, LAPACK_sgeqrf, LAPACK_sorgqr); - } - - DLLEXPORT lapack_int s_qr_thin_factor(lapack_int m, lapack_int n, float q[], float tau[], float r[], float work[], lapack_int len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, LAPACK_sgeqrf, LAPACK_sorgqr); - } - - DLLEXPORT lapack_int d_qr_factor(lapack_int m, lapack_int n, double r[], double tau[], double q[], double work[], lapack_int len) - { - return qr_factor(m, n, r, tau, q, work, len, LAPACK_dgeqrf, LAPACK_dorgqr); - } - - DLLEXPORT lapack_int d_qr_thin_factor(lapack_int m, lapack_int n, double q[], double tau[], double r[], double work[], lapack_int len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, LAPACK_dgeqrf, LAPACK_dorgqr); - } - - DLLEXPORT lapack_int c_qr_factor(lapack_int m, lapack_int n, lapack_complex_float r[], lapack_complex_float tau[], lapack_complex_float q[], lapack_complex_float work[], lapack_int len) - { - return qr_factor(m, n, r, tau, q, work, len, LAPACK_cgeqrf, LAPACK_cungqr); - } - - DLLEXPORT lapack_int c_qr_thin_factor(lapack_int m, lapack_int n, lapack_complex_float q[], lapack_complex_float tau[], lapack_complex_float r[], lapack_complex_float work[], lapack_int len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, LAPACK_cgeqrf, LAPACK_cungqr); - } - - DLLEXPORT lapack_int z_qr_factor(lapack_int m, lapack_int n, lapack_complex_double r[], lapack_complex_double tau[], lapack_complex_double q[], lapack_complex_double work[], lapack_int len) - { - return qr_factor(m, n, r, tau, q, work, len, LAPACK_zgeqrf, LAPACK_zungqr); - } - - DLLEXPORT lapack_int z_qr_thin_factor(lapack_int m, lapack_int n, lapack_complex_double q[], lapack_complex_double tau[], lapack_complex_double r[], lapack_complex_double work[], lapack_int len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, LAPACK_zgeqrf, LAPACK_zungqr); - } - - DLLEXPORT lapack_int s_qr_solve(lapack_int m, lapack_int n, lapack_int bn, float a[], float b[], float x[], float work[], lapack_int len) - { - return qr_solve(m, n, bn, a, b, x, work, len, LAPACK_sgels); - } - - DLLEXPORT lapack_int d_qr_solve(lapack_int m, lapack_int n, lapack_int bn, double a[], double b[], double x[], double work[], lapack_int len) - { - return qr_solve(m, n, bn, a, b, x, work, len, LAPACK_dgels); - } - - DLLEXPORT lapack_int c_qr_solve(lapack_int m, lapack_int n, lapack_int bn, lapack_complex_float a[], lapack_complex_float b[], lapack_complex_float x[], lapack_complex_float work[], lapack_int len) - { - return qr_solve(m, n, bn, a, b, x, work, len, LAPACK_cgels); - } - - DLLEXPORT lapack_int z_qr_solve(lapack_int m, lapack_int n, lapack_int bn, lapack_complex_double a[], lapack_complex_double b[], lapack_complex_double x[], lapack_complex_double work[], lapack_int len) - { - return qr_solve(m, n, bn, a, b, x, work, len, LAPACK_zgels); - } - - DLLEXPORT lapack_int s_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, float r[], float b[], float tau[], float x[], float work[], lapack_int len) - { - return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, LAPACK_sormqr, cblas_strsm); - } - - DLLEXPORT lapack_int d_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, double r[], double b[], double tau[], double x[], double work[], lapack_int len) - { - return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, LAPACK_dormqr, cblas_dtrsm); - } - - DLLEXPORT lapack_int c_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, lapack_complex_float r[], lapack_complex_float b[], lapack_complex_float tau[], lapack_complex_float x[], lapack_complex_float work[], lapack_int len) - { - return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, LAPACK_cunmqr, cblas_ctrsm); - } - - DLLEXPORT lapack_int z_qr_solve_factored(lapack_int m, lapack_int n, lapack_int bn, lapack_complex_double r[], lapack_complex_double b[], lapack_complex_double tau[], lapack_complex_double x[], lapack_complex_double work[], lapack_int len) - { - return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, LAPACK_zunmqr, cblas_ztrsm); - } - - DLLEXPORT lapack_int s_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, float a[], float s[], float u[], float v[], float work[], lapack_int len) - { - return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, LAPACK_sgesvd); - } - - DLLEXPORT lapack_int d_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, double a[], double s[], double u[], double v[], double work[], lapack_int len) - { - return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, LAPACK_dgesvd); - } - - DLLEXPORT lapack_int c_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, lapack_complex_float a[], lapack_complex_float s[], lapack_complex_float u[], lapack_complex_float v[], lapack_complex_float work[], lapack_int len) - { - return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, LAPACK_cgesvd); - } - - DLLEXPORT lapack_int z_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, lapack_complex_double a[], lapack_complex_double s[], lapack_complex_double u[], lapack_complex_double v[], lapack_complex_double work[], lapack_int len) - { - return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, LAPACK_zgesvd); - } - - DLLEXPORT lapack_int s_eigen(bool isSymmetric, lapack_int n, float a[], float vectors[], lapack_complex_double 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 lapack_int d_eigen(bool isSymmetric, lapack_int n, double a[], double vectors[], lapack_complex_double 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 lapack_int c_eigen(bool isSymmetric, lapack_int n, lapack_complex_float a[], lapack_complex_float vectors[], lapack_complex_double values[], lapack_complex_float d[]) - { - if (isSymmetric) - { - return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_cheev); - } - else - { - return eigen_complex_factor(n, a, vectors, values, d, LAPACKE_cgees, LAPACKE_ctrevc); - } - } - - DLLEXPORT lapack_int z_eigen(bool isSymmetric, lapack_int n, lapack_complex_double a[], lapack_complex_double vectors[], lapack_complex_double values[], lapack_complex_double 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); - } - } -} diff --git a/src/NativeProviders/OpenBLAS/lapack.h b/src/NativeProviders/OpenBLAS/lapack.h new file mode 100644 index 00000000..30d40bbe --- /dev/null +++ b/src/NativeProviders/OpenBLAS/lapack.h @@ -0,0 +1,9 @@ +#pragma once + +#define LAPACK_COMPLEX_CUSTOM +#include +#define lapack_complex_float std::complex +#define lapack_complex_double std::complex + +#include "cblas.h" +#include "lapacke.h" diff --git a/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj b/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj index 504a3317..002e17f4 100644 --- a/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj +++ b/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj @@ -289,10 +289,10 @@ + + - - @@ -300,6 +300,9 @@ + + + diff --git a/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters b/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters index c543369a..ce59f97e 100644 --- a/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters +++ b/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters @@ -15,12 +15,6 @@ - - Source Files - - - Source Files - Source Files @@ -33,6 +27,12 @@ Source Files + + Source Files + + + Source Files + @@ -43,5 +43,14 @@ Header Files + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/src/NativeProviders/Windows/OpenBLAS/OpenBLASWrapper.vcxproj b/src/NativeProviders/Windows/OpenBLAS/OpenBLASWrapper.vcxproj index eb3db333..ad28493e 100644 --- a/src/NativeProviders/Windows/OpenBLAS/OpenBLASWrapper.vcxproj +++ b/src/NativeProviders/Windows/OpenBLAS/OpenBLASWrapper.vcxproj @@ -203,16 +203,18 @@ + + - - - + + + diff --git a/src/NativeProviders/Windows/OpenBLAS/OpenBLASWrapper.vcxproj.filters b/src/NativeProviders/Windows/OpenBLAS/OpenBLASWrapper.vcxproj.filters index 3a4caaa1..4f847d3b 100644 --- a/src/NativeProviders/Windows/OpenBLAS/OpenBLASWrapper.vcxproj.filters +++ b/src/NativeProviders/Windows/OpenBLAS/OpenBLASWrapper.vcxproj.filters @@ -15,16 +15,16 @@ - + Source Files - + Source Files - + Source Files - + Source Files @@ -34,10 +34,16 @@ - + Header Files - + + Header Files + + + Header Files + + Header Files diff --git a/src/Numerics/Control.cs b/src/Numerics/Control.cs index 4fd3fee5..825f1463 100644 --- a/src/Numerics/Control.cs +++ b/src/Numerics/Control.cs @@ -88,7 +88,9 @@ namespace MathNet.Numerics break; default: +#if NATIVE if (!TryUseNative()) +#endif { UseManaged(); } diff --git a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex.cs b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex.cs index a683b7bf..9b387546 100644 --- a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex.cs +++ b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex.cs @@ -76,8 +76,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArrayTooSmall, rows * columns), "matrix"); } - var work = new double[rows]; - return SafeNativeMethods.z_matrix_norm((byte)norm, rows, columns, matrix, work); + return SafeNativeMethods.z_matrix_norm((byte)norm, rows, columns, matrix); } /// @@ -229,7 +228,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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); } @@ -264,7 +263,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (data.Length != order * order) + if (data.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "data"); } @@ -274,7 +273,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - SafeNativeMethods.z_lu_factor(order, data, ipiv); + var info = SafeNativeMethods.z_lu_factor(order, data, ipiv); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -291,82 +295,27 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("a"); } - if (a.Length != order * order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - var work = new Complex[order]; - SafeNativeMethods.z_lu_inverse(order, a, work, work.Length); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(Complex[] a, int order, int[] ipiv) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } - - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - var work = new Complex[order]; - SafeNativeMethods.z_lu_inverse_factored(order, a, ipiv, work, order); - } - - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(Complex[] a, int order, Complex[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } + var info = SafeNativeMethods.z_lu_inverse(order, a); - if (a.Length != order * order) + if (info == (int)NativeError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + throw new MemoryAllocationException(); } - if (work == null) + if (info < 0) { - throw new ArgumentNullException("work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (work.Length < order) + if (info > 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new SingularUMatrixException(info); } - - SafeNativeMethods.z_lu_inverse(order, a, work, work.Length); } /// @@ -375,12 +324,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// The LU factored N by N matrix. Contains the inverse On exit. /// The order of the square matrix . /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is equivalent to the GETRI LAPACK routine. [SecuritySafeCritical] - public override void LUInverseFactored(Complex[] a, int order, int[] ipiv, Complex[] work) + public override void LUInverseFactored(Complex[] a, int order, int[] ipiv) { if (a == null) { @@ -392,7 +338,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -402,17 +348,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } + var info = SafeNativeMethods.z_lu_inverse_factored(order, a, ipiv); - if (work.Length < order) + if (info < 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - SafeNativeMethods.z_lu_inverse_factored(order, a, ipiv, work, order); + if (info > 0) + { + throw new SingularUMatrixException(info); + } } /// @@ -431,12 +377,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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"); } @@ -446,7 +392,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.z_lu_solve(order, columnsOfB, a, b); + var info = SafeNativeMethods.z_lu_solve(order, columnsOfB, a, b); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -471,7 +427,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -481,7 +437,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -491,7 +447,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.z_lu_solve_factored(order, columnsOfB, a, ipiv, b); + var info = SafeNativeMethods.z_lu_solve_factored(order, columnsOfB, a, ipiv, b); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -514,13 +480,18 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } var info = SafeNativeMethods.z_cholesky_factor(order, a); + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + if (info > 0) { throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite); @@ -549,7 +520,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -559,7 +530,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.z_cholesky_solve(orderA, columnsB, a, b); + var info = SafeNativeMethods.z_cholesky_solve(orderA, columnsB, a, b); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -583,7 +564,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -593,51 +574,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.z_cholesky_solve_factored(orderA, columnsB, a, b); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void QRFactor(Complex[] r, int rowsR, int columnsR, Complex[] q, Complex[] tau) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } + var info = SafeNativeMethods.z_cholesky_solve_factored(orderA, columnsB, a, b); - if (r.Length != rowsR * columnsR) + if (info < 0) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (q.Length != rowsR * rowsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); - } - - var work = new Complex[columnsR * Control.BlockSize]; - SafeNativeMethods.z_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -647,16 +589,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// it is overwritten with the R matrix of the QR factorization. /// The number of rows in the A matrix. /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// A min(m,n) vector. On exit, contains additional information /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is similar to the GEQRF and ORGQR LAPACK routines. [SecuritySafeCritical] - public override void QRFactor(Complex[] r, int rowsR, int columnsR, Complex[] q, Complex[] tau, Complex[] work) + public override void QRFactor(Complex[] r, int rowsR, int columnsR, Complex[] q, Complex[] tau) { if (r == null) { @@ -668,12 +607,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -683,18 +617,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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) + var info = SafeNativeMethods.z_qr_factor(rowsR, columnsR, r, tau, q); + + if (info < 0) { - work[0] = columnsR * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.z_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -737,66 +670,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - var work = new Complex[columnsA * Control.BlockSize]; - SafeNativeMethods.z_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); - } - - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void ThinQRFactor(Complex[] q, int rowsA, int columnsA, Complex[] r, Complex[] tau, Complex[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (q.Length != rowsA * columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA * columnsA) - { - throw new ArgumentException( - string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } + var info = SafeNativeMethods.z_qr_thin_factor(rowsA, columnsA, q, tau, r); - if (work.Length < columnsA * Control.BlockSize) + if (info < 0) { - work[0] = columnsA * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.z_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); } /// @@ -812,27 +691,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// Rows must be greater or equal to columns. [SecuritySafeCritical] public override void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full) - { - var work = new Complex[columns * Control.BlockSize]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x, Complex[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -849,11 +707,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("x"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (a.Length != rows * columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); @@ -874,56 +727,40 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < 1) + var info = SafeNativeMethods.z_qr_solve(rows, columns, columnsB, a, b, x); + + if (info == (int)NativeError.MemoryAllocation) { - work[0] = rows * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new MemoryAllocationException(); } - SafeNativeMethods.z_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length); - } + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolveFactored(Complex[] q, Complex[] r, int rowsR, int columnsR, Complex[] tau, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full) - { - var work = new Complex[columnsR * Control.BlockSize]; - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); + if (info > 0) + { + throw new ArgumentException(Resources.ArgumentMatrixNotRankDeficient, "a"); + } } /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. + /// The Q matrix obtained by calling . /// The R matrix obtained by calling . /// The number of rows in the A matrix. /// The number of columns in the A matrix. /// Contains additional information on Q. Only used for the native solver /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. + /// The B matrix. /// The number of columns of B. /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. [SecuritySafeCritical] - public override void QRSolveFactored(Complex[] q, Complex[] r, int rowsA, int columnsA, Complex[] tau, Complex[] b, int columnsB, Complex[] x, Complex[] work, QRMethod method = QRMethod.Full) + public override void QRSolveFactored(Complex[] q, Complex[] r, int rowsA, int columnsA, Complex[] tau, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full) { if (r == null) { @@ -945,11 +782,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - int rowsQ, columnsQ, rowsR, columnsR; if (method == QRMethod.Full) { @@ -982,15 +814,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); } - if (work.Length < 1) - { - work[0] = rowsA * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - if (method == QRMethod.Full) { - SafeNativeMethods.z_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length); + var info = SafeNativeMethods.z_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } else { @@ -1000,61 +836,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas } } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA * rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA * columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - var work = new Complex[(2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -1081,24 +862,23 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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[(2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; 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); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -1114,12 +894,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// The work array. For real matrices, the work array should be at least - /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). - /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) + public override void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt) { if (a == null) { @@ -1141,17 +918,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("vt"); } - if (work == null) - { - 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"); } @@ -1161,18 +933,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - if (work.Length == 0) + var info = SafeNativeMethods.z_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt); + + if (info == (int) NativeError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); + throw new MemoryAllocationException(); } - if (work.Length < (2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)) + if (info < 0) { - work[0] = (2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA); - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (SafeNativeMethods.z_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt, work, work.Length) > 0) + if (info > 0) { throw new NonConvergenceException(); } @@ -1229,7 +1002,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); } - if (SafeNativeMethods.z_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD) > 0) + var info = SafeNativeMethods.z_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + + if (info > 0) { throw new NonConvergenceException(); } diff --git a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex32.cs b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex32.cs index 9f118068..44692f36 100644 --- a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex32.cs +++ b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex32.cs @@ -76,8 +76,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArrayTooSmall, rows * columns), "matrix"); } - var work = new float[rows]; - return SafeNativeMethods.c_matrix_norm((byte)norm, rows, columns, matrix, work); + return SafeNativeMethods.c_matrix_norm((byte)norm, rows, columns, matrix); } /// @@ -229,7 +228,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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); } @@ -264,7 +263,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (data.Length != order * order) + if (data.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "data"); } @@ -274,7 +273,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - SafeNativeMethods.c_lu_factor(order, data, ipiv); + var info = SafeNativeMethods.c_lu_factor(order, data, ipiv); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -291,82 +295,27 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("a"); } - 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); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(Complex32[] a, int order, int[] ipiv) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } - - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - var work = new Complex32[order]; - SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv, work, order); - } - - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(Complex32[] a, int order, Complex32[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } + var info = SafeNativeMethods.c_lu_inverse(order, a); - if (a.Length != order * order) + if (info == (int)NativeError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + throw new MemoryAllocationException(); } - if (work == null) + if (info < 0) { - throw new ArgumentNullException("work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (work.Length < order) + if (info > 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new SingularUMatrixException(info); } - - SafeNativeMethods.c_lu_inverse(order, a, work, work.Length); } /// @@ -375,12 +324,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// The LU factored N by N matrix. Contains the inverse On exit. /// The order of the square matrix . /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is equivalent to the GETRI LAPACK routine. [SecuritySafeCritical] - public override void LUInverseFactored(Complex32[] a, int order, int[] ipiv, Complex32[] work) + public override void LUInverseFactored(Complex32[] a, int order, int[] ipiv) { if (a == null) { @@ -392,7 +338,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -402,17 +348,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } + var info = SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv); - if (work.Length < order) + if (info < 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv, work, order); + if (info > 0) + { + throw new SingularUMatrixException(info); + } } /// @@ -431,12 +377,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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"); } @@ -446,7 +392,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_lu_solve(order, columnsOfB, a, b); + var info = SafeNativeMethods.c_lu_solve(order, columnsOfB, a, b); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -471,7 +427,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -481,7 +437,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -491,7 +447,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_lu_solve_factored(order, columnsOfB, a, ipiv, b); + var info = SafeNativeMethods.c_lu_solve_factored(order, columnsOfB, a, ipiv, b); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -514,13 +475,18 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } var info = SafeNativeMethods.c_cholesky_factor(order, a); + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + if (info > 0) { throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite); @@ -549,7 +515,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -559,7 +525,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_cholesky_solve(orderA, columnsB, a, b); + var info = SafeNativeMethods.c_cholesky_solve(orderA, columnsB, a, b); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -583,7 +559,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -593,51 +569,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.c_cholesky_solve_factored(orderA, columnsB, a, b); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void QRFactor(Complex32[] r, int rowsR, int columnsR, Complex32[] q, Complex32[] tau) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (r.Length != rowsR * columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); - } + var info = SafeNativeMethods.c_cholesky_solve_factored(orderA, columnsB, a, b); - if (tau.Length < Math.Min(rowsR, columnsR)) + if (info < 0) { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (q.Length != rowsR * rowsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); - } - - var work = new Complex32[columnsR * Control.BlockSize]; - SafeNativeMethods.c_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -647,16 +584,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// it is overwritten with the R matrix of the QR factorization. /// The number of rows in the A matrix. /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// A min(m,n) vector. On exit, contains additional information /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is similar to the GEQRF and ORGQR LAPACK routines. [SecuritySafeCritical] - public override void QRFactor(Complex32[] r, int rowsR, int columnsR, Complex32[] q, Complex32[] tau, Complex32[] work) + public override void QRFactor(Complex32[] r, int rowsR, int columnsR, Complex32[] q, Complex32[] tau) { if (r == null) { @@ -668,12 +602,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -683,18 +612,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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) + var info = SafeNativeMethods.c_qr_factor(rowsR, columnsR, r, tau, q); + + if (info < 0) { - work[0] = columnsR * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.c_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -737,66 +665,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - var work = new Complex32[columnsA * Control.BlockSize]; - SafeNativeMethods.c_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); - } + var info = SafeNativeMethods.c_qr_thin_factor(rowsA, columnsA, q, tau, r); - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void ThinQRFactor(Complex32[] q, int rowsA, int columnsA, Complex32[] r, Complex32[] tau, Complex32[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) + if (info < 0) { - throw new ArgumentNullException("q"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (q.Length != rowsA * columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA * columnsA) - { - throw new ArgumentException( - string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } - - if (work.Length < columnsA * Control.BlockSize) - { - work[0] = columnsA * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - - SafeNativeMethods.c_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); } /// @@ -812,27 +686,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// Rows must be greater or equal to columns. [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]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x, Complex32[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -849,11 +702,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("x"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (a.Length != rows * columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); @@ -874,56 +722,40 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < 1) + var info = SafeNativeMethods.c_qr_solve(rows, columns, columnsB, a, b, x); + + if (info == (int)NativeError.MemoryAllocation) { - work[0] = rows * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new MemoryAllocationException(); } - SafeNativeMethods.c_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length); - } + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [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]; - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); + if (info > 0) + { + throw new ArgumentException(Resources.ArgumentMatrixNotRankDeficient, "a"); + } } /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. + /// The Q matrix obtained by calling . /// The R matrix obtained by calling . /// The number of rows in the A matrix. /// The number of columns in the A matrix. /// Contains additional information on Q. Only used for the native solver /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. + /// The B matrix. /// The number of columns of B. /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. [SecuritySafeCritical] - public override void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsA, int columnsA, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x, Complex32[] work, QRMethod method = QRMethod.Full) + public override void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsA, int columnsA, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full) { if (r == null) { @@ -945,11 +777,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - int rowsQ, columnsQ, rowsR, columnsR; if (method == QRMethod.Full) { @@ -982,15 +809,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); } - if (work.Length < 1) - { - work[0] = rowsA * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - if (method == QRMethod.Full) { - SafeNativeMethods.c_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length); + var info = SafeNativeMethods.c_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } else { @@ -1000,61 +831,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas } } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA * rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA * columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - var work = new Complex32[(2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -1081,24 +857,23 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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 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); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -1114,12 +889,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// The work array. For real matrices, the work array should be at least - /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). - /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) + public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt) { if (a == null) { @@ -1141,11 +913,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("vt"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (u.Length != rowsA * rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); @@ -1161,18 +928,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - if (work.Length == 0) + var info = SafeNativeMethods.c_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt); + + if (info == (int)NativeError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); + throw new MemoryAllocationException(); } - if (work.Length < (2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)) + if (info < 0) { - work[0] = (2 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA); - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (SafeNativeMethods.c_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt, work, work.Length) > 0) + if (info > 0) { throw new NonConvergenceException(); } @@ -1226,10 +994,22 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas if (matrixD.Length != order * order) { - throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); + throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); } - if (SafeNativeMethods.c_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD) > 0) + var info = SafeNativeMethods.c_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + + if (info > 0) { throw new NonConvergenceException(); } diff --git a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Double.cs b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Double.cs index 0143e0be..637acb01 100644 --- a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Double.cs +++ b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Double.cs @@ -76,8 +76,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArrayTooSmall, rows * columns), "matrix"); } - var work = new double[rows]; - return SafeNativeMethods.d_matrix_norm((byte)norm, rows, columns, matrix, work); + return SafeNativeMethods.d_matrix_norm((byte)norm, rows, columns, matrix); } /// @@ -229,7 +228,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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); } @@ -264,7 +263,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (data.Length != order * order) + if (data.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "data"); } @@ -274,7 +273,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - SafeNativeMethods.d_lu_factor(order, data, ipiv); + var info = SafeNativeMethods.d_lu_factor(order, data, ipiv); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -291,82 +295,27 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("a"); } - 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); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(double[] a, int order, int[] ipiv) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } - - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - var work = new double[order]; - SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv, work, order); - } - - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(double[] a, int order, double[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } + var info = SafeNativeMethods.d_lu_inverse(order, a); - if (a.Length != order * order) + if (info == (int)NativeError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + throw new MemoryAllocationException(); } - if (work == null) + if (info < 0) { - throw new ArgumentNullException("work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (work.Length < order) + if (info > 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new SingularUMatrixException(info); } - - SafeNativeMethods.d_lu_inverse(order, a, work, work.Length); } /// @@ -375,12 +324,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// The LU factored N by N matrix. Contains the inverse On exit. /// The order of the square matrix . /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is equivalent to the GETRI LAPACK routine. [SecuritySafeCritical] - public override void LUInverseFactored(double[] a, int order, int[] ipiv, double[] work) + public override void LUInverseFactored(double[] a, int order, int[] ipiv) { if (a == null) { @@ -392,7 +338,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -402,17 +348,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } + var info = SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv); - if (work.Length < order) + if (info < 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - SafeNativeMethods.d_lu_inverse_factored(order, a, ipiv, work, order); + if (info > 0) + { + throw new SingularUMatrixException(info); + } } /// @@ -431,12 +377,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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"); } @@ -446,7 +392,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_lu_solve(order, columnsOfB, a, b); + var info = SafeNativeMethods.d_lu_solve(order, columnsOfB, a, b); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -471,7 +427,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -481,7 +437,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -491,7 +447,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_lu_solve_factored(order, columnsOfB, a, ipiv, b); + var info = SafeNativeMethods.d_lu_solve_factored(order, columnsOfB, a, ipiv, b); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -514,13 +475,23 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } var info = SafeNativeMethods.d_cholesky_factor(order, a); + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + if (info > 0) { throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite); @@ -549,7 +520,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -559,7 +530,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_cholesky_solve(orderA, columnsB, a, b); + var info = SafeNativeMethods.d_cholesky_solve(orderA, columnsB, a, b); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -583,7 +564,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -593,51 +574,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.d_cholesky_solve_factored(orderA, columnsB, a, b); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void QRFactor(double[] r, int rowsR, int columnsR, double[] q, double[] tau) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } + var info = SafeNativeMethods.d_cholesky_solve_factored(orderA, columnsB, a, b); - if (r.Length != rowsR * columnsR) + if (info < 0) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (q.Length != rowsR * rowsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); - } - - var work = new double[columnsR * Control.BlockSize]; - SafeNativeMethods.d_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -647,16 +589,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// it is overwritten with the R matrix of the QR factorization. /// The number of rows in the A matrix. /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// A min(m,n) vector. On exit, contains additional information /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is similar to the GEQRF and ORGQR LAPACK routines. [SecuritySafeCritical] - public override void QRFactor(double[] r, int rowsR, int columnsR, double[] q, double[] tau, double[] work) + public override void QRFactor(double[] r, int rowsR, int columnsR, double[] q, double[] tau) { if (r == null) { @@ -668,12 +607,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -683,18 +617,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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) + var info = SafeNativeMethods.d_qr_factor(rowsR, columnsR, r, tau, q); + + if (info < 0) { - work[0] = columnsR * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.d_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -722,7 +655,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("q"); } - if (q.Length != rowsA * columnsA) + if (q.Length != rowsA*columnsA) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); } @@ -732,71 +665,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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 double[columnsA * Control.BlockSize]; - SafeNativeMethods.d_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); - } - - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void ThinQRFactor(double[] q, int rowsA, int columnsA, double[] r, double[] tau, double[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (q.Length != rowsA * columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA * columnsA) - { - throw new ArgumentException( - string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } + var info = SafeNativeMethods.d_qr_thin_factor(rowsA, columnsA, q, tau, r); - if (work.Length < columnsA * Control.BlockSize) + if (info < 0) { - work[0] = columnsA * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.d_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); } /// @@ -812,27 +691,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// Rows must be greater or equal to columns. [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]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolve(double[] a, int rows, int columns, double[] b, int columnsB, double[] x, double[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -849,11 +707,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("x"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (a.Length != rows * columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); @@ -874,56 +727,40 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < 1) + var info = SafeNativeMethods.d_qr_solve(rows, columns, columnsB, a, b, x); + + if (info == (int)NativeError.MemoryAllocation) { - work[0] = rows * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new MemoryAllocationException(); } - SafeNativeMethods.d_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length); - } + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [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]; - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); + if (info > 0) + { + throw new ArgumentException(Resources.ArgumentMatrixNotRankDeficient, "a"); + } } /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. + /// The Q matrix obtained by calling . /// The R matrix obtained by calling . /// The number of rows in the A matrix. /// The number of columns in the A matrix. /// Contains additional information on Q. Only used for the native solver /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. + /// The B matrix. /// The number of columns of B. /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. [SecuritySafeCritical] - public override void QRSolveFactored(double[] q, double[] r, int rowsA, int columnsA, double[] tau, double[] b, int columnsB, double[] x, double[] work, QRMethod method = QRMethod.Full) + public override void QRSolveFactored(double[] q, double[] r, int rowsA, int columnsA, double[] tau, double[] b, int columnsB, double[] x, QRMethod method = QRMethod.Full) { if (r == null) { @@ -945,11 +782,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - int rowsQ, columnsQ, rowsR, columnsR; if (method == QRMethod.Full) { @@ -982,15 +814,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); } - if (work.Length < 1) - { - work[0] = rowsA * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - if (method == QRMethod.Full) { - SafeNativeMethods.d_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length); + var info = SafeNativeMethods.d_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } else { @@ -1000,61 +836,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas } } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA * rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA * columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - 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))]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -1081,24 +862,23 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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 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); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -1114,12 +894,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// The work array. For real matrices, the work array should be at least - /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). - /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt, double[] work) + public override void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt) { if (a == null) { @@ -1141,11 +918,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("vt"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (u.Length != rowsA * rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); @@ -1161,18 +933,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - if (work.Length == 0) + var info = SafeNativeMethods.d_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt); + + if (info == (int)NativeError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); + throw new MemoryAllocationException(); } - if (work.Length < Math.Max((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5 * Math.Min(rowsA, columnsA))) + if (info < 0) { - work[0] = Math.Max((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA), 5 * Math.Min(rowsA, columnsA)); - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (SafeNativeMethods.d_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt, work, work.Length) > 0) + if (info > 0) { throw new NonConvergenceException(); } @@ -1194,9 +967,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("matrix"); } - if (matrix.Length != order * order) + if (matrix.Length != order*order) { - throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrix"); + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrix"); } if (matrixEv == null) @@ -1204,9 +977,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("matrixEv"); } - if (matrixEv.Length != order * order) + if (matrixEv.Length != order*order) { - throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixEv"); + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixEv"); } if (vectorEv == null) @@ -1224,12 +997,24 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("matrixD"); } - if (matrixD.Length != order * order) + if (matrixD.Length != order*order) { - throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixD"); } - if (SafeNativeMethods.d_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD) > 0) + var info = SafeNativeMethods.d_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + + if (info > 0) { throw new NonConvergenceException(); } diff --git a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Single.cs b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Single.cs index 61c934c1..c228e039 100644 --- a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Single.cs +++ b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Single.cs @@ -76,8 +76,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArrayTooSmall, rows * columns), "matrix"); } - var work = new float[rows]; - return SafeNativeMethods.s_matrix_norm((byte)norm, rows, columns, matrix, work); + return SafeNativeMethods.s_matrix_norm((byte)norm, rows, columns, matrix); } /// @@ -229,7 +228,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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); } @@ -264,7 +263,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (data.Length != order * order) + if (data.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "data"); } @@ -274,7 +273,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - SafeNativeMethods.s_lu_factor(order, data, ipiv); + var info = SafeNativeMethods.s_lu_factor(order, data, ipiv); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -291,82 +295,27 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(float[] a, int order, int[] ipiv) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } + var info = SafeNativeMethods.s_lu_inverse(order, a); - if (a.Length != order * order) + if (info == (int)NativeError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); + throw new MemoryAllocationException(); } - if (ipiv.Length != order) + if (info < 0) { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); + throw new InvalidParameterException(Math.Abs(info)); } - var work = new float[order]; - SafeNativeMethods.s_lu_inverse_factored(order, a, ipiv, work, order); - } - - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(float[] a, int order, float[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (a.Length != order * order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (work.Length < order) + if (info > 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new SingularUMatrixException(info); } - - SafeNativeMethods.s_lu_inverse(order, a, work, work.Length); } /// @@ -375,12 +324,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// The LU factored N by N matrix. Contains the inverse On exit. /// The order of the square matrix . /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is equivalent to the GETRI LAPACK routine. [SecuritySafeCritical] - public override void LUInverseFactored(float[] a, int order, int[] ipiv, float[] work) + public override void LUInverseFactored(float[] a, int order, int[] ipiv) { if (a == null) { @@ -392,7 +338,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -402,17 +348,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } + var info = SafeNativeMethods.s_lu_inverse_factored(order, a, ipiv); - if (work.Length < order) + if (info < 0) { - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - SafeNativeMethods.s_lu_inverse_factored(order, a, ipiv, work, order); + if (info > 0) + { + throw new SingularUMatrixException(info); + } } /// @@ -431,12 +377,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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"); } @@ -446,7 +392,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_lu_solve(order, columnsOfB, a, b); + var info = SafeNativeMethods.s_lu_solve(order, columnsOfB, a, b); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -471,7 +427,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("ipiv"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } @@ -481,7 +437,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); } - if (b.Length != columnsOfB * order) + if (b.Length != columnsOfB*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -491,7 +447,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_lu_solve_factored(order, columnsOfB, a, ipiv, b); + var info = SafeNativeMethods.s_lu_solve_factored(order, columnsOfB, a, ipiv, b); + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -514,13 +475,18 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentMustBePositive, "order"); } - if (a.Length != order * order) + if (a.Length != order*order) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); } var info = SafeNativeMethods.s_cholesky_factor(order, a); + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + if (info > 0) { throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite); @@ -549,7 +515,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -559,7 +525,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_cholesky_solve(orderA, columnsB, a, b); + var info = SafeNativeMethods.s_cholesky_solve(orderA, columnsB, a, b); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } /// @@ -583,7 +559,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("b"); } - if (b.Length != orderA * columnsB) + if (b.Length != orderA*columnsB) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } @@ -593,51 +569,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentReferenceDifferent); } - SafeNativeMethods.s_cholesky_solve_factored(orderA, columnsB, a, b); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void QRFactor(float[] r, int rowsR, int columnsR, float[] q, float[] tau) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (r.Length != rowsR * columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); - } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } + var info = SafeNativeMethods.s_cholesky_solve_factored(orderA, columnsB, a, b); - if (q.Length != rowsR * rowsR) + if (info < 0) { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); + throw new InvalidParameterException(Math.Abs(info)); } - - var work = new float[columnsR * Control.BlockSize]; - SafeNativeMethods.s_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -647,16 +584,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// it is overwritten with the R matrix of the QR factorization. /// The number of rows in the A matrix. /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the + /// On exit, A M by M matrix that holds the Q matrix of the /// QR factorization. /// A min(m,n) vector. On exit, contains additional information /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// This is similar to the GEQRF and ORGQR LAPACK routines. [SecuritySafeCritical] - public override void QRFactor(float[] r, int rowsR, int columnsR, float[] q, float[] tau, float[] work) + public override void QRFactor(float[] r, int rowsR, int columnsR, float[] q, float[] tau) { if (r == null) { @@ -668,12 +602,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (r.Length != rowsR * columnsR) + if (r.Length != rowsR*columnsR) { throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); } @@ -683,18 +612,17 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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) + var info = SafeNativeMethods.s_qr_factor(rowsR, columnsR, r, tau, q); + + if (info < 0) { - work[0] = columnsR * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - - SafeNativeMethods.s_qr_factor(rowsR, columnsR, r, tau, q, work, work.Length); } /// @@ -737,66 +665,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); } - var work = new float[columnsA * Control.BlockSize]; - SafeNativeMethods.s_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); - } - - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - [SecuritySafeCritical] - public override void ThinQRFactor(float[] q, int rowsA, int columnsA, float[] r, float[] tau, float[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (q.Length != rowsA * columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } + var info = SafeNativeMethods.s_qr_thin_factor(rowsA, columnsA, q, tau, r); - if (r.Length != columnsA * columnsA) + if (info < 0) { - throw new ArgumentException( - string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); + throw new InvalidParameterException(Math.Abs(info)); } - - if (work.Length < columnsA * Control.BlockSize) - { - work[0] = columnsA * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - - SafeNativeMethods.s_qr_thin_factor(rowsA, columnsA, q, tau, r, work, work.Length); } /// @@ -812,27 +686,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// Rows must be greater or equal to columns. [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]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [SecuritySafeCritical] - public override void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, float[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -849,11 +702,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("x"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (a.Length != rows * columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); @@ -874,56 +722,40 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < 1) + var info = SafeNativeMethods.s_qr_solve(rows, columns, columnsB, a, b, x); + + if (info == (int)NativeError.MemoryAllocation) { - work[0] = rows * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new MemoryAllocationException(); } - SafeNativeMethods.s_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length); - } + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by calling . - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - [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]; - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method); + if (info > 0) + { + throw new ArgumentException(Resources.ArgumentMatrixNotRankDeficient, "a"); + } } /// /// Solves A*X=B for X using a previously QR factored matrix. /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. + /// The Q matrix obtained by calling . /// The R matrix obtained by calling . /// The number of rows in the A matrix. /// The number of columns in the A matrix. /// Contains additional information on Q. Only used for the native solver /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. + /// The B matrix. /// The number of columns of B. /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. [SecuritySafeCritical] - public override void QRSolveFactored(float[] q, float[] r, int rowsA, int columnsA, float[] tau, float[] b, int columnsB, float[] x, float[] work, QRMethod method = QRMethod.Full) + public override void QRSolveFactored(float[] q, float[] r, int rowsA, int columnsA, float[] tau, float[] b, int columnsB, float[] x, QRMethod method = QRMethod.Full) { if (r == null) { @@ -945,11 +777,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("q"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - int rowsQ, columnsQ, rowsR, columnsR; if (method == QRMethod.Full) { @@ -982,15 +809,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x"); } - if (work.Length < 1) - { - work[0] = rowsA * Control.BlockSize; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - if (method == QRMethod.Full) { - SafeNativeMethods.s_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length); + var info = SafeNativeMethods.s_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } } else { @@ -1000,61 +831,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas } } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA * rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA * columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - 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))]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -1081,24 +857,23 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas 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 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); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -1114,12 +889,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// The work array. For real matrices, the work array should be at least - /// Max(3*Min(M, N) + Max(M, N), 5*Min(M,N)). For complex matrices, 2*Min(M, N) + Max(M, N). - /// On exit, work[0] contains the optimal work size value. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt, float[] work) + public override void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt) { if (a == null) { @@ -1141,17 +913,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("vt"); } - if (work == null) - { - 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"); } @@ -1161,18 +928,19 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); } - if (work.Length == 0) + var info = SafeNativeMethods.s_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt); + + if (info == (int)NativeError.MemoryAllocation) { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); + throw new MemoryAllocationException(); } - if (work.Length < Math.Max(((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5 * Math.Min(rowsA, columnsA))) + if (info < 0) { - work[0] = Math.Max(((3 * Math.Min(rowsA, columnsA)) + Math.Max(rowsA, columnsA)), 5 * Math.Min(rowsA, columnsA)); - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); + throw new InvalidParameterException(Math.Abs(info)); } - if (SafeNativeMethods.s_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt, work, work.Length) > 0) + if (info > 0) { throw new NonConvergenceException(); } @@ -1194,9 +962,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("matrix"); } - if (matrix.Length != order * order) + if (matrix.Length != order*order) { - throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrix"); + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrix"); } if (matrixEv == null) @@ -1204,9 +972,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("matrixEv"); } - if (matrixEv.Length != order * order) + if (matrixEv.Length != order*order) { - throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixEv"); + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixEv"); } if (vectorEv == null) @@ -1224,12 +992,24 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas throw new ArgumentNullException("matrixD"); } - if (matrixD.Length != order * order) + if (matrixD.Length != order*order) { - throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order * order), "matrixD"); + throw new ArgumentException(String.Format(Resources.ArgumentArrayWrongLength, order*order), "matrixD"); } - if (SafeNativeMethods.s_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD) > 0) + var info = SafeNativeMethods.s_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD); + + if (info == (int)NativeError.MemoryAllocation) + { + throw new MemoryAllocationException(); + } + + if (info < 0) + { + throw new InvalidParameterException(Math.Abs(info)); + } + + if (info > 0) { throw new NonConvergenceException(); } diff --git a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs index 5e4f5f61..ba7d8876 100644 --- a/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs @@ -34,6 +34,17 @@ using System; namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas { + /// + /// Error codes return from the native OpenBLAS provider. + /// + public enum NativeError : int + { + /// + /// Unable to allocate memory. + /// + MemoryAllocation = -999999 + } + internal enum ParallelType : int { Sequential = 0, diff --git a/src/Numerics/Providers/LinearAlgebra/OpenBlas/SafeNativeMethods.cs b/src/Numerics/Providers/LinearAlgebra/OpenBlas/SafeNativeMethods.cs index fa59a5d7..fc024d90 100644 --- a/src/Numerics/Providers/LinearAlgebra/OpenBlas/SafeNativeMethods.cs +++ b/src/Numerics/Providers/LinearAlgebra/OpenBlas/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-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -117,16 +117,28 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas #region LAPACK [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern float s_matrix_norm(byte norm, int rows, int columns, [In] float[] a, [In, Out] float[] work); + internal static extern float s_matrix_norm(byte norm, int rows, int columns, [In] float[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern float d_matrix_norm(byte norm, int rows, int columns, [In] double[] a, [In, Out] double[] work); + internal static extern double d_matrix_norm(byte norm, int rows, int columns, [In] double[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern float c_matrix_norm(byte norm, int rows, int columns, [In] Complex32[] a, [In, Out] float[] work); + internal static extern float c_matrix_norm(byte norm, int rows, int columns, [In] Complex32[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern double z_matrix_norm(byte norm, int rows, int columns, [In] Complex[] a, [In, Out] double[] work); + internal static extern double z_matrix_norm(byte norm, int rows, int columns, [In] Complex[] a); + + [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] + internal static extern int s_cholesky_factor(int n, [In, Out] float[] a); + + [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] + internal static extern int d_cholesky_factor(int n, [In, Out] double[] a); + + [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] + internal static extern int c_cholesky_factor(int n, [In, Out] Complex32[] a); + + [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] + internal static extern int z_cholesky_factor(int n, [In, Out] Complex[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] internal static extern int s_lu_factor(int n, [In, Out] float[] a, [In, Out] int[] ipiv); @@ -141,28 +153,28 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas internal static extern int z_lu_factor(int n, [In, Out] Complex[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_lu_inverse(int n, [In, Out] float[] a, [In, Out] float[] work, int lwork); + internal static extern int s_lu_inverse(int n, [In, Out] float[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_lu_inverse(int n, [In, Out] double[] a, [In, Out] double[] work, int lwork); + internal static extern int d_lu_inverse(int n, [In, Out] double[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_lu_inverse(int n, [In, Out] Complex32[] a, [In, Out] Complex32[] work, int lwork); + internal static extern int c_lu_inverse(int n, [In, Out] Complex32[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_lu_inverse(int n, [In, Out] Complex[] a, [In, Out] Complex[] work, int lwork); + internal static extern int z_lu_inverse(int n, [In, Out] Complex[] a); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_lu_inverse_factored(int n, [In, Out] float[] a, [In, Out] int[] ipiv, [In, Out] float[] work, int lwork); + internal static extern int s_lu_inverse_factored(int n, [In, Out] float[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_lu_inverse_factored(int n, [In, Out] double[] a, [In, Out] int[] ipiv, [In, Out] double[] work, int lwork); + internal static extern int d_lu_inverse_factored(int n, [In, Out] double[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_lu_inverse_factored(int n, [In, Out] Complex32[] a, [In, Out] int[] ipiv, [In, Out] Complex32[] work, int lwork); + internal static extern int c_lu_inverse_factored(int n, [In, Out] Complex32[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_lu_inverse_factored(int n, [In, Out] Complex[] a, [In, Out] int[] ipiv, [In, Out] Complex[] work, int lwork); + internal static extern int z_lu_inverse_factored(int n, [In, Out] Complex[] a, [In, Out] int[] ipiv); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] internal static extern int s_lu_solve_factored(int n, int nrhs, float[] a, [In, Out] int[] ipiv, [In, Out] float[] b); @@ -188,18 +200,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] internal static extern int z_lu_solve(int n, int nrhs, Complex[] a, [In, Out] Complex[] b); - [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_cholesky_factor(int n, [In, Out] float[] a); - - [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_cholesky_factor(int n, [In, Out] double[] a); - - [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_cholesky_factor(int n, [In, Out] Complex32[] a); - - [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_cholesky_factor(int n, [In, Out] Complex[] a); - [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] internal static extern int s_cholesky_solve(int n, int nrhs, float[] a, [In, Out] float[] b); @@ -225,77 +225,77 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas internal static extern int z_cholesky_solve_factored(int n, int nrhs, Complex[] a, [In, Out] Complex[] b); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_qr_factor(int m, int n, [In, Out] float[] r, [In, Out] float[] tau, [In, Out] float[] q, [In, Out] float[] work, int len); + internal static extern int s_qr_factor(int m, int n, [In, Out] float[] r, [In, Out] float[] tau, [In, Out] float[] q); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_qr_thin_factor(int m, int n, [In, Out] float[] q, [In, Out] float[] tau, [In, Out] float[] r, [In, Out] float[] work, int len); + internal static extern int d_qr_factor(int m, int n, [In, Out] double[] r, [In, Out] double[] tau, [In, Out] double[] q); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_qr_factor(int m, int n, [In, Out] double[] r, [In, Out] double[] tau, [In, Out] double[] q, [In, Out] double[] work, int len); + internal static extern int c_qr_factor(int m, int n, [In, Out] Complex32[] r, [In, Out] Complex32[] tau, [In, Out] Complex32[] q); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_qr_thin_factor(int m, int n, [In, Out] double[] q, [In, Out] double[] tau, [In, Out] double[] r, [In, Out] double[] work, int len); + internal static extern int z_qr_factor(int m, int n, [In, Out] Complex[] r, [In, Out] Complex[] tau, [In, Out] Complex[] q); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_qr_factor(int m, int n, [In, Out] Complex32[] r, [In, Out] Complex32[] tau, [In, Out] Complex32[] q, [In, Out] Complex32[] work, int len); + internal static extern int s_qr_thin_factor(int m, int n, [In, Out] float[] q, [In, Out] float[] tau, [In, Out] float[] r); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_qr_thin_factor(int m, int n, [In, Out] Complex32[] q, [In, Out] Complex32[] tau, [In, Out] Complex32[] r, [In, Out] Complex32[] work, int len); + internal static extern int d_qr_thin_factor(int m, int n, [In, Out] double[] q, [In, Out] double[] tau, [In, Out] double[] r); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_qr_factor(int m, int n, [In, Out] Complex[] r, [In, Out] Complex[] tau, [In, Out] Complex[] q, [In, Out] Complex[] work, int len); + internal static extern int c_qr_thin_factor(int m, int n, [In, Out] Complex32[] q, [In, Out] Complex32[] tau, [In, Out] Complex32[] r); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_qr_thin_factor(int m, int n, [In, Out] Complex[] q, [In, Out] Complex[] tau, [In, Out] Complex[] r, [In, Out] Complex[] work, int len); + internal static extern int z_qr_thin_factor(int m, int n, [In, Out] Complex[] q, [In, Out] Complex[] tau, [In, Out] Complex[] r); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_qr_solve(int m, int n, int bn, float[] r, float[] b, [In, Out] float[] x, [In, Out] float[] work, int len); + internal static extern int s_qr_solve(int m, int n, int bn, float[] r, float[] b, [In, Out] float[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_qr_solve(int m, int n, int bn, double[] r, double[] b, [In, Out] double[] x, [In, Out] double[] work, int len); + internal static extern int d_qr_solve(int m, int n, int bn, double[] r, double[] b, [In, Out] double[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_qr_solve(int m, int n, int bn, Complex32[] r, Complex32[] b, [In, Out] Complex32[] x, [In, Out] Complex32[] work, int len); + internal static extern int c_qr_solve(int m, int n, int bn, Complex32[] r, Complex32[] b, [In, Out] Complex32[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_qr_solve(int m, int n, int bn, Complex[] r, Complex[] b, [In, Out] Complex[] x, [In, Out] Complex[] work, int len); + internal static extern int z_qr_solve(int m, int n, int bn, Complex[] r, Complex[] b, [In, Out] Complex[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_qr_solve_factored(int m, int n, int bn, float[] r, float[] b, float[] tau, [In, Out] float[] x, [In, Out] float[] work, int len); + internal static extern int s_qr_solve_factored(int m, int n, int bn, float[] r, float[] b, float[] tau, [In, Out] float[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_qr_solve_factored(int m, int n, int bn, double[] r, double[] b, double[] tau, [In, Out] double[] x, [In, Out] double[] work, int len); + internal static extern int d_qr_solve_factored(int m, int n, int bn, double[] r, double[] b, double[] tau, [In, Out] double[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_qr_solve_factored(int m, int n, int bn, Complex32[] r, Complex32[] b, Complex32[] tau, [In, Out] Complex32[] x, [In, Out] Complex32[] work, int len); + internal static extern int c_qr_solve_factored(int m, int n, int bn, Complex32[] r, Complex32[] b, Complex32[] tau, [In, Out] Complex32[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int z_qr_solve_factored(int m, int n, int bn, Complex[] r, Complex[] b, Complex[] tau, [In, Out] Complex[] x, [In, Out] Complex[] work, int len); + internal static extern int z_qr_solve_factored(int m, int n, int bn, Complex[] r, Complex[] b, Complex[] tau, [In, Out] Complex[] x); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_svd_factor(bool computeVectors, int m, int n, [In, Out] float[] a, [In, Out] float[] s, [In, Out] float[] u, [In, Out] float[] v, [In, Out] float[] work, int len); + internal static extern int s_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] float[] a, [In, Out] float[] s, [In, Out] float[] u, [In, Out] float[] v); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int d_svd_factor(bool computeVectors, int m, int n, [In, Out] double[] a, [In, Out] double[] s, [In, Out] double[] u, [In, Out] double[] v, [In, Out] double[] work, int len); + internal static extern int d_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] double[] a, [In, Out] double[] s, [In, Out] double[] u, [In, Out] double[] v); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int c_svd_factor(bool computeVectors, int m, int n, [In, Out] Complex32[] a, [In, Out] Complex32[] s, [In, Out] Complex32[] u, [In, Out] Complex32[] v, [In, Out] Complex32[] work, int len); + internal static extern int c_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] Complex32[] a, [In, Out] Complex32[] s, [In, Out] Complex32[] u, [In, Out] Complex32[] v); [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); + internal static extern int z_svd_factor([MarshalAs(UnmanagedType.U1)] bool computeVectors, int m, int n, [In, Out] Complex[] a, [In, Out] Complex[] s, [In, Out] Complex[] u, [In, Out] Complex[] v); [DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)] - internal static extern int s_eigen(bool isSymmetric, int n, [In, Out] float[] a, [In, Out] float[] vectors, [In, Out] Complex[] values, [In, Out] float[] d); + internal static extern int s_eigen([MarshalAs(UnmanagedType.U1)] 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, Out] double[] a, [In, Out] double[] vectors, [In, Out] Complex[] values, [In, Out] double[] d); + internal static extern int d_eigen([MarshalAs(UnmanagedType.U1)] 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, Out] Complex32[] a, [In, Out] Complex32[] vectors, [In, Out] Complex[] values, [In, Out] Complex32[] d); + internal static extern int c_eigen([MarshalAs(UnmanagedType.U1)] 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, Out] Complex[] a, [In, Out] Complex[] vectors, [In, Out] Complex[] values, [In, Out] Complex[] d); - + internal static extern int z_eigen([MarshalAs(UnmanagedType.U1)] bool isSymmetric, int n, [In] Complex[] a, [In, Out] Complex[] vectors, [In, Out] Complex[] values, [In, Out] Complex[] d); + #endregion LAPACK } } From 484cb758e85a41e63702b1ca87180be30fdb99e3 Mon Sep 17 00:00:00 2001 From: Marcus Cuda Date: Wed, 22 Jul 2015 12:48:36 +0300 Subject: [PATCH 3/4] tweaked headers --- src/NativeProviders/Common/lapack_common.h | 79 +++++++++++----------- src/NativeProviders/MKL/lapack.h | 12 ++-- src/NativeProviders/OpenBLAS/lapack.h | 2 + 3 files changed, 46 insertions(+), 47 deletions(-) diff --git a/src/NativeProviders/Common/lapack_common.h b/src/NativeProviders/Common/lapack_common.h index 5441d599..e3c596b7 100644 --- a/src/NativeProviders/Common/lapack_common.h +++ b/src/NativeProviders/Common/lapack_common.h @@ -1,63 +1,62 @@ -#ifndef LAPACK_COMMON_H -#define LAPACK_COMMON_H +#pragma once -#include +const int INSUFFICIENT_MEMORY = -999999; + +#ifndef LAPACK_MEMORY +#define LAPACK_MEMORY +#include + +template using array_ptr = std::unique_ptr; -void shift_ipiv_down(int m, int ipiv[]); -inline void shift_ipiv_down(int m, int ipiv[]){ - for(int i = 0; i < m; ++i ){ +template +inline array_ptr array_new(const int size) +{ + return array_ptr(new T[size]); +} + +#endif + +template +inline array_ptr array_clone(const int size, const T* array) +{ + auto clone = array_new(size); + memcpy(clone.get(), array, size * sizeof(T)); + return clone; +} + +inline void shift_ipiv_down(int m, int ipiv[]) +{ + for(auto i = 0; i < m; ++i ) + { ipiv[i] -= 1; } } -void shift_ipiv_up(int m, int ipiv[]); -inline void shift_ipiv_up(int m, int ipiv[]){ - for(int i = 0; i < m; ++i ){ +inline void shift_ipiv_up(int m, int ipiv[]) +{ + for(auto i = 0; i < m; ++i ) + { ipiv[i] += 1; } } template -inline T* Clone(const int m, const int n, const T* a){ - T* clone = new T[m*n]; +inline T* Clone(const int m, const int n, const T* a) +{ + auto clone = new T[m*n]; memcpy(clone, a, m*n*sizeof(T)); return clone; } template -inline void copyBtoX (int m, int n, int bn, T b[], T x[]){ - for (int i = 0; i < n; ++i) +inline void copyBtoX (int m, int n, int bn, T b[], T x[]) +{ + for (auto i = 0; i < n; ++i) { - for (int j = 0; j < bn; ++j) + for (auto j = 0; j < bn; ++j) { x[j * n + i] = b[j * m + i]; } } } -#ifndef LAPACK_MEMORY -#define LAPACK_MEMORY - -#include - -const int INSUFFICIENT_MEMORY = -999999; -const int ALIGNMENT = 64; - -template using array_ptr = std::unique_ptr; - -template -inline array_ptr array_new(const int size, int alignment = ALIGNMENT) -{ - return array_ptr(new T[size]); -} - -#endif - -template -inline array_ptr array_clone(const int size, const T* array) { - auto clone = array_new(size); - memcpy(clone.get(), array, size * sizeof(T)); - return clone; -} - -#endif \ No newline at end of file diff --git a/src/NativeProviders/MKL/lapack.h b/src/NativeProviders/MKL/lapack.h index b57ca9ee..bf9e9c45 100644 --- a/src/NativeProviders/MKL/lapack.h +++ b/src/NativeProviders/MKL/lapack.h @@ -1,15 +1,14 @@ #pragma once #include +#include + #define MKL_Complex8 std::complex #define MKL_Complex16 std::complex +#define LAPACK_MEMORY #include "mkl.h" -#define LAPACK_MEMORY -#include - -const int INSUFFICIENT_MEMORY = -999999; const int ALIGNMENT = 64; struct array_free @@ -20,9 +19,9 @@ struct array_free template using array_ptr = std::unique_ptr; template -inline array_ptr array_new(const int size, int alignment = ALIGNMENT) +inline array_ptr array_new(const int size) { - auto ret = static_cast(mkl_malloc(size * sizeof(T), alignment)); + auto ret = static_cast(mkl_malloc(size * sizeof(T), ALIGNMENT)); if (!ret) { @@ -31,4 +30,3 @@ inline array_ptr array_new(const int size, int alignment = ALIGNMENT) return array_ptr(ret); } - diff --git a/src/NativeProviders/OpenBLAS/lapack.h b/src/NativeProviders/OpenBLAS/lapack.h index 30d40bbe..3c9fe4b5 100644 --- a/src/NativeProviders/OpenBLAS/lapack.h +++ b/src/NativeProviders/OpenBLAS/lapack.h @@ -7,3 +7,5 @@ #include "cblas.h" #include "lapacke.h" + + From e1e2bb294e47f71ef59df99a55e510c9e6b4a9c5 Mon Sep 17 00:00:00 2001 From: Marcus Cuda Date: Sat, 25 Jul 2015 12:16:46 +0300 Subject: [PATCH 4/4] removed work arrays from the LA provider interface --- MathNet.Numerics.NativeProviders.sln | 44 ++ .../Cuda/CudaLinearAlgebraProvider.Complex.cs | 136 +--- .../CudaLinearAlgebraProvider.Complex32.cs | 137 +--- .../Cuda/CudaLinearAlgebraProvider.Double.cs | 135 +--- .../Cuda/CudaLinearAlgebraProvider.Single.cs | 137 +--- .../LinearAlgebra/ILinearAlgebraProvider.cs | 112 +--- .../ManagedLinearAlgebraProvider.Complex.cs | 291 +-------- .../ManagedLinearAlgebraProvider.Complex32.cs | 293 +-------- .../ManagedLinearAlgebraProvider.Double.cs | 298 +-------- .../ManagedLinearAlgebraProvider.Single.cs | 291 +-------- .../Complex/LinearAlgebraProviderTests.cs | 602 +----------------- .../Complex32/LinearAlgebraProviderTests.cs | 558 +--------------- .../Double/LinearAlgebraProviderTests.cs | 558 +--------------- .../Single/LinearAlgebraProviderTests.cs | 558 +--------------- src/UnitTests/UnitTests-CUDA.csproj | 4 + src/UnitTests/UnitTests-MKL.csproj | 15 +- src/UnitTests/UnitTests-OpenBLAS.csproj | 4 + 17 files changed, 102 insertions(+), 4071 deletions(-) diff --git a/MathNet.Numerics.NativeProviders.sln b/MathNet.Numerics.NativeProviders.sln index 4e790037..21805ccb 100644 --- a/MathNet.Numerics.NativeProviders.sln +++ b/MathNet.Numerics.NativeProviders.sln @@ -26,6 +26,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenBLAS", "src\NativeProvi EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests-OpenBLAS", "src\UnitTests\UnitTests-OpenBLAS.csproj", "{96B903EF-3EE1-4569-803C-0482D2F5ED37}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestData", "src\TestData\TestData.csproj", "{AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -344,6 +346,48 @@ Global {96B903EF-3EE1-4569-803C-0482D2F5ED37}.Release-Signed|Mixed Platforms.Build.0 = Release|Any CPU {96B903EF-3EE1-4569-803C-0482D2F5ED37}.Release-Signed|Win32.ActiveCfg = Release|Any CPU {96B903EF-3EE1-4569-803C-0482D2F5ED37}.Release-Signed|x64.ActiveCfg = Release|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Debug|Win32.ActiveCfg = Debug|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Debug|x64.ActiveCfg = Debug|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release|Any CPU.Build.0 = Release|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release|Win32.ActiveCfg = Release|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release|x64.ActiveCfg = Release|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-CUDA|Any CPU.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-CUDA|Any CPU.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-CUDA|Mixed Platforms.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-CUDA|Mixed Platforms.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-CUDA|Win32.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-CUDA|Win32.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-CUDA|x64.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-CUDA|x64.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-MKL|Any CPU.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-MKL|Any CPU.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-MKL|Mixed Platforms.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-MKL|Mixed Platforms.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-MKL|Win32.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-MKL|Win32.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-MKL|x64.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-MKL|x64.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-OpenBLAS|Any CPU.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-OpenBLAS|Any CPU.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-OpenBLAS|Mixed Platforms.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-OpenBLAS|Mixed Platforms.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-OpenBLAS|Win32.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-OpenBLAS|Win32.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-OpenBLAS|x64.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-OpenBLAS|x64.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-Signed|Any CPU.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-Signed|Any CPU.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-Signed|Mixed Platforms.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-Signed|Mixed Platforms.Build.0 = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-Signed|Win32.ActiveCfg = Release-Signed|Any CPU + {AF3253C9-4DB5-45A0-98CF-C105FDA9DA47}.Release-Signed|x64.ActiveCfg = Release-Signed|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex.cs b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex.cs index 31abfbc5..ac729107 100644 --- a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex.cs +++ b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -33,7 +33,6 @@ using System; using System.Numerics; using System.Security; -using MathNet.Numerics.LinearAlgebra.Factorization; using MathNet.Numerics.Properties; namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda @@ -295,73 +294,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda BLAS(SafeNativeMethods.z_lu_inverse_factored(_blasHandle, order, a, ipiv)); } - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// Not supported. Should be left null. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(Complex[] a, int order, Complex[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - - Solver(SafeNativeMethods.z_lu_inverse(_solverHandle, _blasHandle, order, a)); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// Not supported. Should be left null. - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(Complex[] a, int order, int[] ipiv, Complex[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - - BLAS(SafeNativeMethods.z_lu_inverse_factored(_blasHandle, order, a, ipiv)); - } - /// /// Solves A*X=B for X using LU factorization. /// @@ -538,60 +470,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda Solver(SafeNativeMethods.z_cholesky_solve_factored(_solverHandle, orderA, columnsB, a, b)); } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, null); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -634,7 +512,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda var clone = new Complex[a.Length]; a.Copy(clone); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, null); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -650,10 +528,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// User work buffers are not supported. Should be null. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) + public override void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt) { if (a == null) { @@ -675,11 +552,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda throw new ArgumentNullException("vt"); } - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); @@ -696,7 +568,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda } if (columnsA > rowsA || !computeVectors) // see remarks http://docs.nvidia.com/cuda/cusolver/index.html#cuds-lt-t-gt-gesvd - base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, new Complex[rowsA]); + base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt); else Solver(SafeNativeMethods.z_svd_factor(_solverHandle, computeVectors, rowsA, columnsA, a, s, u, vt)); } } diff --git a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex32.cs b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex32.cs index 81679c15..01b8c46e 100644 --- a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex32.cs +++ b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex32.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -31,9 +31,7 @@ #if NATIVE using System; -using System.Numerics; using System.Security; -using MathNet.Numerics.LinearAlgebra.Factorization; using MathNet.Numerics.Properties; namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda @@ -295,73 +293,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda BLAS(SafeNativeMethods.c_lu_inverse_factored(_blasHandle, order, a, ipiv)); } - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// Not supported. Should be left null. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(Complex32[] a, int order, Complex32[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - - Solver(SafeNativeMethods.c_lu_inverse(_solverHandle, _blasHandle, order, a)); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// Not supported. Should be left null. - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(Complex32[] a, int order, int[] ipiv, Complex32[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - - BLAS(SafeNativeMethods.c_lu_inverse_factored(_blasHandle, order, a, ipiv)); - } - /// /// Solves A*X=B for X using LU factorization. /// @@ -538,60 +469,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda Solver(SafeNativeMethods.c_cholesky_solve_factored(_solverHandle, orderA, columnsB, a, b)); } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, null); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -634,7 +511,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda var clone = new Complex32[a.Length]; a.Copy(clone); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, null); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -650,10 +527,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// Not supported. Should be left null. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) + public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt) { if (a == null) { @@ -675,11 +551,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda throw new ArgumentNullException("vt"); } - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); @@ -696,7 +567,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda } if (columnsA > rowsA || !computeVectors) // see remarks http://docs.nvidia.com/cuda/cusolver/index.html#cuds-lt-t-gt-gesvd - base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, new Complex32[rowsA]); + base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt); else Solver(SafeNativeMethods.c_svd_factor(_solverHandle, computeVectors, rowsA, columnsA, a, s, u, vt)); } } diff --git a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Double.cs b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Double.cs index 6e73ed46..0f462589 100644 --- a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Double.cs +++ b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Double.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -31,9 +31,7 @@ #if NATIVE using System; -using System.Numerics; using System.Security; -using MathNet.Numerics.LinearAlgebra.Factorization; using MathNet.Numerics.Properties; namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda @@ -295,73 +293,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda BLAS(SafeNativeMethods.d_lu_inverse_factored(_blasHandle, order, a, ipiv)); } - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// Not supported. Should be left null. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(double[] a, int order, double[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - - Solver(SafeNativeMethods.d_lu_inverse(_solverHandle, _blasHandle, order, a)); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// Not supported. Should be left null. - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(double[] a, int order, int[] ipiv, double[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - - BLAS(SafeNativeMethods.d_lu_inverse_factored(_blasHandle, order, a, ipiv)); - } - /// /// Solves A*X=B for X using LU factorization. /// @@ -538,60 +469,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda Solver(SafeNativeMethods.d_cholesky_solve_factored(_solverHandle, orderA, columnsB, a, b)); } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, null); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -650,10 +527,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// Not supported. Should be left null. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt, double[] work) + public override void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt) { if (a == null) { @@ -675,11 +551,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda throw new ArgumentNullException("vt"); } - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); @@ -696,7 +567,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda } if (columnsA > rowsA || !computeVectors) // see remarks http://docs.nvidia.com/cuda/cusolver/index.html#cuds-lt-t-gt-gesvd - base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, new double[rowsA]); + base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt); else Solver (SafeNativeMethods.d_svd_factor(_solverHandle, computeVectors, rowsA, columnsA, a, s, u, vt)); } } diff --git a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Single.cs b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Single.cs index 0ac4e34f..c68dc1c5 100644 --- a/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Single.cs +++ b/src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Single.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -31,9 +31,7 @@ #if NATIVE using System; -using System.Numerics; using System.Security; -using MathNet.Numerics.LinearAlgebra.Factorization; using MathNet.Numerics.Properties; namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda @@ -295,73 +293,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda BLAS(SafeNativeMethods.s_lu_inverse_factored(_blasHandle, order, a, ipiv)); } - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// Not supported. Should be left null. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - [SecuritySafeCritical] - public override void LUInverse(float[] a, int order, float[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - - Solver(SafeNativeMethods.s_lu_inverse(_solverHandle, _blasHandle, order, a)); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// Not supported. This should be left null. - /// This is equivalent to the GETRI LAPACK routine. - [SecuritySafeCritical] - public override void LUInverseFactored(float[] a, int order, int[] ipiv, float[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (ipiv == null) - { - throw new ArgumentNullException("ipiv"); - } - - if (a.Length != order*order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); - } - - if (ipiv.Length != order) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "ipiv"); - } - - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - - BLAS(SafeNativeMethods.s_lu_inverse_factored(_blasHandle, order, a, ipiv)); - } - /// /// Solves A*X=B for X using LU factorization. /// @@ -538,60 +469,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda Solver(SafeNativeMethods.s_cholesky_solve_factored(_solverHandle, orderA, columnsB, a, b)); } - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// This is equivalent to the GESVD LAPACK routine. - [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, null); - } - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -634,7 +511,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda var clone = new float[a.Length]; a.Copy(clone); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, null); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } @@ -650,10 +527,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda /// singular vectors. /// If is true, on exit VT contains the transposed /// right singular vectors. - /// Not supported. Should be left null. /// This is equivalent to the GESVD LAPACK routine. [SecuritySafeCritical] - public override void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt, float[] work) + public override void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt) { if (a == null) { @@ -675,11 +551,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda throw new ArgumentNullException("vt"); } - if (work != null) - { - throw new ArgumentException(Resources.UserWorkBufferNotSupported); - } - if (u.Length != rowsA*rowsA) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); @@ -696,7 +567,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda } if (columnsA > rowsA || !computeVectors) // see remarks http://docs.nvidia.com/cuda/cusolver/index.html#cuds-lt-t-gt-gesvd - base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, new float[rowsA]); + base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt); else Solver(SafeNativeMethods.s_svd_factor(_solverHandle, computeVectors, rowsA, columnsA, a, s, u, vt)); } } diff --git a/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs b/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs index 4b49da14..176ba9a3 100644 --- a/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs +++ b/src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs @@ -269,29 +269,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// This is equivalent to the GETRI LAPACK routine. void LUInverseFactored(T[] a, int order, int[] ipiv); - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - void LUInverse(T[] a, int order, T[] work); - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRI LAPACK routine. - void LUInverseFactored(T[] a, int order, int[] ipiv, T[] work); - /// /// Solves A*X=B for X using LU factorization. /// @@ -356,23 +333,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// This is similar to the GEQRF and ORGQR LAPACK routines. void QRFactor(T[] a, int rowsA, int columnsA, T[] q, T[] tau); - /// - /// Computes the full QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - void QRFactor(T[] a, int rowsA, int columnsA, T[] q, T[] tau, T[] work); - /// /// Computes the thin QR factorization of A where M > N. /// @@ -387,23 +347,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// This is similar to the GEQRF and ORGQR LAPACK routines. void ThinQRFactor(T[] a, int rowsA, int columnsA, T[] r, T[] tau); - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - void ThinQRFactor(T[] a, int rowsA, int columnsA, T[] r, T[] tau, T[] work); - /// /// Solves A*X=B for X using QR factorization of A. /// @@ -417,22 +360,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// Rows must be greater or equal to columns. void QRSolve(T[] a, int rows, int columns, T[] b, int columnsB, T[] x, QRMethod method = QRMethod.Full); - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On entry the B matrix; on exit the X matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - void QRSolve(T[] a, int rows, int columns, T[] b, int columnsB, T[] x, T[] work, QRMethod method = QRMethod.Full); - /// /// Solves A*X=B for X using a previously QR factored matrix. /// @@ -450,26 +377,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// The type of QR factorization to perform. void QRSolveFactored(T[] q, T[] r, int rowsA, int columnsA, T[] tau, T[] b, int columnsB, T[] x, QRMethod method = QRMethod.Full); - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// Rows must be greater or equal to columns. - /// The type of QR factorization to perform. - void QRSolveFactored(T[] q, T[] r, int rowsA, int columnsA, T[] tau, T[] b, int columnsB, T[] x, T[] work, QRMethod method = QRMethod.Full); - /// /// Computes the singular value decomposition of A. /// @@ -485,23 +392,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// This is equivalent to the GESVD LAPACK routine. void SingularValueDecomposition(bool computeVectors, T[] a, int rowsA, int columnsA, T[] s, T[] u, T[] vt); - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// The work array. On exit, work[0] contains the optimal work size value. - /// - /// This is equivalent to the GESVD LAPACK routine. - void SingularValueDecomposition(bool computeVectors, T[] a, int rowsA, int columnsA, T[] s, T[] u, T[] vt, T[] work); - /// /// Solves A*X=B for X using the singular value decomposition of A. /// @@ -520,7 +410,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// The number of columns in the A matrix. /// The s values returned by . /// The left singular vectors returned by . - /// The right singular vectors returned by . + /// The right singular vectors returned by . /// The B matrix /// The number of columns of B. /// On exit, the solution matrix. diff --git a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs index ce777bf1..a6a1fe37 100644 --- a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs +++ b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -1058,35 +1058,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra inverse.Copy(a); } - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - public virtual void LUInverse(Complex[] a, int order, Complex[] work) - { - LUInverse(a, order); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRI LAPACK routine. - public virtual void LUInverseFactored(Complex[] a, int order, int[] ipiv, Complex[] work) - { - LUInverseFactored(a, order, ipiv); - } - /// /// Solves A*X=B for X using LU factorization. /// @@ -1469,72 +1440,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = columnsR > rowsR ? new Complex[rowsR*rowsR] : new Complex[rowsR*columnsR]; - QRFactor(r, rowsR, columnsR, q, tau, work); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - public virtual void QRFactor(Complex[] r, int rowsR, int columnsR, Complex[] q, Complex[] tau, Complex[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); - } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (q.Length != rowsR*rowsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); - } - - if (columnsR > rowsR) - { - if (work.Length < rowsR*rowsR) - { - work[0] = rowsR*rowsR; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - } - else - { - if (work.Length < rowsR*columnsR) - { - work[0] = rowsR*columnsR; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - } CommonParallel.For(0, rowsR, (a, b) => { @@ -1555,8 +1460,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { ComputeQR(work, i, q, i, rowsR, i, rowsR, Control.MaxDegreeOfParallelism); } - - work[0] = columnsR > rowsR ? rowsR*rowsR : rowsR*columnsR; } /// @@ -1599,61 +1502,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = new Complex[rowsA*columnsA]; - ThinQRFactor(a, rowsA, columnsA, r, tau, work); - } - - /// - /// Computes the QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - public virtual void ThinQRFactor(Complex[] a, int rowsA, int columnsA, Complex[] r, Complex[] tau, Complex[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (a.Length != rowsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "a"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } - - if (work.Length < rowsA*columnsA) - { - work[0] = rowsA*columnsA; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } var minmn = Math.Min(rowsA, columnsA); for (var i = 0; i < minmn; i++) @@ -1684,8 +1532,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { ComputeQR(work, i, a, i, rowsA, i, columnsA, Control.MaxDegreeOfParallelism); } - - work[0] = rowsA*columnsA; } @@ -1815,26 +1661,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// The type of QR factorization to perform. /// 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]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - public virtual void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x, Complex[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -1851,10 +1677,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentNullException("x"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } + if (a.Length != rows*columns) { @@ -1876,11 +1699,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentException(Resources.ArgumentArraysSameLength, "x"); } - if (work.Length < rows*columns) - { - work[0] = rows*columns; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } + var work = new Complex[rows * columns]; var clone = new Complex[a.Length]; a.Copy(clone); @@ -1897,31 +1716,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra ThinQRFactor(clone, rows, columns, r, work); QRSolveFactored(clone, r, rows, columns, null, b, columnsB, x, method); } - - work[0] = rows*columns; - } - - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - public virtual void QRSolveFactored(Complex[] q, Complex[] r, int rowsR, int columnsR, Complex[] tau, Complex[] b, int columnsB, Complex[] x, Complex[] work, QRMethod method = QRMethod.Full) - { - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, method); } /// @@ -2102,77 +1896,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = new Complex[rowsA]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// The work array. Length should be at least . - /// This is equivalent to the GESVD LAPACK routine. - /// - public virtual void SingularValueDecomposition(bool computeVectors, Complex[] a, int rowsA, int columnsA, Complex[] s, Complex[] u, Complex[] vt, Complex[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - if (work.Length == 0) - { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); - } - - if (work.Length < rowsA) - { - work[0] = rowsA; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - + const int maxiter = 1000; var e = new Complex[columnsA]; @@ -2784,10 +2508,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra // a singular vector of length rows+1 when rows < columns. The last element is not used and needs to be removed. // We should port lapack's svd routine to remove this problem. Array.Copy(stemp, s, Math.Min(rowsA, columnsA)); - - // 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; } /// @@ -2826,14 +2546,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra 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 clone = new Complex[a.Length]; a.Copy(clone); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } diff --git a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs index fcb6a9e3..d68b9142 100644 --- a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs +++ b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -1055,35 +1055,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra inverse.Copy(a); } - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - public virtual void LUInverse(Complex32[] a, int order, Complex32[] work) - { - LUInverse(a, order); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRI LAPACK routine. - public virtual void LUInverseFactored(Complex32[] a, int order, int[] ipiv, Complex32[] work) - { - LUInverseFactored(a, order, ipiv); - } - /// /// Solves A*X=B for X using LU factorization. /// @@ -1466,72 +1437,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = columnsR > rowsR ? new Complex32[rowsR*rowsR] : new Complex32[rowsR*columnsR]; - QRFactor(r, rowsR, columnsR, q, tau, work); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - public virtual void QRFactor(Complex32[] r, int rowsR, int columnsR, Complex32[] q, Complex32[] tau, Complex32[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); - } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (q.Length != rowsR*rowsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); - } - - if (columnsR > rowsR) - { - if (work.Length < rowsR*rowsR) - { - work[0] = rowsR*rowsR; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - } - else - { - if (work.Length < rowsR*columnsR) - { - work[0] = rowsR*columnsR; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - } CommonParallel.For(0, rowsR, (a, b) => { @@ -1552,8 +1457,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { ComputeQR(work, i, q, i, rowsR, i, rowsR, Control.MaxDegreeOfParallelism); } - - work[0] = columnsR > rowsR ? rowsR*rowsR : rowsR*columnsR; } /// @@ -1596,62 +1499,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = new Complex32[rowsA*columnsA]; - ThinQRFactor(a, rowsA, columnsA, r, tau, work); - } - - /// - /// Computes the QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - public virtual void ThinQRFactor(Complex32[] a, int rowsA, int columnsA, Complex32[] r, Complex32[] tau, Complex32[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (a.Length != rowsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "a"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } - - if (work.Length < rowsA*columnsA) - { - work[0] = rowsA*columnsA; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - + var minmn = Math.Min(rowsA, columnsA); for (var i = 0; i < minmn; i++) { @@ -1681,8 +1529,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { ComputeQR(work, i, a, i, rowsA, i, columnsA, Control.MaxDegreeOfParallelism); } - - work[0] = rowsA*columnsA; } @@ -1812,26 +1658,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. public virtual void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full) - { - var work = new Complex32[rows*columns]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - public virtual void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x, Complex32[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -1848,11 +1674,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentNullException("x"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (a.Length != rows*columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); @@ -1873,11 +1694,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < rows*columns) - { - work[0] = rows*columns; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } + var work = new Complex32[rows * columns]; var clone = new Complex32[a.Length]; a.Copy(clone); @@ -1894,31 +1711,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra ThinQRFactor(clone, rows, columns, r, work); QRSolveFactored(clone, r, rows, columns, null, b, columnsB, x, method); } - - work[0] = rows*columns; - } - - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - public virtual void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsR, int columnsR, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x, Complex32[] work, QRMethod method = QRMethod.Full) - { - QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, method); } /// @@ -2099,77 +1891,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = new Complex32[rowsA]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// The work array. Length should be at least . - /// This is equivalent to the GESVD LAPACK routine. - /// - public virtual void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt, Complex32[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - if (work.Length == 0) - { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); - } - - if (work.Length < rowsA) - { - work[0] = rowsA; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - + const int maxiter = 1000; var e = new Complex32[columnsA]; @@ -2781,10 +2503,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra // a singular vector of length rows+1 when rows < columns. The last element is not used and needs to be removed. // We should port lapack's svd routine to remove this problem. Array.Copy(stemp, s, Math.Min(rowsA, columnsA)); - - // 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; } /// @@ -2823,14 +2541,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - var work = new Complex32[rowsA]; var s = new Complex32[Math.Min(rowsA, columnsA)]; var u = new Complex32[rowsA*rowsA]; var vt = new Complex32[columnsA*columnsA]; var clone = new Complex32[a.Length]; a.Copy(clone); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } diff --git a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs index c2adea46..d3462126 100644 --- a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs +++ b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -941,35 +941,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra inverse.Copy(a); } - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - public virtual void LUInverse(double[] a, int order, double[] work) - { - LUInverse(a, order); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRI LAPACK routine. - public virtual void LUInverseFactored(double[] a, int order, int[] ipiv, double[] work) - { - LUInverseFactored(a, order, ipiv); - } - /// /// Solves A*X=B for X using LU factorization. /// @@ -1351,83 +1322,15 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); } - - var work = columnsR > rowsR ? new double[rowsR*rowsR] : new double[rowsR*columnsR]; - QRFactor(r, rowsR, columnsR, q, tau, work); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - public virtual void QRFactor(double[] r, int rowsR, int columnsR, double[] q, double[] tau, double[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); - } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (q.Length != rowsR*rowsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); - } - - if (columnsR > rowsR) - { - if (work.Length < rowsR*rowsR) - { - work[0] = rowsR*rowsR; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - } - else - { - if (work.Length < rowsR*columnsR) - { - work[0] = rowsR*columnsR; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - } - CommonParallel.For(0, rowsR, (a, b) => { - for (int i = a; i < b; i++) + for (var i = a; i < b; i++) { q[(i*rowsR) + i] = 1.0; } }); + var work = columnsR > rowsR ? new double[rowsR * rowsR] : new double[rowsR * columnsR]; var minmn = Math.Min(rowsR, columnsR); for (var i = 0; i < minmn; i++) { @@ -1439,8 +1342,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { ComputeQR(work, i, q, i, rowsR, i, rowsR, Control.MaxDegreeOfParallelism); } - - work[0] = columnsR > rowsR ? rowsR*rowsR : rowsR*columnsR; } /// @@ -1483,62 +1384,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = new double[rowsA*columnsA]; - ThinQRFactor(a, rowsA, columnsA, r, tau, work); - } - - /// - /// Computes the thin QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - public virtual void ThinQRFactor(double[] a, int rowsA, int columnsA, double[] r, double[] tau, double[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (a.Length != rowsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "a"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } - - if (work.Length < rowsA*columnsA) - { - work[0] = rowsA*columnsA; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - + var minmn = Math.Min(rowsA, columnsA); for (var i = 0; i < minmn; i++) { @@ -1568,8 +1414,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { ComputeQR(work, i, a, i, rowsA, i, columnsA, Control.MaxDegreeOfParallelism); } - - work[0] = rowsA*columnsA; } #region QR Factor Helper functions @@ -1699,26 +1543,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. public virtual void QRSolve(double[] a, int rows, int columns, double[] b, int columnsB, double[] x, QRMethod method = QRMethod.Full) - { - var work = new double[rows*columns]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } - - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - public virtual void QRSolve(double[] a, int rows, int columns, double[] b, int columnsB, double[] x, double[] work, QRMethod method = QRMethod.Full) { if (a == null) { @@ -1735,11 +1559,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentNullException("x"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (a.Length != rows*columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); @@ -1760,11 +1579,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < rows*columns) - { - work[0] = rows*columns; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } + var work = new double[rows * columns]; var clone = new double[a.Length]; a.Copy(clone); @@ -1781,31 +1596,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra ThinQRFactor(clone, rows, columns, r, work); QRSolveFactored(clone, r, rows, columns, null, b, columnsB, x, method); } - - work[0] = rows*columns; - } - - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - public virtual void QRSolveFactored(double[] q, double[] r, int rowsA, int columnsA, double[] tau, double[] b, int columnsB, double[] x, double[] work, QRMethod method = QRMethod.Full) - { - QRSolveFactored(q, r, rowsA, columnsA, tau, b, columnsB, x, method); } /// @@ -1986,76 +1776,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = new double[rowsA]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// The work array. Length should be at least . - /// This is equivalent to the GESVD LAPACK routine. - /// - public virtual void SingularValueDecomposition(bool computeVectors, double[] a, int rowsA, int columnsA, double[] s, double[] u, double[] vt, double[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - if (work.Length == 0) - { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); - } - - if (work.Length < rowsA) - { - work[0] = rowsA; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } const int maxiter = 1000; @@ -2672,10 +2392,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra // a singular vector of length rows+1 when rows < columns. The last element is not used and needs to be removed. // We should port lapack's svd routine to remove this problem. Buffer.BlockCopy(stemp, 0, s, 0, Math.Min(rowsA, columnsA)*Constants.SizeOfDouble); - - // 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; } /// @@ -2770,15 +2486,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - - var work = new double[rowsA]; var s = new double[Math.Min(rowsA, columnsA)]; var u = new double[rowsA*rowsA]; var vt = new double[columnsA*columnsA]; var clone = new double[a.Length]; Buffer.BlockCopy(a, 0, clone, 0, a.Length*Constants.SizeOfDouble); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } diff --git a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs index 7ed95c45..05f7989c 100644 --- a/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs +++ b/src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -941,35 +941,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra inverse.Copy(a); } - /// - /// Computes the inverse of matrix using LU factorization. - /// - /// The N by N matrix to invert. Contains the inverse On exit. - /// The order of the square matrix . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRF and GETRI LAPACK routines. - public virtual void LUInverse(float[] a, int order, float[] work) - { - LUInverse(a, order); - } - - /// - /// Computes the inverse of a previously factored matrix. - /// - /// The LU factored N by N matrix. Contains the inverse On exit. - /// The order of the square matrix . - /// The pivot indices of . - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is equivalent to the GETRI LAPACK routine. - public virtual void LUInverseFactored(float[] a, int order, int[] ipiv, float[] work) - { - LUInverseFactored(a, order, ipiv); - } - /// /// Solves A*X=B for X using LU factorization. /// @@ -1352,72 +1323,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = columnsR > rowsR ? new float[rowsR*rowsR] : new float[rowsR*columnsR]; - QRFactor(r, rowsR, columnsR, q, tau, work); - } - - /// - /// Computes the QR factorization of A. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the R matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A M by M matrix that holds the Q matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - public virtual void QRFactor(float[] r, int rowsR, int columnsR, float[] q, float[] tau, float[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (q == null) - { - throw new ArgumentNullException("q"); - } - - if (work == null) - { - throw new ArgumentNullException("q"); - } - - if (r.Length != rowsR*columnsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "r"); - } - - if (tau.Length < Math.Min(rowsR, columnsR)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (q.Length != rowsR*rowsR) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q"); - } - - if (columnsR > rowsR) - { - if (work.Length < rowsR*rowsR) - { - work[0] = rowsR*rowsR; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - } - else - { - if (work.Length < rowsR*columnsR) - { - work[0] = rowsR*columnsR; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - } CommonParallel.For(0, rowsR, (a, b) => { @@ -1438,8 +1343,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { ComputeQR(work, i, q, i, rowsR, i, rowsR, Control.MaxDegreeOfParallelism); } - - work[0] = columnsR > rowsR ? rowsR*rowsR : rowsR*columnsR; } /// @@ -1482,61 +1385,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = new float[rowsA*columnsA]; - ThinQRFactor(a, rowsA, columnsA, r, tau, work); - } - - /// - /// Computes the QR factorization of A where M > N. - /// - /// On entry, it is the M by N A matrix to factor. On exit, - /// it is overwritten with the Q matrix of the QR factorization. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// On exit, A N by N matrix that holds the R matrix of the - /// QR factorization. - /// A min(m,n) vector. On exit, contains additional information - /// to be used by the QR solve routine. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// This is similar to the GEQRF and ORGQR LAPACK routines. - public virtual void ThinQRFactor(float[] a, int rowsA, int columnsA, float[] r, float[] tau, float[] work) - { - if (r == null) - { - throw new ArgumentNullException("r"); - } - - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (a.Length != rowsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "a"); - } - - if (tau.Length < Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau"); - } - - if (r.Length != columnsA*columnsA) - { - throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r"); - } - - if (work.Length < rowsA*columnsA) - { - work[0] = rowsA*columnsA; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } var minmn = Math.Min(rowsA, columnsA); for (var i = 0; i < minmn; i++) @@ -1567,8 +1415,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra { ComputeQR(work, i, a, i, rowsA, i, columnsA, Control.MaxDegreeOfParallelism); } - - work[0] = rowsA*columnsA; } @@ -1687,22 +1533,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra #endregion - /// - /// Solves A*X=B for X using QR factorization of A. - /// - /// The A matrix. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The B matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - public virtual void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, QRMethod method = QRMethod.Full) - { - var work = new float[rows*columns]; - QRSolve(a, rows, columns, b, columnsB, x, work, method); - } /// /// Solves A*X=B for X using QR factorization of A. @@ -1713,12 +1543,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra /// The B matrix. /// The number of columns of B. /// On exit, the solution matrix. - /// The work array. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. /// The type of QR factorization to perform. /// Rows must be greater or equal to columns. - public virtual void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, float[] work, QRMethod method = QRMethod.Full) + public virtual void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, QRMethod method = QRMethod.Full) { if (a == null) { @@ -1735,11 +1562,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentNullException("x"); } - if (work == null) - { - throw new ArgumentNullException("work"); - } - if (a.Length != rows*columns) { throw new ArgumentException(Resources.ArgumentArraysSameLength, "a"); @@ -1760,11 +1582,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentException(Resources.RowsLessThanColumns); } - if (work.Length < rows*columns) - { - work[0] = rows*columns; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } + var work = new float[rows * columns]; var clone = new float[a.Length]; a.Copy(clone); @@ -1781,31 +1599,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra ThinQRFactor(clone, rows, columns, r, work); QRSolveFactored(clone, r, rows, columns, null, b, columnsB, x, method); } - - work[0] = rows*columns; - } - - /// - /// Solves A*X=B for X using a previously QR factored matrix. - /// - /// The Q matrix obtained by QR factor. This is only used for the managed provider and can be - /// null for the native provider. The native provider uses the Q portion stored in the R matrix. - /// The R matrix obtained by calling . - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// Contains additional information on Q. Only used for the native solver - /// and can be null for the managed provider. - /// On entry the B matrix; on exit the X matrix. - /// The number of columns of B. - /// On exit, the solution matrix. - /// The work array - only used in the native provider. The array must have a length of at least N, - /// but should be N*blocksize. The blocksize is machine dependent. On exit, work[0] contains the optimal - /// work size value. - /// The type of QR factorization to perform. - /// Rows must be greater or equal to columns. - public virtual void QRSolveFactored(float[] q, float[] r, int rowsA, int columnsA, float[] tau, float[] b, int columnsB, float[] x, float[] work, QRMethod method = QRMethod.Full) - { - QRSolveFactored(q, r, rowsA, columnsA, tau, b, columnsB, x, method); } /// @@ -1986,76 +1779,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra } var work = new float[rowsA]; - SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt, work); - } - - /// - /// Computes the singular value decomposition of A. - /// - /// Compute the singular U and VT vectors or not. - /// On entry, the M by N matrix to decompose. On exit, A may be overwritten. - /// The number of rows in the A matrix. - /// The number of columns in the A matrix. - /// The singular values of A in ascending value. - /// If is true, on exit U contains the left - /// singular vectors. - /// If is true, on exit VT contains the transposed - /// right singular vectors. - /// The work array. Length should be at least . - /// - public virtual void SingularValueDecomposition(bool computeVectors, float[] a, int rowsA, int columnsA, float[] s, float[] u, float[] vt, float[] work) - { - if (a == null) - { - throw new ArgumentNullException("a"); - } - - if (s == null) - { - throw new ArgumentNullException("s"); - } - - if (u == null) - { - throw new ArgumentNullException("u"); - } - - if (vt == null) - { - throw new ArgumentNullException("vt"); - } - - if (work == null) - { - throw new ArgumentNullException("work"); - } - - if (u.Length != rowsA*rowsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "u"); - } - - if (vt.Length != columnsA*columnsA) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "vt"); - } - - if (s.Length != Math.Min(rowsA, columnsA)) - { - throw new ArgumentException(Resources.ArgumentArraysSameLength, "s"); - } - - if (work.Length == 0) - { - throw new ArgumentException(Resources.ArgumentSingleDimensionArray, "work"); - } - - if (work.Length < rowsA) - { - work[0] = rowsA; - throw new ArgumentException(Resources.WorkArrayTooSmall, "work"); - } - + const int maxiter = 1000; var e = new float[columnsA]; @@ -2673,10 +2397,6 @@ namespace MathNet.Numerics.Providers.LinearAlgebra // a singular vector of length rows+1 when rows < columns. The last element is not used and needs to be removed. // We should port lapack's svd routine to remove this problem. Buffer.BlockCopy(stemp, 0, s, 0, Math.Min(rowsA, columnsA)*Constants.SizeOfFloat); - - // 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; } /// @@ -2772,14 +2492,13 @@ namespace MathNet.Numerics.Providers.LinearAlgebra throw new ArgumentException(Resources.ArgumentArraysSameLength, "b"); } - var work = new float[rowsA]; var s = new float[Math.Min(rowsA, columnsA)]; var u = new float[rowsA*rowsA]; var vt = new float[columnsA*columnsA]; var clone = new float[a.Length]; Buffer.BlockCopy(a, 0, clone, 0, a.Length*Constants.SizeOfFloat); - SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt, work); + SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt); SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x); } diff --git a/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs index 3998ae08..bc60a10e 100644 --- a/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs +++ b/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -433,72 +433,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13); } -#if ! MKL - /// - /// Can compute the inverse of a matrix using LU factorization - /// with a work array. - /// - [Test] - public void CanComputeLuInverseWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - -#if CUDA - Complex[] work = null; -#else - var work = new Complex[matrix.RowCount]; -#endif - Control.LinearAlgebraProvider.LUInverse(a, matrix.RowCount, work); - - AssertHelpers.AlmostEqualRelative(a[0], -0.454545454545454, 13); - AssertHelpers.AlmostEqualRelative(a[1], -0.909090909090908, 13); - AssertHelpers.AlmostEqualRelative(a[2], 0.454545454545454, 13); - AssertHelpers.AlmostEqualRelative(a[3], -0.340909090909090, 13); - AssertHelpers.AlmostEqualRelative(a[4], -2.045454545454543, 13); - AssertHelpers.AlmostEqualRelative(a[5], 1.477272727272726, 13); - AssertHelpers.AlmostEqualRelative(a[6], -0.113636363636364, 13); - AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727, 13); - AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13); - } -#endif - -#if ! MKL - /// - /// Can compute the inverse of a matrix using LU factorization - /// using a previously factored matrix with a work array. - /// - [Test] - public void CanComputeLuInverseOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - - var ipiv = new int[matrix.RowCount]; - - Control.LinearAlgebraProvider.LUFactor(a, matrix.RowCount, ipiv); - -#if CUDA - Complex[] work = null; -#else - var work = new Complex[matrix.RowCount]; -#endif - Control.LinearAlgebraProvider.LUInverseFactored(a, matrix.RowCount, ipiv, work); - - AssertHelpers.AlmostEqualRelative(a[0], -0.454545454545454, 13); - AssertHelpers.AlmostEqualRelative(a[1], -0.909090909090908, 13); - AssertHelpers.AlmostEqualRelative(a[2], 0.454545454545454, 13); - AssertHelpers.AlmostEqualRelative(a[3], -0.340909090909090, 13); - AssertHelpers.AlmostEqualRelative(a[4], -2.045454545454543, 13); - AssertHelpers.AlmostEqualRelative(a[5], 1.477272727272726, 13); - AssertHelpers.AlmostEqualRelative(a[6], -0.113636363636364, 13); - AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727, 13); - AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13); - } -#endif - /// /// Can solve Ax=b using LU factorization. /// @@ -696,92 +630,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex } } -#if ! MKL - /// - /// Can compute QR factorization of a square matrix using a work array. - /// - [Test] - public void CanComputeQRFactorSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var r = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new Complex[3]; - var q = new Complex[matrix.RowCount*matrix.RowCount]; - var work = new Complex[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q); - var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } - - /// - /// Can compute QR factorization of a tall matrix using a work matrix. - /// - [Test] - public void CanComputeQRFactorTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var r = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new Complex[3]; - var q = new Complex[matrix.RowCount*matrix.RowCount]; - var work = new Complex[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } - - /// - /// Can compute QR factorization of a wide matrix using a work matrix. - /// - [Test] - public void CanComputeQRFactorWideMatrixWithWorkArray() - { - var matrix = _matrices["Wide2x3"]; - var r = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new Complex[3]; - var q = new Complex[matrix.RowCount*matrix.RowCount]; - var work = new Complex[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } -#endif - /// /// Can compute thin QR factorization of a square matrix. /// @@ -836,63 +684,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex } } -#if ! MKL - /// - /// Can compute thin QR factorization of a square matrix using a work array. - /// - [Test] - public void CanComputeThinQRFactorSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var r = new Complex[matrix.ColumnCount*matrix.ColumnCount]; - var tau = new Complex[3]; - var q = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, q, q.Length); - - var work = new Complex[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var mq = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, q); - var mr = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, r); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } - - /// - /// Can compute thin QR factorization of a tall matrix using a work matrix. - /// - [Test] - public void CanComputeThinQRFactorTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var r = new Complex[matrix.ColumnCount*matrix.ColumnCount]; - var tau = new Complex[3]; - var q = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, q, q.Length); - - var work = new Complex[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var mq = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, q); - var mr = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, r); - var a = mq*mr; - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } -#endif - /// /// Can solve Ax=b using QR factorization with a square A matrix. /// @@ -944,94 +735,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } - -#if ! MKL - /// - /// Can solve Ax=b using QR factorization with a square A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingQRSquareMatrixUsingWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new Complex[matrix.ColumnCount*2]; - var work = new Complex[matrix.RowCount*matrix.RowCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work); - - NotModified(3, 3, a, matrix); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); - } - - /// - /// Can solve Ax=b using QR factorization with a tall A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingQRTallMatrixUsingWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new Complex[matrix.ColumnCount*2]; - var work = new Complex[matrix.RowCount*matrix.RowCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work); - - NotModified(3, 2, a, matrix); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); - } - - /// - /// Can solve Ax=b using QR factorization with a square A matrix - /// using a factored A matrix. - /// - [Test] - public void CanSolveUsingQRSquareMatrixOnFactoredMatrix() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new Complex[matrix.ColumnCount]; - var q = new Complex[matrix.ColumnCount*matrix.ColumnCount]; - Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau); - - var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new Complex[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); - } -#endif /// /// Can solve Ax=b using QR factorization with a tall A matrix /// using a factored A matrix. @@ -1060,68 +763,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } -#if ! MKL - /// - /// Can solve Ax=b using QR factorization with a square A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingQRSquareMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new Complex[matrix.ColumnCount]; - var q = new Complex[matrix.ColumnCount*matrix.ColumnCount]; - var work = new Complex[2048]; - Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new Complex[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); - } - - /// - /// Can solve Ax=b using QR factorization with a tall A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingQRTallMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new Complex[matrix.ColumnCount]; - var q = new Complex[matrix.RowCount*matrix.RowCount]; - var work = new Complex[2048]; - Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new Complex[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); - } -#endif - /// /// Can solve Ax=b using thin QR factorization with a square A matrix. /// @@ -1174,64 +815,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } -#if ! MKL - /// - /// Can solve Ax=b using thin QR factorization with a square A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingThinQRSquareMatrixUsingWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new Complex[matrix.ColumnCount*2]; - var work = new Complex[matrix.RowCount*matrix.ColumnCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work, QRMethod.Thin); - - NotModified(3, 3, a, matrix); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); - } - - /// - /// Can solve Ax=b using thin QR factorization with a tall A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingThinQRTallMatrixUsingWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new Complex[matrix.ColumnCount*2]; - var work = new Complex[matrix.RowCount*matrix.ColumnCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work, QRMethod.Thin); - - NotModified(3, 2, a, matrix); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); - } -#endif - /// /// Can solve Ax=b using thin QR factorization with a square A matrix /// using a factored A matrix. @@ -1290,66 +873,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } - /// - /// Can solve Ax=b using thin QR factorization with a square A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingThinQRSquareMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new Complex[matrix.ColumnCount]; - var r = new Complex[matrix.ColumnCount*matrix.ColumnCount]; - var work = new Complex[2048]; - Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new Complex[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work, QRMethod.Thin); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); - } - - /// - /// Can solve Ax=b using thin QR factorization with a tall A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingThinQRTallMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new Complex[matrix.ColumnCount]; - var r = new Complex[matrix.ColumnCount*matrix.ColumnCount]; - var work = new Complex[2048]; - Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var b = new[] {new Complex(1.0, 0), 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new Complex[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work, QRMethod.Thin); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); - } - /// /// Can compute the SVD factorization of a square matrix. /// @@ -1455,129 +978,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 14); } - /// - /// Can compute the SVD factorization of a square matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new Complex[matrix.RowCount]; - var u = new Complex[matrix.RowCount*matrix.RowCount]; - var vt = new Complex[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - Complex[] work = null; -#else - var work = new Complex[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u); - var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 13); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 13); - AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 13); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 13); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 13); - AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 13); - AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 13); - AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 13); - AssertHelpers.AlmostEqualRelative(matrix[2, 2], result[2, 2], 13); - } - - /// - /// Can compute the SVD factorization of a tall matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new Complex[matrix.ColumnCount]; - var u = new Complex[matrix.RowCount*matrix.RowCount]; - var vt = new Complex[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - Complex[] work = null; -#else - var work = new Complex[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u); - var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 14); - } - - /// - /// Can compute the SVD factorization of a wide matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfWideMatrixWithWorkArray() - { - var matrix = _matrices["Wide2x3"]; - var a = new Complex[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new Complex[matrix.RowCount]; - var u = new Complex[matrix.RowCount*matrix.RowCount]; - var vt = new Complex[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - Complex[] work = null; -#else - var work = new Complex[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u); - var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 14); - } - /// /// Can solve Ax=b using SVD factorization with a square A matrix. /// diff --git a/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs index d0b8a4e3..1b597d22 100644 --- a/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs +++ b/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -437,68 +437,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32 AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364f, 5); } - /// - /// Can compute the inverse of a matrix using LU factorization - /// with a work array. - /// - [Test] - public void CanComputeLuInverseWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex32[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - -#if CUDA - Complex32[] work = null; -#else - var work = new Complex32[matrix.RowCount]; -#endif - Control.LinearAlgebraProvider.LUInverse(a, matrix.RowCount, work); - - AssertHelpers.AlmostEqualRelative(a[0], -0.454545454545454f, 5); - AssertHelpers.AlmostEqualRelative(a[1], -0.909090909090908f, 5); - AssertHelpers.AlmostEqualRelative(a[2], 0.454545454545454f, 5); - AssertHelpers.AlmostEqualRelative(a[3], -0.340909090909090f, 5); - AssertHelpers.AlmostEqualRelative(a[4], -2.045454545454543f, 5); - AssertHelpers.AlmostEqualRelative(a[5], 1.477272727272726f, 5); - AssertHelpers.AlmostEqualRelative(a[6], -0.113636363636364f, 5); - AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727f, 5); - AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364f, 5); - } - - /// - /// Can compute the inverse of a matrix using LU factorization - /// using a previously factored matrix with a work array. - /// - [Test] - public void CanComputeLuInverseOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex32[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - - var ipiv = new int[matrix.RowCount]; - - Control.LinearAlgebraProvider.LUFactor(a, matrix.RowCount, ipiv); - -#if CUDA - Complex32[] work = null; -#else - var work = new Complex32[matrix.RowCount]; -#endif - Control.LinearAlgebraProvider.LUInverseFactored(a, matrix.RowCount, ipiv, work); - - AssertHelpers.AlmostEqualRelative(a[0], -0.454545454545454f, 5); - AssertHelpers.AlmostEqualRelative(a[1], -0.909090909090908f, 5); - AssertHelpers.AlmostEqualRelative(a[2], 0.454545454545454f, 5); - AssertHelpers.AlmostEqualRelative(a[3], -0.340909090909090f, 5); - AssertHelpers.AlmostEqualRelative(a[4], -2.045454545454543f, 5); - AssertHelpers.AlmostEqualRelative(a[5], 1.477272727272726f, 5); - AssertHelpers.AlmostEqualRelative(a[6], -0.113636363636364f, 5); - AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727f, 5); - AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364f, 5); - } - /// /// Can solve Ax=b using LU factorization. /// @@ -696,90 +634,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32 } } - /// - /// Can compute QR factorization of a square matrix using a work array. - /// - [Test] - public void CanComputeQRFactorSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var r = new Complex32[matrix.RowCount*matrix.ColumnCount]; - var tau = new Complex32[3]; - var q = new Complex32[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, r, r.Length); - - var work = new Complex32[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q); - var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - - /// - /// Can compute QR factorization of a tall matrix using a work matrix. - /// - [Test] - public void CanComputeQRFactorTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var r = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new Complex32[3]; - var q = new Complex32[matrix.RowCount*matrix.RowCount]; - var work = new Complex32[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - - /// - /// Can compute QR factorization of a wide matrix using a work matrix. - /// - [Test] - public void CanComputeQRFactorWideMatrixWithWorkArray() - { - var matrix = _matrices["Wide2x3"]; - var r = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new Complex32[3]; - var q = new Complex32[matrix.RowCount*matrix.RowCount]; - var work = new Complex32[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - /// /// Can compute thin QR factorization of a square matrix. /// @@ -834,61 +688,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32 } } - /// - /// Can compute thin QR factorization of a square matrix using a work array. - /// - [Test] - public void CanComputeThinQRFactorSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var r = new Complex32[matrix.ColumnCount*matrix.ColumnCount]; - var tau = new Complex32[3]; - var q = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, q, q.Length); - - var work = new Complex32[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var mq = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, q); - var mr = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, r); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - - /// - /// Can compute thin QR factorization of a tall matrix using a work matrix. - /// - [Test] - public void CanComputeThinQRFactorTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var r = new Complex32[matrix.ColumnCount*matrix.ColumnCount]; - var tau = new Complex32[3]; - var q = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, q, q.Length); - - var work = new Complex32[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var mq = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, q); - var mr = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, r); - var a = mq*mr; - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - /// /// Can solve Ax=b using QR factorization with a square A matrix. /// @@ -941,62 +740,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32 AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); } - /// - /// Can solve Ax=b using QR factorization with a square A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingQRSquareMatrixUsingWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {new Complex32(1.0f, 0.0f), 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new Complex32[matrix.ColumnCount*2]; - var work = new Complex32[matrix.RowCount*matrix.RowCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work); - - NotModified(3, 3, a, matrix); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 5); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 5); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 4); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 4); - } - - /// - /// Can solve Ax=b using QR factorization with a tall A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingQRTallMatrixUsingWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {new Complex32(1.0f, 0.0f), 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new Complex32[matrix.ColumnCount*2]; - var work = new Complex32[matrix.RowCount*matrix.RowCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work); - - NotModified(3, 2, a, matrix); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 5); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 5); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 5); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); - } - /// /// Can solve Ax=b using QR factorization with a square A matrix /// using a factored A matrix. @@ -1055,66 +798,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32 AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); } - /// - /// Can solve Ax=b using QR factorization with a square A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingQRSquareMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex32[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new Complex32[matrix.ColumnCount]; - var q = new Complex32[matrix.ColumnCount*matrix.ColumnCount]; - var work = new Complex32[2048]; - Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var b = new[] {new Complex32(1.0f, 0.0f), 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new Complex32[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 5); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 5); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 4); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 4); - } - - /// - /// Can solve Ax=b using QR factorization with a tall A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingQRTallMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new Complex32[matrix.ColumnCount]; - var q = new Complex32[matrix.RowCount*matrix.RowCount]; - var work = new Complex32[2048]; - Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var b = new[] {new Complex32(1.0f, 0.0f), 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new Complex32[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 5); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 5); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 5); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); - } - /// /// Can solve Ax=b using thin QR factorization with a square A matrix. /// @@ -1167,62 +850,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32 AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); } - /// - /// Can solve Ax=b using thin QR factorization with a square A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingThinQRSquareMatrixUsingWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {new Complex32(1.0f, 0.0f), 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new Complex32[matrix.ColumnCount*2]; - var work = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work, QRMethod.Thin); - - NotModified(3, 3, a, matrix); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 5); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 5); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 4); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 4); - } - - /// - /// Can solve Ax=b using thin QR factorization with a tall A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingThinQRTallMatrixUsingWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {new Complex32(1.0f, 0.0f), 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new Complex32[matrix.ColumnCount*2]; - var work = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work, QRMethod.Thin); - - NotModified(3, 2, a, matrix); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 5); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 5); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 5); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); - } - /// /// Can solve Ax=b using thin QR factorization with a square A matrix /// using a factored A matrix. @@ -1281,66 +908,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32 AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); } - /// - /// Can solve Ax=b using thin QR factorization with a square A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingThinQRSquareMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new Complex32[matrix.ColumnCount]; - var r = new Complex32[matrix.ColumnCount*matrix.ColumnCount]; - var work = new Complex32[2048]; - Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var b = new[] {new Complex32(1.0f, 0.0f), 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new Complex32[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work, QRMethod.Thin); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 5); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 5); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 4); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 4); - } - - /// - /// Can solve Ax=b using thin QR factorization with a tall A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingThinQRTallMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new Complex32[matrix.ColumnCount]; - var r = new Complex32[matrix.ColumnCount*matrix.ColumnCount]; - var work = new Complex32[2048]; - Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var b = new[] {new Complex32(1.0f, 0.0f), 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new Complex32[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work, QRMethod.Thin); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 5); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 5); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 5); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); - } - /// /// Can compute the SVD factorization of a square matrix. /// @@ -1446,129 +1013,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32 AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 4); } - /// - /// Can compute the SVD factorization of a square matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new Complex32[matrix.RowCount]; - var u = new Complex32[matrix.RowCount*matrix.RowCount]; - var vt = new Complex32[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - Complex32[] work = null; -#else - var work = new Complex32[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u); - var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 2], result[2, 2], 5); - } - - /// - /// Can compute the SVD factorization of a tall matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new Complex32[matrix.ColumnCount]; - var u = new Complex32[matrix.RowCount*matrix.RowCount]; - var vt = new Complex32[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - Complex32[] work = null; -#else - var work = new Complex32[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u); - var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 4); - } - - /// - /// Can compute the SVD factorization of a wide matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfWideMatrixWithWorkArray() - { - var matrix = _matrices["Wide2x3"]; - var a = new Complex32[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new Complex32[matrix.RowCount]; - var u = new Complex32[matrix.RowCount*matrix.RowCount]; - var vt = new Complex32[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - Complex32[] work = null; -#else - var work = new Complex32[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u); - var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 4); - } - /// /// Can solve Ax=b using SVD factorization with a square A matrix. /// diff --git a/src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs index 6546bc55..a232431f 100644 --- a/src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs +++ b/src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -427,68 +427,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13); } - /// - /// Can compute the inverse of a matrix using LU factorization - /// with a work array. - /// - [Test] - public void CanComputeLuInverseWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new double[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - -#if CUDA - double[] work = null; -#else - var work = new double[matrix.RowCount]; -#endif - Control.LinearAlgebraProvider.LUInverse(a, matrix.RowCount, work); - - AssertHelpers.AlmostEqualRelative(a[0], -0.454545454545454, 13); - AssertHelpers.AlmostEqualRelative(a[1], -0.909090909090908, 13); - AssertHelpers.AlmostEqualRelative(a[2], 0.454545454545454, 13); - AssertHelpers.AlmostEqualRelative(a[3], -0.340909090909090, 13); - AssertHelpers.AlmostEqualRelative(a[4], -2.045454545454543, 13); - AssertHelpers.AlmostEqualRelative(a[5], 1.477272727272726, 13); - AssertHelpers.AlmostEqualRelative(a[6], -0.113636363636364, 13); - AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727, 13); - AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13); - } - - /// - /// Can compute the inverse of a matrix using LU factorization - /// using a previously factored matrix with a work array. - /// - [Test] - public void CanComputeLuInverseOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new double[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - - var ipiv = new int[matrix.RowCount]; - - Control.LinearAlgebraProvider.LUFactor(a, matrix.RowCount, ipiv); - -#if CUDA - double[] work = null; -#else - var work = new double[matrix.RowCount]; -#endif - Control.LinearAlgebraProvider.LUInverseFactored(a, matrix.RowCount, ipiv, work); - - AssertHelpers.AlmostEqualRelative(a[0], -0.454545454545454, 13); - AssertHelpers.AlmostEqualRelative(a[1], -0.909090909090908, 13); - AssertHelpers.AlmostEqualRelative(a[2], 0.454545454545454, 13); - AssertHelpers.AlmostEqualRelative(a[3], -0.340909090909090, 13); - AssertHelpers.AlmostEqualRelative(a[4], -2.045454545454543, 13); - AssertHelpers.AlmostEqualRelative(a[5], 1.477272727272726, 13); - AssertHelpers.AlmostEqualRelative(a[6], -0.113636363636364, 13); - AssertHelpers.AlmostEqualRelative(a[7], 0.227272727272727, 13); - AssertHelpers.AlmostEqualRelative(a[8], -0.113636363636364, 13); - } - /// /// Can solve Ax=b using LU factorization. /// @@ -686,90 +624,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double } } - /// - /// Can compute QR factorization of a square matrix using a work array. - /// - [Test] - public void CanComputeQRFactorSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var r = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new double[3]; - var q = new double[matrix.RowCount*matrix.RowCount]; - var work = new double[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mq = Matrix.Build.Dense(matrix.RowCount, matrix.RowCount, q); - var mr = Matrix.Build.Dense(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } - - /// - /// Can compute QR factorization of a tall matrix using a work matrix. - /// - [Test] - public void CanComputeQRFactorTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var r = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new double[3]; - var q = new double[matrix.RowCount*matrix.RowCount]; - var work = new double[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mr = Matrix.Build.Dense(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var mq = Matrix.Build.Dense(matrix.RowCount, matrix.RowCount, q); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } - - /// - /// Can compute QR factorization of a wide matrix using a work matrix. - /// - [Test] - public void CanComputeQRFactorWideMatrixWithWorkArray() - { - var matrix = _matrices["Wide2x3"]; - var r = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new double[3]; - var q = new double[matrix.RowCount*matrix.RowCount]; - var work = new double[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mr = Matrix.Build.Dense(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var mq = Matrix.Build.Dense(matrix.RowCount, matrix.RowCount, q); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } - /// /// Can compute thin QR factorization of a square matrix. /// @@ -824,61 +678,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double } } - /// - /// Can compute thin QR factorization of a square matrix using a work array. - /// - [Test] - public void CanComputeThinQRFactorSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var r = new double[matrix.ColumnCount*matrix.ColumnCount]; - var tau = new double[3]; - var q = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, q, q.Length); - - var work = new double[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var mq = Matrix.Build.Dense(matrix.RowCount, matrix.ColumnCount, q); - var mr = Matrix.Build.Dense(matrix.ColumnCount, matrix.ColumnCount, r); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } - - /// - /// Can compute thin QR factorization of a tall matrix using a work matrix. - /// - [Test] - public void CanComputeThinQRFactorTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var r = new double[matrix.ColumnCount*matrix.ColumnCount]; - var tau = new double[3]; - var q = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, q, q.Length); - - var work = new double[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var mq = Matrix.Build.Dense(matrix.RowCount, matrix.ColumnCount, q); - var mr = Matrix.Build.Dense(matrix.ColumnCount, matrix.ColumnCount, r); - var a = mq*mr; - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 14); - } - } - } - /// /// Can solve Ax=b using QR factorization with a square A matrix. /// @@ -931,62 +730,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } - /// - /// Can solve Ax=b using QR factorization with a square A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingQRSquareMatrixUsingWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new double[matrix.ColumnCount*2]; - var work = new double[matrix.RowCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work); - - NotModified(3, 3, a, matrix); - - var mx = Matrix.Build.Dense(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); - } - - /// - /// Can solve Ax=b using QR factorization with a tall A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingQRTallMatrixUsingWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new double[matrix.ColumnCount*2]; - var work = new double[matrix.RowCount*matrix.RowCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work); - - NotModified(3, 2, a, matrix); - - var mb = Matrix.Build.Dense(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); - } - /// /// Can solve Ax=b using QR factorization with a square A matrix /// using a factored A matrix. @@ -1045,66 +788,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } - /// - /// Can solve Ax=b using QR factorization with a square A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingQRSquareMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new double[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new double[matrix.ColumnCount]; - var q = new double[matrix.ColumnCount*matrix.ColumnCount]; - var work = new double[2048]; - Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var b = new[] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new double[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work); - - var mx = Matrix.Build.Dense(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); - } - - /// - /// Can solve Ax=b using QR factorization with a tall A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingQRTallMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new double[matrix.ColumnCount]; - var q = new double[matrix.RowCount*matrix.RowCount]; - var work = new double[2048]; - Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var b = new[] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new double[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work); - - var mb = Matrix.Build.Dense(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); - } - /// /// Can solve Ax=b using thin QR factorization with a square A matrix. /// @@ -1157,62 +840,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } - /// - /// Can solve Ax=b using thin QR factorization with a square A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingThinQRSquareMatrixUsingWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new double[matrix.ColumnCount*2]; - var work = new double[matrix.RowCount*matrix.ColumnCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work, QRMethod.Thin); - - NotModified(3, 3, a, matrix); - - var mx = Matrix.Build.Dense(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); - } - - /// - /// Can solve Ax=b using thin QR factorization with a tall A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingThinQRTallMatrixUsingWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new double[matrix.ColumnCount*2]; - var work = new double[matrix.RowCount*matrix.ColumnCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work, QRMethod.Thin); - - NotModified(3, 2, a, matrix); - - var mb = Matrix.Build.Dense(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); - } - /// /// Can solve Ax=b using thin QR factorization with a square A matrix /// using a factored A matrix. @@ -1271,66 +898,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); } - /// - /// Can solve Ax=b using thin QR factorization with a square A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingThinQRSquareMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new double[matrix.ColumnCount]; - var r = new double[matrix.ColumnCount*matrix.ColumnCount]; - var work = new double[2048]; - Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var b = new[] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new double[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work, QRMethod.Thin); - - var mx = Matrix.Build.Dense(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 13); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 13); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 13); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 13); - } - - /// - /// Can solve Ax=b using thin QR factorization with a tall A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingThinQRTallMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new double[matrix.ColumnCount]; - var r = new double[matrix.ColumnCount*matrix.ColumnCount]; - var work = new double[2048]; - Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var b = new[] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; - var x = new double[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work, QRMethod.Thin); - - var mb = Matrix.Build.Dense(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 13); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 13); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 13); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 13); - } - /// /// Can compute the SVD factorization of a square matrix. /// @@ -1436,129 +1003,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 14); } - /// - /// Can compute the SVD factorization of a square matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new double[matrix.RowCount]; - var u = new double[matrix.RowCount*matrix.RowCount]; - var vt = new double[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - double[] work = null; -#else - var work = new double[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = Matrix.Build.Dense(matrix.RowCount, matrix.RowCount, u); - var mV = Matrix.Build.Dense(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 14); - AssertHelpers.AlmostEqualRelative(matrix[2, 2], result[2, 2], 14); - } - - /// - /// Can compute the SVD factorization of a tall matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new double[matrix.ColumnCount]; - var u = new double[matrix.RowCount*matrix.RowCount]; - var vt = new double[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - double[] work = null; -#else - var work = new double[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = Matrix.Build.Dense(matrix.RowCount, matrix.RowCount, u); - var mV = Matrix.Build.Dense(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 14); - } - - /// - /// Can compute the SVD factorization of a wide matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfWideMatrixWithWorkArray() - { - var matrix = _matrices["Wide2x3"]; - var a = new double[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new double[matrix.RowCount]; - var u = new double[matrix.RowCount*matrix.RowCount]; - var vt = new double[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - double[] work = null; -#else - var work = new double[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = Matrix.Build.Dense(matrix.RowCount, matrix.RowCount, u); - var mV = Matrix.Build.Dense(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 14); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 14); - AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 14); - AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 14); - } - /// /// Can solve Ax=b using SVD factorization with a square A matrix. /// diff --git a/src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs index fab970db..a64a6973 100644 --- a/src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs +++ b/src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2013 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -435,68 +435,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single AssertHelpers.AlmostEqual(a[8], -0.113636363636364, 5); } - /// - /// Can compute the inverse of a matrix using LU factorization - /// with a work array. - /// - [Test] - public void CanComputeLuInverseWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new float[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - -#if CUDA - float[] work = null; -#else - var work = new float[matrix.RowCount]; -#endif - Control.LinearAlgebraProvider.LUInverse(a, matrix.RowCount, work); - - AssertHelpers.AlmostEqual(a[0], -0.454545454545454, 5); - AssertHelpers.AlmostEqual(a[1], -0.909090909090908, 5); - AssertHelpers.AlmostEqual(a[2], 0.454545454545454, 5); - AssertHelpers.AlmostEqual(a[3], -0.340909090909090, 5); - AssertHelpers.AlmostEqual(a[4], -2.045454545454543, 5); - AssertHelpers.AlmostEqual(a[5], 1.477272727272726, 5); - AssertHelpers.AlmostEqual(a[6], -0.113636363636364, 5); - AssertHelpers.AlmostEqual(a[7], 0.227272727272727, 5); - AssertHelpers.AlmostEqual(a[8], -0.113636363636364, 5); - } - - /// - /// Can compute the inverse of a matrix using LU factorization - /// using a previously factored matrix with a work array. - /// - [Test] - public void CanComputeLuInverseOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new float[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - - var ipiv = new int[matrix.RowCount]; - - Control.LinearAlgebraProvider.LUFactor(a, matrix.RowCount, ipiv); - -#if CUDA - float[] work = null; -#else - var work = new float[matrix.RowCount]; -#endif - Control.LinearAlgebraProvider.LUInverseFactored(a, matrix.RowCount, ipiv, work); - - AssertHelpers.AlmostEqual(a[0], -0.454545454545454, 5); - AssertHelpers.AlmostEqual(a[1], -0.909090909090908, 5); - AssertHelpers.AlmostEqual(a[2], 0.454545454545454, 5); - AssertHelpers.AlmostEqual(a[3], -0.340909090909090, 5); - AssertHelpers.AlmostEqual(a[4], -2.045454545454543, 5); - AssertHelpers.AlmostEqual(a[5], 1.477272727272726, 5); - AssertHelpers.AlmostEqual(a[6], -0.113636363636364, 5); - AssertHelpers.AlmostEqual(a[7], 0.227272727272727, 5); - AssertHelpers.AlmostEqual(a[8], -0.113636363636364, 5); - } - /// /// Can solve Ax=b using LU factorization. /// @@ -694,90 +632,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single } } - /// - /// Can compute QR factorization of a square matrix using a work array. - /// - [Test] - public void CanComputeQRFactorSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var r = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new float[3]; - var q = new float[matrix.RowCount*matrix.RowCount]; - var work = new float[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q); - var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - - /// - /// Can compute QR factorization of a tall matrix using a work matrix. - /// - [Test] - public void CanComputeQRFactorTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var r = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new float[3]; - var q = new float[matrix.RowCount*matrix.RowCount]; - var work = new float[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - - /// - /// Can compute QR factorization of a wide matrix using a work matrix. - /// - [Test] - public void CanComputeQRFactorWideMatrixWithWorkArray() - { - var matrix = _matrices["Wide2x3"]; - var r = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, r, r.Length); - - var tau = new float[3]; - var q = new float[matrix.RowCount*matrix.RowCount]; - var work = new float[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.QRFactor(r, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var mr = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, r).UpperTriangle(); - var mq = new DenseMatrix(matrix.RowCount, matrix.RowCount, q); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - /// /// Can compute thin QR factorization of a square matrix. /// @@ -832,61 +686,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single } } - /// - /// Can compute thin QR factorization of a square matrix using a work array. - /// - [Test] - public void CanComputeThinQRFactorSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var r = new float[matrix.ColumnCount*matrix.ColumnCount]; - var tau = new float[3]; - var q = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, q, q.Length); - - var work = new float[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var mq = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, q); - var mr = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, r); - var a = mq*mr; - - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - - /// - /// Can compute thin QR factorization of a tall matrix using a work matrix. - /// - [Test] - public void CanComputeThinQRFactorTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var r = new float[matrix.ColumnCount*matrix.ColumnCount]; - var tau = new float[3]; - var q = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, q, q.Length); - - var work = new float[matrix.ColumnCount*Control.BlockSize]; - Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var mq = new DenseMatrix(matrix.RowCount, matrix.ColumnCount, q); - var mr = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, r); - var a = mq*mr; - for (var row = 0; row < matrix.RowCount; row++) - { - for (var col = 0; col < matrix.ColumnCount; col++) - { - AssertHelpers.AlmostEqualRelative(matrix[row, col], a[row, col], 5); - } - } - } - /// /// Can solve Ax=b using QR factorization with a square A matrix. /// @@ -939,62 +738,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); } - /// - /// Can solve Ax=b using QR factorization with a square A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingQRSquareMatrixUsingWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new float[matrix.ColumnCount*2]; - var work = new float[matrix.RowCount*matrix.RowCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work); - - NotModified(3, 3, a, matrix); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 5); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 5); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 4); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 4); - } - - /// - /// Can solve Ax=b using QR factorization with a tall A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingQRTallMatrixUsingWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new float[matrix.ColumnCount*2]; - var work = new float[matrix.RowCount*matrix.RowCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work); - - NotModified(3, 2, a, matrix); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 5); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 5); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 5); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); - } - /// /// Can solve Ax=b using QR factorization with a square A matrix /// using a factored A matrix. @@ -1053,66 +796,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); } - /// - /// Can solve Ax=b using QR factorization with a square A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingQRSquareMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new float[matrix.RowCount*matrix.RowCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new float[matrix.ColumnCount]; - var q = new float[matrix.ColumnCount*matrix.ColumnCount]; - var work = new float[2048]; - Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var b = new[] {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new float[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 5); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 5); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 4); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 4); - } - - /// - /// Can solve Ax=b using QR factorization with a tall A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingQRTallMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new float[matrix.ColumnCount]; - var q = new float[matrix.RowCount*matrix.RowCount]; - var work = new float[2048]; - Control.LinearAlgebraProvider.QRFactor(a, matrix.RowCount, matrix.ColumnCount, q, tau, work); - - var b = new[] {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new float[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(q, a, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 5); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 5); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 5); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); - } - /// /// Can solve Ax=b using thin QR factorization with a square A matrix. /// @@ -1165,62 +848,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); } - /// - /// Can solve Ax=b using thin QR factorization with a square A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingThinQRSquareMatrixUsingWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new float[matrix.ColumnCount*2]; - var work = new float[matrix.RowCount*matrix.ColumnCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work, QRMethod.Thin); - - NotModified(3, 3, a, matrix); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 5); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 5); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 4); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 4); - } - - /// - /// Can solve Ax=b using thin QR factorization with a tall A matrix - /// using a work array. - /// - [Test] - public void CanSolveUsingThinQRTallMatrixUsingWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var b = new[] {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new float[matrix.ColumnCount*2]; - var work = new float[matrix.RowCount*matrix.ColumnCount]; - Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, work, QRMethod.Thin); - - NotModified(3, 2, a, matrix); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 5); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 5); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 5); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); - } - /// /// Can solve Ax=b using thin QR factorization with a square A matrix /// using a factored A matrix. @@ -1279,66 +906,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); } - /// - /// Can solve Ax=b using thin QR factorization with a square A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingThinQRSquareMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new float[matrix.ColumnCount]; - var r = new float[matrix.ColumnCount*matrix.ColumnCount]; - var work = new float[2048]; - Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var b = new[] {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new float[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work, QRMethod.Thin); - - var mx = new DenseMatrix(matrix.ColumnCount, 2, x); - var mb = matrix*mx; - - AssertHelpers.AlmostEqualRelative(mb[0, 0], b[0], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 0], b[1], 5); - AssertHelpers.AlmostEqualRelative(mb[2, 0], b[2], 5); - AssertHelpers.AlmostEqualRelative(mb[0, 1], b[3], 5); - AssertHelpers.AlmostEqualRelative(mb[1, 1], b[4], 4); - AssertHelpers.AlmostEqualRelative(mb[2, 1], b[5], 4); - } - - /// - /// Can solve Ax=b using thin QR factorization with a tall A matrix - /// using a factored A matrix with a work array. - /// - [Test] - public void CanSolveUsingThinQRTallMatrixOnFactoredMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var tau = new float[matrix.ColumnCount]; - var r = new float[matrix.ColumnCount*matrix.ColumnCount]; - var work = new float[2048]; - Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau, work); - - var b = new[] {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; - var x = new float[matrix.ColumnCount*2]; - Control.LinearAlgebraProvider.QRSolveFactored(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, work, QRMethod.Thin); - - var mb = new DenseMatrix(matrix.RowCount, 2, b); - var test = (matrix.Transpose()*matrix).Inverse()*matrix.Transpose()*mb; - - AssertHelpers.AlmostEqualRelative(test[0, 0], x[0], 5); - AssertHelpers.AlmostEqualRelative(test[1, 0], x[1], 5); - AssertHelpers.AlmostEqualRelative(test[0, 1], x[2], 5); - AssertHelpers.AlmostEqualRelative(test[1, 1], x[3], 5); - } - /// /// Can compute the SVD factorization of a square matrix. /// @@ -1444,129 +1011,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 5); } - /// - /// Can compute the SVD factorization of a square matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfSquareMatrixWithWorkArray() - { - var matrix = _matrices["Square3x3"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new float[matrix.RowCount]; - var u = new float[matrix.RowCount*matrix.RowCount]; - var vt = new float[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - float[] work = null; -#else - var work = new float[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u); - var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 2], result[2, 2], 5); - } - - /// - /// Can compute the SVD factorization of a tall matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfTallMatrixWithWorkArray() - { - var matrix = _matrices["Tall3x2"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new float[matrix.ColumnCount]; - var u = new float[matrix.RowCount*matrix.RowCount]; - var vt = new float[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - float[] work = null; -#else - var work = new float[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u); - var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 0], result[2, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[2, 1], result[2, 1], 5); - } - - /// - /// Can compute the SVD factorization of a wide matrix using - /// a work array. - /// - [Test] - public void CanComputeSVDFactorizationOfWideMatrixWithWorkArray() - { - var matrix = _matrices["Wide2x3"]; - var a = new float[matrix.RowCount*matrix.ColumnCount]; - Array.Copy(matrix.Values, a, a.Length); - - var s = new float[matrix.RowCount]; - var u = new float[matrix.RowCount*matrix.RowCount]; - var vt = new float[matrix.ColumnCount*matrix.ColumnCount]; -#if CUDA - float[] work = null; -#else - var work = new float[100]; -#endif - - Control.LinearAlgebraProvider.SingularValueDecomposition(true, a, matrix.RowCount, matrix.ColumnCount, s, u, vt, work); - - var w = new DenseMatrix(matrix.RowCount, matrix.ColumnCount); - for (var index = 0; index < s.Length; index++) - { - w[index, index] = s[index]; - } - - var mU = new DenseMatrix(matrix.RowCount, matrix.RowCount, u); - var mV = new DenseMatrix(matrix.ColumnCount, matrix.ColumnCount, vt); - var result = mU*w*mV; - - AssertHelpers.AlmostEqualRelative(matrix[0, 0], result[0, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 0], result[1, 0], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 1], result[0, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 1], result[1, 1], 5); - AssertHelpers.AlmostEqualRelative(matrix[0, 2], result[0, 2], 5); - AssertHelpers.AlmostEqualRelative(matrix[1, 2], result[1, 2], 5); - } - /// /// Can solve Ax=b using SVD factorization with a square A matrix. /// diff --git a/src/UnitTests/UnitTests-CUDA.csproj b/src/UnitTests/UnitTests-CUDA.csproj index 074df81c..291c5d99 100644 --- a/src/UnitTests/UnitTests-CUDA.csproj +++ b/src/UnitTests/UnitTests-CUDA.csproj @@ -336,6 +336,10 @@ {b7cae5f4-a23f-4438-b5be-41226618b695} Numerics + + {af3253c9-4db5-45a0-98cf-c105fda9da47} + TestData + diff --git a/src/UnitTests/UnitTests-MKL.csproj b/src/UnitTests/UnitTests-MKL.csproj index f0972c67..024b8d9a 100644 --- a/src/UnitTests/UnitTests-MKL.csproj +++ b/src/UnitTests/UnitTests-MKL.csproj @@ -130,6 +130,10 @@ + + + + @@ -652,6 +656,10 @@ {b7cae5f4-a23f-4438-b5be-41226618b695} Numerics + + {af3253c9-4db5-45a0-98cf-c105fda9da47} + TestData + @@ -664,10 +672,5 @@ - - - - - - + \ No newline at end of file diff --git a/src/UnitTests/UnitTests-OpenBLAS.csproj b/src/UnitTests/UnitTests-OpenBLAS.csproj index 94b0ac3e..7cad1e62 100644 --- a/src/UnitTests/UnitTests-OpenBLAS.csproj +++ b/src/UnitTests/UnitTests-OpenBLAS.csproj @@ -336,6 +336,10 @@ {b7cae5f4-a23f-4438-b5be-41226618b695} Numerics + + {af3253c9-4db5-45a0-98cf-c105fda9da47} + TestData +