Added the function for making kdtrees out of hyperrectangles.
This commit is contained in:
@@ -8,6 +8,8 @@ librule(
|
||||
"gen_range.h",
|
||||
"gen_kdtree.h",
|
||||
"gen_kdtree_impl.h",
|
||||
"gen_kdtree_hyper.h",
|
||||
"gen_kdtree_hyper_impl.h",
|
||||
"gen_metric_tree.h",
|
||||
"gen_metric_tree_impl.h",
|
||||
"general_spacetree.h"], # include files part of the 'lib'
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright 2007 Georgia Institute of Technology. All rights reserved.
|
||||
// ABSOLUTELY NOT FOR DISTRIBUTION
|
||||
/**
|
||||
* @file tree/kdtree.h
|
||||
*
|
||||
* Tools for kd-trees.
|
||||
*
|
||||
* Eventually we hope to support KD trees with non-L2 (Euclidean)
|
||||
* metrics, like Manhattan distance.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
|
||||
#ifndef TREE_GEN_KDTREE_HYPER_H
|
||||
#define TREE_GEN_KDTREE_HYPER_H
|
||||
|
||||
#include "general_spacetree.h"
|
||||
#include "general_type_bounds.h"
|
||||
|
||||
#include "fastlib/base/common.h"
|
||||
#include "fastlib/col/arraylist.h"
|
||||
#include "fastlib/fx/fx.h"
|
||||
|
||||
#include "gen_kdtree_hyper_impl.h"
|
||||
|
||||
/**
|
||||
* Regular pointer-style trees (as opposed to THOR trees).
|
||||
*/
|
||||
namespace proximity {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a KD tree from hyperrectangles
|
||||
*
|
||||
* @experimental
|
||||
*
|
||||
* This requires you to pass in two unitialized ArrayLists which will contain
|
||||
* index mappings so you can account for the re-ordering of the matrix.
|
||||
* (By unitialized I mean don't call Init on it)
|
||||
*
|
||||
* @param matrix data where each column is a point, WHICH WILL BE RE-ORDERED
|
||||
* @param leaf_size the maximum points in a leaf
|
||||
* @param old_from_new pointer to an unitialized arraylist; it will map
|
||||
* new indices to original
|
||||
* @param new_from_old pointer to an unitialized arraylist; it will map
|
||||
* original indexes to new indices
|
||||
*/
|
||||
template<typename T, typename TKdTree, typename TKdTreeSplitter>
|
||||
TKdTree *MakeGenKdTree(GenMatrix<T>& lower_limit_matrix,
|
||||
GenMatrix<T>& upper_limit_matrix,
|
||||
index_t leaf_size,
|
||||
ArrayList<index_t> *old_from_new = NULL,
|
||||
ArrayList<index_t> *new_from_old = NULL) {
|
||||
|
||||
TKdTree *node = new TKdTree();
|
||||
index_t *old_from_new_ptr;
|
||||
|
||||
if (old_from_new) {
|
||||
old_from_new->Init(lower_limit_matrix.n_cols());
|
||||
|
||||
for (index_t i = 0; i < lower_limit_matrix.n_cols(); i++) {
|
||||
(*old_from_new)[i] = i;
|
||||
}
|
||||
|
||||
old_from_new_ptr = old_from_new->begin();
|
||||
}
|
||||
else {
|
||||
old_from_new_ptr = NULL;
|
||||
}
|
||||
|
||||
node->Init(0, lower_limit_matrix.n_cols());
|
||||
node->bound().Init(lower_limit_matrix.n_rows());
|
||||
tree_gen_kdtree_private::FindBoundFromMatrix
|
||||
(lower_limit_matrix, upper_limit_matrix, 0, lower_limit_matrix.n_cols(),
|
||||
&node->bound());
|
||||
|
||||
tree_gen_kdtree_private::SplitGenKdTree<T, TKdTree, TKdTreeSplitter>
|
||||
(lower_limit_matrix, upper_limit_matrix, node, leaf_size,
|
||||
old_from_new_ptr);
|
||||
|
||||
if (new_from_old) {
|
||||
new_from_old->Init(lower_limit_matrix.n_cols());
|
||||
for (index_t i = 0; i < lower_limit_matrix.n_cols(); i++) {
|
||||
(*new_from_old)[(*old_from_new)[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,177 @@
|
||||
/* Implementation for the regular pointer-style kd-tree builder. */
|
||||
|
||||
#include "fastlib/fastlib_int.h"
|
||||
|
||||
namespace tree_gen_kdtree_private {
|
||||
|
||||
template<typename T, typename TBound>
|
||||
void FindBoundFromMatrix(const GenMatrix<T>& lower_limit_matrix,
|
||||
const GenMatrix<T>& upper_limit_matrix,
|
||||
index_t first, index_t count, TBound *bounds) {
|
||||
|
||||
index_t end = first + count;
|
||||
for (index_t i = first; i < end; i++) {
|
||||
GenVector<T> col;
|
||||
|
||||
lower_limit_matrix.MakeColumnVector(i, &col);
|
||||
*bounds |= col;
|
||||
|
||||
col.Destruct();
|
||||
upper_limit_matrix.MakeColumnVector(i, &col);
|
||||
*bounds |= col;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename TBound>
|
||||
index_t MatrixPartition(GenMatrix<T>& lower_limit_matrix,
|
||||
GenMatrix<T>& upper_limit_matrix,
|
||||
index_t dim, double splitvalue,
|
||||
index_t first, index_t count, TBound* left_bound,
|
||||
TBound* right_bound, index_t *old_from_new) {
|
||||
|
||||
index_t left = first;
|
||||
index_t right = first + count - 1;
|
||||
|
||||
/* At any point:
|
||||
*
|
||||
* everything < left is correct
|
||||
* everything > right is correct
|
||||
*/
|
||||
for (;;) {
|
||||
|
||||
// If the lower limit is at most the split value, then put it in
|
||||
// the left.
|
||||
while (lower_limit_matrix.get(dim, left) <= splitvalue &&
|
||||
likely(left <= right)) {
|
||||
GenVector<T> left_vector;
|
||||
lower_limit_matrix.MakeColumnVector(left, &left_vector);
|
||||
*left_bound |= left_vector;
|
||||
left_vector.Destruct();
|
||||
upper_limit_matrix.MakeColumnVector(left, &left_vector);
|
||||
*left_bound |= left_vector;
|
||||
left++;
|
||||
}
|
||||
|
||||
// If the upper limit is at least the split value, then put it
|
||||
// in the right.
|
||||
while (upper_limit_matrix.get(dim, right) >= splitvalue &&
|
||||
likely(left <= right)) {
|
||||
GenVector<T> right_vector;
|
||||
lower_limit_matrix.MakeColumnVector(right, &right_vector);
|
||||
*right_bound |= right_vector;
|
||||
right_vector.Destruct();
|
||||
upper_limit_matrix.MakeColumnVector(right, &right_vector);
|
||||
*right_bound |= right_vector;
|
||||
right--;
|
||||
}
|
||||
|
||||
if (unlikely(left > right)) {
|
||||
/* left == right + 1 */
|
||||
break;
|
||||
}
|
||||
|
||||
GenVector<T> left_vector;
|
||||
GenVector<T> right_vector;
|
||||
|
||||
// First swap the lower limits.
|
||||
lower_limit_matrix.MakeColumnVector(left, &left_vector);
|
||||
lower_limit_matrix.MakeColumnVector(right, &right_vector);
|
||||
|
||||
left_vector.SwapValues(&right_vector);
|
||||
|
||||
*left_bound |= left_vector;
|
||||
*right_bound |= right_vector;
|
||||
|
||||
// Then swap the upper limits.
|
||||
left_vector.Destruct();
|
||||
right_vector.Destruct();
|
||||
upper_limit_matrix.MakeColumnVector(left, &left_vector);
|
||||
upper_limit_matrix.MakeColumnVector(right, &right_vector);
|
||||
|
||||
left_vector.SwapValues(&right_vector);
|
||||
|
||||
*left_bound |= left_vector;
|
||||
*right_bound |= right_vector;
|
||||
|
||||
// Swap indices...
|
||||
if (old_from_new) {
|
||||
index_t t = old_from_new[left];
|
||||
old_from_new[left] = old_from_new[right];
|
||||
old_from_new[right] = t;
|
||||
}
|
||||
|
||||
DEBUG_ASSERT(left <= right);
|
||||
right--;
|
||||
}
|
||||
|
||||
DEBUG_ASSERT(left == right + 1);
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
template<typename T, typename TKdTree, typename TKdTreeSplitter>
|
||||
void SplitGenKdTree(GenMatrix<T>& lower_limit_matrix,
|
||||
GenMatrix<T>& upper_limit_matrix, TKdTree *node,
|
||||
index_t leaf_size, index_t *old_from_new) {
|
||||
|
||||
TKdTree *left = NULL;
|
||||
TKdTree *right = NULL;
|
||||
|
||||
if (node->count() > leaf_size) {
|
||||
index_t split_dim = BIG_BAD_NUMBER;
|
||||
T max_width = -1;
|
||||
|
||||
for (index_t d = 0; d < lower_limit_matrix.n_rows(); d++) {
|
||||
T w = node->bound().get(d).width();
|
||||
|
||||
if (unlikely(w > max_width)) {
|
||||
max_width = w;
|
||||
split_dim = d;
|
||||
}
|
||||
}
|
||||
|
||||
// choose the split value along the dimension to be splitted
|
||||
double split_val =
|
||||
TKdTreeSplitter::ChooseKdTreeSplitValue(lower_limit_matrix,
|
||||
upper_limit_matrix, node,
|
||||
split_dim);
|
||||
|
||||
if (max_width < DBL_EPSILON) {
|
||||
// Okay, we can't do any splitting, because all these points are the
|
||||
// same. We have to give up.
|
||||
}
|
||||
else {
|
||||
left = new TKdTree();
|
||||
left->bound().Init(lower_limit_matrix.n_rows());
|
||||
|
||||
right = new TKdTree();
|
||||
right->bound().Init(lower_limit_matrix.n_rows());
|
||||
|
||||
index_t split_col =
|
||||
MatrixPartition(lower_limit_matrix, upper_limit_matrix,
|
||||
split_dim, split_val,
|
||||
node->begin(), node->count(),
|
||||
&left->bound(), &right->bound(),
|
||||
old_from_new);
|
||||
|
||||
VERBOSE_MSG(3.0,"split (%d,[%d],%d) dim %d on %f (between %f, %f)",
|
||||
node->begin(), split_col,
|
||||
node->begin() + node->count(), split_dim, split_val,
|
||||
node->bound().get(split_dim).lo,
|
||||
node->bound().get(split_dim).hi);
|
||||
|
||||
left->Init(node->begin(), split_col - node->begin());
|
||||
right->Init(split_col, node->begin() + node->count() - split_col);
|
||||
|
||||
SplitGenKdTree<T, TKdTree, TKdTreeSplitter>
|
||||
(lower_limit_matrix, upper_limit_matrix, left, leaf_size,
|
||||
old_from_new);
|
||||
SplitGenKdTree<T, TKdTree, TKdTreeSplitter>
|
||||
(lower_limit_matrix, upper_limit_matrix, right, leaf_size,
|
||||
old_from_new);
|
||||
}
|
||||
}
|
||||
|
||||
node->set_children(matrix, left, right);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user