2016-11-13 48 views
1

我一直在學習有關Accelerate框架的知識,並且正在寫一個Vector類以配合我的學習經驗。我決定我需要實現序列協議,並且在幾次錯誤的開始和大量搜索我的問題的相關信息之後,終於找到了一個似乎可行的解決方案。不知道我的解決方案是否合適,如果有更好的方法可以做到這一點,我們希望評論。目前的代碼有點長,但不是超長的,所以我會在這裏發佈。在一個類中正確實現序列協議

import Foundation 
import Accelerate 

public class Vdsp{ 
public class VectorD: Sequence, IteratorProtocol { 
    var vindex = 0 

    public func makeIterator() -> Double? { 
     return next() 
    } 
    public func next() -> Double? { 
     let nextIndex = self.vindex * self.s + self.o 
     guard self.vindex < self.l && nextIndex < self.count 
      else { 
       self.vindex = 0 
       return nil 
     } 
     self.vindex += 1 
     return self.data[nextIndex] 
    } 

    public let count : Int 
    fileprivate var l: Int 
    fileprivate var o: Int 
    fileprivate var s: Int 
    public var length : Int { 
     get { 
      return self.l 
     } 
     set (value){ 
      let l = (value - 1) * self.s + self.o 
      if l < 0 || l >= self.count { 
       preconditionFailure("length exceeds vector boundary") 
      } 
      self.l = value 
     } 
    } 
    public var stride : Int { 
     get { 
      return self.s 
     } 
     set (value){ 
      let l = (self.l - 1) * value + self.o 
      if l < 0 || l >= self.count { 
       preconditionFailure("stride will cause vector to exceed vector boundary") 
      } 
      self.s = value 
     } 
    } 
    public var offset : Int { 
     get { 
      return self.o 
     } 
     set (value){ 
      let l = (self.l - 1) * self.s + value 
      if l < 0 || l >= self.count { 
       preconditionFailure("stride will cause vector to exceed vector boundary") 
      } 
      self.o = value 
     } 
    } 
    // length * stride + offset >= 0 and <= count 
    public var data : Array<Double> 
    public init(length: Int){ 
     self.count = length 
     self.l = length 
     self.s = 1 
     self.o = 0 
     data = Array(repeating: 0.0, count: count) 
    } 
    // MARK: - Utility functions 
    public var empty : VectorD { // Create a new vector unit stride, zero offset 
     get{ 
      return VectorD(length: length) 
     } 
    } 
    public func display(decimals: Int) -> String { 
     let fmt = String("%0." + String(decimals) + "f\n") 
     var aString = "" 
     for i in 0..<length { 
      aString += String(format: fmt!, self.data[offset + i * stride]) 
     } 
     return aString 
    } 
    // MARK: - Subscripts and Operators 
    public subscript(index: Int) -> Double { 
     get { 
      if index > length { 
       preconditionFailure("index \(index) out of bounds") 
      } else { 
       return data[self.offset + index * self.stride] 
      } 
     } 
     set(newValue) { 
      if index > self.length { 
       preconditionFailure("index \(index) out of bounds") 
      } else { 
       self.data[self.offset + index * self.stride] = newValue 
      } 
     } 
    } 


    public static func + (left: VectorD, right: VectorD) -> VectorD { 
     return Vdsp.add(left, right) 
    } 
    public static func + (left: Double, right: VectorD) -> VectorD { 
     return Vdsp.add(left, right) 
    } 
    public static func + (left: VectorD, right: Double) -> VectorD { 
     return Vdsp.add(right, left) 
    } 
    public static func * (left: VectorD, right: VectorD) -> VectorD { 
     return Vdsp.mul(left, right) 
    } 
    public static func * (left: Double, right: VectorD) -> VectorD { 
     return Vdsp.mul(left, right) 
    } 
    public static func * (left: VectorD, right: Double) -> VectorD { 
     return Vdsp.mul(right, left) 
    } 

    // MARK: - vDSP routines as methods of VectorD 
    public func fill(value: Double){ 
     var v = value 
     vDSP_vfillD(&v, &data + offset, stride, vDSP_Length(length)) 
    } 
    public func ramp(start: Double, increment: Double){ 
     var s = start 
     var i = increment 
     vDSP_vrampD(&s, &i, &data + offset, stride, vDSP_Length(length)) 
    } 
    public var sumval : Double { 
     get { 
      var s : Double = 0.0 
      vDSP_sveD(&data + offset, stride, &s, vDSP_Length(length)) 
      return s 
     } 
    } 

} 
// MARK: - vDSP routines as class functions of Vdsp 
public static func add(_ v1: VectorD, _ v2: VectorD) -> VectorD { 
    let v3 = v1.empty 
    vDSP_vaddD(&v1.data + v1.offset, v1.stride, &v2.data + v2.offset , v2.stride, &v3.data, 1, vDSP_Length(v3.length)) 
    return v3 
} 
public static func add(_ s: Double, _ v: VectorD) -> VectorD { 
    var sdta = s 
    let r = v.empty 
    vDSP_vsaddD(&v.data + v.offset, v.stride, &sdta, &r.data, 1, vDSP_Length(v.length)) 
    return r 
} 

public static func mul(_ v1: VectorD, _ v2: VectorD) -> VectorD { 
    let v3 = v1.empty 
    vDSP_vmulD(&v1.data + v1.offset, v1.stride, &v2.data + v2.offset, v2.stride, &v3.data, 1, vDSP_Length(v3.length)) 
    return v3 
} 
public static func mul(_ s: Double, _ v: VectorD) -> VectorD { 
    var sdta = s 
    let r = v.empty 
    vDSP_vsmulD(&v.data + v.offset, v.stride, &sdta, &r.data, 1, vDSP_Length(v.length)) 
    return r 
    } 
} 

我與

//: Playground for Accelerate 

import UIKit 

let V = Vdsp.VectorD(length: 10);V.ramp(start: 0.1, increment: 0.2) 
print("Vector V after ramp(0.1,0.2)");print(V.display(decimals: 3)) 
V.length = 4 
V.stride = 2 
V.offset = 1 
print("Vector V after attribute modification") 
print(V.display(decimals: 3)) 
let Q = V.empty 
Q.ramp(start: 1.0, increment: 1.0) 
print("Vector Q after ramp(1.0,1.0)");print(Q.display(decimals: 3)) 
print("V * Q"); var R = V * Q 
for i in 0..<V.length { 
    print("\(V[i]) * \(Q[i]) = \(R[i])") 
} 
R = V + Q; print("V + Q = R") 
for i in 0..<V.length { 
    print("\(V[i]) + \(Q[i]) = \(R[i])") 
} 
print("\n") 
for item in V.data { 
    print(item) 
} 
print("\n") 
for item in V { 
    print(item) 
} 

print("\n") 
V.offset = 3 
for item in V { 
    print(item) 
} 

行使這一點,我似乎得到正確的輸出。 Sequence協議位於VectorD類的前幾行。

回答

0

您的Sequence協議的實施不正確。

首先,你的makeIterator()方法並不因爲它的簽名錯誤, 它不會返回Iterator使用。 (您可以在不改變任何內容的情況下從代碼中刪除該函數)。遍歷向量元素的工作原理 ,因爲對於所有聲明符合Sequence的 迭代器,默認實現爲makeIterator()

其次,您的next()方法使用實例變量vindex ,它在到達迭代結束後重置爲零。 換句話說,假定全部元素在 再次迭代相同的向量之前被檢索。這給了意想不到的輸出:

let V = Vdsp.VectorD(length: 10) 
V.ramp(start: 1.0, increment: 1.0) 

print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0] 
print(Array(V.prefix(4))) // [5.0, 6.0, 7.0, 8.0] 
print(Array(V.prefix(4))) // [9.0, 10.0] 
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0] 

這裏是一個可能的實現Sequence協議:

public class VectorD: Sequence { 

    public func makeIterator() -> AnyIterator<Double> { 
     var vindex = 0 
     return AnyIterator { 
      let nextIndex = vindex * self.s + self.o 
      guard vindex < self.l && nextIndex < self.count else { 
       return nil 
      } 
      vindex += 1 
      return self.data[nextIndex] 
     } 
    } 

    // ... 

} 

注意vindex現在的makeIterator() 一個局部變量,並通過關閉抓獲。再次 調用makeIterator()從一開始,即使前面的迭代並 無法檢索的所有元素將啓動:使用stride()方法從雨燕標準 庫

print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0] 
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0] 

另一種可能的實現是

public class VectorD: Sequence { 

    public func makeIterator() -> AnyIterator<Double> { 
     let upperBound = Swift.min(count, o + l * s) 
     let it = Swift.stride(from: o, to: upperBound, by: s) 
      .lazy.map { self.data[$0] }.makeIterator() 
     return AnyIterator(it) 
    } 

    // ... 
}