matrix.hpp
Go to the documentation of this file.
1 /*!
2  * \brief Dense Matrix class
3  *
4  * \author O. Krause
5  * \date 2013
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_CPU_MATRIX_HPP
29 #define REMORA_CPU_MATRIX_HPP
30 
31 #include "../detail/matrix_proxy_classes.hpp"
32 #include <initializer_list>
33 #include <boost/serialization/collection_size_type.hpp>
34 #include <boost/serialization/array.hpp>
35 #include <boost/serialization/nvp.hpp>
36 #include <boost/serialization/vector.hpp>
37 
38 namespace remora {
39 
40 /** \brief A dense matrix of values of type \c T.
41  *
42  * For a \f$(m \times n)\f$-dimensional matrix and \f$ 0 \leq i < m, 0 \leq j < n\f$, every element \f$ m_{i,j} \f$ is mapped to
43  * the \f$(i.n + j)\f$-th element of the container for row major orientation or the \f$ (i + j.m) \f$-th element of
44  * the container for column major orientation. In a dense matrix all elements are represented in memory in a
45  * contiguous chunk of memory by definition.
46  *
47  * Orientation can also be specified, otherwise a \c row_major is used.
48  *
49  * \tparam T the type of object stored in the matrix (like double, float, complex, etc...)
50  * \tparam L the storage organization. It can be either \c row_major or \c column_major. Default is \c row_major
51  */
52 template<class T, class L>
53 class matrix<T,L,cpu_tag>:public matrix_container<matrix<T, L, cpu_tag>, cpu_tag > {
54  typedef matrix<T, L> self_type;
55  typedef std::vector<T> array_type;
56 public:
57  typedef typename array_type::value_type value_type;
58  typedef typename array_type::const_reference const_reference;
59  typedef typename array_type::reference reference;
60  typedef typename array_type::size_type size_type;
61 
62  typedef matrix_reference<self_type const> const_closure_type;
63  typedef matrix_reference<self_type> closure_type;
64  typedef dense_matrix_storage<T, continuous_dense_tag> storage_type;
65  typedef dense_matrix_storage<T const, continuous_dense_tag> const_storage_type;
66  typedef elementwise<dense_tag> evaluation_category;
67  typedef L orientation;
68 
69  // Construction
70 
71  /// \brief Default dense matrix constructor. Make a dense matrix of size (0,0)
72  matrix():m_size1(0), m_size2(0){}
73 
74  /// \brief Constructor from a nested initializer list.
75  ///
76  /// Constructs a matrix like this: m = {{1,2},{3,4}}.
77  /// \param list The nested initializer list storing the values of the matrix.
78  matrix(std::initializer_list<std::initializer_list<T> > list)
79  : m_size1(list.size())
80  , m_size2(list.begin()->size())
81  , m_data(m_size1*m_size2){
82  auto pos = list.begin();
83  for(std::size_t i = 0; i != list.size(); ++i,++pos){
84  REMORA_SIZE_CHECK(pos->size() == m_size2);
85  std::copy(pos->begin(),pos->end(),row_begin(i));
86  }
87  }
88 
89  /// \brief Dense matrix constructor with defined size
90  /// \param size1 number of rows
91  /// \param size2 number of columns
92  matrix(size_type size1, size_type size2)
93  :m_size1(size1)
94  , m_size2(size2)
95  , m_data(size1 * size2) {}
96 
97  /// \brief Dense matrix constructor with defined size a initial value for all the matrix elements
98  /// \param size1 number of rows
99  /// \param size2 number of columns
100  /// \param init initial value assigned to all elements
101  matrix(size_type size1, size_type size2, value_type const& init)
102  : m_size1(size1)
103  , m_size2(size2)
104  , m_data(size1 * size2, init) {}
105 
106  /// \brief Copy-constructor of a dense matrix
107  ///\param m is a dense matrix
108  matrix(matrix const& m) = default;
109 
110  /// \brief Move-constructor of a dense matrix
111  ///\param m is a dense matrix
112  //~ matrix(matrix&& m) = default; //vc++ can not default this
113  matrix(matrix&& m):m_size1(m.m_size1), m_size2(m.m_size2), m_data(std::move(m.m_data)){}
114 
115  /// \brief Constructor of a dense matrix from a matrix expression.
116  ///
117  /// Constructs the matrix by evaluating the expression and assigning the
118  /// results to the newly constructed matrix using a call to assign.
119  ///
120  /// \param e is a matrix expression
121  template<class E>
122  matrix(matrix_expression<E, cpu_tag> const& e)
123  : m_size1(e().size1())
124  , m_size2(e().size2())
125  , m_data(m_size1 * m_size2) {
126  assign(*this,e);
127  }
128 
129  // Assignment
130 
131  /// \brief Assigns m to this
132  matrix& operator = (matrix const& m) = default;
133 
134  /// \brief Move-Assigns m to this
135  //~ matrix& operator = (matrix&& m) = default;//vc++ can not default this
136  matrix& operator = (matrix&& m) {
137  m_size1 = m.m_size1;
138  m_size2 = m.m_size2;
139  m_data = std::move(m.m_data);
140  return *this;
141  }
142 
143 
144  /// \brief Assigns m to this
145  ///
146  /// evaluates the expression and assign the
147  /// results to this using a call to assign.
148  /// As containers are assumed to not overlap, no temporary is created
149  ///
150  /// \param m is a matrix expression
151  template<class C>
152  matrix& operator = (matrix_container<C, cpu_tag> const& m) {
153  resize(m().size1(), m().size2());
154  assign(*this, m);
155  return *this;
156  }
157  /// \brief Assigns e to this
158  ///
159  /// evaluates the expression and assign the
160  /// results to this using a call to assign.
161  /// A temporary is created to prevent aliasing.
162  ///
163  /// \param e is a matrix expression
164  template<class E>
165  matrix& operator = (matrix_expression<E, cpu_tag> const& e) {
166  self_type temporary(e);
167  swap(temporary);
168  return *this;
169  }
170 
171  ///\brief Returns the number of rows of the matrix.
172  size_type size1() const {
173  return m_size1;
174  }
175  ///\brief Returns the number of columns of the matrix.
176  size_type size2() const {
177  return m_size2;
178  }
179 
180  ///\brief Returns the underlying storage structure for low level access
181  storage_type raw_storage(){
182  return {m_data.data(), orientation::index_m(m_size1,m_size2)};
183  }
184 
185  ///\brief Returns the underlying storage structure for low level access
186  const_storage_type raw_storage()const{
187  return {m_data.data(), orientation::index_m(m_size1,m_size2)};
188  }
189  typename device_traits<cpu_tag>::queue_type& queue(){
190  return device_traits<cpu_tag>::default_queue();
191  }
192 
193  // ---------
194  // High level interface
195  // ---------
196 
197  // Resizing
198  /// \brief Resize a matrix to new dimensions. If resizing is performed, the data is not preserved.
199  /// \param size1 the new number of rows
200  /// \param size2 the new number of colums
201  void resize(size_type size1, size_type size2) {
202  m_data.resize(size1* size2);
203  m_size1 = size1;
204  m_size2 = size2;
205  }
206 
207  void clear(){
208  std::fill(m_data.begin(), m_data.end(), value_type/*zero*/());
209  }
210 
211  // Element access
212  const_reference operator()(size_type i, size_type j) const {
213  REMORA_SIZE_CHECK(i < size1());
214  REMORA_SIZE_CHECK(j < size2());
215  return m_data[orientation::element(i, m_size1, j, m_size2)];
216  }
217  reference operator()(size_type i, size_type j) {
218  REMORA_SIZE_CHECK(i < size1());
219  REMORA_SIZE_CHECK(j < size2());
220  return m_data[orientation::element(i, m_size1, j, m_size2)];
221  }
222 
223  void set_element(size_type i, size_type j,value_type t){
224  REMORA_SIZE_CHECK(i < size1());
225  REMORA_SIZE_CHECK(j < size2());
226  m_data[orientation::element(i, m_size1, j, m_size2)] = t;
227  }
228 
229  // Swapping
230  void swap(matrix& m) {
231  std::swap(m_size1, m.m_size1);
232  std::swap(m_size2, m.m_size2);
233  m_data.swap(m.m_data);
234  }
235  friend void swap(matrix& m1, matrix& m2) {
236  m1.swap(m2);
237  }
238 
239  friend void swap_rows(matrix& a, size_type i, matrix& b, size_type j){
240  REMORA_SIZE_CHECK(i < a.size1());
241  REMORA_SIZE_CHECK(j < b.size1());
242  REMORA_SIZE_CHECK(a.size2() == b.size2());
243  for(std::size_t k = 0; k != a.size2(); ++k){
244  std::swap(a(i,k),b(j,k));
245  }
246  }
247 
248  void swap_rows(size_type i, size_type j) {
249  if(i == j) return;
250  for(std::size_t k = 0; k != size2(); ++k){
251  std::swap((*this)(i,k),(*this)(j,k));
252  }
253  }
254 
255 
256  friend void swap_columns(matrix& a, size_type i, matrix& b, size_type j){
257  REMORA_SIZE_CHECK(i < a.size2());
258  REMORA_SIZE_CHECK(j < b.size2());
259  REMORA_SIZE_CHECK(a.size1() == b.size1());
260  for(std::size_t k = 0; k != a.size1(); ++k){
261  std::swap(a(k,i),b(k,j));
262  }
263  }
264 
265  void swap_columns(size_type i, size_type j) {
266  if(i == j) return;
267  for(std::size_t k = 0; k != size1(); ++k){
268  std::swap((*this)(k,i),(*this)(k,j));
269  }
270  }
271 
272  //Iterators
273  typedef iterators::dense_storage_iterator<value_type> row_iterator;
274  typedef iterators::dense_storage_iterator<value_type> column_iterator;
275  typedef iterators::dense_storage_iterator<value_type const> const_row_iterator;
276  typedef iterators::dense_storage_iterator<value_type const> const_column_iterator;
277 
278  const_row_iterator row_begin(size_type i) const {
279  return const_row_iterator(m_data.data() + i*stride1(),0,stride2());
280  }
281  const_row_iterator row_end(size_type i) const {
282  return const_row_iterator(m_data.data() + i*stride1()+stride2()*size2(),size2(),stride2());
283  }
284  row_iterator row_begin(size_type i){
285  return row_iterator(m_data.data() + i*stride1(),0,stride2());
286  }
287  row_iterator row_end(size_type i){
288  return row_iterator(m_data.data() + i*stride1()+stride2()*size2(),size2(),stride2());
289  }
290 
291  const_row_iterator column_begin(std::size_t j) const {
292  return const_column_iterator(m_data.data() + j*stride2(),0,stride1());
293  }
294  const_column_iterator column_end(std::size_t j) const {
295  return const_column_iterator(m_data.data() + j*stride2()+ stride1()*size1(),size1(),stride1());
296  }
297  column_iterator column_begin(std::size_t j){
298  return column_iterator(m_data.data() + j*stride2(),0,stride1());
299  }
300  column_iterator column_end(std::size_t j){
301  return column_iterator(m_data.data() + j * stride2()+ stride1() * size1(), size1(), stride1());
302  }
303 
304  typedef typename major_iterator<self_type>::type major_iterator;
305 
306  //sparse interface
307  major_iterator set_element(major_iterator pos, size_type index, value_type value) {
308  REMORA_RANGE_CHECK(pos.index() == index);
309  *pos=value;
310  return pos;
311  }
312 
313  major_iterator clear_element(major_iterator elem) {
314  *elem = value_type();
315  return elem+1;
316  }
317 
318  major_iterator clear_range(major_iterator start, major_iterator end) {
319  std::fill(start,end,value_type());
320  return end;
321  }
322 
323  void reserve(size_type non_zeros) {}
324  void reserve_row(std::size_t, std::size_t){}
325  void reserve_column(std::size_t, std::size_t){}
326 
327  // Serialization
328  template<class Archive>
329  void serialize(Archive& ar, const unsigned int /* file_version */) {
330 
331  // we need to copy to a collection_size_type to get a portable
332  // and efficient boost::serialization
333  boost::serialization::collection_size_type s1(m_size1);
334  boost::serialization::collection_size_type s2(m_size2);
335 
336  // serialize the sizes
337  ar& boost::serialization::make_nvp("size1",s1)
338  & boost::serialization::make_nvp("size2",s2);
339 
340  // copy the values back if loading
341  if (Archive::is_loading::value) {
342  m_size1 = s1;
343  m_size2 = s2;
344  }
345  ar& boost::serialization::make_nvp("data",m_data);
346  }
347 
348 private:
349  size_type stride1() const {
350  return orientation::stride1(m_size1, m_size2);
351  }
352  size_type stride2() const {
353  return orientation::stride2(m_size1, m_size2);
354  }
355 
356  size_type m_size1;
357  size_type m_size2;
358  array_type m_data;
359 };
360 template<class T, class L>
361 struct matrix_temporary_type<T,L,dense_tag, cpu_tag>{
362  typedef matrix<T,L> type;
363 };
364 
365 template<class T>
366 struct matrix_temporary_type<T,unknown_orientation,dense_tag, cpu_tag>{
367  typedef matrix<T,row_major> type;
368 };
369 
370 }
371 
372 #endif