I was thinking about your comment regarding the use of Array. If I define a matrix type to perform matrix multiplication, then I would implement it as shown below. Notice the underlying values are stored as a generic array such as let values: [T].
import Accelerate
struct Matrix<T> {
let rows: Int
let columns: Int
let values: [T]
init(_ content: [[T]]) {
self.rows = content.count
self.columns = content[0].count
self.values = content.flatMap { $0 }
}
init(rows: Int, columns: Int, values: [T]) {
self.rows = rows
self.columns = columns
self.values = values
}
}
func cblas_zgemm_wrapper(
_ m: Int,
_ n: Int,
_ k: Int,
_ alpha: UnsafeRawPointer,
_ a: UnsafeRawPointer,
_ lda: Int,
_ b: UnsafeRawPointer,
_ ldb: Int,
_ beta: UnsafeRawPointer,
_ c: UnsafeRawPointer,
_ ldc: Int
) {
cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, m, k, .init(alpha), .init(a), lda, .init(b), ldb, .init(beta), .init(c), ldc)
}
extension Matrix {
static func * (lhs: Matrix, rhs: Matrix) -> Matrix where T == Double {
precondition(lhs.columns == rhs.rows, "Number of columns in left matrix must equal number of rows in right matrix")
var a = lhs.values
var b = rhs.values
var c = [Double](repeating: 0.0, count: lhs.rows * rhs.columns)
let m = lhs.rows // rows in matrices A and C
let n = rhs.columns // columns in matrices B and C
let k = lhs.columns // columns in matrix A and rows in matrix B
let alpha = 1.0
let beta = 0.0
// matrix multiplication where C â αAB + ÎČC
cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, n, k, alpha, &a, k, &b, n, beta, &c, n)
let mat = Matrix(rows: lhs.rows, columns: rhs.columns, values: c)
return mat
}
static func * (lhs: Matrix, rhs: Matrix) -> Matrix where T == DSPDoubleComplex {
precondition(lhs.columns == rhs.rows, "Number of columns in left matrix must equal number of rows in right matrix")
let a = lhs.values
let b = rhs.values
let c = [DSPDoubleComplex](repeating: DSPDoubleComplex(), count: lhs.rows * rhs.columns)
let m = lhs.rows // rows in matrices A and C
let n = rhs.columns // columns in matrices B and C
let k = lhs.columns // columns in matrix A and rows in matrix B
let alpha = [DSPDoubleComplex(real: 1.0, imag: 0.0)]
let beta = [DSPDoubleComplex(real: 1.0, imag: 0.0)]
cblas_zgemm_wrapper(m, n, k, alpha, a, k, b, n, beta, c, n)
let mat = Matrix(rows: lhs.rows, columns: rhs.columns, values: c)
return mat
}
}
I would use the matrix type as shown here:
import Accelerate
let a = Matrix([[DSPDoubleComplex(real: 1.0, imag: 2.0), DSPDoubleComplex(real: 2.0, imag: 3.0)],
[DSPDoubleComplex(real: 5.0, imag: 6.0), DSPDoubleComplex(real: 7.0, imag: 8.0)]])
let b = Matrix([[DSPDoubleComplex(real: 1.0, imag: 2.0), DSPDoubleComplex(real: 2.0, imag: 3.0)],
[DSPDoubleComplex(real: 5.0, imag: 6.0), DSPDoubleComplex(real: 7.0, imag: 8.0)]])
let c = a * b
for i in 0..<c.rows {
for j in 0..<c.columns {
print(c.values[i * c.columns + j], terminator: " ")
}
print()
}
// This prints
// DSPDoubleComplex(real: -11.0, imag: 31.0) DSPDoubleComplex(real: -14.0, imag: 44.0)
// DSPDoubleComplex(real: -20.0, imag: 98.0) DSPDoubleComplex(real: -23.0, imag: 139.0)
So @gchilds, are you recommending that I don't use an array like let values: [T] for the underlying data storage? If you use an unsafe buffer pointer to store the values then how would you initialize the actual values of matrix A and B?