Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to speed up numpy.all and numpy.nonzero()?

Tags:

python

numpy

I need to check if a point lies inside a bounding cuboid. The number of cuboids is very large (~4M). The code I come up with is:

import numpy as np

# set the numbers of points and cuboids
n_points = 64
n_cuboid = 4000000

# generate the test data
points = np.random.rand(1, 3, n_points)*512
cuboid_min = np.random.rand(n_cuboid, 3, 1)*512
cuboid_max = cuboid_min + np.random.rand(n_cuboid, 3, 1)*8

# main body: check if the points are inside the cuboids
inside_cuboid = np.all((points > cuboid_min) & (points < cuboid_max), axis=1)
indices = np.nonzero(inside_cuboid)

It takes 8 seconds to run np.all and 3 seconds to run np.nonzero on my computer. Any idea to speed up the code?

like image 762
f. c. Avatar asked Sep 19 '20 09:09

f. c.


1 Answers

We can reduce memory congestion for all-reduction with slicing along the smallest axis length of 3 to get inside_cuboid -

out = (points[0,0,:] > cuboid_min[:,0]) & (points[0,0,:] < cuboid_max[:,0]) & \
      (points[0,1,:] > cuboid_min[:,1]) & (points[0,1,:] < cuboid_max[:,1]) & \
      (points[0,2,:] > cuboid_min[:,2]) & (points[0,2,:] < cuboid_max[:,2])

Timings -

In [43]: %timeit np.all((points > cuboid_min) & (points < cuboid_max), axis=1)
2.49 s ± 20 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [51]: %%timeit
    ...: out = (points[0,0,:] > cuboid_min[:,0]) & (points[0,0,:] < cuboid_max[:,0]) & \
    ...:       (points[0,1,:] > cuboid_min[:,1]) & (points[0,1,:] < cuboid_max[:,1]) & \
    ...:       (points[0,2,:] > cuboid_min[:,2]) & (points[0,2,:] < cuboid_max[:,2])
1.95 s ± 10.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
like image 157
Divakar Avatar answered Sep 29 '22 21:09

Divakar