Uma introdução ao SuanShu

Uma introdução ao SuanShu

1. Introdução

The SuanShu is a Java math library for numerical analysis, statistics, root finding, linear algebra, optimization, and lots more. Uma das coisas que ele fornece é a funcionalidade para números reais e complexos.

Há uma versão de código aberto da biblioteca, bem como uma versão que requer uma licença - com diferentes formas de licença: acadêmica, comercial e de contribuidor.

Observe que os exemplos abaixo usam a versão licenciada por meio depom.xml. A versão de código aberto atualmente não está disponível em um repositório Maven; a versão licenciada exige que um servidor de licenças esteja em execução. Como resultado, não há nenhum teste para este pacote no GitHub.

2. Configuração para SuanShu

Vamos começar adicionando a dependência Maven aopom.xml:


    
        com.numericalmethod
        suanshu
        4.0.0
    


    
        nm-repo
        Numerical Method's Maven Repository
        http://repo.numericalmethod.com/maven/
        default
    

3. Trabalhando com Vetores

The SuanShu library provides classes for both dense vectors and sparse vectors. Um vetordense é um vetor onde a maioria dos elementos tem um valor diferente de zero, ao contrário de um vetorsparse onde a maioria dos valores tem um valor zero.

A implementação de um vetordense simplesmente usa um array Java de números reais / complexos, enquanto a implementação de um vetorsparse usa um array Java deentries, onde cadaentry tem um índice e um valor real / complexo.

Podemos ver como isso faria uma enorme diferença no armazenamento quando temos um vetor grande, onde a maioria dos valores é zero. A maioria das bibliotecas matemáticas usa uma abordagem como essa quando precisa oferecer suporte a vetores de tamanhos grandes.

Vejamos algumas das operações básicas de vetor.

3.1. Adicionando Vetores

Adicionar 2 vetores é bastante simples usando o métodoadd():

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

O resultado que veremos é:

[6.000000, 6.000000, 6.000000, 6.000000, 6.000000]

Também podemos adicionar os mesmos números a todos os elementos usando o métodoadd(double).

3.2. Dimensionamento de vetores

Escalando um vetor (ou seja, multiplicar por uma constante) também é muito fácil:

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

A saída:

[2.000000, 4.000000, 6.000000, 8.000000, 10.000000]

3.3. Produto Interno Vector

Calcular o produto interno de 2 vetores requer uma chamada para o métodoinnerProduct(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. Lidando com Erros

A biblioteca verifica se os vetores em que estamos operando são compatíveis com a operação que estamos executando. Por exemplo, adicionar um vetor de tamanho 2 a um vetor de tamanho 3 não deve ser possível. Portanto, o código abaixo deve resultar em uma exceção:

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

E, de fato, sim - executar esse código resulta em:

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.example.suanshu.SuanShuMath.addingIncorrectVectors(SuanShuMath.java:21)
    at com.example.suanshu.SuanShuMath.main(SuanShuMath.java:8)

4. Trabalhando com matrizes

In addition to vectors, the library also provides support for matrix operations. Semelhante a vetores, matrizes são suportadas no formatodenseesparse, e para números reais e complexos.

4.1. Adicionando Matrizes

Adicionar matrizes é tão simples quanto trabalhar com vetores:

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. Matrizes de multiplicação

A biblioteca matemática pode ser usada para multiplicar matrizes:

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

Multiplicar uma matriz 2 × 3 por uma matriz 3 × 2 resultará em uma matriz 2 × 2.

E para provar que a biblioteca faz verificações adequadas dos tamanhos das matrizes, vamos tentar fazer uma multiplicação que deve falhar:

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

A execução resultará na seguinte saída.

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.example.suanshu.SuanShuMath.multiplyIncorrectMatrices(SuanShuMath.java:98)
    at com.example.suanshu.SuanShuMath.main(SuanShuMath.java:22)

4.3. Calculando uma matriz inversa

Calcular o inverso de uma matriz pode ser um processo demorado, mas a biblioteca de matemática SuanShu facilita:

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

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

Podemos verificar isso usando a biblioteca SuanShu, mas multiplicando a matriz por sua inversa: o resultado deve ser a matriz de identidade. Podemos fazer isso adicionando o seguinte ao método acima:

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

5. Resolvendo Polinômios

One of the other areas the SuanShu provides support for is polynomials. Fornece métodos para avaliar um polinômio, mas também para encontrar sua raiz (valores de entrada onde o polinômio é avaliado como 0).

5.1. Criando um polinômio

Um polinômio pode ser criado especificando seus coeficientes. Portanto, um polinômio como3x2-5x+1 pode ser criado com:

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

Como podemos ver, começamos com o coeficiente do mais alto grau primeiro.

5.2. Avaliando um polinômio

O métodoevaluate() pode ser usado para avaliar o polinômio. Isso pode ser feito para entradas reais e complexas.

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

O resultado que veremos é:

51.0
-13.000000+2.000000i

5.3. Encontrando as raízes de um polinômio

Encontrar as raízes de um polinômio é facilitado pela biblioteca de matemática SuanShu. Ele fornece algoritmos conhecidos para determinar as raízes de polinômios de vários graus e, com base no grau mais alto do polinômio, a classe PolyRoot escolhe o melhor método:

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

A saída:

[-2.0, 1.0]

Então, 2 raízes reais foram encontradas para este polinômio da amostra: -2 e 1. Naturalmente, raízes complexas também são suportadas.

6. Conclusão

Este artigo é apenas uma breve introdução à biblioteca de matemática SuanShu.

Como sempre, o código-fonte completo do artigo está disponívelover on GitHub.