<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 23 Nov 2016, at 01:50, Hooman Mehr via swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">For example, this reduces the six variants of sum to two:<div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">public</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">protocol</span><span style="font-variant-ligatures: no-common-ligatures" class=""> ContiguousBufferedArray: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">RandomAccessCollection</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><br class="webkit-block-placeholder"></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> withUnsafeBufferPointer<R>(</span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">_</span><span style="font-variant-ligatures: no-common-ligatures" class=""> body: (</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">UnsafeBufferPointer</span><span style="font-variant-ligatures: no-common-ligatures" class=""><Iterator.Element>) </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">throws</span><span style="font-variant-ligatures: no-common-ligatures" class=""> -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">R</span><span style="font-variant-ligatures: no-common-ligatures" class="">) </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">rethrows</span><span style="font-variant-ligatures: no-common-ligatures" class=""> -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">R</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(79, 129, 135);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">extension</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Array</span><span style="font-variant-ligatures: no-common-ligatures;" class="">: </span><span style="font-variant-ligatures: no-common-ligatures" class="">ContiguousBufferedArray</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> {}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(79, 129, 135);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">extension</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">ContiguousArray</span><span style="font-variant-ligatures: no-common-ligatures;" class="">: </span><span style="font-variant-ligatures: no-common-ligatures" class="">ContiguousBufferedArray</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> {}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(79, 129, 135);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">extension</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">ArraySlice</span><span style="font-variant-ligatures: no-common-ligatures;" class="">: </span><span style="font-variant-ligatures: no-common-ligatures" class="">ContiguousBufferedArray</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> {}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> sum<A>(</span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">_</span><span style="font-variant-ligatures: no-common-ligatures" class=""> array: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">A</span><span style="font-variant-ligatures: no-common-ligatures" class="">) -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Double</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">where</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">A</span><span style="font-variant-ligatures: no-common-ligatures" class="">: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">ContiguousBufferedArray</span><span style="font-variant-ligatures: no-common-ligatures" class="">, </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">A</span><span style="font-variant-ligatures: no-common-ligatures" class="">.Iterator.Element == </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Double</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">var</span><span style="font-variant-ligatures: no-common-ligatures" class=""> result = </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Double</span><span style="font-variant-ligatures: no-common-ligatures" class="">()</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> array.</span><span style="font-variant-ligatures: no-common-ligatures; color: #31595d" class="">withUnsafeBufferPointer</span><span style="font-variant-ligatures: no-common-ligatures" class=""> { </span><span style="font-variant-ligatures: no-common-ligatures; color: #3e1e81" class="">vDSP_sveD</span><span style="font-variant-ligatures: no-common-ligatures" class="">($0.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">baseAddress</span><span style="font-variant-ligatures: no-common-ligatures" class="">!, </span><span style="font-variant-ligatures: no-common-ligatures; color: #272ad8" class="">1</span><span style="font-variant-ligatures: no-common-ligatures" class="">, &result, </span><span style="font-variant-ligatures: no-common-ligatures; color: #3e1e81" class="">numericCast</span><span style="font-variant-ligatures: no-common-ligatures" class="">(array.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">count</span><span style="font-variant-ligatures: no-common-ligatures" class="">)) }</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> result</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> sum<A>(</span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">_</span><span style="font-variant-ligatures: no-common-ligatures" class=""> array: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">A</span><span style="font-variant-ligatures: no-common-ligatures" class="">) -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Float</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">where</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">A</span><span style="font-variant-ligatures: no-common-ligatures" class="">: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">ContiguousBufferedArray</span><span style="font-variant-ligatures: no-common-ligatures" class="">, </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">A</span><span style="font-variant-ligatures: no-common-ligatures" class="">.Iterator.Element == </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Float</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">var</span><span style="font-variant-ligatures: no-common-ligatures" class=""> result = </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Float</span><span style="font-variant-ligatures: no-common-ligatures" class="">()</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> array.</span><span style="font-variant-ligatures: no-common-ligatures; color: #31595d" class="">withUnsafeBufferPointer</span><span style="font-variant-ligatures: no-common-ligatures" class=""> { </span><span style="font-variant-ligatures: no-common-ligatures; color: #3e1e81" class="">vDSP_sve</span><span style="font-variant-ligatures: no-common-ligatures" class="">($0.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">baseAddress</span><span style="font-variant-ligatures: no-common-ligatures" class="">!, </span><span style="font-variant-ligatures: no-common-ligatures; color: #272ad8" class="">1</span><span style="font-variant-ligatures: no-common-ligatures" class="">, &result, </span><span style="font-variant-ligatures: no-common-ligatures; color: #3e1e81" class="">numericCast</span><span style="font-variant-ligatures: no-common-ligatures" class="">(array.</span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">count</span><span style="font-variant-ligatures: no-common-ligatures" class="">)) }</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #ba2da2" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> result</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class="">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.</span></div></div></div></div></blockquote><div><br class=""></div><div><br class=""></div><div>DaveA mentioned at the start of the month that they were looking at ways to allow better contiguous memory optimisations (including vectorisation).</div><div><br class=""></div><div><blockquote type="cite" class=""><pre style="font-family: courier, 'courier new', monospace; font-size: 14px; white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 0px;" class="">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.</pre></blockquote><div class=""><br class=""></div><div class=""><a href="https://www.mail-archive.com/swift-evolution@swift.org/msg18395.html" class="">https://www.mail-archive.com/swift-evolution@swift.org/msg18395.html</a></div><div class=""><br class=""></div><div class="">- Karl</div></div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div class=""><blockquote type="cite" class=""><div class="">On Nov 22, 2016, at 4:46 PM, Rick Mann <<a href="mailto:rmann@latencyzero.com" class="">rmann@latencyzero.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">That sounds interesting. Would you mind making that pitch on swift-evolution? I just barely understood what you said :/<br class=""><br class=""><blockquote type="cite" class="">On Nov 22, 2016, at 07:46 , Hooman Mehr <<a href="mailto:hooman@mac.com" class="">hooman@mac.com</a>> wrote:<br class=""><br class="">It is good to know that <br class=""><br class="">extension Array where Element == Double { }<br class=""><br class="">will work pretty soon with Swift 3.1.<br class=""><br class="">Back to reduce(0,+):<br class=""><br class="">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.<br class=""><br class="">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). <br class=""><br class="">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.<br class=""><br class="">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.<br class=""><br class=""><blockquote type="cite" class="">On Nov 21, 2016, at 7:05 PM, Rick Mann <<a href="mailto:rmann@latencyzero.com" class="">rmann@latencyzero.com</a>> wrote:<br class=""><br class="">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).<br class=""><br class=""><blockquote type="cite" class="">On Nov 21, 2016, at 18:29 , Hooman Mehr <<a href="mailto:hooman@mac.com" class="">hooman@mac.com</a>> wrote:<br class=""><br class="">This is not possible in Swift 3.0. Swift 4.0 will improve things with conditional conformances.<br class=""><br class="">For now, the best solution is using global functions instead of extending types or protocols.<br class=""><br class="">For example you can do this now:<br class=""><br class="">extension Array where Element: FloatingPoint {<br class=""><br class=""> func sum() -> Element {<br class=""> guard count > 0 else { return 0 }<br class=""> switch self[0] {<br class=""> case is Double:<br class=""> var result = Double()<br class=""> vDSP_sveD(unsafeBitCast(self, to: Array<Double>.self), 1, &result, vDSP_Length(count))<br class=""> print("vDSP")<br class=""> return unsafeBitCast(result, to: Element.self)<br class=""> case is Float:<br class=""> var result = Float()<br class=""> vDSP_sve(unsafeBitCast(self, to: Array<Float>.self), 1, &result, vDSP_Length(count))<br class=""> print("vDSP")<br class=""> return unsafeBitCast(result, to: Element.self)<br class=""> default:<br class=""> print("default")<br class=""> return reduce(0, +)<br class=""> }<br class=""> }<br class="">}<br class=""><br class="">But this is not very efficient, especially if it is defined in another module, which limits optimizations.<br class=""><br class="">Instead, a family of overloaded global functions gives you the most coverage and best performance, at the expense of repetition and boilerplate code:<br class=""><br class="">func sum<S: Sequence>(_ sequence: S) -> S.Iterator.Element where S.Iterator.Element: Integer {<br class=""> var result: S.Iterator.Element = 0<br class=""> for element in sequence { result += element }<br class=""> return result<br class="">}<br class=""><br class="">func sum<S: Sequence>(_ sequence: S) -> S.Iterator.Element where S.Iterator.Element: FloatingPoint {<br class=""> var result: S.Iterator.Element = 0<br class=""> for element in sequence { result += element }<br class=""> return result<br class="">}<br class=""><br class="">func sum(_ array: Array<Double>) -> Double {<br class=""> var result = Double()<br class=""> vDSP_sveD(array, 1, &result, vDSP_Length(array.count))<br class=""> return result<br class="">}<br class=""><br class="">func sum(_ array: ContiguousArray<Double>) -> Double {<br class=""> var result = Double()<br class=""> array.withUnsafeBufferPointer { vDSP_sveD($0.baseAddress!, 1, &result, vDSP_Length(array.count)) }<br class=""> return result<br class="">}<br class=""><br class="">func sum(_ array: ArraySlice<Double>) -> Double {<br class=""> var result = Double()<br class=""> array.withUnsafeBufferPointer { vDSP_sveD($0.baseAddress!, 1, &result, vDSP_Length(array.count)) }<br class=""> return result<br class="">}<br class=""><br class="">func sum(_ array: Array<Float>) -> Float {<br class=""> var result = Float()<br class=""> vDSP_sve(array, 1, &result, vDSP_Length(array.count))<br class=""> return result<br class="">}<br class=""><br class="">func sum(_ array: ContiguousArray<Float>) -> Float {<br class=""> var result = Float()<br class=""> array.withUnsafeBufferPointer { vDSP_sve($0.baseAddress!, 1, &result, vDSP_Length(array.count)) }<br class=""> return result<br class="">}<br class=""><br class="">func sum(_ array: ArraySlice<Float>) -> Float {<br class=""> var result = Float()<br class=""> array.withUnsafeBufferPointer { vDSP_sve($0.baseAddress!, 1, &result, vDSP_Length(array.count)) }<br class=""> return result<br class="">}<br class=""><br class="">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)<br class=""><br class=""><br class=""><blockquote type="cite" class="">On Nov 21, 2016, at 4:32 PM, Rick Mann via swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> wrote:<br class=""><br class="">My googling is not turning up an answer that works in Xcode 8.1. I'd like to do this:<br class=""><br class=""><br class="">import Accelerate<br class=""><br class="">extension<br class="">Array<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>where Element == Double<br class="">{<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>func<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>sum()<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span>-> Double<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>{<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span>var result: Double = 0.0<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span>vDSP_sveD(self, 1, &result, vDSP_Length(self.count))<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span>return result<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}<br class="">}<br class=""><br class="">But I get "same-type requirement makes generic parameter 'Element' non-generic."<br class=""><br class="">Also, will there ever be any way to specialize something like<br class=""><br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let numbers: [Double] = ...<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let sum = numbers.reduce(0.0, +)<br class=""><br class="">Into a call to vDSP_sveD()? Would it require compiler optimizations for Accelerate?<br class=""><br class="">Thanks!<br class=""><br class="">-- <br class="">Rick Mann<br class=""><a href="mailto:rmann@latencyzero.com" class="">rmann@latencyzero.com</a><br class=""><br class=""><br class="">_______________________________________________<br class="">swift-users mailing list<br class=""><a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-users<br class=""></blockquote><br class=""></blockquote><br class=""><br class="">-- <br class="">Rick Mann<br class=""><a href="mailto:rmann@latencyzero.com" class="">rmann@latencyzero.com</a><br class=""><br class=""><br class=""></blockquote><br class=""></blockquote><br class=""><br class="">-- <br class="">Rick Mann<br class=""><a href="mailto:rmann@latencyzero.com" class="">rmann@latencyzero.com</a><br class=""><br class=""><br class=""></div></div></blockquote></div><br class=""></div></div>_______________________________________________<br class="">swift-users mailing list<br class=""><a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-users<br class=""></div></blockquote></div><br class=""></body></html>