/* * ===================================================================================== * * Filename: nmf_tree_impl.h * * Description: * * Version: 1.0 * Created: 08/18/2008 01:12:28 PM EDT * Revision: none * Compiler: gcc * * Author: Nikolaos Vasiloglou (NV), nvasil@ieee.org * Company: Georgia Tech Fastlab-ESP Lab * * ===================================================================================== */ #ifdef NMF_TREE_IMPL_H_ #define NMF_TREE_IMP_H_ // we use this macro to avoid including this file directly #ifdef NMF_TREE_H_ template void NmfTreeConstructor::Init(fx_module *module, ArrayList &rows, ArrayList &columns, ArrayList &values) { module_=fx_submodule(module, "tree");; fx_module *l_bfgs_module=fx_submodule(module_, "optimizer"); fx_module *relaxed_nmf_module=fx_submodule(module_, "l_bfgs"); rows_.Copy(rows); columns_.Copy(columns); values_.Copy(values); index_t num_of_rows=*std::max_element(rows_.begin(), rows_.end())+1; index_t num_of_columns=*std::max_element(columns_.begin(), columns_.end())+1; new_dimension_ = fx_param_int(module, "new_dimension", 5); data_matrix_.Init(new_dimension_, num_of_rows+num_of_columns); w_matrix_.Alias(data_matrix_.ptr(), new_dimension_, num_of_rows_); h_matrix_.Alias(data_matrix_.ptr(), new_dimension_, num_of_columns_); lower_bound_.Init(new_dimension_, num_of_rows+num_of_columns); upper_bound_.Init(new_dimension_, num_of_rows+num_of_columns); lower_bound_.SetAll(fx_param_double(module_, "lower_bound", 1e-5)); upper_bound_.SetAll(fx_param_double(module_, "upper_bound", 1.0)); opt_fun_.Init(relaxed_nmf_module, &rows_, &columns_, &values_, &lower_bound, & upper_bound); l_bfgs_engine_.Init(&opt_fun, l_bfgs_module_); leaf_size_=fx_param_int(module, "leaf_size", 20); old_from_new_h_.Init(num_of_columns_); for (index_t i = 0; i < num_of_rows_; i++) { old_from_new_h_[i] = i; } old_from_new_w_.Init(num_of_rows_); for (index_t i = 0; i < num_of_columns_; i++) { old_from_new_w_[i] = i; } } template void NmfTreeConstructor::MakeNmfTree() { parent_= new TKdTree(); parent_->Init(0, data_matrix.n_cols()); MakeNmfTreeMidpointSelective(parent_w_, parent_h_); } template void NmfTreeConstructor::MakeNmfTreeMidpointSelective( TKdTree *node1, TKdTree *node2) { GenVector split_dimensions; split_dimensions.Init(data_matrix_.n_rows()); int i; for (i = 0; i < data_matrix.n_rows(); i++){ split_dimensions[i] = i; } SelectSplitKdTreeMidpoint(node1, node2, split_dimensions); } template void NmfTreeConstructor::SelectSplitKdTreeMidpoint(TKdTree *node1, TKdTree *node2, const GenVector& split_dimensions) { TKdTree *left = NULL; TKdTree *right = NULL; optimizer.Reset(); GenMatrix init_matrix; opt_fun.GiveInitMatrix(&init_matrix); optimizer_.set(init_matrix); optimizer_ComputeLocalOptimumBFGS(); tree_kdtree_private::SelectFindBoundFromMatrix(data_matrix_, split_dimensions, node->begin(), node->count(), &node->bound()); if (node1->count() > leaf_size_ && node2->count() > leaf_size_) { SplitAndBound(node1, w_matrix_, split_dimensions); SplitAndBound(node2, h_matrix_, split_dimensions); SelectSplitKdTreeMidpoint(node1->left(), node2->left(), split_dimensions); SelectSplitKdTreeMidpoint(node1->right(), node2->right(), split_dimensions); } else { if (node1->count() > leaf_size_ && node2->count() < leaf_size_) { SplitAndBound(node1, w_matrix_, split_dimensions); SelectSplitKdTreeMidpoint(node1->left(), node2->left(), split_dimensions); SelectSplitKdTreeMidpoint(node1->right(), node2->right(), split_dimensions); } else { if (node1->count() < leaf_size_ && node2->count() > leaf_size_) { SplitAndBound(node2, h_matrix_, split_dimensions); SelectSplitKdTreeMidpoint(node1->left(), node2->left(), split_dimensions); SelectSplitKdTreeMidpoint(node1->right(), node2->right(), split_dimensions); } } } } template void NmfTreeConstructor::SplitAndBound(TKdTree *node, GenMatrix *data_matrix, GenVector &split_dimensions) { index_t split_dim = BIG_BAD_NUMBER; double max_width = -1; for (index_t d = 0; d < split_dimensions.length(); d++) { double w = node->bound().get(d).width(); if (w > max_width) { max_width = w; split_dim = d; } } double split_val = node->bound().get(split_dim).mid(); if (max_width == 0) { // Okay, we can't do any splitting, because all these points are the // same. We have to give up. } else { left = new TKdTree(); node->left->bound().Init(split_dimensions.length()); node->right = new TKdTree(); node->right->bound().Init(split_dimensions.length()); index_t split_col = tree_kdtree_private::SelectMatrixPartition(data_matrix, split_dimensions, (int)split_dimensions[split_dim], split_val, node->begin(), node->count(), &node->left->bound(), &node->right->bound(), old_from_new_); VERBOSE_MSG(3.0,"split (%d,[%d],%d) dim %d on %f (between %f, %f)", node->begin(), split_col, node->begin() + node->count(), (int)split_dimensions[split_dim], split_val, node->bound().get(split_dim).lo, node->bound().get(split_dim).hi); node->left->Init(node->begin(), split_col - node->begin()); node->right->Init(split_col, node->begin() + node->count() - split_col); // This should never happen if max_width > 0 DEBUG_ASSERT(node->left->count() != 0 && node->right->count() != 0); } template index_t NmfTreeConstructor::SelectMatrixPartition(GenMatrix& matrix, const Vector& split_dimensions, index_t dim, double splitvalue, index_t first, index_t count, TBound* left_bound, TBound* right_bound) { index_t left = first; index_t right = first + count - 1; /* At any point: * * everything < left is correct * everything > right is correct */ for (;;) { while (matrix.get(dim, left) < splitvalue && likely(left <= right)) { GenVector left_vector; matrix.MakeColumnVector(left, &left_vector); if (split_dimensions.length() == matrix.n_rows()) { *left_bound |= left_vector; } else { GenVector sub_left_vector; sub_left_vector.Init(split_dimensions.length()); MakeBoundVector(left_vector, split_dimensions, &sub_left_vector); *left_bound |= sub_left_vector; } left++; } while (matrix.get(dim, right) >= splitvalue && likely(left <= right)) { GenVector right_vector; matrix.MakeColumnVector(right, &right_vector); if (split_dimensions.length() == matrix.n_rows()) { *right_bound |= right_vector; } else { GenVector sub_right_vector; sub_right_vector.Init(split_dimensions.length()); MakeBoundVector(right_vector, split_dimensions, &sub_right_vector); *right_bound |= sub_right_vector; } right--; } if (unlikely(left > right)) { /* left == right + 1 */ break; } GenVector left_vector; GenVector right_vector; matrix.MakeColumnVector(left, &left_vector); matrix.MakeColumnVector(right, &right_vector); left_vector.SwapValues(&right_vector); if (split_dimensions.length() == matrix.n_rows()) { *left_bound |= left_vector; } else { GenVector sub_left_vector; sub_left_vector.Init(split_dimensions.length()); MakeBoundVector(left_vector, split_dimensions, &sub_left_vector); *left_bound |= sub_left_vector; } if (split_dimensions.length() == matrix.n_rows()){ *right_bound |= right_vector; } else { GenVector sub_right_vector; sub_right_vector.Init(split_dimensions.length()); MakeBoundVector(right_vector, split_dimensions, &sub_right_vector); *right_bound |= sub_right_vector; } index_t t = old_from_new[left]; old_from_new[left] = old_from_new[right]; old_from_new[right] = t; DEBUG_ASSERT(left <= right); right--; // this conditional is always true, I belueve //if (likely(left <= right)) { // right--; //} } DEBUG_ASSERT(left == right + 1); return left; } #endif // NMF_TREE_H_ #endif // NMF_TREE_IMPL_H_