> On 23 Nov 2016, at 01:50, Hooman Mehr via swift-users <swift-users@swift.org> 
> 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.


DaveA mentioned at the start of the month that they were looking at ways to 
allow better contiguous memory optimisations (including vectorisation).

> If you think about what it means to build APIs for contiguous memory
> into abstractions like Sequence or Collection, at least without
> penalizing the lowest-level code, it means exposing UnsafeBufferPointers
> as a first-class part of the protocols, which is really
> unappealing... unless you consider that *borrowed* UnsafeBufferPointers
> can be made safe.

https://www.mail-archive.com/swift-evolution@swift.org/msg18395.html 
<https://www.mail-archive.com/swift-evolution@swift.org/msg18395.html>

- Karl

> 
>> On Nov 22, 2016, at 4:46 PM, Rick Mann <rm...@latencyzero.com 
>> <mailto: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 
>>> <mailto: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 
>>>> <mailto: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 
>>>>> <mailto: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 <mailto: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 <mailto:rm...@latencyzero.com>
>>>>>> 
>>>>>> 
>>>>>> _______________________________________________
>>>>>> swift-users mailing list
>>>>>> swift-users@swift.org
>>>>>> https://lists.swift.org/mailman/listinfo/swift-users
>>>>> 
>>>> 
>>>> 
>>>> -- 
>>>> Rick Mann
>>>> rm...@latencyzero.com <mailto:rm...@latencyzero.com>
>>>> 
>>>> 
>>> 
>> 
>> 
>> -- 
>> Rick Mann
>> rm...@latencyzero.com <mailto:rm...@latencyzero.com>
>> 
>> 
> 
> _______________________________________________
> swift-users mailing list
> swift-users@swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to