2 // Copyright (c) 2000-2010
3 // Joerg Walter, Mathias Koch, David Bellot
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 // The authors gratefully acknowledge the support of
10 // GeNeSys mbH & Co. KG in producing this work.
13 #ifndef BOOST_UBLAS_HERMITIAN_H
14 #define BOOST_UBLAS_HERMITIAN_H
16 #include <boost/numeric/ublas/matrix.hpp>
17 #include <boost/numeric/ublas/triangular.hpp> // for resize_preserve
18 #include <boost/numeric/ublas/detail/temporary.hpp>
20 // Iterators based on ideas of Jeremy Siek
21 // Hermitian matrices are square. Thanks to Peter Schmitteckert for spotting this.
23 namespace boost { namespace numeric { namespace ublas {
26 bool is_hermitian (const M &m) {
27 typedef typename M::size_type size_type;
29 if (m.size1 () != m.size2 ())
31 size_type size = BOOST_UBLAS_SAME (m.size1 (), m.size2 ());
32 for (size_type i = 0; i < size; ++ i) {
33 for (size_type j = i; j < size; ++ j) {
34 if (m (i, j) != conj (m (j, i)))
41 #ifdef BOOST_UBLAS_STRICT_HERMITIAN
44 class hermitian_matrix_element:
45 public container_reference<M> {
47 typedef M matrix_type;
48 typedef typename M::size_type size_type;
49 typedef typename M::value_type value_type;
50 typedef const value_type &const_reference;
51 typedef value_type &reference;
52 typedef value_type *pointer;
54 // Construction and destruction
56 hermitian_matrix_element (matrix_type &m, size_type i, size_type j, value_type d):
57 container_reference<matrix_type> (m), i_ (i), j_ (j), d_ (d), dirty_ (false) {}
59 ~hermitian_matrix_element () {
61 (*this) ().insert_element (i_, j_, d_);
66 hermitian_matrix_element &operator = (const hermitian_matrix_element &p) {
67 // Overide the implict copy assignment
74 hermitian_matrix_element &operator = (const D &d) {
81 hermitian_matrix_element &operator += (const D &d) {
88 hermitian_matrix_element &operator -= (const D &d) {
95 hermitian_matrix_element &operator *= (const D &d) {
102 hermitian_matrix_element &operator /= (const D &d) {
111 bool operator == (const D &d) const {
116 bool operator != (const D &d) const {
122 operator const_reference () const {
128 void swap (hermitian_matrix_element p) {
132 std::swap (d_, p.d_);
136 friend void swap (hermitian_matrix_element p1, hermitian_matrix_element p2) {
148 struct type_traits<hermitian_matrix_element<M> > {
149 typedef typename M::value_type element_type;
150 typedef type_traits<hermitian_matrix_element<M> > self_type;
151 typedef typename type_traits<element_type>::value_type value_type;
152 typedef typename type_traits<element_type>::const_reference const_reference;
153 typedef hermitian_matrix_element<M> reference;
154 typedef typename type_traits<element_type>::real_type real_type;
155 typedef typename type_traits<element_type>::precision_type precision_type;
157 static const unsigned plus_complexity = type_traits<element_type>::plus_complexity;
158 static const unsigned multiplies_complexity = type_traits<element_type>::multiplies_complexity;
162 real_type real (const_reference t) {
163 return type_traits<element_type>::real (t);
167 real_type imag (const_reference t) {
168 return type_traits<element_type>::imag (t);
172 value_type conj (const_reference t) {
173 return type_traits<element_type>::conj (t);
178 real_type type_abs (const_reference t) {
179 return type_traits<element_type>::type_abs (t);
183 value_type type_sqrt (const_reference t) {
184 return type_traits<element_type>::type_sqrt (t);
189 real_type norm_1 (const_reference t) {
190 return type_traits<element_type>::norm_1 (t);
194 real_type norm_2 (const_reference t) {
195 return type_traits<element_type>::norm_2 (t);
199 real_type norm_inf (const_reference t) {
200 return type_traits<element_type>::norm_inf (t);
205 bool equals (const_reference t1, const_reference t2) {
206 return type_traits<element_type>::equals (t1, t2);
210 template<class M1, class T2>
211 struct promote_traits<hermitian_matrix_element<M1>, T2> {
212 typedef typename promote_traits<typename hermitian_matrix_element<M1>::value_type, T2>::promote_type promote_type;
214 template<class T1, class M2>
215 struct promote_traits<T1, hermitian_matrix_element<M2> > {
216 typedef typename promote_traits<T1, typename hermitian_matrix_element<M2>::value_type>::promote_type promote_type;
218 template<class M1, class M2>
219 struct promote_traits<hermitian_matrix_element<M1>, hermitian_matrix_element<M2> > {
220 typedef typename promote_traits<typename hermitian_matrix_element<M1>::value_type,
221 typename hermitian_matrix_element<M2>::value_type>::promote_type promote_type;
225 /** \brief A hermitian matrix of values of type \c T
227 * For a \f$(n \times n)\f$-dimensional matrix and \f$ 0 \leq i < n, 0 \leq j < n\f$, every element
228 * \f$m_{i,j}\f$ is mapped to the \f$(i.n + j)\f$-th element of the container for row major orientation
229 * or the \f$(i + j.m)\f$-th element of the container for column major orientation. And
230 * \f$\forall i,j\f$, \f$m_{i,j} = \overline{m_{i,j}}\f$.
232 * Orientation and storage can also be specified, otherwise a row major and unbounded array are used.
233 * It is \b not required by the storage to initialize elements of the matrix.
234 * Moreover, only the given triangular matrix is stored and the storage of hermitian matrices is packed.
236 * See http://en.wikipedia.org/wiki/Hermitian_matrix for more details on hermitian matrices.
238 * \tparam T the type of object stored in the matrix (like double, float, complex, etc...)
239 * \tparam TRI the type of triangular matrix is either \c lower or \c upper. Default is \c lower
240 * \tparam L the storage organization. It is either \c row_major or \c column_major. Default is \c row_major
241 * \tparam A the type of Storage array. Default is \unbounded_array.
243 template<class T, class TRI, class L, class A>
244 class hermitian_matrix:
245 public matrix_container<hermitian_matrix<T, TRI, L, A> > {
247 typedef T &true_reference;
249 typedef TRI triangular_type;
250 typedef L layout_type;
251 typedef hermitian_matrix<T, TRI, L, A> self_type;
253 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
254 using matrix_container<self_type>::operator ();
256 typedef typename A::size_type size_type;
257 typedef typename A::difference_type difference_type;
258 typedef T value_type;
259 // FIXME no better way to not return the address of a temporary?
260 // typedef const T &const_reference;
261 typedef const T const_reference;
262 #ifndef BOOST_UBLAS_STRICT_HERMITIAN
263 typedef T &reference;
265 typedef hermitian_matrix_element<self_type> reference;
267 typedef A array_type;
269 typedef const matrix_reference<const self_type> const_closure_type;
270 typedef matrix_reference<self_type> closure_type;
271 typedef vector<T, A> vector_temporary_type;
272 typedef matrix<T, L, A> matrix_temporary_type; // general sub-matrix
273 typedef packed_tag storage_category;
274 typedef typename L::orientation_category orientation_category;
276 // Construction and destruction
279 matrix_container<self_type> (),
280 size_ (0), data_ (0) {}
282 hermitian_matrix (size_type size):
283 matrix_container<self_type> (),
284 size_ (BOOST_UBLAS_SAME (size, size)), data_ (triangular_type::packed_size (layout_type (), size, size)) {
287 hermitian_matrix (size_type size1, size_type size2):
288 matrix_container<self_type> (),
289 size_ (BOOST_UBLAS_SAME (size1, size2)), data_ (triangular_type::packed_size (layout_type (), size1, size2)) {
292 hermitian_matrix (size_type size, const array_type &data):
293 matrix_container<self_type> (),
294 size_ (size), data_ (data) {}
296 hermitian_matrix (const hermitian_matrix &m):
297 matrix_container<self_type> (),
298 size_ (m.size_), data_ (m.data_) {}
301 hermitian_matrix (const matrix_expression<AE> &ae):
302 matrix_container<self_type> (),
303 size_ (BOOST_UBLAS_SAME (ae ().size1 (), ae ().size2 ())),
304 data_ (triangular_type::packed_size (layout_type (), size_, size_)) {
305 matrix_assign<scalar_assign> (*this, ae);
310 size_type size1 () const {
314 size_type size2 () const {
320 const array_type &data () const {
324 array_type &data () {
330 void resize (size_type size, bool preserve = true) {
332 self_type temporary (size, size);
333 detail::matrix_resize_preserve<layout_type, triangular_type> (*this, temporary);
336 data ().resize (triangular_type::packed_size (layout_type (), size, size));
341 void resize (size_type size1, size_type size2, bool preserve = true) {
342 resize (BOOST_UBLAS_SAME (size1, size2), preserve);
345 void resize_packed_preserve (size_type size) {
346 size_ = BOOST_UBLAS_SAME (size, size);
347 data ().resize (triangular_type::packed_size (layout_type (), size_, size_), value_type ());
352 const_reference operator () (size_type i, size_type j) const {
353 BOOST_UBLAS_CHECK (i < size_, bad_index ());
354 BOOST_UBLAS_CHECK (j < size_, bad_index ());
356 // return type_traits<value_type>::real (data () [triangular_type::element (layout_type (), i, size_, i, size_)]);
358 if (triangular_type::other (i, j))
359 return data () [triangular_type::element (layout_type (), i, size_, j, size_)];
361 return type_traits<value_type>::conj (data () [triangular_type::element (layout_type (), j, size_, i, size_)]);
364 true_reference at_element (size_type i, size_type j) {
365 BOOST_UBLAS_CHECK (i < size_, bad_index ());
366 BOOST_UBLAS_CHECK (j < size_, bad_index ());
367 BOOST_UBLAS_CHECK (triangular_type::other (i, j), bad_index ());
368 return data () [triangular_type::element (layout_type (), i, size_, j, size_)];
371 reference operator () (size_type i, size_type j) {
372 #ifndef BOOST_UBLAS_STRICT_HERMITIAN
373 if (!triangular_type::other (i, j)) {
374 bad_index ().raise ();
377 return at_element (i, j);
379 if (triangular_type::other (i, j))
380 return reference (*this, i, j, data () [triangular_type::element (layout_type (), i, size_, j, size_)]);
382 return reference (*this, i, j, type_traits<value_type>::conj (data () [triangular_type::element (layout_type (), j, size_, i, size_)]));
386 // Element assignemnt
388 true_reference insert_element (size_type i, size_type j, const_reference t) {
389 BOOST_UBLAS_CHECK (i < size_, bad_index ());
390 BOOST_UBLAS_CHECK (j < size_, bad_index ());
391 if (triangular_type::other (i, j)) {
392 return (data () [triangular_type::element (layout_type (), i, size_, j, size_)] = t);
394 return (data () [triangular_type::element (layout_type (), j, size_, i, size_)] = type_traits<value_type>::conj (t));
398 void erase_element (size_type i, size_type j) {
399 BOOST_UBLAS_CHECK (i < size_, bad_index ());
400 BOOST_UBLAS_CHECK (j < size_, bad_index ());
401 data () [triangular_type::element (layout_type (), i, size_, j, size_)] = value_type/*zero*/();
407 std::fill (data ().begin (), data ().end (), value_type/*zero*/());
412 hermitian_matrix &operator = (const hermitian_matrix &m) {
418 hermitian_matrix &assign_temporary (hermitian_matrix &m) {
424 hermitian_matrix &operator = (const matrix_expression<AE> &ae) {
425 self_type temporary (ae);
426 return assign_temporary (temporary);
430 hermitian_matrix &assign (const matrix_expression<AE> &ae) {
431 matrix_assign<scalar_assign> (*this, ae);
436 hermitian_matrix& operator += (const matrix_expression<AE> &ae) {
437 self_type temporary (*this + ae);
438 return assign_temporary (temporary);
442 hermitian_matrix &plus_assign (const matrix_expression<AE> &ae) {
443 matrix_assign<scalar_plus_assign> (*this, ae);
448 hermitian_matrix& operator -= (const matrix_expression<AE> &ae) {
449 self_type temporary (*this - ae);
450 return assign_temporary (temporary);
454 hermitian_matrix &minus_assign (const matrix_expression<AE> &ae) {
455 matrix_assign<scalar_minus_assign> (*this, ae);
460 hermitian_matrix& operator *= (const AT &at) {
461 // Multiplication is only allowed for real scalars,
462 // otherwise the resulting matrix isn't hermitian.
463 // Thanks to Peter Schmitteckert for spotting this.
464 BOOST_UBLAS_CHECK (type_traits<value_type>::imag (at) == 0, non_real ());
465 matrix_assign_scalar<scalar_multiplies_assign> (*this, at);
470 hermitian_matrix& operator /= (const AT &at) {
471 // Multiplication is only allowed for real scalars,
472 // otherwise the resulting matrix isn't hermitian.
473 // Thanks to Peter Schmitteckert for spotting this.
474 BOOST_UBLAS_CHECK (type_traits<value_type>::imag (at) == 0, non_real ());
475 matrix_assign_scalar<scalar_divides_assign> (*this, at);
481 void swap (hermitian_matrix &m) {
483 std::swap (size_, m.size_);
484 data ().swap (m.data ());
488 friend void swap (hermitian_matrix &m1, hermitian_matrix &m2) {
493 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
494 typedef indexed_iterator1<self_type, packed_random_access_iterator_tag> iterator1;
495 typedef indexed_iterator2<self_type, packed_random_access_iterator_tag> iterator2;
496 typedef indexed_const_iterator1<self_type, packed_random_access_iterator_tag> const_iterator1;
497 typedef indexed_const_iterator2<self_type, packed_random_access_iterator_tag> const_iterator2;
499 class const_iterator1;
501 class const_iterator2;
504 typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
505 typedef reverse_iterator_base1<iterator1> reverse_iterator1;
506 typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
507 typedef reverse_iterator_base2<iterator2> reverse_iterator2;
511 const_iterator1 find1 (int /* rank */, size_type i, size_type j) const {
512 return const_iterator1 (*this, i, j);
515 iterator1 find1 (int rank, size_type i, size_type j) {
517 i = triangular_type::mutable_restrict1 (i, j, size1(), size2());
519 i = triangular_type::global_mutable_restrict1 (i, size1(), j, size2());
520 return iterator1 (*this, i, j);
523 const_iterator2 find2 (int /* rank */, size_type i, size_type j) const {
524 return const_iterator2 (*this, i, j);
527 iterator2 find2 (int rank, size_type i, size_type j) {
529 j = triangular_type::mutable_restrict2 (i, j, size1(), size2());
531 j = triangular_type::global_mutable_restrict2 (i, size1(), j, size2());
532 return iterator2 (*this, i, j);
535 // Iterators simply are indices.
537 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
538 class const_iterator1:
539 public container_const_reference<hermitian_matrix>,
540 public random_access_iterator_base<packed_random_access_iterator_tag,
541 const_iterator1, value_type> {
543 typedef typename hermitian_matrix::value_type value_type;
544 typedef typename hermitian_matrix::difference_type difference_type;
545 typedef typename hermitian_matrix::const_reference reference;
546 typedef const typename hermitian_matrix::pointer pointer;
548 typedef const_iterator2 dual_iterator_type;
549 typedef const_reverse_iterator2 dual_reverse_iterator_type;
551 // Construction and destruction
554 container_const_reference<self_type> (), it1_ (), it2_ () {}
556 const_iterator1 (const self_type &m, size_type it1, size_type it2):
557 container_const_reference<self_type> (m), it1_ (it1), it2_ (it2) {}
559 const_iterator1 (const iterator1 &it):
560 container_const_reference<self_type> (it ()), it1_ (it.it1_), it2_ (it.it2_) {}
564 const_iterator1 &operator ++ () {
569 const_iterator1 &operator -- () {
574 const_iterator1 &operator += (difference_type n) {
579 const_iterator1 &operator -= (difference_type n) {
584 difference_type operator - (const const_iterator1 &it) const {
585 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
586 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
587 return it1_ - it.it1_;
592 const_reference operator * () const {
593 return (*this) () (it1_, it2_);
596 const_reference operator [] (difference_type n) const {
600 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
602 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
605 const_iterator2 begin () const {
606 return (*this) ().find2 (1, it1_, 0);
609 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
612 const_iterator2 end () const {
613 return (*this) ().find2 (1, it1_, (*this) ().size2 ());
616 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
619 const_reverse_iterator2 rbegin () const {
620 return const_reverse_iterator2 (end ());
623 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
626 const_reverse_iterator2 rend () const {
627 return const_reverse_iterator2 (begin ());
633 size_type index1 () const {
637 size_type index2 () const {
643 const_iterator1 &operator = (const const_iterator1 &it) {
644 container_const_reference<self_type>::assign (&it ());
652 bool operator == (const const_iterator1 &it) const {
653 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
654 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
655 return it1_ == it.it1_;
658 bool operator < (const const_iterator1 &it) const {
659 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
660 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
661 return it1_ < it.it1_;
671 const_iterator1 begin1 () const {
672 return find1 (0, 0, 0);
675 const_iterator1 end1 () const {
676 return find1 (0, size_, 0);
679 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
681 public container_reference<hermitian_matrix>,
682 public random_access_iterator_base<packed_random_access_iterator_tag,
683 iterator1, value_type> {
685 typedef typename hermitian_matrix::value_type value_type;
686 typedef typename hermitian_matrix::difference_type difference_type;
687 typedef typename hermitian_matrix::true_reference reference;
688 typedef typename hermitian_matrix::pointer pointer;
690 typedef iterator2 dual_iterator_type;
691 typedef reverse_iterator2 dual_reverse_iterator_type;
693 // Construction and destruction
696 container_reference<self_type> (), it1_ (), it2_ () {}
698 iterator1 (self_type &m, size_type it1, size_type it2):
699 container_reference<self_type> (m), it1_ (it1), it2_ (it2) {}
703 iterator1 &operator ++ () {
708 iterator1 &operator -- () {
713 iterator1 &operator += (difference_type n) {
718 iterator1 &operator -= (difference_type n) {
723 difference_type operator - (const iterator1 &it) const {
724 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
725 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
726 return it1_ - it.it1_;
731 reference operator * () const {
732 return (*this) ().at_element (it1_, it2_);
735 reference operator [] (difference_type n) const {
739 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
741 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
744 iterator2 begin () const {
745 return (*this) ().find2 (1, it1_, 0);
748 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
751 iterator2 end () const {
752 return (*this) ().find2 (1, it1_, (*this) ().size2 ());
755 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
758 reverse_iterator2 rbegin () const {
759 return reverse_iterator2 (end ());
762 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
765 reverse_iterator2 rend () const {
766 return reverse_iterator2 (begin ());
772 size_type index1 () const {
776 size_type index2 () const {
782 iterator1 &operator = (const iterator1 &it) {
783 container_reference<self_type>::assign (&it ());
791 bool operator == (const iterator1 &it) const {
792 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
793 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
794 return it1_ == it.it1_;
797 bool operator < (const iterator1 &it) const {
798 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
799 BOOST_UBLAS_CHECK (it2_ == it.it2_, external_logic ());
800 return it1_ < it.it1_;
807 friend class const_iterator1;
812 iterator1 begin1 () {
813 return find1 (0, 0, 0);
817 return find1 (0, size_, 0);
820 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
821 class const_iterator2:
822 public container_const_reference<hermitian_matrix>,
823 public random_access_iterator_base<packed_random_access_iterator_tag,
824 const_iterator2, value_type> {
826 typedef typename hermitian_matrix::value_type value_type;
827 typedef typename hermitian_matrix::difference_type difference_type;
828 typedef typename hermitian_matrix::const_reference reference;
829 typedef const typename hermitian_matrix::pointer pointer;
831 typedef const_iterator1 dual_iterator_type;
832 typedef const_reverse_iterator1 dual_reverse_iterator_type;
834 // Construction and destruction
837 container_const_reference<self_type> (), it1_ (), it2_ () {}
839 const_iterator2 (const self_type &m, size_type it1, size_type it2):
840 container_const_reference<self_type> (m), it1_ (it1), it2_ (it2) {}
842 const_iterator2 (const iterator2 &it):
843 container_const_reference<self_type> (it ()), it1_ (it.it1_), it2_ (it.it2_) {}
847 const_iterator2 &operator ++ () {
852 const_iterator2 &operator -- () {
857 const_iterator2 &operator += (difference_type n) {
862 const_iterator2 &operator -= (difference_type n) {
867 difference_type operator - (const const_iterator2 &it) const {
868 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
869 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
870 return it2_ - it.it2_;
875 const_reference operator * () const {
876 return (*this) () (it1_, it2_);
879 const_reference operator [] (difference_type n) const {
883 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
885 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
888 const_iterator1 begin () const {
889 return (*this) ().find1 (1, 0, it2_);
892 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
895 const_iterator1 end () const {
896 return (*this) ().find1 (1, (*this) ().size1 (), it2_);
899 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
902 const_reverse_iterator1 rbegin () const {
903 return const_reverse_iterator1 (end ());
906 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
909 const_reverse_iterator1 rend () const {
910 return const_reverse_iterator1 (begin ());
916 size_type index1 () const {
920 size_type index2 () const {
926 const_iterator2 &operator = (const const_iterator2 &it) {
927 container_const_reference<self_type>::assign (&it ());
935 bool operator == (const const_iterator2 &it) const {
936 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
937 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
938 return it2_ == it.it2_;
941 bool operator < (const const_iterator2 &it) const {
942 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
943 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
944 return it2_ < it.it2_;
954 const_iterator2 begin2 () const {
955 return find2 (0, 0, 0);
958 const_iterator2 end2 () const {
959 return find2 (0, 0, size_);
962 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
964 public container_reference<hermitian_matrix>,
965 public random_access_iterator_base<packed_random_access_iterator_tag,
966 iterator2, value_type> {
968 typedef typename hermitian_matrix::value_type value_type;
969 typedef typename hermitian_matrix::difference_type difference_type;
970 typedef typename hermitian_matrix::true_reference reference;
971 typedef typename hermitian_matrix::pointer pointer;
973 typedef iterator1 dual_iterator_type;
974 typedef reverse_iterator1 dual_reverse_iterator_type;
976 // Construction and destruction
979 container_reference<self_type> (), it1_ (), it2_ () {}
981 iterator2 (self_type &m, size_type it1, size_type it2):
982 container_reference<self_type> (m), it1_ (it1), it2_ (it2) {}
986 iterator2 &operator ++ () {
991 iterator2 &operator -- () {
996 iterator2 &operator += (difference_type n) {
1001 iterator2 &operator -= (difference_type n) {
1006 difference_type operator - (const iterator2 &it) const {
1007 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1008 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
1009 return it2_ - it.it2_;
1014 reference operator * () const {
1015 return (*this) ().at_element (it1_, it2_);
1018 reference operator [] (difference_type n) const {
1019 return *(*this + n);
1022 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1024 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1025 typename self_type::
1027 iterator1 begin () const {
1028 return (*this) ().find1 (1, 0, it2_);
1031 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1032 typename self_type::
1034 iterator1 end () const {
1035 return (*this) ().find1 (1, (*this) ().size1 (), it2_);
1038 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1039 typename self_type::
1041 reverse_iterator1 rbegin () const {
1042 return reverse_iterator1 (end ());
1045 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1046 typename self_type::
1048 reverse_iterator1 rend () const {
1049 return reverse_iterator1 (begin ());
1055 size_type index1 () const {
1059 size_type index2 () const {
1065 iterator2 &operator = (const iterator2 &it) {
1066 container_reference<self_type>::assign (&it ());
1074 bool operator == (const iterator2 &it) const {
1075 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1076 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
1077 return it2_ == it.it2_;
1080 bool operator < (const iterator2 &it) const {
1081 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1082 BOOST_UBLAS_CHECK (it1_ == it.it1_, external_logic ());
1083 return it2_ < it.it2_;
1090 friend class const_iterator2;
1095 iterator2 begin2 () {
1096 return find2 (0, 0, 0);
1100 return find2 (0, 0, size_);
1103 // Reverse iterators
1106 const_reverse_iterator1 rbegin1 () const {
1107 return const_reverse_iterator1 (end1 ());
1110 const_reverse_iterator1 rend1 () const {
1111 return const_reverse_iterator1 (begin1 ());
1115 reverse_iterator1 rbegin1 () {
1116 return reverse_iterator1 (end1 ());
1119 reverse_iterator1 rend1 () {
1120 return reverse_iterator1 (begin1 ());
1124 const_reverse_iterator2 rbegin2 () const {
1125 return const_reverse_iterator2 (end2 ());
1128 const_reverse_iterator2 rend2 () const {
1129 return const_reverse_iterator2 (begin2 ());
1133 reverse_iterator2 rbegin2 () {
1134 return reverse_iterator2 (end2 ());
1137 reverse_iterator2 rend2 () {
1138 return reverse_iterator2 (begin2 ());
1146 /** \brief A Hermitian matrix adaptator: convert a any matrix into a Hermitian matrix expression
1148 * For a \f$(m\times n)\f$-dimensional matrix, the \c hermitian_adaptor will provide a hermitian matrix.
1149 * Storage and location are based on those of the underlying matrix. This is important because
1150 * a \c hermitian_adaptor does not copy the matrix data to a new place. Therefore, modifying values
1151 * in a \c hermitian_adaptor matrix will also modify the underlying matrix too.
1153 * \tparam M the type of matrix used to generate a hermitian matrix
1155 template<class M, class TRI>
1156 class hermitian_adaptor:
1157 public matrix_expression<hermitian_adaptor<M, TRI> > {
1159 typedef hermitian_adaptor<M, TRI> self_type;
1160 typedef typename M::value_type &true_reference;
1162 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
1163 using matrix_expression<self_type>::operator ();
1165 typedef const M const_matrix_type;
1166 typedef M matrix_type;
1167 typedef TRI triangular_type;
1168 typedef typename M::size_type size_type;
1169 typedef typename M::difference_type difference_type;
1170 typedef typename M::value_type value_type;
1171 typedef typename M::value_type const_reference;
1172 #ifndef BOOST_UBLAS_STRICT_HERMITIAN
1173 typedef typename boost::mpl::if_<boost::is_const<M>,
1174 typename M::value_type,
1175 typename M::reference>::type reference;
1177 typedef typename boost::mpl::if_<boost::is_const<M>,
1178 typename M::value_type,
1179 hermitian_matrix_element<self_type> >::type reference;
1181 typedef typename boost::mpl::if_<boost::is_const<M>,
1182 typename M::const_closure_type,
1183 typename M::closure_type>::type matrix_closure_type;
1184 typedef const self_type const_closure_type;
1185 typedef self_type closure_type;
1186 // Replaced by _temporary_traits to avoid type requirements on M
1187 //typedef typename M::vector_temporary_type vector_temporary_type;
1188 //typedef typename M::matrix_temporary_type matrix_temporary_type;
1189 typedef typename storage_restrict_traits<typename M::storage_category,
1190 packed_proxy_tag>::storage_category storage_category;
1191 typedef typename M::orientation_category orientation_category;
1193 // Construction and destruction
1195 hermitian_adaptor (matrix_type &data):
1196 matrix_expression<self_type> (),
1198 BOOST_UBLAS_CHECK (data_.size1 () == data_.size2 (), bad_size ());
1201 hermitian_adaptor (const hermitian_adaptor &m):
1202 matrix_expression<self_type> (),
1204 BOOST_UBLAS_CHECK (data_.size1 () == data_.size2 (), bad_size ());
1209 size_type size1 () const {
1210 return data_.size1 ();
1213 size_type size2 () const {
1214 return data_.size2 ();
1217 // Storage accessors
1219 const matrix_closure_type &data () const {
1223 matrix_closure_type &data () {
1228 #ifndef BOOST_UBLAS_PROXY_CONST_MEMBER
1230 const_reference operator () (size_type i, size_type j) const {
1231 BOOST_UBLAS_CHECK (i < size1 (), bad_index ());
1232 BOOST_UBLAS_CHECK (j < size2 (), bad_index ());
1234 // return type_traits<value_type>::real (data () (i, i));
1236 if (triangular_type::other (i, j))
1237 return data () (i, j);
1239 return type_traits<value_type>::conj (data () (j, i));
1242 reference operator () (size_type i, size_type j) {
1243 BOOST_UBLAS_CHECK (i < size1 (), bad_index ());
1244 BOOST_UBLAS_CHECK (j < size2 (), bad_index ());
1245 #ifndef BOOST_UBLAS_STRICT_HERMITIAN
1246 if (triangular_type::other (i, j))
1247 return data () (i, j);
1249 external_logic ().raise ();
1250 return conj_ = type_traits<value_type>::conj (data () (j, i));
1253 if (triangular_type::other (i, j))
1254 return reference (*this, i, j, data () (i, j));
1256 return reference (*this, i, j, type_traits<value_type>::conj (data () (j, i)));
1260 true_reference insert_element (size_type i, size_type j, value_type t) {
1261 BOOST_UBLAS_CHECK (i < size1 (), bad_index ());
1262 BOOST_UBLAS_CHECK (j < size2 (), bad_index ());
1264 // data () (i, i) = type_traits<value_type>::real (t);
1266 if (triangular_type::other (i, j))
1267 return data () (i, j) = t;
1269 return data () (j, i) = type_traits<value_type>::conj (t);
1273 reference operator () (size_type i, size_type j) {
1274 BOOST_UBLAS_CHECK (i < size1 (), bad_index ());
1275 BOOST_UBLAS_CHECK (j < size2 (), bad_index ());
1276 #ifndef BOOST_UBLAS_STRICT_HERMITIAN
1277 if (triangular_type::other (i, j))
1278 return data () (i, j);
1280 external_logic ().raise ();
1281 return conj_ = type_traits<value_type>::conj (data () (j, i));
1284 if (triangular_type::other (i, j))
1285 return reference (*this, i, j, data () (i, j));
1287 return reference (*this, i, j, type_traits<value_type>::conj (data () (j, i)));
1291 true_reference insert_element (size_type i, size_type j, value_type t) {
1292 BOOST_UBLAS_CHECK (i < size1 (), bad_index ());
1293 BOOST_UBLAS_CHECK (j < size2 (), bad_index ());
1295 // data () (i, i) = type_traits<value_type>::real (t);
1297 if (triangular_type::other (i, j))
1298 return data () (i, j) = t;
1300 return data () (j, i) = type_traits<value_type>::conj (t);
1306 hermitian_adaptor &operator = (const hermitian_adaptor &m) {
1307 matrix_assign<scalar_assign, triangular_type> (*this, m);
1311 hermitian_adaptor &assign_temporary (hermitian_adaptor &m) {
1317 hermitian_adaptor &operator = (const matrix_expression<AE> &ae) {
1318 matrix_assign<scalar_assign, triangular_type> (*this, matrix<value_type> (ae));
1323 hermitian_adaptor &assign (const matrix_expression<AE> &ae) {
1324 matrix_assign<scalar_assign, triangular_type> (*this, ae);
1329 hermitian_adaptor& operator += (const matrix_expression<AE> &ae) {
1330 matrix_assign<scalar_assign, triangular_type> (*this, matrix<value_type> (*this + ae));
1335 hermitian_adaptor &plus_assign (const matrix_expression<AE> &ae) {
1336 matrix_assign<scalar_plus_assign, triangular_type> (*this, ae);
1341 hermitian_adaptor& operator -= (const matrix_expression<AE> &ae) {
1342 matrix_assign<scalar_assign, triangular_type> (*this, matrix<value_type> (*this - ae));
1347 hermitian_adaptor &minus_assign (const matrix_expression<AE> &ae) {
1348 matrix_assign<scalar_minus_assign, triangular_type> (*this, ae);
1353 hermitian_adaptor& operator *= (const AT &at) {
1354 // Multiplication is only allowed for real scalars,
1355 // otherwise the resulting matrix isn't hermitian.
1356 // Thanks to Peter Schmitteckert for spotting this.
1357 BOOST_UBLAS_CHECK (type_traits<value_type>::imag (at) == 0, non_real ());
1358 matrix_assign_scalar<scalar_multiplies_assign> (*this, at);
1363 hermitian_adaptor& operator /= (const AT &at) {
1364 // Multiplication is only allowed for real scalars,
1365 // otherwise the resulting matrix isn't hermitian.
1366 // Thanks to Peter Schmitteckert for spotting this.
1367 BOOST_UBLAS_CHECK (type_traits<value_type>::imag (at) == 0, non_real ());
1368 matrix_assign_scalar<scalar_divides_assign> (*this, at);
1372 // Closure comparison
1374 bool same_closure (const hermitian_adaptor &ha) const {
1375 return (*this).data ().same_closure (ha.data ());
1380 void swap (hermitian_adaptor &m) {
1382 matrix_swap<scalar_swap, triangular_type> (*this, m);
1385 friend void swap (hermitian_adaptor &m1, hermitian_adaptor &m2) {
1391 // Use matrix iterator
1392 typedef typename M::const_iterator1 const_subiterator1_type;
1393 typedef typename boost::mpl::if_<boost::is_const<M>,
1394 typename M::const_iterator1,
1395 typename M::iterator1>::type subiterator1_type;
1396 typedef typename M::const_iterator2 const_subiterator2_type;
1397 typedef typename boost::mpl::if_<boost::is_const<M>,
1398 typename M::const_iterator2,
1399 typename M::iterator2>::type subiterator2_type;
1402 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1403 typedef indexed_iterator1<self_type, packed_random_access_iterator_tag> iterator1;
1404 typedef indexed_iterator2<self_type, packed_random_access_iterator_tag> iterator2;
1405 typedef indexed_const_iterator1<self_type, dense_random_access_iterator_tag> const_iterator1;
1406 typedef indexed_const_iterator2<self_type, dense_random_access_iterator_tag> const_iterator2;
1408 class const_iterator1;
1410 class const_iterator2;
1413 typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
1414 typedef reverse_iterator_base1<iterator1> reverse_iterator1;
1415 typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
1416 typedef reverse_iterator_base2<iterator2> reverse_iterator2;
1420 const_iterator1 find1 (int rank, size_type i, size_type j) const {
1421 if (triangular_type::other (i, j)) {
1422 if (triangular_type::other (size1 (), j)) {
1423 return const_iterator1 (*this, 0, 0,
1424 data ().find1 (rank, i, j), data ().find1 (rank, size1 (), j),
1425 data ().find2 (rank, size2 (), size1 ()), data ().find2 (rank, size2 (), size1 ()));
1427 return const_iterator1 (*this, 0, 1,
1428 data ().find1 (rank, i, j), data ().find1 (rank, j, j),
1429 data ().find2 (rank, j, j), data ().find2 (rank, j, size1 ()));
1432 if (triangular_type::other (size1 (), j)) {
1433 return const_iterator1 (*this, 1, 0,
1434 data ().find1 (rank, j, j), data ().find1 (rank, size1 (), j),
1435 data ().find2 (rank, j, i), data ().find2 (rank, j, j));
1437 return const_iterator1 (*this, 1, 1,
1438 data ().find1 (rank, size1 (), size2 ()), data ().find1 (rank, size1 (), size2 ()),
1439 data ().find2 (rank, j, i), data ().find2 (rank, j, size1 ()));
1444 iterator1 find1 (int rank, size_type i, size_type j) {
1446 i = triangular_type::mutable_restrict1 (i, j, size1(), size2());
1448 i = triangular_type::global_mutable_restrict1 (i, size1(), j, size2());
1449 return iterator1 (*this, data ().find1 (rank, i, j));
1452 const_iterator2 find2 (int rank, size_type i, size_type j) const {
1453 if (triangular_type::other (i, j)) {
1454 if (triangular_type::other (i, size2 ())) {
1455 return const_iterator2 (*this, 1, 1,
1456 data ().find1 (rank, size2 (), size1 ()), data ().find1 (rank, size2 (), size1 ()),
1457 data ().find2 (rank, i, j), data ().find2 (rank, i, size2 ()));
1459 return const_iterator2 (*this, 1, 0,
1460 data ().find1 (rank, i, i), data ().find1 (rank, size2 (), i),
1461 data ().find2 (rank, i, j), data ().find2 (rank, i, i));
1464 if (triangular_type::other (i, size2 ())) {
1465 return const_iterator2 (*this, 0, 1,
1466 data ().find1 (rank, j, i), data ().find1 (rank, i, i),
1467 data ().find2 (rank, i, i), data ().find2 (rank, i, size2 ()));
1469 return const_iterator2 (*this, 0, 0,
1470 data ().find1 (rank, j, i), data ().find1 (rank, size2 (), i),
1471 data ().find2 (rank, size1 (), size2 ()), data ().find2 (rank, size2 (), size2 ()));
1476 iterator2 find2 (int rank, size_type i, size_type j) {
1478 j = triangular_type::mutable_restrict2 (i, j, size1(), size2());
1480 j = triangular_type::global_mutable_restrict2 (i, size1(), j, size2());
1481 return iterator2 (*this, data ().find2 (rank, i, j));
1484 // Iterators simply are indices.
1486 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
1487 class const_iterator1:
1488 public container_const_reference<hermitian_adaptor>,
1489 public random_access_iterator_base<typename iterator_restrict_traits<
1490 typename const_subiterator1_type::iterator_category, dense_random_access_iterator_tag>::iterator_category,
1491 const_iterator1, value_type> {
1493 typedef typename const_subiterator1_type::value_type value_type;
1494 typedef typename const_subiterator1_type::difference_type difference_type;
1495 // FIXME no better way to not return the address of a temporary?
1496 // typedef typename const_subiterator1_type::reference reference;
1497 typedef typename const_subiterator1_type::value_type reference;
1498 typedef typename const_subiterator1_type::pointer pointer;
1500 typedef const_iterator2 dual_iterator_type;
1501 typedef const_reverse_iterator2 dual_reverse_iterator_type;
1503 // Construction and destruction
1506 container_const_reference<self_type> (),
1507 begin_ (-1), end_ (-1), current_ (-1),
1508 it1_begin_ (), it1_end_ (), it1_ (),
1509 it2_begin_ (), it2_end_ (), it2_ () {}
1511 const_iterator1 (const self_type &m, int begin, int end,
1512 const const_subiterator1_type &it1_begin, const const_subiterator1_type &it1_end,
1513 const const_subiterator2_type &it2_begin, const const_subiterator2_type &it2_end):
1514 container_const_reference<self_type> (m),
1515 begin_ (begin), end_ (end), current_ (begin),
1516 it1_begin_ (it1_begin), it1_end_ (it1_end), it1_ (it1_begin_),
1517 it2_begin_ (it2_begin), it2_end_ (it2_end), it2_ (it2_begin_) {
1518 if (current_ == 0 && it1_ == it1_end_)
1520 if (current_ == 1 && it2_ == it2_end_)
1522 if ((current_ == 0 && it1_ == it1_end_) ||
1523 (current_ == 1 && it2_ == it2_end_))
1525 BOOST_UBLAS_CHECK (current_ == end_ ||
1526 (current_ == 0 && it1_ != it1_end_) ||
1527 (current_ == 1 && it2_ != it2_end_), internal_logic ());
1529 // FIXME cannot compile
1530 // iterator1 does not have these members!
1532 const_iterator1 (const iterator1 &it):
1533 container_const_reference<self_type> (it ()),
1534 begin_ (it.begin_), end_ (it.end_), current_ (it.current_),
1535 it1_begin_ (it.it1_begin_), it1_end_ (it.it1_end_), it1_ (it.it1_),
1536 it2_begin_ (it.it2_begin_), it2_end_ (it.it2_end_), it2_ (it.it2_) {
1537 BOOST_UBLAS_CHECK (current_ == end_ ||
1538 (current_ == 0 && it1_ != it1_end_) ||
1539 (current_ == 1 && it2_ != it2_end_), internal_logic ());
1544 const_iterator1 &operator ++ () {
1545 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
1546 if (current_ == 0) {
1547 BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
1549 if (it1_ == it1_end_ && end_ == 1) {
1553 } else /* if (current_ == 1) */ {
1554 BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
1556 if (it2_ == it2_end_ && end_ == 0) {
1564 const_iterator1 &operator -- () {
1565 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
1566 if (current_ == 0) {
1567 if (it1_ == it1_begin_ && begin_ == 1) {
1569 BOOST_UBLAS_CHECK (it2_ != it2_begin_, internal_logic ());
1575 } else /* if (current_ == 1) */ {
1576 if (it2_ == it2_begin_ && begin_ == 0) {
1578 BOOST_UBLAS_CHECK (it1_ != it1_begin_, internal_logic ());
1588 const_iterator1 &operator += (difference_type n) {
1589 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
1590 if (current_ == 0) {
1591 size_type d = (std::min) (n, it1_end_ - it1_);
1594 if (n > 0 || (end_ == 1 && it1_ == it1_end_)) {
1595 BOOST_UBLAS_CHECK (end_ == 1, external_logic ());
1596 d = (std::min) (n, it2_end_ - it2_begin_);
1597 it2_ = it2_begin_ + d;
1601 } else /* if (current_ == 1) */ {
1602 size_type d = (std::min) (n, it2_end_ - it2_);
1605 if (n > 0 || (end_ == 0 && it2_ == it2_end_)) {
1606 BOOST_UBLAS_CHECK (end_ == 0, external_logic ());
1607 d = (std::min) (n, it1_end_ - it1_begin_);
1608 it1_ = it1_begin_ + d;
1613 BOOST_UBLAS_CHECK (n == 0, external_logic ());
1617 const_iterator1 &operator -= (difference_type n) {
1618 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
1619 if (current_ == 0) {
1620 size_type d = (std::min) (n, it1_ - it1_begin_);
1624 BOOST_UBLAS_CHECK (end_ == 1, external_logic ());
1625 d = (std::min) (n, it2_end_ - it2_begin_);
1626 it2_ = it2_end_ - d;
1630 } else /* if (current_ == 1) */ {
1631 size_type d = (std::min) (n, it2_ - it2_begin_);
1635 BOOST_UBLAS_CHECK (end_ == 0, external_logic ());
1636 d = (std::min) (n, it1_end_ - it1_begin_);
1637 it1_ = it1_end_ - d;
1642 BOOST_UBLAS_CHECK (n == 0, external_logic ());
1646 difference_type operator - (const const_iterator1 &it) const {
1647 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1648 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
1649 BOOST_UBLAS_CHECK (it.current_ == 0 || it.current_ == 1, internal_logic ());
1650 BOOST_UBLAS_CHECK (/* begin_ == it.begin_ && */ end_ == it.end_, internal_logic ());
1651 if (current_ == 0 && it.current_ == 0) {
1652 return it1_ - it.it1_;
1653 } else if (current_ == 0 && it.current_ == 1) {
1654 if (end_ == 1 && it.end_ == 1) {
1655 return (it1_ - it.it1_end_) + (it.it2_begin_ - it.it2_);
1656 } else /* if (end_ == 0 && it.end_ == 0) */ {
1657 return (it1_ - it.it1_begin_) + (it.it2_end_ - it.it2_);
1660 } else if (current_ == 1 && it.current_ == 0) {
1661 if (end_ == 1 && it.end_ == 1) {
1662 return (it2_ - it.it2_begin_) + (it.it1_end_ - it.it1_);
1663 } else /* if (end_ == 0 && it.end_ == 0) */ {
1664 return (it2_ - it.it2_end_) + (it.it1_begin_ - it.it1_);
1666 } else /* if (current_ == 1 && it.current_ == 1) */ {
1667 return it2_ - it.it2_;
1673 const_reference operator * () const {
1674 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
1675 if (current_ == 0) {
1676 BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
1677 if (triangular_type::other (index1 (), index2 ()))
1680 return type_traits<value_type>::conj (*it1_);
1681 } else /* if (current_ == 1) */ {
1682 BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
1683 if (triangular_type::other (index1 (), index2 ()))
1686 return type_traits<value_type>::conj (*it2_);
1690 const_reference operator [] (difference_type n) const {
1691 return *(*this + n);
1694 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1696 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1697 typename self_type::
1699 const_iterator2 begin () const {
1700 return (*this) ().find2 (1, index1 (), 0);
1703 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1704 typename self_type::
1706 const_iterator2 end () const {
1707 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
1710 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1711 typename self_type::
1713 const_reverse_iterator2 rbegin () const {
1714 return const_reverse_iterator2 (end ());
1717 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1718 typename self_type::
1720 const_reverse_iterator2 rend () const {
1721 return const_reverse_iterator2 (begin ());
1727 size_type index1 () const {
1728 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
1729 if (current_ == 0) {
1730 BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
1731 return it1_.index1 ();
1732 } else /* if (current_ == 1) */ {
1733 BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
1734 return it2_.index2 ();
1738 size_type index2 () const {
1739 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
1740 if (current_ == 0) {
1741 BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
1742 return it1_.index2 ();
1743 } else /* if (current_ == 1) */ {
1744 BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
1745 return it2_.index1 ();
1751 const_iterator1 &operator = (const const_iterator1 &it) {
1752 container_const_reference<self_type>::assign (&it ());
1755 current_ = it.current_;
1756 it1_begin_ = it.it1_begin_;
1757 it1_end_ = it.it1_end_;
1759 it2_begin_ = it.it2_begin_;
1760 it2_end_ = it.it2_end_;
1767 bool operator == (const const_iterator1 &it) const {
1768 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1769 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
1770 BOOST_UBLAS_CHECK (it.current_ == 0 || it.current_ == 1, internal_logic ());
1771 BOOST_UBLAS_CHECK (/* begin_ == it.begin_ && */ end_ == it.end_, internal_logic ());
1772 return (current_ == 0 && it.current_ == 0 && it1_ == it.it1_) ||
1773 (current_ == 1 && it.current_ == 1 && it2_ == it.it2_);
1776 bool operator < (const const_iterator1 &it) const {
1777 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1778 return it - *this > 0;
1785 const_subiterator1_type it1_begin_;
1786 const_subiterator1_type it1_end_;
1787 const_subiterator1_type it1_;
1788 const_subiterator2_type it2_begin_;
1789 const_subiterator2_type it2_end_;
1790 const_subiterator2_type it2_;
1795 const_iterator1 begin1 () const {
1796 return find1 (0, 0, 0);
1799 const_iterator1 end1 () const {
1800 return find1 (0, size1 (), 0);
1803 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
1805 public container_reference<hermitian_adaptor>,
1806 public random_access_iterator_base<typename iterator_restrict_traits<
1807 typename subiterator1_type::iterator_category, packed_random_access_iterator_tag>::iterator_category,
1808 iterator1, value_type> {
1810 typedef typename subiterator1_type::value_type value_type;
1811 typedef typename subiterator1_type::difference_type difference_type;
1812 typedef typename subiterator1_type::reference reference;
1813 typedef typename subiterator1_type::pointer pointer;
1815 typedef iterator2 dual_iterator_type;
1816 typedef reverse_iterator2 dual_reverse_iterator_type;
1818 // Construction and destruction
1821 container_reference<self_type> (), it1_ () {}
1823 iterator1 (self_type &m, const subiterator1_type &it1):
1824 container_reference<self_type> (m), it1_ (it1) {}
1828 iterator1 &operator ++ () {
1833 iterator1 &operator -- () {
1838 iterator1 &operator += (difference_type n) {
1843 iterator1 &operator -= (difference_type n) {
1848 difference_type operator - (const iterator1 &it) const {
1849 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1850 return it1_ - it.it1_;
1855 reference operator * () const {
1859 reference operator [] (difference_type n) const {
1860 return *(*this + n);
1863 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1865 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1866 typename self_type::
1868 iterator2 begin () const {
1869 return (*this) ().find2 (1, index1 (), 0);
1872 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1873 typename self_type::
1875 iterator2 end () const {
1876 return (*this) ().find2 (1, index1 (), (*this) ().size2 ());
1879 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1880 typename self_type::
1882 reverse_iterator2 rbegin () const {
1883 return reverse_iterator2 (end ());
1886 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1887 typename self_type::
1889 reverse_iterator2 rend () const {
1890 return reverse_iterator2 (begin ());
1896 size_type index1 () const {
1897 return it1_.index1 ();
1900 size_type index2 () const {
1901 return it1_.index2 ();
1906 iterator1 &operator = (const iterator1 &it) {
1907 container_reference<self_type>::assign (&it ());
1914 bool operator == (const iterator1 &it) const {
1915 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1916 return it1_ == it.it1_;
1919 bool operator < (const iterator1 &it) const {
1920 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1921 return it1_ < it.it1_;
1925 subiterator1_type it1_;
1927 friend class const_iterator1;
1932 iterator1 begin1 () {
1933 return find1 (0, 0, 0);
1937 return find1 (0, size1 (), 0);
1940 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
1941 class const_iterator2:
1942 public container_const_reference<hermitian_adaptor>,
1943 public random_access_iterator_base<typename iterator_restrict_traits<
1944 typename const_subiterator2_type::iterator_category, dense_random_access_iterator_tag>::iterator_category,
1945 const_iterator2, value_type> {
1947 typedef typename const_subiterator2_type::value_type value_type;
1948 typedef typename const_subiterator2_type::difference_type difference_type;
1949 // FIXME no better way to not return the address of a temporary?
1950 // typedef typename const_subiterator2_type::reference reference;
1951 typedef typename const_subiterator2_type::value_type reference;
1952 typedef typename const_subiterator2_type::pointer pointer;
1954 typedef const_iterator1 dual_iterator_type;
1955 typedef const_reverse_iterator1 dual_reverse_iterator_type;
1957 // Construction and destruction
1960 container_const_reference<self_type> (),
1961 begin_ (-1), end_ (-1), current_ (-1),
1962 it1_begin_ (), it1_end_ (), it1_ (),
1963 it2_begin_ (), it2_end_ (), it2_ () {}
1965 const_iterator2 (const self_type &m, int begin, int end,
1966 const const_subiterator1_type &it1_begin, const const_subiterator1_type &it1_end,
1967 const const_subiterator2_type &it2_begin, const const_subiterator2_type &it2_end):
1968 container_const_reference<self_type> (m),
1969 begin_ (begin), end_ (end), current_ (begin),
1970 it1_begin_ (it1_begin), it1_end_ (it1_end), it1_ (it1_begin_),
1971 it2_begin_ (it2_begin), it2_end_ (it2_end), it2_ (it2_begin_) {
1972 if (current_ == 0 && it1_ == it1_end_)
1974 if (current_ == 1 && it2_ == it2_end_)
1976 if ((current_ == 0 && it1_ == it1_end_) ||
1977 (current_ == 1 && it2_ == it2_end_))
1979 BOOST_UBLAS_CHECK (current_ == end_ ||
1980 (current_ == 0 && it1_ != it1_end_) ||
1981 (current_ == 1 && it2_ != it2_end_), internal_logic ());
1983 // FIXME cannot compiler
1984 // iterator2 does not have these members!
1986 const_iterator2 (const iterator2 &it):
1987 container_const_reference<self_type> (it ()),
1988 begin_ (it.begin_), end_ (it.end_), current_ (it.current_),
1989 it1_begin_ (it.it1_begin_), it1_end_ (it.it1_end_), it1_ (it.it1_),
1990 it2_begin_ (it.it2_begin_), it2_end_ (it.it2_end_), it2_ (it.it2_) {
1991 BOOST_UBLAS_CHECK (current_ == end_ ||
1992 (current_ == 0 && it1_ != it1_end_) ||
1993 (current_ == 1 && it2_ != it2_end_), internal_logic ());
1998 const_iterator2 &operator ++ () {
1999 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
2000 if (current_ == 0) {
2001 BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
2003 if (it1_ == it1_end_ && end_ == 1) {
2007 } else /* if (current_ == 1) */ {
2008 BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
2010 if (it2_ == it2_end_ && end_ == 0) {
2018 const_iterator2 &operator -- () {
2019 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
2020 if (current_ == 0) {
2021 if (it1_ == it1_begin_ && begin_ == 1) {
2023 BOOST_UBLAS_CHECK (it2_ != it2_begin_, internal_logic ());
2029 } else /* if (current_ == 1) */ {
2030 if (it2_ == it2_begin_ && begin_ == 0) {
2032 BOOST_UBLAS_CHECK (it1_ != it1_begin_, internal_logic ());
2042 const_iterator2 &operator += (difference_type n) {
2043 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
2044 if (current_ == 0) {
2045 size_type d = (std::min) (n, it1_end_ - it1_);
2048 if (n > 0 || (end_ == 1 && it1_ == it1_end_)) {
2049 BOOST_UBLAS_CHECK (end_ == 1, external_logic ());
2050 d = (std::min) (n, it2_end_ - it2_begin_);
2051 it2_ = it2_begin_ + d;
2055 } else /* if (current_ == 1) */ {
2056 size_type d = (std::min) (n, it2_end_ - it2_);
2059 if (n > 0 || (end_ == 0 && it2_ == it2_end_)) {
2060 BOOST_UBLAS_CHECK (end_ == 0, external_logic ());
2061 d = (std::min) (n, it1_end_ - it1_begin_);
2062 it1_ = it1_begin_ + d;
2067 BOOST_UBLAS_CHECK (n == 0, external_logic ());
2071 const_iterator2 &operator -= (difference_type n) {
2072 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
2073 if (current_ == 0) {
2074 size_type d = (std::min) (n, it1_ - it1_begin_);
2078 BOOST_UBLAS_CHECK (end_ == 1, external_logic ());
2079 d = (std::min) (n, it2_end_ - it2_begin_);
2080 it2_ = it2_end_ - d;
2084 } else /* if (current_ == 1) */ {
2085 size_type d = (std::min) (n, it2_ - it2_begin_);
2089 BOOST_UBLAS_CHECK (end_ == 0, external_logic ());
2090 d = (std::min) (n, it1_end_ - it1_begin_);
2091 it1_ = it1_end_ - d;
2096 BOOST_UBLAS_CHECK (n == 0, external_logic ());
2100 difference_type operator - (const const_iterator2 &it) const {
2101 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
2102 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
2103 BOOST_UBLAS_CHECK (it.current_ == 0 || it.current_ == 1, internal_logic ());
2104 BOOST_UBLAS_CHECK (/* begin_ == it.begin_ && */ end_ == it.end_, internal_logic ());
2105 if (current_ == 0 && it.current_ == 0) {
2106 return it1_ - it.it1_;
2107 } else if (current_ == 0 && it.current_ == 1) {
2108 if (end_ == 1 && it.end_ == 1) {
2109 return (it1_ - it.it1_end_) + (it.it2_begin_ - it.it2_);
2110 } else /* if (end_ == 0 && it.end_ == 0) */ {
2111 return (it1_ - it.it1_begin_) + (it.it2_end_ - it.it2_);
2114 } else if (current_ == 1 && it.current_ == 0) {
2115 if (end_ == 1 && it.end_ == 1) {
2116 return (it2_ - it.it2_begin_) + (it.it1_end_ - it.it1_);
2117 } else /* if (end_ == 0 && it.end_ == 0) */ {
2118 return (it2_ - it.it2_end_) + (it.it1_begin_ - it.it1_);
2120 } else /* if (current_ == 1 && it.current_ == 1) */ {
2121 return it2_ - it.it2_;
2127 const_reference operator * () const {
2128 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
2129 if (current_ == 0) {
2130 BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
2131 if (triangular_type::other (index1 (), index2 ()))
2134 return type_traits<value_type>::conj (*it1_);
2135 } else /* if (current_ == 1) */ {
2136 BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
2137 if (triangular_type::other (index1 (), index2 ()))
2140 return type_traits<value_type>::conj (*it2_);
2144 const_reference operator [] (difference_type n) const {
2145 return *(*this + n);
2148 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
2150 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2151 typename self_type::
2153 const_iterator1 begin () const {
2154 return (*this) ().find1 (1, 0, index2 ());
2157 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2158 typename self_type::
2160 const_iterator1 end () const {
2161 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
2164 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2165 typename self_type::
2167 const_reverse_iterator1 rbegin () const {
2168 return const_reverse_iterator1 (end ());
2171 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2172 typename self_type::
2174 const_reverse_iterator1 rend () const {
2175 return const_reverse_iterator1 (begin ());
2181 size_type index1 () const {
2182 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
2183 if (current_ == 0) {
2184 BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
2185 return it1_.index2 ();
2186 } else /* if (current_ == 1) */ {
2187 BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
2188 return it2_.index1 ();
2192 size_type index2 () const {
2193 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
2194 if (current_ == 0) {
2195 BOOST_UBLAS_CHECK (it1_ != it1_end_, internal_logic ());
2196 return it1_.index1 ();
2197 } else /* if (current_ == 1) */ {
2198 BOOST_UBLAS_CHECK (it2_ != it2_end_, internal_logic ());
2199 return it2_.index2 ();
2205 const_iterator2 &operator = (const const_iterator2 &it) {
2206 container_const_reference<self_type>::assign (&it ());
2209 current_ = it.current_;
2210 it1_begin_ = it.it1_begin_;
2211 it1_end_ = it.it1_end_;
2213 it2_begin_ = it.it2_begin_;
2214 it2_end_ = it.it2_end_;
2221 bool operator == (const const_iterator2 &it) const {
2222 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
2223 BOOST_UBLAS_CHECK (current_ == 0 || current_ == 1, internal_logic ());
2224 BOOST_UBLAS_CHECK (it.current_ == 0 || it.current_ == 1, internal_logic ());
2225 BOOST_UBLAS_CHECK (/* begin_ == it.begin_ && */ end_ == it.end_, internal_logic ());
2226 return (current_ == 0 && it.current_ == 0 && it1_ == it.it1_) ||
2227 (current_ == 1 && it.current_ == 1 && it2_ == it.it2_);
2230 bool operator < (const const_iterator2 &it) const {
2231 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
2232 return it - *this > 0;
2239 const_subiterator1_type it1_begin_;
2240 const_subiterator1_type it1_end_;
2241 const_subiterator1_type it1_;
2242 const_subiterator2_type it2_begin_;
2243 const_subiterator2_type it2_end_;
2244 const_subiterator2_type it2_;
2249 const_iterator2 begin2 () const {
2250 return find2 (0, 0, 0);
2253 const_iterator2 end2 () const {
2254 return find2 (0, 0, size2 ());
2257 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
2259 public container_reference<hermitian_adaptor>,
2260 public random_access_iterator_base<typename iterator_restrict_traits<
2261 typename subiterator2_type::iterator_category, packed_random_access_iterator_tag>::iterator_category,
2262 iterator2, value_type> {
2264 typedef typename subiterator2_type::value_type value_type;
2265 typedef typename subiterator2_type::difference_type difference_type;
2266 typedef typename subiterator2_type::reference reference;
2267 typedef typename subiterator2_type::pointer pointer;
2269 typedef iterator1 dual_iterator_type;
2270 typedef reverse_iterator1 dual_reverse_iterator_type;
2272 // Construction and destruction
2275 container_reference<self_type> (), it2_ () {}
2277 iterator2 (self_type &m, const subiterator2_type &it2):
2278 container_reference<self_type> (m), it2_ (it2) {}
2282 iterator2 &operator ++ () {
2287 iterator2 &operator -- () {
2292 iterator2 &operator += (difference_type n) {
2297 iterator2 &operator -= (difference_type n) {
2302 difference_type operator - (const iterator2 &it) const {
2303 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
2304 return it2_ - it.it2_;
2309 reference operator * () const {
2313 reference operator [] (difference_type n) const {
2314 return *(*this + n);
2317 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
2319 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2320 typename self_type::
2322 iterator1 begin () const {
2323 return (*this) ().find1 (1, 0, index2 ());
2326 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2327 typename self_type::
2329 iterator1 end () const {
2330 return (*this) ().find1 (1, (*this) ().size1 (), index2 ());
2333 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2334 typename self_type::
2336 reverse_iterator1 rbegin () const {
2337 return reverse_iterator1 (end ());
2340 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
2341 typename self_type::
2343 reverse_iterator1 rend () const {
2344 return reverse_iterator1 (begin ());
2350 size_type index1 () const {
2351 return it2_.index1 ();
2354 size_type index2 () const {
2355 return it2_.index2 ();
2360 iterator2 &operator = (const iterator2 &it) {
2361 container_reference<self_type>::assign (&it ());
2368 bool operator == (const iterator2 &it) const {
2369 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
2370 return it2_ == it.it2_;
2373 bool operator < (const iterator2 &it) const {
2374 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
2375 return it2_ < it.it2_;
2379 subiterator2_type it2_;
2381 friend class const_iterator2;
2386 iterator2 begin2 () {
2387 return find2 (0, 0, 0);
2391 return find2 (0, 0, size2 ());
2394 // Reverse iterators
2397 const_reverse_iterator1 rbegin1 () const {
2398 return const_reverse_iterator1 (end1 ());
2401 const_reverse_iterator1 rend1 () const {
2402 return const_reverse_iterator1 (begin1 ());
2406 reverse_iterator1 rbegin1 () {
2407 return reverse_iterator1 (end1 ());
2410 reverse_iterator1 rend1 () {
2411 return reverse_iterator1 (begin1 ());
2415 const_reverse_iterator2 rbegin2 () const {
2416 return const_reverse_iterator2 (end2 ());
2419 const_reverse_iterator2 rend2 () const {
2420 return const_reverse_iterator2 (begin2 ());
2424 reverse_iterator2 rbegin2 () {
2425 return reverse_iterator2 (end2 ());
2428 reverse_iterator2 rend2 () {
2429 return reverse_iterator2 (begin2 ());
2433 matrix_closure_type data_;
2434 static value_type conj_;
2437 template<class M, class TRI>
2438 typename hermitian_adaptor<M, TRI>::value_type hermitian_adaptor<M, TRI>::conj_;
2440 // Specialization for temporary_traits
2441 template <class M, class TRI>
2442 struct vector_temporary_traits< hermitian_adaptor<M, TRI> >
2443 : vector_temporary_traits< M > {} ;
2444 template <class M, class TRI>
2445 struct vector_temporary_traits< const hermitian_adaptor<M, TRI> >
2446 : vector_temporary_traits< M > {} ;
2448 template <class M, class TRI>
2449 struct matrix_temporary_traits< hermitian_adaptor<M, TRI> >
2450 : matrix_temporary_traits< M > {} ;
2451 template <class M, class TRI>
2452 struct matrix_temporary_traits< const hermitian_adaptor<M, TRI> >
2453 : matrix_temporary_traits< M > {} ;