Multiplicação de matrizes em Java
1. Visão geral
Neste tutorial, veremos como podemos multiplicar duas matrizes em Java.
Como o conceito de matriz não existe nativamente na linguagem, nós o implementaremos e também trabalharemos com algumas bibliotecas para ver como eles lidam com a multiplicação de matrizes.
No final, faremos um pequeno benchmarking das diferentes soluções que exploramos para determinar a mais rápida.
2. O exemplo
Vamos começar configurando um exemplo que poderemos consultar ao longo deste tutorial.
Primeiro, vamos imaginar uma matriz 3 × 2:
https://www..com/wp-content/uploads/2019/07/firstMatrix.png [imagem:/wp-content/uploads/2019/07/firstMatrix.png [A = \ {\ {1, 5} , \ {2, 3}, \ {1, 7}}, largura = 234, altura = 144]]
Vamos agora imaginar uma segunda matriz, desta vez com duas linhas por quatro colunas:
link:/wp-content/uploads/2019/07/secondMatrux.png [imagem:/wp-content/uploads/2019/07/secondMatrux.png [B = \ {\ {1, 2, 3, 7}, \ {5, 2, 8, 1}}, largura = 348, altura = 107]]
Então, a multiplicação da primeira matriz pela segunda matriz, o que resultará em uma matriz 3 × 4:
link:/wp-content/uploads/2019/07/multiplicatedMatrix.png [imagem:/wp-content/uploads/2019/07/multiplicatedMatrix.png [C = \ {\ {26, 12, 43, 12}, \ {17, 10, 30, 17}, \ {36, 16, 59, 14}}, largura = 443, altura = 151]]
Como lembrete, este resultado é obtido calculando cada célula da matriz resultante com esta fórmula :
link:/wp-content/uploads/2019/07/multiplicationAlgorithm.png [imagem:/wp-content/uploads/2019/07/multiplicationAlgorithm.png [Fórmula de multiplicação de matrizes, largura = 228, altura = 24]]
Onde r é o número de linhas da matriz A, c é o número de colunas da matriz B e n é o número de colunas da matriz A, que deve corresponder ao número de linhas da matriz B.
3. Multiplicação da matriz
3.1. Implementação Própria
Vamos começar com nossa própria implementação de matrizes.
Vamos mantê-lo simples e apenas usar duas matrizes dimensionais double :
double[][] firstMatrix = {
new double[]{1d, 5d},
new double[]{2d, 3d},
new double[]{1d, 7d}
};
double[][] secondMatrix = {
new double[]{1d, 2d, 3d, 7d},
new double[]{5d, 2d, 8d, 1d}
};
Essas são as duas matrizes do nosso exemplo. Vamos criar o esperado como resultado de sua multiplicação:
double[][] expected = {
new double[]{26d, 12d, 43d, 12d},
new double[]{17d, 10d, 30d, 17d},
new double[]{36d, 16d, 59d, 14d}
};
Agora que tudo está configurado, vamos implementar o algoritmo de multiplicação. Primeiro, criaremos uma matriz de resultados vazia e percorreremos suas células para armazenar o valor esperado em cada uma delas:
double[][] multiplyMatrices(double[][] firstMatrix, double[][] secondMatrix) {
double[][] result = new double[firstMatrix.length][secondMatrix[0].length];
for (int row = 0; row < result.length; row++) {
for (int col = 0; col < result[row].length; col++) {
result[row][col] = multiplyMatricesCell(firstMatrix, secondMatrix, row, col);
}
}
return result;
}
Por fim, vamos implementar o cálculo de uma única célula. Para conseguir isso, usaremos a fórmula mostrada anteriormente na apresentação do exemplo :
double multiplyMatricesCell(double[][] firstMatrix, double[][] secondMatrix, int row, int col) {
double cell = 0;
for (int i = 0; i < secondMatrix.length; i++) {
cell += firstMatrix[row][i] *secondMatrix[i][col];
}
return cell;
}
Por fim, vamos verificar se o resultado do algoritmo corresponde ao resultado esperado:
double[][] actual = multiplyMatrices(firstMatrix, secondMatrix);
assertThat(actual).isEqualTo(expected);
3.2. EJML
A primeira biblioteca que examinaremos é o EJML, que significa Biblioteca Java Matriz eficiente. No momento da elaboração deste tutorial, é* uma das bibliotecas de matrizes Java atualizadas mais recentemente *. Seu objetivo é ser o mais eficiente possível em relação ao cálculo e uso de memória.
Teremos que adicionar a dependência da biblioteca em nosso pom.xml:
<dependency>
<groupId>org.ejml</groupId>
<artifactId>ejml-all</artifactId>
<version>0.38</version>
</dependency>
Usaremos praticamente o mesmo padrão de antes: criando duas matrizes de acordo com o nosso exemplo e verificando se o resultado de sua multiplicação é o que calculamos anteriormente.
Então, vamos criar nossas matrizes usando EJML. Para conseguir isso, usaremos a classe SimpleMatrix oferecida pela biblioteca .
Pode levar uma matriz double de duas dimensões como entrada para seu construtor:
SimpleMatrix firstMatrix = new SimpleMatrix(
new double[][] {
new double[] {1d, 5d},
new double[] {2d, 3d},
new double[] {1d ,7d}
}
);
SimpleMatrix secondMatrix = new SimpleMatrix(
new double[][] {
new double[] {1d, 2d, 3d, 7d},
new double[] {5d, 2d, 8d, 1d}
}
);
E agora, vamos definir nossa matriz esperada para a multiplicação:
SimpleMatrix expected = new SimpleMatrix(
new double[][] {
new double[] {26d, 12d, 43d, 12d},
new double[] {17d, 10d, 30d, 17d},
new double[] {36d, 16d, 59d, 14d}
}
);
Agora que estamos prontos, vamos ver como multiplicar as duas matrizes. A classe SimpleMatrix oferece um método mult () _ usando outro _SimpleMatrix