dense.hpp
Go to the documentation of this file.
1/*!
2 * \brief Dense Matrix and Vector classes
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_DENSE_HPP
29#define REMORA_CPU_DENSE_HPP
30
31#include "iterator.hpp"
32#include "../detail/proxy_optimizers_fwd.hpp"
33#include "../assignment.hpp"
34
35
36#include <initializer_list>
37#include <boost/serialization/collection_size_type.hpp>
38#include <boost/serialization/array.hpp>
39#include <boost/serialization/nvp.hpp>
40#include <boost/serialization/vector.hpp>
41
42namespace remora{
43
44/// \brief Represents a given chunk of memory as a dense vector of elements of type T.
45///
46/// This adaptor is read/write if T is non-const and read-only if T is const.
47template<class T, class Tag>
48class dense_vector_adaptor<T, Tag, cpu_tag>: public vector_expression<dense_vector_adaptor<T, Tag, cpu_tag>, cpu_tag > {
49public:
50
51 typedef std::size_t size_type;
52 typedef typename std::remove_const<T>::type value_type;
53 typedef value_type const& const_reference;
54 typedef T& reference;
55
56 typedef dense_vector_adaptor<T const, Tag, cpu_tag> const_closure_type;
57 typedef dense_vector_adaptor closure_type;
58 typedef dense_vector_storage<T, Tag> storage_type;
59 typedef dense_vector_storage<value_type const, Tag> const_storage_type;
60 typedef elementwise<dense_tag> evaluation_category;
61
62 // Construction and destruction
63
64 /// \brief Constructor of a vector proxy from a vector
65 ///
66 /// Be aware that the expression must live longer than the proxy!
67 /// \param expression The Expression from which to construct the Proxy
68 dense_vector_adaptor(vector<value_type, cpu_tag> const& expression)
69 : m_values(expression.raw_storage().values)
70 , m_size(expression.size())
71 , m_stride(expression.raw_storage().stride){}
72
73 /// \brief Constructor of a vector proxy from a vector
74 ///
75 /// Be aware that the expression must live longer than the proxy!
76 /// \param expression The Expression from which to construct the Proxy
77 dense_vector_adaptor(vector<value_type, cpu_tag>& expression)
78 : m_values(expression.raw_storage().values)
79 , m_size(expression.size())
80 , m_stride(expression.raw_storage().stride){}
81
82 /// \brief Constructor of a vector proxy from a block of memory
83 /// \param values the block of memory used
84 /// \param size size of the vector
85 /// \param stride distance between elements of the vector in memory
86 dense_vector_adaptor(T* values, size_type size, size_type stride = 1 ):
87 m_values(values),m_size(size),m_stride(stride){}
88
89
90 dense_vector_adaptor(storage_type const& storage, no_queue, size_type size):
91 m_values(storage.values),m_size(size),m_stride(storage.stride){}
92
93
94 /// \brief Copy-constructor of a vector
95 /// \param v is the proxy to be copied
96 template<class U, class Tag2>
97 dense_vector_adaptor(dense_vector_adaptor<U, Tag2> const& v)
98 : m_values(v.raw_storage().values)
99 , m_size(v.size())
100 , m_stride(v.raw_storage().stride){
101 static_assert(std::is_convertible<Tag2,Tag>::value, "Can not convert storage type of argument to the given Tag");
102 }
103
104 dense_vector_adaptor& operator = (dense_vector_adaptor const& e) {
105 return assign(*this, typename vector_temporary<dense_vector_adaptor>::type(e));
106 }
107 template<class E>
108 dense_vector_adaptor& operator = (vector_expression<E, cpu_tag> const& e) {
109 return assign(*this, typename vector_temporary<E>::type(e));
110 }
111
112 /// \brief Return the size of the vector.
113 size_type size() const {
114 return m_size;
115 }
116
117 ///\brief Returns the underlying storage structure for low level access
118 storage_type raw_storage() const{
119 return {m_values,m_stride};
120 }
121
122 typename device_traits<cpu_tag>::queue_type& queue() const{
123 return device_traits<cpu_tag>::default_queue();
124 }
125 // --------------
126 // Element access
127 // --------------
128
129 /// \brief Return a const reference to the element \f$i\f$
130 /// \param i index of the element
131 const_reference operator()(size_type i) const {
132 return m_values[i*m_stride];
133 }
134
135 /// \brief Return a reference to the element \f$i\f$
136 /// \param i index of the element
137 reference operator()(size_type i) {
138 return m_values[i*m_stride];
139 }
140
141 /// \brief Return a const reference to the element \f$i\f$
142 /// \param i index of the element
143 const_reference operator[](size_type i) const {
144 return m_values[i*m_stride];
145 }
146
147 /// \brief Return a reference to the element \f$i\f$
148 /// \param i index of the element
149 reference operator[](size_type i) {
150 return m_values[i*m_stride];
151 }
152
153 void clear(){
154 std::fill(begin(), end(), value_type/*zero*/());
155 }
156
157 // --------------
158 // ITERATORS
159 // --------------
160
161 typedef iterators::dense_storage_iterator<T> iterator;
162 typedef iterators::dense_storage_iterator<value_type const> const_iterator;
163
164 /// \brief return an iterator on the first element of the vector
165 const_iterator begin() const {
166 return const_iterator(m_values, 0, m_stride);
167 }
168
169 /// \brief return an iterator after the last element of the vector
170 const_iterator end() const {
171 return const_iterator(m_values + size() * m_stride, size(), m_stride);
172 }
173
174 /// \brief Return an iterator on the first element of the vector
175 iterator begin(){
176 return iterator(m_values, 0, m_stride);
177 }
178
179 /// \brief Return an iterator at the end of the vector
180 iterator end(){
181 return iterator(m_values + size() * m_stride, size(), m_stride);
182 }
183
184private:
185 dense_vector_adaptor(vector<value_type, cpu_tag>&& expression); // no construction from temporaries
186 T* m_values;
187 size_type m_size;
188 size_type m_stride;
189};
190
191
192template<class T,class Orientation, class Tag>
193class dense_matrix_adaptor<T,Orientation,Tag, cpu_tag>: public matrix_expression<dense_matrix_adaptor<T,Orientation, Tag, cpu_tag>, cpu_tag > {
194public:
195 typedef std::size_t size_type;
196 typedef typename std::remove_const<T>::type value_type;
197 typedef value_type result_type;
198 typedef value_type const& const_reference;
199 typedef T& reference;
200
201 typedef dense_matrix_adaptor<T,Orientation, Tag, cpu_tag> closure_type;
202 typedef dense_matrix_adaptor<value_type const,Orientation, Tag, cpu_tag> const_closure_type;
203 typedef dense_matrix_storage<T,Tag> storage_type;
204 typedef dense_matrix_storage<value_type const,Tag> const_storage_type;
205 typedef Orientation orientation;
206 typedef elementwise<dense_tag> evaluation_category;
207
208 template<class,class,class,class> friend class dense_matrix_adaptor;
209
210 // Construction and destruction
211 template<class U, class TagU>
212 dense_matrix_adaptor(dense_matrix_adaptor<U, Orientation, TagU, cpu_tag> const& expression)
213 : m_values(expression.m_values)
214 , m_size1(expression.size1())
215 , m_size2(expression.size2())
216 , m_leading_dimension(expression.m_leading_dimension)
217 {static_assert(std::is_convertible<TagU,Tag>::value, "Can not convert storage type of argument to the given Tag");}
218
219 dense_matrix_adaptor(storage_type const& storage, no_queue, std::size_t size1, std::size_t size2)
220 : m_values(storage.values)
221 , m_size1(size1)
222 , m_size2(size2)
223 , m_leading_dimension(storage.leading_dimension){}
224
225 /// \brief Constructor of a vector proxy from a Dense matrix
226 ///
227 /// Be aware that the expression must live longer than the proxy!
228 /// \param expression Expression from which to construct the Proxy
229 dense_matrix_adaptor(matrix<value_type, Orientation, cpu_tag> const& expression)
230 : m_size1(expression.size1())
231 , m_size2(expression.size2())
232 {
233 auto storage = expression.raw_storage();
234 m_values = storage.values;
235 m_leading_dimension = storage.leading_dimension;
236 }
237
238 /// \brief Constructor of a vector proxy from a Dense matrix
239 ///
240 /// Be aware that the expression must live longer than the proxy!
241 /// \param expression Expression from which to construct the Proxy
242 dense_matrix_adaptor(matrix<value_type, Orientation, cpu_tag>& expression)
243 : m_size1(expression.size1())
244 , m_size2(expression.size2()){
245 auto storage = expression.raw_storage();
246 m_values = storage.values;
247 m_leading_dimension = storage.leading_dimension;
248 }
249
250 /// \brief Constructor of a vector proxy from a block of memory
251 /// \param values the block of memory used
252 /// \param size1 size in 1st direction
253 /// \param size2 size in 2nd direction
254 /// \param leading_dimension distance between two elements in the "slow" direction.
255 dense_matrix_adaptor(
256 T* values,
257 size_type size1, size_type size2,
258 size_type leading_dimension = 0
259 )
260 : m_values(values)
261 , m_size1(size1)
262 , m_size2(size2)
263 , m_leading_dimension(leading_dimension)
264 {
265 if(!m_leading_dimension)
266 m_leading_dimension = orientation::index_m(m_size1,m_size2);
267 }
268
269 // ---------
270 // Dense low level interface
271 // ---------
272
273 /// \brief Return the number of rows of the matrix
274 size_type size1() const {
275 return m_size1;
276 }
277 /// \brief Return the number of columns of the matrix
278 size_type size2() const {
279 return m_size2;
280 }
281
282 ///\brief Returns the underlying storage structure for low level access
283 storage_type raw_storage()const{
284 return {m_values, m_leading_dimension};
285 }
286
287 typename device_traits<cpu_tag>::queue_type& queue()const{
288 return device_traits<cpu_tag>::default_queue();
289 }
290
291 // ---------
292 // High level interface
293 // ---------
294
295 // -------
296 // ASSIGNING
297 // -------
298
299 dense_matrix_adaptor& operator = (dense_matrix_adaptor const& e) {
300 REMORA_SIZE_CHECK(size1() == e.size1());
301 REMORA_SIZE_CHECK(size2() == e.size2());
302 return assign(*this, typename matrix_temporary<dense_matrix_adaptor>::type(e));
303 }
304 template<class E>
305 dense_matrix_adaptor& operator = (matrix_expression<E, cpu_tag> const& e) {
306 REMORA_SIZE_CHECK(size1() == e().size1());
307 REMORA_SIZE_CHECK(size2() == e().size2());
308 return assign(*this, typename matrix_temporary<dense_matrix_adaptor>::type(e));
309 }
310 template<class E>
311 dense_matrix_adaptor& operator = (vector_set_expression<E, cpu_tag> const& e) {
312 REMORA_SIZE_CHECK(size1() == typename E::point_orientation::index_M(e().size(), e().point_size()));
313 REMORA_SIZE_CHECK(size2() == typename E::point_orientation::index_M(e().size(), e().point_size()));
314 return assign(*this, typename matrix_temporary<dense_matrix_adaptor>::type(e));
315 }
316
317 // --------------
318 // Element access
319 // --------------
320
321 reference operator() (size_type i, size_type j) const {
322 REMORA_SIZE_CHECK( i < m_size1);
323 REMORA_SIZE_CHECK( j < m_size2);
324 return m_values[orientation::element(i, j, m_leading_dimension)];
325 }
326 void set_element(size_type i, size_type j,value_type t){
327 REMORA_SIZE_CHECK( i < m_size1);
328 REMORA_SIZE_CHECK( j < m_size2);
329 return m_values[orientation::element(i, j, m_leading_dimension)];
330 }
331
332 // --------------
333 // ITERATORS
334 // --------------
335
336 typedef iterators::dense_storage_iterator<T> major_iterator;
337 typedef iterators::dense_storage_iterator<value_type const> const_major_iterator;
338
339 const_major_iterator major_begin(size_type i) const {
340 return const_major_iterator(m_values + i * m_leading_dimension, 0, 1);
341 }
342 const_major_iterator major_end(size_type i) const {
343 return const_major_iterator(m_values + i * m_leading_dimension + minor_size(*this), minor_size(*this), 1);
344 }
345 major_iterator major_begin(size_type i){
346 return major_iterator(m_values + i * m_leading_dimension, 0, 1);
347 }
348 major_iterator major_end(size_type i){
349 return major_iterator(m_values + i * m_leading_dimension + minor_size(*this), minor_size(*this), 1);
350 }
351
352 void swap_rows(size_type i, size_type j){
353 for(std::size_t k = 0; k != size2(); ++k){
354 std::swap((*this)(i,k),(*this)(j,k));
355 }
356 }
357
358 void swap_columns(size_type i, size_type j){
359 for(std::size_t k = 0; k != size1(); ++k){
360 std::swap((*this)(k,i),(*this)(k,j));
361 }
362 }
363
364 major_iterator set_element(major_iterator pos, size_type index, value_type value) {
365 REMORA_RANGE_CHECK(index == pos.index());
366 *pos = value;
367 //return the iterator to the next element
368 return pos + 1;
369 }
370
371
372 void clear(){
373 for(size_type i = 0; i != major_size(*this); ++i){
374 for(size_type j = 0; j != minor_size(*this); ++j){
375 m_values[i * m_leading_dimension + j] = value_type();
376 }
377 }
378 }
379private:
380 dense_matrix_adaptor(matrix<value_type, Orientation, cpu_tag>&& expression); //no construction from temporary matrix
381 T* m_values;
382 size_type m_size1;
383 size_type m_size2;
384 size_type m_leading_dimension;
385};
386
387
388/** \brief A dense matrix of values of type \c T.
389 *
390 * 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
391 * 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
392 * the container for column major orientation. In a dense matrix all elements are represented in memory in a
393 * contiguous chunk of memory by definition.
394 *
395 * Orientation can also be specified, otherwise a \c major_major is used.
396 *
397 * \tparam T the type of object stored in the matrix (like double, float, complex, etc...)
398 * \tparam L the storage organization. It can be either \c major_major or \c minor_major. Default is \c major_major
399 */
400template<class T, class L>
401class matrix<T,L,cpu_tag>:public matrix_container<matrix<T, L, cpu_tag>, cpu_tag > {
402 typedef std::vector<T> array_type;
403public:
404 typedef typename array_type::value_type value_type;
405 typedef typename array_type::const_reference const_reference;
406 typedef typename array_type::reference reference;
407 typedef typename array_type::size_type size_type;
408
409 typedef dense_matrix_adaptor<T const,L, continuous_dense_tag, cpu_tag> const_closure_type;
410 typedef dense_matrix_adaptor<T,L, continuous_dense_tag, cpu_tag> closure_type;
411 typedef dense_matrix_storage<T, continuous_dense_tag> storage_type;
412 typedef dense_matrix_storage<T const, continuous_dense_tag> const_storage_type;
413 typedef elementwise<dense_tag> evaluation_category;
414 typedef L orientation;
415
416 // Construction
417
418 /// \brief Default dense matrix constructor. Make a dense matrix of size (0,0)
419 matrix():m_size1(0), m_size2(0){}
420
421 /// \brief Constructor from a nested initializer list.
422 ///
423 /// Constructs a matrix like this: m = {{1,2},{3,4}}.
424 /// \param list The nested initializer list storing the values of the matrix.
425 matrix(std::initializer_list<std::initializer_list<T> > list)
426 : m_size1(list.size())
427 , m_size2(list.begin()->size())
428 , m_data(m_size1*m_size2){
429 auto pos = list.begin();
430 for(std::size_t i = 0; i != list.size(); ++i,++pos){
431 REMORA_SIZE_CHECK(pos->size() == m_size2);
432 std::copy(pos->begin(),pos->end(),major_begin(i));
433 }
434 }
435
436 /// \brief Dense matrix constructor with defined size
437 /// \param size1 number of rows
438 /// \param size2 number of columns
439 matrix(size_type size1, size_type size2)
440 :m_size1(size1)
441 , m_size2(size2)
442 , m_data(size1 * size2) {}
443
444 /// \brief Dense matrix constructor with defined size a initial value for all the matrix elements
445 /// \param size1 number of rows
446 /// \param size2 number of columns
447 /// \param init initial value assigned to all elements
448 matrix(size_type size1, size_type size2, value_type const& init)
449 : m_size1(size1)
450 , m_size2(size2)
451 , m_data(size1 * size2, init) {}
452
453 /// \brief Copy-constructor of a dense matrix
454 ///\param m is a dense matrix
455 matrix(matrix const& m) = default;
456
457 /// \brief Move-constructor of a dense matrix
458 ///\param m is a dense matrix
459 //~ matrix(matrix&& m) = default; //vc++ can not default this
460 matrix(matrix&& m):m_size1(m.m_size1), m_size2(m.m_size2), m_data(std::move(m.m_data)){}
461
462 /// \brief Constructor of a dense matrix from a matrix expression.
463 ///
464 /// Constructs the matrix by evaluating the expression and assigning the
465 /// results to the newly constructed matrix using a call to assign.
466 ///
467 /// \param e is a matrix expression
468 template<class E>
469 matrix(matrix_expression<E, cpu_tag> const& e)
470 : m_size1(e().size1())
471 , m_size2(e().size2())
472 , m_data(m_size1 * m_size2) {
473 assign(*this,e);
474 }
475
476 /// \brief Constructor of a dense matrix from a vector-set expression.
477 ///
478 /// Constructs the matrix by evaluating the expression and assigning the
479 /// results to the newly constructed matrix using a call to assign.
480 ///
481 /// \param e is a vector set expression
482 template<class E>
483 matrix(vector_set_expression<E, cpu_tag> const& e)
484 : m_size1(E::point_orientation::index_M(e().size(), e().point_size()))
485 , m_size2(E::point_orientation::index_m(e().size(), e().point_size()))
486 , m_data(m_size1 * m_size2) {
487 assign(*this,e().expression());
488 }
489
490 // Assignment
491
492 /// \brief Assigns m to this
493 matrix& operator = (matrix const& m) = default;
494
495 /// \brief Move-Assigns m to this
496 //~ matrix& operator = (matrix&& m) = default;//vc++ can not default this
497 matrix& operator = (matrix&& m) {
498 m_size1 = m.m_size1;
499 m_size2 = m.m_size2;
500 m_data = std::move(m.m_data);
501 return *this;
502 }
503
504
505 /// \brief Assigns m to this
506 ///
507 /// evaluates the expression and assign the
508 /// results to this using a call to assign.
509 /// As containers are assumed to not overlap, no temporary is created
510 ///
511 /// \param m is a matrix expression
512 template<class C>
513 matrix& operator = (matrix_container<C, cpu_tag> const& m) {
514 resize(m().size1(), m().size2());
515 assign(*this, m);
516 return *this;
517 }
518 /// \brief Assigns e to this
519 ///
520 /// evaluates the expression and assign the
521 /// results to this using a call to assign.
522 /// A temporary is created to prevent aliasing.
523 ///
524 /// \param e is a matrix expression
525 template<class E>
526 matrix& operator = (matrix_expression<E, cpu_tag> const& e) {
527 matrix temporary(e);
528 swap(temporary);
529 return *this;
530 }
531
532 /// \brief Assigns e to this
533 ///
534 /// evaluates the vector-set expression and assign the
535 /// results to this using a call to assign.
536 /// A temporary is created to prevent aliasing.
537 ///
538 /// \param e is a matrix expression
539 template<class E>
540 matrix& operator = (vector_set_expression<E, cpu_tag> const& e) {
541 matrix temporary(e);
542 swap(temporary);
543 return *this;
544 }
545
546 ///\brief Returns the number of rows of the matrix.
547 size_type size1() const {
548 return m_size1;
549 }
550 ///\brief Returns the number of columns of the matrix.
551 size_type size2() const {
552 return m_size2;
553 }
554
555 ///\brief Returns the underlying storage structure for low level access
556 storage_type raw_storage(){
557 return {m_data.data(), leading_dimension()};
558 }
559
560 ///\brief Returns the underlying storage structure for low level access
561 const_storage_type raw_storage()const{
562 return {m_data.data(), leading_dimension()};
563 }
564 typename device_traits<cpu_tag>::queue_type& queue() const{
565 return device_traits<cpu_tag>::default_queue();
566 }
567
568 // ---------
569 // High level interface
570 // ---------
571
572 // Resizing
573 /// \brief Resize a matrix to new dimensions. If resizing is performed, the data is not preserved.
574 /// \param size1 the new number of rows
575 /// \param size2 the new number of colums
576 void resize(size_type size1, size_type size2) {
577 m_data.resize(size1* size2);
578 m_size1 = size1;
579 m_size2 = size2;
580 }
581
582 void clear(){
583 std::fill(m_data.begin(), m_data.end(), value_type/*zero*/());
584 }
585
586 // Element access
587 const_reference operator()(size_type i, size_type j) const {
588 REMORA_SIZE_CHECK(i < size1());
589 REMORA_SIZE_CHECK(j < size2());
590 return m_data[orientation::element(i, j, leading_dimension())];
591 }
592 reference operator()(size_type i, size_type j) {
593 REMORA_SIZE_CHECK(i < size1());
594 REMORA_SIZE_CHECK(j < size2());
595 return m_data[orientation::element(i, j, leading_dimension())];
596 }
597
598 void set_element(size_type i, size_type j,value_type t){
599 REMORA_SIZE_CHECK(i < size1());
600 REMORA_SIZE_CHECK(j < size2());
601 m_data[orientation::element(i, j, leading_dimension())] = t;
602 }
603
604 // Swapping
605 void swap(matrix& m) {
606 std::swap(m_size1, m.m_size1);
607 std::swap(m_size2, m.m_size2);
608 m_data.swap(m.m_data);
609 }
610 friend void swap(matrix& m1, matrix& m2) {
611 m1.swap(m2);
612 }
613
614 friend void swap_rows(matrix& a, size_type i, matrix& b, size_type j){
615 REMORA_SIZE_CHECK(i < a.size1());
616 REMORA_SIZE_CHECK(j < b.size1());
617 REMORA_SIZE_CHECK(a.size2() == b.size2());
618 for(std::size_t k = 0; k != a.size2(); ++k){
619 std::swap(a(i,k),b(j,k));
620 }
621 }
622
623 void swap_rows(size_type i, size_type j) {
624 if(i == j) return;
625 for(std::size_t k = 0; k != size2(); ++k){
626 std::swap((*this)(i,k),(*this)(j,k));
627 }
628 }
629
630
631 friend void swap_columns(matrix& a, size_type i, matrix& b, size_type j){
632 REMORA_SIZE_CHECK(i < a.size2());
633 REMORA_SIZE_CHECK(j < b.size2());
634 REMORA_SIZE_CHECK(a.size1() == b.size1());
635 for(std::size_t k = 0; k != a.size1(); ++k){
636 std::swap(a(k,i),b(k,j));
637 }
638 }
639
640 void swap_columns(size_type i, size_type j) {
641 if(i == j) return;
642 for(std::size_t k = 0; k != size1(); ++k){
643 std::swap((*this)(k,i),(*this)(k,j));
644 }
645 }
646
647 //Iterators
648 typedef iterators::dense_storage_iterator<T> major_iterator;
649 typedef iterators::dense_storage_iterator<value_type const> const_major_iterator;
650
651 const_major_iterator major_begin(size_type i) const {
652 return const_major_iterator(m_data.data() + i * leading_dimension(), 0, 1);
653 }
654 const_major_iterator major_end(size_type i) const {
655 return const_major_iterator(m_data.data() + i * leading_dimension() + minor_size(*this), minor_size(*this), 1);
656 }
657 major_iterator major_begin(size_type i){
658 return major_iterator(m_data.data() + i * leading_dimension(), 0, 1);
659 }
660 major_iterator major_end(size_type i){
661 return major_iterator(m_data.data() + i * leading_dimension() + minor_size(*this), minor_size(*this), 1);
662 }
663
664 major_iterator set_element(major_iterator pos, size_type index, value_type value) {
665 REMORA_RANGE_CHECK(index == pos.index());
666 *pos = value;
667 //return the iterator to the next element
668 return pos + 1;
669 }
670
671 // Serialization
672 template<class Archive>
673 void serialize(Archive& ar, const unsigned int /* file_version */) {
674
675 // we need to copy to a collection_size_type to get a portable
676 // and efficient boost::serialization
677 boost::serialization::collection_size_type s1(m_size1);
678 boost::serialization::collection_size_type s2(m_size2);
679
680 // serialize the sizes
681 ar& boost::serialization::make_nvp("size1",s1)
682 & boost::serialization::make_nvp("size2",s2);
683
684 // copy the values back if loading
685 if (Archive::is_loading::value) {
686 m_size1 = s1;
687 m_size2 = s2;
688 }
689 ar& boost::serialization::make_nvp("data",m_data);
690 }
691
692private:
693 size_type leading_dimension() const {
694 return orientation::index_m(m_size1, m_size2);
695 }
696
697 size_type m_size1;
698 size_type m_size2;
699 array_type m_data;
700};
701
702template<class T>
703class vector<T,cpu_tag>: public vector_container<vector<T, cpu_tag>, cpu_tag > {
704
705 typedef std::vector<typename std::conditional<std::is_same<T,bool>::value,char,T>::type > array_type;
706public:
707 typedef typename array_type::value_type value_type;
708 typedef typename array_type::const_reference const_reference;
709 typedef typename array_type::reference reference;
710 typedef typename array_type::size_type size_type;
711
712 typedef dense_vector_adaptor<T const, continuous_dense_tag, cpu_tag> const_closure_type;
713 typedef dense_vector_adaptor<T,continuous_dense_tag, cpu_tag> closure_type;
714 typedef dense_vector_storage<value_type, continuous_dense_tag> storage_type;
715 typedef dense_vector_storage<value_type const, continuous_dense_tag> const_storage_type;
716 typedef elementwise<dense_tag> evaluation_category;
717
718 // Construction and destruction
719
720 /// \brief Constructor of a vector
721 /// By default it is empty, i.e. \c size()==0.
722 vector() = default;
723
724 /// \brief Constructor of a vector with a predefined size
725 /// By default, its elements are initialized to 0.
726 /// \param size initial size of the vector
727 explicit vector(size_type size):m_storage(size) {}
728
729 /// \brief Constructor of a vector with a predefined size and a unique initial value
730 /// \param size of the vector
731 /// \param init value to assign to each element of the vector
732 vector(size_type size, const value_type& init):m_storage(size, init) {}
733
734 /// \brief Copy-constructor of a vector
735 /// \param v is the vector to be duplicated
736 vector(vector const& v) = default;
737
738 /// \brief Move-constructor of a vector
739 /// \param v is the vector to be moved
740 //~ vector(vector && v) = default; //vc++ can not default this. true story
741 vector(vector && v): m_storage(std::move(v.m_storage)){}
742
743 vector(std::initializer_list<T> list) : m_storage(list.begin(),list.end()){}
744
745 /// \brief Constructs the vector from a predefined range
746 template<class Iter>
747 vector(Iter begin, Iter end):m_storage(begin,end){}
748
749 /// \brief Copy-constructor of a vector from a vector_expression
750 /// \param e the vector_expression whose values will be duplicated into the vector
751 template<class E>
752 vector(vector_expression<E, cpu_tag> const& e):m_storage(e().size()) {
753 assign(*this, e);
754 }
755
756 // -------------------
757 // Assignment operators
758 // -------------------
759
760 /// \brief Assign a full vector (\e RHS-vector) to the current vector (\e LHS-vector)
761 /// Assign a full vector (\e RHS-vector) to the current vector (\e LHS-vector). This method does not create any temporary.
762 /// \param v is the source vector container
763 /// \return a reference to a vector (i.e. the destination vector)
764 vector& operator = (vector const& v) = default;
765
766 /// \brief Move-Assign a full vector (\e RHS-vector) to the current vector (\e LHS-vector)
767 /// \param v is the source vector container
768 /// \return a reference to a vector (i.e. the destination vector)
769 //~ vector& operator = (vector && v) = default; //vc++ can not default this. true story
770 vector& operator = (vector && v){
771 m_storage = std::move(v.m_storage);
772 return *this;
773 }
774
775 /// \brief Assign a full vector (\e RHS-vector) to the current vector (\e LHS-vector)
776 /// Assign a full vector (\e RHS-vector) to the current vector (\e LHS-vector). This method does not create any temporary.
777 /// \param v is the source vector container
778 /// \return a reference to a vector (i.e. the destination vector)
779 template<class C> // Container assignment without temporary
780 vector& operator = (vector_container<C, cpu_tag> const& v) {
781 resize(v().size());
782 return assign(*this, v);
783 }
784
785 /// \brief Assign the result of a vector_expression to the vector
786 /// Assign the result of a vector_expression to the vector.
787 /// \param e is a const reference to the vector_expression
788 /// \return a reference to the resulting vector
789 template<class E>
790 vector& operator = (vector_expression<E, cpu_tag> const& e) {
791 vector temporary(e);
792 swap(*this,temporary);
793 return *this;
794 }
795
796 // ---------
797 // Storage interface
798 // ---------
799
800 /// \brief Return the size of the vector.
801 size_type size() const {
802 return m_storage.size();
803 }
804
805 ///\brief Returns the underlying storage structure for low level access
806 storage_type raw_storage(){
807 return {m_storage.data(),1};
808 }
809
810 ///\brief Returns the underlying storage structure for low level access
811 const_storage_type raw_storage() const{
812 return {m_storage.data(),1};
813 }
814 typename device_traits<cpu_tag>::queue_type& queue() const{
815 return device_traits<cpu_tag>::default_queue();
816 }
817
818 // ---------
819 // High level interface
820 // ---------
821
822 /// \brief Return the maximum size of the data container.
823 /// Return the upper bound (maximum size) on the data container. Depending on the container, it can be bigger than the current size of the vector.
824 size_type max_size() const {
825 return m_storage.max_size();
826 }
827
828 /// \brief Return true if the vector is empty (\c size==0)
829 /// \return \c true if empty, \c false otherwise
830 bool empty() const {
831 return m_storage.empty();
832 }
833
834 /// \brief Resize the vector
835 /// \param size new size of the vector
836 void resize(size_type size) {
837 m_storage.resize(size);
838 }
839
840 // --------------
841 // Element access
842 // --------------
843
844 /// \brief Return a const reference to the element \f$i\f$
845 /// Return a const reference to the element \f$i\f$. With some compilers, this notation will be faster than \c operator[]
846 /// \param i index of the element
847 const_reference operator()(size_type i) const {
848 REMORA_RANGE_CHECK(i < size());
849 return m_storage[i];
850 }
851
852 /// \brief Return a reference to the element \f$i\f$
853 /// Return a reference to the element \f$i\f$. With some compilers, this notation will be faster than \c operator[]
854 /// \param i index of the element
855 reference operator()(size_type i) {
856 REMORA_RANGE_CHECK(i < size());
857 return m_storage[i];
858 }
859
860 /// \brief Return a const reference to the element \f$i\f$
861 /// \param i index of the element
862 const_reference operator [](size_type i) const {
863 REMORA_RANGE_CHECK(i < size());
864 return m_storage[i];
865 }
866
867 /// \brief Return a reference to the element \f$i\f$
868 /// \param i index of the element
869 reference operator [](size_type i) {
870 REMORA_RANGE_CHECK(i < size());
871 return m_storage[i];
872 }
873
874 ///\brief Returns the first element of the vector
875 reference front(){
876 return m_storage[0];
877 }
878 ///\brief Returns the first element of the vector
879 const_reference front()const{
880 return m_storage[0];
881 }
882 ///\brief Returns the last element of the vector
883 reference back(){
884 return m_storage[size()-1];
885 }
886 ///\brief Returns the last element of the vector
887 const_reference back()const{
888 return m_storage[size()-1];
889 }
890
891 ///\brief resizes the vector by appending a new element to the end. this invalidates storage
892 void push_back(value_type const& element){
893 m_storage.push_back(element);
894 }
895
896 /// \brief Clear the vector, i.e. set all values to the \c zero value.
897 void clear() {
898 std::fill(m_storage.begin(), m_storage.end(), value_type/*zero*/());
899 }
900
901 // Iterator types
902 typedef iterators::dense_storage_iterator<value_type> iterator;
903 typedef iterators::dense_storage_iterator<value_type const> const_iterator;
904
905 /// \brief return an iterator on the first element of the vector
906 const_iterator cbegin() const {
907 return const_iterator(m_storage.data(),0);
908 }
909
910 /// \brief return an iterator after the last element of the vector
911 const_iterator cend() const {
912 return const_iterator(m_storage.data()+size(),size());
913 }
914
915 /// \brief return an iterator on the first element of the vector
916 const_iterator begin() const {
917 return cbegin();
918 }
919
920 /// \brief return an iterator after the last element of the vector
921 const_iterator end() const {
922 return cend();
923 }
924
925 /// \brief Return an iterator on the first element of the vector
926 iterator begin(){
927 return iterator(m_storage.data(),0);
928 }
929
930 /// \brief Return an iterator at the end of the vector
931 iterator end(){
932 return iterator(m_storage.data()+size(),size());
933 }
934
935 /// \brief Swap the content of two vectors
936 /// \param v1 is the first vector. It takes values from v2
937 /// \param v2 is the second vector It takes values from v1
938 friend void swap(vector& v1, vector& v2) {
939 v1.m_storage.swap(v2.m_storage);
940 }
941 // -------------
942 // Serialization
943 // -------------
944
945 /// Serialize a vector into and archive as defined in Boost
946 /// \param ar Archive object. Can be a flat file, an XML file or any other stream
947 /// \param file_version Optional file version (not yet used)
948 template<class Archive>
949 void serialize(Archive &ar, const unsigned int file_version) {
950 boost::serialization::collection_size_type count(size());
951 ar & count;
952 if(!Archive::is_saving::value){
953 resize(count);
954 }
955 if (!empty())
956 ar & boost::serialization::make_array(m_storage.data(),size());
957 (void) file_version;//prevent warning
958 }
959
960private:
961 array_type m_storage;
962};
963
964
965template<class T, class Orientation, bool Upper, bool Unit>
966class dense_triangular_proxy<T, Orientation, triangular_tag<Upper, Unit> , cpu_tag>
967: public matrix_expression<dense_triangular_proxy<T, Orientation, triangular_tag<Upper, Unit>, cpu_tag>, cpu_tag> {
968public:
969 typedef std::size_t size_type;
970 typedef typename std::remove_const<T>::type value_type;
971 typedef value_type result_type;
972 typedef typename std::conditional<Unit, value_type const&, T&>::type reference;
973 typedef value_type const& const_reference;
974 typedef dense_triangular_proxy<value_type const, Orientation, triangular_tag<Upper, Unit> , cpu_tag> const_closure_type;
975 typedef dense_triangular_proxy<T, Orientation, triangular_tag<Upper, Unit> , cpu_tag> closure_type;
976
977 typedef dense_matrix_storage<T, dense_tag> storage_type;
978 typedef dense_matrix_storage<value_type const, dense_tag> const_storage_type;
979
980 typedef elementwise<dense_tag> evaluation_category;
981 typedef triangular<Orientation,triangular_tag<Upper, Unit> > orientation;
982
983
984 template<class U>
985 dense_triangular_proxy(dense_triangular_proxy<U, Orientation, triangular_tag<Upper, Unit>, cpu_tag> const& expression)
986 : m_values(expression.raw_storage().values)
987 , m_size1(expression.size1())
988 , m_size2(expression.size2())
989 , m_leading_dimension(expression.raw_storage().leading_dimension){}
990
991 /// \brief Constructor of a vector proxy from a Dense matrix
992 ///
993 /// Be aware that the expression must live longer than the proxy!
994 /// \param expression Expression from which to construct the Proxy
995 dense_triangular_proxy(storage_type const& storage, no_queue, std::size_t size1, std::size_t size2)
996 : m_values(storage.values)
997 , m_size1(size1)
998 , m_size2(size2)
999 , m_leading_dimension(storage.leading_dimension){}
1000
1001 dense_matrix_adaptor<T, Orientation, dense_tag, cpu_tag> to_dense() const{
1002 return {raw_storage(), queue(), m_size1, m_size2};
1003 }
1004
1005
1006 /// \brief Return the number of rows of the matrix
1007 size_type size1() const {
1008 return m_size1;
1009 }
1010 /// \brief Return the number of columns of the matrix
1011 size_type size2() const {
1012 return m_size2;
1013 }
1014
1015 ///\brief Returns the underlying storage structure for low level access
1016 storage_type raw_storage() const{
1017 return {m_values, m_leading_dimension};
1018 }
1019
1020 typename device_traits<cpu_tag>::queue_type& queue()const{
1021 return device_traits<cpu_tag>::default_queue();
1022 }
1023
1024 typedef iterators::dense_storage_iterator<value_type> major_iterator;
1025 typedef iterators::dense_storage_iterator<value_type const> const_major_iterator;
1026
1027 const_major_iterator major_begin(size_type i) const {
1028 std::size_t start = Upper? i + Unit: 0;
1029 return const_major_iterator(m_values + orientation::element(i,start, m_leading_dimension),start, 1);
1030 }
1031 const_major_iterator major_end(size_type i) const {
1032 std::size_t end = Upper? m_size2: i +1 - Unit;
1033 return const_major_iterator(m_values + orientation::element(i,end, m_leading_dimension),end, 1);
1034 }
1035 major_iterator major_begin(size_type i){
1036 std::size_t start = Upper? i + Unit: 0;
1037 return major_iterator(m_values + orientation::element(i,start, m_leading_dimension),start, 1);
1038 }
1039 major_iterator major_end(size_type i){
1040 std::size_t end = Upper? m_size2: i + 1 - Unit;
1041 return major_iterator(m_values + orientation::element(i,end, m_leading_dimension),end, 1);
1042 }
1043
1044private:
1045 T* m_values;
1046 std::size_t m_size1;
1047 std::size_t m_size2;
1048 std::size_t m_leading_dimension;
1049};
1050
1051
1052namespace detail{
1053template<class T, class Orientation>
1054struct vector_to_matrix_optimizer<dense_vector_adaptor<T, continuous_dense_tag, cpu_tag>, Orientation >{
1055 typedef dense_matrix_adaptor<T, Orientation, continuous_dense_tag, cpu_tag> type;
1056
1057 static type create(
1058 dense_vector_adaptor<T, continuous_dense_tag, cpu_tag> const& v,
1059 std::size_t size1, std::size_t size2
1060 ){
1061 dense_matrix_storage<T, continuous_dense_tag> storage = {v.raw_storage().values, Orientation::index_m(size1,size2)};
1062 return type(storage, v.queue(), size1, size2);
1063 }
1064};
1065
1066
1067}}
1068
1069#endif