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

matrix_expression.hpp

Go to the documentation of this file.
00001 //
00002 //  Copyright (c) 2000-2002
00003 //  Joerg Walter, Mathias Koch
00004 //
00005 //  Distributed under the Boost Software License, Version 1.0. (See
00006 //  accompanying file LICENSE_1_0.txt or copy at
00007 //  http://www.boost.org/LICENSE_1_0.txt)
00008 //
00009 //  The authors gratefully acknowledge the support of
00010 //  GeNeSys mbH & Co. KG in producing this work.
00011 //
00012 
00013 #ifndef _BOOST_UBLAS_MATRIX_EXPRESSION_
00014 #define _BOOST_UBLAS_MATRIX_EXPRESSION_
00015 
00016 #include <boost/numeric/ublas/vector_expression.hpp>
00017 
00018 // Expression templates based on ideas of Todd Veldhuizen and Geoffrey Furnish
00019 // Iterators based on ideas of Jeremy Siek
00020 //
00021 // Classes that model the Matrix Expression concept
00022 
00023 namespace boost { namespace numeric { namespace ublas {
00024 
00025     template<class E>
00026     class matrix_reference:
00027         public matrix_expression<matrix_reference<E> > {
00028 
00029         typedef matrix_reference<E> self_type;
00030     public:
00031 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
00032         using matrix_expression<self_type>::operator ();
00033 #endif
00034         typedef typename E::size_type size_type;
00035         typedef typename E::difference_type difference_type;
00036         typedef typename E::value_type value_type;
00037         typedef typename E::const_reference const_reference;
00038         typedef typename boost::mpl::if_<boost::is_const<E>,
00039                                           typename E::const_reference,
00040                                           typename E::reference>::type reference;
00041         typedef E referred_type;
00042         typedef const self_type const_closure_type;
00043         typedef self_type closure_type;
00044         typedef typename E::orientation_category orientation_category;
00045         typedef typename E::storage_category storage_category;
00046 
00047         // Construction and destruction
00048         BOOST_UBLAS_INLINE
00049         explicit matrix_reference (referred_type &e):
00050               e_ (e) {}
00051 
00052         // Accessors
00053         BOOST_UBLAS_INLINE
00054         size_type size1 () const {
00055             return e_.size1 ();
00056         }
00057         BOOST_UBLAS_INLINE
00058         size_type size2 () const {
00059             return e_.size2 ();
00060         }
00061 
00062     public:
00063         // Expression accessors - const correct
00064         BOOST_UBLAS_INLINE
00065         const referred_type &expression () const {
00066             return e_;
00067         }
00068         BOOST_UBLAS_INLINE
00069         referred_type &expression () {
00070             return e_;
00071         }
00072 
00073     public:
00074         // Element access
00075 #ifndef BOOST_UBLAS_REFERENCE_CONST_MEMBER
00076         BOOST_UBLAS_INLINE
00077         const_reference operator () (size_type i, size_type j) const {
00078             return expression () (i, j);
00079         }
00080         BOOST_UBLAS_INLINE
00081         reference operator () (size_type i, size_type j) {
00082             return expression () (i, j);
00083         }
00084 #else
00085         BOOST_UBLAS_INLINE
00086         reference operator () (size_type i, size_type j) const {
00087             return expression () (i, j);
00088         }
00089 #endif
00090 
00091         // Assignment
00092         BOOST_UBLAS_INLINE
00093         matrix_reference &operator = (const matrix_reference &m) {
00094             expression ().operator = (m);
00095             return *this;
00096         }
00097         template<class AE>
00098         BOOST_UBLAS_INLINE
00099         matrix_reference &operator = (const matrix_expression<AE> &ae) {
00100             expression ().operator = (ae);
00101             return *this;
00102         }
00103         template<class AE>
00104         BOOST_UBLAS_INLINE
00105         matrix_reference &assign (const matrix_expression<AE> &ae) {
00106             expression ().assign (ae);
00107             return *this;
00108         }
00109         template<class AE>
00110         BOOST_UBLAS_INLINE
00111         matrix_reference &operator += (const matrix_expression<AE> &ae) {
00112             expression ().operator += (ae);
00113             return *this;
00114         }
00115         template<class AE>
00116         BOOST_UBLAS_INLINE
00117         matrix_reference &plus_assign (const matrix_expression<AE> &ae) {
00118             expression ().plus_assign (ae);
00119             return *this;
00120         }
00121         template<class AE>
00122         BOOST_UBLAS_INLINE
00123         matrix_reference &operator -= (const matrix_expression<AE> &ae) {
00124             expression ().operator -= (ae);
00125             return *this;
00126         }
00127         template<class AE>
00128         BOOST_UBLAS_INLINE
00129         matrix_reference &minus_assign (const matrix_expression<AE> &ae) {
00130             expression ().minus_assign (ae);
00131             return *this;
00132         }
00133         template<class AT>
00134         BOOST_UBLAS_INLINE
00135         matrix_reference &operator *= (const AT &at) {
00136             expression ().operator *= (at);
00137             return *this;
00138         }
00139         template<class AT>
00140         BOOST_UBLAS_INLINE
00141         matrix_reference &operator /= (const AT &at) {
00142             expression ().operator /= (at);
00143             return *this;
00144         }
00145 
00146          // Swapping
00147         BOOST_UBLAS_INLINE
00148         void swap (matrix_reference &m) {
00149             expression ().swap (m.expression ());
00150         }
00151 
00152         // Closure comparison
00153         BOOST_UBLAS_INLINE
00154         bool same_closure (const matrix_reference &mr) const {
00155             return &(*this).e_ == &mr.e_;
00156         }
00157 
00158         // Iterator types
00159         typedef typename E::const_iterator1 const_iterator1;
00160         typedef typename boost::mpl::if_<boost::is_const<E>,
00161                                           typename E::const_iterator1,
00162                                           typename E::iterator1>::type iterator1;
00163         typedef typename E::const_iterator2 const_iterator2;
00164         typedef typename boost::mpl::if_<boost::is_const<E>,
00165                                           typename E::const_iterator2,
00166                                           typename E::iterator2>::type iterator2;
00167 
00168         // Element lookup
00169         BOOST_UBLAS_INLINE
00170         const_iterator1 find1 (int rank, size_type i, size_type j) const {
00171             return expression ().find1 (rank, i, j);
00172         }
00173         BOOST_UBLAS_INLINE
00174         iterator1 find1 (int rank, size_type i, size_type j) {
00175             return expression ().find1 (rank, i, j);
00176         }
00177         BOOST_UBLAS_INLINE
00178         const_iterator2 find2 (int rank, size_type i, size_type j) const {
00179             return expression ().find2 (rank, i, j);
00180         }
00181         BOOST_UBLAS_INLINE
00182         iterator2 find2 (int rank, size_type i, size_type j) {
00183             return expression ().find2 (rank, i, j);
00184         }
00185 
00186         // Iterators are the iterators of the referenced expression.
00187 
00188         BOOST_UBLAS_INLINE
00189         const_iterator1 begin1 () const {
00190             return expression ().begin1 ();
00191         }
00192         BOOST_UBLAS_INLINE
00193         const_iterator1 end1 () const {
00194             return expression ().end1 ();
00195         }
00196 
00197         BOOST_UBLAS_INLINE
00198         iterator1 begin1 () {
00199             return expression ().begin1 ();
00200         }
00201         BOOST_UBLAS_INLINE
00202         iterator1 end1 () {
00203             return expression ().end1 ();
00204         }
00205 
00206         BOOST_UBLAS_INLINE
00207         const_iterator2 begin2 () const {
00208             return expression ().begin2 ();
00209         }
00210         BOOST_UBLAS_INLINE
00211         const_iterator2 end2 () const {
00212             return expression ().end2 ();
00213         }
00214 
00215         BOOST_UBLAS_INLINE
00216         iterator2 begin2 () {
00217             return expression ().begin2 ();
00218         }
00219         BOOST_UBLAS_INLINE
00220         iterator2 end2 () {
00221             return expression ().end2 ();
00222         }
00223 
00224         // Reverse iterators
00225         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
00226         typedef reverse_iterator_base1<iterator1> reverse_iterator1;
00227 
00228         BOOST_UBLAS_INLINE
00229         const_reverse_iterator1 rbegin1 () const {
00230             return const_reverse_iterator1 (end1 ());
00231         }
00232         BOOST_UBLAS_INLINE
00233         const_reverse_iterator1 rend1 () const {
00234             return const_reverse_iterator1 (begin1 ());
00235         }
00236 
00237         BOOST_UBLAS_INLINE
00238         reverse_iterator1 rbegin1 () {
00239             return reverse_iterator1 (end1 ());
00240         }
00241         BOOST_UBLAS_INLINE
00242         reverse_iterator1 rend1 () {
00243             return reverse_iterator1 (begin1 ());
00244         }
00245 
00246         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
00247         typedef reverse_iterator_base2<iterator2> reverse_iterator2;
00248 
00249         BOOST_UBLAS_INLINE
00250         const_reverse_iterator2 rbegin2 () const {
00251             return const_reverse_iterator2 (end2 ());
00252         }
00253         BOOST_UBLAS_INLINE
00254         const_reverse_iterator2 rend2 () const {
00255             return const_reverse_iterator2 (begin2 ());
00256         }
00257 
00258         BOOST_UBLAS_INLINE
00259         reverse_iterator2 rbegin2 () {
00260             return reverse_iterator2 (end2 ());
00261         }
00262         BOOST_UBLAS_INLINE
00263         reverse_iterator2 rend2 () {
00264             return reverse_iterator2 (begin2 ());
00265         }
00266 
00267     private:
00268         referred_type &e_;
00269     };
00270 
00271 
00272     template<class E1, class E2, class F>
00273     class vector_matrix_binary:
00274         public matrix_expression<vector_matrix_binary<E1, E2, F> > {
00275 
00276         typedef E1 expression1_type;
00277         typedef E2 expression2_type;
00278     public:
00279         typedef typename E1::const_closure_type expression1_closure_type;
00280         typedef typename E2::const_closure_type expression2_closure_type;
00281     private:
00282         typedef vector_matrix_binary<E1, E2, F> self_type;
00283     public:
00284 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
00285         using matrix_expression<self_type>::operator ();
00286 #endif
00287         typedef F functor_type;
00288         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
00289         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
00290         typedef typename F::result_type value_type;
00291         typedef value_type const_reference;
00292         typedef const_reference reference;
00293         typedef const self_type const_closure_type;
00294         typedef const_closure_type closure_type;
00295         typedef unknown_orientation_tag orientation_category;
00296         typedef unknown_storage_tag storage_category;
00297 
00298         // Construction and destruction 
00299         BOOST_UBLAS_INLINE
00300         vector_matrix_binary (const expression1_type &e1, const expression2_type &e2): 
00301             e1_ (e1), e2_ (e2) {}
00302 
00303         // Accessors
00304         BOOST_UBLAS_INLINE
00305         size_type size1 () const {
00306             return e1_.size ();
00307         }
00308         BOOST_UBLAS_INLINE
00309         size_type size2 () const { 
00310             return e2_.size ();
00311         }
00312 
00313     public:
00314         // Expression accessors
00315         BOOST_UBLAS_INLINE
00316         const expression1_closure_type &expression1 () const {
00317             return e1_;
00318         }
00319         BOOST_UBLAS_INLINE
00320         const expression2_closure_type &expression2 () const {
00321             return e2_;
00322         }
00323 
00324     public:
00325         // Element access
00326         BOOST_UBLAS_INLINE
00327         const_reference operator () (size_type i, size_type j) const {
00328             return functor_type::apply (e1_ (i), e2_ (j));
00329         }
00330 
00331         // Closure comparison
00332         BOOST_UBLAS_INLINE
00333         bool same_closure (const vector_matrix_binary &vmb) const {
00334             return (*this).expression1 ().same_closure (vmb.expression1 ()) &&
00335                    (*this).expression2 ().same_closure (vmb.expression2 ());
00336         }
00337 
00338         // Iterator types
00339     private:
00340         typedef typename E1::const_iterator const_subiterator1_type;
00341         typedef typename E2::const_iterator const_subiterator2_type;
00342         typedef const value_type *const_pointer;
00343 
00344     public:
00345 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
00346         typedef typename iterator_restrict_traits<typename const_subiterator1_type::iterator_category,
00347                                                   typename const_subiterator2_type::iterator_category>::iterator_category iterator_category;
00348         typedef indexed_const_iterator1<const_closure_type, iterator_category> const_iterator1;
00349         typedef const_iterator1 iterator1;
00350         typedef indexed_const_iterator2<const_closure_type, iterator_category> const_iterator2;
00351         typedef const_iterator2 iterator2;
00352 #else
00353         class const_iterator1;
00354         typedef const_iterator1 iterator1;
00355         class const_iterator2;
00356         typedef const_iterator2 iterator2;
00357 #endif
00358         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
00359         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
00360 
00361         // Element lookup
00362         BOOST_UBLAS_INLINE
00363         const_iterator1 find1 (int rank, size_type i, size_type j) const {
00364             const_subiterator1_type it1 (e1_.find (i));
00365             const_subiterator1_type it1_end (e1_.find (size1 ()));
00366             const_subiterator2_type it2 (e2_.find (j));
00367             const_subiterator2_type it2_end (e2_.find (size2 ()));
00368             if (it2 == it2_end || (rank == 1 && (it2.index () != j || *it2 == value_type/*zero*/()))) {
00369                 it1 = it1_end;
00370                 it2 = it2_end;
00371             }
00372 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
00373             return const_iterator1 (*this, it1.index (), it2.index ());
00374 #else
00375 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00376             return const_iterator1 (*this, it1, it2, it2 != it2_end ? *it2 : value_type/*zero*/());
00377 #else
00378             return const_iterator1 (*this, it1, it2);
00379 #endif
00380 #endif
00381         }
00382         BOOST_UBLAS_INLINE
00383         const_iterator2 find2 (int rank, size_type i, size_type j) const {
00384             const_subiterator2_type it2 (e2_.find (j));
00385             const_subiterator2_type it2_end (e2_.find (size2 ()));
00386             const_subiterator1_type it1 (e1_.find (i));
00387             const_subiterator1_type it1_end (e1_.find (size1 ()));
00388             if (it1 == it1_end || (rank == 1 && (it1.index () != i || *it1 == value_type/*zero*/()))) {
00389                 it2 = it2_end;
00390                 it1 = it1_end;
00391             }
00392 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
00393             return const_iterator2 (*this, it1.index (), it2.index ());
00394 #else
00395 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00396             return const_iterator2 (*this, it1, it2, it1 != it1_end ? *it1 : value_type/*zero*/());
00397 #else
00398             return const_iterator2 (*this, it1, it2);
00399 #endif
00400 #endif
00401         }
00402 
00403         // Iterators enhance the iterators of the referenced expressions
00404         // with the binary functor.
00405 
00406 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
00407         class const_iterator1:
00408             public container_const_reference<vector_matrix_binary>,
00409             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
00410                                                                           typename E2::const_iterator::iterator_category>::iterator_category>::template
00411                 iterator_base<const_iterator1, value_type>::type {
00412         public:
00413             typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
00414                                                       typename E2::const_iterator::iterator_category>::iterator_category iterator_category;
00415             typedef typename vector_matrix_binary::difference_type difference_type;
00416             typedef typename vector_matrix_binary::value_type value_type;
00417             typedef typename vector_matrix_binary::const_reference reference;
00418             typedef typename vector_matrix_binary::const_pointer pointer;
00419 
00420             typedef const_iterator2 dual_iterator_type;
00421             typedef const_reverse_iterator2 dual_reverse_iterator_type;
00422 
00423             // Construction and destruction
00424 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00425             BOOST_UBLAS_INLINE
00426             const_iterator1 ():
00427                 container_const_reference<self_type> (), it1_ (), it2_ (), t2_ () {}
00428             BOOST_UBLAS_INLINE
00429             const_iterator1 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2, value_type t2):
00430                 container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2), t2_ (t2) {}
00431 #else
00432             BOOST_UBLAS_INLINE
00433             const_iterator1 ():
00434                 container_const_reference<self_type> (), it1_ (), it2_ () {}
00435             BOOST_UBLAS_INLINE
00436             const_iterator1 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2):
00437                 container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2) {}
00438 #endif
00439 
00440             // Arithmetic
00441             BOOST_UBLAS_INLINE
00442             const_iterator1 &operator ++ () {
00443                 ++ it1_;
00444                 return *this;
00445             }
00446             BOOST_UBLAS_INLINE
00447             const_iterator1 &operator -- () {
00448                 -- it1_;
00449                 return *this;
00450             }
00451             BOOST_UBLAS_INLINE
00452             const_iterator1 &operator += (difference_type n) {
00453                 it1_ += n;
00454                 return *this;
00455             }
00456             BOOST_UBLAS_INLINE
00457             const_iterator1 &operator -= (difference_type n) {
00458                 it1_ -= n;
00459                 return *this;
00460             }
00461             BOOST_UBLAS_INLINE
00462             difference_type operator - (const const_iterator1 &it) const {
00463                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
00464                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
00465                 return it1_ - it.it1_;
00466             }
00467 
00468             // Dereference
00469             BOOST_UBLAS_INLINE
00470             const_reference operator * () const {
00471 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00472                 return functor_type::apply (*it1_, t2_);
00473 #else
00474                 return functor_type::apply (*it1_, *it2_);
00475 #endif
00476             }
00477             BOOST_UBLAS_INLINE
00478             const_reference operator [] (difference_type n) const {
00479                 return *(*this + n);
00480             }
00481 
00482 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
00483             BOOST_UBLAS_INLINE
00484 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00485             typename self_type::
00486 #endif
00487             const_iterator2 begin () const {
00488                 return (*this) ().find2 (1, index1 (), 0);
00489             }
00490             BOOST_UBLAS_INLINE
00491 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00492             typename self_type::
00493 #endif
00494             const_iterator2 end () const {
00495                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
00496             }
00497             BOOST_UBLAS_INLINE
00498 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00499             typename self_type::
00500 #endif
00501             const_reverse_iterator2 rbegin () const {
00502                 return const_reverse_iterator2 (end ());
00503             }
00504             BOOST_UBLAS_INLINE
00505 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00506             typename self_type::
00507 #endif
00508             const_reverse_iterator2 rend () const {
00509                 return const_reverse_iterator2 (begin ());
00510             }
00511 #endif
00512 
00513             // Indices
00514             BOOST_UBLAS_INLINE
00515             size_type index1 () const {
00516                 return it1_.index ();
00517             }
00518             BOOST_UBLAS_INLINE
00519             size_type  index2 () const {
00520                 return it2_.index ();
00521             }
00522 
00523             // Assignment
00524             BOOST_UBLAS_INLINE
00525             const_iterator1 &operator = (const const_iterator1 &it) {
00526                 container_const_reference<self_type>::assign (&it ());
00527                 it1_ = it.it1_;
00528                 it2_ = it.it2_;
00529 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00530                 t2_ = it.t2_;
00531 #endif
00532                 return *this;
00533             }
00534 
00535             // Comparison
00536             BOOST_UBLAS_INLINE
00537             bool operator == (const const_iterator1 &it) const {
00538                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
00539                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
00540                 return it1_ == it.it1_;
00541             }
00542             BOOST_UBLAS_INLINE
00543             bool operator < (const const_iterator1 &it) const {
00544                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
00545                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
00546                 return it1_ < it.it1_;
00547             }
00548 
00549         private:
00550 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00551             const_subiterator1_type it1_;
00552             // Mutable due to assignment
00553             /* const */ const_subiterator2_type it2_;
00554             value_type t2_;
00555 #else
00556             const_subiterator1_type it1_;
00557             const_subiterator2_type it2_;
00558 #endif
00559         };
00560 #endif
00561 
00562         BOOST_UBLAS_INLINE
00563         const_iterator1 begin1 () const {
00564             return find1 (0, 0, 0);
00565         }
00566         BOOST_UBLAS_INLINE
00567         const_iterator1 end1 () const {
00568             return find1 (0, size1 (), 0);
00569         }
00570 
00571 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
00572         class const_iterator2:
00573             public container_const_reference<vector_matrix_binary>,
00574             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
00575                                                                           typename E2::const_iterator::iterator_category>::iterator_category>::template
00576                 iterator_base<const_iterator2, value_type>::type {
00577         public:
00578             typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category, 
00579                                                       typename E2::const_iterator::iterator_category>::iterator_category iterator_category;
00580             typedef typename vector_matrix_binary::difference_type difference_type;
00581             typedef typename vector_matrix_binary::value_type value_type;
00582             typedef typename vector_matrix_binary::const_reference reference;
00583             typedef typename vector_matrix_binary::const_pointer pointer;
00584 
00585             typedef const_iterator1 dual_iterator_type;
00586             typedef const_reverse_iterator1 dual_reverse_iterator_type;
00587 
00588             // Construction and destruction
00589 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00590             BOOST_UBLAS_INLINE
00591             const_iterator2 ():
00592                 container_const_reference<self_type> (), it1_ (), it2_ (), t1_ () {}
00593             BOOST_UBLAS_INLINE
00594             const_iterator2 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2, value_type t1):
00595                 container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2), t1_ (t1) {}
00596 #else
00597             BOOST_UBLAS_INLINE
00598             const_iterator2 ():
00599                 container_const_reference<self_type> (), it1_ (), it2_ () {}
00600             BOOST_UBLAS_INLINE
00601             const_iterator2 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2):
00602                 container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2) {}
00603 #endif
00604 
00605             // Arithmetic
00606             BOOST_UBLAS_INLINE
00607             const_iterator2 &operator ++ () {
00608                 ++ it2_;
00609                 return *this;
00610             }
00611             BOOST_UBLAS_INLINE
00612             const_iterator2 &operator -- () {
00613                 -- it2_;
00614                 return *this;
00615             }
00616             BOOST_UBLAS_INLINE
00617             const_iterator2 &operator += (difference_type n) {
00618                 it2_ += n;
00619                 return *this;
00620             }
00621             BOOST_UBLAS_INLINE
00622             const_iterator2 &operator -= (difference_type n) {
00623                 it2_ -= n;
00624                 return *this;
00625             }
00626             BOOST_UBLAS_INLINE
00627             difference_type operator - (const const_iterator2 &it) const {
00628                 BOOST_UBLAS_CHECK ((*this) ().same_closure(it ()), external_logic ());
00629                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
00630                 return it2_ - it.it2_;
00631             }
00632 
00633             // Dereference
00634             BOOST_UBLAS_INLINE
00635             const_reference operator * () const {
00636 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00637                 return functor_type::apply (t1_, *it2_);
00638 #else
00639                 return functor_type::apply (*it1_, *it2_);
00640 #endif
00641             }
00642             BOOST_UBLAS_INLINE
00643             const_reference operator [] (difference_type n) const {
00644                 return *(*this + n);
00645             }
00646 
00647 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
00648             BOOST_UBLAS_INLINE
00649 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00650             typename self_type::
00651 #endif
00652             const_iterator1 begin () const {
00653                 return (*this) ().find1 (1, 0, index2 ());
00654             }
00655             BOOST_UBLAS_INLINE
00656 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00657             typename self_type::
00658 #endif
00659             const_iterator1 end () const {
00660                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
00661             }
00662             BOOST_UBLAS_INLINE
00663 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00664             typename self_type::
00665 #endif
00666             const_reverse_iterator1 rbegin () const {
00667                 return const_reverse_iterator1 (end ());
00668             }
00669             BOOST_UBLAS_INLINE
00670 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00671             typename self_type::
00672 #endif
00673             const_reverse_iterator1 rend () const {
00674                 return const_reverse_iterator1 (begin ());
00675             }
00676 #endif
00677 
00678             // Indices
00679             BOOST_UBLAS_INLINE
00680             size_type index1 () const {
00681                 return it1_.index ();
00682             }
00683             BOOST_UBLAS_INLINE
00684             size_type  index2 () const {
00685                 return it2_.index ();
00686             }
00687 
00688             // Assignment
00689             BOOST_UBLAS_INLINE
00690             const_iterator2 &operator = (const const_iterator2 &it) {
00691                 container_const_reference<self_type>::assign (&it ());
00692                 it1_ = it.it1_;
00693                 it2_ = it.it2_;
00694 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00695                 t1_ = it.t1_;
00696 #endif
00697                 return *this;
00698             }
00699 
00700             // Comparison
00701             BOOST_UBLAS_INLINE
00702             bool operator == (const const_iterator2 &it) const {
00703                 BOOST_UBLAS_CHECK ((*this) ().same_closure( it ()), external_logic ());
00704                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
00705                 return it2_ == it.it2_;
00706             }
00707             BOOST_UBLAS_INLINE
00708             bool operator < (const const_iterator2 &it) const {
00709                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
00710                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
00711                 return it2_ < it.it2_;
00712             }
00713 
00714         private:
00715 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
00716             // Mutable due to assignment
00717             /* const */ const_subiterator1_type it1_;
00718             const_subiterator2_type it2_;
00719             value_type t1_;
00720 #else
00721             const_subiterator1_type it1_;
00722             const_subiterator2_type it2_;
00723 #endif
00724         };
00725 #endif
00726 
00727         BOOST_UBLAS_INLINE
00728         const_iterator2 begin2 () const {
00729             return find2 (0, 0, 0);
00730         }
00731         BOOST_UBLAS_INLINE
00732         const_iterator2 end2 () const {
00733             return find2 (0, 0, size2 ());
00734         }
00735 
00736         // Reverse iterators
00737 
00738         BOOST_UBLAS_INLINE
00739         const_reverse_iterator1 rbegin1 () const {
00740             return const_reverse_iterator1 (end1 ());
00741         }
00742         BOOST_UBLAS_INLINE
00743         const_reverse_iterator1 rend1 () const {
00744             return const_reverse_iterator1 (begin1 ());
00745         }
00746 
00747         BOOST_UBLAS_INLINE
00748         const_reverse_iterator2 rbegin2 () const {
00749             return const_reverse_iterator2 (end2 ());
00750         }
00751         BOOST_UBLAS_INLINE
00752         const_reverse_iterator2 rend2 () const {
00753             return const_reverse_iterator2 (begin2 ());
00754         }
00755 
00756     private:
00757         expression1_closure_type e1_;
00758         expression2_closure_type e2_;
00759     };
00760 
00761     template<class E1, class E2, class F>
00762     struct vector_matrix_binary_traits {
00763         typedef vector_matrix_binary<E1, E2, F> expression_type;
00764 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
00765         typedef expression_type result_type; 
00766 #else
00767         // ISSUE matrix is arbitary temporary type
00768         typedef matrix<typename F::value_type> result_type;
00769 #endif
00770     };
00771 
00772     // (outer_prod (v1, v2)) [i] [j] = v1 [i] * v2 [j]
00773     template<class E1, class E2>
00774     BOOST_UBLAS_INLINE
00775     typename vector_matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, typename E2::value_type> >::result_type
00776     outer_prod (const vector_expression<E1> &e1,
00777                 const vector_expression<E2> &e2) {
00778         BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0);
00779         typedef typename vector_matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, typename E2::value_type> >::expression_type expression_type;
00780         return expression_type (e1 (), e2 ());
00781     }
00782 
00783     template<class E, class F>
00784     class matrix_unary1:
00785         public matrix_expression<matrix_unary1<E, F> > {
00786 
00787         typedef E expression_type;
00788         typedef F functor_type;
00789     public:
00790         typedef typename E::const_closure_type expression_closure_type;
00791     private:
00792         typedef matrix_unary1<E, F> self_type;
00793     public:
00794 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
00795         using matrix_expression<self_type>::operator ();
00796 #endif
00797         typedef typename E::size_type size_type;
00798         typedef typename E::difference_type difference_type;
00799         typedef typename F::result_type value_type;
00800         typedef value_type const_reference;
00801         typedef const_reference reference;
00802         typedef const self_type const_closure_type;
00803         typedef const_closure_type closure_type;
00804         typedef typename E::orientation_category orientation_category;
00805         typedef unknown_storage_tag storage_category;
00806 
00807         // Construction and destruction
00808         BOOST_UBLAS_INLINE
00809         explicit matrix_unary1 (const expression_type &e):
00810             e_ (e) {}
00811 
00812         // Accessors
00813         BOOST_UBLAS_INLINE
00814         size_type size1 () const {
00815             return e_.size1 ();
00816         }
00817         BOOST_UBLAS_INLINE
00818         size_type size2 () const {
00819             return e_.size2 ();
00820         }
00821 
00822     public:
00823         // Expression accessors
00824         BOOST_UBLAS_INLINE
00825         const expression_closure_type &expression () const {
00826             return e_;
00827         }
00828 
00829     public:
00830         // Element access
00831         BOOST_UBLAS_INLINE
00832         const_reference operator () (size_type i, size_type j) const {
00833             return functor_type::apply (e_ (i, j));
00834         }
00835 
00836         // Closure comparison
00837         BOOST_UBLAS_INLINE
00838         bool same_closure (const matrix_unary1 &mu1) const {
00839             return (*this).expression ().same_closure (mu1.expression ());
00840         }
00841 
00842         // Iterator types
00843     private:
00844         typedef typename E::const_iterator1 const_subiterator1_type;
00845         typedef typename E::const_iterator2 const_subiterator2_type;
00846         typedef const value_type *const_pointer;
00847 
00848     public:
00849 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
00850         typedef indexed_const_iterator1<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator1;
00851         typedef const_iterator1 iterator1;
00852         typedef indexed_const_iterator2<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator2;
00853         typedef const_iterator2 iterator2;
00854 #else
00855         class const_iterator1;
00856         typedef const_iterator1 iterator1;
00857         class const_iterator2;
00858         typedef const_iterator2 iterator2;
00859 #endif
00860         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
00861         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
00862 
00863         // Element lookup
00864         BOOST_UBLAS_INLINE
00865         const_iterator1 find1 (int rank, size_type i, size_type j) const {
00866             const_subiterator1_type it1 (e_.find1 (rank, i, j));
00867 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
00868             return const_iterator1 (*this, it1.index1 (), it1.index2 ());
00869 #else
00870             return const_iterator1 (*this, it1);
00871 #endif
00872         }
00873         BOOST_UBLAS_INLINE
00874         const_iterator2 find2 (int rank, size_type i, size_type j) const {
00875             const_subiterator2_type it2 (e_.find2 (rank, i, j));
00876 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
00877             return const_iterator2 (*this, it2.index1 (), it2.index2 ());
00878 #else
00879             return const_iterator2 (*this, it2);
00880 #endif
00881         }
00882 
00883         // Iterators enhance the iterators of the referenced expression
00884         // with the unary functor.
00885 
00886 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
00887         class const_iterator1:
00888             public container_const_reference<matrix_unary1>,
00889             public iterator_base_traits<typename E::const_iterator1::iterator_category>::template
00890                 iterator_base<const_iterator1, value_type>::type {
00891         public:
00892             typedef typename E::const_iterator1::iterator_category iterator_category;
00893             typedef typename matrix_unary1::difference_type difference_type;
00894             typedef typename matrix_unary1::value_type value_type;
00895             typedef typename matrix_unary1::const_reference reference;
00896             typedef typename matrix_unary1::const_pointer pointer;
00897 
00898             typedef const_iterator2 dual_iterator_type;
00899             typedef const_reverse_iterator2 dual_reverse_iterator_type;
00900 
00901             // Construction and destruction
00902             BOOST_UBLAS_INLINE
00903             const_iterator1 ():
00904                 container_const_reference<self_type> (), it_ () {}
00905             BOOST_UBLAS_INLINE
00906             const_iterator1 (const self_type &mu, const const_subiterator1_type &it):
00907                 container_const_reference<self_type> (mu), it_ (it) {}
00908 
00909             // Arithmetic
00910             BOOST_UBLAS_INLINE
00911             const_iterator1 &operator ++ () {
00912                 ++ it_;
00913                 return *this;
00914             }
00915             BOOST_UBLAS_INLINE
00916             const_iterator1 &operator -- () {
00917                 -- it_;
00918                 return *this;
00919             }
00920             BOOST_UBLAS_INLINE
00921             const_iterator1 &operator += (difference_type n) {
00922                 it_ += n;
00923                 return *this;
00924             }
00925             BOOST_UBLAS_INLINE
00926             const_iterator1 &operator -= (difference_type n) {
00927                 it_ -= n;
00928                 return *this;
00929             }
00930             BOOST_UBLAS_INLINE
00931             difference_type operator - (const const_iterator1 &it) const {
00932                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
00933                 return it_ - it.it_;
00934             }
00935 
00936             // Dereference
00937             BOOST_UBLAS_INLINE
00938             const_reference operator * () const {
00939                 return functor_type::apply (*it_);
00940             }
00941             BOOST_UBLAS_INLINE
00942             const_reference operator [] (difference_type n) const {
00943                 return *(*this + n);
00944             }
00945 
00946 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
00947             BOOST_UBLAS_INLINE
00948 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00949             typename self_type::
00950 #endif
00951             const_iterator2 begin () const {
00952                 return (*this) ().find2 (1, index1 (), 0);
00953             }
00954             BOOST_UBLAS_INLINE
00955 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00956             typename self_type::
00957 #endif
00958             const_iterator2 end () const {
00959                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
00960             }
00961             BOOST_UBLAS_INLINE
00962 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00963             typename self_type::
00964 #endif
00965             const_reverse_iterator2 rbegin () const {
00966                 return const_reverse_iterator2 (end ());
00967             }
00968             BOOST_UBLAS_INLINE
00969 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
00970             typename self_type::
00971 #endif
00972             const_reverse_iterator2 rend () const {
00973                 return const_reverse_iterator2 (begin ());
00974             }
00975 #endif
00976 
00977             // Indices
00978             BOOST_UBLAS_INLINE
00979             size_type index1 () const {
00980                 return it_.index1 ();
00981             }
00982             BOOST_UBLAS_INLINE
00983             size_type index2 () const {
00984                 return it_.index2 ();
00985             }
00986 
00987             // Assignment 
00988             BOOST_UBLAS_INLINE
00989             const_iterator1 &operator = (const const_iterator1 &it) {
00990                 container_const_reference<self_type>::assign (&it ());
00991                 it_ = it.it_;
00992                 return *this;
00993             }
00994 
00995             // Comparison
00996             BOOST_UBLAS_INLINE
00997             bool operator == (const const_iterator1 &it) const {
00998                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
00999                 return it_ == it.it_;
01000             }
01001             BOOST_UBLAS_INLINE
01002             bool operator < (const const_iterator1 &it) const {
01003                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01004                 return it_ < it.it_;
01005             }
01006 
01007         private:
01008             const_subiterator1_type it_;
01009         };
01010 #endif
01011 
01012         BOOST_UBLAS_INLINE
01013         const_iterator1 begin1 () const {
01014             return find1 (0, 0, 0);
01015         }
01016         BOOST_UBLAS_INLINE
01017         const_iterator1 end1 () const {
01018             return find1 (0, size1 (), 0);
01019         }
01020 
01021 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
01022         class const_iterator2:
01023             public container_const_reference<matrix_unary1>,
01024             public iterator_base_traits<typename E::const_iterator2::iterator_category>::template
01025                 iterator_base<const_iterator2, value_type>::type {
01026         public:
01027             typedef typename E::const_iterator2::iterator_category iterator_category;
01028             typedef typename matrix_unary1::difference_type difference_type;
01029             typedef typename matrix_unary1::value_type value_type;
01030             typedef typename matrix_unary1::const_reference reference;
01031             typedef typename matrix_unary1::const_pointer pointer;
01032 
01033             typedef const_iterator1 dual_iterator_type;
01034             typedef const_reverse_iterator1 dual_reverse_iterator_type;
01035 
01036             // Construction and destruction
01037             BOOST_UBLAS_INLINE
01038             const_iterator2 ():
01039                 container_const_reference<self_type> (), it_ () {}
01040             BOOST_UBLAS_INLINE
01041             const_iterator2 (const self_type &mu, const const_subiterator2_type &it):
01042                 container_const_reference<self_type> (mu), it_ (it) {}
01043 
01044             // Arithmetic
01045             BOOST_UBLAS_INLINE
01046             const_iterator2 &operator ++ () {
01047                 ++ it_;
01048                 return *this;
01049             }
01050             BOOST_UBLAS_INLINE
01051             const_iterator2 &operator -- () {
01052                 -- it_;
01053                 return *this;
01054             }
01055             BOOST_UBLAS_INLINE
01056             const_iterator2 &operator += (difference_type n) {
01057                 it_ += n;
01058                 return *this;
01059             }
01060             BOOST_UBLAS_INLINE
01061             const_iterator2 &operator -= (difference_type n) {
01062                 it_ -= n;
01063                 return *this;
01064             }
01065             BOOST_UBLAS_INLINE
01066             difference_type operator - (const const_iterator2 &it) const {
01067                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01068                 return it_ - it.it_;
01069             }
01070 
01071             // Dereference
01072             BOOST_UBLAS_INLINE
01073             const_reference operator * () const {
01074                 return functor_type::apply (*it_);
01075             }
01076             BOOST_UBLAS_INLINE
01077             const_reference operator [] (difference_type n) const {
01078                 return *(*this + n);
01079             }
01080 
01081 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
01082             BOOST_UBLAS_INLINE
01083 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01084             typename self_type::
01085 #endif
01086             const_iterator1 begin () const {
01087                 return (*this) ().find1 (1, 0, index2 ());
01088             }
01089             BOOST_UBLAS_INLINE
01090 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01091             typename self_type::
01092 #endif
01093             const_iterator1 end () const {
01094                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
01095             }
01096             BOOST_UBLAS_INLINE
01097 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01098             typename self_type::
01099 #endif
01100             const_reverse_iterator1 rbegin () const {
01101                 return const_reverse_iterator1 (end ());
01102             }
01103             BOOST_UBLAS_INLINE
01104 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01105             typename self_type::
01106 #endif
01107             const_reverse_iterator1 rend () const {
01108                 return const_reverse_iterator1 (begin ());
01109             }
01110 #endif
01111 
01112             // Indices
01113             BOOST_UBLAS_INLINE
01114             size_type index1 () const {
01115                 return it_.index1 ();
01116             }
01117             BOOST_UBLAS_INLINE
01118             size_type index2 () const {
01119                 return it_.index2 ();
01120             }
01121 
01122             // Assignment 
01123             BOOST_UBLAS_INLINE
01124             const_iterator2 &operator = (const const_iterator2 &it) {
01125                 container_const_reference<self_type>::assign (&it ());
01126                 it_ = it.it_;
01127                 return *this;
01128             }
01129 
01130             // Comparison
01131             BOOST_UBLAS_INLINE
01132             bool operator == (const const_iterator2 &it) const {
01133                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01134                 return it_ == it.it_;
01135             }
01136             BOOST_UBLAS_INLINE
01137             bool operator < (const const_iterator2 &it) const {
01138                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01139                 return it_ < it.it_;
01140             }
01141 
01142         private:
01143             const_subiterator2_type it_;
01144         };
01145 #endif
01146 
01147         BOOST_UBLAS_INLINE
01148         const_iterator2 begin2 () const {
01149             return find2 (0, 0, 0);
01150         }
01151         BOOST_UBLAS_INLINE
01152         const_iterator2 end2 () const {
01153             return find2 (0, 0, size2 ());
01154         }
01155 
01156         // Reverse iterators
01157 
01158         BOOST_UBLAS_INLINE
01159         const_reverse_iterator1 rbegin1 () const {
01160             return const_reverse_iterator1 (end1 ());
01161         }
01162         BOOST_UBLAS_INLINE
01163         const_reverse_iterator1 rend1 () const {
01164             return const_reverse_iterator1 (begin1 ());
01165         }
01166 
01167         BOOST_UBLAS_INLINE
01168         const_reverse_iterator2 rbegin2 () const {
01169             return const_reverse_iterator2 (end2 ());
01170         }
01171         BOOST_UBLAS_INLINE
01172         const_reverse_iterator2 rend2 () const {
01173             return const_reverse_iterator2 (begin2 ());
01174         }
01175 
01176     private:
01177         expression_closure_type e_;
01178     };
01179 
01180     template<class E, class F>
01181     struct matrix_unary1_traits {
01182         typedef matrix_unary1<E, F> expression_type;
01183 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
01184         typedef expression_type result_type; 
01185 #else
01186         typedef typename E::matrix_temporary_type result_type;
01187 #endif
01188     };
01189 
01190     // (- m) [i] [j] = - m [i] [j]
01191     template<class E>
01192     BOOST_UBLAS_INLINE
01193     typename matrix_unary1_traits<E, scalar_negate<typename E::value_type> >::result_type
01194     operator - (const matrix_expression<E> &e) {
01195         typedef typename matrix_unary1_traits<E, scalar_negate<typename E::value_type> >::expression_type expression_type;
01196         return expression_type (e ());
01197     }
01198 
01199     // (conj m) [i] [j] = conj (m [i] [j])
01200     template<class E> 
01201     BOOST_UBLAS_INLINE
01202     typename matrix_unary1_traits<E, scalar_conj<typename E::value_type> >::result_type
01203     conj (const matrix_expression<E> &e) {
01204         typedef typename matrix_unary1_traits<E, scalar_conj<typename E::value_type> >::expression_type expression_type;
01205         return expression_type (e ());
01206     }
01207 
01208     // (real m) [i] [j] = real (m [i] [j])
01209     template<class E> 
01210     BOOST_UBLAS_INLINE
01211     typename matrix_unary1_traits<E, scalar_real<typename E::value_type> >::result_type
01212     real (const matrix_expression<E> &e) {
01213         typedef typename matrix_unary1_traits<E, scalar_real<typename E::value_type> >::expression_type expression_type;
01214         return expression_type (e ());
01215     }
01216 
01217     // (imag m) [i] [j] = imag (m [i] [j])
01218     template<class E> 
01219     BOOST_UBLAS_INLINE
01220     typename matrix_unary1_traits<E, scalar_imag<typename E::value_type> >::result_type
01221     imag (const matrix_expression<E> &e) {
01222         typedef typename matrix_unary1_traits<E, scalar_imag<typename E::value_type> >::expression_type expression_type;
01223         return expression_type (e ());
01224     }
01225 
01226     template<class E, class F>
01227     class matrix_unary2:
01228         public matrix_expression<matrix_unary2<E, F> > {
01229 
01230         typedef typename boost::mpl::if_<boost::is_same<F, scalar_identity<typename E::value_type> >,
01231                                           E,
01232                                           const E>::type expression_type;
01233         typedef F functor_type;
01234     public:
01235         typedef typename boost::mpl::if_<boost::is_const<expression_type>,
01236                                           typename E::const_closure_type,
01237                                           typename E::closure_type>::type expression_closure_type;
01238     private:
01239         typedef matrix_unary2<E, F> self_type;
01240     public:
01241 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
01242         using matrix_expression<self_type>::operator ();
01243 #endif
01244         typedef typename E::size_type size_type;
01245         typedef typename E::difference_type difference_type;
01246         typedef typename F::result_type value_type;
01247         typedef value_type const_reference;
01248         typedef typename boost::mpl::if_<boost::is_same<F, scalar_identity<value_type> >,
01249                                           typename E::reference,
01250                                           value_type>::type reference;
01251 
01252         typedef const self_type const_closure_type;
01253         typedef self_type closure_type;
01254         typedef typename boost::mpl::if_<boost::is_same<typename E::orientation_category,
01255                                                          row_major_tag>,
01256                                           column_major_tag,
01257                 typename boost::mpl::if_<boost::is_same<typename E::orientation_category,
01258                                                          column_major_tag>,
01259                                           row_major_tag,
01260                                           typename E::orientation_category>::type>::type orientation_category;
01261         typedef typename E::storage_category storage_category;
01262 
01263         // Construction and destruction
01264         BOOST_UBLAS_INLINE
01265         // matrix_unary2 may be used as mutable expression -
01266         // this is the only non const expression constructor
01267         explicit matrix_unary2 (expression_type &e):
01268             e_ (e) {}
01269 
01270         // Accessors
01271         BOOST_UBLAS_INLINE
01272         size_type size1 () const {
01273             return e_.size2 ();
01274         }
01275         BOOST_UBLAS_INLINE
01276         size_type size2 () const {
01277             return e_.size1 ();
01278         }
01279 
01280     public:
01281         // Expression accessors
01282         BOOST_UBLAS_INLINE
01283         const expression_closure_type &expression () const {
01284             return e_;
01285         }
01286 
01287     public:
01288         // Element access
01289         BOOST_UBLAS_INLINE
01290         const_reference operator () (size_type i, size_type j) const {
01291             return functor_type::apply (e_ (j, i));
01292         }
01293         BOOST_UBLAS_INLINE
01294         reference operator () (size_type i, size_type j) {
01295             BOOST_STATIC_ASSERT ((boost::is_same<functor_type, scalar_identity<value_type > >::value));
01296             return e_ (j, i);
01297         }
01298 
01299         // Closure comparison
01300         BOOST_UBLAS_INLINE
01301         bool same_closure (const matrix_unary2 &mu2) const {
01302             return (*this).expression ().same_closure (mu2.expression ());
01303         }
01304 
01305         // Iterator types
01306     private:
01307         typedef typename E::const_iterator1 const_subiterator2_type;
01308         typedef typename E::const_iterator2 const_subiterator1_type;
01309         typedef const value_type *const_pointer;
01310 
01311     public:
01312 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
01313         typedef indexed_const_iterator1<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator1;
01314         typedef const_iterator1 iterator1;
01315         typedef indexed_const_iterator2<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator2;
01316         typedef const_iterator2 iterator2;
01317 #else
01318         class const_iterator1;
01319         typedef const_iterator1 iterator1;
01320         class const_iterator2;
01321         typedef const_iterator2 iterator2;
01322 #endif
01323         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
01324         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
01325 
01326         // Element lookup
01327         BOOST_UBLAS_INLINE
01328         const_iterator1 find1 (int rank, size_type i, size_type j) const {
01329             const_subiterator1_type it1 (e_.find2 (rank, j, i));
01330 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
01331             return const_iterator1 (*this, it1.index2 (), it1.index1 ());
01332 #else
01333             return const_iterator1 (*this, it1);
01334 #endif
01335         }
01336         BOOST_UBLAS_INLINE
01337         const_iterator2 find2 (int rank, size_type i, size_type j) const {
01338             const_subiterator2_type it2 (e_.find1 (rank, j, i));
01339 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
01340             return const_iterator2 (*this, it2.index2 (), it2.index1 ());
01341 #else
01342             return const_iterator2 (*this, it2);
01343 #endif
01344         }
01345 
01346         // Iterators enhance the iterators of the referenced expression
01347         // with the unary functor.
01348 
01349 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
01350         class const_iterator1:
01351             public container_const_reference<matrix_unary2>,
01352             public iterator_base_traits<typename E::const_iterator2::iterator_category>::template
01353                 iterator_base<const_iterator1, value_type>::type {
01354         public:
01355             typedef typename E::const_iterator2::iterator_category iterator_category;
01356             typedef typename matrix_unary2::difference_type difference_type;
01357             typedef typename matrix_unary2::value_type value_type;
01358             typedef typename matrix_unary2::const_reference reference;
01359             typedef typename matrix_unary2::const_pointer pointer;
01360 
01361             typedef const_iterator2 dual_iterator_type;
01362             typedef const_reverse_iterator2 dual_reverse_iterator_type;
01363 
01364             // Construction and destruction
01365             BOOST_UBLAS_INLINE
01366             const_iterator1 ():
01367                 container_const_reference<self_type> (), it_ () {}
01368             BOOST_UBLAS_INLINE
01369             const_iterator1 (const self_type &mu, const const_subiterator1_type &it):
01370                 container_const_reference<self_type> (mu), it_ (it) {}
01371 
01372             // Arithmetic
01373             BOOST_UBLAS_INLINE
01374             const_iterator1 &operator ++ () {
01375                 ++ it_;
01376                 return *this;
01377             }
01378             BOOST_UBLAS_INLINE
01379             const_iterator1 &operator -- () {
01380                 -- it_;
01381                 return *this;
01382             }
01383             BOOST_UBLAS_INLINE
01384             const_iterator1 &operator += (difference_type n) {
01385                 it_ += n;
01386                 return *this;
01387             }
01388             BOOST_UBLAS_INLINE
01389             const_iterator1 &operator -= (difference_type n) {
01390                 it_ -= n;
01391                 return *this;
01392             }
01393             BOOST_UBLAS_INLINE
01394             difference_type operator - (const const_iterator1 &it) const {
01395                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01396                 return it_ - it.it_;
01397             }
01398 
01399             // Dereference
01400             BOOST_UBLAS_INLINE
01401             const_reference operator * () const {
01402                 return functor_type::apply (*it_);
01403             }
01404             BOOST_UBLAS_INLINE
01405             const_reference operator [] (difference_type n) const {
01406                 return *(*this + n);
01407             }
01408 
01409 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
01410             BOOST_UBLAS_INLINE
01411 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01412             typename self_type::
01413 #endif
01414             const_iterator2 begin () const {
01415                 return (*this) ().find2 (1, index1 (), 0);
01416             }
01417             BOOST_UBLAS_INLINE
01418 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01419             typename self_type::
01420 #endif
01421             const_iterator2 end () const {
01422                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
01423             }
01424             BOOST_UBLAS_INLINE
01425 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01426             typename self_type::
01427 #endif
01428             const_reverse_iterator2 rbegin () const {
01429                 return const_reverse_iterator2 (end ());
01430             }
01431             BOOST_UBLAS_INLINE
01432 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01433             typename self_type::
01434 #endif
01435             const_reverse_iterator2 rend () const {
01436                 return const_reverse_iterator2 (begin ());
01437             }
01438 #endif
01439 
01440             // Indices
01441             BOOST_UBLAS_INLINE
01442             size_type index1 () const {
01443                 return it_.index2 ();
01444             }
01445             BOOST_UBLAS_INLINE
01446             size_type index2 () const {
01447                 return it_.index1 ();
01448             }
01449 
01450             // Assignment 
01451             BOOST_UBLAS_INLINE
01452             const_iterator1 &operator = (const const_iterator1 &it) {
01453                 container_const_reference<self_type>::assign (&it ());
01454                 it_ = it.it_;
01455                 return *this;
01456             }
01457 
01458             // Comparison
01459             BOOST_UBLAS_INLINE
01460             bool operator == (const const_iterator1 &it) const {
01461                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01462                 return it_ == it.it_;
01463             }
01464             BOOST_UBLAS_INLINE
01465             bool operator < (const const_iterator1 &it) const {
01466                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01467                 return it_ < it.it_;
01468             }
01469 
01470         private:
01471             const_subiterator1_type it_;
01472         };
01473 #endif
01474 
01475         BOOST_UBLAS_INLINE
01476         const_iterator1 begin1 () const {
01477             return find1 (0, 0, 0);
01478         }
01479         BOOST_UBLAS_INLINE
01480         const_iterator1 end1 () const {
01481             return find1 (0, size1 (), 0);
01482         }
01483 
01484 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
01485         class const_iterator2:
01486             public container_const_reference<matrix_unary2>,
01487             public iterator_base_traits<typename E::const_iterator1::iterator_category>::template
01488                 iterator_base<const_iterator2, value_type>::type {
01489         public:
01490             typedef typename E::const_iterator1::iterator_category iterator_category;
01491             typedef typename matrix_unary2::difference_type difference_type;
01492             typedef typename matrix_unary2::value_type value_type;
01493             typedef typename matrix_unary2::const_reference reference;
01494             typedef typename matrix_unary2::const_pointer pointer;
01495 
01496             typedef const_iterator1 dual_iterator_type;
01497             typedef const_reverse_iterator1 dual_reverse_iterator_type;
01498 
01499             // Construction and destruction
01500             BOOST_UBLAS_INLINE
01501             const_iterator2 ():
01502                 container_const_reference<self_type> (), it_ () {}
01503             BOOST_UBLAS_INLINE
01504             const_iterator2 (const self_type &mu, const const_subiterator2_type &it):
01505                 container_const_reference<self_type> (mu), it_ (it) {}
01506 
01507             // Arithmetic
01508             BOOST_UBLAS_INLINE
01509             const_iterator2 &operator ++ () {
01510                 ++ it_;
01511                 return *this;
01512             }
01513             BOOST_UBLAS_INLINE
01514             const_iterator2 &operator -- () {
01515                 -- it_;
01516                 return *this;
01517             }
01518             BOOST_UBLAS_INLINE
01519             const_iterator2 &operator += (difference_type n) {
01520                 it_ += n;
01521                 return *this;
01522             }
01523             BOOST_UBLAS_INLINE
01524             const_iterator2 &operator -= (difference_type n) {
01525                 it_ -= n;
01526                 return *this;
01527             }
01528             BOOST_UBLAS_INLINE
01529             difference_type operator - (const const_iterator2 &it) const {
01530                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01531                 return it_ - it.it_;
01532             }
01533 
01534             // Dereference
01535             BOOST_UBLAS_INLINE
01536             const_reference operator * () const {
01537                 return functor_type::apply (*it_);
01538             }
01539             BOOST_UBLAS_INLINE
01540             const_reference operator [] (difference_type n) const {
01541                 return *(*this + n);
01542             }
01543 
01544 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
01545             BOOST_UBLAS_INLINE
01546 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01547             typename self_type::
01548 #endif
01549             const_iterator1 begin () const {
01550                 return (*this) ().find1 (1, 0, index2 ());
01551             }
01552             BOOST_UBLAS_INLINE
01553 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01554             typename self_type::
01555 #endif
01556             const_iterator1 end () const {
01557                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
01558             }
01559             BOOST_UBLAS_INLINE
01560 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01561             typename self_type::
01562 #endif
01563             const_reverse_iterator1 rbegin () const {
01564                 return const_reverse_iterator1 (end ());
01565             }
01566             BOOST_UBLAS_INLINE
01567 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
01568             typename self_type::
01569 #endif
01570             const_reverse_iterator1 rend () const {
01571                 return const_reverse_iterator1 (begin ());
01572             }
01573 #endif
01574 
01575             // Indices
01576             BOOST_UBLAS_INLINE
01577             size_type index1 () const {
01578                 return it_.index2 ();
01579             }
01580             BOOST_UBLAS_INLINE
01581             size_type index2 () const {
01582                 return it_.index1 ();
01583             }
01584 
01585             // Assignment
01586             BOOST_UBLAS_INLINE
01587             const_iterator2 &operator = (const const_iterator2 &it) {
01588                 container_const_reference<self_type>::assign (&it ());
01589                 it_ = it.it_;
01590                 return *this;
01591             }
01592 
01593             // Comparison
01594             BOOST_UBLAS_INLINE
01595             bool operator == (const const_iterator2 &it) const {
01596                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01597                 return it_ == it.it_;
01598             }
01599             BOOST_UBLAS_INLINE
01600             bool operator < (const const_iterator2 &it) const {
01601                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
01602                 return it_ < it.it_;
01603             }
01604 
01605         private:
01606             const_subiterator2_type it_;
01607         };
01608 #endif
01609 
01610         BOOST_UBLAS_INLINE
01611         const_iterator2 begin2 () const {
01612             return find2 (0, 0, 0);
01613         }
01614         BOOST_UBLAS_INLINE
01615         const_iterator2 end2 () const {
01616             return find2 (0, 0, size2 ());
01617         }
01618 
01619         // Reverse iterators
01620 
01621         BOOST_UBLAS_INLINE
01622         const_reverse_iterator1 rbegin1 () const {
01623             return const_reverse_iterator1 (end1 ());
01624         }
01625         BOOST_UBLAS_INLINE
01626         const_reverse_iterator1 rend1 () const {
01627             return const_reverse_iterator1 (begin1 ());
01628         }
01629 
01630         BOOST_UBLAS_INLINE
01631         const_reverse_iterator2 rbegin2 () const {
01632             return const_reverse_iterator2 (end2 ());
01633         }
01634         BOOST_UBLAS_INLINE
01635         const_reverse_iterator2 rend2 () const {
01636             return const_reverse_iterator2 (begin2 ());
01637         }
01638 
01639     private:
01640         expression_closure_type e_;
01641     };
01642 
01643     template<class E, class F>
01644     struct matrix_unary2_traits {
01645         typedef matrix_unary2<E, F> expression_type;
01646 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
01647         typedef expression_type result_type; 
01648 #else
01649         typedef typename E::matrix_temporary_type result_type;
01650 #endif
01651     };
01652 
01653     // (trans m) [i] [j] = m [j] [i]
01654     template<class E>
01655     BOOST_UBLAS_INLINE
01656     typename matrix_unary2_traits<const E, scalar_identity<typename E::value_type> >::result_type
01657     trans (const matrix_expression<E> &e) {
01658         typedef typename matrix_unary2_traits<const E, scalar_identity<typename E::value_type> >::expression_type expression_type;
01659         return expression_type (e ());
01660     }
01661     template<class E>
01662     BOOST_UBLAS_INLINE
01663     typename matrix_unary2_traits<E, scalar_identity<typename E::value_type> >::result_type
01664     trans (matrix_expression<E> &e) {
01665         typedef typename matrix_unary2_traits<E, scalar_identity<typename E::value_type> >::expression_type expression_type;
01666         return expression_type (e ());
01667     }
01668 
01669     // (herm m) [i] [j] = conj (m [j] [i])
01670     template<class E>
01671     BOOST_UBLAS_INLINE
01672     typename matrix_unary2_traits<E, scalar_conj<typename E::value_type> >::result_type
01673     herm (const matrix_expression<E> &e) {
01674         typedef typename matrix_unary2_traits<E, scalar_conj<typename E::value_type> >::expression_type expression_type;
01675         return expression_type (e ());
01676     }
01677 
01678     template<class E1, class E2, class F>
01679     class matrix_binary:
01680         public matrix_expression<matrix_binary<E1, E2, F> > {
01681 
01682         typedef E1 expression1_type;
01683         typedef E2 expression2_type;
01684         typedef F functor_type;
01685     public:
01686         typedef typename E1::const_closure_type expression1_closure_type;
01687         typedef typename E2::const_closure_type expression2_closure_type;
01688     private:
01689         typedef matrix_binary<E1, E2, F> self_type;
01690     public:
01691 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
01692         using matrix_expression<self_type>::operator ();
01693 #endif
01694         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
01695         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
01696         typedef typename F::result_type value_type;
01697         typedef value_type const_reference;
01698         typedef const_reference reference;
01699         typedef const self_type const_closure_type;
01700         typedef const_closure_type closure_type;
01701         typedef unknown_orientation_tag orientation_category;
01702         typedef unknown_storage_tag storage_category;
01703 
01704         // Construction and destruction
01705         BOOST_UBLAS_INLINE
01706         matrix_binary (const E1 &e1, const E2 &e2): 
01707             e1_ (e1), e2_ (e2) {}
01708 
01709         // Accessors
01710         BOOST_UBLAS_INLINE
01711         size_type size1 () const { 
01712             return BOOST_UBLAS_SAME (e1_.size1 (), e2_.size1 ());
01713         }
01714         BOOST_UBLAS_INLINE
01715         size_type size2 () const {
01716             return BOOST_UBLAS_SAME (e1_.size2 (), e2_.size2 ());
01717         }
01718 
01719     public:
01720         // Expression accessors
01721         BOOST_UBLAS_INLINE
01722         const expression1_closure_type &expression1 () const {
01723             return e1_;
01724         }
01725         BOOST_UBLAS_INLINE
01726         const expression2_closure_type &expression2 () const {
01727             return e2_;
01728         }
01729 
01730     public:
01731         // Element access
01732         BOOST_UBLAS_INLINE
01733         const_reference operator () (size_type i, size_type j) const {
01734             return functor_type::apply (e1_ (i, j), e2_ (i, j));
01735         }
01736 
01737         // Closure comparison
01738         BOOST_UBLAS_INLINE
01739         bool same_closure (const matrix_binary &mb) const {
01740             return (*this).expression1 ().same_closure (mb.expression1 ()) &&
01741                    (*this).expression2 ().same_closure (mb.expression2 ());
01742         }
01743 
01744         // Iterator types
01745     private:
01746         typedef typename E1::const_iterator1 const_iterator11_type;
01747         typedef typename E1::const_iterator2 const_iterator12_type;
01748         typedef typename E2::const_iterator1 const_iterator21_type;
01749         typedef typename E2::const_iterator2 const_iterator22_type;
01750         typedef const value_type *const_pointer;
01751 
01752     public:
01753 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
01754         typedef typename iterator_restrict_traits<typename const_iterator11_type::iterator_category,
01755                                                   typename const_iterator21_type::iterator_category>::iterator_category iterator_category1;
01756         typedef indexed_const_iterator1<const_closure_type, iterator_category1> const_iterator1;
01757         typedef const_iterator1 iterator1;
01758         typedef typename iterator_restrict_traits<typename const_iterator12_type::iterator_category,
01759                                                   typename const_iterator22_type::iterator_category>::iterator_category iterator_category2;
01760         typedef indexed_const_iterator2<const_closure_type, iterator_category2> const_iterator2;
01761         typedef const_iterator2 iterator2;
01762 #else
01763         class const_iterator1;
01764         typedef const_iterator1 iterator1;
01765         class const_iterator2;
01766         typedef const_iterator2 iterator2;
01767 #endif
01768         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
01769         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
01770 
01771         // Element lookup
01772         BOOST_UBLAS_INLINE
01773         const_iterator1 find1 (int rank, size_type i, size_type j) const {
01774             const_iterator11_type it11 (e1_.find1 (rank, i, j));
01775             const_iterator11_type it11_end (e1_.find1 (rank, size1 (), j));
01776             const_iterator21_type it21 (e2_.find1 (rank, i, j));
01777             const_iterator21_type it21_end (e2_.find1 (rank, size1 (), j));
01778             BOOST_UBLAS_CHECK (rank == 0 || it11 == it11_end || it11.index2 () == j, internal_logic ())
01779             BOOST_UBLAS_CHECK (rank == 0 || it21 == it21_end || it21.index2 () == j, internal_logic ())
01780             i = (std::min) (it11 != it11_end ? it11.index1 () : size1 (),
01781                           it21 != it21_end ? it21.index1 () : size1 ());
01782 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
01783             return const_iterator1 (*this, i, j);
01784 #else
01785             return const_iterator1 (*this, i, j, it11, it11_end, it21, it21_end);
01786 #endif
01787         }
01788         BOOST_UBLAS_INLINE
01789         const_iterator2 find2 (int rank, size_type i, size_type j) const {
01790             const_iterator12_type it12 (e1_.find2 (rank, i, j));
01791             const_iterator12_type it12_end (e1_.find2 (rank, i, size2 ()));
01792             const_iterator22_type it22 (e2_.find2 (rank, i, j));
01793             const_iterator22_type it22_end (e2_.find2 (rank, i, size2 ()));
01794             BOOST_UBLAS_CHECK (rank == 0 || it12 == it12_end || it12.index1 () == i, internal_logic ())
01795             BOOST_UBLAS_CHECK (rank == 0 || it22 == it22_end || it22.index1 () == i, internal_logic ())
01796             j = (std::min) (it12 != it12_end ? it12.index2 () : size2 (),
01797                           it22 != it22_end ? it22.index2 () : size2 ());
01798 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
01799             return const_iterator2 (*this, i, j);
01800 #else
01801             return const_iterator2 (*this, i, j, it12, it12_end, it22, it22_end);
01802 #endif
01803         }
01804 
01805         // Iterators enhance the iterators of the referenced expression
01806         // with the binary functor.
01807 
01808 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
01809         class const_iterator1:
01810             public container_const_reference<matrix_binary>,
01811             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
01812                                                                           typename E2::const_iterator1::iterator_category>::iterator_category>::template
01813                 iterator_base<const_iterator1, value_type>::type {
01814         public:
01815             typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
01816                                                       typename E2::const_iterator1::iterator_category>::iterator_category iterator_category;
01817             typedef typename matrix_binary::difference_type difference_type;
01818             typedef typename matrix_binary::value_type value_type;
01819             typedef typename matrix_binary::const_reference reference;
01820             typedef typename matrix_binary::const_pointer pointer;
01821 
01822             typedef const_iterator2 dual_iterator_type;
01823             typedef const_reverse_iterator2 dual_reverse_iterator_type;
01824 
01825             // Construction and destruction
01826             BOOST_UBLAS_INLINE
01827             const_iterator1 ():
01828                 container_const_reference<self_type> (), i_ (), j_ (), it1_ (), it1_end_ (), it2_ (), it2_end_ () {}
01829             BOOST_UBLAS_INLINE
01830             const_iterator1 (const self_type &mb, size_type i, size_type j,
01831                              const const_iterator11_type &it1, const const_iterator11_type &it1_end,
01832                              const const_iterator21_type &it2, const const_iterator21_type &it2_end):
01833                 container_const_reference<self_type> (mb), i_ (i), j_ (j), it1_ (it1), it1_end_ (it1_end), it2_ (it2), it2_end_ (it2_end) {}
01834 
01835         private:
01836             // Dense specializations
01837             BOOST_UBLAS_INLINE
01838             void increment (dense_random_access_iterator_tag) {
01839                 ++ i_; ++ it1_; ++ it2_;
01840             }
01841             BOOST_UBLAS_INLINE
01842             void decrement (dense_random_access_iterator_tag) {
01843                 -- i_; -- it1_; -- it2_;
01844             }
01845             BOOST_UBLAS_INLINE
01846             void increment (dense_random_access_iterator_tag, difference_type n) {
01847                  i_ += n; it1_ += n; it2_ += n;
01848             }
01849             BOOST_UBLAS_INLINE
01850             void decrement (dense_random_access_iterator_tag, difference_type n) {
01851                 i_ -= n; it1_ -= n; it2_ -= n;
01852             }
01853             BOOST_UBLAS_INLINE
01854             value_type dereference (dense_random_access_iterator_tag) const {
01855                 return functor_type::apply (*it1_, *it2_);
01856             }
01857 
01858             // Packed specializations
01859             BOOST_UBLAS_INLINE
01860             void increment (packed_random_access_iterator_tag) {
01861                 if (it1_ != it1_end_)
01862                     if (it1_.index1 () <= i_)
01863                         ++ it1_;
01864                 if (it2_ != it2_end_)
01865                     if (it2_.index1 () <= i_)
01866                         ++ it2_;
01867                 ++ i_;
01868             }
01869             BOOST_UBLAS_INLINE
01870             void decrement (packed_random_access_iterator_tag) {
01871                 if (it1_ != it1_end_)
01872                     if (i_ <= it1_.index1 ())
01873                         -- it1_;
01874                 if (it2_ != it2_end_)
01875                     if (i_ <= it2_.index1 ())
01876                         -- it2_;
01877                 -- i_;
01878             }
01879             BOOST_UBLAS_INLINE
01880             void increment (packed_random_access_iterator_tag, difference_type n) {
01881                 while (n > 0) {
01882                     increment (packed_random_access_iterator_tag ());
01883                     --n;
01884                 }
01885                 while (n < 0) {
01886                     decrement (packed_random_access_iterator_tag ());
01887                     ++n;
01888                 }
01889             }
01890             BOOST_UBLAS_INLINE
01891             void decrement (packed_random_access_iterator_tag, difference_type n) {
01892                 while (n > 0) {
01893                     decrement (packed_random_access_iterator_tag ());
01894                     --n;
01895                 }
01896                 while (n < 0) {
01897                     increment (packed_random_access_iterator_tag ());
01898                     ++n;
01899                 }
01900             }
01901             BOOST_UBLAS_INLINE
01902             value_type dereference (packed_random_access_iterator_tag) const {
01903                 value_type t1 = value_type/*zero*/();
01904                 if (it1_ != it1_end_) {
01905                     BOOST_UBLAS_CHECK (it1_.index2 () == j_, internal_logic ());
01906                     if (it1_.index1 () == i_)
01907                         t1 = *it1_;
01908                 }
01909                 value_type t2 = value_type/*zero*/();
01910                 if (it2_ != it2_end_) {
01911                     BOOST_UBLAS_CHECK (it2_.index2 () == j_, internal_logic ());
01912                     if (it2_.index1 () == i_)
01913                         t2 = *it2_;
01914                 }
01915                 return functor_type::apply (t1, t2);
01916             }
01917 
01918             // Sparse specializations
01919             BOOST_UBLAS_INLINE
01920             void increment (sparse_bidirectional_iterator_tag) {
01921                 size_type index1 = (*this) ().size1 ();
01922                 if (it1_ != it1_end_) {
01923                     if (it1_.index1 () <= i_)
01924                         ++ it1_;
01925                     if (it1_ != it1_end_)
01926                         index1 = it1_.index1 ();
01927                 }
01928                 size_type index2 = (*this) ().size1 ();
01929                 if (it2_ != it2_end_)
01930                     if (it2_.index1 () <= i_)
01931                         ++ it2_;
01932                     if (it2_ != it2_end_) {
01933                         index2 = it2_.index1 ();
01934                 }
01935                 i_ = (std::min) (index1, index2);
01936             }
01937             BOOST_UBLAS_INLINE
01938             void decrement (sparse_bidirectional_iterator_tag) {
01939                 size_type index1 = (*this) ().size1 ();
01940                 if (it1_ != it1_end_) {
01941                     if (i_ <= it1_.index1 ())
01942                         -- it1_;
01943                     if (it1_ != it1_end_)
01944                         index1 = it1_.index1 ();
01945                 }
01946                 size_type index2 = (*this) ().size1 ();
01947                 if (it2_ != it2_end_) {
01948                     if (i_ <= it2_.index1 ())
01949                         -- it2_;
01950                     if (it2_ != it2_end_)
01951                         index2 = it2_.index1 ();
01952                 }
01953                 i_ = (std::max) (index1, index2);
01954             }
01955             BOOST_UBLAS_INLINE
01956             void increment (sparse_bidirectional_iterator_tag, difference_type n) {
01957                 while (n > 0) {
01958                     increment (sparse_bidirectional_iterator_tag ());
01959                     --n;
01960                 }
01961                 while (n < 0) {
01962                     decrement (sparse_bidirectional_iterator_tag ());
01963                     ++n;
01964                 }
01965             }
01966             BOOST_UBLAS_INLINE
01967             void decrement (sparse_bidirectional_iterator_tag, difference_type n) {
01968                 while (n > 0) {
01969                     decrement (sparse_bidirectional_iterator_tag ());
01970                     --n;
01971                 }
01972                 while (n < 0) {
01973                     increment (sparse_bidirectional_iterator_tag ());
01974                     ++n;
01975                 }
01976             }
01977             BOOST_UBLAS_INLINE
01978             value_type dereference (sparse_bidirectional_iterator_tag) const {
01979                 value_type t1 = value_type/*zero*/();
01980                 if (it1_ != it1_end_) {
01981                     BOOST_UBLAS_CHECK (it1_.index2 () == j_, internal_logic ());
01982                     if (it1_.index1 () == i_)
01983                         t1 = *it1_;
01984                 }
01985                 value_type t2 = value_type/*zero*/();
01986                 if (it2_ != it2_end_) {
01987                     BOOST_UBLAS_CHECK (it2_.index2 () == j_, internal_logic ());
01988                     if (it2_.index1 () == i_)
01989                         t2 = *it2_;
01990                 }
01991                 return functor_type::apply (t1, t2);
01992             }
01993 
01994         public:
01995             // Arithmetic
01996             BOOST_UBLAS_INLINE
01997             const_iterator1 &operator ++ () {
01998                 increment (iterator_category ());
01999                 return *this;
02000             }
02001             BOOST_UBLAS_INLINE
02002             const_iterator1 &operator -- () {
02003                 decrement (iterator_category ());
02004                 return *this;
02005             }
02006             BOOST_UBLAS_INLINE
02007             const_iterator1 &operator += (difference_type n) {
02008                 increment (iterator_category (), n);
02009                 return *this;
02010             }
02011             BOOST_UBLAS_INLINE
02012             const_iterator1 &operator -= (difference_type n) {
02013                 decrement (iterator_category (), n);
02014                 return *this;
02015             }
02016             BOOST_UBLAS_INLINE
02017             difference_type operator - (const const_iterator1 &it) const {
02018                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02019                 BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ());
02020                 return index1 () - it.index1 ();
02021             }
02022 
02023             // Dereference
02024             BOOST_UBLAS_INLINE
02025             const_reference operator * () const {
02026                 return dereference (iterator_category ());
02027             }
02028             BOOST_UBLAS_INLINE
02029             const_reference operator [] (difference_type n) const {
02030                 return *(*this + n);
02031             }
02032 
02033 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
02034             BOOST_UBLAS_INLINE
02035 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02036             typename self_type::
02037 #endif
02038             const_iterator2 begin () const {
02039                 return (*this) ().find2 (1, index1 (), 0);
02040             }
02041             BOOST_UBLAS_INLINE
02042 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02043             typename self_type::
02044 #endif
02045             const_iterator2 end () const {
02046                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
02047             }
02048             BOOST_UBLAS_INLINE
02049 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02050             typename self_type::
02051 #endif
02052             const_reverse_iterator2 rbegin () const {
02053                 return const_reverse_iterator2 (end ());
02054             }
02055             BOOST_UBLAS_INLINE
02056 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02057             typename self_type::
02058 #endif
02059             const_reverse_iterator2 rend () const {
02060                 return const_reverse_iterator2 (begin ());
02061             }
02062 #endif
02063 
02064             // Indices
02065             BOOST_UBLAS_INLINE
02066             size_type index1 () const {
02067                 return i_;
02068             }
02069             BOOST_UBLAS_INLINE
02070             size_type index2 () const {
02071                 // if (it1_ != it1_end_ && it2_ != it2_end_)
02072                 //    return BOOST_UBLAS_SAME (it1_.index2 (), it2_.index2 ());
02073                 // else
02074                     return j_;
02075             }
02076 
02077             // Assignment
02078             BOOST_UBLAS_INLINE
02079             const_iterator1 &operator = (const const_iterator1 &it) {
02080                 container_const_reference<self_type>::assign (&it ());
02081                 i_ = it.i_;
02082                 j_ = it.j_;
02083                 it1_ = it.it1_;
02084                 it1_end_ = it.it1_end_;
02085                 it2_ = it.it2_;
02086                 it2_end_ = it.it2_end_;
02087                 return *this;
02088             }
02089 
02090             // Comparison
02091             BOOST_UBLAS_INLINE
02092             bool operator == (const const_iterator1 &it) const {
02093                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02094                 BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ());
02095                 return index1 () == it.index1 ();
02096             }
02097             BOOST_UBLAS_INLINE
02098             bool operator < (const const_iterator1 &it) const {
02099                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02100                 BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ());
02101                 return index1 () < it.index1 ();
02102             }
02103 
02104         private:
02105             size_type i_;
02106             size_type j_;
02107             const_iterator11_type it1_;
02108             const_iterator11_type it1_end_;
02109             const_iterator21_type it2_;
02110             const_iterator21_type it2_end_;
02111         };
02112 #endif
02113 
02114         BOOST_UBLAS_INLINE
02115         const_iterator1 begin1 () const {
02116             return find1 (0, 0, 0);
02117         }
02118         BOOST_UBLAS_INLINE
02119         const_iterator1 end1 () const {
02120             return find1 (0, size1 (), 0);
02121         }
02122 
02123 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
02124         class const_iterator2:
02125             public container_const_reference<matrix_binary>,
02126             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator2::iterator_category,
02127                                                                           typename E2::const_iterator2::iterator_category>::iterator_category>::template
02128                 iterator_base<const_iterator2, value_type>::type {
02129         public:
02130             typedef typename iterator_restrict_traits<typename E1::const_iterator2::iterator_category,
02131                                                       typename E2::const_iterator2::iterator_category>::iterator_category iterator_category;
02132             typedef typename matrix_binary::difference_type difference_type;
02133             typedef typename matrix_binary::value_type value_type;
02134             typedef typename matrix_binary::const_reference reference;
02135             typedef typename matrix_binary::const_pointer pointer;
02136 
02137             typedef const_iterator1 dual_iterator_type;
02138             typedef const_reverse_iterator1 dual_reverse_iterator_type;
02139 
02140             // Construction and destruction
02141             BOOST_UBLAS_INLINE
02142             const_iterator2 ():
02143                 container_const_reference<self_type> (), i_ (), j_ (), it1_ (), it1_end_ (), it2_ (), it2_end_ () {}
02144             BOOST_UBLAS_INLINE
02145             const_iterator2 (const self_type &mb, size_type i, size_type j,
02146                              const const_iterator12_type &it1, const const_iterator12_type &it1_end,
02147                              const const_iterator22_type &it2, const const_iterator22_type &it2_end):
02148                 container_const_reference<self_type> (mb), i_ (i), j_ (j), it1_ (it1), it1_end_ (it1_end), it2_ (it2), it2_end_ (it2_end) {}
02149 
02150         private:
02151             // Dense access specializations
02152             BOOST_UBLAS_INLINE
02153             void increment (dense_random_access_iterator_tag) {
02154                 ++ j_; ++ it1_; ++ it2_;
02155             }
02156             BOOST_UBLAS_INLINE
02157             void decrement (dense_random_access_iterator_tag) {
02158                 -- j_; -- it1_; -- it2_;
02159             }
02160             BOOST_UBLAS_INLINE
02161             void increment (dense_random_access_iterator_tag, difference_type n) {
02162                 j_ += n; it1_ += n; it2_ += n;
02163             }
02164             BOOST_UBLAS_INLINE
02165             void decrement (dense_random_access_iterator_tag, difference_type n) {
02166                 j_ -= n; it1_ -= n; it2_ -= n;
02167             }
02168             BOOST_UBLAS_INLINE
02169             value_type dereference (dense_random_access_iterator_tag) const {
02170                 return functor_type::apply (*it1_, *it2_);
02171             }
02172 
02173             // Packed specializations
02174             BOOST_UBLAS_INLINE
02175             void increment (packed_random_access_iterator_tag) {
02176                 if (it1_ != it1_end_)
02177                     if (it1_.index2 () <= j_)
02178                         ++ it1_;
02179                 if (it2_ != it2_end_)
02180                     if (it2_.index2 () <= j_)
02181                         ++ it2_;
02182                 ++ j_;
02183             }
02184             BOOST_UBLAS_INLINE
02185             void decrement (packed_random_access_iterator_tag) {
02186                 if (it1_ != it1_end_)
02187                     if (j_ <= it1_.index2 ())
02188                         -- it1_;
02189                 if (it2_ != it2_end_)
02190                     if (j_ <= it2_.index2 ())
02191                         -- it2_;
02192                 -- j_;
02193             }
02194             BOOST_UBLAS_INLINE
02195             void increment (packed_random_access_iterator_tag, difference_type n) {
02196                 while (n > 0) {
02197                     increment (packed_random_access_iterator_tag ());
02198                     --n;
02199                 }
02200                 while (n < 0) {
02201                     decrement (packed_random_access_iterator_tag ());
02202                     ++n;
02203                 }
02204             }
02205             BOOST_UBLAS_INLINE
02206             void decrement (packed_random_access_iterator_tag, difference_type n) {
02207                 while (n > 0) {
02208                     decrement (packed_random_access_iterator_tag ());
02209                     --n;
02210                 }
02211                 while (n < 0) {
02212                     increment (packed_random_access_iterator_tag ());
02213                     ++n;
02214                 }
02215             }
02216             BOOST_UBLAS_INLINE
02217             value_type dereference (packed_random_access_iterator_tag) const {
02218                 value_type t1 = value_type/*zero*/();
02219                 if (it1_ != it1_end_) {
02220                     BOOST_UBLAS_CHECK (it1_.index1 () == i_, internal_logic ());
02221                     if (it1_.index2 () == j_)
02222                         t1 = *it1_;
02223                 }
02224                 value_type t2 = value_type/*zero*/();
02225                 if (it2_ != it2_end_) {
02226                     BOOST_UBLAS_CHECK (it2_.index1 () == i_, internal_logic ());
02227                     if (it2_.index2 () == j_)
02228                         t2 = *it2_;
02229                 }
02230                 return functor_type::apply (t1, t2);
02231             }
02232 
02233             // Sparse specializations
02234             BOOST_UBLAS_INLINE
02235             void increment (sparse_bidirectional_iterator_tag) {
02236                 size_type index1 = (*this) ().size2 ();
02237                 if (it1_ != it1_end_) {
02238                     if (it1_.index2 () <= j_)
02239                         ++ it1_;
02240                     if (it1_ != it1_end_)
02241                         index1 = it1_.index2 ();
02242                 }
02243                 size_type index2 = (*this) ().size2 ();
02244                 if (it2_ != it2_end_) {
02245                     if (it2_.index2 () <= j_)
02246                         ++ it2_;
02247                     if (it2_ != it2_end_)
02248                         index2 = it2_.index2 ();
02249                 }
02250                 j_ = (std::min) (index1, index2);
02251             }
02252             BOOST_UBLAS_INLINE
02253             void decrement (sparse_bidirectional_iterator_tag) {
02254                 size_type index1 = (*this) ().size2 ();
02255                 if (it1_ != it1_end_) {
02256                     if (j_ <= it1_.index2 ())
02257                         -- it1_;
02258                     if (it1_ != it1_end_)
02259                         index1 = it1_.index2 ();
02260                 }
02261                 size_type index2 = (*this) ().size2 ();
02262                 if (it2_ != it2_end_) {
02263                     if (j_ <= it2_.index2 ())
02264                         -- it2_;
02265                     if (it2_ != it2_end_)
02266                         index2 = it2_.index2 ();
02267                 }
02268                 j_ = (std::max) (index1, index2);
02269             }
02270             BOOST_UBLAS_INLINE
02271             void increment (sparse_bidirectional_iterator_tag, difference_type n) {
02272                 while (n > 0) {
02273                     increment (sparse_bidirectional_iterator_tag ());
02274                     --n;
02275                 }
02276                 while (n < 0) {
02277                     decrement (sparse_bidirectional_iterator_tag ());
02278                     ++n;
02279                 }
02280             }
02281             BOOST_UBLAS_INLINE
02282             void decrement (sparse_bidirectional_iterator_tag, difference_type n) {
02283                 while (n > 0) {
02284                     decrement (sparse_bidirectional_iterator_tag ());
02285                     --n;
02286                 }
02287                 while (n < 0) {
02288                     increment (sparse_bidirectional_iterator_tag ());
02289                     ++n;
02290                 }
02291             }
02292             BOOST_UBLAS_INLINE
02293             value_type dereference (sparse_bidirectional_iterator_tag) const {
02294                 value_type t1 = value_type/*zero*/();
02295                 if (it1_ != it1_end_) {
02296                     BOOST_UBLAS_CHECK (it1_.index1 () == i_, internal_logic ());
02297                     if (it1_.index2 () == j_)
02298                         t1 = *it1_;
02299                 }
02300                 value_type t2 = value_type/*zero*/();
02301                 if (it2_ != it2_end_) {
02302                     BOOST_UBLAS_CHECK (it2_.index1 () == i_, internal_logic ());
02303                     if (it2_.index2 () == j_)
02304                         t2 = *it2_;
02305                 }
02306                 return functor_type::apply (t1, t2);
02307             }
02308 
02309         public:
02310             // Arithmetic
02311             BOOST_UBLAS_INLINE
02312             const_iterator2 &operator ++ () {
02313                 increment (iterator_category ());
02314                 return *this;
02315             }
02316             BOOST_UBLAS_INLINE
02317             const_iterator2 &operator -- () {
02318                 decrement (iterator_category ());
02319                 return *this;
02320             }
02321             BOOST_UBLAS_INLINE
02322             const_iterator2 &operator += (difference_type n) {
02323                 increment (iterator_category (), n);
02324                 return *this;
02325             }
02326             BOOST_UBLAS_INLINE
02327             const_iterator2 &operator -= (difference_type n) {
02328                 decrement (iterator_category (), n);
02329                 return *this;
02330             }
02331             BOOST_UBLAS_INLINE
02332             difference_type operator - (const const_iterator2 &it) const {
02333                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02334                 BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ());
02335                 return index2 () - it.index2 ();
02336             }
02337 
02338             // Dereference
02339             BOOST_UBLAS_INLINE
02340             const_reference operator * () const {
02341                 return dereference (iterator_category ());
02342             }
02343             BOOST_UBLAS_INLINE
02344             const_reference operator [] (difference_type n) const {
02345                 return *(*this + n);
02346             }
02347 
02348 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
02349             BOOST_UBLAS_INLINE
02350 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02351             typename self_type::
02352 #endif
02353             const_iterator1 begin () const {
02354                 return (*this) ().find1 (1, 0, index2 ());
02355             }
02356             BOOST_UBLAS_INLINE
02357 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02358             typename self_type::
02359 #endif
02360             const_iterator1 end () const {
02361                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
02362             }
02363             BOOST_UBLAS_INLINE
02364 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02365             typename self_type::
02366 #endif
02367             const_reverse_iterator1 rbegin () const {
02368                 return const_reverse_iterator1 (end ());
02369             }
02370             BOOST_UBLAS_INLINE
02371 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02372             typename self_type::
02373 #endif
02374             const_reverse_iterator1 rend () const {
02375                 return const_reverse_iterator1 (begin ());
02376             }
02377 #endif
02378 
02379             // Indices
02380             BOOST_UBLAS_INLINE
02381             size_type index1 () const {
02382                 // if (it1_ != it1_end_ && it2_ != it2_end_)
02383                 //    return BOOST_UBLAS_SAME (it1_.index1 (), it2_.index1 ());
02384                 // else
02385                     return i_;
02386             }
02387             BOOST_UBLAS_INLINE
02388             size_type index2 () const {
02389                 return j_;
02390             }
02391 
02392             // Assignment
02393             BOOST_UBLAS_INLINE
02394             const_iterator2 &operator = (const const_iterator2 &it) {
02395                 container_const_reference<self_type>::assign (&it ());
02396                 i_ = it.i_;
02397                 j_ = it.j_;
02398                 it1_ = it.it1_;
02399                 it1_end_ = it.it1_end_;
02400                 it2_ = it.it2_;
02401                 it2_end_ = it.it2_end_;
02402                 return *this;
02403             }
02404 
02405             // Comparison
02406             BOOST_UBLAS_INLINE
02407             bool operator == (const const_iterator2 &it) const {
02408                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02409                 BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ());
02410                 return index2 () == it.index2 ();
02411             }
02412             BOOST_UBLAS_INLINE
02413             bool operator < (const const_iterator2 &it) const {
02414                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02415                 BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ());
02416                 return index2 () < it.index2 ();
02417             }
02418 
02419         private:
02420             size_type i_;
02421             size_type j_;
02422             const_iterator12_type it1_;
02423             const_iterator12_type it1_end_;
02424             const_iterator22_type it2_;
02425             const_iterator22_type it2_end_;
02426         };
02427 #endif
02428 
02429         BOOST_UBLAS_INLINE
02430         const_iterator2 begin2 () const {
02431             return find2 (0, 0, 0);
02432         }
02433         BOOST_UBLAS_INLINE
02434         const_iterator2 end2 () const {
02435             return find2 (0, 0, size2 ());
02436         }
02437 
02438         // Reverse iterators
02439 
02440         BOOST_UBLAS_INLINE
02441         const_reverse_iterator1 rbegin1 () const {
02442             return const_reverse_iterator1 (end1 ());
02443         }
02444         BOOST_UBLAS_INLINE
02445         const_reverse_iterator1 rend1 () const {
02446             return const_reverse_iterator1 (begin1 ());
02447         }
02448 
02449         BOOST_UBLAS_INLINE
02450         const_reverse_iterator2 rbegin2 () const {
02451             return const_reverse_iterator2 (end2 ());
02452         }
02453         BOOST_UBLAS_INLINE
02454         const_reverse_iterator2 rend2 () const {
02455             return const_reverse_iterator2 (begin2 ());
02456         }
02457 
02458     private:
02459         expression1_closure_type e1_;
02460         expression2_closure_type e2_;
02461     };
02462 
02463     template<class E1, class E2, class F>
02464     struct matrix_binary_traits {
02465         typedef matrix_binary<E1, E2, F> expression_type;
02466 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
02467         typedef expression_type result_type; 
02468 #else
02469         typedef typename E1::matrix_temporary_type result_type;
02470 #endif
02471     };
02472 
02473     // (m1 + m2) [i] [j] = m1 [i] [j] + m2 [i] [j]
02474     template<class E1, class E2>
02475     BOOST_UBLAS_INLINE
02476     typename matrix_binary_traits<E1, E2, scalar_plus<typename E1::value_type,
02477                                                       typename E2::value_type> >::result_type
02478     operator + (const matrix_expression<E1> &e1,
02479                 const matrix_expression<E2> &e2) {
02480         typedef typename matrix_binary_traits<E1, E2, scalar_plus<typename E1::value_type,
02481                                                                   typename E2::value_type> >::expression_type expression_type;
02482         return expression_type (e1 (), e2 ());
02483     }
02484 
02485     // (m1 - m2) [i] [j] = m1 [i] [j] - m2 [i] [j]
02486     template<class E1, class E2>
02487     BOOST_UBLAS_INLINE
02488     typename matrix_binary_traits<E1, E2, scalar_minus<typename E1::value_type,
02489                                                        typename E2::value_type> >::result_type
02490     operator - (const matrix_expression<E1> &e1,
02491                 const matrix_expression<E2> &e2) {
02492         typedef typename matrix_binary_traits<E1, E2, scalar_minus<typename E1::value_type,
02493                                                                    typename E2::value_type> >::expression_type expression_type;
02494         return expression_type (e1 (), e2 ());
02495     }
02496 
02497     // (m1 * m2) [i] [j] = m1 [i] [j] * m2 [i] [j]
02498     template<class E1, class E2>
02499     BOOST_UBLAS_INLINE
02500     typename matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type,
02501                                                             typename E2::value_type> >::result_type
02502     element_prod (const matrix_expression<E1> &e1,
02503                   const matrix_expression<E2> &e2) {
02504         typedef typename matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type,
02505                                                                         typename E2::value_type> >::expression_type expression_type;
02506         return expression_type (e1 (), e2 ());
02507     }
02508 
02509     // (m1 / m2) [i] [j] = m1 [i] [j] / m2 [i] [j]
02510     template<class E1, class E2>
02511     BOOST_UBLAS_INLINE
02512     typename matrix_binary_traits<E1, E2, scalar_divides<typename E1::value_type,
02513                                                          typename E2::value_type> >::result_type
02514     element_div (const matrix_expression<E1> &e1,
02515                  const matrix_expression<E2> &e2) {
02516         typedef typename matrix_binary_traits<E1, E2, scalar_divides<typename E1::value_type,
02517                                                                      typename E2::value_type> >::expression_type expression_type;
02518         return expression_type (e1 (), e2 ());
02519     }
02520 
02521     template<class E1, class E2, class F>
02522     class matrix_binary_scalar1:
02523         public matrix_expression<matrix_binary_scalar1<E1, E2, F> > {
02524 
02525         typedef E1 expression1_type;
02526         typedef E2 expression2_type;
02527         typedef F functor_type;
02528         typedef const E1& expression1_closure_type;
02529         typedef typename E2::const_closure_type expression2_closure_type;
02530         typedef matrix_binary_scalar1<E1, E2, F> self_type;
02531     public:
02532 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
02533         using matrix_expression<self_type>::operator ();
02534 #endif
02535         typedef typename E2::size_type size_type;
02536         typedef typename E2::difference_type difference_type;
02537         typedef typename F::result_type value_type;
02538         typedef value_type const_reference;
02539         typedef const_reference reference;
02540         typedef const self_type const_closure_type;
02541         typedef const_closure_type closure_type;
02542         typedef typename E2::orientation_category orientation_category;
02543         typedef unknown_storage_tag storage_category;
02544 
02545         // Construction and destruction
02546         BOOST_UBLAS_INLINE
02547         matrix_binary_scalar1 (const expression1_type &e1, const expression2_type &e2):
02548             e1_ (e1), e2_ (e2) {}
02549 
02550         // Accessors
02551         BOOST_UBLAS_INLINE
02552         size_type size1 () const {
02553             return e2_.size1 ();
02554         }
02555         BOOST_UBLAS_INLINE
02556         size_type size2 () const {
02557             return e2_.size2 ();
02558         }
02559 
02560     public:
02561         // Element access
02562         BOOST_UBLAS_INLINE
02563         const_reference operator () (size_type i, size_type j) const {
02564             return functor_type::apply (expression1_type (e1_), e2_ (i, j));
02565         }
02566 
02567         // Closure comparison
02568         BOOST_UBLAS_INLINE
02569         bool same_closure (const matrix_binary_scalar1 &mbs1) const {
02570             return &e1_ == &(mbs1.e1_) &&
02571                    (*this).e2_.same_closure (mbs1.e2_);
02572         }
02573 
02574         // Iterator types
02575     private:
02576         typedef expression1_type const_subiterator1_type;
02577         typedef typename E2::const_iterator1 const_iterator21_type;
02578         typedef typename E2::const_iterator2 const_iterator22_type;
02579         typedef const value_type *const_pointer;
02580 
02581     public:
02582 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
02583         typedef indexed_const_iterator1<const_closure_type, typename const_iterator21_type::iterator_category> const_iterator1;
02584         typedef const_iterator1 iterator1;
02585         typedef indexed_const_iterator2<const_closure_type, typename const_iterator22_type::iterator_category> const_iterator2;
02586         typedef const_iterator2 iterator2;
02587 #else
02588         class const_iterator1;
02589         typedef const_iterator1 iterator1;
02590         class const_iterator2;
02591         typedef const_iterator2 iterator2;
02592 #endif
02593         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
02594         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
02595 
02596         // Element lookup
02597         BOOST_UBLAS_INLINE
02598         const_iterator1 find1 (int rank, size_type i, size_type j) const {
02599             const_iterator21_type it21 (e2_.find1 (rank, i, j));
02600 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
02601             return const_iterator1 (*this, it21.index1 (), it21.index2 ());
02602 #else
02603             return const_iterator1 (*this, const_subiterator1_type (e1_), it21);
02604 #endif
02605         }
02606         BOOST_UBLAS_INLINE
02607         const_iterator2 find2 (int rank, size_type i, size_type j) const {
02608             const_iterator22_type it22 (e2_.find2 (rank, i, j));
02609 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
02610             return const_iterator2 (*this, it22.index1 (), it22.index2 ());
02611 #else
02612             return const_iterator2 (*this, const_subiterator1_type (e1_), it22);
02613 #endif
02614         }
02615 
02616         // Iterators enhance the iterators of the referenced expression
02617         // with the binary functor.
02618 
02619 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
02620         class const_iterator1:
02621             public container_const_reference<matrix_binary_scalar1>,
02622             public iterator_base_traits<typename E2::const_iterator1::iterator_category>::template
02623                 iterator_base<const_iterator1, value_type>::type {
02624         public:
02625             typedef typename E2::const_iterator1::iterator_category iterator_category;
02626             typedef typename matrix_binary_scalar1::difference_type difference_type;
02627             typedef typename matrix_binary_scalar1::value_type value_type;
02628             typedef typename matrix_binary_scalar1::const_reference reference;
02629             typedef typename matrix_binary_scalar1::const_pointer pointer;
02630 
02631             typedef const_iterator2 dual_iterator_type;
02632             typedef const_reverse_iterator2 dual_reverse_iterator_type;
02633 
02634             // Construction and destruction
02635             BOOST_UBLAS_INLINE
02636             const_iterator1 ():
02637                 container_const_reference<self_type> (), it1_ (), it2_ () {}
02638             BOOST_UBLAS_INLINE
02639             const_iterator1 (const self_type &mbs, const const_subiterator1_type &it1, const const_iterator21_type &it2):
02640                 container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {}
02641 
02642             // Arithmetic
02643             BOOST_UBLAS_INLINE
02644             const_iterator1 &operator ++ () {
02645                 ++ it2_;
02646                 return *this;
02647             }
02648             BOOST_UBLAS_INLINE
02649             const_iterator1 &operator -- () {
02650                 -- it2_ ;
02651                 return *this;
02652             }
02653             BOOST_UBLAS_INLINE
02654             const_iterator1 &operator += (difference_type n) {
02655                 it2_ += n;
02656                 return *this;
02657             }
02658             BOOST_UBLAS_INLINE
02659             const_iterator1 &operator -= (difference_type n) {
02660                 it2_ -= n;
02661                 return *this;
02662             }
02663             BOOST_UBLAS_INLINE
02664             difference_type operator - (const const_iterator1 &it) const {
02665                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02666                 // FIXME we shouldn't compare floats
02667                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
02668                 return it2_ - it.it2_;
02669             }
02670 
02671             // Dereference
02672             BOOST_UBLAS_INLINE
02673             const_reference operator * () const {
02674                 return functor_type::apply (it1_, *it2_);
02675             }
02676             BOOST_UBLAS_INLINE
02677             const_reference operator [] (difference_type n) const {
02678                 return *(*this + n);
02679             }
02680 
02681 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
02682             BOOST_UBLAS_INLINE
02683 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02684             typename self_type::
02685 #endif
02686             const_iterator2 begin () const {
02687                 return (*this) ().find2 (1, index1 (), 0);
02688             }
02689             BOOST_UBLAS_INLINE
02690 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02691             typename self_type::
02692 #endif
02693             const_iterator2 end () const {
02694                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
02695             }
02696             BOOST_UBLAS_INLINE
02697 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02698             typename self_type::
02699 #endif
02700             const_reverse_iterator2 rbegin () const {
02701                 return const_reverse_iterator2 (end ());
02702             }
02703             BOOST_UBLAS_INLINE
02704 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02705             typename self_type::
02706 #endif
02707             const_reverse_iterator2 rend () const {
02708                 return const_reverse_iterator2 (begin ());
02709             }
02710 #endif
02711 
02712             // Indices
02713             BOOST_UBLAS_INLINE
02714             size_type index1 () const {
02715                 return it2_.index1 ();
02716             }
02717             BOOST_UBLAS_INLINE
02718             size_type index2 () const {
02719                 return it2_.index2 ();
02720             }
02721 
02722             // Assignment 
02723             BOOST_UBLAS_INLINE
02724             const_iterator1 &operator = (const const_iterator1 &it) {
02725                 container_const_reference<self_type>::assign (&it ());
02726                 it1_ = it.it1_;
02727                 it2_ = it.it2_;
02728                 return *this;
02729             }
02730 
02731             // Comparison
02732             BOOST_UBLAS_INLINE
02733             bool operator == (const const_iterator1 &it) const {
02734                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02735                 // FIXME we shouldn't compare floats
02736                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
02737                 return it2_ == it.it2_;
02738             }
02739             BOOST_UBLAS_INLINE
02740             bool operator < (const const_iterator1 &it) const {
02741                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02742                 // FIXME we shouldn't compare floats
02743                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
02744                 return it2_ < it.it2_;
02745             }
02746 
02747         private:
02748             const_subiterator1_type it1_;
02749             const_iterator21_type it2_;
02750         };
02751 #endif
02752 
02753         BOOST_UBLAS_INLINE
02754         const_iterator1 begin1 () const {
02755             return find1 (0, 0, 0);
02756         }
02757         BOOST_UBLAS_INLINE
02758         const_iterator1 end1 () const {
02759             return find1 (0, size1 (), 0);
02760         }
02761 
02762 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
02763         class const_iterator2:
02764             public container_const_reference<matrix_binary_scalar1>,
02765             public iterator_base_traits<typename E2::const_iterator2::iterator_category>::template
02766                 iterator_base<const_iterator2, value_type>::type {
02767         public:
02768             typedef typename E2::const_iterator2::iterator_category iterator_category;
02769             typedef typename matrix_binary_scalar1::difference_type difference_type;
02770             typedef typename matrix_binary_scalar1::value_type value_type;
02771             typedef typename matrix_binary_scalar1::const_reference reference;
02772             typedef typename matrix_binary_scalar1::const_pointer pointer;
02773 
02774             typedef const_iterator1 dual_iterator_type;
02775             typedef const_reverse_iterator1 dual_reverse_iterator_type;
02776 
02777             // Construction and destruction
02778             BOOST_UBLAS_INLINE
02779             const_iterator2 ():
02780                 container_const_reference<self_type> (), it1_ (), it2_ () {}
02781             BOOST_UBLAS_INLINE
02782             const_iterator2 (const self_type &mbs, const const_subiterator1_type &it1, const const_iterator22_type &it2):
02783                 container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {}
02784 
02785             // Arithmetic
02786             BOOST_UBLAS_INLINE
02787             const_iterator2 &operator ++ () {
02788                 ++ it2_;
02789                 return *this;
02790             }
02791             BOOST_UBLAS_INLINE
02792             const_iterator2 &operator -- () {
02793                 -- it2_;
02794                 return *this;
02795             }
02796             BOOST_UBLAS_INLINE
02797             const_iterator2 &operator += (difference_type n) {
02798                 it2_ += n;
02799                 return *this;
02800             }
02801             BOOST_UBLAS_INLINE
02802             const_iterator2 &operator -= (difference_type n) {
02803                 it2_ -= n;
02804                 return *this;
02805             }
02806             BOOST_UBLAS_INLINE
02807             difference_type operator - (const const_iterator2 &it) const {
02808                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02809                 // FIXME we shouldn't compare floats
02810                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
02811                 return it2_ - it.it2_;
02812             }
02813 
02814             // Dereference
02815             BOOST_UBLAS_INLINE
02816             const_reference operator * () const {
02817                 return functor_type::apply (it1_, *it2_);
02818             }
02819             BOOST_UBLAS_INLINE
02820             const_reference operator [] (difference_type n) const {
02821                 return *(*this + n);
02822             }
02823 
02824 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
02825             BOOST_UBLAS_INLINE
02826 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02827             typename self_type::
02828 #endif
02829             const_iterator1 begin () const {
02830                 return (*this) ().find1 (1, 0, index2 ());
02831             }
02832             BOOST_UBLAS_INLINE
02833 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02834             typename self_type::
02835 #endif
02836             const_iterator1 end () const {
02837                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
02838             }
02839             BOOST_UBLAS_INLINE
02840 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02841             typename self_type::
02842 #endif
02843             const_reverse_iterator1 rbegin () const {
02844                 return const_reverse_iterator1 (end ());
02845             }
02846             BOOST_UBLAS_INLINE
02847 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
02848             typename self_type::
02849 #endif
02850             const_reverse_iterator1 rend () const {
02851                 return const_reverse_iterator1 (begin ());
02852             }
02853 #endif
02854 
02855             // Indices
02856             BOOST_UBLAS_INLINE
02857             size_type index1 () const {
02858                 return it2_.index1 ();
02859             }
02860             BOOST_UBLAS_INLINE
02861             size_type index2 () const {
02862                 return it2_.index2 ();
02863             }
02864 
02865             // Assignment 
02866             BOOST_UBLAS_INLINE
02867             const_iterator2 &operator = (const const_iterator2 &it) {
02868                 container_const_reference<self_type>::assign (&it ());
02869                 it1_ = it.it1_;
02870                 it2_ = it.it2_;
02871                 return *this;
02872             }
02873 
02874             // Comparison
02875             BOOST_UBLAS_INLINE
02876             bool operator == (const const_iterator2 &it) const {
02877                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02878                 // FIXME we shouldn't compare floats
02879                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
02880                 return it2_ == it.it2_;
02881             }
02882             BOOST_UBLAS_INLINE
02883             bool operator < (const const_iterator2 &it) const {
02884                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
02885                 // FIXME we shouldn't compare floats
02886                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
02887                 return it2_ < it.it2_;
02888             }
02889 
02890         private:
02891             const_subiterator1_type it1_;
02892             const_iterator22_type it2_;
02893         };
02894 #endif
02895 
02896         BOOST_UBLAS_INLINE
02897         const_iterator2 begin2 () const {
02898             return find2 (0, 0, 0);
02899         }
02900         BOOST_UBLAS_INLINE
02901         const_iterator2 end2 () const {
02902             return find2 (0, 0, size2 ());
02903         }
02904 
02905         // Reverse iterators
02906 
02907         BOOST_UBLAS_INLINE
02908         const_reverse_iterator1 rbegin1 () const {
02909             return const_reverse_iterator1 (end1 ());
02910         }
02911         BOOST_UBLAS_INLINE
02912         const_reverse_iterator1 rend1 () const {
02913             return const_reverse_iterator1 (begin1 ());
02914         }
02915 
02916         BOOST_UBLAS_INLINE
02917         const_reverse_iterator2 rbegin2 () const {
02918             return const_reverse_iterator2 (end2 ());
02919         }
02920         BOOST_UBLAS_INLINE
02921         const_reverse_iterator2 rend2 () const {
02922             return const_reverse_iterator2 (begin2 ());
02923         }
02924 
02925     private:
02926         expression1_closure_type e1_;
02927         expression2_closure_type e2_;
02928     };
02929 
02930     template<class E1, class E2, class F>
02931     struct matrix_binary_scalar1_traits {
02932         typedef matrix_binary_scalar1<E1, E2, F> expression_type;   // allow E1 to be builtin type
02933 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
02934         typedef expression_type result_type;
02935 #else
02936         typedef typename E2::matrix_temporary_type result_type;
02937 #endif
02938     };
02939 
02940     // (t * m) [i] [j] = t * m [i] [j]
02941     template<class T1, class E2>
02942     BOOST_UBLAS_INLINE
02943     typename enable_if< is_convertible<T1, typename E2::value_type >,
02944     typename matrix_binary_scalar1_traits<const T1, E2, scalar_multiplies<T1, typename E2::value_type> >::result_type
02945     >::type
02946     operator * (const T1 &e1,
02947                 const matrix_expression<E2> &e2) {
02948         typedef typename matrix_binary_scalar1_traits<const T1, E2, scalar_multiplies<T1, typename E2::value_type> >::expression_type expression_type;
02949         return expression_type (e1, e2 ());
02950     }
02951 
02952 
02953     template<class E1, class E2, class F>
02954     class matrix_binary_scalar2:
02955         public matrix_expression<matrix_binary_scalar2<E1, E2, F> > {
02956 
02957         typedef E1 expression1_type;
02958         typedef E2 expression2_type;
02959         typedef F functor_type;
02960     public:
02961         typedef typename E1::const_closure_type expression1_closure_type;
02962         typedef const E2& expression2_closure_type;
02963     private:
02964         typedef matrix_binary_scalar2<E1, E2, F> self_type;
02965     public:
02966 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
02967         using matrix_expression<self_type>::operator ();
02968 #endif
02969         typedef typename E1::size_type size_type;
02970         typedef typename E1::difference_type difference_type;
02971         typedef typename F::result_type value_type;
02972         typedef value_type const_reference;
02973         typedef const_reference reference;
02974 
02975         typedef const self_type const_closure_type;
02976         typedef const_closure_type closure_type;
02977         typedef typename E1::orientation_category orientation_category;
02978         typedef unknown_storage_tag storage_category;
02979 
02980         // Construction and destruction
02981         BOOST_UBLAS_INLINE
02982         matrix_binary_scalar2 (const expression1_type &e1, const expression2_type &e2): 
02983             e1_ (e1), e2_ (e2) {}
02984 
02985         // Accessors
02986         BOOST_UBLAS_INLINE
02987         size_type size1 () const {
02988             return e1_.size1 ();
02989         }
02990         BOOST_UBLAS_INLINE
02991         size_type size2 () const {
02992             return e1_.size2 ();
02993         }
02994 
02995     public:
02996         // Element access
02997         BOOST_UBLAS_INLINE
02998         const_reference operator () (size_type i, size_type j) const {
02999             return functor_type::apply (e1_ (i, j), expression2_type (e2_));
03000         }
03001 
03002         // Closure comparison
03003         BOOST_UBLAS_INLINE
03004         bool same_closure (const matrix_binary_scalar2 &mbs2) const {
03005             return (*this).e1_.same_closure (mbs2.e1_) &&
03006                    &e2_ == &(mbs2.e2_);
03007         }
03008 
03009         // Iterator types
03010     private:
03011         typedef typename E1::const_iterator1 const_iterator11_type;
03012         typedef typename E1::const_iterator2 const_iterator12_type;
03013         typedef expression2_type const_subiterator2_type;
03014         typedef const value_type *const_pointer;
03015 
03016     public:
03017 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
03018         typedef indexed_const_iterator1<const_closure_type, typename const_iterator11_type::iterator_category> const_iterator1;
03019         typedef const_iterator1 iterator1;
03020         typedef indexed_const_iterator2<const_closure_type, typename const_iterator12_type::iterator_category> const_iterator2;
03021         typedef const_iterator2 iterator2;
03022 #else
03023         class const_iterator1;
03024         typedef const_iterator1 iterator1;
03025         class const_iterator2;
03026         typedef const_iterator2 iterator2;
03027 #endif
03028         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
03029         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
03030 
03031         // Element lookup
03032         BOOST_UBLAS_INLINE
03033         const_iterator1 find1 (int rank, size_type i, size_type j) const {
03034             const_iterator11_type it11 (e1_.find1 (rank, i, j));
03035 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
03036             return const_iterator1 (*this, it11.index1 (), it11.index2 ());
03037 #else
03038             return const_iterator1 (*this, it11, const_subiterator2_type (e2_));
03039 #endif
03040         }
03041         BOOST_UBLAS_INLINE
03042         const_iterator2 find2 (int rank, size_type i, size_type j) const {
03043             const_iterator12_type it12 (e1_.find2 (rank, i, j));
03044 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
03045             return const_iterator2 (*this, it12.index1 (), it12.index2 ());
03046 #else
03047             return const_iterator2 (*this, it12, const_subiterator2_type (e2_));
03048 #endif
03049         }
03050 
03051         // Iterators enhance the iterators of the referenced expression
03052         // with the binary functor.
03053 
03054 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
03055         class const_iterator1:
03056             public container_const_reference<matrix_binary_scalar2>,
03057             public iterator_base_traits<typename E1::const_iterator1::iterator_category>::template
03058                 iterator_base<const_iterator1, value_type>::type {
03059         public:
03060             typedef typename E1::const_iterator1::iterator_category iterator_category;
03061             typedef typename matrix_binary_scalar2::difference_type difference_type;
03062             typedef typename matrix_binary_scalar2::value_type value_type;
03063             typedef typename matrix_binary_scalar2::const_reference reference;
03064             typedef typename matrix_binary_scalar2::const_pointer pointer;
03065 
03066             typedef const_iterator2 dual_iterator_type;
03067             typedef const_reverse_iterator2 dual_reverse_iterator_type;
03068 
03069             // Construction and destruction
03070             BOOST_UBLAS_INLINE
03071             const_iterator1 ():
03072                 container_const_reference<self_type> (), it1_ (), it2_ () {}
03073             BOOST_UBLAS_INLINE
03074             const_iterator1 (const self_type &mbs, const const_iterator11_type &it1, const const_subiterator2_type &it2):
03075                 container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {}
03076 
03077             // Arithmetic
03078             BOOST_UBLAS_INLINE
03079             const_iterator1 &operator ++ () {
03080                 ++ it1_;
03081                 return *this;
03082             }
03083             BOOST_UBLAS_INLINE
03084             const_iterator1 &operator -- () {
03085                 -- it1_ ;
03086                 return *this;
03087             }
03088             BOOST_UBLAS_INLINE
03089             const_iterator1 &operator += (difference_type n) {
03090                 it1_ += n;
03091                 return *this;
03092             }
03093             BOOST_UBLAS_INLINE
03094             const_iterator1 &operator -= (difference_type n) {
03095                 it1_ -= n;
03096                 return *this;
03097             }
03098             BOOST_UBLAS_INLINE
03099             difference_type operator - (const const_iterator1 &it) const {
03100                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03101                 // FIXME we shouldn't compare floats
03102                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
03103                 return it1_ - it.it1_;
03104             }
03105 
03106             // Dereference
03107             BOOST_UBLAS_INLINE
03108             const_reference operator * () const {
03109                 return functor_type::apply (*it1_, it2_);
03110             }
03111             BOOST_UBLAS_INLINE
03112             const_reference operator [] (difference_type n) const {
03113                 return *(*this + n);
03114             }
03115 
03116 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
03117             BOOST_UBLAS_INLINE
03118 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
03119             typename self_type::
03120 #endif
03121             const_iterator2 begin () const {
03122                 return (*this) ().find2 (1, index1 (), 0);
03123             }
03124             BOOST_UBLAS_INLINE
03125 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
03126             typename self_type::
03127 #endif
03128             const_iterator2 end () const {
03129                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
03130             }
03131             BOOST_UBLAS_INLINE
03132 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
03133             typename self_type::
03134 #endif
03135             const_reverse_iterator2 rbegin () const {
03136                 return const_reverse_iterator2 (end ());
03137             }
03138             BOOST_UBLAS_INLINE
03139 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
03140             typename self_type::
03141 #endif
03142             const_reverse_iterator2 rend () const {
03143                 return const_reverse_iterator2 (begin ());
03144             }
03145 #endif
03146 
03147             // Indices
03148             BOOST_UBLAS_INLINE
03149             size_type index1 () const {
03150                 return it1_.index1 ();
03151             }
03152             BOOST_UBLAS_INLINE
03153             size_type index2 () const {
03154                 return it1_.index2 ();
03155             }
03156 
03157             // Assignment 
03158             BOOST_UBLAS_INLINE
03159             const_iterator1 &operator = (const const_iterator1 &it) {
03160                 container_const_reference<self_type>::assign (&it ());
03161                 it1_ = it.it1_;
03162                 it2_ = it.it2_;
03163                 return *this;
03164             }
03165 
03166             // Comparison
03167             BOOST_UBLAS_INLINE
03168             bool operator == (const const_iterator1 &it) const {
03169                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03170                 // FIXME we shouldn't compare floats
03171                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
03172                 return it1_ == it.it1_;
03173             }
03174             BOOST_UBLAS_INLINE
03175             bool operator < (const const_iterator1 &it) const {
03176                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03177                 // FIXME we shouldn't compare floats
03178                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
03179                 return it1_ < it.it1_;
03180             }
03181 
03182         private:
03183             const_iterator11_type it1_;
03184             const_subiterator2_type it2_;
03185         };
03186 #endif
03187 
03188         BOOST_UBLAS_INLINE
03189         const_iterator1 begin1 () const {
03190             return find1 (0, 0, 0);
03191         }
03192         BOOST_UBLAS_INLINE
03193         const_iterator1 end1 () const {
03194             return find1 (0, size1 (), 0);
03195         }
03196 
03197 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
03198         class const_iterator2:
03199             public container_const_reference<matrix_binary_scalar2>,
03200             public iterator_base_traits<typename E1::const_iterator2::iterator_category>::template
03201                 iterator_base<const_iterator2, value_type>::type {
03202         public:
03203             typedef typename E1::const_iterator2::iterator_category iterator_category;
03204             typedef typename matrix_binary_scalar2::difference_type difference_type;
03205             typedef typename matrix_binary_scalar2::value_type value_type;
03206             typedef typename matrix_binary_scalar2::const_reference reference;
03207             typedef typename matrix_binary_scalar2::const_pointer pointer;
03208 
03209             typedef const_iterator1 dual_iterator_type;
03210             typedef const_reverse_iterator1 dual_reverse_iterator_type;
03211 
03212             // Construction and destruction
03213             BOOST_UBLAS_INLINE
03214             const_iterator2 ():
03215                 container_const_reference<self_type> (), it1_ (), it2_ () {}
03216             BOOST_UBLAS_INLINE
03217             const_iterator2 (const self_type &mbs, const const_iterator12_type &it1, const const_subiterator2_type &it2):
03218                 container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {}
03219 
03220             // Arithmetic
03221             BOOST_UBLAS_INLINE
03222             const_iterator2 &operator ++ () {
03223                 ++ it1_;
03224                 return *this;
03225             }
03226             BOOST_UBLAS_INLINE
03227             const_iterator2 &operator -- () {
03228                 -- it1_;
03229                 return *this;
03230             }
03231             BOOST_UBLAS_INLINE
03232             const_iterator2 &operator += (difference_type n) {
03233                 it1_ += n;
03234                 return *this;
03235             }
03236             BOOST_UBLAS_INLINE
03237             const_iterator2 &operator -= (difference_type n) {
03238                 it1_ -= n;
03239                 return *this;
03240             }
03241             BOOST_UBLAS_INLINE
03242             difference_type operator - (const const_iterator2 &it) const {
03243                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03244                 // FIXME we shouldn't compare floats
03245                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
03246                 return it1_ - it.it1_;
03247             }
03248 
03249             // Dereference
03250             BOOST_UBLAS_INLINE
03251             const_reference operator * () const {
03252                 return functor_type::apply (*it1_, it2_);
03253             }
03254             BOOST_UBLAS_INLINE
03255             const_reference operator [] (difference_type n) const {
03256                 return *(*this + n);
03257             }
03258 
03259 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
03260             BOOST_UBLAS_INLINE
03261 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
03262             typename self_type::
03263 #endif
03264             const_iterator1 begin () const {
03265                 return (*this) ().find1 (1, 0, index2 ());
03266             }
03267             BOOST_UBLAS_INLINE
03268 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
03269             typename self_type::
03270 #endif
03271             const_iterator1 end () const {
03272                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
03273             }
03274             BOOST_UBLAS_INLINE
03275 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
03276             typename self_type::
03277 #endif
03278             const_reverse_iterator1 rbegin () const {
03279                 return const_reverse_iterator1 (end ());
03280             }
03281             BOOST_UBLAS_INLINE
03282 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
03283             typename self_type::
03284 #endif
03285             const_reverse_iterator1 rend () const {
03286                 return const_reverse_iterator1 (begin ());
03287             }
03288 #endif
03289 
03290             // Indices
03291             BOOST_UBLAS_INLINE
03292             size_type index1 () const {
03293                 return it1_.index1 ();
03294             }
03295             BOOST_UBLAS_INLINE
03296             size_type index2 () const {
03297                 return it1_.index2 ();
03298             }
03299 
03300             // Assignment 
03301             BOOST_UBLAS_INLINE
03302             const_iterator2 &operator = (const const_iterator2 &it) {
03303                 container_const_reference<self_type>::assign (&it ());
03304                 it1_ = it.it1_;
03305                 it2_ = it.it2_;
03306                 return *this;
03307             }
03308 
03309             // Comparison
03310             BOOST_UBLAS_INLINE
03311             bool operator == (const const_iterator2 &it) const {
03312                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03313                 // FIXME we shouldn't compare floats
03314                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
03315                 return it1_ == it.it1_;
03316             }
03317             BOOST_UBLAS_INLINE
03318             bool operator < (const const_iterator2 &it) const {
03319                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03320                 // FIXME we shouldn't compare floats
03321                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
03322                 return it1_ < it.it1_;
03323             }
03324 
03325         private:
03326             const_iterator12_type it1_;
03327             const_subiterator2_type it2_;
03328         };
03329 #endif
03330 
03331         BOOST_UBLAS_INLINE
03332         const_iterator2 begin2 () const {
03333             return find2 (0, 0, 0);
03334         }
03335         BOOST_UBLAS_INLINE
03336         const_iterator2 end2 () const {
03337             return find2 (0, 0, size2 ());
03338         }
03339 
03340         // Reverse iterators
03341 
03342         BOOST_UBLAS_INLINE
03343         const_reverse_iterator1 rbegin1 () const {
03344             return const_reverse_iterator1 (end1 ());
03345         }
03346         BOOST_UBLAS_INLINE
03347         const_reverse_iterator1 rend1 () const {
03348             return const_reverse_iterator1 (begin1 ());
03349         }
03350 
03351         BOOST_UBLAS_INLINE
03352         const_reverse_iterator2 rbegin2 () const {
03353             return const_reverse_iterator2 (end2 ());
03354         }
03355         BOOST_UBLAS_INLINE
03356         const_reverse_iterator2 rend2 () const {
03357             return const_reverse_iterator2 (begin2 ());
03358         }
03359 
03360     private:
03361         expression1_closure_type e1_;
03362         expression2_closure_type e2_;
03363     };
03364 
03365     template<class E1, class E2, class F>
03366     struct matrix_binary_scalar2_traits {
03367         typedef matrix_binary_scalar2<E1, E2, F> expression_type;   // allow E2 to be builtin type
03368 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
03369         typedef expression_type result_type; 
03370 #else
03371         typedef typename E1::matrix_temporary_type result_type;
03372 #endif
03373     };
03374 
03375     // (m * t) [i] [j] = m [i] [j] * t
03376     template<class E1, class T2>
03377     BOOST_UBLAS_INLINE
03378     typename enable_if< is_convertible<T2, typename E1::value_type>,
03379     typename matrix_binary_scalar2_traits<E1, const T2, scalar_multiplies<typename E1::value_type, T2> >::result_type
03380     >::type
03381     operator * (const matrix_expression<E1> &e1,
03382                 const T2 &e2) {
03383         typedef typename matrix_binary_scalar2_traits<E1, const T2, scalar_multiplies<typename E1::value_type, T2> >::expression_type expression_type;
03384         return expression_type (e1 (), e2);
03385     }
03386 
03387     // (m / t) [i] [j] = m [i] [j] / t
03388     template<class E1, class T2>
03389     BOOST_UBLAS_INLINE
03390     typename matrix_binary_scalar2_traits<E1, const T2, scalar_divides<typename E1::value_type, T2> >::result_type
03391     operator / (const matrix_expression<E1> &e1,
03392                 const T2 &e2) {
03393         typedef typename matrix_binary_scalar2_traits<E1, const T2, scalar_divides<typename E1::value_type, T2> >::expression_type expression_type;
03394         return expression_type (e1 (), e2);
03395     }
03396 
03397 
03398     template<class E1, class E2, class F>
03399     class matrix_vector_binary1:
03400         public vector_expression<matrix_vector_binary1<E1, E2, F> > {
03401 
03402     public:
03403         typedef E1 expression1_type;
03404         typedef E2 expression2_type;
03405     private:
03406         typedef F functor_type;
03407     public:
03408         typedef typename E1::const_closure_type expression1_closure_type;
03409         typedef typename E2::const_closure_type expression2_closure_type;
03410     private:
03411         typedef matrix_vector_binary1<E1, E2, F> self_type;
03412     public:
03413 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
03414         using vector_expression<self_type>::operator ();
03415 #endif
03416         static const unsigned complexity = 1;
03417         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
03418         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
03419         typedef typename F::result_type value_type;
03420         typedef value_type const_reference;
03421         typedef const_reference reference;
03422         typedef const self_type const_closure_type;
03423         typedef const_closure_type closure_type;
03424         typedef unknown_storage_tag storage_category;
03425 
03426         // Construction and destruction
03427         BOOST_UBLAS_INLINE
03428         matrix_vector_binary1 (const expression1_type &e1, const expression2_type &e2):
03429             e1_ (e1), e2_ (e2) {}
03430 
03431         // Accessors
03432         BOOST_UBLAS_INLINE
03433         size_type size () const {
03434             return e1_.size1 ();
03435         }
03436 
03437     public:
03438         // Expression accessors
03439         BOOST_UBLAS_INLINE
03440         const expression1_closure_type &expression1 () const {
03441             return e1_;
03442         }
03443         BOOST_UBLAS_INLINE
03444         const expression2_closure_type &expression2 () const {
03445             return e2_;
03446         }
03447 
03448     public:
03449         // Element access
03450         BOOST_UBLAS_INLINE
03451         const_reference operator () (size_type i) const {
03452             return functor_type::apply (e1_, e2_, i);
03453         }
03454 
03455         // Closure comparison
03456         BOOST_UBLAS_INLINE
03457         bool same_closure (const matrix_vector_binary1 &mvb1) const {
03458             return (*this).expression1 ().same_closure (mvb1.expression1 ()) &&
03459                    (*this).expression2 ().same_closure (mvb1.expression2 ());
03460         }
03461 
03462         // Iterator types
03463     private:
03464         typedef typename E1::const_iterator1 const_subiterator1_type;
03465         typedef typename E2::const_iterator const_subiterator2_type;
03466         typedef const value_type *const_pointer;
03467 
03468     public:
03469 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
03470         typedef indexed_const_iterator<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator;
03471         typedef const_iterator iterator;
03472 #else
03473         class const_iterator;
03474         typedef const_iterator iterator;
03475 #endif
03476 
03477         // Element lookup
03478         BOOST_UBLAS_INLINE
03479         const_iterator find (size_type i) const {
03480 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
03481             const_subiterator1_type it1 (e1_.find1 (0, i, 0));
03482             return const_iterator (*this, it1.index1 ());
03483 #else
03484             return const_iterator (*this, e1_.find1 (0, i, 0));
03485 #endif
03486         }
03487 
03488 
03489 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
03490         class const_iterator:
03491             public container_const_reference<matrix_vector_binary1>,
03492             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
03493                                                                           typename E2::const_iterator::iterator_category>::iterator_category>::template
03494                 iterator_base<const_iterator, value_type>::type {
03495         public:
03496             typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category, 
03497                                                       typename E2::const_iterator::iterator_category>::iterator_category iterator_category;
03498             typedef typename matrix_vector_binary1::difference_type difference_type;
03499             typedef typename matrix_vector_binary1::value_type value_type;
03500             typedef typename matrix_vector_binary1::const_reference reference;
03501             typedef typename matrix_vector_binary1::const_pointer pointer;
03502 
03503             // Construction and destruction
03504 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03505             BOOST_UBLAS_INLINE
03506             const_iterator ():
03507                 container_const_reference<self_type> (), it1_ (), e2_begin_ (), e2_end_ () {}
03508             BOOST_UBLAS_INLINE
03509             const_iterator (const self_type &mvb, const const_subiterator1_type &it1):
03510                 container_const_reference<self_type> (mvb), it1_ (it1), e2_begin_ (mvb.expression2 ().begin ()), e2_end_ (mvb.expression2 ().end ()) {}
03511 #else
03512             BOOST_UBLAS_INLINE
03513             const_iterator ():
03514                 container_const_reference<self_type> (), it1_ () {}
03515             BOOST_UBLAS_INLINE
03516             const_iterator (const self_type &mvb, const const_subiterator1_type &it1):
03517                 container_const_reference<self_type> (mvb), it1_ (it1) {}
03518 #endif
03519 
03520         private:
03521             // Dense random access specialization
03522             BOOST_UBLAS_INLINE
03523             value_type dereference (dense_random_access_iterator_tag) const {
03524                 const self_type &mvb = (*this) ();
03525 #ifdef BOOST_UBLAS_USE_INDEXING
03526                 return mvb (index ());
03527 #elif BOOST_UBLAS_USE_ITERATING
03528                 difference_type size = BOOST_UBLAS_SAME (mvb.expression1 ().size2 (), mvb.expression2 ().size ());
03529 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03530                 return functor_type::apply (size, it1_.begin (), e2_begin_);
03531 #else
03532                 return functor_type::apply (size, it1_.begin (), mvb.expression2 ().begin ());
03533 #endif
03534 #else
03535                 difference_type size = BOOST_UBLAS_SAME (mvb.expression1 ().size2 (), mvb.expression2 ().size ());
03536                 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
03537 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03538                     return functor_type::apply (size, it1_.begin (), e2_begin_);
03539 #else
03540                     return functor_type::apply (size, it1_.begin (), mvb.expression2 ().begin ());
03541 #endif
03542                 else
03543                     return mvb (index ());
03544 #endif
03545             }
03546 
03547             // Packed bidirectional specialization
03548             BOOST_UBLAS_INLINE
03549             value_type dereference (packed_random_access_iterator_tag) const {
03550 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03551                 return functor_type::apply (it1_.begin (), it1_.end (), e2_begin_, e2_end_);
03552 #else
03553                 const self_type &mvb = (*this) ();
03554 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
03555                 return functor_type::apply (it1_.begin (), it1_.end (),
03556                                         mvb.expression2 ().begin (), mvb.expression2 ().end ());
03557 #else
03558                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
03559                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
03560                                         mvb.expression2 ().begin (), mvb.expression2 ().end ());
03561 #endif
03562 #endif
03563             }
03564 
03565             // Sparse bidirectional specialization
03566             BOOST_UBLAS_INLINE
03567             value_type dereference (sparse_bidirectional_iterator_tag) const {
03568 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03569                 return functor_type::apply (it1_.begin (), it1_.end (), e2_begin_, e2_end_, sparse_bidirectional_iterator_tag ());
03570 #else
03571                 const self_type &mvb = (*this) ();
03572 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
03573                 return functor_type::apply (it1_.begin (), it1_.end (),
03574                                         mvb.expression2 ().begin (), mvb.expression2 ().end (), sparse_bidirectional_iterator_tag ());
03575 #else
03576                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
03577                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
03578                                         mvb.expression2 ().begin (), mvb.expression2 ().end (), sparse_bidirectional_iterator_tag ());
03579 #endif
03580 #endif
03581             }
03582 
03583         public:
03584             // Arithmetic
03585             BOOST_UBLAS_INLINE
03586             const_iterator &operator ++ () {
03587                 ++ it1_;
03588                 return *this;
03589             }
03590             BOOST_UBLAS_INLINE
03591             const_iterator &operator -- () {
03592                 -- it1_;
03593                 return *this;
03594             }
03595             BOOST_UBLAS_INLINE
03596             const_iterator &operator += (difference_type n) {
03597                 it1_ += n;
03598                 return *this;
03599             }
03600             BOOST_UBLAS_INLINE
03601             const_iterator &operator -= (difference_type n) {
03602                 it1_ -= n;
03603                 return *this;
03604             }
03605             BOOST_UBLAS_INLINE
03606             difference_type operator - (const const_iterator &it) const {
03607                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03608                 return it1_ - it.it1_;
03609             }
03610 
03611             // Dereference
03612             BOOST_UBLAS_INLINE
03613             const_reference operator * () const {
03614                 return dereference (iterator_category ());
03615             }
03616             BOOST_UBLAS_INLINE
03617             const_reference operator [] (difference_type n) const {
03618                 return *(*this + n);
03619             }
03620 
03621             // Index
03622             BOOST_UBLAS_INLINE
03623             size_type index () const {
03624                 return it1_.index1 ();
03625             }
03626 
03627             // Assignment
03628             BOOST_UBLAS_INLINE
03629             const_iterator &operator = (const const_iterator &it) {
03630                 container_const_reference<self_type>::assign (&it ());
03631                 it1_ = it.it1_;
03632 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03633                 e2_begin_ = it.e2_begin_;
03634                 e2_end_ = it.e2_end_;
03635 #endif
03636                 return *this;
03637             }
03638 
03639             // Comparison
03640             BOOST_UBLAS_INLINE
03641             bool operator == (const const_iterator &it) const {
03642                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03643                 return it1_ == it.it1_;
03644             }
03645             BOOST_UBLAS_INLINE
03646             bool operator < (const const_iterator &it) const {
03647                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03648                 return it1_ < it.it1_;
03649             }
03650 
03651         private:
03652             const_subiterator1_type it1_;
03653 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03654             // Mutable due to assignment
03655             /* const */ const_subiterator2_type e2_begin_;
03656             /* const */ const_subiterator2_type e2_end_;
03657 #endif
03658         };
03659 #endif
03660 
03661         BOOST_UBLAS_INLINE
03662         const_iterator begin () const {
03663             return find (0);
03664         }
03665         BOOST_UBLAS_INLINE
03666         const_iterator end () const {
03667             return find (size ()); 
03668         }
03669 
03670         // Reverse iterator
03671         typedef reverse_iterator_base<const_iterator> const_reverse_iterator;
03672 
03673         BOOST_UBLAS_INLINE
03674         const_reverse_iterator rbegin () const {
03675             return const_reverse_iterator (end ());
03676         }
03677         BOOST_UBLAS_INLINE
03678         const_reverse_iterator rend () const {
03679             return const_reverse_iterator (begin ());
03680         }
03681 
03682     private:
03683         expression1_closure_type e1_;
03684         expression2_closure_type e2_;
03685     };
03686 
03687     template<class T1, class E1, class T2, class E2>
03688     struct matrix_vector_binary1_traits {
03689         typedef unknown_storage_tag storage_category;
03690         typedef row_major_tag orientation_category;
03691         typedef typename promote_traits<T1, T2>::promote_type promote_type;
03692         typedef matrix_vector_binary1<E1, E2, matrix_vector_prod1<E1, E2, promote_type> > expression_type;
03693 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
03694         typedef expression_type result_type;
03695 #else
03696         typedef typename E1::vector_temporary_type result_type;
03697 #endif
03698     };
03699 
03700     template<class E1, class E2>
03701     BOOST_UBLAS_INLINE
03702     typename matrix_vector_binary1_traits<typename E1::value_type, E1,
03703                                           typename E2::value_type, E2>::result_type
03704     prod (const matrix_expression<E1> &e1,
03705           const vector_expression<E2> &e2,
03706           unknown_storage_tag,
03707           row_major_tag) {
03708         typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1,
03709                                                       typename E2::value_type, E2>::expression_type expression_type;
03710         return expression_type (e1 (), e2 ());
03711     }
03712 
03713     // Dispatcher
03714     template<class E1, class E2>
03715     BOOST_UBLAS_INLINE
03716     typename matrix_vector_binary1_traits<typename E1::value_type, E1,
03717                                           typename E2::value_type, E2>::result_type
03718     prod (const matrix_expression<E1> &e1,
03719           const vector_expression<E2> &e2) {
03720         BOOST_STATIC_ASSERT (E2::complexity == 0);
03721         typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1,
03722                                                       typename E2::value_type, E2>::storage_category storage_category;
03723         typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1,
03724                                                       typename E2::value_type, E2>::orientation_category orientation_category;
03725         return prod (e1, e2, storage_category (), orientation_category ());
03726     }
03727 
03728     template<class E1, class E2>
03729     BOOST_UBLAS_INLINE
03730     typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
03731                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
03732     prec_prod (const matrix_expression<E1> &e1,
03733                const vector_expression<E2> &e2,
03734                unknown_storage_tag,
03735                row_major_tag) {
03736         typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
03737                                                       typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type;
03738         return expression_type (e1 (), e2 ());
03739     }
03740 
03741     // Dispatcher
03742     template<class E1, class E2>
03743     BOOST_UBLAS_INLINE
03744     typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
03745                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
03746     prec_prod (const matrix_expression<E1> &e1,
03747                const vector_expression<E2> &e2) {
03748         BOOST_STATIC_ASSERT (E2::complexity == 0);
03749         typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
03750                                                       typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category;
03751         typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
03752                                                       typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category;
03753         return prec_prod (e1, e2, storage_category (), orientation_category ());
03754     }
03755 
03756     template<class V, class E1, class E2>
03757     BOOST_UBLAS_INLINE
03758     V &
03759     prod (const matrix_expression<E1> &e1,
03760           const vector_expression<E2> &e2,
03761           V &v) {
03762         return v.assign (prod (e1, e2));
03763     }
03764 
03765     template<class V, class E1, class E2>
03766     BOOST_UBLAS_INLINE
03767     V &
03768     prec_prod (const matrix_expression<E1> &e1,
03769                const vector_expression<E2> &e2,
03770                V &v) {
03771         return v.assign (prec_prod (e1, e2));
03772     }
03773 
03774     template<class V, class E1, class E2>
03775     BOOST_UBLAS_INLINE
03776     V
03777     prod (const matrix_expression<E1> &e1,
03778           const vector_expression<E2> &e2) {
03779         return V (prod (e1, e2));
03780     }
03781 
03782     template<class V, class E1, class E2>
03783     BOOST_UBLAS_INLINE
03784     V
03785     prec_prod (const matrix_expression<E1> &e1,
03786                const vector_expression<E2> &e2) {
03787         return V (prec_prod (e1, e2));
03788     }
03789 
03790     template<class E1, class E2, class F>
03791     class matrix_vector_binary2:
03792         public vector_expression<matrix_vector_binary2<E1, E2, F> > {
03793 
03794         typedef E1 expression1_type;
03795         typedef E2 expression2_type;
03796         typedef F functor_type;
03797     public:
03798         typedef typename E1::const_closure_type expression1_closure_type;
03799         typedef typename E2::const_closure_type expression2_closure_type;
03800     private:
03801         typedef matrix_vector_binary2<E1, E2, F> self_type;
03802     public:
03803 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
03804         using vector_expression<self_type>::operator ();
03805 #endif
03806         static const unsigned complexity = 1;
03807         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
03808         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
03809         typedef typename F::result_type value_type;
03810         typedef value_type const_reference;
03811         typedef const_reference reference;
03812         typedef const self_type const_closure_type;
03813         typedef const_closure_type closure_type;
03814         typedef unknown_storage_tag storage_category;
03815 
03816         // Construction and destruction
03817         BOOST_UBLAS_INLINE
03818         matrix_vector_binary2 (const expression1_type &e1, const expression2_type &e2): 
03819             e1_ (e1), e2_ (e2) {}
03820 
03821         // Accessors
03822         BOOST_UBLAS_INLINE
03823         size_type size () const { 
03824             return e2_.size2 (); 
03825         }
03826 
03827     public:
03828         // Expression accessors
03829         BOOST_UBLAS_INLINE
03830         const expression1_closure_type &expression1 () const {
03831             return e1_;
03832         }
03833         BOOST_UBLAS_INLINE
03834         const expression2_closure_type &expression2 () const {
03835             return e2_;
03836         }
03837     public:
03838 
03839         // Element access
03840         BOOST_UBLAS_INLINE
03841         const_reference operator () (size_type j) const { 
03842             return functor_type::apply (e1_, e2_, j); 
03843         }
03844 
03845         // Closure comparison
03846         BOOST_UBLAS_INLINE
03847         bool same_closure (const matrix_vector_binary2 &mvb2) const {
03848             return (*this).expression1 ().same_closure (mvb2.expression1 ()) &&
03849                    (*this).expression2 ().same_closure (mvb2.expression2 ());
03850         }
03851 
03852         // Iterator types
03853     private:
03854         typedef typename E1::const_iterator const_subiterator1_type;
03855         typedef typename E2::const_iterator2 const_subiterator2_type;
03856         typedef const value_type *const_pointer;
03857 
03858     public:
03859 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
03860         typedef indexed_const_iterator<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator;
03861         typedef const_iterator iterator;
03862 #else
03863         class const_iterator;
03864         typedef const_iterator iterator;
03865 #endif
03866 
03867         // Element lookup
03868         BOOST_UBLAS_INLINE
03869         const_iterator find (size_type j) const {
03870 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
03871             const_subiterator2_type it2 (e2_.find2 (0, 0, j));
03872             return const_iterator (*this, it2.index2 ());
03873 #else
03874             return const_iterator (*this, e2_.find2 (0, 0, j));
03875 #endif
03876         }
03877 
03878 
03879 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
03880         class const_iterator:
03881             public container_const_reference<matrix_vector_binary2>,
03882             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
03883                                                                           typename E2::const_iterator2::iterator_category>::iterator_category>::template
03884                 iterator_base<const_iterator, value_type>::type {
03885         public:
03886             typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
03887                                                       typename E2::const_iterator2::iterator_category>::iterator_category iterator_category;
03888             typedef typename matrix_vector_binary2::difference_type difference_type;
03889             typedef typename matrix_vector_binary2::value_type value_type;
03890             typedef typename matrix_vector_binary2::const_reference reference;
03891             typedef typename matrix_vector_binary2::const_pointer pointer;
03892 
03893             // Construction and destruction
03894 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03895             BOOST_UBLAS_INLINE
03896             const_iterator ():
03897                 container_const_reference<self_type> (), it2_ (), e1_begin_ (), e1_end_ () {}
03898             BOOST_UBLAS_INLINE
03899             const_iterator (const self_type &mvb, const const_subiterator2_type &it2):
03900                 container_const_reference<self_type> (mvb), it2_ (it2), e1_begin_ (mvb.expression1 ().begin ()), e1_end_ (mvb.expression1 ().end ()) {}
03901 #else
03902             BOOST_UBLAS_INLINE
03903             const_iterator ():
03904                 container_const_reference<self_type> (), it2_ () {}
03905             BOOST_UBLAS_INLINE
03906             const_iterator (const self_type &mvb, const const_subiterator2_type &it2):
03907                 container_const_reference<self_type> (mvb), it2_ (it2) {}
03908 #endif
03909 
03910         private:
03911             // Dense random access specialization
03912             BOOST_UBLAS_INLINE
03913             value_type dereference (dense_random_access_iterator_tag) const {
03914                 const self_type &mvb = (*this) ();
03915 #ifdef BOOST_UBLAS_USE_INDEXING
03916                 return mvb (index ());
03917 #elif BOOST_UBLAS_USE_ITERATING
03918                 difference_type size = BOOST_UBLAS_SAME (mvb.expression2 ().size1 (), mvb.expression1 ().size ());
03919 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03920                 return functor_type::apply (size, e1_begin_, it2_.begin ());
03921 #else
03922                 return functor_type::apply (size, mvb.expression1 ().begin (), it2_.begin ());
03923 #endif
03924 #else
03925                 difference_type size = BOOST_UBLAS_SAME (mvb.expression2 ().size1 (), mvb.expression1 ().size ());
03926                 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
03927 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03928                     return functor_type::apply (size, e1_begin_, it2_.begin ());
03929 #else
03930                     return functor_type::apply (size, mvb.expression1 ().begin (), it2_.begin ());
03931 #endif
03932                 else
03933                     return mvb (index ());
03934 #endif
03935             }
03936 
03937             // Packed bidirectional specialization
03938             BOOST_UBLAS_INLINE
03939             value_type dereference (packed_random_access_iterator_tag) const {
03940 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03941                 return functor_type::apply (e1_begin_, e1_end_, it2_.begin (), it2_.end ());
03942 #else
03943                 const self_type &mvb = (*this) ();
03944 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
03945                 return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (),
03946                                         it2_.begin (), it2_.end ());
03947 #else
03948                 return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (),
03949                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
03950                                         boost::numeric::ublas::end (it2_, iterator2_tag ()));
03951 #endif
03952 #endif
03953             }
03954 
03955             // Sparse bidirectional specialization
03956             BOOST_UBLAS_INLINE
03957             value_type dereference (sparse_bidirectional_iterator_tag) const {
03958 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
03959                 return functor_type::apply (e1_begin_, e1_end_, it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
03960 #else
03961                 const self_type &mvb = (*this) ();
03962 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
03963                 return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (),
03964                                         it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
03965 #else
03966                 return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (),
03967                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
03968                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ());
03969 #endif
03970 #endif
03971             }
03972 
03973         public:
03974             // Arithmetic
03975             BOOST_UBLAS_INLINE
03976             const_iterator &operator ++ () {
03977                 ++ it2_;
03978                 return *this;
03979             }
03980             BOOST_UBLAS_INLINE
03981             const_iterator &operator -- () {
03982                 -- it2_;
03983                 return *this;
03984             }
03985             BOOST_UBLAS_INLINE
03986             const_iterator &operator += (difference_type n) {
03987                 it2_ += n;
03988                 return *this;
03989             }
03990             BOOST_UBLAS_INLINE
03991             const_iterator &operator -= (difference_type n) {
03992                 it2_ -= n;
03993                 return *this;
03994             }
03995             BOOST_UBLAS_INLINE
03996             difference_type operator - (const const_iterator &it) const {
03997                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
03998                 return it2_ - it.it2_;
03999             }
04000 
04001             // Dereference
04002             BOOST_UBLAS_INLINE
04003             const_reference operator * () const {
04004                 return dereference (iterator_category ());
04005             }
04006             BOOST_UBLAS_INLINE
04007             const_reference operator [] (difference_type n) const {
04008                 return *(*this + n);
04009             }
04010 
04011             // Index
04012             BOOST_UBLAS_INLINE
04013             size_type index () const {
04014                 return it2_.index2 ();
04015             }
04016 
04017             // Assignment 
04018             BOOST_UBLAS_INLINE
04019             const_iterator &operator = (const const_iterator &it) {
04020                 container_const_reference<self_type>::assign (&it ());
04021                 it2_ = it.it2_;
04022 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04023                 e1_begin_ = it.e1_begin_;
04024                 e1_end_ = it.e1_end_;
04025 #endif
04026                 return *this;
04027             }
04028 
04029             // Comparison
04030             BOOST_UBLAS_INLINE
04031             bool operator == (const const_iterator &it) const {
04032                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
04033                 return it2_ == it.it2_;
04034             }
04035             BOOST_UBLAS_INLINE
04036             bool operator < (const const_iterator &it) const {
04037                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
04038                 return it2_ < it.it2_;
04039             }
04040 
04041         private:
04042             const_subiterator2_type it2_;
04043 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04044             // Mutable due to assignment 
04045             /* const */ const_subiterator1_type e1_begin_;
04046             /* const */ const_subiterator1_type e1_end_;
04047 #endif
04048         };
04049 #endif
04050 
04051         BOOST_UBLAS_INLINE
04052         const_iterator begin () const {
04053             return find (0);
04054         }
04055         BOOST_UBLAS_INLINE
04056         const_iterator end () const {
04057             return find (size ()); 
04058         }
04059 
04060         // Reverse iterator
04061         typedef reverse_iterator_base<const_iterator> const_reverse_iterator;
04062 
04063         BOOST_UBLAS_INLINE
04064         const_reverse_iterator rbegin () const {
04065             return const_reverse_iterator (end ());
04066         }
04067         BOOST_UBLAS_INLINE
04068         const_reverse_iterator rend () const {
04069             return const_reverse_iterator (begin ());
04070         }
04071 
04072     private:
04073         expression1_closure_type e1_;
04074         expression2_closure_type e2_;
04075     };
04076 
04077     template<class T1, class E1, class T2, class E2>
04078     struct matrix_vector_binary2_traits {
04079         typedef unknown_storage_tag storage_category;
04080         typedef column_major_tag orientation_category;
04081         typedef typename promote_traits<T1, T2>::promote_type promote_type;
04082         typedef matrix_vector_binary2<E1, E2, matrix_vector_prod2<E1, E2, promote_type> > expression_type;
04083 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
04084         typedef expression_type result_type;
04085 #else
04086         typedef typename E2::vector_temporary_type result_type;
04087 #endif
04088     };
04089 
04090     template<class E1, class E2>
04091     BOOST_UBLAS_INLINE
04092     typename matrix_vector_binary2_traits<typename E1::value_type, E1,
04093                                           typename E2::value_type, E2>::result_type
04094     prod (const vector_expression<E1> &e1,
04095           const matrix_expression<E2> &e2,
04096           unknown_storage_tag,
04097           column_major_tag) {
04098         typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1,
04099                                                       typename E2::value_type, E2>::expression_type expression_type;
04100         return expression_type (e1 (), e2 ());
04101     }
04102 
04103     // Dispatcher
04104     template<class E1, class E2>
04105     BOOST_UBLAS_INLINE
04106     typename matrix_vector_binary2_traits<typename E1::value_type, E1,
04107                                           typename E2::value_type, E2>::result_type
04108     prod (const vector_expression<E1> &e1,
04109           const matrix_expression<E2> &e2) {
04110         BOOST_STATIC_ASSERT (E1::complexity == 0);
04111         typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1,
04112                                                       typename E2::value_type, E2>::storage_category storage_category;
04113         typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1,
04114                                                       typename E2::value_type, E2>::orientation_category orientation_category;
04115         return prod (e1, e2, storage_category (), orientation_category ());
04116     }
04117 
04118     template<class E1, class E2>
04119     BOOST_UBLAS_INLINE
04120     typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04121                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
04122     prec_prod (const vector_expression<E1> &e1,
04123                const matrix_expression<E2> &e2,
04124                unknown_storage_tag,
04125                column_major_tag) {
04126         typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04127                                                       typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type;
04128         return expression_type (e1 (), e2 ());
04129     }
04130 
04131     // Dispatcher
04132     template<class E1, class E2>
04133     BOOST_UBLAS_INLINE
04134     typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04135                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
04136     prec_prod (const vector_expression<E1> &e1,
04137                const matrix_expression<E2> &e2) {
04138         BOOST_STATIC_ASSERT (E1::complexity == 0);
04139         typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04140                                                       typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category;
04141         typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04142                                                       typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category;
04143         return prec_prod (e1, e2, storage_category (), orientation_category ());
04144     }
04145 
04146     template<class V, class E1, class E2>
04147     BOOST_UBLAS_INLINE
04148     V &
04149     prod (const vector_expression<E1> &e1,
04150           const matrix_expression<E2> &e2,
04151           V &v) {
04152         return v.assign (prod (e1, e2));
04153     }
04154 
04155     template<class V, class E1, class E2>
04156     BOOST_UBLAS_INLINE
04157     V &
04158     prec_prod (const vector_expression<E1> &e1,
04159                const matrix_expression<E2> &e2,
04160                V &v) {
04161         return v.assign (prec_prod (e1, e2));
04162     }
04163 
04164     template<class V, class E1, class E2>
04165     BOOST_UBLAS_INLINE
04166     V
04167     prod (const vector_expression<E1> &e1,
04168           const matrix_expression<E2> &e2) {
04169         return V (prod (e1, e2));
04170     }
04171 
04172     template<class V, class E1, class E2>
04173     BOOST_UBLAS_INLINE
04174     V
04175     prec_prod (const vector_expression<E1> &e1,
04176                const matrix_expression<E2> &e2) {
04177         return V (prec_prod (e1, e2));
04178     }
04179 
04180     template<class E1, class E2, class F>
04181     class matrix_matrix_binary:
04182         public matrix_expression<matrix_matrix_binary<E1, E2, F> > {
04183 
04184     public:
04185         typedef E1 expression1_type;
04186         typedef E2 expression2_type;
04187     private:
04188         typedef F functor_type;
04189     public:
04190         typedef typename E1::const_closure_type expression1_closure_type;
04191         typedef typename E2::const_closure_type expression2_closure_type;
04192     private:
04193         typedef matrix_matrix_binary<E1, E2, F> self_type;
04194     public:
04195 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
04196         using matrix_expression<self_type>::operator ();
04197 #endif
04198         static const unsigned complexity = 1;
04199         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
04200         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
04201         typedef typename F::result_type value_type;
04202         typedef value_type const_reference;
04203         typedef const_reference reference;
04204         typedef const self_type const_closure_type;
04205         typedef const_closure_type closure_type;
04206         typedef unknown_orientation_tag orientation_category;
04207         typedef unknown_storage_tag storage_category;
04208 
04209         // Construction and destruction
04210         BOOST_UBLAS_INLINE
04211         matrix_matrix_binary (const expression1_type &e1, const expression2_type &e2):
04212             e1_ (e1), e2_ (e2) {}
04213 
04214         // Accessors
04215         BOOST_UBLAS_INLINE
04216         size_type size1 () const {
04217             return e1_.size1 ();
04218         }
04219         BOOST_UBLAS_INLINE
04220         size_type size2 () const {
04221             return e2_.size2 ();
04222         }
04223 
04224     public:
04225         // Expression accessors
04226         BOOST_UBLAS_INLINE
04227         const expression1_closure_type &expression1 () const {
04228             return e1_;
04229         }
04230         BOOST_UBLAS_INLINE
04231         const expression2_closure_type &expression2 () const {
04232             return e2_;
04233         }
04234 
04235     public:
04236         // Element access
04237         BOOST_UBLAS_INLINE
04238         const_reference operator () (size_type i, size_type j) const {
04239             return functor_type::apply (e1_, e2_, i, j);
04240         }
04241 
04242         // Closure comparison
04243         BOOST_UBLAS_INLINE
04244         bool same_closure (const matrix_matrix_binary &mmb) const {
04245             return (*this).expression1 ().same_closure (mmb.expression1 ()) &&
04246                    (*this).expression2 ().same_closure (mmb.expression2 ());
04247         }
04248 
04249         // Iterator types
04250     private:
04251         typedef typename E1::const_iterator1 const_iterator11_type;
04252         typedef typename E1::const_iterator2 const_iterator12_type;
04253         typedef typename E2::const_iterator1 const_iterator21_type;
04254         typedef typename E2::const_iterator2 const_iterator22_type;
04255         typedef const value_type *const_pointer;
04256 
04257     public:
04258 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
04259         typedef typename iterator_restrict_traits<typename const_iterator11_type::iterator_category,
04260                                                   typename const_iterator22_type::iterator_category>::iterator_category iterator_category;
04261         typedef indexed_const_iterator1<const_closure_type, iterator_category> const_iterator1;
04262         typedef const_iterator1 iterator1;
04263         typedef indexed_const_iterator2<const_closure_type, iterator_category> const_iterator2;
04264         typedef const_iterator2 iterator2;
04265 #else
04266         class const_iterator1;
04267         typedef const_iterator1 iterator1;
04268         class const_iterator2;
04269         typedef const_iterator2 iterator2;
04270 #endif
04271         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
04272         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
04273 
04274         // Element lookup
04275         BOOST_UBLAS_INLINE
04276         const_iterator1 find1 (int /* rank */, size_type i, size_type j) const {
04277             // FIXME sparse matrix tests fail!
04278             // const_iterator11_type it11 (e1_.find1 (rank, i, 0));
04279             const_iterator11_type it11 (e1_.find1 (0, i, 0));
04280 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
04281             return const_iterator1 (*this, it11.index1 (), j);
04282 #else
04283             // FIXME sparse matrix tests fail!
04284             // const_iterator22_type it22 (e2_.find2 (rank, 0, j));
04285             const_iterator22_type it22 (e2_.find2 (0, 0, j));
04286             return const_iterator1 (*this, it11, it22);
04287 #endif
04288         }
04289         BOOST_UBLAS_INLINE
04290         const_iterator2 find2 (int /* rank */, size_type i, size_type j) const {
04291             // FIXME sparse matrix tests fail!
04292             // const_iterator22_type it22 (e2_.find2 (rank, 0, j));
04293             const_iterator22_type it22 (e2_.find2 (0, 0, j));
04294 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
04295             return const_iterator2 (*this, i, it22.index2 ());
04296 #else
04297             // FIXME sparse matrix tests fail!
04298             // const_iterator11_type it11 (e1_.find1 (rank, i, 0));
04299             const_iterator11_type it11 (e1_.find1 (0, i, 0));
04300             return const_iterator2 (*this, it11, it22);
04301 #endif
04302         }
04303 
04304 
04305 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
04306         class const_iterator1:
04307             public container_const_reference<matrix_matrix_binary>,
04308             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
04309                                                                           typename E2::const_iterator2::iterator_category>::iterator_category>::template
04310                 iterator_base<const_iterator1, value_type>::type {
04311         public:
04312             typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
04313                                                       typename E2::const_iterator2::iterator_category>::iterator_category iterator_category;
04314             typedef typename matrix_matrix_binary::difference_type difference_type;
04315             typedef typename matrix_matrix_binary::value_type value_type;
04316             typedef typename matrix_matrix_binary::const_reference reference;
04317             typedef typename matrix_matrix_binary::const_pointer pointer;
04318 
04319             typedef const_iterator2 dual_iterator_type;
04320             typedef const_reverse_iterator2 dual_reverse_iterator_type;
04321 
04322             // Construction and destruction
04323 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04324             BOOST_UBLAS_INLINE
04325             const_iterator1 ():
04326                 container_const_reference<self_type> (), it1_ (), it2_ (), it2_begin_ (), it2_end_ () {}
04327             BOOST_UBLAS_INLINE
04328             const_iterator1 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2):
04329                 container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2), it2_begin_ (it2.begin ()), it2_end_ (it2.end ()) {}
04330 #else
04331             BOOST_UBLAS_INLINE
04332             const_iterator1 ():
04333                 container_const_reference<self_type> (), it1_ (), it2_ () {}
04334             BOOST_UBLAS_INLINE
04335             const_iterator1 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2):
04336                 container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2) {}
04337 #endif
04338 
04339         private:
04340             // Random access specialization
04341             BOOST_UBLAS_INLINE
04342             value_type dereference (dense_random_access_iterator_tag) const {
04343                 const self_type &mmb = (*this) ();
04344 #ifdef BOOST_UBLAS_USE_INDEXING
04345                 return mmb (index1 (), index2 ());
04346 #elif BOOST_UBLAS_USE_ITERATING
04347                 difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ());
04348 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04349                 return functor_type::apply (size, it1_.begin (), it2_begin_);
04350 #else
04351                 return functor_type::apply (size, it1_.begin (), it2_.begin ());
04352 #endif
04353 #else
04354                 difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ());
04355                 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
04356 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04357                     return functor_type::apply (size, it1_.begin (), it2_begin_);
04358 #else
04359                     return functor_type::apply (size, it1_.begin (), it2_.begin ());
04360 #endif
04361                 else
04362                     return mmb (index1 (), index2 ());
04363 #endif
04364             }
04365 
04366             // Packed bidirectional specialization
04367             BOOST_UBLAS_INLINE
04368             value_type dereference (packed_random_access_iterator_tag) const {
04369 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04370                 return functor_type::apply (it1_.begin (), it1_.end (),
04371                                         it2_begin_, it2_end_, packed_random_access_iterator_tag ());
04372 #else
04373 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
04374                 return functor_type::apply (it1_.begin (), it1_.end (),
04375                                         it2_.begin (), it2_.end (), packed_random_access_iterator_tag ());
04376 #else
04377                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
04378                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
04379                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
04380                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), packed_random_access_iterator_tag ());
04381 #endif
04382 #endif
04383             }
04384 
04385             // Sparse bidirectional specialization
04386             BOOST_UBLAS_INLINE
04387             value_type dereference (sparse_bidirectional_iterator_tag) const {
04388 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04389                 return functor_type::apply (it1_.begin (), it1_.end (),
04390                                         it2_begin_, it2_end_, sparse_bidirectional_iterator_tag ());
04391 #else
04392 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
04393                 return functor_type::apply (it1_.begin (), it1_.end (),
04394                                         it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
04395 #else
04396                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
04397                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
04398                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
04399                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ());
04400 #endif
04401 #endif
04402             }
04403 
04404         public:
04405             // Arithmetic
04406             BOOST_UBLAS_INLINE
04407             const_iterator1 &operator ++ () {
04408                 ++ it1_;
04409                 return *this;
04410             }
04411             BOOST_UBLAS_INLINE
04412             const_iterator1 &operator -- () {
04413                 -- it1_;
04414                 return *this;
04415             }
04416             BOOST_UBLAS_INLINE
04417             const_iterator1 &operator += (difference_type n) {
04418                 it1_ += n;
04419                 return *this;
04420             }
04421             BOOST_UBLAS_INLINE
04422             const_iterator1 &operator -= (difference_type n) {
04423                 it1_ -= n;
04424                 return *this;
04425             }
04426             BOOST_UBLAS_INLINE
04427             difference_type operator - (const const_iterator1 &it) const {
04428                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
04429                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
04430                 return it1_ - it.it1_;
04431             }
04432 
04433             // Dereference
04434             BOOST_UBLAS_INLINE
04435             const_reference operator * () const {
04436                 return dereference (iterator_category ());
04437             }
04438             BOOST_UBLAS_INLINE
04439             const_reference operator [] (difference_type n) const {
04440                 return *(*this + n);
04441             }
04442 
04443 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
04444             BOOST_UBLAS_INLINE
04445 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
04446             typename self_type::
04447 #endif
04448             const_iterator2 begin () const {
04449                 return (*this) ().find2 (1, index1 (), 0);
04450             }
04451             BOOST_UBLAS_INLINE
04452 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
04453             typename self_type::
04454 #endif
04455             const_iterator2 end () const {
04456                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
04457             }
04458             BOOST_UBLAS_INLINE
04459 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
04460             typename self_type::
04461 #endif
04462             const_reverse_iterator2 rbegin () const {
04463                 return const_reverse_iterator2 (end ());
04464             }
04465             BOOST_UBLAS_INLINE
04466 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
04467             typename self_type::
04468 #endif
04469             const_reverse_iterator2 rend () const {
04470                 return const_reverse_iterator2 (begin ());
04471             }
04472 #endif
04473 
04474             // Indices
04475             BOOST_UBLAS_INLINE
04476             size_type index1 () const {
04477                 return it1_.index1 ();
04478             }
04479             BOOST_UBLAS_INLINE
04480             size_type index2 () const {
04481                 return it2_.index2 ();
04482             }
04483 
04484             // Assignment
04485             BOOST_UBLAS_INLINE
04486             const_iterator1 &operator = (const const_iterator1 &it) {
04487                 container_const_reference<self_type>::assign (&it ());
04488                 it1_ = it.it1_;
04489                 it2_ = it.it2_;
04490 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04491                 it2_begin_ = it.it2_begin_;
04492                 it2_end_ = it.it2_end_;
04493 #endif
04494                 return *this;
04495             }
04496 
04497             // Comparison
04498             BOOST_UBLAS_INLINE
04499             bool operator == (const const_iterator1 &it) const {
04500                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
04501                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
04502                 return it1_ == it.it1_;
04503             }
04504             BOOST_UBLAS_INLINE
04505             bool operator < (const const_iterator1 &it) const {
04506                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
04507                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
04508                 return it1_ < it.it1_;
04509             }
04510 
04511         private:
04512             const_iterator11_type it1_;
04513             // Mutable due to assignment
04514             /* const */ const_iterator22_type it2_;
04515 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04516             /* const */ const_iterator21_type it2_begin_;
04517             /* const */ const_iterator21_type it2_end_;
04518 #endif
04519         };
04520 #endif
04521 
04522         BOOST_UBLAS_INLINE
04523         const_iterator1 begin1 () const {
04524             return find1 (0, 0, 0);
04525         }
04526         BOOST_UBLAS_INLINE
04527         const_iterator1 end1 () const {
04528             return find1 (0, size1 (), 0);
04529         }
04530 
04531 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
04532         class const_iterator2:
04533             public container_const_reference<matrix_matrix_binary>,
04534             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
04535                                                                           typename E2::const_iterator2::iterator_category>::iterator_category>::template
04536                 iterator_base<const_iterator2, value_type>::type {
04537         public:
04538             typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
04539                                                       typename E2::const_iterator2::iterator_category>::iterator_category iterator_category;
04540             typedef typename matrix_matrix_binary::difference_type difference_type;
04541             typedef typename matrix_matrix_binary::value_type value_type;
04542             typedef typename matrix_matrix_binary::const_reference reference;
04543             typedef typename matrix_matrix_binary::const_pointer pointer;
04544 
04545             typedef const_iterator1 dual_iterator_type;
04546             typedef const_reverse_iterator1 dual_reverse_iterator_type;
04547 
04548             // Construction and destruction
04549 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04550             BOOST_UBLAS_INLINE
04551             const_iterator2 ():
04552                 container_const_reference<self_type> (), it1_ (), it2_ (), it1_begin_ (), it1_end_ () {}
04553             BOOST_UBLAS_INLINE
04554             const_iterator2 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2):
04555                 container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2), it1_begin_ (it1.begin ()), it1_end_ (it1.end ()) {}
04556 #else
04557             BOOST_UBLAS_INLINE
04558             const_iterator2 ():
04559                 container_const_reference<self_type> (), it1_ (), it2_ () {}
04560             BOOST_UBLAS_INLINE
04561             const_iterator2 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2):
04562                 container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2) {}
04563 #endif
04564 
04565         private:
04566             // Random access specialization
04567             BOOST_UBLAS_INLINE
04568             value_type dereference (dense_random_access_iterator_tag) const {
04569                 const self_type &mmb = (*this) ();
04570 #ifdef BOOST_UBLAS_USE_INDEXING
04571                 return mmb (index1 (), index2 ());
04572 #elif BOOST_UBLAS_USE_ITERATING
04573                 difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ());
04574 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04575                 return functor_type::apply (size, it1_begin_, it2_.begin ());
04576 #else
04577                 return functor_type::apply (size, it1_.begin (), it2_.begin ());
04578 #endif
04579 #else
04580                 difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ());
04581                 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
04582 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04583                     return functor_type::apply (size, it1_begin_, it2_.begin ());
04584 #else
04585                     return functor_type::apply (size, it1_.begin (), it2_.begin ());
04586 #endif
04587                 else
04588                     return mmb (index1 (), index2 ());
04589 #endif
04590             }
04591 
04592             // Packed bidirectional specialization
04593             BOOST_UBLAS_INLINE
04594             value_type dereference (packed_random_access_iterator_tag) const {
04595 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04596                 return functor_type::apply (it1_begin_, it1_end_,
04597                                         it2_.begin (), it2_.end (), packed_random_access_iterator_tag ());
04598 #else
04599 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
04600                 return functor_type::apply (it1_.begin (), it1_.end (),
04601                                         it2_.begin (), it2_.end (), packed_random_access_iterator_tag ());
04602 #else
04603                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
04604                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
04605                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
04606                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), packed_random_access_iterator_tag ());
04607 #endif
04608 #endif
04609             }
04610 
04611             // Sparse bidirectional specialization
04612             BOOST_UBLAS_INLINE
04613             value_type dereference (sparse_bidirectional_iterator_tag) const {
04614 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04615                 return functor_type::apply (it1_begin_, it1_end_,
04616                                         it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
04617 #else
04618 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
04619                 return functor_type::apply (it1_.begin (), it1_.end (),
04620                                         it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
04621 #else
04622                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
04623                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
04624                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
04625                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ());
04626 #endif
04627 #endif
04628             }
04629 
04630         public:
04631             // Arithmetic
04632             BOOST_UBLAS_INLINE
04633             const_iterator2 &operator ++ () {
04634                 ++ it2_;
04635                 return *this;
04636             }
04637             BOOST_UBLAS_INLINE
04638             const_iterator2 &operator -- () {
04639                 -- it2_;
04640                 return *this;
04641             }
04642             BOOST_UBLAS_INLINE
04643             const_iterator2 &operator += (difference_type n) {
04644                 it2_ += n;
04645                 return *this;
04646             }
04647             BOOST_UBLAS_INLINE
04648             const_iterator2 &operator -= (difference_type n) {
04649                 it2_ -= n;
04650                 return *this;
04651             }
04652             BOOST_UBLAS_INLINE
04653             difference_type operator - (const const_iterator2 &it) const {
04654                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
04655                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
04656                 return it2_ - it.it2_;
04657             }
04658 
04659             // Dereference
04660             BOOST_UBLAS_INLINE
04661             const_reference operator * () const {
04662                 return dereference (iterator_category ());
04663             }
04664             BOOST_UBLAS_INLINE
04665             const_reference operator [] (difference_type n) const {
04666                 return *(*this + n);
04667             }
04668 
04669 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
04670             BOOST_UBLAS_INLINE
04671 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
04672             typename self_type::
04673 #endif
04674             const_iterator1 begin () const {
04675                 return (*this) ().find1 (1, 0, index2 ());
04676             }
04677             BOOST_UBLAS_INLINE
04678 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
04679             typename self_type::
04680 #endif
04681             const_iterator1 end () const {
04682                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
04683             }
04684             BOOST_UBLAS_INLINE
04685 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
04686             typename self_type::
04687 #endif
04688             const_reverse_iterator1 rbegin () const {
04689                 return const_reverse_iterator1 (end ());
04690             }
04691             BOOST_UBLAS_INLINE
04692 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
04693             typename self_type::
04694 #endif
04695             const_reverse_iterator1 rend () const {
04696                 return const_reverse_iterator1 (begin ());
04697             }
04698 #endif
04699 
04700             // Indices
04701             BOOST_UBLAS_INLINE
04702             size_type index1 () const {
04703                 return it1_.index1 ();
04704             }
04705             BOOST_UBLAS_INLINE
04706             size_type index2 () const {
04707                 return it2_.index2 ();
04708             }
04709 
04710             // Assignment
04711             BOOST_UBLAS_INLINE
04712             const_iterator2 &operator = (const const_iterator2 &it) {
04713                 container_const_reference<self_type>::assign (&it ());
04714                 it1_ = it.it1_;
04715                 it2_ = it.it2_;
04716 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04717                 it1_begin_ = it.it1_begin_;
04718                 it1_end_ = it.it1_end_;
04719 #endif
04720                 return *this;
04721             }
04722 
04723             // Comparison
04724             BOOST_UBLAS_INLINE
04725             bool operator == (const const_iterator2 &it) const {
04726                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
04727                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
04728                 return it2_ == it.it2_;
04729             }
04730             BOOST_UBLAS_INLINE
04731             bool operator < (const const_iterator2 &it) const {
04732                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
04733                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
04734                 return it2_ < it.it2_;
04735             }
04736 
04737         private:
04738             // Mutable due to assignment
04739             /* const */ const_iterator11_type it1_;
04740             const_iterator22_type it2_;
04741 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
04742             /* const */ const_iterator12_type it1_begin_;
04743             /* const */ const_iterator12_type it1_end_;
04744 #endif
04745         };
04746 #endif
04747 
04748         BOOST_UBLAS_INLINE
04749         const_iterator2 begin2 () const {
04750             return find2 (0, 0, 0);
04751         }
04752         BOOST_UBLAS_INLINE
04753         const_iterator2 end2 () const {
04754             return find2 (0, 0, size2 ());
04755         }
04756 
04757         // Reverse iterators
04758 
04759         BOOST_UBLAS_INLINE
04760         const_reverse_iterator1 rbegin1 () const {
04761             return const_reverse_iterator1 (end1 ());
04762         }
04763         BOOST_UBLAS_INLINE
04764         const_reverse_iterator1 rend1 () const {
04765             return const_reverse_iterator1 (begin1 ());
04766         }
04767 
04768         BOOST_UBLAS_INLINE
04769         const_reverse_iterator2 rbegin2 () const {
04770             return const_reverse_iterator2 (end2 ());
04771         }
04772         BOOST_UBLAS_INLINE
04773         const_reverse_iterator2 rend2 () const {
04774             return const_reverse_iterator2 (begin2 ());
04775         }
04776 
04777     private:
04778         expression1_closure_type e1_;
04779         expression2_closure_type e2_;
04780     };
04781 
04782     template<class T1, class E1, class T2, class E2>
04783     struct matrix_matrix_binary_traits {
04784         typedef unknown_storage_tag storage_category;
04785         typedef unknown_orientation_tag orientation_category;
04786         typedef typename promote_traits<T1, T2>::promote_type promote_type;
04787         typedef matrix_matrix_binary<E1, E2, matrix_matrix_prod<E1, E2, promote_type> > expression_type;
04788 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
04789         typedef expression_type result_type;
04790 #else
04791         typedef typename E1::matrix_temporary_type result_type;
04792 #endif
04793     };
04794 
04795     template<class E1, class E2>
04796     BOOST_UBLAS_INLINE
04797     typename matrix_matrix_binary_traits<typename E1::value_type, E1,
04798                                          typename E2::value_type, E2>::result_type
04799     prod (const matrix_expression<E1> &e1,
04800           const matrix_expression<E2> &e2,
04801           unknown_storage_tag,
04802           unknown_orientation_tag) {
04803         typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1,
04804                                                      typename E2::value_type, E2>::expression_type expression_type;
04805         return expression_type (e1 (), e2 ());
04806     }
04807 
04808     // Dispatcher
04809     template<class E1, class E2>
04810     BOOST_UBLAS_INLINE
04811     typename matrix_matrix_binary_traits<typename E1::value_type, E1,
04812                                          typename E2::value_type, E2>::result_type
04813     prod (const matrix_expression<E1> &e1,
04814           const matrix_expression<E2> &e2) {
04815         BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0);
04816         typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1,
04817                                                      typename E2::value_type, E2>::storage_category storage_category;
04818         typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1,
04819                                                      typename E2::value_type, E2>::orientation_category orientation_category;
04820         return prod (e1, e2, storage_category (), orientation_category ());
04821     }
04822 
04823     template<class E1, class E2>
04824     BOOST_UBLAS_INLINE
04825     typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04826                                          typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
04827     prec_prod (const matrix_expression<E1> &e1,
04828                const matrix_expression<E2> &e2,
04829                unknown_storage_tag,
04830                unknown_orientation_tag) {
04831         typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04832                                                      typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type;
04833         return expression_type (e1 (), e2 ());
04834     }
04835 
04836     // Dispatcher
04837     template<class E1, class E2>
04838     BOOST_UBLAS_INLINE
04839     typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04840                                          typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
04841     prec_prod (const matrix_expression<E1> &e1,
04842                const matrix_expression<E2> &e2) {
04843         BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0);
04844         typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04845                                                      typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category;
04846         typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
04847                                                      typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category;
04848         return prec_prod (e1, e2, storage_category (), orientation_category ());
04849     }
04850 
04851     template<class M, class E1, class E2>
04852     BOOST_UBLAS_INLINE
04853     M &
04854     prod (const matrix_expression<E1> &e1,
04855           const matrix_expression<E2> &e2,
04856           M &m) {
04857         return m.assign (prod (e1, e2));
04858     }
04859 
04860     template<class M, class E1, class E2>
04861     BOOST_UBLAS_INLINE
04862     M &
04863     prec_prod (const matrix_expression<E1> &e1,
04864                const matrix_expression<E2> &e2,
04865                M &m) {
04866         return m.assign (prec_prod (e1, e2));
04867     }
04868 
04869     template<class M, class E1, class E2>
04870     BOOST_UBLAS_INLINE
04871     M
04872     prod (const matrix_expression<E1> &e1,
04873           const matrix_expression<E2> &e2) {
04874         return M (prod (e1, e2));
04875     }
04876 
04877     template<class M, class E1, class E2>
04878     BOOST_UBLAS_INLINE
04879     M
04880     prec_prod (const matrix_expression<E1> &e1,
04881                const matrix_expression<E2> &e2) {
04882         return M (prec_prod (e1, e2));
04883     }
04884 
04885     template<class E, class F>
04886     class matrix_scalar_unary:
04887         public scalar_expression<matrix_scalar_unary<E, F> > {
04888     public:
04889         typedef E expression_type;
04890         typedef F functor_type;
04891         typedef typename F::result_type value_type;
04892         typedef typename E::const_closure_type expression_closure_type;
04893 
04894         // Construction and destruction
04895         BOOST_UBLAS_INLINE
04896         explicit matrix_scalar_unary (const expression_type &e):
04897             e_ (e) {}
04898 
04899     private:
04900         // Expression accessors
04901         BOOST_UBLAS_INLINE
04902         const expression_closure_type &expression () const {
04903             return e_;
04904         }
04905 
04906     public:
04907         BOOST_UBLAS_INLINE
04908         operator value_type () const {
04909             return functor_type::apply (e_);
04910         }
04911 
04912     private:
04913         expression_closure_type e_;
04914     };
04915 
04916     template<class E, class F>
04917     struct matrix_scalar_unary_traits {
04918         typedef matrix_scalar_unary<E, F> expression_type;
04919 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
04920          typedef expression_type result_type;
04921 #else
04922          typedef typename F::result_type result_type;
04923 #endif
04924     };
04925 
04926     template<class E>
04927     BOOST_UBLAS_INLINE
04928     typename matrix_scalar_unary_traits<E, matrix_norm_1<E> >::result_type
04929     norm_1 (const matrix_expression<E> &e) {
04930         typedef typename matrix_scalar_unary_traits<E, matrix_norm_1<E> >::expression_type expression_type;
04931         return expression_type (e ());
04932     }
04933 
04934     template<class E>
04935     BOOST_UBLAS_INLINE
04936     typename matrix_scalar_unary_traits<E, matrix_norm_frobenius<E> >::result_type
04937     norm_frobenius (const matrix_expression<E> &e) {
04938         typedef typename matrix_scalar_unary_traits<E, matrix_norm_frobenius<E> >::expression_type expression_type;
04939         return expression_type (e ());
04940     }
04941 
04942     template<class E>
04943     BOOST_UBLAS_INLINE
04944     typename matrix_scalar_unary_traits<E, matrix_norm_inf<E> >::result_type
04945     norm_inf (const matrix_expression<E> &e) {
04946         typedef typename matrix_scalar_unary_traits<E, matrix_norm_inf<E> >::expression_type expression_type;
04947         return expression_type (e ());
04948     }
04949 
04950 }}}
04951 
04952 #endif