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

Reply via email to