title: Optimizing Cython loop compared to Numpy
body: <pre><code>#cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, language_level=3
  cpdef int query(double[::1] q, double[:,::1] data) nogil:
      cdef:
          int n = data.shape[0]
          int dim = data.shape[1]
          int best_i = -1
          double best_ip = -1
          double ip
      for i in range(n):
          ip = 0
          for j in range(dim):
              ip += q[j] * data[i, j]
          if ip &gt; best_ip:
              best_i = i
              best_ip = ip
      return best_i
  </code></pre>
  <p>After compiling, I time the code from Python:</p>
  <pre><code>import numpy as np
  import ip
  n, dim = 10**6, 10**2
  X = np.random.randn(n, dim)
  q = np.random.randn(dim)
  %timeit ip.query(q, X)
  </code></pre>
  <p>This takes roughly 100ms. Meanwhile the equivalent <code>numpy code</code>:</p>
  <pre><code>%timeit np.argmax(q @ X.T)
  </code></pre>
  <p>Takes just around 50ms.</p>
  <p>This is odd, since the <code>NumPy</code> code seemingly has to allocate the big array <code>q @ X.T</code> before taking the argmax. I thus wonder if there are some optimizations I am lacking?</p>
  <p>I have added <code>extra_compile_args=[&quot;-O3&quot;, '-march=native'],</code> to my setup.py and I also tried changing the function definition to</p>
  <pre><code>cpdef int query(np.ndarray[double] q, np.ndarray[double, ndim=2] data):
  </code></pre>
  <p>but it had virtually no difference in performance.</p>