2016-11-13 4 views
1

Я работаю над тем, чтобы узнать что-то о ракурсе Accelerate, и я пишу класс Vector, чтобы согласиться с моим опытом обучения. Я решил, что мне нужно реализовать протокол Sequence и после нескольких ложных запусков и многого поиска релевантной информации для моей проблемы, наконец, придумал решение, которое, похоже, работает. Не уверен, что мое решение является правильным или нет, и хотел бы прокомментировать, если есть лучшие способы сделать это. Текущий код немного длинный, но не супер длинный, поэтому я отправлю его здесь.Правильная реализация протокола последовательности в классе

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. (Вы можете удалить эту функцию из своего кода, ничего не меняя.) Итерация над векторными элементами работает , потому что есть реализация по умолчанию makeIterator() для всех итераторов , которые объявлены в соответствии с Sequence.

Во-вторых, ваш метод 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() снова начнется с самого начала, даже если предыдущая итерация сделал не извлечь все элементы:

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

    // ... 
} 

с использованием метода stride() от стандартной библиотеки Swift ,

Смежные вопросы