diff --git a/src/NativeWrappers/MKL/lapack.cpp b/src/NativeWrappers/MKL/lapack.cpp
index 0024ac31..92f7d827 100644
--- a/src/NativeWrappers/MKL/lapack.cpp
+++ b/src/NativeWrappers/MKL/lapack.cpp
@@ -538,6 +538,27 @@ extern "C"{
return info;
}
+ DLLEXPORT MKL_INT s_qr_thin_factor(MKL_INT m, MKL_INT n, float q[], float tau[], float r[], float work[], MKL_INT len)
+ {
+ MKL_INT info = 0;
+ sgeqrf_(&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];
+ }
+ }
+ }
+
+ sorgqr_(&m, &n, &n, q, &m, tau, work, &len, &info);
+
+ return info;
+ }
+
+
DLLEXPORT MKL_INT d_qr_factor(MKL_INT m, MKL_INT n, double r[], double tau[], double q[], double work[], MKL_INT len)
{
MKL_INT info = 0;
@@ -567,6 +588,26 @@ extern "C"{
return info;
}
+ DLLEXPORT MKL_INT d_qr_thin_factor(MKL_INT m, MKL_INT n, double q[], double tau[], double r[], double work[], MKL_INT len)
+ {
+ MKL_INT info = 0;
+ dgeqrf_(&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];
+ }
+ }
+ }
+
+ dorgqr_(&m, &n, &n, q, &m, tau, work, &len, &info);
+
+ return info;
+ }
+
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)
{
MKL_INT info = 0;
@@ -596,6 +637,26 @@ extern "C"{
return info;
}
+ DLLEXPORT MKL_INT c_qr_thin_factor(MKL_INT m, MKL_INT n, MKL_Complex8 q[], MKL_Complex8 tau[], MKL_Complex8 r[], MKL_Complex8 work[], MKL_INT len)
+ {
+ MKL_INT info = 0;
+ cgeqrf_(&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];
+ }
+ }
+ }
+
+ cungqr_(&m, &n, &n, q, &m, tau, work, &len, &info);
+
+ return info;
+ }
+
DLLEXPORT MKL_INT z_qr_factor(MKL_INT m, MKL_INT n, MKL_Complex16 r[], MKL_Complex16 tau[], MKL_Complex16 q[], MKL_Complex16 work[], MKL_INT len)
{
MKL_INT info = 0;
@@ -625,29 +686,41 @@ extern "C"{
return info;
}
- DLLEXPORT MKL_INT s_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, float r[], float b[], float x[], float work[], MKL_INT len)
+ DLLEXPORT MKL_INT z_qr_thin_factor(MKL_INT m, MKL_INT n, MKL_Complex16 q[], MKL_Complex16 tau[], MKL_Complex16 r[], MKL_Complex16 work[], MKL_INT len)
{
MKL_INT info = 0;
- float* clone_r = new float[m*n];
- std::memcpy(clone_r, r, m*n*sizeof(float));
-
- float* tau = new float[std::max(1, std::min(m,n))];
- sgeqrf_(&m, &n, clone_r, &m, tau, work, &len, &info);
+ zgeqrf_(&m, &n, q, &m, tau, work, &len, &info);
- if (info != 0)
+ for (MKL_INT i = 0; i < n; ++i)
{
- delete[] clone_r;
- delete[] tau;
- return info;
+ for (MKL_INT j = 0; j < n; ++j)
+ {
+ if( i <= j) {
+ r[j * n + i] = q[j * m + i];
+ }
+ }
}
+ zungqr_(&m, &n, &n, q, &m, tau, work, &len, &info);
+
+ return info;
+ }
+
+ DLLEXPORT MKL_INT s_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, float a[], float b[], float x[], float work[], MKL_INT len)
+ {
+ MKL_INT info = 0;
+ MKL_INT* jpvt = new MKL_INT[n];
+ MKL_INT rank = 0;
+ float cond = -1.0;
+
+ float* clone_a = new float[m*n];
+ std::memcpy(clone_a, a, m*n*sizeof(float));
+
float* clone_b = new float[m*bn];
std::memcpy(clone_b, b, m*bn*sizeof(float));
- char side ='L';
- char tran = 'T';
- sormqr_(&side, &tran, &m, &bn, &n, clone_r, &m, tau, clone_b, &m, work, &len, &info);
- cblas_strsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, 1.0, clone_r, m, clone_b, m);
+ sgelsy_(&m, &n, &bn, clone_a, &m, clone_b, &m, jpvt, &cond, &rank, work, &len, &info);
+
for (MKL_INT i = 0; i < n; ++i)
{
for (MKL_INT j = 0; j < bn; ++j)
@@ -656,36 +729,57 @@ extern "C"{
}
}
- delete[] clone_r;
- delete[] tau;
+ delete[] jpvt;
+ delete[] clone_a;
delete[] clone_b;
return info;
}
- DLLEXPORT MKL_INT d_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, double r[], double b[], double x[], double work[], MKL_INT len)
+ 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)
{
MKL_INT info = 0;
- double* clone_r = new double[m*n];
- std::memcpy(clone_r, r, m*n*sizeof(double));
+ MKL_INT* jpvt = new MKL_INT[n];
+ MKL_INT rank = 0;
+ double cond = -1.0;
- double* tau = new double[std::max(1, std::min(m,n))];
- dgeqrf_(&m, &n, clone_r, &m, tau, work, &len, &info);
+ double* clone_a = new double[m*n];
+ std::memcpy(clone_a, a, m*n*sizeof(double));
- if (info != 0)
+ double* clone_b = new double[m*bn];
+ std::memcpy(clone_b, b, m*bn*sizeof(double));
+
+ dgelsy_(&m, &n, &bn, clone_a, &m, clone_b, &m, jpvt, &cond, &rank, work, &len, &info);
+
+ for (MKL_INT i = 0; i < n; ++i)
{
- delete[] clone_r;
- delete[] tau;
- return info;
+ for (MKL_INT j = 0; j < bn; ++j)
+ {
+ x[j * n + i] = clone_b[j * m + i];
+ }
}
- double* clone_b = new double[m*bn];
- std::memcpy(clone_b, b, m*bn*sizeof(double));
+ delete[] jpvt;
+ delete[] clone_a;
+ delete[] clone_b;
+ return info;
+ }
- char side ='L';
- char tran = 'T';
+ 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)
+ {
+ MKL_INT info = 0;
+ MKL_INT* jpvt = new MKL_INT[n];
+ float* rwork = new float[2*n];
+ MKL_INT rank = 0;
+ float cond = -1.0;
+
+ MKL_Complex8* clone_a = new MKL_Complex8[m*n];
+ std::memcpy(clone_a, a, m*n*sizeof(MKL_Complex8));
+
+ MKL_Complex8* clone_b = new MKL_Complex8[m*bn];
+ std::memcpy(clone_b, b, m*bn*sizeof(MKL_Complex8));
+
+ cgelsy_(&m, &n, &bn, clone_a, &m, clone_b, &m, jpvt, &cond, &rank, work, &len, rwork, &info);
- dormqr_(&side, &tran, &m, &bn, &n, clone_r, &m, tau, clone_b, &m, work, &len, &info);
- cblas_dtrsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, 1.0, clone_r, m, clone_b, m);
for (MKL_INT i = 0; i < n; ++i)
{
for (MKL_INT j = 0; j < bn; ++j)
@@ -694,37 +788,55 @@ extern "C"{
}
}
+ delete[] jpvt;
+ delete[] rwork;
+ delete[] clone_a;
delete[] clone_b;
- delete[] tau;
- delete[] clone_r;
return info;
}
- DLLEXPORT MKL_INT c_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex8 r[], MKL_Complex8 b[], MKL_Complex8 x[], MKL_Complex8 work[], MKL_INT len)
+ DLLEXPORT MKL_INT z_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex16 a[], MKL_Complex16 b[], MKL_Complex16 x[], MKL_Complex16 work[], MKL_INT len)
{
MKL_INT info = 0;
- MKL_Complex8* clone_r = new MKL_Complex8[m*n];
- std::memcpy(clone_r, r, m*n*sizeof(MKL_Complex8));
+ MKL_INT* jpvt = new MKL_INT[n];
+ double* rwork = new double[2*n];
+ MKL_INT rank = 0;
+ double cond = -1.0;
+
+ MKL_Complex16* clone_a = new MKL_Complex16[m*n];
+ std::memcpy(clone_a, a, m*n*sizeof(MKL_Complex16));
+
+ MKL_Complex16* clone_b = new MKL_Complex16[m*bn];
+ std::memcpy(clone_b, b, m*bn*sizeof(MKL_Complex16));
- MKL_Complex8* tau = new MKL_Complex8[std::min(m,n)];
- cgeqrf_(&m, &n, clone_r, &m, tau, work, &len, &info);
+ zgelsy_(&m, &n, &bn, clone_a, &m, clone_b, &m, jpvt, &cond, &rank, work, &len, rwork, &info);
- if (info != 0)
+ for (MKL_INT i = 0; i < n; ++i)
{
- delete[] clone_r;
- delete[] tau;
- return info;
+ for (MKL_INT j = 0; j < bn; ++j)
+ {
+ x[j * n + i] = clone_b[j * m + i];
+ }
}
- char side ='L';
- char tran = 'C';
+ delete[] jpvt;
+ delete[] rwork;
+ delete[] clone_a;
+ delete[] clone_b;
+ return info;
+ }
- MKL_Complex8* clone_b = new MKL_Complex8[m*bn];
- std::memcpy(clone_b, b, m*bn*sizeof(MKL_Complex8));
+ DLLEXPORT MKL_INT s_thin_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, float a[], float b[], float x[], float work[], MKL_INT len)
+ {
+ MKL_INT info = 0;
- cunmqr_(&side, &tran, &m, &bn, &n, clone_r, &m, tau, clone_b, &m, work, &len, &info);
- MKL_Complex8 one = {1.0, 0.0};
- cblas_ctrsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, &one, clone_r, m, clone_b, m);
+ float* clone_a = new float[m*n];
+ std::memcpy(clone_a, a, m*n*sizeof(float));
+
+ float* clone_b = new float[m*bn];
+ std::memcpy(clone_b, b, m*bn*sizeof(float));
+ char N = 'N';
+ sgels_(&N, &m, &n, &bn, clone_a, &m, clone_b, &m, work, &len, &info);
for (MKL_INT i = 0; i < n; ++i)
{
@@ -734,37 +846,74 @@ extern "C"{
}
}
- delete[] clone_r;
- delete[] tau;
+ delete[] clone_a;
delete[] clone_b;
return info;
}
- DLLEXPORT MKL_INT z_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex16 r[], MKL_Complex16 b[], MKL_Complex16 x[], MKL_Complex16 work[], MKL_INT len)
+ DLLEXPORT MKL_INT d_thin_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, double a[], double b[], double x[], double work[], MKL_INT len)
{
MKL_INT info = 0;
- MKL_Complex16* clone_r = new MKL_Complex16[m*n];
- std::memcpy(clone_r, r, m*n*sizeof(MKL_Complex16));
- MKL_Complex16* tau = new MKL_Complex16[std::min(m,n)];
- zgeqrf_(&m, &n, clone_r, &m, tau, work, &len, &info);
+ double* clone_a = new double[m*n];
+ std::memcpy(clone_a, a, m*n*sizeof(double));
+
+ double* clone_b = new double[m*bn];
+ std::memcpy(clone_b, b, m*bn*sizeof(double));
- if (info != 0)
+ char N = 'N';
+ dgels_(&N, &m, &n, &bn, clone_a, &m, clone_b, &m, work, &len, &info);
+
+ for (MKL_INT i = 0; i < n; ++i)
{
- delete[] clone_r;
- delete[] tau;
- return info;
+ for (MKL_INT j = 0; j < bn; ++j)
+ {
+ x[j * n + i] = clone_b[j * m + i];
+ }
}
- char side ='L';
- char tran = 'C';
+ delete[] clone_a;
+ delete[] clone_b;
+ return info;
+ }
+
+ DLLEXPORT MKL_INT c_thin_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)
+ {
+ MKL_INT info = 0;
+ MKL_Complex8* clone_a = new MKL_Complex8[m*n];
+ std::memcpy(clone_a, a, m*n*sizeof(MKL_Complex8));
+
+ MKL_Complex8* clone_b = new MKL_Complex8[m*bn];
+ std::memcpy(clone_b, b, m*bn*sizeof(MKL_Complex8));
+
+ char N = 'N';
+ cgels_(&N, &m, &n, &bn, clone_a, &m, clone_b, &m, work, &len, &info);
+
+ for (MKL_INT i = 0; i < n; ++i)
+ {
+ for (MKL_INT j = 0; j < bn; ++j)
+ {
+ x[j * n + i] = clone_b[j * m + i];
+ }
+ }
+
+ delete[] clone_a;
+ delete[] clone_b;
+ return info;
+ }
+
+ DLLEXPORT MKL_INT z_thin_qr_solve(MKL_INT m, MKL_INT n, MKL_INT bn, MKL_Complex16 a[], MKL_Complex16 b[], MKL_Complex16 x[], MKL_Complex16 work[], MKL_INT len)
+ {
+ MKL_INT info = 0;
+
+ MKL_Complex16* clone_a = new MKL_Complex16[m*n];
+ std::memcpy(clone_a, a, m*n*sizeof(MKL_Complex16));
MKL_Complex16* clone_b = new MKL_Complex16[m*bn];
std::memcpy(clone_b, b, m*bn*sizeof(MKL_Complex16));
- zunmqr_(&side, &tran, &m, &bn, &n, clone_r, &m, tau, clone_b, &m, work, &len, &info);
- MKL_Complex16 one = {1.0, 0.0};
- cblas_ztrsm(CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, &one, clone_r, m, clone_b, m);
+ char N = 'N';
+ zgels_(&N, &m, &n, &bn, clone_a, &m, clone_b, &m, work, &len, &info);
for (MKL_INT i = 0; i < n; ++i)
{
@@ -774,8 +923,7 @@ extern "C"{
}
}
- delete[] clone_r;
- delete[] tau;
+ delete[] clone_a;
delete[] clone_b;
return info;
}
diff --git a/src/NativeWrappers/MKL/lapack.h b/src/NativeWrappers/MKL/lapack.h
index 3026b4af..bd702cfb 100644
--- a/src/NativeWrappers/MKL/lapack.h
+++ b/src/NativeWrappers/MKL/lapack.h
@@ -1,7 +1,7 @@
#ifndef LAPACK_H
#define LAPACK_H
-#include "blas.h"
+//#include "blas.h"
#include "mkl_lapack.h"
#endif
diff --git a/src/NativeWrappers/Windows/ACMLWrapper/ACMKWrapper.vcxproj b/src/NativeWrappers/Windows/ACML/ACMLWrapper.vcxproj
similarity index 97%
rename from src/NativeWrappers/Windows/ACMLWrapper/ACMKWrapper.vcxproj
rename to src/NativeWrappers/Windows/ACML/ACMLWrapper.vcxproj
index adde35e4..e93d47fe 100644
--- a/src/NativeWrappers/Windows/ACMLWrapper/ACMKWrapper.vcxproj
+++ b/src/NativeWrappers/Windows/ACML/ACMLWrapper.vcxproj
@@ -29,23 +29,27 @@
DynamicLibrarytrueUnicode
+ v110DynamicLibrarytrueUnicode
+ v110DynamicLibraryfalsetrueUnicode
+ v110DynamicLibraryfalsetrueUnicode
+ v110
diff --git a/src/NativeWrappers/Windows/ACMLWrapper/ACMKWrapper.vcxproj.filters b/src/NativeWrappers/Windows/ACMLWrapper/ACMKWrapper.vcxproj.filters
deleted file mode 100644
index 30541be3..00000000
--- a/src/NativeWrappers/Windows/ACMLWrapper/ACMKWrapper.vcxproj.filters
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hpp;hxx;hm;inl;inc;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
-
-
- Resource Files
-
-
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
-
\ No newline at end of file
diff --git a/src/NativeWrappers/Windows/ACMLWrapperTests/ACMLWrapperTests.csproj b/src/NativeWrappers/Windows/ACMLWrapperTests/ACMLWrapperTests.csproj
index c5e97dfb..2745705a 100644
--- a/src/NativeWrappers/Windows/ACMLWrapperTests/ACMLWrapperTests.csproj
+++ b/src/NativeWrappers/Windows/ACMLWrapperTests/ACMLWrapperTests.csproj
@@ -36,7 +36,7 @@
..\..\..\..\out\debug\Net40\MathNet.Numerics.dll
- ..\..\..\..\lib\NUnit.2.5.9\nunit.framework.dll
+ ..\..\..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll
diff --git a/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj b/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj
index 31d75391..e2bbc0bb 100644
--- a/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj
+++ b/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj
@@ -25,23 +25,27 @@
DynamicLibrary
+ v110MultiBytetrueParallelDynamicLibrary
+ v110MultiByteParallelDynamicLibrary
+ v110MultiBytetrueParallelDynamicLibrary
+ v110MultiByteParallel
@@ -62,32 +66,28 @@
- <_ProjectFileVersion>10.0.30319.1
- $(SolutionDir)$(Platform)\$(Configuration)\
- $(Platform)\$(Configuration)\
- $(SolutionDir)$(Platform)\$(Configuration)\
- $(Platform)\$(Configuration)\
- $(SolutionDir)$(Platform)\$(Configuration)\
- $(Platform)\$(Configuration)\
- $(SolutionDir)$(Platform)\$(Configuration)\
- $(Platform)\$(Configuration)\
- AllRules.ruleset
-
-
- AllRules.ruleset
-
-
- AllRules.ruleset
-
-
- AllRules.ruleset
-
-
+ <_ProjectFileVersion>11.0.50727.1
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\Disabled
- ..\..\Common;..\..\MKL;C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\include;
+ $(ProjectDir)..\..\Common;$(ProjectDir)..\..\MKL;$(MKLIncludeDir);%(AdditionalIncludeDirectories)_WINDOWS;%(PreprocessorDefinitions)trueEnableFastChecks
@@ -99,12 +99,12 @@
mkl_intel_c.lib;mkl_intel_thread.lib;mkl_core.lib;libiomp5md.lib;%(AdditionalDependencies)$(OutDir)MathNET.Numerics.MKL.dll
- C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\lib\ia32;C:\Program Files (x86)\Intel\ComposerXE-2011\compiler\lib\ia32;
+ C:\Program Files (x86)\Intel\Compiler\11.1\046\lib\ia32;C:\Program Files (x86)\Intel\Compiler\11.1\046\mkl\ia32\lib;%(AdditionalLibraryDirectories)trueMachineX86
- copy "C:\Program Files (x86)\Intel\Composer XE\redist\ia32\compiler\libiomp5md.dll" $(OutDir)
+ copy "$(CompilerPathForVC)\libiomp5md.dll" $(OutDir)
@@ -113,7 +113,7 @@
Disabled
- ..\..\Common;..\..\MKL;C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\include;
+ $(ProjectDir)..\..\Common;$(ProjectDir)..\..\MKL;$(MKLIncludeDir);%(AdditionalIncludeDirectories)_WINDOWS;%(PreprocessorDefinitions)trueEnableFastChecks
@@ -125,19 +125,19 @@
mkl_intel_lp64.lib;mkl_intel_thread.lib;mkl_core.lib;libiomp5md.lib;%(AdditionalDependencies)$(OutDir)MathNET.Numerics.MKL.dll
- C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\lib\intel64;C:\Program Files (x86)\Intel\ComposerXE-2011\compiler\lib\intel64
+ C:\Program Files (x86)\Intel\Compiler\11.1\046\lib\intel64;C:\Program Files (x86)\Intel\Compiler\11.1\046\mkl\em64t\lib;%(AdditionalLibraryDirectories)trueMachineX64
- copy "C:\Program Files (x86)\Intel\Composer XE\redist\intel64\compiler\libiomp5md.dll" $(OutDir)
+ copy "$(CompilerPathForVC)\libiomp5md.dll" $(OutDir)MaxSpeedtrue
- ..\..\Common;..\..\MKL;C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\include;
+ $(ProjectDir)..\..\Common;$(ProjectDir)..\..\MKL;$(MKLIncludeDir);%(AdditionalIncludeDirectories)_WINDOWS;%(PreprocessorDefinitions)MultiThreadedtrue
@@ -148,14 +148,14 @@
mkl_intel_c.lib;mkl_intel_thread.lib;mkl_core.lib;libiomp5md.lib;%(AdditionalDependencies)$(OutDir)MathNET.Numerics.MKL.dll
- C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\lib\ia32;C:\Program Files (x86)\Intel\ComposerXE-2011\compiler\lib\ia32;
+ C:\Program Files (x86)\Intel\Compiler\11.1\060\lib\ia32;C:\Program Files (x86)\Intel\Compiler\11.1\060\mkl\ia32\lib;%(AdditionalLibraryDirectories)truetruetrueMachineX86
- copy "C:\Program Files (x86)\Intel\Composer XE\redist\ia32\compiler\libiomp5md.dll" $(OutDir)
+ copy "$(CompilerPathForVC)\libiomp5md.dll" $(OutDir)
@@ -165,7 +165,7 @@
MaxSpeedtrue
- ..\..\Common;..\..\MKL;C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\include;
+ $(ProjectDir)..\..\Common;$(ProjectDir)..\..\MKL;$(MKLIncludeDir);%(AdditionalIncludeDirectories)_WINDOWS;%(PreprocessorDefinitions)MultiThreadedtrue
@@ -176,26 +176,26 @@
mkl_intel_lp64.lib;mkl_intel_thread.lib;mkl_core.lib;libiomp5md.lib;%(AdditionalDependencies)$(OutDir)MathNET.Numerics.MKL.dll
- C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\lib\intel64;C:\Program Files (x86)\Intel\ComposerXE-2011\compiler\lib\intel64
+ C:\Program Files (x86)\Intel\Compiler\11.1\060\lib\intel64;C:\Program Files (x86)\Intel\Compiler\11.1\060\mkl\em64t\lib;%(AdditionalLibraryDirectories)truetruetrueMachineX64
- copy "C:\Program Files (x86)\Intel\Composer XE\redist\intel64\compiler\libiomp5md.dll" $(OutDir)
+ copy "$(CompilerPathForVC)\libiomp5md.dll" $(OutDir)
-
-
-
-
+
+
+
+
diff --git a/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters b/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters
index 5d4163bf..631d1787 100644
--- a/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters
+++ b/src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters
@@ -15,17 +15,6 @@
-
- Header Files
-
-
- Header Files
-
-
-
-
- Source Files
- Source Files
@@ -35,6 +24,17 @@
Source Files
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
diff --git a/src/NativeWrappers/Windows/MKLWrapperTests/MKLWrapperTests.csproj b/src/NativeWrappers/Windows/MKLWrapperTests/MKLWrapperTests.csproj
index 19875a21..e8fe842c 100644
--- a/src/NativeWrappers/Windows/MKLWrapperTests/MKLWrapperTests.csproj
+++ b/src/NativeWrappers/Windows/MKLWrapperTests/MKLWrapperTests.csproj
@@ -59,8 +59,9 @@
False..\..\..\..\out\debug\Net40\MathNet.Numerics.dll
-
- ..\..\..\..\lib\NUnit.2.5.9\nunit.framework.dll
+
+ False
+ ..\..\..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll
diff --git a/src/NativeWrappers/Windows/NativeWrappers.sln b/src/NativeWrappers/Windows/NativeWrappers.sln
index 0862f0ac..7d2b73a9 100644
--- a/src/NativeWrappers/Windows/NativeWrappers.sln
+++ b/src/NativeWrappers/Windows/NativeWrappers.sln
@@ -1,6 +1,6 @@
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{5A0892FF-82CE-40FC-BCE1-73810C615F52}"
ProjectSection(SolutionItems) = preProject
..\Common\resource.h = ..\Common\resource.h
@@ -13,14 +13,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MKLWrapper", "MKL\MKLWrappe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MKLWrapperTests", "MKLWrapperTests\MKLWrapperTests.csproj", "{D0AD591B-0CE6-4A6D-8DEA-01777EE09BC3}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GotoBLAS2Wrapper", "GotoBLAS2\GotoBLAS2Wrapper.vcxproj", "{507FF69E-32A6-495A-9DE2-20EC10EE8963}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GotoBLAS2WrapperTests", "GotoBLAS2WrapperTests\GotoBLAS2WrapperTests.csproj", "{56FFAB18-CAA6-4913-8123-610872BFD60A}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ACMLWrapper", "ACMLWrapper\ACMKWrapper.vcxproj", "{8774BCBE-27D0-44D2-A1B3-8ED705E252CB}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACMLWrapperTests", "ACMLWrapperTests\ACMLWrapperTests.csproj", "{8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -59,57 +51,6 @@ Global
{D0AD591B-0CE6-4A6D-8DEA-01777EE09BC3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D0AD591B-0CE6-4A6D-8DEA-01777EE09BC3}.Release|Win32.ActiveCfg = Release|Any CPU
{D0AD591B-0CE6-4A6D-8DEA-01777EE09BC3}.Release|x64.ActiveCfg = Release|Any CPU
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Debug|Any CPU.ActiveCfg = Debug|x64
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Debug|Mixed Platforms.Build.0 = Debug|x64
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Debug|Win32.ActiveCfg = Debug|Win32
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Debug|Win32.Build.0 = Debug|Win32
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Debug|x64.ActiveCfg = Debug|x64
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Debug|x64.Build.0 = Debug|x64
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Release|Any CPU.ActiveCfg = Release|x64
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Release|Mixed Platforms.ActiveCfg = Release|x64
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Release|Mixed Platforms.Build.0 = Release|x64
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Release|Win32.ActiveCfg = Release|Win32
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Release|Win32.Build.0 = Release|Win32
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Release|x64.ActiveCfg = Release|x64
- {507FF69E-32A6-495A-9DE2-20EC10EE8963}.Release|x64.Build.0 = Release|x64
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Debug|x64.ActiveCfg = Debug|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Release|Any CPU.Build.0 = Release|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Release|Win32.ActiveCfg = Release|Any CPU
- {56FFAB18-CAA6-4913-8123-610872BFD60A}.Release|x64.ActiveCfg = Release|Any CPU
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Debug|Any CPU.ActiveCfg = Debug|x64
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Debug|Mixed Platforms.Build.0 = Debug|x64
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Debug|Win32.ActiveCfg = Debug|Win32
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Debug|Win32.Build.0 = Debug|Win32
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Debug|x64.ActiveCfg = Debug|x64
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Debug|x64.Build.0 = Debug|x64
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Release|Any CPU.ActiveCfg = Release|x64
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Release|Mixed Platforms.ActiveCfg = Release|x64
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Release|Mixed Platforms.Build.0 = Release|x64
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Release|Win32.ActiveCfg = Release|Win32
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Release|Win32.Build.0 = Release|Win32
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Release|x64.ActiveCfg = Release|x64
- {8774BCBE-27D0-44D2-A1B3-8ED705E252CB}.Release|x64.Build.0 = Release|x64
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Release|Any CPU.Build.0 = Release|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Release|Win32.ActiveCfg = Release|Any CPU
- {8A42A7F3-23C0-46D9-9DBA-B9039EB3C8EB}.Release|x64.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex.cs b/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex.cs
index fa88f11d..163af11f 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex.cs
@@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Acml
{
using System;
diff --git a/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex32.cs b/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex32.cs
index 0cbbc22d..6b68c436 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex32.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex32.cs
@@ -32,6 +32,8 @@
Last generated on UTC 2011-04-17 06:45:26Z
*/
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Acml
{
using System;
diff --git a/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.double.cs b/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.double.cs
index 66442c58..40083473 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.double.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.double.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Acml
{
using System;
diff --git a/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.float.cs b/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.float.cs
index 4e394c37..8a2f05e4 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.float.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.float.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Acml
{
using System;
diff --git a/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex.cs b/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex.cs
index 705a1d30..3a21567f 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
{
using System;
@@ -541,7 +543,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
/// 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)
+ public override void QRFactor(Complex[] r, int rowsR, int columnsR, Complex[] q, Complex[] tau, QRMethod method = QRMethod.Full)
{
if (r == null)
{
@@ -747,8 +749,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
///
/// 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 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
@@ -814,7 +816,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
///
/// 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 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
diff --git a/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex32.cs b/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex32.cs
index 45e8eeac..3afee23b 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex32.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex32.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
{
using System;
@@ -540,7 +542,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
/// 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)
+ public override void QRFactor(Complex32[] r, int rowsR, int columnsR, Complex32[] q, Complex32[] tau, QRMethod method = QRMethod.Full)
{
if (r == null)
{
@@ -746,8 +748,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
///
/// 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 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
@@ -813,7 +815,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
///
/// 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 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
diff --git a/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.double.cs b/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.double.cs
index 29824847..76319b64 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.double.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.double.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
{
using System;
@@ -540,7 +542,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
/// 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)
+ public override void QRFactor(double[] r, int rowsR, int columnsR, double[] q, double[] tau, QRMethod method = QRMethod.Full)
{
if (r == null)
{
@@ -746,8 +748,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
///
/// 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 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
@@ -813,7 +815,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
///
/// 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 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
diff --git a/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.float.cs b/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.float.cs
index 5dc75c37..76b4e5d5 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.float.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.float.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
{
using System;
@@ -540,7 +542,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
/// 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)
+ public override void QRFactor(float[] r, int rowsR, int columnsR, float[] q, float[] tau, QRMethod method = QRMethod.Full)
{
if (r == null)
{
@@ -746,8 +748,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
///
/// 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 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
@@ -813,7 +815,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
///
/// 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 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
diff --git a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs
index 8d4fdb85..a06f1af9 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs
@@ -25,6 +25,9 @@
//
// INITIAL DRAFT MISSING EXCEPTION SPECIFICATIONS
+
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra
{
using System.Numerics;
@@ -313,27 +316,58 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
void CholeskySolveFactored(T[] a, int orderA, T[] b, int columnsB);
///
- /// Computes the QR factorization of A.
+ /// Computes the full QR factorization of A.
///
- /// On entry, it is the M by N A matrix to factor. On exit,
+ /// 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.
+ /// 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.
- void QRFactor(T[] r, int rowsR, int columnsR, T[] q, T[] tau);
+ void QRFactor(T[] a, int rowsA, int columnsA, T[] q, T[] tau);
///
- /// Computes the QR factorization of A.
+ /// 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
+ /// 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.
+ ///
+ /// 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.
+ /// 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.
@@ -341,7 +375,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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[] r, int rowsR, int columnsR, T[] q, T[] tau, T[] work);
+ 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.
@@ -352,8 +386,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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.
- void QRSolve(T[] a, int rows, int columns, T[] b, int columnsB, T[] x);
+ 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.
@@ -367,8 +402,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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);
+ 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.
@@ -384,7 +420,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// The number of columns of B.
/// On exit, the solution matrix.
/// Rows must be greater or equal to columns.
- void QRSolveFactored(T[] q, T[] r, int rowsR, int columnsR, T[] tau, T[] b, int columnsB, T[] x);
+ /// The type of QR factorization to perform.
+ void QRSolveFactored(T[] q, T[] r, int rowsR, int columnsR, T[] tau, T[] b, int columnsB, T[] x, QRMethod method = QRMethod.Full);
///
/// Solves A*X=B for X using a previously QR factored matrix.
@@ -403,7 +440,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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.
- void QRSolveFactored(T[] q, T[] r, int rowsR, int columnsR, T[] tau, T[] b, int columnsB, T[] x, T[] work);
+ /// The type of QR factorization to perform.
+ void QRSolveFactored(T[] q, T[] r, int rowsR, int columnsR, T[] tau, T[] b, int columnsB, T[] x, T[] work, QRMethod method = QRMethod.Full);
///
/// Computes the singular value decomposition of A.
diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs
index 5b84df9d..3a0ff630 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs
@@ -23,6 +23,9 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
+
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra
{
using System;
@@ -1482,7 +1485,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
}
- var work = new Complex[rowsR * rowsR];
+ var work = columnsR > rowsR ? new Complex[rowsR * rowsR] : new Complex[rowsR * columnsR];
QRFactor(r, rowsR, columnsR, q, tau, work);
}
@@ -1533,10 +1536,21 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
}
- if (work.Length < rowsR * rowsR)
+ if (columnsR > rowsR)
{
- work[0] = rowsR * rowsR;
- throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
+ 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, i => q[(i * rowsR) + i] = Complex.One);
@@ -1553,9 +1567,139 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
ComputeQR(work, i, q, i, rowsR, i, rowsR, Control.NumberOfParallelWorkerThreads);
}
- work[0] = rowsR * rowsR;
+ work[0] = columnsR > rowsR ? rowsR * rowsR : rowsR * columnsR;
+ }
+
+ ///
+ /// 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 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.
+ /// This is similar to the GEQRF and ORGQR LAPACK routines.
+ public virtual void ThinQRFactor(Complex[] a, int rowsA, int columnsA, Complex[] r, Complex[] tau)
+ {
+ if (r == null)
+ {
+ throw new ArgumentNullException("r");
+ }
+
+ if (a == null)
+ {
+ throw new ArgumentNullException("a");
+ }
+
+ 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");
+ }
+
+ 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("q");
+ }
+
+ if (work == null)
+ {
+ throw new ArgumentNullException("q");
+ }
+
+ 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++)
+ {
+ GenerateColumn(work, a, rowsA, i, i);
+ ComputeQR(work, i, a, i, rowsA, i + 1, columnsA, Control.NumberOfParallelWorkerThreads);
+ }
+
+ //copy R
+ for (var j = 0; j < columnsA; j++)
+ {
+ var rIndex = j * columnsA;
+ var aIndex = j * rowsA;
+ for (var i = 0; i < columnsA; i++)
+ {
+ r[rIndex + i] = a[aIndex + i];
+ }
+ }
+
+ //clear A and set diagonals to 1
+ Array.Clear(a, 0, a.Length);
+ for (var i = 0; i < columnsA; i++)
+ {
+ a[i * rowsA + i] = Complex.One;
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(work, i, a, i, rowsA, i, columnsA, Control.NumberOfParallelWorkerThreads);
+ }
+
+ work[0] = rowsA * columnsA;
+ }
+
+
#region QR Factor Helper functions
///
@@ -1667,46 +1811,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x)
+ public virtual void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full)
{
- if (a == null)
- {
- throw new ArgumentNullException("a");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("b");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("x");
- }
-
- if (a.Length != rows * columns)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "a");
- }
-
- if (b.Length != rows * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columns * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rows < columns)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
- var work = new Complex[rows * rows];
- QRSolve(a, rows, columns, b, columnsB, x, work);
+ var work = new Complex[rows * columns];
+ QRSolve(a, rows, columns, b, columnsB, x, work, method);
}
///
@@ -1721,8 +1831,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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)
+ 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)
{
@@ -1764,19 +1875,29 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
}
- if (work.Length < rows * rows)
+ if (work.Length < rows * columns)
{
- work[0] = rows * rows;
+ work[0] = rows * columns;
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
var clone = new Complex[a.Length];
a.Copy(clone);
- var q = new Complex[rows * rows];
- QRFactor(clone, rows, columns, q, work);
- QRSolveFactored(q, clone, rows, columns, null, b, columnsB, x);
- work[0] = rows * rows;
+ if (method == QRMethod.Full)
+ {
+ var q = new Complex[rows * rows];
+ QRFactor(clone, rows, columns, q, work);
+ QRSolveFactored(q, clone, rows, columns, null, b, columnsB, x, method);
+ }
+ else
+ {
+ var r = new Complex[columns * columns];
+ ThinQRFactor(clone, rows, columns, r, work);
+ QRSolveFactored(clone, r, rows, columns, null, b, columnsB, x, method);
+ }
+
+ work[0] = rows * columns;
}
///
@@ -1795,10 +1916,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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)
+ 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);
+ QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, method);
}
///
@@ -1806,15 +1928,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
///
/// 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.
+ /// 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.
- public virtual void QRSolveFactored(Complex[] q, Complex[] r, int rowsR, int columnsR, Complex[] tau, Complex[] b, int columnsB, Complex[] x)
+ public virtual 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)
{
@@ -1836,50 +1959,63 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentNullException("q");
}
- if (r.Length != rowsR * columnsR)
+ if (rowsA < columnsA)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
+ throw new ArgumentException(Resources.RowsLessThanColumns);
}
- if (q.Length != rowsR * rowsR)
+ int rowsQ, columnsQ, rowsR, columnsR;
+ if( method == QRMethod.Full)
{
- throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
+ rowsQ = columnsQ = rowsR = rowsA;
+ columnsR = columnsA;
+ }
+ else
+ {
+ rowsQ = rowsA;
+ columnsQ = rowsR = columnsR = columnsA;
+ }
+
+ if (r.Length != rowsR * columnsR)
+ {
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r");
}
- if (b.Length != rowsR * columnsB)
+ if (q.Length != rowsQ * columnsQ)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q");
}
- if (x.Length != columnsR * columnsB)
+ if (b.Length != rowsA * columnsB)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b");
}
- if (rowsR < columnsR)
+ if (x.Length != columnsA * columnsB)
{
- throw new ArgumentException(Resources.RowsLessThanColumns);
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x");
}
var sol = new Complex[b.Length];
// Copy B matrix to "sol", so B data will not be changed
- CommonParallel.For(0, b.Length, index => sol[index] = b[index]);
+ Array.Copy(b, sol, b.Length);
// Compute Y = transpose(Q)*B
- var column = new Complex[rowsR];
+ var column = new Complex[rowsA];
for (var j = 0; j < columnsB; j++)
{
- var jm = j * rowsR;
- CommonParallel.For(0, rowsR, k => column[k] = sol[jm + k]);
+ var jm = j * rowsA;
+ CommonParallel.For(0, rowsA, k => column[k] = sol[jm + k]);
CommonParallel.For(
- 0,
- rowsR,
+ 0,
+ columnsA,
i =>
{
- var im = i * rowsR;
+ var im = i * rowsA;
+
var sum = Complex.Zero;
- for (var k = 0; k < rowsR; k++)
+ for (var k = 0; k < rowsA; k++)
{
sum += q[im + k].Conjugate() * column[k];
}
@@ -1889,19 +2025,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
}
// Solve R*X = Y;
- for (var k = columnsR - 1; k >= 0; k--)
+ for (var k = columnsA - 1; k >= 0; k--)
{
var km = k * rowsR;
for (var j = 0; j < columnsB; j++)
{
- sol[(j * rowsR) + k] /= r[km + k];
+ sol[(j * rowsA) + k] /= r[km + k];
}
for (var i = 0; i < k; i++)
{
for (var j = 0; j < columnsB; j++)
{
- var jm = j * rowsR;
+ var jm = j * rowsA;
sol[jm + i] -= sol[jm + k] * r[km + i];
}
}
@@ -1909,16 +2045,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
// Fill result matrix
CommonParallel.For(
- 0,
- columnsR,
+ 0,
+ columnsR,
row =>
{
for (var col = 0; col < columnsB; col++)
{
- x[(col * columnsR) + row] = sol[row + (col * rowsR)];
+ x[(col * columnsA) + row] = sol[row + (col * rowsA)];
}
});
- }
+ }
///
/// Computes the singular value decomposition of A.
diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs
index 61c955e4..728caf75 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs
@@ -23,6 +23,10 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
+
+using System.Numerics;
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra
{
using System;
@@ -1478,7 +1482,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
}
- var work = new Complex32[rowsR * rowsR];
+ var work = columnsR > rowsR ? new Complex32 [rowsR * rowsR] : new Complex32[rowsR * columnsR];
QRFactor(r, rowsR, columnsR, q, tau, work);
}
@@ -1529,10 +1533,21 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
}
- if (work.Length < rowsR * rowsR)
+ if (columnsR > rowsR)
{
- work[0] = rowsR * rowsR;
- throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
+ 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, i => q[(i * rowsR) + i] = Complex32.One);
@@ -1549,9 +1564,139 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
ComputeQR(work, i, q, i, rowsR, i, rowsR, Control.NumberOfParallelWorkerThreads);
}
- work[0] = rowsR * rowsR;
+ work[0] = columnsR > rowsR ? rowsR * rowsR : rowsR * columnsR;
+ }
+
+ ///
+ /// 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 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.
+ /// This is similar to the GEQRF and ORGQR LAPACK routines.
+ public virtual void ThinQRFactor(Complex32[] a, int rowsA, int columnsA, Complex32[] r, Complex32[] tau)
+ {
+ if (r == null)
+ {
+ throw new ArgumentNullException("r");
+ }
+
+ if (a == null)
+ {
+ throw new ArgumentNullException("a");
+ }
+
+ 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");
+ }
+
+ 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("q");
+ }
+
+ if (work == null)
+ {
+ throw new ArgumentNullException("q");
+ }
+
+ 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++)
+ {
+ GenerateColumn(work, a, rowsA, i, i);
+ ComputeQR(work, i, a, i, rowsA, i + 1, columnsA, Control.NumberOfParallelWorkerThreads);
+ }
+
+ //copy R
+ for (var j = 0; j < columnsA; j++)
+ {
+ var rIndex = j * columnsA;
+ var aIndex = j * rowsA;
+ for (var i = 0; i < columnsA; i++)
+ {
+ r[rIndex + i] = a[aIndex + i];
+ }
+ }
+
+ //clear A and set diagonals to 1
+ Array.Clear(a, 0, a.Length);
+ for (var i = 0; i < columnsA; i++)
+ {
+ a[i * rowsA + i] = Complex32.One;
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(work, i, a, i, rowsA, i, columnsA, Control.NumberOfParallelWorkerThreads);
+ }
+
+ work[0] = rowsA * columnsA;
}
+
#region QR Factor Helper functions
///
@@ -1663,46 +1808,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x)
+ public virtual void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full)
{
- if (a == null)
- {
- throw new ArgumentNullException("a");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("b");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("x");
- }
-
- if (a.Length != rows * columns)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "a");
- }
-
- if (b.Length != rows * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columns * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rows < columns)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
- var work = new Complex32[rows * rows];
- QRSolve(a, rows, columns, b, columnsB, x, work);
+ var work = new Complex32[rows * columns];
+ QRSolve(a, rows, columns, b, columnsB, x, work, method);
}
///
@@ -1717,8 +1828,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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)
+ 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)
{
@@ -1760,19 +1872,29 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(Resources.RowsLessThanColumns);
}
- if (work.Length < rows * rows)
+ if (work.Length < rows * columns)
{
- work[0] = rows * rows;
+ work[0] = rows * columns;
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
var clone = new Complex32[a.Length];
a.Copy(clone);
- var q = new Complex32[rows * rows];
- QRFactor(clone, rows, columns, q, work);
- QRSolveFactored(q, clone, rows, columns, null, b, columnsB, x);
- work[0] = rows * rows;
+ if (method == QRMethod.Full)
+ {
+ var q = new Complex32[rows * rows];
+ QRFactor(clone, rows, columns, q, work);
+ QRSolveFactored(q, clone, rows, columns, null, b, columnsB, x, method);
+ }
+ else
+ {
+ var r = new Complex32[columns * columns];
+ ThinQRFactor(clone, rows, columns, r, work);
+ QRSolveFactored(clone, r, rows, columns, null, b, columnsB, x, method);
+ }
+
+ work[0] = rows * columns;
}
///
@@ -1791,10 +1913,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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)
+ 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);
+ QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, method);
}
///
@@ -1802,15 +1925,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
///
/// 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.
+ /// 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.
- public virtual void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsR, int columnsR, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x)
+ public virtual 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)
{
@@ -1832,50 +1956,63 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentNullException("q");
}
- if (r.Length != rowsR * columnsR)
+ if (rowsA < columnsA)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
+ throw new ArgumentException(Resources.RowsLessThanColumns);
}
- if (q.Length != rowsR * rowsR)
+ int rowsQ, columnsQ, rowsR, columnsR;
+ if (method == QRMethod.Full)
{
- throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
+ rowsQ = columnsQ = rowsR = rowsA;
+ columnsR = columnsA;
+ }
+ else
+ {
+ rowsQ = rowsA;
+ columnsQ = rowsR = columnsR = columnsA;
}
- if (b.Length != rowsR * columnsB)
+ if (r.Length != rowsR * columnsR)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r");
}
- if (x.Length != columnsR * columnsB)
+ if (q.Length != rowsQ * columnsQ)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q");
}
- if (rowsR < columnsR)
+ if (b.Length != rowsA * columnsB)
{
- throw new ArgumentException(Resources.RowsLessThanColumns);
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b");
+ }
+
+ if (x.Length != columnsA * columnsB)
+ {
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x");
}
var sol = new Complex32[b.Length];
// Copy B matrix to "sol", so B data will not be changed
- CommonParallel.For(0, b.Length, index => sol[index] = b[index]);
+ Array.Copy(b, sol, b.Length);
// Compute Y = transpose(Q)*B
- var column = new Complex32[rowsR];
+ var column = new Complex32[rowsA];
for (var j = 0; j < columnsB; j++)
{
- var jm = j * rowsR;
- CommonParallel.For(0, rowsR, k => column[k] = sol[jm + k]);
+ var jm = j * rowsA;
+ CommonParallel.For(0, rowsA, k => column[k] = sol[jm + k]);
CommonParallel.For(
0,
- rowsR,
+ columnsA,
i =>
{
- var im = i * rowsR;
+ var im = i * rowsA;
+
var sum = Complex32.Zero;
- for (var k = 0; k < rowsR; k++)
+ for (var k = 0; k < rowsA; k++)
{
sum += q[im + k].Conjugate() * column[k];
}
@@ -1885,19 +2022,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
}
// Solve R*X = Y;
- for (var k = columnsR - 1; k >= 0; k--)
+ for (var k = columnsA - 1; k >= 0; k--)
{
var km = k * rowsR;
for (var j = 0; j < columnsB; j++)
{
- sol[(j * rowsR) + k] /= r[km + k];
+ sol[(j * rowsA) + k] /= r[km + k];
}
for (var i = 0; i < k; i++)
{
for (var j = 0; j < columnsB; j++)
{
- var jm = j * rowsR;
+ var jm = j * rowsA;
sol[jm + i] -= sol[jm + k] * r[km + i];
}
}
@@ -1911,7 +2048,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
{
for (var col = 0; col < columnsB; col++)
{
- x[(col * columnsR) + row] = sol[row + (col * rowsR)];
+ x[(col * columnsA) + row] = sol[row + (col * rowsA)];
}
});
}
diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs
index aabfc893..860d886d 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs
@@ -23,6 +23,9 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
+
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra
{
using System;
@@ -1339,6 +1342,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// QR factorization.
/// A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.
+ /// The type of QR factorization to perform.
/// This is similar to the GEQRF and ORGQR LAPACK routines.
public virtual void QRFactor(double[] r, int rowsR, int columnsR, double[] q, double[] tau)
{
@@ -1367,7 +1371,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
}
- var work = new double[rowsR * rowsR];
+
+ var work = columnsR > rowsR ? new double[rowsR * rowsR] : new double[rowsR * columnsR];
QRFactor(r, rowsR, columnsR, q, tau, work);
}
@@ -1418,10 +1423,21 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
}
- if (work.Length < rowsR * rowsR)
+ if (columnsR > rowsR)
{
- work[0] = rowsR * rowsR;
- throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
+ 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, i => q[(i * rowsR) + i] = 1.0);
@@ -1438,7 +1454,136 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
ComputeQR(work, i, q, i, rowsR, i, rowsR, Control.NumberOfParallelWorkerThreads);
}
- work[0] = rowsR * rowsR;
+ work[0] = columnsR > rowsR ? rowsR * rowsR : rowsR * columnsR;
+ }
+
+ ///
+ /// 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 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.
+ /// This is similar to the GEQRF and ORGQR LAPACK routines.
+ public virtual void ThinQRFactor(double[] a, int rowsA, int columnsA, double[] r, double[] tau)
+ {
+ if (r == null)
+ {
+ throw new ArgumentNullException("r");
+ }
+
+ if (a == null)
+ {
+ throw new ArgumentNullException("a");
+ }
+
+ 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");
+ }
+
+ 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("q");
+ }
+
+ if (work == null)
+ {
+ throw new ArgumentNullException("q");
+ }
+
+ 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++)
+ {
+ GenerateColumn(work, a, rowsA, i, i);
+ ComputeQR(work, i, a, i, rowsA, i + 1, columnsA, Control.NumberOfParallelWorkerThreads);
+ }
+
+ //copy R
+ for (var j = 0; j < columnsA; j++ )
+ {
+ var rIndex = j * columnsA;
+ var aIndex = j * rowsA;
+ for (var i = 0; i < columnsA; i++)
+ {
+ r[rIndex + i] = a[aIndex+i];
+ }
+ }
+
+ //clear A and set diagonals to 1
+ Array.Clear(a, 0, a.Length);
+ for (var i = 0; i < columnsA; i++ )
+ {
+ a[i * rowsA + i] = 1.0;
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(work, i, a, i, rowsA, i, columnsA, Control.NumberOfParallelWorkerThreads);
+ }
+
+ work[0] = rowsA * columnsA;
}
#region QR Factor Helper functions
@@ -1553,46 +1698,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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(double[] a, int rows, int columns, double[] b, int columnsB, double[] x)
+ public virtual void QRSolve(double[] a, int rows, int columns, double[] b, int columnsB, double[] x, QRMethod method = QRMethod.Full)
{
- if (a == null)
- {
- throw new ArgumentNullException("a");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("b");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("x");
- }
-
- if (a.Length != rows * columns)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "a");
- }
-
- if (b.Length != rows * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columns * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rows < columns)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
- var work = new double[rows * rows];
- QRSolve(a, rows, columns, b, columnsB, x, work);
+ var work = new double[rows * columns];
+ QRSolve(a, rows, columns, b, columnsB, x, work, method);
}
///
@@ -1607,8 +1718,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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)
+ 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)
{
@@ -1650,19 +1762,28 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(Resources.RowsLessThanColumns);
}
- if (work.Length < rows * rows)
+ if (work.Length < rows * columns)
{
- work[0] = rows * rows;
+ work[0] = rows * columns;
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
var clone = new double[a.Length];
- a.Copy(clone);
- var q = new double[rows * rows];
- QRFactor(clone, rows, columns, q, work);
- QRSolveFactored(q, clone, rows, columns, null, b, columnsB, x);
+ a.Copy(clone);
+
+ if (method == QRMethod.Full)
+ {
+ var q = new double[rows * rows];
+ QRFactor(clone, rows, columns, q, work);
+ QRSolveFactored(q, clone, rows, columns, null, b, columnsB, x, method);
+ } else
+ {
+ var r = new double[columns * columns];
+ ThinQRFactor(clone, rows, columns, r, work);
+ QRSolveFactored(clone, r, rows, columns, null, b, columnsB, x, method);
+ }
- work[0] = rows * rows;
+ work[0] = rows * columns;
}
///
@@ -1671,8 +1792,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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.
+ /// 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.
@@ -1681,10 +1802,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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 rowsR, int columnsR, double[] tau, double[] b, int columnsB, double[] x, double[] work)
+ 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, rowsR, columnsR, tau, b, columnsB, x);
+ QRSolveFactored(q, r, rowsA, columnsA, tau, b, columnsB, x, method);
}
///
@@ -1692,15 +1814,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
///
/// 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.
+ /// 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.
- public virtual void QRSolveFactored(double[] q, double[] r, int rowsR, int columnsR, double[] tau, double[] b, int columnsB, double[] x)
+ public virtual 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)
{
@@ -1722,29 +1845,41 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentNullException("q");
}
- if (r.Length != rowsR * columnsR)
+ if (rowsA < columnsA)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
+ throw new ArgumentException(Resources.RowsLessThanColumns);
}
- if (q.Length != rowsR * rowsR)
+ int rowsQ, columnsQ, rowsR, columnsR;
+ if( method == QRMethod.Full)
{
- throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
+ rowsQ = columnsQ = rowsR = rowsA;
+ columnsR = columnsA;
+ }
+ else
+ {
+ rowsQ = rowsA;
+ columnsQ = rowsR = columnsR = columnsA;
}
- if (b.Length != rowsR * columnsB)
+ if (r.Length != rowsR * columnsR)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r");
}
- if (x.Length != columnsR * columnsB)
+ if (q.Length != rowsQ * columnsQ)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q");
+ }
+
+ if (b.Length != rowsA * columnsB)
+ {
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b");
}
- if (rowsR < columnsR)
+ if (x.Length != columnsA * columnsB)
{
- throw new ArgumentException(Resources.RowsLessThanColumns);
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x");
}
var sol = new double[b.Length];
@@ -1753,20 +1888,20 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
Buffer.BlockCopy(b, 0, sol, 0, b.Length * Constants.SizeOfDouble);
// Compute Y = transpose(Q)*B
- var column = new double[rowsR];
+ var column = new double[rowsA];
for (var j = 0; j < columnsB; j++)
{
- var jm = j * rowsR;
- CommonParallel.For(0, rowsR, k => column[k] = sol[jm + k]);
+ var jm = j * rowsA;
+ CommonParallel.For(0, rowsA, k => column[k] = sol[jm + k]);
CommonParallel.For(
0,
- rowsR,
+ columnsA,
i =>
{
- var im = i * rowsR;
+ var im = i * rowsA;
var sum = 0.0;
- for (var k = 0; k < rowsR; k++)
+ for (var k = 0; k < rowsA; k++)
{
sum += q[im + k] * column[k];
}
@@ -1776,19 +1911,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
}
// Solve R*X = Y;
- for (var k = columnsR - 1; k >= 0; k--)
+ for (var k = columnsA - 1; k >= 0; k--)
{
var km = k * rowsR;
for (var j = 0; j < columnsB; j++)
{
- sol[(j * rowsR) + k] /= r[km + k];
+ sol[(j * rowsA) + k] /= r[km + k];
}
for (var i = 0; i < k; i++)
{
for (var j = 0; j < columnsB; j++)
{
- var jm = j * rowsR;
+ var jm = j * rowsA;
sol[jm + i] -= sol[jm + k] * r[km + i];
}
}
@@ -1802,7 +1937,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
{
for (var col = 0; col < columnsB; col++)
{
- x[(col * columnsR) + row] = sol[row + (col * rowsR)];
+ x[(col * columnsA) + row] = sol[row + (col * rowsA)];
}
});
}
diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs
index 1a6b3162..925c1791 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs
@@ -23,6 +23,9 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
+
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra
{
using System;
@@ -1368,7 +1371,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
}
- var work = new float[rowsR * rowsR];
+ var work = columnsR > rowsR ? new float[rowsR * rowsR] : new float[rowsR * columnsR];
QRFactor(r, rowsR, columnsR, q, tau, work);
}
@@ -1419,10 +1422,21 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
}
- if (work.Length < rowsR * rowsR)
+ if (columnsR > rowsR)
{
- work[0] = rowsR * rowsR;
- throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
+ 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, i => q[(i * rowsR) + i] = 1.0f);
@@ -1439,9 +1453,139 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
ComputeQR(work, i, q, i, rowsR, i, rowsR, Control.NumberOfParallelWorkerThreads);
}
- work[0] = rowsR * rowsR;
+ work[0] = columnsR > rowsR ? rowsR * rowsR : rowsR * columnsR;
}
+ ///
+ /// 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 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.
+ /// This is similar to the GEQRF and ORGQR LAPACK routines.
+ public virtual void ThinQRFactor(float[] a, int rowsA, int columnsA, float[] r, float[] tau)
+ {
+ if (r == null)
+ {
+ throw new ArgumentNullException("r");
+ }
+
+ if (a == null)
+ {
+ throw new ArgumentNullException("a");
+ }
+
+ 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");
+ }
+
+ 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("q");
+ }
+
+ if (work == null)
+ {
+ throw new ArgumentNullException("q");
+ }
+
+ 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++)
+ {
+ GenerateColumn(work, a, rowsA, i, i);
+ ComputeQR(work, i, a, i, rowsA, i + 1, columnsA, Control.NumberOfParallelWorkerThreads);
+ }
+
+ //copy R
+ for (var j = 0; j < columnsA; j++)
+ {
+ var rIndex = j * columnsA;
+ var aIndex = j * rowsA;
+ for (var i = 0; i < columnsA; i++)
+ {
+ r[rIndex + i] = a[aIndex + i];
+ }
+ }
+
+ //clear A and set diagonals to 1
+ Array.Clear(a, 0, a.Length);
+ for (var i = 0; i < columnsA; i++)
+ {
+ a[i * rowsA + i] = 1.0f;
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(work, i, a, i, rowsA, i, columnsA, Control.NumberOfParallelWorkerThreads);
+ }
+
+ work[0] = rowsA * columnsA;
+ }
+
+
#region QR Factor Helper functions
///
@@ -1554,46 +1698,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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)
+ public virtual void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, QRMethod method = QRMethod.Full)
{
- if (a == null)
- {
- throw new ArgumentNullException("a");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("b");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("x");
- }
-
- if (a.Length != rows * columns)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "a");
- }
-
- if (b.Length != rows * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columns * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rows < columns)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
- var work = new float[rows * rows];
- QRSolve(a, rows, columns, b, columnsB, x, work);
+ var work = new float[rows * columns];
+ QRSolve(a, rows, columns, b, columnsB, x, work, method);
}
///
@@ -1608,8 +1718,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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)
+ public virtual void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, float[] work, QRMethod method = QRMethod.Full)
{
if (a == null)
{
@@ -1651,19 +1762,29 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentException(Resources.RowsLessThanColumns);
}
- if (work.Length < rows * rows)
+ if (work.Length < rows * columns)
{
- work[0] = rows * rows;
+ work[0] = rows * columns;
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
var clone = new float[a.Length];
- a.Copy(clone);
- var q = new float[rows * rows];
- QRFactor(clone, rows, columns, q, work);
- QRSolveFactored(q, clone, rows, columns, null, b, columnsB, x);
+ a.Copy(clone);
- work[0] = rows * rows;
+ if (method == QRMethod.Full)
+ {
+ var q = new float[rows * rows];
+ QRFactor(clone, rows, columns, q, work);
+ QRSolveFactored(q, clone, rows, columns, null, b, columnsB, x, method);
+ }
+ else
+ {
+ var r = new float[columns * columns];
+ ThinQRFactor(clone, rows, columns, r, work);
+ QRSolveFactored(clone, r, rows, columns, null, b, columnsB, x, method);
+ }
+
+ work[0] = rows * columns;
}
///
@@ -1672,8 +1793,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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.
+ /// 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.
@@ -1682,9 +1803,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// 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.
- public virtual void QRSolveFactored(float[] q, float[] r, int rowsR, int columnsR, float[] tau, float[] b, int columnsB, float[] x, float[] work)
+ /// 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, rowsR, columnsR, tau, b, columnsB, x);
+ QRSolveFactored(q, r, rowsA, columnsA, tau, b, columnsB, x, method);
}
///
@@ -1692,15 +1815,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
///
/// 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.
+ /// 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.
- public virtual void QRSolveFactored(float[] q, float[] r, int rowsR, int columnsR, float[] tau, float[] b, int columnsB, float[] x)
+ public virtual 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)
{
@@ -1722,29 +1846,41 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
throw new ArgumentNullException("q");
}
- if (r.Length != rowsR * columnsR)
+ if (rowsA < columnsA)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
+ throw new ArgumentException(Resources.RowsLessThanColumns);
}
- if (q.Length != rowsR * rowsR)
+ int rowsQ, columnsQ, rowsR, columnsR;
+ if (method == QRMethod.Full)
{
- throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * rowsR"), "q");
+ rowsQ = columnsQ = rowsR = rowsA;
+ columnsR = columnsA;
+ }
+ else
+ {
+ rowsQ = rowsA;
+ columnsQ = rowsR = columnsR = columnsA;
}
- if (b.Length != rowsR * columnsB)
+ if (r.Length != rowsR * columnsR)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r");
}
- if (x.Length != columnsR * columnsB)
+ if (q.Length != rowsQ * columnsQ)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q");
+ }
+
+ if (b.Length != rowsA * columnsB)
+ {
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b");
}
- if (rowsR < columnsR)
+ if (x.Length != columnsA * columnsB)
{
- throw new ArgumentException(Resources.RowsLessThanColumns);
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x");
}
var sol = new float[b.Length];
@@ -1753,20 +1889,20 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
Buffer.BlockCopy(b, 0, sol, 0, b.Length * Constants.SizeOfFloat);
// Compute Y = transpose(Q)*B
- var column = new float[rowsR];
+ var column = new float[rowsA];
for (var j = 0; j < columnsB; j++)
{
- var jm = j * rowsR;
- CommonParallel.For(0, rowsR, k => column[k] = sol[jm + k]);
+ var jm = j * rowsA;
+ CommonParallel.For(0, rowsA, k => column[k] = sol[jm + k]);
CommonParallel.For(
0,
- rowsR,
+ columnsA,
i =>
{
- var im = i * rowsR;
+ var im = i * rowsA;
var sum = 0.0f;
- for (var k = 0; k < rowsR; k++)
+ for (var k = 0; k < rowsA; k++)
{
sum += q[im + k] * column[k];
}
@@ -1776,19 +1912,19 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
}
// Solve R*X = Y;
- for (var k = columnsR - 1; k >= 0; k--)
+ for (var k = columnsA - 1; k >= 0; k--)
{
var km = k * rowsR;
for (var j = 0; j < columnsB; j++)
{
- sol[(j * rowsR) + k] /= r[km + k];
+ sol[(j * rowsA) + k] /= r[km + k];
}
for (var i = 0; i < k; i++)
{
for (var j = 0; j < columnsB; j++)
{
- var jm = j * rowsR;
+ var jm = j * rowsA;
sol[jm + i] -= sol[jm + k] * r[km + i];
}
}
@@ -1802,7 +1938,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
{
for (var col = 0; col < columnsB; col++)
{
- x[(col * columnsR) + row] = sol[row + (col * rowsR)];
+ x[(col * columnsA) + row] = sol[row + (col * rowsA)];
}
});
}
diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs
index f3fd66e5..5ac470e4 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
{
using System;
@@ -666,46 +668,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x)
+ [SecuritySafeCritical]
+ public override void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full)
{
- if (a == null)
- {
- throw new ArgumentNullException("a");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("b");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("x");
- }
-
- if (a.Length != rows * columns)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "a");
- }
-
- if (b.Length != rows * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columns * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rows < columns)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
var work = new Complex[columns * Control.BlockSize];
- QRSolve(a, rows, columns, b, columnsB, x, work);
+ QRSolve(a, rows, columns, b, columnsB, x, work, method);
}
///
@@ -720,8 +689,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolve(Complex[] a, int rows, int columns, Complex[] b, int columnsB, Complex[] x, Complex[] work)
+ [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)
{
@@ -769,7 +740,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
- SafeNativeMethods.z_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ if (method == QRMethod.Full)
+ {
+ SafeNativeMethods.z_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ }
+ else
+ {
+ SafeNativeMethods.z_thin_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ }
}
///
@@ -784,57 +762,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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)
+ public override void QRSolveFactored(Complex[] q, Complex[] r, int rowsR, int columnsR, Complex[] tau, Complex[] b, int columnsB, Complex[] x, QRMethod method = QRMethod.Full)
{
- if (r == null)
- {
- throw new ArgumentNullException("r");
- }
-
- if (q == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (r.Length != rowsR * columnsR)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
- }
-
- if (q.Length != rowsR * rowsR)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "q");
- }
-
- if (b.Length != rowsR * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columnsR * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rowsR < columnsR)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
var work = new Complex[columnsR * Control.BlockSize];
- QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work);
+ QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method);
}
///
@@ -843,8 +777,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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.
+ /// 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.
@@ -853,8 +787,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolveFactored(Complex[] q, Complex[] r, int rowsR, int columnsR, Complex[] tau, Complex[] b, int columnsB, Complex[] x, Complex[] work)
+ [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)
{
if (r == null)
{
@@ -881,38 +817,54 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
throw new ArgumentNullException("work");
}
- if (r.Length != rowsR * columnsR)
+ int rowsQ, columnsQ, rowsR, columnsR;
+ if (method == QRMethod.Full)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
+ rowsQ = columnsQ = rowsR = rowsA;
+ columnsR = columnsA;
+ }
+ else
+ {
+ rowsQ = rowsA;
+ columnsQ = rowsR = columnsR = columnsA;
}
- if (q.Length != rowsR * rowsR)
+ if (r.Length != rowsR * columnsR)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "q");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r");
}
- if (b.Length != rowsR * columnsB)
+ if (q.Length != rowsQ * columnsQ)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q");
}
- if (x.Length != columnsR * columnsB)
+ if (b.Length != rowsA * columnsB)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b");
}
- if (rowsR < columnsR)
+ if (x.Length != columnsA * columnsB)
{
- throw new ArgumentException(Resources.RowsLessThanColumns);
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x");
}
if (work.Length < 1)
{
- work[0] = rowsR * Control.BlockSize;
+ work[0] = rowsA * Control.BlockSize;
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
- SafeNativeMethods.z_qr_solve_factored(rowsR, columnsR, columnsB, r, b, tau, x, work, work.Length);
+ if (method == QRMethod.Full)
+ {
+ SafeNativeMethods.z_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length);
+ }
+ else
+ {
+ // we don't have access to the raw Q matrix any more(it is stored in R in the full QR), need to think about this.
+ // let just call the managed version in the meantime. The heavy lifting has already been done. -marcus
+ base.QRSolveFactored(q, r, rowsA, columnsA, tau, b, columnsB, x, QRMethod.Thin);
+ }
}
///
diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs
index 95fba8cf..d1a0433c 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
{
using System;
@@ -665,46 +667,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x)
+ [SecuritySafeCritical]
+ public override void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full)
{
- if (a == null)
- {
- throw new ArgumentNullException("a");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("b");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("x");
- }
-
- if (a.Length != rows * columns)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "a");
- }
-
- if (b.Length != rows * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columns * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rows < columns)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
var work = new Complex32[columns * Control.BlockSize];
- QRSolve(a, rows, columns, b, columnsB, x, work);
+ QRSolve(a, rows, columns, b, columnsB, x, work, method);
}
///
@@ -719,8 +688,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x, Complex32[] work)
+ [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)
{
@@ -768,7 +739,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
- SafeNativeMethods.c_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ if (method == QRMethod.Full)
+ {
+ SafeNativeMethods.c_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ }
+ else
+ {
+ SafeNativeMethods.c_thin_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ }
}
///
@@ -783,57 +761,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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)
+ public override void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsR, int columnsR, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full)
{
- if (r == null)
- {
- throw new ArgumentNullException("r");
- }
-
- if (q == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (r.Length != rowsR * columnsR)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
- }
-
- if (q.Length != rowsR * rowsR)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "q");
- }
-
- if (b.Length != rowsR * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columnsR * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rowsR < columnsR)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
var work = new Complex32[columnsR * Control.BlockSize];
- QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work);
+ QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method);
}
///
@@ -842,8 +776,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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.
+ /// 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.
@@ -852,8 +786,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsR, int columnsR, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x, Complex32[] work)
+ [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)
{
if (r == null)
{
@@ -880,38 +816,54 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
throw new ArgumentNullException("work");
}
- if (r.Length != rowsR * columnsR)
+ int rowsQ, columnsQ, rowsR, columnsR;
+ if (method == QRMethod.Full)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
+ rowsQ = columnsQ = rowsR = rowsA;
+ columnsR = columnsA;
+ }
+ else
+ {
+ rowsQ = rowsA;
+ columnsQ = rowsR = columnsR = columnsA;
}
- if (q.Length != rowsR * rowsR)
+ if (r.Length != rowsR * columnsR)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "q");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r");
}
- if (b.Length != rowsR * columnsB)
+ if (q.Length != rowsQ * columnsQ)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q");
}
- if (x.Length != columnsR * columnsB)
+ if (b.Length != rowsA * columnsB)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b");
}
- if (rowsR < columnsR)
+ if (x.Length != columnsA * columnsB)
{
- throw new ArgumentException(Resources.RowsLessThanColumns);
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x");
}
if (work.Length < 1)
{
- work[0] = rowsR * Control.BlockSize;
+ work[0] = rowsA * Control.BlockSize;
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
- SafeNativeMethods.c_qr_solve_factored(rowsR, columnsR, columnsB, r, b, tau, x, work, work.Length);
+ if (method == QRMethod.Full)
+ {
+ SafeNativeMethods.c_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length);
+ }
+ else
+ {
+ // we don't have access to the raw Q matrix any more(it is stored in R in the full QR), need to think about this.
+ // let just call the managed version in the meantime. The heavy lifting has already been done. -marcus
+ base.QRSolveFactored(q, r, rowsA, columnsA, tau, b, columnsB, x, QRMethod.Thin);
+ }
}
///
diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs
index e7236f26..474f2642 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
{
using System;
@@ -657,54 +659,125 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
}
///
- /// Solves A*X=B for X using QR factorization of A.
+ /// Computes the thin QR factorization of A where M > N.
///
- /// 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.
- /// Rows must be greater or equal to columns.
- public override void QRSolve(double[] a, int rows, int columns, double[] b, int columnsB, double[] x)
+ /// 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.
+ /// 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)
{
- if (a == null)
+ if (r == null)
{
- throw new ArgumentNullException("a");
+ throw new ArgumentNullException("r");
}
- if (b == null)
+ if (q == null)
{
- throw new ArgumentNullException("b");
+ throw new ArgumentNullException("q");
}
- if (x == null)
+ if (q.Length != rowsA * columnsA)
{
- throw new ArgumentNullException("x");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "rowsR * columnsR"), "q");
}
- if (a.Length != rows * columns)
+ if (tau.Length < Math.Min(rowsA, columnsA))
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "a");
+ throw new ArgumentException(string.Format(Resources.ArrayTooSmall, "min(m,n)"), "tau");
}
- if (b.Length != rows * columnsB)
+ if (r.Length != columnsA*columnsA)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, "columnsA * columnsA"), "r");
}
- if (x.Length != columns * columnsB)
+ 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 ArgumentException(Resources.ArgumentArraysSameLength, "x");
+ throw new ArgumentNullException("r");
}
- if (rows < columns)
+ if (q == null)
{
- throw new ArgumentException(Resources.RowsLessThanColumns);
+ 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);
+ }
+
+ ///
+ /// 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.
+ [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);
+ QRSolve(a, rows, columns, b, columnsB, x, work, method);
}
///
@@ -719,8 +792,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolve(double[] a, int rows, int columns, double[] b, int columnsB, double[] x, double[] work)
+ [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)
{
@@ -768,7 +843,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
- SafeNativeMethods.d_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ if (method == QRMethod.Full)
+ {
+ SafeNativeMethods.d_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ }
+ else
+ {
+ SafeNativeMethods.d_thin_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ }
}
///
@@ -783,57 +865,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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)
+ public override void QRSolveFactored(double[] q, double[] r, int rowsR, int columnsR, double[] tau, double[] b, int columnsB, double[] x, QRMethod method = QRMethod.Full)
{
- if (r == null)
- {
- throw new ArgumentNullException("r");
- }
-
- if (q == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (r.Length != rowsR * columnsR)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
- }
-
- if (q.Length != rowsR * rowsR)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "q");
- }
-
- if (b.Length != rowsR * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columnsR * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rowsR < columnsR)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
var work = new double[columnsR * Control.BlockSize];
- QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work);
+ QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method);
}
///
@@ -842,8 +880,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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.
+ /// 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.
@@ -852,8 +890,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolveFactored(double[] q, double[] r, int rowsR, int columnsR, double[] tau, double[] b, int columnsB, double[] x, double[] work)
+ [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)
{
if (r == null)
{
@@ -880,38 +920,54 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
throw new ArgumentNullException("work");
}
- if (r.Length != rowsR * columnsR)
+ int rowsQ, columnsQ, rowsR, columnsR;
+ if( method == QRMethod.Full)
+ {
+ rowsQ = columnsQ = rowsR = rowsA;
+ columnsR = columnsA;
+ }
+ else
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
+ rowsQ = rowsA;
+ columnsQ = rowsR = columnsR = columnsA;
}
- if (q.Length != rowsR * rowsR)
+ if (r.Length != rowsR * columnsR)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "q");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r");
}
- if (b.Length != rowsR * columnsB)
+ if (q.Length != rowsQ * columnsQ)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q");
}
- if (x.Length != columnsR * columnsB)
+ if (b.Length != rowsA * columnsB)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b");
}
- if (rowsR < columnsR)
+ if (x.Length != columnsA * columnsB)
{
- throw new ArgumentException(Resources.RowsLessThanColumns);
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x");
}
if (work.Length < 1)
{
- work[0] = rowsR * Control.BlockSize;
+ work[0] = rowsA * Control.BlockSize;
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
- SafeNativeMethods.d_qr_solve_factored(rowsR, columnsR, columnsB, r, b, tau, x, work, work.Length);
+ if (method == QRMethod.Full)
+ {
+ SafeNativeMethods.d_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length);
+ }
+ else
+ {
+ // we don't have access to the raw Q matrix any more(it is stored in R in the full QR), need to think about this.
+ // let just call the managed version in the meantime. The heavy lifting has already been done. -marcus
+ base.QRSolveFactored(q, r, rowsA, columnsA, tau, b, columnsB, x, QRMethod.Thin);
+ }
}
///
diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.float.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.float.cs
index a95d3e38..6da7054e 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.float.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.float.cs
@@ -32,6 +32,8 @@
Last generated on UTC 2011-04-17 06:45:23Z
*/
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
{
using System;
@@ -669,46 +671,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x)
+ [SecuritySafeCritical]
+ public override void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, QRMethod method = QRMethod.Full)
{
- if (a == null)
- {
- throw new ArgumentNullException("a");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("b");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("x");
- }
-
- if (a.Length != rows * columns)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "a");
- }
-
- if (b.Length != rows * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columns * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rows < columns)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
var work = new float[columns * Control.BlockSize];
- QRSolve(a, rows, columns, b, columnsB, x, work);
+ QRSolve(a, rows, columns, b, columnsB, x, work, method);
}
///
@@ -723,8 +692,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolve(float[] a, int rows, int columns, float[] b, int columnsB, float[] x, float[] work)
+ [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)
{
@@ -772,7 +743,14 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
- SafeNativeMethods.s_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ if (method == QRMethod.Full)
+ {
+ SafeNativeMethods.s_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ }
+ else
+ {
+ SafeNativeMethods.s_thin_qr_solve(rows, columns, columnsB, a, b, x, work, work.Length);
+ }
}
///
@@ -787,57 +765,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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)
+ public override void QRSolveFactored(float[] q, float[] r, int rowsR, int columnsR, float[] tau, float[] b, int columnsB, float[] x, QRMethod method = QRMethod.Full)
{
- if (r == null)
- {
- throw new ArgumentNullException("r");
- }
-
- if (q == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (b == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (x == null)
- {
- throw new ArgumentNullException("q");
- }
-
- if (r.Length != rowsR * columnsR)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
- }
-
- if (q.Length != rowsR * rowsR)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "q");
- }
-
- if (b.Length != rowsR * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
- }
-
- if (x.Length != columnsR * columnsB)
- {
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
- }
-
- if (rowsR < columnsR)
- {
- throw new ArgumentException(Resources.RowsLessThanColumns);
- }
-
var work = new float[columnsR * Control.BlockSize];
- QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work);
+ QRSolveFactored(q, r, rowsR, columnsR, tau, b, columnsB, x, work, method);
}
///
@@ -846,8 +780,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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.
+ /// 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.
@@ -856,8 +790,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// 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 override void QRSolveFactored(float[] q, float[] r, int rowsR, int columnsR, float[] tau, float[] b, int columnsB, float[] x, float[] work)
+ [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)
{
if (r == null)
{
@@ -884,38 +820,54 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
throw new ArgumentNullException("work");
}
- if (r.Length != rowsR * columnsR)
+ int rowsQ, columnsQ, rowsR, columnsR;
+ if (method == QRMethod.Full)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "r");
+ rowsQ = columnsQ = rowsR = rowsA;
+ columnsR = columnsA;
+ }
+ else
+ {
+ rowsQ = rowsA;
+ columnsQ = rowsR = columnsR = columnsA;
}
- if (q.Length != rowsR * rowsR)
+ if (r.Length != rowsR * columnsR)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "q");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR * columnsR), "r");
}
- if (b.Length != rowsR * columnsB)
+ if (q.Length != rowsQ * columnsQ)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "b");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ * columnsQ), "q");
}
- if (x.Length != columnsR * columnsB)
+ if (b.Length != rowsA * columnsB)
{
- throw new ArgumentException(Resources.ArgumentArraysSameLength, "x");
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA * columnsB), "b");
}
- if (rowsR < columnsR)
+ if (x.Length != columnsA * columnsB)
{
- throw new ArgumentException(Resources.RowsLessThanColumns);
+ throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA * columnsB), "x");
}
if (work.Length < 1)
{
- work[0] = rowsR * Control.BlockSize;
+ work[0] = rowsA * Control.BlockSize;
throw new ArgumentException(Resources.WorkArrayTooSmall, "work");
}
- SafeNativeMethods.s_qr_solve_factored(rowsR, columnsR, columnsB, r, b, tau, x, work, work.Length);
+ if (method == QRMethod.Full)
+ {
+ SafeNativeMethods.s_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x, work, work.Length);
+ }
+ else
+ {
+ // we don't have access to the raw Q matrix any more(it is stored in R in the full QR), need to think about this.
+ // let just call the managed version in the meantime. The heavy lifting has already been done. -marcus
+ base.QRSolveFactored(q, r, rowsA, columnsA, tau, b, columnsB, x, QRMethod.Thin);
+ }
}
///
diff --git a/src/Numerics/Algorithms/LinearAlgebra/Mkl/SafeNativeMethods.cs b/src/Numerics/Algorithms/LinearAlgebra/Mkl/SafeNativeMethods.cs
index 4be8e91d..eceb2d2a 100644
--- a/src/Numerics/Algorithms/LinearAlgebra/Mkl/SafeNativeMethods.cs
+++ b/src/Numerics/Algorithms/LinearAlgebra/Mkl/SafeNativeMethods.cs
@@ -218,6 +218,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
[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);
+ [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);
+
+ [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);
+
+ [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);
+
+ [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);
+
[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);
@@ -230,6 +242,18 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
[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);
+ [DllImport(DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int s_thin_qr_solve(int m, int n, int bn, float[] r, float[] b, [In, Out] float[] x, [In, Out] float[] work, int len);
+
+ [DllImport(DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int d_thin_qr_solve(int m, int n, int bn, double[] r, double[] b, [In, Out] double[] x, [In, Out] double[] work, int len);
+
+ [DllImport(DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int c_thin_qr_solve(int m, int n, int bn, Complex32[] r, Complex32[] b, [In, Out] Complex32[] x, [In, Out] Complex32[] work, int len);
+
+ [DllImport(DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int z_thin_qr_solve(int m, int n, int bn, Complex[] r, Complex[] b, [In, Out] Complex[] x, [In, Out] Complex[] work, int len);
+
[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);
diff --git a/src/Numerics/LinearAlgebra/Complex/ExtensionMethods.cs b/src/Numerics/LinearAlgebra/Complex/ExtensionMethods.cs
index 0b228593..fb5e2c8d 100644
--- a/src/Numerics/LinearAlgebra/Complex/ExtensionMethods.cs
+++ b/src/Numerics/LinearAlgebra/Complex/ExtensionMethods.cs
@@ -60,10 +60,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// Computes the QR decomposition for a matrix.
///
/// The matrix to factor.
+ /// The type of QR factorization to perform.
/// The QR decomposition object.
- public static QR QR(this Matrix matrix)
+ public static QR QR(this Matrix matrix, QRMethod method = QRMethod.Full)
{
- return (QR)QR.Create(matrix);
+ return (QR)QR.Create(matrix, method);
}
///
diff --git a/src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs b/src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs
index 8cd0e2e4..341b9e9e 100644
--- a/src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs
+++ b/src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{
using System;
@@ -60,9 +62,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// QR factorization when the constructor is called and cache it's factorization.
///
/// The matrix to factor.
+ /// The type of QR factorization to perform.
/// If is null.
/// If row count is less then column count
- public DenseQR(DenseMatrix matrix)
+ public DenseQR(DenseMatrix matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@@ -74,10 +77,22 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw Matrix.DimensionsDontMatch(matrix);
}
- MatrixR = matrix.Clone();
- MatrixQ = new DenseMatrix(matrix.RowCount);
Tau = new Complex[Math.Min(matrix.RowCount, matrix.ColumnCount)];
- Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount, ((DenseMatrix)MatrixQ).Data, Tau);
+
+ if (method == QRMethod.Full)
+ {
+ MatrixR = matrix.Clone();
+ MatrixQ = new DenseMatrix(matrix.RowCount);
+ Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount,
+ ((DenseMatrix)MatrixQ).Data, Tau);
+ }
+ else
+ {
+ MatrixQ = matrix.Clone();
+ MatrixR = new DenseMatrix(matrix.ColumnCount);
+ Control.LinearAlgebraProvider.ThinQRFactor(((DenseMatrix)MatrixQ).Data, matrix.RowCount, matrix.ColumnCount,
+ ((DenseMatrix)MatrixR).Data, Tau);
+ }
}
///
diff --git a/src/Numerics/LinearAlgebra/Complex/Factorization/QR.cs b/src/Numerics/LinearAlgebra/Complex/Factorization/QR.cs
index 3c5d9161..95919f1e 100644
--- a/src/Numerics/LinearAlgebra/Complex/Factorization/QR.cs
+++ b/src/Numerics/LinearAlgebra/Complex/Factorization/QR.cs
@@ -33,12 +33,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
///
/// A class which encapsulates the functionality of the QR decomposition.
- /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix (m x m)
- /// (its columns are orthogonal unit vectors meaning QTQ = I) and R (m x n) is an upper triangular matrix
+ /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix
+ /// (its columns are orthogonal unit vectors meaning QTQ = I) and R is an upper triangular matrix
/// (also called right triangular matrix).
///
///
/// The computation of the QR decomposition is done at construction time by Householder transformation.
+ /// If a factorization is peformed, the resulting Q matrix is an m x m matrix
+ /// and the R matrix is an m x n matrix. If a factorization is performed, the
+ /// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
///
public abstract class QR : QR
{
diff --git a/src/Numerics/LinearAlgebra/Complex/Factorization/UserQR.cs b/src/Numerics/LinearAlgebra/Complex/Factorization/UserQR.cs
index 9051fa9f..04a1fcbe 100644
--- a/src/Numerics/LinearAlgebra/Complex/Factorization/UserQR.cs
+++ b/src/Numerics/LinearAlgebra/Complex/Factorization/UserQR.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
{
using System;
@@ -53,8 +55,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// QR factorization when the constructor is called and cache it's factorization.
///
/// The matrix to factor.
+ /// The QR factorization method to use.
/// If is null.
- public UserQR(Matrix matrix)
+ public UserQR(Matrix matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@@ -66,25 +69,57 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw Matrix.DimensionsDontMatch(matrix);
}
- MatrixR = matrix.Clone();
- MatrixQ = matrix.CreateMatrix(matrix.RowCount, matrix.RowCount);
-
- for (var i = 0; i < matrix.RowCount; i++)
- {
- MatrixQ.At(i, i, 1.0);
- }
-
var minmn = Math.Min(matrix.RowCount, matrix.ColumnCount);
var u = new Complex[minmn][];
- for (var i = 0; i < minmn; i++)
+
+ if (method == QRMethod.Full)
{
- u[i] = GenerateColumn(MatrixR, i, i);
- ComputeQR(u[i], MatrixR, i, matrix.RowCount, i + 1, matrix.ColumnCount, Control.NumberOfParallelWorkerThreads);
- }
+ MatrixR = matrix.Clone();
+ MatrixQ = matrix.CreateMatrix(matrix.RowCount, matrix.RowCount);
- for (var i = minmn - 1; i >= 0; i--)
+ for (var i = 0; i < matrix.RowCount; i++)
+ {
+ MatrixQ.At(i, i, 1.0f);
+ }
+
+ for (var i = 0; i < minmn; i++)
+ {
+ u[i] = GenerateColumn(MatrixR, i, i);
+ ComputeQR(u[i], MatrixR, i, matrix.RowCount, i + 1, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.RowCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+ }
+ else
{
- ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.RowCount, Control.NumberOfParallelWorkerThreads);
+ MatrixR = matrix.CreateMatrix(matrix.ColumnCount, matrix.ColumnCount);
+ MatrixQ = matrix.Clone();
+
+ for (var i = 0; i < minmn; i++)
+ {
+ u[i] = GenerateColumn(MatrixQ, i, i);
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i + 1, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+
+ MatrixR = MatrixQ.SubMatrix(0, matrix.ColumnCount, 0, matrix.ColumnCount);
+ MatrixQ.Clear();
+
+ for (var i = 0; i < matrix.ColumnCount; i++)
+ {
+ MatrixQ.At(i, i, 1.0f);
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
}
}
diff --git a/src/Numerics/LinearAlgebra/Complex32/ExtensionMethods.cs b/src/Numerics/LinearAlgebra/Complex32/ExtensionMethods.cs
index 8960dc5c..cc6c5856 100644
--- a/src/Numerics/LinearAlgebra/Complex32/ExtensionMethods.cs
+++ b/src/Numerics/LinearAlgebra/Complex32/ExtensionMethods.cs
@@ -60,10 +60,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// Computes the QR decomposition for a matrix.
///
/// The matrix to factor.
+ /// The type of QR factorization to perform.
/// The QR decomposition object.
- public static QR QR(this Matrix matrix)
+ public static QR QR(this Matrix matrix, QRMethod method = QRMethod.Full)
{
- return (QR)QR.Create(matrix);
+ return (QR)QR.Create(matrix, method);
}
///
diff --git a/src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs b/src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs
index 5a54f50a..04f9d8cb 100644
--- a/src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs
+++ b/src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{
using System;
@@ -60,9 +62,10 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// QR factorization when the constructor is called and cache it's factorization.
///
/// The matrix to factor.
+ /// The QR factorization method to use.
/// If is null.
/// If row count is less then column count
- public DenseQR(DenseMatrix matrix)
+ public DenseQR(DenseMatrix matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@@ -74,10 +77,22 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw Matrix.DimensionsDontMatch(matrix);
}
- MatrixR = matrix.Clone();
- MatrixQ = new DenseMatrix(matrix.RowCount);
Tau = new Complex32[Math.Min(matrix.RowCount, matrix.ColumnCount)];
- Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount, ((DenseMatrix)MatrixQ).Data, Tau);
+
+ if (method == QRMethod.Full)
+ {
+ MatrixR = matrix.Clone();
+ MatrixQ = new DenseMatrix(matrix.RowCount);
+ Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount,
+ ((DenseMatrix)MatrixQ).Data, Tau);
+ }
+ else
+ {
+ MatrixQ = matrix.Clone();
+ MatrixR = new DenseMatrix(matrix.ColumnCount);
+ Control.LinearAlgebraProvider.ThinQRFactor(((DenseMatrix)MatrixQ).Data, matrix.RowCount, matrix.ColumnCount,
+ ((DenseMatrix)MatrixR).Data, Tau);
+ }
}
///
diff --git a/src/Numerics/LinearAlgebra/Complex32/Factorization/QR.cs b/src/Numerics/LinearAlgebra/Complex32/Factorization/QR.cs
index c899365e..02450a73 100644
--- a/src/Numerics/LinearAlgebra/Complex32/Factorization/QR.cs
+++ b/src/Numerics/LinearAlgebra/Complex32/Factorization/QR.cs
@@ -33,12 +33,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
///
/// A class which encapsulates the functionality of the QR decomposition.
- /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix (m x m)
- /// (its columns are orthogonal unit vectors meaning QTQ = I) and R (m x n) is an upper triangular matrix
+ /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix
+ /// (its columns are orthogonal unit vectors meaning QTQ = I) and R is an upper triangular matrix
/// (also called right triangular matrix).
///
///
/// The computation of the QR decomposition is done at construction time by Householder transformation.
+ /// If a factorization is peformed, the resulting Q matrix is an m x m matrix
+ /// and the R matrix is an m x n matrix. If a factorization is performed, the
+ /// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
///
public abstract class QR : QR
{
diff --git a/src/Numerics/LinearAlgebra/Complex32/Factorization/UserQR.cs b/src/Numerics/LinearAlgebra/Complex32/Factorization/UserQR.cs
index cba8adab..4cc9907a 100644
--- a/src/Numerics/LinearAlgebra/Complex32/Factorization/UserQR.cs
+++ b/src/Numerics/LinearAlgebra/Complex32/Factorization/UserQR.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
{
using System;
@@ -53,8 +55,9 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// QR factorization when the constructor is called and cache it's factorization.
///
/// The matrix to factor.
+ /// The QR factorization method to use.
/// If is null.
- public UserQR(Matrix matrix)
+ public UserQR(Matrix matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@@ -66,25 +69,57 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw Matrix.DimensionsDontMatch(matrix);
}
- MatrixR = matrix.Clone();
- MatrixQ = matrix.CreateMatrix(matrix.RowCount, matrix.RowCount);
-
- for (var i = 0; i < matrix.RowCount; i++)
- {
- MatrixQ.At(i, i, 1.0f);
- }
-
var minmn = Math.Min(matrix.RowCount, matrix.ColumnCount);
var u = new Complex32[minmn][];
- for (var i = 0; i < minmn; i++)
+
+ if (method == QRMethod.Full)
{
- u[i] = GenerateColumn(MatrixR, i, i);
- ComputeQR(u[i], MatrixR, i, matrix.RowCount, i + 1, matrix.ColumnCount, Control.NumberOfParallelWorkerThreads);
- }
+ MatrixR = matrix.Clone();
+ MatrixQ = matrix.CreateMatrix(matrix.RowCount, matrix.RowCount);
- for (var i = minmn - 1; i >= 0; i--)
+ for (var i = 0; i < matrix.RowCount; i++)
+ {
+ MatrixQ.At(i, i, 1.0f);
+ }
+
+ for (var i = 0; i < minmn; i++)
+ {
+ u[i] = GenerateColumn(MatrixR, i, i);
+ ComputeQR(u[i], MatrixR, i, matrix.RowCount, i + 1, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.RowCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+ }
+ else
{
- ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.RowCount, Control.NumberOfParallelWorkerThreads);
+ MatrixR = matrix.CreateMatrix(matrix.ColumnCount, matrix.ColumnCount);
+ MatrixQ = matrix.Clone();
+
+ for (var i = 0; i < minmn; i++)
+ {
+ u[i] = GenerateColumn(MatrixQ, i, i);
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i + 1, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+
+ MatrixR = MatrixQ.SubMatrix(0, matrix.ColumnCount, 0, matrix.ColumnCount);
+ MatrixQ.Clear();
+
+ for (var i = 0; i < matrix.ColumnCount; i++)
+ {
+ MatrixQ.At(i, i, 1.0f);
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
}
}
diff --git a/src/Numerics/LinearAlgebra/Double/ExtensionMethods.cs b/src/Numerics/LinearAlgebra/Double/ExtensionMethods.cs
index e46fb617..b00cdc6e 100644
--- a/src/Numerics/LinearAlgebra/Double/ExtensionMethods.cs
+++ b/src/Numerics/LinearAlgebra/Double/ExtensionMethods.cs
@@ -59,10 +59,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// Computes the QR decomposition for a matrix.
///
/// The matrix to factor.
+ /// The type of QR factorization to perform.
/// The QR decomposition object.
- public static QR QR(this Matrix matrix)
+ public static QR QR(this Matrix matrix, QRMethod method = QRMethod.Full)
{
- return (QR)QR.Create(matrix);
+ return (QR)QR.Create(matrix, method);
}
///
diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs b/src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs
index 0feb4858..3cb58563 100644
--- a/src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs
+++ b/src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{
using System;
@@ -59,9 +61,10 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// QR factorization when the constructor is called and cache it's factorization.
///
/// The matrix to factor.
+ /// The type of QR factorization to perform.
/// If is null.
/// If row count is less then column count
- public DenseQR(DenseMatrix matrix)
+ public DenseQR(DenseMatrix matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@@ -73,10 +76,23 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw Matrix.DimensionsDontMatch(matrix);
}
- MatrixR = matrix.Clone();
- MatrixQ = new DenseMatrix(matrix.RowCount);
Tau = new double[Math.Min(matrix.RowCount, matrix.ColumnCount)];
- Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount, ((DenseMatrix)MatrixQ).Data, Tau);
+
+ if (method == QRMethod.Full)
+ {
+ MatrixR = matrix.Clone();
+ MatrixQ = new DenseMatrix(matrix.RowCount);
+ Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount,
+ ((DenseMatrix)MatrixQ).Data, Tau);
+ }
+ else
+ {
+ MatrixQ = matrix.Clone();
+ MatrixR = new DenseMatrix(matrix.ColumnCount);
+ Control.LinearAlgebraProvider.ThinQRFactor(((DenseMatrix) MatrixQ).Data, matrix.RowCount,
+ matrix.ColumnCount,
+ ((DenseMatrix) MatrixR).Data, Tau);
+ }
}
///
diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/QR.cs b/src/Numerics/LinearAlgebra/Double/Factorization/QR.cs
index 59fad79a..a6dba90d 100644
--- a/src/Numerics/LinearAlgebra/Double/Factorization/QR.cs
+++ b/src/Numerics/LinearAlgebra/Double/Factorization/QR.cs
@@ -32,12 +32,15 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
///
/// A class which encapsulates the functionality of the QR decomposition.
- /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix (m x m)
- /// (its columns are orthogonal unit vectors meaning QTQ = I) and R (m x n) is an upper triangular matrix
+ /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix
+ /// (its columns are orthogonal unit vectors meaning QTQ = I) and R is an upper triangular matrix
/// (also called right triangular matrix).
///
///
/// The computation of the QR decomposition is done at construction time by Householder transformation.
+ /// If a factorization is performed, the resulting Q matrix is an m x m matrix
+ /// and the R matrix is an m x n matrix. If a factorization is performed, the
+ /// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
///
public abstract class QR : QR
{
diff --git a/src/Numerics/LinearAlgebra/Double/Factorization/UserQR.cs b/src/Numerics/LinearAlgebra/Double/Factorization/UserQR.cs
index 591bc5a3..eaac74ee 100644
--- a/src/Numerics/LinearAlgebra/Double/Factorization/UserQR.cs
+++ b/src/Numerics/LinearAlgebra/Double/Factorization/UserQR.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
{
using System;
@@ -52,8 +54,9 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// QR factorization when the constructor is called and cache it's factorization.
///
/// The matrix to factor.
+ /// The QR factorization method to use.
/// If is null.
- public UserQR(Matrix matrix)
+ public UserQR(Matrix matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@@ -65,25 +68,58 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw Matrix.DimensionsDontMatch(matrix);
}
- MatrixR = matrix.Clone();
- MatrixQ = matrix.CreateMatrix(matrix.RowCount, matrix.RowCount);
-
- for (var i = 0; i < matrix.RowCount; i++)
- {
- MatrixQ.At(i, i, 1.0);
- }
-
var minmn = Math.Min(matrix.RowCount, matrix.ColumnCount);
var u = new double[minmn][];
- for (var i = 0; i < minmn; i++)
+
+ if (method == QRMethod.Full)
{
- u[i] = GenerateColumn(MatrixR, i, i);
- ComputeQR(u[i], MatrixR, i, matrix.RowCount, i + 1, matrix.ColumnCount, Control.NumberOfParallelWorkerThreads);
- }
+ MatrixR = matrix.Clone();
+ MatrixQ = matrix.CreateMatrix(matrix.RowCount, matrix.RowCount);
+
+ for (var i = 0; i < matrix.RowCount; i++)
+ {
+ MatrixQ.At(i, i, 1.0);
+ }
+
+ for (var i = 0; i < minmn; i++)
+ {
+ u[i] = GenerateColumn(MatrixR, i, i);
+ ComputeQR(u[i], MatrixR, i, matrix.RowCount, i + 1, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
- for (var i = minmn - 1; i >= 0; i--)
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.RowCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+ }
+ else
{
- ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.RowCount, Control.NumberOfParallelWorkerThreads);
+ MatrixR = matrix.CreateMatrix(matrix.ColumnCount, matrix.ColumnCount);
+ MatrixQ = matrix.Clone();
+
+ for (var i = 0; i < minmn; i++)
+ {
+ u[i] = GenerateColumn(MatrixQ, i, i);
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i + 1, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+
+ MatrixR = MatrixQ.SubMatrix(0, matrix.ColumnCount, 0, matrix.ColumnCount);
+ MatrixQ.Clear();
+
+ for (var i = 0; i < matrix.ColumnCount; i++)
+ {
+ MatrixQ.At(i, i, 1.0);
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+
}
}
diff --git a/src/Numerics/LinearAlgebra/Generic/Factorization/GramSchmidt.cs b/src/Numerics/LinearAlgebra/Generic/Factorization/GramSchmidt.cs
index 70bb4722..697e96a0 100644
--- a/src/Numerics/LinearAlgebra/Generic/Factorization/GramSchmidt.cs
+++ b/src/Numerics/LinearAlgebra/Generic/Factorization/GramSchmidt.cs
@@ -47,7 +47,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
///
/// The matrix to factor.
/// A QR factorization object.
- new internal static GramSchmidt Create(Matrix matrix)
+ internal static GramSchmidt Create(Matrix matrix)
{
if (typeof(T) == typeof(double))
{
diff --git a/src/Numerics/LinearAlgebra/Generic/Factorization/QR.cs b/src/Numerics/LinearAlgebra/Generic/Factorization/QR.cs
index 669375a7..0afbe870 100644
--- a/src/Numerics/LinearAlgebra/Generic/Factorization/QR.cs
+++ b/src/Numerics/LinearAlgebra/Generic/Factorization/QR.cs
@@ -31,14 +31,33 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
using Generic;
using Numerics;
+ ///
+ /// The type of QR factorization go perform.
+ ///
+ public enum QRMethod
+ {
+ ///
+ /// Compute the full QR factorization of a matrix.
+ ///
+ Full = 0,
+
+ ///
+ /// Compute the thin QR factorixation of a matrix.
+ ///
+ Thin = 1
+ }
+
///
/// A class which encapsulates the functionality of the QR decomposition.
- /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix (m x m)
- /// (its columns are orthogonal unit vectors meaning QTQ = I) and R (m x n) is an upper triangular matrix
+ /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix
+ /// (its columns are orthogonal unit vectors meaning QTQ = I) and R is an upper triangular matrix
/// (also called right triangular matrix).
///
///
/// The computation of the QR decomposition is done at construction time by Householder transformation.
+ /// If a factorization is performed, the resulting Q matrix is an m x m matrix
+ /// and the R matrix is an m x n matrix. If a factorization is performed, the
+ /// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
///
/// Supported data types are double, single, , and .
public abstract class QR : ISolver
@@ -66,18 +85,19 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
/// Internal method which routes the call to perform the QR factorization to the appropriate class.
///
/// The matrix to factor.
+ /// The type of QR factorization to perform.
/// A QR factorization object.
- internal static QR Create(Matrix matrix)
+ internal static QR Create(Matrix matrix, QRMethod method = QRMethod.Full)
{
if (typeof(T) == typeof(double))
{
var dense = matrix as LinearAlgebra.Double.DenseMatrix;
if (dense != null)
{
- return new LinearAlgebra.Double.Factorization.DenseQR(dense) as QR;
+ return new LinearAlgebra.Double.Factorization.DenseQR(dense, method) as QR;
}
- return new LinearAlgebra.Double.Factorization.UserQR(matrix as Matrix) as QR;
+ return new LinearAlgebra.Double.Factorization.UserQR(matrix as Matrix, method) as QR;
}
if (typeof(T) == typeof(float))
@@ -85,10 +105,10 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
var dense = matrix as LinearAlgebra.Single.DenseMatrix;
if (dense != null)
{
- return new LinearAlgebra.Single.Factorization.DenseQR(dense) as QR;
+ return new LinearAlgebra.Single.Factorization.DenseQR(dense, method) as QR;
}
- return new LinearAlgebra.Single.Factorization.UserQR(matrix as Matrix) as QR;
+ return new LinearAlgebra.Single.Factorization.UserQR(matrix as Matrix, method) as QR;
}
if (typeof(T) == typeof(Complex))
@@ -96,10 +116,10 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
var dense = matrix as LinearAlgebra.Complex.DenseMatrix;
if (dense != null)
{
- return new LinearAlgebra.Complex.Factorization.DenseQR(dense) as QR;
+ return new LinearAlgebra.Complex.Factorization.DenseQR(dense, method) as QR;
}
- return new LinearAlgebra.Complex.Factorization.UserQR(matrix as Matrix) as QR;
+ return new LinearAlgebra.Complex.Factorization.UserQR(matrix as Matrix, method) as QR;
}
if (typeof(T) == typeof(Complex32))
@@ -107,10 +127,10 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
var dense = matrix as LinearAlgebra.Complex32.DenseMatrix;
if (dense != null)
{
- return new LinearAlgebra.Complex32.Factorization.DenseQR(dense) as QR;
+ return new LinearAlgebra.Complex32.Factorization.DenseQR(dense, method) as QR;
}
- return new LinearAlgebra.Complex32.Factorization.UserQR(matrix as Matrix) as QR;
+ return new LinearAlgebra.Complex32.Factorization.UserQR(matrix as Matrix, method) as QR;
}
throw new NotSupportedException();
diff --git a/src/Numerics/LinearAlgebra/Single/ExtensionMethods.cs b/src/Numerics/LinearAlgebra/Single/ExtensionMethods.cs
index b0855c7a..720c14d1 100644
--- a/src/Numerics/LinearAlgebra/Single/ExtensionMethods.cs
+++ b/src/Numerics/LinearAlgebra/Single/ExtensionMethods.cs
@@ -59,10 +59,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// Computes the QR decomposition for a matrix.
///
/// The matrix to factor.
+ /// The type of QR factorization to perform.
/// The QR decomposition object.
- public static QR QR(this Matrix matrix)
+ public static QR QR(this Matrix matrix, QRMethod method = QRMethod.Full)
{
- return (QR)QR.Create(matrix);
+ return (QR)QR.Create(matrix, method);
}
///
diff --git a/src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs b/src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs
index 05c4a593..9157b412 100644
--- a/src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs
+++ b/src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{
using System;
@@ -59,9 +61,10 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// QR factorization when the constructor is called and cache it's factorization.
///
/// The matrix to factor.
+ /// The QR factorization method to use.
/// If is null.
/// If row count is less then column count
- public DenseQR(DenseMatrix matrix)
+ public DenseQR(DenseMatrix matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@@ -73,10 +76,22 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw Matrix.DimensionsDontMatch(matrix);
}
- MatrixR = matrix.Clone();
- MatrixQ = new DenseMatrix(matrix.RowCount);
Tau = new float[Math.Min(matrix.RowCount, matrix.ColumnCount)];
- Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount, ((DenseMatrix)MatrixQ).Data, Tau);
+
+ if (method == QRMethod.Full)
+ {
+ MatrixR = matrix.Clone();
+ MatrixQ = new DenseMatrix(matrix.RowCount);
+ Control.LinearAlgebraProvider.QRFactor(((DenseMatrix)MatrixR).Data, matrix.RowCount, matrix.ColumnCount,
+ ((DenseMatrix)MatrixQ).Data, Tau);
+ }
+ else
+ {
+ MatrixQ = matrix.Clone();
+ MatrixR = new DenseMatrix(matrix.ColumnCount);
+ Control.LinearAlgebraProvider.ThinQRFactor(((DenseMatrix)MatrixQ).Data, matrix.RowCount, matrix.ColumnCount,
+ ((DenseMatrix)MatrixR).Data, Tau);
+ }
}
///
diff --git a/src/Numerics/LinearAlgebra/Single/Factorization/QR.cs b/src/Numerics/LinearAlgebra/Single/Factorization/QR.cs
index 1b3b6af0..cb84c150 100644
--- a/src/Numerics/LinearAlgebra/Single/Factorization/QR.cs
+++ b/src/Numerics/LinearAlgebra/Single/Factorization/QR.cs
@@ -32,12 +32,15 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
///
/// A class which encapsulates the functionality of the QR decomposition.
- /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix (m x m)
- /// (its columns are orthogonal unit vectors meaning QTQ = I) and R (m x n) is an upper triangular matrix
+ /// Any real square matrix A (m x n) may be decomposed as A = QR where Q is an orthogonal matrix
+ /// (its columns are orthogonal unit vectors meaning QTQ = I) and R is an upper triangular matrix
/// (also called right triangular matrix).
///
///
/// The computation of the QR decomposition is done at construction time by Householder transformation.
+ /// If a factorization is peformed, the resulting Q matrix is an m x m matrix
+ /// and the R matrix is an m x n matrix. If a factorization is performed, the
+ /// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
///
public abstract class QR : QR
{
diff --git a/src/Numerics/LinearAlgebra/Single/Factorization/UserQR.cs b/src/Numerics/LinearAlgebra/Single/Factorization/UserQR.cs
index af3bc5aa..047c4ff7 100644
--- a/src/Numerics/LinearAlgebra/Single/Factorization/UserQR.cs
+++ b/src/Numerics/LinearAlgebra/Single/Factorization/UserQR.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
{
using System;
@@ -52,8 +54,9 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// QR factorization when the constructor is called and cache it's factorization.
///
/// The matrix to factor.
+ /// The QR factorization method to use.
/// If is null.
- public UserQR(Matrix matrix)
+ public UserQR(Matrix matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@@ -65,25 +68,57 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw Matrix.DimensionsDontMatch(matrix);
}
- MatrixR = matrix.Clone();
- MatrixQ = matrix.CreateMatrix(matrix.RowCount, matrix.RowCount);
-
- for (var i = 0; i < matrix.RowCount; i++)
- {
- MatrixQ.At(i, i, 1.0f);
- }
-
var minmn = Math.Min(matrix.RowCount, matrix.ColumnCount);
var u = new float[minmn][];
- for (var i = 0; i < minmn; i++)
+
+ if (method == QRMethod.Full)
{
- u[i] = GenerateColumn(MatrixR, i, i);
- ComputeQR(u[i], MatrixR, i, matrix.RowCount, i + 1, matrix.ColumnCount, Control.NumberOfParallelWorkerThreads);
- }
+ MatrixR = matrix.Clone();
+ MatrixQ = matrix.CreateMatrix(matrix.RowCount, matrix.RowCount);
- for (var i = minmn - 1; i >= 0; i--)
+ for (var i = 0; i < matrix.RowCount; i++)
+ {
+ MatrixQ.At(i, i, 1.0f);
+ }
+
+ for (var i = 0; i < minmn; i++)
+ {
+ u[i] = GenerateColumn(MatrixR, i, i);
+ ComputeQR(u[i], MatrixR, i, matrix.RowCount, i + 1, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.RowCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+ }
+ else
{
- ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.RowCount, Control.NumberOfParallelWorkerThreads);
+ MatrixR = matrix.CreateMatrix(matrix.ColumnCount, matrix.ColumnCount);
+ MatrixQ = matrix.Clone();
+
+ for (var i = 0; i < minmn; i++)
+ {
+ u[i] = GenerateColumn(MatrixQ, i, i);
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i + 1, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
+
+ MatrixR = MatrixQ.SubMatrix(0, matrix.ColumnCount, 0, matrix.ColumnCount);
+ MatrixQ.Clear();
+
+ for (var i = 0; i < matrix.ColumnCount; i++)
+ {
+ MatrixQ.At(i, i, 1.0f);
+ }
+
+ for (var i = minmn - 1; i >= 0; i--)
+ {
+ ComputeQR(u[i], MatrixQ, i, matrix.RowCount, i, matrix.ColumnCount,
+ Control.NumberOfParallelWorkerThreads);
+ }
}
}
diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj
index 18d2fdbb..4eda2e3b 100644
--- a/src/Numerics/Numerics.csproj
+++ b/src/Numerics/Numerics.csproj
@@ -85,22 +85,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs
index a1f5b6b9..8d431820 100644
--- a/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs
+++ b/src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs
@@ -789,6 +789,115 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex
}
}
+ ///
+ /// Can compute thin QR factorization of a square matrix.
+ ///
+ [Test]
+ public void CanComputeThinQRFactorSquareMatrix()
+ {
+ 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.Data, q, q.Length);
+
+ Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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.AlmostEqual(matrix[row, col], a[row, col], 14);
+ }
+ }
+ }
+
+ ///
+ /// Can compute thin QR factorization of a tall matrix.
+ ///
+ [Test]
+ public void CanComputeThinQRFactorTallMatrix()
+ {
+ 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.Data, q, q.Length);
+
+ Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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.AlmostEqual(matrix[row, col], a[row, col], 14);
+ }
+ }
+ }
+
+ ///
+ /// 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.Data, q, q.Length);
+
+ var work = new Complex[matrix.RowCount * matrix.ColumnCount];
+ 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.AlmostEqual(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.Data, q, q.Length);
+
+ var work = new Complex[matrix.RowCount * matrix.ColumnCount];
+ 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.AlmostEqual(matrix[row, col], a[row, col], 14);
+ }
+ }
+ }
+
///
/// Can solve Ax=b using QR factorization with a square A matrix.
///
@@ -807,7 +916,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex
var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
var mb = matrix * mx;
-
+ Console.WriteLine(mx);
AssertHelpers.AlmostEqual(mb[0, 0], b[0], 14);
AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);
@@ -1015,6 +1124,232 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex
AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
}
+ ///
+ /// Can solve Ax=b using thin QR factorization with a square A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRSquareMatrix()
+ {
+ var matrix = _matrices["Square3x3"];
+ var a = new Complex[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, 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];
+ Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, QRMethod.Thin);
+
+ NotModified(3, 3, a, matrix);
+
+ var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 14);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 14);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 14);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 14);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a tall A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRTallMatrix()
+ {
+ var matrix = _matrices["Tall3x2"];
+ var a = new Complex[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, 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];
+ Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, 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.AlmostEqual(test[0, 0], x[0], 14);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 14);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 14);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(mb[0, 0], b[0], 14);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 14);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 14);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 14);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(test[0, 0], x[0], 14);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 14);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 14);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a square A matrix
+ /// using a factored A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRSquareMatrixOnFactoredMatrix()
+ {
+ var matrix = _matrices["Square3x3"];
+ var a = new Complex[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, a, a.Length);
+
+ var tau = new Complex[matrix.ColumnCount];
+ var r = new Complex[matrix.ColumnCount * matrix.ColumnCount];
+ Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, 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(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, QRMethod.Thin);
+
+ var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 14);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 14);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 14);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 14);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a tall A matrix
+ /// using a factored A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRTallMatrixOnFactoredMatrix()
+ {
+ var matrix = _matrices["Tall3x2"];
+ var a = new Complex[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, a, a.Length);
+
+ var tau = new Complex[matrix.ColumnCount];
+ var r = new Complex[matrix.ColumnCount * matrix.ColumnCount];
+ Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, 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(a, r, matrix.RowCount, matrix.ColumnCount, tau, b, 2, x, QRMethod.Thin);
+
+ var mb = new DenseMatrix(matrix.RowCount, 2, b);
+ var test = (matrix.Transpose() * matrix).Inverse() * matrix.Transpose() * mb;
+
+ AssertHelpers.AlmostEqual(test[0, 0], x[0], 14);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 14);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 14);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(mb[0, 0], b[0], 14);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 14);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 14);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 14);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(test[0, 0], x[0], 14);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 14);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 14);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
+ }
+
///
/// Can compute the SVD factorization of a square matrix.
///
diff --git a/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs
index 5a664193..f8ae7f55 100644
--- a/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs
+++ b/src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs
@@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32
{
using System;
@@ -796,6 +798,115 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32
}
}
+ ///
+ /// Can compute thin QR factorization of a square matrix.
+ ///
+ [Test]
+ public void CanComputeThinQRFactorSquareMatrix()
+ {
+ 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.Data, q, q.Length);
+
+ Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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.AlmostEqual(matrix[row, col], a[row, col], 6);
+ }
+ }
+ }
+
+ ///
+ /// Can compute thin QR factorization of a tall matrix.
+ ///
+ [Test]
+ public void CanComputeThinQRFactorTallMatrix()
+ {
+ 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.Data, q, q.Length);
+
+ Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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.AlmostEqual(matrix[row, col], a[row, col], 6);
+ }
+ }
+ }
+
+ ///
+ /// 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.Data, q, q.Length);
+
+ var work = new Complex32[matrix.RowCount * matrix.ColumnCount];
+ 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.AlmostEqual(matrix[row, col], a[row, col], 6);
+ }
+ }
+ }
+
+ ///
+ /// 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.Data, q, q.Length);
+
+ var work = new Complex32[matrix.RowCount * matrix.ColumnCount];
+ 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.AlmostEqual(matrix[row, col], a[row, col], 6);
+ }
+ }
+ }
+
///
/// Can solve Ax=b using QR factorization with a square A matrix.
///
@@ -1022,6 +1133,232 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32
AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
}
+ ///
+ /// Can solve Ax=b using thin QR factorization with a square A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRSquareMatrix()
+ {
+ var matrix = _matrices["Square3x3"];
+ var a = new Complex32[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, 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];
+ Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, QRMethod.Thin);
+
+ NotModified(3, 3, a, matrix);
+
+ var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 5);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 5);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 5);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 5);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 5);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 5);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a tall A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRTallMatrix()
+ {
+ var matrix = _matrices["Tall3x2"];
+ var a = new Complex32[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, 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];
+ Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, 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.AlmostEqual(test[0, 0], x[0], 6);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 6);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 6);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(mb[0, 0], b[0], 5);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 5);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 5);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 5);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 5);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 5);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(test[0, 0], x[0], 6);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 6);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 6);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a square A matrix
+ /// using a factored A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRSquareMatrixOnFactoredMatrix()
+ {
+ var matrix = _matrices["Square3x3"];
+ var a = new Complex32[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, a, a.Length);
+
+ var tau = new Complex32[matrix.ColumnCount];
+ var r = new Complex32[matrix.ColumnCount * matrix.ColumnCount];
+ Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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, QRMethod.Thin);
+
+ var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 5);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 5);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 5);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 5);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 5);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 5);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a tall A matrix
+ /// using a factored A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRTallMatrixOnFactoredMatrix()
+ {
+ var matrix = _matrices["Tall3x2"];
+ var a = new Complex32[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, a, a.Length);
+
+ var tau = new Complex32[matrix.ColumnCount];
+ var r = new Complex32[matrix.ColumnCount * matrix.ColumnCount];
+ Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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, QRMethod.Thin);
+
+ var mb = new DenseMatrix(matrix.RowCount, 2, b);
+ var test = (matrix.Transpose() * matrix).Inverse() * matrix.Transpose() * mb;
+
+ AssertHelpers.AlmostEqual(test[0, 0], x[0], 6);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 6);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 6);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(mb[0, 0], b[0], 5);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 5);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 5);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 5);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 5);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 5);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(test[0, 0], x[0], 6);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 6);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 6);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
+ }
+
///
/// Can compute the SVD factorization of a square matrix.
///
diff --git a/src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs
index d73274a1..6b414058 100644
--- a/src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs
+++ b/src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs
@@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double
{
using System;
@@ -787,11 +789,121 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double
}
}
+ ///
+ /// Can compute thin QR factorization of a square matrix.
+ ///
+ [Test]
+ public void CanComputeThinQRFactorSquareMatrix()
+ {
+ 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.Data, q, q.Length);
+
+ Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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.AlmostEqual(matrix[row, col], a[row, col], 14);
+ }
+ }
+ }
+
+ ///
+ /// Can compute thin QR factorization of a tall matrix.
+ ///
+ [Test]
+ public void CanComputeThinQRFactorTallMatrix()
+ {
+ 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.Data, q, q.Length);
+
+ Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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.AlmostEqual(matrix[row, col], a[row, col], 14);
+ }
+ }
+ }
+
+ ///
+ /// 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.Data, q, q.Length);
+
+ var work = new double[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.AlmostEqual(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.Data, q, q.Length);
+
+ var work = new double[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.AlmostEqual(matrix[row, col], a[row, col], 14);
+ }
+ }
+ }
+
///
/// Can solve Ax=b using QR factorization with a square A matrix.
///
[Test]
- public void CanSolveUsingQRSquareMatrix()
+ public void CanSolveUsingQRSquareMatrix()
{
var matrix = _matrices["Square3x3"];
var a = new double[matrix.RowCount * matrix.ColumnCount];
@@ -852,7 +964,7 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double
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];
+ 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);
@@ -1013,6 +1125,232 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double
AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
}
+ ///
+ /// Can solve Ax=b using thin QR factorization with a square A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRSquareMatrix()
+ {
+ var matrix = _matrices["Square3x3"];
+ var a = new double[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, 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];
+ Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, QRMethod.Thin);
+
+ NotModified(3, 3, a, matrix);
+
+ var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 14);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 14);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 14);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 14);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a tall A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRTallMatrix()
+ {
+ var matrix = _matrices["Tall3x2"];
+ var a = new double[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, 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];
+ Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, 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.AlmostEqual(test[0, 0], x[0], 14);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 14);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 14);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
+ }
+
+ ///
+ /// 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.Data, 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 = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 14);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 14);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 14);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 14);
+ }
+
+ ///
+ /// 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.Data, 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 = new DenseMatrix(matrix.RowCount, 2, b);
+ var test = (matrix.Transpose() * matrix).Inverse() * matrix.Transpose() * mb;
+
+ AssertHelpers.AlmostEqual(test[0, 0], x[0], 14);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 14);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 14);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a square A matrix
+ /// using a factored A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRSquareMatrixOnFactoredMatrix()
+ {
+ var matrix = _matrices["Square3x3"];
+ var a = new double[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, a, a.Length);
+
+ var tau = new double[matrix.ColumnCount];
+ var r = new double[matrix.ColumnCount * matrix.ColumnCount];
+ Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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, QRMethod.Thin);
+
+ var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 14);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 14);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 14);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 14);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a tall A matrix
+ /// using a factored A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRTallMatrixOnFactoredMatrix()
+ {
+ var matrix = _matrices["Tall3x2"];
+ var a = new double[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, a, a.Length);
+
+ var tau = new double[matrix.ColumnCount];
+ var r = new double[matrix.ColumnCount * matrix.ColumnCount];
+ Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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, QRMethod.Thin);
+
+ var mb = new DenseMatrix(matrix.RowCount, 2, b);
+ var test = (matrix.Transpose() * matrix).Inverse() * matrix.Transpose() * mb;
+
+ AssertHelpers.AlmostEqual(test[0, 0], x[0], 14);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 14);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 14);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
+ }
+
+ ///
+ /// 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.Data, 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 = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 14);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 14);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 14);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 14);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 14);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 14);
+ }
+
+ ///
+ /// 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.Data, 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 = new DenseMatrix(matrix.RowCount, 2, b);
+ var test = (matrix.Transpose() * matrix).Inverse() * matrix.Transpose() * mb;
+
+ AssertHelpers.AlmostEqual(test[0, 0], x[0], 14);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 14);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 14);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 14);
+ }
+
///
/// Can compute the SVD factorization of a square matrix.
///
diff --git a/src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs b/src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs
index 56ce00d2..d5e30da8 100644
--- a/src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs
+++ b/src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs
@@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single
{
using System;
@@ -795,6 +797,115 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single
}
}
+ ///
+ /// Can compute thin QR factorization of a square matrix.
+ ///
+ [Test]
+ public void CanComputeThinQRFactorSquareMatrix()
+ {
+ 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.Data, q, q.Length);
+
+ Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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.AlmostEqual(matrix[row, col], a[row, col], 6);
+ }
+ }
+ }
+
+ ///
+ /// Can compute thin QR factorization of a tall matrix.
+ ///
+ [Test]
+ public void CanComputeThinQRFactorTallMatrix()
+ {
+ 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.Data, q, q.Length);
+
+ Control.LinearAlgebraProvider.ThinQRFactor(q, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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.AlmostEqual(matrix[row, col], a[row, col], 6);
+ }
+ }
+ }
+
+ ///
+ /// 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.Data, q, q.Length);
+
+ var work = new float[matrix.RowCount * matrix.ColumnCount];
+ 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.AlmostEqual(matrix[row, col], a[row, col], 6);
+ }
+ }
+ }
+
+ ///
+ /// 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.Data, q, q.Length);
+
+ var work = new float[matrix.RowCount * matrix.ColumnCount];
+ 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.AlmostEqual(matrix[row, col], a[row, col], 6);
+ }
+ }
+ }
+
///
/// Can solve Ax=b using QR factorization with a square A matrix.
///
@@ -1021,6 +1132,232 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single
AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
}
+ ///
+ /// Can solve Ax=b using thin QR factorization with a square A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRSquareMatrix()
+ {
+ var matrix = _matrices["Square3x3"];
+ var a = new float[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, 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];
+ Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, QRMethod.Thin);
+
+ NotModified(3, 3, a, matrix);
+
+ var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 5);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 5);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 5);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 5);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 5);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 5);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a tall A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRTallMatrix()
+ {
+ var matrix = _matrices["Tall3x2"];
+ var a = new float[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, 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];
+ Control.LinearAlgebraProvider.QRSolve(a, matrix.RowCount, matrix.ColumnCount, b, 2, x, 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.AlmostEqual(test[0, 0], x[0], 6);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 6);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 6);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(mb[0, 0], b[0], 5);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 5);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 5);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 5);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 5);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 5);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(test[0, 0], x[0], 6);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 6);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 6);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a square A matrix
+ /// using a factored A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRSquareMatrixOnFactoredMatrix()
+ {
+ var matrix = _matrices["Square3x3"];
+ var a = new float[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, a, a.Length);
+
+ var tau = new float[matrix.ColumnCount];
+ var r = new float[matrix.ColumnCount * matrix.ColumnCount];
+ Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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, QRMethod.Thin);
+
+ var mx = new DenseMatrix(matrix.ColumnCount, 2, x);
+ var mb = matrix * mx;
+
+ AssertHelpers.AlmostEqual(mb[0, 0], b[0], 5);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 5);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 5);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 5);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 5);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 5);
+ }
+
+ ///
+ /// Can solve Ax=b using thin QR factorization with a tall A matrix
+ /// using a factored A matrix.
+ ///
+ [Test]
+ public void CanSolveUsingThinQRTallMatrixOnFactoredMatrix()
+ {
+ var matrix = _matrices["Tall3x2"];
+ var a = new float[matrix.RowCount * matrix.ColumnCount];
+ Array.Copy(matrix.Data, a, a.Length);
+
+ var tau = new float[matrix.ColumnCount];
+ var r = new float[matrix.ColumnCount * matrix.ColumnCount];
+ Control.LinearAlgebraProvider.ThinQRFactor(a, matrix.RowCount, matrix.ColumnCount, r, tau);
+
+ 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, QRMethod.Thin);
+
+ var mb = new DenseMatrix(matrix.RowCount, 2, b);
+ var test = (matrix.Transpose() * matrix).Inverse() * matrix.Transpose() * mb;
+
+ AssertHelpers.AlmostEqual(test[0, 0], x[0], 6);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 6);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 6);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(mb[0, 0], b[0], 5);
+ AssertHelpers.AlmostEqual(mb[1, 0], b[1], 5);
+ AssertHelpers.AlmostEqual(mb[2, 0], b[2], 5);
+ AssertHelpers.AlmostEqual(mb[0, 1], b[3], 5);
+ AssertHelpers.AlmostEqual(mb[1, 1], b[4], 5);
+ AssertHelpers.AlmostEqual(mb[2, 1], b[5], 5);
+ }
+
+ ///
+ /// 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.Data, 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.AlmostEqual(test[0, 0], x[0], 6);
+ AssertHelpers.AlmostEqual(test[1, 0], x[1], 6);
+ AssertHelpers.AlmostEqual(test[0, 1], x[2], 6);
+ AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
+ }
+
///
/// Can compute the SVD factorization of a square matrix.
///
diff --git a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/QRTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/QRTests.cs
index e7d56d70..0be6f6e6 100644
--- a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/QRTests.cs
+++ b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/QRTests.cs
@@ -1,4 +1,4 @@
-//
+//
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
@@ -88,6 +88,38 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
+ ///
+ /// Can factorize identity matrix using thin QR.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(10)]
+ [TestCase(100)]
+ public void CanFactorizeIdentityUsingThinQR(int order)
+ {
+ var matrixI = DenseMatrix.Identity(order);
+ var factorQR = matrixI.QR(QRMethod.Thin);
+ var r = factorQR.R;
+
+ Assert.AreEqual(matrixI.ColumnCount, r.RowCount);
+ Assert.AreEqual(matrixI.ColumnCount, r.ColumnCount);
+
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(1.0, r[i, j].Magnitude);
+ }
+ else
+ {
+ Assert.AreEqual(Complex.Zero, r[i, j]);
+ }
+ }
+ }
+ }
+
///
/// Identity determinant is one.
///
@@ -151,6 +183,64 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
+ ///
+ /// Can factorize a random matrix using thin QR.
+ ///
+ /// Matrix row number.
+ /// Matrix column number.
+ [TestCase(1, 1)]
+ [TestCase(2, 2)]
+ [TestCase(5, 5)]
+ [TestCase(10, 6)]
+ [TestCase(50, 48)]
+ [TestCase(100, 98)]
+ public void CanFactorizeRandomMatrixUsingThinQR(int row, int column)
+ {
+ var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column);
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var q = factorQR.Q;
+ var r = factorQR.R;
+
+ // Make sure the R has the right dimensions.
+ Assert.AreEqual(column, r.RowCount);
+ Assert.AreEqual(column, r.ColumnCount);
+
+ // Make sure the Q has the right dimensions.
+ Assert.AreEqual(row, q.RowCount);
+ Assert.AreEqual(column, q.ColumnCount);
+
+ // Make sure the R factor is upper triangular.
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i > j)
+ {
+ Assert.AreEqual(Complex.Zero, r[i, j]);
+ }
+ }
+ }
+
+ // Make sure the Q is unitary --> (Q*)x(Q) = I
+ var matrixQсtQ = q.ConjugateTranspose() * q;
+ for (var i = 0; i < matrixQсtQ.RowCount; i++)
+ {
+ for (var j = 0; j < matrixQсtQ.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(matrixQсtQ[i, j].Real, 1.0f, 1e-3f);
+ Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f);
+ }
+ else
+ {
+ Assert.AreEqual(matrixQсtQ[i, j].Real, 0.0f, 1e-3f);
+ Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f);
+ }
+ }
+ }
+ }
+
///
/// Can solve a system of linear equations for a random vector (Ax=b).
///
@@ -339,5 +429,194 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
}
+
+ ///
+ /// Can solve a system of linear equations for a random vector (Ax=b).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var vectorb = MatrixLoader.GenerateRandomDenseVector(order);
+ var resultx = factorQR.Solve(vectorb);
+
+ Assert.AreEqual(matrixA.ColumnCount, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < order; i++)
+ {
+ AssertHelpers.AlmostEqual(vectorb[i], matrixBReconstruct[i], 9);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order);
+ var matrixX = factorQR.Solve(matrixB);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ AssertHelpers.AlmostEqual(matrixB[i, j], matrixBReconstruct[i, j], 9);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve for a random vector into a result vector.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorWhenResultVectorGivenUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var vectorb = MatrixLoader.GenerateRandomDenseVector(order);
+ var vectorbCopy = vectorb.Clone();
+ var resultx = new DenseVector(order);
+ factorQR.Solve(vectorb, resultx);
+
+ Assert.AreEqual(vectorb.Count, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ AssertHelpers.AlmostEqual(vectorb[i], matrixBReconstruct[i], 9);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure b didn't change.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ Assert.AreEqual(vectorbCopy[i], vectorb[i]);
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixWhenResultMatrixGivenUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order);
+ var matrixBCopy = matrixB.Clone();
+
+ var matrixX = new DenseMatrix(order, order);
+ factorQR.Solve(matrixB, matrixX);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ AssertHelpers.AlmostEqual(matrixB[i, j], matrixBReconstruct[i, j], 9);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure B didn't change.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]);
+ }
+ }
+ }
}
}
diff --git a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserQRTests.cs b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserQRTests.cs
index 43ea2fcf..f1e1d399 100644
--- a/src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserQRTests.cs
+++ b/src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserQRTests.cs
@@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
{
using System;
@@ -88,6 +90,38 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
+ ///
+ /// Can factorize identity matrix using thin QR.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(10)]
+ [TestCase(100)]
+ public void CanFactorizeIdentityUsingThinQR(int order)
+ {
+ var matrixI = UserDefinedMatrix.Identity(order);
+ var factorQR = matrixI.QR(QRMethod.Thin);
+ var r = factorQR.R;
+
+ Assert.AreEqual(matrixI.RowCount, r.RowCount);
+ Assert.AreEqual(matrixI.ColumnCount, r.ColumnCount);
+
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(-Complex.One, r[i, j]);
+ }
+ else
+ {
+ Assert.AreEqual(Complex.Zero, r[i, j]);
+ }
+ }
+ }
+ }
+
///
/// Identity determinant is one.
///
@@ -151,6 +185,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
+ ///
+ /// Can factorize a random matrix using thin QR.
+ ///
+ /// Matrix row number.
+ /// Matrix column number.
+ [TestCase(1, 1)]
+ [TestCase(2, 2)]
+ [TestCase(5, 5)]
+ [TestCase(10, 6)]
+ [TestCase(50, 48)]
+ [TestCase(100, 98)]
+ public void CanFactorizeRandomMatrixUsingThinQR(int row, int column)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column);
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var q = factorQR.Q;
+ var r = factorQR.R;
+
+ // Make sure the R has the right dimensions.
+ Assert.AreEqual(column, r.RowCount);
+ Assert.AreEqual(column, r.ColumnCount);
+
+ // Make sure the Q has the right dimensions.
+ Assert.AreEqual(row, q.RowCount);
+ Assert.AreEqual(column, q.ColumnCount);
+
+ // Make sure the R factor is upper triangular.
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i > j)
+ {
+ Assert.AreEqual(Complex.Zero, r[i, j]);
+ }
+ }
+ }
+
+ // Make sure the Q*R is the original matrix.
+ var matrixQfromR = q * r;
+ for (var i = 0; i < matrixQfromR.RowCount; i++)
+ {
+ for (var j = 0; j < matrixQfromR.ColumnCount; j++)
+ {
+ AssertHelpers.AlmostEqual(matrixA[i, j], matrixQfromR[i, j], 9);
+ }
+ }
+ }
+
///
/// Can solve a system of linear equations for a random vector (Ax=b).
///
@@ -339,5 +422,194 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
}
+
+ ///
+ /// Can solve a system of linear equations for a random vector (Ax=b).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order);
+ var resultx = factorQR.Solve(vectorb);
+
+ Assert.AreEqual(matrixA.ColumnCount, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < order; i++)
+ {
+ AssertHelpers.AlmostEqual(vectorb[i], matrixBReconstruct[i], 9);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixX = factorQR.Solve(matrixB);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ AssertHelpers.AlmostEqual(matrixB[i, j], matrixBReconstruct[i, j], 9);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve for a random vector into a result vector.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorWhenResultVectorGivenUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order);
+ var vectorbCopy = vectorb.Clone();
+ var resultx = new UserDefinedVector(order);
+ factorQR.Solve(vectorb, resultx);
+
+ Assert.AreEqual(vectorb.Count, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ AssertHelpers.AlmostEqual(vectorb[i], matrixBReconstruct[i], 9);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure b didn't change.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ Assert.AreEqual(vectorbCopy[i], vectorb[i]);
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixWhenResultMatrixGivenUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixBCopy = matrixB.Clone();
+
+ var matrixX = new UserDefinedMatrix(order, order);
+ factorQR.Solve(matrixB, matrixX);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ AssertHelpers.AlmostEqual(matrixB[i, j], matrixBReconstruct[i, j], 9);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure B didn't change.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]);
+ }
+ }
+ }
}
}
diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/QRTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/QRTests.cs
index 4e4b4ee0..029b42e1 100644
--- a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/QRTests.cs
+++ b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/QRTests.cs
@@ -88,6 +88,39 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
+ ///
+ /// Can factorize identity matrix using thin QR.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(10)]
+ [TestCase(100)]
+ public void CanFactorizeIdentityUsingThinQR(int order)
+ {
+ var matrixI = DenseMatrix.Identity(order);
+ var factorQR = matrixI.QR(QRMethod.Thin);
+ var r = factorQR.R;
+
+ Assert.AreEqual(matrixI.ColumnCount, r.RowCount);
+ Assert.AreEqual(matrixI.ColumnCount, r.ColumnCount);
+
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(1.0, r[i, j].Magnitude);
+ }
+ else
+ {
+ Assert.AreEqual(Complex32.Zero, r[i, j]);
+ }
+ }
+ }
+ }
+
+
///
/// Identity determinant is one.
///
@@ -171,6 +204,64 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
+ ///
+ /// Can factorize a random matrix using thin QR.
+ ///
+ /// Matrix row number.
+ /// Matrix column number.
+ [TestCase(1, 1)]
+ [TestCase(2, 2)]
+ [TestCase(5, 5)]
+ [TestCase(10, 6)]
+ [TestCase(50, 48)]
+ [TestCase(100, 98)]
+ public void CanFactorizeRandomMatrixUsingThinQR(int row, int column)
+ {
+ var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column);
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var q = factorQR.Q;
+ var r = factorQR.R;
+
+ // Make sure the R has the right dimensions.
+ Assert.AreEqual(column, r.RowCount);
+ Assert.AreEqual(column, r.ColumnCount);
+
+ // Make sure the Q has the right dimensions.
+ Assert.AreEqual(row, q.RowCount);
+ Assert.AreEqual(column, q.ColumnCount);
+
+ // Make sure the R factor is upper triangular.
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i > j)
+ {
+ Assert.AreEqual(Complex32.Zero, r[i, j]);
+ }
+ }
+ }
+
+ // Make sure the Q is unitary --> (Q*)x(Q) = I
+ var matrixQсtQ = q.ConjugateTranspose() * q;
+ for (var i = 0; i < matrixQсtQ.RowCount; i++)
+ {
+ for (var j = 0; j < matrixQсtQ.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(matrixQсtQ[i, j].Real, 1.0f, 1e-3f);
+ Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f);
+ }
+ else
+ {
+ Assert.AreEqual(matrixQсtQ[i, j].Real, 0.0f, 1e-3f);
+ Assert.AreEqual(matrixQсtQ[i, j].Imaginary, 0.0f, 1e-3f);
+ }
+ }
+ }
+ }
+
///
/// Can solve a system of linear equations for a random vector (Ax=b).
///
diff --git a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserQRTests.cs b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserQRTests.cs
index 04956678..ecff2b28 100644
--- a/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserQRTests.cs
+++ b/src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserQRTests.cs
@@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
{
using System;
@@ -87,6 +89,38 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
+ ///
+ /// Can factorize identity matrix using thin QR.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(10)]
+ [TestCase(100)]
+ public void CanFactorizeIdentityUsingThinQR(int order)
+ {
+ var matrixI = UserDefinedMatrix.Identity(order);
+ var factorQR = matrixI.QR(QRMethod.Thin);
+ var r = factorQR.R;
+
+ Assert.AreEqual(matrixI.RowCount, r.RowCount);
+ Assert.AreEqual(matrixI.ColumnCount, r.ColumnCount);
+
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(-Complex32.One, r[i, j]);
+ }
+ else
+ {
+ Assert.AreEqual(Complex32.Zero, r[i, j]);
+ }
+ }
+ }
+ }
+
///
/// Identity determinant is one.
///
@@ -170,6 +204,56 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
+ ///
+ /// Can factorize a random matrix using thin QR.
+ ///
+ /// Matrix row number.
+ /// Matrix column number.
+ [TestCase(1, 1)]
+ [TestCase(2, 2)]
+ [TestCase(5, 5)]
+ [TestCase(10, 6)]
+ [TestCase(50, 48)]
+ [TestCase(100, 98)]
+ public void CanFactorizeRandomMatrixUsingThinQR(int row, int column)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column);
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var q = factorQR.Q;
+ var r = factorQR.R;
+
+ // Make sure the R has the right dimensions.
+ Assert.AreEqual(column, r.RowCount);
+ Assert.AreEqual(column, r.ColumnCount);
+
+ // Make sure the Q has the right dimensions.
+ Assert.AreEqual(row, q.RowCount);
+ Assert.AreEqual(column, q.ColumnCount);
+
+ // Make sure the R factor is upper triangular.
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i > j)
+ {
+ Assert.AreEqual(Complex32.Zero, r[i, j]);
+ }
+ }
+ }
+
+ // Make sure the Q*R is the original matrix.
+ var matrixQfromR = q * r;
+ for (var i = 0; i < matrixQfromR.RowCount; i++)
+ {
+ for (var j = 0; j < matrixQfromR.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixA[i, j].Real, matrixQfromR[i, j].Real, 1e-3f);
+ Assert.AreEqual(matrixA[i, j].Imaginary, matrixQfromR[i, j].Imaginary, 1e-3f);
+ }
+ }
+ }
+
///
/// Can solve a system of linear equations for a random vector (Ax=b).
///
@@ -362,5 +446,198 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
}
+
+ ///
+ /// Can solve a system of linear equations for a random vector (Ax=b).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order);
+ var resultx = factorQR.Solve(vectorb);
+
+ Assert.AreEqual(matrixA.ColumnCount, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < order; i++)
+ {
+ Assert.AreEqual(vectorb[i].Real, matrixBReconstruct[i].Real, 1e-3f);
+ Assert.AreEqual(vectorb[i].Imaginary, matrixBReconstruct[i].Imaginary, 1e-3f);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixX = factorQR.Solve(matrixB);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f);
+ Assert.AreEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve for a random vector into a result vector.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorWhenResultVectorGivenUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order);
+ var vectorbCopy = vectorb.Clone();
+ var resultx = new UserDefinedVector(order);
+ factorQR.Solve(vectorb, resultx);
+
+ Assert.AreEqual(vectorb.Count, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ Assert.AreEqual(vectorb[i].Real, matrixBReconstruct[i].Real, 1e-3f);
+ Assert.AreEqual(vectorb[i].Imaginary, matrixBReconstruct[i].Imaginary, 1e-3f);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure b didn't change.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ Assert.AreEqual(vectorbCopy[i], vectorb[i]);
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixWhenResultMatrixGivenUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixBCopy = matrixB.Clone();
+
+ var matrixX = new UserDefinedMatrix(order, order);
+ factorQR.Solve(matrixB, matrixX);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, 1e-3f);
+ Assert.AreEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, 1e-3f);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure B didn't change.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]);
+ }
+ }
+ }
}
}
diff --git a/src/UnitTests/LinearAlgebraTests/Double/Factorization/QRTests.cs b/src/UnitTests/LinearAlgebraTests/Double/Factorization/QRTests.cs
index e8edb44b..03fb1f4b 100644
--- a/src/UnitTests/LinearAlgebraTests/Double/Factorization/QRTests.cs
+++ b/src/UnitTests/LinearAlgebraTests/Double/Factorization/QRTests.cs
@@ -87,6 +87,38 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
}
}
+ ///
+ /// Can factorize identity matrix using thin QR.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(10)]
+ [TestCase(100)]
+ public void CanFactorizeIdentityUsingThinQR(int order)
+ {
+ var matrixI = DenseMatrix.Identity(order);
+ var factorQR = matrixI.QR(QRMethod.Thin);
+ var r = factorQR.R;
+
+ Assert.AreEqual(matrixI.ColumnCount, r.RowCount);
+ Assert.AreEqual(matrixI.ColumnCount, r.ColumnCount);
+
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(1.0, Math.Abs(r[i, j]));
+ }
+ else
+ {
+ Assert.AreEqual(0.0, r[i, j]);
+ }
+ }
+ }
+ }
+
///
/// Identity determinant is one.
///
@@ -150,6 +182,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
}
}
+ ///
+ /// Can factorize a random matrix using thin QR.
+ ///
+ /// Matrix row number.
+ /// Matrix column number.
+ [TestCase(1, 1)]
+ [TestCase(2, 2)]
+ [TestCase(5, 5)]
+ [TestCase(10, 6)]
+ [TestCase(50, 48)]
+ [TestCase(100, 98)]
+ public void CanFactorizeRandomMatrixUsingThinQR(int row, int column)
+ {
+ var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column);
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var q = factorQR.Q;
+ var r = factorQR.R;
+
+ // Make sure the R has the right dimensions.
+ Assert.AreEqual(column, r.RowCount);
+ Assert.AreEqual(column, r.ColumnCount);
+
+ // Make sure the Q has the right dimensions.
+ Assert.AreEqual(row, q.RowCount);
+ Assert.AreEqual(column, q.ColumnCount);
+
+ // Make sure the R factor is upper triangular.
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i > j)
+ {
+ Assert.AreEqual(0.0, r[i, j]);
+ }
+ }
+ }
+
+ // Make sure the Q*R is the original matrix.
+ var matrixQfromR = q * r;
+ for (var i = 0; i < matrixQfromR.RowCount; i++)
+ {
+ for (var j = 0; j < matrixQfromR.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixA[i, j], matrixQfromR[i, j], 1.0e-11);
+ }
+ }
+ }
+
///
/// Can solve a system of linear equations for a random vector (Ax=b).
///
diff --git a/src/UnitTests/LinearAlgebraTests/Double/Factorization/UserQRTests.cs b/src/UnitTests/LinearAlgebraTests/Double/Factorization/UserQRTests.cs
index a3404a92..c59039eb 100644
--- a/src/UnitTests/LinearAlgebraTests/Double/Factorization/UserQRTests.cs
+++ b/src/UnitTests/LinearAlgebraTests/Double/Factorization/UserQRTests.cs
@@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
{
using System;
@@ -86,6 +88,38 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
}
}
+ ///
+ /// Can factorize identity matrix using thin QR.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(10)]
+ [TestCase(100)]
+ public void CanFactorizeIdentityUsingThinQR(int order)
+ {
+ var matrixI = UserDefinedMatrix.Identity(order);
+ var factorQR = matrixI.QR(QRMethod.Thin);
+ var r = factorQR.R;
+
+ Assert.AreEqual(matrixI.RowCount, r.RowCount);
+ Assert.AreEqual(matrixI.ColumnCount, r.ColumnCount);
+
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(-1.0, r[i, j]);
+ }
+ else
+ {
+ Assert.AreEqual(0.0, r[i, j]);
+ }
+ }
+ }
+ }
+
///
/// Identity determinant is one.
///
@@ -149,6 +183,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
}
}
+ ///
+ /// Can factorize a random matrix using thin QR.
+ ///
+ /// Matrix row number.
+ /// Matrix column number.
+ [TestCase(1, 1)]
+ [TestCase(2, 2)]
+ [TestCase(5, 5)]
+ [TestCase(10, 6)]
+ [TestCase(50, 48)]
+ [TestCase(100, 98)]
+ public void CanFactorizeRandomMatrixUsingThinQR(int row, int column)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column);
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var q = factorQR.Q;
+ var r = factorQR.R;
+
+ // Make sure the R has the right dimensions.
+ Assert.AreEqual(column, r.RowCount);
+ Assert.AreEqual(column, r.ColumnCount);
+
+ // Make sure the Q has the right dimensions.
+ Assert.AreEqual(row, q.RowCount);
+ Assert.AreEqual(column, q.ColumnCount);
+
+ // Make sure the R factor is upper triangular.
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i > j)
+ {
+ Assert.AreEqual(0.0, r[i, j]);
+ }
+ }
+ }
+
+ // Make sure the Q*R is the original matrix.
+ var matrixQfromR = q * r;
+ for (var i = 0; i < matrixQfromR.RowCount; i++)
+ {
+ for (var j = 0; j < matrixQfromR.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixA[i, j], matrixQfromR[i, j], 1.0e-11);
+ }
+ }
+ }
+
///
/// Can solve a system of linear equations for a random vector (Ax=b).
///
@@ -337,5 +420,194 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
}
}
}
+
+ ///
+ /// Can solve a system of linear equations for a random vector (Ax=b).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order);
+ var resultx = factorQR.Solve(vectorb);
+
+ Assert.AreEqual(matrixA.ColumnCount, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < order; i++)
+ {
+ Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1.0e-11);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixX = factorQR.Solve(matrixB);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1.0e-11);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve for a random vector into a result vector.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorWhenResultVectorGivenUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order);
+ var vectorbCopy = vectorb.Clone();
+ var resultx = new UserDefinedVector(order);
+ factorQR.Solve(vectorb, resultx);
+
+ Assert.AreEqual(vectorb.Count, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1.0e-11);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure b didn't change.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ Assert.AreEqual(vectorbCopy[i], vectorb[i]);
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixWhenResultMatrixGivenUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixBCopy = matrixB.Clone();
+
+ var matrixX = new UserDefinedMatrix(order, order);
+ factorQR.Solve(matrixB, matrixX);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1.0e-11);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure B didn't change.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]);
+ }
+ }
+ }
}
}
diff --git a/src/UnitTests/LinearAlgebraTests/Single/Factorization/QRTests.cs b/src/UnitTests/LinearAlgebraTests/Single/Factorization/QRTests.cs
index 29980350..05069d08 100644
--- a/src/UnitTests/LinearAlgebraTests/Single/Factorization/QRTests.cs
+++ b/src/UnitTests/LinearAlgebraTests/Single/Factorization/QRTests.cs
@@ -87,6 +87,39 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
}
}
+ ///
+ /// Can factorize identity matrix using thin QR.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(10)]
+ [TestCase(100)]
+ public void CanFactorizeIdentityUsingThinQR(int order)
+ {
+ var matrixI = DenseMatrix.Identity(order);
+ var factorQR = matrixI.QR(QRMethod.Thin);
+ var r = factorQR.R;
+
+ Assert.AreEqual(matrixI.ColumnCount, r.RowCount);
+ Assert.AreEqual(matrixI.ColumnCount, r.ColumnCount);
+
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(1.0, Math.Abs(r[i, j]));
+ }
+ else
+ {
+ Assert.AreEqual(0.0, r[i, j]);
+ }
+ }
+ }
+ }
+
+
///
/// Identity determinant is one.
///
@@ -150,6 +183,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
}
}
+ ///
+ /// Can factorize a random matrix using thin QR.
+ ///
+ /// Matrix row number.
+ /// Matrix column number.
+ [TestCase(1, 1)]
+ [TestCase(2, 2)]
+ [TestCase(5, 5)]
+ [TestCase(10, 6)]
+ [TestCase(50, 48)]
+ [TestCase(100, 98)]
+ public void CanFactorizeRandomMatrixUsingThinQR(int row, int column)
+ {
+ var matrixA = MatrixLoader.GenerateRandomDenseMatrix(row, column);
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var q = factorQR.Q;
+ var r = factorQR.R;
+
+ // Make sure the R has the right dimensions.
+ Assert.AreEqual(column, r.RowCount);
+ Assert.AreEqual(column, r.ColumnCount);
+
+ // Make sure the Q has the right dimensions.
+ Assert.AreEqual(row, q.RowCount);
+ Assert.AreEqual(column, q.ColumnCount);
+
+ // Make sure the R factor is upper triangular.
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i > j)
+ {
+ Assert.AreEqual(0.0, r[i, j]);
+ }
+ }
+ }
+
+ // Make sure the Q*R is the original matrix.
+ var matrixQfromR = q * r;
+ for (var i = 0; i < matrixQfromR.RowCount; i++)
+ {
+ for (var j = 0; j < matrixQfromR.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixA[i, j], matrixQfromR[i, j], 1.0e-4);
+ }
+ }
+ }
+
///
/// Can solve a system of linear equations for a random vector (Ax=b).
///
diff --git a/src/UnitTests/LinearAlgebraTests/Single/Factorization/UserQRTests.cs b/src/UnitTests/LinearAlgebraTests/Single/Factorization/UserQRTests.cs
index 9340c2fe..b418829b 100644
--- a/src/UnitTests/LinearAlgebraTests/Single/Factorization/UserQRTests.cs
+++ b/src/UnitTests/LinearAlgebraTests/Single/Factorization/UserQRTests.cs
@@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
+
namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
{
using System;
@@ -86,6 +88,38 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
}
}
+ ///
+ /// Can factorize identity matrix using thin QR.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(10)]
+ [TestCase(100)]
+ public void CanFactorizeIdentityUsingThinQR(int order)
+ {
+ var matrixI = UserDefinedMatrix.Identity(order);
+ var factorQR = matrixI.QR(QRMethod.Thin);
+ var r = factorQR.R;
+
+ Assert.AreEqual(matrixI.RowCount, r.RowCount);
+ Assert.AreEqual(matrixI.ColumnCount, r.ColumnCount);
+
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i == j)
+ {
+ Assert.AreEqual(-1.0, r[i, j]);
+ }
+ else
+ {
+ Assert.AreEqual(0.0, r[i, j]);
+ }
+ }
+ }
+ }
+
///
/// Identity determinant is one.
///
@@ -149,6 +183,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
}
}
+ ///
+ /// Can factorize a random matrix using thin QR.
+ ///
+ /// Matrix row number.
+ /// Matrix column number.
+ [TestCase(1, 1)]
+ [TestCase(2, 2)]
+ [TestCase(5, 5)]
+ [TestCase(10, 6)]
+ [TestCase(50, 48)]
+ [TestCase(100, 98)]
+ public void CanFactorizeRandomMatrixUsingThinQR(int row, int column)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(row, column);
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var q = factorQR.Q;
+ var r = factorQR.R;
+
+ // Make sure the R has the right dimensions.
+ Assert.AreEqual(column, r.RowCount);
+ Assert.AreEqual(column, r.ColumnCount);
+
+ // Make sure the Q has the right dimensions.
+ Assert.AreEqual(row, q.RowCount);
+ Assert.AreEqual(column, q.ColumnCount);
+
+ // Make sure the R factor is upper triangular.
+ for (var i = 0; i < r.RowCount; i++)
+ {
+ for (var j = 0; j < r.ColumnCount; j++)
+ {
+ if (i > j)
+ {
+ Assert.AreEqual(0.0, r[i, j]);
+ }
+ }
+ }
+
+ // Make sure the Q*R is the original matrix.
+ var matrixQfromR = q * r;
+ for (var i = 0; i < matrixQfromR.RowCount; i++)
+ {
+ for (var j = 0; j < matrixQfromR.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixA[i, j], matrixQfromR[i, j], 1.0e-4);
+ }
+ }
+ }
+
///
/// Can solve a system of linear equations for a random vector (Ax=b).
///
@@ -337,5 +420,194 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
}
}
}
+
+ ///
+ /// Can solve a system of linear equations for a random vector (Ax=b).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order);
+ var resultx = factorQR.Solve(vectorb);
+
+ Assert.AreEqual(matrixA.ColumnCount, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < order; i++)
+ {
+ Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-4);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B).
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixX = factorQR.Solve(matrixB);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1e-4);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+ }
+
+ ///
+ /// Can solve for a random vector into a result vector.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomVectorWhenResultVectorGivenUsingThinQR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+ var vectorb = MatrixLoader.GenerateRandomUserDefinedVector(order);
+ var vectorbCopy = vectorb.Clone();
+ var resultx = new UserDefinedVector(order);
+ factorQR.Solve(vectorb, resultx);
+
+ Assert.AreEqual(vectorb.Count, resultx.Count);
+
+ var matrixBReconstruct = matrixA * resultx;
+
+ // Check the reconstruction.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-4);
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure b didn't change.
+ for (var i = 0; i < vectorb.Count; i++)
+ {
+ Assert.AreEqual(vectorbCopy[i], vectorb[i]);
+ }
+ }
+
+ ///
+ /// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
+ ///
+ /// Matrix order.
+ [TestCase(1)]
+ [TestCase(2)]
+ [TestCase(5)]
+ [TestCase(10)]
+ [TestCase(50)]
+ [TestCase(100)]
+ public void CanSolveForRandomMatrixWhenResultMatrixGivenUsingThinAR(int order)
+ {
+ var matrixA = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixACopy = matrixA.Clone();
+ var factorQR = matrixA.QR(QRMethod.Thin);
+
+ var matrixB = MatrixLoader.GenerateRandomUserDefinedMatrix(order, order);
+ var matrixBCopy = matrixB.Clone();
+
+ var matrixX = new UserDefinedMatrix(order, order);
+ factorQR.Solve(matrixB, matrixX);
+
+ // The solution X row dimension is equal to the column dimension of A
+ Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount);
+
+ // The solution X has the same number of columns as B
+ Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount);
+
+ var matrixBReconstruct = matrixA * matrixX;
+
+ // Check the reconstruction.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixB[i, j], matrixBReconstruct[i, j], 1e-4);
+ }
+ }
+
+ // Make sure A didn't change.
+ for (var i = 0; i < matrixA.RowCount; i++)
+ {
+ for (var j = 0; j < matrixA.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixACopy[i, j], matrixA[i, j]);
+ }
+ }
+
+ // Make sure B didn't change.
+ for (var i = 0; i < matrixB.RowCount; i++)
+ {
+ for (var j = 0; j < matrixB.ColumnCount; j++)
+ {
+ Assert.AreEqual(matrixBCopy[i, j], matrixB[i, j]);
+ }
+ }
+ }
}
}
diff --git a/src/UnitTests/Setup.cs b/src/UnitTests/Setup.cs
index 18231463..6b51861a 100644
--- a/src/UnitTests/Setup.cs
+++ b/src/UnitTests/Setup.cs
@@ -45,13 +45,5 @@ public class Setup
{
MathNet.Numerics.Control.LinearAlgebraProvider = new MathNet.Numerics.Algorithms.LinearAlgebra.Mkl.MklLinearAlgebraProvider();
}
- else if (provider.Contains("gotoblas"))
- {
- MathNet.Numerics.Control.LinearAlgebraProvider = new MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas.GotoBlasLinearAlgebraProvider();
- }
- else if (provider.Contains("acml"))
- {
- MathNet.Numerics.Control.LinearAlgebraProvider = new MathNet.Numerics.Algorithms.LinearAlgebra.Acml.AcmlLinearAlgebraProvider();
- }
}
}