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