From b6c0c4e9d68e079e6bde537cbf87f0a70f07feff Mon Sep 17 00:00:00 2001 From: Dongryeol Lee Date: Sun, 23 Jan 2011 03:12:57 +0000 Subject: [PATCH] Going. --- .../thesis_research/core/tree/gen_kdtree.h | 137 ++++++++++++++++-- 1 file changed, 123 insertions(+), 14 deletions(-) diff --git a/fastlib/trunk/contrib/dongryel/thesis_research/core/tree/gen_kdtree.h b/fastlib/trunk/contrib/dongryel/thesis_research/core/tree/gen_kdtree.h index c3dc2021e2..d7e662a8e6 100644 --- a/fastlib/trunk/contrib/dongryel/thesis_research/core/tree/gen_kdtree.h +++ b/fastlib/trunk/contrib/dongryel/thesis_research/core/tree/gen_kdtree.h @@ -14,6 +14,10 @@ namespace core { namespace parallel { + +/** @brief A class that combines two bounding boxes and produces the + * tightest bounding box that contains both. + */ class HrectBoundCombine: public std::binary_function < core::tree::HrectBound, core::tree::HrectBound, core::tree::HrectBound > { @@ -32,6 +36,10 @@ class HrectBoundCombine: namespace boost { namespace mpi { + +/** @brief HrectBoundCombine function is a commutative reduction + * operator. + */ template<> class is_commutative < core::parallel::HrectBoundCombine, core::tree::HrectBound > : @@ -48,11 +56,32 @@ namespace tree { */ class GenKdTreeMidpointSplitter { public: - template + + /** @brief Computes the widest dimension and its width of a + * bounding box. + */ + template + static void ComputeWidestDimension( + const BoundType &bound, int *split_dim, double *max_width) { + + *split_dim = -1; + *max_width = -1.0; + for(int d = 0; d < bound.dim(); d++) { + double w = bound.get(d).width(); + if(w > *max_width) { + *max_width = w; + *split_dim = d; + } + } + } + + /** @brief The splitter that simply returns the mid point of the + * splitting dimension. + */ + template static double ChooseKdTreeSplitValue( - const core::table::DenseMatrix &matrix, - TKdTree *node, int split_dim) { - return node->bound().get(split_dim).mid(); + const BoundType &bound, int split_dim) { + return bound.get(split_dim).mid(); } }; @@ -62,8 +91,12 @@ template< typename IncomingStatisticType > class GenKdTree { public: + /** @brief The bounding primitive used in kd-tree. + */ typedef core::tree::HrectBound BoundType; + /** @brief The statistics type used in the tree. + */ typedef IncomingStatisticType StatisticType; template @@ -101,6 +134,8 @@ class GenKdTree { core::parallel::HrectBoundCombine()); } + /** @brief Makes a leaf node by constructing its bound. + */ template static void MakeLeafNode( const MetricType &metric_in, @@ -110,14 +145,22 @@ class GenKdTree { FindBoundFromMatrix(metric_in, matrix, begin, count, bounds); } + /** @brief Combines the bounding primitives of the children node + * to form the bound for the self. + */ template static void CombineBounds( const MetricType &metric_in, core::table::DenseMatrix &matrix, TreeType *node, TreeType *left, TreeType *right) { + // Do nothing. } + /** @brief Computes two bounding primitives and membership vectors + * for a given consecutive column points in the data + * matrix. + */ template static void ComputeMemberships( const MetricType &metric_in, @@ -130,8 +173,11 @@ class GenKdTree { int split_dim = static_cast(left_bound.get(0).lo); double split_val = left_bound.get(0).hi; - // Reset the left bound. + // Reset the left bound and the right bound. left_bound.Reset(); + right_bound.Reset(); + *left_count = 0; + left_membership->resize(end - first); // Build the bounds for the kd-tree. for(int left = first; left < end; left++) { @@ -153,6 +199,74 @@ class GenKdTree { } } + template + static bool AttemptSplitting( + boost::mpi::communicator &comm, + const MetricType &metric_in, + const BoundType &bound, + DistributedTableType *distributed_table_in) { + + // Splitting dimension/widest dimension info. + int split_dim = -1; + double max_width = -1; + + // Find the splitting dimension. + core::tree::GenKdTreeMidpointSplitter::ComputeWidestDimension( + bound, &split_dim, &max_width); + + // Choose the split value along the dimension to be splitted. + double split_val = + core::tree::GenKdTreeMidpointSplitter::ChooseKdTreeSplitValue( + bound, split_dim); + + if(max_width < std::numeric_limits::epsilon()) { + return false; + } + + // Copy the split dimension and split value. + BoundType left_bound; + left_bound.Init(bound.dim()); + left_bound.get(0).lo = split_dim; + left_bound.get(0).hi = split_val; + BoundType right_bound; + right_bound.Init(bound.dim()); + + // Assign the point on the local process using the splitting + // value. + int left_count; + std::deque left_membership; + ComputeMemberships( + metric_in, distributed_table_in->table()->data(), 0, + distributed_table_in->n_entries(), left_bound, right_bound, + &left_count, &left_membership); + + std::vector< std::vector > assigned_point_indices(comm.size()); + std::vector membership_counts_per_process(comm.size(), 0); + + // Loop through the membership vectors and assign to the right + // process partner. + int left_destination = + (comm.rank() % 2 == 0) ? comm.rank() : comm.rank() - 1; + int right_destination = (comm.rank() % 2 == 0) ? + comm.rank() + 1 : comm.rank(); + right_destination = right_destination % comm.size(); + for(unsigned int i = 0; i < left_membership.size(); i++) { + if(left_membership[i]) { + assigned_point_indices[left_destination].push_back(i); + membership_counts_per_process[left_destination]++; + } + else { + assigned_point_indices[right_destination].push_back(i); + membership_counts_per_process[right_destination]++; + } + } + + return true; + } + + /** @brief Attempts to split a kd-tree node and reshuffles the + * data accordingly and creates two child nodes. + */ template static bool AttemptSplitting( const MetricType &metric_in, @@ -168,19 +282,14 @@ class GenKdTree { int split_dim = -1; double max_width = -1; - for(int d = 0; d < matrix.n_rows(); d++) { - double w = node->bound().get(d).width(); - - if(w > max_width) { - max_width = w; - split_dim = d; - } - } + // Find the splitting dimension. + core::tree::GenKdTreeMidpointSplitter::ComputeWidestDimension( + node->bound(), &split_dim, &max_width); // Choose the split value along the dimension to be splitted. double split_val = core::tree::GenKdTreeMidpointSplitter::ChooseKdTreeSplitValue( - matrix, node, split_dim); + node->bound(), split_dim); if(max_width < std::numeric_limits::epsilon()) { return false;