for var stack:[Double]
for i in 1...N {
stack[sp+i] += stack[sp+b+i]
}
conveniently becomes
vDSP.add(stack[sp+1 ... sp+N], stack[sp+b+1 ... sp+b+N], &stack[sp+1 ... sp+N])
since ArraySlice<Double> conforms to AccelerateBuffer.
What would be the equivalent Accelerate magic for var stack: [Complex] (where Complex is defined the usual way).
Bonus points if it is simple to use in a generic. i.e.
func evaluate(T:Computable) { // Double and Complex conform to Computable
var stack:[T]
etc...
vDSP_zvaddD looks promising, but [Complex] interleaves real and imaginary parts, and to use vDSP_zvaddD would seem to require getting an UnsafePointer<DSPDoubleSplitComplex> from ArraySlice<Double>.
(I will be needing all the usual arithmetic and transcendental operations on double precision Double and Complex, and mixed vector-scalar operations, as well....)
2 Likes
scanon
(Steve Canon)
2
My initial thought here is to provide a split complex buffer type that conforms to Collection with Element == Complex, but also has contiguous real and imaginary parts that can be used to make nice wrappers for the vDSP interfaces. This is something that I've been meaning to design out and add, but simply haven't gotten around to yet.
5 Likes
scanon
(Steve Canon)
3
Extremely sketchy draft of what I'm talking about here:
Note that the actual implementation here is not at all what I would end up doing eventually, but it at least outlines what such a project would look like and how it could interoperate with Accelerate.
3 Likes
RonAvitzur
(Ron Avitzur)
4
There's enough here that I don't understand that I am not sure where to begin my questions.
I'm trying to implement the equivalent of
func vvMultiply(stack: inout [Complex], sp: Int, n: Int) {
for i in 1...n { stack[sp+i] *= stack[sp+n+1+i] }
}
using vDSP_zvmulD
- Is vDSP_zvmulD the appropriate API?
- How do I approach that?
1 Like
RonAvitzur
(Ron Avitzur)
5
Current attempt (seems to work....)
func vSquare(_ stack: inout [Complex], sp: Int, n: Int) {
stack.withUnsafeMutablePointerToDouble {
let p = $0 + 2*sp + 2
var dsc = DSPDoubleSplitComplex(realp: p, imagp: p + 1)
vDSP_zvmulD(&dsc, 2, &dsc, 2, &dsc, 2, UInt(n), +1)
}
}
extension Array where Element == Complex {
func withUnsafeMutablePointerToDouble(_ body: (UnsafeMutablePointer<Double>) -> ()) {
self.withUnsafeBufferPointer {
let complexBufferBaseAddress = $0.baseAddress!
let numDoubles = $0.count * 2
complexBufferBaseAddress.withMemoryRebound(to: Double.self, capacity: numDoubles) { doubleBufferBaseAddress in
let doubleBuffer = UnsafeBufferPointer(start: doubleBufferBaseAddress, count: numDoubles)
body(UnsafeMutablePointer<Double>(mutating: doubleBuffer.baseAddress!))
}
}
}
}
1 Like
RonAvitzur
(Ron Avitzur)
6
Finally getting around to implementing the vector-scalar ops, and again, [Double] conformance to AccelerateBuffer makes the Double version simple, but my attempt for the Complex version seems overly verbose. Any suggestions for simplifying:
static func vsMul(_ scalar: Complex, _ stack: inout [Complex], sp: Int, spResult: Int, n: Int) {
stack.withUnsafeMutablePointerToDouble { p in
var re = scalar.re, im = scalar.im
withUnsafeMutablePointer(to: &re) { pRe in
withUnsafeMutablePointer(to: &im) { pIm in
let p1 = p + 2*sp + 2
let p2 = p + 2*spResult + 2
var dsc1 = DSPDoubleSplitComplex(realp: p1, imagp: p1 + 1)
var dsc2 = DSPDoubleSplitComplex(realp: p2, imagp: p2 + 1)
var dscScalar = DSPDoubleSplitComplex(realp: pRe, imagp: pIm)
vDSP_zvzsmlD(&dsc1, 2, &dscScalar, &dsc2, 2, UInt(n))
}
}
}
}
which seems to work to do:
for i in 1...n { stack[spResult + i] = stack[sp + i] * scalar }
2 Likes