Использование поддержки комплексных чисел Accelerate Framework в Swift

Мне нужно выполнить следующие операции в Swift с Accelerate Multiply, Complex Conjugate и Exp. Я уже делал это, используя код Complex Swift от dankogai, но он слишком медленный для работа, которую я делаю. У меня возникли проблемы с созданием рабочей версии с использованием платформы Accelerate, и я надеюсь ускорить свое понимание.

Свифт-код

let frequencyShift = (2 * M_PI * Double(self.centralFrequency) * delays).i / Double(self.samplingFrequencyHertz)
let result = conj(exp(frequencyShift))

delays — это массив примерно из 200 тыс. двойников, и эти строки будут вызываться пару сотен раз. Я преобразовываю их в сложные числа в стиле Swift Complex, а затем вызываю сложные методы exp() и conj() для результата.

Умножить

Комплексное векторно-скалярное умножение двойной точности.

vDSP_zvzsmlD

сопряжение

Комплексно-векторное сопряжение; двойная точность.

vDSP_zvconjD

Есть ли эквивалент exp() в Accelerate и как бы вы реорганизовали этот код для выполнения эквивалентной версии операций Accelerate?


person Cameron Lowell Palmer    schedule 20.01.2016    source источник


Ответы (1)


Общие принципы использования Accelerate with Swift

Я считаю полезным сначала попытаться преобразовать ваш код из наивной реализации с использованием циклов for в карты. Если ваш код структурирован для работы с картами, то переключиться на ускорение становится довольно легко, поскольку вы уже занимались структурированием своего алгоритма в векторизованные операции.

Цикл for для отображения

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
})

Версия для работы с массивами одинакового размера

Если вы обнаружите, что хотите перечислить два или более массива одинакового размера, то приведенное выше может объединить карту с перечислением

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 в Accelerate, но вы можете разбить значения и выполнить необходимую операцию над действительными и мнимыми числами, используя метод Эйлера, показанный ниже, используя библиотеку Complex Swift.

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. Комплексное сопряжение вычисляется просто путем отрицания мнимой части.

person Cameron Lowell Palmer    schedule 22.01.2016
comment
Вау, об устранении malloc/free в Swift стоит знать, я рад, что заглянул в эту тему! - person Maury Markowitz; 15.04.2016