release(camera-ai): publish 0.4.12 catalog portability fix
This commit is contained in:
@@ -1,284 +1,284 @@
|
||||
{{py:
|
||||
|
||||
# Generated file: _ball_tree.pyx
|
||||
|
||||
implementation_specific_values = [
|
||||
# The values are arranged as follows:
|
||||
#
|
||||
# name_suffix, INPUT_DTYPE_t, INPUT_DTYPE
|
||||
#
|
||||
('64', 'float64_t', 'np.float64'),
|
||||
('32', 'float32_t', 'np.float32')
|
||||
]
|
||||
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
}}
|
||||
|
||||
|
||||
__all__ = ['BallTree', 'BallTree64', 'BallTree32']
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
DOC_DICT{{name_suffix}} = {
|
||||
'BinaryTree': 'BallTree{{name_suffix}}',
|
||||
'binary_tree': 'ball_tree{{name_suffix}}',
|
||||
}
|
||||
|
||||
VALID_METRICS{{name_suffix}} = [
|
||||
'BrayCurtisDistance{{name_suffix}}',
|
||||
'CanberraDistance{{name_suffix}}',
|
||||
'ChebyshevDistance{{name_suffix}}',
|
||||
'DiceDistance{{name_suffix}}',
|
||||
'EuclideanDistance{{name_suffix}}',
|
||||
'HammingDistance{{name_suffix}}',
|
||||
'HaversineDistance{{name_suffix}}',
|
||||
'JaccardDistance{{name_suffix}}',
|
||||
'MahalanobisDistance{{name_suffix}}',
|
||||
'ManhattanDistance{{name_suffix}}',
|
||||
'MinkowskiDistance{{name_suffix}}',
|
||||
'PyFuncDistance{{name_suffix}}',
|
||||
'RogersTanimotoDistance{{name_suffix}}',
|
||||
'RussellRaoDistance{{name_suffix}}',
|
||||
'SEuclideanDistance{{name_suffix}}',
|
||||
'SokalMichenerDistance{{name_suffix}}',
|
||||
'SokalSneathDistance{{name_suffix}}',
|
||||
'WMinkowskiDistance{{name_suffix}}',
|
||||
]
|
||||
|
||||
{{endfor}}
|
||||
|
||||
include "_binary_tree.pxi"
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
# Inherit BallTree{{name_suffix}} from BinaryTree{{name_suffix}}
|
||||
cdef class BallTree{{name_suffix}}(BinaryTree{{name_suffix}}):
|
||||
__doc__ = CLASS_DOC.format(**DOC_DICT{{name_suffix}})
|
||||
pass
|
||||
|
||||
{{endfor}}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# The functions below specialized the Binary Tree as a Ball Tree
|
||||
#
|
||||
# Note that these functions use the concept of "reduced distance".
|
||||
# The reduced distance, defined for some metrics, is a quantity which
|
||||
# is more efficient to compute than the distance, but preserves the
|
||||
# relative rankings of the true distance. For example, the reduced
|
||||
# distance for the Euclidean metric is the squared-euclidean distance.
|
||||
# For some metrics, the reduced distance is simply the distance.
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
cdef int allocate_data{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t n_nodes,
|
||||
intp_t n_features,
|
||||
) except -1:
|
||||
"""Allocate arrays needed for the KD Tree"""
|
||||
tree.node_bounds = np.zeros((1, n_nodes, n_features), dtype={{INPUT_DTYPE}})
|
||||
return 0
|
||||
|
||||
|
||||
cdef int init_node{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
NodeData_t[::1] node_data,
|
||||
intp_t i_node,
|
||||
intp_t idx_start,
|
||||
intp_t idx_end,
|
||||
) except -1:
|
||||
"""Initialize the node for the dataset stored in tree.data"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
cdef intp_t n_points = idx_end - idx_start
|
||||
|
||||
cdef intp_t i, j
|
||||
cdef float64_t radius
|
||||
cdef const {{INPUT_DTYPE_t}} *this_pt
|
||||
|
||||
cdef intp_t* idx_array = &tree.idx_array[0]
|
||||
cdef const {{INPUT_DTYPE_t}}* data = &tree.data[0, 0]
|
||||
cdef {{INPUT_DTYPE_t}}* centroid = &tree.node_bounds[0, i_node, 0]
|
||||
|
||||
cdef bint with_sample_weight = tree.sample_weight is not None
|
||||
cdef const {{INPUT_DTYPE_t}}* sample_weight
|
||||
cdef float64_t sum_weight_node
|
||||
if with_sample_weight:
|
||||
sample_weight = &tree.sample_weight[0]
|
||||
|
||||
# determine Node centroid
|
||||
for j in range(n_features):
|
||||
centroid[j] = 0
|
||||
|
||||
if with_sample_weight:
|
||||
sum_weight_node = 0
|
||||
for i in range(idx_start, idx_end):
|
||||
sum_weight_node += sample_weight[idx_array[i]]
|
||||
this_pt = data + n_features * idx_array[i]
|
||||
for j from 0 <= j < n_features:
|
||||
centroid[j] += this_pt[j] * sample_weight[idx_array[i]]
|
||||
|
||||
for j in range(n_features):
|
||||
centroid[j] /= sum_weight_node
|
||||
else:
|
||||
for i in range(idx_start, idx_end):
|
||||
this_pt = data + n_features * idx_array[i]
|
||||
for j from 0 <= j < n_features:
|
||||
centroid[j] += this_pt[j]
|
||||
|
||||
for j in range(n_features):
|
||||
centroid[j] /= n_points
|
||||
|
||||
# determine Node radius
|
||||
radius = 0
|
||||
for i in range(idx_start, idx_end):
|
||||
radius = fmax(radius,
|
||||
tree.rdist(centroid,
|
||||
data + n_features * idx_array[i],
|
||||
n_features))
|
||||
|
||||
node_data[i_node].radius = tree.dist_metric._rdist_to_dist(radius)
|
||||
node_data[i_node].idx_start = idx_start
|
||||
node_data[i_node].idx_end = idx_end
|
||||
return 0
|
||||
|
||||
|
||||
cdef inline float64_t min_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum distance between a point and a node"""
|
||||
cdef float64_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0],
|
||||
tree.data.shape[1])
|
||||
return fmax(0, dist_pt - tree.node_data[i_node].radius)
|
||||
|
||||
|
||||
cdef inline float64_t max_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the maximum distance between a point and a node"""
|
||||
cdef float64_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0],
|
||||
tree.data.shape[1])
|
||||
return dist_pt + tree.node_data[i_node].radius
|
||||
|
||||
|
||||
cdef inline int min_max_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
float64_t* min_dist,
|
||||
float64_t* max_dist,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum and maximum distance between a point and a node"""
|
||||
cdef float64_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0],
|
||||
tree.data.shape[1])
|
||||
cdef float64_t rad = tree.node_data[i_node].radius
|
||||
min_dist[0] = fmax(0, dist_pt - rad)
|
||||
max_dist[0] = dist_pt + rad
|
||||
return 0
|
||||
|
||||
|
||||
cdef inline float64_t min_rdist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum reduced-distance between a point and a node"""
|
||||
if tree.euclidean:
|
||||
return euclidean_dist_to_rdist{{name_suffix}}(
|
||||
min_dist{{name_suffix}}(tree, i_node, pt)
|
||||
)
|
||||
else:
|
||||
return tree.dist_metric._dist_to_rdist(
|
||||
min_dist{{name_suffix}}(tree, i_node, pt)
|
||||
)
|
||||
|
||||
|
||||
cdef inline float64_t max_rdist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the maximum reduced-distance between a point and a node"""
|
||||
if tree.euclidean:
|
||||
return euclidean_dist_to_rdist{{name_suffix}}(
|
||||
max_dist{{name_suffix}}(tree, i_node, pt)
|
||||
)
|
||||
else:
|
||||
return tree.dist_metric._dist_to_rdist(
|
||||
max_dist{{name_suffix}}(tree, i_node, pt)
|
||||
)
|
||||
|
||||
|
||||
cdef inline float64_t min_dist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""compute the minimum distance between two nodes"""
|
||||
cdef float64_t dist_pt = tree1.dist(&tree2.node_bounds[0, i_node2, 0],
|
||||
&tree1.node_bounds[0, i_node1, 0],
|
||||
tree1.data.shape[1])
|
||||
return fmax(0, (dist_pt - tree1.node_data[i_node1].radius
|
||||
- tree2.node_data[i_node2].radius))
|
||||
|
||||
|
||||
cdef inline float64_t max_dist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""compute the maximum distance between two nodes"""
|
||||
cdef float64_t dist_pt = tree1.dist(&tree2.node_bounds[0, i_node2, 0],
|
||||
&tree1.node_bounds[0, i_node1, 0],
|
||||
tree1.data.shape[1])
|
||||
return (dist_pt + tree1.node_data[i_node1].radius
|
||||
+ tree2.node_data[i_node2].radius)
|
||||
|
||||
|
||||
cdef inline float64_t min_rdist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""compute the minimum reduced distance between two nodes"""
|
||||
if tree1.euclidean:
|
||||
return euclidean_dist_to_rdist{{name_suffix}}(
|
||||
min_dist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
else:
|
||||
return tree1.dist_metric._dist_to_rdist(
|
||||
min_dist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
|
||||
|
||||
cdef inline float64_t max_rdist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""compute the maximum reduced distance between two nodes"""
|
||||
if tree1.euclidean:
|
||||
return euclidean_dist_to_rdist{{name_suffix}}(
|
||||
max_dist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
else:
|
||||
return tree1.dist_metric._dist_to_rdist(
|
||||
max_dist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
|
||||
{{endfor}}
|
||||
|
||||
|
||||
class BallTree(BallTree64):
|
||||
__doc__ = CLASS_DOC.format(BinaryTree="BallTree")
|
||||
pass
|
||||
{{py:
|
||||
|
||||
# Generated file: _ball_tree.pyx
|
||||
|
||||
implementation_specific_values = [
|
||||
# The values are arranged as follows:
|
||||
#
|
||||
# name_suffix, INPUT_DTYPE_t, INPUT_DTYPE
|
||||
#
|
||||
('64', 'float64_t', 'np.float64'),
|
||||
('32', 'float32_t', 'np.float32')
|
||||
]
|
||||
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
}}
|
||||
|
||||
|
||||
__all__ = ['BallTree', 'BallTree64', 'BallTree32']
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
DOC_DICT{{name_suffix}} = {
|
||||
'BinaryTree': 'BallTree{{name_suffix}}',
|
||||
'binary_tree': 'ball_tree{{name_suffix}}',
|
||||
}
|
||||
|
||||
VALID_METRICS{{name_suffix}} = [
|
||||
'BrayCurtisDistance{{name_suffix}}',
|
||||
'CanberraDistance{{name_suffix}}',
|
||||
'ChebyshevDistance{{name_suffix}}',
|
||||
'DiceDistance{{name_suffix}}',
|
||||
'EuclideanDistance{{name_suffix}}',
|
||||
'HammingDistance{{name_suffix}}',
|
||||
'HaversineDistance{{name_suffix}}',
|
||||
'JaccardDistance{{name_suffix}}',
|
||||
'MahalanobisDistance{{name_suffix}}',
|
||||
'ManhattanDistance{{name_suffix}}',
|
||||
'MinkowskiDistance{{name_suffix}}',
|
||||
'PyFuncDistance{{name_suffix}}',
|
||||
'RogersTanimotoDistance{{name_suffix}}',
|
||||
'RussellRaoDistance{{name_suffix}}',
|
||||
'SEuclideanDistance{{name_suffix}}',
|
||||
'SokalMichenerDistance{{name_suffix}}',
|
||||
'SokalSneathDistance{{name_suffix}}',
|
||||
'WMinkowskiDistance{{name_suffix}}',
|
||||
]
|
||||
|
||||
{{endfor}}
|
||||
|
||||
include "_binary_tree.pxi"
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
# Inherit BallTree{{name_suffix}} from BinaryTree{{name_suffix}}
|
||||
cdef class BallTree{{name_suffix}}(BinaryTree{{name_suffix}}):
|
||||
__doc__ = CLASS_DOC.format(**DOC_DICT{{name_suffix}})
|
||||
pass
|
||||
|
||||
{{endfor}}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# The functions below specialized the Binary Tree as a Ball Tree
|
||||
#
|
||||
# Note that these functions use the concept of "reduced distance".
|
||||
# The reduced distance, defined for some metrics, is a quantity which
|
||||
# is more efficient to compute than the distance, but preserves the
|
||||
# relative rankings of the true distance. For example, the reduced
|
||||
# distance for the Euclidean metric is the squared-euclidean distance.
|
||||
# For some metrics, the reduced distance is simply the distance.
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
cdef int allocate_data{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t n_nodes,
|
||||
intp_t n_features,
|
||||
) except -1:
|
||||
"""Allocate arrays needed for the KD Tree"""
|
||||
tree.node_bounds = np.zeros((1, n_nodes, n_features), dtype={{INPUT_DTYPE}})
|
||||
return 0
|
||||
|
||||
|
||||
cdef int init_node{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
NodeData_t[::1] node_data,
|
||||
intp_t i_node,
|
||||
intp_t idx_start,
|
||||
intp_t idx_end,
|
||||
) except -1:
|
||||
"""Initialize the node for the dataset stored in tree.data"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
cdef intp_t n_points = idx_end - idx_start
|
||||
|
||||
cdef intp_t i, j
|
||||
cdef float64_t radius
|
||||
cdef const {{INPUT_DTYPE_t}} *this_pt
|
||||
|
||||
cdef intp_t* idx_array = &tree.idx_array[0]
|
||||
cdef const {{INPUT_DTYPE_t}}* data = &tree.data[0, 0]
|
||||
cdef {{INPUT_DTYPE_t}}* centroid = &tree.node_bounds[0, i_node, 0]
|
||||
|
||||
cdef bint with_sample_weight = tree.sample_weight is not None
|
||||
cdef const {{INPUT_DTYPE_t}}* sample_weight
|
||||
cdef float64_t sum_weight_node
|
||||
if with_sample_weight:
|
||||
sample_weight = &tree.sample_weight[0]
|
||||
|
||||
# determine Node centroid
|
||||
for j in range(n_features):
|
||||
centroid[j] = 0
|
||||
|
||||
if with_sample_weight:
|
||||
sum_weight_node = 0
|
||||
for i in range(idx_start, idx_end):
|
||||
sum_weight_node += sample_weight[idx_array[i]]
|
||||
this_pt = data + n_features * idx_array[i]
|
||||
for j from 0 <= j < n_features:
|
||||
centroid[j] += this_pt[j] * sample_weight[idx_array[i]]
|
||||
|
||||
for j in range(n_features):
|
||||
centroid[j] /= sum_weight_node
|
||||
else:
|
||||
for i in range(idx_start, idx_end):
|
||||
this_pt = data + n_features * idx_array[i]
|
||||
for j from 0 <= j < n_features:
|
||||
centroid[j] += this_pt[j]
|
||||
|
||||
for j in range(n_features):
|
||||
centroid[j] /= n_points
|
||||
|
||||
# determine Node radius
|
||||
radius = 0
|
||||
for i in range(idx_start, idx_end):
|
||||
radius = fmax(radius,
|
||||
tree.rdist(centroid,
|
||||
data + n_features * idx_array[i],
|
||||
n_features))
|
||||
|
||||
node_data[i_node].radius = tree.dist_metric._rdist_to_dist(radius)
|
||||
node_data[i_node].idx_start = idx_start
|
||||
node_data[i_node].idx_end = idx_end
|
||||
return 0
|
||||
|
||||
|
||||
cdef inline float64_t min_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum distance between a point and a node"""
|
||||
cdef float64_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0],
|
||||
tree.data.shape[1])
|
||||
return fmax(0, dist_pt - tree.node_data[i_node].radius)
|
||||
|
||||
|
||||
cdef inline float64_t max_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the maximum distance between a point and a node"""
|
||||
cdef float64_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0],
|
||||
tree.data.shape[1])
|
||||
return dist_pt + tree.node_data[i_node].radius
|
||||
|
||||
|
||||
cdef inline int min_max_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
float64_t* min_dist,
|
||||
float64_t* max_dist,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum and maximum distance between a point and a node"""
|
||||
cdef float64_t dist_pt = tree.dist(pt, &tree.node_bounds[0, i_node, 0],
|
||||
tree.data.shape[1])
|
||||
cdef float64_t rad = tree.node_data[i_node].radius
|
||||
min_dist[0] = fmax(0, dist_pt - rad)
|
||||
max_dist[0] = dist_pt + rad
|
||||
return 0
|
||||
|
||||
|
||||
cdef inline float64_t min_rdist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum reduced-distance between a point and a node"""
|
||||
if tree.euclidean:
|
||||
return euclidean_dist_to_rdist{{name_suffix}}(
|
||||
min_dist{{name_suffix}}(tree, i_node, pt)
|
||||
)
|
||||
else:
|
||||
return tree.dist_metric._dist_to_rdist(
|
||||
min_dist{{name_suffix}}(tree, i_node, pt)
|
||||
)
|
||||
|
||||
|
||||
cdef inline float64_t max_rdist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the maximum reduced-distance between a point and a node"""
|
||||
if tree.euclidean:
|
||||
return euclidean_dist_to_rdist{{name_suffix}}(
|
||||
max_dist{{name_suffix}}(tree, i_node, pt)
|
||||
)
|
||||
else:
|
||||
return tree.dist_metric._dist_to_rdist(
|
||||
max_dist{{name_suffix}}(tree, i_node, pt)
|
||||
)
|
||||
|
||||
|
||||
cdef inline float64_t min_dist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""compute the minimum distance between two nodes"""
|
||||
cdef float64_t dist_pt = tree1.dist(&tree2.node_bounds[0, i_node2, 0],
|
||||
&tree1.node_bounds[0, i_node1, 0],
|
||||
tree1.data.shape[1])
|
||||
return fmax(0, (dist_pt - tree1.node_data[i_node1].radius
|
||||
- tree2.node_data[i_node2].radius))
|
||||
|
||||
|
||||
cdef inline float64_t max_dist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""compute the maximum distance between two nodes"""
|
||||
cdef float64_t dist_pt = tree1.dist(&tree2.node_bounds[0, i_node2, 0],
|
||||
&tree1.node_bounds[0, i_node1, 0],
|
||||
tree1.data.shape[1])
|
||||
return (dist_pt + tree1.node_data[i_node1].radius
|
||||
+ tree2.node_data[i_node2].radius)
|
||||
|
||||
|
||||
cdef inline float64_t min_rdist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""compute the minimum reduced distance between two nodes"""
|
||||
if tree1.euclidean:
|
||||
return euclidean_dist_to_rdist{{name_suffix}}(
|
||||
min_dist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
else:
|
||||
return tree1.dist_metric._dist_to_rdist(
|
||||
min_dist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
|
||||
|
||||
cdef inline float64_t max_rdist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""compute the maximum reduced distance between two nodes"""
|
||||
if tree1.euclidean:
|
||||
return euclidean_dist_to_rdist{{name_suffix}}(
|
||||
max_dist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
else:
|
||||
return tree1.dist_metric._dist_to_rdist(
|
||||
max_dist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
|
||||
{{endfor}}
|
||||
|
||||
|
||||
class BallTree(BallTree64):
|
||||
__doc__ = CLASS_DOC.format(BinaryTree="BallTree")
|
||||
pass
|
||||
|
||||
+2478
-2478
File diff suppressed because it is too large
Load Diff
@@ -1,336 +1,336 @@
|
||||
{{py:
|
||||
|
||||
# Generated file: _kd_tree.pyx
|
||||
|
||||
implementation_specific_values = [
|
||||
# The values are arranged as follows:
|
||||
#
|
||||
# name_suffix, INPUT_DTYPE_t, INPUT_DTYPE
|
||||
#
|
||||
('64', 'float64_t', 'np.float64'),
|
||||
('32', 'float32_t', 'np.float32')
|
||||
]
|
||||
|
||||
# By Jake Vanderplas (2013) <jakevdp@cs.washington.edu>
|
||||
# written for the scikit-learn project
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
}}
|
||||
|
||||
|
||||
__all__ = ['KDTree', 'KDTree64', 'KDTree32']
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
DOC_DICT{{name_suffix}} = {
|
||||
'BinaryTree': 'KDTree{{name_suffix}}',
|
||||
'binary_tree': 'kd_tree{{name_suffix}}',
|
||||
}
|
||||
|
||||
VALID_METRICS{{name_suffix}} = [
|
||||
'EuclideanDistance{{name_suffix}}',
|
||||
'ManhattanDistance{{name_suffix}}',
|
||||
'ChebyshevDistance{{name_suffix}}',
|
||||
'MinkowskiDistance{{name_suffix}}'
|
||||
]
|
||||
|
||||
{{endfor}}
|
||||
|
||||
include "_binary_tree.pxi"
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
# Inherit KDTree{{name_suffix}} from BinaryTree{{name_suffix}}
|
||||
cdef class KDTree{{name_suffix}}(BinaryTree{{name_suffix}}):
|
||||
__doc__ = CLASS_DOC.format(**DOC_DICT{{name_suffix}})
|
||||
pass
|
||||
|
||||
{{endfor}}
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# The functions below specialized the Binary Tree as a KD Tree
|
||||
#
|
||||
# Note that these functions use the concept of "reduced distance".
|
||||
# The reduced distance, defined for some metrics, is a quantity which
|
||||
# is more efficient to compute than the distance, but preserves the
|
||||
# relative rankings of the true distance. For example, the reduced
|
||||
# distance for the Euclidean metric is the squared-euclidean distance.
|
||||
# For some metrics, the reduced distance is simply the distance.
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
cdef int allocate_data{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t n_nodes,
|
||||
intp_t n_features,
|
||||
) except -1:
|
||||
"""Allocate arrays needed for the KD Tree"""
|
||||
tree.node_bounds = np.zeros((2, n_nodes, n_features), dtype={{INPUT_DTYPE}})
|
||||
return 0
|
||||
|
||||
|
||||
cdef int init_node{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
NodeData_t[::1] node_data,
|
||||
intp_t i_node,
|
||||
intp_t idx_start,
|
||||
intp_t idx_end,
|
||||
) except -1:
|
||||
"""Initialize the node for the dataset stored in tree.data"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
cdef intp_t i, j
|
||||
cdef float64_t rad = 0
|
||||
|
||||
cdef {{INPUT_DTYPE_t}}* lower_bounds = &tree.node_bounds[0, i_node, 0]
|
||||
cdef {{INPUT_DTYPE_t}}* upper_bounds = &tree.node_bounds[1, i_node, 0]
|
||||
cdef const {{INPUT_DTYPE_t}}* data = &tree.data[0, 0]
|
||||
cdef const intp_t* idx_array = &tree.idx_array[0]
|
||||
|
||||
cdef const {{INPUT_DTYPE_t}}* data_row
|
||||
|
||||
# determine Node bounds
|
||||
for j in range(n_features):
|
||||
lower_bounds[j] = INF
|
||||
upper_bounds[j] = -INF
|
||||
|
||||
# Compute the actual data range. At build time, this is slightly
|
||||
# slower than using the previously-computed bounds of the parent node,
|
||||
# but leads to more compact trees and thus faster queries.
|
||||
for i in range(idx_start, idx_end):
|
||||
data_row = data + idx_array[i] * n_features
|
||||
for j in range(n_features):
|
||||
lower_bounds[j] = fmin(lower_bounds[j], data_row[j])
|
||||
upper_bounds[j] = fmax(upper_bounds[j], data_row[j])
|
||||
|
||||
for j in range(n_features):
|
||||
if tree.dist_metric.p == INF:
|
||||
rad = fmax(rad, 0.5 * (upper_bounds[j] - lower_bounds[j]))
|
||||
else:
|
||||
rad += pow(0.5 * abs(upper_bounds[j] - lower_bounds[j]),
|
||||
tree.dist_metric.p)
|
||||
|
||||
node_data[i_node].idx_start = idx_start
|
||||
node_data[i_node].idx_end = idx_end
|
||||
|
||||
# The radius will hold the size of the circumscribed hypersphere measured
|
||||
# with the specified metric: in querying, this is used as a measure of the
|
||||
# size of each node when deciding which nodes to split.
|
||||
node_data[i_node].radius = pow(rad, 1. / tree.dist_metric.p)
|
||||
return 0
|
||||
|
||||
|
||||
cdef float64_t min_rdist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum reduced-distance between a point and a node"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
cdef float64_t d, d_lo, d_hi, rdist=0.0
|
||||
cdef intp_t j
|
||||
|
||||
if tree.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
d_lo = tree.node_bounds[0, i_node, j] - pt[j]
|
||||
d_hi = pt[j] - tree.node_bounds[1, i_node, j]
|
||||
d = (d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi))
|
||||
rdist = fmax(rdist, 0.5 * d)
|
||||
else:
|
||||
# here we'll use the fact that x + abs(x) = 2 * max(x, 0)
|
||||
for j in range(n_features):
|
||||
d_lo = tree.node_bounds[0, i_node, j] - pt[j]
|
||||
d_hi = pt[j] - tree.node_bounds[1, i_node, j]
|
||||
d = (d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi))
|
||||
rdist += pow(0.5 * d, tree.dist_metric.p)
|
||||
|
||||
return rdist
|
||||
|
||||
|
||||
cdef float64_t min_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the minimum distance between a point and a node"""
|
||||
if tree.dist_metric.p == INF:
|
||||
return min_rdist{{name_suffix}}(tree, i_node, pt)
|
||||
else:
|
||||
return pow(
|
||||
min_rdist{{name_suffix}}(tree, i_node, pt),
|
||||
1. / tree.dist_metric.p
|
||||
)
|
||||
|
||||
|
||||
cdef float64_t max_rdist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the maximum reduced-distance between a point and a node"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
|
||||
cdef float64_t d_lo, d_hi, rdist=0.0
|
||||
cdef intp_t j
|
||||
|
||||
if tree.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
rdist = fmax(rdist, fabs(pt[j] - tree.node_bounds[0, i_node, j]))
|
||||
rdist = fmax(rdist, fabs(pt[j] - tree.node_bounds[1, i_node, j]))
|
||||
else:
|
||||
for j in range(n_features):
|
||||
d_lo = fabs(pt[j] - tree.node_bounds[0, i_node, j])
|
||||
d_hi = fabs(pt[j] - tree.node_bounds[1, i_node, j])
|
||||
rdist += pow(fmax(d_lo, d_hi), tree.dist_metric.p)
|
||||
|
||||
return rdist
|
||||
|
||||
|
||||
cdef float64_t max_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the maximum distance between a point and a node"""
|
||||
if tree.dist_metric.p == INF:
|
||||
return max_rdist{{name_suffix}}(tree, i_node, pt)
|
||||
else:
|
||||
return pow(
|
||||
max_rdist{{name_suffix}}(tree, i_node, pt),
|
||||
1. / tree.dist_metric.p
|
||||
)
|
||||
|
||||
|
||||
cdef inline int min_max_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
float64_t* min_dist,
|
||||
float64_t* max_dist,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum and maximum distance between a point and a node"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
|
||||
cdef float64_t d, d_lo, d_hi
|
||||
cdef intp_t j
|
||||
|
||||
min_dist[0] = 0.0
|
||||
max_dist[0] = 0.0
|
||||
|
||||
if tree.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
d_lo = tree.node_bounds[0, i_node, j] - pt[j]
|
||||
d_hi = pt[j] - tree.node_bounds[1, i_node, j]
|
||||
d = (d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi))
|
||||
min_dist[0] = fmax(min_dist[0], 0.5 * d)
|
||||
max_dist[0] = fmax(max_dist[0], fabs(d_lo))
|
||||
max_dist[0] = fmax(max_dist[0], fabs(d_hi))
|
||||
else:
|
||||
# as above, use the fact that x + abs(x) = 2 * max(x, 0)
|
||||
for j in range(n_features):
|
||||
d_lo = tree.node_bounds[0, i_node, j] - pt[j]
|
||||
d_hi = pt[j] - tree.node_bounds[1, i_node, j]
|
||||
d = (d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi))
|
||||
min_dist[0] += pow(0.5 * d, tree.dist_metric.p)
|
||||
max_dist[0] += pow(fmax(fabs(d_lo), fabs(d_hi)),
|
||||
tree.dist_metric.p)
|
||||
|
||||
min_dist[0] = pow(min_dist[0], 1. / tree.dist_metric.p)
|
||||
max_dist[0] = pow(max_dist[0], 1. / tree.dist_metric.p)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
cdef inline float64_t min_rdist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""Compute the minimum reduced distance between two nodes"""
|
||||
cdef intp_t n_features = tree1.data.shape[1]
|
||||
|
||||
cdef float64_t d, d1, d2, rdist=0.0
|
||||
cdef intp_t j
|
||||
|
||||
if tree1.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
d1 = (tree1.node_bounds[0, i_node1, j]
|
||||
- tree2.node_bounds[1, i_node2, j])
|
||||
d2 = (tree2.node_bounds[0, i_node2, j]
|
||||
- tree1.node_bounds[1, i_node1, j])
|
||||
d = (d1 + fabs(d1)) + (d2 + fabs(d2))
|
||||
|
||||
rdist = fmax(rdist, 0.5 * d)
|
||||
else:
|
||||
# here we'll use the fact that x + abs(x) = 2 * max(x, 0)
|
||||
for j in range(n_features):
|
||||
d1 = (tree1.node_bounds[0, i_node1, j]
|
||||
- tree2.node_bounds[1, i_node2, j])
|
||||
d2 = (tree2.node_bounds[0, i_node2, j]
|
||||
- tree1.node_bounds[1, i_node1, j])
|
||||
d = (d1 + fabs(d1)) + (d2 + fabs(d2))
|
||||
|
||||
rdist += pow(0.5 * d, tree1.dist_metric.p)
|
||||
|
||||
return rdist
|
||||
|
||||
|
||||
cdef inline float64_t min_dist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""Compute the minimum distance between two nodes"""
|
||||
return tree1.dist_metric._rdist_to_dist(
|
||||
min_rdist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
|
||||
|
||||
cdef inline float64_t max_rdist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""Compute the maximum reduced distance between two nodes"""
|
||||
cdef intp_t n_features = tree1.data.shape[1]
|
||||
|
||||
cdef float64_t d1, d2, rdist=0.0
|
||||
cdef intp_t j
|
||||
|
||||
if tree1.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
rdist = fmax(rdist, fabs(tree1.node_bounds[0, i_node1, j]
|
||||
- tree2.node_bounds[1, i_node2, j]))
|
||||
rdist = fmax(rdist, fabs(tree1.node_bounds[1, i_node1, j]
|
||||
- tree2.node_bounds[0, i_node2, j]))
|
||||
else:
|
||||
for j in range(n_features):
|
||||
d1 = fabs(tree1.node_bounds[0, i_node1, j]
|
||||
- tree2.node_bounds[1, i_node2, j])
|
||||
d2 = fabs(tree1.node_bounds[1, i_node1, j]
|
||||
- tree2.node_bounds[0, i_node2, j])
|
||||
rdist += pow(fmax(d1, d2), tree1.dist_metric.p)
|
||||
|
||||
return rdist
|
||||
|
||||
|
||||
cdef inline float64_t max_dist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""Compute the maximum distance between two nodes"""
|
||||
return tree1.dist_metric._rdist_to_dist(
|
||||
max_rdist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
|
||||
{{endfor}}
|
||||
|
||||
|
||||
class KDTree(KDTree64):
|
||||
__doc__ = CLASS_DOC.format(BinaryTree="KDTree")
|
||||
pass
|
||||
{{py:
|
||||
|
||||
# Generated file: _kd_tree.pyx
|
||||
|
||||
implementation_specific_values = [
|
||||
# The values are arranged as follows:
|
||||
#
|
||||
# name_suffix, INPUT_DTYPE_t, INPUT_DTYPE
|
||||
#
|
||||
('64', 'float64_t', 'np.float64'),
|
||||
('32', 'float32_t', 'np.float32')
|
||||
]
|
||||
|
||||
# By Jake Vanderplas (2013) <jakevdp@cs.washington.edu>
|
||||
# written for the scikit-learn project
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
}}
|
||||
|
||||
|
||||
__all__ = ['KDTree', 'KDTree64', 'KDTree32']
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
DOC_DICT{{name_suffix}} = {
|
||||
'BinaryTree': 'KDTree{{name_suffix}}',
|
||||
'binary_tree': 'kd_tree{{name_suffix}}',
|
||||
}
|
||||
|
||||
VALID_METRICS{{name_suffix}} = [
|
||||
'EuclideanDistance{{name_suffix}}',
|
||||
'ManhattanDistance{{name_suffix}}',
|
||||
'ChebyshevDistance{{name_suffix}}',
|
||||
'MinkowskiDistance{{name_suffix}}'
|
||||
]
|
||||
|
||||
{{endfor}}
|
||||
|
||||
include "_binary_tree.pxi"
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
# Inherit KDTree{{name_suffix}} from BinaryTree{{name_suffix}}
|
||||
cdef class KDTree{{name_suffix}}(BinaryTree{{name_suffix}}):
|
||||
__doc__ = CLASS_DOC.format(**DOC_DICT{{name_suffix}})
|
||||
pass
|
||||
|
||||
{{endfor}}
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# The functions below specialized the Binary Tree as a KD Tree
|
||||
#
|
||||
# Note that these functions use the concept of "reduced distance".
|
||||
# The reduced distance, defined for some metrics, is a quantity which
|
||||
# is more efficient to compute than the distance, but preserves the
|
||||
# relative rankings of the true distance. For example, the reduced
|
||||
# distance for the Euclidean metric is the squared-euclidean distance.
|
||||
# For some metrics, the reduced distance is simply the distance.
|
||||
|
||||
{{for name_suffix, INPUT_DTYPE_t, INPUT_DTYPE in implementation_specific_values}}
|
||||
|
||||
cdef int allocate_data{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t n_nodes,
|
||||
intp_t n_features,
|
||||
) except -1:
|
||||
"""Allocate arrays needed for the KD Tree"""
|
||||
tree.node_bounds = np.zeros((2, n_nodes, n_features), dtype={{INPUT_DTYPE}})
|
||||
return 0
|
||||
|
||||
|
||||
cdef int init_node{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
NodeData_t[::1] node_data,
|
||||
intp_t i_node,
|
||||
intp_t idx_start,
|
||||
intp_t idx_end,
|
||||
) except -1:
|
||||
"""Initialize the node for the dataset stored in tree.data"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
cdef intp_t i, j
|
||||
cdef float64_t rad = 0
|
||||
|
||||
cdef {{INPUT_DTYPE_t}}* lower_bounds = &tree.node_bounds[0, i_node, 0]
|
||||
cdef {{INPUT_DTYPE_t}}* upper_bounds = &tree.node_bounds[1, i_node, 0]
|
||||
cdef const {{INPUT_DTYPE_t}}* data = &tree.data[0, 0]
|
||||
cdef const intp_t* idx_array = &tree.idx_array[0]
|
||||
|
||||
cdef const {{INPUT_DTYPE_t}}* data_row
|
||||
|
||||
# determine Node bounds
|
||||
for j in range(n_features):
|
||||
lower_bounds[j] = INF
|
||||
upper_bounds[j] = -INF
|
||||
|
||||
# Compute the actual data range. At build time, this is slightly
|
||||
# slower than using the previously-computed bounds of the parent node,
|
||||
# but leads to more compact trees and thus faster queries.
|
||||
for i in range(idx_start, idx_end):
|
||||
data_row = data + idx_array[i] * n_features
|
||||
for j in range(n_features):
|
||||
lower_bounds[j] = fmin(lower_bounds[j], data_row[j])
|
||||
upper_bounds[j] = fmax(upper_bounds[j], data_row[j])
|
||||
|
||||
for j in range(n_features):
|
||||
if tree.dist_metric.p == INF:
|
||||
rad = fmax(rad, 0.5 * (upper_bounds[j] - lower_bounds[j]))
|
||||
else:
|
||||
rad += pow(0.5 * abs(upper_bounds[j] - lower_bounds[j]),
|
||||
tree.dist_metric.p)
|
||||
|
||||
node_data[i_node].idx_start = idx_start
|
||||
node_data[i_node].idx_end = idx_end
|
||||
|
||||
# The radius will hold the size of the circumscribed hypersphere measured
|
||||
# with the specified metric: in querying, this is used as a measure of the
|
||||
# size of each node when deciding which nodes to split.
|
||||
node_data[i_node].radius = pow(rad, 1. / tree.dist_metric.p)
|
||||
return 0
|
||||
|
||||
|
||||
cdef float64_t min_rdist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum reduced-distance between a point and a node"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
cdef float64_t d, d_lo, d_hi, rdist=0.0
|
||||
cdef intp_t j
|
||||
|
||||
if tree.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
d_lo = tree.node_bounds[0, i_node, j] - pt[j]
|
||||
d_hi = pt[j] - tree.node_bounds[1, i_node, j]
|
||||
d = (d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi))
|
||||
rdist = fmax(rdist, 0.5 * d)
|
||||
else:
|
||||
# here we'll use the fact that x + abs(x) = 2 * max(x, 0)
|
||||
for j in range(n_features):
|
||||
d_lo = tree.node_bounds[0, i_node, j] - pt[j]
|
||||
d_hi = pt[j] - tree.node_bounds[1, i_node, j]
|
||||
d = (d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi))
|
||||
rdist += pow(0.5 * d, tree.dist_metric.p)
|
||||
|
||||
return rdist
|
||||
|
||||
|
||||
cdef float64_t min_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the minimum distance between a point and a node"""
|
||||
if tree.dist_metric.p == INF:
|
||||
return min_rdist{{name_suffix}}(tree, i_node, pt)
|
||||
else:
|
||||
return pow(
|
||||
min_rdist{{name_suffix}}(tree, i_node, pt),
|
||||
1. / tree.dist_metric.p
|
||||
)
|
||||
|
||||
|
||||
cdef float64_t max_rdist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the maximum reduced-distance between a point and a node"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
|
||||
cdef float64_t d_lo, d_hi, rdist=0.0
|
||||
cdef intp_t j
|
||||
|
||||
if tree.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
rdist = fmax(rdist, fabs(pt[j] - tree.node_bounds[0, i_node, j]))
|
||||
rdist = fmax(rdist, fabs(pt[j] - tree.node_bounds[1, i_node, j]))
|
||||
else:
|
||||
for j in range(n_features):
|
||||
d_lo = fabs(pt[j] - tree.node_bounds[0, i_node, j])
|
||||
d_hi = fabs(pt[j] - tree.node_bounds[1, i_node, j])
|
||||
rdist += pow(fmax(d_lo, d_hi), tree.dist_metric.p)
|
||||
|
||||
return rdist
|
||||
|
||||
|
||||
cdef float64_t max_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
) except -1:
|
||||
"""Compute the maximum distance between a point and a node"""
|
||||
if tree.dist_metric.p == INF:
|
||||
return max_rdist{{name_suffix}}(tree, i_node, pt)
|
||||
else:
|
||||
return pow(
|
||||
max_rdist{{name_suffix}}(tree, i_node, pt),
|
||||
1. / tree.dist_metric.p
|
||||
)
|
||||
|
||||
|
||||
cdef inline int min_max_dist{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree,
|
||||
intp_t i_node,
|
||||
const {{INPUT_DTYPE_t}}* pt,
|
||||
float64_t* min_dist,
|
||||
float64_t* max_dist,
|
||||
) except -1 nogil:
|
||||
"""Compute the minimum and maximum distance between a point and a node"""
|
||||
cdef intp_t n_features = tree.data.shape[1]
|
||||
|
||||
cdef float64_t d, d_lo, d_hi
|
||||
cdef intp_t j
|
||||
|
||||
min_dist[0] = 0.0
|
||||
max_dist[0] = 0.0
|
||||
|
||||
if tree.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
d_lo = tree.node_bounds[0, i_node, j] - pt[j]
|
||||
d_hi = pt[j] - tree.node_bounds[1, i_node, j]
|
||||
d = (d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi))
|
||||
min_dist[0] = fmax(min_dist[0], 0.5 * d)
|
||||
max_dist[0] = fmax(max_dist[0], fabs(d_lo))
|
||||
max_dist[0] = fmax(max_dist[0], fabs(d_hi))
|
||||
else:
|
||||
# as above, use the fact that x + abs(x) = 2 * max(x, 0)
|
||||
for j in range(n_features):
|
||||
d_lo = tree.node_bounds[0, i_node, j] - pt[j]
|
||||
d_hi = pt[j] - tree.node_bounds[1, i_node, j]
|
||||
d = (d_lo + fabs(d_lo)) + (d_hi + fabs(d_hi))
|
||||
min_dist[0] += pow(0.5 * d, tree.dist_metric.p)
|
||||
max_dist[0] += pow(fmax(fabs(d_lo), fabs(d_hi)),
|
||||
tree.dist_metric.p)
|
||||
|
||||
min_dist[0] = pow(min_dist[0], 1. / tree.dist_metric.p)
|
||||
max_dist[0] = pow(max_dist[0], 1. / tree.dist_metric.p)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
cdef inline float64_t min_rdist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""Compute the minimum reduced distance between two nodes"""
|
||||
cdef intp_t n_features = tree1.data.shape[1]
|
||||
|
||||
cdef float64_t d, d1, d2, rdist=0.0
|
||||
cdef intp_t j
|
||||
|
||||
if tree1.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
d1 = (tree1.node_bounds[0, i_node1, j]
|
||||
- tree2.node_bounds[1, i_node2, j])
|
||||
d2 = (tree2.node_bounds[0, i_node2, j]
|
||||
- tree1.node_bounds[1, i_node1, j])
|
||||
d = (d1 + fabs(d1)) + (d2 + fabs(d2))
|
||||
|
||||
rdist = fmax(rdist, 0.5 * d)
|
||||
else:
|
||||
# here we'll use the fact that x + abs(x) = 2 * max(x, 0)
|
||||
for j in range(n_features):
|
||||
d1 = (tree1.node_bounds[0, i_node1, j]
|
||||
- tree2.node_bounds[1, i_node2, j])
|
||||
d2 = (tree2.node_bounds[0, i_node2, j]
|
||||
- tree1.node_bounds[1, i_node1, j])
|
||||
d = (d1 + fabs(d1)) + (d2 + fabs(d2))
|
||||
|
||||
rdist += pow(0.5 * d, tree1.dist_metric.p)
|
||||
|
||||
return rdist
|
||||
|
||||
|
||||
cdef inline float64_t min_dist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""Compute the minimum distance between two nodes"""
|
||||
return tree1.dist_metric._rdist_to_dist(
|
||||
min_rdist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
|
||||
|
||||
cdef inline float64_t max_rdist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""Compute the maximum reduced distance between two nodes"""
|
||||
cdef intp_t n_features = tree1.data.shape[1]
|
||||
|
||||
cdef float64_t d1, d2, rdist=0.0
|
||||
cdef intp_t j
|
||||
|
||||
if tree1.dist_metric.p == INF:
|
||||
for j in range(n_features):
|
||||
rdist = fmax(rdist, fabs(tree1.node_bounds[0, i_node1, j]
|
||||
- tree2.node_bounds[1, i_node2, j]))
|
||||
rdist = fmax(rdist, fabs(tree1.node_bounds[1, i_node1, j]
|
||||
- tree2.node_bounds[0, i_node2, j]))
|
||||
else:
|
||||
for j in range(n_features):
|
||||
d1 = fabs(tree1.node_bounds[0, i_node1, j]
|
||||
- tree2.node_bounds[1, i_node2, j])
|
||||
d2 = fabs(tree1.node_bounds[1, i_node1, j]
|
||||
- tree2.node_bounds[0, i_node2, j])
|
||||
rdist += pow(fmax(d1, d2), tree1.dist_metric.p)
|
||||
|
||||
return rdist
|
||||
|
||||
|
||||
cdef inline float64_t max_dist_dual{{name_suffix}}(
|
||||
BinaryTree{{name_suffix}} tree1,
|
||||
intp_t i_node1,
|
||||
BinaryTree{{name_suffix}} tree2,
|
||||
intp_t i_node2,
|
||||
) except -1:
|
||||
"""Compute the maximum distance between two nodes"""
|
||||
return tree1.dist_metric._rdist_to_dist(
|
||||
max_rdist_dual{{name_suffix}}(tree1, i_node1, tree2, i_node2)
|
||||
)
|
||||
|
||||
{{endfor}}
|
||||
|
||||
|
||||
class KDTree(KDTree64):
|
||||
__doc__ = CLASS_DOC.format(BinaryTree="KDTree")
|
||||
pass
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from cython cimport floating
|
||||
from ..utils._typedefs cimport float64_t, intp_t
|
||||
|
||||
cdef int partition_node_indices(
|
||||
const floating *data,
|
||||
intp_t *node_indices,
|
||||
intp_t split_dim,
|
||||
intp_t split_index,
|
||||
intp_t n_features,
|
||||
intp_t n_points) except -1
|
||||
from cython cimport floating
|
||||
from ..utils._typedefs cimport float64_t, intp_t
|
||||
|
||||
cdef int partition_node_indices(
|
||||
const floating *data,
|
||||
intp_t *node_indices,
|
||||
intp_t split_dim,
|
||||
intp_t split_index,
|
||||
intp_t n_features,
|
||||
intp_t n_points) except -1
|
||||
|
||||
+122
-122
@@ -1,122 +1,122 @@
|
||||
# BinaryTrees rely on partial sorts to partition their nodes during their
|
||||
# initialisation.
|
||||
#
|
||||
# The C++ std library exposes nth_element, an efficient partial sort for this
|
||||
# situation which has a linear time complexity as well as the best performances.
|
||||
#
|
||||
# To use std::algorithm::nth_element, a few fixture are defined using Cython:
|
||||
# - partition_node_indices, a Cython function used in BinaryTrees, that calls
|
||||
# - partition_node_indices_inner, a C++ function that wraps nth_element and uses
|
||||
# - an IndexComparator to state how to compare KDTrees' indices
|
||||
#
|
||||
# IndexComparator has been defined so that partial sorts are stable with
|
||||
# respect to the nodes initial indices.
|
||||
#
|
||||
# See for reference:
|
||||
# - https://en.cppreference.com/w/cpp/algorithm/nth_element.
|
||||
# - https://github.com/scikit-learn/scikit-learn/pull/11103
|
||||
# - https://github.com/scikit-learn/scikit-learn/pull/19473
|
||||
from cython cimport floating
|
||||
|
||||
|
||||
cdef extern from *:
|
||||
"""
|
||||
#include <algorithm>
|
||||
|
||||
template<class D, class I>
|
||||
class IndexComparator {
|
||||
private:
|
||||
const D *data;
|
||||
I split_dim, n_features;
|
||||
public:
|
||||
IndexComparator(const D *data, const I &split_dim, const I &n_features):
|
||||
data(data), split_dim(split_dim), n_features(n_features) {}
|
||||
|
||||
bool operator()(const I &a, const I &b) const {
|
||||
D a_value = data[a * n_features + split_dim];
|
||||
D b_value = data[b * n_features + split_dim];
|
||||
return a_value == b_value ? a < b : a_value < b_value;
|
||||
}
|
||||
};
|
||||
|
||||
template<class D, class I>
|
||||
void partition_node_indices_inner(
|
||||
const D *data,
|
||||
I *node_indices,
|
||||
const I &split_dim,
|
||||
const I &split_index,
|
||||
const I &n_features,
|
||||
const I &n_points) {
|
||||
IndexComparator<D, I> index_comparator(data, split_dim, n_features);
|
||||
std::nth_element(
|
||||
node_indices,
|
||||
node_indices + split_index,
|
||||
node_indices + n_points,
|
||||
index_comparator);
|
||||
}
|
||||
"""
|
||||
void partition_node_indices_inner[D, I](
|
||||
const D *data,
|
||||
I *node_indices,
|
||||
I split_dim,
|
||||
I split_index,
|
||||
I n_features,
|
||||
I n_points) except +
|
||||
|
||||
|
||||
cdef int partition_node_indices(
|
||||
const floating *data,
|
||||
intp_t *node_indices,
|
||||
intp_t split_dim,
|
||||
intp_t split_index,
|
||||
intp_t n_features,
|
||||
intp_t n_points) except -1:
|
||||
"""Partition points in the node into two equal-sized groups.
|
||||
|
||||
Upon return, the values in node_indices will be rearranged such that
|
||||
(assuming numpy-style indexing):
|
||||
|
||||
data[node_indices[0:split_index], split_dim]
|
||||
<= data[node_indices[split_index], split_dim]
|
||||
|
||||
and
|
||||
|
||||
data[node_indices[split_index], split_dim]
|
||||
<= data[node_indices[split_index:n_points], split_dim]
|
||||
|
||||
The algorithm is essentially a partial in-place quicksort around a
|
||||
set pivot.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : double pointer
|
||||
Pointer to a 2D array of the training data, of shape [N, n_features].
|
||||
N must be greater than any of the values in node_indices.
|
||||
node_indices : int pointer
|
||||
Pointer to a 1D array of length n_points. This lists the indices of
|
||||
each of the points within the current node. This will be modified
|
||||
in-place.
|
||||
split_dim : int
|
||||
the dimension on which to split. This will usually be computed via
|
||||
the routine ``find_node_split_dim``.
|
||||
split_index : int
|
||||
the index within node_indices around which to split the points.
|
||||
n_features: int
|
||||
the number of features (i.e columns) in the 2D array pointed by data.
|
||||
n_points : int
|
||||
the length of node_indices. This is also the number of points in
|
||||
the original dataset.
|
||||
Returns
|
||||
-------
|
||||
status : int
|
||||
integer exit status. On return, the contents of node_indices are
|
||||
modified as noted above.
|
||||
"""
|
||||
partition_node_indices_inner(
|
||||
data,
|
||||
node_indices,
|
||||
split_dim,
|
||||
split_index,
|
||||
n_features,
|
||||
n_points)
|
||||
return 0
|
||||
# BinaryTrees rely on partial sorts to partition their nodes during their
|
||||
# initialisation.
|
||||
#
|
||||
# The C++ std library exposes nth_element, an efficient partial sort for this
|
||||
# situation which has a linear time complexity as well as the best performances.
|
||||
#
|
||||
# To use std::algorithm::nth_element, a few fixture are defined using Cython:
|
||||
# - partition_node_indices, a Cython function used in BinaryTrees, that calls
|
||||
# - partition_node_indices_inner, a C++ function that wraps nth_element and uses
|
||||
# - an IndexComparator to state how to compare KDTrees' indices
|
||||
#
|
||||
# IndexComparator has been defined so that partial sorts are stable with
|
||||
# respect to the nodes initial indices.
|
||||
#
|
||||
# See for reference:
|
||||
# - https://en.cppreference.com/w/cpp/algorithm/nth_element.
|
||||
# - https://github.com/scikit-learn/scikit-learn/pull/11103
|
||||
# - https://github.com/scikit-learn/scikit-learn/pull/19473
|
||||
from cython cimport floating
|
||||
|
||||
|
||||
cdef extern from *:
|
||||
"""
|
||||
#include <algorithm>
|
||||
|
||||
template<class D, class I>
|
||||
class IndexComparator {
|
||||
private:
|
||||
const D *data;
|
||||
I split_dim, n_features;
|
||||
public:
|
||||
IndexComparator(const D *data, const I &split_dim, const I &n_features):
|
||||
data(data), split_dim(split_dim), n_features(n_features) {}
|
||||
|
||||
bool operator()(const I &a, const I &b) const {
|
||||
D a_value = data[a * n_features + split_dim];
|
||||
D b_value = data[b * n_features + split_dim];
|
||||
return a_value == b_value ? a < b : a_value < b_value;
|
||||
}
|
||||
};
|
||||
|
||||
template<class D, class I>
|
||||
void partition_node_indices_inner(
|
||||
const D *data,
|
||||
I *node_indices,
|
||||
const I &split_dim,
|
||||
const I &split_index,
|
||||
const I &n_features,
|
||||
const I &n_points) {
|
||||
IndexComparator<D, I> index_comparator(data, split_dim, n_features);
|
||||
std::nth_element(
|
||||
node_indices,
|
||||
node_indices + split_index,
|
||||
node_indices + n_points,
|
||||
index_comparator);
|
||||
}
|
||||
"""
|
||||
void partition_node_indices_inner[D, I](
|
||||
const D *data,
|
||||
I *node_indices,
|
||||
I split_dim,
|
||||
I split_index,
|
||||
I n_features,
|
||||
I n_points) except +
|
||||
|
||||
|
||||
cdef int partition_node_indices(
|
||||
const floating *data,
|
||||
intp_t *node_indices,
|
||||
intp_t split_dim,
|
||||
intp_t split_index,
|
||||
intp_t n_features,
|
||||
intp_t n_points) except -1:
|
||||
"""Partition points in the node into two equal-sized groups.
|
||||
|
||||
Upon return, the values in node_indices will be rearranged such that
|
||||
(assuming numpy-style indexing):
|
||||
|
||||
data[node_indices[0:split_index], split_dim]
|
||||
<= data[node_indices[split_index], split_dim]
|
||||
|
||||
and
|
||||
|
||||
data[node_indices[split_index], split_dim]
|
||||
<= data[node_indices[split_index:n_points], split_dim]
|
||||
|
||||
The algorithm is essentially a partial in-place quicksort around a
|
||||
set pivot.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : double pointer
|
||||
Pointer to a 2D array of the training data, of shape [N, n_features].
|
||||
N must be greater than any of the values in node_indices.
|
||||
node_indices : int pointer
|
||||
Pointer to a 1D array of length n_points. This lists the indices of
|
||||
each of the points within the current node. This will be modified
|
||||
in-place.
|
||||
split_dim : int
|
||||
the dimension on which to split. This will usually be computed via
|
||||
the routine ``find_node_split_dim``.
|
||||
split_index : int
|
||||
the index within node_indices around which to split the points.
|
||||
n_features: int
|
||||
the number of features (i.e columns) in the 2D array pointed by data.
|
||||
n_points : int
|
||||
the length of node_indices. This is also the number of points in
|
||||
the original dataset.
|
||||
Returns
|
||||
-------
|
||||
status : int
|
||||
integer exit status. On return, the contents of node_indices are
|
||||
modified as noted above.
|
||||
"""
|
||||
partition_node_indices_inner(
|
||||
data,
|
||||
node_indices,
|
||||
split_dim,
|
||||
split_index,
|
||||
n_features,
|
||||
n_points)
|
||||
return 0
|
||||
|
||||
@@ -1,92 +1,92 @@
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# See quad_tree.pyx for details.
|
||||
|
||||
cimport numpy as cnp
|
||||
from ..utils._typedefs cimport float32_t, intp_t
|
||||
|
||||
# This is effectively an ifdef statement in Cython
|
||||
# It allows us to write printf debugging lines
|
||||
# and remove them at compile time
|
||||
cdef enum:
|
||||
DEBUGFLAG = 0
|
||||
|
||||
cdef float EPSILON = 1e-6
|
||||
|
||||
# XXX: Careful to not change the order of the arguments. It is important to
|
||||
# have is_leaf and max_width consecutive as it permits to avoid padding by
|
||||
# the compiler and keep the size coherent for both C and numpy data structures.
|
||||
cdef struct Cell:
|
||||
# Base storage structure for cells in a QuadTree object
|
||||
|
||||
# Tree structure
|
||||
intp_t parent # Parent cell of this cell
|
||||
intp_t[8] children # Array pointing to children of this cell
|
||||
|
||||
# Cell description
|
||||
intp_t cell_id # Id of the cell in the cells array in the Tree
|
||||
intp_t point_index # Index of the point at this cell (only defined
|
||||
# # in non empty leaf)
|
||||
bint is_leaf # Does this cell have children?
|
||||
float32_t squared_max_width # Squared value of the maximum width w
|
||||
intp_t depth # Depth of the cell in the tree
|
||||
intp_t cumulative_size # Number of points included in the subtree with
|
||||
# # this cell as a root.
|
||||
|
||||
# Internal constants
|
||||
float32_t[3] center # Store the center for quick split of cells
|
||||
float32_t[3] barycenter # Keep track of the center of mass of the cell
|
||||
|
||||
# Cell boundaries
|
||||
float32_t[3] min_bounds # Inferior boundaries of this cell (inclusive)
|
||||
float32_t[3] max_bounds # Superior boundaries of this cell (exclusive)
|
||||
|
||||
|
||||
cdef class _QuadTree:
|
||||
# The QuadTree object is a quad tree structure constructed by inserting
|
||||
# recursively points in the tree and splitting cells in 4 so that each
|
||||
# leaf cell contains at most one point.
|
||||
# This structure also handle 3D data, inserted in trees with 8 children
|
||||
# for each node.
|
||||
|
||||
# Parameters of the tree
|
||||
cdef public int n_dimensions # Number of dimensions in X
|
||||
cdef public int verbose # Verbosity of the output
|
||||
cdef intp_t n_cells_per_cell # Number of children per node. (2 ** n_dimension)
|
||||
|
||||
# Tree inner structure
|
||||
cdef public intp_t max_depth # Max depth of the tree
|
||||
cdef public intp_t cell_count # Counter for node IDs
|
||||
cdef public intp_t capacity # Capacity of tree, in terms of nodes
|
||||
cdef public intp_t n_points # Total number of points
|
||||
cdef Cell* cells # Array of nodes
|
||||
|
||||
# Point insertion methods
|
||||
cdef int insert_point(self, float32_t[3] point, intp_t point_index,
|
||||
intp_t cell_id=*) except -1 nogil
|
||||
cdef intp_t _insert_point_in_new_child(self, float32_t[3] point, Cell* cell,
|
||||
intp_t point_index, intp_t size=*
|
||||
) noexcept nogil
|
||||
cdef intp_t _select_child(self, float32_t[3] point, Cell* cell) noexcept nogil
|
||||
cdef bint _is_duplicate(self, float32_t[3] point1, float32_t[3] point2) noexcept nogil
|
||||
|
||||
# Create a summary of the Tree compare to a query point
|
||||
cdef long summarize(self, float32_t[3] point, float32_t* results,
|
||||
float squared_theta=*, intp_t cell_id=*, long idx=*
|
||||
) noexcept nogil
|
||||
|
||||
# Internal cell initialization methods
|
||||
cdef void _init_cell(self, Cell* cell, intp_t parent, intp_t depth) noexcept nogil
|
||||
cdef void _init_root(self, float32_t[3] min_bounds, float32_t[3] max_bounds
|
||||
) noexcept nogil
|
||||
|
||||
# Private methods
|
||||
cdef int _check_point_in_cell(self, float32_t[3] point, Cell* cell
|
||||
) except -1 nogil
|
||||
|
||||
# Private array manipulation to manage the ``cells`` array
|
||||
cdef int _resize(self, intp_t capacity) except -1 nogil
|
||||
cdef int _resize_c(self, intp_t capacity=*) except -1 nogil
|
||||
cdef int _get_cell(self, float32_t[3] point, intp_t cell_id=*) except -1 nogil
|
||||
cdef Cell[:] _get_cell_ndarray(self)
|
||||
# Authors: The scikit-learn developers
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# See quad_tree.pyx for details.
|
||||
|
||||
cimport numpy as cnp
|
||||
from ..utils._typedefs cimport float32_t, intp_t
|
||||
|
||||
# This is effectively an ifdef statement in Cython
|
||||
# It allows us to write printf debugging lines
|
||||
# and remove them at compile time
|
||||
cdef enum:
|
||||
DEBUGFLAG = 0
|
||||
|
||||
cdef float EPSILON = 1e-6
|
||||
|
||||
# XXX: Careful to not change the order of the arguments. It is important to
|
||||
# have is_leaf and max_width consecutive as it permits to avoid padding by
|
||||
# the compiler and keep the size coherent for both C and numpy data structures.
|
||||
cdef struct Cell:
|
||||
# Base storage structure for cells in a QuadTree object
|
||||
|
||||
# Tree structure
|
||||
intp_t parent # Parent cell of this cell
|
||||
intp_t[8] children # Array pointing to children of this cell
|
||||
|
||||
# Cell description
|
||||
intp_t cell_id # Id of the cell in the cells array in the Tree
|
||||
intp_t point_index # Index of the point at this cell (only defined
|
||||
# # in non empty leaf)
|
||||
bint is_leaf # Does this cell have children?
|
||||
float32_t squared_max_width # Squared value of the maximum width w
|
||||
intp_t depth # Depth of the cell in the tree
|
||||
intp_t cumulative_size # Number of points included in the subtree with
|
||||
# # this cell as a root.
|
||||
|
||||
# Internal constants
|
||||
float32_t[3] center # Store the center for quick split of cells
|
||||
float32_t[3] barycenter # Keep track of the center of mass of the cell
|
||||
|
||||
# Cell boundaries
|
||||
float32_t[3] min_bounds # Inferior boundaries of this cell (inclusive)
|
||||
float32_t[3] max_bounds # Superior boundaries of this cell (exclusive)
|
||||
|
||||
|
||||
cdef class _QuadTree:
|
||||
# The QuadTree object is a quad tree structure constructed by inserting
|
||||
# recursively points in the tree and splitting cells in 4 so that each
|
||||
# leaf cell contains at most one point.
|
||||
# This structure also handle 3D data, inserted in trees with 8 children
|
||||
# for each node.
|
||||
|
||||
# Parameters of the tree
|
||||
cdef public int n_dimensions # Number of dimensions in X
|
||||
cdef public int verbose # Verbosity of the output
|
||||
cdef intp_t n_cells_per_cell # Number of children per node. (2 ** n_dimension)
|
||||
|
||||
# Tree inner structure
|
||||
cdef public intp_t max_depth # Max depth of the tree
|
||||
cdef public intp_t cell_count # Counter for node IDs
|
||||
cdef public intp_t capacity # Capacity of tree, in terms of nodes
|
||||
cdef public intp_t n_points # Total number of points
|
||||
cdef Cell* cells # Array of nodes
|
||||
|
||||
# Point insertion methods
|
||||
cdef int insert_point(self, float32_t[3] point, intp_t point_index,
|
||||
intp_t cell_id=*) except -1 nogil
|
||||
cdef intp_t _insert_point_in_new_child(self, float32_t[3] point, Cell* cell,
|
||||
intp_t point_index, intp_t size=*
|
||||
) noexcept nogil
|
||||
cdef intp_t _select_child(self, float32_t[3] point, Cell* cell) noexcept nogil
|
||||
cdef bint _is_duplicate(self, float32_t[3] point1, float32_t[3] point2) noexcept nogil
|
||||
|
||||
# Create a summary of the Tree compare to a query point
|
||||
cdef long summarize(self, float32_t[3] point, float32_t* results,
|
||||
float squared_theta=*, intp_t cell_id=*, long idx=*
|
||||
) noexcept nogil
|
||||
|
||||
# Internal cell initialization methods
|
||||
cdef void _init_cell(self, Cell* cell, intp_t parent, intp_t depth) noexcept nogil
|
||||
cdef void _init_root(self, float32_t[3] min_bounds, float32_t[3] max_bounds
|
||||
) noexcept nogil
|
||||
|
||||
# Private methods
|
||||
cdef int _check_point_in_cell(self, float32_t[3] point, Cell* cell
|
||||
) except -1 nogil
|
||||
|
||||
# Private array manipulation to manage the ``cells`` array
|
||||
cdef int _resize(self, intp_t capacity) except -1 nogil
|
||||
cdef int _resize_c(self, intp_t capacity=*) except -1 nogil
|
||||
cdef int _get_cell(self, float32_t[3] point, intp_t cell_id=*) except -1 nogil
|
||||
cdef Cell[:] _get_cell_ndarray(self)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,53 +1,53 @@
|
||||
_binary_tree_pxi = custom_target(
|
||||
'_binary_tree_pxi',
|
||||
output: '_binary_tree.pxi',
|
||||
input: '_binary_tree.pxi.tp',
|
||||
command: [tempita, '@INPUT@', '-o', '@OUTDIR@'],
|
||||
)
|
||||
|
||||
# .pyx is generated so this is needed to make Cython compilation work. The pxi
|
||||
# file is included avoid "missing dependency paths" with ninja -t missindeps
|
||||
neighbors_cython_tree = [
|
||||
fs.copyfile('__init__.py'),
|
||||
fs.copyfile('_partition_nodes.pxd'),
|
||||
_binary_tree_pxi,
|
||||
]
|
||||
|
||||
name_list = ['_ball_tree', '_kd_tree']
|
||||
|
||||
foreach name: name_list
|
||||
pyx = custom_target(
|
||||
name + '_pyx',
|
||||
output: name + '.pyx',
|
||||
input: name + '.pyx.tp',
|
||||
command: [tempita, '@INPUT@', '-o', '@OUTDIR@'],
|
||||
# TODO in principle this should go in py.exension_module below. This is
|
||||
# temporary work-around for dependency issue with .pyx.tp files. For more
|
||||
# details, see https://github.com/mesonbuild/meson/issues/13212
|
||||
depends: [neighbors_cython_tree, utils_cython_tree, metrics_cython_tree],
|
||||
)
|
||||
py.extension_module(
|
||||
name,
|
||||
cython_gen.process(pyx),
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/neighbors',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
|
||||
neighbors_extension_metadata = {
|
||||
'_partition_nodes':
|
||||
{'sources': [cython_gen_cpp.process('_partition_nodes.pyx')],
|
||||
'dependencies': [np_dep]},
|
||||
'_quad_tree': {'sources': [cython_gen.process('_quad_tree.pyx')], 'dependencies': [np_dep]},
|
||||
}
|
||||
|
||||
foreach ext_name, ext_dict : neighbors_extension_metadata
|
||||
py.extension_module(
|
||||
ext_name,
|
||||
[ext_dict.get('sources'), utils_cython_tree],
|
||||
dependencies: ext_dict.get('dependencies'),
|
||||
subdir: 'sklearn/neighbors',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
_binary_tree_pxi = custom_target(
|
||||
'_binary_tree_pxi',
|
||||
output: '_binary_tree.pxi',
|
||||
input: '_binary_tree.pxi.tp',
|
||||
command: [tempita, '@INPUT@', '-o', '@OUTDIR@'],
|
||||
)
|
||||
|
||||
# .pyx is generated so this is needed to make Cython compilation work. The pxi
|
||||
# file is included avoid "missing dependency paths" with ninja -t missindeps
|
||||
neighbors_cython_tree = [
|
||||
fs.copyfile('__init__.py'),
|
||||
fs.copyfile('_partition_nodes.pxd'),
|
||||
_binary_tree_pxi,
|
||||
]
|
||||
|
||||
name_list = ['_ball_tree', '_kd_tree']
|
||||
|
||||
foreach name: name_list
|
||||
pyx = custom_target(
|
||||
name + '_pyx',
|
||||
output: name + '.pyx',
|
||||
input: name + '.pyx.tp',
|
||||
command: [tempita, '@INPUT@', '-o', '@OUTDIR@'],
|
||||
# TODO in principle this should go in py.exension_module below. This is
|
||||
# temporary work-around for dependency issue with .pyx.tp files. For more
|
||||
# details, see https://github.com/mesonbuild/meson/issues/13212
|
||||
depends: [neighbors_cython_tree, utils_cython_tree, metrics_cython_tree],
|
||||
)
|
||||
py.extension_module(
|
||||
name,
|
||||
cython_gen.process(pyx),
|
||||
dependencies: [np_dep],
|
||||
subdir: 'sklearn/neighbors',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
|
||||
neighbors_extension_metadata = {
|
||||
'_partition_nodes':
|
||||
{'sources': [cython_gen_cpp.process('_partition_nodes.pyx')],
|
||||
'dependencies': [np_dep]},
|
||||
'_quad_tree': {'sources': [cython_gen.process('_quad_tree.pyx')], 'dependencies': [np_dep]},
|
||||
}
|
||||
|
||||
foreach ext_name, ext_dict : neighbors_extension_metadata
|
||||
py.extension_module(
|
||||
ext_name,
|
||||
[ext_dict.get('sources'), utils_cython_tree],
|
||||
dependencies: ext_dict.get('dependencies'),
|
||||
subdir: 'sklearn/neighbors',
|
||||
install: true
|
||||
)
|
||||
endforeach
|
||||
|
||||
Reference in New Issue
Block a user