2
\$\begingroup\$

i've written a basic function to split an array into stride by 2:

[z] -> [x],[y]

    func splitArray(Z x:[Float64])->(Real:[Float64],Imag:[Float64])
    {
      guard (x.count % 2 == 0) else {"BOMB:: need even number of elements in array \(#file) \(#line) \(#function)"
      return ([0.0],[0.0])
      }
      var Real:[Float64] = zeroD(npts: Int(x.count/2) )
      var Imag:[Float64] = zeroD(npts: Int(x.count/2) )
      var ida:Int = 0, idb:Int = 0
  for elem in stride(from:0, to: x.count-1, by:2)
  {
      Real[ida] = x[elem]
      ida += 1
  }
  for elem in stride(from:1, to:x.count, by:2)
  {
    Imag[idb] = x[elem]
    idb += 1
  }
      return (Real,Imag)
}

Does anyone have a faster map? Sometimes map is not that fast and just hides the loop?

I'm hoping for solutions which have been designed to crunch big data arrays or like google's big table, although not sparse. Something like a Metal/GPU pipeline? hyper-threading model? an Atomic que/stack? pulling in an external optimized lib like boost?

The algorithm behind map is unknown, sometimes it's faster than a simple loop sometimes not. It's not deterministic, generally not a good thing, but it's easy to implement.

I've tried unrolling loops in Xcode flags but seems to make no different with an arrays of size MxN>[500,500].

\$\endgroup\$
  • 1
    \$\begingroup\$ Is this example code, or do all of your error messages contain expletives like this one does? \$\endgroup\$ – Phrancis Nov 26 '16 at 21:42
  • 1
    \$\begingroup\$ all of my error messages contain adult words in at least 5 languages, english, french, german, spanish and sometimes Latin. uproxx.com/life/people-swear-articuate-intelligent \$\endgroup\$ – μολὼν.λαβέ Nov 26 '16 at 22:11
  • 4
    \$\begingroup\$ You're welcome to put expletives in your code, but I would consider that unprofessional and I would call you out on it, especially if it's in stdout. Comments are another thing, but stdout/stderr really just stinks of unprofessionalism. Also, hilariously, the article you cited to excuse your swearing because it makes people articulate incorrectly spelled 'articulate'. \$\endgroup\$ – Dan Pantry Nov 27 '16 at 0:06
  • \$\begingroup\$ Can you provide more details on the performance problem? How large is the array? What hardware (iPhone, Mac, ...)? What time did you measure? What does "and just hides the loop" mean? Also please add the zeroD() function to make the code self-contained. – In my quick test splitting a 100,000 element array with your code took approx 0.0003 seconds on a MacBook, which seems not to bad to me. \$\endgroup\$ – Martin R Nov 28 '16 at 7:53
1
\$\begingroup\$

As others have commented, it's not clear what your performance issue is currently and what your performance target is, but the function could certainly be rewritten to be more concise and use only a single "loop", like this:

func split<T>(array:[T])->(real:[T], imag:[T]) {
    // I didn't include your guard because it wasn't necessary for safety in this implementation, but you could include it here if you wished.
    return array.enumerated().reduce(([T](), [T]())) {
        (result:(real:[T], imag:[T]), input:(index:Int, element:T)) in
        input.index % 2 == 0 ? (result.real + [input.element], result.imag) : (result.real, result.imag + [input.element])
    }
}

This implementation uses reduce to loop through the source array once, and accumulate a tuple of two arrays as a result. The reduce is use on the enumerated() source array, so that the closure received both the element, and the index of that element in the original array. This way, by checking the mod 2 of the index, we can see if the element was in an even or an odd position and add it to the correct resulting array accordingly.

Lastly, since we don't really need to know what the specific type of the array's element is for this behavior, this implementation is generic and will split any array of anything into two new arrays: one with all the even-indexed elements, and one with all the odd-indexed elements.

\$\endgroup\$
  • 1
    \$\begingroup\$ I will elucidate the question. i left the loops basic so others could follow what the loop was doing. yes i could have written a perl like complicated-as-hell one or two liner but then people would complain about that as well. what i was hoping for was that someone had already found an algorithm/model for using Metal/GPU pipeline or threading model or an Atomic que/stack, instead of map for crunching big multidimensional arrays. the numerical implementation of this map algorithm is a big black hole. stating that i'm searching through a genomic pile of SNPs or Phenotypes doesn't matter \$\endgroup\$ – μολὼν.λαβέ Dec 4 '16 at 4:20
  • \$\begingroup\$ @GAlexander Thanks for the clarification — makes sense! Unfortunately I've done almost nothing with Metal or crunching arrays of the dimensions you're working with, so maybe someone else will have some better suggestions along those lines. \$\endgroup\$ – Daniel Hall Dec 4 '16 at 4:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.