Browse Source

Merge branch 'fft'

benchmark-la
Christoph Ruegg 10 years ago
parent
commit
9ee9627a09
  1. 4
      MathNet.Numerics.All.sln
  2. 8
      src/NativeProviders/CUDA/lapack.cpp
  3. 2
      src/NativeProviders/Common/WindowsDLL.cpp
  4. 14
      src/NativeProviders/Common/lapack.cpp
  5. 4
      src/NativeProviders/Linux/mkl_build.sh
  6. 25
      src/NativeProviders/MKL/capabilities.cpp
  7. 54
      src/NativeProviders/MKL/fft.cpp
  8. 4
      src/NativeProviders/OSX/mkl_build.sh
  9. 1
      src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj
  10. 3
      src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters
  11. 124
      src/Numerics/Control.cs
  12. 47
      src/Numerics/IntegralTransforms/Fourier.cs
  13. 24
      src/Numerics/Numerics.csproj
  14. 111
      src/Numerics/Providers/Common/Cuda/CudaProvider.cs
  15. 13
      src/Numerics/Providers/Common/Cuda/CudaProviderCapabilities.cs
  16. 5
      src/Numerics/Providers/Common/Cuda/SafeNativeMethods.cs
  17. 262
      src/Numerics/Providers/Common/Mkl/MklProvider.cs
  18. 15
      src/Numerics/Providers/Common/Mkl/MklProviderCapabilities.cs
  19. 66
      src/Numerics/Providers/Common/Mkl/MklProviderPrecision.cs
  20. 21
      src/Numerics/Providers/Common/Mkl/SafeNativeMethods.cs
  21. 10
      src/Numerics/Providers/Common/NativeProviderLoader.cs
  22. 125
      src/Numerics/Providers/Common/OpenBlas/OpenBlasProvider.cs
  23. 13
      src/Numerics/Providers/Common/OpenBlas/OpenBlasProviderCapabilities.cs
  24. 4
      src/Numerics/Providers/Common/OpenBlas/SafeNativeMethods.cs
  25. 101
      src/Numerics/Providers/FourierTransform/FourierTransformControl.cs
  26. 64
      src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs
  27. 111
      src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs
  28. 183
      src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs
  29. 3
      src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex.cs
  30. 5
      src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex32.cs
  31. 5
      src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Double.cs
  32. 5
      src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Single.cs
  33. 59
      src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.cs
  34. 18
      src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs
  35. 122
      src/Numerics/Providers/LinearAlgebra/LinearAlgebraControl.cs
  36. 9
      src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.cs
  37. 1
      src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs
  38. 1
      src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs
  39. 1
      src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Double.cs
  40. 1
      src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Single.cs
  41. 178
      src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs
  42. 3
      src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex.cs
  43. 3
      src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex32.cs
  44. 3
      src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Double.cs
  45. 5
      src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Single.cs
  46. 65
      src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs
  47. 103
      src/UnitTests/FourierTransformProviderTests/FourierTransformProviderTests.cs
  48. 70
      src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs

4
MathNet.Numerics.All.sln

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Readme", "Readme", "{C2F37492-38AE-4186-8A7F-17B0B080942C}"
ProjectSection(SolutionItems) = preProject

8
src/NativeProviders/CUDA/lapack.cpp

@ -65,7 +65,7 @@ inline int lu_inverse(cusolverDnHandle_t solverHandle, cublasHandle_t blasHandle
getrf(solverHandle, n, n, d_A, n, work, d_I, d_info);
cudaMemcpy(&info, d_info, sizeof(int), cudaMemcpyDeviceToHost);
cudaFree(work);
if (info != 0)
@ -134,7 +134,7 @@ inline int lu_inverse_factored(cublasHandle_t blasHandle, int n, T a[], int ipiv
getri(blasHandle, n, d_Aarray, n, d_I, d_Carray, n, d_info, 1);
cudaMemcpy(&info, d_info, sizeof(int), cudaMemcpyDeviceToHost);
cublasGetMatrix(n, n, sizeof(T), d_C, n, a, n);
cublasGetMatrix(n, n, sizeof(T), d_C, n, a, n);
cublasGetVector(n, sizeof(int), d_I, 1, ipiv, 1);
shift_ipiv_down(n, ipiv);
@ -299,7 +299,7 @@ inline int cholesky_solve(cusolverDnHandle_t solverHandle, int n, int nrhs, T a[
cudaMemcpy(&info, d_info, sizeof(int), cudaMemcpyDeviceToHost);
cudaFree(work);
if (info != 0)
{
cudaFree(d_A);
@ -425,7 +425,7 @@ inline int cholesky_solve_factored(cusolverDnHandle_t solverHandle, int n, int n
// int info = 0;
// ormqr(solverHandle, &side, &tran, &m, &bn, &n, r, &m, tau, clone_b, &m, work, &len, &info);
// trsm(blasHandle, CblasColMajor, CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, n, bn, 1.0, r, m, clone_b, m);
//
//
// copyBtoX(m, n, bn, clone_b, x);
// delete[] clone_b;
// return info;

2
src/NativeProviders/Common/WindowsDLL.cpp

@ -2,7 +2,7 @@
#define VC_EXTRALEAN
#endif
#include "windows.h"
BOOL APIENTRY DllMain( HANDLE, DWORD, LPVOID ){
return TRUE;
}

14
src/NativeProviders/Common/lapack.cpp

@ -16,12 +16,12 @@ inline lapack_int lu_factor(lapack_int m, T a[], lapack_int ipiv[], GETRF getrf)
template<typename T, typename GETRF, typename GETRI>
inline lapack_int lu_inverse(lapack_int n, T a[], GETRF getrf, GETRI getri)
{
try
try
{
auto ipiv = array_new<lapack_int>(n);
auto info = getrf(LAPACK_COL_MAJOR, n, n, a, n, ipiv.get());
if (info != 0)
if (info != 0)
{
return info;
}
@ -29,7 +29,7 @@ inline lapack_int lu_inverse(lapack_int n, T a[], GETRF getrf, GETRI getri)
info = getri(LAPACK_COL_MAJOR, n, a, n, ipiv.get());
return info;
}
catch (std::bad_alloc&)
catch (std::bad_alloc&)
{
return INSUFFICIENT_MEMORY;
}
@ -56,20 +56,20 @@ inline lapack_int lu_solve_factored(lapack_int n, lapack_int nrhs, T a[], lapack
template<typename T, typename GETRF, typename GETRS>
inline lapack_int lu_solve(lapack_int n, lapack_int nrhs, T a[], T b[], GETRF getrf, GETRS getrs)
{
try
try
{
auto clone = array_clone(n * n, a);
auto ipiv = array_new<lapack_int>(n);
auto info = getrf(LAPACK_COL_MAJOR, n, n, clone.get(), n, ipiv.get());
if (info != 0)
if (info != 0)
{
return info;
}
return getrs(LAPACK_COL_MAJOR, 'N', n, nrhs, clone.get(), n, ipiv.get(), b, n);
}
catch (std::bad_alloc&)
catch (std::bad_alloc&)
{
return INSUFFICIENT_MEMORY;
}
@ -264,7 +264,7 @@ inline lapack_int svd_factor(bool compute_vectors, lapack_int m, lapack_int n, T
template<typename T, typename R, typename GESVD>
inline lapack_int complex_svd_factor(bool compute_vectors, lapack_int m, lapack_int n, T a[], T s[], T u[], T v[], GESVD gesvd)
{
try
try
{
auto dim_s = std::min(m, n);
auto s_local = array_new<R>(dim_s);

4
src/NativeProviders/Linux/mkl_build.sh

@ -7,10 +7,10 @@ export OUT=../../../out/MKL/Linux
mkdir -p $OUT/x64
mkdir -p $OUT/x86
g++ -std=c++11 -D_M_X64 -DGCC -m64 --shared -fPIC -o $OUT/x64/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common -I../MKL ../MKL/memory.c ../MKL/capabilities.cpp ../MKL/vector_functions.c ../Common/blas.c ../Common/lapack.cpp -Wl,--start-group $MKL/lib/intel64/libmkl_intel_lp64.a $MKL/lib/intel64/libmkl_intel_thread.a $MKL/lib/intel64/libmkl_core.a -Wl,--end-group -L$OPENMP/intel64 -liomp5 -lpthread -lm
g++ -std=c++11 -D_M_X64 -DGCC -m64 --shared -fPIC -o $OUT/x64/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common -I../MKL ../MKL/memory.c ../MKL/capabilities.cpp ../MKL/vector_functions.c ../Common/blas.c ../Common/lapack.cpp ../MKL/fft.cpp -Wl,--start-group $MKL/lib/intel64/libmkl_intel_lp64.a $MKL/lib/intel64/libmkl_intel_thread.a $MKL/lib/intel64/libmkl_core.a -Wl,--end-group -L$OPENMP/intel64 -liomp5 -lpthread -lm
cp $OPENMP/intel64/libiomp5.so $OUT/x64/
g++ -std=c++11 -D_M_IX86 -DGCC -m32 --shared -fPIC -o $OUT/x86/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common -I../MKL ../MKL/memory.c ../MKL/capabilities.cpp ../MKL/vector_functions.c ../Common/blas.c ../Common/lapack.cpp -Wl,--start-group $MKL/lib/ia32/libmkl_intel.a $MKL/lib/ia32/libmkl_intel_thread.a $MKL/lib/ia32/libmkl_core.a -Wl,--end-group -L$OPENMP/ia32 -liomp5 -lpthread -lm
g++ -std=c++11 -D_M_IX86 -DGCC -m32 --shared -fPIC -o $OUT/x86/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common -I../MKL ../MKL/memory.c ../MKL/capabilities.cpp ../MKL/vector_functions.c ../Common/blas.c ../Common/lapack.cpp ../MKL/fft.cpp -Wl,--start-group $MKL/lib/ia32/libmkl_intel.a $MKL/lib/ia32/libmkl_intel_thread.a $MKL/lib/ia32/libmkl_core.a -Wl,--end-group -L$OPENMP/ia32 -liomp5 -lpthread -lm
cp $OPENMP/ia32/libiomp5.so $OUT/x86/

25
src/NativeProviders/MKL/capabilities.cpp

@ -40,8 +40,28 @@ extern "C" {
return 0;
#endif
// MKL VERSION
case 32: // major version
{
MKLVersion Version;
mkl_get_version(&Version);
return Version.MajorVersion;
}
case 33: // minor version
{
MKLVersion Version;
mkl_get_version(&Version);
return Version.MinorVersion;
}
case 34: // update version
{
MKLVersion Version;
mkl_get_version(&Version);
return Version.UpdateVersion;
}
// COMMON/SHARED
case 64: return 10; // revision
case 64: return 11; // revision
case 65: return 1; // numerical consistency, precision and accuracy modes
case 66: return 1; // threading control
case 67: return 1; // memory management
@ -54,7 +74,8 @@ extern "C" {
case 256: return 0; // basic optimization
// FFT
case 384: return 0; // basic FFT
case 384: return 1; // basic FFT (major - breaking)
case 385: return 0; // basic FFT (minor - non-breaking)
default: return 0; // unknown or not supported

54
src/NativeProviders/MKL/fft.cpp

@ -0,0 +1,54 @@
#include "wrapper_common.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include "mkl_dfti.h"
template<typename Data, typename Precision, typename FFT>
inline MKL_INT64 fft_1d_inplace(const MKL_INT64 n, Data x[], const Precision forward_scale, const Precision backward_scale, const DFTI_CONFIG_VALUE precision, const DFTI_CONFIG_VALUE domain, FFT fft)
{
MKL_LONG status;
DFTI_DESCRIPTOR_HANDLE descriptor = nullptr;
status = DftiCreateDescriptor(&descriptor, precision, domain, 1, static_cast<MKL_LONG>(n));
if (0 != status) goto cleanup;
status = DftiSetValue(descriptor, DFTI_FORWARD_SCALE, forward_scale);
if (0 != status) goto cleanup;
status = DftiSetValue(descriptor, DFTI_BACKWARD_SCALE, backward_scale);
if (0 != status) goto cleanup;
status = DftiCommitDescriptor(descriptor);
if (0 != status) goto cleanup;
status = fft(descriptor, x);
cleanup:
DftiFreeDescriptor(&descriptor);
return static_cast<MKL_INT64>(status);
}
extern "C" {
DLLEXPORT MKL_INT64 z_fft_forward_inplace(const MKL_INT64 n, const double scaling, MKL_Complex16 x[])
{
return fft_1d_inplace(n, x, scaling, 1.0, DFTI_DOUBLE, DFTI_COMPLEX, DftiComputeForward);
}
DLLEXPORT MKL_INT64 c_fft_forward_inplace(const MKL_INT64 n, const float scaling, MKL_Complex8 x[])
{
return fft_1d_inplace(n, x, scaling, 1.0f, DFTI_SINGLE, DFTI_COMPLEX, DftiComputeForward);
}
DLLEXPORT MKL_INT64 z_fft_backward_inplace(const MKL_INT64 n, const double scaling, MKL_Complex16 x[])
{
return fft_1d_inplace(n, x, 1.0, scaling, DFTI_DOUBLE, DFTI_COMPLEX, DftiComputeBackward);
}
DLLEXPORT MKL_INT64 c_fft_backward_inplace(const MKL_INT64 n, const float scaling, MKL_Complex8 x[])
{
return fft_1d_inplace(n, x, 1.0f, scaling, DFTI_SINGLE, DFTI_COMPLEX, DftiComputeBackward);
}
}

4
src/NativeProviders/OSX/mkl_build.sh

@ -6,10 +6,10 @@ export OUT=../../../out/MKL/OSX
mkdir -p $OUT/x64
mkdir -p $OUT/x86
clang++ -std=c++11 -D_M_X64 -DGCC -m64 --shared -fPIC -o $OUT/x64/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common -I../MKL ../MKL/memory.c ../MKL/capabilities.cpp ../MKL/vector_functions.c ../Common/blas.c ../Common/lapack.cpp $MKL/lib/libmkl_intel_lp64.a $MKL/lib/libmkl_core.a $MKL/lib/libmkl_intel_thread.a -L$OPENMP -liomp5 -lpthread -lm
clang++ -std=c++11 -D_M_X64 -DGCC -m64 --shared -fPIC -o $OUT/x64/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common -I../MKL ../MKL/memory.c ../MKL/capabilities.cpp ../MKL/vector_functions.c ../Common/blas.c ../Common/lapack.cpp ../MKL/fft.cpp $MKL/lib/libmkl_intel_lp64.a $MKL/lib/libmkl_core.a $MKL/lib/libmkl_intel_thread.a -L$OPENMP -liomp5 -lpthread -lm
cp $OPENMP/libiomp5.dylib $OUT/x64/
clang++ -std=c++11 -D_M_IX86 -DGCC -m32 --shared -fPIC -o $OUT/x86/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common -I../MKL ../MKL/memory.c ../MKL/capabilities.cpp ../MKL/vector_functions.c ../Common/blas.c ../Common/lapack.cpp $MKL/lib/libmkl_intel_lp64.a $MKL/lib/libmkl_core.a $MKL/lib/libmkl_intel_thread.a -L$OPENMP -liomp5 -lpthread -lm
clang++ -std=c++11 -D_M_IX86 -DGCC -m32 --shared -fPIC -o $OUT/x86/MathNet.Numerics.MKL.dll -I$MKL/include -I../Common -I../MKL ../MKL/memory.c ../MKL/capabilities.cpp ../MKL/vector_functions.c ../Common/blas.c ../Common/lapack.cpp ../MKL/fft.cpp $MKL/lib/libmkl_intel_lp64.a $MKL/lib/libmkl_core.a $MKL/lib/libmkl_intel_thread.a -L$OPENMP -liomp5 -lpthread -lm
cp $OPENMP/libiomp5.dylib $OUT/x86/

1
src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj

@ -294,6 +294,7 @@
<ClCompile Include="..\..\MKL\capabilities.cpp" />
<ClCompile Include="..\..\MKL\memory.c" />
<ClCompile Include="..\..\MKL\vector_functions.c" />
<ClCompile Include="..\..\MKL\fft.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\MKL\resource.rc" />

3
src/NativeProviders/Windows/MKL/MKLWrapper.vcxproj.filters

@ -33,6 +33,9 @@
<ClCompile Include="..\..\Common\blas.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\MKL\fft.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\MKL\resource.rc">

124
src/Numerics/Control.cs

@ -27,9 +27,10 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using MathNet.Numerics.Providers.LinearAlgebra;
using System;
using System.Threading.Tasks;
using MathNet.Numerics.Providers.FourierTransform;
using MathNet.Numerics.Providers.LinearAlgebra;
namespace MathNet.Numerics
{
@ -38,13 +39,12 @@ namespace MathNet.Numerics
/// </summary>
public static class Control
{
const string EnvVarLAProvider = "MathNetNumericsLAProvider";
static int _maxDegreeOfParallelism;
static int _blockSize;
static int _parallelizeOrder;
static int _parallelizeElements;
static ILinearAlgebraProvider _linearAlgebraProvider;
static IFourierTransformProvider _fourierTransformProvider;
static readonly object _staticLock = new object();
static Control()
@ -66,53 +66,10 @@ namespace MathNet.Numerics
TaskScheduler = TaskScheduler.Default;
}
private static void InitializeDefaultLinearAlgebraProvider()
{
lock (_staticLock)
{
if (_linearAlgebraProvider == null)
{
#if NATIVE
try
{
var value = Environment.GetEnvironmentVariable(EnvVarLAProvider);
switch (value != null ? value.ToUpperInvariant() : string.Empty)
{
case "MKL":
UseNativeMKL();
break;
case "CUDA":
UseNativeCUDA();
break;
case "OPENBLAS":
UseNativeOpenBLAS();
break;
default:
if (!TryUseNative())
{
UseManaged();
}
break;
}
}
catch
{
// We don't care about any failures here at all (because "auto")
UseManaged();
}
#else
UseManaged();
#endif
}
}
}
public static void UseManaged()
{
LinearAlgebraProvider = new ManagedLinearAlgebraProvider();
LinearAlgebraControl.UseManaged();
FourierTransformControl.UseManaged();
}
#if NATIVE
@ -123,7 +80,8 @@ namespace MathNet.Numerics
/// </summary>
public static void UseNativeMKL()
{
LinearAlgebraProvider = new Providers.LinearAlgebra.Mkl.MklLinearAlgebraProvider();
LinearAlgebraControl.UseNativeMKL();
FourierTransformControl.UseNativeMKL();
}
/// <summary>
@ -131,12 +89,31 @@ namespace MathNet.Numerics
/// Throws if it is not available or failed to initialize, in which case the previous provider is still active.
/// </summary>
[CLSCompliant(false)]
[Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")]
public static void UseNativeMKL(
Providers.LinearAlgebra.Mkl.MklConsistency consistency = Providers.LinearAlgebra.Mkl.MklConsistency.Auto,
Providers.LinearAlgebra.Mkl.MklPrecision precision = Providers.LinearAlgebra.Mkl.MklPrecision.Double,
Providers.LinearAlgebra.Mkl.MklAccuracy accuracy = Providers.LinearAlgebra.Mkl.MklAccuracy.High)
{
LinearAlgebraProvider = new Providers.LinearAlgebra.Mkl.MklLinearAlgebraProvider(consistency, precision, accuracy);
LinearAlgebraControl.UseNativeMKL(
(Providers.Common.Mkl.MklConsistency)consistency,
(Providers.Common.Mkl.MklPrecision)precision,
(Providers.Common.Mkl.MklAccuracy)accuracy);
FourierTransformControl.UseNativeMKL();
}
/// <summary>
/// Use the Intel MKL native provider for linear algebra, with the specified configuration parameters.
/// Throws if it is not available or failed to initialize, in which case the previous provider is still active.
/// </summary>
[CLSCompliant(false)]
public static void UseNativeMKL(
Providers.Common.Mkl.MklConsistency consistency = Providers.Common.Mkl.MklConsistency.Auto,
Providers.Common.Mkl.MklPrecision precision = Providers.Common.Mkl.MklPrecision.Double,
Providers.Common.Mkl.MklAccuracy accuracy = Providers.Common.Mkl.MklAccuracy.High)
{
LinearAlgebraControl.UseNativeMKL(consistency, precision, accuracy);
FourierTransformControl.UseNativeMKL();
}
/// <summary>
@ -157,7 +134,7 @@ namespace MathNet.Numerics
/// </summary>
public static void UseNativeCUDA()
{
LinearAlgebraProvider = new Providers.LinearAlgebra.Cuda.CudaLinearAlgebraProvider();
LinearAlgebraControl.UseNativeCUDA();
}
/// <summary>
@ -178,7 +155,7 @@ namespace MathNet.Numerics
/// </summary>
public static void UseNativeOpenBLAS()
{
LinearAlgebraProvider = new Providers.LinearAlgebra.OpenBlas.OpenBlasLinearAlgebraProvider();
LinearAlgebraControl.UseNativeOpenBLAS();
}
/// <summary>
@ -226,6 +203,7 @@ namespace MathNet.Numerics
ThreadSafeRandomNumberGenerators = false;
LinearAlgebraProvider.InitializeVerify();
FourierTransformProvider.InitializeVerify();
}
public static void UseMultiThreading()
@ -234,6 +212,7 @@ namespace MathNet.Numerics
ThreadSafeRandomNumberGenerators = true;
LinearAlgebraProvider.InitializeVerify();
FourierTransformProvider.InitializeVerify();
}
/// <summary>
@ -266,7 +245,15 @@ namespace MathNet.Numerics
get
{
if (_linearAlgebraProvider == null)
InitializeDefaultLinearAlgebraProvider();
{
lock (_staticLock)
{
if (_linearAlgebraProvider == null)
{
LinearAlgebraControl.UseDefault();
}
}
}
return _linearAlgebraProvider;
}
@ -279,6 +266,36 @@ namespace MathNet.Numerics
}
}
/// <summary>
/// Gets or sets the fourier transform provider. Consider to use UseNativeMKL or UseManaged instead.
/// </summary>
/// <value>The linear algebra provider.</value>
public static IFourierTransformProvider FourierTransformProvider
{
get
{
if (_fourierTransformProvider == null)
{
lock (_staticLock)
{
if (_fourierTransformProvider == null)
{
FourierTransformControl.UseDefault();
}
}
}
return _fourierTransformProvider;
}
set
{
value.InitializeVerify();
// only actually set if verification did not throw
_fourierTransformProvider = value;
}
}
/// <summary>
/// Gets or sets a value indicating how many parallel worker threads shall be used
/// when parallelization is applicable.
@ -293,6 +310,7 @@ namespace MathNet.Numerics
// Reinitialize providers:
LinearAlgebraProvider.InitializeVerify();
FourierTransformProvider.InitializeVerify();
}
}

47
src/Numerics/IntegralTransforms/Fourier.cs

@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2015 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -28,6 +28,7 @@
// </copyright>
using System;
using MathNet.Numerics.Providers.FourierTransform;
namespace MathNet.Numerics.IntegralTransforms
{
@ -46,7 +47,7 @@ namespace MathNet.Numerics.IntegralTransforms
/// <param name="samples">Sample vector, where the FFT is evaluated in place.</param>
public static void Forward(Complex[] samples)
{
BluesteinForward(samples, FourierOptions.Default);
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling);
}
/// <summary>
@ -56,7 +57,23 @@ namespace MathNet.Numerics.IntegralTransforms
/// <param name="options">Fourier Transform Convention Options.</param>
public static void Forward(Complex[] samples, FourierOptions options)
{
BluesteinForward(samples, options);
switch (options)
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent:
Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.NoScaling);
break;
default:
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling);
break;
}
}
/// <summary>
@ -65,7 +82,7 @@ namespace MathNet.Numerics.IntegralTransforms
/// <param name="samples">Sample vector, where the FFT is evaluated in place.</param>
public static void Inverse(Complex[] samples)
{
BluesteinInverse(samples, FourierOptions.Default);
Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.SymmetricScaling);
}
/// <summary>
@ -75,7 +92,27 @@ namespace MathNet.Numerics.IntegralTransforms
/// <param name="options">Fourier Transform Convention Options.</param>
public static void Inverse(Complex[] samples, FourierOptions options)
{
BluesteinInverse(samples, options);
switch (options)
{
case FourierOptions.NoScaling:
Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.BackwardScaling);
break;
case FourierOptions.InverseExponent:
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.ForwardScaling);
break;
default:
Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.SymmetricScaling);
break;
}
}
/// <summary>

24
src/Numerics/Numerics.csproj

@ -172,6 +172,14 @@
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Providers\Common\Cuda\CudaProvider.cs" />
<Compile Include="Providers\Common\Mkl\MklProvider.cs" />
<Compile Include="Providers\Common\Mkl\MklProviderPrecision.cs" />
<Compile Include="Providers\Common\OpenBlas\OpenBlasProvider.cs" />
<Compile Include="Providers\FourierTransform\IFourierTransformProvider.cs" />
<Compile Include="Providers\FourierTransform\FourierTransformControl.cs" />
<Compile Include="Providers\FourierTransform\ManagedFourierTransformProvider.cs" />
<Compile Include="Providers\FourierTransform\Mkl\MklFourierTransformProvider.cs" />
<Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Complex.cs" />
<Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Complex32.cs" />
<Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Double.cs" />
@ -182,15 +190,16 @@
<Compile Include="Providers\LinearAlgebra\Cuda\CudaLinearAlgebraProvider.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaLinearAlgebraProvider.Double.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaLinearAlgebraProvider.Single.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaProviderCapabilities.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\SafeNativeMethods.cs" />
<Compile Include="Providers\LinearAlgebra\Mkl\MklProviderCapabilities.cs" />
<Compile Include="Providers\Common\Cuda\CudaProviderCapabilities.cs" />
<Compile Include="Providers\Common\Cuda\SafeNativeMethods.cs" />
<Compile Include="Providers\Common\Mkl\MklProviderCapabilities.cs" />
<Compile Include="Providers\LinearAlgebra\LinearAlgebraControl.cs" />
<Compile Include="Providers\LinearAlgebra\OpenBlas\OpenBlasLinearAlgebraProvider.cs" />
<Compile Include="Providers\LinearAlgebra\OpenBlas\OpenBlasLinearAlgebraProvider.Complex.cs" />
<Compile Include="Providers\LinearAlgebra\OpenBlas\OpenBlasLinearAlgebraProvider.Complex32.cs" />
<Compile Include="Providers\LinearAlgebra\OpenBlas\OpenBlasLinearAlgebraProvider.Double.cs" />
<Compile Include="Providers\LinearAlgebra\OpenBlas\OpenBlasLinearAlgebraProvider.Single.cs" />
<Compile Include="Providers\LinearAlgebra\OpenBlas\SafeNativeMethods.cs" />
<Compile Include="Providers\Common\OpenBlas\SafeNativeMethods.cs" />
<Compile Include="Providers\LinearAlgebra\ManagedLinearAlgebraProvider.Complex32.cs" />
<Compile Include="Providers\LinearAlgebra\ManagedLinearAlgebraProvider.Complex.cs" />
<Compile Include="Providers\LinearAlgebra\ManagedLinearAlgebraProvider.Double.cs" />
@ -202,7 +211,7 @@
<Compile Include="Providers\LinearAlgebra\Mkl\MklLinearAlgebraProvider.cs" />
<Compile Include="Providers\LinearAlgebra\Mkl\MklLinearAlgebraProvider.Double.cs" />
<Compile Include="Providers\LinearAlgebra\Mkl\MklLinearAlgebraProvider.Single.cs" />
<Compile Include="Providers\LinearAlgebra\Mkl\SafeNativeMethods.cs" />
<Compile Include="Providers\Common\Mkl\SafeNativeMethods.cs" />
<Compile Include="ArrayExtensions.cs" />
<Compile Include="Complex64.cs" />
<Compile Include="Combinatorics.cs" />
@ -220,8 +229,8 @@
<Compile Include="LinearAlgebra\Vector.BCL.cs" />
<Compile Include="LinearAlgebra\Vector.Operators.cs" />
<Compile Include="Exceptions.cs" />
<Compile Include="Providers\LinearAlgebra\OpenBlas\OpenBlasProviderCapabilities.cs" />
<Compile Include="Providers\NativeProviderLoader.cs" />
<Compile Include="Providers\Common\OpenBlas\OpenBlasProviderCapabilities.cs" />
<Compile Include="Providers\Common\NativeProviderLoader.cs" />
<Compile Include="Random\SystemRandomSource.cs" />
<Compile Include="Random\RandomSeed.cs" />
<Compile Include="RootFinding\Broyden.cs" />
@ -476,5 +485,6 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

111
src/Numerics/Providers/Common/Cuda/CudaProvider.cs

@ -0,0 +1,111 @@
// <copyright file="CudaProvider.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
#if NATIVE
using System;
using System.Collections.Generic;
namespace MathNet.Numerics.Providers.Common.Cuda
{
internal static class CudaProvider
{
static int _nativeRevision;
static bool _nativeX86;
static bool _nativeX64;
static bool _nativeIA64;
public static bool IsAvailable(int minRevision)
{
try
{
if (!NativeProviderLoader.TryLoad(SafeNativeMethods.DllName))
{
return false;
}
int a = SafeNativeMethods.query_capability(0);
int b = SafeNativeMethods.query_capability(1);
int nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision);
return a == 0 && b == -1 && nativeRevision >= minRevision;
}
catch
{
return false;
}
}
public static void Load(int minRevision)
{
int a, b;
try
{
NativeProviderLoader.TryLoad(SafeNativeMethods.DllName);
a = SafeNativeMethods.query_capability(0);
b = SafeNativeMethods.query_capability(1);
_nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision);
_nativeX86 = SafeNativeMethods.query_capability((int)ProviderPlatform.x86) > 0;
_nativeX64 = SafeNativeMethods.query_capability((int)ProviderPlatform.x64) > 0;
_nativeIA64 = SafeNativeMethods.query_capability((int)ProviderPlatform.ia64) > 0;
}
catch (DllNotFoundException e)
{
throw new NotSupportedException("Cuda Native Provider not found.", e);
}
catch (BadImageFormatException e)
{
throw new NotSupportedException("Cuda Native Provider found but failed to load. Please verify that the platform matches (x64 vs x32, Windows vs Linux).", e);
}
catch (EntryPointNotFoundException e)
{
throw new NotSupportedException("Cuda Native Provider does not support capability querying and is therefore not compatible. Consider upgrading to a newer version.", e);
}
if (a != 0 || b != -1 || _nativeRevision < minRevision)
{
throw new NotSupportedException("Cuda Native Provider too old. Consider upgrading to a newer version.");
}
}
public static string Describe()
{
var parts = new List<string>();
if (_nativeX86) parts.Add("x86");
if (_nativeX64) parts.Add("x64");
if (_nativeIA64) parts.Add("IA64");
parts.Add("revision " + _nativeRevision);
return string.Concat("Nvidia CUDA (", string.Join("; ", parts), ")");
}
}
}
#endif

13
src/Numerics/Providers/LinearAlgebra/Cuda/CudaProviderCapabilities.cs → src/Numerics/Providers/Common/Cuda/CudaProviderCapabilities.cs

@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2015 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -27,7 +27,9 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
#if NATIVE
namespace MathNet.Numerics.Providers.Common.Cuda
{
internal enum ProviderPlatform : int
{
@ -43,6 +45,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
internal enum ProviderCapability : int
{
LinearAlgebra = 128,
LinearAlgebraMajor = 128,
LinearAlgebraMinor = 129,
}
}
}
#endif

5
src/Numerics/Providers/LinearAlgebra/Cuda/SafeNativeMethods.cs → src/Numerics/Providers/Common/Cuda/SafeNativeMethods.cs

@ -2,7 +2,7 @@
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009-2014 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -32,8 +32,9 @@ using System;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Security;
using MathNet.Numerics.Providers.LinearAlgebra;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
namespace MathNet.Numerics.Providers.Common.Cuda
{
/// <summary>
/// P/Invoke methods to the native math libraries.

262
src/Numerics/Providers/Common/Mkl/MklProvider.cs

@ -0,0 +1,262 @@
// <copyright file="MklProvider.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
#if NATIVE
using System;
using System.Collections.Generic;
namespace MathNet.Numerics.Providers.Common.Mkl
{
internal static class MklProvider
{
static Version _mklVersion;
static int _nativeRevision;
static bool _nativeX86;
static bool _nativeX64;
static bool _nativeIA64;
public static bool IsAvailable(int minRevision)
{
try
{
if (!NativeProviderLoader.TryLoad(SafeNativeMethods.DllName))
{
return false;
}
int a = SafeNativeMethods.query_capability(0);
int b = SafeNativeMethods.query_capability(1);
int nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision);
return a == 0 && b == -1 && nativeRevision >= minRevision;
}
catch
{
return false;
}
}
public static void Load(int minRevision)
{
int a, b;
try
{
NativeProviderLoader.TryLoad(SafeNativeMethods.DllName);
a = SafeNativeMethods.query_capability(0);
b = SafeNativeMethods.query_capability(1);
_nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision);
_nativeX86 = SafeNativeMethods.query_capability((int)ProviderPlatform.x86) > 0;
_nativeX64 = SafeNativeMethods.query_capability((int)ProviderPlatform.x64) > 0;
_nativeIA64 = SafeNativeMethods.query_capability((int)ProviderPlatform.ia64) > 0;
_mklVersion = new Version(
SafeNativeMethods.query_capability((int)ProviderConfig.MklMajorVersion),
SafeNativeMethods.query_capability((int)ProviderConfig.MklMinorVersion),
SafeNativeMethods.query_capability((int)ProviderConfig.MklUpdateVersion));
}
catch (DllNotFoundException e)
{
throw new NotSupportedException("MKL Native Provider not found.", e);
}
catch (BadImageFormatException e)
{
throw new NotSupportedException("MKL Native Provider found but failed to load. Please verify that the platform matches (x64 vs x32, Windows vs Linux).", e);
}
catch (EntryPointNotFoundException e)
{
throw new NotSupportedException("MKL Native Provider does not support capability querying and is therefore not compatible. Consider upgrading to a newer version.", e);
}
if (a != 0 || b != -1 || _nativeRevision < minRevision)
{
throw new NotSupportedException("MKL Native Provider too old. Consider upgrading to a newer version.");
}
ConfigureThreading();
}
static void ConfigureThreading()
{
// set threading settings, if supported
if (SafeNativeMethods.query_capability((int)ProviderConfig.Threading) > 0)
{
SafeNativeMethods.set_max_threads(Control.MaxDegreeOfParallelism);
}
}
public static void ConfigurePrecision(MklConsistency consistency, MklPrecision precision, MklAccuracy accuracy)
{
// set numerical consistency, precision and accuracy modes, if supported
if (SafeNativeMethods.query_capability((int)ProviderConfig.Precision) > 0)
{
SafeNativeMethods.set_consistency_mode((int)consistency);
SafeNativeMethods.set_vml_mode((uint)precision | (uint)accuracy);
}
}
/// <summary>
/// Frees the memory allocated to the MKL memory pool.
/// </summary>
public static void FreeBuffers()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.free_buffers();
}
/// <summary>
/// Frees the memory allocated to the MKL memory pool on the current thread.
/// </summary>
public static void ThreadFreeBuffers()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.thread_free_buffers();
}
/// <summary>
/// Disable the MKL memory pool. May impact performance.
/// </summary>
public static void DisableMemoryPool()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.disable_fast_mm();
}
/// <summary>
/// Retrieves information about the MKL memory pool.
/// </summary>
/// <param name="allocatedBuffers">On output, returns the number of memory buffers allocated.</param>
/// <returns>Returns the number of bytes allocated to all memory buffers.</returns>
public static long MemoryStatistics(out int allocatedBuffers)
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
return SafeNativeMethods.mem_stat(out allocatedBuffers);
}
/// <summary>
/// Enable gathering of peak memory statistics of the MKL memory pool.
/// </summary>
public static void EnablePeakMemoryStatistics()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.peak_mem_usage((int)MklMemoryRequestMode.Enable);
}
/// <summary>
/// Disable gathering of peak memory statistics of the MKL memory pool.
/// </summary>
public static void DisablePeakMemoryStatistics()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.peak_mem_usage((int)MklMemoryRequestMode.Disable);
}
/// <summary>
/// Measures peak memory usage of the MKL memory pool.
/// </summary>
/// <param name="reset">Whether the usage counter should be reset.</param>
/// <returns>The peak number of bytes allocated to all memory buffers.</returns>
public static long PeakMemoryStatistics(bool reset = true)
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
return SafeNativeMethods.peak_mem_usage((int)(reset ? MklMemoryRequestMode.PeakMemoryReset : MklMemoryRequestMode.PeakMemory));
}
public static string Describe()
{
var parts = new List<string>();
if (_nativeX86) parts.Add("x86");
if (_nativeX64) parts.Add("x64");
if (_nativeIA64) parts.Add("IA64");
parts.Add("revision " + _nativeRevision);
if (_mklVersion.Major > 0)
{
parts.Add(_mklVersion.Build == 0
? string.Concat("MKL ", _mklVersion.ToString(2))
: string.Concat("MKL ", _mklVersion.ToString(2), " Update ", _mklVersion.Build));
}
return string.Concat("Intel MKL (", string.Join("; ", parts), ")");
}
enum MklMemoryRequestMode : int
{
/// <summary>
/// Disable gathering memory usage
/// </summary>
Disable = 0,
/// <summary>
/// Enable gathering memory usage
/// </summary>
Enable = 1,
/// <summary>
/// Return peak memory usage
/// </summary>
PeakMemory = 2,
/// <summary>
/// Return peak memory usage and reset counter
/// </summary>
PeakMemoryReset = -1
}
}
}
#endif

15
src/Numerics/Providers/LinearAlgebra/Mkl/MklProviderCapabilities.cs → src/Numerics/Providers/Common/Mkl/MklProviderCapabilities.cs

@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2015 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -27,7 +27,9 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
#if NATIVE
namespace MathNet.Numerics.Providers.Common.Mkl
{
internal enum ProviderPlatform : int
{
@ -38,6 +40,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
internal enum ProviderConfig : int
{
MklMajorVersion = 32,
MklMinorVersion = 33,
MklUpdateVersion = 34,
Revision = 64,
Precision = 65,
Threading = 66,
@ -46,7 +51,11 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
internal enum ProviderCapability : int
{
LinearAlgebra = 128,
LinearAlgebraMajor = 128,
LinearAlgebraMinor = 129,
FourierTransformMajor = 384,
FourierTransformMinor = 385
}
}
#endif

66
src/Numerics/Providers/Common/Mkl/MklProviderPrecision.cs

@ -0,0 +1,66 @@
// <copyright file="MklProviderPrecision.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using System;
namespace MathNet.Numerics.Providers.Common.Mkl
{
/// <summary>
/// Consistency vs. performance trade-off between runs on different machines.
/// </summary>
public enum MklConsistency : int
{
/// <summary>Consistent on the same CPU only (maximum performance)</summary>
Auto = 2,
/// <summary>Consistent on Intel and compatible CPUs with SSE2 support (maximum compatibility)</summary>
Compatible = 3,
/// <summary>Consistent on Intel CPUs supporting SSE2 or later</summary>
SSE2 = 4,
/// <summary>Consistent on Intel CPUs supporting SSE4.2 or later</summary>
SSE4_2 = 8,
/// <summary>Consistent on Intel CPUs supporting AVX or later</summary>
AVX = 9,
/// <summary>Consistent on Intel CPUs supporting AVX2 or later</summary>
AVX2 = 10
}
[CLSCompliant(false)]
public enum MklAccuracy : uint
{
Low = 0x1,
High = 0x2
}
[CLSCompliant(false)]
public enum MklPrecision : uint
{
Single = 0x10,
Double = 0x20
}
}

21
src/Numerics/Providers/LinearAlgebra/Mkl/SafeNativeMethods.cs → src/Numerics/Providers/Common/Mkl/SafeNativeMethods.cs

@ -2,7 +2,7 @@
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009-2014 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -31,8 +31,9 @@
using System.Numerics;
using System.Runtime.InteropServices;
using System.Security;
using MathNet.Numerics.Providers.LinearAlgebra;
namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
namespace MathNet.Numerics.Providers.Common.Mkl
{
/// <summary>
/// P/Invoke methods to the native math libraries.
@ -367,6 +368,22 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
#endregion Vector Functions
#region FFT
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern long z_fft_forward_inplace(long n, double scaling, [In, Out] Complex[] x);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern long c_fft_forward_inplace(long n, float scaling, [In, Out] Complex32[] x);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern long z_fft_backward_inplace(long n, double scaling, [In, Out] Complex[] x);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern long c_fft_backward_inplace(long n, float scaling, [In, Out] Complex32[] x);
#endregion FFT
// ReSharper restore InconsistentNaming
}
}

10
src/Numerics/Providers/NativeProviderLoader.cs → src/Numerics/Providers/Common/NativeProviderLoader.cs

@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2015 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -27,6 +27,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
#if NATIVE
using System;
using System.Collections.Generic;
using System.IO;
@ -35,9 +37,7 @@ using System.Runtime.InteropServices;
using System.Security;
using System.Threading;
#if NATIVE
namespace MathNet.Numerics.Providers
namespace MathNet.Numerics.Providers.Common
{
/// <summary>
/// Helper class to load native libraries depending on the architecture of the OS and process.
@ -243,4 +243,4 @@ namespace MathNet.Numerics.Providers
}
}
#endif
#endif

125
src/Numerics/Providers/Common/OpenBlas/OpenBlasProvider.cs

@ -0,0 +1,125 @@
// <copyright file="OpenBlasProvider.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
#if NATIVE
using System;
using System.Collections.Generic;
namespace MathNet.Numerics.Providers.Common.OpenBlas
{
internal static class OpenBlasProvider
{
static int _nativeRevision;
static bool _nativeX86;
static bool _nativeX64;
static bool _nativeIA64;
static bool _nativeARM;
public static bool IsAvailable(int minRevision)
{
try
{
if (!NativeProviderLoader.TryLoad(SafeNativeMethods.DllName))
{
return false;
}
int a = SafeNativeMethods.query_capability(0);
int b = SafeNativeMethods.query_capability(1);
int nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision);
return a == 0 && b == -1 && nativeRevision >= minRevision;
}
catch
{
return false;
}
}
public static void Load(int minRevision)
{
int a, b;
try
{
NativeProviderLoader.TryLoad(SafeNativeMethods.DllName);
a = SafeNativeMethods.query_capability(0);
b = SafeNativeMethods.query_capability(1);
_nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision);
_nativeX86 = SafeNativeMethods.query_capability((int)ProviderPlatform.x86) > 0;
_nativeX64 = SafeNativeMethods.query_capability((int)ProviderPlatform.x64) > 0;
_nativeIA64 = SafeNativeMethods.query_capability((int)ProviderPlatform.ia64) > 0;
_nativeARM = SafeNativeMethods.query_capability((int)ProviderPlatform.arm) > 0;
}
catch (DllNotFoundException e)
{
throw new NotSupportedException("OpenBLAS Native Provider not found.", e);
}
catch (BadImageFormatException e)
{
throw new NotSupportedException("OpenBLAS Native Provider found but failed to load. Please verify that the platform matches (x64 vs x32, Windows vs Linux).", e);
}
catch (EntryPointNotFoundException e)
{
throw new NotSupportedException("OpenBLAS Native Provider does not support capability querying and is therefore not compatible. Consider upgrading to a newer version.", e);
}
if (a != 0 || b != -1 || _nativeRevision < minRevision)
{
throw new NotSupportedException("OpenBLAS Native Provider too old. Consider upgrading to a newer version.");
}
ConfigureThreading();
}
static void ConfigureThreading()
{
// set threading settings, if supported
if (SafeNativeMethods.query_capability((int)ProviderConfig.Threading) > 0)
{
SafeNativeMethods.set_max_threads(Control.MaxDegreeOfParallelism);
}
}
public static string Describe()
{
var parts = new List<string>();
if (_nativeX86) parts.Add("x86");
if (_nativeX64) parts.Add("x64");
if (_nativeIA64) parts.Add("IA64");
if (_nativeARM) parts.Add("ARM");
parts.Add("revision " + _nativeRevision);
return string.Concat("OpenBLAS (", string.Join("; ", parts), ")");
}
}
}
#endif

13
src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasProviderCapabilities.cs → src/Numerics/Providers/Common/OpenBlas/OpenBlasProviderCapabilities.cs

@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2015 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -27,7 +27,9 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
#if NATIVE
namespace MathNet.Numerics.Providers.Common.OpenBlas
{
internal enum ProviderPlatform : int
{
@ -45,6 +47,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
internal enum ProviderCapability : int
{
LinearAlgebra = 128,
LinearAlgebraMajor = 128,
LinearAlgebraMinor = 129
}
}
}
#endif

4
src/Numerics/Providers/LinearAlgebra/OpenBlas/SafeNativeMethods.cs → src/Numerics/Providers/Common/OpenBlas/SafeNativeMethods.cs

@ -31,8 +31,10 @@
using System.Numerics;
using System.Runtime.InteropServices;
using System.Security;
using MathNet.Numerics.Providers.LinearAlgebra;
using MathNet.Numerics.Providers.LinearAlgebra.OpenBlas;
namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
namespace MathNet.Numerics.Providers.Common.OpenBlas
{
/// <summary>
/// P/Invoke methods to the native math libraries.

101
src/Numerics/Providers/FourierTransform/FourierTransformControl.cs

@ -0,0 +1,101 @@
// <copyright file="FourierTransformControl.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using System;
namespace MathNet.Numerics.Providers.FourierTransform
{
internal static class FourierTransformControl
{
const string EnvVarFFTProvider = "MathNetNumericsFFTProvider";
public static void UseManaged()
{
Control.FourierTransformProvider = new ManagedFourierTransformProvider();
}
#if NATIVE
public static void UseNativeMKL()
{
Control.FourierTransformProvider = new Mkl.MklFourierTransformProvider();
}
#endif
public static bool TryUse(IFourierTransformProvider provider)
{
try
{
if (!provider.IsAvailable())
{
return false;
}
Control.FourierTransformProvider = provider;
return true;
}
catch
{
// intentionally swallow exceptions here - use the explicit variants if you're interested in why
return false;
}
}
public static void UseBest()
{
#if NATIVE
if (!TryUse(new Mkl.MklFourierTransformProvider()))
{
UseManaged();
}
#else
UseManaged();
#endif
}
public static void UseDefault()
{
#if NATIVE
var value = Environment.GetEnvironmentVariable(EnvVarFFTProvider);
switch (value != null ? value.ToUpperInvariant() : string.Empty)
{
case "MKL":
UseNativeMKL();
break;
default:
UseBest();
break;
}
#else
UseManaged();
#endif
}
}
}

64
src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs

@ -0,0 +1,64 @@
// <copyright file="IFourierTransformProvider.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.Providers.FourierTransform
{
#if !NOSYSNUMERICS
using Complex = System.Numerics.Complex;
#endif
public enum FourierTransformScaling : int
{
NoScaling = 0,
SymmetricScaling = 1,
BackwardScaling = 2,
ForwardScaling = 3
}
public interface IFourierTransformProvider
{
/// <summary>
/// Try to find out whether the provider is available, at least in principle.
/// Verification may still fail if available, but it will certainly fail if unavailable.
/// </summary>
bool IsAvailable();
/// <summary>
/// Initialize and verify that the provided is indeed available. If not, fall back to alternatives like the managed provider
/// </summary>
void InitializeVerify();
void ForwardInplace(Complex[] complex, FourierTransformScaling scaling);
void BackwardInplace(Complex[] complex, FourierTransformScaling scaling);
Complex[] Forward(Complex[] complexTimeSpace, FourierTransformScaling scaling);
Complex[] Backward(Complex[] complexFrequenceSpace, FourierTransformScaling scaling);
}
}

111
src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs

@ -0,0 +1,111 @@
// <copyright file="ManagedFourierTransformProvider.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using System.Collections;
using MathNet.Numerics.IntegralTransforms;
namespace MathNet.Numerics.Providers.FourierTransform
{
#if !NOSYSNUMERICS
using Complex = System.Numerics.Complex;
#endif
public class ManagedFourierTransformProvider : IFourierTransformProvider
{
/// <summary>
/// Try to find out whether the provider is available, at least in principle.
/// Verification may still fail if available, but it will certainly fail if unavailable.
/// </summary>
public bool IsAvailable()
{
return true;
}
/// <summary>
/// Initialize and verify that the provided is indeed available. If not, fall back to alternatives like the managed provider
/// </summary>
public void InitializeVerify()
{
}
public string ToString()
{
return "Managed";
}
public void ForwardInplace(Complex[] complex, FourierTransformScaling scaling)
{
switch (scaling)
{
case FourierTransformScaling.SymmetricScaling:
Fourier.BluesteinForward(complex, FourierOptions.Default);
break;
case FourierTransformScaling.ForwardScaling:
// Only backward scaling can be expressed with options, hence the double-inverse
Fourier.BluesteinInverse(complex, FourierOptions.AsymmetricScaling | FourierOptions.InverseExponent);
break;
default:
Fourier.BluesteinForward(complex, FourierOptions.NoScaling);
break;
}
}
public void BackwardInplace(Complex[] complex, FourierTransformScaling scaling)
{
switch (scaling)
{
case FourierTransformScaling.SymmetricScaling:
Fourier.BluesteinInverse(complex, FourierOptions.Default);
break;
case FourierTransformScaling.BackwardScaling:
Fourier.BluesteinInverse(complex, FourierOptions.AsymmetricScaling);
break;
default:
Fourier.BluesteinInverse(complex, FourierOptions.NoScaling);
break;
}
}
public Complex[] Forward(Complex[] complexTimeSpace, FourierTransformScaling scaling)
{
Complex[] work = new Complex[complexTimeSpace.Length];
complexTimeSpace.Copy(work);
ForwardInplace(work, scaling);
return work;
}
public Complex[] Backward(Complex[] complexFrequenceSpace, FourierTransformScaling scaling)
{
Complex[] work = new Complex[complexFrequenceSpace.Length];
complexFrequenceSpace.Copy(work);
BackwardInplace(work, scaling);
return work;
}
}
}

183
src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs

@ -0,0 +1,183 @@
// <copyright file="MklFourierTransformProvider.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
#if NATIVE
using System;
using System.Numerics;
using MathNet.Numerics.Providers.Common.Mkl;
namespace MathNet.Numerics.Providers.FourierTransform.Mkl
{
public class MklFourierTransformProvider : IFourierTransformProvider
{
/// <summary>
/// Try to find out whether the provider is available, at least in principle.
/// Verification may still fail if available, but it will certainly fail if unavailable.
/// </summary>
public bool IsAvailable()
{
return MklProvider.IsAvailable(minRevision: 11);
}
/// <summary>
/// Initialize and verify that the provided is indeed available. If not, fall back to alternatives like the managed provider
/// </summary>
public void InitializeVerify()
{
MklProvider.Load(minRevision: 11);
// we only support exactly one major version, since major version changes imply a breaking change.
int fftMajor = SafeNativeMethods.query_capability((int)ProviderCapability.FourierTransformMajor);
int fftMinor = SafeNativeMethods.query_capability((int)ProviderCapability.FourierTransformMinor);
if (!(fftMajor == 1 && fftMinor >= 0))
{
throw new NotSupportedException(string.Format("MKL Native Provider not compatible. Expecting fourier transform v1 but provider implements v{0}.", fftMajor));
}
}
/// <summary>
/// Frees the memory allocated to the MKL memory pool.
/// </summary>
public void FreeBuffers()
{
MklProvider.FreeBuffers();
}
/// <summary>
/// Frees the memory allocated to the MKL memory pool on the current thread.
/// </summary>
public void ThreadFreeBuffers()
{
MklProvider.ThreadFreeBuffers();
}
/// <summary>
/// Disable the MKL memory pool. May impact performance.
/// </summary>
public void DisableMemoryPool()
{
MklProvider.DisableMemoryPool();
}
/// <summary>
/// Retrieves information about the MKL memory pool.
/// </summary>
/// <param name="allocatedBuffers">On output, returns the number of memory buffers allocated.</param>
/// <returns>Returns the number of bytes allocated to all memory buffers.</returns>
public long MemoryStatistics(out int allocatedBuffers)
{
return MklProvider.MemoryStatistics(out allocatedBuffers);
}
/// <summary>
/// Enable gathering of peak memory statistics of the MKL memory pool.
/// </summary>
public void EnablePeakMemoryStatistics()
{
MklProvider.EnablePeakMemoryStatistics();
}
/// <summary>
/// Disable gathering of peak memory statistics of the MKL memory pool.
/// </summary>
public void DisablePeakMemoryStatistics()
{
MklProvider.DisablePeakMemoryStatistics();
}
/// <summary>
/// Measures peak memory usage of the MKL memory pool.
/// </summary>
/// <param name="reset">Whether the usage counter should be reset.</param>
/// <returns>The peak number of bytes allocated to all memory buffers.</returns>
public long PeakMemoryStatistics(bool reset = true)
{
return MklProvider.PeakMemoryStatistics(reset);
}
public override string ToString()
{
return MklProvider.Describe();
}
public void ForwardInplace(Complex[] complex, FourierTransformScaling scaling)
{
SafeNativeMethods.z_fft_forward_inplace(complex.Length, ForwardScaling(scaling, complex.Length), complex);
}
public void BackwardInplace(Complex[] complex, FourierTransformScaling scaling)
{
SafeNativeMethods.z_fft_backward_inplace(complex.Length, BackwardScaling(scaling, complex.Length), complex);
}
public Complex[] Forward(Complex[] complexTimeSpace, FourierTransformScaling scaling)
{
Complex[] work = new Complex[complexTimeSpace.Length];
complexTimeSpace.Copy(work);
ForwardInplace(work, scaling);
return work;
}
public Complex[] Backward(Complex[] complexFrequenceSpace, FourierTransformScaling scaling)
{
Complex[] work = new Complex[complexFrequenceSpace.Length];
complexFrequenceSpace.Copy(work);
BackwardInplace(work, scaling);
return work;
}
static double ForwardScaling(FourierTransformScaling scaling, int length)
{
switch (scaling)
{
case FourierTransformScaling.SymmetricScaling:
return Math.Sqrt(1.0/length);
case FourierTransformScaling.ForwardScaling:
return 1.0/length;
default:
return 1.0;
}
}
static double BackwardScaling(FourierTransformScaling scaling, int length)
{
switch (scaling)
{
case FourierTransformScaling.SymmetricScaling:
return Math.Sqrt(1.0/length);
case FourierTransformScaling.BackwardScaling:
return 1.0/length;
default:
return 1.0;
}
}
}
}
#endif

3
src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex.cs

@ -33,6 +33,7 @@ using System;
using System.Numerics;
using System.Security;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Providers.Common.Cuda;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
{
@ -569,7 +570,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
if (columnsA > rowsA || !computeVectors) // see remarks http://docs.nvidia.com/cuda/cusolver/index.html#cuds-lt-t-gt-gesvd
base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt);
else Solver(SafeNativeMethods.z_svd_factor(_solverHandle, computeVectors, rowsA, columnsA, a, s, u, vt));
}
}
}
}

5
src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Complex32.cs

@ -32,6 +32,7 @@
using System;
using System.Security;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Providers.Common.Cuda;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
{
@ -466,7 +467,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
}
Solver(SafeNativeMethods.c_cholesky_solve_factored(_solverHandle, orderA, columnsB, a, b));
}
}
/// <summary>
/// Solves A*X=B for X using the singular value decomposition of A.
@ -568,7 +569,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
if (columnsA > rowsA || !computeVectors) // see remarks http://docs.nvidia.com/cuda/cusolver/index.html#cuds-lt-t-gt-gesvd
base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt);
else Solver(SafeNativeMethods.c_svd_factor(_solverHandle, computeVectors, rowsA, columnsA, a, s, u, vt));
}
}
}
}

5
src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Double.cs

@ -32,6 +32,7 @@
using System;
using System.Security;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Providers.Common.Cuda;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
{
@ -466,7 +467,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
}
Solver(SafeNativeMethods.d_cholesky_solve_factored(_solverHandle, orderA, columnsB, a, b));
}
}
/// <summary>
/// Solves A*X=B for X using the singular value decomposition of A.
@ -568,7 +569,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
if (columnsA > rowsA || !computeVectors) // see remarks http://docs.nvidia.com/cuda/cusolver/index.html#cuds-lt-t-gt-gesvd
base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt);
else Solver (SafeNativeMethods.d_svd_factor(_solverHandle, computeVectors, rowsA, columnsA, a, s, u, vt));
}
}
}
}

5
src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.Single.cs

@ -32,6 +32,7 @@
using System;
using System.Security;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Providers.Common.Cuda;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
{
@ -466,7 +467,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
}
Solver(SafeNativeMethods.s_cholesky_solve_factored(_solverHandle, orderA, columnsB, a, b));
}
}
/// <summary>
/// Solves A*X=B for X using the singular value decomposition of A.
@ -568,7 +569,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
if (columnsA > rowsA || !computeVectors) // see remarks http://docs.nvidia.com/cuda/cusolver/index.html#cuds-lt-t-gt-gesvd
base.SingularValueDecomposition(computeVectors, a, rowsA, columnsA, s, u, vt);
else Solver(SafeNativeMethods.s_svd_factor(_solverHandle, computeVectors, rowsA, columnsA, a, s, u, vt));
}
}
}
}

59
src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.cs

@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2015 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -27,10 +27,11 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using System;
#if NATIVE
using System;
using MathNet.Numerics.Providers.Common.Cuda;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
{
/// <summary>
@ -38,51 +39,32 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
/// </summary>
public partial class CudaLinearAlgebraProvider : ManagedLinearAlgebraProvider, IDisposable
{
int _nativeRevision;
bool _nativeIX86;
bool _nativeX64;
bool _nativeIA64;
IntPtr _blasHandle;
IntPtr _solverHandle;
/// <summary>
/// Try to find out whether the provider is available, at least in principle.
/// Verification may still fail if available, but it will certainly fail if unavailable.
/// </summary>
public override bool IsAvailable()
{
return CudaProvider.IsAvailable(minRevision: 1);
}
/// <summary>
/// Initialize and verify that the provided is indeed available.
/// If calling this method fails, consider to fall back to alternatives like the managed provider.
/// </summary>
public override void InitializeVerify()
{
int a, b, linearAlgebra;
try
{
// Load the native library
NativeProviderLoader.TryLoad(SafeNativeMethods.DllName);
CudaProvider.Load(minRevision: 1);
a = SafeNativeMethods.query_capability(0);
b = SafeNativeMethods.query_capability(1);
int linearAlgebra = SafeNativeMethods.query_capability((int)ProviderCapability.LinearAlgebraMajor);
_nativeIX86 = SafeNativeMethods.query_capability((int)ProviderPlatform.x86) > 0;
_nativeX64 = SafeNativeMethods.query_capability((int)ProviderPlatform.x64) > 0;
_nativeIA64 = SafeNativeMethods.query_capability((int)ProviderPlatform.ia64) > 0;
_nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision);
linearAlgebra = SafeNativeMethods.query_capability((int)ProviderCapability.LinearAlgebra);
}
catch (DllNotFoundException e)
{
throw new NotSupportedException("Cuda Native Provider not found.", e);
}
catch (BadImageFormatException e)
{
throw new NotSupportedException("Cuda Native Provider found but failed to load. Please verify that the platform matches (x64 vs x32, Windows vs Linux).", e);
}
catch (EntryPointNotFoundException e)
// we only support exactly one major version, since major version changes imply a breaking change.
if (linearAlgebra != 1)
{
throw new NotSupportedException("Cuda Native Provider does not support capability querying and is therefore not compatible. Consider upgrading to a newer version.", e);
}
if (a != 0 || b != -1 || linearAlgebra <=0 || _nativeRevision < 1)
{
throw new NotSupportedException("Cuda Native Provider too old or not compatible. Consider upgrading to a newer version.");
throw new NotSupportedException(string.Format("Cuda Native Provider not compatible. Expecting linear algebra v1 but provider implements v{0}.", linearAlgebra));
}
BLAS(SafeNativeMethods.createBLASHandle(ref _blasHandle));
@ -175,12 +157,9 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
public override string ToString()
{
return string.Format("Nvidia CUDA ({1}; revision {0})",
_nativeRevision,
_nativeIX86 ? "x86" : _nativeX64 ? "x64" : _nativeIA64 ? "IA64" : "unknown");
return CudaProvider.Describe();
}
public void Dispose()
{
BLAS(SafeNativeMethods.destroyBLASHandle(_blasHandle));

18
src/Numerics/Providers/LinearAlgebra/ILinearAlgebraProvider.cs

@ -2,9 +2,9 @@
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
//
// Copyright (c) 2009-2013 Math.NET
//
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@ -13,10 +13,10 @@
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@ -93,6 +93,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra
ILinearAlgebraProvider<Complex>,
ILinearAlgebraProvider<Complex32>
{
/// <summary>
/// Try to find out whether the provider is available, at least in principle.
/// Verification may still fail if available, but it will certainly fail if unavailable.
/// </summary>
bool IsAvailable();
/// <summary>
/// Initialize and verify that the provided is indeed available. If not, fall back to alternatives like the managed provider
/// </summary>
@ -151,7 +157,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra
T DotProduct(T[] x, T[] y);
/// <summary>
/// Does a point wise add of two arrays <c>z = x + y</c>. This can be used
/// Does a point wise add of two arrays <c>z = x + y</c>. This can be used
/// to add vectors or matrices.
/// </summary>
/// <param name="x">The array x.</param>
@ -163,7 +169,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra
void AddArrays(T[] x, T[] y, T[] result);
/// <summary>
/// Does a point wise subtraction of two arrays <c>z = x - y</c>. This can be used
/// Does a point wise subtraction of two arrays <c>z = x - y</c>. This can be used
/// to subtract vectors or matrices.
/// </summary>
/// <param name="x">The array x.</param>

122
src/Numerics/Providers/LinearAlgebra/LinearAlgebraControl.cs

@ -0,0 +1,122 @@
// <copyright file="LinearAlgebraControl.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using System;
namespace MathNet.Numerics.Providers.LinearAlgebra
{
internal static class LinearAlgebraControl
{
const string EnvVarLAProvider = "MathNetNumericsLAProvider";
public static void UseManaged()
{
Control.LinearAlgebraProvider = new ManagedLinearAlgebraProvider();
}
#if NATIVE
public static void UseNativeMKL(
Common.Mkl.MklConsistency consistency = Common.Mkl.MklConsistency.Auto,
Common.Mkl.MklPrecision precision = Common.Mkl.MklPrecision.Double,
Common.Mkl.MklAccuracy accuracy = Common.Mkl.MklAccuracy.High)
{
Control.LinearAlgebraProvider = new Mkl.MklLinearAlgebraProvider(consistency, precision, accuracy);
}
public static void UseNativeCUDA()
{
Control.LinearAlgebraProvider = new Cuda.CudaLinearAlgebraProvider();
}
public static void UseNativeOpenBLAS()
{
Control.LinearAlgebraProvider = new OpenBlas.OpenBlasLinearAlgebraProvider();
}
#endif
public static bool TryUse(ILinearAlgebraProvider provider)
{
try
{
if (!provider.IsAvailable())
{
return false;
}
Control.LinearAlgebraProvider = provider;
return true;
}
catch
{
// intentionally swallow exceptions here - use the explicit variants if you're interested in why
return false;
}
}
public static void UseBest()
{
#if NATIVE
if (!(TryUse(new Cuda.CudaLinearAlgebraProvider())
|| TryUse(new Mkl.MklLinearAlgebraProvider())
|| TryUse(new OpenBlas.OpenBlasLinearAlgebraProvider())))
{
UseManaged();
}
#else
UseManaged();
#endif
}
public static void UseDefault()
{
#if NATIVE
var value = Environment.GetEnvironmentVariable(EnvVarLAProvider);
switch (value != null ? value.ToUpperInvariant() : string.Empty)
{
case "MKL":
UseNativeMKL();
break;
case "CUDA":
UseNativeCUDA();
break;
case "OPENBLAS":
UseNativeOpenBLAS();
break;
default:
UseBest();
break;
}
#else
UseManaged();
#endif
}
}
}

9
src/Numerics/Providers/LinearAlgebra/ManagedLinearAlgebraProvider.cs

@ -34,6 +34,15 @@ namespace MathNet.Numerics.Providers.LinearAlgebra
/// </summary>
public partial class ManagedLinearAlgebraProvider : ILinearAlgebraProvider
{
/// <summary>
/// Try to find out whether the provider is available, at least in principle.
/// Verification may still fail if available, but it will certainly fail if unavailable.
/// </summary>
public virtual bool IsAvailable()
{
return true;
}
/// <summary>
/// Initialize and verify that the provided is indeed available. If not, fall back to alternatives like the managed provider
/// </summary>

1
src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex.cs

@ -34,6 +34,7 @@ using System.Numerics;
using System.Security;
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Providers.Common.Mkl;
namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
{

1
src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Complex32.cs

@ -34,6 +34,7 @@ using System.Numerics;
using System.Security;
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Providers.Common.Mkl;
namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
{

1
src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Double.cs

@ -34,6 +34,7 @@ using System.Numerics;
using System.Security;
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Providers.Common.Mkl;
namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
{

1
src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.Single.cs

@ -34,6 +34,7 @@ using System.Numerics;
using System.Security;
using MathNet.Numerics.LinearAlgebra.Factorization;
using MathNet.Numerics.Properties;
using MathNet.Numerics.Providers.Common.Mkl;
namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
{

178
src/Numerics/Providers/LinearAlgebra/Mkl/MklLinearAlgebraProvider.cs

@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2015 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -27,10 +27,11 @@
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using System;
#if NATIVE
using System;
using MathNet.Numerics.Providers.Common.Mkl;
namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
{
/// <summary>
@ -47,6 +48,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// <summary>
/// Consistency vs. performance trade-off between runs on different machines.
/// </summary>
[Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")]
public enum MklConsistency : int
{
/// <summary>Consistent on the same CPU only (maximum performance)</summary>
@ -64,6 +66,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
}
[CLSCompliant(false)]
[Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")]
public enum MklAccuracy : uint
{
Low = 0x1,
@ -71,48 +74,21 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
}
[CLSCompliant(false)]
[Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")]
public enum MklPrecision : uint
{
Single = 0x10,
Double = 0x20
}
internal enum MklMemoryRequestMode : int
{
/// <summary>
/// Disable gathering memory usage
/// </summary>
Disable = 0,
/// <summary>
/// Enable gathering memory usage
/// </summary>
Enable = 1,
/// <summary>
/// Return peak memory usage
/// </summary>
PeakMemory = 2,
/// <summary>
/// Return peak memory usage and reset counter
/// </summary>
PeakMemoryReset = -1
}
/// <summary>
/// Intel's Math Kernel Library (MKL) linear algebra provider.
/// </summary>
public partial class MklLinearAlgebraProvider : ManagedLinearAlgebraProvider
{
int _nativeRevision;
bool _nativeIX86;
bool _nativeX64;
bool _nativeIA64;
readonly MklConsistency _consistency;
readonly MklPrecision _precision;
readonly MklAccuracy _accuracy;
readonly Common.Mkl.MklConsistency _consistency;
readonly Common.Mkl.MklPrecision _precision;
readonly Common.Mkl.MklAccuracy _accuracy;
/// <param name="consistency">
/// Sets the desired bit consistency on repeated identical computations on varying CPU architectures,
@ -121,10 +97,28 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// <param name="precision">VML optimal precision and rounding.</param>
/// <param name="accuracy">VML accuracy mode.</param>
[CLSCompliant(false)]
[Obsolete("Will be removed in the next major version. Use the enums in the Common namespace instead.")]
public MklLinearAlgebraProvider(
MklConsistency consistency = MklConsistency.Auto,
MklPrecision precision = MklPrecision.Double,
MklAccuracy accuracy = MklAccuracy.High)
{
_consistency = (Common.Mkl.MklConsistency)consistency;
_precision = (Common.Mkl.MklPrecision)precision;
_accuracy = (Common.Mkl.MklAccuracy)accuracy;
}
/// <param name="consistency">
/// Sets the desired bit consistency on repeated identical computations on varying CPU architectures,
/// as a trade-off with performance.
/// </param>
/// <param name="precision">VML optimal precision and rounding.</param>
/// <param name="accuracy">VML accuracy mode.</param>
[CLSCompliant(false)]
public MklLinearAlgebraProvider(
Common.Mkl.MklConsistency consistency = Common.Mkl.MklConsistency.Auto,
Common.Mkl.MklPrecision precision = Common.Mkl.MklPrecision.Double,
Common.Mkl.MklAccuracy accuracy = Common.Mkl.MklAccuracy.High)
{
_consistency = consistency;
_precision = precision;
@ -133,9 +127,18 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
public MklLinearAlgebraProvider()
{
_consistency = MklConsistency.Auto;
_precision = MklPrecision.Double;
_accuracy = MklAccuracy.High;
_consistency = Common.Mkl.MklConsistency.Auto;
_precision = Common.Mkl.MklPrecision.Double;
_accuracy = Common.Mkl.MklAccuracy.High;
}
/// <summary>
/// Try to find out whether the provider is available, at least in principle.
/// Verification may still fail if available, but it will certainly fail if unavailable.
/// </summary>
public override bool IsAvailable()
{
return MklProvider.IsAvailable(minRevision: 4);
}
/// <summary>
@ -144,58 +147,16 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// </summary>
public override void InitializeVerify()
{
int a, b, linearAlgebra;
try
{
// Load the native library
NativeProviderLoader.TryLoad(SafeNativeMethods.DllName);
MklProvider.Load(minRevision: 4);
MklProvider.ConfigurePrecision(_consistency, _precision, _accuracy);
a = SafeNativeMethods.query_capability(0);
b = SafeNativeMethods.query_capability(1);
_nativeIX86 = SafeNativeMethods.query_capability((int)ProviderPlatform.x86) > 0;
_nativeX64 = SafeNativeMethods.query_capability((int)ProviderPlatform.x64) > 0;
_nativeIA64 = SafeNativeMethods.query_capability((int)ProviderPlatform.ia64) > 0;
_nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision);
linearAlgebra = SafeNativeMethods.query_capability((int)ProviderCapability.LinearAlgebra);
}
catch (DllNotFoundException e)
{
throw new NotSupportedException("MKL Native Provider not found.", e);
}
catch (BadImageFormatException e)
{
throw new NotSupportedException("MKL Native Provider found but failed to load. Please verify that the platform matches (x64 vs x32, Windows vs Linux).", e);
}
catch (EntryPointNotFoundException e)
{
throw new NotSupportedException("MKL Native Provider does not support capability querying and is therefore not compatible. Consider upgrading to a newer version.", e);
}
if (a != 0 || b != -1 || _nativeRevision < 4)
{
throw new NotSupportedException("MKL Native Provider too old. Consider upgrading to a newer version.");
}
int linearAlgebra = SafeNativeMethods.query_capability((int)ProviderCapability.LinearAlgebraMajor);
// we only support exactly one major version, since major version changes imply a breaking change.
if (linearAlgebra != 2)
{
throw new NotSupportedException(string.Format("MKL Native Provider not compatible. Expecting linear algebra v2 but provider implements v{0}.", linearAlgebra));
}
// set numerical consistency, precision and accuracy modes, if supported
if (SafeNativeMethods.query_capability((int)ProviderConfig.Precision) > 0)
{
SafeNativeMethods.set_consistency_mode((int)_consistency);
SafeNativeMethods.set_vml_mode((uint)_precision | (uint)_accuracy);
}
// set threading settings, if supported
if (SafeNativeMethods.query_capability((int)ProviderConfig.Threading) > 0)
{
SafeNativeMethods.set_max_threads(Control.MaxDegreeOfParallelism);
}
}
/// <summary>
@ -203,12 +164,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// </summary>
public void FreeBuffers()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.free_buffers();
MklProvider.FreeBuffers();
}
/// <summary>
@ -216,12 +172,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// </summary>
public void ThreadFreeBuffers()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.thread_free_buffers();
MklProvider.ThreadFreeBuffers();
}
/// <summary>
@ -229,12 +180,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// </summary>
public void DisableMemoryPool()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.disable_fast_mm();
MklProvider.DisableMemoryPool();
}
/// <summary>
@ -244,12 +190,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// <returns>Returns the number of bytes allocated to all memory buffers.</returns>
public long MemoryStatistics(out int allocatedBuffers)
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
return SafeNativeMethods.mem_stat(out allocatedBuffers);
return MklProvider.MemoryStatistics(out allocatedBuffers);
}
/// <summary>
@ -257,12 +198,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// </summary>
public void EnablePeakMemoryStatistics()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.peak_mem_usage((int)MklMemoryRequestMode.Enable);
MklProvider.EnablePeakMemoryStatistics();
}
/// <summary>
@ -270,12 +206,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// </summary>
public void DisablePeakMemoryStatistics()
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
SafeNativeMethods.peak_mem_usage((int)MklMemoryRequestMode.Disable);
MklProvider.DisablePeakMemoryStatistics();
}
/// <summary>
@ -285,19 +216,12 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Mkl
/// <returns>The peak number of bytes allocated to all memory buffers.</returns>
public long PeakMemoryStatistics(bool reset = true)
{
if (SafeNativeMethods.query_capability((int)ProviderConfig.Memory) < 1)
{
throw new NotSupportedException("MKL Native Provider does not support memory management functions. Consider upgrading to a newer version.");
}
return SafeNativeMethods.peak_mem_usage((int)(reset ? MklMemoryRequestMode.PeakMemoryReset : MklMemoryRequestMode.PeakMemory));
return MklProvider.PeakMemoryStatistics(reset);
}
public override string ToString()
{
return string.Format("Intel MKL ({1}; revision {0})",
_nativeRevision,
_nativeIX86 ? "x86" : _nativeX64 ? "x64" : _nativeIA64 ? "IA64" : "unknown");
return MklProvider.Describe();
}
}
}

3
src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex.cs

@ -34,6 +34,7 @@ using MathNet.Numerics.Properties;
using System;
using System.Numerics;
using System.Security;
using MathNet.Numerics.Providers.Common.OpenBlas;
namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
{
@ -357,7 +358,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
if (info > 0)
{
throw new SingularUMatrixException(info);
}
}
}
/// <summary>

3
src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Complex32.cs

@ -34,6 +34,7 @@ using MathNet.Numerics.Properties;
using System;
using System.Numerics;
using System.Security;
using MathNet.Numerics.Providers.Common.OpenBlas;
namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
{
@ -357,7 +358,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
if (info > 0)
{
throw new SingularUMatrixException(info);
}
}
}
/// <summary>

3
src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Double.cs

@ -34,6 +34,7 @@ using MathNet.Numerics.Properties;
using System;
using System.Numerics;
using System.Security;
using MathNet.Numerics.Providers.Common.OpenBlas;
namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
{
@ -357,7 +358,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
if (info > 0)
{
throw new SingularUMatrixException(info);
}
}
}
/// <summary>

5
src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.Single.cs

@ -34,6 +34,7 @@ using MathNet.Numerics.Properties;
using System;
using System.Numerics;
using System.Security;
using MathNet.Numerics.Providers.Common.OpenBlas;
namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
{
@ -357,7 +358,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
if (info > 0)
{
throw new SingularUMatrixException(info);
}
}
}
/// <summary>
@ -811,7 +812,7 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
if (method == QRMethod.Full)
{
var info = SafeNativeMethods.s_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x);
if (info == (int)NativeError.MemoryAllocation)
{
throw new MemoryAllocationException();

65
src/Numerics/Providers/LinearAlgebra/OpenBlas/OpenBlasLinearAlgebraProvider.cs

@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2015 Math.NET
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -30,6 +30,7 @@
#if NATIVE
using System;
using MathNet.Numerics.Providers.Common.OpenBlas;
namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
{
@ -56,61 +57,35 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.OpenBlas
/// </summary>
public partial class OpenBlasLinearAlgebraProvider : ManagedLinearAlgebraProvider
{
int _nativeRevision;
bool _nativeIX86;
bool _nativeX64;
bool _nativeIA64;
bool _nativeARM;
/// <summary>
/// Try to find out whether the provider is available, at least in principle.
/// Verification may still fail if available, but it will certainly fail if unavailable.
/// </summary>
public override bool IsAvailable()
{
return OpenBlasProvider.IsAvailable(minRevision: 1);
}
/// <summary>
/// Initialize and verify that the provided is indeed available.
/// If not, fall back to alternatives like the managed provider
/// </summary>
public override void InitializeVerify()
{
int a, b, linearAlgebra;
try
{
// Load the native library
NativeProviderLoader.TryLoad(SafeNativeMethods.DllName);
a = SafeNativeMethods.query_capability(0);
b = SafeNativeMethods.query_capability(1);
OpenBlasProvider.Load(minRevision: 1);
_nativeIX86 = SafeNativeMethods.query_capability((int)ProviderPlatform.x86) > 0;
_nativeX64 = SafeNativeMethods.query_capability((int)ProviderPlatform.x64) > 0;
_nativeIA64 = SafeNativeMethods.query_capability((int)ProviderPlatform.ia64) > 0;
_nativeARM = SafeNativeMethods.query_capability((int)ProviderPlatform.arm) > 0;
_nativeRevision = SafeNativeMethods.query_capability((int)ProviderConfig.Revision);
linearAlgebra = SafeNativeMethods.query_capability((int)ProviderCapability.LinearAlgebra);
}
catch (DllNotFoundException e)
{
throw new NotSupportedException("OpenBLAS Native Provider not found.", e);
}
catch (BadImageFormatException e)
{
throw new NotSupportedException("OpenBLAS Native Provider found but failed to load. Please verify that the platform matches (x64 vs x32, Windows vs Linux).", e);
}
catch (EntryPointNotFoundException e)
{
throw new NotSupportedException("OpenBLAS Native Provider does not support capability querying and is therefore not compatible. Consider upgrading to a newer version.", e);
}
if (a != 0 || b != -1 || linearAlgebra <=0 || _nativeRevision < 1)
{
throw new NotSupportedException("OpenBLAS Native Provider too old or not compatible. Consider upgrading to a newer version.");
}
int linearAlgebra = SafeNativeMethods.query_capability((int)ProviderCapability.LinearAlgebraMajor);
// set threading settings, if supported
if (SafeNativeMethods.query_capability((int)ProviderConfig.Threading) > 0)
// we only support exactly one major version, since major version changes imply a breaking change.
if (linearAlgebra != 1)
{
SafeNativeMethods.set_max_threads(Control.MaxDegreeOfParallelism);
throw new NotSupportedException(string.Format("OpenBLAS Native Provider not compatible. Expecting linear algebra v1 but provider implements v{0}.", linearAlgebra));
}
}
public override string ToString()
{
return string.Format("OpenBLAS ({1}; revision {0})",
_nativeRevision,
_nativeIX86 ? "x86" : _nativeX64 ? "x64" : _nativeIA64 ? "IA64" : _nativeARM ? "ARM" : "unknown");
return OpenBlasProvider.Describe();
}
}
}

103
src/UnitTests/FourierTransformProviderTests/FourierTransformProviderTests.cs

@ -0,0 +1,103 @@
// <copyright file="FourierTransformProviderTests.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
using System;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.Providers.FourierTransform;
using MathNet.Numerics.Statistics;
using NUnit.Framework;
namespace MathNet.Numerics.UnitTests.FourierTransformProviderTests
{
#if NOSYSNUMERICS
using Complex = Numerics.Complex;
#else
using Complex = System.Numerics.Complex;
#endif
/// <summary>
/// Base class for linear algebra provider tests.
/// </summary>
[TestFixture, Category("LAProvider")]
public class LinearAlgebraProviderTests
{
[Test]
public void ForwardInplaceRealSine()
{
var samples = Generate.PeriodicMap(16, w => new Complex(Math.Sin(w), 0), 16, 1.0, Constants.Pi2);
var spectrum = new Complex[samples.Length];
// real-odd transforms to imaginary odd
samples.Copy(spectrum);
Control.FourierTransformProvider.ForwardInplace(spectrum, FourierTransformScaling.BackwardScaling);
// all real components must be zero
foreach (var c in spectrum)
{
Assert.AreEqual(0, c.Real, 1e-12, "real");
}
// all imaginary components except second and last musth be zero
for (var i = 0; i < spectrum.Length; i++)
{
if (i == 1)
{
Assert.AreEqual(-8, spectrum[i].Imaginary, 1e-12, "imag second");
}
else if (i == spectrum.Length - 1)
{
Assert.AreEqual(8, spectrum[i].Imaginary, 1e-12, "imag last");
}
else
{
Assert.AreEqual(0, spectrum[i].Imaginary, 1e-12, "imag");
}
}
}
[TestCase(0x1000)]
[TestCase(0x7FF)]
public void ForwardInplaceParsevalTheorem(int count)
{
var samples = Generate.RandomComplex(count, GetUniform(1));
var timeSpaceEnergy = Generate.Map(samples, s => s.MagnitudeSquared()).Mean();
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling);
var frequencySpaceEnergy = Generate.Map(samples, s => s.MagnitudeSquared()).Mean();
Assert.AreEqual(timeSpaceEnergy, frequencySpaceEnergy, 1e-12);
}
IContinuousDistribution GetUniform(int seed)
{
return new ContinuousUniform(-1, 1, new System.Random(seed));
}
}
}

70
src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs

@ -30,6 +30,7 @@
using System;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.IntegralTransforms;
using MathNet.Numerics.Providers.FourierTransform;
using NUnit.Framework;
namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
@ -69,6 +70,24 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
AssertHelpers.AlmostEqual(spectrumNaive, spectrumFast, maximumErrorDecimalPlaces);
}
static void VerifyInplace(
Complex[] samples,
int maximumErrorDecimalPlaces,
FourierOptions options,
Action<Complex[], FourierOptions> expected,
Action<Complex[], FourierOptions> actual)
{
var spectrumExpected = new Complex[samples.Length];
samples.CopyTo(spectrumExpected, 0);
expected(spectrumExpected, options);
var spectrumActual = new Complex[samples.Length];
samples.CopyTo(spectrumActual, 0);
actual(spectrumActual, options);
AssertHelpers.AlmostEqual(spectrumExpected, spectrumActual, maximumErrorDecimalPlaces);
}
/// <summary>
/// Fourier Radix2XX matches naive on real sine.
/// </summary>
@ -144,6 +163,57 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
Verify(samples, 10, options, Fourier.NaiveInverse, Fourier.BluesteinInverse);
}
/// <summary>
/// Fourier bluestein matches providers on random power of two.
/// </summary>
/// <param name="options">Fourier options.</param>
[TestCase(FourierOptions.Default)]
[TestCase(FourierOptions.NoScaling)]
[TestCase(FourierOptions.AsymmetricScaling)]
[TestCase(FourierOptions.InverseExponent)]
[TestCase(FourierOptions.InverseExponent | FourierOptions.NoScaling)]
[TestCase(FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling)]
public void FourierBluesteinMatchesProvider_Random_Arbitrary(FourierOptions options)
{
var samples = Generate.RandomComplex(0x7F, GetUniform(1));
VerifyInplace(samples, 10, options, Fourier.Forward, Fourier.BluesteinForward);
VerifyInplace(samples, 10, options, Fourier.Inverse, Fourier.BluesteinInverse);
}
[Test]
public void AlgorithmsMatchProvider_PowerOfTwo_Large()
{
// 65536 = 2^16
const FourierOptions options = FourierOptions.NoScaling;
var samples = Generate.RandomComplex(65536, GetUniform(1));
var provider = Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling);
Verify(samples, 10, options, (a, b) => provider, Fourier.Radix2Forward);
Verify(samples, 10, options, (a, b) => provider, Fourier.BluesteinForward);
}
[Test]
public void AlgorithmsMatchProvider_Arbitrary_Large()
{
// 30870 = 2*3*3*5*7*7*7
const FourierOptions options = FourierOptions.NoScaling;
var samples = Generate.RandomComplex(30870, GetUniform(1));
var provider = Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling);
Verify(samples, 10, options, (a, b) => provider, Fourier.BluesteinForward);
}
[Test]
public void AlgorithmsMatchProvider_Arbitrary_Large_GH286()
{
const FourierOptions options = FourierOptions.NoScaling;
var samples = Generate.RandomComplex(46500, GetUniform(1));
var provider = Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling);
Verify(samples, 10, options, (a, b) => provider, Fourier.BluesteinForward);
}
[Test, Explicit("Long-Running")]
public void AlgorithmsMatchNaive_PowerOfTwo_Large()
{

Loading…
Cancel
Save