3 // Gunter Winkler, Joerg Walter
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 // The authors gratefully acknowledge the support of
10 // GeNeSys mbH & Co. KG in producing this work.
13 #ifndef _BOOST_UBLAS_VECTOR_OF_VECTOR_
14 #define _BOOST_UBLAS_VECTOR_OF_VECTOR_
16 #include <boost/type_traits.hpp>
18 #include <boost/numeric/ublas/storage_sparse.hpp>
19 #include <boost/numeric/ublas/matrix_sparse.hpp>
21 // Iterators based on ideas of Jeremy Siek
23 namespace boost { namespace numeric { namespace ublas {
25 // uBLAS sparse vector based sparse matrix class
26 // FIXME outer vector can be sparse type but it is completely filled
27 template<class T, class L, class A>
28 class generalized_vector_of_vector:
29 public matrix_container<generalized_vector_of_vector<T, L, A> > {
31 typedef T &true_reference;
33 typedef const T *const_pointer;
34 typedef L layout_type;
35 typedef generalized_vector_of_vector<T, L, A> self_type;
37 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
38 using matrix_container<self_type>::operator ();
40 typedef typename A::size_type size_type;
41 typedef typename A::difference_type difference_type;
43 typedef const T &const_reference;
44 #ifndef BOOST_UBLAS_STRICT_VECTOR_SPARSE
47 typedef sparse_matrix_element<self_type> reference;
50 typedef const matrix_reference<const self_type> const_closure_type;
51 typedef matrix_reference<self_type> closure_type;
52 typedef typename A::value_type vector_data_value_type;
53 typedef vector_data_value_type vector_temporary_type;
54 typedef self_type matrix_temporary_type;
55 typedef sparse_tag storage_category;
56 typedef typename L::orientation_category orientation_category;
58 // Construction and destruction
60 generalized_vector_of_vector ():
61 matrix_container<self_type> (),
62 size1_ (0), size2_ (0), data_ (1) {
63 const size_type sizeM = layout_type::size_M (size1_, size2_);
64 // create size1+1 empty vector elements
65 data_.insert_element (sizeM, vector_data_value_type ());
66 storage_invariants ();
69 generalized_vector_of_vector (size_type size1, size_type size2, size_type non_zeros = 0):
70 matrix_container<self_type> (),
71 size1_ (size1), size2_ (size2), data_ (layout_type::size_M (size1_, size2_) + 1) {
72 const size_type sizeM = layout_type::size_M (size1_, size2_);
73 const size_type sizem = layout_type::size_m (size1_, size2_);
74 for (size_type i = 0; i < sizeM; ++ i) // create size1 vector elements
75 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
76 data_.insert_element (sizeM, vector_data_value_type ());
77 storage_invariants ();
80 generalized_vector_of_vector (const generalized_vector_of_vector &m):
81 matrix_container<self_type> (),
82 size1_ (m.size1_), size2_ (m.size2_), data_ (m.data_) {
83 storage_invariants ();
87 generalized_vector_of_vector (const matrix_expression<AE> &ae, size_type non_zeros = 0):
88 matrix_container<self_type> (),
89 size1_ (ae ().size1 ()), size2_ (ae ().size2 ()), data_ (layout_type::size_M (size1_, size2_) + 1) {
90 const size_type sizeM = layout_type::size_M (size1_, size2_);
91 const size_type sizem = layout_type::size_m (size1_, size2_);
92 for (size_type i = 0; i < sizeM; ++ i) // create size1 vector elements
93 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
94 data_.insert_element (sizeM, vector_data_value_type ());
95 storage_invariants ();
96 matrix_assign<scalar_assign> (*this, ae);
101 size_type size1 () const {
105 size_type size2 () const {
109 size_type nnz_capacity () const {
110 size_type non_zeros = 0;
111 for (const_vectoriterator_type itv = data_.begin (); itv != data_.end (); ++ itv)
112 non_zeros += (*itv).nnz_capacity ();
116 size_type nnz () const {
117 size_type non_zeros = 0;
118 for (const_vectoriterator_type itv = data_.begin (); itv != data_.end (); ++ itv)
119 non_zeros += (*itv).nnz ();
125 const array_type &data () const {
129 array_type &data () {
135 void resize (size_type size1, size_type size2, bool preserve = true) {
136 const size_type oldM = layout_type::size_M (size1_, size2_);
139 const size_type sizeM = layout_type::size_M (size1_, size2_);
140 const size_type sizem = layout_type::size_m (size1_, size2_);
141 data ().resize (sizeM + 1, preserve);
143 for (size_type i = 0; (i <= oldM) && (i < sizeM); ++ i)
144 ref (data () [i]).resize (sizem, preserve);
145 for (size_type i = oldM+1; i < sizeM; ++ i) // create new vector elements
146 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
148 data_.insert_element (sizeM, vector_data_value_type ());
150 ref (data () [sizeM]).resize (0, false);
153 for (size_type i = 0; i < sizeM; ++ i)
154 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
155 data_.insert_element (sizeM, vector_data_value_type ());
157 storage_invariants ();
162 pointer find_element (size_type i, size_type j) {
163 return const_cast<pointer> (const_cast<const self_type&>(*this).find_element (i, j));
166 const_pointer find_element (size_type i, size_type j) const {
167 const size_type elementM = layout_type::index_M (i, j);
168 const size_type elementm = layout_type::index_m (i, j);
169 // optimise: check the storage_type and index directly if element always exists
170 if (boost::is_convertible<typename array_type::storage_category, packed_tag>::value) {
171 return & (data () [elementM] [elementm]);
174 const typename array_type::value_type *pv = data ().find_element (elementM);
177 return pv->find_element (elementm);
183 const_reference operator () (size_type i, size_type j) const {
184 const_pointer p = find_element (i, j);
185 // optimise: check the storage_type and index directly if element always exists
186 if (boost::is_convertible<typename array_type::storage_category, packed_tag>::value) {
187 BOOST_UBLAS_CHECK (p, internal_logic () );
198 reference operator () (size_type i, size_type j) {
199 #ifndef BOOST_UBLAS_STRICT_MATRIX_SPARSE
200 return at_element (i, j);
202 return reference (*this, i, j);
208 generalized_vector_of_vector &operator = (const generalized_vector_of_vector &m) {
214 storage_invariants ();
218 generalized_vector_of_vector &assign_temporary (generalized_vector_of_vector &m) {
224 generalized_vector_of_vector &operator = (const matrix_expression<AE> &ae) {
225 self_type temporary (ae);
226 return assign_temporary (temporary);
230 generalized_vector_of_vector &assign (const matrix_expression<AE> &ae) {
231 matrix_assign<scalar_assign> (*this, ae);
236 generalized_vector_of_vector& operator += (const matrix_expression<AE> &ae) {
237 self_type temporary (*this + ae);
238 return assign_temporary (temporary);
242 generalized_vector_of_vector &plus_assign (const matrix_expression<AE> &ae) {
243 matrix_assign<scalar_plus_assign> (*this, ae);
248 generalized_vector_of_vector& operator -= (const matrix_expression<AE> &ae) {
249 self_type temporary (*this - ae);
250 return assign_temporary (temporary);
254 generalized_vector_of_vector &minus_assign (const matrix_expression<AE> &ae) {
255 matrix_assign<scalar_minus_assign> (*this, ae);
260 generalized_vector_of_vector& operator *= (const AT &at) {
261 matrix_assign_scalar<scalar_multiplies_assign> (*this, at);
266 generalized_vector_of_vector& operator /= (const AT &at) {
267 matrix_assign_scalar<scalar_divides_assign> (*this, at);
273 void swap (generalized_vector_of_vector &m) {
275 std::swap (size1_, m.size1_);
276 std::swap (size2_, m.size2_);
277 data ().swap (m.data ());
279 storage_invariants ();
282 friend void swap (generalized_vector_of_vector &m1, generalized_vector_of_vector &m2) {
288 vectoriterator_type itv (data ().begin ());
289 vectoriterator_type itv_end (data ().end ());
290 while (itv != itv_end) {
296 // Element insertion and erasure
298 true_reference insert_element (size_type i, size_type j, const_reference t) {
299 const size_type elementM = layout_type::index_M (i, j);
300 const size_type elementm = layout_type::index_m (i, j);
301 vector_data_value_type& vd (ref (data () [elementM]));
302 storage_invariants ();
303 return vd.insert_element (elementm, t);
306 void append_element (size_type i, size_type j, const_reference t) {
307 const size_type elementM = layout_type::index_M (i, j);
308 const size_type elementm = layout_type::index_m (i, j);
309 vector_data_value_type& vd (ref (data () [elementM]));
310 storage_invariants ();
311 return vd.append_element (elementm, t);
314 void erase_element (size_type i, size_type j) {
315 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
316 if (itv == data ().end ())
318 (*itv).erase_element (layout_type::index_m (i, j));
319 storage_invariants ();
323 const size_type sizeM = layout_type::size_M (size1_, size2_);
324 // FIXME should clear data () if this is done via value_type/*zero*/() then it is not size preserving
325 for (size_type i = 0; i < sizeM; ++ i)
326 ref (data () [i]).clear ();
327 storage_invariants ();
332 // Use vector iterator
333 typedef typename A::const_iterator const_vectoriterator_type;
334 typedef typename A::iterator vectoriterator_type;
335 typedef typename A::value_type::const_iterator const_subiterator_type;
336 typedef typename A::value_type::iterator subiterator_type;
339 true_reference at_element (size_type i, size_type j) {
340 return ref (ref (data () [layout_type::index_M (i, j)]) [layout_type::index_m (i, j)]);
344 class const_iterator1;
346 class const_iterator2;
348 typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
349 typedef reverse_iterator_base1<iterator1> reverse_iterator1;
350 typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
351 typedef reverse_iterator_base2<iterator2> reverse_iterator2;
354 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
355 const_iterator1 find1 (int rank, size_type i, size_type j, int direction = 1) const {
357 const_vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
358 const_vectoriterator_type itv_end (data ().end ());
360 return const_iterator1 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
362 const_subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
363 const_subiterator_type it_end ((*itv).end ());
365 return const_iterator1 (*this, rank, i, j, itv, it);
366 if (it != it_end && it.index () == layout_type::index_m (i, j))
367 return const_iterator1 (*this, rank, i, j, itv, it);
369 if (layout_type::fast_i ()) {
371 return const_iterator1 (*this, rank, i, j, itv, it);
375 return const_iterator1 (*this, rank, i, j, itv, it);
378 } else /* if (direction < 0) */ {
379 if (layout_type::fast_i ()) {
380 if (it == (*itv).begin ())
381 return const_iterator1 (*this, rank, i, j, itv, it);
386 return const_iterator1 (*this, rank, i, j, itv, it);
392 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
393 iterator1 find1 (int rank, size_type i, size_type j, int direction = 1) {
395 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
396 vectoriterator_type itv_end (data ().end ());
398 return iterator1 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
400 subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
401 subiterator_type it_end ((*itv).end ());
403 return iterator1 (*this, rank, i, j, itv, it);
404 if (it != it_end && it.index () == layout_type::index_m (i, j))
405 return iterator1 (*this, rank, i, j, itv, it);
407 if (layout_type::fast_i ()) {
409 return iterator1 (*this, rank, i, j, itv, it);
413 return iterator1 (*this, rank, i, j, itv, it);
416 } else /* if (direction < 0) */ {
417 if (layout_type::fast_i ()) {
418 if (it == (*itv).begin ())
419 return iterator1 (*this, rank, i, j, itv, it);
424 return iterator1 (*this, rank, i, j, itv, it);
430 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
431 const_iterator2 find2 (int rank, size_type i, size_type j, int direction = 1) const {
433 const_vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
434 const_vectoriterator_type itv_end (data ().end ());
436 return const_iterator2 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
438 const_subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
439 const_subiterator_type it_end ((*itv).end ());
441 return const_iterator2 (*this, rank, i, j, itv, it);
442 if (it != it_end && it.index () == layout_type::index_m (i, j))
443 return const_iterator2 (*this, rank, i, j, itv, it);
445 if (layout_type::fast_j ()) {
447 return const_iterator2 (*this, rank, i, j, itv, it);
451 return const_iterator2 (*this, rank, i, j, itv, it);
454 } else /* if (direction < 0) */ {
455 if (layout_type::fast_j ()) {
456 if (it == (*itv).begin ())
457 return const_iterator2 (*this, rank, i, j, itv, it);
462 return const_iterator2 (*this, rank, i, j, itv, it);
468 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
469 iterator2 find2 (int rank, size_type i, size_type j, int direction = 1) {
471 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
472 vectoriterator_type itv_end (data ().end ());
474 return iterator2 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
476 subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
477 subiterator_type it_end ((*itv).end ());
479 return iterator2 (*this, rank, i, j, itv, it);
480 if (it != it_end && it.index () == layout_type::index_m (i, j))
481 return iterator2 (*this, rank, i, j, itv, it);
483 if (layout_type::fast_j ()) {
485 return iterator2 (*this, rank, i, j, itv, it);
489 return iterator2 (*this, rank, i, j, itv, it);
492 } else /* if (direction < 0) */ {
493 if (layout_type::fast_j ()) {
494 if (it == (*itv).begin ())
495 return iterator2 (*this, rank, i, j, itv, it);
500 return iterator2 (*this, rank, i, j, itv, it);
508 class const_iterator1:
509 public container_const_reference<generalized_vector_of_vector>,
510 public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
511 const_iterator1, value_type> {
513 typedef typename generalized_vector_of_vector::difference_type difference_type;
514 typedef typename generalized_vector_of_vector::value_type value_type;
515 typedef typename generalized_vector_of_vector::const_reference reference;
516 typedef const typename generalized_vector_of_vector::pointer pointer;
518 typedef const_iterator2 dual_iterator_type;
519 typedef const_reverse_iterator2 dual_reverse_iterator_type;
521 // Construction and destruction
524 container_const_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
526 const_iterator1 (const self_type &m, int rank, size_type i, size_type j, const const_vectoriterator_type &itv, const const_subiterator_type &it):
527 container_const_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
529 const_iterator1 (const iterator1 &it):
530 container_const_reference<self_type> (it ()), rank_ (it.rank_), i_ (it.i_), j_ (it.j_), itv_ (it.itv_), it_ (it.it_) {}
534 const_iterator1 &operator ++ () {
535 if (rank_ == 1 && layout_type::fast_i ())
538 const self_type &m = (*this) ();
540 if (rank_ == 1 && ++ itv_ == m.end1 ().itv_)
541 *this = m.find1 (rank_, i_, j_, 1);
542 else if (rank_ == 1) {
543 it_ = (*itv_).begin ();
544 if (it_ == (*itv_).end () || index2 () != j_)
545 *this = m.find1 (rank_, i_, j_, 1);
551 const_iterator1 &operator -- () {
552 if (rank_ == 1 && layout_type::fast_i ())
555 const self_type &m = (*this) ();
557 if (rank_ == 1 && -- itv_ == m.end1 ().itv_)
558 *this = m.find1 (rank_, i_, j_, -1);
559 else if (rank_ == 1) {
560 it_ = (*itv_).begin ();
561 if (it_ == (*itv_).end () || index2 () != j_)
562 *this = m.find1 (rank_, i_, j_, -1);
570 const_reference operator * () const {
571 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
572 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
576 return (*this) () (i_, j_);
580 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
582 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
585 const_iterator2 begin () const {
586 const self_type &m = (*this) ();
587 return m.find2 (1, index1 (), 0);
590 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
593 const_iterator2 cbegin () const {
597 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
600 const_iterator2 end () const {
601 const self_type &m = (*this) ();
602 return m.find2 (1, index1 (), m.size2 ());
605 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
608 const_iterator2 cend () const {
613 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
616 const_reverse_iterator2 rbegin () const {
617 return const_reverse_iterator2 (end ());
620 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
623 const_reverse_iterator2 crbegin () const {
627 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
630 const_reverse_iterator2 rend () const {
631 return const_reverse_iterator2 (begin ());
634 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
637 const_reverse_iterator2 crend () const {
644 size_type index1 () const {
645 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
647 BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
648 return layout_type::index_M (itv_.index (), it_.index ());
654 size_type index2 () const {
655 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
657 BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
658 return layout_type::index_m (itv_.index (), it_.index ());
666 const_iterator1 &operator = (const const_iterator1 &it) {
667 container_const_reference<self_type>::assign (&it ());
678 bool operator == (const const_iterator1 &it) const {
679 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
680 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
681 if (rank_ == 1 || it.rank_ == 1) {
682 return it_ == it.it_;
684 return i_ == it.i_ && j_ == it.j_;
692 const_vectoriterator_type itv_;
693 const_subiterator_type it_;
697 const_iterator1 begin1 () const {
698 return find1 (0, 0, 0);
701 const_iterator1 cbegin1 () const {
705 const_iterator1 end1 () const {
706 return find1 (0, size1_, 0);
709 const_iterator1 cend1 () const {
714 public container_reference<generalized_vector_of_vector>,
715 public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
716 iterator1, value_type> {
718 typedef typename generalized_vector_of_vector::difference_type difference_type;
719 typedef typename generalized_vector_of_vector::value_type value_type;
720 typedef typename generalized_vector_of_vector::true_reference reference;
721 typedef typename generalized_vector_of_vector::pointer pointer;
723 typedef iterator2 dual_iterator_type;
724 typedef reverse_iterator2 dual_reverse_iterator_type;
726 // Construction and destruction
729 container_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
731 iterator1 (self_type &m, int rank, size_type i, size_type j, const vectoriterator_type &itv, const subiterator_type &it):
732 container_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
736 iterator1 &operator ++ () {
737 if (rank_ == 1 && layout_type::fast_i ())
740 self_type &m = (*this) ();
742 if (rank_ == 1 && ++ itv_ == m.end1 ().itv_)
743 *this = m.find1 (rank_, i_, j_, 1);
744 else if (rank_ == 1) {
745 it_ = (*itv_).begin ();
746 if (it_ == (*itv_).end () || index2 () != j_)
747 *this = m.find1 (rank_, i_, j_, 1);
753 iterator1 &operator -- () {
754 if (rank_ == 1 && layout_type::fast_i ())
757 self_type &m = (*this) ();
759 if (rank_ == 1 && -- itv_ == m.end1 ().itv_)
760 *this = m.find1 (rank_, i_, j_, -1);
761 else if (rank_ == 1) {
762 it_ = (*itv_).begin ();
763 if (it_ == (*itv_).end () || index2 () != j_)
764 *this = m.find1 (rank_, i_, j_, -1);
772 true_reference operator * () const {
773 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
774 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
778 return (*this) ().at_element (i_, j_);
782 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
784 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
787 iterator2 begin () const {
788 self_type &m = (*this) ();
789 return m.find2 (1, index1 (), 0);
792 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
795 iterator2 end () const {
796 self_type &m = (*this) ();
797 return m.find2 (1, index1 (), m.size2 ());
800 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
803 reverse_iterator2 rbegin () const {
804 return reverse_iterator2 (end ());
807 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
810 reverse_iterator2 rend () const {
811 return reverse_iterator2 (begin ());
817 size_type index1 () const {
818 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
820 BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
821 return layout_type::index_M (itv_.index (), it_.index ());
827 size_type index2 () const {
828 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
830 BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
831 return layout_type::index_m (itv_.index (), it_.index ());
839 iterator1 &operator = (const iterator1 &it) {
840 container_reference<self_type>::assign (&it ());
851 bool operator == (const iterator1 &it) const {
852 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
853 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
854 if (rank_ == 1 || it.rank_ == 1) {
855 return it_ == it.it_;
857 return i_ == it.i_ && j_ == it.j_;
865 vectoriterator_type itv_;
866 subiterator_type it_;
868 friend class const_iterator1;
872 iterator1 begin1 () {
873 return find1 (0, 0, 0);
877 return find1 (0, size1_, 0);
880 class const_iterator2:
881 public container_const_reference<generalized_vector_of_vector>,
882 public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
883 const_iterator2, value_type> {
885 typedef typename generalized_vector_of_vector::difference_type difference_type;
886 typedef typename generalized_vector_of_vector::value_type value_type;
887 typedef typename generalized_vector_of_vector::const_reference reference;
888 typedef const typename generalized_vector_of_vector::pointer pointer;
890 typedef const_iterator1 dual_iterator_type;
891 typedef const_reverse_iterator1 dual_reverse_iterator_type;
893 // Construction and destruction
896 container_const_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
898 const_iterator2 (const self_type &m, int rank, size_type i, size_type j, const const_vectoriterator_type &itv, const const_subiterator_type &it):
899 container_const_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
901 const_iterator2 (const iterator2 &it):
902 container_const_reference<self_type> (it ()), rank_ (it.rank_), i_ (it.i_), j_ (it.j_), itv_ (it.itv_), it_ (it.it_) {}
906 const_iterator2 &operator ++ () {
907 if (rank_ == 1 && layout_type::fast_j ())
910 const self_type &m = (*this) ();
912 if (rank_ == 1 && ++ itv_ == m.end2 ().itv_)
913 *this = m.find2 (rank_, i_, j_, 1);
914 else if (rank_ == 1) {
915 it_ = (*itv_).begin ();
916 if (it_ == (*itv_).end () || index1 () != i_)
917 *this = m.find2 (rank_, i_, j_, 1);
923 const_iterator2 &operator -- () {
924 if (rank_ == 1 && layout_type::fast_j ())
927 const self_type &m = (*this) ();
929 if (rank_ == 1 && -- itv_ == m.end2 ().itv_)
930 *this = m.find2 (rank_, i_, j_, -1);
931 else if (rank_ == 1) {
932 it_ = (*itv_).begin ();
933 if (it_ == (*itv_).end () || index1 () != i_)
934 *this = m.find2 (rank_, i_, j_, -1);
942 const_reference operator * () const {
943 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
944 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
948 return (*this) () (i_, j_);
952 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
954 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
957 const_iterator1 begin () const {
958 const self_type &m = (*this) ();
959 return m.find1 (1, 0, index2 ());
962 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
965 const_iterator1 cbegin () const {
969 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
972 const_iterator1 end () const {
973 const self_type &m = (*this) ();
974 return m.find1 (1, m.size1 (), index2 ());
977 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
980 const_iterator1 cend () const {
984 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
987 const_reverse_iterator1 rbegin () const {
988 return const_reverse_iterator1 (end ());
991 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
994 const_reverse_iterator1 crbegin () const {
998 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1001 const_reverse_iterator1 rend () const {
1002 return const_reverse_iterator1 (begin ());
1005 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1006 typename self_type::
1008 const_reverse_iterator1 crend () const {
1015 size_type index1 () const {
1016 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1018 BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
1019 return layout_type::index_M (itv_.index (), it_.index ());
1025 size_type index2 () const {
1026 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1028 BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
1029 return layout_type::index_m (itv_.index (), it_.index ());
1037 const_iterator2 &operator = (const const_iterator2 &it) {
1038 container_const_reference<self_type>::assign (&it ());
1049 bool operator == (const const_iterator2 &it) const {
1050 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1051 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
1052 if (rank_ == 1 || it.rank_ == 1) {
1053 return it_ == it.it_;
1055 return i_ == it.i_ && j_ == it.j_;
1063 const_vectoriterator_type itv_;
1064 const_subiterator_type it_;
1068 const_iterator2 begin2 () const {
1069 return find2 (0, 0, 0);
1072 const_iterator2 cbegin2 () const {
1076 const_iterator2 end2 () const {
1077 return find2 (0, 0, size2_);
1080 const_iterator2 cend2 () const {
1085 public container_reference<generalized_vector_of_vector>,
1086 public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
1087 iterator2, value_type> {
1089 typedef typename generalized_vector_of_vector::difference_type difference_type;
1090 typedef typename generalized_vector_of_vector::value_type value_type;
1091 typedef typename generalized_vector_of_vector::true_reference reference;
1092 typedef typename generalized_vector_of_vector::pointer pointer;
1094 typedef iterator1 dual_iterator_type;
1095 typedef reverse_iterator1 dual_reverse_iterator_type;
1097 // Construction and destruction
1100 container_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
1102 iterator2 (self_type &m, int rank, size_type i, size_type j, const vectoriterator_type &itv, const subiterator_type &it):
1103 container_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
1107 iterator2 &operator ++ () {
1108 if (rank_ == 1 && layout_type::fast_j ())
1111 self_type &m = (*this) ();
1113 if (rank_ == 1 && ++ itv_ == m.end2 ().itv_)
1114 *this = m.find2 (rank_, i_, j_, 1);
1115 else if (rank_ == 1) {
1116 it_ = (*itv_).begin ();
1117 if (it_ == (*itv_).end () || index1 () != i_)
1118 *this = m.find2 (rank_, i_, j_, 1);
1124 iterator2 &operator -- () {
1125 if (rank_ == 1 && layout_type::fast_j ())
1128 self_type &m = (*this) ();
1130 if (rank_ == 1 && -- itv_ == m.end2 ().itv_)
1131 *this = m.find2 (rank_, i_, j_, -1);
1132 else if (rank_ == 1) {
1133 it_ = (*itv_).begin ();
1134 if (it_ == (*itv_).end () || index1 () != i_)
1135 *this = m.find2 (rank_, i_, j_, -1);
1143 true_reference operator * () const {
1144 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
1145 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
1149 return (*this) ().at_element (i_, j_);
1153 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1155 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1156 typename self_type::
1158 iterator1 begin () const {
1159 self_type &m = (*this) ();
1160 return m.find1 (1, 0, index2 ());
1163 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1164 typename self_type::
1166 iterator1 end () const {
1167 self_type &m = (*this) ();
1168 return m.find1 (1, m.size1 (), index2 ());
1171 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1172 typename self_type::
1174 reverse_iterator1 rbegin () const {
1175 return reverse_iterator1 (end ());
1178 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1179 typename self_type::
1181 reverse_iterator1 rend () const {
1182 return reverse_iterator1 (begin ());
1188 size_type index1 () const {
1189 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1191 BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
1192 return layout_type::index_M (itv_.index (), it_.index ());
1198 size_type index2 () const {
1199 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1201 BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
1202 return layout_type::index_m (itv_.index (), it_.index ());
1210 iterator2 &operator = (const iterator2 &it) {
1211 container_reference<self_type>::assign (&it ());
1222 bool operator == (const iterator2 &it) const {
1223 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1224 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
1225 if (rank_ == 1 || it.rank_ == 1) {
1226 return it_ == it.it_;
1228 return i_ == it.i_ && j_ == it.j_;
1236 vectoriterator_type itv_;
1237 subiterator_type it_;
1239 friend class const_iterator2;
1243 iterator2 begin2 () {
1244 return find2 (0, 0, 0);
1248 return find2 (0, 0, size2_);
1251 // Reverse iterators
1254 const_reverse_iterator1 rbegin1 () const {
1255 return const_reverse_iterator1 (end1 ());
1258 const_reverse_iterator1 crbegin1 () const {
1262 const_reverse_iterator1 rend1 () const {
1263 return const_reverse_iterator1 (begin1 ());
1266 const_reverse_iterator1 crend1 () const {
1271 reverse_iterator1 rbegin1 () {
1272 return reverse_iterator1 (end1 ());
1275 reverse_iterator1 rend1 () {
1276 return reverse_iterator1 (begin1 ());
1280 const_reverse_iterator2 rbegin2 () const {
1281 return const_reverse_iterator2 (end2 ());
1284 const_reverse_iterator2 crbegin2 () const {
1288 const_reverse_iterator2 rend2 () const {
1289 return const_reverse_iterator2 (begin2 ());
1292 const_reverse_iterator2 crend2 () const {
1297 reverse_iterator2 rbegin2 () {
1298 return reverse_iterator2 (end2 ());
1301 reverse_iterator2 rend2 () {
1302 return reverse_iterator2 (begin2 ());
1306 template<class Archive>
1307 void serialize(Archive & ar, const unsigned int /* file_version */){
1309 // we need to copy to a collection_size_type to get a portable
1310 // and efficient serialization
1311 serialization::collection_size_type s1 (size1_);
1312 serialization::collection_size_type s2 (size2_);
1314 // serialize the sizes
1315 ar & serialization::make_nvp("size1",s1)
1316 & serialization::make_nvp("size2",s2);
1318 // copy the values back if loading
1319 if (Archive::is_loading::value) {
1324 ar & serialization::make_nvp("data", data_);
1326 storage_invariants();
1330 void storage_invariants () const
1332 BOOST_UBLAS_CHECK (layout_type::size_M (size1_, size2_) + 1 == data_.size (), internal_logic ());
1333 BOOST_UBLAS_CHECK (data ().begin () != data ().end (), internal_logic ());
1339 static const value_type zero_;
1342 template<class T, class L, class A>
1343 const typename generalized_vector_of_vector<T, L, A>::value_type generalized_vector_of_vector<T, L, A>::zero_ = value_type/*zero*/();