Abstraindo a dependência da biblioteca Matrix

Sep 28 2020

Estou escrevendo uma biblioteca de álgebra linear de brinquedo para aprendizado e para ser usada em uma biblioteca de rede neural de brinquedo. Gostaria de usar diferentes bibliotecas de álgebra linear Java para testar a eficiência, mas estou preso na abstração.

Suponha que eu gostaria que minha própria abstração Matrix fosse adicionar, subtrair, multiplicar, hadamardMultiply, map e mapElements assim:

// I would prefer for this to force the implementing classes to be immutable...
// M is the type of implementing matrix
public interface Matrix<M,T extends Number> {
    M add(M in); // return this matrix + in
    // overload add(T)
    // default subtract = add (-1 * T)
    M multiply(M in); // return this matrix X in
    // overload multiply(T)
    // default divide = multiply(T^-1)
    M hadamardMultiply(M in); // return this matrix hadamard in
    T map(Function<M,T> map); // f: M -> T
    M mapElements(UnaryOperator<T> map); // f: T -> T
}

O que quero dizer com imutável é que minha API deve ser semelhante a

Matrix<vendor.matrix.VendorMatrix, Double> multiple = myMatrix.multiply(someOtherMatrix);
// or
Matrix<vendor.matrix.VendorMatrix, Double> add = myMatrix.add(5);
// and
Matrix<vendor.matrix.VendorMatrix, Double> mapped = myMatrix.map(e -> e / Math.PI);

que não deve alterar o myMatrix.

Agora já usei o UJMP anteriormente e, portanto, preciso implementar esse wrapper em torno dessa biblioteca, e foi aqui que me deparei com o problema de que esses métodos não podem retornar minha Matrix, eles devem retornar o tipo das matrizes nas classes de implementação. No entanto, isso quebra a abstração.

Então pensei que a próxima etapa seria fazer uma classe UJMPMatrix, que estende qualquer classe de matriz desejada da biblioteca (neste caso UJMP) e implementa minha interface Matrix assim:

public class UJMPMatrix extends org.ujmp.core.DefaultDenseDoubleMatrix2D 
    implements my.library.Matrix<org.ujmp.core.Matrix, Double> {
....
}

Com isso, agora perdi a abstração, pois o defaultdensedoublematrix2d já contém todos esses métodos, quando desejo apenas os fornecidos em minha interface. Como eu prossigo?

Respostas

2 Guillaume Sep 28 2020 at 14:02

Se UJMPMatrix estende DefaultDenseDoubleMatrix2D, todos os métodos públicos UJMP são expostos. Você precisa usar o padrão de delegado.

Em relação à tipagem dos genéricos, você também precisará alterá-la para que possa aceitar outros UJMPMatrix como argumentos do método.

public class UJMPMatrix implements my.library.Matrix<UJMPMatrix, Double> {
    private org.ujmp.core.DefaultDenseDoubleMatrix2D delegate;
    
    // Implement the methods of your interface by using the delegate
}