Skip to content
Commits on Source (5)
Metadata-Version: 1.1
Name: pykdtree
Version: 1.2.2
Version: 1.3.0
Summary: Fast kd-tree implementation with OpenMP-enabled queries
Home-page: UNKNOWN
Author: Esben S. Nielsen
......
README.rst
\ No newline at end of file
.. image:: https://travis-ci.org/storpipfugl/pykdtree.svg?branch=master
:target: https://travis-ci.org/storpipfugl/pykdtree
.. image:: https://ci.appveyor.com/api/projects/status/ubo92368ktt2d25g/branch/master
:target: https://ci.appveyor.com/project/storpipfugl/pykdtree
========
pykdtree
========
Objective
---------
pykdtree is a kd-tree implementation for fast nearest neighbour search in Python.
The aim is to be the fastest implementation around for common use cases (low dimensions and low number of neighbours) for both tree construction and queries.
The implementation is based on scipy.spatial.cKDTree and libANN by combining the best features from both and focus on implementation efficiency.
The interface is similar to that of scipy.spatial.cKDTree except only Euclidean distance measure is supported.
Queries are optionally multithreaded using OpenMP.
Installation
------------
Default build of pykdtree with OpenMP enabled queries using libgomp
.. code-block:: bash
$ cd <pykdtree_dir>
$ python setup.py install
If it fails with undefined compiler flags or you want to use another OpenMP implementation please modify setup.py at the indicated point to match your system.
Building without OpenMP support is controlled by the USE_OMP environment variable
.. code-block:: bash
$ cd <pykdtree_dir>
$ export USE_OMP=0
$ python setup.py install
Note evironment variables are by default not exported when using sudo so in this case do
.. code-block:: bash
$ USE_OMP=0 sudo -E python setup.py install
Usage
-----
The usage of pykdtree is similar to scipy.spatial.cKDTree so for now refer to its documentation
>>> from pykdtree.kdtree import KDTree
>>> kd_tree = KDTree(data_pts)
>>> dist, idx = kd_tree.query(query_pts, k=8)
The number of threads to be used in OpenMP enabled queries can be controlled with the standard OpenMP environment variable OMP_NUM_THREADS.
The **leafsize** argument (number of data points per leaf) for the tree creation can be used to control the memory overhead of the kd-tree. pykdtree uses a default **leafsize=16**.
Increasing **leafsize** will reduce the memory overhead and construction time but increase query time.
pykdtree accepts data in double precision (numpy.float64) or single precision (numpy.float32) floating point. If data of another type is used an internal copy in double precision is made resulting in a memory overhead. If the kd-tree is constructed on single precision data the query points must be single precision as well.
Benchmarks
----------
Comparison with scipy.spatial.cKDTree and libANN. This benchmark is on geospatial 3D data with 10053632 data points and 4276224 query points. The results are indexed relative to the construction time of scipy.spatial.cKDTree. A leafsize of 10 (scipy.spatial.cKDTree default) is used.
Note: libANN is *not* thread safe. In this benchmark libANN is compiled with "-O3 -funroll-loops -ffast-math -fprefetch-loop-arrays" in order to achieve optimum performance.
================== ===================== ====== ======== ==================
Operation scipy.spatial.cKDTree libANN pykdtree pykdtree 4 threads
------------------ --------------------- ------ -------- ------------------
Construction 100 304 96 96
query 1 neighbour 1267 294 223 70
Total 1 neighbour 1367 598 319 166
query 8 neighbours 2193 625 449 143
Total 8 neighbours 2293 929 545 293
================== ===================== ====== ======== ==================
Looking at the combined construction and query this gives the following performance improvement relative to scipy.spatial.cKDTree
========== ====== ======== ==================
Neighbours libANN pykdtree pykdtree 4 threads
---------- ------ -------- ------------------
1 129% 329% 723%
8 147% 320% 682%
========== ====== ======== ==================
Note: mileage will vary with the dataset at hand and computer architecture.
Test
----
Run the unit tests using nosetest
.. code-block:: bash
$ cd <pykdtree_dir>
$ python setup.py nosetests
Installing on AppVeyor
----------------------
Pykdtree requires the "stdint.h" header file which is not available on certain
versions of Windows or certain Windows compilers including those on the
continuous integration platform AppVeyor. To get around this the header file(s)
can be downloaded and placed in the correct "include" directory. This can
be done by adding the `anaconda/missing-headers.ps1` script to your repository
and running it the install step of `appveyor.yml`:
# install missing headers that aren't included with MSVC 2008
# https://github.com/omnia-md/conda-recipes/pull/524
- "powershell ./appveyor/missing-headers.ps1"
In addition to this, AppVeyor does not support OpenMP so this feature must be
turned off by adding the following to `appveyor.yml` in the
`environment` section:
environment:
global:
# Don't build with openmp because it isn't supported in appveyor's compilers
USE_OMP: "0"
Changelog
---------
v1.3.0 : Keyword argument "mask" added to "qeury" method. OpenMP compilation now works for MS Visual Studio compiler
v1.2.2 : Build process fixes
v1.2.1 : Fixed OpenMP thread safety issue introduced in v1.2.0
v1.2.0 : 64 and 32 bit MSVC Windows support added
v1.1.1 : Same as v1.1 release due to incorrect pypi release
v1.1 : Build process improvements. Add data attribute to kdtree class for scipy interface compatibility
v1.0 : Switched license from GPLv3 to LGPLv3
v0.3 : Avoid zipping of installed egg
v0.2 : Reduced memory footprint. Can now handle single precision data internally avoiding copy conversion to double precision. Default leafsize changed from 10 to 16 as this reduces the memory footprint and makes it a cache line multiplum (negligible if any query performance observed in benchmarks). Reduced memory allocation for leaf nodes. Applied patch for building on OS X.
v0.1 : Initial version.
pykdtree (1.2.2-5) UNRELEASED; urgency=medium
pykdtree (1.3.0-1) unstable; urgency=medium
* New upstream release.
* Update Vcs-* URLs for Salsa.
* Bump Standards-Version to 4.1.4, no changes.
* Change Homepage & Source URL to GitHub repository.
* Strip trailing whitespace from rules files.
* debian/patches
- drop 0002-safe-clean.patch, no longer necessary
-- Antonio Valentino <antonio.valentino@tiscali.it> Sat, 31 Mar 2018 12:50:49 +0200
-- Antonio Valentino <antonio.valentino@tiscali.it> Mon, 04 Jun 2018 19:37:00 +0000
pykdtree (1.2.2-4) unstable; urgency=medium
......
From: Antonio Valentino <antonio.valentino@tiscali.it>
Date: Sun, 22 Jun 2014 14:28:53 +0200
Subject: safe clean
---
pykdtree.egg-info/requires.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pykdtree.egg-info/requires.txt b/pykdtree.egg-info/requires.txt
index 296d654..b26e81f 100644
--- a/pykdtree.egg-info/requires.txt
+++ b/pykdtree.egg-info/requires.txt
@@ -1 +1,2 @@
-numpy
\ No newline at end of file
+numpy
+
0001-fix_egginfo_source.patch
0002-safe-clean.patch
Metadata-Version: 1.1
Name: pykdtree
Version: 1.2.2
Version: 1.3.0
Summary: Fast kd-tree implementation with OpenMP-enabled queries
Home-page: UNKNOWN
Author: Esben S. Nielsen
......
......@@ -94,11 +94,13 @@ float get_cube_offset_float(int8_t dim, float *point_coord, float *bbox);
float get_min_dist_float(float *point_coord, int8_t no_dims, float *bbox);
void search_leaf_float(float *restrict pa, uint32_t *restrict pidx, int8_t no_dims, uint32_t start_idx, uint32_t n, float *restrict point_coord,
uint32_t k, uint32_t *restrict closest_idx, float *restrict closest_dist);
void search_leaf_float_mask(float *restrict pa, uint32_t *restrict pidx, int8_t no_dims, uint32_t start_idx, uint32_t n, float *restrict point_coord,
uint32_t k, uint8_t *restrict mask, uint32_t *restrict closest_idx, float *restrict closest_dist);
void search_splitnode_float(Node_float *root, float *pa, uint32_t *pidx, int8_t no_dims, float *point_coord,
float min_dist, uint32_t k, float distance_upper_bound, float eps_fac, uint32_t * closest_idx, float *closest_dist);
float min_dist, uint32_t k, float distance_upper_bound, float eps_fac, uint8_t *mask, uint32_t * closest_idx, float *closest_dist);
void search_tree_float(Tree_float *tree, float *pa, float *point_coords,
uint32_t num_points, uint32_t k, float distance_upper_bound,
float eps, uint32_t *closest_idxs, float *closest_dists);
float eps, uint8_t *mask, uint32_t *closest_idxs, float *closest_dists);
void insert_point_double(uint32_t *closest_idx, double *closest_dist, uint32_t pidx, double cur_dist, uint32_t k);
......@@ -116,11 +118,13 @@ double get_cube_offset_double(int8_t dim, double *point_coord, double *bbox);
double get_min_dist_double(double *point_coord, int8_t no_dims, double *bbox);
void search_leaf_double(double *restrict pa, uint32_t *restrict pidx, int8_t no_dims, uint32_t start_idx, uint32_t n, double *restrict point_coord,
uint32_t k, uint32_t *restrict closest_idx, double *restrict closest_dist);
void search_leaf_double_mask(double *restrict pa, uint32_t *restrict pidx, int8_t no_dims, uint32_t start_idx, uint32_t n, double *restrict point_coord,
uint32_t k, uint8_t *restrict mask, uint32_t *restrict closest_idx, double *restrict closest_dist);
void search_splitnode_double(Node_double *root, double *pa, uint32_t *pidx, int8_t no_dims, double *point_coord,
double min_dist, uint32_t k, double distance_upper_bound, double eps_fac, uint32_t * closest_idx, double *closest_dist);
double min_dist, uint32_t k, double distance_upper_bound, double eps_fac, uint8_t *mask, uint32_t * closest_idx, double *closest_dist);
void search_tree_double(Tree_double *tree, double *pa, double *point_coords,
uint32_t num_points, uint32_t k, double distance_upper_bound,
double eps, uint32_t *closest_idxs, double *closest_dists);
double eps, uint8_t *mask, uint32_t *closest_idxs, double *closest_dists);
......@@ -580,6 +584,43 @@ void search_leaf_float(float *restrict pa, uint32_t *restrict pidx, int8_t no_di
}
}
/************************************************
Search a leaf node for closest point with data point mask
Params:
pa : data points
pidx : permutation index of data points
no_dims : number of dimensions
start_idx : index of first data point to use
size : number of data points
point_coord : query point
mask : boolean array of invalid (True) and valid (False) data points
closest_idx : index of closest data point found (return)
closest_dist : distance to closest point (return)
************************************************/
void search_leaf_float_mask(float *restrict pa, uint32_t *restrict pidx, int8_t no_dims, uint32_t start_idx, uint32_t n, float *restrict point_coord,
uint32_t k, uint8_t *mask, uint32_t *restrict closest_idx, float *restrict closest_dist)
{
float cur_dist;
uint32_t i;
/* Loop through all points in leaf */
for (i = 0; i < n; i++)
{
/* Is this point masked out? */
if (mask[start_idx + i])
{
continue;
}
/* Get distance to query point */
cur_dist = calc_dist_float(&PA(start_idx + i, 0), point_coord, no_dims);
/* Update closest info if new point is closest so far*/
if (cur_dist < closest_dist[k - 1])
{
insert_point_float(closest_idx, closest_dist, pidx[start_idx + i], cur_dist, k);
}
}
}
/************************************************
Search subtree for nearest to query point
Params:
......@@ -589,11 +630,13 @@ Params:
no_dims : number of dimensions
point_coord : query point
min_dist : minumum distance to nearest neighbour
mask : boolean array of invalid (True) and valid (False) data points
closest_idx : index of closest data point found (return)
closest_dist : distance to closest point (return)
************************************************/
void search_splitnode_float(Node_float *root, float *pa, uint32_t *pidx, int8_t no_dims, float *point_coord,
float min_dist, uint32_t k, float distance_upper_bound, float eps_fac, uint32_t *closest_idx, float *closest_dist)
float min_dist, uint32_t k, float distance_upper_bound, float eps_fac, uint8_t *mask,
uint32_t *closest_idx, float *closest_dist)
{
int8_t dim;
float dist_left, dist_right;
......@@ -610,8 +653,15 @@ void search_splitnode_float(Node_float *root, float *pa, uint32_t *pidx, int8_t
/* Handle leaf node */
if (dim == -1)
{
if (mask)
{
search_leaf_float_mask(pa, pidx, no_dims, root->start_idx, root->n, point_coord, k, mask, closest_idx, closest_dist);
}
else
{
search_leaf_float(pa, pidx, no_dims, root->start_idx, root->n, point_coord, k, closest_idx, closest_dist);
}
return;
}
......@@ -625,7 +675,7 @@ void search_splitnode_float(Node_float *root, float *pa, uint32_t *pidx, int8_t
if (dist_left < closest_dist[k - 1] * eps_fac)
{
/* Search left subtree if minimum distance is below limit */
search_splitnode_float((Node_float *)root->left_child, pa, pidx, no_dims, point_coord, dist_left, k, distance_upper_bound, eps_fac, closest_idx, closest_dist);
search_splitnode_float((Node_float *)root->left_child, pa, pidx, no_dims, point_coord, dist_left, k, distance_upper_bound, eps_fac, mask, closest_idx, closest_dist);
}
/* Right of cutting plane. Update minimum distance.
......@@ -640,7 +690,7 @@ void search_splitnode_float(Node_float *root, float *pa, uint32_t *pidx, int8_t
if (dist_right < closest_dist[k - 1] * eps_fac)
{
/* Search right subtree if minimum distance is below limit*/
search_splitnode_float((Node_float *)root->right_child, pa, pidx, no_dims, point_coord, dist_right, k, distance_upper_bound, eps_fac, closest_idx, closest_dist);
search_splitnode_float((Node_float *)root->right_child, pa, pidx, no_dims, point_coord, dist_right, k, distance_upper_bound, eps_fac, mask, closest_idx, closest_dist);
}
}
else
......@@ -650,7 +700,7 @@ void search_splitnode_float(Node_float *root, float *pa, uint32_t *pidx, int8_t
if (dist_right < closest_dist[k - 1] * eps_fac)
{
/* Search right subtree if minimum distance is below limit*/
search_splitnode_float((Node_float *)root->right_child, pa, pidx, no_dims, point_coord, dist_right, k, distance_upper_bound, eps_fac, closest_idx, closest_dist);
search_splitnode_float((Node_float *)root->right_child, pa, pidx, no_dims, point_coord, dist_right, k, distance_upper_bound, eps_fac, mask, closest_idx, closest_dist);
}
/* Left of cutting plane. Update minimum distance.
......@@ -665,7 +715,7 @@ void search_splitnode_float(Node_float *root, float *pa, uint32_t *pidx, int8_t
if (dist_left < closest_dist[k - 1] * eps_fac)
{
/* Search left subtree if minimum distance is below limit*/
search_splitnode_float((Node_float *)root->left_child, pa, pidx, no_dims, point_coord, dist_left, k, distance_upper_bound, eps_fac, closest_idx, closest_dist);
search_splitnode_float((Node_float *)root->left_child, pa, pidx, no_dims, point_coord, dist_left, k, distance_upper_bound, eps_fac, mask, closest_idx, closest_dist);
}
}
}
......@@ -678,19 +728,27 @@ Params:
pidx : permutation index of data points
point_coords : query points
num_points : number of query points
mask : boolean array of invalid (True) and valid (False) data points
closest_idx : index of closest data point found (return)
closest_dist : distance to closest point (return)
************************************************/
void search_tree_float(Tree_float *tree, float *pa, float *point_coords,
uint32_t num_points, uint32_t k, float distance_upper_bound,
float eps, uint32_t *closest_idxs, float *closest_dists)
float eps, uint8_t *mask, uint32_t *closest_idxs, float *closest_dists)
{
float min_dist;
float eps_fac = 1 / ((1 + eps) * (1 + eps));
int8_t no_dims = tree->no_dims;
float *bbox = tree->bbox;
uint32_t *pidx = tree->pidx;
uint32_t i, j;
uint32_t j = 0;
#if defined(_MSC_VER) && defined(_OPENMP)
int32_t i = 0;
int32_t local_num_points = (int32_t) num_points;
#else
uint32_t i;
uint32_t local_num_points = num_points;
#endif
Node_float *root = (Node_float *)tree->root;
/* Queries are OpenMP enabled */
......@@ -700,7 +758,7 @@ void search_tree_float(Tree_float *tree, float *pa, float *point_coords,
for spatial coherent query datasets
*/
#pragma omp for private(i, j) schedule(static, 100) nowait
for (i = 0; i < num_points; i++)
for (i = 0; i < local_num_points; i++)
{
for (j = 0; j < k; j++)
{
......@@ -709,7 +767,7 @@ void search_tree_float(Tree_float *tree, float *pa, float *point_coords,
}
min_dist = get_min_dist_float(point_coords + no_dims * i, no_dims, bbox);
search_splitnode_float(root, pa, pidx, no_dims, point_coords + no_dims * i, min_dist,
k, distance_upper_bound, eps_fac, &closest_idxs[i * k], &closest_dists[i * k]);
k, distance_upper_bound, eps_fac, mask, &closest_idxs[i * k], &closest_dists[i * k]);
}
}
}
......@@ -1170,6 +1228,43 @@ void search_leaf_double(double *restrict pa, uint32_t *restrict pidx, int8_t no_
}
}
/************************************************
Search a leaf node for closest point with data point mask
Params:
pa : data points
pidx : permutation index of data points
no_dims : number of dimensions
start_idx : index of first data point to use
size : number of data points
point_coord : query point
mask : boolean array of invalid (True) and valid (False) data points
closest_idx : index of closest data point found (return)
closest_dist : distance to closest point (return)
************************************************/
void search_leaf_double_mask(double *restrict pa, uint32_t *restrict pidx, int8_t no_dims, uint32_t start_idx, uint32_t n, double *restrict point_coord,
uint32_t k, uint8_t *mask, uint32_t *restrict closest_idx, double *restrict closest_dist)
{
double cur_dist;
uint32_t i;
/* Loop through all points in leaf */
for (i = 0; i < n; i++)
{
/* Is this point masked out? */
if (mask[start_idx + i])
{
continue;
}
/* Get distance to query point */
cur_dist = calc_dist_double(&PA(start_idx + i, 0), point_coord, no_dims);
/* Update closest info if new point is closest so far*/
if (cur_dist < closest_dist[k - 1])
{
insert_point_double(closest_idx, closest_dist, pidx[start_idx + i], cur_dist, k);
}
}
}
/************************************************
Search subtree for nearest to query point
Params:
......@@ -1179,11 +1274,13 @@ Params:
no_dims : number of dimensions
point_coord : query point
min_dist : minumum distance to nearest neighbour
mask : boolean array of invalid (True) and valid (False) data points
closest_idx : index of closest data point found (return)
closest_dist : distance to closest point (return)
************************************************/
void search_splitnode_double(Node_double *root, double *pa, uint32_t *pidx, int8_t no_dims, double *point_coord,
double min_dist, uint32_t k, double distance_upper_bound, double eps_fac, uint32_t *closest_idx, double *closest_dist)
double min_dist, uint32_t k, double distance_upper_bound, double eps_fac, uint8_t *mask,
uint32_t *closest_idx, double *closest_dist)
{
int8_t dim;
double dist_left, dist_right;
......@@ -1200,8 +1297,15 @@ void search_splitnode_double(Node_double *root, double *pa, uint32_t *pidx, int8
/* Handle leaf node */
if (dim == -1)
{
if (mask)
{
search_leaf_double_mask(pa, pidx, no_dims, root->start_idx, root->n, point_coord, k, mask, closest_idx, closest_dist);
}
else
{
search_leaf_double(pa, pidx, no_dims, root->start_idx, root->n, point_coord, k, closest_idx, closest_dist);
}
return;
}
......@@ -1215,7 +1319,7 @@ void search_splitnode_double(Node_double *root, double *pa, uint32_t *pidx, int8
if (dist_left < closest_dist[k - 1] * eps_fac)
{
/* Search left subtree if minimum distance is below limit */
search_splitnode_double((Node_double *)root->left_child, pa, pidx, no_dims, point_coord, dist_left, k, distance_upper_bound, eps_fac, closest_idx, closest_dist);
search_splitnode_double((Node_double *)root->left_child, pa, pidx, no_dims, point_coord, dist_left, k, distance_upper_bound, eps_fac, mask, closest_idx, closest_dist);
}
/* Right of cutting plane. Update minimum distance.
......@@ -1230,7 +1334,7 @@ void search_splitnode_double(Node_double *root, double *pa, uint32_t *pidx, int8
if (dist_right < closest_dist[k - 1] * eps_fac)
{
/* Search right subtree if minimum distance is below limit*/
search_splitnode_double((Node_double *)root->right_child, pa, pidx, no_dims, point_coord, dist_right, k, distance_upper_bound, eps_fac, closest_idx, closest_dist);
search_splitnode_double((Node_double *)root->right_child, pa, pidx, no_dims, point_coord, dist_right, k, distance_upper_bound, eps_fac, mask, closest_idx, closest_dist);
}
}
else
......@@ -1240,7 +1344,7 @@ void search_splitnode_double(Node_double *root, double *pa, uint32_t *pidx, int8
if (dist_right < closest_dist[k - 1] * eps_fac)
{
/* Search right subtree if minimum distance is below limit*/
search_splitnode_double((Node_double *)root->right_child, pa, pidx, no_dims, point_coord, dist_right, k, distance_upper_bound, eps_fac, closest_idx, closest_dist);
search_splitnode_double((Node_double *)root->right_child, pa, pidx, no_dims, point_coord, dist_right, k, distance_upper_bound, eps_fac, mask, closest_idx, closest_dist);
}
/* Left of cutting plane. Update minimum distance.
......@@ -1255,7 +1359,7 @@ void search_splitnode_double(Node_double *root, double *pa, uint32_t *pidx, int8
if (dist_left < closest_dist[k - 1] * eps_fac)
{
/* Search left subtree if minimum distance is below limit*/
search_splitnode_double((Node_double *)root->left_child, pa, pidx, no_dims, point_coord, dist_left, k, distance_upper_bound, eps_fac, closest_idx, closest_dist);
search_splitnode_double((Node_double *)root->left_child, pa, pidx, no_dims, point_coord, dist_left, k, distance_upper_bound, eps_fac, mask, closest_idx, closest_dist);
}
}
}
......@@ -1268,19 +1372,27 @@ Params:
pidx : permutation index of data points
point_coords : query points
num_points : number of query points
mask : boolean array of invalid (True) and valid (False) data points
closest_idx : index of closest data point found (return)
closest_dist : distance to closest point (return)
************************************************/
void search_tree_double(Tree_double *tree, double *pa, double *point_coords,
uint32_t num_points, uint32_t k, double distance_upper_bound,
double eps, uint32_t *closest_idxs, double *closest_dists)
double eps, uint8_t *mask, uint32_t *closest_idxs, double *closest_dists)
{
double min_dist;
double eps_fac = 1 / ((1 + eps) * (1 + eps));
int8_t no_dims = tree->no_dims;
double *bbox = tree->bbox;
uint32_t *pidx = tree->pidx;
uint32_t i, j;
uint32_t j = 0;
#if defined(_MSC_VER) && defined(_OPENMP)
int32_t i = 0;
int32_t local_num_points = (int32_t) num_points;
#else
uint32_t i;
uint32_t local_num_points = num_points;
#endif
Node_double *root = (Node_double *)tree->root;
/* Queries are OpenMP enabled */
......@@ -1290,7 +1402,7 @@ void search_tree_double(Tree_double *tree, double *pa, double *point_coords,
for spatial coherent query datasets
*/
#pragma omp for private(i, j) schedule(static, 100) nowait
for (i = 0; i < num_points; i++)
for (i = 0; i < local_num_points; i++)
{
for (j = 0; j < k; j++)
{
......@@ -1299,7 +1411,7 @@ void search_tree_double(Tree_double *tree, double *pa, double *point_coords,
}
min_dist = get_min_dist_double(point_coords + no_dims * i, no_dims, bbox);
search_splitnode_double(root, pa, pidx, no_dims, point_coords + no_dims * i, min_dist,
k, distance_upper_bound, eps_fac, &closest_idxs[i * k], &closest_dists[i * k]);
k, distance_upper_bound, eps_fac, mask, &closest_idxs[i * k], &closest_dists[i * k]);
}
}
}
This diff is collapsed.
......@@ -300,3 +300,45 @@ def test_scipy_comp():
assert id(kdtree.data) == id(kdtree.data_pts)
def test1d_mask():
data_pts = np.arange(1000)
kdtree = KDTree(data_pts, leafsize=15)
query_pts = np.arange(400, 300, -10)
query_mask = np.zeros(data_pts.shape[0]).astype(bool)
query_mask[400] = True
dist, idx = kdtree.query(query_pts, mask=query_mask)
assert idx[0] == 399 # would be 400 if no mask
assert dist[0] == 1.
assert idx[1] == 390
def test1d_all_masked():
data_pts = np.arange(1000)
kdtree = KDTree(data_pts, leafsize=15)
query_pts = np.arange(400, 300, -10)
query_mask = np.ones(data_pts.shape[0]).astype(bool)
dist, idx = kdtree.query(query_pts, mask=query_mask)
# all invalid
assert np.all(i >= 1000 for i in idx)
assert np.all(d >= 1001 for d in dist)
def test3d_mask():
#7, 93, 45
query_pts = np.array([[ 787014.438, -340616.906, 6313018.],
[751763.125, -59925.969, 6326205.5],
[769957.188, -202418.125, 6321069.5]])
kdtree = KDTree(data_pts_real)
query_mask = np.zeros(data_pts_real.shape[0])
query_mask[6:10] = True
dist, idx = kdtree.query(query_pts, sqr_dists=True, mask=query_mask)
epsilon = 1e-5
assert idx[0] == 5 # would be 7 if no mask
assert idx[1] == 93
assert idx[2] == 45
# would be 0 if no mask
assert abs(dist[0] - 66759196.1053) < epsilon * dist[0]
assert abs(dist[1] - 3.) < epsilon * dist[1]
assert abs(dist[2] - 20001.) < epsilon * dist[2]
......@@ -5,5 +5,4 @@ release = 1
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
......@@ -73,7 +73,7 @@ class build_ext_subclass(build_ext):
setup(
name='pykdtree',
version='1.2.2',
version='1.3.0',
description='Fast kd-tree implementation with OpenMP-enabled queries',
author='Esben S. Nielsen',
author_email='storpipfugl@gmail.com',
......