在类

时间:2016-11-13 17:07:46

标签: swift protocols signal-processing

我一直在研究有关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类的前几行。

1 个答案:

答案 0 :(得分:2)

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

    // ...
}

使用Swift标准中的stride()方法 库。