title: Divide an array into subarrays as equally as possible for core-mapping
body: <p>What algorithms are used to map an image array to multiple cores for processing? I've been trying to come up with something that will return a list of (disjoint) ranges over which to iterate in an array, and so far I have the following.</p>
  
  <pre><code>#!/usr/bin/env python3
  # -*- coding: utf-8 -*-
  
  import numpy as np
  
  
  def divider(arr_dims, coreNum=1):
      """ Get a bunch of iterable ranges; 
      Example input: [[[0, 24], [15, 25]]]
      """
      if (coreNum == 1):
          return arr_dims
  
      elif (coreNum &lt; 1):
          raise ValueError(\
        'partitioner expected a positive number of cores, got %d'\
                      % coreNum
          )
  
      elif (coreNum % 2):
          raise ValueError(\
        'partitioner expected an even number of cores, got %d'\
                      % coreNum
          )
  
      total = []
  
      # Split each coordinate in arr_dims in _half_
      for arr_dim in arr_dims:
          dY = arr_dim[0][1] - arr_dim[0][0]
          dX = arr_dim[1][1] - arr_dim[1][0]
  
          if ((coreNum,)*2 &gt; (dY, dX)):
              coreNum = max(dY, dX)
              coreNum -= 1 if (coreNum % 2 and coreNum &gt; 1) else 0
  
          new_c1, new_c2, = [], []
  
          if (dY &gt;= dX):
              # Subimage height is greater than its width
              half = dY // 2
              new_c1.append([arr_dim[0][0], arr_dim[0][0] + half])
              new_c1.append(arr_dim[1])
  
              new_c2.append([arr_dim[0][0] + half, arr_dim[0][1]])
              new_c2.append(arr_dim[1])
  
          else:
              # Subimage width is greater than its height
              half = dX // 2
              new_c1.append(arr_dim[0])
              new_c1.append([arr_dim[1][0], half])
  
              new_c2.append(arr_dim[0])
              new_c2.append([arr_dim[1][0] + half, arr_dim[1][1]])
  
          total.append(new_c1), total.append(new_c2)
  
      # If the number of cores is 1, we get back the total; Else,
      # we split each in total, etc.; it's turtles all the way down
      return divider(total, coreNum // 2)
  
  
  if __name__ == '__main__':
      import numpy as np
      X = np.random.randn(25 - 1, 36 - 1)
      dims = [zip([0, 0], list(X.shape))]
      dims = [list(j) for i in dims for j in dims[0] if type(j) != list]
      print(divider([dims], 2))
  </code></pre>
  
  <p>It's incredibly limited, however, because it only accepts a number of cores that's some power of 2, and then I'm certain there's edge cases I'm overlooking. Running it returns <code>[[[0, 24], [0, 17]], [[0, 24], [17, 35]]]</code>, and then using <code>pathos</code> I've mapped the first set to one core in my laptop and the second to another.</p>
  
  <p>I guess I just don't know how to geometrically walk my way through partitioning an image into segments that are as similar in <em>size</em> as possible, so that each core on a given machine has the same amount of work to do.</p>