Memory<T> to store their data.Zipf distribution, also known as the zeta distribution, and the Zipfian distribution which is a truncated version with finite support.Cohen’s d and Hedges’ g) for one and two sample T tests.MultipleTesting class to apply various correction methods (Bonferroni, Holm, etc.) when running multiple tests.generalized harmonic numbers and related functions like PowerSum (Faulhaber’s function).logistic regression.global optimization: Particle Swarm Optimization, Differential Evolution, Covariance Matrix Adaptation - Evolution Strategy (CMA-ES), Simulated Annealing.Fourier transforms, especially for sizes that are not the product of small primes.Linear Discriminant Analysis (LDA) class.QuadraticDiscriminantAnalysis (QDA) class to classify data using a quadratic decision boundary.Fligner-Killeen test for equality of variances.Folded normal distribution and hyperbolic secant distribution.LinearAlgebraPool<T> to provide memory-efficient storage for short-lived vectors and matrices.LinearAlgebraPool<T> in many algorithms.probability distributions and statistical tests, including contingency tables.Compare class to compare numbers and sequences within a specified tolerance.IntegrationRules class to create stand-alone integration rules for a variety of weight functions.Discrete Cosine Transform and its inverse.GumbelDistribution class to make a clearer distinction between the variants that model the smallest or the largest extreme value.ChiDistribution class to represent the chi distribution and compute probabilities and quantiles.HalleySolver class to solve equations using Halley’s method, a third-order root-finding algorithm.Parameter objects.Absolute Differences (SAD) of two sequences.VandermondeMatrix<T> class to represent Vandermonde matrices and solve Vandermode systems of equations efficiently.FiniteDifferenceMethod class to represent finite difference methods for approximating derivatives of functions.Derivative method to support higher-order derivatives, higher order methods, and more.PartialLeastSquares class would not compute the predicted values correctly under some conditions.Pricipal Component Analysis class.BigInteger has been improved across the board. The difference is particularly noticeable for small numbers. By extension, BigRational and BigFloat benefit as well.Pricipal Component Analysis has been enhanced. Centering of variables can be disabled, and a new scaling option has bee added that ensures that the maximum absolute value of a variable is 1.nearest correlation matrix. The method is more reliable and now has the option to specify a minimum value for the eigenvalues of the resulting matrix.Extreme Optimization is now Numerics.NET, affirming our position as the leading numerical library for .NET.
Version 9 completes our migration: Both the NuGet packages and the namespaces have been changed to reflect this.
This will require some changes in your projects, but migration should be pretty straightforward:
If you encounter any challenges, we’re always here to help.
The packages are available on the NuGet Gallery.
All NuGet packages now start with the Numerics.NET prefix. We’ve also reorganized them in a more convenient way. The functionality is spread over several core packages, while a number of bundles offer a simple way to get everything you need.
The main bundle packages are:
Of course you stil have the option of installing the individual packages if that is what you prefer.
A tensor is a generalization of vectors and matrices to arbitrary dimensions. With the growing popularity in areas such as machine learning and AI, the time has come to add support for tensors to Numerics.NET.
There is so much new here that we’ve written an entire post just on the topic of tensors in Numerics.NET: In Depth: Tensors.
Some of the features in Numerics.NET’s tensor type are not available in other tensor libraries include:
Tensor.Add(left, right, result). This avoids unnecessary allocations and can dramatically improve performance.In previous versions, vectors and matrices always used managed arrays to store their. This incurred a penalty when working with some native code because it was necessary to copy the data between managed and unmanaged memory.
In version 9, vectors and matrices now support using Memory<T> to store the elements. This means you can create vectors and matrices directly from native memory. No more copying needed!
The core implementations of linear algebra methods have been refitted to use Span<T> instead of arrays. This was a major undertaking that enables better performance and more flexibility in the future. For example, it is what allows us to use Memory<T> for element storage.
The one drawback is that the new API is not compatible with C++/CLI, which doesn’t support ref structs like Span<T>. So, there are no more mixed-mode native assemblies.
Two new matrix decompositions make their debut in version 9. The Schur decomposition writes a square matrix A as
where Z is orthogonal (unitary) and T, the Schur form of A, is upper triangular. The diagonal elements of T are also the eigenvalues of A. For real matrices with complex eigenvalues, the real Schur form of A is returned. This is an upper quasi-triangular matrix where 2x2 blocks on the diagonal correspond to pairs of complex conjugate eigenvalues.
Similar to eigensystems, there is also a generalization of the Schur decomposition to two matrices. This generalized Schur decomposition, also called the QZ decomposition, rewrites two square matrices A and B as
where again S and T are upper triangular, and Q and Z are orthogonal (unitary).
Numerics.NET has had facilities for the generic implementation of numerical algorithms for over a decade. Our linear algebra library has supported arbitrary numerical types since 2008!
We continue to build on this foundation. The new tensor library is of course generic over the element type, but there’s more.
Our generic arithmetic implementation is built on a static class, Operations<T>, that provides all common operations on numbers. Thanks to JIT optimizations, performance is on par with hard-coded types.
The Operations<T> class now fully supports complex numbers and nullable numeric types. We’ve also brought this class up to speed with all the latest updates to the System.Math class and numeric types in recent .NET versions.
All our special number types (Quad, BigInteger, BigRational, BigFloat) implement the INumber<T> interface introduced in .NET 7.0. We’re not really happy with Microsoft’s work here. While the introduction of these interfaces is clearly a step forward in some ways, the way this was designed has some serious problems.
For .NET 7.0+ only, we’ve added generic implementations of some of the most common algorithms. The class names are the same but there is an extra type argument, which must implement INumber<T>. To find the classes, add .Generic to the namespace of the original (non-generic) class.
The following algorithms have a generic implementation:
We’ve added a new random number generator, PCG32, that is fast and compact. It is the new default random number generator.
Some new methods were recently added to .NET’s built-in random number generator. This includes GetItems, NextInt64 and NextSingle.
We’ve added implementations of these methods to our extended random number generator class so they are available to earlier .NET versions as well.
We’ve even added a few more! The GetItems method (introduced in .NET 8.0) returns a set of items chosen at random from a set of choices with replacement. This means that the same value can appear multiple times in the output. Many applications require items that are chosen without replacement. This means that every choice can appear at most once in the output. The GetItemsWithoutReplacement method does just that.
So-called special functions are a nearly limitless group of funcions that appear in science. Some are better known and more widely used than others.
In version 9, we’ve expanded our support for special functions considerably. We’ve added:
BigFloat functions.The API around aggregators (like Sum, Variance) has been overhauled to be more consistent and much more powerful.
Previously, there were two types of aggregators: normal aggregators always returned a value of a specific type. For example, computing the mean of an array always returned a double.
Aggregators now have an As<T> method that lets you change that. The input elements are converted to the result type. The converted elements are then used to compute the aggregate.
This is a breaking change. If you have code that depends on the type of the result of an aggregator being fixed, you will need to update it. For example, instead of Aggregators.Mean, you now use Aggregators.Mean.As<double>().
All aggregators support skipping missing values in the input. More generally, you can apply any condition to the input values and only those values that meet the condition will be included in the aggregation.
Internally, many of the aggregators use accumulators. These are simple structures that incrementally accumulate the result of the aggregation.
These accumulators have now been made public in the Numerics.NET.DataAnalysis.Accumulators namespace.
One accumulator can be the basis for several different aggregators. For example, the VarianceAccumulator<T> can return the count, the mean, as well as both the population and sample variance and standard deviation.
We’ve added a number of probability distributions. The following contiunous distributions are new in version 9:
Arcsine distributionHyperbolic distributionInverse chi square distributionInverse gamma distributionInverse Gaussian distributionInverse Weibull distributionJohnson family of distributionsMaxwell distributionNormal inverse Gaussian distributionAlso new is the log-series distribution, a discrete distribution with applications in biology and finance.
No major new features here.