«1. Введение

SuanShu — это математическая библиотека Java для численного анализа, статистики, поиска корней, линейной алгебры, оптимизации и многого другого. Одна из вещей, которую он предоставляет, — это функциональность как для действительных, так и для комплексных чисел.

Существует версия библиотеки с открытым исходным кодом, а также версия, для которой требуется лицензия, с различными формами лицензии: академическая, коммерческая и авторская.

Обратите внимание, что в приведенных ниже примерах используется лицензионная версия через файл pom.xml. Версия с открытым исходным кодом в настоящее время недоступна в репозитории Maven; лицензионная версия требует запуска сервера лицензий. В результате на GitHub нет тестов для этого пакета.

2. Настройка SuanShu

Давайте начнем с добавления зависимости Maven в 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>

3. Работа с векторами

Библиотека SuanShu предоставляет классы для обоих плотных векторов и разреженные векторы. Плотный вектор — это вектор, в котором большинство элементов имеют ненулевое значение, в отличие от разреженного вектора, в котором большинство значений имеют нулевое значение.

Реализация плотного вектора просто использует массив Java действительных/комплексных чисел, в то время как реализация разреженного вектора использует массив записей Java, где каждая запись имеет индекс и действительное/комплексное значение.

Мы можем видеть, как это будет иметь огромное значение в хранении, когда у нас есть большой вектор, где большинство значений равны нулю. Большинство математических библиотек используют подобный подход, когда им нужно поддерживать векторы больших размеров.

Давайте рассмотрим некоторые основные векторные операции.

3.1. Добавление векторов

Добавить два вектора довольно просто, используя метод add():

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);
}

Результат, который мы увидим:

[6.000000, 6.000000, 6.000000, 6.000000, 6.000000]

Мы также можем добавить одинаковые числа ко всем элементам, используя метод добавить (двойной) метод.

3.2. Масштабирование векторов

Масштабирование вектора (т.е. умножение на константу) также очень просто:

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);
}

Вывод:

[2.000000, 4.000000, 6.000000, 8.000000, 10.000000]

3.3. Внутреннее произведение вектора

Вычисление внутреннего произведения двух векторов требует вызова метода innerProduct(Vector):

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);
}

3.4. Работа с ошибками

Библиотека проверяет, что векторы, над которыми мы работаем, совместимы с выполняемой нами операцией. Например, добавление вектора размера 2 к вектору размера 3 не должно быть возможным. Таким образом, приведенный ниже код должен привести к исключению:

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);
}

И действительно, выполнение этого кода приводит к:

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)

4. Работа с матрицами

Помимо векторов, библиотека также обеспечивает поддержку матричных операций. Подобно векторам, матрицы поддерживаются в плотном и разреженном формате, а также для действительных и комплексных чисел.

4.1. Добавление матриц

Добавление матриц так же просто, как работа с векторами:

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);
}

4.2. Умножение матриц

Математическая библиотека может использоваться для умножения матриц:

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);
}

Умножение матрицы 2×3 на матрицу 3×2 даст матрицу 2×2.

И чтобы убедиться, что библиотека правильно проверяет размеры матриц, давайте попробуем выполнить умножение, которое должно завершиться ошибкой:

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);
}

Выполнение этого приведет к следующему результату.

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)

4.3. Вычисление обратной матрицы

Вычисление обратной матрицы может быть длительным процессом, выполняемым вручную, но математическая библиотека SuanShu упрощает его:

public void inverseMatrix() {
    Matrix m1 = new DenseMatrix(new double[][]{
        {1, 2},
        {3, 4}
    });

    Inverse m2 = new Inverse(m1);
    log.info("Inverting a matrix: {}", m2);
}

Мы можем проверить это, используя библиотеку SuanShu, но умножая матрицу на ее инверсия: результатом должна быть единичная матрица. Мы можем сделать это, добавив к описанному выше методу следующее:

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

5. Решение полиномов

Одной из других областей, для которых SuanShu обеспечивает поддержку, являются полиномы. Он предоставляет методы для оценки полинома, а также для нахождения его корня (входные значения, где полином оценивается как 0).

5.1. Создание многочлена

Многочлен можно создать, указав его коэффициенты. Таким образом, многочлен типа 3×2-5x+1 может быть создан с помощью:

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

Как мы видим, мы начинаем с коэффициента для высшей степени.

5.2. Вычисление многочлена

Для вычисления многочлена можно использовать метод Assessment(). Это можно сделать для реальных и сложных входных данных.

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)));
}

«

51.0
-13.000000+2.000000i

Результат, который мы увидим:

5.3. Поиск корней многочлена

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);
}

Поиск корней многочлена упрощается благодаря математической библиотеке SuanShu. Он предоставляет известные алгоритмы определения корней для полиномов различных степеней и на основе высшей степени полинома класс PolyRoot выбирает наилучший метод:

[-2.0, 1.0]

Вывод:

Итак 2 Для этого типового полинома были найдены действительные корни: -2 и 1. Естественно, комплексные корни также поддерживаются.

6. Заключение

Эта статья является кратким введением в математическую библиотеку SuanShu.