**I just announced the new *** Learn Spring * course, focused on the fundamentals of Spring 5 and Spring Boot 2:

*Learn Spring*course, focused on the fundamentals of Spring 5 and Spring Boot 2:

Last modified: January 24, 2019

**The SuanShu is a Java math library for numerical analysis, statistics, root finding, linear algebra, optimization, and lots more.** One of the things it provides is functionality for both real and complex numbers.

There’s an open-source version of the library, as well as a version that requires a license -with different forms of the license: academic, commercial, and contributor.

Note that the examples below use the licensed version through the *pom.xml*. The open-source version is currently not available in a Maven repository; the licensed version requires a license server to be running. As a result, there aren’t any tests for this package in GitHub.

Let’s start with adding the Maven dependency to the *pom.xml*:

<dependencies> <dependency> <groupId>com.numericalmethod</groupId> <artifactId>suanshu</artifactId> <version>4.0.0</version> </dependency> </dependencies> <repositories> <repository> <id>nm-repo</id> <name>Numerical Method's Maven Repository</name> <url>http://repo.numericalmethod.com/maven/</url> <layout>default</layout> </repository> </repositories>

**The SuanShu library provides classes for both dense vectors and sparse vectors.** A

The implementation of a *dense* vector simply uses a Java array of real/complex numbers while the implementation of a *sparse* vector uses a Java array of *entries*, where each *entry* has an index and a real/complex value.

We can see how that would make a huge difference in storage when we have a large vector where most values are zero. Most mathematical libraries use an approach like this when they need to support vectors of large sizes.

Let’s look at some of the basic vector operations.

Adding 2 vectors is pretty straightforward using the *add()* method:

public void addingVectors() throws Exception { Vector v1 = new DenseVector(new double[] {1, 2, 3, 4, 5}); Vector v2 = new DenseVector(new double[] {5, 4, 3, 2, 1}); Vector v3 = v1.add(v2); log.info("Adding vectors: {}", v3); }

The output we’ll see is:

[6.000000, 6.000000, 6.000000, 6.000000, 6.000000]

We can also add the same numbers to all elements using the *add(double)* method.

Scaling a vector (i.e. multiplying by a constant) is also very easy:

public void scaleVector() throws Exception { Vector v1 = new DenseVector(new double[]{1, 2, 3, 4, 5}); Vector v2 = v1.scaled(2.0); log.info("Scaling a vector: {}", v2); }

The output:

[2.000000, 4.000000, 6.000000, 8.000000, 10.000000]

Calculating the inner product of 2 vectors requires a call to the *innerProduct(Vector)* method:

public void innerProductVectors() throws Exception { Vector v1 = new DenseVector(new double[]{1, 2, 3, 4, 5}); Vector v2 = new DenseVector(new double[]{5, 4, 3, 2, 1}); double inner = v1.innerProduct(v2); log.info("Vector inner product: {}", inner); }

The library verifies that the vectors we are operating on are compatible with the operation we are executing. For instance, adding a size-2 vector to a size-3 vector should not be possible. So the code below should result in an exception:

public void addingIncorrectVectors() throws Exception { Vector v1 = new DenseVector(new double[] {1, 2, 3}); Vector v2 = new DenseVector(new double[] {5, 4}); Vector v3 = v1.add(v2); }

And indeed it does – running this code results in:

Exception in thread "main" com.numericalmethod.suanshu.vector.doubles.IsVector$SizeMismatch: vectors do not have the same size: 3 and 2 at com.numericalmethod.suanshu.vector.doubles.IsVector.throwIfNotEqualSize(IsVector.java:101) at com.numericalmethod.suanshu.vector.doubles.dense.DenseVector.add(DenseVector.java:174) at com.baeldung.suanshu.SuanShuMath.addingIncorrectVectors(SuanShuMath.java:21) at com.baeldung.suanshu.SuanShuMath.main(SuanShuMath.java:8)

**In addition to vectors, the library also provides support for matrix operations.** Similar to vectors, matrices are supported in *dense* and *sparse* format, and for real and complex numbers.

Adding matrices is just as simple as working with vectors:

public void addingMatrices() throws Exception { Matrix m1 = new DenseMatrix(new double[][]{ {1, 2, 3}, {4, 5, 6} }); Matrix m2 = new DenseMatrix(new double[][]{ {3, 2, 1}, {6, 5, 4} }); Matrix m3 = m1.add(m2); log.info("Adding matrices: {}", m3); }

The math library can be used to multiply matrices:

public void multiplyMatrices() throws Exception { Matrix m1 = new DenseMatrix(new double[][]{ {1, 2, 3}, {4, 5, 6} }); Matrix m2 = new DenseMatrix(new double[][]{ {1, 4}, {2, 5}, {3, 6} }); Matrix m3 = m1.multiply(m2); log.info("Multiplying matrices: {}", m3); }

Multiplying a 2×3 matrix with a 3×2 matrix will result in a 2×2 matrix.

And to prove the library does proper checks of the matrix sizes, let’s try to do a multiplication that should fail:

public void multiplyIncorrectMatrices() throws Exception { Matrix m1 = new DenseMatrix(new double[][]{ {1, 2, 3}, {4, 5, 6} }); Matrix m2 = new DenseMatrix(new double[][]{ {3, 2, 1}, {6, 5, 4} }); Matrix m3 = m1.multiply(m2); }

Executing that will result in the following output.

Exception in thread "main" com.numericalmethod.suanshu.matrix.MatrixMismatchException: matrix with 3 columns and matrix with 2 rows cannot multiply due to mis-matched dimension at com.numericalmethod.suanshu.datastructure.DimensionCheck.throwIfIncompatible4Multiplication(DimensionCheck.java:164) at com.numericalmethod.suanshu.matrix.doubles.matrixtype.dense.DenseMatrix.multiply(DenseMatrix.java:374) at com.baeldung.suanshu.SuanShuMath.multiplyIncorrectMatrices(SuanShuMath.java:98) at com.baeldung.suanshu.SuanShuMath.main(SuanShuMath.java:22)

Calculating the inverse of a matrix can be a lengthy process to do manually but the SuanShu math library makes it easy:

public void inverseMatrix() { Matrix m1 = new DenseMatrix(new double[][]{ {1, 2}, {3, 4} }); Inverse m2 = new Inverse(m1); log.info("Inverting a matrix: {}", m2); }

We can verify this using the SuanShu library but multiplying the matrix with its inverse: the result should be the identity matrix. We can do this by adding the following to the method above:

log.info("Verifying a matrix inverse: {}", m1.multiply(m2));

**One of the other areas the SuanShu provides support for is polynomials.** It provides methods for evaluating a polynomial but also for finding its root (input values where the polynomial evaluates to 0).

A polynomial can be created by specifying its coefficients. So a polynomial like *3x ^{2}-5x+1* can be created with:

public Polynomial createPolynomial() { return new Polynomial(new double[]{3, -5, 1}); }

As we can see, we start with the coefficient for the highest degree first.

The *evaluate()* method can be used to evaluate the polynomial. This can be done for real and complex inputs.

public void evaluatePolynomial(Polynomial p) { log.info("Evaluating a polynomial using a real number: {}", p.evaluate(5)); log.info("Evaluating a polynomial using a complex number: {}", p.evaluate(new Complex(1, 2))); }

The output we’ll see is:

51.0 -13.000000+2.000000i

Finding a polynomial’s roots is made easy by the SuanShu math library. It provides well-known algorithms to determine the roots for polynomials of various degrees and based on the highest degree of the polynomial, the PolyRoot class chooses the best method:

public void solvePolynomial() { Polynomial p = new Polynomial(new double[]{2, 2, -4}); PolyRootSolver solver = new PolyRoot(); List<? extends Number> roots = solver.solve(p); log.info("Finding polynomial roots: {}", roots); }

The output:

[-2.0, 1.0]

So 2 real roots were found for this sample polynomial: -2 and 1. Naturally, complex roots are supported as well.

This article is just a short introduction to the SuanShu math library.

As always, the full source code of the article is available over on GitHub.