Files
mlpack/fastlib/thor/rbfs_impl.h
T

287 lines
8.9 KiB
C++

/**
* @file rbfs_impl.h
*
* Depth-first dual-tree solver template implementations.
*/
template<typename GNP>
DualTreeRecursiveBreadth<GNP>::~DualTreeRecursiveBreadth() {
r_nodes_.StopRead(0);
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::Doit(
const typename GNP::Param& param_in,
index_t q_root_index,
index_t q_end_index,
DistributedCache *q_points,
DistributedCache *q_nodes,
DistributedCache *r_points,
DistributedCache *r_nodes,
DistributedCache *q_results) {
param_.Copy(param_in);
q_nodes_.Init(q_nodes, BlockDevice::M_READ);
r_points_.Init(r_points, BlockDevice::M_READ);
r_nodes_.Init(r_nodes, BlockDevice::M_READ);
const typename GNP::QNode *q_root = q_nodes_.StartRead(q_root_index);
q_results_.Init(q_results, BlockDevice::M_OVERWRITE,
q_root->begin(), q_root->end());
q_points_.Init(q_points, BlockDevice::M_READ,
q_root->begin(), q_root->end());
q_nodes_.StopRead(q_root_index);
global_result_.Init(param_);
r_root_ = r_nodes_.StartRead(0);
do_naive_ = false;
Begin_(q_root_index);
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::Begin_(index_t q_root_index) {
typename GNP::Delta delta;
CacheRead<typename GNP::QNode> q_root(&q_nodes_, q_root_index);
stats_.Init();
stats_.tuples_analyzed = q_root->count() * r_root_->count();
stats_.n_queries = q_root->count();
Queue queue;
queue.Init(param_);
queue.Consider(param_, *q_root, *r_root_, 0, &global_result_);
Divide_(q_root_index, &queue);
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::PushDownPostprocess_(
const typename GNP::QNode& q_node,
const typename GNP::QPostponed& postponed) {
if (q_node.is_leaf()) {
index_t q_i = q_node.begin();
CacheWriteIter<typename GNP::QResult> q_result(&q_results_, q_i);
CacheReadIter<typename GNP::QPoint> q_point(&q_points_, q_i);
for (; q_i < q_node.end(); q_i++, q_result.Next(), q_point.Next()) {
q_result->ApplyPostponed(param_, postponed, *q_point, q_i);
q_result->Postprocess(param_, *q_point, q_i, *r_root_);
global_result_.ApplyResult(param_, *q_point, q_i, *q_result);
}
} else {
for (int k = 0; k < GNP::QNode::CARDINALITY; k++) {
CacheRead<typename GNP::QNode> q_child(&q_nodes_, q_node.child(k));
PushDownPostprocess_(*q_child, postponed);
}
}
}
template<typename GNP>
bool DualTreeRecursiveBreadth<GNP>::BeginExploringQueue_(
const typename GNP::QNode& q_node, Queue *parent_queue) {
if (parent_queue->q.size() == 0
|| !GNP::Algorithm::ConsiderQueryTermination(
param_, q_node, parent_queue->summary_result,
global_result_, &parent_queue->postponed)) {
// Distribute mass results to the leaves
PushDownPostprocess_(q_node, parent_queue->postponed);
return false;
} else {
return true;
}
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::Queue::Init(
const typename GNP::Param& param) {
q.Init();
summary_result.Init(param);
postponed.Init(param);
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::Queue::Consider(
const typename GNP::Param& param,
const typename GNP::QNode& q_node, const typename GNP::RNode& r_node,
index_t r_index,
typename GNP::GlobalResult *global_result) {
QueueItem *item = q.AddBack();
item->r_index = r_index;
if (likely(GNP::Algorithm::ConsiderPairIntrinsic(param, q_node, r_node,
&item->delta, global_result, &postponed))) {
summary_result.ApplyDelta(param, item->delta);
} else {
q.PopBack();
}
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::Queue::Reconsider(
const typename GNP::Param& param,
const QueueItem& item) {
new(q.AddBack())QueueItem(item);
summary_result.ApplyDelta(param, item.delta);
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::Queue::Done(
const typename GNP::Param& param,
const typename GNP::QPostponed& parent_postponed,
const typename GNP::QNode& q_node) {
postponed.ApplyPostponed(param, parent_postponed);
summary_result.ApplyPostponed(param, postponed, q_node);
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::DivideReferences_(
index_t q_node_i, Queue* parent_queue) {
const typename GNP::QNode q_node(*q_nodes_.StartRead(q_node_i));
q_nodes_.StopRead(q_node_i);
if (!BeginExploringQueue_(q_node, parent_queue)) {
return;
}
Queue child_queue;
child_queue.Init(param_);
DEBUG_ONLY(stats_.node_node_considered += parent_queue->q.size());
for (index_t i = 0; i < parent_queue->q.size(); i++) {
const QueueItem *item = &parent_queue->q[i];
CacheRead<typename GNP::RNode> r_node(&r_nodes_, item->r_index);
if (likely(GNP::Algorithm::ConsiderPairExtrinsic(
param_, q_node, *r_node, item->delta, parent_queue->summary_result,
global_result_, &parent_queue->postponed))) {
if (!r_node->is_leaf()) {
for (int k_r = 0; k_r < GNP::RNode::CARDINALITY; k_r++) {
index_t r_child_i = r_node->child(k_r);
CacheRead<typename GNP::RNode> r_child(&r_nodes_, r_child_i);
child_queue.Consider(param_, q_node, *r_child, r_child_i,
&global_result_);
}
} else {
BaseCase_(q_node, *r_node);
}
}
}
child_queue.Done(param_, parent_queue->postponed, q_node);
DivideReferences_(q_node_i, &child_queue);
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::Divide_(
index_t q_node_i, Queue* parent_queue) {
const typename GNP::QNode q_node(*q_nodes_.StartRead(q_node_i));
q_nodes_.StopRead(q_node_i);
if (q_node.is_leaf()) {
DivideReferences_(q_node_i, parent_queue);
return;
}
if (!BeginExploringQueue_(q_node, parent_queue)) {
return;
}
Queue child_queues[GNP::QNode::CARDINALITY];
const typename GNP::QNode *q_children[GNP::QNode::CARDINALITY];
for (int k = 0; k < GNP::QNode::CARDINALITY; k++) {
q_children[k] = q_nodes_.StartRead(q_node.child(k));
child_queues[k].Init(param_);
}
DEBUG_ONLY(stats_.node_node_considered += parent_queue->q.size());
for (index_t i = 0; i < parent_queue->q.size(); i++) {
const QueueItem *item = &parent_queue->q[i];
CacheRead<typename GNP::RNode> r_node(&r_nodes_, item->r_index);
if (likely(GNP::Algorithm::ConsiderPairExtrinsic(
param_, q_node, *r_node, item->delta, parent_queue->summary_result,
global_result_, &parent_queue->postponed))) {
if (!r_node->is_leaf()) {
for (int k_r = 0; k_r < GNP::RNode::CARDINALITY; k_r++) {
index_t r_child_i = r_node->child(k_r);
CacheRead<typename GNP::RNode> r_child(&r_nodes_, r_child_i);
for (int k_q = 0; k_q < GNP::QNode::CARDINALITY; k_q++) {
child_queues[k_q].Consider(param_, *q_children[k_q], *r_child,
r_child_i, &global_result_);
}
}
} else {
for (int k_q = 0; k_q < GNP::QNode::CARDINALITY; k_q++) {
child_queues[k_q].Reconsider(param_, *item);
}
}
}
}
// Release the locks on the children to ease cache pressure in the FIFO
for (int k = 0; k < GNP::QNode::CARDINALITY; k++) {
child_queues[k].Done(param_, parent_queue->postponed, *q_children[k]);
q_nodes_.StopRead(q_node.child(k));
}
for (int k = 0; k < GNP::QNode::CARDINALITY; k++) {
Divide_(q_node.child(k), &child_queues[k]);
}
}
template<typename GNP>
void DualTreeRecursiveBreadth<GNP>::BaseCase_(
const typename GNP::QNode& q_node,
const typename GNP::RNode& r_node) {
DEBUG_ONLY(stats_.node_point_considered += q_node.count());
typename GNP::PairVisitor visitor;
visitor.Init(param_);
CacheRead<typename GNP::QPoint> first_q_point(&q_points_, q_node.begin());
CacheWrite<typename GNP::QResult> first_q_result(&q_results_, q_node.begin());
CacheRead<typename GNP::RPoint> first_r_point(&r_points_, r_node.begin());
size_t q_point_stride = q_points_.n_elem_bytes();
size_t q_result_stride = q_results_.n_elem_bytes();
size_t r_point_stride = r_points_.n_elem_bytes();
index_t q_end = q_node.end();
const typename GNP::QPoint *q_point = first_q_point;
typename GNP::QResult *q_result = first_q_result;
for (index_t q_i = q_node.begin(); q_i < q_end; ++q_i) {
if (visitor.StartVisitingQueryPoint(param_, *q_point, q_i, r_node,
q_result, &global_result_)) {
const typename GNP::RPoint *r_point = first_r_point;
index_t r_i = r_node.begin();
index_t r_left = r_node.count();
for (;;) {
visitor.VisitPair(param_, *q_point, q_i, *r_point, r_i);
if (unlikely(--r_left == 0)) {
break;
}
r_i++;
r_point = mem::PointerAdd(r_point, r_point_stride);
}
visitor.FinishVisitingQueryPoint(param_, *q_point, q_i, r_node,
q_result, &global_result_);
DEBUG_ONLY(stats_.point_point_considered += r_node.count());
}
q_point = mem::PointerAdd(q_point, q_point_stride);
q_result = mem::PointerAdd(q_result, q_result_stride);
}
}