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