3 // Gunter Winkler, Joerg Walter
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_VECTOR_OF_VECTOR_
14 #define _BOOST_UBLAS_VECTOR_OF_VECTOR_
16 #include <boost/type_traits.hpp>
18 #include <boost/numeric/ublas/storage_sparse.hpp>
19 #include <boost/numeric/ublas/matrix_sparse.hpp>
21 // Iterators based on ideas of Jeremy Siek
23 namespace boost
{ namespace numeric
{ namespace ublas
{
25 // uBLAS sparse vector based sparse matrix class
26 // FIXME outer vector can be sparse type but it is completely filled
27 template<class T
, class L
, class A
>
28 class generalized_vector_of_vector
:
29 public matrix_container
<generalized_vector_of_vector
<T
, L
, A
> > {
31 typedef T
&true_reference
;
33 typedef const T
*const_pointer
;
34 typedef L layout_type
;
35 typedef generalized_vector_of_vector
<T
, L
, A
> self_type
;
37 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
38 using matrix_container
<self_type
>::operator ();
40 typedef typename
A::size_type size_type
;
41 typedef typename
A::difference_type difference_type
;
43 typedef const T
&const_reference
;
44 #ifndef BOOST_UBLAS_STRICT_VECTOR_SPARSE
47 typedef sparse_matrix_element
<self_type
> reference
;
50 typedef const matrix_reference
<const self_type
> const_closure_type
;
51 typedef matrix_reference
<self_type
> closure_type
;
52 typedef typename
A::value_type vector_data_value_type
;
53 typedef vector_data_value_type vector_temporary_type
;
54 typedef self_type matrix_temporary_type
;
55 typedef sparse_tag storage_category
;
56 typedef typename
L::orientation_category orientation_category
;
58 // Construction and destruction
60 generalized_vector_of_vector ():
61 matrix_container
<self_type
> (),
62 size1_ (0), size2_ (0), data_ (1) {
63 const size_type sizeM
= layout_type::size_M (size1_
, size2_
);
64 // create size1+1 empty vector elements
65 data_
.insert_element (sizeM
, vector_data_value_type ());
66 storage_invariants ();
69 generalized_vector_of_vector (size_type size1
, size_type size2
, size_type non_zeros
= 0):
70 matrix_container
<self_type
> (),
71 size1_ (size1
), size2_ (size2
), data_ (layout_type::size_M (size1_
, size2_
) + 1) {
72 const size_type sizeM
= layout_type::size_M (size1_
, size2_
);
73 const size_type sizem
= layout_type::size_m (size1_
, size2_
);
74 for (size_type i
= 0; i
< sizeM
; ++ i
) // create size1 vector elements
75 data_
.insert_element (i
, vector_data_value_type ()) .resize (sizem
, false);
76 data_
.insert_element (sizeM
, vector_data_value_type ());
77 storage_invariants ();
80 generalized_vector_of_vector (const generalized_vector_of_vector
&m
):
81 matrix_container
<self_type
> (),
82 size1_ (m
.size1_
), size2_ (m
.size2_
), data_ (m
.data_
) {
83 storage_invariants ();
87 generalized_vector_of_vector (const matrix_expression
<AE
> &ae
, size_type non_zeros
= 0):
88 matrix_container
<self_type
> (),
89 size1_ (ae ().size1 ()), size2_ (ae ().size2 ()), data_ (layout_type::size_M (size1_
, size2_
) + 1) {
90 const size_type sizeM
= layout_type::size_M (size1_
, size2_
);
91 const size_type sizem
= layout_type::size_m (size1_
, size2_
);
92 for (size_type i
= 0; i
< sizeM
; ++ i
) // create size1 vector elements
93 data_
.insert_element (i
, vector_data_value_type ()) .resize (sizem
, false);
94 data_
.insert_element (sizeM
, vector_data_value_type ());
95 storage_invariants ();
96 matrix_assign
<scalar_assign
> (*this, ae
);
101 size_type
size1 () const {
105 size_type
size2 () const {
109 size_type
nnz_capacity () const {
110 size_type non_zeros
= 0;
111 for (const_vectoriterator_type itv
= data_
.begin (); itv
!= data_
.end (); ++ itv
)
112 non_zeros
+= (*itv
).nnz_capacity ();
116 size_type
nnz () const {
117 size_type non_zeros
= 0;
118 for (const_vectoriterator_type itv
= data_
.begin (); itv
!= data_
.end (); ++ itv
)
119 non_zeros
+= (*itv
).nnz ();
125 const array_type
&data () const {
129 array_type
&data () {
135 void resize (size_type size1
, size_type size2
, bool preserve
= true) {
136 const size_type oldM
= layout_type::size_M (size1_
, size2_
);
139 const size_type sizeM
= layout_type::size_M (size1_
, size2_
);
140 const size_type sizem
= layout_type::size_m (size1_
, size2_
);
141 data ().resize (sizeM
+ 1, preserve
);
143 for (size_type i
= 0; (i
<= oldM
) && (i
< sizeM
); ++ i
)
144 ref (data () [i
]).resize (sizem
, preserve
);
145 for (size_type i
= oldM
+1; i
< sizeM
; ++ i
) // create new vector elements
146 data_
.insert_element (i
, vector_data_value_type ()) .resize (sizem
, false);
148 data_
.insert_element (sizeM
, vector_data_value_type ());
150 ref (data () [sizeM
]).resize (0, false);
153 for (size_type i
= 0; i
< sizeM
; ++ i
)
154 data_
.insert_element (i
, vector_data_value_type ()) .resize (sizem
, false);
155 data_
.insert_element (sizeM
, vector_data_value_type ());
157 storage_invariants ();
162 pointer
find_element (size_type i
, size_type j
) {
163 return const_cast<pointer
> (const_cast<const self_type
&>(*this).find_element (i
, j
));
166 const_pointer
find_element (size_type i
, size_type j
) const {
167 const size_type elementM
= layout_type::index_M (i
, j
);
168 const size_type elementm
= layout_type::index_m (i
, j
);
169 // optimise: check the storage_type and index directly if element always exists
170 if (boost::is_convertible
<typename
array_type::storage_category
, packed_tag
>::value
) {
171 return & (data () [elementM
] [elementm
]);
174 const typename
array_type::value_type
*pv
= data ().find_element (elementM
);
177 return pv
->find_element (elementm
);
183 const_reference
operator () (size_type i
, size_type j
) const {
184 const_pointer p
= find_element (i
, j
);
185 // optimise: check the storage_type and index directly if element always exists
186 if (boost::is_convertible
<typename
array_type::storage_category
, packed_tag
>::value
) {
187 BOOST_UBLAS_CHECK (p
, internal_logic () );
198 reference
operator () (size_type i
, size_type j
) {
199 #ifndef BOOST_UBLAS_STRICT_MATRIX_SPARSE
200 return at_element (i
, j
);
202 return reference (*this, i
, j
);
208 generalized_vector_of_vector
&operator = (const generalized_vector_of_vector
&m
) {
214 storage_invariants ();
218 generalized_vector_of_vector
&assign_temporary (generalized_vector_of_vector
&m
) {
224 generalized_vector_of_vector
&operator = (const matrix_expression
<AE
> &ae
) {
225 self_type
temporary (ae
);
226 return assign_temporary (temporary
);
230 generalized_vector_of_vector
&assign (const matrix_expression
<AE
> &ae
) {
231 matrix_assign
<scalar_assign
> (*this, ae
);
236 generalized_vector_of_vector
& operator += (const matrix_expression
<AE
> &ae
) {
237 self_type
temporary (*this + ae
);
238 return assign_temporary (temporary
);
242 generalized_vector_of_vector
&plus_assign (const matrix_expression
<AE
> &ae
) {
243 matrix_assign
<scalar_plus_assign
> (*this, ae
);
248 generalized_vector_of_vector
& operator -= (const matrix_expression
<AE
> &ae
) {
249 self_type
temporary (*this - ae
);
250 return assign_temporary (temporary
);
254 generalized_vector_of_vector
&minus_assign (const matrix_expression
<AE
> &ae
) {
255 matrix_assign
<scalar_minus_assign
> (*this, ae
);
260 generalized_vector_of_vector
& operator *= (const AT
&at
) {
261 matrix_assign_scalar
<scalar_multiplies_assign
> (*this, at
);
266 generalized_vector_of_vector
& operator /= (const AT
&at
) {
267 matrix_assign_scalar
<scalar_divides_assign
> (*this, at
);
273 void swap (generalized_vector_of_vector
&m
) {
275 std::swap (size1_
, m
.size1_
);
276 std::swap (size2_
, m
.size2_
);
277 data ().swap (m
.data ());
279 storage_invariants ();
282 friend void swap (generalized_vector_of_vector
&m1
, generalized_vector_of_vector
&m2
) {
288 vectoriterator_type
itv (data ().begin ());
289 vectoriterator_type
itv_end (data ().end ());
290 while (itv
!= itv_end
) {
296 // Element insertion and erasure
298 true_reference
insert_element (size_type i
, size_type j
, const_reference t
) {
299 const size_type elementM
= layout_type::index_M (i
, j
);
300 const size_type elementm
= layout_type::index_m (i
, j
);
301 vector_data_value_type
& vd (ref (data () [elementM
]));
302 storage_invariants ();
303 return vd
.insert_element (elementm
, t
);
306 void append_element (size_type i
, size_type j
, const_reference t
) {
307 const size_type elementM
= layout_type::index_M (i
, j
);
308 const size_type elementm
= layout_type::index_m (i
, j
);
309 vector_data_value_type
& vd (ref (data () [elementM
]));
310 storage_invariants ();
311 return vd
.append_element (elementm
, t
);
314 void erase_element (size_type i
, size_type j
) {
315 vectoriterator_type
itv (data ().find (layout_type::index_M (i
, j
)));
316 if (itv
== data ().end ())
318 (*itv
).erase_element (layout_type::index_m (i
, j
));
319 storage_invariants ();
323 const size_type sizeM
= layout_type::size_M (size1_
, size2_
);
324 // FIXME should clear data () if this is done via value_type/*zero*/() then it is not size preserving
325 for (size_type i
= 0; i
< sizeM
; ++ i
)
326 ref (data () [i
]).clear ();
327 storage_invariants ();
332 // Use vector iterator
333 typedef typename
A::const_iterator const_vectoriterator_type
;
334 typedef typename
A::iterator vectoriterator_type
;
335 typedef typename
A::value_type::const_iterator const_subiterator_type
;
336 typedef typename
A::value_type::iterator subiterator_type
;
339 true_reference
at_element (size_type i
, size_type j
) {
340 return ref (ref (data () [layout_type::index_M (i
, j
)]) [layout_type::index_m (i
, j
)]);
344 class const_iterator1
;
346 class const_iterator2
;
348 typedef reverse_iterator_base1
<const_iterator1
> const_reverse_iterator1
;
349 typedef reverse_iterator_base1
<iterator1
> reverse_iterator1
;
350 typedef reverse_iterator_base2
<const_iterator2
> const_reverse_iterator2
;
351 typedef reverse_iterator_base2
<iterator2
> reverse_iterator2
;
354 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
355 const_iterator1
find1 (int rank
, size_type i
, size_type j
, int direction
= 1) const {
357 const_vectoriterator_type
itv (data ().find (layout_type::index_M (i
, j
)));
358 const_vectoriterator_type
itv_end (data ().end ());
360 return const_iterator1 (*this, rank
, i
, j
, itv_end
, (*(-- itv
)).end ());
362 const_subiterator_type
it ((*itv
).find (layout_type::index_m (i
, j
)));
363 const_subiterator_type
it_end ((*itv
).end ());
365 return const_iterator1 (*this, rank
, i
, j
, itv
, it
);
366 if (it
!= it_end
&& it
.index () == layout_type::index_m (i
, j
))
367 return const_iterator1 (*this, rank
, i
, j
, itv
, it
);
369 if (layout_type::fast_i ()) {
371 return const_iterator1 (*this, rank
, i
, j
, itv
, it
);
375 return const_iterator1 (*this, rank
, i
, j
, itv
, it
);
378 } else /* if (direction < 0) */ {
379 if (layout_type::fast_i ()) {
380 if (it
== (*itv
).begin ())
381 return const_iterator1 (*this, rank
, i
, j
, itv
, it
);
386 return const_iterator1 (*this, rank
, i
, j
, itv
, it
);
392 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
393 iterator1
find1 (int rank
, size_type i
, size_type j
, int direction
= 1) {
395 vectoriterator_type
itv (data ().find (layout_type::index_M (i
, j
)));
396 vectoriterator_type
itv_end (data ().end ());
398 return iterator1 (*this, rank
, i
, j
, itv_end
, (*(-- itv
)).end ());
400 subiterator_type
it ((*itv
).find (layout_type::index_m (i
, j
)));
401 subiterator_type
it_end ((*itv
).end ());
403 return iterator1 (*this, rank
, i
, j
, itv
, it
);
404 if (it
!= it_end
&& it
.index () == layout_type::index_m (i
, j
))
405 return iterator1 (*this, rank
, i
, j
, itv
, it
);
407 if (layout_type::fast_i ()) {
409 return iterator1 (*this, rank
, i
, j
, itv
, it
);
413 return iterator1 (*this, rank
, i
, j
, itv
, it
);
416 } else /* if (direction < 0) */ {
417 if (layout_type::fast_i ()) {
418 if (it
== (*itv
).begin ())
419 return iterator1 (*this, rank
, i
, j
, itv
, it
);
424 return iterator1 (*this, rank
, i
, j
, itv
, it
);
430 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
431 const_iterator2
find2 (int rank
, size_type i
, size_type j
, int direction
= 1) const {
433 const_vectoriterator_type
itv (data ().find (layout_type::index_M (i
, j
)));
434 const_vectoriterator_type
itv_end (data ().end ());
436 return const_iterator2 (*this, rank
, i
, j
, itv_end
, (*(-- itv
)).end ());
438 const_subiterator_type
it ((*itv
).find (layout_type::index_m (i
, j
)));
439 const_subiterator_type
it_end ((*itv
).end ());
441 return const_iterator2 (*this, rank
, i
, j
, itv
, it
);
442 if (it
!= it_end
&& it
.index () == layout_type::index_m (i
, j
))
443 return const_iterator2 (*this, rank
, i
, j
, itv
, it
);
445 if (layout_type::fast_j ()) {
447 return const_iterator2 (*this, rank
, i
, j
, itv
, it
);
451 return const_iterator2 (*this, rank
, i
, j
, itv
, it
);
454 } else /* if (direction < 0) */ {
455 if (layout_type::fast_j ()) {
456 if (it
== (*itv
).begin ())
457 return const_iterator2 (*this, rank
, i
, j
, itv
, it
);
462 return const_iterator2 (*this, rank
, i
, j
, itv
, it
);
468 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
469 iterator2
find2 (int rank
, size_type i
, size_type j
, int direction
= 1) {
471 vectoriterator_type
itv (data ().find (layout_type::index_M (i
, j
)));
472 vectoriterator_type
itv_end (data ().end ());
474 return iterator2 (*this, rank
, i
, j
, itv_end
, (*(-- itv
)).end ());
476 subiterator_type
it ((*itv
).find (layout_type::index_m (i
, j
)));
477 subiterator_type
it_end ((*itv
).end ());
479 return iterator2 (*this, rank
, i
, j
, itv
, it
);
480 if (it
!= it_end
&& it
.index () == layout_type::index_m (i
, j
))
481 return iterator2 (*this, rank
, i
, j
, itv
, it
);
483 if (layout_type::fast_j ()) {
485 return iterator2 (*this, rank
, i
, j
, itv
, it
);
489 return iterator2 (*this, rank
, i
, j
, itv
, it
);
492 } else /* if (direction < 0) */ {
493 if (layout_type::fast_j ()) {
494 if (it
== (*itv
).begin ())
495 return iterator2 (*this, rank
, i
, j
, itv
, it
);
500 return iterator2 (*this, rank
, i
, j
, itv
, it
);
508 class const_iterator1
:
509 public container_const_reference
<generalized_vector_of_vector
>,
510 public bidirectional_iterator_base
<sparse_bidirectional_iterator_tag
,
511 const_iterator1
, value_type
> {
513 typedef typename
generalized_vector_of_vector::difference_type difference_type
;
514 typedef typename
generalized_vector_of_vector::value_type value_type
;
515 typedef typename
generalized_vector_of_vector::const_reference reference
;
516 typedef const typename
generalized_vector_of_vector::pointer pointer
;
518 typedef const_iterator2 dual_iterator_type
;
519 typedef const_reverse_iterator2 dual_reverse_iterator_type
;
521 // Construction and destruction
524 container_const_reference
<self_type
> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
526 const_iterator1 (const self_type
&m
, int rank
, size_type i
, size_type j
, const const_vectoriterator_type
&itv
, const const_subiterator_type
&it
):
527 container_const_reference
<self_type
> (m
), rank_ (rank
), i_ (i
), j_ (j
), itv_ (itv
), it_ (it
) {}
529 const_iterator1 (const iterator1
&it
):
530 container_const_reference
<self_type
> (it ()), rank_ (it
.rank_
), i_ (it
.i_
), j_ (it
.j_
), itv_ (it
.itv_
), it_ (it
.it_
) {}
534 const_iterator1
&operator ++ () {
535 if (rank_
== 1 && layout_type::fast_i ())
538 const self_type
&m
= (*this) ();
540 if (rank_
== 1 && ++ itv_
== m
.end1 ().itv_
)
541 *this = m
.find1 (rank_
, i_
, j_
, 1);
542 else if (rank_
== 1) {
543 it_
= (*itv_
).begin ();
544 if (it_
== (*itv_
).end () || index2 () != j_
)
545 *this = m
.find1 (rank_
, i_
, j_
, 1);
551 const_iterator1
&operator -- () {
552 if (rank_
== 1 && layout_type::fast_i ())
555 const self_type
&m
= (*this) ();
557 if (rank_
== 1 && -- itv_
== m
.end1 ().itv_
)
558 *this = m
.find1 (rank_
, i_
, j_
, -1);
559 else if (rank_
== 1) {
560 it_
= (*itv_
).begin ();
561 if (it_
== (*itv_
).end () || index2 () != j_
)
562 *this = m
.find1 (rank_
, i_
, j_
, -1);
570 const_reference
operator * () const {
571 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
572 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
576 return (*this) () (i_
, j_
);
580 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
582 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
585 const_iterator2
begin () const {
586 const self_type
&m
= (*this) ();
587 return m
.find2 (1, index1 (), 0);
590 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
593 const_iterator2
end () const {
594 const self_type
&m
= (*this) ();
595 return m
.find2 (1, index1 (), m
.size2 ());
598 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
601 const_reverse_iterator2
rbegin () const {
602 return const_reverse_iterator2 (end ());
605 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
608 const_reverse_iterator2
rend () const {
609 return const_reverse_iterator2 (begin ());
615 size_type
index1 () const {
616 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_
), bad_index ());
618 BOOST_UBLAS_CHECK (layout_type::index_M (itv_
.index (), it_
.index ()) < (*this) ().size1 (), bad_index ());
619 return layout_type::index_M (itv_
.index (), it_
.index ());
625 size_type
index2 () const {
626 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_
), bad_index ());
628 BOOST_UBLAS_CHECK (layout_type::index_m (itv_
.index (), it_
.index ()) < (*this) ().size2 (), bad_index ());
629 return layout_type::index_m (itv_
.index (), it_
.index ());
637 const_iterator1
&operator = (const const_iterator1
&it
) {
638 container_const_reference
<self_type
>::assign (&it ());
649 bool operator == (const const_iterator1
&it
) const {
650 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
651 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
652 if (rank_
== 1 || it
.rank_
== 1) {
653 return it_
== it
.it_
;
655 return i_
== it
.i_
&& j_
== it
.j_
;
663 const_vectoriterator_type itv_
;
664 const_subiterator_type it_
;
668 const_iterator1
begin1 () const {
669 return find1 (0, 0, 0);
672 const_iterator1
end1 () const {
673 return find1 (0, size1_
, 0);
677 public container_reference
<generalized_vector_of_vector
>,
678 public bidirectional_iterator_base
<sparse_bidirectional_iterator_tag
,
679 iterator1
, value_type
> {
681 typedef typename
generalized_vector_of_vector::difference_type difference_type
;
682 typedef typename
generalized_vector_of_vector::value_type value_type
;
683 typedef typename
generalized_vector_of_vector::true_reference reference
;
684 typedef typename
generalized_vector_of_vector::pointer pointer
;
686 typedef iterator2 dual_iterator_type
;
687 typedef reverse_iterator2 dual_reverse_iterator_type
;
689 // Construction and destruction
692 container_reference
<self_type
> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
694 iterator1 (self_type
&m
, int rank
, size_type i
, size_type j
, const vectoriterator_type
&itv
, const subiterator_type
&it
):
695 container_reference
<self_type
> (m
), rank_ (rank
), i_ (i
), j_ (j
), itv_ (itv
), it_ (it
) {}
699 iterator1
&operator ++ () {
700 if (rank_
== 1 && layout_type::fast_i ())
703 self_type
&m
= (*this) ();
705 if (rank_
== 1 && ++ itv_
== m
.end1 ().itv_
)
706 *this = m
.find1 (rank_
, i_
, j_
, 1);
707 else if (rank_
== 1) {
708 it_
= (*itv_
).begin ();
709 if (it_
== (*itv_
).end () || index2 () != j_
)
710 *this = m
.find1 (rank_
, i_
, j_
, 1);
716 iterator1
&operator -- () {
717 if (rank_
== 1 && layout_type::fast_i ())
720 self_type
&m
= (*this) ();
722 if (rank_
== 1 && -- itv_
== m
.end1 ().itv_
)
723 *this = m
.find1 (rank_
, i_
, j_
, -1);
724 else if (rank_
== 1) {
725 it_
= (*itv_
).begin ();
726 if (it_
== (*itv_
).end () || index2 () != j_
)
727 *this = m
.find1 (rank_
, i_
, j_
, -1);
735 true_reference
operator * () const {
736 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
737 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
741 return (*this) ().at_element (i_
, j_
);
745 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
747 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
750 iterator2
begin () const {
751 self_type
&m
= (*this) ();
752 return m
.find2 (1, index1 (), 0);
755 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
758 iterator2
end () const {
759 self_type
&m
= (*this) ();
760 return m
.find2 (1, index1 (), m
.size2 ());
763 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
766 reverse_iterator2
rbegin () const {
767 return reverse_iterator2 (end ());
770 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
773 reverse_iterator2
rend () const {
774 return reverse_iterator2 (begin ());
780 size_type
index1 () const {
781 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_
), bad_index ());
783 BOOST_UBLAS_CHECK (layout_type::index_M (itv_
.index (), it_
.index ()) < (*this) ().size1 (), bad_index ());
784 return layout_type::index_M (itv_
.index (), it_
.index ());
790 size_type
index2 () const {
791 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_
), bad_index ());
793 BOOST_UBLAS_CHECK (layout_type::index_m (itv_
.index (), it_
.index ()) < (*this) ().size2 (), bad_index ());
794 return layout_type::index_m (itv_
.index (), it_
.index ());
802 iterator1
&operator = (const iterator1
&it
) {
803 container_reference
<self_type
>::assign (&it ());
814 bool operator == (const iterator1
&it
) const {
815 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
816 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
817 if (rank_
== 1 || it
.rank_
== 1) {
818 return it_
== it
.it_
;
820 return i_
== it
.i_
&& j_
== it
.j_
;
828 vectoriterator_type itv_
;
829 subiterator_type it_
;
831 friend class const_iterator1
;
835 iterator1
begin1 () {
836 return find1 (0, 0, 0);
840 return find1 (0, size1_
, 0);
843 class const_iterator2
:
844 public container_const_reference
<generalized_vector_of_vector
>,
845 public bidirectional_iterator_base
<sparse_bidirectional_iterator_tag
,
846 const_iterator2
, value_type
> {
848 typedef typename
generalized_vector_of_vector::difference_type difference_type
;
849 typedef typename
generalized_vector_of_vector::value_type value_type
;
850 typedef typename
generalized_vector_of_vector::const_reference reference
;
851 typedef const typename
generalized_vector_of_vector::pointer pointer
;
853 typedef const_iterator1 dual_iterator_type
;
854 typedef const_reverse_iterator1 dual_reverse_iterator_type
;
856 // Construction and destruction
859 container_const_reference
<self_type
> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
861 const_iterator2 (const self_type
&m
, int rank
, size_type i
, size_type j
, const const_vectoriterator_type
&itv
, const const_subiterator_type
&it
):
862 container_const_reference
<self_type
> (m
), rank_ (rank
), i_ (i
), j_ (j
), itv_ (itv
), it_ (it
) {}
864 const_iterator2 (const iterator2
&it
):
865 container_const_reference
<self_type
> (it ()), rank_ (it
.rank_
), i_ (it
.i_
), j_ (it
.j_
), itv_ (it
.itv_
), it_ (it
.it_
) {}
869 const_iterator2
&operator ++ () {
870 if (rank_
== 1 && layout_type::fast_j ())
873 const self_type
&m
= (*this) ();
875 if (rank_
== 1 && ++ itv_
== m
.end2 ().itv_
)
876 *this = m
.find2 (rank_
, i_
, j_
, 1);
877 else if (rank_
== 1) {
878 it_
= (*itv_
).begin ();
879 if (it_
== (*itv_
).end () || index1 () != i_
)
880 *this = m
.find2 (rank_
, i_
, j_
, 1);
886 const_iterator2
&operator -- () {
887 if (rank_
== 1 && layout_type::fast_j ())
890 const self_type
&m
= (*this) ();
892 if (rank_
== 1 && -- itv_
== m
.end2 ().itv_
)
893 *this = m
.find2 (rank_
, i_
, j_
, -1);
894 else if (rank_
== 1) {
895 it_
= (*itv_
).begin ();
896 if (it_
== (*itv_
).end () || index1 () != i_
)
897 *this = m
.find2 (rank_
, i_
, j_
, -1);
905 const_reference
operator * () const {
906 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
907 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
911 return (*this) () (i_
, j_
);
915 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
917 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
920 const_iterator1
begin () const {
921 const self_type
&m
= (*this) ();
922 return m
.find1 (1, 0, index2 ());
925 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
928 const_iterator1
end () const {
929 const self_type
&m
= (*this) ();
930 return m
.find1 (1, m
.size1 (), index2 ());
933 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
936 const_reverse_iterator1
rbegin () const {
937 return const_reverse_iterator1 (end ());
940 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
943 const_reverse_iterator1
rend () const {
944 return const_reverse_iterator1 (begin ());
950 size_type
index1 () const {
951 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_
, (*this) ().size2 ()), bad_index ());
953 BOOST_UBLAS_CHECK (layout_type::index_M (itv_
.index (), it_
.index ()) < (*this) ().size1 (), bad_index ());
954 return layout_type::index_M (itv_
.index (), it_
.index ());
960 size_type
index2 () const {
961 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_
, (*this) ().size2 ()), bad_index ());
963 BOOST_UBLAS_CHECK (layout_type::index_m (itv_
.index (), it_
.index ()) < (*this) ().size2 (), bad_index ());
964 return layout_type::index_m (itv_
.index (), it_
.index ());
972 const_iterator2
&operator = (const const_iterator2
&it
) {
973 container_const_reference
<self_type
>::assign (&it ());
984 bool operator == (const const_iterator2
&it
) const {
985 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
986 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
987 if (rank_
== 1 || it
.rank_
== 1) {
988 return it_
== it
.it_
;
990 return i_
== it
.i_
&& j_
== it
.j_
;
998 const_vectoriterator_type itv_
;
999 const_subiterator_type it_
;
1003 const_iterator2
begin2 () const {
1004 return find2 (0, 0, 0);
1007 const_iterator2
end2 () const {
1008 return find2 (0, 0, size2_
);
1012 public container_reference
<generalized_vector_of_vector
>,
1013 public bidirectional_iterator_base
<sparse_bidirectional_iterator_tag
,
1014 iterator2
, value_type
> {
1016 typedef typename
generalized_vector_of_vector::difference_type difference_type
;
1017 typedef typename
generalized_vector_of_vector::value_type value_type
;
1018 typedef typename
generalized_vector_of_vector::true_reference reference
;
1019 typedef typename
generalized_vector_of_vector::pointer pointer
;
1021 typedef iterator1 dual_iterator_type
;
1022 typedef reverse_iterator1 dual_reverse_iterator_type
;
1024 // Construction and destruction
1027 container_reference
<self_type
> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
1029 iterator2 (self_type
&m
, int rank
, size_type i
, size_type j
, const vectoriterator_type
&itv
, const subiterator_type
&it
):
1030 container_reference
<self_type
> (m
), rank_ (rank
), i_ (i
), j_ (j
), itv_ (itv
), it_ (it
) {}
1034 iterator2
&operator ++ () {
1035 if (rank_
== 1 && layout_type::fast_j ())
1038 self_type
&m
= (*this) ();
1040 if (rank_
== 1 && ++ itv_
== m
.end2 ().itv_
)
1041 *this = m
.find2 (rank_
, i_
, j_
, 1);
1042 else if (rank_
== 1) {
1043 it_
= (*itv_
).begin ();
1044 if (it_
== (*itv_
).end () || index1 () != i_
)
1045 *this = m
.find2 (rank_
, i_
, j_
, 1);
1051 iterator2
&operator -- () {
1052 if (rank_
== 1 && layout_type::fast_j ())
1055 self_type
&m
= (*this) ();
1057 if (rank_
== 1 && -- itv_
== m
.end2 ().itv_
)
1058 *this = m
.find2 (rank_
, i_
, j_
, -1);
1059 else if (rank_
== 1) {
1060 it_
= (*itv_
).begin ();
1061 if (it_
== (*itv_
).end () || index1 () != i_
)
1062 *this = m
.find2 (rank_
, i_
, j_
, -1);
1070 true_reference
operator * () const {
1071 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
1072 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
1076 return (*this) ().at_element (i_
, j_
);
1080 #ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1082 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1083 typename
self_type::
1085 iterator1
begin () const {
1086 self_type
&m
= (*this) ();
1087 return m
.find1 (1, 0, index2 ());
1090 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1091 typename
self_type::
1093 iterator1
end () const {
1094 self_type
&m
= (*this) ();
1095 return m
.find1 (1, m
.size1 (), index2 ());
1098 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1099 typename
self_type::
1101 reverse_iterator1
rbegin () const {
1102 return reverse_iterator1 (end ());
1105 #ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1106 typename
self_type::
1108 reverse_iterator1
rend () const {
1109 return reverse_iterator1 (begin ());
1115 size_type
index1 () const {
1116 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_
, (*this) ().size2 ()), bad_index ());
1118 BOOST_UBLAS_CHECK (layout_type::index_M (itv_
.index (), it_
.index ()) < (*this) ().size1 (), bad_index ());
1119 return layout_type::index_M (itv_
.index (), it_
.index ());
1125 size_type
index2 () const {
1126 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_
, (*this) ().size2 ()), bad_index ());
1128 BOOST_UBLAS_CHECK (layout_type::index_m (itv_
.index (), it_
.index ()) < (*this) ().size2 (), bad_index ());
1129 return layout_type::index_m (itv_
.index (), it_
.index ());
1137 iterator2
&operator = (const iterator2
&it
) {
1138 container_reference
<self_type
>::assign (&it ());
1149 bool operator == (const iterator2
&it
) const {
1150 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1151 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
1152 if (rank_
== 1 || it
.rank_
== 1) {
1153 return it_
== it
.it_
;
1155 return i_
== it
.i_
&& j_
== it
.j_
;
1163 vectoriterator_type itv_
;
1164 subiterator_type it_
;
1166 friend class const_iterator2
;
1170 iterator2
begin2 () {
1171 return find2 (0, 0, 0);
1175 return find2 (0, 0, size2_
);
1178 // Reverse iterators
1181 const_reverse_iterator1
rbegin1 () const {
1182 return const_reverse_iterator1 (end1 ());
1185 const_reverse_iterator1
rend1 () const {
1186 return const_reverse_iterator1 (begin1 ());
1190 reverse_iterator1
rbegin1 () {
1191 return reverse_iterator1 (end1 ());
1194 reverse_iterator1
rend1 () {
1195 return reverse_iterator1 (begin1 ());
1199 const_reverse_iterator2
rbegin2 () const {
1200 return const_reverse_iterator2 (end2 ());
1203 const_reverse_iterator2
rend2 () const {
1204 return const_reverse_iterator2 (begin2 ());
1208 reverse_iterator2
rbegin2 () {
1209 return reverse_iterator2 (end2 ());
1212 reverse_iterator2
rend2 () {
1213 return reverse_iterator2 (begin2 ());
1217 template<class Archive
>
1218 void serialize(Archive
& ar
, const unsigned int /* file_version */){
1220 // we need to copy to a collection_size_type to get a portable
1221 // and efficient serialization
1222 serialization::collection_size_type
s1 (size1_
);
1223 serialization::collection_size_type
s2 (size2_
);
1225 // serialize the sizes
1226 ar
& serialization::make_nvp("size1",s1
)
1227 & serialization::make_nvp("size2",s2
);
1229 // copy the values back if loading
1230 if (Archive::is_loading::value
) {
1235 ar
& serialization::make_nvp("data", data_
);
1237 storage_invariants();
1241 void storage_invariants () const
1243 BOOST_UBLAS_CHECK (layout_type::size_M (size1_
, size2_
) + 1 == data_
.size (), internal_logic ());
1244 BOOST_UBLAS_CHECK (data ().begin () != data ().end (), internal_logic ());
1250 static const value_type zero_
;
1253 template<class T
, class L
, class A
>
1254 const typename generalized_vector_of_vector
<T
, L
, A
>::value_type generalized_vector_of_vector
<T
, L
, A
>::zero_
= value_type
/*zero*/();