diff --git a/fastlib2/contrib/dongryel/regression/local_linear_krylov.h b/fastlib2/contrib/dongryel/regression/local_linear_krylov.h index f35defe7db..a9cf30f9b7 100644 --- a/fastlib2/contrib/dongryel/regression/local_linear_krylov.h +++ b/fastlib2/contrib/dongryel/regression/local_linear_krylov.h @@ -1,7 +1,11 @@ /** @file local_linear_krylov.h + * + * This implementation can handle only non-negative training target + * values and points that lie the positive quadrant. * * @author Dongryeol Lee (dongryel@cc.gatech.edu) * @see local_linear_krylov_main.cc + * * @bug No known bugs. */ @@ -62,7 +66,12 @@ class LocalLinearKrylov { /** @brief The data weighted by the target values. */ Vector sum_targets_weighted_by_data_; - + + /** @brief The 1-norm of the vector containing the target values + * weighted by the data. + */ + double l1_norm_sum_targets_weighted_by_data_; + /** @brief The bounding box for the solution vectors. */ DHrectBound<2> bound_for_solutions_; @@ -91,6 +100,8 @@ class LocalLinearKrylov { postponed_right_hand_sides_u_.Init(dimension + 1); sum_targets_weighted_by_data_.Init(dimension + 1); bound_for_solutions_.Init(dimension + 1); + + l1_norm_sum_targets_weighted_by_data_ = 0; } /** @brief Computing the statistics for a leaf node involves @@ -120,6 +131,9 @@ class LocalLinearKrylov { ////////// Private Member Variables ////////// + /** @brief The required relative error. */ + double relative_error_; + /** @brief The module holding the list of parameters. */ struct datanode *module_; @@ -196,6 +210,10 @@ class LocalLinearKrylov { */ int num_finite_difference_prunes_; + /** @brief Temporary variable for holding newly refined lower bound. + */ + Vector new_right_hand_sides_l_; + /** @brief Temporary variable for holding lower bound change made * during a prune. */ @@ -212,6 +230,18 @@ class LocalLinearKrylov { ////////// Private Member Functions ////////// + /** @brief Compute the L1 norm of the given vector. + */ + double L1Norm_(Vector &v) { + + double norm = 0; + + for(index_t i = 0; i < v.length(); i++) { + norm += fabs(v[i]); + } + return norm; + } + /** @brief Determine which of the node to expand first. */ void BestNodePartners_(Tree *nd, Tree *nd1, Tree *nd2, Tree **partner1, @@ -231,7 +261,7 @@ class LocalLinearKrylov { } bool PrunableRightHandSides_(Tree *qnode, Tree *rnode, DRange &dsqd_range, - DRange &kernel_value_range); + DRange &kernel_value_range, double &used_error); /** @brief The base-case exhaustive computation for dual-tree based * computation of B^T W(q) Y. @@ -324,6 +354,9 @@ class LocalLinearKrylov { regression_estimates_.SetZero(); num_finite_difference_prunes_ = 0; + // Set relative error. + relative_error_ = fx_param_double(module_, "relative_error", 0.01); + // The computation proceeds in three phases: // // Phase 1: Compute B^T W(q) Y vector for each query point. @@ -397,6 +430,7 @@ class LocalLinearKrylov { right_hand_sides_u_.Init(row_length_, qset_.n_cols()); solution_vectors_.Init(row_length_, qset_.n_cols()); regression_estimates_.Init(qset_.n_cols()); + new_right_hand_sides_l_.Init(row_length_); right_hand_sides_l_change_.Init(row_length_); right_hand_sides_e_change_.Init(row_length_); right_hand_sides_u_change_.Init(row_length_); diff --git a/fastlib2/contrib/dongryel/regression/local_linear_krylov_main.cc b/fastlib2/contrib/dongryel/regression/local_linear_krylov_main.cc index 5ddaa261b0..9b78221b74 100644 --- a/fastlib2/contrib/dongryel/regression/local_linear_krylov_main.cc +++ b/fastlib2/contrib/dongryel/regression/local_linear_krylov_main.cc @@ -49,7 +49,7 @@ int main(int argc, char *argv[]) { // Declare local linear krylov object. LocalLinearKrylov local_linear; local_linear.Init(queries, references, reference_targets, - queries_equal_references, local_linear_module); + queries_equal_references, local_linear_module); local_linear.Compute(); // Finalize FastExec and print output results. 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 9d4f8eba25..f4a5ce14cf 100644 --- a/fastlib2/contrib/dongryel/regression/local_linear_krylov_setup_impl.h +++ b/fastlib2/contrib/dongryel/regression/local_linear_krylov_setup_impl.h @@ -6,9 +6,51 @@ template bool LocalLinearKrylov::PrunableRightHandSides_ -(Tree *qnode, Tree *rnode, DRange &dsqd_range, DRange &kernel_value_range) { +(Tree *qnode, Tree *rnode, DRange &dsqd_range, DRange &kernel_value_range, + double &used_error) { + + // try pruning after bound refinement: first compute distance/kernel + // value bounds + dsqd_range.lo = qnode->bound().MinDistanceSq(rnode->bound()); + dsqd_range.hi = qnode->bound().MaxDistanceSq(rnode->bound()); + kernel_value_range = kernel_.RangeUnnormOnSq(dsqd_range); + + // Compute the vector component lower and upper bound changes. This + // assumes that the maximum kernel value is 1. + la::ScaleOverwrite(kernel_value_range.lo, + rnode->stat().sum_targets_weighted_by_data_, + &right_hand_sides_l_change_); + la::ScaleOverwrite(0.5 * (kernel_value_range.lo + + kernel_value_range.hi), + rnode->stat().sum_targets_weighted_by_data_, + &right_hand_sides_e_change_); + la::ScaleOverwrite((kernel_value_range.hi - 1.0), + rnode->stat().sum_targets_weighted_by_data_, + &right_hand_sides_u_change_); + + // Refine the lower bound based on the current postponed lower bound + // change and the newly gained refinement due to comparing the + // current query and reference node pair. + la::AddOverwrite(qnode->stat().right_hand_sides_l_, + qnode->stat().postponed_right_hand_sides_l_, + &new_right_hand_sides_l_); + la::AddTo(right_hand_sides_l_change_, &new_right_hand_sides_l_); + + // Compute the L1 norm of the most refined lower bound. + double l1_norm_new_right_hand_sides_l_ = L1Norm_(new_right_hand_sides_l_); + + // Compute the allowed amount of error for pruning the given query + // and reference pair. + double allowed_err = + (relative_error_ * (rnode->stat().l1_norm_sum_targets_weighted_by_data_) * + l1_norm_new_right_hand_sides_l_) / + (rroot_->stat().l1_norm_sum_targets_weighted_by_data_); + + used_error = 0.5 * kernel_value_range.width() * + (rnode->stat().l1_norm_sum_targets_weighted_by_data_); - return true; + // check pruning condition + return (used_error <= allowed_err); } template @@ -95,13 +137,17 @@ void LocalLinearKrylov::DualtreeRightHandSidesBase_ template void LocalLinearKrylov::DualtreeRightHandSidesCanonical_ (Tree *qnode, Tree *rnode) { - + + // Total amount of used error + double used_error; + // 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)) { + if(PrunableRightHandSides_(qnode, rnode, dsqd_range, kernel_value_range, + used_error)) { la::AddTo(right_hand_sides_l_change_, &(qnode->stat().postponed_right_hand_sides_l_)); la::AddTo(right_hand_sides_e_change_,