triangular_matrix.hpp
Go to the documentation of this file.
1 /*!
2  * \brief Implements a matrix with triangular storage layout
3  *
4  * \author O. Krause
5  * \date 2015
6  *
7  *
8  * \par Copyright 1995-2015 Shark Development Team
9  *
10  * <BR><HR>
11  * This file is part of Shark.
12  * <http://image.diku.dk/shark/>
13  *
14  * Shark is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU Lesser General Public License as published
16  * by the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * Shark is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
26  *
27  */
28 #ifndef REMORA_TRIANGULAR_MATRIX_HPP
29 #define REMORA_TRIANGULAR_MATRIX_HPP
30 
31 
32 #include "assignment.hpp"
33 #include "detail/matrix_proxy_classes.hpp"
34 
35 #include <boost/serialization/collection_size_type.hpp>
36 #include <boost/serialization/array.hpp>
37 #include <boost/serialization/nvp.hpp>
38 #include <boost/serialization/vector.hpp>
39 
40 namespace remora{
41 
42 template<class T, class Orientation, class TriangularType>
43 class triangular_matrix:public matrix_container<triangular_matrix<T,Orientation,TriangularType>, cpu_tag > {
44  typedef triangular_matrix<T, Orientation,TriangularType> self_type;
45  typedef std::vector<T> array_type;
46 public:
47  typedef typename array_type::value_type value_type;
48  typedef value_type const_reference;
49  typedef value_type reference;
50  typedef std::size_t size_type;
51 
52  typedef const matrix_reference<const self_type> const_closure_type;
53  typedef matrix_reference<self_type> closure_type;
54  typedef packed_matrix_storage<T> storage_type;
55  typedef packed_matrix_storage<T const> const_storage_type;
56  typedef elementwise<packed_tag> evaluation_category;
57  typedef triangular<Orientation,TriangularType> orientation;
58 
59  // Construction and destruction
60 
61  /// Default triangular_matrix constructor. Make a dense matrix of size (0,0)
62  triangular_matrix():m_size(0){}
63 
64  /** Packed matrix constructor with defined size
65  * \param size number of rows and columns
66  */
67  triangular_matrix(size_type size):m_size(size),m_data(size * (size+1)/2) {}
68 
69  /** Packed matrix constructor with defined size and an initial value for all triangular matrix elements
70  * \param size number of rows and columns
71  * \param init initial value of the non-zero elements
72  */
73  triangular_matrix(size_type size, value_type init):m_size(size),m_data(size * (size+1)/2,init) {}
74 
75  /** Copy-constructor of a dense matrix
76  * \param m is a dense matrix
77  */
78  triangular_matrix(triangular_matrix const& m):m_size(m.m_size), m_data(m.m_data) {}
79 
80  /** Copy-constructor of a dense matrix from a matrix expression
81  * \param e is a matrix expression which has to be triangular
82  */
83  template<class E>
84  triangular_matrix(matrix_expression<E, cpu_tag> const& e)
85  :m_size(e().size1()), m_data(m_size * (m_size+1)/2)
86  {
87  assign(*this, e);
88  }
89 
90  ///\brief Returns the number of rows of the matrix.
91  size_type size1() const {
92  return m_size;
93  }
94  ///\brief Returns the number of columns of the matrix.
95  size_type size2() const {
96  return m_size;
97  }
98 
99  storage_type raw_storage(){
100  return {m_data.data(), m_data.size()};
101  }
102 
103  const_storage_type raw_storage()const{
104  return {m_data.data(), m_data.size()};
105  }
106 
107  typename device_traits<cpu_tag>::queue_type& queue(){
108  return device_traits<cpu_tag>::default_queue();
109  }
110 
111 
112  // Resizing
113  /** Resize a matrix to new dimensions. If resizing is performed, the data is not preserved.
114  * \param size the new number of rows and columns
115  */
116  void resize(size_type size) {
117  m_data.resize(size*(size+1)/2);
118  m_size = size;
119  }
120 
121  void resize(size_type size1, size_type size2) {
122  REMORA_SIZE_CHECK(size1 == size2);
123  resize(size1);
124  (void)size2;
125  }
126 
127  void clear(){
128  std::fill(m_data.begin(), m_data.end(), value_type/*zero*/());
129  }
130 
131  // Element access read only
132  const_reference operator()(size_type i, size_type j) const {
133  REMORA_SIZE_CHECK(i < size1());
134  REMORA_SIZE_CHECK(j < size2());
135  if(!orientation::non_zero(i,j))
136  return value_type();
137  REMORA_SIZE_CHECK(orientation::element(i,j,size1(),packed_tag())<m_data.size());
138  return m_data [orientation::element(i,j,size1(),packed_tag())];
139  }
140 
141  // separate write access
142  void set_element(size_type i,size_type j, value_type t){
143  REMORA_SIZE_CHECK(i < size1());
144  REMORA_SIZE_CHECK(j < size2());
145  REMORA_SIZE_CHECK(orientation::non_zero(i,j));
146  m_data [orientation::element(i,j,size1(),packed_tag())] = t;
147  }
148 
149  bool non_zero(size_type i,size_type j)const{
150  REMORA_SIZE_CHECK(i < size1());
151  REMORA_SIZE_CHECK(j < size2());
152  return orientation::non_zero(i,j);
153  }
154 
155  /*! @note "pass by value" the key idea to enable move semantics */
156  triangular_matrix& operator = (triangular_matrix m) {
157  swap(m);
158  return *this;
159  }
160  template<class C> // Container assignment without temporary
161  triangular_matrix& operator = (matrix_container<C, cpu_tag> const& m) {
162  REMORA_SIZE_CHECK(m().size1()==m().size2());
163  resize(m().size1());
164  assign(*this, m);
165  return *this;
166  }
167  template<class E>
168  triangular_matrix& operator = (matrix_expression<E, cpu_tag> const& e) {
169  self_type temporary(e);
170  swap(temporary);
171  return *this;
172  }
173 
174  // Swapping
175  void swap(triangular_matrix& m) {
176  std::swap(m_size, m.m_size);
177  m_data.swap(m.m_data);
178  }
179  friend void swap(triangular_matrix& m1, triangular_matrix& m2) {
180  m1.swap(m2);
181  }
182 
183  ///////////iterators
184  template<class TIter>
185  class major1_iterator:
186  public iterators::random_access_iterator_base<
187  major1_iterator<TIter>,
188  typename std::remove_const<T>::type,
189  iterators::packed_random_access_iterator_tag
190  >{
191  private:
192  std::ptrdiff_t offset(std::ptrdiff_t n)const{
193  size_type k = m_index;
194  if(n >= 0){
195  return (n*(2*k+n+1))/2;
196  }else{
197  k+= n;
198  n*=-1;
199  return -(n*(2*k+n+1))/2;
200  }
201  }
202  public:
203  typedef typename std::remove_const<TIter>::type value_type;
204  typedef TIter& reference;
205  typedef TIter* pointer;
206 
207  // Construction
208  major1_iterator() {}
209  major1_iterator(pointer arrayBegin, size_type index, size_type /*size*/)
210  :m_pos(arrayBegin), m_index(index){}
211 
212  template<class U>
213  major1_iterator(major1_iterator<U> const& iter)
214  :m_pos(iter.m_pos), m_index(iter.m_index){}
215 
216  template<class U>
217  major1_iterator& operator=(major1_iterator<U> const& iter){
218  m_pos = iter.m_pos;
219  m_index = iter.m_index;
220  return *this;
221  }
222 
223  // Arithmetic
224  major1_iterator& operator ++ () {
225  ++m_index;
226  m_pos += m_index;
227  return *this;
228  }
229  major1_iterator& operator -- () {
230  m_pos -= m_index;
231  --m_index;
232  return *this;
233  }
234  major1_iterator& operator += (size_type n) {
235  m_pos += offset(n);
236  m_index += n;
237  return *this;
238  }
239  major1_iterator& operator -= (size_type n) {
240  m_pos += offset(-(std::ptrdiff_t)n);
241  m_index -= n;
242  return *this;
243  }
244  template<class U>
245  size_type operator - (major1_iterator<U> const& it) const {
246  return m_index - it.m_index;
247  }
248 
249  // Dereference
250  reference operator*() const {
251  return *m_pos;
252  }
253  reference operator [](size_type n) const {
254  return m_pos[offset(n)];
255  }
256 
257  // Index
258  size_type index() const {
259  return m_index;
260  }
261 
262  // Comparison
263  template<class U>
264  bool operator == (major1_iterator<U> const& it) const {
265  return m_index == it.m_index;
266  }
267  template<class U>
268  bool operator < (major1_iterator<U> const& it) const {
269  return m_index < it.m_index;
270  }
271 
272  private:
273  pointer m_pos;
274  size_type m_index;
275  template<class> friend class major1_iterator;
276  };
277 
278  template<class TIter>
279  class major2_iterator:
280  public iterators::random_access_iterator_base<
281  major2_iterator<TIter>,
282  typename std::remove_const<T>::type,
283  iterators::packed_random_access_iterator_tag
284  >{
285  private:
286  std::ptrdiff_t offset(std::ptrdiff_t n)const{
287  size_type k = m_size-m_index-1;
288  if(n >= 0){
289  return (2*k*n-n*n+n)/2;
290  }else{
291  n*=-1;
292  k+= n;
293  return -(2*k*n-n*n+n)/2;
294  }
295  }
296  public:
297  typedef typename std::remove_const<TIter>::type value_type;
298  typedef TIter& reference;
299  typedef TIter* pointer;
300 
301  // Construction
302  major2_iterator() {}
303  major2_iterator(pointer arrayBegin, size_type index, size_type size)
304  :m_pos(arrayBegin), m_index(index), m_size(size){}
305 
306  template<class U>
307  major2_iterator(major2_iterator<U> const& iter)
308  :m_pos(iter.m_pos), m_index(iter.m_index), m_size(iter.m_size){}
309 
310  template<class U>
311  major2_iterator& operator=(major2_iterator<U> const& iter){
312  m_pos = iter.m_pos;
313  m_index = iter.m_index;
314  m_size = iter.m_size;
315  return *this;
316  }
317 
318  // Arithmetic
319  major2_iterator& operator ++ () {
320  ++m_index;
321  m_pos += m_size-m_index;
322  return *this;
323  }
324  major2_iterator& operator -- () {
325  m_pos -= m_size-m_index;
326  --m_index;
327  return *this;
328  }
329  major2_iterator& operator += (size_type n) {
330  m_pos += offset(n);
331  m_index += n;
332  return *this;
333  }
334  major2_iterator& operator -= (size_type n) {
335  m_pos += offset(-(std::ptrdiff_t)n);
336  m_index -= n;
337  return *this;
338  }
339  template<class U>
340  std::ptrdiff_t operator - (major2_iterator<U> const& it) const {
341  return static_cast<std::ptrdiff_t>(m_index) - static_cast<std::ptrdiff_t>(it.m_index);
342  }
343 
344  // Dereference
345  reference operator*() const {
346  return *m_pos;
347  }
348  reference operator [](size_type n) const {
349  return m_pos[offset(n)];
350  }
351 
352  // Index
353  size_type index() const {
354  return m_index;
355  }
356 
357  // Comparison
358  template<class U>
359  bool operator == (major2_iterator<U> const& it) const {
360  return m_index == it.m_index;
361  }
362  template<class U>
363  bool operator < (major2_iterator<U> const& it) const {
364  return m_index < it.m_index;
365  }
366 
367  private:
368  pointer m_pos;
369  size_type m_index;
370  size_type m_size;
371  template<class> friend class major2_iterator;
372  };
373 
374  typedef typename std::conditional<
375  std::is_same<Orientation,row_major>::value,
376  iterators::dense_storage_iterator<value_type,iterators::packed_random_access_iterator_tag>,
377  typename std::conditional<
378  TriangularType::is_upper,
379  major1_iterator<value_type>,
380  major2_iterator<value_type>
381  >::type
382  >::type row_iterator;
383  typedef typename std::conditional<
384  std::is_same<Orientation,row_major>::value,
385  typename std::conditional<
386  TriangularType::is_upper,
387  major2_iterator<value_type>,
388  major1_iterator<value_type>
389  >::type,
390  iterators::dense_storage_iterator<value_type,iterators::packed_random_access_iterator_tag>
391  >::type column_iterator;
392 
393  typedef typename std::conditional<
394  std::is_same<Orientation,row_major>::value,
395  iterators::dense_storage_iterator<value_type const,iterators::packed_random_access_iterator_tag>,
396  typename std::conditional<
397  TriangularType::is_upper,
398  major1_iterator<value_type const>,
399  major2_iterator<value_type const>
400  >::type
401  >::type const_row_iterator;
402  typedef typename std::conditional<
403  std::is_same<Orientation,row_major>::value,
404  typename std::conditional<
405  TriangularType::is_upper,
406  major2_iterator<value_type const>,
407  major1_iterator<value_type const>
408  >::type,
409  iterators::dense_storage_iterator<value_type const,iterators::packed_random_access_iterator_tag>
410  >::type const_column_iterator;
411 
412 public:
413 
414  const_row_iterator row_begin(size_type i) const {
415  size_type index = TriangularType::is_upper?i:0;
416  return const_row_iterator(
417  m_data.data()+orientation::element(i,index,size1(),packed_tag())
418  ,index
419  ,orientation::orientation::stride2(size1(),size2())//1 if row_major, size2() otherwise
420  );
421  }
422  const_row_iterator row_end(size_type i) const {
423  size_type index = TriangularType::is_upper?size2():i+1;
424  return const_row_iterator(
425  m_data.data() + orientation::element(i, index, size1(),packed_tag())
426  ,index
427  ,orientation::orientation::stride2(size1(),size2())//1 if row_major, size2() otherwise
428  );
429  }
430  row_iterator row_begin(size_type i){
431  size_type index = TriangularType::is_upper?i:0;
432  return row_iterator(
433  m_data.data() + orientation::element(i, index, size1(),packed_tag())
434  ,index
435  ,orientation::orientation::stride2(size1(),size2())//1 if row_major, size2() otherwise
436  );
437  }
438  row_iterator row_end(size_type i){
439  size_type index = TriangularType::is_upper?size2():i+1;
440  return row_iterator(
441  m_data.data() + orientation::element(i, index, size1(),packed_tag())
442  ,index
443  ,orientation::orientation::stride2(size1(),size2())//1 if row_major, size2() otherwise
444  );
445  }
446 
447  const_column_iterator column_begin(size_type i) const {
448  size_type index = TriangularType::is_upper?0:i;
449  return const_column_iterator(
450  m_data.data() + orientation::element(index, i, size1(),packed_tag())
451  ,index
452  ,orientation::orientation::stride1(size1(),size2())//size1() if row_major, 1 otherwise
453  );
454  }
455  const_column_iterator column_end(size_type i) const {
456  size_type index = TriangularType::is_upper?i+1:size2();
457  return const_column_iterator(
458  m_data.data() + orientation::element(index, i, size1(),packed_tag())
459  ,index
460  ,orientation::orientation::stride1(size1(),size2())//size1() if row_major, 1 otherwise
461  );
462  }
463  column_iterator column_begin(size_type i){
464  size_type index = TriangularType::is_upper?0:i;
465  return column_iterator(
466  m_data.data() + orientation::element(index, i, size1(),packed_tag())
467  ,index
468  ,orientation::orientation::stride1(size1(),size2())//size1() if row_major, 1 otherwise
469  );
470  }
471  column_iterator column_end(size_type i){
472  size_type index = TriangularType::is_upper?i+1:size2();
473  return column_iterator(
474  m_data.data() + orientation::element(index, i, size1(),packed_tag())
475  ,index
476  ,orientation::orientation::stride1(size1(),size2())//size1() if row_major, 1 otherwise
477  );
478  }
479 
480  // Serialization
481  template<class Archive>
482  void serialize(Archive& ar, const unsigned int /* file_version */) {
483  boost::serialization::collection_size_type s(m_size);
484 
485  // serialize the sizes
486  ar & boost::serialization::make_nvp("size",s);
487 
488  // copy the values back if loading
489  if (Archive::is_loading::value) {
490  m_size = s;
491  }
492  ar & boost::serialization::make_nvp("data",m_data);
493  }
494 
495 private:
496  size_type m_size;
497  array_type m_data;
498 };
499 
500 template<class T, class Orientation, class TriangularType>
501 struct const_expression<triangular_matrix<T,Orientation, TriangularType> >{
502  typedef triangular_matrix<T,Orientation, TriangularType> const type;
503 };
504 template<class T, class Orientation, class TriangularType>
505 struct const_expression<triangular_matrix<T,Orientation, TriangularType> const>{
506  typedef triangular_matrix<T,Orientation, TriangularType> const type;
507 };
508 
509 template<class T, class Orientation, class TriangularType>
510 struct matrix_temporary_type<T,triangular<Orientation, TriangularType >,packed_tag, cpu_tag> {
511  typedef triangular_matrix<T,Orientation, TriangularType> type;
512 };
513 
514 }
515 
516 #endif