Skeleton 4-way recursion code added in
This commit is contained in:
@@ -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.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user