1. Overview
We’re frequently in need of using mathematical tools, and sometimes java.lang.Math is simply not enough. Fortunately, Apache Commons has the goal of filling in the leaks of the standard library, with Apache Commons Math.
Apache Commons Math is the biggest open-source library of mathematical functions and utilities for Java. Given that this article is just an introduction, we will just give an overview of the library and present the most compelling use cases.
2. Starting with Apache Commons Math
2.1. The Usages of Apache Commons Math
Apache Commons Math consists of mathematical functions (erf for instance), structures representing mathematical concepts (like complex numbers, polynomials, vectors, etc.), and algorithms that we can apply to these structures (root finding, optimization, curve fitting, computation of intersections of geometrical figures, etc.).
2.2. Maven Configuration
If you’re using Maven, simply add this dependency:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
2.3. Package Overview
Apache Commons Math is divided into several packages:
- org.apache.commons.math3.stat – statistics and statistical tests
- org.apache.commons.math3.distribution – probability distributions
- org.apache.commons.math3.random – random numbers, strings and data generation
- org.apache.commons.math3.analysis – root finding, integration, interpolation, polynomials, etc.
- org.apache.commons.math3.linear – matrices, solving linear systems
- org.apache.commons.math3.geometry – geometry (Euclidean spaces and binary space partitioning)
- org.apache.commons.math3.transform – transform methods (fast Fourier)
- org.apache.commons.math3.ode – ordinary differential equations integration
- org.apache.commons.math3.fitting – curve fitting
- org.apache.commons.math3.optim – function maximization or minimization
- org.apache.commons.math3.genetics – genetic algorithms
- org.apache.commons.math3.ml – machine learning (clustering and neural networks)
- org.apache.commons.math3.util – common math/stat functions extending java.lang.Math
- org.apache.commons.math3.special – special functions (Gamma, Beta)
- org.apache.commons.math3.complex – complex numbers
- org.apache.commons.math3.fraction – rational numbers
3. Statistics, Probabilities, and Randomness
3.1. Statistics
The package org.apache.commons.math3.stat provides several tools for statistical computations. For example, to compute mean, standard deviation, and many more, we can use DescriptiveStatistics:
double[] values = new double[] {65, 51 , 16, 11 , 6519, 191 ,0 , 98, 19854, 1, 32};
DescriptiveStatistics descriptiveStatistics = new DescriptiveStatistics();
for (double v : values) {
descriptiveStatistics.addValue(v);
}
double mean = descriptiveStatistics.getMean();
double median = descriptiveStatistics.getPercentile(50);
double standardDeviation = descriptiveStatistics.getStandardDeviation();
In this package, we can find tools for computing the covariance, correlation, or to perform statistical tests (using TestUtils).
3.2. Probabilities and Distributions
In core Java, Math.random() can be used for generating random values, but these values are uniformly distributed between 0 and 1.
Sometimes, we want to produce a random value using a more complex distribution. For this, we can use the framework provided by org.apache.commons.math3.distribution.
Here is how to generate random values according to the normal distribution with the mean of 10 and the standard deviation of 3:
NormalDistribution normalDistribution = new NormalDistribution(10, 3);
double randomValue = normalDistribution.sample();
Or we can obtain the probability P(X = x) of getting a value for discrete distributions, or the cumulative probability P(X <= x) for continuous distributions.
4. Analysis
Analysis related functions and algorithms can be found in org.apache.commons.math3.analysis.
4.1. Root Finding
A root is a value where a function has the value of 0. Commons-Math includes implementation of several root-finding algorithms.
Here, we try to find the root of v -> (v * v) – 2 :
UnivariateFunction function = v -> Math.pow(v, 2) - 2;
UnivariateSolver solver = new BracketingNthOrderBrentSolver(1.0e-12, 1.0e-8, 5);
double c = solver.solve(100, function, -10.0, 10.0, 0);
First, we start by defining the function, then we define the solver, and we set the desired accuracy. Finally, we call the solve() API.
The root-finding operation will be performed using several iterations, so it’s a matter of finding a compromise between execution time and accuracy.
4.2. Calculating Integrals
The integration works almost like root finding:
UnivariateFunction function = v -> v;
UnivariateIntegrator integrator = new SimpsonIntegrator(1.0e-12, 1.0e-8, 1, 32);
double i = integrator.integrate(100, function, 0, 10);
We start by defining a function, we choose an integrator among the available integration solutions existing, we set the desired accuracy, and finally, we integrate.
5. Linear Algebra
If we have a linear system of equations under the form AX = B where A is a matrix of real numbers, and B a vector of real numbers – Commons Math provides structures to represent both the matrix and the vector, and also provide solvers to find the value of X:
RealMatrix a = new Array2DRowRealMatrix(
new double[][] { { 2, 3, -2 }, { -1, 7, 6 }, { 4, -3, -5 } },
false);
RealVector b = new ArrayRealVector(n
ew double[] { 1, -2, 1 },
false);
DecompositionSolver solver = new LUDecomposition(a).getSolver();
RealVector solution = solver.solve(b);
The case is pretty straightforward: we define a matrix a from an array of array of doubles, and a vector b from an array of a vector.
Then, we create an LUDecomposition which provides a solver for equations under the form AX = B. As its name states it, LUDecomposition relies on the LU decomposition, and thus works only with square matrices.
For other matrices, different solvers exist, usually solving the equation using the least square method.
6. Geometry
The package org.apache.commons.math3.geometry provides several classes for representing geometrical objects and several tools to manipulate them. It is important to note that this package is divided into different sub-packages, regarding of the kind of geometry we want to use:
It is important to note that this package is divided into different sub-packages, regarding of the kind of geometry we want to use:
- org.apache.commons.math3.geometry.euclidean.oned – 1D Euclidean geometry
- org.apache.commons.math3.geometry.euclidean.twod – 2D Euclidean geometry
- org.apache.commons.math3.geometry.euclidean.threed – 3D Euclidean geometry
- org.apache.commons.math3.geometry.spherical.oned – 1D spherical geometry
- org.apache.commons.math3.geometry.spherical.twod – 2D spherical geometry
The most useful classes are probably Vector2D, Vector3D, Line, and Segment. They are used for representing 2D vectors (or points), 3D vectors, lines, and segments respectively.
When using classes mentioned above, it is possible to perform some computation. For instance, the following code performs the calculation of the intersection of two 2D lines:
Line l1 = new Line(new Vector2D(0, 0), new Vector2D(1, 1), 0);
Line l2 = new Line(new Vector2D(0, 1), new Vector2D(1, 1.5), 0);
Vector2D intersection = l1.intersection(l2);
It is also feasible to use these structures to get the distance of a point to a line, or the closest point of a line to another line (in 3D).
7. Optimization, Genetic Algorithms, and Machine Learning
Commons-Math also provides some tools and algorithms for more complex tasks related to optimization and machine learning.
7.1. Optimization
Optimization usually consists of minimizing or maximizing cost functions. Algorithms for optimization can be found in org.apache.commons.math3.optim and org.apache.commons.math3.optimimization. It includes linear and nonlinear optimization algorithms.
We can note that there are duplicate classes in the optim and optimization packages: the optimization package is mostly deprecated and will be removed in the Commons Math 4.
7.2. Genetic Algorithms
Genetic algorithms are a kind of meta-heuristics: they are a solution to finding an acceptable solution to a problem when deterministic algorithms are too slow. An overview of genetic algorithms can be found here.
The package org.apache.commons.math3.genetics provides a framework to perform computations using genetic algorithms. It contains structure that can be used to represent a population and a chromosome, and standard algorithms to perform mutation, crossover, and selection operations.
The following classes give a good start point:
- GeneticAlgorithm – the genetic algorithm framework
- Population – the interface representing a population
- Chromosome – the interface representing a chromosome
7.3. Machine Learning
Machine learning in Commons-Math is divided into two parts: clustering and neural networks.
The clustering part consists of putting a label on vectors according to their similarity regarding a distance metric. The clustering algorithms provided are based on the K-means algorithm.
The neural network part gives classes to represent networks (Network) and neurons (Neuron). One may note that the provided functions are limited compared to the most common neural network frameworks, but it can still be useful for small applications with low requirements.
8. Utilities
8.1. FastMath
FastMath is a static class located in org.apache.commons.math3.util and working exactly like java.lang.Math.
Its purpose is to provide, at least the same functions that we can found in java.lang.Math, but with faster implementations. So, when a program is heavily relying on mathematical computations, it is a good idea to replace calls to Math.sin() (for instance) to calls to FastMath.sin() to improve the performance of the application. On the other hand please note that FastMath is less accurate than java.lang.Math.
8.2. Common and Special Functions
Commons-Math provides standard mathematical functions that are not implemented in java.lang.Math (like factorial). Most of these functions can be found in the packages org.apache.commons.math3.special and org.apache.commons.math3.util.
For instance, if we want to compute the factorial of 10 we can simply do:
long factorial = CombinatorialUtils.factorial(10);
Functions related to arithmetic (gcd, lcm, etc.) can be found in ArithmeticUtils, and functions related to combinatorial can be found in CombinatorialUtils. Some other special functions, like erf, can be accessed in org.apache.commons.math3.special.
8.3. Fraction and Complex Numbers
It is also possible to handle more complex types using commons-math: fraction and complex numbers. These structures allow us to perform specific computation on this kind of numbers.
Then, we can compute the sum of two fractions and display the result as a string representation of a fraction (i.e. under the form “a / b”):
Fraction lhs = new Fraction(1, 3);
Fraction rhs = new Fraction(2, 5);
Fraction sum = lhs.add(rhs);
String str = new FractionFormat().format(sum);
Or, we can quickly compute power of complex numbers:
Complex first = new Complex(1.0, 3.0);
Complex second = new Complex(2.0, 5.0);
Complex power = first.pow(second);
9. Conclusion
In this tutorial, we presented a few of the interesting things you can do using Apache Commons Math.
Unfortunately, this article can’t cover the whole field of analysis or linear algebra, and thus, only provides examples for the most common situations.
However, for more information, we can read the well-written documentation, which provides a lot of details for all aspects of the library.
And, as always, the code samples can be found here on GitHub.