1 //
2 //  Copyright (c) 2000-2002
3 //  Joerg Walter, Mathias Koch
4 //
5 //  Permission to use, copy, modify, distribute and sell this software
6 //  and its documentation for any purpose is hereby granted without fee,
7 //  provided that the above copyright notice appear in all copies and
8 //  that both that copyright notice and this permission notice appear
9 //  in supporting documentation.  The authors make no representations
10 //  about the suitability of this software for any purpose.
11 //  It is provided "as is" without express or implied warranty.
12 //
13 //  The authors gratefully acknowledge the support of
14 //  GeNeSys mbH & Co. KG in producing this work.
15 //
16 
17 #ifndef _BOOST_UBLAS_MATRIX_EXPRESSION_
18 #define _BOOST_UBLAS_MATRIX_EXPRESSION_
19 
20 #include <boost/numeric/ublas/vector_expression.hpp>
21 
22 // Expression templates based on ideas of Todd Veldhuizen and Geoffrey Furnish
23 // Iterators based on ideas of Jeremy Siek
24 //
25 // Classes that model the Matrix Expression concept
26 
27 namespace boost { namespace numeric { namespace ublas {
28 
29     template<class E>
30     class matrix_reference:
31         public matrix_expression<matrix_reference<E> > {
32 
33         typedef matrix_reference<E> self_type;
34     public:
35 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
36         using matrix_expression<self_type>::operator ();
37 #endif
38         typedef typename E::size_type size_type;
39         typedef typename E::difference_type difference_type;
40         typedef typename E::value_type value_type;
41         typedef typename E::const_reference const_reference;
42         typedef typename boost::mpl::if_<boost::is_const<E>,
43                                           typename E::const_reference,
44                                           typename E::reference>::type reference;
45         typedef E refered_type;
46         typedef const self_type const_closure_type;
47         typedef const_closure_type closure_type;
48         typedef typename E::orientation_category orientation_category;
49         typedef typename E::storage_category storage_category;
50 
51         // Construction and destruction
52         BOOST_UBLAS_INLINE
matrix_reference(refered_type & e)53         explicit matrix_reference (refered_type &e):
54               e_ (e) {}
55 
56         // Accessors
57         BOOST_UBLAS_INLINE
size1() const58         size_type size1 () const {
59             return e_.size1 ();
60         }
61         BOOST_UBLAS_INLINE
size2() const62         size_type size2 () const {
63             return e_.size2 ();
64         }
65 
66     public:
67         // Expression accessors - const correct
68         BOOST_UBLAS_INLINE
expression() const69         const refered_type &expression () const {
70             return e_;
71         }
72         BOOST_UBLAS_INLINE
expression()73         refered_type &expression () {
74             return e_;
75         }
76 
77     public:
78         // Element access
79 #ifndef BOOST_UBLAS_REFERENCE_CONST_MEMBER
80         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j) const81         const_reference operator () (size_type i, size_type j) const {
82             return expression () (i, j);
83         }
84         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j)85         reference operator () (size_type i, size_type j) {
86             return expression () (i, j);
87         }
88 #else
89         BOOST_UBLAS_INLINE
90         reference operator () (size_type i, size_type j) const {
91             return expression () (i, j);
92         }
93 #endif
94 
95         // Assignment
96         BOOST_UBLAS_INLINE
operator =(const matrix_reference & m)97         matrix_reference &operator = (const matrix_reference &m) {
98             expression ().operator = (m);
99             return *this;
100         }
101         template<class AE>
102         BOOST_UBLAS_INLINE
operator =(const matrix_expression<AE> & ae)103         matrix_reference &operator = (const matrix_expression<AE> &ae) {
104             expression ().operator = (ae);
105             return *this;
106         }
107         template<class AE>
108         BOOST_UBLAS_INLINE
assign(const matrix_expression<AE> & ae)109         matrix_reference &assign (const matrix_expression<AE> &ae) {
110             expression ().assign (ae);
111             return *this;
112         }
113         template<class AE>
114         BOOST_UBLAS_INLINE
operator +=(const matrix_expression<AE> & ae)115         matrix_reference &operator += (const matrix_expression<AE> &ae) {
116             expression ().operator += (ae);
117             return *this;
118         }
119         template<class AE>
120         BOOST_UBLAS_INLINE
plus_assign(const matrix_expression<AE> & ae)121         matrix_reference &plus_assign (const matrix_expression<AE> &ae) {
122             expression ().plus_assign (ae);
123             return *this;
124         }
125         template<class AE>
126         BOOST_UBLAS_INLINE
operator -=(const matrix_expression<AE> & ae)127         matrix_reference &operator -= (const matrix_expression<AE> &ae) {
128             expression ().operator -= (ae);
129             return *this;
130         }
131         template<class AE>
132         BOOST_UBLAS_INLINE
minus_assign(const matrix_expression<AE> & ae)133         matrix_reference &minus_assign (const matrix_expression<AE> &ae) {
134             expression ().minus_assign (ae);
135             return *this;
136         }
137         template<class AT>
138         BOOST_UBLAS_INLINE
operator *=(const AT & at)139         matrix_reference &operator *= (const AT &at) {
140             expression ().operator *= (at);
141             return *this;
142         }
143         template<class AT>
144         BOOST_UBLAS_INLINE
operator /=(const AT & at)145         matrix_reference &operator /= (const AT &at) {
146             expression ().operator /= (at);
147             return *this;
148         }
149 
150          // Swapping
151         BOOST_UBLAS_INLINE
swap(matrix_reference & m)152         void swap (matrix_reference &m) {
153             expression ().swap (m.expression ());
154         }
155 
156         // Closure comparison
157         BOOST_UBLAS_INLINE
same_closure(const matrix_reference & mr) const158         bool same_closure (const matrix_reference &mr) const {
159             return &(*this).e_ == &mr.e_;
160         }
161 
162         // Iterator types
163         typedef typename E::const_iterator1 const_iterator1;
164         typedef typename boost::mpl::if_<boost::is_const<E>,
165                                           typename E::const_iterator1,
166                                           typename E::iterator1>::type iterator1;
167         typedef typename E::const_iterator2 const_iterator2;
168         typedef typename boost::mpl::if_<boost::is_const<E>,
169                                           typename E::const_iterator2,
170                                           typename E::iterator2>::type iterator2;
171 
172         // Element lookup
173         BOOST_UBLAS_INLINE
find1(int rank,size_type i,size_type j) const174         const_iterator1 find1 (int rank, size_type i, size_type j) const {
175             return expression ().find1 (rank, i, j);
176         }
177         BOOST_UBLAS_INLINE
find1(int rank,size_type i,size_type j)178         iterator1 find1 (int rank, size_type i, size_type j) {
179             return expression ().find1 (rank, i, j);
180         }
181         BOOST_UBLAS_INLINE
find2(int rank,size_type i,size_type j) const182         const_iterator2 find2 (int rank, size_type i, size_type j) const {
183             return expression ().find2 (rank, i, j);
184         }
185         BOOST_UBLAS_INLINE
find2(int rank,size_type i,size_type j)186         iterator2 find2 (int rank, size_type i, size_type j) {
187             return expression ().find2 (rank, i, j);
188         }
189 
190         // Iterators are the iterators of the referenced expression.
191 
192         BOOST_UBLAS_INLINE
begin1() const193         const_iterator1 begin1 () const {
194             return expression ().begin1 ();
195         }
196         BOOST_UBLAS_INLINE
end1() const197         const_iterator1 end1 () const {
198             return expression ().end1 ();
199         }
200 
201         BOOST_UBLAS_INLINE
begin1()202         iterator1 begin1 () {
203             return expression ().begin1 ();
204         }
205         BOOST_UBLAS_INLINE
end1()206         iterator1 end1 () {
207             return expression ().end1 ();
208         }
209 
210         BOOST_UBLAS_INLINE
begin2() const211         const_iterator2 begin2 () const {
212             return expression ().begin2 ();
213         }
214         BOOST_UBLAS_INLINE
end2() const215         const_iterator2 end2 () const {
216             return expression ().end2 ();
217         }
218 
219         BOOST_UBLAS_INLINE
begin2()220         iterator2 begin2 () {
221             return expression ().begin2 ();
222         }
223         BOOST_UBLAS_INLINE
end2()224         iterator2 end2 () {
225             return expression ().end2 ();
226         }
227 
228         // Reverse iterators
229         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
230         typedef reverse_iterator_base1<iterator1> reverse_iterator1;
231 
232         BOOST_UBLAS_INLINE
rbegin1() const233         const_reverse_iterator1 rbegin1 () const {
234             return const_reverse_iterator1 (end1 ());
235         }
236         BOOST_UBLAS_INLINE
rend1() const237         const_reverse_iterator1 rend1 () const {
238             return const_reverse_iterator1 (begin1 ());
239         }
240 
241         BOOST_UBLAS_INLINE
rbegin1()242         reverse_iterator1 rbegin1 () {
243             return reverse_iterator1 (end1 ());
244         }
245         BOOST_UBLAS_INLINE
rend1()246         reverse_iterator1 rend1 () {
247             return reverse_iterator1 (begin1 ());
248         }
249 
250         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
251         typedef reverse_iterator_base2<iterator2> reverse_iterator2;
252 
253         BOOST_UBLAS_INLINE
rbegin2() const254         const_reverse_iterator2 rbegin2 () const {
255             return const_reverse_iterator2 (end2 ());
256         }
257         BOOST_UBLAS_INLINE
rend2() const258         const_reverse_iterator2 rend2 () const {
259             return const_reverse_iterator2 (begin2 ());
260         }
261 
262         BOOST_UBLAS_INLINE
rbegin2()263         reverse_iterator2 rbegin2 () {
264             return reverse_iterator2 (end2 ());
265         }
266         BOOST_UBLAS_INLINE
rend2()267         reverse_iterator2 rend2 () {
268             return reverse_iterator2 (begin2 ());
269         }
270 
271     private:
272         refered_type &e_;
273     };
274 
275 
276     template<class E1, class E2, class F>
277     class vector_matrix_binary:
278         public matrix_expression<vector_matrix_binary<E1, E2, F> > {
279 
280         typedef E1 expression1_type;
281         typedef E2 expression2_type;
282     public:
283         typedef typename E1::const_closure_type expression1_closure_type;
284         typedef typename E2::const_closure_type expression2_closure_type;
285     private:
286         typedef vector_matrix_binary<E1, E2, F> self_type;
287     public:
288 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
289         using matrix_expression<self_type>::operator ();
290 #endif
291         typedef F functor_type;
292         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
293         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
294         typedef typename F::result_type value_type;
295         typedef value_type const_reference;
296         typedef const_reference reference;
297         typedef const self_type const_closure_type;
298         typedef const_closure_type closure_type;
299         typedef unknown_orientation_tag orientation_category;
300         typedef unknown_storage_tag storage_category;
301 
302         // Construction and destruction
303         BOOST_UBLAS_INLINE
vector_matrix_binary(const expression1_type & e1,const expression2_type & e2)304         vector_matrix_binary (const expression1_type &e1, const expression2_type &e2):
305             e1_ (e1), e2_ (e2) {}
306 
307         // Accessors
308         BOOST_UBLAS_INLINE
size1() const309         size_type size1 () const {
310             return e1_.size ();
311         }
312         BOOST_UBLAS_INLINE
size2() const313         size_type size2 () const {
314             return e2_.size ();
315         }
316 
317     public:
318         // Expression accessors
319         BOOST_UBLAS_INLINE
expression1() const320         const expression1_closure_type &expression1 () const {
321             return e1_;
322         }
323         BOOST_UBLAS_INLINE
expression2() const324         const expression2_closure_type &expression2 () const {
325             return e2_;
326         }
327 
328     public:
329         // Element access
330         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j) const331         const_reference operator () (size_type i, size_type j) const {
332             return functor_type::apply (e1_ (i), e2_ (j));
333         }
334 
335         // Closure comparison
336         BOOST_UBLAS_INLINE
same_closure(const vector_matrix_binary & vmb) const337         bool same_closure (const vector_matrix_binary &vmb) const {
338             return (*this).expression1 ().same_closure (vmb.expression1 ()) &&
339                    (*this).expression2 ().same_closure (vmb.expression2 ());
340         }
341 
342         // Iterator types
343     private:
344         typedef typename E1::const_iterator const_subiterator1_type;
345         typedef typename E2::const_iterator const_subiterator2_type;
346         typedef const value_type *const_pointer;
347 
348     public:
349 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
350         typedef typename iterator_restrict_traits<typename const_subiterator1_type::iterator_category,
351                                                   typename const_subiterator2_type::iterator_category>::iterator_category iterator_category;
352         typedef indexed_const_iterator1<const_closure_type, iterator_category> const_iterator1;
353         typedef const_iterator1 iterator1;
354         typedef indexed_const_iterator2<const_closure_type, iterator_category> const_iterator2;
355         typedef const_iterator2 iterator2;
356 #else
357         class const_iterator1;
358         typedef const_iterator1 iterator1;
359         class const_iterator2;
360         typedef const_iterator2 iterator2;
361 #endif
362         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
363         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
364 
365         // Element lookup
366         BOOST_UBLAS_INLINE
find1(int rank,size_type i,size_type j) const367         const_iterator1 find1 (int rank, size_type i, size_type j) const {
368             const_subiterator1_type it1 (e1_.find (i));
369             const_subiterator1_type it1_end (e1_.find (size1 ()));
370             const_subiterator2_type it2 (e2_.find (j));
371             const_subiterator2_type it2_end (e2_.find (size2 ()));
372             if (it2 == it2_end || (rank == 1 && (it2.index () != j || *it2 == value_type/*zero*/()))) {
373                 it1 = it1_end;
374                 it2 = it2_end;
375             }
376 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
377             return const_iterator1 (*this, it1.index (), it2.index ());
378 #else
379 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
380             return const_iterator1 (*this, it1, it2, it2 != it2_end ? *it2 : value_type/*zero*/());
381 #else
382             return const_iterator1 (*this, it1, it2);
383 #endif
384 #endif
385         }
386         BOOST_UBLAS_INLINE
find2(int rank,size_type i,size_type j) const387         const_iterator2 find2 (int rank, size_type i, size_type j) const {
388             const_subiterator2_type it2 (e2_.find (j));
389             const_subiterator2_type it2_end (e2_.find (size2 ()));
390             const_subiterator1_type it1 (e1_.find (i));
391             const_subiterator1_type it1_end (e1_.find (size1 ()));
392             if (it1 == it1_end || (rank == 1 && (it1.index () != i || *it1 == value_type/*zero*/()))) {
393                 it2 = it2_end;
394                 it1 = it1_end;
395             }
396 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
397             return const_iterator2 (*this, it1.index (), it2.index ());
398 #else
399 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
400             return const_iterator2 (*this, it1, it2, it1 != it1_end ? *it1 : value_type/*zero*/());
401 #else
402             return const_iterator2 (*this, it1, it2);
403 #endif
404 #endif
405         }
406 
407         // Iterators enhance the iterators of the referenced expressions
408         // with the binary functor.
409 
410 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
411         class const_iterator1:
412             public container_const_reference<vector_matrix_binary>,
413             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
414                                                                           typename E2::const_iterator::iterator_category>::iterator_category>::template
415                 iterator_base<const_iterator1, value_type>::type {
416         public:
417             typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
418                                                       typename E2::const_iterator::iterator_category>::iterator_category iterator_category;
419             typedef typename vector_matrix_binary::difference_type difference_type;
420             typedef typename vector_matrix_binary::value_type value_type;
421             typedef typename vector_matrix_binary::const_reference reference;
422             typedef typename vector_matrix_binary::const_pointer pointer;
423 
424             typedef const_iterator2 dual_iterator_type;
425             typedef const_reverse_iterator2 dual_reverse_iterator_type;
426 
427             // Construction and destruction
428 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
429             BOOST_UBLAS_INLINE
const_iterator1()430             const_iterator1 ():
431                 container_const_reference<self_type> (), it1_ (), it2_ (), t2_ () {}
432             BOOST_UBLAS_INLINE
const_iterator1(const self_type & vmb,const const_subiterator1_type & it1,const const_subiterator2_type & it2,value_type t2)433             const_iterator1 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2, value_type t2):
434                 container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2), t2_ (t2) {}
435 #else
436             BOOST_UBLAS_INLINE
const_iterator1()437             const_iterator1 ():
438                 container_const_reference<self_type> (), it1_ (), it2_ () {}
439             BOOST_UBLAS_INLINE
const_iterator1(const self_type & vmb,const const_subiterator1_type & it1,const const_subiterator2_type & it2)440             const_iterator1 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2):
441                 container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2) {}
442 #endif
443 
444             // Arithmetic
445             BOOST_UBLAS_INLINE
operator ++()446             const_iterator1 &operator ++ () {
447                 ++ it1_;
448                 return *this;
449             }
450             BOOST_UBLAS_INLINE
operator --()451             const_iterator1 &operator -- () {
452                 -- it1_;
453                 return *this;
454             }
455             BOOST_UBLAS_INLINE
operator +=(difference_type n)456             const_iterator1 &operator += (difference_type n) {
457                 it1_ += n;
458                 return *this;
459             }
460             BOOST_UBLAS_INLINE
operator -=(difference_type n)461             const_iterator1 &operator -= (difference_type n) {
462                 it1_ -= n;
463                 return *this;
464             }
465             BOOST_UBLAS_INLINE
operator -(const const_iterator1 & it) const466             difference_type operator - (const const_iterator1 &it) const {
467                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
468                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
469                 return it1_ - it.it1_;
470             }
471 
472             // Dereference
473             BOOST_UBLAS_INLINE
operator *() const474             const_reference operator * () const {
475 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
476                 return functor_type::apply (*it1_, t2_);
477 #else
478                 return functor_type::apply (*it1_, *it2_);
479 #endif
480             }
481 
482 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
483             BOOST_UBLAS_INLINE
484 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
485             typename self_type::
486 #endif
begin() const487             const_iterator2 begin () const {
488                 return (*this) ().find2 (1, index1 (), 0);
489             }
490             BOOST_UBLAS_INLINE
491 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
492             typename self_type::
493 #endif
end() const494             const_iterator2 end () const {
495                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
496             }
497             BOOST_UBLAS_INLINE
498 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
499             typename self_type::
500 #endif
rbegin() const501             const_reverse_iterator2 rbegin () const {
502                 return const_reverse_iterator2 (end ());
503             }
504             BOOST_UBLAS_INLINE
505 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
506             typename self_type::
507 #endif
rend() const508             const_reverse_iterator2 rend () const {
509                 return const_reverse_iterator2 (begin ());
510             }
511 #endif
512 
513             // Indices
514             BOOST_UBLAS_INLINE
index1() const515             size_type index1 () const {
516                 return it1_.index ();
517             }
518             BOOST_UBLAS_INLINE
index2() const519             size_type  index2 () const {
520                 return it2_.index ();
521             }
522 
523             // Assignment
524             BOOST_UBLAS_INLINE
operator =(const const_iterator1 & it)525             const_iterator1 &operator = (const const_iterator1 &it) {
526                 container_const_reference<self_type>::assign (&it ());
527                 it1_ = it.it1_;
528                 it2_ = it.it2_;
529 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
530                 t2_ = it.t2_;
531 #endif
532                 return *this;
533             }
534 
535             // Comparison
536             BOOST_UBLAS_INLINE
operator ==(const const_iterator1 & it) const537             bool operator == (const const_iterator1 &it) const {
538                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
539                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
540                 return it1_ == it.it1_;
541             }
542             BOOST_UBLAS_INLINE
operator <(const const_iterator1 & it) const543             bool operator < (const const_iterator1 &it) const {
544                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
545                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
546                 return it1_ < it.it1_;
547             }
548 
549         private:
550 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
551             const_subiterator1_type it1_;
552             // Mutable due to assignment
553             /* const */ const_subiterator2_type it2_;
554             value_type t2_;
555 #else
556             const_subiterator1_type it1_;
557             const_subiterator2_type it2_;
558 #endif
559         };
560 #endif
561 
562         BOOST_UBLAS_INLINE
begin1() const563         const_iterator1 begin1 () const {
564             return find1 (0, 0, 0);
565         }
566         BOOST_UBLAS_INLINE
end1() const567         const_iterator1 end1 () const {
568             return find1 (0, size1 (), 0);
569         }
570 
571 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
572         class const_iterator2:
573             public container_const_reference<vector_matrix_binary>,
574             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
575                                                                           typename E2::const_iterator::iterator_category>::iterator_category>::template
576                 iterator_base<const_iterator2, value_type>::type {
577         public:
578             typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
579                                                       typename E2::const_iterator::iterator_category>::iterator_category iterator_category;
580             typedef typename vector_matrix_binary::difference_type difference_type;
581             typedef typename vector_matrix_binary::value_type value_type;
582             typedef typename vector_matrix_binary::const_reference reference;
583             typedef typename vector_matrix_binary::const_pointer pointer;
584 
585             typedef const_iterator1 dual_iterator_type;
586             typedef const_reverse_iterator1 dual_reverse_iterator_type;
587 
588             // Construction and destruction
589 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
590             BOOST_UBLAS_INLINE
const_iterator2()591             const_iterator2 ():
592                 container_const_reference<self_type> (), it1_ (), it2_ (), t1_ () {}
593             BOOST_UBLAS_INLINE
const_iterator2(const self_type & vmb,const const_subiterator1_type & it1,const const_subiterator2_type & it2,value_type t1)594             const_iterator2 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2, value_type t1):
595                 container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2), t1_ (t1) {}
596 #else
597             BOOST_UBLAS_INLINE
const_iterator2()598             const_iterator2 ():
599                 container_const_reference<self_type> (), it1_ (), it2_ () {}
600             BOOST_UBLAS_INLINE
const_iterator2(const self_type & vmb,const const_subiterator1_type & it1,const const_subiterator2_type & it2)601             const_iterator2 (const self_type &vmb, const const_subiterator1_type &it1, const const_subiterator2_type &it2):
602                 container_const_reference<self_type> (vmb), it1_ (it1), it2_ (it2) {}
603 #endif
604 
605             // Arithmetic
606             BOOST_UBLAS_INLINE
operator ++()607             const_iterator2 &operator ++ () {
608                 ++ it2_;
609                 return *this;
610             }
611             BOOST_UBLAS_INLINE
operator --()612             const_iterator2 &operator -- () {
613                 -- it2_;
614                 return *this;
615             }
616             BOOST_UBLAS_INLINE
operator +=(difference_type n)617             const_iterator2 &operator += (difference_type n) {
618                 it2_ += n;
619                 return *this;
620             }
621             BOOST_UBLAS_INLINE
operator -=(difference_type n)622             const_iterator2 &operator -= (difference_type n) {
623                 it2_ -= n;
624                 return *this;
625             }
626             BOOST_UBLAS_INLINE
operator -(const const_iterator2 & it) const627             difference_type operator - (const const_iterator2 &it) const {
628                 BOOST_UBLAS_CHECK ((*this) ().same_closure(it ()), external_logic ());
629                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
630                 return it2_ - it.it2_;
631             }
632 
633             // Dereference
634             BOOST_UBLAS_INLINE
operator *() const635             const_reference operator * () const {
636 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
637                 return functor_type::apply (t1_, *it2_);
638 #else
639                 return functor_type::apply (*it1_, *it2_);
640 #endif
641             }
642 
643 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
644             BOOST_UBLAS_INLINE
645 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
646             typename self_type::
647 #endif
begin() const648             const_iterator1 begin () const {
649                 return (*this) ().find1 (1, 0, index2 ());
650             }
651             BOOST_UBLAS_INLINE
652 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
653             typename self_type::
654 #endif
end() const655             const_iterator1 end () const {
656                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
657             }
658             BOOST_UBLAS_INLINE
659 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
660             typename self_type::
661 #endif
rbegin() const662             const_reverse_iterator1 rbegin () const {
663                 return const_reverse_iterator1 (end ());
664             }
665             BOOST_UBLAS_INLINE
666 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
667             typename self_type::
668 #endif
rend() const669             const_reverse_iterator1 rend () const {
670                 return const_reverse_iterator1 (begin ());
671             }
672 #endif
673 
674             // Indices
675             BOOST_UBLAS_INLINE
index1() const676             size_type index1 () const {
677                 return it1_.index ();
678             }
679             BOOST_UBLAS_INLINE
index2() const680             size_type  index2 () const {
681                 return it2_.index ();
682             }
683 
684             // Assignment
685             BOOST_UBLAS_INLINE
operator =(const const_iterator2 & it)686             const_iterator2 &operator = (const const_iterator2 &it) {
687                 container_const_reference<self_type>::assign (&it ());
688                 it1_ = it.it1_;
689                 it2_ = it.it2_;
690 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
691                 t1_ = it.t1_;
692 #endif
693                 return *this;
694             }
695 
696             // Comparison
697             BOOST_UBLAS_INLINE
operator ==(const const_iterator2 & it) const698             bool operator == (const const_iterator2 &it) const {
699                 BOOST_UBLAS_CHECK ((*this) ().same_closure( it ()), external_logic ());
700                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
701                 return it2_ == it.it2_;
702             }
703             BOOST_UBLAS_INLINE
operator <(const const_iterator2 & it) const704             bool operator < (const const_iterator2 &it) const {
705                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
706                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
707                 return it2_ < it.it2_;
708             }
709 
710         private:
711 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
712             // Mutable due to assignment
713             /* const */ const_subiterator1_type it1_;
714             const_subiterator2_type it2_;
715             value_type t1_;
716 #else
717             const_subiterator1_type it1_;
718             const_subiterator2_type it2_;
719 #endif
720         };
721 #endif
722 
723         BOOST_UBLAS_INLINE
begin2() const724         const_iterator2 begin2 () const {
725             return find2 (0, 0, 0);
726         }
727         BOOST_UBLAS_INLINE
end2() const728         const_iterator2 end2 () const {
729             return find2 (0, 0, size2 ());
730         }
731 
732         // Reverse iterators
733 
734         BOOST_UBLAS_INLINE
rbegin1() const735         const_reverse_iterator1 rbegin1 () const {
736             return const_reverse_iterator1 (end1 ());
737         }
738         BOOST_UBLAS_INLINE
rend1() const739         const_reverse_iterator1 rend1 () const {
740             return const_reverse_iterator1 (begin1 ());
741         }
742 
743         BOOST_UBLAS_INLINE
rbegin2() const744         const_reverse_iterator2 rbegin2 () const {
745             return const_reverse_iterator2 (end2 ());
746         }
747         BOOST_UBLAS_INLINE
rend2() const748         const_reverse_iterator2 rend2 () const {
749             return const_reverse_iterator2 (begin2 ());
750         }
751 
752     private:
753         expression1_closure_type e1_;
754         expression2_closure_type e2_;
755     };
756 
757     template<class E1, class E2, class F>
758     struct vector_matrix_binary_traits {
759         typedef vector_matrix_binary<E1, E2, F> expression_type;
760 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
761         typedef expression_type result_type;
762 #else
763         // ISSUE matrix is arbitary temporary type
764         typedef matrix<typename F::value_type> result_type;
765 #endif
766     };
767 
768     // (outer_prod (v1, v2)) [i] [j] = v1 [i] * v2 [j]
769     template<class E1, class E2>
770     BOOST_UBLAS_INLINE
771     typename vector_matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, typename E2::value_type> >::result_type
outer_prod(const vector_expression<E1> & e1,const vector_expression<E2> & e2)772     outer_prod (const vector_expression<E1> &e1,
773                 const vector_expression<E2> &e2) {
774         BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0);
775         typedef typename vector_matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type, typename E2::value_type> >::expression_type expression_type;
776         return expression_type (e1 (), e2 ());
777     }
778 
779     template<class E, class F>
780     class matrix_unary1:
781         public matrix_expression<matrix_unary1<E, F> > {
782 
783         typedef E expression_type;
784         typedef F functor_type;
785     public:
786         typedef typename E::const_closure_type expression_closure_type;
787     private:
788         typedef matrix_unary1<E, F> self_type;
789     public:
790 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
791         using matrix_expression<self_type>::operator ();
792 #endif
793         typedef typename E::size_type size_type;
794         typedef typename E::difference_type difference_type;
795         typedef typename F::result_type value_type;
796         typedef value_type const_reference;
797         typedef const_reference reference;
798         typedef const self_type const_closure_type;
799         typedef const_closure_type closure_type;
800         typedef typename E::orientation_category orientation_category;
801         typedef unknown_storage_tag storage_category;
802 
803         // Construction and destruction
804         BOOST_UBLAS_INLINE
matrix_unary1(const expression_type & e)805         explicit matrix_unary1 (const expression_type &e):
806             e_ (e) {}
807 
808         // Accessors
809         BOOST_UBLAS_INLINE
size1() const810         size_type size1 () const {
811             return e_.size1 ();
812         }
813         BOOST_UBLAS_INLINE
size2() const814         size_type size2 () const {
815             return e_.size2 ();
816         }
817 
818     public:
819         // Expression accessors
820         BOOST_UBLAS_INLINE
expression() const821         const expression_closure_type &expression () const {
822             return e_;
823         }
824 
825     public:
826         // Element access
827         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j) const828         const_reference operator () (size_type i, size_type j) const {
829             return functor_type::apply (e_ (i, j));
830         }
831 
832         // Closure comparison
833         BOOST_UBLAS_INLINE
same_closure(const matrix_unary1 & mu1) const834         bool same_closure (const matrix_unary1 &mu1) const {
835             return (*this).expression ().same_closure (mu1.expression ());
836         }
837 
838         // Iterator types
839     private:
840         typedef typename E::const_iterator1 const_subiterator1_type;
841         typedef typename E::const_iterator2 const_subiterator2_type;
842         typedef const value_type *const_pointer;
843 
844     public:
845 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
846         typedef indexed_const_iterator1<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator1;
847         typedef const_iterator1 iterator1;
848         typedef indexed_const_iterator2<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator2;
849         typedef const_iterator2 iterator2;
850 #else
851         class const_iterator1;
852         typedef const_iterator1 iterator1;
853         class const_iterator2;
854         typedef const_iterator2 iterator2;
855 #endif
856         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
857         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
858 
859         // Element lookup
860         BOOST_UBLAS_INLINE
find1(int rank,size_type i,size_type j) const861         const_iterator1 find1 (int rank, size_type i, size_type j) const {
862             const_subiterator1_type it1 (e_.find1 (rank, i, j));
863 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
864             return const_iterator1 (*this, it1.index1 (), it1.index2 ());
865 #else
866             return const_iterator1 (*this, it1);
867 #endif
868         }
869         BOOST_UBLAS_INLINE
find2(int rank,size_type i,size_type j) const870         const_iterator2 find2 (int rank, size_type i, size_type j) const {
871             const_subiterator2_type it2 (e_.find2 (rank, i, j));
872 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
873             return const_iterator2 (*this, it2.index1 (), it2.index2 ());
874 #else
875             return const_iterator2 (*this, it2);
876 #endif
877         }
878 
879         // Iterators enhance the iterators of the referenced expression
880         // with the unary functor.
881 
882 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
883         class const_iterator1:
884             public container_const_reference<matrix_unary1>,
885             public iterator_base_traits<typename E::const_iterator1::iterator_category>::template
886                 iterator_base<const_iterator1, value_type>::type {
887         public:
888             typedef typename E::const_iterator1::iterator_category iterator_category;
889             typedef typename matrix_unary1::difference_type difference_type;
890             typedef typename matrix_unary1::value_type value_type;
891             typedef typename matrix_unary1::const_reference reference;
892             typedef typename matrix_unary1::const_pointer pointer;
893 
894             typedef const_iterator2 dual_iterator_type;
895             typedef const_reverse_iterator2 dual_reverse_iterator_type;
896 
897             // Construction and destruction
898             BOOST_UBLAS_INLINE
const_iterator1()899             const_iterator1 ():
900                 container_const_reference<self_type> (), it_ () {}
901             BOOST_UBLAS_INLINE
const_iterator1(const self_type & mu,const const_subiterator1_type & it)902             const_iterator1 (const self_type &mu, const const_subiterator1_type &it):
903                 container_const_reference<self_type> (mu), it_ (it) {}
904 
905             // Arithmetic
906             BOOST_UBLAS_INLINE
operator ++()907             const_iterator1 &operator ++ () {
908                 ++ it_;
909                 return *this;
910             }
911             BOOST_UBLAS_INLINE
operator --()912             const_iterator1 &operator -- () {
913                 -- it_;
914                 return *this;
915             }
916             BOOST_UBLAS_INLINE
operator +=(difference_type n)917             const_iterator1 &operator += (difference_type n) {
918                 it_ += n;
919                 return *this;
920             }
921             BOOST_UBLAS_INLINE
operator -=(difference_type n)922             const_iterator1 &operator -= (difference_type n) {
923                 it_ -= n;
924                 return *this;
925             }
926             BOOST_UBLAS_INLINE
operator -(const const_iterator1 & it) const927             difference_type operator - (const const_iterator1 &it) const {
928                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
929                 return it_ - it.it_;
930             }
931 
932             // Dereference
933             BOOST_UBLAS_INLINE
operator *() const934             const_reference operator * () const {
935                 return functor_type::apply (*it_);
936             }
937 
938 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
939             BOOST_UBLAS_INLINE
940 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
941             typename self_type::
942 #endif
begin() const943             const_iterator2 begin () const {
944                 return (*this) ().find2 (1, index1 (), 0);
945             }
946             BOOST_UBLAS_INLINE
947 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
948             typename self_type::
949 #endif
end() const950             const_iterator2 end () const {
951                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
952             }
953             BOOST_UBLAS_INLINE
954 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
955             typename self_type::
956 #endif
rbegin() const957             const_reverse_iterator2 rbegin () const {
958                 return const_reverse_iterator2 (end ());
959             }
960             BOOST_UBLAS_INLINE
961 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
962             typename self_type::
963 #endif
rend() const964             const_reverse_iterator2 rend () const {
965                 return const_reverse_iterator2 (begin ());
966             }
967 #endif
968 
969             // Indices
970             BOOST_UBLAS_INLINE
index1() const971             size_type index1 () const {
972                 return it_.index1 ();
973             }
974             BOOST_UBLAS_INLINE
index2() const975             size_type index2 () const {
976                 return it_.index2 ();
977             }
978 
979             // Assignment
980             BOOST_UBLAS_INLINE
operator =(const const_iterator1 & it)981             const_iterator1 &operator = (const const_iterator1 &it) {
982                 container_const_reference<self_type>::assign (&it ());
983                 it_ = it.it_;
984                 return *this;
985             }
986 
987             // Comparison
988             BOOST_UBLAS_INLINE
operator ==(const const_iterator1 & it) const989             bool operator == (const const_iterator1 &it) const {
990                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
991                 return it_ == it.it_;
992             }
993             BOOST_UBLAS_INLINE
operator <(const const_iterator1 & it) const994             bool operator < (const const_iterator1 &it) const {
995                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
996                 return it_ < it.it_;
997             }
998 
999         private:
1000             const_subiterator1_type it_;
1001         };
1002 #endif
1003 
1004         BOOST_UBLAS_INLINE
begin1() const1005         const_iterator1 begin1 () const {
1006             return find1 (0, 0, 0);
1007         }
1008         BOOST_UBLAS_INLINE
end1() const1009         const_iterator1 end1 () const {
1010             return find1 (0, size1 (), 0);
1011         }
1012 
1013 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
1014         class const_iterator2:
1015             public container_const_reference<matrix_unary1>,
1016             public iterator_base_traits<typename E::const_iterator2::iterator_category>::template
1017                 iterator_base<const_iterator2, value_type>::type {
1018         public:
1019             typedef typename E::const_iterator2::iterator_category iterator_category;
1020             typedef typename matrix_unary1::difference_type difference_type;
1021             typedef typename matrix_unary1::value_type value_type;
1022             typedef typename matrix_unary1::const_reference reference;
1023             typedef typename matrix_unary1::const_pointer pointer;
1024 
1025             typedef const_iterator1 dual_iterator_type;
1026             typedef const_reverse_iterator1 dual_reverse_iterator_type;
1027 
1028             // Construction and destruction
1029             BOOST_UBLAS_INLINE
const_iterator2()1030             const_iterator2 ():
1031                 container_const_reference<self_type> (), it_ () {}
1032             BOOST_UBLAS_INLINE
const_iterator2(const self_type & mu,const const_subiterator2_type & it)1033             const_iterator2 (const self_type &mu, const const_subiterator2_type &it):
1034                 container_const_reference<self_type> (mu), it_ (it) {}
1035 
1036             // Arithmetic
1037             BOOST_UBLAS_INLINE
operator ++()1038             const_iterator2 &operator ++ () {
1039                 ++ it_;
1040                 return *this;
1041             }
1042             BOOST_UBLAS_INLINE
operator --()1043             const_iterator2 &operator -- () {
1044                 -- it_;
1045                 return *this;
1046             }
1047             BOOST_UBLAS_INLINE
operator +=(difference_type n)1048             const_iterator2 &operator += (difference_type n) {
1049                 it_ += n;
1050                 return *this;
1051             }
1052             BOOST_UBLAS_INLINE
operator -=(difference_type n)1053             const_iterator2 &operator -= (difference_type n) {
1054                 it_ -= n;
1055                 return *this;
1056             }
1057             BOOST_UBLAS_INLINE
operator -(const const_iterator2 & it) const1058             difference_type operator - (const const_iterator2 &it) const {
1059                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1060                 return it_ - it.it_;
1061             }
1062 
1063             // Dereference
1064             BOOST_UBLAS_INLINE
operator *() const1065             const_reference operator * () const {
1066                 return functor_type::apply (*it_);
1067             }
1068 
1069 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1070             BOOST_UBLAS_INLINE
1071 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1072             typename self_type::
1073 #endif
begin() const1074             const_iterator1 begin () const {
1075                 return (*this) ().find1 (1, 0, index2 ());
1076             }
1077             BOOST_UBLAS_INLINE
1078 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1079             typename self_type::
1080 #endif
end() const1081             const_iterator1 end () const {
1082                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
1083             }
1084             BOOST_UBLAS_INLINE
1085 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1086             typename self_type::
1087 #endif
rbegin() const1088             const_reverse_iterator1 rbegin () const {
1089                 return const_reverse_iterator1 (end ());
1090             }
1091             BOOST_UBLAS_INLINE
1092 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1093             typename self_type::
1094 #endif
rend() const1095             const_reverse_iterator1 rend () const {
1096                 return const_reverse_iterator1 (begin ());
1097             }
1098 #endif
1099 
1100             // Indices
1101             BOOST_UBLAS_INLINE
index1() const1102             size_type index1 () const {
1103                 return it_.index1 ();
1104             }
1105             BOOST_UBLAS_INLINE
index2() const1106             size_type index2 () const {
1107                 return it_.index2 ();
1108             }
1109 
1110             // Assignment
1111             BOOST_UBLAS_INLINE
operator =(const const_iterator2 & it)1112             const_iterator2 &operator = (const const_iterator2 &it) {
1113                 container_const_reference<self_type>::assign (&it ());
1114                 it_ = it.it_;
1115                 return *this;
1116             }
1117 
1118             // Comparison
1119             BOOST_UBLAS_INLINE
operator ==(const const_iterator2 & it) const1120             bool operator == (const const_iterator2 &it) const {
1121                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1122                 return it_ == it.it_;
1123             }
1124             BOOST_UBLAS_INLINE
operator <(const const_iterator2 & it) const1125             bool operator < (const const_iterator2 &it) const {
1126                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1127                 return it_ < it.it_;
1128             }
1129 
1130         private:
1131             const_subiterator2_type it_;
1132         };
1133 #endif
1134 
1135         BOOST_UBLAS_INLINE
begin2() const1136         const_iterator2 begin2 () const {
1137             return find2 (0, 0, 0);
1138         }
1139         BOOST_UBLAS_INLINE
end2() const1140         const_iterator2 end2 () const {
1141             return find2 (0, 0, size2 ());
1142         }
1143 
1144         // Reverse iterators
1145 
1146         BOOST_UBLAS_INLINE
rbegin1() const1147         const_reverse_iterator1 rbegin1 () const {
1148             return const_reverse_iterator1 (end1 ());
1149         }
1150         BOOST_UBLAS_INLINE
rend1() const1151         const_reverse_iterator1 rend1 () const {
1152             return const_reverse_iterator1 (begin1 ());
1153         }
1154 
1155         BOOST_UBLAS_INLINE
rbegin2() const1156         const_reverse_iterator2 rbegin2 () const {
1157             return const_reverse_iterator2 (end2 ());
1158         }
1159         BOOST_UBLAS_INLINE
rend2() const1160         const_reverse_iterator2 rend2 () const {
1161             return const_reverse_iterator2 (begin2 ());
1162         }
1163 
1164     private:
1165         expression_closure_type e_;
1166     };
1167 
1168     template<class E, class F>
1169     struct matrix_unary1_traits {
1170         typedef matrix_unary1<E, F> expression_type;
1171 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
1172         typedef expression_type result_type;
1173 #else
1174         typedef typename E::matrix_temporary_type result_type;
1175 #endif
1176     };
1177 
1178     // (- m) [i] [j] = - m [i] [j]
1179     template<class E>
1180     BOOST_UBLAS_INLINE
1181     typename matrix_unary1_traits<E, scalar_negate<typename E::value_type> >::result_type
operator -(const matrix_expression<E> & e)1182     operator - (const matrix_expression<E> &e) {
1183         typedef typename matrix_unary1_traits<E, scalar_negate<typename E::value_type> >::expression_type expression_type;
1184         return expression_type (e ());
1185     }
1186 
1187     // (conj m) [i] [j] = conj (m [i] [j])
1188     template<class E>
1189     BOOST_UBLAS_INLINE
1190     typename matrix_unary1_traits<E, scalar_conj<typename E::value_type> >::result_type
conj(const matrix_expression<E> & e)1191     conj (const matrix_expression<E> &e) {
1192         typedef typename matrix_unary1_traits<E, scalar_conj<typename E::value_type> >::expression_type expression_type;
1193         return expression_type (e ());
1194     }
1195 
1196     // (real m) [i] [j] = real (m [i] [j])
1197     template<class E>
1198     BOOST_UBLAS_INLINE
1199     typename matrix_unary1_traits<E, scalar_real<typename E::value_type> >::result_type
real(const matrix_expression<E> & e)1200     real (const matrix_expression<E> &e) {
1201         typedef typename matrix_unary1_traits<E, scalar_real<typename E::value_type> >::expression_type expression_type;
1202         return expression_type (e ());
1203     }
1204 
1205     // (imag m) [i] [j] = imag (m [i] [j])
1206     template<class E>
1207     BOOST_UBLAS_INLINE
1208     typename matrix_unary1_traits<E, scalar_imag<typename E::value_type> >::result_type
imag(const matrix_expression<E> & e)1209     imag (const matrix_expression<E> &e) {
1210         typedef typename matrix_unary1_traits<E, scalar_imag<typename E::value_type> >::expression_type expression_type;
1211         return expression_type (e ());
1212     }
1213 
1214     template<class E, class F>
1215     class matrix_unary2:
1216         public matrix_expression<matrix_unary2<E, F> > {
1217 
1218         typedef typename boost::mpl::if_<boost::is_same<F, scalar_identity<typename E::value_type> >,
1219                                           E,
1220                                           const E>::type expression_type;
1221         typedef F functor_type;
1222     public:
1223         typedef typename boost::mpl::if_<boost::is_const<expression_type>,
1224                                           typename E::const_closure_type,
1225                                           typename E::closure_type>::type expression_closure_type;
1226     private:
1227         typedef matrix_unary2<E, F> self_type;
1228     public:
1229 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
1230         using matrix_expression<self_type>::operator ();
1231 #endif
1232         typedef typename E::size_type size_type;
1233         typedef typename E::difference_type difference_type;
1234         typedef typename F::result_type value_type;
1235         typedef value_type const_reference;
1236         typedef typename boost::mpl::if_<boost::is_same<F, scalar_identity<value_type> >,
1237                                           typename E::reference,
1238                                           value_type>::type reference;
1239 
1240         typedef const self_type const_closure_type;
1241         typedef self_type closure_type;
1242         // typedef typename E::orientation_category orientation_category;
1243         typedef typename boost::mpl::if_<boost::is_same<typename E::orientation_category,
1244                                                          row_major_tag>,
1245                                           column_major_tag,
1246                 typename boost::mpl::if_<boost::is_same<typename E::orientation_category,
1247                                                          column_major_tag>,
1248                                           row_major_tag,
1249                                           typename E::orientation_category>::type>::type orientation_category;
1250         // typedef unknown_storage_tag storage_category;
1251         typedef typename E::storage_category storage_category;
1252 
1253         // Construction and destruction
1254         BOOST_UBLAS_INLINE
1255         // ISSUE may be used as mutable expression.
1256         // matrix_unary2 (const expression_type &e):
matrix_unary2(expression_type & e)1257         explicit matrix_unary2 (expression_type &e):
1258             e_ (e) {}
1259 
1260         // Accessors
1261         BOOST_UBLAS_INLINE
size1() const1262         size_type size1 () const {
1263             return e_.size2 ();
1264         }
1265         BOOST_UBLAS_INLINE
size2() const1266         size_type size2 () const {
1267             return e_.size1 ();
1268         }
1269 
1270     public:
1271         // Expression accessors
1272         BOOST_UBLAS_INLINE
expression() const1273         const expression_closure_type &expression () const {
1274             return e_;
1275         }
1276 
1277     public:
1278         // Element access
1279         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j) const1280         const_reference operator () (size_type i, size_type j) const {
1281             return functor_type::apply (e_ (j, i));
1282         }
1283         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j)1284         reference operator () (size_type i, size_type j) {
1285             BOOST_STATIC_ASSERT ((boost::is_same<functor_type, scalar_identity<value_type > >::value));
1286             return e_ (j, i);
1287         }
1288 
1289         // Closure comparison
1290         BOOST_UBLAS_INLINE
same_closure(const matrix_unary2 & mu2) const1291         bool same_closure (const matrix_unary2 &mu2) const {
1292             return (*this).expression ().same_closure (mu2.expression ());
1293         }
1294 
1295         // Iterator types
1296     private:
1297         typedef typename E::const_iterator1 const_subiterator2_type;
1298         typedef typename E::const_iterator2 const_subiterator1_type;
1299         typedef const value_type *const_pointer;
1300 
1301     public:
1302 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1303         typedef indexed_const_iterator1<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator1;
1304         typedef const_iterator1 iterator1;
1305         typedef indexed_const_iterator2<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator2;
1306         typedef const_iterator2 iterator2;
1307 #else
1308         class const_iterator1;
1309         typedef const_iterator1 iterator1;
1310         class const_iterator2;
1311         typedef const_iterator2 iterator2;
1312 #endif
1313         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
1314         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
1315 
1316         // Element lookup
1317         BOOST_UBLAS_INLINE
find1(int rank,size_type i,size_type j) const1318         const_iterator1 find1 (int rank, size_type i, size_type j) const {
1319             const_subiterator1_type it1 (e_.find2 (rank, j, i));
1320 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1321             return const_iterator1 (*this, it1.index2 (), it1.index1 ());
1322 #else
1323             return const_iterator1 (*this, it1);
1324 #endif
1325         }
1326         BOOST_UBLAS_INLINE
find2(int rank,size_type i,size_type j) const1327         const_iterator2 find2 (int rank, size_type i, size_type j) const {
1328             const_subiterator2_type it2 (e_.find1 (rank, j, i));
1329 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1330             return const_iterator2 (*this, it2.index2 (), it2.index1 ());
1331 #else
1332             return const_iterator2 (*this, it2);
1333 #endif
1334         }
1335 
1336         // Iterators enhance the iterators of the referenced expression
1337         // with the unary functor.
1338 
1339 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
1340         class const_iterator1:
1341             public container_const_reference<matrix_unary2>,
1342             public iterator_base_traits<typename E::const_iterator2::iterator_category>::template
1343                 iterator_base<const_iterator1, value_type>::type {
1344         public:
1345             typedef typename E::const_iterator2::iterator_category iterator_category;
1346             typedef typename matrix_unary2::difference_type difference_type;
1347             typedef typename matrix_unary2::value_type value_type;
1348             typedef typename matrix_unary2::const_reference reference;
1349             typedef typename matrix_unary2::const_pointer pointer;
1350 
1351             typedef const_iterator2 dual_iterator_type;
1352             typedef const_reverse_iterator2 dual_reverse_iterator_type;
1353 
1354             // Construction and destruction
1355             BOOST_UBLAS_INLINE
const_iterator1()1356             const_iterator1 ():
1357                 container_const_reference<self_type> (), it_ () {}
1358             BOOST_UBLAS_INLINE
const_iterator1(const self_type & mu,const const_subiterator1_type & it)1359             const_iterator1 (const self_type &mu, const const_subiterator1_type &it):
1360                 container_const_reference<self_type> (mu), it_ (it) {}
1361 
1362             // Arithmetic
1363             BOOST_UBLAS_INLINE
operator ++()1364             const_iterator1 &operator ++ () {
1365                 ++ it_;
1366                 return *this;
1367             }
1368             BOOST_UBLAS_INLINE
operator --()1369             const_iterator1 &operator -- () {
1370                 -- it_;
1371                 return *this;
1372             }
1373             BOOST_UBLAS_INLINE
operator +=(difference_type n)1374             const_iterator1 &operator += (difference_type n) {
1375                 it_ += n;
1376                 return *this;
1377             }
1378             BOOST_UBLAS_INLINE
operator -=(difference_type n)1379             const_iterator1 &operator -= (difference_type n) {
1380                 it_ -= n;
1381                 return *this;
1382             }
1383             BOOST_UBLAS_INLINE
operator -(const const_iterator1 & it) const1384             difference_type operator - (const const_iterator1 &it) const {
1385                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1386                 return it_ - it.it_;
1387             }
1388 
1389             // Dereference
1390             BOOST_UBLAS_INLINE
operator *() const1391             const_reference operator * () const {
1392                 return functor_type::apply (*it_);
1393             }
1394 
1395 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1396             BOOST_UBLAS_INLINE
1397 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1398             typename self_type::
1399 #endif
begin() const1400             const_iterator2 begin () const {
1401                 return (*this) ().find2 (1, index1 (), 0);
1402             }
1403             BOOST_UBLAS_INLINE
1404 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1405             typename self_type::
1406 #endif
end() const1407             const_iterator2 end () const {
1408                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
1409             }
1410             BOOST_UBLAS_INLINE
1411 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1412             typename self_type::
1413 #endif
rbegin() const1414             const_reverse_iterator2 rbegin () const {
1415                 return const_reverse_iterator2 (end ());
1416             }
1417             BOOST_UBLAS_INLINE
1418 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1419             typename self_type::
1420 #endif
rend() const1421             const_reverse_iterator2 rend () const {
1422                 return const_reverse_iterator2 (begin ());
1423             }
1424 #endif
1425 
1426             // Indices
1427             BOOST_UBLAS_INLINE
index1() const1428             size_type index1 () const {
1429                 return it_.index2 ();
1430             }
1431             BOOST_UBLAS_INLINE
index2() const1432             size_type index2 () const {
1433                 return it_.index1 ();
1434             }
1435 
1436             // Assignment
1437             BOOST_UBLAS_INLINE
operator =(const const_iterator1 & it)1438             const_iterator1 &operator = (const const_iterator1 &it) {
1439                 container_const_reference<self_type>::assign (&it ());
1440                 it_ = it.it_;
1441                 return *this;
1442             }
1443 
1444             // Comparison
1445             BOOST_UBLAS_INLINE
operator ==(const const_iterator1 & it) const1446             bool operator == (const const_iterator1 &it) const {
1447                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1448                 return it_ == it.it_;
1449             }
1450             BOOST_UBLAS_INLINE
operator <(const const_iterator1 & it) const1451             bool operator < (const const_iterator1 &it) const {
1452                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1453                 return it_ < it.it_;
1454             }
1455 
1456         private:
1457             const_subiterator1_type it_;
1458         };
1459 #endif
1460 
1461         BOOST_UBLAS_INLINE
begin1() const1462         const_iterator1 begin1 () const {
1463             return find1 (0, 0, 0);
1464         }
1465         BOOST_UBLAS_INLINE
end1() const1466         const_iterator1 end1 () const {
1467             return find1 (0, size1 (), 0);
1468         }
1469 
1470 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
1471         class const_iterator2:
1472             public container_const_reference<matrix_unary2>,
1473             public iterator_base_traits<typename E::const_iterator1::iterator_category>::template
1474                 iterator_base<const_iterator2, value_type>::type {
1475         public:
1476             typedef typename E::const_iterator1::iterator_category iterator_category;
1477             typedef typename matrix_unary2::difference_type difference_type;
1478             typedef typename matrix_unary2::value_type value_type;
1479             typedef typename matrix_unary2::const_reference reference;
1480             typedef typename matrix_unary2::const_pointer pointer;
1481 
1482             typedef const_iterator1 dual_iterator_type;
1483             typedef const_reverse_iterator1 dual_reverse_iterator_type;
1484 
1485             // Construction and destruction
1486             BOOST_UBLAS_INLINE
const_iterator2()1487             const_iterator2 ():
1488                 container_const_reference<self_type> (), it_ () {}
1489             BOOST_UBLAS_INLINE
const_iterator2(const self_type & mu,const const_subiterator2_type & it)1490             const_iterator2 (const self_type &mu, const const_subiterator2_type &it):
1491                 container_const_reference<self_type> (mu), it_ (it) {}
1492 
1493             // Arithmetic
1494             BOOST_UBLAS_INLINE
operator ++()1495             const_iterator2 &operator ++ () {
1496                 ++ it_;
1497                 return *this;
1498             }
1499             BOOST_UBLAS_INLINE
operator --()1500             const_iterator2 &operator -- () {
1501                 -- it_;
1502                 return *this;
1503             }
1504             BOOST_UBLAS_INLINE
operator +=(difference_type n)1505             const_iterator2 &operator += (difference_type n) {
1506                 it_ += n;
1507                 return *this;
1508             }
1509             BOOST_UBLAS_INLINE
operator -=(difference_type n)1510             const_iterator2 &operator -= (difference_type n) {
1511                 it_ -= n;
1512                 return *this;
1513             }
1514             BOOST_UBLAS_INLINE
operator -(const const_iterator2 & it) const1515             difference_type operator - (const const_iterator2 &it) const {
1516                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1517                 return it_ - it.it_;
1518             }
1519 
1520             // Dereference
1521             BOOST_UBLAS_INLINE
operator *() const1522             const_reference operator * () const {
1523                 return functor_type::apply (*it_);
1524             }
1525 
1526 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1527             BOOST_UBLAS_INLINE
1528 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1529             typename self_type::
1530 #endif
begin() const1531             const_iterator1 begin () const {
1532                 return (*this) ().find1 (1, 0, index2 ());
1533             }
1534             BOOST_UBLAS_INLINE
1535 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1536             typename self_type::
1537 #endif
end() const1538             const_iterator1 end () const {
1539                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
1540             }
1541             BOOST_UBLAS_INLINE
1542 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1543             typename self_type::
1544 #endif
rbegin() const1545             const_reverse_iterator1 rbegin () const {
1546                 return const_reverse_iterator1 (end ());
1547             }
1548             BOOST_UBLAS_INLINE
1549 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1550             typename self_type::
1551 #endif
rend() const1552             const_reverse_iterator1 rend () const {
1553                 return const_reverse_iterator1 (begin ());
1554             }
1555 #endif
1556 
1557             // Indices
1558             BOOST_UBLAS_INLINE
index1() const1559             size_type index1 () const {
1560                 return it_.index2 ();
1561             }
1562             BOOST_UBLAS_INLINE
index2() const1563             size_type index2 () const {
1564                 return it_.index1 ();
1565             }
1566 
1567             // Assignment
1568             BOOST_UBLAS_INLINE
operator =(const const_iterator2 & it)1569             const_iterator2 &operator = (const const_iterator2 &it) {
1570                 container_const_reference<self_type>::assign (&it ());
1571                 it_ = it.it_;
1572                 return *this;
1573             }
1574 
1575             // Comparison
1576             BOOST_UBLAS_INLINE
operator ==(const const_iterator2 & it) const1577             bool operator == (const const_iterator2 &it) const {
1578                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1579                 return it_ == it.it_;
1580             }
1581             BOOST_UBLAS_INLINE
operator <(const const_iterator2 & it) const1582             bool operator < (const const_iterator2 &it) const {
1583                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1584                 return it_ < it.it_;
1585             }
1586 
1587         private:
1588             const_subiterator2_type it_;
1589         };
1590 #endif
1591 
1592         BOOST_UBLAS_INLINE
begin2() const1593         const_iterator2 begin2 () const {
1594             return find2 (0, 0, 0);
1595         }
1596         BOOST_UBLAS_INLINE
end2() const1597         const_iterator2 end2 () const {
1598             return find2 (0, 0, size2 ());
1599         }
1600 
1601         // Reverse iterators
1602 
1603         BOOST_UBLAS_INLINE
rbegin1() const1604         const_reverse_iterator1 rbegin1 () const {
1605             return const_reverse_iterator1 (end1 ());
1606         }
1607         BOOST_UBLAS_INLINE
rend1() const1608         const_reverse_iterator1 rend1 () const {
1609             return const_reverse_iterator1 (begin1 ());
1610         }
1611 
1612         BOOST_UBLAS_INLINE
rbegin2() const1613         const_reverse_iterator2 rbegin2 () const {
1614             return const_reverse_iterator2 (end2 ());
1615         }
1616         BOOST_UBLAS_INLINE
rend2() const1617         const_reverse_iterator2 rend2 () const {
1618             return const_reverse_iterator2 (begin2 ());
1619         }
1620 
1621     private:
1622         expression_closure_type e_;
1623     };
1624 
1625     template<class E, class F>
1626     struct matrix_unary2_traits {
1627         typedef matrix_unary2<E, F> expression_type;
1628 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
1629         typedef expression_type result_type;
1630 #else
1631         typedef typename E::matrix_temporary_type result_type;
1632 #endif
1633     };
1634 
1635     // (trans m) [i] [j] = m [j] [i]
1636     template<class E>
1637     BOOST_UBLAS_INLINE
1638     typename matrix_unary2_traits<const E, scalar_identity<typename E::value_type> >::result_type
trans(const matrix_expression<E> & e)1639     trans (const matrix_expression<E> &e) {
1640         typedef typename matrix_unary2_traits<const E, scalar_identity<typename E::value_type> >::expression_type expression_type;
1641         return expression_type (e ());
1642     }
1643     template<class E>
1644     BOOST_UBLAS_INLINE
1645     typename matrix_unary2_traits<E, scalar_identity<typename E::value_type> >::result_type
trans(matrix_expression<E> & e)1646     trans (matrix_expression<E> &e) {
1647         typedef typename matrix_unary2_traits<E, scalar_identity<typename E::value_type> >::expression_type expression_type;
1648         return expression_type (e ());
1649     }
1650 
1651     // (herm m) [i] [j] = conj (m [j] [i])
1652     template<class E>
1653     BOOST_UBLAS_INLINE
1654     typename matrix_unary2_traits<E, scalar_conj<typename E::value_type> >::result_type
herm(const matrix_expression<E> & e)1655     herm (const matrix_expression<E> &e) {
1656         typedef typename matrix_unary2_traits<E, scalar_conj<typename E::value_type> >::expression_type expression_type;
1657         return expression_type (e ());
1658     }
1659 
1660     template<class E1, class E2, class F>
1661     class matrix_binary:
1662         public matrix_expression<matrix_binary<E1, E2, F> > {
1663 
1664         typedef E1 expression1_type;
1665         typedef E2 expression2_type;
1666         typedef F functor_type;
1667     public:
1668         typedef typename E1::const_closure_type expression1_closure_type;
1669         typedef typename E2::const_closure_type expression2_closure_type;
1670     private:
1671         typedef matrix_binary<E1, E2, F> self_type;
1672     public:
1673 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
1674         using matrix_expression<self_type>::operator ();
1675 #endif
1676         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
1677         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
1678         typedef typename F::result_type value_type;
1679         typedef value_type const_reference;
1680         typedef const_reference reference;
1681         typedef const self_type const_closure_type;
1682         typedef const_closure_type closure_type;
1683         typedef unknown_orientation_tag orientation_category;
1684         typedef unknown_storage_tag storage_category;
1685 
1686         // Construction and destruction
1687         BOOST_UBLAS_INLINE
matrix_binary(const E1 & e1,const E2 & e2)1688         matrix_binary (const E1 &e1, const E2 &e2):
1689             e1_ (e1), e2_ (e2) {}
1690 
1691         // Accessors
1692         BOOST_UBLAS_INLINE
size1() const1693         size_type size1 () const {
1694             return BOOST_UBLAS_SAME (e1_.size1 (), e2_.size1 ());
1695         }
1696         BOOST_UBLAS_INLINE
size2() const1697         size_type size2 () const {
1698             return BOOST_UBLAS_SAME (e1_.size2 (), e2_.size2 ());
1699         }
1700 
1701     public:
1702         // Expression accessors
1703         BOOST_UBLAS_INLINE
expression1() const1704         const expression1_closure_type &expression1 () const {
1705             return e1_;
1706         }
1707         BOOST_UBLAS_INLINE
expression2() const1708         const expression2_closure_type &expression2 () const {
1709             return e2_;
1710         }
1711 
1712     public:
1713         // Element access
1714         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j) const1715         const_reference operator () (size_type i, size_type j) const {
1716             return functor_type::apply (e1_ (i, j), e2_ (i, j));
1717         }
1718 
1719         // Closure comparison
1720         BOOST_UBLAS_INLINE
same_closure(const matrix_binary & mb) const1721         bool same_closure (const matrix_binary &mb) const {
1722             return (*this).expression1 ().same_closure (mb.expression1 ()) &&
1723                    (*this).expression2 ().same_closure (mb.expression2 ());
1724         }
1725 
1726         // Iterator types
1727     private:
1728         typedef typename E1::const_iterator1 const_iterator11_type;
1729         typedef typename E1::const_iterator2 const_iterator12_type;
1730         typedef typename E2::const_iterator1 const_iterator21_type;
1731         typedef typename E2::const_iterator2 const_iterator22_type;
1732         typedef const value_type *const_pointer;
1733 
1734     public:
1735 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1736         typedef typename iterator_restrict_traits<typename const_iterator11_type::iterator_category,
1737                                                   typename const_iterator21_type::iterator_category>::iterator_category iterator_category1;
1738         typedef indexed_const_iterator1<const_closure_type, iterator_category1> const_iterator1;
1739         typedef const_iterator1 iterator1;
1740         typedef typename iterator_restrict_traits<typename const_iterator12_type::iterator_category,
1741                                                   typename const_iterator22_type::iterator_category>::iterator_category iterator_category2;
1742         typedef indexed_const_iterator2<const_closure_type, iterator_category2> const_iterator2;
1743         typedef const_iterator2 iterator2;
1744 #else
1745         class const_iterator1;
1746         typedef const_iterator1 iterator1;
1747         class const_iterator2;
1748         typedef const_iterator2 iterator2;
1749 #endif
1750         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
1751         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
1752 
1753         // Element lookup
1754         BOOST_UBLAS_INLINE
find1(int rank,size_type i,size_type j) const1755         const_iterator1 find1 (int rank, size_type i, size_type j) const {
1756             const_iterator11_type it11 (e1_.find1 (rank, i, j));
1757             const_iterator11_type it11_end (e1_.find1 (rank, size1 (), j));
1758             const_iterator21_type it21 (e2_.find1 (rank, i, j));
1759             const_iterator21_type it21_end (e2_.find1 (rank, size1 (), j));
1760             BOOST_UBLAS_CHECK (rank == 0 || it11 == it11_end || it11.index2 () == j, internal_logic ())
1761             BOOST_UBLAS_CHECK (rank == 0 || it21 == it21_end || it21.index2 () == j, internal_logic ())
1762             i = (std::min) (it11 != it11_end ? it11.index1 () : size1 (),
1763                           it21 != it21_end ? it21.index1 () : size1 ());
1764 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1765             return const_iterator1 (*this, i, j);
1766 #else
1767             return const_iterator1 (*this, i, j, it11, it11_end, it21, it21_end);
1768 #endif
1769         }
1770         BOOST_UBLAS_INLINE
find2(int rank,size_type i,size_type j) const1771         const_iterator2 find2 (int rank, size_type i, size_type j) const {
1772             const_iterator12_type it12 (e1_.find2 (rank, i, j));
1773             const_iterator12_type it12_end (e1_.find2 (rank, i, size2 ()));
1774             const_iterator22_type it22 (e2_.find2 (rank, i, j));
1775             const_iterator22_type it22_end (e2_.find2 (rank, i, size2 ()));
1776             BOOST_UBLAS_CHECK (rank == 0 || it12 == it12_end || it12.index1 () == i, internal_logic ())
1777             BOOST_UBLAS_CHECK (rank == 0 || it22 == it22_end || it22.index1 () == i, internal_logic ())
1778             j = (std::min) (it12 != it12_end ? it12.index2 () : size2 (),
1779                           it22 != it22_end ? it22.index2 () : size2 ());
1780 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1781             return const_iterator2 (*this, i, j);
1782 #else
1783             return const_iterator2 (*this, i, j, it12, it12_end, it22, it22_end);
1784 #endif
1785         }
1786 
1787         // Iterators enhance the iterators of the referenced expression
1788         // with the binary functor.
1789 
1790 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
1791         class const_iterator1:
1792             public container_const_reference<matrix_binary>,
1793             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
1794                                                                           typename E2::const_iterator1::iterator_category>::iterator_category>::template
1795                 iterator_base<const_iterator1, value_type>::type {
1796         public:
1797             typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
1798                                                       typename E2::const_iterator1::iterator_category>::iterator_category iterator_category;
1799             typedef typename matrix_binary::difference_type difference_type;
1800             typedef typename matrix_binary::value_type value_type;
1801             typedef typename matrix_binary::const_reference reference;
1802             typedef typename matrix_binary::const_pointer pointer;
1803 
1804             typedef const_iterator2 dual_iterator_type;
1805             typedef const_reverse_iterator2 dual_reverse_iterator_type;
1806 
1807             // Construction and destruction
1808             BOOST_UBLAS_INLINE
const_iterator1()1809             const_iterator1 ():
1810                 container_const_reference<self_type> (), i_ (), j_ (), it1_ (), it1_end_ (), it2_ (), it2_end_ () {}
1811             BOOST_UBLAS_INLINE
const_iterator1(const self_type & mb,size_type i,size_type j,const const_iterator11_type & it1,const const_iterator11_type & it1_end,const const_iterator21_type & it2,const const_iterator21_type & it2_end)1812             const_iterator1 (const self_type &mb, size_type i, size_type j,
1813                              const const_iterator11_type &it1, const const_iterator11_type &it1_end,
1814                              const const_iterator21_type &it2, const const_iterator21_type &it2_end):
1815                 container_const_reference<self_type> (mb), i_ (i), j_ (j), it1_ (it1), it1_end_ (it1_end), it2_ (it2), it2_end_ (it2_end) {}
1816 
1817             // Dense specializations
1818             BOOST_UBLAS_INLINE
increment(dense_random_access_iterator_tag)1819             void increment (dense_random_access_iterator_tag) {
1820                 ++ i_, ++ it1_, ++ it2_;
1821             }
1822             BOOST_UBLAS_INLINE
decrement(dense_random_access_iterator_tag)1823             void decrement (dense_random_access_iterator_tag) {
1824                 -- i_, -- it1_, -- it2_;
1825             }
1826             BOOST_UBLAS_INLINE
dereference(dense_random_access_iterator_tag) const1827             value_type dereference (dense_random_access_iterator_tag) const {
1828                 return functor_type::apply (*it1_, *it2_);
1829             }
1830 
1831             // Packed specializations
1832             BOOST_UBLAS_INLINE
increment(packed_random_access_iterator_tag)1833             void increment (packed_random_access_iterator_tag) {
1834                 if (it1_ != it1_end_)
1835                     if (it1_.index1 () <= i_)
1836                         ++ it1_;
1837                 if (it2_ != it2_end_)
1838                     if (it2_.index1 () <= i_)
1839                         ++ it2_;
1840                 ++ i_;
1841             }
1842             BOOST_UBLAS_INLINE
decrement(packed_random_access_iterator_tag)1843             void decrement (packed_random_access_iterator_tag) {
1844                 if (it1_ != it1_end_)
1845                     if (i_ <= it1_.index1 ())
1846                         -- it1_;
1847                 if (it2_ != it2_end_)
1848                     if (i_ <= it2_.index1 ())
1849                         -- it2_;
1850                 -- i_;
1851             }
1852             BOOST_UBLAS_INLINE
dereference(packed_random_access_iterator_tag) const1853             value_type dereference (packed_random_access_iterator_tag) const {
1854                 value_type t1 = value_type/*zero*/();
1855                 if (it1_ != it1_end_) {
1856                     BOOST_UBLAS_CHECK (it1_.index2 () == j_, internal_logic ());
1857                     if (it1_.index1 () == i_)
1858                         t1 = *it1_;
1859                 }
1860                 value_type t2 = value_type/*zero*/();
1861                 if (it2_ != it2_end_) {
1862                     BOOST_UBLAS_CHECK (it2_.index2 () == j_, internal_logic ());
1863                     if (it2_.index1 () == i_)
1864                         t2 = *it2_;
1865                 }
1866                 return functor_type::apply (t1, t2);
1867             }
1868 
1869             // Sparse specializations
1870             BOOST_UBLAS_INLINE
increment(sparse_bidirectional_iterator_tag)1871             void increment (sparse_bidirectional_iterator_tag) {
1872                 size_type index1 = (*this) ().size1 ();
1873                 if (it1_ != it1_end_) {
1874                     if (it1_.index1 () <= i_)
1875                         ++ it1_;
1876                     if (it1_ != it1_end_)
1877                         index1 = it1_.index1 ();
1878                 }
1879                 size_type index2 = (*this) ().size1 ();
1880                 if (it2_ != it2_end_)
1881                     if (it2_.index1 () <= i_)
1882                         ++ it2_;
1883                     if (it2_ != it2_end_) {
1884                         index2 = it2_.index1 ();
1885                 }
1886                 i_ = (std::min) (index1, index2);
1887             }
1888             BOOST_UBLAS_INLINE
decrement(sparse_bidirectional_iterator_tag)1889             void decrement (sparse_bidirectional_iterator_tag) {
1890                 size_type index1 = (*this) ().size1 ();
1891                 if (it1_ != it1_end_) {
1892                     if (i_ <= it1_.index1 ())
1893                         -- it1_;
1894                     if (it1_ != it1_end_)
1895                         index1 = it1_.index1 ();
1896                 }
1897                 size_type index2 = (*this) ().size1 ();
1898                 if (it2_ != it2_end_) {
1899                     if (i_ <= it2_.index1 ())
1900                         -- it2_;
1901                     if (it2_ != it2_end_)
1902                         index2 = it2_.index1 ();
1903                 }
1904                 i_ = (std::max) (index1, index2);
1905             }
1906             BOOST_UBLAS_INLINE
dereference(sparse_bidirectional_iterator_tag) const1907             value_type dereference (sparse_bidirectional_iterator_tag) const {
1908                 value_type t1 = value_type/*zero*/();
1909                 if (it1_ != it1_end_) {
1910                     BOOST_UBLAS_CHECK (it1_.index2 () == j_, internal_logic ());
1911                     if (it1_.index1 () == i_)
1912                         t1 = *it1_;
1913                 }
1914                 value_type t2 = value_type/*zero*/();
1915                 if (it2_ != it2_end_) {
1916                     BOOST_UBLAS_CHECK (it2_.index2 () == j_, internal_logic ());
1917                     if (it2_.index1 () == i_)
1918                         t2 = *it2_;
1919                 }
1920                 return functor_type::apply (t1, t2);
1921             }
1922 
1923             // Arithmetic
1924             BOOST_UBLAS_INLINE
operator ++()1925             const_iterator1 &operator ++ () {
1926                 increment (iterator_category ());
1927                 return *this;
1928             }
1929             BOOST_UBLAS_INLINE
operator --()1930             const_iterator1 &operator -- () {
1931                 decrement (iterator_category ());
1932                 return *this;
1933             }
1934             BOOST_UBLAS_INLINE
operator +=(difference_type n)1935             const_iterator1 &operator += (difference_type n) {
1936                 i_ += n, it1_ += n, it2_ += n;
1937                 return *this;
1938             }
1939             BOOST_UBLAS_INLINE
operator -=(difference_type n)1940             const_iterator1 &operator -= (difference_type n) {
1941                 i_ -= n, it1_ -= n, it2_ -= n;
1942                 return *this;
1943             }
1944             BOOST_UBLAS_INLINE
operator -(const const_iterator1 & it) const1945             difference_type operator - (const const_iterator1 &it) const {
1946                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1947                 BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ());
1948                 return index1 () - it.index1 ();
1949             }
1950 
1951             // Dereference
1952             BOOST_UBLAS_INLINE
operator *() const1953             const_reference operator * () const {
1954                 return dereference (iterator_category ());
1955             }
1956 
1957 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1958             BOOST_UBLAS_INLINE
1959 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1960             typename self_type::
1961 #endif
begin() const1962             const_iterator2 begin () const {
1963                 return (*this) ().find2 (1, index1 (), 0);
1964             }
1965             BOOST_UBLAS_INLINE
1966 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1967             typename self_type::
1968 #endif
end() const1969             const_iterator2 end () const {
1970                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
1971             }
1972             BOOST_UBLAS_INLINE
1973 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1974             typename self_type::
1975 #endif
rbegin() const1976             const_reverse_iterator2 rbegin () const {
1977                 return const_reverse_iterator2 (end ());
1978             }
1979             BOOST_UBLAS_INLINE
1980 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1981             typename self_type::
1982 #endif
rend() const1983             const_reverse_iterator2 rend () const {
1984                 return const_reverse_iterator2 (begin ());
1985             }
1986 #endif
1987 
1988             // Indices
1989             BOOST_UBLAS_INLINE
index1() const1990             size_type index1 () const {
1991                 return i_;
1992             }
1993             BOOST_UBLAS_INLINE
index2() const1994             size_type index2 () const {
1995                 // if (it1_ != it1_end_ && it2_ != it2_end_)
1996                 //    return BOOST_UBLAS_SAME (it1_.index2 (), it2_.index2 ());
1997                 // else
1998                     return j_;
1999             }
2000 
2001             // Assignment
2002             BOOST_UBLAS_INLINE
operator =(const const_iterator1 & it)2003             const_iterator1 &operator = (const const_iterator1 &it) {
2004                 container_const_reference<self_type>::assign (&it ());
2005                 i_ = it.i_;
2006                 j_ = it.j_;
2007                 it1_ = it.it1_;
2008                 it1_end_ = it.it1_end_;
2009                 it2_ = it.it2_;
2010                 it2_end_ = it.it2_end_;
2011                 return *this;
2012             }
2013 
2014             // Comparison
2015             BOOST_UBLAS_INLINE
operator ==(const const_iterator1 & it) const2016             bool operator == (const const_iterator1 &it) const {
2017                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2018                 BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ());
2019                 return index1 () == it.index1 ();
2020             }
2021             BOOST_UBLAS_INLINE
operator <(const const_iterator1 & it) const2022             bool operator < (const const_iterator1 &it) const {
2023                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2024                 BOOST_UBLAS_CHECK (index2 () == it.index2 (), external_logic ());
2025                 return index1 () < it.index1 ();
2026             }
2027 
2028         private:
2029             size_type i_;
2030             size_type j_;
2031             const_iterator11_type it1_;
2032             const_iterator11_type it1_end_;
2033             const_iterator21_type it2_;
2034             const_iterator21_type it2_end_;
2035         };
2036 #endif
2037 
2038         BOOST_UBLAS_INLINE
begin1() const2039         const_iterator1 begin1 () const {
2040             return find1 (0, 0, 0);
2041         }
2042         BOOST_UBLAS_INLINE
end1() const2043         const_iterator1 end1 () const {
2044             return find1 (0, size1 (), 0);
2045         }
2046 
2047 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
2048         class const_iterator2:
2049             public container_const_reference<matrix_binary>,
2050             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator2::iterator_category,
2051                                                                           typename E2::const_iterator2::iterator_category>::iterator_category>::template
2052                 iterator_base<const_iterator2, value_type>::type {
2053         public:
2054             typedef typename iterator_restrict_traits<typename E1::const_iterator2::iterator_category,
2055                                                       typename E2::const_iterator2::iterator_category>::iterator_category iterator_category;
2056             typedef typename matrix_binary::difference_type difference_type;
2057             typedef typename matrix_binary::value_type value_type;
2058             typedef typename matrix_binary::const_reference reference;
2059             typedef typename matrix_binary::const_pointer pointer;
2060 
2061             typedef const_iterator1 dual_iterator_type;
2062             typedef const_reverse_iterator1 dual_reverse_iterator_type;
2063 
2064             // Construction and destruction
2065             BOOST_UBLAS_INLINE
const_iterator2()2066             const_iterator2 ():
2067                 container_const_reference<self_type> (), i_ (), j_ (), it1_ (), it1_end_ (), it2_ (), it2_end_ () {}
2068             BOOST_UBLAS_INLINE
const_iterator2(const self_type & mb,size_type i,size_type j,const const_iterator12_type & it1,const const_iterator12_type & it1_end,const const_iterator22_type & it2,const const_iterator22_type & it2_end)2069             const_iterator2 (const self_type &mb, size_type i, size_type j,
2070                              const const_iterator12_type &it1, const const_iterator12_type &it1_end,
2071                              const const_iterator22_type &it2, const const_iterator22_type &it2_end):
2072                 container_const_reference<self_type> (mb), i_ (i), j_ (j), it1_ (it1), it1_end_ (it1_end), it2_ (it2), it2_end_ (it2_end) {}
2073 
2074             // Dense access specializations
2075             BOOST_UBLAS_INLINE
increment(dense_random_access_iterator_tag)2076             void increment (dense_random_access_iterator_tag) {
2077                 ++ j_, ++ it1_, ++ it2_;
2078             }
2079             BOOST_UBLAS_INLINE
decrement(dense_random_access_iterator_tag)2080             void decrement (dense_random_access_iterator_tag) {
2081                 -- j_, -- it1_, -- it2_;
2082             }
2083             BOOST_UBLAS_INLINE
dereference(dense_random_access_iterator_tag) const2084             value_type dereference (dense_random_access_iterator_tag) const {
2085                 return functor_type::apply (*it1_, *it2_);
2086             }
2087 
2088             // Packed specializations
2089             BOOST_UBLAS_INLINE
increment(packed_random_access_iterator_tag)2090             void increment (packed_random_access_iterator_tag) {
2091                 if (it1_ != it1_end_)
2092                     if (it1_.index2 () <= j_)
2093                         ++ it1_;
2094                 if (it2_ != it2_end_)
2095                     if (it2_.index2 () <= j_)
2096                         ++ it2_;
2097                 ++ j_;
2098             }
2099             BOOST_UBLAS_INLINE
decrement(packed_random_access_iterator_tag)2100             void decrement (packed_random_access_iterator_tag) {
2101                 if (it1_ != it1_end_)
2102                     if (j_ <= it1_.index2 ())
2103                         -- it1_;
2104                 if (it2_ != it2_end_)
2105                     if (j_ <= it2_.index2 ())
2106                         -- it2_;
2107                 -- j_;
2108             }
2109             BOOST_UBLAS_INLINE
dereference(packed_random_access_iterator_tag) const2110             value_type dereference (packed_random_access_iterator_tag) const {
2111                 value_type t1 = value_type/*zero*/();
2112                 if (it1_ != it1_end_) {
2113                     BOOST_UBLAS_CHECK (it1_.index1 () == i_, internal_logic ());
2114                     if (it1_.index2 () == j_)
2115                         t1 = *it1_;
2116                 }
2117                 value_type t2 = value_type/*zero*/();
2118                 if (it2_ != it2_end_) {
2119                     BOOST_UBLAS_CHECK (it2_.index1 () == i_, internal_logic ());
2120                     if (it2_.index2 () == j_)
2121                         t2 = *it2_;
2122                 }
2123                 return functor_type::apply (t1, t2);
2124             }
2125 
2126             // Sparse specializations
2127             BOOST_UBLAS_INLINE
increment(sparse_bidirectional_iterator_tag)2128             void increment (sparse_bidirectional_iterator_tag) {
2129                 size_type index1 = (*this) ().size2 ();
2130                 if (it1_ != it1_end_) {
2131                     if (it1_.index2 () <= j_)
2132                         ++ it1_;
2133                     if (it1_ != it1_end_)
2134                         index1 = it1_.index2 ();
2135                 }
2136                 size_type index2 = (*this) ().size2 ();
2137                 if (it2_ != it2_end_) {
2138                     if (it2_.index2 () <= j_)
2139                         ++ it2_;
2140                     if (it2_ != it2_end_)
2141                         index2 = it2_.index2 ();
2142                 }
2143                 j_ = (std::min) (index1, index2);
2144             }
2145             BOOST_UBLAS_INLINE
decrement(sparse_bidirectional_iterator_tag)2146             void decrement (sparse_bidirectional_iterator_tag) {
2147                 size_type index1 = (*this) ().size2 ();
2148                 if (it1_ != it1_end_) {
2149                     if (j_ <= it1_.index2 ())
2150                         -- it1_;
2151                     if (it1_ != it1_end_)
2152                         index1 = it1_.index2 ();
2153                 }
2154                 size_type index2 = (*this) ().size2 ();
2155                 if (it2_ != it2_end_) {
2156                     if (j_ <= it2_.index2 ())
2157                         -- it2_;
2158                     if (it2_ != it2_end_)
2159                         index2 = it2_.index2 ();
2160                 }
2161                 j_ = (std::max) (index1, index2);
2162             }
2163             BOOST_UBLAS_INLINE
dereference(sparse_bidirectional_iterator_tag) const2164             value_type dereference (sparse_bidirectional_iterator_tag) const {
2165                 value_type t1 = value_type/*zero*/();
2166                 if (it1_ != it1_end_) {
2167                     BOOST_UBLAS_CHECK (it1_.index1 () == i_, internal_logic ());
2168                     if (it1_.index2 () == j_)
2169                         t1 = *it1_;
2170                 }
2171                 value_type t2 = value_type/*zero*/();
2172                 if (it2_ != it2_end_) {
2173                     BOOST_UBLAS_CHECK (it2_.index1 () == i_, internal_logic ());
2174                     if (it2_.index2 () == j_)
2175                         t2 = *it2_;
2176                 }
2177                 return functor_type::apply (t1, t2);
2178             }
2179 
2180             // Arithmetic
2181             BOOST_UBLAS_INLINE
operator ++()2182             const_iterator2 &operator ++ () {
2183                 increment (iterator_category ());
2184                 return *this;
2185             }
2186             BOOST_UBLAS_INLINE
operator --()2187             const_iterator2 &operator -- () {
2188                 decrement (iterator_category ());
2189                 return *this;
2190             }
2191             BOOST_UBLAS_INLINE
operator +=(difference_type n)2192             const_iterator2 &operator += (difference_type n) {
2193                 j_ += n, it1_ += n, it2_ += n;
2194                 return *this;
2195             }
2196             BOOST_UBLAS_INLINE
operator -=(difference_type n)2197             const_iterator2 &operator -= (difference_type n) {
2198                 j_ -= n, it1_ -= n, it2_ -= n;
2199                 return *this;
2200             }
2201             BOOST_UBLAS_INLINE
operator -(const const_iterator2 & it) const2202             difference_type operator - (const const_iterator2 &it) const {
2203                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2204                 BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ());
2205                 return index2 () - it.index2 ();
2206             }
2207 
2208             // Dereference
2209             BOOST_UBLAS_INLINE
operator *() const2210             const_reference operator * () const {
2211                 return dereference (iterator_category ());
2212             }
2213 
2214 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
2215             BOOST_UBLAS_INLINE
2216 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2217             typename self_type::
2218 #endif
begin() const2219             const_iterator1 begin () const {
2220                 return (*this) ().find1 (1, 0, index2 ());
2221             }
2222             BOOST_UBLAS_INLINE
2223 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2224             typename self_type::
2225 #endif
end() const2226             const_iterator1 end () const {
2227                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
2228             }
2229             BOOST_UBLAS_INLINE
2230 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2231             typename self_type::
2232 #endif
rbegin() const2233             const_reverse_iterator1 rbegin () const {
2234                 return const_reverse_iterator1 (end ());
2235             }
2236             BOOST_UBLAS_INLINE
2237 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2238             typename self_type::
2239 #endif
rend() const2240             const_reverse_iterator1 rend () const {
2241                 return const_reverse_iterator1 (begin ());
2242             }
2243 #endif
2244 
2245             // Indices
2246             BOOST_UBLAS_INLINE
index1() const2247             size_type index1 () const {
2248                 // if (it1_ != it1_end_ && it2_ != it2_end_)
2249                 //    return BOOST_UBLAS_SAME (it1_.index1 (), it2_.index1 ());
2250                 // else
2251                     return i_;
2252             }
2253             BOOST_UBLAS_INLINE
index2() const2254             size_type index2 () const {
2255                 return j_;
2256             }
2257 
2258             // Assignment
2259             BOOST_UBLAS_INLINE
operator =(const const_iterator2 & it)2260             const_iterator2 &operator = (const const_iterator2 &it) {
2261                 container_const_reference<self_type>::assign (&it ());
2262                 i_ = it.i_;
2263                 j_ = it.j_;
2264                 it1_ = it.it1_;
2265                 it1_end_ = it.it1_end_;
2266                 it2_ = it.it2_;
2267                 it2_end_ = it.it2_end_;
2268                 return *this;
2269             }
2270 
2271             // Comparison
2272             BOOST_UBLAS_INLINE
operator ==(const const_iterator2 & it) const2273             bool operator == (const const_iterator2 &it) const {
2274                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2275                 BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ());
2276                 return index2 () == it.index2 ();
2277             }
2278             BOOST_UBLAS_INLINE
operator <(const const_iterator2 & it) const2279             bool operator < (const const_iterator2 &it) const {
2280                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2281                 BOOST_UBLAS_CHECK (index1 () == it.index1 (), external_logic ());
2282                 return index2 () < it.index2 ();
2283             }
2284 
2285         private:
2286             size_type i_;
2287             size_type j_;
2288             const_iterator12_type it1_;
2289             const_iterator12_type it1_end_;
2290             const_iterator22_type it2_;
2291             const_iterator22_type it2_end_;
2292         };
2293 #endif
2294 
2295         BOOST_UBLAS_INLINE
begin2() const2296         const_iterator2 begin2 () const {
2297             return find2 (0, 0, 0);
2298         }
2299         BOOST_UBLAS_INLINE
end2() const2300         const_iterator2 end2 () const {
2301             return find2 (0, 0, size2 ());
2302         }
2303 
2304         // Reverse iterators
2305 
2306         BOOST_UBLAS_INLINE
rbegin1() const2307         const_reverse_iterator1 rbegin1 () const {
2308             return const_reverse_iterator1 (end1 ());
2309         }
2310         BOOST_UBLAS_INLINE
rend1() const2311         const_reverse_iterator1 rend1 () const {
2312             return const_reverse_iterator1 (begin1 ());
2313         }
2314 
2315         BOOST_UBLAS_INLINE
rbegin2() const2316         const_reverse_iterator2 rbegin2 () const {
2317             return const_reverse_iterator2 (end2 ());
2318         }
2319         BOOST_UBLAS_INLINE
rend2() const2320         const_reverse_iterator2 rend2 () const {
2321             return const_reverse_iterator2 (begin2 ());
2322         }
2323 
2324     private:
2325         expression1_closure_type e1_;
2326         expression2_closure_type e2_;
2327     };
2328 
2329     template<class E1, class E2, class F>
2330     struct matrix_binary_traits {
2331         typedef matrix_binary<E1, E2, F> expression_type;
2332 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
2333         typedef expression_type result_type;
2334 #else
2335         typedef typename E1::matrix_temporary_type result_type;
2336 #endif
2337     };
2338 
2339     // (m1 + m2) [i] [j] = m1 [i] [j] + m2 [i] [j]
2340     template<class E1, class E2>
2341     BOOST_UBLAS_INLINE
2342     typename matrix_binary_traits<E1, E2, scalar_plus<typename E1::value_type,
2343                                                       typename E2::value_type> >::result_type
operator +(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)2344     operator + (const matrix_expression<E1> &e1,
2345                 const matrix_expression<E2> &e2) {
2346         typedef typename matrix_binary_traits<E1, E2, scalar_plus<typename E1::value_type,
2347                                                                               typename E2::value_type> >::expression_type expression_type;
2348         return expression_type (e1 (), e2 ());
2349     }
2350 
2351     // (m1 - m2) [i] [j] = m1 [i] [j] - m2 [i] [j]
2352     template<class E1, class E2>
2353     BOOST_UBLAS_INLINE
2354     typename matrix_binary_traits<E1, E2, scalar_minus<typename E1::value_type,
2355                                                        typename E2::value_type> >::result_type
operator -(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)2356     operator - (const matrix_expression<E1> &e1,
2357                 const matrix_expression<E2> &e2) {
2358         typedef typename matrix_binary_traits<E1, E2, scalar_minus<typename E1::value_type,
2359                                                                                typename E2::value_type> >::expression_type expression_type;
2360         return expression_type (e1 (), e2 ());
2361     }
2362 
2363     // (m1 * m2) [i] [j] = m1 [i] [j] * m2 [i] [j]
2364     template<class E1, class E2>
2365     BOOST_UBLAS_INLINE
2366     typename matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type,
2367                                                             typename E2::value_type> >::result_type
element_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)2368     element_prod (const matrix_expression<E1> &e1,
2369                   const matrix_expression<E2> &e2) {
2370         typedef typename matrix_binary_traits<E1, E2, scalar_multiplies<typename E1::value_type,
2371                                                                                     typename E2::value_type> >::expression_type expression_type;
2372         return expression_type (e1 (), e2 ());
2373     }
2374 
2375     // (m1 / m2) [i] [j] = m1 [i] [j] / m2 [i] [j]
2376     template<class E1, class E2>
2377     BOOST_UBLAS_INLINE
2378     typename matrix_binary_traits<E1, E2, scalar_divides<typename E1::value_type,
2379                                                        typename E2::value_type> >::result_type
element_div(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)2380     element_div (const matrix_expression<E1> &e1,
2381                  const matrix_expression<E2> &e2) {
2382         typedef typename matrix_binary_traits<E1, E2, scalar_divides<typename E1::value_type,
2383                                                                                  typename E2::value_type> >::expression_type expression_type;
2384         return expression_type (e1 (), e2 ());
2385     }
2386 
2387     template<class E1, class E2, class F>
2388     class matrix_binary_scalar1:
2389         public matrix_expression<matrix_binary_scalar1<E1, E2, F> > {
2390 
2391         typedef E1 expression1_type;
2392         typedef E2 expression2_type;
2393         typedef F functor_type;
2394         typedef const E1& expression1_closure_type;
2395         typedef typename E2::const_closure_type expression2_closure_type;
2396         typedef matrix_binary_scalar1<E1, E2, F> self_type;
2397     public:
2398 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
2399         using matrix_expression<self_type>::operator ();
2400 #endif
2401         typedef typename E2::size_type size_type;
2402         typedef typename E2::difference_type difference_type;
2403         typedef typename F::result_type value_type;
2404         typedef value_type const_reference;
2405         typedef const_reference reference;
2406         typedef const self_type const_closure_type;
2407         typedef const_closure_type closure_type;
2408         typedef typename E2::orientation_category orientation_category;
2409         typedef unknown_storage_tag storage_category;
2410 
2411         // Construction and destruction
2412         BOOST_UBLAS_INLINE
matrix_binary_scalar1(const expression1_type & e1,const expression2_type & e2)2413         matrix_binary_scalar1 (const expression1_type &e1, const expression2_type &e2):
2414             e1_ (e1), e2_ (e2) {}
2415 
2416         // Accessors
2417         BOOST_UBLAS_INLINE
size1() const2418         size_type size1 () const {
2419             return e2_.size1 ();
2420         }
2421         BOOST_UBLAS_INLINE
size2() const2422         size_type size2 () const {
2423             return e2_.size2 ();
2424         }
2425 
2426     public:
2427         // Element access
2428         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j) const2429         const_reference operator () (size_type i, size_type j) const {
2430             return functor_type::apply (expression1_type (e1_), e2_ (i, j));
2431         }
2432 
2433         // Closure comparison
2434         BOOST_UBLAS_INLINE
same_closure(const matrix_binary_scalar1 & mbs1) const2435         bool same_closure (const matrix_binary_scalar1 &mbs1) const {
2436             return &e1_ == &(mbs1.e1_) &&
2437                    (*this).e2_.same_closure (mbs1.e2_);
2438         }
2439 
2440         // Iterator types
2441     private:
2442         typedef expression1_type const_subiterator1_type;
2443         typedef typename E2::const_iterator1 const_iterator21_type;
2444         typedef typename E2::const_iterator2 const_iterator22_type;
2445         typedef const value_type *const_pointer;
2446 
2447     public:
2448 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
2449         typedef indexed_const_iterator1<const_closure_type, typename const_iterator21_type::iterator_category> const_iterator1;
2450         typedef const_iterator1 iterator1;
2451         typedef indexed_const_iterator2<const_closure_type, typename const_iterator22_type::iterator_category> const_iterator2;
2452         typedef const_iterator2 iterator2;
2453 #else
2454         class const_iterator1;
2455         typedef const_iterator1 iterator1;
2456         class const_iterator2;
2457         typedef const_iterator2 iterator2;
2458 #endif
2459         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
2460         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
2461 
2462         // Element lookup
2463         BOOST_UBLAS_INLINE
find1(int rank,size_type i,size_type j) const2464         const_iterator1 find1 (int rank, size_type i, size_type j) const {
2465             const_iterator21_type it21 (e2_.find1 (rank, i, j));
2466 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
2467             return const_iterator1 (*this, it21.index1 (), it21.index2 ());
2468 #else
2469             return const_iterator1 (*this, const_subiterator1_type (e1_), it21);
2470 #endif
2471         }
2472         BOOST_UBLAS_INLINE
find2(int rank,size_type i,size_type j) const2473         const_iterator2 find2 (int rank, size_type i, size_type j) const {
2474             const_iterator22_type it22 (e2_.find2 (rank, i, j));
2475 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
2476             return const_iterator2 (*this, it22.index1 (), it22.index2 ());
2477 #else
2478             return const_iterator2 (*this, const_subiterator1_type (e1_), it22);
2479 #endif
2480         }
2481 
2482         // Iterators enhance the iterators of the referenced expression
2483         // with the binary functor.
2484 
2485 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
2486         class const_iterator1:
2487             public container_const_reference<matrix_binary_scalar1>,
2488             public iterator_base_traits<typename E2::const_iterator1::iterator_category>::template
2489                 iterator_base<const_iterator1, value_type>::type {
2490         public:
2491             typedef typename E2::const_iterator1::iterator_category iterator_category;
2492             typedef typename matrix_binary_scalar1::difference_type difference_type;
2493             typedef typename matrix_binary_scalar1::value_type value_type;
2494             typedef typename matrix_binary_scalar1::const_reference reference;
2495             typedef typename matrix_binary_scalar1::const_pointer pointer;
2496 
2497             typedef const_iterator2 dual_iterator_type;
2498             typedef const_reverse_iterator2 dual_reverse_iterator_type;
2499 
2500             // Construction and destruction
2501             BOOST_UBLAS_INLINE
const_iterator1()2502             const_iterator1 ():
2503                 container_const_reference<self_type> (), it1_ (), it2_ () {}
2504             BOOST_UBLAS_INLINE
const_iterator1(const self_type & mbs,const const_subiterator1_type & it1,const const_iterator21_type & it2)2505             const_iterator1 (const self_type &mbs, const const_subiterator1_type &it1, const const_iterator21_type &it2):
2506                 container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {}
2507 
2508             // Arithmetic
2509             BOOST_UBLAS_INLINE
operator ++()2510             const_iterator1 &operator ++ () {
2511                 ++ it2_;
2512                 return *this;
2513             }
2514             BOOST_UBLAS_INLINE
operator --()2515             const_iterator1 &operator -- () {
2516                 -- it2_ ;
2517                 return *this;
2518             }
2519             BOOST_UBLAS_INLINE
operator +=(difference_type n)2520             const_iterator1 &operator += (difference_type n) {
2521                 it2_ += n;
2522                 return *this;
2523             }
2524             BOOST_UBLAS_INLINE
operator -=(difference_type n)2525             const_iterator1 &operator -= (difference_type n) {
2526                 it2_ -= n;
2527                 return *this;
2528             }
2529             BOOST_UBLAS_INLINE
operator -(const const_iterator1 & it) const2530             difference_type operator - (const const_iterator1 &it) const {
2531                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2532                 // FIXME we shouldn't compare floats
2533                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
2534                 return it2_ - it.it2_;
2535             }
2536 
2537             // Dereference
2538             BOOST_UBLAS_INLINE
operator *() const2539             const_reference operator * () const {
2540                 return functor_type::apply (it1_, *it2_);
2541             }
2542 
2543 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
2544             BOOST_UBLAS_INLINE
2545 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2546             typename self_type::
2547 #endif
begin() const2548             const_iterator2 begin () const {
2549                 return (*this) ().find2 (1, index1 (), 0);
2550             }
2551             BOOST_UBLAS_INLINE
2552 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2553             typename self_type::
2554 #endif
end() const2555             const_iterator2 end () const {
2556                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
2557             }
2558             BOOST_UBLAS_INLINE
2559 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2560             typename self_type::
2561 #endif
rbegin() const2562             const_reverse_iterator2 rbegin () const {
2563                 return const_reverse_iterator2 (end ());
2564             }
2565             BOOST_UBLAS_INLINE
2566 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2567             typename self_type::
2568 #endif
rend() const2569             const_reverse_iterator2 rend () const {
2570                 return const_reverse_iterator2 (begin ());
2571             }
2572 #endif
2573 
2574             // Indices
2575             BOOST_UBLAS_INLINE
index1() const2576             size_type index1 () const {
2577                 return it2_.index1 ();
2578             }
2579             BOOST_UBLAS_INLINE
index2() const2580             size_type index2 () const {
2581                 return it2_.index2 ();
2582             }
2583 
2584             // Assignment
2585             BOOST_UBLAS_INLINE
operator =(const const_iterator1 & it)2586             const_iterator1 &operator = (const const_iterator1 &it) {
2587                 container_const_reference<self_type>::assign (&it ());
2588                 it1_ = it.it1_;
2589                 it2_ = it.it2_;
2590                 return *this;
2591             }
2592 
2593             // Comparison
2594             BOOST_UBLAS_INLINE
operator ==(const const_iterator1 & it) const2595             bool operator == (const const_iterator1 &it) const {
2596                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2597                 // FIXME we shouldn't compare floats
2598                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
2599                 return it2_ == it.it2_;
2600             }
2601             BOOST_UBLAS_INLINE
operator <(const const_iterator1 & it) const2602             bool operator < (const const_iterator1 &it) const {
2603                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2604                 // FIXME we shouldn't compare floats
2605                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
2606                 return it2_ < it.it2_;
2607             }
2608 
2609         private:
2610             const_subiterator1_type it1_;
2611             const_iterator21_type it2_;
2612         };
2613 #endif
2614 
2615         BOOST_UBLAS_INLINE
begin1() const2616         const_iterator1 begin1 () const {
2617             return find1 (0, 0, 0);
2618         }
2619         BOOST_UBLAS_INLINE
end1() const2620         const_iterator1 end1 () const {
2621             return find1 (0, size1 (), 0);
2622         }
2623 
2624 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
2625         class const_iterator2:
2626             public container_const_reference<matrix_binary_scalar1>,
2627             public iterator_base_traits<typename E2::const_iterator2::iterator_category>::template
2628                 iterator_base<const_iterator2, value_type>::type {
2629         public:
2630             typedef typename E2::const_iterator2::iterator_category iterator_category;
2631             typedef typename matrix_binary_scalar1::difference_type difference_type;
2632             typedef typename matrix_binary_scalar1::value_type value_type;
2633             typedef typename matrix_binary_scalar1::const_reference reference;
2634             typedef typename matrix_binary_scalar1::const_pointer pointer;
2635 
2636             typedef const_iterator1 dual_iterator_type;
2637             typedef const_reverse_iterator1 dual_reverse_iterator_type;
2638 
2639             // Construction and destruction
2640             BOOST_UBLAS_INLINE
const_iterator2()2641             const_iterator2 ():
2642                 container_const_reference<self_type> (), it1_ (), it2_ () {}
2643             BOOST_UBLAS_INLINE
const_iterator2(const self_type & mbs,const const_subiterator1_type & it1,const const_iterator22_type & it2)2644             const_iterator2 (const self_type &mbs, const const_subiterator1_type &it1, const const_iterator22_type &it2):
2645                 container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {}
2646 
2647             // Arithmetic
2648             BOOST_UBLAS_INLINE
operator ++()2649             const_iterator2 &operator ++ () {
2650                 ++ it2_;
2651                 return *this;
2652             }
2653             BOOST_UBLAS_INLINE
operator --()2654             const_iterator2 &operator -- () {
2655                 -- it2_;
2656                 return *this;
2657             }
2658             BOOST_UBLAS_INLINE
operator +=(difference_type n)2659             const_iterator2 &operator += (difference_type n) {
2660                 it2_ += n;
2661                 return *this;
2662             }
2663             BOOST_UBLAS_INLINE
operator -=(difference_type n)2664             const_iterator2 &operator -= (difference_type n) {
2665                 it2_ -= n;
2666                 return *this;
2667             }
2668             BOOST_UBLAS_INLINE
operator -(const const_iterator2 & it) const2669             difference_type operator - (const const_iterator2 &it) const {
2670                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2671                 // FIXME we shouldn't compare floats
2672                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
2673                 return it2_ - it.it2_;
2674             }
2675 
2676             // Dereference
2677             BOOST_UBLAS_INLINE
operator *() const2678             const_reference operator * () const {
2679                 return functor_type::apply (it1_, *it2_);
2680             }
2681 
2682 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
2683             BOOST_UBLAS_INLINE
2684 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2685             typename self_type::
2686 #endif
begin() const2687             const_iterator1 begin () const {
2688                 return (*this) ().find1 (1, 0, index2 ());
2689             }
2690             BOOST_UBLAS_INLINE
2691 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2692             typename self_type::
2693 #endif
end() const2694             const_iterator1 end () const {
2695                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
2696             }
2697             BOOST_UBLAS_INLINE
2698 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2699             typename self_type::
2700 #endif
rbegin() const2701             const_reverse_iterator1 rbegin () const {
2702                 return const_reverse_iterator1 (end ());
2703             }
2704             BOOST_UBLAS_INLINE
2705 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2706             typename self_type::
2707 #endif
rend() const2708             const_reverse_iterator1 rend () const {
2709                 return const_reverse_iterator1 (begin ());
2710             }
2711 #endif
2712 
2713             // Indices
2714             BOOST_UBLAS_INLINE
index1() const2715             size_type index1 () const {
2716                 return it2_.index1 ();
2717             }
2718             BOOST_UBLAS_INLINE
index2() const2719             size_type index2 () const {
2720                 return it2_.index2 ();
2721             }
2722 
2723             // Assignment
2724             BOOST_UBLAS_INLINE
operator =(const const_iterator2 & it)2725             const_iterator2 &operator = (const const_iterator2 &it) {
2726                 container_const_reference<self_type>::assign (&it ());
2727                 it1_ = it.it1_;
2728                 it2_ = it.it2_;
2729                 return *this;
2730             }
2731 
2732             // Comparison
2733             BOOST_UBLAS_INLINE
operator ==(const const_iterator2 & it) const2734             bool operator == (const const_iterator2 &it) const {
2735                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2736                 // FIXME we shouldn't compare floats
2737                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
2738                 return it2_ == it.it2_;
2739             }
2740             BOOST_UBLAS_INLINE
operator <(const const_iterator2 & it) const2741             bool operator < (const const_iterator2 &it) const {
2742                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2743                 // FIXME we shouldn't compare floats
2744                 // BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
2745                 return it2_ < it.it2_;
2746             }
2747 
2748         private:
2749             const_subiterator1_type it1_;
2750             const_iterator22_type it2_;
2751         };
2752 #endif
2753 
2754         BOOST_UBLAS_INLINE
begin2() const2755         const_iterator2 begin2 () const {
2756             return find2 (0, 0, 0);
2757         }
2758         BOOST_UBLAS_INLINE
end2() const2759         const_iterator2 end2 () const {
2760             return find2 (0, 0, size2 ());
2761         }
2762 
2763         // Reverse iterators
2764 
2765         BOOST_UBLAS_INLINE
rbegin1() const2766         const_reverse_iterator1 rbegin1 () const {
2767             return const_reverse_iterator1 (end1 ());
2768         }
2769         BOOST_UBLAS_INLINE
rend1() const2770         const_reverse_iterator1 rend1 () const {
2771             return const_reverse_iterator1 (begin1 ());
2772         }
2773 
2774         BOOST_UBLAS_INLINE
rbegin2() const2775         const_reverse_iterator2 rbegin2 () const {
2776             return const_reverse_iterator2 (end2 ());
2777         }
2778         BOOST_UBLAS_INLINE
rend2() const2779         const_reverse_iterator2 rend2 () const {
2780             return const_reverse_iterator2 (begin2 ());
2781         }
2782 
2783     private:
2784         expression1_closure_type e1_;
2785         expression2_closure_type e2_;
2786     };
2787 
2788     template<class E1, class E2, class F>
2789     struct matrix_binary_scalar1_traits {
2790         typedef matrix_binary_scalar1<E1, E2, F> expression_type;   // allow E1 to be builtin type
2791 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
2792         typedef expression_type result_type;
2793 #else
2794         typedef typename E2::matrix_temporary_type result_type;
2795 #endif
2796     };
2797 
2798     // (t * m) [i] [j] = t * m [i] [j]
2799     template<class T1, class E2>
2800     BOOST_UBLAS_INLINE
2801     typename matrix_binary_scalar1_traits<const T1, E2, scalar_multiplies<T1, typename E2::value_type> >::result_type
operator *(const T1 & e1,const matrix_expression<E2> & e2)2802     operator * (const T1 &e1,
2803                 const matrix_expression<E2> &e2) {
2804         typedef typename matrix_binary_scalar1_traits<const T1, E2, scalar_multiplies<T1, typename E2::value_type> >::expression_type expression_type;
2805         return expression_type (e1, e2 ());
2806     }
2807 
2808 
2809     template<class E1, class E2, class F>
2810     class matrix_binary_scalar2:
2811         public matrix_expression<matrix_binary_scalar2<E1, E2, F> > {
2812 
2813         typedef E1 expression1_type;
2814         typedef E2 expression2_type;
2815         typedef F functor_type;
2816     public:
2817         typedef typename E1::const_closure_type expression1_closure_type;
2818         typedef const E2& expression2_closure_type;
2819     private:
2820         typedef matrix_binary_scalar2<E1, E2, F> self_type;
2821     public:
2822 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
2823         using matrix_expression<self_type>::operator ();
2824 #endif
2825         typedef typename E1::size_type size_type;
2826         typedef typename E1::difference_type difference_type;
2827         typedef typename F::result_type value_type;
2828         typedef value_type const_reference;
2829         typedef const_reference reference;
2830 
2831         typedef const self_type const_closure_type;
2832         typedef const_closure_type closure_type;
2833         typedef typename E1::orientation_category orientation_category;
2834         typedef unknown_storage_tag storage_category;
2835 
2836         // Construction and destruction
2837         BOOST_UBLAS_INLINE
matrix_binary_scalar2(const expression1_type & e1,const expression2_type & e2)2838         matrix_binary_scalar2 (const expression1_type &e1, const expression2_type &e2):
2839             e1_ (e1), e2_ (e2) {}
2840 
2841         // Accessors
2842         BOOST_UBLAS_INLINE
size1() const2843         size_type size1 () const {
2844             return e1_.size1 ();
2845         }
2846         BOOST_UBLAS_INLINE
size2() const2847         size_type size2 () const {
2848             return e1_.size2 ();
2849         }
2850 
2851     public:
2852         // Element access
2853         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j) const2854         const_reference operator () (size_type i, size_type j) const {
2855             return functor_type::apply (e1_ (i, j), expression2_type (e2_));
2856         }
2857 
2858         // Closure comparison
2859         BOOST_UBLAS_INLINE
same_closure(const matrix_binary_scalar2 & mbs2) const2860         bool same_closure (const matrix_binary_scalar2 &mbs2) const {
2861             return (*this).e1_.same_closure (mbs2.e1_) &&
2862                    &e2_ == &(mbs2.e2_);
2863         }
2864 
2865         // Iterator types
2866     private:
2867         typedef typename E1::const_iterator1 const_iterator11_type;
2868         typedef typename E1::const_iterator2 const_iterator12_type;
2869         typedef expression2_type const_subiterator2_type;
2870         typedef const value_type *const_pointer;
2871 
2872     public:
2873 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
2874         typedef indexed_const_iterator1<const_closure_type, typename const_iterator11_type::iterator_category> const_iterator1;
2875         typedef const_iterator1 iterator1;
2876         typedef indexed_const_iterator2<const_closure_type, typename const_iterator12_type::iterator_category> const_iterator2;
2877         typedef const_iterator2 iterator2;
2878 #else
2879         class const_iterator1;
2880         typedef const_iterator1 iterator1;
2881         class const_iterator2;
2882         typedef const_iterator2 iterator2;
2883 #endif
2884         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
2885         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
2886 
2887         // Element lookup
2888         BOOST_UBLAS_INLINE
find1(int rank,size_type i,size_type j) const2889         const_iterator1 find1 (int rank, size_type i, size_type j) const {
2890             const_iterator11_type it11 (e1_.find1 (rank, i, j));
2891 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
2892             return const_iterator1 (*this, it11.index1 (), it11.index2 ());
2893 #else
2894             return const_iterator1 (*this, it11, const_subiterator2_type (e2_));
2895 #endif
2896         }
2897         BOOST_UBLAS_INLINE
find2(int rank,size_type i,size_type j) const2898         const_iterator2 find2 (int rank, size_type i, size_type j) const {
2899             const_iterator12_type it12 (e1_.find2 (rank, i, j));
2900 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
2901             return const_iterator2 (*this, it12.index1 (), it12.index2 ());
2902 #else
2903             return const_iterator2 (*this, it12, const_subiterator2_type (e2_));
2904 #endif
2905         }
2906 
2907         // Iterators enhance the iterators of the referenced expression
2908         // with the binary functor.
2909 
2910 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
2911         class const_iterator1:
2912             public container_const_reference<matrix_binary_scalar2>,
2913             public iterator_base_traits<typename E1::const_iterator1::iterator_category>::template
2914                 iterator_base<const_iterator1, value_type>::type {
2915         public:
2916             typedef typename E1::const_iterator1::iterator_category iterator_category;
2917             typedef typename matrix_binary_scalar2::difference_type difference_type;
2918             typedef typename matrix_binary_scalar2::value_type value_type;
2919             typedef typename matrix_binary_scalar2::const_reference reference;
2920             typedef typename matrix_binary_scalar2::const_pointer pointer;
2921 
2922             typedef const_iterator2 dual_iterator_type;
2923             typedef const_reverse_iterator2 dual_reverse_iterator_type;
2924 
2925             // Construction and destruction
2926             BOOST_UBLAS_INLINE
const_iterator1()2927             const_iterator1 ():
2928                 container_const_reference<self_type> (), it1_ (), it2_ () {}
2929             BOOST_UBLAS_INLINE
const_iterator1(const self_type & mbs,const const_iterator11_type & it1,const const_subiterator2_type & it2)2930             const_iterator1 (const self_type &mbs, const const_iterator11_type &it1, const const_subiterator2_type &it2):
2931                 container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {}
2932 
2933             // Arithmetic
2934             BOOST_UBLAS_INLINE
operator ++()2935             const_iterator1 &operator ++ () {
2936                 ++ it1_;
2937                 return *this;
2938             }
2939             BOOST_UBLAS_INLINE
operator --()2940             const_iterator1 &operator -- () {
2941                 -- it1_ ;
2942                 return *this;
2943             }
2944             BOOST_UBLAS_INLINE
operator +=(difference_type n)2945             const_iterator1 &operator += (difference_type n) {
2946                 it1_ += n;
2947                 return *this;
2948             }
2949             BOOST_UBLAS_INLINE
operator -=(difference_type n)2950             const_iterator1 &operator -= (difference_type n) {
2951                 it1_ -= n;
2952                 return *this;
2953             }
2954             BOOST_UBLAS_INLINE
operator -(const const_iterator1 & it) const2955             difference_type operator - (const const_iterator1 &it) const {
2956                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
2957                 // FIXME we shouldn't compare floats
2958                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
2959                 return it1_ - it.it1_;
2960             }
2961 
2962             // Dereference
2963             BOOST_UBLAS_INLINE
operator *() const2964             const_reference operator * () const {
2965                 return functor_type::apply (*it1_, it2_);
2966             }
2967 
2968 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
2969             BOOST_UBLAS_INLINE
2970 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2971             typename self_type::
2972 #endif
begin() const2973             const_iterator2 begin () const {
2974                 return (*this) ().find2 (1, index1 (), 0);
2975             }
2976             BOOST_UBLAS_INLINE
2977 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2978             typename self_type::
2979 #endif
end() const2980             const_iterator2 end () const {
2981                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
2982             }
2983             BOOST_UBLAS_INLINE
2984 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2985             typename self_type::
2986 #endif
rbegin() const2987             const_reverse_iterator2 rbegin () const {
2988                 return const_reverse_iterator2 (end ());
2989             }
2990             BOOST_UBLAS_INLINE
2991 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2992             typename self_type::
2993 #endif
rend() const2994             const_reverse_iterator2 rend () const {
2995                 return const_reverse_iterator2 (begin ());
2996             }
2997 #endif
2998 
2999             // Indices
3000             BOOST_UBLAS_INLINE
index1() const3001             size_type index1 () const {
3002                 return it1_.index1 ();
3003             }
3004             BOOST_UBLAS_INLINE
index2() const3005             size_type index2 () const {
3006                 return it1_.index2 ();
3007             }
3008 
3009             // Assignment
3010             BOOST_UBLAS_INLINE
operator =(const const_iterator1 & it)3011             const_iterator1 &operator = (const const_iterator1 &it) {
3012                 container_const_reference<self_type>::assign (&it ());
3013                 it1_ = it.it1_;
3014                 it2_ = it.it2_;
3015                 return *this;
3016             }
3017 
3018             // Comparison
3019             BOOST_UBLAS_INLINE
operator ==(const const_iterator1 & it) const3020             bool operator == (const const_iterator1 &it) const {
3021                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3022                 // FIXME we shouldn't compare floats
3023                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
3024                 return it1_ == it.it1_;
3025             }
3026             BOOST_UBLAS_INLINE
operator <(const const_iterator1 & it) const3027             bool operator < (const const_iterator1 &it) const {
3028                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3029                 // FIXME we shouldn't compare floats
3030                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
3031                 return it1_ < it.it1_;
3032             }
3033 
3034         private:
3035             const_iterator11_type it1_;
3036             const_subiterator2_type it2_;
3037         };
3038 #endif
3039 
3040         BOOST_UBLAS_INLINE
begin1() const3041         const_iterator1 begin1 () const {
3042             return find1 (0, 0, 0);
3043         }
3044         BOOST_UBLAS_INLINE
end1() const3045         const_iterator1 end1 () const {
3046             return find1 (0, size1 (), 0);
3047         }
3048 
3049 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
3050         class const_iterator2:
3051             public container_const_reference<matrix_binary_scalar2>,
3052             public iterator_base_traits<typename E1::const_iterator2::iterator_category>::template
3053                 iterator_base<const_iterator2, value_type>::type {
3054         public:
3055             typedef typename E1::const_iterator2::iterator_category iterator_category;
3056             typedef typename matrix_binary_scalar2::difference_type difference_type;
3057             typedef typename matrix_binary_scalar2::value_type value_type;
3058             typedef typename matrix_binary_scalar2::const_reference reference;
3059             typedef typename matrix_binary_scalar2::const_pointer pointer;
3060 
3061             typedef const_iterator1 dual_iterator_type;
3062             typedef const_reverse_iterator1 dual_reverse_iterator_type;
3063 
3064             // Construction and destruction
3065             BOOST_UBLAS_INLINE
const_iterator2()3066             const_iterator2 ():
3067                 container_const_reference<self_type> (), it1_ (), it2_ () {}
3068             BOOST_UBLAS_INLINE
const_iterator2(const self_type & mbs,const const_iterator12_type & it1,const const_subiterator2_type & it2)3069             const_iterator2 (const self_type &mbs, const const_iterator12_type &it1, const const_subiterator2_type &it2):
3070                 container_const_reference<self_type> (mbs), it1_ (it1), it2_ (it2) {}
3071 
3072             // Arithmetic
3073             BOOST_UBLAS_INLINE
operator ++()3074             const_iterator2 &operator ++ () {
3075                 ++ it1_;
3076                 return *this;
3077             }
3078             BOOST_UBLAS_INLINE
operator --()3079             const_iterator2 &operator -- () {
3080                 -- it1_;
3081                 return *this;
3082             }
3083             BOOST_UBLAS_INLINE
operator +=(difference_type n)3084             const_iterator2 &operator += (difference_type n) {
3085                 it1_ += n;
3086                 return *this;
3087             }
3088             BOOST_UBLAS_INLINE
operator -=(difference_type n)3089             const_iterator2 &operator -= (difference_type n) {
3090                 it1_ -= n;
3091                 return *this;
3092             }
3093             BOOST_UBLAS_INLINE
operator -(const const_iterator2 & it) const3094             difference_type operator - (const const_iterator2 &it) const {
3095                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3096                 // FIXME we shouldn't compare floats
3097                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
3098                 return it1_ - it.it1_;
3099             }
3100 
3101             // Dereference
3102             BOOST_UBLAS_INLINE
operator *() const3103             const_reference operator * () const {
3104                 return functor_type::apply (*it1_, it2_);
3105             }
3106 
3107 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
3108             BOOST_UBLAS_INLINE
3109 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
3110             typename self_type::
3111 #endif
begin() const3112             const_iterator1 begin () const {
3113                 return (*this) ().find1 (1, 0, index2 ());
3114             }
3115             BOOST_UBLAS_INLINE
3116 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
3117             typename self_type::
3118 #endif
end() const3119             const_iterator1 end () const {
3120                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
3121             }
3122             BOOST_UBLAS_INLINE
3123 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
3124             typename self_type::
3125 #endif
rbegin() const3126             const_reverse_iterator1 rbegin () const {
3127                 return const_reverse_iterator1 (end ());
3128             }
3129             BOOST_UBLAS_INLINE
3130 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
3131             typename self_type::
3132 #endif
rend() const3133             const_reverse_iterator1 rend () const {
3134                 return const_reverse_iterator1 (begin ());
3135             }
3136 #endif
3137 
3138             // Indices
3139             BOOST_UBLAS_INLINE
index1() const3140             size_type index1 () const {
3141                 return it1_.index1 ();
3142             }
3143             BOOST_UBLAS_INLINE
index2() const3144             size_type index2 () const {
3145                 return it1_.index2 ();
3146             }
3147 
3148             // Assignment
3149             BOOST_UBLAS_INLINE
operator =(const const_iterator2 & it)3150             const_iterator2 &operator = (const const_iterator2 &it) {
3151                 container_const_reference<self_type>::assign (&it ());
3152                 it1_ = it.it1_;
3153                 it2_ = it.it2_;
3154                 return *this;
3155             }
3156 
3157             // Comparison
3158             BOOST_UBLAS_INLINE
operator ==(const const_iterator2 & it) const3159             bool operator == (const const_iterator2 &it) const {
3160                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3161                 // FIXME we shouldn't compare floats
3162                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
3163                 return it1_ == it.it1_;
3164             }
3165             BOOST_UBLAS_INLINE
operator <(const const_iterator2 & it) const3166             bool operator < (const const_iterator2 &it) const {
3167                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3168                 // FIXME we shouldn't compare floats
3169                 // BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
3170                 return it1_ < it.it1_;
3171             }
3172 
3173         private:
3174             const_iterator12_type it1_;
3175             const_subiterator2_type it2_;
3176         };
3177 #endif
3178 
3179         BOOST_UBLAS_INLINE
begin2() const3180         const_iterator2 begin2 () const {
3181             return find2 (0, 0, 0);
3182         }
3183         BOOST_UBLAS_INLINE
end2() const3184         const_iterator2 end2 () const {
3185             return find2 (0, 0, size2 ());
3186         }
3187 
3188         // Reverse iterators
3189 
3190         BOOST_UBLAS_INLINE
rbegin1() const3191         const_reverse_iterator1 rbegin1 () const {
3192             return const_reverse_iterator1 (end1 ());
3193         }
3194         BOOST_UBLAS_INLINE
rend1() const3195         const_reverse_iterator1 rend1 () const {
3196             return const_reverse_iterator1 (begin1 ());
3197         }
3198 
3199         BOOST_UBLAS_INLINE
rbegin2() const3200         const_reverse_iterator2 rbegin2 () const {
3201             return const_reverse_iterator2 (end2 ());
3202         }
3203         BOOST_UBLAS_INLINE
rend2() const3204         const_reverse_iterator2 rend2 () const {
3205             return const_reverse_iterator2 (begin2 ());
3206         }
3207 
3208     private:
3209         expression1_closure_type e1_;
3210         expression2_closure_type e2_;
3211     };
3212 
3213     template<class E1, class E2, class F>
3214     struct matrix_binary_scalar2_traits {
3215         typedef matrix_binary_scalar2<E1, E2, F> expression_type;   // allow E2 to be builtin type
3216 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
3217         typedef expression_type result_type;
3218 #else
3219         typedef typename E1::matrix_temporary_type result_type;
3220 #endif
3221     };
3222 
3223     // (m * t) [i] [j] = m [i] [j] * t
3224     template<class E1, class T2>
3225     BOOST_UBLAS_INLINE
3226     typename matrix_binary_scalar2_traits<E1, const T2, scalar_multiplies<typename E1::value_type, T2> >::result_type
operator *(const matrix_expression<E1> & e1,const T2 & e2)3227     operator * (const matrix_expression<E1> &e1,
3228                 const T2 &e2) {
3229         typedef typename matrix_binary_scalar2_traits<E1, const T2, scalar_multiplies<typename E1::value_type, T2> >::expression_type expression_type;
3230         return expression_type (e1 (), e2);
3231     }
3232 
3233     // (m / t) [i] [j] = m [i] [j] / t
3234     template<class E1, class T2>
3235     BOOST_UBLAS_INLINE
3236     typename matrix_binary_scalar2_traits<E1, const T2, scalar_divides<typename E1::value_type, T2> >::result_type
operator /(const matrix_expression<E1> & e1,const T2 & e2)3237     operator / (const matrix_expression<E1> &e1,
3238                 const T2 &e2) {
3239         typedef typename matrix_binary_scalar2_traits<E1, const T2, scalar_divides<typename E1::value_type, T2> >::expression_type expression_type;
3240         return expression_type (e1 (), e2);
3241     }
3242 
3243 
3244     template<class E1, class E2, class F>
3245     class matrix_vector_binary1:
3246         public vector_expression<matrix_vector_binary1<E1, E2, F> > {
3247 
3248     public:
3249         typedef E1 expression1_type;
3250         typedef E2 expression2_type;
3251     private:
3252         typedef F functor_type;
3253     public:
3254         typedef typename E1::const_closure_type expression1_closure_type;
3255         typedef typename E2::const_closure_type expression2_closure_type;
3256     private:
3257         typedef matrix_vector_binary1<E1, E2, F> self_type;
3258     public:
3259 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
3260         using vector_expression<self_type>::operator ();
3261 #endif
3262         static const unsigned complexity = 1;
3263         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
3264         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
3265         typedef typename F::result_type value_type;
3266         typedef value_type const_reference;
3267         typedef const_reference reference;
3268         typedef const self_type const_closure_type;
3269         typedef const_closure_type closure_type;
3270         typedef unknown_storage_tag storage_category;
3271 
3272         // Construction and destruction
3273         BOOST_UBLAS_INLINE
matrix_vector_binary1(const expression1_type & e1,const expression2_type & e2)3274         matrix_vector_binary1 (const expression1_type &e1, const expression2_type &e2):
3275             e1_ (e1), e2_ (e2) {}
3276 
3277         // Accessors
3278         BOOST_UBLAS_INLINE
size() const3279         size_type size () const {
3280             return e1_.size1 ();
3281         }
3282 
3283     public:
3284         // Expression accessors
3285         BOOST_UBLAS_INLINE
expression1() const3286         const expression1_closure_type &expression1 () const {
3287             return e1_;
3288         }
3289         BOOST_UBLAS_INLINE
expression2() const3290         const expression2_closure_type &expression2 () const {
3291             return e2_;
3292         }
3293 
3294     public:
3295         // Element access
3296         BOOST_UBLAS_INLINE
operator ()(size_type i) const3297         const_reference operator () (size_type i) const {
3298             return functor_type::apply (e1_, e2_, i);
3299         }
3300 
3301         // Closure comparison
3302         BOOST_UBLAS_INLINE
same_closure(const matrix_vector_binary1 & mvb1) const3303         bool same_closure (const matrix_vector_binary1 &mvb1) const {
3304             return (*this).expression1 ().same_closure (mvb1.expression1 ()) &&
3305                    (*this).expression2 ().same_closure (mvb1.expression2 ());
3306         }
3307 
3308         // Iterator types
3309     private:
3310         typedef typename E1::const_iterator1 const_subiterator1_type;
3311         typedef typename E2::const_iterator const_subiterator2_type;
3312         typedef const value_type *const_pointer;
3313 
3314     public:
3315 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
3316         typedef indexed_const_iterator<const_closure_type, typename const_subiterator1_type::iterator_category> const_iterator;
3317         typedef const_iterator iterator;
3318 #else
3319         class const_iterator;
3320         typedef const_iterator iterator;
3321 #endif
3322 
3323         // Element lookup
3324         BOOST_UBLAS_INLINE
find(size_type i) const3325         const_iterator find (size_type i) const {
3326 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
3327             const_subiterator1_type it1 (e1_.find1 (0, i, 0));
3328             return const_iterator (*this, it1.index1 ());
3329 #else
3330             return const_iterator (*this, e1_.find1 (0, i, 0));
3331 #endif
3332         }
3333 
3334 
3335 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
3336         class const_iterator:
3337             public container_const_reference<matrix_vector_binary1>,
3338             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
3339                                                                           typename E2::const_iterator::iterator_category>::iterator_category>::template
3340                 iterator_base<const_iterator, value_type>::type {
3341         public:
3342             typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
3343                                                       typename E2::const_iterator::iterator_category>::iterator_category iterator_category;
3344             typedef typename matrix_vector_binary1::difference_type difference_type;
3345             typedef typename matrix_vector_binary1::value_type value_type;
3346             typedef typename matrix_vector_binary1::const_reference reference;
3347             typedef typename matrix_vector_binary1::const_pointer pointer;
3348 
3349             // Construction and destruction
3350 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3351             BOOST_UBLAS_INLINE
const_iterator()3352             const_iterator ():
3353                 container_const_reference<self_type> (), it1_ (), e2_begin_ (), e2_end_ () {}
3354             BOOST_UBLAS_INLINE
const_iterator(const self_type & mvb,const const_subiterator1_type & it1)3355             const_iterator (const self_type &mvb, const const_subiterator1_type &it1):
3356                 container_const_reference<self_type> (mvb), it1_ (it1), e2_begin_ (mvb.expression2 ().begin ()), e2_end_ (mvb.expression2 ().end ()) {}
3357 #else
3358             BOOST_UBLAS_INLINE
const_iterator()3359             const_iterator ():
3360                 container_const_reference<self_type> (), it1_ () {}
3361             BOOST_UBLAS_INLINE
const_iterator(const self_type & mvb,const const_subiterator1_type & it1)3362             const_iterator (const self_type &mvb, const const_subiterator1_type &it1):
3363                 container_const_reference<self_type> (mvb), it1_ (it1) {}
3364 #endif
3365 
3366             // Dense random access specialization
3367             BOOST_UBLAS_INLINE
dereference(dense_random_access_iterator_tag) const3368             value_type dereference (dense_random_access_iterator_tag) const {
3369                 const self_type &mvb = (*this) ();
3370 #ifdef BOOST_UBLAS_USE_INDEXING
3371                 return mvb (index ());
3372 #elif BOOST_UBLAS_USE_ITERATING
3373                 difference_type size = BOOST_UBLAS_SAME (mvb.expression1 ().size2 (), mvb.expression2 ().size ());
3374 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3375                 return functor_type::apply (size, it1_.begin (), e2_begin_);
3376 #else
3377                 return functor_type::apply (size, it1_.begin (), mvb.expression2 ().begin ());
3378 #endif
3379 #else
3380                 difference_type size = BOOST_UBLAS_SAME (mvb.expression1 ().size2 (), mvb.expression2 ().size ());
3381                 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
3382 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3383                     return functor_type::apply (size, it1_.begin (), e2_begin_);
3384 #else
3385                     return functor_type::apply (size, it1_.begin (), mvb.expression2 ().begin ());
3386 #endif
3387                 else
3388                     return mvb (index ());
3389 #endif
3390             }
3391 
3392             // Packed bidirectional specialization
3393             BOOST_UBLAS_INLINE
dereference(packed_random_access_iterator_tag) const3394             value_type dereference (packed_random_access_iterator_tag) const {
3395 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3396                 return functor_type::apply (it1_.begin (), it1_.end (), e2_begin_, e2_end_);
3397 #else
3398                 const self_type &mvb = (*this) ();
3399 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
3400                 return functor_type::apply (it1_.begin (), it1_.end (),
3401                                         mvb.expression2 ().begin (), mvb.expression2 ().end ());
3402 #else
3403                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
3404                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
3405                                         mvb.expression2 ().begin (), mvb.expression2 ().end ());
3406 #endif
3407 #endif
3408             }
3409 
3410             // Sparse bidirectional specialization
3411             BOOST_UBLAS_INLINE
dereference(sparse_bidirectional_iterator_tag) const3412             value_type dereference (sparse_bidirectional_iterator_tag) const {
3413 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3414                 return functor_type::apply (it1_.begin (), it1_.end (), e2_begin_, e2_end_, sparse_bidirectional_iterator_tag ());
3415 #else
3416                 const self_type &mvb = (*this) ();
3417 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
3418                 return functor_type::apply (it1_.begin (), it1_.end (),
3419                                         mvb.expression2 ().begin (), mvb.expression2 ().end (), sparse_bidirectional_iterator_tag ());
3420 #else
3421                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
3422                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
3423                                         mvb.expression2 ().begin (), mvb.expression2 ().end (), sparse_bidirectional_iterator_tag ());
3424 #endif
3425 #endif
3426             }
3427 
3428             // Arithmetic
3429             BOOST_UBLAS_INLINE
operator ++()3430             const_iterator &operator ++ () {
3431                 ++ it1_;
3432                 return *this;
3433             }
3434             BOOST_UBLAS_INLINE
operator --()3435             const_iterator &operator -- () {
3436                 -- it1_;
3437                 return *this;
3438             }
3439             BOOST_UBLAS_INLINE
operator +=(difference_type n)3440             const_iterator &operator += (difference_type n) {
3441                 it1_ += n;
3442                 return *this;
3443             }
3444             BOOST_UBLAS_INLINE
operator -=(difference_type n)3445             const_iterator &operator -= (difference_type n) {
3446                 it1_ -= n;
3447                 return *this;
3448             }
3449             BOOST_UBLAS_INLINE
operator -(const const_iterator & it) const3450             difference_type operator - (const const_iterator &it) const {
3451                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3452                 return it1_ - it.it1_;
3453             }
3454 
3455             // Dereference
3456             BOOST_UBLAS_INLINE
operator *() const3457             const_reference operator * () const {
3458                 return dereference (iterator_category ());
3459             }
3460 
3461             // Index
3462             BOOST_UBLAS_INLINE
index() const3463             size_type index () const {
3464                 return it1_.index1 ();
3465             }
3466 
3467             // Assignment
3468             BOOST_UBLAS_INLINE
operator =(const const_iterator & it)3469             const_iterator &operator = (const const_iterator &it) {
3470                 container_const_reference<self_type>::assign (&it ());
3471                 it1_ = it.it1_;
3472 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3473                 e2_begin_ = it.e2_begin_;
3474                 e2_end_ = it.e2_end_;
3475 #endif
3476                 return *this;
3477             }
3478 
3479             // Comparison
3480             BOOST_UBLAS_INLINE
operator ==(const const_iterator & it) const3481             bool operator == (const const_iterator &it) const {
3482                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3483                 return it1_ == it.it1_;
3484             }
3485             BOOST_UBLAS_INLINE
operator <(const const_iterator & it) const3486             bool operator < (const const_iterator &it) const {
3487                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3488                 return it1_ < it.it1_;
3489             }
3490 
3491         private:
3492             const_subiterator1_type it1_;
3493 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3494             // Mutable due to assignment
3495             /* const */ const_subiterator2_type e2_begin_;
3496             /* const */ const_subiterator2_type e2_end_;
3497 #endif
3498         };
3499 #endif
3500 
3501         BOOST_UBLAS_INLINE
begin() const3502         const_iterator begin () const {
3503             return find (0);
3504         }
3505         BOOST_UBLAS_INLINE
end() const3506         const_iterator end () const {
3507             return find (size ());
3508         }
3509 
3510         // Reverse iterator
3511         typedef reverse_iterator_base<const_iterator> const_reverse_iterator;
3512 
3513         BOOST_UBLAS_INLINE
rbegin() const3514         const_reverse_iterator rbegin () const {
3515             return const_reverse_iterator (end ());
3516         }
3517         BOOST_UBLAS_INLINE
rend() const3518         const_reverse_iterator rend () const {
3519             return const_reverse_iterator (begin ());
3520         }
3521 
3522     private:
3523         expression1_closure_type e1_;
3524         expression2_closure_type e2_;
3525     };
3526 
3527     template<class T1, class E1, class T2, class E2>
3528     struct matrix_vector_binary1_traits {
3529         typedef unknown_storage_tag storage_category;
3530         typedef row_major_tag orientation_category;
3531         typedef typename promote_traits<T1, T2>::promote_type promote_type;
3532         typedef matrix_vector_binary1<E1, E2, matrix_vector_prod1<T1, T2, promote_type> > expression_type;
3533 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
3534         typedef expression_type result_type;
3535 #else
3536         typedef typename E1::vector_temporary_type result_type;
3537 #endif
3538     };
3539 
3540     template<class E1, class E2>
3541     BOOST_UBLAS_INLINE
3542     typename matrix_vector_binary1_traits<typename E1::value_type, E1,
3543                                           typename E2::value_type, E2>::result_type
prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2,unknown_storage_tag,row_major_tag)3544     prod (const matrix_expression<E1> &e1,
3545           const vector_expression<E2> &e2,
3546           unknown_storage_tag,
3547           row_major_tag) {
3548         typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1,
3549                                                                   typename E2::value_type, E2>::expression_type expression_type;
3550         return expression_type (e1 (), e2 ());
3551     }
3552 
3553     // Dispatcher
3554     template<class E1, class E2>
3555     BOOST_UBLAS_INLINE
3556     typename matrix_vector_binary1_traits<typename E1::value_type, E1,
3557                                           typename E2::value_type, E2>::result_type
prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2)3558     prod (const matrix_expression<E1> &e1,
3559           const vector_expression<E2> &e2) {
3560         BOOST_STATIC_ASSERT (E2::complexity == 0);
3561         typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1,
3562                                                                   typename E2::value_type, E2>::storage_category storage_category;
3563         typedef typename matrix_vector_binary1_traits<typename E1::value_type, E1,
3564                                                                   typename E2::value_type, E2>::orientation_category orientation_category;
3565         return prod (e1, e2, storage_category (), orientation_category ());
3566     }
3567 
3568     template<class E1, class E2>
3569     BOOST_UBLAS_INLINE
3570     typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3571                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
prec_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2,unknown_storage_tag,row_major_tag)3572     prec_prod (const matrix_expression<E1> &e1,
3573                const vector_expression<E2> &e2,
3574                unknown_storage_tag,
3575                row_major_tag) {
3576         typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3577                                                                   typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type;
3578         return expression_type (e1 (), e2 ());
3579     }
3580 
3581     // Dispatcher
3582     template<class E1, class E2>
3583     BOOST_UBLAS_INLINE
3584     typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3585                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
prec_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2)3586     prec_prod (const matrix_expression<E1> &e1,
3587                const vector_expression<E2> &e2) {
3588         BOOST_STATIC_ASSERT (E2::complexity == 0);
3589         typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3590                                                                   typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category;
3591         typedef typename matrix_vector_binary1_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3592                                                                   typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category;
3593         return prec_prod (e1, e2, storage_category (), orientation_category ());
3594     }
3595 
3596     template<class V, class E1, class E2>
3597     BOOST_UBLAS_INLINE
3598     V &
prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2,V & v)3599     prod (const matrix_expression<E1> &e1,
3600           const vector_expression<E2> &e2,
3601           V &v) {
3602         return v.assign (prod (e1, e2));
3603     }
3604 
3605     template<class V, class E1, class E2>
3606     BOOST_UBLAS_INLINE
3607     V &
prec_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2,V & v)3608     prec_prod (const matrix_expression<E1> &e1,
3609                const vector_expression<E2> &e2,
3610                V &v) {
3611         return v.assign (prec_prod (e1, e2));
3612     }
3613 
3614     template<class V, class E1, class E2>
3615     BOOST_UBLAS_INLINE
3616     V
prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2)3617     prod (const matrix_expression<E1> &e1,
3618           const vector_expression<E2> &e2) {
3619         return V (prod (e1, e2));
3620     }
3621 
3622     template<class V, class E1, class E2>
3623     BOOST_UBLAS_INLINE
3624     V
prec_prod(const matrix_expression<E1> & e1,const vector_expression<E2> & e2)3625     prec_prod (const matrix_expression<E1> &e1,
3626                const vector_expression<E2> &e2) {
3627         return V (prec_prod (e1, e2));
3628     }
3629 
3630     template<class E1, class E2, class F>
3631     class matrix_vector_binary2:
3632         public vector_expression<matrix_vector_binary2<E1, E2, F> > {
3633 
3634         typedef E1 expression1_type;
3635         typedef E2 expression2_type;
3636         typedef F functor_type;
3637     public:
3638         typedef typename E1::const_closure_type expression1_closure_type;
3639         typedef typename E2::const_closure_type expression2_closure_type;
3640     private:
3641         typedef matrix_vector_binary2<E1, E2, F> self_type;
3642     public:
3643 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
3644         using vector_expression<self_type>::operator ();
3645 #endif
3646         static const unsigned complexity = 1;
3647         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
3648         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
3649         typedef typename F::result_type value_type;
3650         typedef value_type const_reference;
3651         typedef const_reference reference;
3652         typedef const self_type const_closure_type;
3653         typedef const_closure_type closure_type;
3654         typedef unknown_storage_tag storage_category;
3655 
3656         // Construction and destruction
3657         BOOST_UBLAS_INLINE
matrix_vector_binary2(const expression1_type & e1,const expression2_type & e2)3658         matrix_vector_binary2 (const expression1_type &e1, const expression2_type &e2):
3659             e1_ (e1), e2_ (e2) {}
3660 
3661         // Accessors
3662         BOOST_UBLAS_INLINE
size() const3663         size_type size () const {
3664             return e2_.size2 ();
3665         }
3666 
3667     public:
3668         // Expression accessors
3669         BOOST_UBLAS_INLINE
expression1() const3670         const expression1_closure_type &expression1 () const {
3671             return e1_;
3672         }
3673         BOOST_UBLAS_INLINE
expression2() const3674         const expression2_closure_type &expression2 () const {
3675             return e2_;
3676         }
3677     public:
3678 
3679         // Element access
3680         BOOST_UBLAS_INLINE
operator ()(size_type j) const3681         const_reference operator () (size_type j) const {
3682             return functor_type::apply (e1_, e2_, j);
3683         }
3684 
3685         // Closure comparison
3686         BOOST_UBLAS_INLINE
same_closure(const matrix_vector_binary2 & mvb2) const3687         bool same_closure (const matrix_vector_binary2 &mvb2) const {
3688             return (*this).expression1 ().same_closure (mvb2.expression1 ()) &&
3689                    (*this).expression2 ().same_closure (mvb2.expression2 ());
3690         }
3691 
3692         // Iterator types
3693     private:
3694         typedef typename E1::const_iterator const_subiterator1_type;
3695         typedef typename E2::const_iterator2 const_subiterator2_type;
3696         typedef const value_type *const_pointer;
3697 
3698     public:
3699 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
3700         typedef indexed_const_iterator<const_closure_type, typename const_subiterator2_type::iterator_category> const_iterator;
3701         typedef const_iterator iterator;
3702 #else
3703         class const_iterator;
3704         typedef const_iterator iterator;
3705 #endif
3706 
3707         // Element lookup
3708         BOOST_UBLAS_INLINE
find(size_type j) const3709         const_iterator find (size_type j) const {
3710 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
3711             const_subiterator2_type it2 (e2_.find2 (0, 0, j));
3712             return const_iterator (*this, it2.index2 ());
3713 #else
3714             return const_iterator (*this, e2_.find2 (0, 0, j));
3715 #endif
3716         }
3717 
3718 
3719 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
3720         class const_iterator:
3721             public container_const_reference<matrix_vector_binary2>,
3722             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
3723                                                                           typename E2::const_iterator2::iterator_category>::iterator_category>::template
3724                 iterator_base<const_iterator, value_type>::type {
3725         public:
3726             typedef typename iterator_restrict_traits<typename E1::const_iterator::iterator_category,
3727                                                       typename E2::const_iterator2::iterator_category>::iterator_category iterator_category;
3728             typedef typename matrix_vector_binary2::difference_type difference_type;
3729             typedef typename matrix_vector_binary2::value_type value_type;
3730             typedef typename matrix_vector_binary2::const_reference reference;
3731             typedef typename matrix_vector_binary2::const_pointer pointer;
3732 
3733             // Construction and destruction
3734 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3735             BOOST_UBLAS_INLINE
const_iterator()3736             const_iterator ():
3737                 container_const_reference<self_type> (), it2_ (), e1_begin_ (), e1_end_ () {}
3738             BOOST_UBLAS_INLINE
const_iterator(const self_type & mvb,const const_subiterator2_type & it2)3739             const_iterator (const self_type &mvb, const const_subiterator2_type &it2):
3740                 container_const_reference<self_type> (mvb), it2_ (it2), e1_begin_ (mvb.expression1 ().begin ()), e1_end_ (mvb.expression1 ().end ()) {}
3741 #else
3742             BOOST_UBLAS_INLINE
const_iterator()3743             const_iterator ():
3744                 container_const_reference<self_type> (), it2_ () {}
3745             BOOST_UBLAS_INLINE
const_iterator(const self_type & mvb,const const_subiterator2_type & it2)3746             const_iterator (const self_type &mvb, const const_subiterator2_type &it2):
3747                 container_const_reference<self_type> (mvb), it2_ (it2) {}
3748 #endif
3749 
3750             // Dense random access specialization
3751             BOOST_UBLAS_INLINE
dereference(dense_random_access_iterator_tag) const3752             value_type dereference (dense_random_access_iterator_tag) const {
3753                 const self_type &mvb = (*this) ();
3754 #ifdef BOOST_UBLAS_USE_INDEXING
3755                 return mvb (index ());
3756 #elif BOOST_UBLAS_USE_ITERATING
3757                 difference_type size = BOOST_UBLAS_SAME (mvb.expression2 ().size1 (), mvb.expression1 ().size ());
3758 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3759                 return functor_type::apply (size, e1_begin_, it2_.begin ());
3760 #else
3761                 return functor_type::apply (size, mvb.expression1 ().begin (), it2_.begin ());
3762 #endif
3763 #else
3764                 difference_type size = BOOST_UBLAS_SAME (mvb.expression2 ().size1 (), mvb.expression1 ().size ());
3765                 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
3766 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3767                     return functor_type::apply (size, e1_begin_, it2_.begin ());
3768 #else
3769                     return functor_type::apply (size, mvb.expression1 ().begin (), it2_.begin ());
3770 #endif
3771                 else
3772                     return mvb (index ());
3773 #endif
3774             }
3775 
3776             // Packed bidirectional specialization
3777             BOOST_UBLAS_INLINE
dereference(packed_random_access_iterator_tag) const3778             value_type dereference (packed_random_access_iterator_tag) const {
3779 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3780                 return functor_type::apply (e1_begin_, e1_end_, it2_.begin (), it2_.end ());
3781 #else
3782                 const self_type &mvb = (*this) ();
3783 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
3784                 return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (),
3785                                         it2_.begin (), it2_.end ());
3786 #else
3787                 return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (),
3788                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
3789                                         boost::numeric::ublas::end (it2_, iterator2_tag ()));
3790 #endif
3791 #endif
3792             }
3793 
3794             // Sparse bidirectional specialization
3795             BOOST_UBLAS_INLINE
dereference(sparse_bidirectional_iterator_tag) const3796             value_type dereference (sparse_bidirectional_iterator_tag) const {
3797 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3798                 return functor_type::apply (e1_begin_, e1_end_, it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
3799 #else
3800                 const self_type &mvb = (*this) ();
3801 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
3802                 return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (),
3803                                         it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
3804 #else
3805                 return functor_type::apply (mvb.expression1 ().begin (), mvb.expression1 ().end (),
3806                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
3807                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ());
3808 #endif
3809 #endif
3810             }
3811 
3812             // Arithmetic
3813             BOOST_UBLAS_INLINE
operator ++()3814             const_iterator &operator ++ () {
3815                 ++ it2_;
3816                 return *this;
3817             }
3818             BOOST_UBLAS_INLINE
operator --()3819             const_iterator &operator -- () {
3820                 -- it2_;
3821                 return *this;
3822             }
3823             BOOST_UBLAS_INLINE
operator +=(difference_type n)3824             const_iterator &operator += (difference_type n) {
3825                 it2_ += n;
3826                 return *this;
3827             }
3828             BOOST_UBLAS_INLINE
operator -=(difference_type n)3829             const_iterator &operator -= (difference_type n) {
3830                 it2_ -= n;
3831                 return *this;
3832             }
3833             BOOST_UBLAS_INLINE
operator -(const const_iterator & it) const3834             difference_type operator - (const const_iterator &it) const {
3835                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3836                 return it2_ - it.it2_;
3837             }
3838 
3839             // Dereference
3840             BOOST_UBLAS_INLINE
operator *() const3841             const_reference operator * () const {
3842                 return dereference (iterator_category ());
3843             }
3844 
3845             // Index
3846             BOOST_UBLAS_INLINE
index() const3847             size_type index () const {
3848                 return it2_.index2 ();
3849             }
3850 
3851             // Assignment
3852             BOOST_UBLAS_INLINE
operator =(const const_iterator & it)3853             const_iterator &operator = (const const_iterator &it) {
3854                 container_const_reference<self_type>::assign (&it ());
3855                 it2_ = it.it2_;
3856 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3857                 e1_begin_ = it.e1_begin_;
3858                 e1_end_ = it.e1_end_;
3859 #endif
3860                 return *this;
3861             }
3862 
3863             // Comparison
3864             BOOST_UBLAS_INLINE
operator ==(const const_iterator & it) const3865             bool operator == (const const_iterator &it) const {
3866                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3867                 return it2_ == it.it2_;
3868             }
3869             BOOST_UBLAS_INLINE
operator <(const const_iterator & it) const3870             bool operator < (const const_iterator &it) const {
3871                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
3872                 return it2_ < it.it2_;
3873             }
3874 
3875         private:
3876             const_subiterator2_type it2_;
3877 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
3878             // Mutable due to assignment
3879             /* const */ const_subiterator1_type e1_begin_;
3880             /* const */ const_subiterator1_type e1_end_;
3881 #endif
3882         };
3883 #endif
3884 
3885         BOOST_UBLAS_INLINE
begin() const3886         const_iterator begin () const {
3887             return find (0);
3888         }
3889         BOOST_UBLAS_INLINE
end() const3890         const_iterator end () const {
3891             return find (size ());
3892         }
3893 
3894         // Reverse iterator
3895         typedef reverse_iterator_base<const_iterator> const_reverse_iterator;
3896 
3897         BOOST_UBLAS_INLINE
rbegin() const3898         const_reverse_iterator rbegin () const {
3899             return const_reverse_iterator (end ());
3900         }
3901         BOOST_UBLAS_INLINE
rend() const3902         const_reverse_iterator rend () const {
3903             return const_reverse_iterator (begin ());
3904         }
3905 
3906     private:
3907         expression1_closure_type e1_;
3908         expression2_closure_type e2_;
3909     };
3910 
3911     template<class T1, class E1, class T2, class E2>
3912     struct matrix_vector_binary2_traits {
3913         typedef unknown_storage_tag storage_category;
3914         typedef column_major_tag orientation_category;
3915         typedef typename promote_traits<T1, T2>::promote_type promote_type;
3916         typedef matrix_vector_binary2<E1, E2, matrix_vector_prod2<T1, T2, promote_type> > expression_type;
3917 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
3918         typedef expression_type result_type;
3919 #else
3920         typedef typename E2::vector_temporary_type result_type;
3921 #endif
3922     };
3923 
3924     template<class E1, class E2>
3925     BOOST_UBLAS_INLINE
3926     typename matrix_vector_binary2_traits<typename E1::value_type, E1,
3927                                           typename E2::value_type, E2>::result_type
prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2,unknown_storage_tag,column_major_tag)3928     prod (const vector_expression<E1> &e1,
3929           const matrix_expression<E2> &e2,
3930           unknown_storage_tag,
3931           column_major_tag) {
3932         typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1,
3933                                                                   typename E2::value_type, E2>::expression_type expression_type;
3934         return expression_type (e1 (), e2 ());
3935     }
3936 
3937     // Dispatcher
3938     template<class E1, class E2>
3939     BOOST_UBLAS_INLINE
3940     typename matrix_vector_binary2_traits<typename E1::value_type, E1,
3941                                           typename E2::value_type, E2>::result_type
prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2)3942     prod (const vector_expression<E1> &e1,
3943           const matrix_expression<E2> &e2) {
3944         BOOST_STATIC_ASSERT (E1::complexity == 0);
3945         typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1,
3946                                                                   typename E2::value_type, E2>::storage_category storage_category;
3947         typedef typename matrix_vector_binary2_traits<typename E1::value_type, E1,
3948                                                                   typename E2::value_type, E2>::orientation_category orientation_category;
3949         return prod (e1, e2, storage_category (), orientation_category ());
3950     }
3951 
3952     template<class E1, class E2>
3953     BOOST_UBLAS_INLINE
3954     typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3955                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
prec_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2,unknown_storage_tag,column_major_tag)3956     prec_prod (const vector_expression<E1> &e1,
3957                const matrix_expression<E2> &e2,
3958                unknown_storage_tag,
3959                column_major_tag) {
3960         typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3961                                                                   typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type;
3962         return expression_type (e1 (), e2 ());
3963     }
3964 
3965     // Dispatcher
3966     template<class E1, class E2>
3967     BOOST_UBLAS_INLINE
3968     typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3969                                           typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
prec_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2)3970     prec_prod (const vector_expression<E1> &e1,
3971                const matrix_expression<E2> &e2) {
3972         BOOST_STATIC_ASSERT (E1::complexity == 0);
3973         typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3974                                                                   typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category;
3975         typedef typename matrix_vector_binary2_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
3976                                                                   typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category;
3977         return prec_prod (e1, e2, storage_category (), orientation_category ());
3978     }
3979 
3980     template<class V, class E1, class E2>
3981     BOOST_UBLAS_INLINE
3982     V &
prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2,V & v)3983     prod (const vector_expression<E1> &e1,
3984           const matrix_expression<E2> &e2,
3985           V &v) {
3986         return v.assign (prod (e1, e2));
3987     }
3988 
3989     template<class V, class E1, class E2>
3990     BOOST_UBLAS_INLINE
3991     V &
prec_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2,V & v)3992     prec_prod (const vector_expression<E1> &e1,
3993                const matrix_expression<E2> &e2,
3994                V &v) {
3995         return v.assign (prec_prod (e1, e2));
3996     }
3997 
3998     template<class V, class E1, class E2>
3999     BOOST_UBLAS_INLINE
4000     V
prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2)4001     prod (const vector_expression<E1> &e1,
4002           const matrix_expression<E2> &e2) {
4003         return V (prod (e1, e2));
4004     }
4005 
4006     template<class V, class E1, class E2>
4007     BOOST_UBLAS_INLINE
4008     V
prec_prod(const vector_expression<E1> & e1,const matrix_expression<E2> & e2)4009     prec_prod (const vector_expression<E1> &e1,
4010                const matrix_expression<E2> &e2) {
4011         return V (prec_prod (e1, e2));
4012     }
4013 
4014     template<class E1, class E2, class F>
4015     class matrix_matrix_binary:
4016         public matrix_expression<matrix_matrix_binary<E1, E2, F> > {
4017 
4018     public:
4019         typedef E1 expression1_type;
4020         typedef E2 expression2_type;
4021     private:
4022         typedef F functor_type;
4023     public:
4024         typedef typename E1::const_closure_type expression1_closure_type;
4025         typedef typename E2::const_closure_type expression2_closure_type;
4026     private:
4027         typedef matrix_matrix_binary<E1, E2, F> self_type;
4028     public:
4029 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
4030         using matrix_expression<self_type>::operator ();
4031 #endif
4032         static const unsigned complexity = 1;
4033         typedef typename promote_traits<typename E1::size_type, typename E2::size_type>::promote_type size_type;
4034         typedef typename promote_traits<typename E1::difference_type, typename E2::difference_type>::promote_type difference_type;
4035         typedef typename F::result_type value_type;
4036         typedef value_type const_reference;
4037         typedef const_reference reference;
4038         typedef const self_type const_closure_type;
4039         typedef const_closure_type closure_type;
4040         typedef unknown_orientation_tag orientation_category;
4041         typedef unknown_storage_tag storage_category;
4042 
4043         // Construction and destruction
4044         BOOST_UBLAS_INLINE
matrix_matrix_binary(const expression1_type & e1,const expression2_type & e2)4045         matrix_matrix_binary (const expression1_type &e1, const expression2_type &e2):
4046             e1_ (e1), e2_ (e2) {}
4047 
4048         // Accessors
4049         BOOST_UBLAS_INLINE
size1() const4050         size_type size1 () const {
4051             return e1_.size1 ();
4052         }
4053         BOOST_UBLAS_INLINE
size2() const4054         size_type size2 () const {
4055             return e2_.size2 ();
4056         }
4057 
4058     public:
4059         // Expression accessors
4060         BOOST_UBLAS_INLINE
expression1() const4061         const expression1_closure_type &expression1 () const {
4062             return e1_;
4063         }
4064         BOOST_UBLAS_INLINE
expression2() const4065         const expression2_closure_type &expression2 () const {
4066             return e2_;
4067         }
4068 
4069     public:
4070         // Element access
4071         BOOST_UBLAS_INLINE
operator ()(size_type i,size_type j) const4072         const_reference operator () (size_type i, size_type j) const {
4073             return functor_type::apply (e1_, e2_, i, j);
4074         }
4075 
4076         // Closure comparison
4077         BOOST_UBLAS_INLINE
same_closure(const matrix_matrix_binary & mmb) const4078         bool same_closure (const matrix_matrix_binary &mmb) const {
4079             return (*this).expression1 ().same_closure (mmb.expression1 ()) &&
4080                    (*this).expression2 ().same_closure (mmb.expression2 ());
4081         }
4082 
4083         // Iterator types
4084     private:
4085         typedef typename E1::const_iterator1 const_iterator11_type;
4086         typedef typename E1::const_iterator2 const_iterator12_type;
4087         typedef typename E2::const_iterator1 const_iterator21_type;
4088         typedef typename E2::const_iterator2 const_iterator22_type;
4089         typedef const value_type *const_pointer;
4090 
4091     public:
4092 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
4093         typedef typename iterator_restrict_traits<typename const_iterator11_type::iterator_category,
4094                                                   typename const_iterator22_type::iterator_category>::iterator_category iterator_category;
4095         typedef indexed_const_iterator1<const_closure_type, iterator_category> const_iterator1;
4096         typedef const_iterator1 iterator1;
4097         typedef indexed_const_iterator2<const_closure_type, iterator_category> const_iterator2;
4098         typedef const_iterator2 iterator2;
4099 #else
4100         class const_iterator1;
4101         typedef const_iterator1 iterator1;
4102         class const_iterator2;
4103         typedef const_iterator2 iterator2;
4104 #endif
4105         typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
4106         typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
4107 
4108         // Element lookup
4109         BOOST_UBLAS_INLINE
find1(int,size_type i,size_type j) const4110         const_iterator1 find1 (int /* rank */, size_type i, size_type j) const {
4111             // FIXME sparse matrix tests fail!
4112             // const_iterator11_type it11 (e1_.find1 (rank, i, 0));
4113             const_iterator11_type it11 (e1_.find1 (0, i, 0));
4114 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
4115             return const_iterator1 (*this, it11.index1 (), j);
4116 #else
4117             // FIXME sparse matrix tests fail!
4118             // const_iterator22_type it22 (e2_.find2 (rank, 0, j));
4119             const_iterator22_type it22 (e2_.find2 (0, 0, j));
4120             return const_iterator1 (*this, it11, it22);
4121 #endif
4122         }
4123         BOOST_UBLAS_INLINE
find2(int,size_type i,size_type j) const4124         const_iterator2 find2 (int /* rank */, size_type i, size_type j) const {
4125             // FIXME sparse matrix tests fail!
4126             // const_iterator22_type it22 (e2_.find2 (rank, 0, j));
4127             const_iterator22_type it22 (e2_.find2 (0, 0, j));
4128 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
4129             return const_iterator2 (*this, i, it22.index2 ());
4130 #else
4131             // FIXME sparse matrix tests fail!
4132             // const_iterator11_type it11 (e1_.find1 (rank, i, 0));
4133             const_iterator11_type it11 (e1_.find1 (0, i, 0));
4134             return const_iterator2 (*this, it11, it22);
4135 #endif
4136         }
4137 
4138 
4139 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
4140         class const_iterator1:
4141             public container_const_reference<matrix_matrix_binary>,
4142             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
4143                                                                           typename E2::const_iterator2::iterator_category>::iterator_category>::template
4144                 iterator_base<const_iterator1, value_type>::type {
4145         public:
4146             typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
4147                                                       typename E2::const_iterator2::iterator_category>::iterator_category iterator_category;
4148             typedef typename matrix_matrix_binary::difference_type difference_type;
4149             typedef typename matrix_matrix_binary::value_type value_type;
4150             typedef typename matrix_matrix_binary::const_reference reference;
4151             typedef typename matrix_matrix_binary::const_pointer pointer;
4152 
4153             typedef const_iterator2 dual_iterator_type;
4154             typedef const_reverse_iterator2 dual_reverse_iterator_type;
4155 
4156             // Construction and destruction
4157 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4158             BOOST_UBLAS_INLINE
const_iterator1()4159             const_iterator1 ():
4160                 container_const_reference<self_type> (), it1_ (), it2_ (), it2_begin_ (), it2_end_ () {}
4161             BOOST_UBLAS_INLINE
const_iterator1(const self_type & mmb,const const_iterator11_type & it1,const const_iterator22_type & it2)4162             const_iterator1 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2):
4163                 container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2), it2_begin_ (it2.begin ()), it2_end_ (it2.end ()) {}
4164 #else
4165             BOOST_UBLAS_INLINE
const_iterator1()4166             const_iterator1 ():
4167                 container_const_reference<self_type> (), it1_ (), it2_ () {}
4168             BOOST_UBLAS_INLINE
const_iterator1(const self_type & mmb,const const_iterator11_type & it1,const const_iterator22_type & it2)4169             const_iterator1 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2):
4170                 container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2) {}
4171 #endif
4172 
4173             // Random access specialization
4174             BOOST_UBLAS_INLINE
dereference(dense_random_access_iterator_tag) const4175             value_type dereference (dense_random_access_iterator_tag) const {
4176                 const self_type &mmb = (*this) ();
4177 #ifdef BOOST_UBLAS_USE_INDEXING
4178                 return mmb (index1 (), index2 ());
4179 #elif BOOST_UBLAS_USE_ITERATING
4180                 difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ());
4181 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4182                 return functor_type::apply (size, it1_.begin (), it2_begin_);
4183 #else
4184                 return functor_type::apply (size, it1_.begin (), it2_.begin ());
4185 #endif
4186 #else
4187                 difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ());
4188                 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
4189 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4190                     return functor_type::apply (size, it1_.begin (), it2_begin_);
4191 #else
4192                     return functor_type::apply (size, it1_.begin (), it2_.begin ());
4193 #endif
4194                 else
4195                     return mmb (index1 (), index2 ());
4196 #endif
4197             }
4198 
4199             // Packed bidirectional specialization
4200             BOOST_UBLAS_INLINE
dereference(packed_random_access_iterator_tag) const4201             value_type dereference (packed_random_access_iterator_tag) const {
4202 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4203                 return functor_type::apply (it1_.begin (), it1_.end (),
4204                                         it2_begin_, it2_end_, packed_random_access_iterator_tag ());
4205 #else
4206 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
4207                 return functor_type::apply (it1_.begin (), it1_.end (),
4208                                         it2_.begin (), it2_.end (), packed_random_access_iterator_tag ());
4209 #else
4210                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
4211                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
4212                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
4213                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), packed_random_access_iterator_tag ());
4214 #endif
4215 #endif
4216             }
4217 
4218             // Sparse bidirectional specialization
4219             BOOST_UBLAS_INLINE
dereference(sparse_bidirectional_iterator_tag) const4220             value_type dereference (sparse_bidirectional_iterator_tag) const {
4221 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4222                 return functor_type::apply (it1_.begin (), it1_.end (),
4223                                         it2_begin_, it2_end_, sparse_bidirectional_iterator_tag ());
4224 #else
4225 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
4226                 return functor_type::apply (it1_.begin (), it1_.end (),
4227                                         it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
4228 #else
4229                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
4230                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
4231                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
4232                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ());
4233 #endif
4234 #endif
4235             }
4236 
4237             // Arithmetic
4238             BOOST_UBLAS_INLINE
operator ++()4239             const_iterator1 &operator ++ () {
4240                 ++ it1_;
4241                 return *this;
4242             }
4243             BOOST_UBLAS_INLINE
operator --()4244             const_iterator1 &operator -- () {
4245                 -- it1_;
4246                 return *this;
4247             }
4248             BOOST_UBLAS_INLINE
operator +=(difference_type n)4249             const_iterator1 &operator += (difference_type n) {
4250                 it1_ += n;
4251                 return *this;
4252             }
4253             BOOST_UBLAS_INLINE
operator -=(difference_type n)4254             const_iterator1 &operator -= (difference_type n) {
4255                 it1_ -= n;
4256                 return *this;
4257             }
4258             BOOST_UBLAS_INLINE
operator -(const const_iterator1 & it) const4259             difference_type operator - (const const_iterator1 &it) const {
4260                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
4261                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
4262                 return it1_ - it.it1_;
4263             }
4264 
4265             // Dereference
4266             BOOST_UBLAS_INLINE
operator *() const4267             const_reference operator * () const {
4268                 return dereference (iterator_category ());
4269             }
4270 
4271 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
4272             BOOST_UBLAS_INLINE
4273 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
4274             typename self_type::
4275 #endif
begin() const4276             const_iterator2 begin () const {
4277                 return (*this) ().find2 (1, index1 (), 0);
4278             }
4279             BOOST_UBLAS_INLINE
4280 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
4281             typename self_type::
4282 #endif
end() const4283             const_iterator2 end () const {
4284                 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
4285             }
4286             BOOST_UBLAS_INLINE
4287 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
4288             typename self_type::
4289 #endif
rbegin() const4290             const_reverse_iterator2 rbegin () const {
4291                 return const_reverse_iterator2 (end ());
4292             }
4293             BOOST_UBLAS_INLINE
4294 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
4295             typename self_type::
4296 #endif
rend() const4297             const_reverse_iterator2 rend () const {
4298                 return const_reverse_iterator2 (begin ());
4299             }
4300 #endif
4301 
4302             // Indices
4303             BOOST_UBLAS_INLINE
index1() const4304             size_type index1 () const {
4305                 return it1_.index1 ();
4306             }
4307             BOOST_UBLAS_INLINE
index2() const4308             size_type index2 () const {
4309                 return it2_.index2 ();
4310             }
4311 
4312             // Assignment
4313             BOOST_UBLAS_INLINE
operator =(const const_iterator1 & it)4314             const_iterator1 &operator = (const const_iterator1 &it) {
4315                 container_const_reference<self_type>::assign (&it ());
4316                 it1_ = it.it1_;
4317                 it2_ = it.it2_;
4318 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4319                 it2_begin_ = it.it2_begin_;
4320                 it2_end_ = it.it2_end_;
4321 #endif
4322                 return *this;
4323             }
4324 
4325             // Comparison
4326             BOOST_UBLAS_INLINE
operator ==(const const_iterator1 & it) const4327             bool operator == (const const_iterator1 &it) const {
4328                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
4329                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
4330                 return it1_ == it.it1_;
4331             }
4332             BOOST_UBLAS_INLINE
operator <(const const_iterator1 & it) const4333             bool operator < (const const_iterator1 &it) const {
4334                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
4335                 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
4336                 return it1_ < it.it1_;
4337             }
4338 
4339         private:
4340             const_iterator11_type it1_;
4341             // Mutable due to assignment
4342             /* const */ const_iterator22_type it2_;
4343 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4344             /* const */ const_iterator21_type it2_begin_;
4345             /* const */ const_iterator21_type it2_end_;
4346 #endif
4347         };
4348 #endif
4349 
4350         BOOST_UBLAS_INLINE
begin1() const4351         const_iterator1 begin1 () const {
4352             return find1 (0, 0, 0);
4353         }
4354         BOOST_UBLAS_INLINE
end1() const4355         const_iterator1 end1 () const {
4356             return find1 (0, size1 (), 0);
4357         }
4358 
4359 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
4360         class const_iterator2:
4361             public container_const_reference<matrix_matrix_binary>,
4362             public iterator_base_traits<typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
4363                                                                           typename E2::const_iterator2::iterator_category>::iterator_category>::template
4364                 iterator_base<const_iterator2, value_type>::type {
4365         public:
4366             typedef typename iterator_restrict_traits<typename E1::const_iterator1::iterator_category,
4367                                                       typename E2::const_iterator2::iterator_category>::iterator_category iterator_category;
4368             typedef typename matrix_matrix_binary::difference_type difference_type;
4369             typedef typename matrix_matrix_binary::value_type value_type;
4370             typedef typename matrix_matrix_binary::const_reference reference;
4371             typedef typename matrix_matrix_binary::const_pointer pointer;
4372 
4373             typedef const_iterator1 dual_iterator_type;
4374             typedef const_reverse_iterator1 dual_reverse_iterator_type;
4375 
4376             // Construction and destruction
4377 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4378             BOOST_UBLAS_INLINE
const_iterator2()4379             const_iterator2 ():
4380                 container_const_reference<self_type> (), it1_ (), it2_ (), it1_begin_ (), it1_end_ () {}
4381             BOOST_UBLAS_INLINE
const_iterator2(const self_type & mmb,const const_iterator11_type & it1,const const_iterator22_type & it2)4382             const_iterator2 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2):
4383                 container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2), it1_begin_ (it1.begin ()), it1_end_ (it1.end ()) {}
4384 #else
4385             BOOST_UBLAS_INLINE
const_iterator2()4386             const_iterator2 ():
4387                 container_const_reference<self_type> (), it1_ (), it2_ () {}
4388             BOOST_UBLAS_INLINE
const_iterator2(const self_type & mmb,const const_iterator11_type & it1,const const_iterator22_type & it2)4389             const_iterator2 (const self_type &mmb, const const_iterator11_type &it1, const const_iterator22_type &it2):
4390                 container_const_reference<self_type> (mmb), it1_ (it1), it2_ (it2) {}
4391 #endif
4392 
4393             // Random access specialization
4394             BOOST_UBLAS_INLINE
dereference(dense_random_access_iterator_tag) const4395             value_type dereference (dense_random_access_iterator_tag) const {
4396                 const self_type &mmb = (*this) ();
4397 #ifdef BOOST_UBLAS_USE_INDEXING
4398                 return mmb (index1 (), index2 ());
4399 #elif BOOST_UBLAS_USE_ITERATING
4400                 difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ());
4401 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4402                 return functor_type::apply (size, it1_begin_, it2_.begin ());
4403 #else
4404                 return functor_type::apply (size, it1_.begin (), it2_.begin ());
4405 #endif
4406 #else
4407                 difference_type size = BOOST_UBLAS_SAME (mmb.expression1 ().size2 (), mmb.expression2 ().size1 ());
4408                 if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
4409 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4410                     return functor_type::apply (size, it1_begin_, it2_.begin ());
4411 #else
4412                     return functor_type::apply (size, it1_.begin (), it2_.begin ());
4413 #endif
4414                 else
4415                     return mmb (index1 (), index2 ());
4416 #endif
4417             }
4418 
4419             // Packed bidirectional specialization
4420             BOOST_UBLAS_INLINE
dereference(packed_random_access_iterator_tag) const4421             value_type dereference (packed_random_access_iterator_tag) const {
4422 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4423                 return functor_type::apply (it1_begin_, it1_end_,
4424                                         it2_.begin (), it2_.end (), packed_random_access_iterator_tag ());
4425 #else
4426 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
4427                 return functor_type::apply (it1_.begin (), it1_.end (),
4428                                         it2_.begin (), it2_.end (), packed_random_access_iterator_tag ());
4429 #else
4430                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
4431                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
4432                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
4433                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), packed_random_access_iterator_tag ());
4434 #endif
4435 #endif
4436             }
4437 
4438             // Sparse bidirectional specialization
4439             BOOST_UBLAS_INLINE
dereference(sparse_bidirectional_iterator_tag) const4440             value_type dereference (sparse_bidirectional_iterator_tag) const {
4441 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4442                 return functor_type::apply (it1_begin_, it1_end_,
4443                                         it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
4444 #else
4445 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
4446                 return functor_type::apply (it1_.begin (), it1_.end (),
4447                                         it2_.begin (), it2_.end (), sparse_bidirectional_iterator_tag ());
4448 #else
4449                 return functor_type::apply (boost::numeric::ublas::begin (it1_, iterator1_tag ()),
4450                                         boost::numeric::ublas::end (it1_, iterator1_tag ()),
4451                                         boost::numeric::ublas::begin (it2_, iterator2_tag ()),
4452                                         boost::numeric::ublas::end (it2_, iterator2_tag ()), sparse_bidirectional_iterator_tag ());
4453 #endif
4454 #endif
4455             }
4456 
4457             // Arithmetic
4458             BOOST_UBLAS_INLINE
operator ++()4459             const_iterator2 &operator ++ () {
4460                 ++ it2_;
4461                 return *this;
4462             }
4463             BOOST_UBLAS_INLINE
operator --()4464             const_iterator2 &operator -- () {
4465                 -- it2_;
4466                 return *this;
4467             }
4468             BOOST_UBLAS_INLINE
operator +=(difference_type n)4469             const_iterator2 &operator += (difference_type n) {
4470                 it2_ += n;
4471                 return *this;
4472             }
4473             BOOST_UBLAS_INLINE
operator -=(difference_type n)4474             const_iterator2 &operator -= (difference_type n) {
4475                 it2_ -= n;
4476                 return *this;
4477             }
4478             BOOST_UBLAS_INLINE
operator -(const const_iterator2 & it) const4479             difference_type operator - (const const_iterator2 &it) const {
4480                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
4481                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
4482                 return it2_ - it.it2_;
4483             }
4484 
4485             // Dereference
4486             BOOST_UBLAS_INLINE
operator *() const4487             const_reference operator * () const {
4488                 return dereference (iterator_category ());
4489             }
4490 
4491 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
4492             BOOST_UBLAS_INLINE
4493 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
4494             typename self_type::
4495 #endif
begin() const4496             const_iterator1 begin () const {
4497                 return (*this) ().find1 (1, 0, index2 ());
4498             }
4499             BOOST_UBLAS_INLINE
4500 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
4501             typename self_type::
4502 #endif
end() const4503             const_iterator1 end () const {
4504                 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
4505             }
4506             BOOST_UBLAS_INLINE
4507 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
4508             typename self_type::
4509 #endif
rbegin() const4510             const_reverse_iterator1 rbegin () const {
4511                 return const_reverse_iterator1 (end ());
4512             }
4513             BOOST_UBLAS_INLINE
4514 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
4515             typename self_type::
4516 #endif
rend() const4517             const_reverse_iterator1 rend () const {
4518                 return const_reverse_iterator1 (begin ());
4519             }
4520 #endif
4521 
4522             // Indices
4523             BOOST_UBLAS_INLINE
index1() const4524             size_type index1 () const {
4525                 return it1_.index1 ();
4526             }
4527             BOOST_UBLAS_INLINE
index2() const4528             size_type index2 () const {
4529                 return it2_.index2 ();
4530             }
4531 
4532             // Assignment
4533             BOOST_UBLAS_INLINE
operator =(const const_iterator2 & it)4534             const_iterator2 &operator = (const const_iterator2 &it) {
4535                 container_const_reference<self_type>::assign (&it ());
4536                 it1_ = it.it1_;
4537                 it2_ = it.it2_;
4538 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4539                 it1_begin_ = it.it1_begin_;
4540                 it1_end_ = it.it1_end_;
4541 #endif
4542                 return *this;
4543             }
4544 
4545             // Comparison
4546             BOOST_UBLAS_INLINE
operator ==(const const_iterator2 & it) const4547             bool operator == (const const_iterator2 &it) const {
4548                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
4549                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
4550                 return it2_ == it.it2_;
4551             }
4552             BOOST_UBLAS_INLINE
operator <(const const_iterator2 & it) const4553             bool operator < (const const_iterator2 &it) const {
4554                 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
4555                 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
4556                 return it2_ < it.it2_;
4557             }
4558 
4559         private:
4560             // Mutable due to assignment
4561             /* const */ const_iterator11_type it1_;
4562             const_iterator22_type it2_;
4563 #ifdef BOOST_UBLAS_USE_INVARIANT_HOISTING
4564             /* const */ const_iterator12_type it1_begin_;
4565             /* const */ const_iterator12_type it1_end_;
4566 #endif
4567         };
4568 #endif
4569 
4570         BOOST_UBLAS_INLINE
begin2() const4571         const_iterator2 begin2 () const {
4572             return find2 (0, 0, 0);
4573         }
4574         BOOST_UBLAS_INLINE
end2() const4575         const_iterator2 end2 () const {
4576             return find2 (0, 0, size2 ());
4577         }
4578 
4579         // Reverse iterators
4580 
4581         BOOST_UBLAS_INLINE
rbegin1() const4582         const_reverse_iterator1 rbegin1 () const {
4583             return const_reverse_iterator1 (end1 ());
4584         }
4585         BOOST_UBLAS_INLINE
rend1() const4586         const_reverse_iterator1 rend1 () const {
4587             return const_reverse_iterator1 (begin1 ());
4588         }
4589 
4590         BOOST_UBLAS_INLINE
rbegin2() const4591         const_reverse_iterator2 rbegin2 () const {
4592             return const_reverse_iterator2 (end2 ());
4593         }
4594         BOOST_UBLAS_INLINE
rend2() const4595         const_reverse_iterator2 rend2 () const {
4596             return const_reverse_iterator2 (begin2 ());
4597         }
4598 
4599     private:
4600         expression1_closure_type e1_;
4601         expression2_closure_type e2_;
4602     };
4603 
4604     template<class T1, class E1, class T2, class E2>
4605     struct matrix_matrix_binary_traits {
4606         typedef unknown_storage_tag storage_category;
4607         typedef unknown_orientation_tag orientation_category;
4608         typedef typename promote_traits<T1, T2>::promote_type promote_type;
4609         typedef matrix_matrix_binary<E1, E2, matrix_matrix_prod<T1, T2, promote_type> > expression_type;
4610 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
4611         typedef expression_type result_type;
4612 #else
4613         typedef typename E1::matrix_temporary_type result_type;
4614 #endif
4615     };
4616 
4617     template<class E1, class E2>
4618     BOOST_UBLAS_INLINE
4619     typename matrix_matrix_binary_traits<typename E1::value_type, E1,
4620                                          typename E2::value_type, E2>::result_type
prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,unknown_storage_tag,unknown_orientation_tag)4621     prod (const matrix_expression<E1> &e1,
4622           const matrix_expression<E2> &e2,
4623           unknown_storage_tag,
4624           unknown_orientation_tag) {
4625         typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1,
4626                                                                  typename E2::value_type, E2>::expression_type expression_type;
4627         return expression_type (e1 (), e2 ());
4628     }
4629 
4630     // Dispatcher
4631     template<class E1, class E2>
4632     BOOST_UBLAS_INLINE
4633     typename matrix_matrix_binary_traits<typename E1::value_type, E1,
4634                                          typename E2::value_type, E2>::result_type
prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)4635     prod (const matrix_expression<E1> &e1,
4636           const matrix_expression<E2> &e2) {
4637         BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0);
4638         typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1,
4639                                                                  typename E2::value_type, E2>::storage_category storage_category;
4640         typedef typename matrix_matrix_binary_traits<typename E1::value_type, E1,
4641                                                                  typename E2::value_type, E2>::orientation_category orientation_category;
4642         return prod (e1, e2, storage_category (), orientation_category ());
4643     }
4644 
4645     template<class E1, class E2>
4646     BOOST_UBLAS_INLINE
4647     typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
4648                                          typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
prec_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,unknown_storage_tag,unknown_orientation_tag)4649     prec_prod (const matrix_expression<E1> &e1,
4650                const matrix_expression<E2> &e2,
4651                unknown_storage_tag,
4652                unknown_orientation_tag) {
4653         typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
4654                                                                  typename type_traits<typename E2::value_type>::precision_type, E2>::expression_type expression_type;
4655         return expression_type (e1 (), e2 ());
4656     }
4657 
4658     // Dispatcher
4659     template<class E1, class E2>
4660     BOOST_UBLAS_INLINE
4661     typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
4662                                          typename type_traits<typename E2::value_type>::precision_type, E2>::result_type
prec_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)4663     prec_prod (const matrix_expression<E1> &e1,
4664                const matrix_expression<E2> &e2) {
4665         BOOST_STATIC_ASSERT (E1::complexity == 0 && E2::complexity == 0);
4666         typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
4667                                                                  typename type_traits<typename E2::value_type>::precision_type, E2>::storage_category storage_category;
4668         typedef typename matrix_matrix_binary_traits<typename type_traits<typename E1::value_type>::precision_type, E1,
4669                                                                  typename type_traits<typename E2::value_type>::precision_type, E2>::orientation_category orientation_category;
4670         return prec_prod (e1, e2, storage_category (), orientation_category ());
4671     }
4672 
4673     template<class M, class E1, class E2>
4674     BOOST_UBLAS_INLINE
4675     M &
prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m)4676     prod (const matrix_expression<E1> &e1,
4677           const matrix_expression<E2> &e2,
4678           M &m) {
4679         return m.assign (prod (e1, e2));
4680     }
4681 
4682     template<class M, class E1, class E2>
4683     BOOST_UBLAS_INLINE
4684     M &
prec_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2,M & m)4685     prec_prod (const matrix_expression<E1> &e1,
4686                const matrix_expression<E2> &e2,
4687                M &m) {
4688         return m.assign (prec_prod (e1, e2));
4689     }
4690 
4691     template<class M, class E1, class E2>
4692     BOOST_UBLAS_INLINE
4693     M
prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)4694     prod (const matrix_expression<E1> &e1,
4695           const matrix_expression<E2> &e2) {
4696         return M (prod (e1, e2));
4697     }
4698 
4699     template<class M, class E1, class E2>
4700     BOOST_UBLAS_INLINE
4701     M
prec_prod(const matrix_expression<E1> & e1,const matrix_expression<E2> & e2)4702     prec_prod (const matrix_expression<E1> &e1,
4703                const matrix_expression<E2> &e2) {
4704         return M (prec_prod (e1, e2));
4705     }
4706 
4707     template<class E, class F>
4708     class matrix_scalar_unary:
4709         public scalar_expression<matrix_scalar_unary<E, F> > {
4710     public:
4711         typedef E expression_type;
4712         typedef F functor_type;
4713         typedef typename F::result_type value_type;
4714         typedef typename E::const_closure_type expression_closure_type;
4715 
4716         // Construction and destruction
4717         BOOST_UBLAS_INLINE
matrix_scalar_unary(const expression_type & e)4718         explicit matrix_scalar_unary (const expression_type &e):
4719             e_ (e) {}
4720 
4721     private:
4722         // Expression accessors
4723         BOOST_UBLAS_INLINE
expression() const4724         const expression_closure_type &expression () const {
4725             return e_;
4726         }
4727 
4728     public:
4729         BOOST_UBLAS_INLINE
operator value_type() const4730         operator value_type () const {
4731             return functor_type::apply (e_);
4732         }
4733 
4734     private:
4735         expression_closure_type e_;
4736     };
4737 
4738     template<class E, class F>
4739     struct matrix_scalar_unary_traits {
4740         typedef matrix_scalar_unary<E, F> expression_type;
4741 #ifndef BOOST_UBLAS_SIMPLE_ET_DEBUG
4742          typedef expression_type result_type;
4743 #else
4744          typedef typename F::result_type result_type;
4745 #endif
4746     };
4747 
4748     template<class E>
4749     BOOST_UBLAS_INLINE
4750     typename matrix_scalar_unary_traits<E, matrix_norm_1<typename E::value_type> >::result_type
norm_1(const matrix_expression<E> & e)4751     norm_1 (const matrix_expression<E> &e) {
4752         typedef typename matrix_scalar_unary_traits<E, matrix_norm_1<typename E::value_type> >::expression_type expression_type;
4753         return expression_type (e ());
4754     }
4755 
4756     template<class E>
4757     BOOST_UBLAS_INLINE
4758     typename matrix_scalar_unary_traits<E, matrix_norm_frobenius<typename E::value_type> >::result_type
norm_frobenius(const matrix_expression<E> & e)4759     norm_frobenius (const matrix_expression<E> &e) {
4760         typedef typename matrix_scalar_unary_traits<E, matrix_norm_frobenius<typename E::value_type> >::expression_type expression_type;
4761         return expression_type (e ());
4762     }
4763 
4764     template<class E>
4765     BOOST_UBLAS_INLINE
4766     typename matrix_scalar_unary_traits<E, matrix_norm_inf<typename E::value_type> >::result_type
norm_inf(const matrix_expression<E> & e)4767     norm_inf (const matrix_expression<E> &e) {
4768         typedef typename matrix_scalar_unary_traits<E, matrix_norm_inf<typename E::value_type> >::expression_type expression_type;
4769         return expression_type (e ());
4770     }
4771 
4772 }}}
4773 
4774 #endif
4775