1 // SPDX-License-Identifier: Apache-2.0
2 //
3 // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au)
4 // Copyright 2008-2016 National ICT Australia (NICTA)
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 // ------------------------------------------------------------------------
17
18
19 //! \addtogroup SpMat
20 //! @{
21
22
23 ///////////////////////////////////////////////////////////////////////////////
24 // SpMat::iterator_base implementation //
25 ///////////////////////////////////////////////////////////////////////////////
26
27
28 template<typename eT>
29 inline
iterator_base()30 SpMat<eT>::iterator_base::iterator_base()
31 : M(nullptr)
32 , internal_col(0)
33 , internal_pos(0)
34 {
35 // Technically this iterator is invalid (it does not point to a valid element)
36 }
37
38
39
40 template<typename eT>
41 inline
iterator_base(const SpMat<eT> & in_M)42 SpMat<eT>::iterator_base::iterator_base(const SpMat<eT>& in_M)
43 : M(&in_M)
44 , internal_col(0)
45 , internal_pos(0)
46 {
47 // Technically this iterator is invalid (it may not point to a valid element)
48 }
49
50
51
52 template<typename eT>
53 inline
iterator_base(const SpMat<eT> & in_M,const uword in_col,const uword in_pos)54 SpMat<eT>::iterator_base::iterator_base(const SpMat<eT>& in_M, const uword in_col, const uword in_pos)
55 : M(&in_M)
56 , internal_col(in_col)
57 , internal_pos(in_pos)
58 {
59 // Nothing to do.
60 }
61
62
63
64 template<typename eT>
65 arma_inline
66 eT
operator *() const67 SpMat<eT>::iterator_base::operator*() const
68 {
69 return M->values[internal_pos];
70 }
71
72
73
74 ///////////////////////////////////////////////////////////////////////////////
75 // SpMat::const_iterator implementation //
76 ///////////////////////////////////////////////////////////////////////////////
77
78 template<typename eT>
79 inline
const_iterator()80 SpMat<eT>::const_iterator::const_iterator()
81 : iterator_base()
82 {
83 }
84
85
86
87 template<typename eT>
88 inline
const_iterator(const SpMat<eT> & in_M,uword initial_pos)89 SpMat<eT>::const_iterator::const_iterator(const SpMat<eT>& in_M, uword initial_pos)
90 : iterator_base(in_M, 0, initial_pos)
91 {
92 // Corner case for empty matrices.
93 if(in_M.n_nonzero == 0)
94 {
95 iterator_base::internal_col = in_M.n_cols;
96 return;
97 }
98
99 // Determine which column we should be in.
100 while(iterator_base::M->col_ptrs[iterator_base::internal_col + 1] <= iterator_base::internal_pos)
101 {
102 iterator_base::internal_col++;
103 }
104 }
105
106
107
108 template<typename eT>
109 inline
const_iterator(const SpMat<eT> & in_M,uword in_row,uword in_col)110 SpMat<eT>::const_iterator::const_iterator(const SpMat<eT>& in_M, uword in_row, uword in_col)
111 : iterator_base(in_M, in_col, 0)
112 {
113 // So we have a position we want to be right after. Skip to the column.
114 iterator_base::internal_pos = iterator_base::M->col_ptrs[iterator_base::internal_col];
115
116 // Now we have to make sure that is the right column.
117 while(iterator_base::M->col_ptrs[iterator_base::internal_col + 1] <= iterator_base::internal_pos)
118 {
119 iterator_base::internal_col++;
120 }
121
122 // Now we have to get to the right row.
123 while((iterator_base::M->row_indices[iterator_base::internal_pos] < in_row) && (iterator_base::internal_col == in_col))
124 {
125 ++(*this); // Increment iterator.
126 }
127 }
128
129
130
131 template<typename eT>
132 inline
const_iterator(const SpMat<eT> & in_M,const uword,const uword in_col,const uword in_pos)133 SpMat<eT>::const_iterator::const_iterator(const SpMat<eT>& in_M, const uword /* in_row */, const uword in_col, const uword in_pos)
134 : iterator_base(in_M, in_col, in_pos)
135 {
136 // Nothing to do.
137 }
138
139
140
141 template<typename eT>
142 inline
const_iterator(const typename SpMat<eT>::const_iterator & other)143 SpMat<eT>::const_iterator::const_iterator(const typename SpMat<eT>::const_iterator& other)
144 : iterator_base(*other.M, other.internal_col, other.internal_pos)
145 {
146 // Nothing to do.
147 }
148
149
150
151 template<typename eT>
152 inline
153 arma_hot
154 typename SpMat<eT>::const_iterator&
operator ++()155 SpMat<eT>::const_iterator::operator++()
156 {
157 ++iterator_base::internal_pos;
158
159 if(iterator_base::internal_pos == iterator_base::M->n_nonzero)
160 {
161 iterator_base::internal_col = iterator_base::M->n_cols;
162 return *this;
163 }
164
165 // Check to see if we moved a column.
166 while(iterator_base::M->col_ptrs[iterator_base::internal_col + 1] <= iterator_base::internal_pos)
167 {
168 ++iterator_base::internal_col;
169 }
170
171 return *this;
172 }
173
174
175
176 template<typename eT>
177 inline
178 arma_warn_unused
179 typename SpMat<eT>::const_iterator
operator ++(int)180 SpMat<eT>::const_iterator::operator++(int)
181 {
182 typename SpMat<eT>::const_iterator tmp(*this);
183
184 ++(*this);
185
186 return tmp;
187 }
188
189
190
191 template<typename eT>
192 inline
193 arma_hot
194 typename SpMat<eT>::const_iterator&
operator --()195 SpMat<eT>::const_iterator::operator--()
196 {
197 --iterator_base::internal_pos;
198
199 // First, see if we moved back a column.
200 while(iterator_base::internal_pos < iterator_base::M->col_ptrs[iterator_base::internal_col])
201 {
202 --iterator_base::internal_col;
203 }
204
205 return *this;
206 }
207
208
209
210 template<typename eT>
211 inline
212 arma_warn_unused
213 typename SpMat<eT>::const_iterator
operator --(int)214 SpMat<eT>::const_iterator::operator--(int)
215 {
216 typename SpMat<eT>::const_iterator tmp(*this);
217
218 --(*this);
219
220 return tmp;
221 }
222
223
224
225 template<typename eT>
226 inline
227 arma_hot
228 bool
operator ==(const const_iterator & rhs) const229 SpMat<eT>::const_iterator::operator==(const const_iterator& rhs) const
230 {
231 return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col);
232 }
233
234
235
236 template<typename eT>
237 inline
238 arma_hot
239 bool
operator !=(const const_iterator & rhs) const240 SpMat<eT>::const_iterator::operator!=(const const_iterator& rhs) const
241 {
242 return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col);
243 }
244
245
246
247 template<typename eT>
248 inline
249 arma_hot
250 bool
operator ==(const typename SpSubview<eT>::const_iterator & rhs) const251 SpMat<eT>::const_iterator::operator==(const typename SpSubview<eT>::const_iterator& rhs) const
252 {
253 return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col);
254 }
255
256
257
258 template<typename eT>
259 inline
260 arma_hot
261 bool
operator !=(const typename SpSubview<eT>::const_iterator & rhs) const262 SpMat<eT>::const_iterator::operator!=(const typename SpSubview<eT>::const_iterator& rhs) const
263 {
264 return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col);
265 }
266
267
268
269 template<typename eT>
270 inline
271 arma_hot
272 bool
operator ==(const const_row_iterator & rhs) const273 SpMat<eT>::const_iterator::operator==(const const_row_iterator& rhs) const
274 {
275 return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col);
276 }
277
278
279
280 template<typename eT>
281 inline
282 arma_hot
283 bool
operator !=(const const_row_iterator & rhs) const284 SpMat<eT>::const_iterator::operator!=(const const_row_iterator& rhs) const
285 {
286 return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col);
287 }
288
289
290
291 template<typename eT>
292 inline
293 arma_hot
294 bool
operator ==(const typename SpSubview<eT>::const_row_iterator & rhs) const295 SpMat<eT>::const_iterator::operator==(const typename SpSubview<eT>::const_row_iterator& rhs) const
296 {
297 return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col);
298 }
299
300
301
302 template<typename eT>
303 inline
304 arma_hot
305 bool
operator !=(const typename SpSubview<eT>::const_row_iterator & rhs) const306 SpMat<eT>::const_iterator::operator!=(const typename SpSubview<eT>::const_row_iterator& rhs) const
307 {
308 return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col);
309 }
310
311
312
313 ///////////////////////////////////////////////////////////////////////////////
314 // SpMat::iterator implementation //
315 ///////////////////////////////////////////////////////////////////////////////
316
317 template<typename eT>
318 inline
319 arma_hot
320 SpValProxy< SpMat<eT> >
operator *()321 SpMat<eT>::iterator::operator*()
322 {
323 return SpValProxy< SpMat<eT> >(
324 iterator_base::M->row_indices[iterator_base::internal_pos],
325 iterator_base::internal_col,
326 access::rw(*iterator_base::M),
327 &access::rw(iterator_base::M->values[iterator_base::internal_pos]));
328 }
329
330
331
332 template<typename eT>
333 inline
334 arma_hot
335 typename SpMat<eT>::iterator&
operator ++()336 SpMat<eT>::iterator::operator++()
337 {
338 const_iterator::operator++();
339
340 return *this;
341 }
342
343
344
345 template<typename eT>
346 inline
347 arma_warn_unused
348 typename SpMat<eT>::iterator
operator ++(int)349 SpMat<eT>::iterator::operator++(int)
350 {
351 typename SpMat<eT>::iterator tmp(*this);
352
353 const_iterator::operator++();
354
355 return tmp;
356 }
357
358
359
360 template<typename eT>
361 inline
362 arma_hot
363 typename SpMat<eT>::iterator&
operator --()364 SpMat<eT>::iterator::operator--()
365 {
366 const_iterator::operator--();
367
368 return *this;
369 }
370
371
372
373 template<typename eT>
374 inline
375 arma_warn_unused
376 typename SpMat<eT>::iterator
operator --(int)377 SpMat<eT>::iterator::operator--(int)
378 {
379 typename SpMat<eT>::iterator tmp(*this);
380
381 const_iterator::operator--();
382
383 return tmp;
384 }
385
386
387
388 ///////////////////////////////////////////////////////////////////////////////
389 // SpMat::const_row_iterator implementation //
390 ///////////////////////////////////////////////////////////////////////////////
391
392 /**
393 * Initialize the const_row_iterator.
394 */
395
396 template<typename eT>
397 inline
const_row_iterator()398 SpMat<eT>::const_row_iterator::const_row_iterator()
399 : iterator_base()
400 , internal_row(0)
401 , actual_pos(0)
402 {
403 }
404
405
406
407 template<typename eT>
408 inline
const_row_iterator(const SpMat<eT> & in_M,uword initial_pos)409 SpMat<eT>::const_row_iterator::const_row_iterator(const SpMat<eT>& in_M, uword initial_pos)
410 : iterator_base(in_M, 0, initial_pos)
411 , internal_row(0)
412 , actual_pos(0)
413 {
414 // Corner case for the end of a matrix.
415 if(initial_pos == in_M.n_nonzero)
416 {
417 iterator_base::internal_col = 0;
418 internal_row = in_M.n_rows;
419 actual_pos = in_M.n_nonzero;
420 iterator_base::internal_pos = in_M.n_nonzero;
421
422 return;
423 }
424
425 // We don't count zeros in our position count, so we have to find the nonzero
426 // value corresponding to the given initial position. We assume initial_pos
427 // is valid.
428
429 // This is irritating because we don't know where the elements are in each row.
430 // What we will do is loop across all columns looking for elements in row 0
431 // (and add to our sum), then in row 1, and so forth, until we get to the desired position.
432 uword cur_pos = std::numeric_limits<uword>::max(); // Invalid value.
433 uword cur_actual_pos = 0;
434
435 for(uword row = 0; row < iterator_base::M->n_rows; ++row)
436 {
437 for(uword col = 0; col < iterator_base::M->n_cols; ++col)
438 {
439 // Find the first element with row greater than or equal to in_row.
440 const uword col_offset = iterator_base::M->col_ptrs[col ];
441 const uword next_col_offset = iterator_base::M->col_ptrs[col + 1];
442
443 const uword* start_ptr = &iterator_base::M->row_indices[ col_offset];
444 const uword* end_ptr = &iterator_base::M->row_indices[next_col_offset];
445
446 if(start_ptr != end_ptr)
447 {
448 const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, row);
449
450 // This is the number of elements in the column with row index less than in_row.
451 const uword offset = uword(pos_ptr - start_ptr);
452
453 if(iterator_base::M->row_indices[col_offset + offset] == row)
454 {
455 cur_actual_pos = col_offset + offset;
456
457 // Increment position portably.
458 if(cur_pos == std::numeric_limits<uword>::max())
459 { cur_pos = 0; }
460 else
461 { ++cur_pos; }
462
463 // Do we terminate?
464 if(cur_pos == initial_pos)
465 {
466 internal_row = row;
467 iterator_base::internal_col = col;
468 iterator_base::internal_pos = cur_pos;
469 actual_pos = cur_actual_pos;
470
471 return;
472 }
473 }
474 }
475 }
476 }
477
478 // If we got to here, then we have gone past the end of the matrix.
479 // This shouldn't happen...
480 iterator_base::internal_pos = iterator_base::M->n_nonzero;
481 iterator_base::internal_col = 0;
482 internal_row = iterator_base::M->n_rows;
483 actual_pos = iterator_base::M->n_nonzero;
484 }
485
486
487
488 template<typename eT>
489 inline
const_row_iterator(const SpMat<eT> & in_M,uword in_row,uword in_col)490 SpMat<eT>::const_row_iterator::const_row_iterator(const SpMat<eT>& in_M, uword in_row, uword in_col)
491 : iterator_base(in_M, in_col, 0)
492 , internal_row(0)
493 , actual_pos(0)
494 {
495 // Start our search in the given row. We need to find two things:
496 //
497 // 1. The first nonzero element (iterating by rows) after (in_row, in_col).
498 // 2. The number of nonzero elements (iterating by rows) that come before
499 // (in_row, in_col).
500 //
501 // We'll find these simultaneously, though we will have to loop over all
502 // columns.
503
504 // This will hold the total number of points with rows less than in_row.
505 uword cur_pos = 0;
506 uword cur_min_row = iterator_base::M->n_rows;
507 uword cur_min_col = 0;
508 uword cur_actual_pos = 0;
509
510 for(uword col = 0; col < iterator_base::M->n_cols; ++col)
511 {
512 // Find the first element with row greater than or equal to in_row.
513 const uword col_offset = iterator_base::M->col_ptrs[col ];
514 const uword next_col_offset = iterator_base::M->col_ptrs[col + 1];
515
516 const uword* start_ptr = &iterator_base::M->row_indices[ col_offset];
517 const uword* end_ptr = &iterator_base::M->row_indices[next_col_offset];
518
519 if(start_ptr != end_ptr)
520 {
521 const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, in_row);
522
523 // This is the number of elements in the column with row index less than in_row.
524 const uword offset = uword(pos_ptr - start_ptr);
525
526 cur_pos += offset;
527
528 if(pos_ptr != end_ptr)
529 {
530 // This is the row index of the first element in the column with row index
531 // greater than or equal to in_row.
532 if((*pos_ptr) < cur_min_row)
533 {
534 // If we are in the desired row but before the desired column,
535 // we can't take this.
536 if(col >= in_col)
537 {
538 cur_min_row = (*pos_ptr);
539 cur_min_col = col;
540 cur_actual_pos = col_offset + offset;
541 }
542 }
543 }
544 }
545 }
546
547 // Now we know what the minimum row is.
548 internal_row = cur_min_row;
549 iterator_base::internal_col = cur_min_col;
550 iterator_base::internal_pos = cur_pos;
551 actual_pos = cur_actual_pos;
552 }
553
554
555
556 /**
557 * Initialize the const_row_iterator from another const_row_iterator.
558 */
559 template<typename eT>
560 inline
const_row_iterator(const typename SpMat<eT>::const_row_iterator & other)561 SpMat<eT>::const_row_iterator::const_row_iterator(const typename SpMat<eT>::const_row_iterator& other)
562 : iterator_base(*other.M, other.internal_col, other.internal_pos)
563 , internal_row(other.internal_row)
564 , actual_pos(other.actual_pos)
565 {
566 // Nothing to do.
567 }
568
569
570
571 /**
572 * Increment the row_iterator.
573 */
574 template<typename eT>
575 inline
576 arma_hot
577 typename SpMat<eT>::const_row_iterator&
operator ++()578 SpMat<eT>::const_row_iterator::operator++()
579 {
580 // We just need to find the next nonzero element.
581 iterator_base::internal_pos++;
582
583 if(iterator_base::internal_pos == iterator_base::M->n_nonzero)
584 {
585 internal_row = iterator_base::M->n_rows;
586 iterator_base::internal_col = 0;
587
588 return *this;
589 }
590
591 // Otherwise, we need to search. We can start in the next column and use
592 // lower_bound() to find the next element.
593 uword next_min_row = iterator_base::M->n_rows;
594 uword next_min_col = iterator_base::M->n_cols;
595 uword next_actual_pos = 0;
596
597 // Search from the current column to the end of the matrix.
598 for(uword col = iterator_base::internal_col + 1; col < iterator_base::M->n_cols; ++col)
599 {
600 // Find the first element with row greater than or equal to in_row.
601 const uword col_offset = iterator_base::M->col_ptrs[col ];
602 const uword next_col_offset = iterator_base::M->col_ptrs[col + 1];
603
604 const uword* start_ptr = &iterator_base::M->row_indices[ col_offset];
605 const uword* end_ptr = &iterator_base::M->row_indices[next_col_offset];
606
607 if(start_ptr != end_ptr)
608 {
609 // Find the first element in the column with row greater than or equal to
610 // the current row.
611 const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row);
612
613 if(pos_ptr != end_ptr)
614 {
615 // We found something in the column, but is the row index correct?
616 if((*pos_ptr) == internal_row)
617 {
618 // Exact match---so we are done.
619 iterator_base::internal_col = col;
620 actual_pos = col_offset + (pos_ptr - start_ptr);
621 return *this;
622 }
623 else if((*pos_ptr) < next_min_row)
624 {
625 // The first element in this column is in a subsequent row, but it's
626 // the minimum row we've seen so far.
627 next_min_row = (*pos_ptr);
628 next_min_col = col;
629 next_actual_pos = col_offset + (pos_ptr - start_ptr);
630 }
631 else if((*pos_ptr) == next_min_row && col < next_min_col)
632 {
633 // The first element in this column is in a subsequent row that we
634 // already have another element for, but the column index is less so
635 // this element will come first.
636 next_min_col = col;
637 next_actual_pos = col_offset + (pos_ptr - start_ptr);
638 }
639 }
640 }
641 }
642
643 // Restart the search in the next row.
644 for(uword col = 0; col <= iterator_base::internal_col; ++col)
645 {
646 // Find the first element with row greater than or equal to in_row + 1.
647 const uword col_offset = iterator_base::M->col_ptrs[col ];
648 const uword next_col_offset = iterator_base::M->col_ptrs[col + 1];
649
650 const uword* start_ptr = &iterator_base::M->row_indices[ col_offset];
651 const uword* end_ptr = &iterator_base::M->row_indices[next_col_offset];
652
653 if(start_ptr != end_ptr)
654 {
655 const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + 1);
656
657 if(pos_ptr != end_ptr)
658 {
659 // We found something in the column, but is the row index correct?
660 if((*pos_ptr) == internal_row + 1)
661 {
662 // Exact match---so we are done.
663 iterator_base::internal_col = col;
664 internal_row++;
665 actual_pos = col_offset + (pos_ptr - start_ptr);
666 return *this;
667 }
668 else if((*pos_ptr) < next_min_row)
669 {
670 // The first element in this column is in a subsequent row,
671 // but it's the minimum row we've seen so far.
672 next_min_row = (*pos_ptr);
673 next_min_col = col;
674 next_actual_pos = col_offset + (pos_ptr - start_ptr);
675 }
676 else if((*pos_ptr) == next_min_row && col < next_min_col)
677 {
678 // The first element in this column is in a subsequent row that we
679 // already have another element for, but the column index is less so
680 // this element will come first.
681 next_min_col = col;
682 next_actual_pos = col_offset + (pos_ptr - start_ptr);
683 }
684 }
685 }
686 }
687
688 iterator_base::internal_col = next_min_col;
689 internal_row = next_min_row;
690 actual_pos = next_actual_pos;
691
692 return *this; // Now we are done.
693 }
694
695
696
697 /**
698 * Increment the row_iterator (but do not return anything.
699 */
700 template<typename eT>
701 inline
702 arma_warn_unused
703 typename SpMat<eT>::const_row_iterator
operator ++(int)704 SpMat<eT>::const_row_iterator::operator++(int)
705 {
706 typename SpMat<eT>::const_row_iterator tmp(*this);
707
708 ++(*this);
709
710 return tmp;
711 }
712
713
714
715 /**
716 * Decrement the row_iterator.
717 */
718 template<typename eT>
719 inline
720 arma_hot
721 typename SpMat<eT>::const_row_iterator&
operator --()722 SpMat<eT>::const_row_iterator::operator--()
723 {
724 if(iterator_base::internal_pos == 0)
725 {
726 // Do nothing; we are already at the beginning.
727 return *this;
728 }
729
730 iterator_base::internal_pos--;
731
732 // We have to search backwards. We'll do this by going backwards over columns
733 // and seeing if we find an element in the same row.
734 uword max_row = 0;
735 uword max_col = 0;
736 uword next_actual_pos = 0;
737
738 //for(uword col = iterator_base::internal_col; col > 1; --col)
739 for(uword col = iterator_base::internal_col; col >= 1; --col)
740 {
741 // Find the first element with row greater than or equal to in_row + 1.
742 const uword col_offset = iterator_base::M->col_ptrs[col - 1];
743 const uword next_col_offset = iterator_base::M->col_ptrs[col ];
744
745 const uword* start_ptr = &iterator_base::M->row_indices[ col_offset];
746 const uword* end_ptr = &iterator_base::M->row_indices[next_col_offset];
747
748 if(start_ptr != end_ptr)
749 {
750 // There are elements in this column.
751 const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + 1);
752
753 if(pos_ptr != start_ptr)
754 {
755 // The element before pos_ptr is the one we are interested in.
756 if(*(pos_ptr - 1) > max_row)
757 {
758 max_row = *(pos_ptr - 1);
759 max_col = col - 1;
760 next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr);
761 }
762 else if(*(pos_ptr - 1) == max_row && (col - 1) > max_col)
763 {
764 max_col = col - 1;
765 next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr);
766 }
767 }
768 }
769 }
770
771 // Now loop around to the columns at the end of the matrix.
772 for(uword col = iterator_base::M->n_cols - 1; col >= iterator_base::internal_col; --col)
773 {
774 // Find the first element with row greater than or equal to in_row + 1.
775 const uword col_offset = iterator_base::M->col_ptrs[col ];
776 const uword next_col_offset = iterator_base::M->col_ptrs[col + 1];
777
778 const uword* start_ptr = &iterator_base::M->row_indices[ col_offset];
779 const uword* end_ptr = &iterator_base::M->row_indices[next_col_offset];
780
781 if(start_ptr != end_ptr)
782 {
783 // There are elements in this column.
784 const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row);
785
786 if(pos_ptr != start_ptr)
787 {
788 // There are elements in this column with row index < internal_row.
789 if(*(pos_ptr - 1) > max_row)
790 {
791 max_row = *(pos_ptr - 1);
792 max_col = col;
793 next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr);
794 }
795 else if(*(pos_ptr - 1) == max_row && col > max_col)
796 {
797 max_col = col;
798 next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr);
799 }
800 }
801 }
802
803 if(col == 0) // Catch edge case that the loop termination condition won't.
804 {
805 break;
806 }
807 }
808
809 iterator_base::internal_col = max_col;
810 internal_row = max_row;
811 actual_pos = next_actual_pos;
812
813 return *this;
814 }
815
816
817
818 /**
819 * Decrement the row_iterator.
820 */
821 template<typename eT>
822 inline
823 arma_warn_unused
824 typename SpMat<eT>::const_row_iterator
operator --(int)825 SpMat<eT>::const_row_iterator::operator--(int)
826 {
827 typename SpMat<eT>::const_row_iterator tmp(*this);
828
829 --(*this);
830
831 return tmp;
832 }
833
834
835
836 template<typename eT>
837 inline
838 arma_hot
839 bool
operator ==(const const_iterator & rhs) const840 SpMat<eT>::const_row_iterator::operator==(const const_iterator& rhs) const
841 {
842 return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col);
843 }
844
845
846
847 template<typename eT>
848 inline
849 arma_hot
850 bool
operator !=(const const_iterator & rhs) const851 SpMat<eT>::const_row_iterator::operator!=(const const_iterator& rhs) const
852 {
853 return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col);
854 }
855
856
857
858 template<typename eT>
859 inline
860 arma_hot
861 bool
operator ==(const typename SpSubview<eT>::const_iterator & rhs) const862 SpMat<eT>::const_row_iterator::operator==(const typename SpSubview<eT>::const_iterator& rhs) const
863 {
864 return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col);
865 }
866
867
868
869 template<typename eT>
870 inline
871 arma_hot
872 bool
operator !=(const typename SpSubview<eT>::const_iterator & rhs) const873 SpMat<eT>::const_row_iterator::operator!=(const typename SpSubview<eT>::const_iterator& rhs) const
874 {
875 return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col);
876 }
877
878
879
880 template<typename eT>
881 inline
882 arma_hot
883 bool
operator ==(const const_row_iterator & rhs) const884 SpMat<eT>::const_row_iterator::operator==(const const_row_iterator& rhs) const
885 {
886 return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col);
887 }
888
889
890
891 template<typename eT>
892 inline
893 arma_hot
894 bool
operator !=(const const_row_iterator & rhs) const895 SpMat<eT>::const_row_iterator::operator!=(const const_row_iterator& rhs) const
896 {
897 return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col);
898 }
899
900
901
902 template<typename eT>
903 inline
904 arma_hot
905 bool
operator ==(const typename SpSubview<eT>::const_row_iterator & rhs) const906 SpMat<eT>::const_row_iterator::operator==(const typename SpSubview<eT>::const_row_iterator& rhs) const
907 {
908 return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col);
909 }
910
911
912
913 template<typename eT>
914 inline
915 arma_hot
916 bool
operator !=(const typename SpSubview<eT>::const_row_iterator & rhs) const917 SpMat<eT>::const_row_iterator::operator!=(const typename SpSubview<eT>::const_row_iterator& rhs) const
918 {
919 return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col);
920 }
921
922
923
924 ///////////////////////////////////////////////////////////////////////////////
925 // SpMat::row_iterator implementation //
926 ///////////////////////////////////////////////////////////////////////////////
927
928 template<typename eT>
929 inline
930 arma_hot
931 SpValProxy< SpMat<eT> >
operator *()932 SpMat<eT>::row_iterator::operator*()
933 {
934 return SpValProxy< SpMat<eT> >(
935 const_row_iterator::internal_row,
936 iterator_base::internal_col,
937 access::rw(*iterator_base::M),
938 &access::rw(iterator_base::M->values[const_row_iterator::actual_pos]));
939 }
940
941
942
943 template<typename eT>
944 inline
945 arma_hot
946 typename SpMat<eT>::row_iterator&
operator ++()947 SpMat<eT>::row_iterator::operator++()
948 {
949 const_row_iterator::operator++();
950
951 return *this;
952 }
953
954
955
956 template<typename eT>
957 inline
958 arma_warn_unused
959 typename SpMat<eT>::row_iterator
operator ++(int)960 SpMat<eT>::row_iterator::operator++(int)
961 {
962 typename SpMat<eT>::row_iterator tmp(*this);
963
964 const_row_iterator::operator++();
965
966 return tmp;
967 }
968
969
970
971 template<typename eT>
972 inline
973 arma_hot
974 typename SpMat<eT>::row_iterator&
operator --()975 SpMat<eT>::row_iterator::operator--()
976 {
977 const_row_iterator::operator--();
978
979 return *this;
980 }
981
982
983
984 template<typename eT>
985 inline
986 arma_warn_unused
987 typename SpMat<eT>::row_iterator
operator --(int)988 SpMat<eT>::row_iterator::operator--(int)
989 {
990 typename SpMat<eT>::row_iterator tmp(*this);
991
992 const_row_iterator::operator--();
993
994 return tmp;
995 }
996
997
998 //! @}
999