planc
Parallel Lowrank Approximation with Non-negativity Constraints
auntf.hpp
Go to the documentation of this file.
1 /* Copyright Ramakrishnan Kannan 2017 */
2 
3 #ifndef NTF_AUNTF_HPP_
4 #define NTF_AUNTF_HPP_
5 
6 #define MPITIC tic();
7 #define MPITOC toc();
8 
9 #include <cblas.h>
10 #include <armadillo>
11 #include <vector>
12 #include "common/ncpfactors.hpp"
13 #include "common/ntf_utils.hpp"
14 #include "common/tensor.hpp"
15 #include "dimtree/ddt.hpp"
16 
17 namespace planc {
18 
19 #define TENSOR_DIM (m_input_tensor.dimensions())
20 #define TENSOR_NUMEL (m_input_tensor.numel())
21 
22 // #ifndef NTF_VERBOSE
23 // #define NTF_VERBOSE 1
24 // #endif
25 
26 // extern "C" void cblas_dgemm_(const CBLAS_LAYOUT Layout,
27 // const CBLAS_TRANSPOSE transa,
28 // const CBLAS_TRANSPOSE transb,
29 // const int m, const int n,
30 // const int k, const double alpha,
31 // const double *a, const int lda,
32 // const double *b, const int ldb,
33 // const double beta, double *c,
34 // const int ldc);
35 class AUNTF {
36  protected:
37  planc::NCPFactors m_ncp_factors;
38  MAT *ncp_mttkrp_t;
39  MAT gram_without_one;
40  virtual MAT update(const int mode) = 0;
41 
42  private:
43  const planc::Tensor &m_input_tensor;
44  int m_num_it;
45  int m_current_it;
46  bool m_compute_error;
47 
48  const int m_low_rank_k;
49  MAT *ncp_krp;
50  const algotype m_updalgo;
51  planc::Tensor *lowranktensor;
52  DenseDimensionTree *kdt;
53  bool m_enable_dim_tree;
54  // needed for acceleration algorithms.
55  bool m_accelerated;
56  double m_rel_error;
57  double m_normA;
58  std::vector<bool> m_stale_mttkrp;
59 
60  // Ensure factor is unnormalised when calling this function
61  void update_factor_mode(const int &current_mode, const MAT &factor) {
62  m_ncp_factors.set(current_mode, factor);
63  m_ncp_factors.normalize(current_mode);
64 
65  if (m_enable_dim_tree) {
66  MAT temp = m_ncp_factors.factor(current_mode).t();
67  kdt->set_factor(temp.memptr(), current_mode);
68  }
69 
70  int num_modes = this->m_input_tensor.modes();
71  for (int mode = 0; mode < num_modes; mode++) {
72  if (mode != current_mode) this->m_stale_mttkrp[current_mode] = true;
73  }
74  }
75  virtual void accelerate() {}
76 
77  public:
78  AUNTF(const planc::Tensor &i_tensor, const int i_k, algotype i_algo)
79  : m_ncp_factors(i_tensor.dimensions(), i_k, false),
80  m_input_tensor(i_tensor),
81  m_low_rank_k(i_k),
82  m_updalgo(i_algo) {
83  m_ncp_factors.normalize();
84  gram_without_one.zeros(i_k, i_k);
85  ncp_mttkrp_t = new MAT[i_tensor.modes()];
86  ncp_krp = new MAT[i_tensor.modes()];
87  for (int i = 0; i < i_tensor.modes(); i++) {
88  UWORD current_size = TENSOR_NUMEL / TENSOR_DIM[i];
89  ncp_krp[i].zeros(current_size, i_k);
90  ncp_mttkrp_t[i].zeros(i_k, TENSOR_DIM[i]);
91  this->m_stale_mttkrp.push_back(true);
92  }
93  lowranktensor = new planc::Tensor(i_tensor.dimensions());
94  m_compute_error = false;
95  m_num_it = 20;
96  m_normA = i_tensor.norm();
97  // INFO << "Init factors for NCP" << std::endl << "======================";
98  // m_ncp_factors.print();
99  this->m_enable_dim_tree = false;
100  }
101  ~AUNTF() {
102  for (int i = 0; i < m_input_tensor.modes(); i++) {
103  ncp_krp[i].clear();
104  ncp_mttkrp_t[i].clear();
105  }
106  delete[] ncp_krp;
107  delete[] ncp_mttkrp_t;
108  if (this->m_enable_dim_tree) {
109  delete kdt;
110  }
111  delete lowranktensor;
112  }
113  NCPFactors &ncp_factors() { return m_ncp_factors; }
114  void dim_tree(bool i_dim_tree) {
115  this->m_enable_dim_tree = i_dim_tree;
116  if (i_dim_tree) {
117  this->kdt = new DenseDimensionTree(m_input_tensor, m_ncp_factors,
118  m_input_tensor.modes() / 2);
119  }
120  }
121  double current_error() const { return this->m_rel_error; }
122  void num_it(const int i_n) { this->m_num_it = i_n; }
123  void computeNTF() {
124  for (m_current_it = 0; m_current_it < m_num_it; m_current_it++) {
125  INFO << "iter::" << this->m_current_it << std::endl;
126  for (int j = 0; j < this->m_input_tensor.modes(); j++) {
127  m_ncp_factors.gram_leave_out_one(j, &gram_without_one);
128 #ifdef NTF_VERBOSE
129  INFO << "gram_without_" << j << "::" << arma::cond(gram_without_one)
130  << std::endl
131  << gram_without_one << std::endl;
132 #endif
133  if (this->m_stale_mttkrp[j]) {
134  m_ncp_factors.krp_leave_out_one(j, &ncp_krp[j]);
135 #ifdef NTF_VERBOSE
136  INFO << "krp_leave_out_" << j << std::endl << ncp_krp[j] << std::endl;
137 #endif
138  if (this->m_enable_dim_tree) {
139  double multittv_time = 0;
140  double mttkrp_time = 0;
141  kdt->in_order_reuse_MTTKRP(j, ncp_mttkrp_t[j].memptr(), false,
142  multittv_time, mttkrp_time);
143  } else {
144  m_input_tensor.mttkrp(j, ncp_krp[j], &ncp_mttkrp_t[j]);
145  }
146  this->m_stale_mttkrp[j] = false;
147 #ifdef NTF_VERBOSE
148  INFO << "mttkrp for factor" << j << std::endl
149  << ncp_mttkrp_t[j] << std::endl;
150 #endif
151  }
152  // MAT factor = update(m_updalgo, gram_without_one, ncp_mttkrp_t[j], j);
153  MAT factor = update(j);
154 #ifdef NTF_VERBOSE
155  INFO << "iter::" << i << "::factor:: " << j << std::endl
156  << factor << std::endl;
157 #endif
158  update_factor_mode(j, factor.t());
159  }
160  if (m_compute_error) {
161  double temp_err = computeObjectiveError();
162  this->m_rel_error = temp_err;
163  INFO << "relative_error at it::" << this->m_current_it
164  << "::" << temp_err << std::endl;
165  }
166  if (this->m_accelerated) accelerate();
167 #ifdef NTF_VERBOSE
168  INFO << "ncp factors" << std::endl;
169  m_ncp_factors.print();
170 #endif
171  }
172  }
173  void accelerated(const bool &set_acceleration) {
174  this->m_accelerated = set_acceleration;
175  this->m_compute_error = true;
176  }
177  bool is_stale_mttkrp(const int &current_mode) const {
178  return this->m_stale_mttkrp[current_mode];
179  }
180  void compute_error(bool i_error) { this->m_compute_error = i_error; }
181  void reset(const NCPFactors &new_factors, bool trans = false) {
182  int m_modes = this->m_input_tensor.modes();
183  if (!trans) {
184  for (int i = 0; i < m_modes; i++) {
185  update_factor_mode(i, new_factors.factor(i));
186  }
187  } else {
188  for (int i = 0; i < m_modes; i++) {
189  update_factor_mode(i, new_factors.factor(i).t());
190  }
191  }
192  m_ncp_factors.set_lambda(new_factors.lambda());
193  }
194  int current_it() const { return m_current_it; }
196  // current low rank tensor
197  // UWORD krpsize = arma::prod(this->m_dimensions);
198  // krpsize /= this->m_dimensions[0];
199  // MAT krpleavingzero.zeros(krpsize, this->m_k);
200  // krp_leave_out_one(0, &krpleavingzero);
201  // MAT lowranktensor(this->m_dimensions[0], krpsize);
202  // lowranktensor = this->ncp_factors[0] * trans(krpleavingzero);
203 
204  // compute current low rank tensor as above.
205  m_ncp_factors.krp_leave_out_one(0, &ncp_krp[0]);
206  // cblas_dgemm_(const CBLAS_LAYOUT Layout,
207  // const CBLAS_TRANSPOSE transa,
208  // const CBLAS_TRANSPOSE transb,
209  // const MKL_INT m, const MKL_INT n,
210  // const MKL_INT k, const double alpha,
211  // const double * a, const MKL_INT lda,
212  // const double * b, const MKL_INT ldb,
213  // const double beta, double * c,
214  // const MKL_INT ldc);
215  // char transa = 'T';
216  // char transb = 'N';
217  int m = m_ncp_factors.factor(0).n_rows;
218  int n = ncp_krp[0].n_rows;
219  int k = m_ncp_factors.factor(0).n_cols;
220  int lda = m;
221  int ldb = n;
222  int ldc = m;
223  double alpha = 1;
224  double beta = 0;
225  char nt = 'N';
226  char t = 'T';
227 
228  MAT unnorm_fac =
229  m_ncp_factors.factor(0) * arma::diagmat(m_ncp_factors.lambda());
230  // double *output_tensor = new double[ldc * n];
231  dgemm_(&nt, &t, &m, &n, &k, &alpha, unnorm_fac.memptr(), &lda,
232  ncp_krp[0].memptr(), &ldb, &beta, &lowranktensor->m_data[0], &ldc);
233  // INFO << "lowrank tensor::" << std::endl;
234  // lowranktensor->print();
235  // for (int i=0; i < ldc*n; i++){
236  // INFO << i << ":" << output_tensor[i] << std::endl;
237  // }
238  double err = m_input_tensor.err(*lowranktensor);
239  err = std::sqrt(err / this->m_normA);
240  return err;
241  }
242  double computeObjectiveError(const NCPFactors &new_factors_t) {
243  reset(new_factors_t, true);
244  return computeObjectiveError();
245  }
246 }; // class AUNTF
247 } // namespace planc
248 
249 #endif // NTF_AUNTF_HPP_
double current_error() const
Definition: auntf.hpp:121
NCPFactors & ncp_factors()
Definition: auntf.hpp:113
Data is stored such that the unfolding is column major.
Definition: tensor.hpp:32
void computeNTF()
Definition: auntf.hpp:123
void print()
prints the entire NCPFactors including the factor matrices
Definition: ncpfactors.hpp:302
void accelerated(const bool &set_acceleration)
Definition: auntf.hpp:173
void gram_leave_out_one(const unsigned int i_n, MAT *o_UtU)
Returns the hadamard of the factor grams except i_n.
Definition: ncpfactors.hpp:139
double computeObjectiveError(const NCPFactors &new_factors_t)
Definition: auntf.hpp:242
double computeObjectiveError()
Definition: auntf.hpp:195
void set_factor(const double *arma_factor_ptr, const long int mode)
Definition: ddt.hpp:93
void normalize()
only during initialization. Reset&#39;s all lambda.
Definition: ncpfactors.hpp:329
double err(const Tensor &b) const
Computes the squared error with the input tensor.
Definition: tensor.hpp:357
std::vector< double > m_data
Definition: tensor.hpp:73
void num_it(const int i_n)
Definition: auntf.hpp:122
algotype
Definition: utils.h:10
void mttkrp(const int i_n, const MAT &i_krp, MAT *o_mttkrp) const
size of krp must be product of all dimensions leaving out nxk.
Definition: tensor.hpp:242
MAT krp_leave_out_one(const unsigned int i_n)
KRP leaving out the mode i_n.
Definition: ncpfactors.hpp:154
void dim_tree(bool i_dim_tree)
Definition: auntf.hpp:114
VEC lambda() const
returns the lambda vector
Definition: ncpfactors.hpp:104
void in_order_reuse_MTTKRP(long int n, double *out, bool colmajor, double &multittv_time, double &mttkrp_time)
Definition: ddt.hpp:134
void set(const int i_n, const MAT &i_factor)
Set the mode i_n with the given factor matrix.
Definition: ncpfactors.hpp:112
#define INFO
Definition: utils.h:36
void set_lambda(const VEC &new_lambda)
sets the lambda vector
Definition: ncpfactors.hpp:117
int modes() const
Return the number of modes. It is a scalar value.
Definition: tensor.hpp:159
#define TENSOR_NUMEL
Definition: auntf.hpp:20
#define UWORD
Definition: utils.h:60
#define TENSOR_DIM
Definition: auntf.hpp:19
#define MAT
Definition: utils.h:52
AUNTF(const planc::Tensor &i_tensor, const int i_k, algotype i_algo)
Definition: auntf.hpp:78
int current_it() const
Definition: auntf.hpp:194
UVEC dimensions() const
Returns a vector of dimensions on every mode.
Definition: tensor.hpp:161
double norm() const
returns the frobenius norm of the tensor
Definition: tensor.hpp:346
void reset(const NCPFactors &new_factors, bool trans=false)
Definition: auntf.hpp:181
ncp_factors contains the factors of the ncp every ith factor is of size n_i * k number of factors is ...
Definition: ncpfactors.hpp:20
void compute_error(bool i_error)
Definition: auntf.hpp:180
MAT & factor(const int i_n) const
factor matrix of a mode i_n
Definition: ncpfactors.hpp:100
bool is_stale_mttkrp(const int &current_mode) const
Definition: auntf.hpp:177