os/ossrv/ossrv_pub/boost_apis/boost/numeric/ublas/symmetric.hpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 //
     2 //  Copyright (c) 2000-2002
     3 //  Joerg Walter, Mathias Koch
     4 //
     5 //  Permission to use, copy, modify, distribute and sell this software
     6 //  and its documentation for any purpose is hereby granted without fee,
     7 //  provided that the above copyright notice appear in all copies and
     8 //  that both that copyright notice and this permission notice appear
     9 //  in supporting documentation.  The authors make no representations
    10 //  about the suitability of this software for any purpose.
    11 //  It is provided "as is" without express or implied warranty.
    12 //
    13 //  The authors gratefully acknowledge the support of
    14 //  GeNeSys mbH & Co. KG in producing this work.
    15 //
    16 
    17 #ifndef _BOOST_UBLAS_SYMMETRIC_
    18 #define _BOOST_UBLAS_SYMMETRIC_
    19 
    20 #include <boost/numeric/ublas/matrix.hpp>
    21 #include <boost/numeric/ublas/detail/temporary.hpp>
    22 
    23 // Iterators based on ideas of Jeremy Siek
    24 // Symmetric matrices are square. Thanks to Peter Schmitteckert for spotting this.
    25 
    26 namespace boost { namespace numeric { namespace ublas {
    27 
    28     template<class M>
    29     bool is_symmetric (const M &m) {
    30         typedef typename M::size_type size_type;
    31 
    32         if (m.size1 () != m.size2 ())
    33             return false;
    34         size_type size = BOOST_UBLAS_SAME (m.size1 (), m.size2 ());
    35         for (size_type i = 0; i < size; ++ i) {
    36             for (size_type j = i; j < size; ++ j) {
    37                 if (m (i, j) != m (j, i))
    38                     return false;
    39             }
    40         }
    41         return true;
    42     }
    43 
    44     // Array based symmetric matrix class
    45     template<class T, class TRI, class L, class A>
    46     class symmetric_matrix:
    47         public matrix_container<symmetric_matrix<T, TRI, L, A> > {
    48 
    49         typedef T *pointer;
    50         typedef TRI triangular_type;
    51         typedef L layout_type;
    52         typedef symmetric_matrix<T, TRI, L, A> self_type;
    53     public:
    54 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
    55         using matrix_container<self_type>::operator ();
    56 #endif
    57         typedef typename A::size_type size_type;
    58         typedef typename A::difference_type difference_type;
    59         typedef T value_type;
    60         typedef const T &const_reference;
    61         typedef T &reference;
    62         typedef A array_type;
    63 
    64         typedef const matrix_reference<const self_type> const_closure_type;
    65         typedef matrix_reference<self_type> closure_type;
    66         typedef vector<T, A> vector_temporary_type;
    67         typedef matrix<T, L, A> matrix_temporary_type;  // general sub-matrix
    68         typedef packed_tag storage_category;
    69         typedef typename L::orientation_category orientation_category;
    70 
    71         // Construction and destruction
    72         BOOST_UBLAS_INLINE
    73         symmetric_matrix ():
    74             matrix_container<self_type> (),
    75             size_ (0), data_ (0) {}
    76         BOOST_UBLAS_INLINE
    77         symmetric_matrix (size_type size):
    78             matrix_container<self_type> (),
    79             size_ (BOOST_UBLAS_SAME (size, size)), data_ (triangular_type::packed_size (layout_type (), size, size)) {
    80         }
    81         BOOST_UBLAS_INLINE
    82         symmetric_matrix (size_type size1, size_type size2):
    83             matrix_container<self_type> (),
    84             size_ (BOOST_UBLAS_SAME (size1, size2)), data_ (triangular_type::packed_size (layout_type (), size1, size2)) {
    85         }
    86         BOOST_UBLAS_INLINE
    87         symmetric_matrix (size_type size, const array_type &data):
    88             matrix_container<self_type> (),
    89             size_ (size), data_ (data) {}
    90         BOOST_UBLAS_INLINE
    91         symmetric_matrix (const symmetric_matrix &m):
    92             matrix_container<self_type> (),
    93             size_ (m.size_), data_ (m.data_) {}
    94         template<class AE>
    95         BOOST_UBLAS_INLINE
    96         symmetric_matrix (const matrix_expression<AE> &ae):
    97             matrix_container<self_type> (),
    98             size_ (BOOST_UBLAS_SAME (ae ().size1 (), ae ().size2 ())),
    99             data_ (triangular_type::packed_size (layout_type (), size_, size_)) {
   100             matrix_assign<scalar_assign> (*this, ae);
   101         }
   102 
   103         // Accessors
   104         BOOST_UBLAS_INLINE
   105         size_type size1 () const {
   106             return size_;
   107         }
   108         BOOST_UBLAS_INLINE
   109         size_type size2 () const {
   110             return size_;
   111         }
   112 
   113         // Storage accessors
   114         BOOST_UBLAS_INLINE
   115         const array_type &data () const {
   116             return data_;
   117         }
   118         BOOST_UBLAS_INLINE
   119         array_type &data () {
   120             return data_;
   121         }
   122 
   123         // Resizing
   124         BOOST_UBLAS_INLINE
   125         void resize (size_type size, bool preserve = true) {
   126             if (preserve) {
   127                 self_type temporary (size, size);
   128                 detail::matrix_resize_preserve<layout_type> (*this, temporary);
   129             }
   130             else {
   131                 data ().resize (triangular_type::packed_size (layout_type (), size, size));
   132                 size_ = size;
   133             }
   134         }
   135         BOOST_UBLAS_INLINE
   136         void resize (size_type size1, size_type size2, bool preserve = true) {
   137             resize (BOOST_UBLAS_SAME (size1, size2), preserve);
   138         }
   139         BOOST_UBLAS_INLINE
   140         void resize_packed_preserve (size_type size) {
   141             size_ = BOOST_UBLAS_SAME (size, size);
   142             data ().resize (triangular_type::packed_size (layout_type (), size_, size_), value_type ());
   143         }
   144 
   145         // Element access
   146         BOOST_UBLAS_INLINE
   147         const_reference operator () (size_type i, size_type j) const {
   148             BOOST_UBLAS_CHECK (i < size_, bad_index ());
   149             BOOST_UBLAS_CHECK (j < size_, bad_index ());
   150             if (triangular_type::other (i, j))
   151                 return data () [triangular_type::element (layout_type (), i, size_, j, size_)];
   152             else
   153                 return data () [triangular_type::element (layout_type (), j, size_, i, size_)];
   154         }
   155         BOOST_UBLAS_INLINE
   156         reference at_element (size_type i, size_type j) {
   157             BOOST_UBLAS_CHECK (i < size_, bad_index ());
   158             BOOST_UBLAS_CHECK (j < size_, bad_index ());
   159             return data () [triangular_type::element (layout_type (), i, size_, j, size_)];
   160         }
   161         BOOST_UBLAS_INLINE
   162         reference operator () (size_type i, size_type j) {
   163             BOOST_UBLAS_CHECK (i < size_, bad_index ());
   164             BOOST_UBLAS_CHECK (j < size_, bad_index ());
   165             if (triangular_type::other (i, j))
   166                 return data () [triangular_type::element (layout_type (), i, size_, j, size_)];
   167             else
   168                 return data () [triangular_type::element (layout_type (), j, size_, i, size_)];
   169         }
   170 
   171         // Element assignment
   172         BOOST_UBLAS_INLINE
   173         reference insert_element (size_type i, size_type j, const_reference t) {
   174             return (operator () (i, j) = t);
   175         }
   176         BOOST_UBLAS_INLINE
   177         void erase_element (size_type i, size_type j) {
   178             operator () (i, j) = value_type/*zero*/();
   179         }
   180         
   181         // Zeroing
   182         BOOST_UBLAS_INLINE
   183         void clear () {
   184             // data ().clear ();
   185             std::fill (data ().begin (), data ().end (), value_type/*zero*/());
   186         }
   187 
   188         // Assignment
   189         BOOST_UBLAS_INLINE
   190         symmetric_matrix &operator = (const symmetric_matrix &m) {
   191             size_ = m.size_;
   192             data () = m.data ();
   193             return *this;
   194         }
   195         BOOST_UBLAS_INLINE
   196         symmetric_matrix &assign_temporary (symmetric_matrix &m) {
   197             swap (m);
   198             return *this;
   199         }
   200         template<class AE>
   201         BOOST_UBLAS_INLINE
   202         symmetric_matrix &operator = (const matrix_expression<AE> &ae) {
   203             self_type temporary (ae);
   204             return assign_temporary (temporary);
   205         }
   206         template<class AE>
   207         BOOST_UBLAS_INLINE
   208         symmetric_matrix &assign (const matrix_expression<AE> &ae) {
   209             matrix_assign<scalar_assign> (*this, ae);
   210             return *this;
   211         }
   212         template<class AE>
   213         BOOST_UBLAS_INLINE
   214         symmetric_matrix& operator += (const matrix_expression<AE> &ae) {
   215             self_type temporary (*this + ae);
   216             return assign_temporary (temporary);
   217         }
   218         template<class AE>
   219         BOOST_UBLAS_INLINE
   220         symmetric_matrix &plus_assign (const matrix_expression<AE> &ae) {
   221             matrix_assign<scalar_plus_assign> (*this, ae);
   222             return *this;
   223         }
   224         template<class AE>
   225         BOOST_UBLAS_INLINE
   226         symmetric_matrix& operator -= (const matrix_expression<AE> &ae) {
   227             self_type temporary (*this - ae);
   228             return assign_temporary (temporary);
   229         }
   230         template<class AE>
   231         BOOST_UBLAS_INLINE
   232         symmetric_matrix &minus_assign (const matrix_expression<AE> &ae) {
   233             matrix_assign<scalar_minus_assign> (*this, ae);
   234             return *this;
   235         }
   236         template<class AT>
   237         BOOST_UBLAS_INLINE
   238         symmetric_matrix& operator *= (const AT &at) {
   239             matrix_assign_scalar<scalar_multiplies_assign> (*this, at);
   240             return *this;
   241         }
   242         template<class AT>
   243         BOOST_UBLAS_INLINE
   244         symmetric_matrix& operator /= (const AT &at) {
   245             matrix_assign_scalar<scalar_divides_assign> (*this, at);
   246             return *this;
   247         }
   248 
   249         // Swapping
   250         BOOST_UBLAS_INLINE
   251         void swap (symmetric_matrix &m) {
   252             if (this != &m) {
   253                 std::swap (size_, m.size_);
   254                 data ().swap (m.data ());
   255             }
   256         }
   257         BOOST_UBLAS_INLINE
   258         friend void swap (symmetric_matrix &m1, symmetric_matrix &m2) {
   259             m1.swap (m2);
   260         }
   261 
   262         // Iterator types
   263 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
   264         typedef indexed_iterator1<self_type, packed_random_access_iterator_tag> iterator1;
   265         typedef indexed_iterator2<self_type, packed_random_access_iterator_tag> iterator2;
   266         typedef indexed_const_iterator1<self_type, dense_random_access_iterator_tag> const_iterator1;
   267         typedef indexed_const_iterator2<self_type, dense_random_access_iterator_tag> const_iterator2;
   268 #else
   269         class const_iterator1;
   270         class iterator1;
   271         class const_iterator2;
   272         class iterator2;
   273 #endif
   274         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
   275         typedef reverse_iterator_base1<iterator1> reverse_iterator1;
   276         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
   277         typedef reverse_iterator_base2<iterator2> reverse_iterator2;
   278 
   279         // Element lookup
   280         BOOST_UBLAS_INLINE
   281         const_iterator1 find1 (int /* rank */, size_type i, size_type j) const {
   282             return const_iterator1 (*this, i, j);
   283         }
   284         BOOST_UBLAS_INLINE
   285         iterator1 find1 (int rank, size_type i, size_type j) {
   286             if (rank == 1)
   287                 i = triangular_type::mutable_restrict1 (i, j);
   288             return iterator1 (*this, i, j);
   289         }
   290         BOOST_UBLAS_INLINE
   291         const_iterator2 find2 (int /* rank */, size_type i, size_type j) const {
   292             return const_iterator2 (*this, i, j);
   293         }
   294         BOOST_UBLAS_INLINE
   295         iterator2 find2 (int rank, size_type i, size_type j) {
   296             if (rank == 1)
   297                 j = triangular_type::mutable_restrict2 (i, j);
   298             return iterator2 (*this, i, j);
   299         }
   300 
   301         // Iterators simply are indices.
   302 
   303 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
   304         class const_iterator1:
   305             public container_const_reference<symmetric_matrix>,
   306             public random_access_iterator_base<dense_random_access_iterator_tag,
   307                                                const_iterator1, value_type> {
   308         public:
   309             typedef typename symmetric_matrix::value_type value_type;
   310             typedef typename symmetric_matrix::difference_type difference_type;
   311             typedef typename symmetric_matrix::const_reference reference;
   312             typedef const typename symmetric_matrix::pointer pointer;
   313 
   314             typedef const_iterator2 dual_iterator_type;
   315             typedef const_reverse_iterator2 dual_reverse_iterator_type;
   316 
   317             // Construction and destruction
   318             BOOST_UBLAS_INLINE
   319             const_iterator1 ():
   320                 container_const_reference<self_type> (), it1_ (), it2_ () {}
   321             BOOST_UBLAS_INLINE
   322             const_iterator1 (const self_type &m, size_type it1, size_type it2):
   323                 container_const_reference<self_type> (m), it1_ (it1), it2_ (it2) {}
   324             BOOST_UBLAS_INLINE
   325             const_iterator1 (const iterator1 &it):
   326                 container_const_reference<self_type> (it ()), it1_ (it.it1_), it2_ (it.it2_) {}
   327 
   328             // Arithmetic
   329             BOOST_UBLAS_INLINE
   330             const_iterator1 &operator ++ () {
   331                 ++ it1_;
   332                 return *this;
   333             }
   334             BOOST_UBLAS_INLINE
   335             const_iterator1 &operator -- () {
   336                 -- it1_;
   337                 return *this;
   338             }
   339             BOOST_UBLAS_INLINE
   340             const_iterator1 &operator += (difference_type n) {
   341                 it1_ += n;
   342                 return *this;
   343             }
   344             BOOST_UBLAS_INLINE
   345             const_iterator1 &operator -= (difference_type n) {
   346                 it1_ -= n;
   347                 return *this;
   348             }
   349             BOOST_UBLAS_INLINE
   350             difference_type operator - (const const_iterator1 &it) const {
   351                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   352                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
   353                 return it1_ - it.it1_;
   354             }
   355 
   356             // Dereference
   357             BOOST_UBLAS_INLINE
   358             const_reference operator * () const {
   359                 return (*this) () (it1_, it2_);
   360             }
   361             BOOST_UBLAS_INLINE
   362             const_reference operator [] (difference_type n) const {
   363                 return *(*this + n);
   364             }
   365 
   366 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
   367             BOOST_UBLAS_INLINE
   368 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   369             typename self_type::
   370 #endif
   371             const_iterator2 begin () const {
   372                 return (*this) ().find2 (1, it1_, 0);
   373             }
   374             BOOST_UBLAS_INLINE
   375 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   376             typename self_type::
   377 #endif
   378             const_iterator2 end () const {
   379                 return (*this) ().find2 (1, it1_, (*this) ().size2 ());
   380             }
   381             BOOST_UBLAS_INLINE
   382 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   383             typename self_type::
   384 #endif
   385             const_reverse_iterator2 rbegin () const {
   386                 return const_reverse_iterator2 (end ());
   387             }
   388             BOOST_UBLAS_INLINE
   389 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   390             typename self_type::
   391 #endif
   392             const_reverse_iterator2 rend () const {
   393                 return const_reverse_iterator2 (begin ());
   394             }
   395 #endif
   396 
   397             // Indices
   398             BOOST_UBLAS_INLINE
   399             size_type index1 () const {
   400                 return it1_;
   401             }
   402             BOOST_UBLAS_INLINE
   403             size_type index2 () const {
   404                 return it2_;
   405             }
   406 
   407             // Assignment
   408             BOOST_UBLAS_INLINE
   409             const_iterator1 &operator = (const const_iterator1 &it) {
   410                 container_const_reference<self_type>::assign (&it ());
   411                 it1_ = it.it1_;
   412                 it2_ = it.it2_;
   413                 return *this;
   414             }
   415 
   416             // Comparison
   417             BOOST_UBLAS_INLINE
   418             bool operator == (const const_iterator1 &it) const {
   419                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   420                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
   421                 return it1_ == it.it1_;
   422             }
   423             BOOST_UBLAS_INLINE
   424             bool operator < (const const_iterator1 &it) const {
   425                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   426                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
   427                 return it1_ < it.it1_;
   428             }
   429 
   430         private:
   431             size_type it1_;
   432             size_type it2_;
   433         };
   434 #endif
   435 
   436         BOOST_UBLAS_INLINE
   437         const_iterator1 begin1 () const {
   438             return find1 (0, 0, 0);
   439         }
   440         BOOST_UBLAS_INLINE
   441         const_iterator1 end1 () const {
   442             return find1 (0, size_, 0);
   443         }
   444 
   445 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
   446         class iterator1:
   447             public container_reference<symmetric_matrix>,
   448             public random_access_iterator_base<packed_random_access_iterator_tag,
   449                                                iterator1, value_type> {
   450         public:
   451             typedef typename symmetric_matrix::value_type value_type;
   452             typedef typename symmetric_matrix::difference_type difference_type;
   453             typedef typename symmetric_matrix::reference reference;
   454             typedef typename symmetric_matrix::pointer pointer;
   455             typedef iterator2 dual_iterator_type;
   456             typedef reverse_iterator2 dual_reverse_iterator_type;
   457 
   458             // Construction and destruction
   459             BOOST_UBLAS_INLINE
   460             iterator1 ():
   461                 container_reference<self_type> (), it1_ (), it2_ () {}
   462             BOOST_UBLAS_INLINE
   463             iterator1 (self_type &m, size_type it1, size_type it2):
   464                 container_reference<self_type> (m), it1_ (it1), it2_ (it2) {}
   465 
   466             // Arithmetic
   467             BOOST_UBLAS_INLINE
   468             iterator1 &operator ++ () {
   469                 ++ it1_;
   470                 return *this;
   471             }
   472             BOOST_UBLAS_INLINE
   473             iterator1 &operator -- () {
   474                 -- it1_;
   475                 return *this;
   476             }
   477             BOOST_UBLAS_INLINE
   478             iterator1 &operator += (difference_type n) {
   479                 it1_ += n;
   480                 return *this;
   481             }
   482             BOOST_UBLAS_INLINE
   483             iterator1 &operator -= (difference_type n) {
   484                 it1_ -= n;
   485                 return *this;
   486             }
   487             BOOST_UBLAS_INLINE
   488             difference_type operator - (const iterator1 &it) const {
   489                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   490                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
   491                 return it1_ - it.it1_;
   492             }
   493 
   494             // Dereference
   495             BOOST_UBLAS_INLINE
   496             reference operator * () const {
   497                 return (*this) () (it1_, it2_);
   498             }
   499             BOOST_UBLAS_INLINE
   500             reference operator [] (difference_type n) const {
   501                 return *(*this + n);
   502             }
   503 
   504 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
   505             BOOST_UBLAS_INLINE
   506 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   507             typename self_type::
   508 #endif
   509             iterator2 begin () const {
   510                 return (*this) ().find2 (1, it1_, 0);
   511             }
   512             BOOST_UBLAS_INLINE
   513 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   514             typename self_type::
   515 #endif
   516             iterator2 end () const {
   517                 return (*this) ().find2 (1, it1_, (*this) ().size2 ());
   518             }
   519             BOOST_UBLAS_INLINE
   520 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   521             typename self_type::
   522 #endif
   523             reverse_iterator2 rbegin () const {
   524                 return reverse_iterator2 (end ());
   525             }
   526             BOOST_UBLAS_INLINE
   527 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   528             typename self_type::
   529 #endif
   530             reverse_iterator2 rend () const {
   531                 return reverse_iterator2 (begin ());
   532             }
   533 #endif
   534 
   535             // Indices
   536             BOOST_UBLAS_INLINE
   537             size_type index1 () const {
   538                 return it1_;
   539             }
   540             BOOST_UBLAS_INLINE
   541             size_type index2 () const {
   542                 return it2_;
   543             }
   544 
   545             // Assignment
   546             BOOST_UBLAS_INLINE
   547             iterator1 &operator = (const iterator1 &it) {
   548                 container_reference<self_type>::assign (&it ());
   549                 it1_ = it.it1_;
   550                 it2_ = it.it2_;
   551                 return *this;
   552             }
   553 
   554             // Comparison
   555             BOOST_UBLAS_INLINE
   556             bool operator == (const iterator1 &it) const {
   557                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   558                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
   559                 return it1_ == it.it1_;
   560             }
   561             BOOST_UBLAS_INLINE
   562             bool operator < (const iterator1 &it) const {
   563                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   564                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
   565                 return it1_ < it.it1_;
   566             }
   567 
   568         private:
   569             size_type it1_;
   570             size_type it2_;
   571 
   572             friend class const_iterator1;
   573         };
   574 #endif
   575 
   576         BOOST_UBLAS_INLINE
   577         iterator1 begin1 () {
   578             return find1 (0, 0, 0);
   579         }
   580         BOOST_UBLAS_INLINE
   581         iterator1 end1 () {
   582             return find1 (0, size_, 0);
   583         }
   584 
   585 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
   586         class const_iterator2:
   587             public container_const_reference<symmetric_matrix>,
   588             public random_access_iterator_base<dense_random_access_iterator_tag,
   589                                                const_iterator2, value_type> {
   590         public:
   591             typedef typename symmetric_matrix::value_type value_type;
   592             typedef typename symmetric_matrix::difference_type difference_type;
   593             typedef typename symmetric_matrix::const_reference reference;
   594             typedef const typename symmetric_matrix::pointer pointer;
   595 
   596             typedef const_iterator1 dual_iterator_type;
   597             typedef const_reverse_iterator1 dual_reverse_iterator_type;
   598 
   599             // Construction and destruction
   600             BOOST_UBLAS_INLINE
   601             const_iterator2 ():
   602                 container_const_reference<self_type> (), it1_ (), it2_ () {}
   603             BOOST_UBLAS_INLINE
   604             const_iterator2 (const self_type &m, size_type it1, size_type it2):
   605                 container_const_reference<self_type> (m), it1_ (it1), it2_ (it2) {}
   606             BOOST_UBLAS_INLINE
   607             const_iterator2 (const iterator2 &it):
   608                 container_const_reference<self_type> (it ()), it1_ (it.it1_), it2_ (it.it2_) {}
   609 
   610             // Arithmetic
   611             BOOST_UBLAS_INLINE
   612             const_iterator2 &operator ++ () {
   613                 ++ it2_;
   614                 return *this;
   615             }
   616             BOOST_UBLAS_INLINE
   617             const_iterator2 &operator -- () {
   618                 -- it2_;
   619                 return *this;
   620             }
   621             BOOST_UBLAS_INLINE
   622             const_iterator2 &operator += (difference_type n) {
   623                 it2_ += n;
   624                 return *this;
   625             }
   626             BOOST_UBLAS_INLINE
   627             const_iterator2 &operator -= (difference_type n) {
   628                 it2_ -= n;
   629                 return *this;
   630             }
   631             BOOST_UBLAS_INLINE
   632             difference_type operator - (const const_iterator2 &it) const {
   633                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   634                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
   635                 return it2_ - it.it2_;
   636             }
   637 
   638             // Dereference
   639             BOOST_UBLAS_INLINE
   640             const_reference operator * () const {
   641                 return (*this) () (it1_, it2_);
   642             }
   643             BOOST_UBLAS_INLINE
   644             const_reference operator [] (difference_type n) const {
   645                 return *(*this + n);
   646             }
   647 
   648 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
   649             BOOST_UBLAS_INLINE
   650 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   651             typename self_type::
   652 #endif
   653             const_iterator1 begin () const {
   654                 return (*this) ().find1 (1, 0, it2_);
   655             }
   656             BOOST_UBLAS_INLINE
   657 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   658             typename self_type::
   659 #endif
   660             const_iterator1 end () const {
   661                 return (*this) ().find1 (1, (*this) ().size1 (), it2_);
   662             }
   663             BOOST_UBLAS_INLINE
   664 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   665             typename self_type::
   666 #endif
   667             const_reverse_iterator1 rbegin () const {
   668                 return const_reverse_iterator1 (end ());
   669             }
   670             BOOST_UBLAS_INLINE
   671 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   672             typename self_type::
   673 #endif
   674             const_reverse_iterator1 rend () const {
   675                 return const_reverse_iterator1 (begin ());
   676             }
   677 #endif
   678 
   679             // Indices
   680             BOOST_UBLAS_INLINE
   681             size_type index1 () const {
   682                 return it1_;
   683             }
   684             BOOST_UBLAS_INLINE
   685             size_type index2 () const {
   686                 return it2_;
   687             }
   688 
   689             // Assignment
   690             BOOST_UBLAS_INLINE
   691             const_iterator2 &operator = (const const_iterator2 &it) {
   692                 container_const_reference<self_type>::assign (&it ());
   693                 it1_ = it.it1_;
   694                 it2_ = it.it2_;
   695                 return *this;
   696             }
   697 
   698             // Comparison
   699             BOOST_UBLAS_INLINE
   700             bool operator == (const const_iterator2 &it) const {
   701                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   702                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
   703                 return it2_ == it.it2_;
   704             }
   705             BOOST_UBLAS_INLINE
   706             bool operator < (const const_iterator2 &it) const {
   707                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   708                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
   709                 return it2_ < it.it2_;
   710             }
   711 
   712         private:
   713             size_type it1_;
   714             size_type it2_;
   715         };
   716 #endif
   717 
   718         BOOST_UBLAS_INLINE
   719         const_iterator2 begin2 () const {
   720             return find2 (0, 0, 0);
   721         }
   722         BOOST_UBLAS_INLINE
   723         const_iterator2 end2 () const {
   724             return find2 (0, 0, size_);
   725         }
   726 
   727 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
   728         class iterator2:
   729             public container_reference<symmetric_matrix>,
   730             public random_access_iterator_base<packed_random_access_iterator_tag,
   731                                                iterator2, value_type> {
   732         public:
   733             typedef typename symmetric_matrix::value_type value_type;
   734             typedef typename symmetric_matrix::difference_type difference_type;
   735             typedef typename symmetric_matrix::reference reference;
   736             typedef typename symmetric_matrix::pointer pointer;
   737 
   738             typedef iterator1 dual_iterator_type;
   739             typedef reverse_iterator1 dual_reverse_iterator_type;
   740 
   741             // Construction and destruction
   742             BOOST_UBLAS_INLINE
   743             iterator2 ():
   744                 container_reference<self_type> (), it1_ (), it2_ () {}
   745             BOOST_UBLAS_INLINE
   746             iterator2 (self_type &m, size_type it1, size_type it2):
   747                 container_reference<self_type> (m), it1_ (it1), it2_ (it2) {}
   748 
   749             // Arithmetic
   750             BOOST_UBLAS_INLINE
   751             iterator2 &operator ++ () {
   752                 ++ it2_;
   753                 return *this;
   754             }
   755             BOOST_UBLAS_INLINE
   756             iterator2 &operator -- () {
   757                 -- it2_;
   758                 return *this;
   759             }
   760             BOOST_UBLAS_INLINE
   761             iterator2 &operator += (difference_type n) {
   762                 it2_ += n;
   763                 return *this;
   764             }
   765             BOOST_UBLAS_INLINE
   766             iterator2 &operator -= (difference_type n) {
   767                 it2_ -= n;
   768                 return *this;
   769             }
   770             BOOST_UBLAS_INLINE
   771             difference_type operator - (const iterator2 &it) const {
   772                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   773                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
   774                 return it2_ - it.it2_;
   775             }
   776 
   777             // Dereference
   778             BOOST_UBLAS_INLINE
   779             reference operator * () const {
   780                 return (*this) () (it1_, it2_);
   781             }
   782             BOOST_UBLAS_INLINE
   783             reference operator [] (difference_type n) const {
   784                 return *(*this + n);
   785             }
   786 
   787 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
   788             BOOST_UBLAS_INLINE
   789 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   790             typename self_type::
   791 #endif
   792             iterator1 begin () const {
   793                 return (*this) ().find1 (1, 0, it2_);
   794             }
   795             BOOST_UBLAS_INLINE
   796 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   797             typename self_type::
   798 #endif
   799             iterator1 end () const {
   800                 return (*this) ().find1 (1, (*this) ().size1 (), it2_);
   801             }
   802             BOOST_UBLAS_INLINE
   803 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   804             typename self_type::
   805 #endif
   806             reverse_iterator1 rbegin () const {
   807                 return reverse_iterator1 (end ());
   808             }
   809             BOOST_UBLAS_INLINE
   810 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
   811             typename self_type::
   812 #endif
   813             reverse_iterator1 rend () const {
   814                 return reverse_iterator1 (begin ());
   815             }
   816 #endif
   817 
   818             // Indices
   819             BOOST_UBLAS_INLINE
   820             size_type index1 () const {
   821                 return it1_;
   822             }
   823             BOOST_UBLAS_INLINE
   824             size_type index2 () const {
   825                 return it2_;
   826             }
   827 
   828             // Assignment
   829             BOOST_UBLAS_INLINE
   830             iterator2 &operator = (const iterator2 &it) {
   831                 container_reference<self_type>::assign (&it ());
   832                 it1_ = it.it1_;
   833                 it2_ = it.it2_;
   834                 return *this;
   835             }
   836 
   837             // Comparison
   838             BOOST_UBLAS_INLINE
   839             bool operator == (const iterator2 &it) const {
   840                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   841                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
   842                 return it2_ == it.it2_;
   843             }
   844             BOOST_UBLAS_INLINE
   845             bool operator < (const iterator2 &it) const {
   846                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
   847                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
   848                 return it2_ < it.it2_;
   849             }
   850 
   851         private:
   852             size_type it1_;
   853             size_type it2_;
   854 
   855             friend class const_iterator2;
   856         };
   857 #endif
   858 
   859         BOOST_UBLAS_INLINE
   860         iterator2 begin2 () {
   861             return find2 (0, 0, 0);
   862         }
   863         BOOST_UBLAS_INLINE
   864         iterator2 end2 () {
   865             return find2 (0, 0, size_);
   866         }
   867 
   868         // Reverse iterators
   869 
   870         BOOST_UBLAS_INLINE
   871         const_reverse_iterator1 rbegin1 () const {
   872             return const_reverse_iterator1 (end1 ());
   873         }
   874         BOOST_UBLAS_INLINE
   875         const_reverse_iterator1 rend1 () const {
   876             return const_reverse_iterator1 (begin1 ());
   877         }
   878 
   879         BOOST_UBLAS_INLINE
   880         reverse_iterator1 rbegin1 () {
   881             return reverse_iterator1 (end1 ());
   882         }
   883         BOOST_UBLAS_INLINE
   884         reverse_iterator1 rend1 () {
   885             return reverse_iterator1 (begin1 ());
   886         }
   887 
   888         BOOST_UBLAS_INLINE
   889         const_reverse_iterator2 rbegin2 () const {
   890             return const_reverse_iterator2 (end2 ());
   891         }
   892         BOOST_UBLAS_INLINE
   893         const_reverse_iterator2 rend2 () const {
   894             return const_reverse_iterator2 (begin2 ());
   895         }
   896 
   897         BOOST_UBLAS_INLINE
   898         reverse_iterator2 rbegin2 () {
   899             return reverse_iterator2 (end2 ());
   900         }
   901         BOOST_UBLAS_INLINE
   902         reverse_iterator2 rend2 () {
   903             return reverse_iterator2 (begin2 ());
   904         }
   905 
   906     private:
   907         size_type size_;
   908         array_type data_;
   909     };
   910 
   911 
   912     // Symmetric matrix adaptor class
   913     template<class M, class TRI>
   914     class symmetric_adaptor:
   915         public matrix_expression<symmetric_adaptor<M, TRI> > {
   916 
   917         typedef symmetric_adaptor<M, TRI> self_type;
   918     public:
   919 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
   920         using matrix_expression<self_type>::operator ();
   921 #endif
   922         typedef const M const_matrix_type;
   923         typedef M matrix_type;
   924         typedef TRI triangular_type;
   925         typedef typename M::size_type size_type;
   926         typedef typename M::difference_type difference_type;
   927         typedef typename M::value_type value_type;
   928         typedef typename M::const_reference const_reference;
   929         typedef typename boost::mpl::if_<boost::is_const<M>,
   930                                           typename M::const_reference,
   931                                           typename M::reference>::type reference;
   932         typedef typename boost::mpl::if_<boost::is_const<M>,
   933                                           typename M::const_closure_type,
   934                                           typename M::closure_type>::type matrix_closure_type;
   935         typedef const self_type const_closure_type;
   936         typedef self_type closure_type;
   937         // Replaced by _temporary_traits to avoid type requirements on M
   938         //typedef typename M::vector_temporary_type vector_temporary_type;
   939         //typedef typename M::matrix_temporary_type matrix_temporary_type;
   940         typedef typename storage_restrict_traits<typename M::storage_category,
   941                                                  packed_proxy_tag>::storage_category storage_category;
   942         typedef typename M::orientation_category orientation_category;
   943 
   944         // Construction and destruction
   945         BOOST_UBLAS_INLINE
   946         symmetric_adaptor (matrix_type &data):
   947             matrix_expression<self_type> (),
   948             data_ (data) {
   949             BOOST_UBLAS_CHECK (data_.size1 () == data_.size2 (), bad_size ());
   950         }
   951         BOOST_UBLAS_INLINE
   952         symmetric_adaptor (const symmetric_adaptor &m):
   953             matrix_expression<self_type> (),
   954             data_ (m.data_) {
   955             BOOST_UBLAS_CHECK (data_.size1 () == data_.size2 (), bad_size ());
   956         }
   957 
   958         // Accessors
   959         BOOST_UBLAS_INLINE
   960         size_type size1 () const {
   961             return data_.size1 ();
   962         }
   963         BOOST_UBLAS_INLINE
   964         size_type size2 () const {
   965             return data_.size2 ();
   966         }
   967 
   968         // Storage accessors
   969         BOOST_UBLAS_INLINE
   970         const matrix_closure_type &data () const {
   971             return data_;
   972         }
   973         BOOST_UBLAS_INLINE
   974         matrix_closure_type &data () {
   975             return data_;
   976         }
   977 
   978         // Element access
   979 #ifndef BOOST_UBLAS_PROXY_CONST_MEMBER
   980         BOOST_UBLAS_INLINE
   981         const_reference operator () (size_type i, size_type j) const {
   982             BOOST_UBLAS_CHECK (i < size1 (), bad_index ());
   983             BOOST_UBLAS_CHECK (j < size2 (), bad_index ());
   984             if (triangular_type::other (i, j))
   985                 return data () (i, j);
   986             else
   987                 return data () (j, i);
   988         }
   989         BOOST_UBLAS_INLINE
   990         reference operator () (size_type i, size_type j) {
   991             BOOST_UBLAS_CHECK (i < size1 (), bad_index ());
   992             BOOST_UBLAS_CHECK (j < size2 (), bad_index ());
   993             if (triangular_type::other (i, j))
   994                 return data () (i, j);
   995             else
   996                 return data () (j, i);
   997         }
   998 #else
   999         BOOST_UBLAS_INLINE
  1000         reference operator () (size_type i, size_type j) const {
  1001             BOOST_UBLAS_CHECK (i < size1 (), bad_index ());
  1002             BOOST_UBLAS_CHECK (j < size2 (), bad_index ());
  1003             if (triangular_type::other (i, j))
  1004                 return data () (i, j);
  1005             else
  1006                 return data () (j, i);
  1007         }
  1008 #endif
  1009 
  1010         // Assignment
  1011         BOOST_UBLAS_INLINE
  1012         symmetric_adaptor &operator = (const symmetric_adaptor &m) {
  1013             matrix_assign<scalar_assign, triangular_type> (*this, m);
  1014             return *this;
  1015         }
  1016         BOOST_UBLAS_INLINE
  1017         symmetric_adaptor &assign_temporary (symmetric_adaptor &m) {
  1018             *this = m;
  1019             return *this;
  1020         }
  1021         template<class AE>
  1022         BOOST_UBLAS_INLINE
  1023         symmetric_adaptor &operator = (const matrix_expression<AE> &ae) {
  1024             matrix_assign<scalar_assign, triangular_type> (*this, matrix<value_type> (ae));
  1025             return *this;
  1026         }
  1027         template<class AE>
  1028         BOOST_UBLAS_INLINE
  1029         symmetric_adaptor &assign (const matrix_expression<AE> &ae) {
  1030             matrix_assign<scalar_assign, triangular_type> (*this, ae);
  1031             return *this;
  1032         }
  1033         template<class AE>
  1034         BOOST_UBLAS_INLINE
  1035         symmetric_adaptor& operator += (const matrix_expression<AE> &ae) {
  1036             matrix_assign<scalar_assign, triangular_type> (*this, matrix<value_type> (*this + ae));
  1037             return *this;
  1038         }
  1039         template<class AE>
  1040         BOOST_UBLAS_INLINE
  1041         symmetric_adaptor &plus_assign (const matrix_expression<AE> &ae) {
  1042             matrix_assign<scalar_plus_assign, triangular_type> (*this, ae);
  1043             return *this;
  1044         }
  1045         template<class AE>
  1046         BOOST_UBLAS_INLINE
  1047         symmetric_adaptor& operator -= (const matrix_expression<AE> &ae) {
  1048             matrix_assign<scalar_assign, triangular_type> (*this, matrix<value_type> (*this - ae));
  1049             return *this;
  1050         }
  1051         template<class AE>
  1052         BOOST_UBLAS_INLINE
  1053         symmetric_adaptor &minus_assign (const matrix_expression<AE> &ae) {
  1054             matrix_assign<scalar_minus_assign, triangular_type> (*this, ae);
  1055             return *this;
  1056         }
  1057         template<class AT>
  1058         BOOST_UBLAS_INLINE
  1059         symmetric_adaptor& operator *= (const AT &at) {
  1060             matrix_assign_scalar<scalar_multiplies_assign> (*this, at);
  1061             return *this;
  1062         }
  1063         template<class AT>
  1064         BOOST_UBLAS_INLINE
  1065         symmetric_adaptor& operator /= (const AT &at) {
  1066             matrix_assign_scalar<scalar_divides_assign> (*this, at);
  1067             return *this;
  1068         }
  1069 
  1070         // Closure comparison
  1071         BOOST_UBLAS_INLINE
  1072         bool same_closure (const symmetric_adaptor &sa) const {
  1073             return (*this).data ().same_closure (sa.data ());
  1074        }
  1075 
  1076         // Swapping
  1077         BOOST_UBLAS_INLINE
  1078         void swap (symmetric_adaptor &m) {
  1079             if (this != &m)
  1080                 matrix_swap<scalar_swap, triangular_type> (*this, m);
  1081         }
  1082         BOOST_UBLAS_INLINE
  1083         friend void swap (symmetric_adaptor &m1, symmetric_adaptor &m2) {
  1084             m1.swap (m2);
  1085         }
  1086 
  1087         // Iterator types
  1088     private:
  1089         // Use matrix iterator
  1090         typedef typename M::const_iterator1 const_subiterator1_type;
  1091         typedef typename boost::mpl::if_<boost::is_const<M>,
  1092                                           typename M::const_iterator1,
  1093                                           typename M::iterator1>::type subiterator1_type;
  1094         typedef typename M::const_iterator2 const_subiterator2_type;
  1095         typedef typename boost::mpl::if_<boost::is_const<M>,
  1096                                           typename M::const_iterator2,
  1097                                           typename M::iterator2>::type subiterator2_type;
  1098 
  1099     public:
  1100 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
  1101         typedef indexed_iterator1<self_type, packed_random_access_iterator_tag> iterator1;
  1102         typedef indexed_iterator2<self_type, packed_random_access_iterator_tag> iterator2;
  1103         typedef indexed_const_iterator1<self_type, dense_random_access_iterator_tag> const_iterator1;
  1104         typedef indexed_const_iterator2<self_type, dense_random_access_iterator_tag> const_iterator2;
  1105 #else
  1106         class const_iterator1;
  1107         class iterator1;
  1108         class const_iterator2;
  1109         class iterator2;
  1110 #endif
  1111         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
  1112         typedef reverse_iterator_base1<iterator1> reverse_iterator1;
  1113         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
  1114         typedef reverse_iterator_base2<iterator2> reverse_iterator2;
  1115 
  1116         // Element lookup
  1117         BOOST_UBLAS_INLINE
  1118         const_iterator1 find1 (int rank, size_type i, size_type j) const {
  1119             if (triangular_type::other (i, j)) {
  1120                 if (triangular_type::other (size1 (), j)) {
  1121                     return const_iterator1 (*this, 0, 0,
  1122                                             data ().find1 (rank, i, j), data ().find1 (rank, size1 (), j),
  1123                                             data ().find2 (rank, size2 (), size1 ()), data ().find2 (rank, size2 (), size1 ()));
  1124                 } else {
  1125                     return const_iterator1 (*this, 0, 1,
  1126                                             data ().find1 (rank, i, j), data ().find1 (rank, j, j),
  1127                                             data ().find2 (rank, j, j), data ().find2 (rank, j, size1 ()));
  1128                 }
  1129             } else {
  1130                 if (triangular_type::other (size1 (), j)) {
  1131                     return const_iterator1 (*this, 1, 0,
  1132                                             data ().find1 (rank, j, j), data ().find1 (rank, size1 (), j),
  1133                                             data ().find2 (rank, j, i), data ().find2 (rank, j, j));
  1134                 } else {
  1135                     return const_iterator1 (*this, 1, 1,
  1136                                             data ().find1 (rank, size1 (), size2 ()), data ().find1 (rank, size1 (), size2 ()),
  1137                                             data ().find2 (rank, j, i), data ().find2 (rank, j, size1 ()));
  1138                 }
  1139             }
  1140         }
  1141         BOOST_UBLAS_INLINE
  1142         iterator1 find1 (int rank, size_type i, size_type j) {
  1143             if (rank == 1)
  1144                 i = triangular_type::mutable_restrict1 (i, j);
  1145             return iterator1 (*this, data ().find1 (rank, i, j));
  1146         }
  1147         BOOST_UBLAS_INLINE
  1148         const_iterator2 find2 (int rank, size_type i, size_type j) const {
  1149             if (triangular_type::other (i, j)) {
  1150                 if (triangular_type::other (i, size2 ())) {
  1151                     return const_iterator2 (*this, 1, 1,
  1152                                             data ().find1 (rank, size2 (), size1 ()), data ().find1 (rank, size2 (), size1 ()),
  1153                                             data ().find2 (rank, i, j), data ().find2 (rank, i, size2 ()));
  1154                 } else {
  1155                     return const_iterator2 (*this, 1, 0,
  1156                                             data ().find1 (rank, i, i), data ().find1 (rank, size2 (), i),
  1157                                             data ().find2 (rank, i, j), data ().find2 (rank, i, i));
  1158                 }
  1159             } else {
  1160                 if (triangular_type::other (i, size2 ())) {
  1161                     return const_iterator2 (*this, 0, 1,
  1162                                             data ().find1 (rank, j, i), data ().find1 (rank, i, i),
  1163                                             data ().find2 (rank, i, i), data ().find2 (rank, i, size2 ()));
  1164                 } else {
  1165                     return const_iterator2 (*this, 0, 0,
  1166                                             data ().find1 (rank, j, i), data ().find1 (rank, size2 (), i),
  1167                                             data ().find2 (rank, size1 (), size2 ()), data ().find2 (rank, size2 (), size2 ()));
  1168                 }
  1169             }
  1170         }
  1171         BOOST_UBLAS_INLINE
  1172         iterator2 find2 (int rank, size_type i, size_type j) {
  1173             if (rank == 1)
  1174                 j = triangular_type::mutable_restrict2 (i, j);
  1175             return iterator2 (*this, data ().find2 (rank, i, j));
  1176         }
  1177 
  1178         // Iterators simply are indices.
  1179 
  1180 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
  1181         class const_iterator1:
  1182             public container_const_reference<symmetric_adaptor>,
  1183             public random_access_iterator_base<typename iterator_restrict_traits<
  1184                                                    typename const_subiterator1_type::iterator_category, dense_random_access_iterator_tag>::iterator_category,
  1185                                                const_iterator1, value_type> {
  1186         public:
  1187             typedef typename const_subiterator1_type::value_type value_type;
  1188             typedef typename const_subiterator1_type::difference_type difference_type;
  1189             typedef typename const_subiterator1_type::reference reference;
  1190             typedef typename const_subiterator1_type::pointer pointer;
  1191 
  1192             typedef const_iterator2 dual_iterator_type;
  1193             typedef const_reverse_iterator2 dual_reverse_iterator_type;
  1194 
  1195             // Construction and destruction
  1196             BOOST_UBLAS_INLINE
  1197             const_iterator1 ():
  1198                 container_const_reference<self_type> (),
  1199                 begin_ (-1), end_ (-1), current_ (-1),
  1200                 it1_begin_ (), it1_end_ (), it1_ (),
  1201                 it2_begin_ (), it2_end_ (), it2_ () {}
  1202             BOOST_UBLAS_INLINE
  1203             const_iterator1 (const self_type &m, int begin, int end,
  1204                              const const_subiterator1_type &it1_begin, const const_subiterator1_type &it1_end,
  1205                              const const_subiterator2_type &it2_begin, const const_subiterator2_type &it2_end):
  1206                 container_const_reference<self_type> (m),
  1207                 begin_ (begin), end_ (end), current_ (begin),
  1208                 it1_begin_ (it1_begin), it1_end_ (it1_end), it1_ (it1_begin_),
  1209                 it2_begin_ (it2_begin), it2_end_ (it2_end), it2_ (it2_begin_) {
  1210                 if (current_ == 0 && it1_ == it1_end_)
  1211                     current_ = 1;
  1212                 if (current_ == 1 && it2_ == it2_end_)
  1213                     current_ = 0;
  1214                 if ((current_ == 0 && it1_ == it1_end_) ||
  1215                     (current_ == 1 && it2_ == it2_end_))
  1216                     current_ = end_;
  1217                 BOOST_UBLAS_CHECK (current_ == end_ ||
  1218                                    (current_ == 0 && it1_ != it1_end_) ||
  1219                                    (current_ == 1 && it2_ != it2_end_), internal_logic ());
  1220             }
  1221             // FIXME cannot compile
  1222             //  iterator1 does not have these members!
  1223             BOOST_UBLAS_INLINE
  1224             const_iterator1 (const iterator1 &it):
  1225                 container_const_reference<self_type> (it ()),
  1226                 begin_ (it.begin_), end_ (it.end_), current_ (it.current_),
  1227                 it1_begin_ (it.it1_begin_), it1_end_ (it.it1_end_), it1_ (it.it1_),
  1228                 it2_begin_ (it.it2_begin_), it2_end_ (it.it2_end_), it2_ (it.it2_) {
  1229                 BOOST_UBLAS_CHECK (current_ == end_ ||
  1230                                    (current_ == 0 && it1_ != it1_end_) ||
  1231                                    (current_ == 1 && it2_ != it2_end_), internal_logic ());
  1232             }
  1233 
  1234             // Arithmetic
  1235             BOOST_UBLAS_INLINE
  1236             const_iterator1 &operator ++ () {
  1237                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1238                 if (current_ == 0) {
  1239                     BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
  1240                     ++ it1_;
  1241                     if (it1_ == it1_end_ && end_ == 1) {
  1242                         it2_ = it2_begin_;
  1243                         current_ = 1;
  1244                     }
  1245                 } else /* if (current_ == 1) */ {
  1246                     BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
  1247                     ++ it2_;
  1248                     if (it2_ == it2_end_ && end_ == 0) {
  1249                         it1_ = it1_begin_;
  1250                         current_ = 0;
  1251                     }
  1252                 }
  1253                 return *this;
  1254             }
  1255             BOOST_UBLAS_INLINE
  1256             const_iterator1 &operator -- () {
  1257                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1258                 if (current_ == 0) {
  1259                     if (it1_ == it1_begin_ && begin_ == 1) {
  1260                         it2_ = it2_end_;
  1261                         BOOST_UBLAS_CHECK (it2_ != it2_begin_, internal_logic ());
  1262                         -- it2_;
  1263                         current_ = 1;
  1264                     } else {
  1265                         -- it1_;
  1266                     }
  1267                 } else /* if (current_ == 1) */ {
  1268                     if (it2_ == it2_begin_ && begin_ == 0) {
  1269                         it1_ = it1_end_;
  1270                         BOOST_UBLAS_CHECK (it1_ != it1_begin_, internal_logic ());
  1271                         -- it1_;
  1272                         current_ = 0;
  1273                     } else {
  1274                         -- it2_;
  1275                     }
  1276                 }
  1277                 return *this;
  1278             }
  1279             BOOST_UBLAS_INLINE
  1280             const_iterator1 &operator += (difference_type n) {
  1281                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1282                 if (current_ == 0) {
  1283                     size_type d = (std::min) (n, it1_end_ - it1_);
  1284                     it1_ += d;
  1285                     n -= d;
  1286                     if (n > 0 || (end_ == 1 && it1_ == it1_end_)) {
  1287                         BOOST_UBLAS_CHECK (end_ == 1, external_logic ());
  1288                         d = (std::min) (n, it2_end_ - it2_begin_);
  1289                         it2_ = it2_begin_ + d;
  1290                         n -= d;
  1291                         current_ = 1;
  1292                     }
  1293                 } else /* if (current_ == 1) */ {
  1294                     size_type d = (std::min) (n, it2_end_ - it2_);
  1295                     it2_ += d;
  1296                     n -= d;
  1297                     if (n > 0 || (end_ == 0 && it2_ == it2_end_)) {
  1298                         BOOST_UBLAS_CHECK (end_ == 0, external_logic ());
  1299                         d = (std::min) (n, it1_end_ - it1_begin_);
  1300                         it1_ = it1_begin_ + d;
  1301                         n -= d;
  1302                         current_ = 0;
  1303                     }
  1304                 }
  1305                 BOOST_UBLAS_CHECK (n == 0, external_logic ());
  1306                 return *this;
  1307             }
  1308             BOOST_UBLAS_INLINE
  1309             const_iterator1 &operator -= (difference_type n) {
  1310                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1311                 if (current_ == 0) {
  1312                     size_type d = (std::min) (n, it1_ - it1_begin_);
  1313                     it1_ -= d;
  1314                     n -= d;
  1315                     if (n > 0) {
  1316                         BOOST_UBLAS_CHECK (end_ == 1, external_logic ());
  1317                         d = (std::min) (n, it2_end_ - it2_begin_);
  1318                         it2_ = it2_end_ - d;
  1319                         n -= d;
  1320                         current_ = 1;
  1321                     }
  1322                 } else /* if (current_ == 1) */ {
  1323                     size_type d = (std::min) (n, it2_ - it2_begin_);
  1324                     it2_ -= d;
  1325                     n -= d;
  1326                     if (n > 0) {
  1327                         BOOST_UBLAS_CHECK (end_ == 0, external_logic ());
  1328                         d = (std::min) (n, it1_end_ - it1_begin_);
  1329                         it1_ = it1_end_ - d;
  1330                         n -= d;
  1331                         current_ = 0;
  1332                     }
  1333                 }
  1334                 BOOST_UBLAS_CHECK (n == 0, external_logic ());
  1335                 return *this;
  1336             }
  1337             BOOST_UBLAS_INLINE
  1338             difference_type operator - (const const_iterator1 &it) const {
  1339                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1340                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1341                 BOOST_UBLAS_CHECK (it.current_ == 0 || it.current_ == 1, internal_logic ());
  1342                 BOOST_UBLAS_CHECK (/* begin_ == it.begin_ && */ end_ == it.end_, internal_logic ());
  1343                 if (current_ == 0 && it.current_ == 0) {
  1344                     return it1_ - it.it1_;
  1345                 } else if (current_ == 0 && it.current_ == 1) {
  1346                     if (end_ == 1 && it.end_ == 1) {
  1347                         return (it1_ - it.it1_end_) + (it.it2_begin_ - it.it2_);
  1348                     } else /* if (end_ == 0 && it.end_ == 0) */ {
  1349                         return (it1_ - it.it1_begin_) + (it.it2_end_ - it.it2_);
  1350                     }
  1351 
  1352                 } else if (current_ == 1 && it.current_ == 0) {
  1353                     if (end_ == 1 && it.end_ == 1) {
  1354                         return (it2_ - it.it2_begin_) + (it.it1_end_ - it.it1_);
  1355                     } else /* if (end_ == 0 && it.end_ == 0) */ {
  1356                         return (it2_ - it.it2_end_) + (it.it1_begin_ - it.it1_);
  1357                     }
  1358                 }
  1359                 /* current_ == 1 && it.current_ == 1 */ {
  1360                     return it2_ - it.it2_;
  1361                 }
  1362             }
  1363 
  1364             // Dereference
  1365             BOOST_UBLAS_INLINE
  1366             const_reference operator * () const {
  1367                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1368                 if (current_ == 0) {
  1369                     BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
  1370                     return *it1_;
  1371                 } else /* if (current_ == 1) */ {
  1372                     BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
  1373                     return *it2_;
  1374                 }
  1375             }
  1376             BOOST_UBLAS_INLINE
  1377             const_reference operator [] (difference_type n) const {
  1378                 return *(*this + n);
  1379             }
  1380 
  1381 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  1382             BOOST_UBLAS_INLINE
  1383 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1384             typename self_type::
  1385 #endif
  1386             const_iterator2 begin () const {
  1387                 return (*this) ().find2 (1, index1 (), 0);
  1388             }
  1389             BOOST_UBLAS_INLINE
  1390 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1391             typename self_type::
  1392 #endif
  1393             const_iterator2 end () const {
  1394                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
  1395             }
  1396             BOOST_UBLAS_INLINE
  1397 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1398             typename self_type::
  1399 #endif
  1400             const_reverse_iterator2 rbegin () const {
  1401                 return const_reverse_iterator2 (end ());
  1402             }
  1403             BOOST_UBLAS_INLINE
  1404 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1405             typename self_type::
  1406 #endif
  1407             const_reverse_iterator2 rend () const {
  1408                 return const_reverse_iterator2 (begin ());
  1409             }
  1410 #endif
  1411 
  1412             // Indices
  1413             BOOST_UBLAS_INLINE
  1414             size_type index1 () const {
  1415                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1416                 if (current_ == 0) {
  1417                     BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
  1418                     return it1_.index1 ();
  1419                 } else /* if (current_ == 1) */ {
  1420                     BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
  1421                     return it2_.index2 ();
  1422                 }
  1423             }
  1424             BOOST_UBLAS_INLINE
  1425             size_type index2 () const {
  1426                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1427                 if (current_ == 0) {
  1428                     BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
  1429                     return it1_.index2 ();
  1430                 } else /* if (current_ == 1) */ {
  1431                     BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
  1432                     return it2_.index1 ();
  1433                 }
  1434             }
  1435 
  1436             // Assignment
  1437             BOOST_UBLAS_INLINE
  1438             const_iterator1 &operator = (const const_iterator1 &it) {
  1439                 container_const_reference<self_type>::assign (&it ());
  1440                 begin_ = it.begin_;
  1441                 end_ = it.end_;
  1442                 current_ = it.current_;
  1443                 it1_begin_ = it.it1_begin_;
  1444                 it1_end_ = it.it1_end_;
  1445                 it1_ = it.it1_;
  1446                 it2_begin_ = it.it2_begin_;
  1447                 it2_end_ = it.it2_end_;
  1448                 it2_ = it.it2_;
  1449                 return *this;
  1450             }
  1451 
  1452             // Comparison
  1453             BOOST_UBLAS_INLINE
  1454             bool operator == (const const_iterator1 &it) const {
  1455                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1456                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1457                 BOOST_UBLAS_CHECK (it.current_ == 0 || it.current_ == 1, internal_logic ());
  1458                 BOOST_UBLAS_CHECK (/* begin_ == it.begin_ && */ end_ == it.end_, internal_logic ());
  1459                 return (current_ == 0 && it.current_ == 0 && it1_ == it.it1_) ||
  1460                        (current_ == 1 && it.current_ == 1 && it2_ == it.it2_);
  1461             }
  1462             BOOST_UBLAS_INLINE
  1463             bool operator < (const const_iterator1 &it) const {
  1464                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1465                 return it - *this > 0;
  1466             }
  1467 
  1468         private:
  1469             int begin_;
  1470             int end_;
  1471             int current_;
  1472             const_subiterator1_type it1_begin_;
  1473             const_subiterator1_type it1_end_;
  1474             const_subiterator1_type it1_;
  1475             const_subiterator2_type it2_begin_;
  1476             const_subiterator2_type it2_end_;
  1477             const_subiterator2_type it2_;
  1478         };
  1479 #endif
  1480 
  1481         BOOST_UBLAS_INLINE
  1482         const_iterator1 begin1 () const {
  1483             return find1 (0, 0, 0);
  1484         }
  1485         BOOST_UBLAS_INLINE
  1486         const_iterator1 end1 () const {
  1487             return find1 (0, size1 (), 0);
  1488         }
  1489 
  1490 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
  1491         class iterator1:
  1492             public container_reference<symmetric_adaptor>,
  1493             public random_access_iterator_base<typename iterator_restrict_traits<
  1494                                                    typename subiterator1_type::iterator_category, packed_random_access_iterator_tag>::iterator_category,
  1495                                                iterator1, value_type> {
  1496         public:
  1497             typedef typename subiterator1_type::value_type value_type;
  1498             typedef typename subiterator1_type::difference_type difference_type;
  1499             typedef typename subiterator1_type::reference reference;
  1500             typedef typename subiterator1_type::pointer pointer;
  1501 
  1502             typedef iterator2 dual_iterator_type;
  1503             typedef reverse_iterator2 dual_reverse_iterator_type;
  1504 
  1505             // Construction and destruction
  1506             BOOST_UBLAS_INLINE
  1507             iterator1 ():
  1508                 container_reference<self_type> (), it1_ () {}
  1509             BOOST_UBLAS_INLINE
  1510             iterator1 (self_type &m, const subiterator1_type &it1):
  1511                 container_reference<self_type> (m), it1_ (it1) {}
  1512 
  1513             // Arithmetic
  1514             BOOST_UBLAS_INLINE
  1515             iterator1 &operator ++ () {
  1516                 ++ it1_;
  1517                 return *this;
  1518             }
  1519             BOOST_UBLAS_INLINE
  1520             iterator1 &operator -- () {
  1521                 -- it1_;
  1522                 return *this;
  1523             }
  1524             BOOST_UBLAS_INLINE
  1525             iterator1 &operator += (difference_type n) {
  1526                 it1_ += n;
  1527                 return *this;
  1528             }
  1529             BOOST_UBLAS_INLINE
  1530             iterator1 &operator -= (difference_type n) {
  1531                 it1_ -= n;
  1532                 return *this;
  1533             }
  1534             BOOST_UBLAS_INLINE
  1535             difference_type operator - (const iterator1 &it) const {
  1536                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1537                 return it1_ - it.it1_;
  1538             }
  1539 
  1540             // Dereference
  1541             BOOST_UBLAS_INLINE
  1542             reference operator * () const {
  1543                 return *it1_;
  1544             }
  1545             BOOST_UBLAS_INLINE
  1546             reference operator [] (difference_type n) const {
  1547                 return *(*this + n);
  1548             }
  1549 
  1550 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  1551             BOOST_UBLAS_INLINE
  1552 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1553             typename self_type::
  1554 #endif
  1555             iterator2 begin () const {
  1556                 return (*this) ().find2 (1, index1 (), 0);
  1557             }
  1558             BOOST_UBLAS_INLINE
  1559 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1560             typename self_type::
  1561 #endif
  1562             iterator2 end () const {
  1563                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
  1564             }
  1565             BOOST_UBLAS_INLINE
  1566 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1567             typename self_type::
  1568 #endif
  1569             reverse_iterator2 rbegin () const {
  1570                 return reverse_iterator2 (end ());
  1571             }
  1572             BOOST_UBLAS_INLINE
  1573 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1574             typename self_type::
  1575 #endif
  1576             reverse_iterator2 rend () const {
  1577                 return reverse_iterator2 (begin ());
  1578             }
  1579 #endif
  1580 
  1581             // Indices
  1582             BOOST_UBLAS_INLINE
  1583             size_type index1 () const {
  1584                 return it1_.index1 ();
  1585             }
  1586             BOOST_UBLAS_INLINE
  1587             size_type index2 () const {
  1588                 return it1_.index2 ();
  1589             }
  1590 
  1591             // Assignment
  1592             BOOST_UBLAS_INLINE
  1593             iterator1 &operator = (const iterator1 &it) {
  1594                 container_reference<self_type>::assign (&it ());
  1595                 it1_ = it.it1_;
  1596                 return *this;
  1597             }
  1598 
  1599             // Comparison
  1600             BOOST_UBLAS_INLINE
  1601             bool operator == (const iterator1 &it) const {
  1602                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1603                 return it1_ == it.it1_;
  1604             }
  1605             BOOST_UBLAS_INLINE
  1606             bool operator < (const iterator1 &it) const {
  1607                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1608                 return it1_ < it.it1_;
  1609             }
  1610 
  1611         private:
  1612             subiterator1_type it1_;
  1613 
  1614             friend class const_iterator1;
  1615         };
  1616 #endif
  1617 
  1618         BOOST_UBLAS_INLINE
  1619         iterator1 begin1 () {
  1620             return find1 (0, 0, 0);
  1621         }
  1622         BOOST_UBLAS_INLINE
  1623         iterator1 end1 () {
  1624             return find1 (0, size1 (), 0);
  1625         }
  1626 
  1627 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
  1628         class const_iterator2:
  1629             public container_const_reference<symmetric_adaptor>,
  1630             public random_access_iterator_base<typename iterator_restrict_traits<
  1631                                                    typename const_subiterator2_type::iterator_category, dense_random_access_iterator_tag>::iterator_category,
  1632                                                const_iterator2, value_type> {
  1633         public:
  1634             typedef typename const_subiterator2_type::value_type value_type;
  1635             typedef typename const_subiterator2_type::difference_type difference_type;
  1636             typedef typename const_subiterator2_type::reference reference;
  1637             typedef typename const_subiterator2_type::pointer pointer;
  1638 
  1639             typedef const_iterator1 dual_iterator_type;
  1640             typedef const_reverse_iterator1 dual_reverse_iterator_type;
  1641 
  1642             // Construction and destruction
  1643             BOOST_UBLAS_INLINE
  1644             const_iterator2 ():
  1645                 container_const_reference<self_type> (),
  1646                 begin_ (-1), end_ (-1), current_ (-1),
  1647                 it1_begin_ (), it1_end_ (), it1_ (),
  1648                 it2_begin_ (), it2_end_ (), it2_ () {}
  1649             BOOST_UBLAS_INLINE
  1650             const_iterator2 (const self_type &m, int begin, int end,
  1651                              const const_subiterator1_type &it1_begin, const const_subiterator1_type &it1_end,
  1652                              const const_subiterator2_type &it2_begin, const const_subiterator2_type &it2_end):
  1653                 container_const_reference<self_type> (m),
  1654                 begin_ (begin), end_ (end), current_ (begin),
  1655                 it1_begin_ (it1_begin), it1_end_ (it1_end), it1_ (it1_begin_),
  1656                 it2_begin_ (it2_begin), it2_end_ (it2_end), it2_ (it2_begin_) {
  1657                 if (current_ == 0 && it1_ == it1_end_)
  1658                     current_ = 1;
  1659                 if (current_ == 1 && it2_ == it2_end_)
  1660                     current_ = 0;
  1661                 if ((current_ == 0 && it1_ == it1_end_) ||
  1662                     (current_ == 1 && it2_ == it2_end_))
  1663                     current_ = end_;
  1664                 BOOST_UBLAS_CHECK (current_ == end_ ||
  1665                                    (current_ == 0 && it1_ != it1_end_) ||
  1666                                    (current_ == 1 && it2_ != it2_end_), internal_logic ());
  1667             }
  1668             // FIXME cannot compiler
  1669             //  iterator2 does not have these members!
  1670             BOOST_UBLAS_INLINE
  1671             const_iterator2 (const iterator2 &it):
  1672                 container_const_reference<self_type> (it ()),
  1673                 begin_ (it.begin_), end_ (it.end_), current_ (it.current_),
  1674                 it1_begin_ (it.it1_begin_), it1_end_ (it.it1_end_), it1_ (it.it1_),
  1675                 it2_begin_ (it.it2_begin_), it2_end_ (it.it2_end_), it2_ (it.it2_) {
  1676                 BOOST_UBLAS_CHECK (current_ == end_ ||
  1677                                    (current_ == 0 && it1_ != it1_end_) ||
  1678                                    (current_ == 1 && it2_ != it2_end_), internal_logic ());
  1679             }
  1680 
  1681             // Arithmetic
  1682             BOOST_UBLAS_INLINE
  1683             const_iterator2 &operator ++ () {
  1684                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1685                 if (current_ == 0) {
  1686                     BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
  1687                     ++ it1_;
  1688                     if (it1_ == it1_end_ && end_ == 1) {
  1689                         it2_ = it2_begin_;
  1690                         current_ = 1;
  1691                     }
  1692                 } else /* if (current_ == 1) */ {
  1693                     BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
  1694                     ++ it2_;
  1695                     if (it2_ == it2_end_ && end_ == 0) {
  1696                         it1_ = it1_begin_;
  1697                         current_ = 0;
  1698                     }
  1699                 }
  1700                 return *this;
  1701             }
  1702             BOOST_UBLAS_INLINE
  1703             const_iterator2 &operator -- () {
  1704                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1705                 if (current_ == 0) {
  1706                     if (it1_ == it1_begin_ && begin_ == 1) {
  1707                         it2_ = it2_end_;
  1708                         BOOST_UBLAS_CHECK (it2_ != it2_begin_, internal_logic ());
  1709                         -- it2_;
  1710                         current_ = 1;
  1711                     } else {
  1712                         -- it1_;
  1713                     }
  1714                 } else /* if (current_ == 1) */ {
  1715                     if (it2_ == it2_begin_ && begin_ == 0) {
  1716                         it1_ = it1_end_;
  1717                         BOOST_UBLAS_CHECK (it1_ != it1_begin_, internal_logic ());
  1718                         -- it1_;
  1719                         current_ = 0;
  1720                     } else {
  1721                         -- it2_;
  1722                     }
  1723                 }
  1724                 return *this;
  1725             }
  1726             BOOST_UBLAS_INLINE
  1727             const_iterator2 &operator += (difference_type n) {
  1728                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1729                 if (current_ == 0) {
  1730                     size_type d = (std::min) (n, it1_end_ - it1_);
  1731                     it1_ += d;
  1732                     n -= d;
  1733                     if (n > 0 || (end_ == 1 && it1_ == it1_end_)) {
  1734                         BOOST_UBLAS_CHECK (end_ == 1, external_logic ());
  1735                         d = (std::min) (n, it2_end_ - it2_begin_);
  1736                         it2_ = it2_begin_ + d;
  1737                         n -= d;
  1738                         current_ = 1;
  1739                     }
  1740                 } else /* if (current_ == 1) */ {
  1741                     size_type d = (std::min) (n, it2_end_ - it2_);
  1742                     it2_ += d;
  1743                     n -= d;
  1744                     if (n > 0 || (end_ == 0 && it2_ == it2_end_)) {
  1745                         BOOST_UBLAS_CHECK (end_ == 0, external_logic ());
  1746                         d = (std::min) (n, it1_end_ - it1_begin_);
  1747                         it1_ = it1_begin_ + d;
  1748                         n -= d;
  1749                         current_ = 0;
  1750                     }
  1751                 }
  1752                 BOOST_UBLAS_CHECK (n == 0, external_logic ());
  1753                 return *this;
  1754             }
  1755             BOOST_UBLAS_INLINE
  1756             const_iterator2 &operator -= (difference_type n) {
  1757                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1758                 if (current_ == 0) {
  1759                     size_type d = (std::min) (n, it1_ - it1_begin_);
  1760                     it1_ -= d;
  1761                     n -= d;
  1762                     if (n > 0) {
  1763                         BOOST_UBLAS_CHECK (end_ == 1, external_logic ());
  1764                         d = (std::min) (n, it2_end_ - it2_begin_);
  1765                         it2_ = it2_end_ - d;
  1766                         n -= d;
  1767                         current_ = 1;
  1768                     }
  1769                 } else /* if (current_ == 1) */ {
  1770                     size_type d = (std::min) (n, it2_ - it2_begin_);
  1771                     it2_ -= d;
  1772                     n -= d;
  1773                     if (n > 0) {
  1774                         BOOST_UBLAS_CHECK (end_ == 0, external_logic ());
  1775                         d = (std::min) (n, it1_end_ - it1_begin_);
  1776                         it1_ = it1_end_ - d;
  1777                         n -= d;
  1778                         current_ = 0;
  1779                     }
  1780                 }
  1781                 BOOST_UBLAS_CHECK (n == 0, external_logic ());
  1782                 return *this;
  1783             }
  1784             BOOST_UBLAS_INLINE
  1785             difference_type operator - (const const_iterator2 &it) const {
  1786                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1787                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1788                 BOOST_UBLAS_CHECK (it.current_ == 0 || it.current_ == 1, internal_logic ());
  1789                 BOOST_UBLAS_CHECK (/* begin_ == it.begin_ && */ end_ == it.end_, internal_logic ());
  1790                 if (current_ == 0 && it.current_ == 0) {
  1791                     return it1_ - it.it1_;
  1792                 } else if (current_ == 0 && it.current_ == 1) {
  1793                     if (end_ == 1 && it.end_ == 1) {
  1794                         return (it1_ - it.it1_end_) + (it.it2_begin_ - it.it2_);
  1795                     } else /* if (end_ == 0 && it.end_ == 0) */ {
  1796                         return (it1_ - it.it1_begin_) + (it.it2_end_ - it.it2_);
  1797                     }
  1798 
  1799                 } else if (current_ == 1 && it.current_ == 0) {
  1800                     if (end_ == 1 && it.end_ == 1) {
  1801                         return (it2_ - it.it2_begin_) + (it.it1_end_ - it.it1_);
  1802                     } else /* if (end_ == 0 && it.end_ == 0) */ {
  1803                         return (it2_ - it.it2_end_) + (it.it1_begin_ - it.it1_);
  1804                     }
  1805                 }
  1806                 /* current_ == 1 && it.current_ == 1 */ {
  1807                     return it2_ - it.it2_;
  1808                 }
  1809             }
  1810 
  1811             // Dereference
  1812             BOOST_UBLAS_INLINE
  1813             const_reference operator * () const {
  1814                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1815                 if (current_ == 0) {
  1816                     BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
  1817                     return *it1_;
  1818                 } else /* if (current_ == 1) */ {
  1819                     BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
  1820                     return *it2_;
  1821                 }
  1822             }
  1823             BOOST_UBLAS_INLINE
  1824             const_reference operator [] (difference_type n) const {
  1825                 return *(*this + n);
  1826             }
  1827 
  1828 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  1829             BOOST_UBLAS_INLINE
  1830 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1831             typename self_type::
  1832 #endif
  1833             const_iterator1 begin () const {
  1834                 return (*this) ().find1 (1, 0, index2 ());
  1835             }
  1836             BOOST_UBLAS_INLINE
  1837 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1838             typename self_type::
  1839 #endif
  1840             const_iterator1 end () const {
  1841                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
  1842             }
  1843             BOOST_UBLAS_INLINE
  1844 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1845             typename self_type::
  1846 #endif
  1847             const_reverse_iterator1 rbegin () const {
  1848                 return const_reverse_iterator1 (end ());
  1849             }
  1850             BOOST_UBLAS_INLINE
  1851 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  1852             typename self_type::
  1853 #endif
  1854             const_reverse_iterator1 rend () const {
  1855                 return const_reverse_iterator1 (begin ());
  1856             }
  1857 #endif
  1858 
  1859             // Indices
  1860             BOOST_UBLAS_INLINE
  1861             size_type index1 () const {
  1862                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1863                 if (current_ == 0) {
  1864                     BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
  1865                     return it1_.index2 ();
  1866                 } else /* if (current_ == 1) */ {
  1867                     BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
  1868                     return it2_.index1 ();
  1869                 }
  1870             }
  1871             BOOST_UBLAS_INLINE
  1872             size_type index2 () const {
  1873                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1874                 if (current_ == 0) {
  1875                     BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
  1876                     return it1_.index1 ();
  1877                 } else /* if (current_ == 1) */ {
  1878                     BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
  1879                     return it2_.index2 ();
  1880                 }
  1881             }
  1882 
  1883             // Assignment
  1884             BOOST_UBLAS_INLINE
  1885             const_iterator2 &operator = (const const_iterator2 &it) {
  1886                 container_const_reference<self_type>::assign (&it ());
  1887                 begin_ = it.begin_;
  1888                 end_ = it.end_;
  1889                 current_ = it.current_;
  1890                 it1_begin_ = it.it1_begin_;
  1891                 it1_end_ = it.it1_end_;
  1892                 it1_ = it.it1_;
  1893                 it2_begin_ = it.it2_begin_;
  1894                 it2_end_ = it.it2_end_;
  1895                 it2_ = it.it2_;
  1896                 return *this;
  1897             }
  1898 
  1899             // Comparison
  1900             BOOST_UBLAS_INLINE
  1901             bool operator == (const const_iterator2 &it) const {
  1902                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1903                 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
  1904                 BOOST_UBLAS_CHECK (it.current_ == 0 || it.current_ == 1, internal_logic ());
  1905                 BOOST_UBLAS_CHECK (/* begin_ == it.begin_ && */ end_ == it.end_, internal_logic ());
  1906                 return (current_ == 0 && it.current_ == 0 && it1_ == it.it1_) ||
  1907                        (current_ == 1 && it.current_ == 1 && it2_ == it.it2_);
  1908             }
  1909             BOOST_UBLAS_INLINE
  1910             bool operator < (const const_iterator2 &it) const {
  1911                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1912                 return it - *this > 0;
  1913             }
  1914 
  1915         private:
  1916             int begin_;
  1917             int end_;
  1918             int current_;
  1919             const_subiterator1_type it1_begin_;
  1920             const_subiterator1_type it1_end_;
  1921             const_subiterator1_type it1_;
  1922             const_subiterator2_type it2_begin_;
  1923             const_subiterator2_type it2_end_;
  1924             const_subiterator2_type it2_;
  1925         };
  1926 #endif
  1927 
  1928         BOOST_UBLAS_INLINE
  1929         const_iterator2 begin2 () const {
  1930             return find2 (0, 0, 0);
  1931         }
  1932         BOOST_UBLAS_INLINE
  1933         const_iterator2 end2 () const {
  1934             return find2 (0, 0, size2 ());
  1935         }
  1936 
  1937 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
  1938         class iterator2:
  1939             public container_reference<symmetric_adaptor>,
  1940             public random_access_iterator_base<typename iterator_restrict_traits<
  1941                                                    typename subiterator2_type::iterator_category, packed_random_access_iterator_tag>::iterator_category,
  1942                                                iterator2, value_type> {
  1943         public:
  1944             typedef typename subiterator2_type::value_type value_type;
  1945             typedef typename subiterator2_type::difference_type difference_type;
  1946             typedef typename subiterator2_type::reference reference;
  1947             typedef typename subiterator2_type::pointer pointer;
  1948 
  1949             typedef iterator1 dual_iterator_type;
  1950             typedef reverse_iterator1 dual_reverse_iterator_type;
  1951 
  1952             // Construction and destruction
  1953             BOOST_UBLAS_INLINE
  1954             iterator2 ():
  1955                 container_reference<self_type> (), it2_ () {}
  1956             BOOST_UBLAS_INLINE
  1957             iterator2 (self_type &m, const subiterator2_type &it2):
  1958                 container_reference<self_type> (m), it2_ (it2) {}
  1959 
  1960             // Arithmetic
  1961             BOOST_UBLAS_INLINE
  1962             iterator2 &operator ++ () {
  1963                 ++ it2_;
  1964                 return *this;
  1965             }
  1966             BOOST_UBLAS_INLINE
  1967             iterator2 &operator -- () {
  1968                 -- it2_;
  1969                 return *this;
  1970             }
  1971             BOOST_UBLAS_INLINE
  1972             iterator2 &operator += (difference_type n) {
  1973                 it2_ += n;
  1974                 return *this;
  1975             }
  1976             BOOST_UBLAS_INLINE
  1977             iterator2 &operator -= (difference_type n) {
  1978                 it2_ -= n;
  1979                 return *this;
  1980             }
  1981             BOOST_UBLAS_INLINE
  1982             difference_type operator - (const iterator2 &it) const {
  1983                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  1984                 return it2_ - it.it2_;
  1985             }
  1986 
  1987             // Dereference
  1988             BOOST_UBLAS_INLINE
  1989             reference operator * () const {
  1990                 return *it2_;
  1991             }
  1992             BOOST_UBLAS_INLINE
  1993             reference operator [] (difference_type n) const {
  1994                 return *(*this + n);
  1995             }
  1996 
  1997 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
  1998             BOOST_UBLAS_INLINE
  1999 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  2000             typename self_type::
  2001 #endif
  2002             iterator1 begin () const {
  2003                 return (*this) ().find1 (1, 0, index2 ());
  2004             }
  2005             BOOST_UBLAS_INLINE
  2006 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  2007             typename self_type::
  2008 #endif
  2009             iterator1 end () const {
  2010                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
  2011             }
  2012             BOOST_UBLAS_INLINE
  2013 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  2014             typename self_type::
  2015 #endif
  2016             reverse_iterator1 rbegin () const {
  2017                 return reverse_iterator1 (end ());
  2018             }
  2019             BOOST_UBLAS_INLINE
  2020 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
  2021             typename self_type::
  2022 #endif
  2023             reverse_iterator1 rend () const {
  2024                 return reverse_iterator1 (begin ());
  2025             }
  2026 #endif
  2027 
  2028             // Indices
  2029             BOOST_UBLAS_INLINE
  2030             size_type index1 () const {
  2031                 return it2_.index1 ();
  2032             }
  2033             BOOST_UBLAS_INLINE
  2034             size_type index2 () const {
  2035                 return it2_.index2 ();
  2036             }
  2037 
  2038             // Assignment
  2039             BOOST_UBLAS_INLINE
  2040             iterator2 &operator = (const iterator2 &it) {
  2041                 container_reference<self_type>::assign (&it ());
  2042                 it2_ = it.it2_;
  2043                 return *this;
  2044             }
  2045 
  2046             // Comparison
  2047             BOOST_UBLAS_INLINE
  2048             bool operator == (const iterator2 &it) const {
  2049                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  2050                 return it2_ == it.it2_;
  2051             }
  2052             BOOST_UBLAS_INLINE
  2053             bool operator < (const iterator2 &it) const {
  2054                 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
  2055                 return it2_ < it.it2_;
  2056             }
  2057 
  2058         private:
  2059             subiterator2_type it2_;
  2060 
  2061             friend class const_iterator2;
  2062         };
  2063 #endif
  2064 
  2065         BOOST_UBLAS_INLINE
  2066         iterator2 begin2 () {
  2067             return find2 (0, 0, 0);
  2068         }
  2069         BOOST_UBLAS_INLINE
  2070         iterator2 end2 () {
  2071             return find2 (0, 0, size2 ());
  2072         }
  2073 
  2074         // Reverse iterators
  2075 
  2076         BOOST_UBLAS_INLINE
  2077         const_reverse_iterator1 rbegin1 () const {
  2078             return const_reverse_iterator1 (end1 ());
  2079         }
  2080         BOOST_UBLAS_INLINE
  2081         const_reverse_iterator1 rend1 () const {
  2082             return const_reverse_iterator1 (begin1 ());
  2083         }
  2084 
  2085         BOOST_UBLAS_INLINE
  2086         reverse_iterator1 rbegin1 () {
  2087             return reverse_iterator1 (end1 ());
  2088         }
  2089         BOOST_UBLAS_INLINE
  2090         reverse_iterator1 rend1 () {
  2091             return reverse_iterator1 (begin1 ());
  2092         }
  2093 
  2094         BOOST_UBLAS_INLINE
  2095         const_reverse_iterator2 rbegin2 () const {
  2096             return const_reverse_iterator2 (end2 ());
  2097         }
  2098         BOOST_UBLAS_INLINE
  2099         const_reverse_iterator2 rend2 () const {
  2100             return const_reverse_iterator2 (begin2 ());
  2101         }
  2102 
  2103         BOOST_UBLAS_INLINE
  2104         reverse_iterator2 rbegin2 () {
  2105             return reverse_iterator2 (end2 ());
  2106         }
  2107         BOOST_UBLAS_INLINE
  2108         reverse_iterator2 rend2 () {
  2109             return reverse_iterator2 (begin2 ());
  2110         }
  2111 
  2112     private:
  2113         matrix_closure_type data_;
  2114     };
  2115 
  2116     // Specialization for temporary_traits
  2117     template <class M, class TRI>
  2118     struct vector_temporary_traits< symmetric_adaptor<M, TRI> >
  2119     : vector_temporary_traits< M > {} ;
  2120     template <class M, class TRI>
  2121     struct vector_temporary_traits< const symmetric_adaptor<M, TRI> >
  2122     : vector_temporary_traits< M > {} ;
  2123 
  2124     template <class M, class TRI>
  2125     struct matrix_temporary_traits< symmetric_adaptor<M, TRI> >
  2126     : matrix_temporary_traits< M > {} ;
  2127     template <class M, class TRI>
  2128     struct matrix_temporary_traits< const symmetric_adaptor<M, TRI> >
  2129     : matrix_temporary_traits< M > {} ;
  2130 
  2131 }}}
  2132 
  2133 #endif