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/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/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/Common/lapack.cpp b/src/NativeProviders/Common/lapack.cpp new file mode 100644 index 00000000..b0955923 --- /dev/null +++ b/src/NativeProviders/Common/lapack.cpp @@ -0,0 +1,744 @@ +#include "wrapper_common.h" + +#include "lapack.h" +#include "lapack_common.h" +#include + +template +inline lapack_int lu_factor(lapack_int m, T a[], lapack_int ipiv[], GETRF getrf) +{ + auto info = getrf(LAPACK_COL_MAJOR, m, m, a, m, ipiv); + shift_ipiv_down(m, ipiv); + return info; +} + +template +inline lapack_int lu_inverse(lapack_int n, T a[], GETRF getrf, GETRI getri) +{ + 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 lapack_int lu_inverse_factored(lapack_int n, T a[], lapack_int ipiv[], GETRI getri) +{ + shift_ipiv_up(n, ipiv); + auto info = getri(LAPACK_COL_MAJOR, n, a, n, ipiv); + 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); + auto info = getrs(LAPACK_COL_MAJOR, 'N', n, nrhs, a, n, ipiv, b, n); + 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) +{ + 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 lapack_int cholesky_factor(lapack_int n, T* a, POTRF potrf) +{ + 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 lapack_int cholesky_solve(lapack_int n, lapack_int nrhs, T a[], T b[], POTRF potrf, POTRS potrs) +{ + try + { + auto clone = array_clone(n * n, a); + auto info = potrf(LAPACK_COL_MAJOR, 'L', n, clone.get(), n); + + 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 lapack_int qr_factor(lapack_int m, lapack_int n, T r[], T tau[], T q[], GEQRF geqrf, ORGQR orgqr) +{ + 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 lapack_int qr_thin_factor(lapack_int m, lapack_int n, T q[], T tau[], T r[], GEQRF geqrf, ORGQR orgqr) +{ + 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 lapack_int qr_solve(lapack_int m, lapack_int n, lapack_int bn, T a[], T b[], T x[], GELS gels) +{ + 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 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) +{ + 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 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 + { + 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, reinterpret_cast(&one), reinterpret_cast(r), m, reinterpret_cast(clone_b.get()), m); + copyBtoX(m, n, bn, clone_b.get(), x); + return info; + } + catch (std::bad_alloc&) + { + return INSUFFICIENT_MEMORY; + } +} + +template +inline lapack_int svd_factor(bool compute_vectors, lapack_int m, lapack_int n, T a[], T s[], T u[], T v[], GESVD gesvd) +{ + 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 lapack_int complex_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, T a[], T s[], T u[], T v[], GESVD gesvd) +{ + 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 lapack_int eigen_factor(lapack_int n, T a[], T vectors[], R values[], T d[], GEES gees, TREVC trevc) +{ + 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 lapack_int eigen_complex_factor(lapack_int n, T a[], T vectors[], lapack_complex_double values[], T d[], GEES gees, TREVC trevc) +{ + try + { + 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; + } +} + +template +inline lapack_int sym_eigen_factor(lapack_int n, T a[], T vectors[], lapack_complex_double values[], T d[], SYEV syev) +{ + try + { + 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] = lapack_complex_double(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" { + + DLLEXPORT float s_matrix_norm(char norm, lapack_int m, lapack_int n, float a[]) + { + return LAPACKE_slange(LAPACK_COL_MAJOR, norm, m, n, a, m); + } + + 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); + } + + 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, lapack_complex_double a[]) + { + return LAPACKE_zlange(LAPACK_COL_MAJOR, norm, m, n, a, m); + } + + DLLEXPORT lapack_int s_lu_factor(lapack_int m, float a[], lapack_int ipiv[]) + { + return lu_factor(m, a, ipiv, LAPACKE_sgetrf); + } + + DLLEXPORT lapack_int d_lu_factor(lapack_int m, double a[], lapack_int ipiv[]) + { + return lu_factor(m, a, ipiv, LAPACKE_dgetrf); + } + + 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, lapack_complex_double 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, 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, lapack_complex_double a[], lapack_complex_double 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, 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, lapack_complex_double a[], lapack_int ipiv[], lapack_complex_double 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, 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, lapack_complex_double a[], lapack_int ipiv[], lapack_complex_double 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, 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, lapack_complex_double a[], lapack_complex_double 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, lapack_complex_float a[]) + { + return cholesky_factor(n, a, LAPACKE_cpotrf); + } + + DLLEXPORT lapack_int z_cholesky_factor(lapack_int n, lapack_complex_double 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, 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, lapack_complex_double a[], lapack_complex_double b[]) + { + return cholesky_solve(n, nrhs, a, b, LAPACKE_zpotrf, LAPACKE_zpotrs); + } + + 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, 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, lapack_complex_double a[], lapack_complex_double 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, 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, 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, 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, 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); + } + + 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, 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, lapack_complex_double a[], lapack_complex_double b[], lapack_complex_double 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, 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); + } + + 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); + } + + 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, lapack_complex_float a[], lapack_complex_float s[], lapack_complex_float u[], lapack_complex_float v[]) + { + 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, lapack_complex_double a[], lapack_complex_double s[], lapack_complex_double u[], lapack_complex_double v[]) + { + 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[], 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/Common/lapack_common.h b/src/NativeProviders/Common/lapack_common.h index 46677a4b..e3c596b7 100644 --- a/src/NativeProviders/Common/lapack_common.h +++ b/src/NativeProviders/Common/lapack_common.h @@ -1,38 +1,62 @@ -#ifndef LAPACK_COMMON_H -#define LAPACK_COMMON_H +#pragma once -#include +const int INSUFFICIENT_MEMORY = -999999; -void shift_ipiv_down(int m, int ipiv[]); -inline void shift_ipiv_down(int m, int ipiv[]){ - for(int i = 0; i < m; ++i ){ +#ifndef LAPACK_MEMORY +#define LAPACK_MEMORY +#include + +template using array_ptr = std::unique_ptr; + +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]; } } } -#endif 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.cpp b/src/NativeProviders/MKL/lapack.cpp deleted file mode 100644 index a1945bce..00000000 --- a/src/NativeProviders/MKL/lapack.cpp +++ /dev/null @@ -1,713 +0,0 @@ -#include -#include - -#define MKL_Complex8 std::complex -#define MKL_Complex16 std::complex - -#include "mkl_lapack.h" -#include "mkl_cblas.h" -#include "lapack_common.h" -#include "wrapper_common.h" -#include "mkl_lapacke.h" -#include "mkl.h" -#include "mkl_trans.h" - -template -inline MKL_INT lu_factor(MKL_INT m, T a[], MKL_INT ipiv[], GETRF getrf) -{ - MKL_INT info = 0; - getrf(&m, &m, a, &m, ipiv, &info); - shift_ipiv_down(m, ipiv); - return info; -} - -template -inline MKL_INT lu_inverse(MKL_INT n, T a[], T work[], MKL_INT lwork, 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; -} - -template -inline MKL_INT lu_inverse_factored(MKL_INT n, T a[], MKL_INT ipiv[], T work[], MKL_INT lwork, 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; -} - -template -inline MKL_INT lu_solve_factored(MKL_INT n, MKL_INT nrhs, T a[], MKL_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; -} - -template -inline MKL_INT lu_solve(MKL_INT n, MKL_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; -} - -template -inline MKL_INT cholesky_factor(MKL_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; -} - -template -inline MKL_INT cholesky_solve(MKL_INT n, MKL_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; -} - -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; -} - -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) -{ - MKL_INT info = 0; - geqrf(&m, &n, r, &m, tau, work, &len, &info); - - for (MKL_INT i = 0; i < m; ++i) - { - for (MKL_INT j = 0; j < m && j < n; ++j) - { - if (i > j) - { - q[j * m + i] = r[j * m + i]; - } - } - } - - //compute the q elements explicitly - if (m <= n) - { - orgqr(&m, &m, &m, q, &m, tau, work, &len, &info); - } - else - { - orgqr(&m, &m, &n, q, &m, tau, work, &len, &info); - } - - return info; -} - -template -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) -{ - MKL_INT info = 0; - geqrf(&m, &n, q, &m, tau, work, &len, &info); - - for (MKL_INT i = 0; i < n; ++i) - { - for (MKL_INT j = 0; j < n; ++j) - { - if (i <= j) - { - r[j * n + i] = q[j * m + i]; - } - } - } - - orgqr(&m, &n, &n, q, &m, tau, work, &len, &info); - return info; -} - -template -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) -{ - T* clone_a = Clone(m, n, a); - T* clone_b = Clone(m, bn, b); - char N = 'N'; - MKL_INT info = 0; - gels(&N, &m, &n, &bn, clone_a, &m, clone_b, &m, work, &len, &info); - copyBtoX(m, n, bn, clone_b, x); - delete[] clone_a; - delete[] clone_b; - return info; -} - -template -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) -{ - T* clone_b = Clone(m, bn, b); - char side ='L'; - char tran = 'T'; - MKL_INT info = 0; - ormqr(&side, &tran, &m, &bn, &n, r, &m, tau, clone_b, &m, work, &len, &info); - trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, 1.0, r, m, clone_b, m); - copyBtoX(m, n, bn, clone_b, x); - delete[] clone_b; - return info; -} - -template -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) -{ - T* clone_b = Clone(m, bn, b); - char side ='L'; - char tran = 'C'; - MKL_INT info = 0; - unmqr(&side, &tran, &m, &bn, &n, r, &m, tau, clone_b, &m, work, &len, &info); - T one = 1.0f; - trsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, &one, r, m, clone_b, m); - copyBtoX(m, n, bn, clone_b, x); - delete[] clone_b; - return info; -} - -template -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) -{ - MKL_INT info = 0; - char job = compute_vectors ? 'A' : 'N'; - gesvd(&job, &job, &m, &n, a, &m, s, u, &m, v, &n, work, &len, &info); - return info; -} - -template -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) -{ - 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; -} - -template -inline MKL_INT eigen_factor(MKL_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; -} - -template -inline MKL_INT eigen_complex_factor(MKL_INT n, T a[], T vectors[], MKL_Complex16 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) - { - delete[] clone_a; - delete[] w; - 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[] w; - return info; - } - - for (MKL_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 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]; - - MKL_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 (MKL_INT index = 0; index < n; ++index) - { - values[index] = MKL_Complex16(w[index]); - } - - 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]; - } - } - } - - delete[] clone_a; - delete[] w; - return info; -} - -extern "C" { - - DLLEXPORT float s_matrix_norm(char norm, MKL_INT m, MKL_INT n, float a[], float work[]) - { - return slange(&norm, &m, &n, a, &m, work); - } - - DLLEXPORT double d_matrix_norm(char norm, MKL_INT m, MKL_INT n, double a[], double work[]) - { - return dlange(&norm, &m, &n, a, &m, work); - } - - DLLEXPORT float c_matrix_norm(char norm, MKL_INT m, MKL_INT n, MKL_Complex8 a[], float work[]) - { - return clange(&norm, &m, &n, a, &m, work); - } - - DLLEXPORT double z_matrix_norm(char norm, MKL_INT m, MKL_INT n, MKL_Complex16 a[], double work[]) - { - return zlange(&norm, &m, &n, a, &m, work); - } - - DLLEXPORT MKL_INT s_lu_factor(MKL_INT m, float a[], MKL_INT ipiv[]) - { - return lu_factor(m, a, ipiv, sgetrf); - } - - DLLEXPORT MKL_INT d_lu_factor(MKL_INT m, double a[], MKL_INT ipiv[]) - { - return lu_factor(m, a, ipiv, dgetrf); - } - - DLLEXPORT MKL_INT c_lu_factor(MKL_INT m, MKL_Complex8 a[], MKL_INT ipiv[]) - { - return lu_factor(m, a, ipiv, cgetrf); - } - - DLLEXPORT MKL_INT z_lu_factor(MKL_INT m, MKL_Complex16 a[], MKL_INT ipiv[]) - { - return lu_factor(m, a, ipiv, zgetrf); - } - - DLLEXPORT MKL_INT s_lu_inverse(MKL_INT n, float a[], float work[], MKL_INT lwork) - { - return lu_inverse(n, a, work, lwork, sgetrf, sgetri); - } - - DLLEXPORT MKL_INT d_lu_inverse(MKL_INT n, double a[], double work[], MKL_INT lwork) - { - return lu_inverse(n, a, work, lwork, dgetrf, dgetri); - } - - DLLEXPORT MKL_INT c_lu_inverse(MKL_INT n, MKL_Complex8 a[], MKL_Complex8 work[], MKL_INT lwork) - { - return lu_inverse(n, a, work, lwork, cgetrf, cgetri); - } - - DLLEXPORT MKL_INT z_lu_inverse(MKL_INT n, MKL_Complex16 a[], MKL_Complex16 work[], MKL_INT lwork) - { - return lu_inverse(n, a, work, lwork, zgetrf, zgetri); - } - - DLLEXPORT MKL_INT s_lu_inverse_factored(MKL_INT n, float a[], MKL_INT ipiv[], float work[], MKL_INT lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, sgetri); - } - - DLLEXPORT MKL_INT d_lu_inverse_factored(MKL_INT n, double a[], MKL_INT ipiv[], double work[], MKL_INT lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, dgetri); - } - - DLLEXPORT MKL_INT c_lu_inverse_factored(MKL_INT n, MKL_Complex8 a[], MKL_INT ipiv[], MKL_Complex8 work[], MKL_INT lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, cgetri); - } - - DLLEXPORT MKL_INT z_lu_inverse_factored(MKL_INT n, MKL_Complex16 a[], MKL_INT ipiv[], MKL_Complex16 work[], MKL_INT lwork) - { - return lu_inverse_factored(n, a, ipiv, work, lwork, zgetri); - } - - DLLEXPORT MKL_INT s_lu_solve_factored(MKL_INT n, MKL_INT nrhs, float a[], MKL_INT ipiv[], float b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, sgetrs); - } - - DLLEXPORT MKL_INT d_lu_solve_factored(MKL_INT n, MKL_INT nrhs, double a[], MKL_INT ipiv[], double b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, dgetrs); - } - - DLLEXPORT MKL_INT c_lu_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_INT ipiv[], MKL_Complex8 b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, cgetrs); - } - - DLLEXPORT MKL_INT z_lu_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_INT ipiv[], MKL_Complex16 b[]) - { - return lu_solve_factored(n, nrhs, a, ipiv, b, zgetrs); - } - - DLLEXPORT MKL_INT s_lu_solve(MKL_INT n, MKL_INT nrhs, float a[], float b[]) - { - return lu_solve(n, nrhs, a, b, sgetrf, sgetrs); - } - - DLLEXPORT MKL_INT d_lu_solve(MKL_INT n, MKL_INT nrhs, double a[], double b[]) - { - return lu_solve(n, nrhs, a, b, dgetrf, dgetrs); - } - - DLLEXPORT MKL_INT c_lu_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_Complex8 b[]) - { - return lu_solve(n, nrhs, a, b, cgetrf, cgetrs); - } - - DLLEXPORT MKL_INT z_lu_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_Complex16 b[]) - { - return lu_solve(n, nrhs, a, b, zgetrf, zgetrs); - } - - DLLEXPORT MKL_INT s_cholesky_factor(MKL_INT n, float a[]) - { - return cholesky_factor(n, a, spotrf); - } - - DLLEXPORT MKL_INT d_cholesky_factor(MKL_INT n, double* a) - { - return cholesky_factor(n, a, dpotrf); - } - - DLLEXPORT MKL_INT c_cholesky_factor(MKL_INT n, MKL_Complex8 a[]) - { - return cholesky_factor(n, a, cpotrf); - } - - DLLEXPORT MKL_INT z_cholesky_factor(MKL_INT n, MKL_Complex16 a[]) - { - return cholesky_factor(n, a, zpotrf); - } - - DLLEXPORT MKL_INT s_cholesky_solve(MKL_INT n, MKL_INT nrhs, float a[], float b[]) - { - return cholesky_solve(n, nrhs, a, b, spotrf, spotrs); - } - - DLLEXPORT MKL_INT d_cholesky_solve(MKL_INT n, MKL_INT nrhs, double a[], double b[]) - { - return cholesky_solve(n, nrhs, a, b, dpotrf, dpotrs); - } - - DLLEXPORT MKL_INT c_cholesky_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_Complex8 b[]) - { - return cholesky_solve(n, nrhs, a, b, cpotrf, cpotrs); - } - - DLLEXPORT MKL_INT z_cholesky_solve(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_Complex16 b[]) - { - return cholesky_solve(n, nrhs, a, b, zpotrf, zpotrs); - } - - DLLEXPORT MKL_INT s_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, float a[], float b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, spotrs); - } - - DLLEXPORT MKL_INT d_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, double a[], double b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, dpotrs); - } - - DLLEXPORT MKL_INT c_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex8 a[], MKL_Complex8 b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, cpotrs); - } - - DLLEXPORT MKL_INT z_cholesky_solve_factored(MKL_INT n, MKL_INT nrhs, MKL_Complex16 a[], MKL_Complex16 b[]) - { - return cholesky_solve_factored(n, nrhs, a, b, zpotrs); - } - - DLLEXPORT MKL_INT s_qr_factor(MKL_INT m, MKL_INT n, float r[], float tau[], float q[], float work[], MKL_INT len) - { - return qr_factor(m, n, r, tau, q, work, len, sgeqrf, sorgqr); - } - - DLLEXPORT MKL_INT s_qr_thin_factor(MKL_INT m, MKL_INT n, float q[], float tau[], float r[], float work[], MKL_INT len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, sgeqrf, sorgqr); - } - - DLLEXPORT MKL_INT d_qr_factor(MKL_INT m, MKL_INT n, double r[], double tau[], double q[], double work[], MKL_INT len) - { - return qr_factor(m, n, r, tau, q, work, len, dgeqrf, dorgqr); - } - - DLLEXPORT MKL_INT d_qr_thin_factor(MKL_INT m, MKL_INT n, double q[], double tau[], double r[], double work[], MKL_INT len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, dgeqrf, dorgqr); - } - - DLLEXPORT MKL_INT c_qr_factor(MKL_INT m, MKL_INT n, MKL_Complex8 r[], MKL_Complex8 tau[], MKL_Complex8 q[], MKL_Complex8 work[], MKL_INT len) - { - return qr_factor(m, n, r, tau, q, work, len, cgeqrf, cungqr); - } - - DLLEXPORT MKL_INT c_qr_thin_factor(MKL_INT m, MKL_INT n, MKL_Complex8 q[], MKL_Complex8 tau[], MKL_Complex8 r[], MKL_Complex8 work[], MKL_INT len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, cgeqrf, cungqr); - } - - DLLEXPORT MKL_INT z_qr_factor(MKL_INT m, MKL_INT n, MKL_Complex16 r[], MKL_Complex16 tau[], MKL_Complex16 q[], MKL_Complex16 work[], MKL_INT len) - { - return qr_factor(m, n, r, tau, q, work, len, zgeqrf, zungqr); - } - - DLLEXPORT MKL_INT z_qr_thin_factor(MKL_INT m, MKL_INT n, MKL_Complex16 q[], MKL_Complex16 tau[], MKL_Complex16 r[], MKL_Complex16 work[], MKL_INT len) - { - return qr_thin_factor(m, n, q, tau, r, work, len, zgeqrf, zungqr); - } - - DLLEXPORT MKL_INT s_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, float a[], float b[], float x[], float work[], MKL_INT len) - { - return qr_solve(m, n, bn, a, b, x, work, len, sgels); - } - - DLLEXPORT MKL_INT d_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, double a[], double b[], double x[], double work[], MKL_INT len) - { - return qr_solve(m, n, bn, a, b, x, work, len, dgels); - } - - DLLEXPORT MKL_INT c_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex8 a[], MKL_Complex8 b[], MKL_Complex8 x[], MKL_Complex8 work[], MKL_INT len) - { - return qr_solve(m, n, bn, a, b, x, work, len, cgels); - } - - DLLEXPORT MKL_INT z_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex16 a[], MKL_Complex16 b[], MKL_Complex16 x[], MKL_Complex16 work[], MKL_INT len) - { - return qr_solve(m, n, bn, a, b, x, work, len, zgels); - } - - DLLEXPORT MKL_INT s_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, float r[], float b[], float tau[], float x[], float work[], MKL_INT len) - { - return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, sormqr, cblas_strsm); - } - - DLLEXPORT MKL_INT d_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, double r[], double b[], double tau[], double x[], double work[], MKL_INT len) - { - return qr_solve_factored(m, n, bn, r, b, tau, x, work, len, dormqr, cblas_dtrsm); - } - - DLLEXPORT MKL_INT c_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex8 r[], MKL_Complex8 b[], MKL_Complex8 tau[], MKL_Complex8 x[], MKL_Complex8 work[], MKL_INT len) - { - return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, cunmqr, cblas_ctrsm); - } - - DLLEXPORT MKL_INT z_qr_solve_factored(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex16 r[], MKL_Complex16 b[], MKL_Complex16 tau[], MKL_Complex16 x[], MKL_Complex16 work[], MKL_INT len) - { - return complex_qr_solve_factored(m, n, bn, r, b, tau, x, work, len, zunmqr, cblas_ztrsm); - } - - DLLEXPORT MKL_INT s_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, float a[], float s[], float u[], float v[], float work[], MKL_INT len) - { - return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, sgesvd); - } - - DLLEXPORT MKL_INT d_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, double a[], double s[], double u[], double v[], double work[], MKL_INT len) - { - return svd_factor(compute_vectors, m, n, a, s, u, v, work, len, dgesvd); - } - - DLLEXPORT MKL_INT c_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, MKL_Complex8 a[], MKL_Complex8 s[], MKL_Complex8 u[], MKL_Complex8 v[], MKL_Complex8 work[], MKL_INT len) - { - return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, cgesvd); - } - - DLLEXPORT MKL_INT z_svd_factor(bool compute_vectors, MKL_INT m, MKL_INT n, MKL_Complex16 a[], MKL_Complex16 s[], MKL_Complex16 u[], MKL_Complex16 v[], MKL_Complex16 work[], MKL_INT len) - { - return complex_svd_factor(compute_vectors, m, n, a, s, u, v, work, len, zgesvd); - } - - DLLEXPORT MKL_INT s_eigen(bool isSymmetric, MKL_INT n, float a[], float vectors[], MKL_Complex16 values[], float d[]) - { - if (isSymmetric) - { - return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_ssyev); - } - else - { - return eigen_factor(n, a, vectors, values, d, LAPACKE_sgees, LAPACKE_strevc); - } - } - - DLLEXPORT MKL_INT d_eigen(bool isSymmetric, MKL_INT n, double a[], double vectors[], MKL_Complex16 values[], double d[]) - { - if (isSymmetric) - { - return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_dsyev); - } - else - { - return eigen_factor(n, a, vectors, values, d, LAPACKE_dgees, LAPACKE_dtrevc); - } - } - - DLLEXPORT MKL_INT c_eigen(bool isSymmetric, MKL_INT n, MKL_Complex8 a[], MKL_Complex8 vectors[], MKL_Complex16 values[], MKL_Complex8 d[]) - { - if (isSymmetric) - { - return sym_eigen_factor(n, a, vectors, values, d, LAPACKE_cheev); - } - else - { - return 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[]) - { - 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/MKL/lapack.h b/src/NativeProviders/MKL/lapack.h new file mode 100644 index 00000000..bf9e9c45 --- /dev/null +++ b/src/NativeProviders/MKL/lapack.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#define MKL_Complex8 std::complex +#define MKL_Complex16 std::complex +#define LAPACK_MEMORY + +#include "mkl.h" + +const int ALIGNMENT = 64; + +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) +{ + auto ret = static_cast(mkl_malloc(size * sizeof(T), ALIGNMENT)); + + if (!ret) + { + throw new std::bad_alloc(); + } + + 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..3c9fe4b5 --- /dev/null +++ b/src/NativeProviders/OpenBLAS/lapack.h @@ -0,0 +1,11 @@ +#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 09081f53..ce59f97e 100644 --- a/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters +++ b/src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters @@ -9,18 +9,12 @@ {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 - - Source Files - - - Source Files - Source Files @@ -33,15 +27,30 @@ Source Files + + Source Files + + + Source Files + - Resource Files + Source Files\Resource Files 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/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/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/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/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 } } diff --git a/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs index d17a75cd..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,68 +433,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex 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 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); - } - - /// - /// 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); - } - /// /// Can solve Ax=b using LU factorization. /// @@ -692,90 +630,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex } } - /// - /// 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); - } - } - } - /// /// Can compute thin QR factorization of a square matrix. /// @@ -830,61 +684,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex } } - /// - /// 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); - } - } - } - /// /// Can solve Ax=b using QR factorization with a square A matrix. /// @@ -936,92 +735,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex 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 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); - } - /// /// Can solve Ax=b using QR factorization with a tall A matrix /// using a factored A matrix. @@ -1050,66 +763,6 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex 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 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); - } - /// /// Can solve Ax=b using thin QR factorization with a square A matrix. /// @@ -1162,62 +815,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 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); - } - /// /// Can solve Ax=b using thin QR factorization with a square A matrix /// using a factored A matrix. @@ -1276,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. /// @@ -1441,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 df1bc55f..024b8d9a 100644 --- a/src/UnitTests/UnitTests-MKL.csproj +++ b/src/UnitTests/UnitTests-MKL.csproj @@ -52,8 +52,328 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -336,6 +656,10 @@ {b7cae5f4-a23f-4438-b5be-41226618b695} Numerics + + {af3253c9-4db5-45a0-98cf-c105fda9da47} + TestData + @@ -348,4 +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 +