如何使用 vDSP 集成 Swift

How to integrate in Swift using vDSP

我试图找到 SciPy's cumtrapz function function in Swift. I found something called vDSP_vtrapzD 的替代品,但我不知道如何使用它。这是我到目前为止所做的:

import Accelerate
var f1: [Double] = [<some data>]
var tdata: [Double] = [<time vector>]
var output = [Double](unsafeUninitializedCapacity:Int(f1.count), initializingWith: {_, _ in})

vDSP_vtrapzD(&f1, 1, &tdata, &output, 1, vDSP_Length(f1.count))

你很接近,但你使用 Array.init(unsafeUninitializedCapacity:initializingWith:) 不正确。来自 its documentation:

Discussion

Inside the closure, set the initializedCount parameter to the number of elements that are initialized by the closure. The memory in the range buffer[0..<initializedCount] must be initialized at the end of the closure’s execution, and the memory in the range buffer[initializedCount...] must be uninitialized. This postcondition must hold even if the initializer closure throws an error.

这个 API 比 Array.init(repeating:count:) 更不安全(但性能更高),它分配一个固定大小的数组,并花时间初始化它的所有内容)。这有两个潜在的缺点:

  • 如果数组的目的是提供一个缓冲区来写入结果,那么在此之前对其进行初始化是多余且浪费的

  • 如果您放入该缓冲区的结果最终大于您的 数组,你需要记住手动“trim”多余的部分 将其复制到新数组中。

Array.init(unsafeUninitializedCapacity:initializingWith:) 通过以下方式对此进行了改进:

  • 询问您可能需要的最大容量
  • 给你一个临时缓冲区的容量
    • 重要的是,它未初始化。这使它更快,但如果使用不当也更危险(buffer underflow errors 的风险)。
    • 然后您准确地告诉它您实际上使用了多少临时缓冲区
    • 它会自动将那么多的缓冲区复制到最终数组中,return 结果就是如此。

您正在使用 Array.init(unsafeUninitializedCapacity:initializingWith:),就好像它是 Array.init(repeating:count:)。要正确使用它,您可以将初始化逻辑放在 initializer 参数中,如下所示:

let result = Array<Double>(unsafeUninitializedCapacity: f1.count, initializingWith: { resultBuffer, count in
    assert(f1.count == tdata.count)
    
    vDSP_vtrapzD(
        &f1,                       // Double-precision real input vector.
        1,                         // Address stride for A.
        &tdata,                    // Pointer to double-precision real input scalar: step size.
        resultBuffer.baseAddress!, // Double-precision real output vector.
        1,                         // Address stride for C.
        vDSP_Length(f1.count)      // The number of elements to process.,
    )
    
    count = f1.count // This tells Swift how many elements of the buffer to copy into the resultant Array
})

仅供参考,您可以在此处看到 vDSP_vtrapzD 的一个很好的 Swift 版本:https://developer.apple.com/documentation/accelerate/vdsp/integration_functions。 returns 结果使用 unsafeUninitializedCapacity 初始值设定项的变体。

在相关说明中,还有一个很好的 Swift API 到 Quadrature:https://developer.apple.com/documentation/accelerate/quadrature-smu

西蒙