Going.
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user