Skeleton 4-way recursion code added in

This commit is contained in:
Dongryeol Lee
2008-02-03 21:02:27 +00:00
parent f144ca5c55
commit 2abc12f6c0
3 changed files with 234 additions and 26 deletions
@@ -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.
}
@@ -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<GaussianKernel> 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;
@@ -4,10 +4,22 @@
#error "This file is not a public header file!"
#endif
template<typename TKernel>
bool LocalLinearKrylov<TKernel>::PrunableRightHandSides_
(Tree *qnode, Tree *rnode, DRange &dsqd_range, DRange &kernel_value_range) {
return true;
}
template<typename TKernel>
void LocalLinearKrylov<TKernel>::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<TKernel>::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<TKernel>::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<TKernel>::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<typename TKernel>
void LocalLinearKrylov<TKernel>::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.
}