From 5adef387dc703f100fa99a2d809c6cdc45366364 Mon Sep 17 00:00:00 2001 From: Bill March Date: Wed, 9 Feb 2011 21:45:56 +0000 Subject: [PATCH] wrote old auton-style multi-tree n-point, did very basic tests, needs more testing. --- .../contrib/march/n_point/CMakeLists.txt | 2 + .../contrib/march/n_point/n_point_main.cc | 20 +- .../march/n_point/single_bandwidth_alg.cc | 213 ++++++++++++++++++ .../march/n_point/single_bandwidth_alg.h | 71 +++++- .../contrib/march/n_point/single_matcher.h | 4 + 5 files changed, 306 insertions(+), 4 deletions(-) diff --git a/fastlib/branches/fastlib-stl/contrib/march/n_point/CMakeLists.txt b/fastlib/branches/fastlib-stl/contrib/march/n_point/CMakeLists.txt index c281644a96..1ab9a9ff45 100644 --- a/fastlib/branches/fastlib-stl/contrib/march/n_point/CMakeLists.txt +++ b/fastlib/branches/fastlib-stl/contrib/march/n_point/CMakeLists.txt @@ -9,6 +9,8 @@ set(SOURCES permutations.cc single_matcher.h single_matcher.cc + single_bandwidth_alg.h + single_bandwidth_alg.cc ) # add directory name to sources diff --git a/fastlib/branches/fastlib-stl/contrib/march/n_point/n_point_main.cc b/fastlib/branches/fastlib-stl/contrib/march/n_point/n_point_main.cc index f505b4d6e3..b2ceecd159 100644 --- a/fastlib/branches/fastlib-stl/contrib/march/n_point/n_point_main.cc +++ b/fastlib/branches/fastlib-stl/contrib/march/n_point/n_point_main.cc @@ -7,8 +7,7 @@ * */ -// take this out later, just debugging with it -#include "single_matcher.h" +#include "single_bandwidth_alg.h" using namespace npt; @@ -37,12 +36,27 @@ int main(int argc, char* argv[]) { upper_bds.load("test_upper_bds.csv"); + arma::mat data; + data.load("test_data.csv"); + + arma::colvec weights(data.n_cols); + weights.fill(1.0); + + index_t leaf_size = 1; + + SingleBandwidthAlg alg(data, weights, data.n_cols, leaf_size, lower_bds, + upper_bds); + + std::cout << "Num tuples: " << alg.num_tuples() << "\n"; + + /* SingleMatcher matcher(3, lower_bds, upper_bds); std::vector perm_ok1(6, true); std::cout << "Testing points: " << matcher.TestPointPair(0.5, 0, 1, perm_ok1) << "\n"; - + */ + //std::vector perm_ok2(6, true); //std::cout << "Testing boxes: " << TestHrectPair(5.0, ); diff --git a/fastlib/branches/fastlib-stl/contrib/march/n_point/single_bandwidth_alg.cc b/fastlib/branches/fastlib-stl/contrib/march/n_point/single_bandwidth_alg.cc index 2ad63ef92b..31a6bdb262 100644 --- a/fastlib/branches/fastlib-stl/contrib/march/n_point/single_bandwidth_alg.cc +++ b/fastlib/branches/fastlib-stl/contrib/march/n_point/single_bandwidth_alg.cc @@ -9,3 +9,216 @@ #include "single_bandwidth_alg.h" +bool npt::SingleBandwidthAlg::CheckNodeList_(std::vector& nodes) { + + bool can_prune = false; + + // note that this has to enforce symmetry + std::vector permutation_ok(matcher_.num_permutations(), true); + + // iterate over all nodes + // IMPORTANT: right now, I'm exiting when I can prune + // I need to double check that this works + for (index_t i = 0; !can_prune && i < tuple_size_; i++) { + + SingleNode* node_i = nodes[i]; + + // iterate over all nodes > i + for (index_t j = i+1; !can_prune && j < tuple_size_; j++) { + + SingleNode* node_j = nodes[j]; + + // check for symmetry + if (node_j->end() <= node_i->begin()) { + return false; + } // symmetry check + + can_prune = matcher_.TestHrectPair(node_i->bound(), node_j->bound(), + i, j, permutation_ok); + + } // for j + + } // for i + + return can_prune; + +} // CheckNodeList + + + +void npt::SingleBandwidthAlg::BaseCaseHelper_(std::vector >& point_sets, + std::vector& permutation_ok, + std::vector& points_in_tuple, + int k) { + + + std::vector permutation_ok_copy(permutation_ok); + + bool bad_symmetry = false; + + std::vector& k_rows = point_sets[k]; + + // iterate over possible kth members of the tuple + for (index_t i = 0; i < k_rows.size(); i++) { + + index_t point_i_index = k_rows[i]; + bool this_point_works = true; + + arma::colvec vec_i = data_points_.col(point_i_index); + + // TODO: Does this leak memory? + permutation_ok_copy.assign(permutation_ok.begin(), permutation_ok.end()); + + // loop over points already in the tuple and check against them + for (index_t j = 0; this_point_works && j < k; j++) { + + index_t point_j_index = points_in_tuple[j]; + + // j comes before i in the tuple, so it should have a lower index + bad_symmetry = (point_i_index <= point_j_index); + + if (!bad_symmetry) { + + arma::colvec vec_j = data_points_.col(j); + + double point_dist_sq = la::DistanceSqEuclidean(vec_i, vec_j); + + this_point_works = matcher_.TestPointPair(point_dist_sq, j, k, + permutation_ok_copy); + + } // check the distances across permutations + + } // for j + + // point i fits in the tuple + if (this_point_works && !bad_symmetry) { + + points_in_tuple[k] = point_i_index; + + // are we finished? + if (k == tuple_size_ - 1) { + + num_tuples_++; + + double this_weight = 1.0; + + for (index_t tuple_ind = 0; tuple_ind < tuple_size_; tuple_ind++) { + + this_weight *= data_weights_(points_in_tuple[tuple_ind]); + + } // iterate over the tuple + + weighted_num_tuples_ += this_weight; + + } + else { + + BaseCaseHelper_(point_sets, permutation_ok_copy, points_in_tuple, k+1); + + } // need to add more points to finish the tuple + + } // point i fits + + } // for i + +} // BaseCaseHelper_ + + + +void npt::SingleBandwidthAlg::BaseCase_(std::vector& nodes) { + + std::vector > point_sets; + + // TODO: can this be done more efficiently? + + // Make a 2D array of the points in the nodes + // iterate over nodes + for (index_t node_ind = 0; node_ind < tuple_size_; node_ind++) { + + point_sets[node_ind].resize(nodes[node_ind]->count()); + + // fill in points in the node + for (index_t point_ind = nodes[node_ind]->begin(); + point_ind < nodes[node_ind]->end(); point_ind++) { + + point_sets[node_ind][point_ind] = point_ind; + + } // points + + } // nodes + + std::vector permutation_ok(matcher_.num_permutations(), true); + + std::vector points_in_tuple(tuple_size_, -1); + + BaseCaseHelper_(point_sets, permutation_ok, points_in_tuple, 0); + +} // BaseCase_() + + + + +void npt::SingleBandwidthAlg::DepthFirstRecursion_(std::vector& nodes) { + + // check for symmetry and pruning + bool can_prune = CheckNodeList_(nodes); + + if (can_prune) { + + // note that this will count prunes based on symmetry too + num_prunes_++; + + } + else { + + // look over all the nodes, see if they are leaves, and if not, which one + // to splits + bool all_leaves = nodes[0]->is_leaf(); + index_t split_index = 0; + // if node 0 is not a leaf, then use it, otherwise don't + index_t split_count = all_leaves ? -1 : nodes[0]->count(); + + // loop over the other nodes, check for leaves and who to split + for (index_t i = 1; i < tuple_size_; i++) { + + if (!(nodes[i]->is_leaf())) { + + all_leaves = false; + + if (nodes[i]->count() > split_count) { + split_count = nodes[i]->count(); + split_index = i; + } + + } // not a leaf + + } // for i + + // Do we do the base case or recurse? + + if (all_leaves) { + + BaseCase_(nodes); + + } + else { + + SingleNode* split_node = nodes[split_index]; + + // left child first + nodes[split_index] = split_node->left(); + DepthFirstRecursion_(nodes); + + // now do the other child + nodes[split_index] = split_node->right(); + DepthFirstRecursion_(nodes); + + // This is important for calls above this one. + nodes[split_index] = split_node; + + + } // not a base case + + } // can't prune + +} // DepthFirstRecursion_ diff --git a/fastlib/branches/fastlib-stl/contrib/march/n_point/single_bandwidth_alg.h b/fastlib/branches/fastlib-stl/contrib/march/n_point/single_bandwidth_alg.h index c7eff7bf77..a160d8caa3 100644 --- a/fastlib/branches/fastlib-stl/contrib/march/n_point/single_bandwidth_alg.h +++ b/fastlib/branches/fastlib-stl/contrib/march/n_point/single_bandwidth_alg.h @@ -29,6 +29,7 @@ namespace npt { // input params index_t num_points_; index_t tuple_size_; + index_t leaf_size_; // the matcher SingleMatcher matcher_; @@ -41,10 +42,78 @@ namespace npt { // the number of times we pruned a tuple int num_prunes_; - NPointNode* tree_; + // define the tree + typedef BinarySpaceTree, arma::mat> SingleNode; + + arma::Col old_from_new_index_; + + SingleNode* tree_; + + + ////////////////////// functions ///////////////////////// + + bool CheckNodeList_(std::vector& nodes); + + void BaseCaseHelper_(std::vector >& point_sets, + std::vector& permutation_ok, + std::vector& points_in_tuple, + int k); + + void BaseCase_(std::vector& nodes); + + void DepthFirstRecursion_(std::vector& nodes); + public: + /** + * Requires the matcher bounds, data, parameters + */ + SingleBandwidthAlg(arma::mat& data, arma::colvec weights, index_t n, + index_t leaf_size, + arma::mat& lower_bds, arma::mat& upper_bds) : + matcher_(n, lower_bds, upper_bds) + { + + data_points_ = data; + data_weights_ = weights; + num_points_ = data_points_.n_cols; + tuple_size_ = n; + leaf_size_ = leaf_size; + + num_tuples_ = 0; + weighted_num_tuples_ = 0.0; + num_prunes_ = 0; + + tree_ = tree::MakeKdTreeMidpoint(data_points_, + leaf_size_, + old_from_new_index_); + + // IMPORTANT: need to permute the weights here + + + + } // constructor + + int num_tuples() { + return num_tuples_; + } + + double weighted_num_tuples() { + return weighted_num_tuples_; + } + + + /** + * Actually run the algorithm. + */ + void ComputeCounts() { + + std::vector node_list(tuple_size_, tree_); + + DepthFirstRecursion_(node_list); + + } // ComputeCounts() diff --git a/fastlib/branches/fastlib-stl/contrib/march/n_point/single_matcher.h b/fastlib/branches/fastlib-stl/contrib/march/n_point/single_matcher.h index b5a95dd6bd..1f944a7057 100644 --- a/fastlib/branches/fastlib-stl/contrib/march/n_point/single_matcher.h +++ b/fastlib/branches/fastlib-stl/contrib/march/n_point/single_matcher.h @@ -75,6 +75,10 @@ namespace npt { index_t tuple_ind_1, index_t tuple_ind_2, std::vector& permutation_ok); + index_t num_permutations() { + return num_permutations_; + } + }; // class