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:
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:
D_t * query_points
D_t * query_points_ptr
D_t * data_ptr
I_t * node_bounds_ptr
D_t * node_bounds_ptr
NodeData_t * node_data_ptr
I_t * indices_ptr
NeighborsHeaps heaps
......@@ -533,9 +564,9 @@ cdef cypclass QueryActor activable:
__init__(
self,
D_t * query_points,
D_t * query_points_ptr,
D_t * data_ptr,
I_t * node_bounds_ptr,
D_t * node_bounds_ptr,
NodeData_t * node_data_ptr,
I_t * indices_ptr,
NeighborsHeaps heaps,
......@@ -546,7 +577,7 @@ cdef cypclass QueryActor activable:
I_t n_nodes,
I_t node_bounds_ptr_offset,
):
self.query_points = query_points
self.query_points_ptr = query_points_ptr
self.data_ptr = data_ptr
self.node_bounds_ptr = node_bounds_ptr
self.node_data_ptr = node_data_ptr
......@@ -559,6 +590,10 @@ cdef cypclass QueryActor activable:
self.n_nodes = n_nodes
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:
cdef:
I_t idx_pt
......@@ -566,35 +601,17 @@ cdef cypclass QueryActor activable:
D_t reduced_dist_LB
for idx_pt in range(idx_start, idx_end):
query_point = self.query_points + idx_pt * self.n_features
reduced_dist_LB = self.min_rdist(0, query_point)
query_point = self.query_points_ptr + idx_pt * self.n_features
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)
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,
I_t idx_node,
I_t idx_pt,
......@@ -606,7 +623,7 @@ cdef cypclass QueryActor activable:
cdef D_t sq_dist, reduced_dist_LB_1, reduced_dist_LB_2
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:
......@@ -633,8 +650,24 @@ cdef cypclass QueryActor activable:
else:
idx_left_node = 2 * idx_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
if reduced_dist_LB_1 <= reduced_dist_LB_2:
......@@ -658,20 +691,20 @@ cdef cypclass KDTree:
This relies on a Cython+ runtime using actors.
"""
I_t _n_samples
I_t _n_features
I_t _leaf_size
I_t _n_levels
I_t _n_nodes
I_t _n_leafs
I_t n_samples
I_t n_features
I_t leaf_size
I_t n_levels
I_t n_nodes
I_t n_leafs
active Node _root
active Node root
D_t *_data_ptr
I_t *_indices_ptr
NodeData_t *_node_data_ptr
D_t * _node_bounds_ptr
I_t _node_bounds_ptr_offset
D_t * data_ptr
I_t * indices_ptr
NodeData_t * node_data_ptr
D_t * node_bounds_ptr
I_t node_bounds_ptr_offset
__init__(
......@@ -688,26 +721,26 @@ cdef cypclass KDTree:
# This OpenMP API is a workable way to access it.
cdef I_t num_workers = omp_get_max_threads()
self._n_samples = X.shape[0]
self._n_features = X.shape[1]
self._leaf_size = leaf_size
self.n_samples = X.shape[0]
self.n_features = X.shape[1]
self.leaf_size = leaf_size
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_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._data_ptr = <D_t *> X.data
self._indices_ptr = <I_t *> malloc(self._n_samples * sizeof(I_t))
self.data_ptr = <D_t *> X.data
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_bounds_ptr_offset = self._n_nodes * self._n_features
self.node_data_ptr = <NodeData_t *> malloc(self.n_nodes * sizeof(NodeData_t))
self.node_bounds_ptr_offset = self.n_nodes * self.n_features
# To be seen as a [2, n_nodes, d] with:
# - elements in [0, :, :] as min
# - 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):
self._indices_ptr[i] = i
for i in range(self.n_samples):
self.indices_ptr[i] = i
# Recursively building the tree here
global scheduler
......@@ -717,8 +750,8 @@ cdef cypclass KDTree:
# the asynchronous construction of the tree.
cdef active Counter counter = consume Counter()
self._root = consume Node(self._node_data_ptr, self._node_bounds_ptr, self._node_bounds_ptr_offset)
if self._root is NULL:
self.root = consume Node(self.node_data_ptr, self.node_bounds_ptr, self.node_bounds_ptr_offset)
if self.root is NULL:
printf("Error consuming node\n")
# When object are activated (set as Actors), methods
......@@ -728,31 +761,31 @@ cdef cypclass KDTree:
#
# Also using this separate method allowing using actors
# because __init__ can't be reified.
self._root.build_node(
self.root.build_node(
sync_method=NULL,
node_index=0,
data_ptr=self._data_ptr,
indices_ptr=self._indices_ptr,
leaf_size=self._leaf_size,
n_features=self._n_features,
data_ptr=self.data_ptr,
indices_ptr=self.indices_ptr,
leaf_size=self.leaf_size,
n_features=self.n_features,
dim=0,
idx_start=0,
idx_end=self._n_samples,
idx_end=self.n_samples,
counter=counter,
)
# Waiting for the tree construction to end
# Somewhat similar to a thread barrier
while initialised < self._n_samples:
while initialised < self.n_samples:
initialised = counter.value(NULL).getIntResult()
counter.reset(NULL)
void __dealloc__(self):
scheduler.finish()
free(self._indices_ptr)
free(self._node_data_ptr)
free(self._node_bounds_ptr)
free(self.indices_ptr)
free(self.node_data_ptr)
free(self.node_bounds_ptr)
void query(self,
np.ndarray query_points, # IN
......@@ -765,7 +798,7 @@ cdef cypclass KDTree:
I_t n_query = query_points.shape[0]
I_t n_features = query_points.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
I_t n_workers = omp_get_max_threads()
I_t n_points_worker = <I_t> ceil(n_query / n_workers)
......@@ -783,17 +816,18 @@ cdef cypclass KDTree:
for idx_worker in range(n_workers):
query_actor = consume QueryActor(
query_points,
self._node_bounds_ptr,
self._node_data_ptr,
self._indices_ptr,
query_points_ptr,
data_ptr,
self.node_bounds_ptr,
self.node_data_ptr,
self.indices_ptr,
heaps,
idx_worker,
n_points_worker * idx_worker,
min(n_points_worker * (idx_worker + 1), n_query),
n_features,
self._n_nodes,
self._node_bounds_ptr_offset,
self.n_nodes,
self.node_bounds_ptr_offset,
)
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