Added the function for making kdtrees out of hyperrectangles.

This commit is contained in:
Dongryeol Lee
2008-04-23 21:33:55 +00:00
parent 4d34c1704b
commit a6db2d18c2
3 changed files with 272 additions and 0 deletions
@@ -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);
}
};