1 //
2 //  Copyright (c) 2003
3 //  Gunter Winkler, Joerg Walter
4 //
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)
8 //
9 //  The authors gratefully acknowledge the support of
10 //  GeNeSys mbH & Co. KG in producing this work.
11 //
12 
13 #ifndef _BOOST_UBLAS_VECTOR_OF_VECTOR_
14 #define _BOOST_UBLAS_VECTOR_OF_VECTOR_
15 
16 #include <boost/type_traits.hpp>
17 
18 #include <boost/numeric/ublas/storage_sparse.hpp>
19 #include <boost/numeric/ublas/matrix_sparse.hpp>
20 
21 // Iterators based on ideas of Jeremy Siek
22 
23 namespace boost { namespace numeric { namespace ublas {
24 
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> > {
30 
31         typedef T &true_reference;
32         typedef T *pointer;
33         typedef const T *const_pointer;
34         typedef L layout_type;
35         typedef generalized_vector_of_vector<T, L, A> self_type;
36     public:
37 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
38         using matrix_container<self_type>::operator ();
39 #endif
40         typedef typename A::size_type size_type;
41         typedef typename A::difference_type difference_type;
42         typedef T value_type;
43         typedef const T &const_reference;
44 #ifndef BOOST_UBLAS_STRICT_VECTOR_SPARSE
45         typedef T &reference;
46 #else
47         typedef sparse_matrix_element<self_type> reference;
48 #endif
49         typedef A array_type;
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;
57 
58         // Construction and destruction
59         BOOST_UBLAS_INLINE
generalized_vector_of_vector()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 ();
67         }
68         BOOST_UBLAS_INLINE
generalized_vector_of_vector(size_type size1,size_type size2,size_type)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 ();
78         }
79         BOOST_UBLAS_INLINE
generalized_vector_of_vector(const generalized_vector_of_vector & m)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 ();
84         }
85         template<class AE>
86         BOOST_UBLAS_INLINE
generalized_vector_of_vector(const matrix_expression<AE> & ae,size_type)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);
97         }
98 
99         // Accessors
100         BOOST_UBLAS_INLINE
size1() const101         size_type size1 () const {
102             return size1_;
103         }
104         BOOST_UBLAS_INLINE
size2() const105         size_type size2 () const {
106             return size2_;
107         }
108         BOOST_UBLAS_INLINE
nnz_capacity() const109         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 ();
113             return non_zeros;
114         }
115         BOOST_UBLAS_INLINE
nnz() const116         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 ();
120             return non_zeros;
121         }
122 
123         // Storage accessors
124         BOOST_UBLAS_INLINE
data() const125         const array_type &data () const {
126             return data_;
127         }
128         BOOST_UBLAS_INLINE
data()129         array_type &data () {
130             return data_;
131         }
132 
133         // Resizing
134         BOOST_UBLAS_INLINE
resize(size_type size1,size_type size2,bool preserve=true)135         void resize (size_type size1, size_type size2, bool preserve = true) {
136             const size_type oldM = layout_type::size_M (size1_, size2_);
137             size1_ = size1;
138             size2_ = 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);
142             if (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);
147                 if (sizeM > oldM) {
148                     data_.insert_element (sizeM, vector_data_value_type ());
149                 } else {
150                     ref (data () [sizeM]).resize (0, false);
151                 }
152             } else {
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 ());
156             }
157             storage_invariants ();
158         }
159 
160         // Element support
161         BOOST_UBLAS_INLINE
find_element(size_type i,size_type j)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));
164         }
165         BOOST_UBLAS_INLINE
find_element(size_type i,size_type j) const166         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]);
172             }
173             else {
174                 const typename array_type::value_type *pv = data ().find_element (elementM);
175                 if (!pv)
176                     return 0;
177                 return pv->find_element (elementm);
178             }
179         }
180 
181         // Element access
182         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j) const183         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 () );
188                 return *p;
189             }
190             else {
191                 if (p)
192                     return *p;
193                 else
194                     return zero_;
195             }
196         }
197         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j)198         reference operator () (size_type i, size_type j) {
199 #ifndef BOOST_UBLAS_STRICT_MATRIX_SPARSE
200             return at_element (i, j);
201 #else
202             return reference (*this, i, j);
203 #endif
204         }
205 
206         // Assignment
207         BOOST_UBLAS_INLINE
operator =(const generalized_vector_of_vector & m)208         generalized_vector_of_vector &operator = (const generalized_vector_of_vector &m) {
209             if (this != &m) {
210                 size1_ = m.size1_;
211                 size2_ = m.size2_;
212                 data () = m.data ();
213             }
214             storage_invariants ();
215             return *this;
216         }
217         BOOST_UBLAS_INLINE
assign_temporary(generalized_vector_of_vector & m)218         generalized_vector_of_vector &assign_temporary (generalized_vector_of_vector &m) {
219             swap (m);
220             return *this;
221         }
222         template<class AE>
223         BOOST_UBLAS_INLINE
operator =(const matrix_expression<AE> & ae)224         generalized_vector_of_vector &operator = (const matrix_expression<AE> &ae) {
225             self_type temporary (ae);
226             return assign_temporary (temporary);
227         }
228         template<class AE>
229         BOOST_UBLAS_INLINE
assign(const matrix_expression<AE> & ae)230         generalized_vector_of_vector &assign (const matrix_expression<AE> &ae) {
231             matrix_assign<scalar_assign> (*this, ae);
232             return *this;
233         }
234         template<class AE>
235         BOOST_UBLAS_INLINE
operator +=(const matrix_expression<AE> & ae)236         generalized_vector_of_vector& operator += (const matrix_expression<AE> &ae) {
237             self_type temporary (*this + ae);
238             return assign_temporary (temporary);
239         }
240         template<class AE>
241         BOOST_UBLAS_INLINE
plus_assign(const matrix_expression<AE> & ae)242         generalized_vector_of_vector &plus_assign (const matrix_expression<AE> &ae) {
243             matrix_assign<scalar_plus_assign> (*this, ae);
244             return *this;
245         }
246         template<class AE>
247         BOOST_UBLAS_INLINE
operator -=(const matrix_expression<AE> & ae)248         generalized_vector_of_vector& operator -= (const matrix_expression<AE> &ae) {
249             self_type temporary (*this - ae);
250             return assign_temporary (temporary);
251         }
252         template<class AE>
253         BOOST_UBLAS_INLINE
minus_assign(const matrix_expression<AE> & ae)254         generalized_vector_of_vector &minus_assign (const matrix_expression<AE> &ae) {
255             matrix_assign<scalar_minus_assign> (*this, ae);
256             return *this;
257         }
258         template<class AT>
259         BOOST_UBLAS_INLINE
operator *=(const AT & at)260         generalized_vector_of_vector& operator *= (const AT &at) {
261             matrix_assign_scalar<scalar_multiplies_assign> (*this, at);
262             return *this;
263         }
264         template<class AT>
265         BOOST_UBLAS_INLINE
operator /=(const AT & at)266         generalized_vector_of_vector& operator /= (const AT &at) {
267             matrix_assign_scalar<scalar_divides_assign> (*this, at);
268             return *this;
269         }
270 
271         // Swapping
272         BOOST_UBLAS_INLINE
swap(generalized_vector_of_vector & m)273         void swap (generalized_vector_of_vector &m) {
274             if (this != &m) {
275                 std::swap (size1_, m.size1_);
276                 std::swap (size2_, m.size2_);
277                 data ().swap (m.data ());
278             }
279             storage_invariants ();
280         }
281         BOOST_UBLAS_INLINE
swap(generalized_vector_of_vector & m1,generalized_vector_of_vector & m2)282         friend void swap (generalized_vector_of_vector &m1, generalized_vector_of_vector &m2) {
283             m1.swap (m2);
284         }
285 
286         // Sorting
sort()287         void sort () {
288             vectoriterator_type itv (data ().begin ());
289             vectoriterator_type itv_end (data ().end ());
290             while (itv != itv_end) {
291                 (*itv).sort ();
292                 ++ itv;
293             }
294         }
295 
296         // Element insertion and erasure
297         BOOST_UBLAS_INLINE
insert_element(size_type i,size_type j,const_reference t)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);
304         }
305         BOOST_UBLAS_INLINE
append_element(size_type i,size_type j,const_reference 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);
312         }
313         BOOST_UBLAS_INLINE
erase_element(size_type i,size_type j)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 ())
317                 return;
318             (*itv).erase_element (layout_type::index_m (i, j));
319             storage_invariants ();
320         }
321         BOOST_UBLAS_INLINE
clear()322         void clear () {
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 ();
328         }
329 
330         // Iterator types
331     private:
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;
337 
338         BOOST_UBLAS_INLINE
at_element(size_type i,size_type j)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)]);
341         }
342 
343     public:
344         class const_iterator1;
345         class iterator1;
346         class const_iterator2;
347         class 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;
352 
353         // Element lookup
354         // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
find1(int rank,size_type i,size_type j,int direction=1) const355         const_iterator1 find1 (int rank, size_type i, size_type j, int direction = 1) const {
356             for (;;) {
357                 const_vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
358                 const_vectoriterator_type itv_end (data ().end ());
359                 if (itv == itv_end)
360                     return const_iterator1 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
361 
362                 const_subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
363                 const_subiterator_type it_end ((*itv).end ());
364                 if (rank == 0)
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);
368                 if (direction > 0) {
369                     if (layout_type::fast_i ()) {
370                         if (it == it_end)
371                             return const_iterator1 (*this, rank, i, j, itv, it);
372                         i = it.index ();
373                     } else {
374                         if (i >= size1_)
375                             return const_iterator1 (*this, rank, i, j, itv, it);
376                         ++ i;
377                     }
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);
382                         --it;
383                         i = it.index ();
384                     } else {
385                         if (i == 0)
386                             return const_iterator1 (*this, rank, i, j, itv, it);
387                         -- i;
388                     }
389                 }
390             }
391         }
392         // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
find1(int rank,size_type i,size_type j,int direction=1)393         iterator1 find1 (int rank, size_type i, size_type j, int direction = 1) {
394             for (;;) {
395                 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
396                 vectoriterator_type itv_end (data ().end ());
397                 if (itv == itv_end)
398                     return iterator1 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
399 
400                 subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
401                 subiterator_type it_end ((*itv).end ());
402                 if (rank == 0)
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);
406                 if (direction > 0) {
407                     if (layout_type::fast_i ()) {
408                         if (it == it_end)
409                             return iterator1 (*this, rank, i, j, itv, it);
410                         i = it.index ();
411                     } else {
412                         if (i >= size1_)
413                             return iterator1 (*this, rank, i, j, itv, it);
414                         ++ i;
415                     }
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);
420                         --it;
421                         i = it.index ();
422                     } else {
423                         if (i == 0)
424                             return iterator1 (*this, rank, i, j, itv, it);
425                         -- i;
426                     }
427                 }
428             }
429         }
430         // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
find2(int rank,size_type i,size_type j,int direction=1) const431         const_iterator2 find2 (int rank, size_type i, size_type j, int direction = 1) const {
432             for (;;) {
433                 const_vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
434                 const_vectoriterator_type itv_end (data ().end ());
435                 if (itv == itv_end)
436                     return const_iterator2 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
437 
438                 const_subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
439                 const_subiterator_type it_end ((*itv).end ());
440                 if (rank == 0)
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);
444                 if (direction > 0) {
445                     if (layout_type::fast_j ()) {
446                         if (it == it_end)
447                             return const_iterator2 (*this, rank, i, j, itv, it);
448                         j = it.index ();
449                     } else {
450                         if (j >= size2_)
451                             return const_iterator2 (*this, rank, i, j, itv, it);
452                         ++ j;
453                     }
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);
458                         --it;
459                         j = it.index ();
460                     } else {
461                         if (j == 0)
462                             return const_iterator2 (*this, rank, i, j, itv, it);
463                         -- j;
464                     }
465                 }
466             }
467         }
468         // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
find2(int rank,size_type i,size_type j,int direction=1)469         iterator2 find2 (int rank, size_type i, size_type j, int direction = 1) {
470             for (;;) {
471                 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
472                 vectoriterator_type itv_end (data ().end ());
473                 if (itv == itv_end)
474                     return iterator2 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
475 
476                 subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
477                 subiterator_type it_end ((*itv).end ());
478                 if (rank == 0)
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);
482                 if (direction > 0) {
483                     if (layout_type::fast_j ()) {
484                         if (it == it_end)
485                             return iterator2 (*this, rank, i, j, itv, it);
486                         j = it.index ();
487                     } else {
488                         if (j >= size2_)
489                             return iterator2 (*this, rank, i, j, itv, it);
490                         ++ j;
491                     }
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);
496                         --it;
497                         j = it.index ();
498                     } else {
499                         if (j == 0)
500                             return iterator2 (*this, rank, i, j, itv, it);
501                         -- j;
502                     }
503                 }
504             }
505         }
506 
507 
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> {
512         public:
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;
517 
518             typedef const_iterator2 dual_iterator_type;
519             typedef const_reverse_iterator2 dual_reverse_iterator_type;
520 
521             // Construction and destruction
522             BOOST_UBLAS_INLINE
const_iterator1()523             const_iterator1 ():
524                 container_const_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
525             BOOST_UBLAS_INLINE
const_iterator1(const self_type & m,int rank,size_type i,size_type j,const const_vectoriterator_type & itv,const const_subiterator_type & 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) {}
528             BOOST_UBLAS_INLINE
const_iterator1(const iterator1 & 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_) {}
531 
532             // Arithmetic
533             BOOST_UBLAS_INLINE
operator ++()534             const_iterator1 &operator ++ () {
535                 if (rank_ == 1 && layout_type::fast_i ())
536                     ++ it_;
537                 else {
538                     const self_type &m = (*this) ();
539                     i_ = index1 () + 1;
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);
546                     }
547                 }
548                 return *this;
549             }
550             BOOST_UBLAS_INLINE
operator --()551             const_iterator1 &operator -- () {
552                 if (rank_ == 1 && layout_type::fast_i ())
553                     -- it_;
554                 else {
555                     const self_type &m = (*this) ();
556                     i_ = index1 () - 1;
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);
563                     }
564                 }
565                 return *this;
566             }
567 
568             // Dereference
569             BOOST_UBLAS_INLINE
operator *() const570             const_reference operator * () const {
571                 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
572                 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
573                 if (rank_ == 1) {
574                     return *it_;
575                 } else {
576                     return (*this) () (i_, j_);
577                 }
578             }
579 
580 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
581             BOOST_UBLAS_INLINE
582 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
583             typename self_type::
584 #endif
begin() const585             const_iterator2 begin () const {
586                 const self_type &m = (*this) ();
587                 return m.find2 (1, index1 (), 0);
588             }
589             BOOST_UBLAS_INLINE
590 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
591             typename self_type::
592 #endif
cbegin() const593             const_iterator2 cbegin () const {
594                 return begin ();
595             }
596             BOOST_UBLAS_INLINE
597 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
598             typename self_type::
599 #endif
end() const600             const_iterator2 end () const {
601                 const self_type &m = (*this) ();
602                 return m.find2 (1, index1 (), m.size2 ());
603             }
604             BOOST_UBLAS_INLINE
605 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
606             typename self_type::
607 #endif
cend() const608             const_iterator2 cend () const {
609                 return end ();
610             }
611 
612             BOOST_UBLAS_INLINE
613 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
614             typename self_type::
615 #endif
rbegin() const616             const_reverse_iterator2 rbegin () const {
617                 return const_reverse_iterator2 (end ());
618             }
619             BOOST_UBLAS_INLINE
620 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
621             typename self_type::
622 #endif
crbegin() const623             const_reverse_iterator2 crbegin () const {
624                 return rbegin ();
625             }
626             BOOST_UBLAS_INLINE
627 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
628             typename self_type::
629 #endif
rend() const630             const_reverse_iterator2 rend () const {
631                 return const_reverse_iterator2 (begin ());
632             }
633             BOOST_UBLAS_INLINE
634 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
635             typename self_type::
636 #endif
crend() const637             const_reverse_iterator2 crend () const {
638                 return rend ();
639             }
640 #endif
641 
642             // Indices
643             BOOST_UBLAS_INLINE
index1() const644             size_type index1 () const {
645                 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
646                 if (rank_ == 1) {
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 ());
649                 } else {
650                     return i_;
651                 }
652             }
653             BOOST_UBLAS_INLINE
index2() const654             size_type index2 () const {
655                 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
656                 if (rank_ == 1) {
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 ());
659                 } else {
660                     return j_;
661                 }
662             }
663 
664             // Assignment
665             BOOST_UBLAS_INLINE
operator =(const const_iterator1 & it)666             const_iterator1 &operator = (const const_iterator1 &it) {
667                 container_const_reference<self_type>::assign (&it ());
668                 rank_ = it.rank_;
669                 i_ = it.i_;
670                 j_ = it.j_;
671                 itv_ = it.itv_;
672                 it_ = it.it_;
673                 return *this;
674             }
675 
676             // Comparison
677             BOOST_UBLAS_INLINE
operator ==(const const_iterator1 & it) const678             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_;
683                 } else {
684                     return i_ == it.i_ && j_ == it.j_;
685                 }
686             }
687 
688         private:
689             int rank_;
690             size_type i_;
691             size_type j_;
692             const_vectoriterator_type itv_;
693             const_subiterator_type it_;
694         };
695 
696         BOOST_UBLAS_INLINE
begin1() const697         const_iterator1 begin1 () const {
698             return find1 (0, 0, 0);
699         }
700         BOOST_UBLAS_INLINE
cbegin1() const701         const_iterator1 cbegin1 () const {
702             return begin1 ();
703         }
704         BOOST_UBLAS_INLINE
end1() const705         const_iterator1 end1 () const {
706             return find1 (0, size1_, 0);
707         }
708         BOOST_UBLAS_INLINE
cend1() const709         const_iterator1 cend1 () const {
710             return end1 ();
711         }
712 
713         class iterator1:
714             public container_reference<generalized_vector_of_vector>,
715             public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
716                                                iterator1, value_type> {
717         public:
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;
722 
723             typedef iterator2 dual_iterator_type;
724             typedef reverse_iterator2 dual_reverse_iterator_type;
725 
726             // Construction and destruction
727             BOOST_UBLAS_INLINE
iterator1()728             iterator1 ():
729                 container_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
730             BOOST_UBLAS_INLINE
iterator1(self_type & m,int rank,size_type i,size_type j,const vectoriterator_type & itv,const subiterator_type & 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) {}
733 
734             // Arithmetic
735             BOOST_UBLAS_INLINE
operator ++()736             iterator1 &operator ++ () {
737                 if (rank_ == 1 && layout_type::fast_i ())
738                     ++ it_;
739                 else {
740                     self_type &m = (*this) ();
741                     i_ = index1 () + 1;
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);
748                     }
749                 }
750                 return *this;
751             }
752             BOOST_UBLAS_INLINE
operator --()753             iterator1 &operator -- () {
754                 if (rank_ == 1 && layout_type::fast_i ())
755                     -- it_;
756                 else {
757                     self_type &m = (*this) ();
758                     i_ = index1 () - 1;
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);
765                     }
766                 }
767                 return *this;
768             }
769 
770             // Dereference
771             BOOST_UBLAS_INLINE
operator *() const772             true_reference operator * () const {
773                 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
774                 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
775                 if (rank_ == 1) {
776                     return *it_;
777                 } else {
778                     return (*this) ().at_element (i_, j_);
779                 }
780             }
781 
782 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
783             BOOST_UBLAS_INLINE
784 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
785             typename self_type::
786 #endif
begin() const787             iterator2 begin () const {
788                 self_type &m = (*this) ();
789                 return m.find2 (1, index1 (), 0);
790             }
791             BOOST_UBLAS_INLINE
792 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
793             typename self_type::
794 #endif
end() const795             iterator2 end () const {
796                 self_type &m = (*this) ();
797                 return m.find2 (1, index1 (), m.size2 ());
798             }
799             BOOST_UBLAS_INLINE
800 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
801             typename self_type::
802 #endif
rbegin() const803             reverse_iterator2 rbegin () const {
804                 return reverse_iterator2 (end ());
805             }
806             BOOST_UBLAS_INLINE
807 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
808             typename self_type::
809 #endif
rend() const810             reverse_iterator2 rend () const {
811                 return reverse_iterator2 (begin ());
812             }
813 #endif
814 
815             // Indices
816             BOOST_UBLAS_INLINE
index1() const817             size_type index1 () const {
818                 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
819                 if (rank_ == 1) {
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 ());
822                 } else {
823                     return i_;
824                 }
825             }
826             BOOST_UBLAS_INLINE
index2() const827             size_type index2 () const {
828                 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
829                 if (rank_ == 1) {
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 ());
832                 } else {
833                     return j_;
834                 }
835             }
836 
837             // Assignment
838             BOOST_UBLAS_INLINE
operator =(const iterator1 & it)839             iterator1 &operator = (const iterator1 &it) {
840                 container_reference<self_type>::assign (&it ());
841                 rank_ = it.rank_;
842                 i_ = it.i_;
843                 j_ = it.j_;
844                 itv_ = it.itv_;
845                 it_ = it.it_;
846                 return *this;
847             }
848 
849             // Comparison
850             BOOST_UBLAS_INLINE
operator ==(const iterator1 & it) const851             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_;
856                 } else {
857                     return i_ == it.i_ && j_ == it.j_;
858                 }
859             }
860 
861         private:
862             int rank_;
863             size_type i_;
864             size_type j_;
865             vectoriterator_type itv_;
866             subiterator_type it_;
867 
868             friend class const_iterator1;
869         };
870 
871         BOOST_UBLAS_INLINE
begin1()872         iterator1 begin1 () {
873             return find1 (0, 0, 0);
874         }
875         BOOST_UBLAS_INLINE
end1()876         iterator1 end1 () {
877             return find1 (0, size1_, 0);
878         }
879 
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> {
884         public:
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;
889 
890             typedef const_iterator1 dual_iterator_type;
891             typedef const_reverse_iterator1 dual_reverse_iterator_type;
892 
893             // Construction and destruction
894             BOOST_UBLAS_INLINE
const_iterator2()895             const_iterator2 ():
896                 container_const_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
897             BOOST_UBLAS_INLINE
const_iterator2(const self_type & m,int rank,size_type i,size_type j,const const_vectoriterator_type & itv,const const_subiterator_type & 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) {}
900             BOOST_UBLAS_INLINE
const_iterator2(const iterator2 & 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_) {}
903 
904             // Arithmetic
905             BOOST_UBLAS_INLINE
operator ++()906             const_iterator2 &operator ++ () {
907                 if (rank_ == 1 && layout_type::fast_j ())
908                     ++ it_;
909                 else {
910                     const self_type &m = (*this) ();
911                     j_ = index2 () + 1;
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);
918                     }
919                 }
920                 return *this;
921             }
922             BOOST_UBLAS_INLINE
operator --()923             const_iterator2 &operator -- () {
924                 if (rank_ == 1 && layout_type::fast_j ())
925                     -- it_;
926                 else {
927                     const self_type &m = (*this) ();
928                     j_ = index2 () - 1;
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);
935                     }
936                 }
937                 return *this;
938             }
939 
940             // Dereference
941             BOOST_UBLAS_INLINE
operator *() const942             const_reference operator * () const {
943                 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
944                 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
945                 if (rank_ == 1) {
946                     return *it_;
947                 } else {
948                     return (*this) () (i_, j_);
949                 }
950             }
951 
952 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
953             BOOST_UBLAS_INLINE
954 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
955             typename self_type::
956 #endif
begin() const957             const_iterator1 begin () const {
958                 const self_type &m = (*this) ();
959                 return m.find1 (1, 0, index2 ());
960             }
961             BOOST_UBLAS_INLINE
962 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
963             typename self_type::
964 #endif
cbegin() const965             const_iterator1 cbegin () const {
966                 return begin ();
967             }
968             BOOST_UBLAS_INLINE
969 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
970             typename self_type::
971 #endif
end() const972             const_iterator1 end () const {
973                 const self_type &m = (*this) ();
974                 return m.find1 (1, m.size1 (), index2 ());
975             }
976             BOOST_UBLAS_INLINE
977 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
978             typename self_type::
979 #endif
cend() const980             const_iterator1 cend () const {
981                 return end ();
982             }
983             BOOST_UBLAS_INLINE
984 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
985             typename self_type::
986 #endif
rbegin() const987             const_reverse_iterator1 rbegin () const {
988                 return const_reverse_iterator1 (end ());
989             }
990             BOOST_UBLAS_INLINE
991 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
992             typename self_type::
993 #endif
crbegin() const994             const_reverse_iterator1 crbegin () const {
995                 return rbegin ();
996             }
997             BOOST_UBLAS_INLINE
998 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
999             typename self_type::
1000 #endif
rend() const1001             const_reverse_iterator1 rend () const {
1002                 return const_reverse_iterator1 (begin ());
1003             }
1004             BOOST_UBLAS_INLINE
1005 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1006             typename self_type::
1007 #endif
crend() const1008             const_reverse_iterator1 crend () const {
1009                 return rend ();
1010             }
1011 #endif
1012 
1013             // Indices
1014             BOOST_UBLAS_INLINE
index1() const1015             size_type index1 () const {
1016                 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1017                 if (rank_ == 1) {
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 ());
1020                 } else {
1021                     return i_;
1022                 }
1023             }
1024             BOOST_UBLAS_INLINE
index2() const1025             size_type index2 () const {
1026                 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1027                 if (rank_ == 1) {
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 ());
1030                 } else {
1031                     return j_;
1032                 }
1033             }
1034 
1035             // Assignment
1036             BOOST_UBLAS_INLINE
operator =(const const_iterator2 & it)1037             const_iterator2 &operator = (const const_iterator2 &it) {
1038                 container_const_reference<self_type>::assign (&it ());
1039                 rank_ = it.rank_;
1040                 i_ = it.i_;
1041                 j_ = it.j_;
1042                 itv_ = it.itv_;
1043                 it_ = it.it_;
1044                 return *this;
1045             }
1046 
1047             // Comparison
1048             BOOST_UBLAS_INLINE
operator ==(const const_iterator2 & it) const1049             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_;
1054                 } else {
1055                     return i_ == it.i_ && j_ == it.j_;
1056                 }
1057             }
1058 
1059         private:
1060             int rank_;
1061             size_type i_;
1062             size_type j_;
1063             const_vectoriterator_type itv_;
1064             const_subiterator_type it_;
1065         };
1066 
1067         BOOST_UBLAS_INLINE
begin2() const1068         const_iterator2 begin2 () const {
1069             return find2 (0, 0, 0);
1070         }
1071         BOOST_UBLAS_INLINE
cbegin2() const1072         const_iterator2 cbegin2 () const {
1073             return begin2 ();
1074         }
1075         BOOST_UBLAS_INLINE
end2() const1076         const_iterator2 end2 () const {
1077             return find2 (0, 0, size2_);
1078         }
1079         BOOST_UBLAS_INLINE
cend2() const1080         const_iterator2 cend2 () const {
1081             return end2 ();
1082         }
1083 
1084         class iterator2:
1085             public container_reference<generalized_vector_of_vector>,
1086             public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
1087                                                iterator2, value_type> {
1088         public:
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;
1093 
1094             typedef iterator1 dual_iterator_type;
1095             typedef reverse_iterator1 dual_reverse_iterator_type;
1096 
1097             // Construction and destruction
1098             BOOST_UBLAS_INLINE
iterator2()1099             iterator2 ():
1100                 container_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
1101             BOOST_UBLAS_INLINE
iterator2(self_type & m,int rank,size_type i,size_type j,const vectoriterator_type & itv,const subiterator_type & 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) {}
1104 
1105             // Arithmetic
1106             BOOST_UBLAS_INLINE
operator ++()1107             iterator2 &operator ++ () {
1108                 if (rank_ == 1 && layout_type::fast_j ())
1109                     ++ it_;
1110                 else {
1111                     self_type &m = (*this) ();
1112                     j_ = index2 () + 1;
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);
1119                     }
1120                 }
1121                 return *this;
1122             }
1123             BOOST_UBLAS_INLINE
operator --()1124             iterator2 &operator -- () {
1125                 if (rank_ == 1 && layout_type::fast_j ())
1126                     -- it_;
1127                 else {
1128                     self_type &m = (*this) ();
1129                     j_ = index2 () - 1;
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);
1136                     }
1137                 }
1138                 return *this;
1139             }
1140 
1141             // Dereference
1142             BOOST_UBLAS_INLINE
operator *() const1143             true_reference operator * () const {
1144                 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
1145                 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
1146                 if (rank_ == 1) {
1147                     return *it_;
1148                 } else {
1149                     return (*this) ().at_element (i_, j_);
1150                 }
1151             }
1152 
1153 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1154             BOOST_UBLAS_INLINE
1155 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1156             typename self_type::
1157 #endif
begin() const1158             iterator1 begin () const {
1159                 self_type &m = (*this) ();
1160                 return m.find1 (1, 0, index2 ());
1161             }
1162             BOOST_UBLAS_INLINE
1163 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1164             typename self_type::
1165 #endif
end() const1166             iterator1 end () const {
1167                 self_type &m = (*this) ();
1168                 return m.find1 (1, m.size1 (), index2 ());
1169             }
1170             BOOST_UBLAS_INLINE
1171 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1172             typename self_type::
1173 #endif
rbegin() const1174             reverse_iterator1 rbegin () const {
1175                 return reverse_iterator1 (end ());
1176             }
1177             BOOST_UBLAS_INLINE
1178 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1179             typename self_type::
1180 #endif
rend() const1181             reverse_iterator1 rend () const {
1182                 return reverse_iterator1 (begin ());
1183             }
1184 #endif
1185 
1186             // Indices
1187             BOOST_UBLAS_INLINE
index1() const1188             size_type index1 () const {
1189                 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1190                 if (rank_ == 1) {
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 ());
1193                 } else {
1194                     return i_;
1195                 }
1196             }
1197             BOOST_UBLAS_INLINE
index2() const1198             size_type index2 () const {
1199                 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1200                 if (rank_ == 1) {
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 ());
1203                 } else {
1204                     return j_;
1205                 }
1206             }
1207 
1208             // Assignment
1209             BOOST_UBLAS_INLINE
operator =(const iterator2 & it)1210             iterator2 &operator = (const iterator2 &it) {
1211                 container_reference<self_type>::assign (&it ());
1212                 rank_ = it.rank_;
1213                 i_ = it.i_;
1214                 j_ = it.j_;
1215                 itv_ = it.itv_;
1216                 it_ = it.it_;
1217                 return *this;
1218             }
1219 
1220             // Comparison
1221             BOOST_UBLAS_INLINE
operator ==(const iterator2 & it) const1222             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_;
1227                 } else {
1228                     return i_ == it.i_ && j_ == it.j_;
1229                 }
1230             }
1231 
1232         private:
1233             int rank_;
1234             size_type i_;
1235             size_type j_;
1236             vectoriterator_type itv_;
1237             subiterator_type it_;
1238 
1239             friend class const_iterator2;
1240         };
1241 
1242         BOOST_UBLAS_INLINE
begin2()1243         iterator2 begin2 () {
1244             return find2 (0, 0, 0);
1245         }
1246         BOOST_UBLAS_INLINE
end2()1247         iterator2 end2 () {
1248             return find2 (0, 0, size2_);
1249         }
1250 
1251         // Reverse iterators
1252 
1253         BOOST_UBLAS_INLINE
rbegin1() const1254         const_reverse_iterator1 rbegin1 () const {
1255             return const_reverse_iterator1 (end1 ());
1256         }
1257         BOOST_UBLAS_INLINE
crbegin1() const1258         const_reverse_iterator1 crbegin1 () const {
1259             return rbegin1 ();
1260         }
1261         BOOST_UBLAS_INLINE
rend1() const1262         const_reverse_iterator1 rend1 () const {
1263             return const_reverse_iterator1 (begin1 ());
1264         }
1265         BOOST_UBLAS_INLINE
crend1() const1266         const_reverse_iterator1 crend1 () const {
1267             return rend1 ();
1268         }
1269 
1270         BOOST_UBLAS_INLINE
rbegin1()1271         reverse_iterator1 rbegin1 () {
1272             return reverse_iterator1 (end1 ());
1273         }
1274         BOOST_UBLAS_INLINE
rend1()1275         reverse_iterator1 rend1 () {
1276             return reverse_iterator1 (begin1 ());
1277         }
1278 
1279         BOOST_UBLAS_INLINE
rbegin2() const1280         const_reverse_iterator2 rbegin2 () const {
1281             return const_reverse_iterator2 (end2 ());
1282         }
1283         BOOST_UBLAS_INLINE
crbegin2() const1284         const_reverse_iterator2 crbegin2 () const {
1285             return rbegin2 ();
1286         }
1287         BOOST_UBLAS_INLINE
rend2() const1288         const_reverse_iterator2 rend2 () const {
1289             return const_reverse_iterator2 (begin2 ());
1290         }
1291         BOOST_UBLAS_INLINE
crend2() const1292         const_reverse_iterator2 crend2 () const {
1293             return rend2 ();
1294         }
1295 
1296         BOOST_UBLAS_INLINE
rbegin2()1297         reverse_iterator2 rbegin2 () {
1298             return reverse_iterator2 (end2 ());
1299         }
1300         BOOST_UBLAS_INLINE
rend2()1301         reverse_iterator2 rend2 () {
1302             return reverse_iterator2 (begin2 ());
1303         }
1304 
1305          // Serialization
1306         template<class Archive>
serialize(Archive & ar,const unsigned int)1307         void serialize(Archive & ar, const unsigned int /* file_version */){
1308 
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_);
1313 
1314             // serialize the sizes
1315             ar & serialization::make_nvp("size1",s1)
1316                & serialization::make_nvp("size2",s2);
1317 
1318             // copy the values back if loading
1319             if (Archive::is_loading::value) {
1320                 size1_ = s1;
1321                 size2_ = s2;
1322             }
1323 
1324             ar & serialization::make_nvp("data", data_);
1325 
1326             storage_invariants();
1327         }
1328 
1329     private:
storage_invariants() const1330         void storage_invariants () const
1331         {
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 ());
1334 
1335         }
1336         size_type size1_;
1337         size_type size2_;
1338         array_type data_;
1339         static const value_type zero_;
1340     };
1341 
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*/();
1344 
1345 }}}
1346 
1347 #endif
1348