Files
mlpack/fastlib/thor/thortree.h
T

299 lines
7.7 KiB
C++

/**
* @file thortree.h
*
* Support for trees in THOR.
*
* Mostly contains decomposition-related code.
*/
#ifndef THOR_THORTREE_H
#define THOR_THORTREE_H
#include "thor_struct.h"
/**
* A single component of the tree, viewed as a work item.
*/
struct TreeGrain {
/** The root node index, also the first node in the contiguous sequence. */
index_t node_index;
/** One past the last node in the contiguous node sequence. */
index_t node_end_index;
/** The first point. */
index_t point_begin_index;
/** One past the last point. */
index_t point_end_index;
template<typename TSkeletonNode>
void Init(const TSkeletonNode& node) {
node_index = node.index();
node_end_index = node.end_index();
point_begin_index = node.node().begin();
point_end_index = node.node().end();
}
void InitInvalid() {
node_index = -1;
node_end_index = -1;
point_begin_index = -1;
point_end_index = -1;
}
bool is_valid() const {
return node_index >= 0;
}
index_t n_points() const {
return point_end_index - point_begin_index;
}
index_t n_nodes() const {
return node_end_index - node_index;
}
OT_DEF_BASIC(TreeGrain) {
OT_MY_OBJECT(node_index);
OT_MY_OBJECT(node_end_index);
OT_MY_OBJECT(point_begin_index);
OT_MY_OBJECT(point_end_index);
}
};
/**
* A distributed decomposition of an ThorTree.
*
* Currently only handles trivial node-to-machine decompositions.
*/
template<typename TNode>
class ThorTreeDecomposition {
public:
typedef TNode Node;
struct Info {
int begin_rank;
int end_rank;
Info(int begin_rank_in, int end_rank_in)
: begin_rank(begin_rank_in), end_rank(end_rank_in) {}
bool is_singleton() const {
return end_rank - begin_rank <= 1;
}
bool contains(int rank) const {
return rank >= begin_rank && rank < end_rank;
}
int Interpolate(index_t numerator, index_t denominator) {
return math::RoundInt(double(end_rank - begin_rank)
* numerator / denominator) + begin_rank;
}
void Fix() {
if (end_rank <= begin_rank) {
end_rank = begin_rank + 1;
}
}
OT_DEF_BASIC(Info) {
OT_MY_OBJECT(begin_rank);
OT_MY_OBJECT(end_rank);
}
};
typedef ThorSkeletonNode<Node, Info> DecompNode;
private:
/**
* The tree decomposition.
*/
DecompNode *root_;
ArrayList<TreeGrain> grain_by_owner_;
OT_DEF(ThorTreeDecomposition) {
OT_PTR(root_);
OT_MY_OBJECT(grain_by_owner_);
}
public:
/**
* Initializes given the root of a decomposition tree.
*/
void Init(DecompNode *root_in) {
root_ = root_in;
DEBUG_ASSERT(root_->info().begin_rank == 0);
DEBUG_ASSERT(root_->info().end_rank == rpc::n_peers());
DEBUG_ASSERT(root_in != NULL);
grain_by_owner_.Init(rpc::n_peers());
for (int i = 0; i < grain_by_owner_.size(); i++) {
grain_by_owner_[i].InitInvalid();
}
FillLinearization_(root_);
}
/** Returns the root of the decomposition tree. */
DecompNode *root() const {
return root_;
}
/**
* Gets the portion of the tree that is assigned to the specified machine.
*/
const TreeGrain& grain_by_owner(int rank) const {
return grain_by_owner_[rank];
}
private:
void FillLinearization_(DecompNode *node);
};
/**
* A ThorTree is a distributed tree of any point and node type.
*
* A ThorTree encapsulates a distributed tree, by containing both of
* its caches, its decomposition, and parameter object.
*/
template<typename TParam, typename TPoint, typename TNode>
class ThorTree {
FORBID_ACCIDENTAL_COPIES(ThorTree);
public:
typedef TParam Param;
typedef TPoint Point;
typedef TNode Node;
typedef typename Node::Bound Bound;
private:
Param param_;
ThorTreeDecomposition<Node> decomp_;
DistributedCache *points_;
DistributedCache *nodes_;
public:
ThorTree() {}
~ThorTree() {
delete points_;
delete nodes_;
}
void Init(const Param& param_in,
const ThorTreeDecomposition<Node> &decomp_in,
DistributedCache *points_in, DistributedCache *nodes_in) {
param_.Copy(param_in);
decomp_.Copy(decomp_in);
points_ = points_in;
nodes_ = nodes_in;
}
void set_param(const Param& param_in) {
param_ = param_in;
}
void set_decomp(const ThorTreeDecomposition<Node>& decomp_in) {
decomp_ = decomp_in;
}
/** Gets the parameter object characterizing this tree. */
const Param& param() const { return param_; }
/** Gets the parameter object characterizing this tree. */
Param& param() { return param_; }
/** Gets the decomposition dividing this tree. */
const ThorTreeDecomposition<Node>& decomp() const { return decomp_; }
/** Gets the array of points comporising this tree. */
DistributedCache& points() { return *points_; }
/** Gets the array of nodes dividing this tree. */
DistributedCache& nodes() { return *nodes_; }
/** Gets the root node. */
const Node& root() const {
// we cheat by using the tree decomposition as a cache of the node
return decomp().root()->node();
}
/** Gets the number of points. */
index_t n_points() const {
return root().count();
}
/**
* Updates each point and reaccumulates all bounds and statistics.
*/
template<typename Result, typename Visitor>
void Update(DistributedCache *results_cache, Visitor *visitor);
/**
* Creates a new cache that has one element per point in the original
* cache, distributed among the machines in the same way the points
* are.
*
* This automatically calls the master or worker version of this depending
* on rank.
*/
template<typename Result>
void CreateResultCache(int channel, const Result& default_result,
double megs, DistributedCache *results);
/**
* Same as CreateResultCache, but only the master calls this.
*
* This actually does the initialization.
*/
template<typename Result>
void CreateResultCacheMaster(int channel, const Result& default_result,
double megs, DistributedCache *results);
/**
* Same as CreateResultCache, but only the workers calls this.
*
* This just waits for the master to sync up.
*/
template<typename Result>
void CreateResultCacheWorker(int channel,
double megs, DistributedCache *results);
};
/**
* A parallelizable tree-updater.
*
* You use this to read from a separate array of results and update each
* query point, simultaneously updating all the statistics in the tree.
*
* This is only parallel so that each machine only works on its local data,
* avoiding communication. Since updating is not CPU intensive this is
* in most cases an I/O bound process, so it is only single-threaded.
*/
template<class TParam, class TPoint, class TNode,
class TResult, class TVisitor>
class ThorUpdate {
public:
typedef TParam Param;
typedef TPoint Point;
typedef TNode Node;
typedef TResult Result;
typedef TVisitor Visitor;
typedef ThorTreeDecomposition<Node> TreeDecomposition;
typedef typename TreeDecomposition::DecompNode DecompNode;
private:
CacheArray<Point> *points_;
CacheArray<Node> *nodes_;
CacheArray<Result> *results_;
Visitor *visitor_;
const Param *param_;
public:
/**
* Perform the tree update for just one machine.
*
* Note that this will *not* perform any reductions on the visitor, each
* machine has its separate visitor for its own part of the tree.
*
* See class-level comments.
*/
void Doit(int my_rank, const Param *param, const TreeDecomposition& decomp,
Visitor *visitor, DistributedCache *results_cache,
DistributedCache *points_cache, DistributedCache *nodes_cache);
private:
void Assemble_(const DecompNode *decomp, Node *parent);
void Recurse_(index_t node_index, Node *parent);
};
#include "thortree_impl.h"
#endif