Files
mlpack/fastlib/u/nvasil/tree/old/tree_impl.h
T
2007-04-28 16:15:38 +00:00

475 lines
16 KiB
C++

#ifndef TREE_IMPL_H_
#define TREE_IMPL_H_
#define __TEMPLATE__ \
template<typename PRECISION, \
typename IDPRECISION, \
typename ALLOCATOR, \
bool diagnostic, \
template<typename PREC, \
typename IDPREC, \
typename ALLOCATOR, \
bool diagnostic> class NODE>
#define __TREE__ Tree<PRECISION, IDPRECISION, ALLOCATOR, diagnostic, NODE>
// Straight forward implemantation of the algorithms as described in Andrew Moore's
// paper. For more information regarding traits of nearest neighbors look at
// traits_nearest_neighbor.h file
__TEMPLATE__
__TREE__::Tree(DataReader<PRECISION, IDPRECISION> *data,
int32 dimension, IDPRECISION num_of_points) {
data_ = data;
dimension_ = dimension;
num_of_points_ = num_of_points;
node_id_=0;
num_of_leafs_=0;
current_level_=0;
max_depth_ = 0;
min_depth_ = numeric_limits<IDPRECISION>::max();
max_points_on_leaf_ = 30;
log_progress_=true;
discriminator_.reset(new PointIdentityDiscriminator<IDPRECISION>());
}
__TEMPLATE__
__TREE__::~Tree(){
}
__TEMPLATE__
void __TREE__::SerialBuildBreadthFirst() {
progress_.Reset();
total_points_visited_ = 0;
list<pair<Node_ptr_ptr, Pivot_t *> > fifo;
Pivot_t *pivot = Policy_t::PivotParent(data_, num_of_points_, dimension_);
parent_.Reset(new Node_t(pivot, node_id_));
node_id_++;
pair<Pivot_t*, Pivot_t*> pivot_pair;
pivot_pair = Policy_t::Pivot(data_, pivot);
delete pivot;
fifo.push_front(make_pair(parent_->get_left().Reference(), pivot_pair.first));
fifo.push_front(make_pair(parent_->get_right().Reference(), pivot_pair.second));
current_level_ =1;
SerialBuildBreadthFirst(fifo);
if (log_progress_==true) {
printf("\n");
}
}
__TEMPLATE__
void __TREE__::SerialBuildBreadthFirst(list<pair<Node_ptr_ptr, Pivot_t *> > &fifo) {
pair<Pivot_t*, Pivot_t*> pivot_pair;
while (!fifo.empty()) {
pair<Node_ptr_ptr, Pivot_t*> fifo_pair;
fifo_pair = fifo.back();
fifo.pop_back();
if (fifo_pair.second->num_of_points_ > max_points_on_leaf_) {
(*fifo_pair.first).Reset(new Node_t(fifo_pair.second, node_id_));
node_id_++;
pivot_pair = Policy_t::Pivot(data_, fifo_pair.second);
delete fifo_pair.second;
fifo.push_front(make_pair((*fifo_pair.first)->get_left().Reference(),
pivot_pair.first));
fifo.push_front(make_pair((*fifo_pair.first)->get_right().Reference(),
pivot_pair.second));
} else {
if (log_progress_==true) {
total_points_visited_ += fifo_pair.second->num_of_points_;
progress_.Show(total_points_visited_, get_num_of_points());
}
(*fifo_pair.first).Reset(new Node_t(fifo_pair.second, node_id_, data_));
num_of_leafs_++;
node_id_++;
}
}
}
__TEMPLATE__
void __TREE__::SerialBuildDepthFirst() {
total_points_visited_ = 0;
min_depth_=numeric_limits<IDPRECISION>::max();
max_depth_=0;
current_level_=0;
progress_.Reset();
SerialBuildDepthFirst(parent_, Policy_t::PivotParent(data_,
num_of_points_,
dimension_));
if (log_progress_==true) {
printf("\n");
}
}
__TEMPLATE__
void __TREE__::SerialBuildDepthFirst(Node_ptr &ptr,
Pivot_t *pivot_info) {
pair<Pivot_t *, Pivot_t *> pivot_pair;
if (pivot_info->num_of_points_ > max_points_on_leaf_) {
ptr.Reset(new Node_t(pivot_info, node_id_));
node_id_++;
pivot_pair = Policy_t::Pivot(data_, pivot_info);
// There is a case where on all the points are the same
// so pivoting returns 0 points on the left side
// In that case we create a gigantic leaf
if (pivot_pair.first->num_of_points_==0) {
if (log_progress_==true) {
total_points_visited_ +=pivot_pair.second->num_of_points_;
progress_.Show(total_points_visited_, get_num_of_points());
}
if (current_level_ > max_depth_) {
max_depth_=current_level_;
}
if (current_level_ < min_depth_) {
min_depth_=current_level_;
}
ptr.Reset(new Node_t(pivot_pair.second, node_id_, data_));
node_id_++;
num_of_leafs_++;
delete pivot_info;
delete pivot_pair.first;
delete pivot_pair.second;
return;
}
delete pivot_info;
current_level_++;
SerialBuildDepthFirst(ptr->get_left(), pivot_pair.first);
SerialBuildDepthFirst(ptr->get_right(), pivot_pair.second);
current_level_--;
} else {
if (log_progress_==true) {
total_points_visited_ += pivot_info->num_of_points_;
progress_.Show(total_points_visited_, get_num_of_points());
}
if (current_level_ > max_depth_) {
max_depth_=current_level_;
}
if (current_level_ < min_depth_) {
min_depth_=current_level_;
}
ptr.Reset(new Node_t(pivot_info, node_id_, data_));
node_id_++;
num_of_leafs_++;
delete pivot_info;
}
}
// This function will return any of the nearest neighbors
// k nearest, range nearest or just nearest
__TEMPLATE__
template<typename POINTTYPE, typename RETURNTYPE, typename NEIGHBORTYPE>
void __TREE__::NearestNeighbor(POINTTYPE &test_point,
RETURNTYPE *nearest_point,
PRECISION *distance,
NEIGHBORTYPE range) {
bool found = false;
*distance = numeric_limits<PRECISION>::max();
TraitsNearestNeighbor<PRECISION, IDPRECISION, ALLOCATOR>::Prepare(*nearest_point, range);
NearestNeighbor(parent_, test_point, nearest_point, distance, range, found);
}
__TEMPLATE__
template<typename POINTTYPE, typename RETURNTYPE, typename NEIGHBORTYPE>
void __TREE__::NearestNeighbor(Node_ptr ptr,
POINTTYPE &test_point,
RETURNTYPE *nearest_point,
PRECISION *distance,
NEIGHBORTYPE range,
bool &found) {
computations_.UpdateComparisons();
if (!ptr->IsLeaf()){
computations_.UpdateComparisons();
pair<Node_ptr, Node_ptr> child_pair =
ptr->ClosestChild(test_point, dimension_, computations_);
NearestNeighbor(child_pair.first, test_point, nearest_point, distance,
range, found);
if (child_pair.second->get_box().CrossesBoundaries(test_point,
dimension_,
*distance,
computations_)) {
NearestNeighbor(child_pair.second,
test_point,
nearest_point,
distance,
range, found);
}
if (found == true) {
return;
} else {
found = ptr->get_box().IsWithin(test_point,
dimension_, *distance,
computations_)==0;
if (found == true) {
return;
}
}
} else {
ptr->FindNearest(test_point, *nearest_point,
*distance, range, dimension_,
*discriminator_,
computations_);
found = ptr->get_box().IsWithin(test_point, dimension_, *distance,
computations_);
}
}
__TEMPLATE__
template<typename NEIGHBORTYPE>
void __TREE__::AllNearestNeighbors(Node_ptr query,
Node_ptr reference,
NEIGHBORTYPE range) {
ResetCounters();
PRECISION distance = numeric_limits<PRECISION>::max();
progress_.Reset();
AllNearestNeighbors(query, reference, range, distance);
total_points_visited_=0;
}
__TEMPLATE__
template<typename NEIGHBORTYPE >
void __TREE__::AllNearestNeighbors(Node_ptr query,
Node_ptr reference,
NEIGHBORTYPE range,
PRECISION distance) {
if (distance > query->get_min_dist_so_far()) {
return ;
} else {
if (query->IsLeaf() && reference->IsLeaf()) {
PRECISION max_distance=numeric_limits<PRECISION>::max();
reference->FindAllNearest(query,
max_distance,
0, // this has to be fixed in the future
// this value is redundant
range,
dimension_,
*discriminator_,
computations_);
query->set_min_dist_so_far(max_distance);
} else {
if (query->IsLeaf() && !reference->IsLeaf()) {
pair<pair<Node_ptr, PRECISION>,
pair<Node_ptr, PRECISION> > closest_child;
closest_child = query->ClosestNode(reference->get_left(),
reference->get_right(),
dimension_,
computations_);
AllNearestNeighbors(query,
closest_child.first.first, // child
range, // range
closest_child.first.second // distance of query
// from the reference child
);
AllNearestNeighbors(query, closest_child.second.first,
range, closest_child.second.second);
} else {
if (!query->IsLeaf() && reference->IsLeaf()) {
pair<pair<Node_ptr, PRECISION>,
pair<Node_ptr, PRECISION> > closest_child;
closest_child = reference->ClosestNode(query->get_left(),
query->get_right(),
dimension_,
computations_);
AllNearestNeighbors(closest_child.first.first,
reference,
range,
closest_child.first.second);
AllNearestNeighbors(closest_child.second.first,
reference,
range,
closest_child.second.second);
query->set_min_dist_so_far(
min(query->get_min_dist_so_far(),
max(query->get_left()->get_min_dist_so_far(),
query->get_right()->get_min_dist_so_far())));
} else {
if (!query->IsLeaf() && !reference->IsLeaf()) {
pair<pair<Node_ptr, PRECISION>,
pair<Node_ptr, PRECISION> > closest_child;
closest_child = query->get_left()->ClosestNode(
reference->get_left(),
reference->get_right(),
dimension_,
computations_);
AllNearestNeighbors(query->get_left(),
closest_child.first.first,
range,
closest_child.first.second);
AllNearestNeighbors(query->get_left(),
closest_child.second.first,
range,
closest_child.second.second);
closest_child = query->get_right()->ClosestNode(
reference->get_left(),
reference->get_right(),
dimension_,
computations_);
AllNearestNeighbors(query->get_right(),
closest_child.first.first,
range,
closest_child.first.second);
AllNearestNeighbors(query->get_right(),
closest_child.second.first,
range,
closest_child.second.second);
query->set_min_dist_so_far(
min(query->get_min_dist_so_far(),
max(query->get_left()->get_min_dist_so_far(),
query->get_right()->get_min_dist_so_far())));
}
}
}
}
}
}
__TEMPLATE__
void __TREE__::Print() {
RecursivePrint(parent_);
}
__TEMPLATE__
void __TREE__::InitAllKNearestNeighborOutput(string file,
int32 range
) {
FILE *fp=fopen(file.c_str(), "w");
const int32 kChunk=8192;
boost::scoped_array<typename Node_t::Result> buffer;
buffer.reset(new typename Node_t::Result[kChunk*range]);
for(IDPRECISION i=0; i<num_of_points_/kChunk; i++) {
fwrite(buffer.get(), sizeof(typename Node_t::Result),kChunk*range, fp );
}
fwrite(buffer.get(), sizeof(typename Node_t::Result),
(num_of_points_%kChunk)*range, fp );
fclose(fp);
int fd=open(file.c_str(), O_RDWR);
typename Node_t::Result *ptr =(typename Node_t::Result *)mmap(NULL,
sizeof(typename Node_t::Result)*range*num_of_points_,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr==MAP_FAILED) {
fprintf(stderr, "Unable to map file: %s", strerror(errno));
assert(false);
}
close(fd);
all_nn_out_.set_ptr(ptr);
InitAllKNearestNeighborOutput(parent_, range);
}
__TEMPLATE__
void __TREE__::InitAllKNearestNeighborOutput(Node_ptr ptr,
int32 range
) {
if (ptr->IsLeaf()) {
ptr->set_kneighbors(all_nn_out_.Allocate(ptr->get_num_of_points(),
range));
ptr->InitKNeighbors(range);
} else {
InitAllKNearestNeighborOutput(ptr->get_left(), range);
InitAllKNearestNeighborOutput(ptr->get_right(), range);
}
}
__TEMPLATE__
void __TREE__::CloseAllKNearestNeighborOutput(int32 range) {
if (munmap(all_nn_out_.get_ptr(),
sizeof(typename Node_t::Result)*range*num_of_points_)<0) {
fprintf(stderr, "Failed to umap file: %s", strerror(errno));
assert(false);
}
}
__TEMPLATE__
void __TREE__::RecursivePrint(Node_ptr ptr) {
string str;
if (ptr->IsLeaf()) {
str = ptr->Print(dimension_);
printf("%s\n", str.c_str());
} else {
str = ptr->Print(dimension_);
printf("%s\n", str.c_str());
RecursivePrint(ptr->get_left());
RecursivePrint(ptr->get_right());
}
}
__TEMPLATE__
void __TREE__::PrintNeighbors(string filename) {
FILE *fp=fopen(filename.c_str(), "w");
PrintNeighborsRecursive(parent_, fp);
fclose(fp);
}
__TEMPLATE__
void __TREE__::PrintNeighborsRecursive(Node_ptr ptr, FILE *fp) {
if (!ptr->IsLeaf()) {
PrintNeighborsRecursive(ptr->get_left(), fp);
PrintNeighborsRecursive(ptr->get_right(), fp);
} else {
if (ptr->get_neighbors() == NULL) {
return;
}
ptr->PrintNeighbors(fp);
ptr->DeleteNeighbors();
}
}
__TEMPLATE__
string __TREE__::Statistics() {
char buff[4096];
sprintf(buff, "Number of points : %llu,\n"
"Number of dimensions : %i\n"
"Number of nodes : %llu,\n"
"Number of leafs : %llu,\n"
"Max tree depth : %llu,\n"
"Min tree depth : %llu,\n",
(unsigned long long)num_of_points_,
dimension_,
(unsigned long long)node_id_,
(unsigned long long)num_of_leafs_,
(unsigned long long)max_depth_,
(unsigned long long)min_depth_);
return string(buff);
}
__TEMPLATE__
string __TREE__::Computations() {
char buff[4096];
sprintf(buff,"number of comparisons: %llu\n"
"number of distances: %llu\n",
(unsigned long long)computations_.get_comparisons(),
(unsigned long long)computations_.get_distances());
return string(buff);
}
__TEMPLATE__
void __TREE__::set_log_file(const string &log_file) {
if (log_file_ptr_ != stderr ) {
if (fclose(log_file_ptr_)!= 0) {
fprintf(stderr, "Cannot close file %s\n", log_file_.c_str());
assert(false);
}
}
log_file_ptr_ = fopen(log_file.c_str(), "wb");
log_file_ = log_file;
}
#undef __TREE__
#undef __TEMPLATE__
#endif /*TREE_IMPL_H_*/