Boost.uBlas 1.49
Linear Algebra in C++: matrices, vectors and numeric algorithms

vector_of_vector.hpp

Go to the documentation of this file.
00001 //
00002 //  Copyright (c) 2003
00003 //  Gunter Winkler, Joerg Walter
00004 //
00005 //  Distributed under the Boost Software License, Version 1.0. (See
00006 //  accompanying file LICENSE_1_0.txt or copy at
00007 //  http://www.boost.org/LICENSE_1_0.txt)
00008 //
00009 //  The authors gratefully acknowledge the support of
00010 //  GeNeSys mbH & Co. KG in producing this work.
00011 //
00012 
00013 #ifndef _BOOST_UBLAS_VECTOR_OF_VECTOR_
00014 #define _BOOST_UBLAS_VECTOR_OF_VECTOR_
00015 
00016 #include <boost/type_traits.hpp>
00017 
00018 #include <boost/numeric/ublas/storage_sparse.hpp>
00019 #include <boost/numeric/ublas/matrix_sparse.hpp>
00020 
00021 // Iterators based on ideas of Jeremy Siek
00022 
00023 namespace boost { namespace numeric { namespace ublas {
00024 
00025     // uBLAS sparse vector based sparse matrix class
00026     // FIXME outer vector can be sparse type but it is completely filled
00027     template<class T, class L, class A>
00028     class generalized_vector_of_vector:
00029         public matrix_container<generalized_vector_of_vector<T, L, A> > {
00030 
00031         typedef T &true_reference;
00032         typedef T *pointer;
00033         typedef const T *const_pointer;
00034         typedef L layout_type;
00035         typedef generalized_vector_of_vector<T, L, A> self_type;
00036     public:
00037 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
00038         using matrix_container<self_type>::operator ();
00039 #endif
00040         typedef typename A::size_type size_type;
00041         typedef typename A::difference_type difference_type;
00042         typedef T value_type;
00043         typedef const T &const_reference;
00044 #ifndef BOOST_UBLAS_STRICT_VECTOR_SPARSE
00045         typedef T &reference;
00046 #else
00047         typedef sparse_matrix_element<self_type> reference;
00048 #endif
00049         typedef A array_type;
00050         typedef const matrix_reference<const self_type> const_closure_type;
00051         typedef matrix_reference<self_type> closure_type;
00052         typedef typename A::value_type vector_data_value_type;
00053         typedef vector_data_value_type vector_temporary_type;
00054         typedef self_type matrix_temporary_type;
00055         typedef sparse_tag storage_category;
00056         typedef typename L::orientation_category orientation_category;
00057 
00058         // Construction and destruction
00059         BOOST_UBLAS_INLINE
00060         generalized_vector_of_vector ():
00061             matrix_container<self_type> (),
00062             size1_ (0), size2_ (0), data_ (1) {
00063             const size_type sizeM = layout_type::size_M (size1_, size2_);
00064              // create size1+1 empty vector elements
00065             data_.insert_element (sizeM, vector_data_value_type ());
00066             storage_invariants ();
00067         }
00068         BOOST_UBLAS_INLINE
00069         generalized_vector_of_vector (size_type size1, size_type size2, size_type non_zeros = 0):
00070             matrix_container<self_type> (),
00071             size1_ (size1), size2_ (size2), data_ (layout_type::size_M (size1_, size2_) + 1) {
00072             const size_type sizeM = layout_type::size_M (size1_, size2_);
00073             const size_type sizem = layout_type::size_m (size1_, size2_);
00074             for (size_type i = 0; i < sizeM; ++ i) // create size1 vector elements
00075                 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
00076             data_.insert_element (sizeM, vector_data_value_type ());
00077             storage_invariants ();
00078         }
00079         BOOST_UBLAS_INLINE
00080         generalized_vector_of_vector (const generalized_vector_of_vector &m):
00081             matrix_container<self_type> (),
00082             size1_ (m.size1_), size2_ (m.size2_), data_ (m.data_) {
00083             storage_invariants ();
00084         }
00085         template<class AE>
00086         BOOST_UBLAS_INLINE
00087         generalized_vector_of_vector (const matrix_expression<AE> &ae, size_type non_zeros = 0):
00088             matrix_container<self_type> (),
00089             size1_ (ae ().size1 ()), size2_ (ae ().size2 ()), data_ (layout_type::size_M (size1_, size2_) + 1) {
00090             const size_type sizeM = layout_type::size_M (size1_, size2_);
00091             const size_type sizem = layout_type::size_m (size1_, size2_);
00092             for (size_type i = 0; i < sizeM; ++ i) // create size1 vector elements
00093                 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
00094             data_.insert_element (sizeM, vector_data_value_type ());
00095             storage_invariants ();
00096             matrix_assign<scalar_assign> (*this, ae);
00097         }
00098 
00099         // Accessors
00100         BOOST_UBLAS_INLINE
00101         size_type size1 () const {
00102             return size1_;
00103         }
00104         BOOST_UBLAS_INLINE
00105         size_type size2 () const {
00106             return size2_;
00107         }
00108         BOOST_UBLAS_INLINE
00109         size_type nnz_capacity () const {
00110             size_type non_zeros = 0;
00111             for (const_vectoriterator_type itv = data_.begin (); itv != data_.end (); ++ itv)
00112                 non_zeros += (*itv).nnz_capacity ();
00113             return non_zeros;
00114         }
00115         BOOST_UBLAS_INLINE
00116         size_type nnz () const {
00117             size_type non_zeros = 0;
00118             for (const_vectoriterator_type itv = data_.begin (); itv != data_.end (); ++ itv)
00119                 non_zeros += (*itv).nnz ();
00120             return non_zeros;
00121         }
00122 
00123         // Storage accessors
00124         BOOST_UBLAS_INLINE
00125         const array_type &data () const {
00126             return data_;
00127         }
00128         BOOST_UBLAS_INLINE
00129         array_type &data () {
00130             return data_;
00131         }
00132 
00133         // Resizing
00134         BOOST_UBLAS_INLINE
00135         void resize (size_type size1, size_type size2, bool preserve = true) {
00136             const size_type oldM = layout_type::size_M (size1_, size2_);
00137             size1_ = size1;
00138             size2_ = size2;
00139             const size_type sizeM = layout_type::size_M (size1_, size2_);
00140             const size_type sizem = layout_type::size_m (size1_, size2_);
00141             data ().resize (sizeM + 1, preserve);
00142             if (preserve) {
00143                 for (size_type i = 0; (i <= oldM) && (i < sizeM); ++ i)
00144                     ref (data () [i]).resize (sizem, preserve);
00145                 for (size_type i = oldM+1; i < sizeM; ++ i) // create new vector elements
00146                     data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
00147                 if (sizeM > oldM) {
00148                     data_.insert_element (sizeM, vector_data_value_type ());
00149                 } else {
00150                     ref (data () [sizeM]).resize (0, false);
00151                 }
00152             } else {
00153                 for (size_type i = 0; i < sizeM; ++ i) 
00154                     data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
00155                 data_.insert_element (sizeM, vector_data_value_type ());
00156             }
00157             storage_invariants ();
00158         }
00159 
00160         // Element support
00161         BOOST_UBLAS_INLINE
00162         pointer find_element (size_type i, size_type j) {
00163             return const_cast<pointer> (const_cast<const self_type&>(*this).find_element (i, j));
00164         }
00165         BOOST_UBLAS_INLINE
00166         const_pointer find_element (size_type i, size_type j) const {
00167             const size_type elementM = layout_type::index_M (i, j);
00168             const size_type elementm = layout_type::index_m (i, j);
00169             // optimise: check the storage_type and index directly if element always exists
00170             if (boost::is_convertible<typename array_type::storage_category, packed_tag>::value) {
00171                 return & (data () [elementM] [elementm]);
00172             }
00173             else {
00174                 const typename array_type::value_type *pv = data ().find_element (elementM);
00175                 if (!pv)
00176                     return 0;
00177                 return pv->find_element (elementm);
00178             }
00179         }
00180 
00181         // Element access
00182         BOOST_UBLAS_INLINE
00183         const_reference operator () (size_type i, size_type j) const {
00184             const_pointer p = find_element (i, j);
00185             // optimise: check the storage_type and index directly if element always exists
00186             if (boost::is_convertible<typename array_type::storage_category, packed_tag>::value) {
00187                 BOOST_UBLAS_CHECK (p, internal_logic () );
00188                 return *p;
00189             }
00190             else {
00191                 if (p)
00192                     return *p;
00193                 else
00194                     return zero_;
00195             }
00196         }
00197         BOOST_UBLAS_INLINE
00198         reference operator () (size_type i, size_type j) {
00199 #ifndef BOOST_UBLAS_STRICT_MATRIX_SPARSE
00200             return at_element (i, j);
00201 #else
00202             return reference (*this, i, j);
00203 #endif
00204         }
00205 
00206         // Assignment
00207         BOOST_UBLAS_INLINE
00208         generalized_vector_of_vector &operator = (const generalized_vector_of_vector &m) {
00209             if (this != &m) {
00210                 size1_ = m.size1_;
00211                 size2_ = m.size2_;
00212                 data () = m.data ();
00213             }
00214             storage_invariants ();
00215             return *this;
00216         }
00217         BOOST_UBLAS_INLINE
00218         generalized_vector_of_vector &assign_temporary (generalized_vector_of_vector &m) {
00219             swap (m);
00220             return *this;
00221         }
00222         template<class AE>
00223         BOOST_UBLAS_INLINE
00224         generalized_vector_of_vector &operator = (const matrix_expression<AE> &ae) {
00225             self_type temporary (ae);
00226             return assign_temporary (temporary);
00227         }
00228         template<class AE>
00229         BOOST_UBLAS_INLINE
00230         generalized_vector_of_vector &assign (const matrix_expression<AE> &ae) {
00231             matrix_assign<scalar_assign> (*this, ae);
00232             return *this;
00233         }
00234         template<class AE>
00235         BOOST_UBLAS_INLINE
00236         generalized_vector_of_vector& operator += (const matrix_expression<AE> &ae) {
00237             self_type temporary (*this + ae);
00238             return assign_temporary (temporary);
00239         }
00240         template<class AE>
00241         BOOST_UBLAS_INLINE
00242         generalized_vector_of_vector &plus_assign (const matrix_expression<AE> &ae) { 
00243             matrix_assign<scalar_plus_assign> (*this, ae);
00244             return *this;
00245         }
00246         template<class AE>
00247         BOOST_UBLAS_INLINE
00248         generalized_vector_of_vector& operator -= (const matrix_expression<AE> &ae) {
00249             self_type temporary (*this - ae);
00250             return assign_temporary (temporary);
00251         }
00252         template<class AE>
00253         BOOST_UBLAS_INLINE
00254         generalized_vector_of_vector &minus_assign (const matrix_expression<AE> &ae) {
00255             matrix_assign<scalar_minus_assign> (*this, ae);
00256             return *this;
00257         }
00258         template<class AT>
00259         BOOST_UBLAS_INLINE
00260         generalized_vector_of_vector& operator *= (const AT &at) {
00261             matrix_assign_scalar<scalar_multiplies_assign> (*this, at);
00262             return *this;
00263         }
00264         template<class AT>
00265         BOOST_UBLAS_INLINE
00266         generalized_vector_of_vector& operator /= (const AT &at) {
00267             matrix_assign_scalar<scalar_divides_assign> (*this, at);
00268             return *this;
00269         }
00270 
00271         // Swapping
00272         BOOST_UBLAS_INLINE
00273         void swap (generalized_vector_of_vector &m) {
00274             if (this != &m) {
00275                 std::swap (size1_, m.size1_);
00276                 std::swap (size2_, m.size2_);
00277                 data ().swap (m.data ());
00278             }
00279             storage_invariants ();
00280         }
00281         BOOST_UBLAS_INLINE
00282         friend void swap (generalized_vector_of_vector &m1, generalized_vector_of_vector &m2) {
00283             m1.swap (m2);
00284         }
00285 
00286         // Sorting
00287         void sort () {
00288             vectoriterator_type itv (data ().begin ());
00289             vectoriterator_type itv_end (data ().end ());
00290             while (itv != itv_end) {
00291                 (*itv).sort ();
00292                 ++ itv;
00293             }
00294         }
00295 
00296         // Element insertion and erasure
00297         BOOST_UBLAS_INLINE
00298         true_reference insert_element (size_type i, size_type j, const_reference t) {
00299             const size_type elementM = layout_type::index_M (i, j);
00300             const size_type elementm = layout_type::index_m (i, j);
00301             vector_data_value_type& vd (ref (data () [elementM]));
00302             storage_invariants ();
00303             return vd.insert_element (elementm, t);
00304         }
00305         BOOST_UBLAS_INLINE
00306         void append_element (size_type i, size_type j, const_reference t) {
00307             const size_type elementM = layout_type::index_M (i, j);
00308             const size_type elementm = layout_type::index_m (i, j);
00309             vector_data_value_type& vd (ref (data () [elementM]));
00310             storage_invariants ();
00311             return vd.append_element (elementm, t);
00312         }
00313         BOOST_UBLAS_INLINE
00314         void erase_element (size_type i, size_type j) {
00315             vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
00316             if (itv == data ().end ())
00317                 return;
00318             (*itv).erase_element (layout_type::index_m (i, j));
00319             storage_invariants ();
00320         }
00321         BOOST_UBLAS_INLINE
00322         void clear () {
00323             const size_type sizeM = layout_type::size_M (size1_, size2_);
00324             // FIXME should clear data () if this is done via value_type/*zero*/() then it is not size preserving
00325             for (size_type i = 0; i < sizeM; ++ i)
00326                 ref (data () [i]).clear ();
00327             storage_invariants ();
00328         }
00329 
00330         // Iterator types
00331     private:
00332         // Use vector iterator
00333         typedef typename A::const_iterator const_vectoriterator_type;
00334         typedef typename A::iterator vectoriterator_type;
00335         typedef typename A::value_type::const_iterator const_subiterator_type;
00336         typedef typename A::value_type::iterator subiterator_type;
00337 
00338         BOOST_UBLAS_INLINE
00339         true_reference at_element (size_type i, size_type j) {
00340             return ref (ref (data () [layout_type::index_M (i, j)]) [layout_type::index_m (i, j)]);
00341         }
00342 
00343     public:
00344         class const_iterator1;
00345         class iterator1;
00346         class const_iterator2;
00347         class iterator2;
00348         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
00349         typedef reverse_iterator_base1<iterator1> reverse_iterator1;
00350         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
00351         typedef reverse_iterator_base2<iterator2> reverse_iterator2;
00352 
00353         // Element lookup
00354         // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.    
00355         const_iterator1 find1 (int rank, size_type i, size_type j, int direction = 1) const {
00356             for (;;) {
00357                 const_vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
00358                 const_vectoriterator_type itv_end (data ().end ());
00359                 if (itv == itv_end)
00360                     return const_iterator1 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
00361 
00362                 const_subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
00363                 const_subiterator_type it_end ((*itv).end ());
00364                 if (rank == 0)
00365                     return const_iterator1 (*this, rank, i, j, itv, it);
00366                 if (it != it_end && it.index () == layout_type::index_m (i, j))
00367                     return const_iterator1 (*this, rank, i, j, itv, it);
00368                 if (direction > 0) {
00369                     if (layout_type::fast_i ()) {
00370                         if (it == it_end)
00371                             return const_iterator1 (*this, rank, i, j, itv, it);
00372                         i = it.index ();
00373                     } else {
00374                         if (i >= size1_)
00375                             return const_iterator1 (*this, rank, i, j, itv, it);
00376                         ++ i;
00377                     }
00378                 } else /* if (direction < 0)  */ {
00379                     if (layout_type::fast_i ()) {
00380                         if (it == (*itv).begin ())
00381                             return const_iterator1 (*this, rank, i, j, itv, it);
00382                         --it;
00383                         i = it.index ();
00384                     } else {
00385                         if (i == 0)
00386                             return const_iterator1 (*this, rank, i, j, itv, it);
00387                         -- i;
00388                     }
00389                 }
00390             }
00391         }
00392         // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.    
00393         iterator1 find1 (int rank, size_type i, size_type j, int direction = 1) {
00394             for (;;) {
00395                 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
00396                 vectoriterator_type itv_end (data ().end ());
00397                 if (itv == itv_end)
00398                     return iterator1 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
00399 
00400                 subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
00401                 subiterator_type it_end ((*itv).end ());
00402                 if (rank == 0)
00403                     return iterator1 (*this, rank, i, j, itv, it);
00404                 if (it != it_end && it.index () == layout_type::index_m (i, j))
00405                     return iterator1 (*this, rank, i, j, itv, it);
00406                 if (direction > 0) {
00407                     if (layout_type::fast_i ()) {
00408                         if (it == it_end)
00409                             return iterator1 (*this, rank, i, j, itv, it);
00410                         i = it.index ();
00411                     } else {
00412                         if (i >= size1_)
00413                             return iterator1 (*this, rank, i, j, itv, it);
00414                         ++ i;
00415                     }
00416                 } else /* if (direction < 0)  */ {
00417                     if (layout_type::fast_i ()) {
00418                         if (it == (*itv).begin ())
00419                             return iterator1 (*this, rank, i, j, itv, it);
00420                         --it;
00421                         i = it.index ();
00422                     } else {
00423                         if (i == 0)
00424                             return iterator1 (*this, rank, i, j, itv, it);
00425                         -- i;
00426                     }
00427                 }
00428             }
00429         }
00430         // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.    
00431         const_iterator2 find2 (int rank, size_type i, size_type j, int direction = 1) const {
00432             for (;;) {
00433                 const_vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
00434                 const_vectoriterator_type itv_end (data ().end ());
00435                 if (itv == itv_end)
00436                     return const_iterator2 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
00437 
00438                 const_subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
00439                 const_subiterator_type it_end ((*itv).end ());
00440                 if (rank == 0)
00441                     return const_iterator2 (*this, rank, i, j, itv, it);
00442                 if (it != it_end && it.index () == layout_type::index_m (i, j))
00443                     return const_iterator2 (*this, rank, i, j, itv, it);
00444                 if (direction > 0) {
00445                     if (layout_type::fast_j ()) {
00446                         if (it == it_end)
00447                             return const_iterator2 (*this, rank, i, j, itv, it);
00448                         j = it.index ();
00449                     } else {
00450                         if (j >= size2_)
00451                             return const_iterator2 (*this, rank, i, j, itv, it);
00452                         ++ j;
00453                     }
00454                 } else /* if (direction < 0)  */ {
00455                     if (layout_type::fast_j ()) {
00456                         if (it == (*itv).begin ())
00457                             return const_iterator2 (*this, rank, i, j, itv, it);
00458                         --it;
00459                         j = it.index ();
00460                     } else {
00461                         if (j == 0)
00462                             return const_iterator2 (*this, rank, i, j, itv, it);
00463                         -- j;
00464                     }
00465                 }
00466             }
00467         }
00468         // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.    
00469         iterator2 find2 (int rank, size_type i, size_type j, int direction = 1) {
00470             for (;;) {
00471                 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
00472                 vectoriterator_type itv_end (data ().end ());
00473                 if (itv == itv_end)
00474                     return iterator2 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
00475 
00476                 subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
00477                 subiterator_type it_end ((*itv).end ());
00478                 if (rank == 0)
00479                     return iterator2 (*this, rank, i, j, itv, it);
00480                 if (it != it_end && it.index () == layout_type::index_m (i, j))
00481                     return iterator2 (*this, rank, i, j, itv, it);
00482                 if (direction > 0) {
00483                     if (layout_type::fast_j ()) {
00484                         if (it == it_end)
00485                             return iterator2 (*this, rank, i, j, itv, it);
00486                         j = it.index ();
00487                     } else {
00488                         if (j >= size2_)
00489                             return iterator2 (*this, rank, i, j, itv, it);
00490                         ++ j;
00491                     }
00492                 } else /* if (direction < 0)  */ {
00493                     if (layout_type::fast_j ()) {
00494                         if (it == (*itv).begin ())
00495                             return iterator2 (*this, rank, i, j, itv, it);
00496                         --it;
00497                         j = it.index ();
00498                     } else {
00499                         if (j == 0)
00500                             return iterator2 (*this, rank, i, j, itv, it);
00501                         -- j;
00502                     }
00503                 }
00504             }
00505         }
00506 
00507 
00508         class const_iterator1:
00509             public container_const_reference<generalized_vector_of_vector>,
00510             public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
00511                                                const_iterator1, value_type> {
00512         public:
00513             typedef typename generalized_vector_of_vector::difference_type difference_type;
00514             typedef typename generalized_vector_of_vector::value_type value_type;
00515             typedef typename generalized_vector_of_vector::const_reference reference;
00516             typedef const typename generalized_vector_of_vector::pointer pointer;
00517 
00518             typedef const_iterator2 dual_iterator_type;
00519             typedef const_reverse_iterator2 dual_reverse_iterator_type;
00520 
00521             // Construction and destruction
00522             BOOST_UBLAS_INLINE
00523             const_iterator1 ():
00524                 container_const_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
00525             BOOST_UBLAS_INLINE
00526             const_iterator1 (const self_type &m, int rank, size_type i, size_type j, const const_vectoriterator_type &itv, const const_subiterator_type &it):
00527                 container_const_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
00528             BOOST_UBLAS_INLINE
00529             const_iterator1 (const iterator1 &it):
00530                 container_const_reference<self_type> (it ()), rank_ (it.rank_), i_ (it.i_), j_ (it.j_), itv_ (it.itv_), it_ (it.it_) {}
00531 
00532             // Arithmetic
00533             BOOST_UBLAS_INLINE
00534             const_iterator1 &operator ++ () {
00535                 if (rank_ == 1 && layout_type::fast_i ())
00536                     ++ it_;
00537                 else {
00538                     const self_type &m = (*this) ();
00539                     i_ = index1 () + 1;
00540                     if (rank_ == 1 && ++ itv_ == m.end1 ().itv_) 
00541                         *this = m.find1 (rank_, i_, j_, 1);
00542                     else if (rank_ == 1) {
00543                         it_ = (*itv_).begin ();
00544                         if (it_ == (*itv_).end () || index2 () != j_)
00545                             *this = m.find1 (rank_, i_, j_, 1);
00546                     }
00547                 }
00548                 return *this;
00549             }
00550             BOOST_UBLAS_INLINE
00551             const_iterator1 &operator -- () {
00552                 if (rank_ == 1 && layout_type::fast_i ())
00553                     -- it_;
00554                 else {
00555                     const self_type &m = (*this) ();
00556                     i_ = index1 () - 1;
00557                     if (rank_ == 1 && -- itv_ == m.end1 ().itv_)
00558                         *this = m.find1 (rank_, i_, j_, -1);
00559                     else if (rank_ == 1) {
00560                         it_ = (*itv_).begin ();
00561                         if (it_ == (*itv_).end () || index2 () != j_)
00562                             *this = m.find1 (rank_, i_, j_, -1);
00563                     } 
00564                 }
00565                 return *this;
00566             }
00567 
00568             // Dereference
00569             BOOST_UBLAS_INLINE
00570             const_reference operator * () const {
00571                 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
00572                 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
00573                 if (rank_ == 1) {
00574                     return *it_;
00575                 } else {
00576                     return (*this) () (i_, j_);
00577                 }
00578             }
00579 
00580 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
00581             BOOST_UBLAS_INLINE
00582 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00583             typename self_type::
00584 #endif
00585             const_iterator2 begin () const {
00586                 const self_type &m = (*this) ();
00587                 return m.find2 (1, index1 (), 0);
00588             }
00589             BOOST_UBLAS_INLINE
00590 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00591             typename self_type::
00592 #endif
00593             const_iterator2 end () const {
00594                 const self_type &m = (*this) ();
00595                 return m.find2 (1, index1 (), m.size2 ());
00596             }
00597             BOOST_UBLAS_INLINE
00598 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00599             typename self_type::
00600 #endif
00601             const_reverse_iterator2 rbegin () const {
00602                 return const_reverse_iterator2 (end ());
00603             }
00604             BOOST_UBLAS_INLINE
00605 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00606             typename self_type::
00607 #endif
00608             const_reverse_iterator2 rend () const {
00609                 return const_reverse_iterator2 (begin ());
00610             }
00611 #endif
00612 
00613             // Indices
00614             BOOST_UBLAS_INLINE
00615             size_type index1 () const {
00616                 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
00617                 if (rank_ == 1) {
00618                     BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
00619                     return layout_type::index_M (itv_.index (), it_.index ());
00620                 } else {
00621                     return i_;
00622                 }
00623             }
00624             BOOST_UBLAS_INLINE
00625             size_type index2 () const {
00626                 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
00627                 if (rank_ == 1) {
00628                     BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
00629                     return layout_type::index_m (itv_.index (), it_.index ());
00630                 } else {
00631                     return j_;
00632                 }
00633             }
00634 
00635             // Assignment
00636             BOOST_UBLAS_INLINE
00637             const_iterator1 &operator = (const const_iterator1 &it) {
00638                 container_const_reference<self_type>::assign (&it ());
00639                 rank_ = it.rank_;
00640                 i_ = it.i_;
00641                 j_ = it.j_;
00642                 itv_ = it.itv_;
00643                 it_ = it.it_;
00644                 return *this;
00645             }
00646 
00647             // Comparison
00648             BOOST_UBLAS_INLINE
00649             bool operator == (const const_iterator1 &it) const {
00650                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
00651                 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
00652                 if (rank_ == 1 || it.rank_ == 1) {
00653                     return it_ == it.it_;
00654                 } else {
00655                     return i_ == it.i_ && j_ == it.j_;
00656                 }
00657             }
00658 
00659         private:
00660             int rank_;
00661             size_type i_;
00662             size_type j_;
00663             const_vectoriterator_type itv_;
00664             const_subiterator_type it_;
00665         };
00666 
00667         BOOST_UBLAS_INLINE
00668         const_iterator1 begin1 () const {
00669             return find1 (0, 0, 0);
00670         }
00671         BOOST_UBLAS_INLINE
00672         const_iterator1 end1 () const {
00673             return find1 (0, size1_, 0);
00674         }
00675 
00676         class iterator1:
00677             public container_reference<generalized_vector_of_vector>,
00678             public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
00679                                                iterator1, value_type> {
00680         public:
00681             typedef typename generalized_vector_of_vector::difference_type difference_type;
00682             typedef typename generalized_vector_of_vector::value_type value_type;
00683             typedef typename generalized_vector_of_vector::true_reference reference;
00684             typedef typename generalized_vector_of_vector::pointer pointer;
00685 
00686             typedef iterator2 dual_iterator_type;
00687             typedef reverse_iterator2 dual_reverse_iterator_type;
00688 
00689             // Construction and destruction
00690             BOOST_UBLAS_INLINE
00691             iterator1 ():
00692                 container_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
00693             BOOST_UBLAS_INLINE
00694             iterator1 (self_type &m, int rank, size_type i, size_type j, const vectoriterator_type &itv, const subiterator_type &it):
00695                 container_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
00696 
00697             // Arithmetic
00698             BOOST_UBLAS_INLINE
00699             iterator1 &operator ++ () {
00700                 if (rank_ == 1 && layout_type::fast_i ())
00701                     ++ it_;
00702                 else {
00703                     self_type &m = (*this) ();
00704                     i_ = index1 () + 1;
00705                     if (rank_ == 1 && ++ itv_ == m.end1 ().itv_)
00706                         *this = m.find1 (rank_, i_, j_, 1);
00707                     else if (rank_ == 1) {
00708                         it_ = (*itv_).begin ();
00709                         if (it_ == (*itv_).end () || index2 () != j_)
00710                             *this = m.find1 (rank_, i_, j_, 1);
00711                     }
00712                 }
00713                 return *this;
00714             }
00715             BOOST_UBLAS_INLINE
00716             iterator1 &operator -- () {
00717                 if (rank_ == 1 && layout_type::fast_i ())
00718                     -- it_;
00719                 else {
00720                     self_type &m = (*this) ();
00721                     i_ = index1 () - 1;
00722                     if (rank_ == 1 && -- itv_ == m.end1 ().itv_)
00723                         *this = m.find1 (rank_, i_, j_, -1);
00724                     else if (rank_ == 1) {
00725                         it_ = (*itv_).begin ();
00726                         if (it_ == (*itv_).end () || index2 () != j_)
00727                             *this = m.find1 (rank_, i_, j_, -1);
00728                     }
00729                 }
00730                 return *this;
00731             }
00732 
00733             // Dereference
00734             BOOST_UBLAS_INLINE
00735             true_reference operator * () const {
00736                 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
00737                 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
00738                 if (rank_ == 1) {
00739                     return *it_;
00740                 } else {
00741                     return (*this) ().at_element (i_, j_);
00742                 }
00743             }
00744 
00745 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
00746             BOOST_UBLAS_INLINE
00747 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00748             typename self_type::
00749 #endif
00750             iterator2 begin () const {
00751                 self_type &m = (*this) ();
00752                 return m.find2 (1, index1 (), 0);
00753             }
00754             BOOST_UBLAS_INLINE
00755 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00756             typename self_type::
00757 #endif
00758             iterator2 end () const {
00759                 self_type &m = (*this) ();
00760                 return m.find2 (1, index1 (), m.size2 ());
00761             }
00762             BOOST_UBLAS_INLINE
00763 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00764             typename self_type::
00765 #endif
00766             reverse_iterator2 rbegin () const {
00767                 return reverse_iterator2 (end ());
00768             }
00769             BOOST_UBLAS_INLINE
00770 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00771             typename self_type::
00772 #endif
00773             reverse_iterator2 rend () const {
00774                 return reverse_iterator2 (begin ());
00775             }
00776 #endif
00777 
00778             // Indices
00779             BOOST_UBLAS_INLINE
00780             size_type index1 () const {
00781                 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
00782                 if (rank_ == 1) {
00783                     BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
00784                     return layout_type::index_M (itv_.index (), it_.index ());
00785                 } else {
00786                     return i_;
00787                 }
00788             }
00789             BOOST_UBLAS_INLINE
00790             size_type index2 () const {
00791                 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
00792                 if (rank_ == 1) {
00793                     BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
00794                     return layout_type::index_m (itv_.index (), it_.index ());
00795                 } else {
00796                     return j_;
00797                 }
00798             }
00799 
00800             // Assignment 
00801             BOOST_UBLAS_INLINE
00802             iterator1 &operator = (const iterator1 &it) {
00803                 container_reference<self_type>::assign (&it ());
00804                 rank_ = it.rank_;
00805                 i_ = it.i_;
00806                 j_ = it.j_;
00807                 itv_ = it.itv_;
00808                 it_ = it.it_;
00809                 return *this;
00810             }
00811 
00812             // Comparison
00813             BOOST_UBLAS_INLINE
00814             bool operator == (const iterator1 &it) const {
00815                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
00816                 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
00817                 if (rank_ == 1 || it.rank_ == 1) {
00818                     return it_ == it.it_;
00819                 } else {
00820                     return i_ == it.i_ && j_ == it.j_;
00821                 }
00822             }
00823 
00824         private:
00825             int rank_;
00826             size_type i_;
00827             size_type j_;
00828             vectoriterator_type itv_;
00829             subiterator_type it_;
00830             
00831             friend class const_iterator1;
00832         };
00833 
00834         BOOST_UBLAS_INLINE
00835         iterator1 begin1 () {
00836             return find1 (0, 0, 0);
00837         }
00838         BOOST_UBLAS_INLINE
00839         iterator1 end1 () {
00840             return find1 (0, size1_, 0);
00841         }
00842 
00843         class const_iterator2:
00844             public container_const_reference<generalized_vector_of_vector>,
00845             public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
00846                                                const_iterator2, value_type> {
00847         public:
00848             typedef typename generalized_vector_of_vector::difference_type difference_type;
00849             typedef typename generalized_vector_of_vector::value_type value_type;
00850             typedef typename generalized_vector_of_vector::const_reference reference;
00851             typedef const typename generalized_vector_of_vector::pointer pointer;
00852 
00853             typedef const_iterator1 dual_iterator_type;
00854             typedef const_reverse_iterator1 dual_reverse_iterator_type;
00855 
00856             // Construction and destruction
00857             BOOST_UBLAS_INLINE
00858             const_iterator2 ():
00859                 container_const_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
00860             BOOST_UBLAS_INLINE
00861             const_iterator2 (const self_type &m, int rank, size_type i, size_type j, const const_vectoriterator_type &itv, const const_subiterator_type &it):
00862                 container_const_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
00863             BOOST_UBLAS_INLINE
00864             const_iterator2 (const iterator2 &it):
00865                 container_const_reference<self_type> (it ()), rank_ (it.rank_), i_ (it.i_), j_ (it.j_), itv_ (it.itv_), it_ (it.it_) {}
00866 
00867             // Arithmetic
00868             BOOST_UBLAS_INLINE
00869             const_iterator2 &operator ++ () {
00870                 if (rank_ == 1 && layout_type::fast_j ())
00871                     ++ it_;
00872                 else {
00873                     const self_type &m = (*this) ();
00874                     j_ = index2 () + 1;
00875                     if (rank_ == 1 && ++ itv_ == m.end2 ().itv_) 
00876                         *this = m.find2 (rank_, i_, j_, 1);
00877                     else if (rank_ == 1) {
00878                         it_ = (*itv_).begin ();
00879                         if (it_ == (*itv_).end () || index1 () != i_)
00880                             *this = m.find2 (rank_, i_, j_, 1);
00881                     }
00882                 }
00883                 return *this;
00884             }
00885             BOOST_UBLAS_INLINE
00886             const_iterator2 &operator -- () {
00887                 if (rank_ == 1 && layout_type::fast_j ())
00888                     -- it_;
00889                 else {
00890                     const self_type &m = (*this) ();
00891                     j_ = index2 () - 1;
00892                     if (rank_ == 1 && -- itv_ == m.end2 ().itv_)
00893                         *this = m.find2 (rank_, i_, j_, -1);
00894                     else if (rank_ == 1) {
00895                         it_ = (*itv_).begin ();
00896                         if (it_ == (*itv_).end () || index1 () != i_)
00897                             *this = m.find2 (rank_, i_, j_, -1);
00898                     }
00899                 }
00900                 return *this;
00901             }
00902 
00903             // Dereference
00904             BOOST_UBLAS_INLINE
00905             const_reference operator * () const {
00906                 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
00907                 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
00908                 if (rank_ == 1) {
00909                     return *it_;
00910                 } else {
00911                     return (*this) () (i_, j_);
00912                 }
00913             }
00914 
00915 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
00916             BOOST_UBLAS_INLINE
00917 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00918             typename self_type::
00919 #endif
00920             const_iterator1 begin () const {
00921                 const self_type &m = (*this) ();
00922                 return m.find1 (1, 0, index2 ());
00923             }
00924             BOOST_UBLAS_INLINE
00925 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00926             typename self_type::
00927 #endif
00928             const_iterator1 end () const {
00929                 const self_type &m = (*this) ();
00930                 return m.find1 (1, m.size1 (), index2 ());
00931             }
00932             BOOST_UBLAS_INLINE
00933 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00934             typename self_type::
00935 #endif
00936             const_reverse_iterator1 rbegin () const {
00937                 return const_reverse_iterator1 (end ());
00938             }
00939             BOOST_UBLAS_INLINE
00940 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00941             typename self_type::
00942 #endif
00943             const_reverse_iterator1 rend () const {
00944                 return const_reverse_iterator1 (begin ());
00945             }
00946 #endif
00947 
00948             // Indices
00949             BOOST_UBLAS_INLINE
00950             size_type index1 () const {
00951                 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
00952                 if (rank_ == 1) {
00953                     BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
00954                     return layout_type::index_M (itv_.index (), it_.index ());
00955                 } else {
00956                     return i_;
00957                 }
00958             }
00959             BOOST_UBLAS_INLINE
00960             size_type index2 () const {
00961                 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
00962                 if (rank_ == 1) {
00963                     BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
00964                     return layout_type::index_m (itv_.index (), it_.index ());
00965                 } else {
00966                     return j_;
00967                 }
00968             }
00969 
00970             // Assignment 
00971             BOOST_UBLAS_INLINE
00972             const_iterator2 &operator = (const const_iterator2 &it) {
00973                 container_const_reference<self_type>::assign (&it ());
00974                 rank_ = it.rank_;
00975                 i_ = it.i_;
00976                 j_ = it.j_;
00977                 itv_ = it.itv_;
00978                 it_ = it.it_;
00979                 return *this;
00980             }
00981 
00982             // Comparison
00983             BOOST_UBLAS_INLINE
00984             bool operator == (const const_iterator2 &it) const {
00985                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
00986                 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
00987                 if (rank_ == 1 || it.rank_ == 1) {
00988                     return it_ == it.it_;
00989                 } else {
00990                     return i_ == it.i_ && j_ == it.j_;
00991                 }
00992             }
00993 
00994         private:
00995             int rank_;
00996             size_type i_;
00997             size_type j_;
00998             const_vectoriterator_type itv_;
00999             const_subiterator_type it_;
01000         };
01001 
01002         BOOST_UBLAS_INLINE
01003         const_iterator2 begin2 () const {
01004             return find2 (0, 0, 0);
01005         }
01006         BOOST_UBLAS_INLINE
01007         const_iterator2 end2 () const {
01008             return find2 (0, 0, size2_);
01009         }
01010 
01011         class iterator2:
01012             public container_reference<generalized_vector_of_vector>,
01013             public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
01014                                                iterator2, value_type> {
01015         public:
01016             typedef typename generalized_vector_of_vector::difference_type difference_type;
01017             typedef typename generalized_vector_of_vector::value_type value_type;
01018             typedef typename generalized_vector_of_vector::true_reference reference;
01019             typedef typename generalized_vector_of_vector::pointer pointer;
01020 
01021             typedef iterator1 dual_iterator_type;
01022             typedef reverse_iterator1 dual_reverse_iterator_type;
01023 
01024             // Construction and destruction
01025             BOOST_UBLAS_INLINE
01026             iterator2 ():
01027                 container_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
01028             BOOST_UBLAS_INLINE
01029             iterator2 (self_type &m, int rank, size_type i, size_type j, const vectoriterator_type &itv, const subiterator_type &it):
01030                 container_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
01031 
01032             // Arithmetic
01033             BOOST_UBLAS_INLINE
01034             iterator2 &operator ++ () {
01035                 if (rank_ == 1 && layout_type::fast_j ())
01036                     ++ it_;
01037                 else {
01038                     self_type &m = (*this) ();
01039                     j_ = index2 () + 1;
01040                     if (rank_ == 1 && ++ itv_ == m.end2 ().itv_)
01041                         *this = m.find2 (rank_, i_, j_, 1);
01042                     else if (rank_ == 1) {
01043                         it_ = (*itv_).begin ();
01044                         if (it_ == (*itv_).end () || index1 () != i_)
01045                             *this = m.find2 (rank_, i_, j_, 1);
01046                     }
01047                 }
01048                 return *this;
01049             }
01050             BOOST_UBLAS_INLINE
01051             iterator2 &operator -- () {
01052                 if (rank_ == 1 && layout_type::fast_j ())
01053                     -- it_;
01054                 else {
01055                     self_type &m = (*this) ();
01056                     j_ = index2 () - 1;
01057                     if (rank_ == 1 && -- itv_ == m.end2 ().itv_)
01058                         *this = m.find2 (rank_, i_, j_, -1);
01059                     else if (rank_ == 1) {
01060                         it_ = (*itv_).begin ();
01061                         if (it_ == (*itv_).end () || index1 () != i_)
01062                             *this = m.find2 (rank_, i_, j_, -1);
01063                     } 
01064                 }
01065                 return *this;
01066             }
01067 
01068             // Dereference
01069             BOOST_UBLAS_INLINE
01070             true_reference operator * () const {
01071                 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
01072                 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
01073                 if (rank_ == 1) {
01074                     return *it_;
01075                 } else {
01076                     return (*this) ().at_element (i_, j_);
01077                 }
01078             }
01079 
01080 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
01081             BOOST_UBLAS_INLINE
01082 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01083             typename self_type::
01084 #endif
01085             iterator1 begin () const {
01086                 self_type &m = (*this) ();
01087                 return m.find1 (1, 0, index2 ());
01088             }
01089             BOOST_UBLAS_INLINE
01090 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01091             typename self_type::
01092 #endif
01093             iterator1 end () const {
01094                 self_type &m = (*this) ();
01095                 return m.find1 (1, m.size1 (), index2 ());
01096             }
01097             BOOST_UBLAS_INLINE
01098 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01099             typename self_type::
01100 #endif
01101             reverse_iterator1 rbegin () const {
01102                 return reverse_iterator1 (end ());
01103             }
01104             BOOST_UBLAS_INLINE
01105 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01106             typename self_type::
01107 #endif
01108             reverse_iterator1 rend () const {
01109                 return reverse_iterator1 (begin ());
01110             }
01111 #endif
01112 
01113             // Indices
01114             BOOST_UBLAS_INLINE
01115             size_type index1 () const {
01116                 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
01117                 if (rank_ == 1) {
01118                     BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
01119                     return layout_type::index_M (itv_.index (), it_.index ());
01120                 } else {
01121                     return i_;
01122                 }
01123             }
01124             BOOST_UBLAS_INLINE
01125             size_type index2 () const {
01126                 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
01127                 if (rank_ == 1) {
01128                     BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
01129                     return layout_type::index_m (itv_.index (), it_.index ());
01130                 } else {
01131                     return j_;
01132                 }
01133             }
01134 
01135             // Assignment 
01136             BOOST_UBLAS_INLINE
01137             iterator2 &operator = (const iterator2 &it) {
01138                 container_reference<self_type>::assign (&it ());
01139                 rank_ = it.rank_;
01140                 i_ = it.i_;
01141                 j_ = it.j_;
01142                 itv_ = it.itv_;
01143                 it_ = it.it_;
01144                 return *this;
01145             }
01146 
01147             // Comparison
01148             BOOST_UBLAS_INLINE
01149             bool operator == (const iterator2 &it) const {
01150                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
01151                 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
01152                 if (rank_ == 1 || it.rank_ == 1) {
01153                     return it_ == it.it_;
01154                 } else {
01155                     return i_ == it.i_ && j_ == it.j_;
01156                 }
01157             }
01158 
01159         private:
01160             int rank_;
01161             size_type i_;
01162             size_type j_;
01163             vectoriterator_type itv_;
01164             subiterator_type it_;
01165 
01166             friend class const_iterator2;
01167         };
01168 
01169         BOOST_UBLAS_INLINE
01170         iterator2 begin2 () {
01171             return find2 (0, 0, 0);
01172         }
01173         BOOST_UBLAS_INLINE
01174         iterator2 end2 () {
01175             return find2 (0, 0, size2_);
01176         }
01177 
01178         // Reverse iterators
01179 
01180         BOOST_UBLAS_INLINE
01181         const_reverse_iterator1 rbegin1 () const {
01182             return const_reverse_iterator1 (end1 ());
01183         }
01184         BOOST_UBLAS_INLINE
01185         const_reverse_iterator1 rend1 () const {
01186             return const_reverse_iterator1 (begin1 ());
01187         }
01188 
01189         BOOST_UBLAS_INLINE
01190         reverse_iterator1 rbegin1 () {
01191             return reverse_iterator1 (end1 ());
01192         }
01193         BOOST_UBLAS_INLINE
01194         reverse_iterator1 rend1 () {
01195             return reverse_iterator1 (begin1 ());
01196         }
01197 
01198         BOOST_UBLAS_INLINE
01199         const_reverse_iterator2 rbegin2 () const {
01200             return const_reverse_iterator2 (end2 ());
01201         }
01202         BOOST_UBLAS_INLINE
01203         const_reverse_iterator2 rend2 () const {
01204             return const_reverse_iterator2 (begin2 ());
01205         }
01206 
01207         BOOST_UBLAS_INLINE
01208         reverse_iterator2 rbegin2 () {
01209             return reverse_iterator2 (end2 ());
01210         }
01211         BOOST_UBLAS_INLINE
01212         reverse_iterator2 rend2 () {
01213             return reverse_iterator2 (begin2 ());
01214         }
01215 
01216          // Serialization
01217         template<class Archive>
01218         void serialize(Archive & ar, const unsigned int /* file_version */){
01219         
01220             // we need to copy to a collection_size_type to get a portable
01221             // and efficient serialization
01222             serialization::collection_size_type s1 (size1_);
01223             serialization::collection_size_type s2 (size2_);
01224           
01225             // serialize the sizes
01226             ar & serialization::make_nvp("size1",s1)
01227                & serialization::make_nvp("size2",s2);
01228 
01229             // copy the values back if loading
01230             if (Archive::is_loading::value) {
01231                 size1_ = s1;
01232                 size2_ = s2;
01233             }
01234 
01235             ar & serialization::make_nvp("data", data_);
01236 
01237             storage_invariants();
01238         }
01239 
01240     private:
01241         void storage_invariants () const
01242         {
01243             BOOST_UBLAS_CHECK (layout_type::size_M (size1_, size2_) + 1 == data_.size (), internal_logic ());
01244             BOOST_UBLAS_CHECK (data ().begin () != data ().end (), internal_logic ());
01245 
01246         }
01247         size_type size1_;
01248         size_type size2_;
01249         array_type data_;
01250         static const value_type zero_;
01251     };
01252 
01253     template<class T, class L, class A>
01254     const typename generalized_vector_of_vector<T, L, A>::value_type generalized_vector_of_vector<T, L, A>::zero_ = value_type/*zero*/();
01255 
01256 }}}
01257 
01258 #endif