title: Fastest way to do loop over 2D arrays in Cython
body: <p>I am trying to loop over 2 2d arrays in Cython. The arrays have the following shape:
  <code>ranges_1</code> is a 6000x3 array of <code>int64</code>, while <code>ranges_2</code> is a 2000x2 of <code>int64</code>. This iteration needs to be perfomed around 10000 times. This would mean that the total number of calculations inside the nested for loop would be around 2000x6000x10000 = 120 billions times.</p>
  <p>This is the code I am using to generate the &quot;dummy&quot; data:</p>
  <pre><code>import numpy as np
  ranges_1 = np.stack([np.random.randint(0, 10_000, 6_000), np.random.randint(0, 10_000, 6_000), np.arange(0, 6_000)], axis=1)
  ranges_2 = np.stack([np.random.randint(0, 10_000, 2_000), np.random.randint(0, 10_000, 2_000)], axis=1)
  </code></pre>
  <p>Which gives 2 arrays like these:</p>
  <pre><code>array([[6131, 1478,    0],
         [9317, 7263,    1],
         [7938, 6249,    2],
         ...,
         [5153,  426, 5997],
         [9164, 9211, 5998],
         [1695, 1792, 5999]])
  </code></pre>
  <p>and:</p>
  <pre><code>array([[ 433,  558],
         [3420, 2494],
         [6367, 7916],
         ...,
         [8693, 1692],
         [1256, 9013],
         [4096, 1860]])
  </code></pre>
  <p>The first implementation I tried is a &quot;naive&quot; version and it's the following (the function inside is just a test function which uses all the data in the array):</p>
  <pre><code>import numpy as np
  cimport numpy as np
  cimport cython
  ctypedef np.int_t DTYPE_t
  
  def test_func(np.ndarray[DTYPE_t, ndim = 2] ranges_1, np.ndarray[DTYPE_t, ndim=2] ranges_2,  int n ):
      k = 0 
      for i in range(n):
  
          for j in range(len(ranges_1)):
              r1 = ranges_1[j]
              a = r1[0]
              b = r1[1]
              c = r1[2]
  
              for f in range(len(ranges_2)):
                  r2 = ranges_2[f]
                  d = r2[0]
                  e = r2[1]
  
                  k = (a + b + c + d + e)/(d+e)
              
      return k
  </code></pre>
  <p>This takes about 5 seconds per each of the 10_000 outside loops.
  So I then tried flatteing out the arrays and, since I know the dimension on the other axis, accessing the items like this:</p>
  <pre><code>import numpy as np
  cimport numpy as np
  cimport cython
  ctypedef np.int_t DTYPE_t
  
  def test_func_flattened(np.ndarray[DTYPE_t, ndim = 1] ranges_1_, np.ndarray[DTYPE_t, ndim=1] ranges_2_,  int n ):
      k = 0 
      for i in range(n):
  
          for j in range(0, len(ranges_1_), 3):
              a = ranges_1_[j]
              b = ranges_1_[j+1]
              c = ranges_1_[j+2]
                  
              for f in range(0, len(ranges_2_), 2):
                  d = ranges_2_[f]
                  e = ranges_2_[f+1]
  
                  k = (a + b + c + d + e)/(d+e)
              
      return k
  </code></pre>
  <p>But that provided no speed up at all. The time to perform one single iteration of the 10_000 seems too high, considered that for one single iteration it's just 12_000_000 operations inside the loop. I also tried implementing a much simpler example both in Cython and in python which was then compiled with numba:</p>
  <pre><code>import numpy as np
  cimport numpy as np
  cimport cython
  ctypedef np.int_t DTYPE_t
  
  def test_1(int n ):
      cdef k = 0 
      cdef a = 0
      for i in range(n):
          a =  i +1
              
      return a
  </code></pre>
  <p>This took 15s to run with n = 1_000_000_000.</p>
  <p>While with <code>numba</code>:</p>
  <pre><code>def test_1_python(n ):
      k = 0 
      a = 0
      
      for i in range(n):
          if i % 2 == 0:
              a = a + 1
          else:
              a = a - 1
              
      return a
  
  test_1_numba= numba.jit(test_1_python)
  
  %%time
  test_1_numba(120_000_000_000)
  </code></pre>
  <p>The full run with n = 120bln took about 6s, (albeit the function inside is simpler) this means that it would be 500 times faster than Cython, could this be possible?</p>
  <p>I am new to Cython so I probably am missing something obvious, but since the numba version (without the array accessing) is tha much faster I think that the difference in speed might come from the overhead associated with accessing the items in the array.</p>
  <p>Is this a wrong assumption?</p>
  <p>If not, what would be the best of going about looping over a 2D list of integers in Cython?</p>