That seems to work well, thanks! > On Nov 22, 2016, at 16:59 , Hooman Mehr <hoo...@mac.com> wrote: > > By the way, even without new Swift 3.1 feature, this works, providing > optimized sum function for all three types: > > extension ContiguousBufferedArray where Iterator.Element == Double { > > func sum() -> Double { > > var result = Double() > withUnsafeBufferPointer { vDSP_sveD($0.baseAddress!, 1, &result, > numericCast(count)) } > return result > } > } > > extension ContiguousBufferedArray where Iterator.Element == Float { > > func sum() -> Float { > > var result = Float() > withUnsafeBufferPointer { vDSP_sve($0.baseAddress!, 1, &result, > numericCast(count)) } > return result > } > } > > >> On Nov 22, 2016, at 4:56 PM, Rick Mann <rm...@latencyzero.com> wrote: >> >> Thanks! It's all very educational, at the least. >> >> Obviously the ideal would be for LLVM to recognize and optimize (there are >> many ways to write the sum of an array), but this is cool. >> >>> On Nov 22, 2016, at 16:50 , Hooman Mehr <hoo...@mac.com> wrote: >>> >>> For example, this reduces the six variants of sum to two: >>> >>> public protocol ContiguousBufferedArray: RandomAccessCollection { >>> >>> func withUnsafeBufferPointer<R>(_ body: >>> (UnsafeBufferPointer<Iterator.Element>) throws -> R) rethrows -> R >>> } >>> >>> extension Array: ContiguousBufferedArray {} >>> extension ContiguousArray: ContiguousBufferedArray {} >>> extension ArraySlice: ContiguousBufferedArray {} >>> >>> func sum<A>(_ array: A) -> Double where A: ContiguousBufferedArray, >>> A.Iterator.Element == Double { >>> var result = Double() >>> array.withUnsafeBufferPointer { vDSP_sveD($0.baseAddress!, 1, &result, >>> numericCast(array.count)) } >>> return result >>> } >>> >>> func sum<A>(_ array: A) -> Float where A: ContiguousBufferedArray, >>> A.Iterator.Element == Float { >>> var result = Float() >>> array.withUnsafeBufferPointer { vDSP_sve($0.baseAddress!, 1, &result, >>> numericCast(array.count)) } >>> return result >>> } >>> >>> I have to think a bit more to see what common API we can extract from array >>> that can be generally useful. I will put up a pic on evolution once I get a >>> clearer idea. >>> >>>> On Nov 22, 2016, at 4:46 PM, Rick Mann <rm...@latencyzero.com> wrote: >>>> >>>> That sounds interesting. Would you mind making that pitch on >>>> swift-evolution? I just barely understood what you said :/ >>>> >>>>> On Nov 22, 2016, at 07:46 , Hooman Mehr <hoo...@mac.com> wrote: >>>>> >>>>> 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 >>>>>> >>>>>> >>>>> >>>> >>>> >>>> -- >>>> Rick Mann >>>> rm...@latencyzero.com >>>> >>>> >>> >> >> >> -- >> Rick Mann >> rm...@latencyzero.com >> >> >
-- Rick Mann rm...@latencyzero.com _______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users