The fastest way to get a cross product

It seems that calculating the cross product of an array of vectors is obviously much faster than using it np.cross. I tried vector-first and vector-last, this does not seem to matter, although this was suggested in response to a similar question . Am I using it incorrectly or is it just slower?

The explicit calculation, apparently, takes about 60 ns per cross-product on a laptop. Is it about ~ as fast as you are going? In this case, there seems to be no reason to go into Cython or PyPy or write custom ufunc.

I also see links to using einsum, but I don’t understand how to use it, and I suspect that it is not so fast.

a = np.random.random(size=300000).reshape(100000,3) # vector last
b = np.random.random(size=300000).reshape(100000,3)
c, d = a.swapaxes(0, 1),  b.swapaxes(0, 1)          # vector first

def npcross_vlast():        return np.cross(a, b)
def npcross_vfirst():       return np.cross(c, d, axisa=0, axisb=0)
def npcross_vfirst_axisc(): return np.cross(c, d, axisa=0, axisb=0, axisc=0)
def explicitcross_vlast():
    e = np.zeros_like(a)
    e[:,0] = a[:,1]*b[:,2] - a[:,2]*b[:,1]
    e[:,1] = a[:,2]*b[:,0] - a[:,0]*b[:,2]
    e[:,2] = a[:,0]*b[:,1] - a[:,1]*b[:,0]
    return e
def explicitcross_vfirst():
    e = np.zeros_like(c)
    e[0,:] = c[1,:]*d[2,:] - c[2,:]*d[1,:]
    e[1,:] = c[2,:]*d[0,:] - c[0,:]*d[2,:]
    e[2,:] = c[0,:]*d[1,:] - c[1,:]*d[0,:]
    return e
print "explicit"
print timeit.timeit(explicitcross_vlast,  number=10)
print timeit.timeit(explicitcross_vfirst, number=10)
print "np.cross"
print timeit.timeit(npcross_vlast,        number=10)
print timeit.timeit(npcross_vfirst,       number=10)
print timeit.timeit(npcross_vfirst_axisc, number=10)
print all([npcross_vlast()[7,i] == npcross_vfirst()[7,i] ==
           npcross_vfirst_axisc()[i,7] == explicitcross_vlast()[7,i] ==
           explicitcross_vfirst()[i,7] for i in range(3)]) # check one

explicit
0.0582590103149
0.0560920238495
np.cross
0.399816989899
0.412983894348
0.411231040955
True
+4
3

, , , , . , , <a x b, c x d> = <a, c><b, d> - <a, d><b, c>.

, -,

eijk = np.zeros((3, 3, 3))
eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1
eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[1, 0, 2] = -1

np.einsum('ijk,aj,ak->ai', eijk, a, b)
np.einsum('iak,ak->ai', np.einsum('ijk,aj->iak', eijk, a), b)

np.cross, einsums , , .

: , np.cross ( n):

enter image description here

import numpy as np
import perfplot

eijk = np.zeros((3, 3, 3))
eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1
eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[1, 0, 2] = -1


perfplot.show(
    setup=lambda n: np.random.rand(2, n, 3),
    n_range=[2**k for k in range(14)],
    kernels=[
        lambda X: np.cross(X[0], X[1]),
        lambda X: np.einsum('ijk,aj,ak->ai', eijk, X[0], X[1]),
        lambda X: np.einsum('iak,ak->ai', np.einsum('ijk,aj->iak', eijk, X[0]), X[1]),
        ],
    labels=['np.cross', 'einsum', 'double einsum'],
    xlabel='len(a)',
    logx=True,
    logy=True,
    )
+1

np.cross numpy 1.9.x.

%timeit explicitcross_vlast()
%timeit explicitcross_vfirst()
%timeit npcross_vlast()
%timeit npcross_vfirst()
%timeit npcross_vfirst_axisc() 

, 1.8.0

100 loops, best of 3: 4.47 ms per loop
100 loops, best of 3: 4.41 ms per loop
10 loops, best of 3: 29.1 ms per loop
10 loops, best of 3: 29.3 ms per loop
10 loops, best of 3: 30.6 ms per loop

1.9.0:

100 loops, best of 3: 4.62 ms per loop
100 loops, best of 3: 4.19 ms per loop
100 loops, best of 3: 4.05 ms per loop
100 loops, best of 3: 4.09 ms per loop
100 loops, best of 3: 4.24 ms per loop

, # 4338.

+3

vlast

def stacked_vlast(a,b):
        x = a[:,1]*b[:,2] - a[:,2]*b[:,1]
        y = a[:,2]*b[:,0] - a[:,0]*b[:,2]
        z = a[:,0]*b[:,1] - a[:,1]*b[:,0]
        return np.array([x,y,z]).T

. , () cross , 5x.

When I use a local copy of the development function cross, I get a little acceleration compared to yours explicit_vlast. This one crossuses the parameter outin an attempt to reduce temporary arrays, but my raw tests show that it doesn't really matter much in speed.

https://github.com/numpy/numpy/blob/master/numpy/core/numeric.py

If the explicit version works, I would not upgrade numpyto get this new one cross.

+1
source

All Articles