Browse Source

added thin qr

pull/57/merge
Marcus Cuda 14 years ago
parent
commit
fe9e158777
  1. 282
      src/NativeWrappers/MKL/lapack.cpp
  2. 2
      src/NativeWrappers/MKL/lapack.h
  3. 4
      src/NativeWrappers/Windows/ACML/ACMLWrapper.vcxproj
  4. 33
      src/NativeWrappers/Windows/ACMLWrapper/ACMKWrapper.vcxproj.filters
  5. 2
      src/NativeWrappers/Windows/ACMLWrapperTests/ACMLWrapperTests.csproj
  6. 74
      src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj
  7. 22
      src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters
  8. 5
      src/NativeWrappers/Windows/MKLWrapperTests/MKLWrapperTests.csproj
  9. 63
      src/NativeWrappers/Windows/NativeWrappers.sln
  10. 2
      src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex.cs
  11. 2
      src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex32.cs
  12. 2
      src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.double.cs
  13. 2
      src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.float.cs
  14. 10
      src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex.cs
  15. 10
      src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex32.cs
  16. 10
      src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.double.cs
  17. 10
      src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.float.cs
  18. 70
      src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs
  19. 296
      src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex.cs
  20. 289
      src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Complex32.cs
  21. 291
      src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Double.cs
  22. 292
      src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.Single.cs
  23. 154
      src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs
  24. 154
      src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs
  25. 232
      src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs
  26. 154
      src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.float.cs
  27. 24
      src/Numerics/Algorithms/LinearAlgebra/Mkl/SafeNativeMethods.cs
  28. 5
      src/Numerics/LinearAlgebra/Complex/ExtensionMethods.cs
  29. 23
      src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs
  30. 7
      src/Numerics/LinearAlgebra/Complex/Factorization/QR.cs
  31. 65
      src/Numerics/LinearAlgebra/Complex/Factorization/UserQR.cs
  32. 5
      src/Numerics/LinearAlgebra/Complex32/ExtensionMethods.cs
  33. 23
      src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs
  34. 7
      src/Numerics/LinearAlgebra/Complex32/Factorization/QR.cs
  35. 65
      src/Numerics/LinearAlgebra/Complex32/Factorization/UserQR.cs
  36. 5
      src/Numerics/LinearAlgebra/Double/ExtensionMethods.cs
  37. 24
      src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs
  38. 7
      src/Numerics/LinearAlgebra/Double/Factorization/QR.cs
  39. 66
      src/Numerics/LinearAlgebra/Double/Factorization/UserQR.cs
  40. 2
      src/Numerics/LinearAlgebra/Generic/Factorization/GramSchmidt.cs
  41. 42
      src/Numerics/LinearAlgebra/Generic/Factorization/QR.cs
  42. 5
      src/Numerics/LinearAlgebra/Single/ExtensionMethods.cs
  43. 23
      src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs
  44. 7
      src/Numerics/LinearAlgebra/Single/Factorization/QR.cs
  45. 65
      src/Numerics/LinearAlgebra/Single/Factorization/UserQR.cs
  46. 16
      src/Numerics/Numerics.csproj
  47. 337
      src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs
  48. 337
      src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs
  49. 342
      src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs
  50. 337
      src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs
  51. 281
      src/UnitTests/LinearAlgebraTests/Complex/Factorization/QRTests.cs
  52. 272
      src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserQRTests.cs
  53. 91
      src/UnitTests/LinearAlgebraTests/Complex32/Factorization/QRTests.cs
  54. 277
      src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserQRTests.cs
  55. 81
      src/UnitTests/LinearAlgebraTests/Double/Factorization/QRTests.cs
  56. 272
      src/UnitTests/LinearAlgebraTests/Double/Factorization/UserQRTests.cs
  57. 82
      src/UnitTests/LinearAlgebraTests/Single/Factorization/QRTests.cs
  58. 272
      src/UnitTests/LinearAlgebraTests/Single/Factorization/UserQRTests.cs
  59. 8
      src/UnitTests/Setup.cs

282
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;
}

2
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

4
src/NativeWrappers/Windows/ACMLWrapper/ACMKWrapper.vcxproj → src/NativeWrappers/Windows/ACML/ACMLWrapper.vcxproj

@ -29,23 +29,27 @@
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">

33
src/NativeWrappers/Windows/ACMLWrapper/ACMKWrapper.vcxproj.filters

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\Common\resource.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\Common\WindowsDLL.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\ACML\blas.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\ACML\lapack.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

2
src/NativeWrappers/Windows/ACMLWrapperTests/ACMLWrapperTests.csproj

@ -36,7 +36,7 @@
<HintPath>..\..\..\..\out\debug\Net40\MathNet.Numerics.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>..\..\..\..\lib\NUnit.2.5.9\nunit.framework.dll</HintPath>
<HintPath>..\..\..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

74
src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj

@ -25,23 +25,27 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<UseIntelMKL>Parallel</UseIntelMKL>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<UseIntelMKL>Parallel</UseIntelMKL>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<UseIntelMKL>Parallel</UseIntelMKL>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<UseIntelMKL>Parallel</UseIntelMKL>
</PropertyGroup>
@ -62,32 +66,28 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\Common;..\..\MKL;C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\include;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common;$(ProjectDir)..\..\MKL;$(MKLIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@ -99,12 +99,12 @@
<Link>
<AdditionalDependencies>mkl_intel_c.lib;mkl_intel_thread.lib;mkl_core.lib;libiomp5md.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)MathNET.Numerics.MKL.dll</OutputFile>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\lib\ia32;C:\Program Files (x86)\Intel\ComposerXE-2011\compiler\lib\ia32;</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Intel\Compiler\11.1\046\lib\ia32;C:\Program Files (x86)\Intel\Compiler\11.1\046\mkl\ia32\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<PostBuildEvent>
<Command>copy "C:\Program Files (x86)\Intel\Composer XE\redist\ia32\compiler\libiomp5md.dll" $(OutDir)</Command>
<Command>copy "$(CompilerPathForVC)\libiomp5md.dll" $(OutDir)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -113,7 +113,7 @@
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\Common;..\..\MKL;C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\include;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common;$(ProjectDir)..\..\MKL;$(MKLIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@ -125,19 +125,19 @@
<Link>
<AdditionalDependencies>mkl_intel_lp64.lib;mkl_intel_thread.lib;mkl_core.lib;libiomp5md.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)MathNET.Numerics.MKL.dll</OutputFile>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\lib\intel64;C:\Program Files (x86)\Intel\ComposerXE-2011\compiler\lib\intel64</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Intel\Compiler\11.1\046\lib\intel64;C:\Program Files (x86)\Intel\Compiler\11.1\046\mkl\em64t\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<TargetMachine>MachineX64</TargetMachine>
</Link>
<PostBuildEvent>
<Command>copy "C:\Program Files (x86)\Intel\Composer XE\redist\intel64\compiler\libiomp5md.dll" $(OutDir)</Command>
<Command>copy "$(CompilerPathForVC)\libiomp5md.dll" $(OutDir)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\Common;..\..\MKL;C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\include;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common;$(ProjectDir)..\..\MKL;$(MKLIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
@ -148,14 +148,14 @@
<Link>
<AdditionalDependencies>mkl_intel_c.lib;mkl_intel_thread.lib;mkl_core.lib;libiomp5md.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)MathNET.Numerics.MKL.dll</OutputFile>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\lib\ia32;C:\Program Files (x86)\Intel\ComposerXE-2011\compiler\lib\ia32;</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Intel\Compiler\11.1\060\lib\ia32;C:\Program Files (x86)\Intel\Compiler\11.1\060\mkl\ia32\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
<PostBuildEvent>
<Command>copy "C:\Program Files (x86)\Intel\Composer XE\redist\ia32\compiler\libiomp5md.dll" $(OutDir)</Command>
<Command>copy "$(CompilerPathForVC)\libiomp5md.dll" $(OutDir)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -165,7 +165,7 @@
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\Common;..\..\MKL;C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\include;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common;$(ProjectDir)..\..\MKL;$(MKLIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
@ -176,26 +176,26 @@
<Link>
<AdditionalDependencies>mkl_intel_lp64.lib;mkl_intel_thread.lib;mkl_core.lib;libiomp5md.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)MathNET.Numerics.MKL.dll</OutputFile>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Intel\ComposerXE-2011\mkl\lib\intel64;C:\Program Files (x86)\Intel\ComposerXE-2011\compiler\lib\intel64</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Intel\Compiler\11.1\060\lib\intel64;C:\Program Files (x86)\Intel\Compiler\11.1\060\mkl\em64t\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX64</TargetMachine>
</Link>
<PostBuildEvent>
<Command>copy "C:\Program Files (x86)\Intel\Composer XE\redist\intel64\compiler\libiomp5md.dll" $(OutDir)</Command>
<Command>copy "$(CompilerPathForVC)\libiomp5md.dll" $(OutDir)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\Common\wrapper_common.h" />
<ClInclude Include="..\..\MKL\lapack.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\Common\WindowsDLL.cpp" />
<ClCompile Include="..\..\MKL\blas.c" />
<ClCompile Include="..\..\MKL\lapack.cpp" />
<ClCompile Include="..\..\MKL\vector_functions.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Common\wrapper_common.h" />
<ClInclude Include="..\..\MKL\lapack.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\Common\resource.rc" />
</ItemGroup>

22
src/NativeWrappers/Windows/MKL/MKLWrapper.vcxproj.filters

@ -15,17 +15,6 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Common\wrapper_common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\MKL\lapack.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\Common\WindowsDLL.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\MKL\blas.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -35,6 +24,17 @@
<ClCompile Include="..\..\MKL\vector_functions.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\Common\WindowsDLL.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\MKL\lapack.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\Common\wrapper_common.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\Common\resource.rc">

5
src/NativeWrappers/Windows/MKLWrapperTests/MKLWrapperTests.csproj

@ -59,8 +59,9 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\out\debug\Net40\MathNet.Numerics.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>..\..\..\..\lib\NUnit.2.5.9\nunit.framework.dll</HintPath>
<Reference Include="nunit.framework, Version=2.5.9.10348, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">

63
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

2
src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.Complex.cs

@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Acml
{
using System;

2
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;

2
src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.double.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Acml
{
using System;

2
src/Numerics/Algorithms/LinearAlgebra/Acml/AcmlLinearAlgebraProvider.float.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Acml
{
using System;

10
src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
[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
/// <summary>
/// Solves A*X=B for X using a previously QR factored matrix.
/// </summary>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(Complex[],int,int,Complex[],Complex[])"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex[],int,int,Complex[],Complex[])"/>. </param>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(Complex[],int,int,Complex[],Complex[],QRMethod)"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex[],int,int,Complex[],Complex[],QRMethod)"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
@ -814,7 +816,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
/// </summary>
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex[],int,int,Complex[],Complex[])"/>. </param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex[],int,int,Complex[],Complex[],QRMethod)"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver

10
src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.Complex32.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
[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
/// <summary>
/// Solves A*X=B for X using a previously QR factored matrix.
/// </summary>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(Complex32[],int,int,Complex32[],Complex32[])"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex32[],int,int,Complex32[],Complex32[])"/>. </param>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(Complex32[],int,int,Complex32[],Complex32[],QRMethod)"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex32[],int,int,Complex32[],Complex32[],QRMethod)"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
@ -813,7 +815,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
/// </summary>
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex32[],int,int,Complex32[],Complex32[])"/>. </param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex32[],int,int,Complex32[],Complex32[],QRMethod)"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver

10
src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.double.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
[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
/// <summary>
/// Solves A*X=B for X using a previously QR factored matrix.
/// </summary>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[])"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[])"/>. </param>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[],QRMethod)"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[],QRMethod)"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
@ -813,7 +815,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
/// </summary>
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[])"/>. </param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[],QRMethod)"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver

10
src/Numerics/Algorithms/LinearAlgebra/GotoBlas/GotoBlasLinearAlgebraProvider.float.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
[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
/// <summary>
/// Solves A*X=B for X using a previously QR factored matrix.
/// </summary>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[])"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[])"/>. </param>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[],QRMethod)"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[],QRMethod)"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
@ -813,7 +815,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.GotoBlas
/// </summary>
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[])"/>. </param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[],QRMethod)"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver

70
src/Numerics/Algorithms/LinearAlgebra/ILinearAlgebraProviderOfT.cs

@ -25,6 +25,9 @@
// </copyright>
// 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);
/// <summary>
/// Computes the QR factorization of A.
/// Computes the full QR factorization of A.
/// </summary>
/// <param name="r">On entry, it is the M by N A matrix to factor. On exit,
/// <param name="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.</param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="q">On exit, A M by M matrix that holds the Q matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
void QRFactor(T[] r, int rowsR, int columnsR, T[] q, T[] tau);
void QRFactor(T[] a, int rowsA, int columnsA, T[] q, T[] tau);
/// <summary>
/// Computes the QR factorization of A.
/// Computes the full QR factorization of A.
/// </summary>
/// <param name="r">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. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="q">On exit, A M by M matrix that holds the Q matrix of the
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="q">On exit, A M by M matrix that holds the Q matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <param name="work">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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
void QRFactor(T[] a, int rowsA, int columnsA, T[] q, T[] tau, T[] work);
/// <summary>
/// Computes the thin QR factorization of A where M &gt; N.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
void ThinQRFactor(T[] a, int rowsA, int columnsA, T[] r, T[] tau);
/// <summary>
/// Computes the thin QR factorization of A where M &gt; N.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
@ -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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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);
/// <summary>
/// Solves A*X=B for X using QR factorization of A.
@ -352,8 +386,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
/// <summary>
/// Solves A*X=B for X using QR factorization of A.
@ -367,8 +402,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
/// <summary>
/// Solves A*X=B for X using a previously QR factored matrix.
@ -384,7 +420,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
void QRSolveFactored(T[] q, T[] r, int rowsR, int columnsR, T[] tau, T[] b, int columnsB, T[] x);
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
void QRSolveFactored(T[] q, T[] r, int rowsR, int columnsR, T[] tau, T[] b, int columnsB, T[] x, QRMethod method = QRMethod.Full);
/// <summary>
/// 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.</param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
void QRSolveFactored(T[] q, T[] r, int rowsR, int columnsR, T[] tau, T[] b, int columnsB, T[] x, T[] work);
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
void QRSolveFactored(T[] q, T[] r, int rowsR, int columnsR, T[] tau, T[] b, int columnsB, T[] x, T[] work, QRMethod method = QRMethod.Full);
/// <summary>
/// Computes the singular value decomposition of A.

296
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.
// </copyright>
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;
}
/// <summary>
/// Computes the QR factorization of A.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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);
}
/// <summary>
/// Computes the QR factorization of A where M &gt; N.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <param name="work">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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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
/// <summary>
@ -1667,46 +1811,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -1721,8 +1831,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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;
}
/// <summary>
@ -1795,10 +1916,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -1806,15 +1928,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// </summary>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(Complex[],int,int,Complex[],Complex[])"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex[],int,int,Complex[],Complex[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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)];
}
});
}
}
/// <summary>
/// Computes the singular value decomposition of A.

289
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.
// </copyright>
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;
}
/// <summary>
/// Computes the QR factorization of A.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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);
}
/// <summary>
/// Computes the QR factorization of A where M &gt; N.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <param name="work">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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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
/// <summary>
@ -1663,46 +1808,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -1717,8 +1828,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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;
}
/// <summary>
@ -1791,10 +1913,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -1802,15 +1925,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// </summary>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(Complex32[],int,int,Complex32[],Complex32[])"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex32[],int,int,Complex32[],Complex32[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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)];
}
});
}

291
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.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.Algorithms.LinearAlgebra
{
using System;
@ -1339,6 +1342,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <param name="method">The type of QR factorization to perform.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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;
}
/// <summary>
/// Computes the QR factorization of A.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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);
}
/// <summary>
/// Computes the thin QR factorization of A where M &gt; N.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <param name="work">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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -1607,8 +1718,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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;
}
/// <summary>
@ -1671,8 +1792,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">On entry the B matrix; on exit the X matrix.</param>
@ -1681,10 +1802,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -1692,15 +1814,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// </summary>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[])"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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)];
}
});
}

292
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.
// </copyright>
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;
}
/// <summary>
/// Computes the QR factorization of A.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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);
}
/// <summary>
/// Computes the QR factorization of A where M &gt; N.
/// </summary>
/// <param name="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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <param name="work">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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
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
/// <summary>
@ -1554,46 +1698,12 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -1608,8 +1718,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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;
}
/// <summary>
@ -1672,8 +1793,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">On entry the B matrix; on exit the X matrix.</param>
@ -1682,9 +1803,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// <param name="work">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.</param>
public virtual void QRSolveFactored(float[] q, float[] r, int rowsR, int columnsR, float[] tau, float[] b, int columnsB, float[] x, float[] work)
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -1692,15 +1815,16 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra
/// </summary>
/// <param name="q">The Q matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[])"/>.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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)];
}
});
}

154
src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
{
using System;
@ -666,46 +668,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -720,8 +689,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
}
/// <summary>
@ -784,57 +762,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
[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);
}
/// <summary>
@ -843,8 +777,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex[],int,int,Complex[],Complex[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">On entry the B matrix; on exit the X matrix.</param>
@ -853,8 +787,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
}
/// <summary>

154
src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
{
using System;
@ -665,46 +667,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -719,8 +688,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
}
/// <summary>
@ -783,57 +761,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
[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);
}
/// <summary>
@ -842,8 +776,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(Complex32[],int,int,Complex32[],Complex32[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">On entry the B matrix; on exit the X matrix.</param>
@ -852,8 +786,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
}
/// <summary>

232
src/Numerics/Algorithms/LinearAlgebra/Mkl/MklLinearAlgebraProvider.double.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
{
using System;
@ -657,54 +659,125 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
}
/// <summary>
/// Solves A*X=B for X using QR factorization of A.
/// Computes the thin QR factorization of A where M &gt; N.
/// </summary>
/// <param name="a">The A matrix.</param>
/// <param name="rows">The number of rows in the A matrix.</param>
/// <param name="columns">The number of columns in the A matrix.</param>
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
public override void QRSolve(double[] a, int rows, int columns, double[] b, int columnsB, double[] x)
/// <param name="q">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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
[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);
}
/// <summary>
/// Computes the thin QR factorization of A where M &gt; N.
/// </summary>
/// <param name="q">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.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="r">On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.</param>
/// <param name="tau">A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.</param>
/// <param name="work">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.</param>
/// <remarks>This is similar to the GEQRF and ORGQR LAPACK routines.</remarks>
[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);
}
/// <summary>
/// Solves A*X=B for X using QR factorization of A.
/// </summary>
/// <param name="a">The A matrix.</param>
/// <param name="rows">The number of rows in the A matrix.</param>
/// <param name="columns">The number of columns in the A matrix.</param>
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
[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);
}
/// <summary>
@ -719,8 +792,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
}
/// <summary>
@ -783,57 +865,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
[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);
}
/// <summary>
@ -842,8 +880,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(double[],int,int,double[],double[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">On entry the B matrix; on exit the X matrix.</param>
@ -852,8 +890,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
}
/// <summary>

154
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
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
/// <summary>
@ -723,8 +692,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
}
/// <summary>
@ -787,57 +765,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="b">The B matrix.</param>
/// <param name="columnsB">The number of columns of B.</param>
/// <param name="x">On exit, the solution matrix.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
[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);
}
/// <summary>
@ -846,8 +780,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="q">The Q matrix obtained by QR factor. This is only used for the managed provider and can be
/// <c>null</c> for the native provider. The native provider uses the Q portion stored in the R matrix.</param>
/// <param name="r">The R matrix obtained by calling <see cref="QRFactor(float[],int,int,float[],float[])"/>. </param>
/// <param name="rowsR">The number of rows in the A matrix.</param>
/// <param name="columnsR">The number of columns in the A matrix.</param>
/// <param name="rowsA">The number of rows in the A matrix.</param>
/// <param name="columnsA">The number of columns in the A matrix.</param>
/// <param name="tau">Contains additional information on Q. Only used for the native solver
/// and can be <c>null</c> for the managed provider.</param>
/// <param name="b">On entry the B matrix; on exit the X matrix.</param>
@ -856,8 +790,10 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra.Mkl
/// <param name="work">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.</param>
/// <param name="method">The type of QR factorization to perform. <seealso cref="QRMethod"/></param>
/// <remarks>Rows must be greater or equal to columns.</remarks>
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);
}
}
/// <summary>

24
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);

5
src/Numerics/LinearAlgebra/Complex/ExtensionMethods.cs

@ -60,10 +60,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex
/// Computes the QR decomposition for a matrix.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The type of QR factorization to perform.</param>
/// <returns>The QR decomposition object.</returns>
public static QR QR(this Matrix<Complex> matrix)
public static QR QR(this Matrix<Complex> matrix, QRMethod method = QRMethod.Full)
{
return (QR)QR<Complex>.Create(matrix);
return (QR)QR<Complex>.Create(matrix, method);
}
/// <summary>

23
src/Numerics/LinearAlgebra/Complex/Factorization/DenseQR.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The type of QR factorization to perform.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If <paramref name="matrix"/> row count is less then column count</exception>
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<ArgumentException>(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);
}
}
/// <summary>

7
src/Numerics/LinearAlgebra/Complex/Factorization/QR.cs

@ -33,12 +33,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
/// <summary>
/// <para>A class which encapsulates the functionality of the QR decomposition.</para>
/// <para>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
/// <para>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).</para>
/// </summary>
/// <remarks>
/// The computation of the QR decomposition is done at construction time by Householder transformation.
/// If a <seealso cref="QRMethod.Full"/> 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 <seealso cref="QRMethod.Thin"/> factorization is performed, the
/// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
/// </remarks>
public abstract class QR : QR<Complex>
{

65
src/Numerics/LinearAlgebra/Complex/Factorization/UserQR.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The QR factorization method to use.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
public UserQR(Matrix<Complex> matrix)
public UserQR(Matrix<Complex> matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@ -66,25 +69,57 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(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);
}
}
}

5
src/Numerics/LinearAlgebra/Complex32/ExtensionMethods.cs

@ -60,10 +60,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32
/// Computes the QR decomposition for a matrix.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The type of QR factorization to perform.</param>
/// <returns>The QR decomposition object.</returns>
public static QR QR(this Matrix<Complex32> matrix)
public static QR QR(this Matrix<Complex32> matrix, QRMethod method = QRMethod.Full)
{
return (QR)QR<Complex32>.Create(matrix);
return (QR)QR<Complex32>.Create(matrix, method);
}
/// <summary>

23
src/Numerics/LinearAlgebra/Complex32/Factorization/DenseQR.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The QR factorization method to use.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If <paramref name="matrix"/> row count is less then column count</exception>
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<ArgumentException>(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);
}
}
/// <summary>

7
src/Numerics/LinearAlgebra/Complex32/Factorization/QR.cs

@ -33,12 +33,15 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
/// <summary>
/// <para>A class which encapsulates the functionality of the QR decomposition.</para>
/// <para>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
/// <para>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).</para>
/// </summary>
/// <remarks>
/// The computation of the QR decomposition is done at construction time by Householder transformation.
/// If a <seealso cref="QRMethod.Full"/> 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 <seealso cref="QRMethod.Thin"/> factorization is performed, the
/// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
/// </remarks>
public abstract class QR : QR<Complex32>
{

65
src/Numerics/LinearAlgebra/Complex32/Factorization/UserQR.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The QR factorization method to use.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
public UserQR(Matrix<Complex32> matrix)
public UserQR(Matrix<Complex32> matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@ -66,25 +69,57 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(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);
}
}
}

5
src/Numerics/LinearAlgebra/Double/ExtensionMethods.cs

@ -59,10 +59,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double
/// Computes the QR decomposition for a matrix.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The type of QR factorization to perform.</param>
/// <returns>The QR decomposition object.</returns>
public static QR QR(this Matrix<double> matrix)
public static QR QR(this Matrix<double> matrix, QRMethod method = QRMethod.Full)
{
return (QR)QR<double>.Create(matrix);
return (QR)QR<double>.Create(matrix, method);
}
/// <summary>

24
src/Numerics/LinearAlgebra/Double/Factorization/DenseQR.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The type of QR factorization to perform.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If <paramref name="matrix"/> row count is less then column count</exception>
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<ArgumentException>(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);
}
}
/// <summary>

7
src/Numerics/LinearAlgebra/Double/Factorization/QR.cs

@ -32,12 +32,15 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
/// <summary>
/// <para>A class which encapsulates the functionality of the QR decomposition.</para>
/// <para>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
/// <para>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).</para>
/// </summary>
/// <remarks>
/// The computation of the QR decomposition is done at construction time by Householder transformation.
/// If a <seealso cref="QRMethod.Full"/> 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 <seealso cref="QRMethod.Thin"/> factorization is performed, the
/// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
/// </remarks>
public abstract class QR : QR<double>
{

66
src/Numerics/LinearAlgebra/Double/Factorization/UserQR.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The QR factorization method to use.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
public UserQR(Matrix<double> matrix)
public UserQR(Matrix<double> matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@ -65,25 +68,58 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(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);
}
}
}

2
src/Numerics/LinearAlgebra/Generic/Factorization/GramSchmidt.cs

@ -47,7 +47,7 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <returns>A QR factorization object.</returns>
new internal static GramSchmidt<T> Create(Matrix<T> matrix)
internal static GramSchmidt<T> Create(Matrix<T> matrix)
{
if (typeof(T) == typeof(double))
{

42
src/Numerics/LinearAlgebra/Generic/Factorization/QR.cs

@ -31,14 +31,33 @@ namespace MathNet.Numerics.LinearAlgebra.Generic.Factorization
using Generic;
using Numerics;
/// <summary>
/// The type of QR factorization go perform.
/// </summary>
public enum QRMethod
{
/// <summary>
/// Compute the full QR factorization of a matrix.
/// </summary>
Full = 0,
/// <summary>
/// Compute the thin QR factorixation of a matrix.
/// </summary>
Thin = 1
}
/// <summary>
/// <para>A class which encapsulates the functionality of the QR decomposition.</para>
/// <para>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
/// <para>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).</para>
/// </summary>
/// <remarks>
/// The computation of the QR decomposition is done at construction time by Householder transformation.
/// If a <seealso cref="QRMethod.Full"/> 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 <seealso cref="QRMethod.Thin"/> factorization is performed, the
/// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
/// </remarks>
/// <typeparam name="T">Supported data types are double, single, <see cref="Complex"/>, and <see cref="Complex32"/>.</typeparam>
public abstract class QR<T> : ISolver<T>
@ -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.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The type of QR factorization to perform.</param>
/// <returns>A QR factorization object.</returns>
internal static QR<T> Create(Matrix<T> matrix)
internal static QR<T> Create(Matrix<T> 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<T>;
return new LinearAlgebra.Double.Factorization.DenseQR(dense, method) as QR<T>;
}
return new LinearAlgebra.Double.Factorization.UserQR(matrix as Matrix<double>) as QR<T>;
return new LinearAlgebra.Double.Factorization.UserQR(matrix as Matrix<double>, method) as QR<T>;
}
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<T>;
return new LinearAlgebra.Single.Factorization.DenseQR(dense, method) as QR<T>;
}
return new LinearAlgebra.Single.Factorization.UserQR(matrix as Matrix<float>) as QR<T>;
return new LinearAlgebra.Single.Factorization.UserQR(matrix as Matrix<float>, method) as QR<T>;
}
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<T>;
return new LinearAlgebra.Complex.Factorization.DenseQR(dense, method) as QR<T>;
}
return new LinearAlgebra.Complex.Factorization.UserQR(matrix as Matrix<Complex>) as QR<T>;
return new LinearAlgebra.Complex.Factorization.UserQR(matrix as Matrix<Complex>, method) as QR<T>;
}
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<T>;
return new LinearAlgebra.Complex32.Factorization.DenseQR(dense, method) as QR<T>;
}
return new LinearAlgebra.Complex32.Factorization.UserQR(matrix as Matrix<Complex32>) as QR<T>;
return new LinearAlgebra.Complex32.Factorization.UserQR(matrix as Matrix<Complex32>, method) as QR<T>;
}
throw new NotSupportedException();

5
src/Numerics/LinearAlgebra/Single/ExtensionMethods.cs

@ -59,10 +59,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single
/// Computes the QR decomposition for a matrix.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The type of QR factorization to perform.</param>
/// <returns>The QR decomposition object.</returns>
public static QR QR(this Matrix<float> matrix)
public static QR QR(this Matrix<float> matrix, QRMethod method = QRMethod.Full)
{
return (QR)QR<float>.Create(matrix);
return (QR)QR<float>.Create(matrix, method);
}
/// <summary>

23
src/Numerics/LinearAlgebra/Single/Factorization/DenseQR.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The QR factorization method to use.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If <paramref name="matrix"/> row count is less then column count</exception>
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<ArgumentException>(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);
}
}
/// <summary>

7
src/Numerics/LinearAlgebra/Single/Factorization/QR.cs

@ -32,12 +32,15 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
/// <summary>
/// <para>A class which encapsulates the functionality of the QR decomposition.</para>
/// <para>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
/// <para>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).</para>
/// </summary>
/// <remarks>
/// The computation of the QR decomposition is done at construction time by Householder transformation.
/// If a <seealso cref="QRMethod.Full"/> 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 <seealso cref="QRMethod.Thin"/> factorization is performed, the
/// resulting Q matrix is an m x n matrix and the R matrix is an n x n matrix.
/// </remarks>
public abstract class QR : QR<float>
{

65
src/Numerics/LinearAlgebra/Single/Factorization/UserQR.cs

@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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.
/// </summary>
/// <param name="matrix">The matrix to factor.</param>
/// <param name="method">The QR factorization method to use.</param>
/// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
public UserQR(Matrix<float> matrix)
public UserQR(Matrix<float> matrix, QRMethod method = QRMethod.Full)
{
if (matrix == null)
{
@ -65,25 +68,57 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Factorization
throw Matrix.DimensionsDontMatch<ArgumentException>(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);
}
}
}

16
src/Numerics/Numerics.csproj

@ -85,22 +85,6 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Algorithms\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Complex.cs">
</Compile>
<Compile Include="Algorithms\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Complex32.cs">
</Compile>
<Compile Include="Algorithms\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.double.cs">
</Compile>
<Compile Include="Algorithms\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.float.cs">
</Compile>
<Compile Include="Algorithms\LinearAlgebra\Acml\SafeNativeMethods.cs">
</Compile>
<Compile Include="Algorithms\LinearAlgebra\GotoBlas\GotoBlasLinearAlgebraProvider.Common.cs" />
<Compile Include="Algorithms\LinearAlgebra\GotoBlas\GotoBlasLinearAlgebraProvider.Complex.cs" />
<Compile Include="Algorithms\LinearAlgebra\GotoBlas\GotoBlasLinearAlgebraProvider.Complex32.cs" />
<Compile Include="Algorithms\LinearAlgebra\GotoBlas\GotoBlasLinearAlgebraProvider.double.cs" />
<Compile Include="Algorithms\LinearAlgebra\GotoBlas\GotoBlasLinearAlgebraProvider.float.cs" />
<Compile Include="Algorithms\LinearAlgebra\GotoBlas\SafeNativeMethods.cs" />
<Compile Include="Algorithms\LinearAlgebra\ManagedLinearAlgebraProvider.Complex32.cs" />
<Compile Include="Algorithms\LinearAlgebra\ManagedLinearAlgebraProvider.Complex.cs" />
<Compile Include="Algorithms\LinearAlgebra\ManagedLinearAlgebraProvider.Single.cs" />

337
src/UnitTests/LinearAlgebraProviderTests/Complex/LinearAlgebraProviderTests.cs

@ -789,6 +789,115 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex
}
}
/// <summary>
/// Can compute thin QR factorization of a square matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a tall matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a square matrix using a work array.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a tall matrix using a work matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can solve Ax=b using QR factorization with a square A matrix.
/// </summary>
@ -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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a factored A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a factored A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a factored A matrix with a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a factored A matrix with a work array.
/// </summary>
[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);
}
/// <summary>
/// Can compute the SVD factorization of a square matrix.
/// </summary>

337
src/UnitTests/LinearAlgebraProviderTests/Complex32/LinearAlgebraProviderTests.cs

@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32
{
using System;
@ -796,6 +798,115 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32
}
}
/// <summary>
/// Can compute thin QR factorization of a square matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a tall matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a square matrix using a work array.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a tall matrix using a work matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can solve Ax=b using QR factorization with a square A matrix.
/// </summary>
@ -1022,6 +1133,232 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Complex32
AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a factored A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a factored A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a factored A matrix with a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a factored A matrix with a work array.
/// </summary>
[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);
}
/// <summary>
/// Can compute the SVD factorization of a square matrix.
/// </summary>

342
src/UnitTests/LinearAlgebraProviderTests/Double/LinearAlgebraProviderTests.cs

@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double
{
using System;
@ -787,11 +789,121 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Double
}
}
/// <summary>
/// Can compute thin QR factorization of a square matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a tall matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a square matrix using a work array.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a tall matrix using a work matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can solve Ax=b using QR factorization with a square A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a factored A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a factored A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a factored A matrix with a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a factored A matrix with a work array.
/// </summary>
[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);
}
/// <summary>
/// Can compute the SVD factorization of a square matrix.
/// </summary>

337
src/UnitTests/LinearAlgebraProviderTests/Single/LinearAlgebraProviderTests.cs

@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.LinearAlgebra.Generic.Factorization;
namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single
{
using System;
@ -795,6 +797,115 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single
}
}
/// <summary>
/// Can compute thin QR factorization of a square matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a tall matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a square matrix using a work array.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can compute thin QR factorization of a tall matrix using a work matrix.
/// </summary>
[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);
}
}
}
/// <summary>
/// Can solve Ax=b using QR factorization with a square A matrix.
/// </summary>
@ -1021,6 +1132,232 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraProviderTests.Single
AssertHelpers.AlmostEqual(test[1, 1], x[3], 6);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a factored A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a factored A matrix.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a square A matrix
/// using a factored A matrix with a work array.
/// </summary>
[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);
}
/// <summary>
/// Can solve Ax=b using thin QR factorization with a tall A matrix
/// using a factored A matrix with a work array.
/// </summary>
[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);
}
/// <summary>
/// Can compute the SVD factorization of a square matrix.
/// </summary>

281
src/UnitTests/LinearAlgebraTests/Complex/Factorization/QRTests.cs

@ -1,4 +1,4 @@
// <copyright file="QRTests.cs" company="Math.NET">
// <copyright file="QRTests.cs" company="Math.NET">
// 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
}
}
/// <summary>
/// Can factorize identity matrix using thin QR.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
/// <summary>
/// Identity determinant is one.
/// </summary>
@ -151,6 +183,64 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
/// <summary>
/// Can factorize a random matrix using thin QR.
/// </summary>
/// <param name="row">Matrix row number.</param>
/// <param name="column">Matrix column number.</param>
[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);
}
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
@ -339,5 +429,194 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve for a random vector into a result vector.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
}

272
src/UnitTests/LinearAlgebraTests/Complex/Factorization/UserQRTests.cs

@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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
}
}
/// <summary>
/// Can factorize identity matrix using thin QR.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
/// <summary>
/// Identity determinant is one.
/// </summary>
@ -151,6 +185,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
/// <summary>
/// Can factorize a random matrix using thin QR.
/// </summary>
/// <param name="row">Matrix row number.</param>
/// <param name="column">Matrix column number.</param>
[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);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
@ -339,5 +422,194 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex.Factorization
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve for a random vector into a result vector.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
}

91
src/UnitTests/LinearAlgebraTests/Complex32/Factorization/QRTests.cs

@ -88,6 +88,39 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
/// <summary>
/// Can factorize identity matrix using thin QR.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
/// <summary>
/// Identity determinant is one.
/// </summary>
@ -171,6 +204,64 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
/// <summary>
/// Can factorize a random matrix using thin QR.
/// </summary>
/// <param name="row">Matrix row number.</param>
/// <param name="column">Matrix column number.</param>
[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);
}
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>

277
src/UnitTests/LinearAlgebraTests/Complex32/Factorization/UserQRTests.cs

@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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
}
}
/// <summary>
/// Can factorize identity matrix using thin QR.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
/// <summary>
/// Identity determinant is one.
/// </summary>
@ -170,6 +204,56 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
/// <summary>
/// Can factorize a random matrix using thin QR.
/// </summary>
/// <param name="row">Matrix row number.</param>
/// <param name="column">Matrix column number.</param>
[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);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
@ -362,5 +446,198 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Complex32.Factorization
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve for a random vector into a result vector.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
}

81
src/UnitTests/LinearAlgebraTests/Double/Factorization/QRTests.cs

@ -87,6 +87,38 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
}
}
/// <summary>
/// Can factorize identity matrix using thin QR.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
/// <summary>
/// Identity determinant is one.
/// </summary>
@ -150,6 +182,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
}
}
/// <summary>
/// Can factorize a random matrix using thin QR.
/// </summary>
/// <param name="row">Matrix row number.</param>
/// <param name="column">Matrix column number.</param>
[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);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>

272
src/UnitTests/LinearAlgebraTests/Double/Factorization/UserQRTests.cs

@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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
}
}
/// <summary>
/// Can factorize identity matrix using thin QR.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
/// <summary>
/// Identity determinant is one.
/// </summary>
@ -149,6 +183,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
}
}
/// <summary>
/// Can factorize a random matrix using thin QR.
/// </summary>
/// <param name="row">Matrix row number.</param>
/// <param name="column">Matrix column number.</param>
[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);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
@ -337,5 +420,194 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Double.Factorization
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve for a random vector into a result vector.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
}

82
src/UnitTests/LinearAlgebraTests/Single/Factorization/QRTests.cs

@ -87,6 +87,39 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
}
}
/// <summary>
/// Can factorize identity matrix using thin QR.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
/// <summary>
/// Identity determinant is one.
/// </summary>
@ -150,6 +183,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
}
}
/// <summary>
/// Can factorize a random matrix using thin QR.
/// </summary>
/// <param name="row">Matrix row number.</param>
/// <param name="column">Matrix column number.</param>
[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);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>

272
src/UnitTests/LinearAlgebraTests/Single/Factorization/UserQRTests.cs

@ -24,6 +24,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
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
}
}
/// <summary>
/// Can factorize identity matrix using thin QR.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
/// <summary>
/// Identity determinant is one.
/// </summary>
@ -149,6 +183,55 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
}
}
/// <summary>
/// Can factorize a random matrix using thin QR.
/// </summary>
/// <param name="row">Matrix row number.</param>
/// <param name="column">Matrix column number.</param>
[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);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
@ -337,5 +420,194 @@ namespace MathNet.Numerics.UnitTests.LinearAlgebraTests.Single.Factorization
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random vector (Ax=b).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B).
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
/// <summary>
/// Can solve for a random vector into a result vector.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
/// <summary>
/// Can solve a system of linear equations for a random matrix (AX=B) into a result matrix.
/// </summary>
/// <param name="order">Matrix order.</param>
[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]);
}
}
}
}
}

8
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();
}
}
}

Loading…
Cancel
Save