This commit is contained in:
Dongryeol Lee
2011-01-23 03:12:57 +00:00
parent 91422d6fc7
commit b6c0c4e9d6
@@ -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<typename TKdTree>
/** @brief Computes the widest dimension and its width of a
* bounding box.
*/
template<typename BoundType>
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<typename BoundType>
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<typename MetricType>
@@ -101,6 +134,8 @@ class GenKdTree {
core::parallel::HrectBoundCombine());
}
/** @brief Makes a leaf node by constructing its bound.
*/
template<typename MetricType>
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<typename MetricType, typename TreeType>
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<typename MetricType>
static void ComputeMemberships(
const MetricType &metric_in,
@@ -130,8 +173,11 @@ class GenKdTree {
int split_dim = static_cast<int>(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<typename MetricType, typename DistributedTableType>
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<double>::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<bool> 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<int> > assigned_point_indices(comm.size());
std::vector<int> 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<typename MetricType, typename TreeType, typename IndexType>
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<double>::epsilon()) {
return false;