Commit 66da8bd7 authored by Julien Jerphanion's avatar Julien Jerphanion

[DEBUG] Execution problems

This does not work and I spent the afternoon trying to understand why...

TypeError: 'consume' operand is not isolated
Exception ignored in: 'KDTree.query'
Traceback (most recent call last):
  File "/home/jjerphan/dev/kdtree/debug.py", line 18, in <module>
      tree.query(Y, knn_indices, knn_distances)
      TypeError: 'consume' operand is not isolated
parent 5d84296d
...@@ -515,12 +515,43 @@ cdef cypclass Node activable: ...@@ -515,12 +515,43 @@ cdef cypclass Node activable:
counter=counter, counter=counter,
) )
# Workaround: min_rdist was moved out of the cypclass to be able
# to get the return value which was not possible
# (compilation problem from C++ code).
cdef D_t min_rdist(
I_t idx_node,
D_t * pt,
D_t * node_bounds_ptr,
I_t n_nodes,
I_t n_features,
I_t node_bounds_ptr_offset,
) nogil except -1:
"""Compute the minimum reduced-distance between a point and a node"""
cdef:
D_t d, d_lo, d_hi, node_min_j, node_max_j, rdist = 0.0
I_t j
for j in range(n_features):
node_min_j = deref(node_bounds_ptr + idx_node + j * n_nodes)
node_max_j = deref(node_bounds_ptr + idx_node + j * n_nodes + node_bounds_ptr_offset)
d_lo = node_min_j - pt[j]
d_hi = pt[j] - node_max_j
# We use the following identity:
#
# 0.5 * (x + abs(x)) = 0.5 * max(x, 0)
#
# twice.
d = 0.5 * ((d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi)))
rdist += d ** 2
return rdist
cdef cypclass QueryActor activable: cdef cypclass QueryActor activable:
D_t * query_points D_t * query_points_ptr
D_t * data_ptr D_t * data_ptr
I_t * node_bounds_ptr D_t * node_bounds_ptr
NodeData_t * node_data_ptr NodeData_t * node_data_ptr
I_t * indices_ptr I_t * indices_ptr
NeighborsHeaps heaps NeighborsHeaps heaps
...@@ -533,9 +564,9 @@ cdef cypclass QueryActor activable: ...@@ -533,9 +564,9 @@ cdef cypclass QueryActor activable:
__init__( __init__(
self, self,
D_t * query_points, D_t * query_points_ptr,
D_t * data_ptr, D_t * data_ptr,
I_t * node_bounds_ptr, D_t * node_bounds_ptr,
NodeData_t * node_data_ptr, NodeData_t * node_data_ptr,
I_t * indices_ptr, I_t * indices_ptr,
NeighborsHeaps heaps, NeighborsHeaps heaps,
...@@ -546,7 +577,7 @@ cdef cypclass QueryActor activable: ...@@ -546,7 +577,7 @@ cdef cypclass QueryActor activable:
I_t n_nodes, I_t n_nodes,
I_t node_bounds_ptr_offset, I_t node_bounds_ptr_offset,
): ):
self.query_points = query_points self.query_points_ptr = query_points_ptr
self.data_ptr = data_ptr self.data_ptr = data_ptr
self.node_bounds_ptr = node_bounds_ptr self.node_bounds_ptr = node_bounds_ptr
self.node_data_ptr = node_data_ptr self.node_data_ptr = node_data_ptr
...@@ -559,6 +590,10 @@ cdef cypclass QueryActor activable: ...@@ -559,6 +590,10 @@ cdef cypclass QueryActor activable:
self.n_nodes = n_nodes self.n_nodes = n_nodes
self.node_bounds_ptr_offset = node_bounds_ptr_offset self.node_bounds_ptr_offset = node_bounds_ptr_offset
# Needed for actors
self._active_result_class = WaitResult.construct
self._active_queue_class = consume BatchMailBox(scheduler)
int query(self) except -1: int query(self) except -1:
cdef: cdef:
I_t idx_pt I_t idx_pt
...@@ -566,35 +601,17 @@ cdef cypclass QueryActor activable: ...@@ -566,35 +601,17 @@ cdef cypclass QueryActor activable:
D_t reduced_dist_LB D_t reduced_dist_LB
for idx_pt in range(idx_start, idx_end): for idx_pt in range(idx_start, idx_end):
query_point = self.query_points + idx_pt * self.n_features query_point = self.query_points_ptr + idx_pt * self.n_features
reduced_dist_LB = self.min_rdist(0, query_point) reduced_dist_LB = min_rdist(
0, # idx_node
query_point,
node_bounds_ptr,
n_nodes,
n_features,
node_bounds_ptr_offset,
)
self._query_single_depthfirst(0, idx_pt, reduced_dist_LB) self._query_single_depthfirst(0, idx_pt, reduced_dist_LB)
D_t min_rdist(self,
I_t idx_node,
D_t * pt,
) except -1:
"""Compute the minimum reduced-distance between a point and a node"""
cdef:
D_t d, d_lo, d_hi, node_min_j, node_max_j, rdist = 0.0
I_t j
for j in range(self.n_features):
node_min_j = deref(self.node_bounds_ptr + idx_node + j * self.n_nodes)
node_max_j = deref(self.node_bounds_ptr + idx_node + j * self.n_nodes + self.node_bounds_ptr_offset)
d_lo = node_min_j - pt[j]
d_hi = pt[j] - node_max_j
# We use the following identity:
#
# 0.5 * (x + abs(x)) = 0.5 * max(x, 0)
#
# twice.
d = 0.5 * ((d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi)))
rdist += d ** 2
return rdist
int _query_single_depthfirst(self, int _query_single_depthfirst(self,
I_t idx_node, I_t idx_node,
I_t idx_pt, I_t idx_pt,
...@@ -606,7 +623,7 @@ cdef cypclass QueryActor activable: ...@@ -606,7 +623,7 @@ cdef cypclass QueryActor activable:
cdef D_t sq_dist, reduced_dist_LB_1, reduced_dist_LB_2 cdef D_t sq_dist, reduced_dist_LB_1, reduced_dist_LB_2
cdef I_t i, idx_left_node, idx_right_node cdef I_t i, idx_left_node, idx_right_node
cdef D_t * query_point = query_points + idx_pt * self.n_features cdef D_t * query_point = query_points_ptr + idx_pt * self.n_features
#------------------------------------------------------------ #------------------------------------------------------------
# Case 1: query point is outside node radius: # Case 1: query point is outside node radius:
...@@ -633,8 +650,24 @@ cdef cypclass QueryActor activable: ...@@ -633,8 +650,24 @@ cdef cypclass QueryActor activable:
else: else:
idx_left_node = 2 * idx_node + 1 idx_left_node = 2 * idx_node + 1
idx_right_node = idx_left_node + 1 idx_right_node = idx_left_node + 1
reduced_dist_LB_1 = self.min_rdist(idx_left_node, query_point)
reduced_dist_LB_2 = self.min_rdist(idx_right_node, query_point) reduced_dist_LB_1 = min_rdist(
idx_left_node,
query_point,
node_bounds_ptr,
n_nodes,
n_features,
node_bounds_ptr_offset,
)
reduced_dist_LB_2 = min_rdist(
idx_right_node,
query_point,
node_bounds_ptr,
n_nodes,
n_features,
node_bounds_ptr_offset,
)
# recursively query subnodes # recursively query subnodes
if reduced_dist_LB_1 <= reduced_dist_LB_2: if reduced_dist_LB_1 <= reduced_dist_LB_2:
...@@ -658,20 +691,20 @@ cdef cypclass KDTree: ...@@ -658,20 +691,20 @@ cdef cypclass KDTree:
This relies on a Cython+ runtime using actors. This relies on a Cython+ runtime using actors.
""" """
I_t _n_samples I_t n_samples
I_t _n_features I_t n_features
I_t _leaf_size I_t leaf_size
I_t _n_levels I_t n_levels
I_t _n_nodes I_t n_nodes
I_t _n_leafs I_t n_leafs
active Node _root active Node root
D_t *_data_ptr D_t * data_ptr
I_t *_indices_ptr I_t * indices_ptr
NodeData_t *_node_data_ptr NodeData_t * node_data_ptr
D_t * _node_bounds_ptr D_t * node_bounds_ptr
I_t _node_bounds_ptr_offset I_t node_bounds_ptr_offset
__init__( __init__(
...@@ -688,26 +721,26 @@ cdef cypclass KDTree: ...@@ -688,26 +721,26 @@ cdef cypclass KDTree:
# This OpenMP API is a workable way to access it. # This OpenMP API is a workable way to access it.
cdef I_t num_workers = omp_get_max_threads() cdef I_t num_workers = omp_get_max_threads()
self._n_samples = X.shape[0] self.n_samples = X.shape[0]
self._n_features = X.shape[1] self.n_features = X.shape[1]
self._leaf_size = leaf_size self.leaf_size = leaf_size
self._n_levels = <I_t> (log2(fmax(1, (self._n_samples - 1) / self._leaf_size)) + 1) self.n_levels = <I_t> (log2(fmax(1, (self.n_samples - 1) / self.leaf_size)) + 1)
self._n_nodes = <I_t> (2 ** (self._n_levels + 1)) self.n_nodes = <I_t> (2 ** (self.n_levels + 1))
self._data_ptr = <D_t *> X.data self.data_ptr = <D_t *> X.data
self._indices_ptr = <I_t *> malloc(self._n_samples * sizeof(I_t)) self.indices_ptr = <I_t *> malloc(self.n_samples * sizeof(I_t))
self._node_data_ptr = <NodeData_t *> malloc(self._n_nodes * sizeof(NodeData_t)) self.node_data_ptr = <NodeData_t *> malloc(self.n_nodes * sizeof(NodeData_t))
self._node_bounds_ptr_offset = self._n_nodes * self._n_features self.node_bounds_ptr_offset = self.n_nodes * self.n_features
# To be seen as a [2, n_nodes, d] with: # To be seen as a [2, n_nodes, d] with:
# - elements in [0, :, :] as min # - elements in [0, :, :] as min
# - elements in [1, :, :] as max # - elements in [1, :, :] as max
self._node_bounds_ptr = <D_t *> malloc(2 * self._node_bounds_ptr_offset * sizeof(D_t)) self.node_bounds_ptr = <D_t *> malloc(2 * self.node_bounds_ptr_offset * sizeof(D_t))
for i in range(self._n_samples): for i in range(self.n_samples):
self._indices_ptr[i] = i self.indices_ptr[i] = i
# Recursively building the tree here # Recursively building the tree here
global scheduler global scheduler
...@@ -717,8 +750,8 @@ cdef cypclass KDTree: ...@@ -717,8 +750,8 @@ cdef cypclass KDTree:
# the asynchronous construction of the tree. # the asynchronous construction of the tree.
cdef active Counter counter = consume Counter() cdef active Counter counter = consume Counter()
self._root = consume Node(self._node_data_ptr, self._node_bounds_ptr, self._node_bounds_ptr_offset) self.root = consume Node(self.node_data_ptr, self.node_bounds_ptr, self.node_bounds_ptr_offset)
if self._root is NULL: if self.root is NULL:
printf("Error consuming node\n") printf("Error consuming node\n")
# When object are activated (set as Actors), methods # When object are activated (set as Actors), methods
...@@ -728,31 +761,31 @@ cdef cypclass KDTree: ...@@ -728,31 +761,31 @@ cdef cypclass KDTree:
# #
# Also using this separate method allowing using actors # Also using this separate method allowing using actors
# because __init__ can't be reified. # because __init__ can't be reified.
self._root.build_node( self.root.build_node(
sync_method=NULL, sync_method=NULL,
node_index=0, node_index=0,
data_ptr=self._data_ptr, data_ptr=self.data_ptr,
indices_ptr=self._indices_ptr, indices_ptr=self.indices_ptr,
leaf_size=self._leaf_size, leaf_size=self.leaf_size,
n_features=self._n_features, n_features=self.n_features,
dim=0, dim=0,
idx_start=0, idx_start=0,
idx_end=self._n_samples, idx_end=self.n_samples,
counter=counter, counter=counter,
) )
# Waiting for the tree construction to end # Waiting for the tree construction to end
# Somewhat similar to a thread barrier # Somewhat similar to a thread barrier
while initialised < self._n_samples: while initialised < self.n_samples:
initialised = counter.value(NULL).getIntResult() initialised = counter.value(NULL).getIntResult()
counter.reset(NULL) counter.reset(NULL)
void __dealloc__(self): void __dealloc__(self):
scheduler.finish() scheduler.finish()
free(self._indices_ptr) free(self.indices_ptr)
free(self._node_data_ptr) free(self.node_data_ptr)
free(self._node_bounds_ptr) free(self.node_bounds_ptr)
void query(self, void query(self,
np.ndarray query_points, # IN np.ndarray query_points, # IN
...@@ -765,7 +798,7 @@ cdef cypclass KDTree: ...@@ -765,7 +798,7 @@ cdef cypclass KDTree:
I_t n_query = query_points.shape[0] I_t n_query = query_points.shape[0]
I_t n_features = query_points.shape[1] I_t n_features = query_points.shape[1]
I_t n_neighbors = knn_indices.shape[1] I_t n_neighbors = knn_indices.shape[1]
D_t * _query_points = <D_t *> query_points.data D_t * query_points_ptr = <D_t *> query_points.data
D_t rdist_lower_bound D_t rdist_lower_bound
I_t n_workers = omp_get_max_threads() I_t n_workers = omp_get_max_threads()
I_t n_points_worker = <I_t> ceil(n_query / n_workers) I_t n_points_worker = <I_t> ceil(n_query / n_workers)
...@@ -783,17 +816,18 @@ cdef cypclass KDTree: ...@@ -783,17 +816,18 @@ cdef cypclass KDTree:
for idx_worker in range(n_workers): for idx_worker in range(n_workers):
query_actor = consume QueryActor( query_actor = consume QueryActor(
query_points, query_points_ptr,
self._node_bounds_ptr, data_ptr,
self._node_data_ptr, self.node_bounds_ptr,
self._indices_ptr, self.node_data_ptr,
self.indices_ptr,
heaps, heaps,
idx_worker, idx_worker,
n_points_worker * idx_worker, n_points_worker * idx_worker,
min(n_points_worker * (idx_worker + 1), n_query), min(n_points_worker * (idx_worker + 1), n_query),
n_features, n_features,
self._n_nodes, self.n_nodes,
self._node_bounds_ptr_offset, self.node_bounds_ptr_offset,
) )
query_actor.query(NULL) query_actor.query(NULL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment