From a6db2d18c2b955fb96ae9be8bee3e6e2b0328360 Mon Sep 17 00:00:00 2001 From: Dongryeol Lee Date: Wed, 23 Apr 2008 21:33:55 +0000 Subject: [PATCH] Added the function for making kdtrees out of hyperrectangles. --- .../dongryel/proximity_project/build.py | 2 + .../proximity_project/gen_kdtree_hyper.h | 93 +++++++++ .../proximity_project/gen_kdtree_hyper_impl.h | 177 ++++++++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 fastlib2/contrib/dongryel/proximity_project/gen_kdtree_hyper.h create mode 100644 fastlib2/contrib/dongryel/proximity_project/gen_kdtree_hyper_impl.h diff --git a/fastlib2/contrib/dongryel/proximity_project/build.py b/fastlib2/contrib/dongryel/proximity_project/build.py index 6fca30ebc5..c93c079ff0 100644 --- a/fastlib2/contrib/dongryel/proximity_project/build.py +++ b/fastlib2/contrib/dongryel/proximity_project/build.py @@ -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' diff --git a/fastlib2/contrib/dongryel/proximity_project/gen_kdtree_hyper.h b/fastlib2/contrib/dongryel/proximity_project/gen_kdtree_hyper.h new file mode 100644 index 0000000000..f792b00858 --- /dev/null +++ b/fastlib2/contrib/dongryel/proximity_project/gen_kdtree_hyper.h @@ -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 + TKdTree *MakeGenKdTree(GenMatrix& lower_limit_matrix, + GenMatrix& upper_limit_matrix, + index_t leaf_size, + ArrayList *old_from_new = NULL, + ArrayList *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 + (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 diff --git a/fastlib2/contrib/dongryel/proximity_project/gen_kdtree_hyper_impl.h b/fastlib2/contrib/dongryel/proximity_project/gen_kdtree_hyper_impl.h new file mode 100644 index 0000000000..72c6a2654a --- /dev/null +++ b/fastlib2/contrib/dongryel/proximity_project/gen_kdtree_hyper_impl.h @@ -0,0 +1,177 @@ +/* Implementation for the regular pointer-style kd-tree builder. */ + +#include "fastlib/fastlib_int.h" + +namespace tree_gen_kdtree_private { + + template + void FindBoundFromMatrix(const GenMatrix& lower_limit_matrix, + const GenMatrix& 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 col; + + lower_limit_matrix.MakeColumnVector(i, &col); + *bounds |= col; + + col.Destruct(); + upper_limit_matrix.MakeColumnVector(i, &col); + *bounds |= col; + } + } + + template + index_t MatrixPartition(GenMatrix& lower_limit_matrix, + GenMatrix& 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 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 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 left_vector; + GenVector 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 + void SplitGenKdTree(GenMatrix& lower_limit_matrix, + GenMatrix& 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 + (lower_limit_matrix, upper_limit_matrix, left, leaf_size, + old_from_new); + SplitGenKdTree + (lower_limit_matrix, upper_limit_matrix, right, leaf_size, + old_from_new); + } + } + + node->set_children(matrix, left, right); + } +};