Fixed the query=reference case

This commit is contained in:
vasiloglou
2008-02-15 16:32:55 +00:00
parent 9846258b24
commit e809c275bc
2 changed files with 178 additions and 53 deletions
+148 -45
View File
@@ -86,15 +86,12 @@ class AllkNN {
}
}; //class AllNNStat
public:
// QueryTrees are BinarySpaceTrees where the data are bounded by
// TreeType are BinarySpaceTrees where the data are bounded by
// Euclidean bounding boxes, the data are stored in a Matrix,
// and each node has a QueryStat for its bound.
typedef BinarySpaceTree<DHrectBound<2>, Matrix, QueryStat> QueryTree;
// ReferenceTrees are the same as QueryTrees, but don't need node
// statistics for this algorithm.
typedef BinarySpaceTree<DHrectBound<2>, Matrix> ReferenceTree;
typedef BinarySpaceTree<DHrectBound<2>, Matrix, QueryStat> TreeType;
/////////////////////////////// Members //////////////////////////////////////////////////
private:
@@ -102,8 +99,8 @@ class AllkNN {
Matrix queries_;
Matrix references_;
// Pointers to the roots of the two trees.
QueryTree* query_tree_;
ReferenceTree* reference_tree_;
TreeType* query_tree_;
TreeType* reference_tree_;
// The total number of prunes.
index_t number_of_prunes_;
// A permutation of the indices for tree building.
@@ -149,22 +146,14 @@ class AllkNN {
delete reference_tree_;
}
}
/** Accessors
*/
QueryTree *get_query_tree() {
return query_tree_;
}
ReferenceTree *get_reference_tree() {
return reference_tree_;
}
/////////////////////////////// Helper Functions ///////////////////////////////////////////////////
/**
* Computes the minimum squared distance between the bounding boxes of two nodes
*/
double MinNodeDistSq_ (QueryTree* query_node, ReferenceTree* reference_node) {
double MinNodeDistSq_ (TreeType* query_node, TreeType* reference_node) {
// node->bound() gives us the DHrectBound class for the node
// It has a function MinDistanceSq which takes another DHrectBound
return query_node->bound().MinDistanceSq(reference_node->bound());
@@ -174,7 +163,7 @@ class AllkNN {
/**
* Performs exhaustive computation between two leaves.
*/
void ComputeBaseCase_(QueryTree* query_node, ReferenceTree* reference_node) {
void ComputeBaseCase_(TreeType* query_node, TreeType* reference_node) {
// DEBUG statements should be used frequently, since they incur no overhead
// when compiled in fast mode
@@ -212,7 +201,9 @@ class AllkNN {
// We'll use lapack to find the distance between the two vectors
double distance = la::DistanceSqEuclidean(query_point, reference_point);
if (unlikely(reference_node == query_node && distance ==0)) {
continue;
}
// If the reference point is closer than the current candidate,
// we'll update the candidate
if (distance < neighbor_distances_[ind+knns_-1]) {
@@ -242,8 +233,8 @@ class AllkNN {
/**
* The recursive function
*/
void ComputeNeighborsRecursion_ (QueryTree* query_node,
ReferenceTree* reference_node, double lower_bound_distance) {
void ComputeNeighborsRecursion_ (TreeType* query_node, TreeType* reference_node,
double lower_bound_distance) {
// DEBUG statements should be used frequently,
// either with or without messages
@@ -395,9 +386,9 @@ class AllkNN {
// This call makes each tree from a matrix, leaf size, and two arrays
// that record the permutation of the data points
// Instead of NULL, it is possible to specify an array new_from_old_
query_tree_ = tree::MakeKdTreeMidpoint<QueryTree>(queries_, leaf_size_,
query_tree_ = tree::MakeKdTreeMidpoint<TreeType>(queries_, leaf_size_,
&old_from_new_queries_, NULL);
reference_tree_ = tree::MakeKdTreeMidpoint<ReferenceTree>(references_,
reference_tree_ = tree::MakeKdTreeMidpoint<TreeType>(references_,
leaf_size_, &old_from_new_references_, NULL);
// Stop the timer we started above
@@ -405,10 +396,52 @@ class AllkNN {
} // Init
/** Use this if you want to run allknn it on a single dataset
* the query tree and reference tree are the same
*/
void Init(const Matrix& references_in, struct datanode* module_in) {
// set the module
module_ = module_in;
// track the number of prunes
number_of_prunes_ = 0;
// Get the leaf size from the module
leaf_size_ = fx_param_int(module_, "leaf_size", 20);
// Make sure the leaf size is valid
DEBUG_ASSERT(leaf_size_ > 0);
// Copy the matrices to the class members since they will be rearranged.
references_.Copy(references_in);
queries_.Alias(references_);
// K-nearest neighbors initialization
knns_ = fx_param_int(module_, "knns", 5);
// Initialize the list of nearest neighbor candidates
neighbor_indices_.Init(references_.n_cols() * knns_);
// Initialize the vector of upper bounds for each point.
neighbor_distances_.Init(references_.n_cols() * knns_);
neighbor_distances_.SetAll(DBL_MAX);
// We'll time tree building
fx_timer_start(module_, "tree_building");
// This call makes each tree from a matrix, leaf size, and two arrays
// that record the permutation of the data points
// Instead of NULL, it is possible to specify an array new_from_old_
query_tree_ = NULL;
reference_tree_ = tree::MakeKdTreeMidpoint<TreeType>(references_,
leaf_size_, &old_from_new_references_, NULL);
// Stop the timer we started above
fx_timer_stop(module_, "tree_building");
}
void Init(const Matrix& queries_in, const Matrix& references_in,
index_t leaf_size, index_t knns) {
// track the number of prunes
number_of_prunes_ = 0;
@@ -438,13 +471,45 @@ class AllkNN {
// This call makes each tree from a matrix, leaf size, and two arrays
// that record the permutation of the data points
// Instead of NULL, it is possible to specify an array new_from_old_
query_tree_ = tree::MakeKdTreeMidpoint<QueryTree>(queries_, leaf_size_,
query_tree_ = tree::MakeKdTreeMidpoint<TreeType>(queries_, leaf_size_,
&old_from_new_queries_, NULL);
reference_tree_ = tree::MakeKdTreeMidpoint<ReferenceTree>(references_,
reference_tree_ = tree::MakeKdTreeMidpoint<TreeType>(references_,
leaf_size_, &old_from_new_references_, NULL);
} // Init
void Init(const Matrix& references_in, index_t leaf_size, index_t knns) {
// track the number of prunes
number_of_prunes_ = 0;
// Make sure the leaf size is valid
leaf_size_ = leaf_size;
DEBUG_ASSERT(leaf_size_ > 0);
// Make sure the knns is valid
knns_ = knns;
DEBUG_ASSERT(knns_ > 0);
// Copy the matrices to the class members since they will be rearranged.
references_.Copy(references_in);
queries_.Alias(references_);
// Initialize the list of nearest neighbor candidates
neighbor_indices_.Init(references_.n_cols() * knns_);
// Initialize the vector of upper bounds for each point.
neighbor_distances_.Init(references_.n_cols() * knns_);
neighbor_distances_.SetAll(DBL_MAX);
// This call makes each tree from a matrix, leaf size, and two arrays
// that record the permutation of the data points
// Instead of NULL, it is possible to specify an array new_from_old_
query_tree_ = NULL;
reference_tree_ = tree::MakeKdTreeMidpoint<TreeType>(references_,
leaf_size_, &old_from_new_references_, NULL);
// This is an annoying feature of fastlib
old_from_new_queries_.Init();
}
/**
* Initializes the AllNN structure for naive computation.
* This means that we simply ignore the tree building.
@@ -466,13 +531,33 @@ class AllkNN {
// that each tree has only one node
leaf_size_ = max(queries_.n_cols(), references_.n_cols());
query_tree_ = tree::MakeKdTreeMidpoint<QueryTree>(queries_,
query_tree_ = tree::MakeKdTreeMidpoint<TreeType>(queries_,
leaf_size_, &old_from_new_queries_, NULL);
reference_tree_ = tree::MakeKdTreeMidpoint<ReferenceTree>(
reference_tree_ = tree::MakeKdTreeMidpoint<TreeType>(
references_, leaf_size_, &old_from_new_references_, NULL);
} // InitNaive
void InitNaive(const Matrix& references_in, index_t knns){
references_.Copy(references_in);
queries_.Alias(references_);
knns_=knns;
neighbor_indices_.Init(references_.n_cols()*knns_);
neighbor_distances_.Init(references_.n_cols()*knns_);
neighbor_distances_.SetAll(DBL_MAX);
// The only difference is that we set leaf_size_ to be large enough
// that each tree has only one node
leaf_size_ = references_.n_cols();
query_tree_ = NULL;
reference_tree_ = tree::MakeKdTreeMidpoint<TreeType>(
references_, leaf_size_, &old_from_new_references_, NULL);
// This is an annoying feature of fastlib
old_from_new_queries_.Init();
} // InitNaive
/**
* Computes the nearest neighbors and stores them in *results
@@ -481,24 +566,38 @@ class AllkNN {
ArrayList<double>* distances) {
// Start on the root of each tree
ComputeNeighborsRecursion_(query_tree_, reference_tree_,
MinNodeDistSq_(query_tree_, reference_tree_));
if (query_tree_!=NULL) {
ComputeNeighborsRecursion_(query_tree_, reference_tree_,
MinNodeDistSq_(query_tree_, reference_tree_));
} else {
ComputeNeighborsRecursion_(reference_tree_, reference_tree_,
MinNodeDistSq_(reference_tree_, reference_tree_));
}
// We need to initialize the results list before filling it
resulting_neighbors->Init(neighbor_indices_.size());
distances->Init(neighbor_distances_.length());
// We need to map the indices back from how they have
// been permuted
for (index_t i = 0; i < neighbor_indices_.size(); i++) {
(*resulting_neighbors)[
old_from_new_queries_[i/knns_]*knns_+ i%knns_] =
old_from_new_references_[neighbor_indices_[i]];
(*distances)[
old_from_new_queries_[i/knns_]*knns_+ i%knns_] =
neighbor_distances_[i];
if (query_tree_ != NULL) {
for (index_t i = 0; i < neighbor_indices_.size(); i++) {
(*resulting_neighbors)[
old_from_new_queries_[i/knns_]*knns_+ i%knns_] =
old_from_new_references_[neighbor_indices_[i]];
(*distances)[
old_from_new_queries_[i/knns_]*knns_+ i%knns_] =
neighbor_distances_[i];
}
} else {
for (index_t i = 0; i < neighbor_indices_.size(); i++) {
(*resulting_neighbors)[
old_from_new_references_[i/knns_]*knns_+ i%knns_] =
old_from_new_references_[neighbor_indices_[i]];
(*distances)[
old_from_new_references_[i/knns_]*knns_+ i%knns_] =
neighbor_distances_[i];
}
}
} // ComputeNeighbors
@@ -507,8 +606,12 @@ class AllkNN {
*/
void ComputeNaive(ArrayList<index_t>* resulting_neighbors,
ArrayList<double>* distances) {
ComputeBaseCase_(query_tree_, reference_tree_);
if (query_tree_!=NULL) {
ComputeBaseCase_(query_tree_, reference_tree_);
} else {
ComputeBaseCase_(reference_tree_, reference_tree_);
}
// The same code as above
resulting_neighbors->Init(neighbor_indices_.size());
distances->Init(neighbor_distances_.length());
@@ -516,10 +619,10 @@ class AllkNN {
// been permuted
for (index_t i = 0; i < neighbor_indices_.size(); i++) {
(*resulting_neighbors)[
old_from_new_queries_[i/knns_]*knns_+ i%knns_] =
old_from_new_references_[i/knns_]*knns_+ i%knns_] =
old_from_new_references_[neighbor_indices_[i]];
(*distances)[
old_from_new_queries_[i/knns_]*knns_+ i%knns_] =
old_from_new_references_[i/knns_]*knns_+ i%knns_] =
neighbor_distances_[i];
}
+30 -8
View File
@@ -13,9 +13,7 @@ class TestAllkNN {
naive_ = new AllkNN();
data_for_tree_ = new Matrix();
data::Load("test_data_3_1000.csv", data_for_tree_);
allknn_->Init(*data_for_tree_, *data_for_tree_, 20, 5);
naive_->InitNaive(*data_for_tree_, *data_for_tree_, 5);
}
}
void Destruct() {
delete data_for_tree_;
@@ -23,8 +21,11 @@ class TestAllkNN {
delete naive_;
}
void TestTreeVsNaive() {
void TestTreeVsNaive1() {
Init();
allknn_->Init(*data_for_tree_, *data_for_tree_, 20, 5);
naive_->InitNaive(*data_for_tree_, *data_for_tree_, 5);
ArrayList<index_t> resulting_neighbors_tree;
ArrayList<double> distances_tree;
allknn_->ComputeNeighbors(&resulting_neighbors_tree,
@@ -37,14 +38,35 @@ class TestAllkNN {
TEST_ASSERT(resulting_neighbors_tree[i] == resulting_neighbors_naive[i]);
TEST_DOUBLE_APPROX(distances_tree[i], distances_naive[i], 1e-5);
}
NOTIFY("Allknn test passed");
NOTIFY("Allknn test 1 passed");
Destruct();
}
void TestAll() {
TestTreeVsNaive();
void TestTreeVsNaive2() {
Init();
allknn_->Init(*data_for_tree_, 20, 5);
naive_->InitNaive(*data_for_tree_, 5);
ArrayList<index_t> resulting_neighbors_tree;
ArrayList<double> distances_tree;
allknn_->ComputeNeighbors(&resulting_neighbors_tree,
&distances_tree);
ArrayList<index_t> resulting_neighbors_naive;
ArrayList<double> distances_naive;
naive_->ComputeNaive(&resulting_neighbors_naive,
&distances_naive);
for(index_t i=0; i<resulting_neighbors_tree.size(); i++) {
TEST_ASSERT(resulting_neighbors_tree[i] == resulting_neighbors_naive[i]);
TEST_DOUBLE_APPROX(distances_tree[i], distances_naive[i], 1e-5);
}
NOTIFY("Allknn test 2 passed");
Destruct();
}
void TestAll() {
TestTreeVsNaive1();
TestTreeVsNaive2();
}
private:
AllkNN *allknn_;
AllkNN *naive_;