vmmlib  1.7.0
 All Classes Namespaces Functions Pages
cp3_tensor.hpp
1 /*
2  * Copyright (c) 2006-2014, Visualization and Multimedia Lab,
3  * University of Zurich <http://vmml.ifi.uzh.ch>,
4  * Eyescale Software GmbH,
5  * Blue Brain Project, EPFL
6  *
7  * This file is part of VMMLib <https://github.com/VMML/vmmlib/>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * Redistributions of source code must retain the above copyright notice, this
13  * list of conditions and the following disclaimer. Redistributions in binary
14  * form must reproduce the above copyright notice, this list of conditions and
15  * the following disclaimer in the documentation and/or other materials provided
16  * with the distribution. Neither the name of the Visualization and Multimedia
17  * Lab, University of Zurich nor the names of its contributors may be used to
18  * endorse or promote products derived from this software without specific prior
19  * written permission.
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * VMMLib - Tensor Classes
35  *
36  * @author Susanne Suter
37  * @author Jonas Boesch
38  * @author Rafael Ballester
39  *
40  * The cp3 tensor class is consists of three basis matrices u1-u3 and R lambda
41  * values for a given rank-R approximation. CP stands for Candecomp/Parafac
42  * (1970)
43  *
44  * - Carroll & Chang, 1970: Analysis of Individual Differences in
45  * Multidimensional Scaling via an N-way generalization of ``Eckart--Young''
46  * decompositions, Psychometrika.
47  * - Harshman, 1970: Foundations of the PARAFAC procedure: Models and conditions
48  * for an 'explanatory' multi-modal factor analysis,UCLA Working Papers in
49  * Phonetics.
50  * - De Lathauwer, De Moor, Vandewalle, 2000: A multilinear singular value
51  * decomposition, SIAM J. Matrix Anal. Appl.
52  * - Kolda & Bader, 2009: Tensor Decompositions and Applications, SIAM Review.
53  */
54 
55 #ifndef __VMML__CP3_TENSOR__HPP__
56 #define __VMML__CP3_TENSOR__HPP__
57 
58 #include <vmmlib/matrix_pseudoinverse.hpp>
59 #include <vmmlib/t3_hopm.hpp>
60 #include <vmmlib/t3_ihopm.hpp>
61 #include <vmmlib/tensor3_iterator.hpp>
62 
63 
64 namespace vmml {
65 
66  template< size_t R, size_t I1, size_t I2, size_t I3,
67  typename T_value = double, typename T_coeff = float >
68  class cp3_tensor
69  {
70  public:
71  typedef float T_internal;
72 
74  typedef typename t3_type::iterator t3_iterator;
76 
78 
82 
84  typedef typename u1_type::iterator u1_iterator;
85  typedef typename u1_type::const_iterator u1_const_iterator;
86 
88  typedef typename u2_type::iterator u2_iterator;
89  typedef typename u2_type::const_iterator u2_const_iterator;
90 
92  typedef typename u3_type::iterator u3_iterator;
93  typedef typename u3_type::const_iterator u3_const_iterator;
94 
98 
101 
102  cp3_tensor(u1_type& U1, u2_type& U2, u3_type& U3, lambda_type& lambdas_);
103  cp3_tensor();
104  ~cp3_tensor();
105 
106  void get_lambdas(lambda_type& data_) const {
107  data_ = *_lambdas;
108  };
109 
110  void get_u1(u1_type& U1) const {
111  U1 = *_u1;
112  };
113 
114  void get_u2(u2_type& U2) const {
115  U2 = *_u2;
116  };
117 
118  void get_u3(u3_type& U3) const {
119  U3 = *_u3;
120  };
121 
122  void set_lambdas(lambda_type& lambdas) {
123  *_lambdas = lambdas;
124  _lambdas_comp->cast_from(lambdas);
125  };
126 
127  void set_u1(u1_type& U1) {
128  *_u1 = U1;
129  _u1_comp->cast_from(U1);
130  };
131 
132  void set_u2(u2_type& U2) {
133  *_u2 = U2;
134  _u1_comp->cast_from(U2);
135  };
136 
137  void set_u3(u3_type& U3) {
138  *_u3 = U3;
139  _u1_comp->cast_from(U3);
140  };
141 
142  void set_lambda_comp(lambda_comp_type& lambdas) {
143  *_lambdas_comp = lambdas;
144  _lambdas->cast_from(lambdas);
145  };
146 
147  void set_u1_comp(u1_comp_type& U1) {
148  *_u1_comp = U1;
149  _u1->cast_from(U1);
150  };
151 
152  void set_u2_comp(u2_comp_type& U2) {
153  *_u2_comp = U2;
154  _u1->cast_from(U2);
155  };
156 
157  void set_u3_comp(u3_comp_type& U3) {
158  *_u3_comp = U3;
159  _u1->cast_from(U3);
160  };
161 
162  void get_lambda_comp(lambda_comp_type& data_) const {
163  data_ = _lambdas_comp;
164  };
165 
166  void get_u1_comp(u1_comp_type& U1) const {
167  U1 = *_u1_comp;
168  };
169 
170  void get_u2_comp(u2_comp_type& U2) const {
171  U2 = *_u2_comp;
172  };
173 
174  void get_u3_comp(u3_comp_type& U3) const {
175  U3 = *_u3_comp;
176  };
177 
178  void export_to(std::vector< T_coeff >& data_) const;
179  void import_from(std::vector< T_coeff >& data_);
180  void reconstruct(t3_type& data_) const;
181  double error(t3_type& data_) const;
182  size_t nnz() const;
183 
184  template< typename T_init >
185  tensor_stats decompose(const t3_type& data_, T_init init, const size_t max_iterations_ = 50, const float tolerance = 1e-04);
186 
187  template< typename T_init >
188  tensor_stats cp_als(const t3_type& data_, T_init init, const size_t max_iterations_ = 50, const float tolerance = 1e-04);
189 
190  template< size_t NBLOCKS, typename T_init >
191  tensor_stats i_cp_als(const t3_type& data_, T_init init, const size_t max_iterations_ = 50, const float tolerance = 1e-04);
192 
193  template< size_t K >
194  void reduce_ranks(const cp3_tensor< K, I1, I2, I3, T_value, T_coeff >& other);
195 
196  protected:
197 
199  };
200 
202  return *this;
203  };
204 
206  friend std::ostream& operator <<(std::ostream& os, const cp3_type& dec_ ) {
207  lambda_type lambdas;
208  dec_.get_lambdas(lambdas);
209  u1_type* u1 = new u1_type;
210  dec_.get_u1(*u1);
211  u2_type* u2 = new u2_type;
212  dec_.get_u2(*u2);
213  u3_type* u3 = new u3_type;
214  dec_.get_u3(*u3);
215 
216  os << "U1: " << std::endl << *u1 << std::endl
217  << "U2: " << std::endl << *u2 << std::endl
218  << "U3: " << std::endl << *u3 << std::endl
219  << "lambdas: " << std::endl << lambdas << std::endl;
220 
221  delete u1;
222  delete u2;
223  delete u3;
224  return os;
225  }
226 
227  void cast_members();
228  void cast_comp_members();
229 
230  private:
231 
232  lambda_type* _lambdas;
233  u1_type* _u1;
234  u2_type* _u2;
235  u3_type* _u3;
236 
237  lambda_comp_type* _lambdas_comp;
238  u1_comp_type* _u1_comp;
239  u2_comp_type* _u2_comp;
240  u3_comp_type* _u3_comp;
241 
242  }; // class cp3_tensor
243 
244 
245 #define VMML_TEMPLATE_STRING template< size_t R, size_t I1, size_t I2, size_t I3, typename T_value, typename T_coeff >
246 #define VMML_TEMPLATE_CLASSNAME cp3_tensor< R, I1, I2, I3, T_value, T_coeff >
247 
248  VMML_TEMPLATE_STRING
249  VMML_TEMPLATE_CLASSNAME::cp3_tensor(u1_type& U1, u2_type& U2, u3_type& U3, lambda_type& lambdas_) {
250  set_lambdas(lambdas_);
251  set_u1(U1);
252  set_u2(U2);
253  set_u3(U3);
254  }
255 
256  VMML_TEMPLATE_STRING
257  VMML_TEMPLATE_CLASSNAME::cp3_tensor() {
258  _lambdas = new vector< R, T_coeff > ();
259  _lambdas->set(0);
260  _u1 = new u1_type();
261  _u1->zero();
262  _u2 = new u2_type();
263  _u2->zero();
264  _u3 = new u3_type();
265  _u3->zero();
266  _lambdas_comp = new vector< R, T_internal>;
267  _lambdas_comp->set(0);
268  _u1_comp = new u1_comp_type;
269  _u1_comp->zero();
270  _u2_comp = new u2_comp_type;
271  _u2_comp->zero();
272  _u3_comp = new u3_comp_type;
273  _u3_comp->zero();
274  }
275 
276  VMML_TEMPLATE_STRING
277  VMML_TEMPLATE_CLASSNAME::~cp3_tensor() {
278  delete _u1;
279  delete _u2;
280  delete _u3;
281  delete _lambdas;
282  delete _u1_comp;
283  delete _u2_comp;
284  delete _u3_comp;
285  delete _lambdas_comp;
286  }
287 
288  VMML_TEMPLATE_STRING
289  void
290  VMML_TEMPLATE_CLASSNAME::cast_members() {
291  _u1->cast_from(*_u1_comp);
292  _u2->cast_from(*_u2_comp);
293  _u3->cast_from(*_u3_comp);
294  _lambdas->cast_from(*_lambdas_comp);
295  }
296 
297  VMML_TEMPLATE_STRING
298  void
299  VMML_TEMPLATE_CLASSNAME::cast_comp_members() {
300  _u1_comp->cast_from(*_u1);
301  _u2_comp->cast_from(*_u2);
302  _u3_comp->cast_from(*_u3);
303  _lambdas_comp->cast_from(_lambdas);
304  }
305 
306  VMML_TEMPLATE_STRING
307  void
308  VMML_TEMPLATE_CLASSNAME::reconstruct(t3_type& data_) const {
309 
310  //FIXME: check data types
311  t3_comp_type data;
312  data.cast_from(data_);
313 
314  typedef t3_hopm< R, I1, I2, I3, T_internal > hopm_type;
315  hopm_type::reconstruct(data, *_u1_comp, *_u2_comp, *_u3_comp, *_lambdas_comp);
316 
317  //convert reconstructed data, which is in type T_internal (double, float) to T_value (uint8 or uint16)
318  if ((sizeof (T_value) == 1) || (sizeof (T_value) == 2)) {
319  data_.float_t_to_uint_t(data);
320  } else {
321  data_.cast_from(data);
322  }
323 
324  }
325 
326  VMML_TEMPLATE_STRING
327  double
328  VMML_TEMPLATE_CLASSNAME::error(t3_type& original) const {
329  typedef t3_hopm< R, I1, I2, I3, T_internal > hopm_type;
330  t3_comp_type data;
331  hopm_type::reconstruct(data, *_u1_comp, *_u2_comp, *_u3_comp, *_lambdas_comp);
332  double err = data.frobenius_norm(original) / original.frobenius_norm() * 100;
333  return err;
334  }
335 
336  VMML_TEMPLATE_STRING
337  template< typename T_init >
338  tensor_stats
339  VMML_TEMPLATE_CLASSNAME::decompose(const t3_type& data_, T_init init, const size_t max_iterations_, const float tolerance) {
340  return cp_als(data_, init, max_iterations_, tolerance );
341  }
342 
343  VMML_TEMPLATE_STRING
344  template< typename T_init >
345  tensor_stats
346  VMML_TEMPLATE_CLASSNAME::cp_als(const t3_type& data_, T_init init, const size_t max_iterations_, const float tolerance) {
347  tensor_stats result;
348 
349  t3_comp_type data;
350  data.cast_from(data_);
351 
352  typedef t3_hopm< R, I1, I2, I3, T_internal > hopm_type;
353  result += hopm_type::als(data, *_u1_comp, *_u2_comp, *_u3_comp, *_lambdas_comp, init, max_iterations_, tolerance);
354 
355  cast_members();
356  return result;
357  }
358 
359  VMML_TEMPLATE_STRING
360  template< size_t NBLOCKS, typename T_init >
361  tensor_stats
362  VMML_TEMPLATE_CLASSNAME::i_cp_als(const t3_type& data_, T_init init, const size_t max_iterations_, const float tolerance) {
363  tensor_stats result;
364 
365  t3_comp_type data;
366  data.cast_from(data_);
367 
368  typedef t3_ihopm< R, NBLOCKS, I1, I2, I3, T_internal > ihopm_type;
369  result += ihopm_type::incremental_als(data, *_u1_comp, *_u2_comp, *_u3_comp, *_lambdas_comp, init, max_iterations_, tolerance);
370 
371 
372  cast_members();
373 
374  return result;
375  }
376 
377  VMML_TEMPLATE_STRING
378  template< size_t K >
379  void
380  VMML_TEMPLATE_CLASSNAME::reduce_ranks(const cp3_tensor< K, I1, I2, I3, T_value, T_coeff >& other)
381  // K -> R; I1, I2, I3 stay the same
382  {
383  assert(R <= K);
384 
385  //reduce basis matrices
386  matrix< I1, K, T_coeff >* u1 = new matrix< I1, K, T_coeff > ();
387  other.get_u1(*u1);
388  matrix< I2, K, T_coeff >* u2 = new matrix< I2, K, T_coeff > ();
389  other.get_u2(*u2);
390  matrix< I3, K, T_coeff >* u3 = new matrix< I3, K, T_coeff > ();
391  other.get_u3(*u3);
392  for (size_t r = 0; r < R; ++r) {
393  _u1->set_column(r, u1->get_column(r));
394  _u2->set_column(r, u2->get_column(r));
395  _u3->set_column(r, u3->get_column(r));
396  }
397  // reduce vector of lambdas
398  vector< K, T_coeff >* lambdas;
399  other.get_lambdas(lambdas);
400  _lambdas_comp->set(lambdas);
401 
402  cast_comp_members();
403 
404  delete u1;
405  delete u2;
406  delete u3;
407  }
408 
409  VMML_TEMPLATE_STRING
410  void
411  VMML_TEMPLATE_CLASSNAME::export_to(std::vector< T_coeff >& data_) const {
412  u1_const_iterator it = _u1->begin(),
413  it_end = _u1->end();
414  for (; it != it_end; ++it) {
415  data_.push_back(*it);
416  }
417 
418  u2_const_iterator u2_it = _u2->begin(),
419  u2_it_end = _u2->end();
420  for (; u2_it != u2_it_end; ++u2_it) {
421  data_.push_back(*u2_it);
422  }
423 
424  u3_const_iterator u3_it = _u3->begin(),
425  u3_it_end = _u3->end();
426  for (; u3_it != u3_it_end; ++u3_it) {
427  data_.push_back(*u3_it);
428  }
429 
430  //TODO: iterate over lambdas
431  }
432 
433  VMML_TEMPLATE_STRING
434  void
435  VMML_TEMPLATE_CLASSNAME::import_from(std::vector< T_coeff >& data_) {
436  size_t i = 0; //iterator over data_
437 
438  u1_iterator it = _u1->begin(),
439  it_end = _u1->end();
440  for (; it != it_end; ++it, ++i) {
441  *it = data_.at(i);
442  }
443 
444  u2_iterator u2_it = _u2->begin(),
445  u2_it_end = _u2->end();
446  for (; u2_it != u2_it_end; ++u2_it, ++i) {
447  *u2_it = data_.at(i);
448  }
449 
450  u3_iterator u3_it = _u3->begin(),
451  u3_it_end = _u3->end();
452  for (; u3_it != u3_it_end; ++u3_it, ++i) {
453  *u3_it = data_.at(i);
454  }
455 
456  //TODO: import lambdas
457 
458  }
459 
460  VMML_TEMPLATE_STRING
461  size_t
462  VMML_TEMPLATE_CLASSNAME::nnz() const {
463  size_t counter = 0;
464 
465  counter += _u1_comp->nnz();
466  counter += _u2_comp->nnz();
467  counter += _u3_comp->nnz();
468  counter += _lambdas_comp->nnz();
469 
470  return counter;
471  }
472 
473 #undef VMML_TEMPLATE_STRING
474 #undef VMML_TEMPLATE_CLASSNAME
475 
476 } // namespace vmml
477 
478 #endif