It is good to know that extension Array where Element == Double { } will work pretty soon with Swift 3.1.
Back to reduce(0,+): If we get specialized instance for a reduce(0,+), so that it is known that “+” is a (Double, Double)->Double function, LLVM’s auto-vectorization should be able to optimize it for the CPU’s vector unit. In theory, it should be possible to add additional optimizers to LLVM layer to use other hardware or numeric libraries for that purpose, but I don’t think it would be a Swift-specific thing. Swift’s generics still has a long way to go. Since they are aiming for ABI stability by Swift 4.0, and there isn’t much time left, I don’t think many of the bigger generics improvements fit with the current Swift evolution discussions, although they could have huge impact on standard library (hence the ABI stability). One thing that might be worth discussing on Swift evolution and can potentially make it to standard library and Swift 4.0 is adding a common protocol for array-like types that have (or can have) contiguous buffers so that manually vectorizing operations on their elements becomes easier and cleaner. At the moment, we can manually define a protocol that extends RandomAccessCollection and provides `withUnsafeBufferPointer` and then declare the conformance of all of the standard library array variants to it so that we can provide a single generic sum global function for summing all of them using vDSP. This protocol may be worth adding to the standard library. > On Nov 21, 2016, at 7:05 PM, Rick Mann <rm...@latencyzero.com> wrote: > > Thanks, Hooman. Is it worth posting on swift-evolution the question about > specializing something like reduce(0, +) (it's complicated because it would > mean specializing reduce() based on both the type and the closure passed, and > that seems like something that would be difficult to specify concisely in the > syntax). > >> On Nov 21, 2016, at 18:29 , Hooman Mehr <hoo...@mac.com> wrote: >> >> This is not possible in Swift 3.0. Swift 4.0 will improve things with >> conditional conformances. >> >> For now, the best solution is using global functions instead of extending >> types or protocols. >> >> For example you can do this now: >> >> extension Array where Element: FloatingPoint { >> >> func sum() -> Element { >> guard count > 0 else { return 0 } >> switch self[0] { >> case is Double: >> var result = Double() >> vDSP_sveD(unsafeBitCast(self, to: Array<Double>.self), 1, >> &result, vDSP_Length(count)) >> print("vDSP") >> return unsafeBitCast(result, to: Element.self) >> case is Float: >> var result = Float() >> vDSP_sve(unsafeBitCast(self, to: Array<Float>.self), 1, &result, >> vDSP_Length(count)) >> print("vDSP") >> return unsafeBitCast(result, to: Element.self) >> default: >> print("default") >> return reduce(0, +) >> } >> } >> } >> >> But this is not very efficient, especially if it is defined in another >> module, which limits optimizations. >> >> Instead, a family of overloaded global functions gives you the most coverage >> and best performance, at the expense of repetition and boilerplate code: >> >> func sum<S: Sequence>(_ sequence: S) -> S.Iterator.Element where >> S.Iterator.Element: Integer { >> var result: S.Iterator.Element = 0 >> for element in sequence { result += element } >> return result >> } >> >> func sum<S: Sequence>(_ sequence: S) -> S.Iterator.Element where >> S.Iterator.Element: FloatingPoint { >> var result: S.Iterator.Element = 0 >> for element in sequence { result += element } >> return result >> } >> >> func sum(_ array: Array<Double>) -> Double { >> var result = Double() >> vDSP_sveD(array, 1, &result, vDSP_Length(array.count)) >> return result >> } >> >> func sum(_ array: ContiguousArray<Double>) -> Double { >> var result = Double() >> array.withUnsafeBufferPointer { vDSP_sveD($0.baseAddress!, 1, &result, >> vDSP_Length(array.count)) } >> return result >> } >> >> func sum(_ array: ArraySlice<Double>) -> Double { >> var result = Double() >> array.withUnsafeBufferPointer { vDSP_sveD($0.baseAddress!, 1, &result, >> vDSP_Length(array.count)) } >> return result >> } >> >> func sum(_ array: Array<Float>) -> Float { >> var result = Float() >> vDSP_sve(array, 1, &result, vDSP_Length(array.count)) >> return result >> } >> >> func sum(_ array: ContiguousArray<Float>) -> Float { >> var result = Float() >> array.withUnsafeBufferPointer { vDSP_sve($0.baseAddress!, 1, &result, >> vDSP_Length(array.count)) } >> return result >> } >> >> func sum(_ array: ArraySlice<Float>) -> Float { >> var result = Float() >> array.withUnsafeBufferPointer { vDSP_sve($0.baseAddress!, 1, &result, >> vDSP_Length(array.count)) } >> return result >> } >> >> The above code covers summing any integer or floating point sequence of >> numbers, while being accelerated for Float and Double array types (Array, >> ContiguousArray and ArraySlice) >> >> >>> On Nov 21, 2016, at 4:32 PM, Rick Mann via swift-users >>> <swift-users@swift.org> wrote: >>> >>> My googling is not turning up an answer that works in Xcode 8.1. I'd like >>> to do this: >>> >>> >>> import Accelerate >>> >>> extension >>> Array >>> where Element == Double >>> { >>> func >>> sum() >>> -> Double >>> { >>> var result: Double = 0.0 >>> vDSP_sveD(self, 1, &result, vDSP_Length(self.count)) >>> return result >>> } >>> } >>> >>> But I get "same-type requirement makes generic parameter 'Element' >>> non-generic." >>> >>> Also, will there ever be any way to specialize something like >>> >>> let numbers: [Double] = ... >>> let sum = numbers.reduce(0.0, +) >>> >>> Into a call to vDSP_sveD()? Would it require compiler optimizations for >>> Accelerate? >>> >>> Thanks! >>> >>> -- >>> Rick Mann >>> rm...@latencyzero.com >>> >>> >>> _______________________________________________ >>> swift-users mailing list >>> swift-users@swift.org >>> https://lists.swift.org/mailman/listinfo/swift-users >> > > > -- > Rick Mann > rm...@latencyzero.com > > _______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users