From 2abc12f6c0e2037d408ea2cfacaa31c687d86556 Mon Sep 17 00:00:00 2001 From: Dongryeol Lee Date: Sun, 3 Feb 2008 21:02:27 +0000 Subject: [PATCH] Skeleton 4-way recursion code added in --- .../dongryel/regression/local_linear_krylov.h | 72 +++++++-- .../regression/local_linear_krylov_main.cc | 45 +++++- .../local_linear_krylov_setup_impl.h | 143 ++++++++++++++++-- 3 files changed, 234 insertions(+), 26 deletions(-) diff --git a/fastlib2/contrib/dongryel/regression/local_linear_krylov.h b/fastlib2/contrib/dongryel/regression/local_linear_krylov.h index f54a4eb2f7..f35defe7db 100644 --- a/fastlib2/contrib/dongryel/regression/local_linear_krylov.h +++ b/fastlib2/contrib/dongryel/regression/local_linear_krylov.h @@ -115,7 +115,8 @@ class LocalLinearKrylov { }; /** @brief The internal tree type used for the computation. */ - typedef BinarySpaceTree< DHrectBound<2>, Matrix, LocalLinearKrylov > Tree; + typedef BinarySpaceTree< DHrectBound<2>, Matrix, LocalLinearKrylovStat > + Tree; ////////// Private Member Variables ////////// @@ -147,7 +148,7 @@ class LocalLinearKrylov { /** @brief The original training target value for the reference * dataset. */ - Vector rset_targets_; + Matrix rset_targets_; /** @brief The original training target value for the reference * dataset weighted by the reference coordinate. (i.e. y_i @@ -159,6 +160,10 @@ class LocalLinearKrylov { */ int dimension_; + /** @brief The length of each column vector in local linear regression. + */ + int row_length_; + /** @brief The lower bounds on the right hand side of the linear system we * are solving for each query point. (i.e. B^T W(q) Y) */ @@ -187,8 +192,47 @@ class LocalLinearKrylov { */ TKernel kernel_; - ////////// Private Member Functions ////////// + /** @brief The number of finite difference prunes made. + */ + int num_finite_difference_prunes_; + + /** @brief Temporary variable for holding lower bound change made + * during a prune. + */ + Vector right_hand_sides_l_change_; + + /** @brief Temporary variable for holding the pruned quantity. + */ + Vector right_hand_sides_e_change_; + /** @brief Temporary variable for holding upper bound change made + * during a prune. + */ + Vector right_hand_sides_u_change_; + + ////////// Private Member Functions ////////// + + /** @brief Determine which of the node to expand first. + */ + void BestNodePartners_(Tree *nd, Tree *nd1, Tree *nd2, Tree **partner1, + Tree **partner2) { + + double d1 = nd->bound().MinDistanceSq(nd1->bound()); + double d2 = nd->bound().MinDistanceSq(nd2->bound()); + + if(d1 <= d2) { + *partner1 = nd1; + *partner2 = nd2; + } + else { + *partner1 = nd2; + *partner2 = nd1; + } + } + + bool PrunableRightHandSides_(Tree *qnode, Tree *rnode, DRange &dsqd_range, + DRange &kernel_value_range); + /** @brief The base-case exhaustive computation for dual-tree based * computation of B^T W(q) Y. * @@ -278,7 +322,8 @@ class LocalLinearKrylov { right_hand_sides_u_.SetZero(); solution_vectors_.SetZero(); regression_estimates_.SetZero(); - + num_finite_difference_prunes_ = 0; + // The computation proceeds in three phases: // // Phase 1: Compute B^T W(q) Y vector for each query point. @@ -313,7 +358,11 @@ class LocalLinearKrylov { // copy reference dataset and reference weights. rset_.Copy(references); rset_targets_.Copy(reference_targets); + + // Record dimensionality and the appropriately cache the number of + // components required for local linear (which is D + 1). dimension_ = rset_.n_rows(); + row_length_ = dimension_ + 1; // copy query dataset. if(queries_equal_references) { @@ -342,13 +391,16 @@ class LocalLinearKrylov { kernel_.Init(fx_param_double_req(module_, "bandwidth")); // allocate memory for storing computation results. - rset_targets_weighted_by_coordinates_.Init(dimension_ + 1, rset_.n_cols()); - right_hand_sides_l_.Init(dimension_ + 1, qset_.n_cols()); - right_hand_sides_e_.Init(dimension_ + 1, qset_.n_cols()); - right_hand_sides_u_.Init(dimension_ + 1, qset_.n_cols()); - solution_vectors_.Init(dimension_ + 1, qset_.n_cols()); + rset_targets_weighted_by_coordinates_.Init(row_length_, rset_.n_cols()); + right_hand_sides_l_.Init(row_length_, qset_.n_cols()); + right_hand_sides_e_.Init(row_length_, qset_.n_cols()); + right_hand_sides_u_.Init(row_length_, qset_.n_cols()); + solution_vectors_.Init(row_length_, qset_.n_cols()); regression_estimates_.Init(qset_.n_cols()); - + right_hand_sides_l_change_.Init(row_length_); + right_hand_sides_e_change_.Init(row_length_); + right_hand_sides_u_change_.Init(row_length_); + // initialize the reference side statistics. } diff --git a/fastlib2/contrib/dongryel/regression/local_linear_krylov_main.cc b/fastlib2/contrib/dongryel/regression/local_linear_krylov_main.cc index 28779eaefb..5ddaa261b0 100644 --- a/fastlib2/contrib/dongryel/regression/local_linear_krylov_main.cc +++ b/fastlib2/contrib/dongryel/regression/local_linear_krylov_main.cc @@ -6,9 +6,52 @@ int main(int argc, char *argv[]) { // Initialize FastExec... fx_init(argc, argv); + ////////// READING PARAMETERS AND LOADING DATA ///////////////////// + + // FASTexec organizes parameters and results into submodules. Think + // of this as creating a new folder named "kde_module" under the + // root directory (NULL) for the Kde object to work inside. Here, + // we initialize it with all parameters defined + // "--local_linear/...=...". + struct datanode* local_linear_module = + fx_submodule(NULL, "local_linear", "local_linear_module"); + + // The reference data file is a required parameter. + const char* references_file_name = fx_param_str_req(NULL, "data"); + + // The file containing the reference target values is a required + // parameter. + const char* reference_targets_file_name = fx_param_str_req(NULL, "dtarget"); + + // The query data file defaults to the references. + const char* queries_file_name = + fx_param_str(NULL, "query", references_file_name); + + // query and reference datasets and target training values. + Matrix references; + Matrix reference_targets; + Matrix queries; + + // flag for telling whether references are equal to queries + bool queries_equal_references = + !strcmp(queries_file_name, references_file_name); + + // data::Load inits a matrix with the contents of a .csv or .arff. + data::Load(references_file_name, &references); + if(queries_equal_references) { + queries.Alias(references); + } + else { + data::Load(queries_file_name, &queries); + } + data::Load(reference_targets_file_name, &reference_targets); + // Declare local linear krylov object. LocalLinearKrylov local_linear; - + local_linear.Init(queries, references, reference_targets, + queries_equal_references, local_linear_module); + local_linear.Compute(); + // Finalize FastExec and print output results. fx_done(); return 0; diff --git a/fastlib2/contrib/dongryel/regression/local_linear_krylov_setup_impl.h b/fastlib2/contrib/dongryel/regression/local_linear_krylov_setup_impl.h index 0ea7acf3ff..9d4f8eba25 100644 --- a/fastlib2/contrib/dongryel/regression/local_linear_krylov_setup_impl.h +++ b/fastlib2/contrib/dongryel/regression/local_linear_krylov_setup_impl.h @@ -4,10 +4,22 @@ #error "This file is not a public header file!" #endif +template +bool LocalLinearKrylov::PrunableRightHandSides_ +(Tree *qnode, Tree *rnode, DRange &dsqd_range, DRange &kernel_value_range) { + + return true; +} + template void LocalLinearKrylov::DualtreeRightHandSidesBase_ (Tree *qnode, Tree *rnode) { + // Clear the summary statistics of the current query node so that we + // can refine it to better bounds. + (qnode->stat().right_hand_sides_l_).SetAll(DBL_MAX); + (qnode->stat().right_hand_sides_u_).SetAll(-DBL_MAX); + // for each query point for(index_t q = qnode->begin(); q < qnode->end(); q++) { @@ -15,9 +27,17 @@ void LocalLinearKrylov::DualtreeRightHandSidesBase_ const double *q_col = qset_.GetColumnPtr(q); // get the column vectors accumulating the sums to update. - const double *q_right_hand_sides_l_ = right_hand_sides_l_.GetColumnPtr(q); - const double *q_right_hand_sides_e_ = right_hand_sides_e_.GetColumnPtr(q); - const double *q_right_hand_sides_u_ = right_hand_sides_u_.GetColumnPtr(q); + double *q_right_hand_sides_l = right_hand_sides_l_.GetColumnPtr(q); + double *q_right_hand_sides_e = right_hand_sides_e_.GetColumnPtr(q); + double *q_right_hand_sides_u = right_hand_sides_u_.GetColumnPtr(q); + + // Incorporate the postponed information. + la::AddTo(row_length_, + (qnode->stat().postponed_right_hand_sides_l_).ptr(), + q_right_hand_sides_l); + la::AddTo(row_length_, + (qnode->stat().postponed_right_hand_sides_u_).ptr(), + q_right_hand_sides_u); // for each reference point for(index_t r = rnode->begin(); r < rnode->end(); r++) { @@ -37,9 +57,9 @@ void LocalLinearKrylov::DualtreeRightHandSidesBase_ // bound quantities. for(index_t d = 0; d <= dimension_; d++) { - q_right_hand_sides_l_[d] += kernel_value * r_weights[d]; - q_right_hand_sides_e_[d] += kernel_value * r_weights[d]; - q_right_hand_sides_u_[d] += kernel_value * r_weights[d]; + q_right_hand_sides_l[d] += kernel_value * r_weights[d]; + q_right_hand_sides_e[d] += kernel_value * r_weights[d]; + q_right_hand_sides_u[d] += kernel_value * r_weights[d]; } // end of iterating over each vector component. @@ -52,27 +72,120 @@ void LocalLinearKrylov::DualtreeRightHandSidesBase_ for(index_t d = 0; d <= dimension_; d++) { // Correct the upper bound for the current query first. - q_right_hand_sides_u_[d] -= (rnode->sum_targets_weighted_by_data_)[d]; + q_right_hand_sides_u[d] -= + (rnode->stat().sum_targets_weighted_by_data_)[d]; // Refine bounds. - qnode->stat().right_hand_sides_l_[d] = - std::min(qnode->stat().right_hand_sides_l_[d], - q_right_hand_sides_l_[d]); - qnode->stat().right_hand_sides_u_[d] = - std::max(qnode->stat().right_hand_sides_u_[d], - q_right_hand_sides_u_[d]); + (qnode->stat().right_hand_sides_l_)[d] = + std::min((qnode->stat().right_hand_sides_l_)[d], + q_right_hand_sides_l[d]); + (qnode->stat().right_hand_sides_u_)[d] = + std::max((qnode->stat().right_hand_sides_u_)[d], + q_right_hand_sides_u[d]); } // end of looping over each vector component. } // end of iterating over each query point. // Clear postponed information. - qnode->stat().postponed_right_hand_sides_l_.SetZero(); - qnode->stat().postponed_right_hand_sides_u_.SetZero(); + (qnode->stat().postponed_right_hand_sides_l_).SetZero(); + (qnode->stat().postponed_right_hand_sides_u_).SetZero(); } template void LocalLinearKrylov::DualtreeRightHandSidesCanonical_ (Tree *qnode, Tree *rnode) { + + // temporary variable for holding distance/kernel value bounds + DRange dsqd_range; + DRange kernel_value_range; + // try finite difference pruning first + if(PrunableRightHandSides_(qnode, rnode, dsqd_range, kernel_value_range)) { + la::AddTo(right_hand_sides_l_change_, + &(qnode->stat().postponed_right_hand_sides_l_)); + la::AddTo(right_hand_sides_e_change_, + &(qnode->stat().postponed_right_hand_sides_e_)); + la::AddTo(right_hand_sides_u_change_, + &(qnode->stat().postponed_right_hand_sides_u_)); + num_finite_difference_prunes_++; + return; + } + + // for leaf query node + if(qnode->is_leaf()) { + + // for leaf pairs, go exhaustive + if(rnode->is_leaf()) { + DualtreeRightHandSidesBase_(qnode, rnode); + return; + } + + // for non-leaf reference, expand reference node + else { + Tree *rnode_first = NULL, *rnode_second = NULL; + BestNodePartners_(qnode, rnode->left(), rnode->right(), &rnode_first, + &rnode_second); + DualtreeRightHandSidesCanonical_(qnode, rnode_first); + DualtreeRightHandSidesCanonical_(qnode, rnode_second); + return; + } + } + + // for non-leaf query node + else { + + // Push down postponed bound changes owned by the current query + // node to the children of the query node and clear them. + la::AddTo(qnode->stat().postponed_right_hand_sides_l_, + &((qnode->left()->stat()).postponed_right_hand_sides_l_)); + la::AddTo(qnode->stat().postponed_right_hand_sides_l_, + &((qnode->right()->stat()).postponed_right_hand_sides_l_)); + la::AddTo(qnode->stat().postponed_right_hand_sides_u_, + &((qnode->left()->stat()).postponed_right_hand_sides_u_)); + la::AddTo(qnode->stat().postponed_right_hand_sides_u_, + &((qnode->right()->stat()).postponed_right_hand_sides_u_)); + (qnode->stat().postponed_right_hand_sides_l_).SetZero(); + (qnode->stat().postponed_right_hand_sides_u_).SetZero(); + + // For a leaf reference node, expand query node + if(rnode->is_leaf()) { + Tree *qnode_first = NULL, *qnode_second = NULL; + + BestNodePartners_(rnode, qnode->left(), qnode->right(), &qnode_first, + &qnode_second); + DualtreeRightHandSidesCanonical_(qnode_first, rnode); + DualtreeRightHandSidesCanonical_(qnode_second, rnode); + } + + // for non-leaf reference node, expand both query and reference nodes + else { + Tree *rnode_first = NULL, *rnode_second = NULL; + + BestNodePartners_(qnode->left(), rnode->left(), rnode->right(), + &rnode_first, &rnode_second); + DualtreeRightHandSidesCanonical_(qnode->left(), rnode_first); + DualtreeRightHandSidesCanonical_(qnode->left(), rnode_second); + + BestNodePartners_(qnode->right(), rnode->left(), rnode->right(), + &rnode_first, &rnode_second); + DualtreeRightHandSidesCanonical_(qnode->right(), rnode_first); + DualtreeRightHandSidesCanonical_(qnode->right(), rnode_second); + } + + // reaccumulate the summary statistics. + for(index_t d = 0; d <= dimension_; d++) { + (qnode->stat().right_hand_sides_l_)[d] = + std::min(((qnode->left()->stat()).right_hand_sides_l_)[d] + + ((qnode->left()->stat()).postponed_right_hand_sides_l_)[d], + ((qnode->right()->stat()).right_hand_sides_l_)[d] + + ((qnode->right()->stat()).postponed_right_hand_sides_l_)[d]); + (qnode->stat().right_hand_sides_u_)[d] = + std::max(((qnode->left()->stat()).right_hand_sides_u_)[d] + + ((qnode->left()->stat()).postponed_right_hand_sides_u_)[d], + ((qnode->right()->stat()).right_hand_sides_u_)[d] + + ((qnode->right()->stat()).postponed_right_hand_sides_u_)[d]); + } + return; + } // end of the case: non-leaf query node. }