在 Swift 中使用 Accelerate Framework 复数支持
Using Accelerate Framework complex number support in Swift
我需要在 Swift 中使用 Accelerate Multiply、Complex Conjugate 和 Exp 执行以下操作。我已经使用 Complex Swift code by dankogai 完成了此操作,但它对于我正在做的工作来说太慢了。我在使用 Accelerate 框架创建工作版本时遇到问题,我希望能加速我的理解。
Swift代码
let frequencyShift = (2 * M_PI * Double(self.centralFrequency) * delays).i / Double(self.samplingFrequencyHertz)
let result = conj(exp(frequencyShift))
delays
是一个包含大约 200k 个双精度数的数组,这些行将被调用数百次。我将它们转换为复数 a la Swift Complex 样式,然后对结果调用复数 exp() 和 conj() 方法。
乘
双精度复向量标量乘法。
vDSP_zvzsmlD
共轭
复向量共轭;双精度。
vDSP_zvconjD
在 Accelerate 中是否有一个 exp()
等效项?您将如何重新组织此代码以执行等效的 Accelerate'd 操作版本?
将 Accelerate 与 Swift
结合使用的一般原则
我发现首先尝试将您的代码从使用 for-loops 的原始实现转换为映射很有帮助。如果您的代码结构适用于地图,那么切换到加速将变得非常容易,因为您已经解决了将算法结构化为矢量化操作的问题。
For-loop映射
let array: [Int] = [1, 2, 3, 4]
let array2 = [Int]()
for value in array {
array2 = value * 2
}
let array: [Int] = [1, 2, 3, 4]
array.map({ (value: Int) -> Int in
return value * 2
})
在相同大小的数组版本上运行
如果你发现你想枚举两个或更多相同大小的数组那么上面可以结合map和enumerate
let alphas: [Double] = betas.enumerate().map({ (index: Int, beta: Double) -> Double in
return beta * phis[index]
})
设置阵列以用于 Accelerate
使用 Accelerate 的方式并不总是显而易见的,特别是 UnsafePointer
和 UnsafeMutablePointer
语法。这基本上是没有必要的。
var alphaLowers = [Double](count: elementDelays.count, repeatedValue: 0)
vDSP_vmulD(&alphas, 1, &x_ns, 1, &alphaLowers, 1, UInt(elementDelays.count))
因此 Swift 允许您创建一个自动内存管理对象,然后简单地将它与符号一起传递,从而避免了 malloc 和 free 的麻烦。我提到这一点是因为它避免了尝试在 UnsafeMutablePointer<Double>(alphaLowers)
.
中包装对象之类的事情
复数
我想做的大部分事情都依赖于涉及复数的运算。因此,要创建一个可以在 Accelerate 中使用的对象,您可以尝试以下操作。
var reals = [Double](count: 100, repeatedValue: 0)
var imaginaries = [Double](count: 100, repeatedValue: 0)
var complexNumbers = DSPDoubleSplitComplex(realp: &reals, imagp: &imaginaries)
复数 exp()
我没有找到 exp 的 Accelerate 等价物,但您可以分解这些值并使用 Complex Swift 库使用下面说明的 Euler 方法对实数和虚数执行必要的操作。
public func exp<T:RealType>(z:Complex<T>) -> Complex<T> {
let r = T.exp(z.re)
let a = z.im
return Complex(r * T.cos(a), r * T.sin(a))
}
我还没有找到避免这个问题的好方法,所以我实际上在没有使用 Accelerate 的情况下执行了这一步。只需将虚部取负即可计算出复共轭。
我需要在 Swift 中使用 Accelerate Multiply、Complex Conjugate 和 Exp 执行以下操作。我已经使用 Complex Swift code by dankogai 完成了此操作,但它对于我正在做的工作来说太慢了。我在使用 Accelerate 框架创建工作版本时遇到问题,我希望能加速我的理解。
Swift代码
let frequencyShift = (2 * M_PI * Double(self.centralFrequency) * delays).i / Double(self.samplingFrequencyHertz)
let result = conj(exp(frequencyShift))
delays
是一个包含大约 200k 个双精度数的数组,这些行将被调用数百次。我将它们转换为复数 a la Swift Complex 样式,然后对结果调用复数 exp() 和 conj() 方法。
乘
双精度复向量标量乘法。
vDSP_zvzsmlD
共轭
复向量共轭;双精度。
vDSP_zvconjD
在 Accelerate 中是否有一个 exp()
等效项?您将如何重新组织此代码以执行等效的 Accelerate'd 操作版本?
将 Accelerate 与 Swift
结合使用的一般原则我发现首先尝试将您的代码从使用 for-loops 的原始实现转换为映射很有帮助。如果您的代码结构适用于地图,那么切换到加速将变得非常容易,因为您已经解决了将算法结构化为矢量化操作的问题。
For-loop映射
let array: [Int] = [1, 2, 3, 4]
let array2 = [Int]()
for value in array {
array2 = value * 2
}
let array: [Int] = [1, 2, 3, 4]
array.map({ (value: Int) -> Int in
return value * 2
})
在相同大小的数组版本上运行
如果你发现你想枚举两个或更多相同大小的数组那么上面可以结合map和enumerate
let alphas: [Double] = betas.enumerate().map({ (index: Int, beta: Double) -> Double in
return beta * phis[index]
})
设置阵列以用于 Accelerate
使用 Accelerate 的方式并不总是显而易见的,特别是 UnsafePointer
和 UnsafeMutablePointer
语法。这基本上是没有必要的。
var alphaLowers = [Double](count: elementDelays.count, repeatedValue: 0)
vDSP_vmulD(&alphas, 1, &x_ns, 1, &alphaLowers, 1, UInt(elementDelays.count))
因此 Swift 允许您创建一个自动内存管理对象,然后简单地将它与符号一起传递,从而避免了 malloc 和 free 的麻烦。我提到这一点是因为它避免了尝试在 UnsafeMutablePointer<Double>(alphaLowers)
.
复数
我想做的大部分事情都依赖于涉及复数的运算。因此,要创建一个可以在 Accelerate 中使用的对象,您可以尝试以下操作。
var reals = [Double](count: 100, repeatedValue: 0)
var imaginaries = [Double](count: 100, repeatedValue: 0)
var complexNumbers = DSPDoubleSplitComplex(realp: &reals, imagp: &imaginaries)
复数 exp()
我没有找到 exp 的 Accelerate 等价物,但您可以分解这些值并使用 Complex Swift 库使用下面说明的 Euler 方法对实数和虚数执行必要的操作。
public func exp<T:RealType>(z:Complex<T>) -> Complex<T> {
let r = T.exp(z.re)
let a = z.im
return Complex(r * T.cos(a), r * T.sin(a))
}
我还没有找到避免这个问题的好方法,所以我实际上在没有使用 Accelerate 的情况下执行了这一步。只需将虚部取负即可计算出复共轭。