diff --git a/src/Numerics/Control.cs b/src/Numerics/Control.cs index 9ccd07e4..f8475fd2 100644 --- a/src/Numerics/Control.cs +++ b/src/Numerics/Control.cs @@ -30,7 +30,6 @@ using MathNet.Numerics.Providers.LinearAlgebra; using System; -using System.IO; using System.Threading.Tasks; namespace MathNet.Numerics @@ -40,6 +39,8 @@ namespace MathNet.Numerics /// public static class Control { + const string EnvVarLAProvider = "MathNetNumericsLAProvider"; + static int _maxDegreeOfParallelism; static int _blockSize; static int _parallelizeOrder; @@ -70,63 +71,58 @@ namespace MathNet.Numerics #else try { - const string name = "MathNetNumericsLAProvider"; - var value = Environment.GetEnvironmentVariable(name); + var value = Environment.GetEnvironmentVariable(EnvVarLAProvider); switch (value != null ? value.ToUpperInvariant() : string.Empty) { #if NATIVE case "MKL": - LinearAlgebraProvider = new Providers.LinearAlgebra.Mkl.MklLinearAlgebraProvider(); + UseNativeMKL(); break; case "CUDA": - LinearAlgebraProvider = new Providers.LinearAlgebra.Cuda.CudaLinearAlgebraProvider(); + UseNativeCUDA(); break; case "OPENBLAS": - LinearAlgebraProvider = new Providers.LinearAlgebra.OpenBlas.OpenBlasLinearAlgebraProvider(); + UseNativeOpenBLAS(); break; #endif default: - LinearAlgebraProvider = new ManagedLinearAlgebraProvider(); + if (!TryUseNative()) + { + UseManaged(); + } break; } } catch { // We don't care about any failures here at all (because "auto") - LinearAlgebraProvider = new ManagedLinearAlgebraProvider(); + UseManaged(); } #endif } - public static void UseSingleThread() - { - _maxDegreeOfParallelism = 1; - ThreadSafeRandomNumberGenerators = false; - - LinearAlgebraProvider.InitializeVerify(); - } - - public static void UseMultiThreading() - { - _maxDegreeOfParallelism = Environment.ProcessorCount; - ThreadSafeRandomNumberGenerators = true; - - LinearAlgebraProvider.InitializeVerify(); - } - public static void UseManaged() { LinearAlgebraProvider = new ManagedLinearAlgebraProvider(); } #if NATIVE + + /// + /// Use the Intel MKL native provider for linear algebra. + /// Throws if it is not available or failed to initialize, in which case the previous provider is still active. + /// public static void UseNativeMKL() { LinearAlgebraProvider = new Providers.LinearAlgebra.Mkl.MklLinearAlgebraProvider(); } + /// + /// 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. + /// [CLSCompliant(false)] public static void UseNativeMKL( Providers.LinearAlgebra.Mkl.MklConsistency consistency = Providers.LinearAlgebra.Mkl.MklConsistency.Auto, @@ -136,17 +132,103 @@ namespace MathNet.Numerics LinearAlgebraProvider = new Providers.LinearAlgebra.Mkl.MklLinearAlgebraProvider(consistency, precision, accuracy); } + /// + /// Try to use the Intel MKL native provider for linear algebra. + /// + /// + /// True if the provider was found and initialized successfully. + /// False if it failed and the previous provider is still active. + /// + public static bool TryUseNativeMKL() + { + return Try(UseNativeMKL); + } + + /// + /// Use the Nvidia CUDA native provider for linear algebra. + /// Throws if it is not available or failed to initialize, in which case the previous provider is still active. + /// public static void UseNativeCUDA() { LinearAlgebraProvider = new Providers.LinearAlgebra.Cuda.CudaLinearAlgebraProvider(); } + /// + /// Try to use the Nvidia CUDA native provider for linear algebra. + /// + /// + /// True if the provider was found and initialized successfully. + /// False if it failed and the previous provider is still active. + /// + public static bool TryUseNativeCUDA() + { + return Try(UseNativeCUDA); + } + + /// + /// Use the OpenBLAS native provider for linear algebra. + /// Throws if it is not available or failed to initialize, in which case the previous provider is still active. + /// public static void UseNativeOpenBLAS() { LinearAlgebraProvider = new Providers.LinearAlgebra.OpenBlas.OpenBlasLinearAlgebraProvider(); } + + /// + /// Try to use the OpenBLAS native provider for linear algebra. + /// + /// + /// True if the provider was found and initialized successfully. + /// False if it failed and the previous provider is still active. + /// + public static bool TryUseNativeOpenBLAS() + { + return Try(UseNativeOpenBLAS); + } + + /// + /// Try to use any available native provider in an undefined order. + /// + /// + /// True if one of the native providers was found and successfully initialized. + /// False if it failed and the previous provider is still active. + /// + public static bool TryUseNative() + { + return TryUseNativeCUDA() || TryUseNativeMKL() || TryUseNativeOpenBLAS(); + } + + static bool Try(Action action) + { + try + { + action(); + return true; + } + catch + { + // intentionally swallow exceptions here - use the non-try variants if you're interested in why + return false; + } + } #endif + public static void UseSingleThread() + { + _maxDegreeOfParallelism = 1; + ThreadSafeRandomNumberGenerators = false; + + LinearAlgebraProvider.InitializeVerify(); + } + + public static void UseMultiThreading() + { + _maxDegreeOfParallelism = Environment.ProcessorCount; + ThreadSafeRandomNumberGenerators = true; + + LinearAlgebraProvider.InitializeVerify(); + } + /// /// Gets or sets a value indicating whether the distribution classes check validate each parameter. /// For the multivariate distributions this could involve an expensive matrix factorization.