Math.NET Numerics with Native Linear Algebra
Linear algebra is one of those areas where performance can be essential, but also one where native optimizations can make a huge difference. That's why in Math.NET Numerics we implemented linear algebra on top of a provider abstraction where providers can be exchanged.
Out of the box Math.NET Numerics only includes a fully managed provider which is supported on all platforms, but unfortunately is also rather slow. This doesn't matter much for most problems, but if you're working with very large dense matrices it can be a dealbreaker. That's why we've added some helper projects you can use to compile your own native provider, but that is still quite involved and requires some experience around C or C++. Not anymore, kudos to @marcuscuda!
Since Math.NET Numerics v2.4 we begin to distribute native providers as NuGet packages, starting with one based on Intel MKL. Enabling native algorithms becomes almost as simple as adding a NuGet package to your project.
Enabling Native Linear Algebra
Since the native providers are optimized for and work on a specific platform only, you'll have to decide exactly what platform your project should target (x64/64-bit, or x86/32-bit), configure your project or compiler accordingly and then choose the matching native package. We might be able to simplify this in the future by distributing both versions together and automatically selecting the right one at runtime, but for now that's how it is.
1: 2: |
|
We're also preparing analog packages for Linux.
I mentioned it is almost as simple as adding a NuGet package. Almost, because you still need to make sure the libraries get copied to your bin directory (e.g. by choosing "Copy always" in VS) and to actually enable them using the Control class:
1:
|
|
Without this line the default provider would have been used instead. Usually the default provider is the
fully managed one mentioned above. However, you can choose the new MKL provider as default
from the outside by setting the MathNetNumericsLAProvider
environment variable to MKL
(Note: does not work on the portable build).
This is especially useful for unit testing against multiple providers, but also e.g.
to upgrade to a faster provider in cases where you cannot actually modify the source code.
If needed you can prevent the environment variable to have any effect in your application
by explicitly configuring a provider yourself, e.g. the managed provider:
1:
|
|
Speed Up
You can expect a very significant speed up with the MKL provider. For example, computing the product of two 1000x1000 dense double matrices I've just measured the following median times on my 4-core x64 Windows desktop, with no code change between them (except configuring the Control class):
- Managed provider (parallelization enabled): 0.9s
- MKL native provider: 0.085s
This might not be a very thorough analysis but shows that even in this simple case the native provider is 10 times faster than our managed provider. Admittedly our managed provider might have some room for improvement (we actually have a promising alternative implementation waiting to be fully tested and integrated), but even with the best generic & portable managed algorithm we're unlikely to ever beat a native provider.
Alternative Native Providers - Call for Help
We try to make alternative providers available the same way in the future, hopefully also including some more open/free ones. Unfortunately, for most of them even just getting them to compile for both x86 and x64 on Windows can be very tricky. We've worked on ACML, Goto (now OpenBLAS) and ATLAS in the past but ran into problems with each of them on Windows. Hence, please let us know if you have any experience you could share with us. Thanks.