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\$
4
  • 1
    \$\begingroup\$ Is this example code, or do all of your error messages contain expletives like this one does? \$\endgroup\$
    – Phrancis
    Commented Nov 26, 2016 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\$ Commented Nov 26, 2016 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
    Commented Nov 27, 2016 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
    Commented Nov 28, 2016 at 7:53

1 Answer 1

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\$
2
  • 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\$ Commented Dec 4, 2016 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\$ Commented Dec 4, 2016 at 4:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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