Accelerate Framework in Swift

zRisingSun發表於2020-06-22

介紹:

      最近看到這篇文章有對Accelerate框架有一個介紹,自己也按照作者給的思路整理了一遍,也算是對這一框架的一個重新的回顧和學習,在以前研究AR先關只是的時候有接觸到這個框架,贊具體裡面的東西沒有好好的實踐一下,文章中有一些關於向量和矩陣運算的實際的Swift例子。可以簡單的看一下。

     Introduction to the Accelerate Framework in Swift

     關於這個框架和文章其實在前面介紹iOS框架系列文章的時候有提過(第一篇),對這個框架有不清楚是做什麼的可以翻翻我以前總結的文章。 

     由於下面的運算都是些向量和矩陣的運算,要是不清楚他們的概念和運算規則的可以看下面,先了解清楚再往下看,這些具體的內容在專案當中其實還是會用到的,比如說視訊編碼處理、AR等等。

     向量

     矩陣

 

Accelerate


 

      使用之前請先匯入這兩個框架:

      NOTE: 下面所有的例子全都是在 Playground 執行驗證

import UIKit
import Accelerate
import simd

      1、cblas_saxpy  

      函式cblas_saxpy(_:_:_:_:_:_:)是一個計算常數乘以一個向量加上一個向量的函式,具體的使用看下面的例子:

var x:[Float] = [1,2,3]
var y:[Float] = [4,5,6]

cblas_saxpy(3, 10, &x, 2, &y, 2)

      具體的驗證結果和詳細的函式引數說明我們會在下面展示,大家可以先看上面給出的函式的說明推導一下結果:

      2、cblas_sdot 這個函式能幫助我們計算出兩個向量的數量積:  ∑ a[i] * b[i] 

y = [4,5,6]
/// x*y = (1*4)+(2*5)+(3*6) = 32
/// 這個函式的具體的引數可以參考上面
cblas_sdot(3, &x, 1, &y, 1)

      3、sgesv_ 這個函式可以幫我們解方程,比如下面的三元三次方程,具體的驗證你可以自己嘗試一下,瞭解一下函式的引數的意義,我們已經驗證過就不再重複結果。

/// 下面我們解一個三元方程
/// 7x+5y-3z = 16
/// 3x-5y+2z = -8
/// 5x+3y-7z = 0
typealias LAInt = __CLPK_integer

var A:[Float] = [

    7, 3, 5,   /// x
    5, -5,3,   /// y
    -3,2,-7    /// z
]

var b:[Float] = [16,-8,0]

/// 定義要解的是一個幾元方程
let equations = 3
/// 方程的個數
var numberOfEquations:LAInt = 3
var columnsIntA:LAInt = 3
var elementsIntB:LAInt = 3
/// 解的個數
var bSolutionCount:LAInt = 1
/// 驗證是否計算有問題
var outputOk:LAInt = 0
/// [0,0,0]
var pivot = [LAInt](repeating: 0, count: equations)

/// 引數定義(按順序):求解的線性方程個數、解的個數、係數矩陣A、
/// 矩陣A的列數、排列矩陣、係數向量B、向量B的列數、輸出值。
sgesv_(&numberOfEquations, &bSolutionCount, &A, &columnsIntA, &pivot, &b, &elementsIntB, &outputOk)

/// outputOk == 0 說明一切計算正確
outputOk

/// 這個結果就是我們想要的答案 [1, 3, 2]
b

 

simd + vecLib + vDSP


       

      具體的這三個框架的內容文章中有介紹過,我們這裡主要的還是驗證和實踐一下里面的例子,看下面的程式碼。

      1、矩陣的加法運算,看下面的例子,注意下面的不是向量的加法,留意區別不要混淆,程式碼簡單我直接截圖順便看驗證結果:

       2、vvfabsf 求絕對值的運算,程式碼如下:

/// fabs 求絕對值
func floats(_ n:Int32) -> [Float]{
    return [Float] (repeating: 0, count: Int(n))
}

var count:Int32 = 4
var aAbsoAbsolute = floats(count)

var c:[Float] = [-1,-2,-3,-4]
vvfabsf(&aAbsoAbsolute, &c, &count)

/// [1,2,3,4] 
aAbsoAbsolute

      3、vvintf 小數取整求絕對值

c = [9.987,6.576,-3.345,-4.9]
var bAbsoAbsolute = floats(count)
vvintf(&bAbsoAbsolute, &c, &count)

/// [9, 6, -3, -4]
bAbsoAbsolute

      4、sqrtf 開平方根

/// sqrt 開平方根  sqrtf()
c = [25,16,9,4]
var cAbsoAbsolute = floats(count)
vvsqrtf(&cAbsoAbsolute, &c, &count)

/// [5, 4, 3, 2]
cAbsoAbsolute

      5、分數取逆 這時候是分母和分子互換位置在做計算得來的

/// 分數取逆 這時候是分母和分子互換位置在做計算得來的
var d:[Float] = [1/3,1/5,3/9,4/2]
var dAbsoAbsolute = floats(count)
vvrecf(&dAbsoAbsolute, &d, &count)

/// [3, 5, 3, 0.5]
dAbsoAbsolute

      6、vDSP_vdist 這個例子其實也很有趣的,具體的例子說明可以參考最上面文章的最後一個例子,我們直接看程式碼和驗證的結果,程式碼裡面有比較詳細的說明,還是值得一看的,能幫助我們回憶鞏固一些知識點:

var points:[CGPoint] = [
    
    CGPoint(x: 0, y: 0),
    CGPoint(x: 0, y: 10),
    CGPoint(x: 0, y: 20),
    CGPoint(x: 0, y: 30),
    CGPoint(x: 0, y: 40),
    CGPoint(x: 0, y: 50),
    CGPoint(x: 0, y: 60),
    CGPoint(x: 0, y: 70),
    CGPoint(x: 0, y: 80)
]
 
let path = UIBezierPath()
path.move(to: points[0])
 
// IMP: Remove the space between the < and points
for i in 1 ..< points.count {
    path.addLine(to: points[i])
}

var xs = points.compactMap { (point) -> Float? in
    return Float(point.x)
}

var ys = points.compactMap { (point) -> Float? in
    return Float(point.y)
}

var distance:[Float] = [Float](repeating: 0, count: points.count)

vDSP_vdist(&xs, 1, &ys, 1, &distance,1,vDSP_Length(points.count))

/// 遍歷
distance.map {$0}

/// 順便幫忙在加深一下對 reduce 函式的理解
/// 給一個初始值 然後對集合的每一個元素進行操作
distance.reduce(0, +)

let initialResult:Float = 0
var reduceResult =  distance.reduce(initialResult) { (tempResult,element) -> Float in
    return tempResult + element
}

reduceResult

     下面是上面例子的結果驗證: 

相關文章