Hi guys, my first question here, hopefully, I'll structure it correctly.
As part of a series of homework assignments for Numerical mathematics, I'm developing a Linear algebra library and I just startled on a problem.
I abstractly defined matrices as
public protocol MatrixProtocol:
ExpressibleByArrayLiteral,
Equatable,
BidirectionalCollection
where Element == Vector
{
associatedtype Value: BinaryFloatingPoint
...
}
As a design decision, I provided default implementations for core operators, like multiplication, so that every conforming type automatically has these capabilities.
public func *<M: MatrixProtocol>(_ m1: M, _ m2: M) -> Matrix<M.Value> {
// slow O(n^3) basic implementation
}
The core data structure is Matrix, which is an n*m dense matrix, backed by an array:
public struct Matrix<T: BinaryFloatingPoint>: MatrixProtocol {
public typealias Value = T
var buffer: [T]
...
}
Now I can provide optimized multiplication overloads using Accelerate:
import Accelerate
public func *(_ m1: Matrix<Double>, _ m2: Matrix<Double>) -> Matrix<Double> {
vDSP_mmulD(...)
}
public func *(_ m1: Matrix<Float>, _ m2: Matrix<Float>) -> Matrix<Float> {
vDSP_mmul(...)
}
Now, let me illustrate the problem:
Let's say I'm working on an algorithm, which extensively uses matrix multiplication, for instance, QR decomposition.
func QRDecompose<M: MatrixProtocol>(_ A: M) {
// dummy implementation
A * A
}
let A: Matrix<Float> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
QRDecompose(A)
I would expect that, since I know that A is Matrix<Float>, the optimized multiplication overload would be selected by the compiler, but instead, the default generic one is.
Is there anything I can do, besides having two additional implementations for each algorithm, when the input matrix is Matrix<Float> / Matrix<Double>, which would lead to a lot of code duplication?
I hope I've stated my problem clearly.
Thanks