Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can numpy einsum() perform a cross-product between segments of a trajectory

Tags:

python

numpy

I perform the cross product of contiguous segments of a trajectory (xy coordinates) using the following script:

In [129]:
def func1(xy, s):
    size = xy.shape[0]-2*s
    out = np.zeros(size)
    for i in range(size):
        p1, p2 = xy[i], xy[i+s]     #segment 1
        p3, p4 = xy[i+s], xy[i+2*s] #segment 2
       out[i] = np.cross(p1-p2, p4-p3)
    return out

def func2(xy, s):
    size = xy.shape[0]-2*s
    p1 = xy[0:size]
    p2 = xy[s:size+s]
    p3 = p2
    p4 = xy[2*s:size+2*s]

    tmp1 = p1-p2
    tmp2 = p4-p3
    return tmp1[:, 0] * tmp2[:, 1] - tmp2[:, 0] * tmp1[:, 1]


In [136]:
xy = np.array([[1,2],[2,3],[3,4],[5,6],[7,8],[2,4],[5,2],[9,9],[1,1]])
func2(xy, 2)

Out[136]:
array([ 0, -3, 16,  1, 22])

func1 is particularly slow because of the inner loop so I rewrote the cross-product myself (func2) which is orders of magnitude faster.

Is it possible to use the numpy einsum function to make the same calculation?

like image 796
user3329302 Avatar asked Oct 31 '22 11:10

user3329302


1 Answers

einsum computes sums of products only, but you could shoehorn the cross-product into a sum of products by reversing the columns of tmp2 and changing the sign of the first column:

def func3(xy, s):
    size = xy.shape[0]-2*s
    tmp1 = xy[0:size] - xy[s:size+s]
    tmp2 = xy[2*s:size+2*s] - xy[s:size+s]
    tmp2 = tmp2[:, ::-1]
    tmp2[:, 0] *= -1
    return np.einsum('ij,ij->i', tmp1, tmp2)

But func3 is slower than func2.

In [80]: xy = np.tile(xy, (1000, 1))

In [104]: %timeit func1(xy, 2)
10 loops, best of 3: 67.5 ms per loop

In [105]: %timeit func2(xy, 2)
10000 loops, best of 3: 73.2 µs per loop

In [106]: %timeit func3(xy, 2)
10000 loops, best of 3: 108 µs per loop

Sanity check:

In [86]: np.allclose(func1(xy, 2), func3(xy, 2))
Out[86]: True

I think the reason why func2 is beating einsum here is because the cost of setting of the loop in einsum for just 2 iterations is too expensive compared to just manually writing out the sum, and the reversing and multiplying eat up some time as well.

like image 171
unutbu Avatar answered Nov 12 '22 23:11

unutbu