1155 lines
31 KiB
C++
1155 lines
31 KiB
C++
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
// Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au)
|
|
// Copyright 2008-2016 National ICT Australia (NICTA)
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
// ------------------------------------------------------------------------
|
|
|
|
|
|
//! \addtogroup SpSubview
|
|
//! @{
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// SpSubview::iterator_base implementation //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::iterator_base::iterator_base(const SpSubview<eT>& in_M)
|
|
: M(&in_M)
|
|
, internal_col(0)
|
|
, internal_pos(0)
|
|
{
|
|
// Technically this iterator is invalid (it may not point to a valid element)
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::iterator_base::iterator_base(const SpSubview<eT>& in_M, const uword in_col, const uword in_pos)
|
|
: M(&in_M)
|
|
, internal_col(in_col)
|
|
, internal_pos(in_pos)
|
|
{
|
|
// Nothing to do.
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// SpSubview::const_iterator implementation //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::const_iterator::const_iterator(const SpSubview<eT>& in_M, const uword initial_pos)
|
|
: iterator_base(in_M, 0, initial_pos)
|
|
{
|
|
// Corner case for empty subviews.
|
|
if(in_M.n_nonzero == 0)
|
|
{
|
|
iterator_base::internal_col = in_M.n_cols;
|
|
skip_pos = in_M.m.n_nonzero;
|
|
return;
|
|
}
|
|
|
|
// Figure out the row and column of the position.
|
|
// lskip_pos holds the number of values which aren't part of this subview.
|
|
const uword aux_col = iterator_base::M->aux_col1;
|
|
const uword aux_row = iterator_base::M->aux_row1;
|
|
const uword ln_rows = iterator_base::M->n_rows;
|
|
const uword ln_cols = iterator_base::M->n_cols;
|
|
|
|
uword cur_pos = 0; // off by one because we might be searching for pos 0
|
|
uword lskip_pos = iterator_base::M->m.col_ptrs[aux_col];
|
|
uword cur_col = 0;
|
|
|
|
while(cur_pos < (iterator_base::internal_pos + 1))
|
|
{
|
|
// Have we stepped forward a column (or multiple columns)?
|
|
while(((lskip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols))
|
|
{
|
|
++cur_col;
|
|
}
|
|
|
|
// See if the current position is in the subview.
|
|
const uword row_index = iterator_base::M->m.row_indices[cur_pos + lskip_pos];
|
|
if(row_index < aux_row)
|
|
{
|
|
++lskip_pos; // not valid
|
|
}
|
|
else if(row_index < (aux_row + ln_rows))
|
|
{
|
|
++cur_pos; // valid, in the subview
|
|
}
|
|
else
|
|
{
|
|
// skip to end of column
|
|
const uword next_colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col + 1];
|
|
lskip_pos += (next_colptr - (cur_pos + lskip_pos));
|
|
}
|
|
}
|
|
|
|
iterator_base::internal_col = cur_col;
|
|
skip_pos = lskip_pos;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::const_iterator::const_iterator(const SpSubview<eT>& in_M, const uword in_row, const uword in_col)
|
|
: iterator_base(in_M, in_col, 0)
|
|
{
|
|
// Corner case for empty subviews.
|
|
if(in_M.n_nonzero == 0)
|
|
{
|
|
// We must be at the last position.
|
|
iterator_base::internal_col = in_M.n_cols;
|
|
skip_pos = in_M.m.n_nonzero;
|
|
return;
|
|
}
|
|
|
|
// We have a destination we want to be just after, but don't know what position that is.
|
|
// Because we have to count the points in this subview and not in this subview, this becomes a little difficult and slow.
|
|
const uword aux_col = iterator_base::M->aux_col1;
|
|
const uword aux_row = iterator_base::M->aux_row1;
|
|
const uword ln_rows = iterator_base::M->n_rows;
|
|
const uword ln_cols = iterator_base::M->n_cols;
|
|
|
|
uword cur_pos = 0;
|
|
skip_pos = iterator_base::M->m.col_ptrs[aux_col];
|
|
uword cur_col = 0;
|
|
|
|
// Skip any empty columns.
|
|
while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols))
|
|
{
|
|
++cur_col;
|
|
}
|
|
|
|
while(cur_col < in_col)
|
|
{
|
|
// See if the current position is in the subview.
|
|
const uword row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos];
|
|
if(row_index < aux_row)
|
|
{
|
|
++skip_pos;
|
|
}
|
|
else if(row_index < (aux_row + ln_rows))
|
|
{
|
|
++cur_pos;
|
|
}
|
|
else
|
|
{
|
|
// skip to end of column
|
|
const uword next_colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col + 1];
|
|
skip_pos += (next_colptr - (cur_pos + skip_pos));
|
|
}
|
|
|
|
// Have we stepped forward a column (or multiple columns)?
|
|
while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols))
|
|
{
|
|
++cur_col;
|
|
}
|
|
}
|
|
|
|
// Now we are either on the right column or ahead of it.
|
|
if(cur_col == in_col)
|
|
{
|
|
// We have to find the right row index.
|
|
uword row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos];
|
|
while((row_index < (in_row + aux_row)))
|
|
{
|
|
if(row_index < aux_row)
|
|
{
|
|
++skip_pos;
|
|
}
|
|
else
|
|
{
|
|
++cur_pos;
|
|
}
|
|
|
|
// Ensure we didn't step forward a column; if we did, we need to stop.
|
|
while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols))
|
|
{
|
|
++cur_col;
|
|
}
|
|
|
|
if(cur_col != in_col)
|
|
{
|
|
break;
|
|
}
|
|
|
|
row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos];
|
|
}
|
|
}
|
|
|
|
// Now we need to find the next valid position in the subview.
|
|
uword row_index;
|
|
while(true)
|
|
{
|
|
const uword next_colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col + 1];
|
|
row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos];
|
|
|
|
// Are we at the last position?
|
|
if(cur_col >= ln_cols)
|
|
{
|
|
cur_col = ln_cols;
|
|
// Make sure we will be pointing at the last element in the parent matrix.
|
|
skip_pos = iterator_base::M->m.n_nonzero - iterator_base::M->n_nonzero;
|
|
break;
|
|
}
|
|
|
|
if(row_index < aux_row)
|
|
{
|
|
++skip_pos;
|
|
}
|
|
else if(row_index < (aux_row + ln_rows))
|
|
{
|
|
break; // found
|
|
}
|
|
else
|
|
{
|
|
skip_pos += (next_colptr - (cur_pos + skip_pos));
|
|
}
|
|
|
|
// Did we move any columns?
|
|
while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols))
|
|
{
|
|
++cur_col;
|
|
}
|
|
}
|
|
|
|
// It is possible we have moved another column.
|
|
while(((skip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]) && (cur_col < ln_cols))
|
|
{
|
|
++cur_col;
|
|
}
|
|
|
|
iterator_base::internal_pos = cur_pos;
|
|
iterator_base::internal_col = cur_col;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::const_iterator::const_iterator(const SpSubview<eT>& in_M, uword in_row, uword in_col, uword in_pos, uword in_skip_pos)
|
|
: iterator_base(in_M, in_col, in_pos)
|
|
, skip_pos(in_skip_pos)
|
|
{
|
|
arma_ignore(in_row);
|
|
|
|
// Nothing to do.
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::const_iterator::const_iterator(const const_iterator& other)
|
|
: iterator_base(*other.M, other.internal_col, other.internal_pos)
|
|
, skip_pos(other.skip_pos)
|
|
{
|
|
// Nothing to do.
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
arma_inline
|
|
eT
|
|
SpSubview<eT>::const_iterator::operator*() const
|
|
{
|
|
return iterator_base::M->m.values[iterator_base::internal_pos + skip_pos];
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::const_iterator&
|
|
SpSubview<eT>::const_iterator::operator++()
|
|
{
|
|
const uword aux_col = iterator_base::M->aux_col1;
|
|
const uword aux_row = iterator_base::M->aux_row1;
|
|
const uword ln_rows = iterator_base::M->n_rows;
|
|
const uword ln_cols = iterator_base::M->n_cols;
|
|
|
|
uword cur_col = iterator_base::internal_col;
|
|
uword cur_pos = iterator_base::internal_pos + 1;
|
|
uword lskip_pos = skip_pos;
|
|
uword row_index;
|
|
|
|
while(true)
|
|
{
|
|
const uword next_colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col + 1];
|
|
row_index = iterator_base::M->m.row_indices[cur_pos + lskip_pos];
|
|
|
|
// Did we move any columns?
|
|
while((cur_col < ln_cols) && ((lskip_pos + cur_pos) >= iterator_base::M->m.col_ptrs[cur_col + aux_col + 1]))
|
|
{
|
|
++cur_col;
|
|
}
|
|
|
|
// Are we at the last position?
|
|
if(cur_col >= ln_cols)
|
|
{
|
|
cur_col = ln_cols;
|
|
// Make sure we will be pointing at the last element in the parent matrix.
|
|
lskip_pos = iterator_base::M->m.n_nonzero - iterator_base::M->n_nonzero;
|
|
break;
|
|
}
|
|
|
|
if(row_index < aux_row)
|
|
{
|
|
++lskip_pos;
|
|
}
|
|
else if(row_index < (aux_row + ln_rows))
|
|
{
|
|
break; // found
|
|
}
|
|
else
|
|
{
|
|
lskip_pos += (next_colptr - (cur_pos + lskip_pos));
|
|
}
|
|
}
|
|
|
|
iterator_base::internal_pos = cur_pos;
|
|
iterator_base::internal_col = cur_col;
|
|
skip_pos = lskip_pos;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::const_iterator
|
|
SpSubview<eT>::const_iterator::operator++(int)
|
|
{
|
|
typename SpSubview<eT>::const_iterator tmp(*this);
|
|
|
|
++(*this);
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::const_iterator&
|
|
SpSubview<eT>::const_iterator::operator--()
|
|
{
|
|
const uword aux_col = iterator_base::M->aux_col1;
|
|
const uword aux_row = iterator_base::M->aux_row1;
|
|
const uword ln_rows = iterator_base::M->n_rows;
|
|
|
|
uword cur_col = iterator_base::internal_col;
|
|
uword cur_pos = iterator_base::internal_pos - 1;
|
|
|
|
// Special condition for end of iterator.
|
|
if((skip_pos + cur_pos + 1) == iterator_base::M->m.n_nonzero)
|
|
{
|
|
// We are at the last element. So we need to set skip_pos back to what it
|
|
// would be if we didn't manually modify it back in operator++().
|
|
skip_pos = iterator_base::M->m.col_ptrs[cur_col + aux_col] - iterator_base::internal_pos;
|
|
}
|
|
|
|
uword row_index;
|
|
|
|
while(true)
|
|
{
|
|
const uword colptr = iterator_base::M->m.col_ptrs[cur_col + aux_col];
|
|
row_index = iterator_base::M->m.row_indices[cur_pos + skip_pos];
|
|
|
|
// Did we move back any columns?
|
|
while((skip_pos + cur_pos) < iterator_base::M->m.col_ptrs[cur_col + aux_col])
|
|
{
|
|
--cur_col;
|
|
}
|
|
|
|
if(row_index < aux_row)
|
|
{
|
|
skip_pos -= (colptr - (cur_pos + skip_pos) + 1);
|
|
}
|
|
else if(row_index < (aux_row + ln_rows))
|
|
{
|
|
break; // found
|
|
}
|
|
else
|
|
{
|
|
--skip_pos;
|
|
}
|
|
}
|
|
|
|
iterator_base::internal_pos = cur_pos;
|
|
iterator_base::internal_col = cur_col;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::const_iterator
|
|
SpSubview<eT>::const_iterator::operator--(int)
|
|
{
|
|
typename SpSubview<eT>::const_iterator tmp(*this);
|
|
|
|
--(*this);
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_iterator::operator==(const const_iterator& rhs) const
|
|
{
|
|
return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_iterator::operator!=(const const_iterator& rhs) const
|
|
{
|
|
return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_iterator::operator==(const typename SpMat<eT>::const_iterator& rhs) const
|
|
{
|
|
return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_iterator::operator!=(const typename SpMat<eT>::const_iterator& rhs) const
|
|
{
|
|
return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_iterator::operator==(const const_row_iterator& rhs) const
|
|
{
|
|
return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_iterator::operator!=(const const_row_iterator& rhs) const
|
|
{
|
|
return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_iterator::operator==(const typename SpMat<eT>::const_row_iterator& rhs) const
|
|
{
|
|
return (rhs.row() == (*this).row()) && (rhs.col() == iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_iterator::operator!=(const typename SpMat<eT>::const_row_iterator& rhs) const
|
|
{
|
|
return (rhs.row() != (*this).row()) || (rhs.col() != iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// SpSubview<eT>::iterator implementation //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpValProxy< SpSubview<eT> >
|
|
SpSubview<eT>::iterator::operator*()
|
|
{
|
|
return SpValProxy< SpSubview<eT> >(
|
|
const_iterator::row(),
|
|
iterator_base::col(),
|
|
access::rw(*iterator_base::M),
|
|
&(access::rw(iterator_base::M->m.values[iterator_base::internal_pos + const_iterator::skip_pos])));
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::iterator&
|
|
SpSubview<eT>::iterator::operator++()
|
|
{
|
|
const_iterator::operator++();
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::iterator
|
|
SpSubview<eT>::iterator::operator++(int)
|
|
{
|
|
typename SpSubview<eT>::iterator tmp(*this);
|
|
|
|
const_iterator::operator++();
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::iterator&
|
|
SpSubview<eT>::iterator::operator--()
|
|
{
|
|
const_iterator::operator--();
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::iterator
|
|
SpSubview<eT>::iterator::operator--(int)
|
|
{
|
|
typename SpSubview<eT>::iterator tmp(*this);
|
|
|
|
const_iterator::operator--();
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// SpSubview<eT>::const_row_iterator implementation //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::const_row_iterator::const_row_iterator()
|
|
: iterator_base()
|
|
, internal_row(0)
|
|
, actual_pos(0)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::const_row_iterator::const_row_iterator(const SpSubview<eT>& in_M, uword initial_pos)
|
|
: iterator_base(in_M, 0, initial_pos)
|
|
, internal_row(0)
|
|
, actual_pos(0)
|
|
{
|
|
// Corner case for the end of a subview.
|
|
if(initial_pos == in_M.n_nonzero)
|
|
{
|
|
iterator_base::internal_col = 0;
|
|
internal_row = in_M.n_rows;
|
|
return;
|
|
}
|
|
|
|
const uword aux_col = iterator_base::M->aux_col1;
|
|
const uword aux_row = iterator_base::M->aux_row1;
|
|
|
|
// We don't count zeros in our position count, so we have to find the nonzero
|
|
// value corresponding to the given initial position, and we also have to skip
|
|
// any nonzero elements that aren't a part of the subview.
|
|
|
|
uword cur_pos = std::numeric_limits<uword>::max();
|
|
uword cur_actual_pos = 0;
|
|
|
|
// Since we don't know where the elements are in each row, we have to loop
|
|
// across all columns looking for elements in row 0 and add to our sum, then
|
|
// in row 1, and so forth, until we get to the desired position.
|
|
for(uword row = 0; row < iterator_base::M->n_rows; ++row)
|
|
{
|
|
for(uword col = 0; col < iterator_base::M->n_cols; ++col)
|
|
{
|
|
// Find the first element with row greater than or equal to row + aux_row.
|
|
const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ];
|
|
const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1];
|
|
|
|
const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset];
|
|
const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset];
|
|
|
|
if(start_ptr != end_ptr)
|
|
{
|
|
const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, row + aux_row);
|
|
|
|
const uword offset = uword(pos_ptr - start_ptr);
|
|
|
|
if(iterator_base::M->m.row_indices[col_offset + offset] == row + aux_row)
|
|
{
|
|
cur_actual_pos = col_offset + offset;
|
|
|
|
// Increment position portably.
|
|
if(cur_pos == std::numeric_limits<uword>::max())
|
|
cur_pos = 0;
|
|
else
|
|
++cur_pos;
|
|
|
|
// Do we terminate?
|
|
if(cur_pos == initial_pos)
|
|
{
|
|
internal_row = row;
|
|
iterator_base::internal_col = col;
|
|
iterator_base::internal_pos = cur_pos;
|
|
actual_pos = cur_actual_pos;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This shouldn't happen.
|
|
iterator_base::internal_pos = iterator_base::M->n_nonzero;
|
|
iterator_base::internal_col = 0;
|
|
internal_row = iterator_base::M->n_rows;
|
|
actual_pos = iterator_base::M->n_nonzero;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::const_row_iterator::const_row_iterator(const SpSubview<eT>& in_M, uword in_row, uword in_col)
|
|
: iterator_base(in_M, in_col, 0)
|
|
, internal_row(0)
|
|
, actual_pos(0)
|
|
{
|
|
// Start our search in the given row. We need to find two things:
|
|
//
|
|
// 1. The first nonzero element (iterating by rows) after (in_row, in_col).
|
|
// 2. The number of nonzero elements (iterating by rows) that come before
|
|
// (in_row, in_col).
|
|
//
|
|
// We'll find these simultaneously, though we will have to loop over all
|
|
// columns.
|
|
|
|
const uword aux_col = iterator_base::M->aux_col1;
|
|
const uword aux_row = iterator_base::M->aux_row1;
|
|
|
|
// This will hold the total number of points in the subview with rows less
|
|
// than in_row.
|
|
uword cur_pos = 0;
|
|
uword cur_min_row = iterator_base::M->n_rows;
|
|
uword cur_min_col = 0;
|
|
uword cur_actual_pos = 0;
|
|
|
|
for(uword col = 0; col < iterator_base::M->n_cols; ++col)
|
|
{
|
|
// Find the first element with row greater than or equal to in_row.
|
|
const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ];
|
|
const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1];
|
|
|
|
const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset];
|
|
const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset];
|
|
|
|
if(start_ptr != end_ptr)
|
|
{
|
|
// First let us find the first element that is in the subview.
|
|
const uword* first_subview_ptr = std::lower_bound(start_ptr, end_ptr, aux_row);
|
|
|
|
if(first_subview_ptr != end_ptr && (*first_subview_ptr) < aux_row + iterator_base::M->n_rows)
|
|
{
|
|
// There exists at least one element in the subview.
|
|
const uword* pos_ptr = std::lower_bound(first_subview_ptr, end_ptr, aux_row + in_row);
|
|
|
|
// This is the number of elements in the subview with row index less
|
|
// than in_row.
|
|
cur_pos += uword(pos_ptr - first_subview_ptr);
|
|
|
|
if(pos_ptr != end_ptr && (*pos_ptr) < aux_row + iterator_base::M->n_rows)
|
|
{
|
|
// This is the row index of the first element in the column with row
|
|
// index greater than or equal to in_row + aux_row.
|
|
if((*pos_ptr) - aux_row < cur_min_row)
|
|
{
|
|
// If we are in the desired row but before the desired column, we
|
|
// can't take this.
|
|
if(col >= in_col)
|
|
{
|
|
cur_min_row = (*pos_ptr) - aux_row;
|
|
cur_min_col = col;
|
|
cur_actual_pos = col_offset + (pos_ptr - start_ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now we know what the minimum row is.
|
|
internal_row = cur_min_row;
|
|
iterator_base::internal_col = cur_min_col;
|
|
iterator_base::internal_pos = cur_pos;
|
|
actual_pos = cur_actual_pos;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpSubview<eT>::const_row_iterator::const_row_iterator(const const_row_iterator& other)
|
|
: iterator_base(*other.M, other.internal_col, other.internal_pos)
|
|
, internal_row(other.internal_row)
|
|
, actual_pos(other.actual_pos)
|
|
{
|
|
// Nothing to do.
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::const_row_iterator&
|
|
SpSubview<eT>::const_row_iterator::operator++()
|
|
{
|
|
// We just need to find the next nonzero element.
|
|
++iterator_base::internal_pos;
|
|
|
|
// If we have exceeded the bounds, update accordingly.
|
|
if(iterator_base::internal_pos >= iterator_base::M->n_nonzero)
|
|
{
|
|
internal_row = iterator_base::M->n_rows;
|
|
iterator_base::internal_col = 0;
|
|
actual_pos = iterator_base::M->n_nonzero;
|
|
|
|
return *this;
|
|
}
|
|
|
|
const uword aux_col = iterator_base::M->aux_col1;
|
|
const uword aux_row = iterator_base::M->aux_row1;
|
|
const uword M_n_cols = iterator_base::M->n_cols;
|
|
|
|
// Otherwise, we need to search. We have to loop over all of the columns in
|
|
// the subview.
|
|
uword next_min_row = iterator_base::M->n_rows;
|
|
uword next_min_col = 0;
|
|
uword next_actual_pos = 0;
|
|
|
|
for(uword col = iterator_base::internal_col + 1; col < M_n_cols; ++col)
|
|
{
|
|
// Find the first element with row greater than or equal to row.
|
|
const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ];
|
|
const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1];
|
|
|
|
const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset];
|
|
const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset];
|
|
|
|
if(start_ptr != end_ptr)
|
|
{
|
|
// Find the first element in the column with row greater than or equal to
|
|
// the current row. Since this is a subview, it's possible that we may
|
|
// find rows past the end of the subview.
|
|
const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + aux_row);
|
|
|
|
if(pos_ptr != end_ptr)
|
|
{
|
|
// We found something; is the row index correct?
|
|
if((*pos_ptr) == internal_row + aux_row && (*pos_ptr) < aux_row + iterator_base::M->n_rows)
|
|
{
|
|
// Exact match---so we are done.
|
|
iterator_base::internal_col = col;
|
|
actual_pos = col_offset + (pos_ptr - start_ptr);
|
|
return *this;
|
|
}
|
|
else if((*pos_ptr) < next_min_row + aux_row && (*pos_ptr) < aux_row + iterator_base::M->n_rows)
|
|
{
|
|
// The first element in this column is in a subsequent row, but it's
|
|
// the minimum row we've seen so far.
|
|
next_min_row = (*pos_ptr) - aux_row;
|
|
next_min_col = col;
|
|
next_actual_pos = col_offset + (pos_ptr - start_ptr);
|
|
}
|
|
else if((*pos_ptr) == next_min_row + aux_row && col < next_min_col && (*pos_ptr) < aux_row + iterator_base::M->n_rows)
|
|
{
|
|
// The first element in this column is in a subsequent row that we
|
|
// already have another element for, but the column index is less so
|
|
// this element will come first.
|
|
next_min_col = col;
|
|
next_actual_pos = col_offset + (pos_ptr - start_ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Restart the search in the next row.
|
|
for(uword col = 0; col <= iterator_base::internal_col; ++col)
|
|
{
|
|
// Find the first element with row greater than or equal to row + 1.
|
|
const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ];
|
|
const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1];
|
|
|
|
const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset];
|
|
const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset];
|
|
|
|
if(start_ptr != end_ptr)
|
|
{
|
|
const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + aux_row + 1);
|
|
|
|
if(pos_ptr != end_ptr)
|
|
{
|
|
// We found something in the column, but is the row index correct?
|
|
if((*pos_ptr) == internal_row + aux_row + 1 && (*pos_ptr) < aux_row + iterator_base::M->n_rows)
|
|
{
|
|
// Exact match---so we are done.
|
|
iterator_base::internal_col = col;
|
|
internal_row++;
|
|
actual_pos = col_offset + (pos_ptr - start_ptr);
|
|
return *this;
|
|
}
|
|
else if((*pos_ptr) < next_min_row + aux_row && (*pos_ptr) < aux_row + iterator_base::M->n_rows)
|
|
{
|
|
// The first element in this column is in a subsequent row, but it's
|
|
// the minimum row we've seen so far.
|
|
next_min_row = (*pos_ptr) - aux_row;
|
|
next_min_col = col;
|
|
next_actual_pos = col_offset + (pos_ptr - start_ptr);
|
|
}
|
|
else if((*pos_ptr) == next_min_row + aux_row && col < next_min_col && (*pos_ptr) < aux_row + iterator_base::M->n_rows)
|
|
{
|
|
// We've found a better column.
|
|
next_min_col = col;
|
|
next_actual_pos = col_offset + (pos_ptr - start_ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
iterator_base::internal_col = next_min_col;
|
|
internal_row = next_min_row;
|
|
actual_pos = next_actual_pos;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::const_row_iterator
|
|
SpSubview<eT>::const_row_iterator::operator++(int)
|
|
{
|
|
typename SpSubview<eT>::const_row_iterator tmp(*this);
|
|
|
|
++(*this);
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::const_row_iterator&
|
|
SpSubview<eT>::const_row_iterator::operator--()
|
|
{
|
|
if(iterator_base::internal_pos == 0)
|
|
{
|
|
// We are already at the beginning.
|
|
return *this;
|
|
}
|
|
|
|
iterator_base::internal_pos--;
|
|
|
|
const uword aux_col = iterator_base::M->aux_col1;
|
|
const uword aux_row = iterator_base::M->aux_row1;
|
|
|
|
// We have to search backwards.
|
|
uword max_row = 0;
|
|
uword max_col = 0;
|
|
uword next_actual_pos = 0;
|
|
|
|
for(uword col = iterator_base::internal_col; col >= 1; --col)
|
|
{
|
|
// Find the first element with row greater than or equal to in_row + 1.
|
|
const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col - 1];
|
|
const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col ];
|
|
|
|
const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset];
|
|
const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset];
|
|
|
|
if(start_ptr != end_ptr)
|
|
{
|
|
// There are elements in this column.
|
|
const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + aux_row + 1);
|
|
|
|
if(pos_ptr != start_ptr)
|
|
{
|
|
if(*(pos_ptr - 1) > max_row + aux_row)
|
|
{
|
|
// There are elements in this column with row index < internal_row.
|
|
max_row = *(pos_ptr - 1) - aux_row;
|
|
max_col = col - 1;
|
|
next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr);
|
|
}
|
|
else if(*(pos_ptr - 1) == max_row + aux_row && (col - 1) >= max_col)
|
|
{
|
|
max_col = col - 1;
|
|
next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(uword col = iterator_base::M->n_cols - 1; col >= iterator_base::internal_col; --col)
|
|
{
|
|
// Find the first element with row greater than or equal to row + 1.
|
|
const uword col_offset = iterator_base::M->m.col_ptrs[col + aux_col ];
|
|
const uword next_col_offset = iterator_base::M->m.col_ptrs[col + aux_col + 1];
|
|
|
|
const uword* start_ptr = &iterator_base::M->m.row_indices[ col_offset];
|
|
const uword* end_ptr = &iterator_base::M->m.row_indices[next_col_offset];
|
|
|
|
if(start_ptr != end_ptr)
|
|
{
|
|
// There are elements in this column.
|
|
const uword* pos_ptr = std::lower_bound(start_ptr, end_ptr, internal_row + aux_row);
|
|
|
|
if(pos_ptr != start_ptr)
|
|
{
|
|
// There are elements in this column with row index < internal_row.
|
|
if(*(pos_ptr - 1) > max_row + aux_row)
|
|
{
|
|
max_row = *(pos_ptr - 1) - aux_row;
|
|
max_col = col;
|
|
next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr);
|
|
}
|
|
else if(*(pos_ptr - 1) == max_row + aux_row && col >= max_col)
|
|
{
|
|
max_col = col;
|
|
next_actual_pos = col_offset + (pos_ptr - 1 - start_ptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(col == 0) // Catch edge case that the loop termination condition won't.
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
iterator_base::internal_col = max_col;
|
|
internal_row = max_row;
|
|
actual_pos = next_actual_pos;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::const_row_iterator
|
|
SpSubview<eT>::const_row_iterator::operator--(int)
|
|
{
|
|
typename SpSubview<eT>::const_row_iterator tmp(*this);
|
|
|
|
--(*this);
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_row_iterator::operator==(const const_iterator& rhs) const
|
|
{
|
|
return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_row_iterator::operator!=(const const_iterator& rhs) const
|
|
{
|
|
return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_row_iterator::operator==(const typename SpMat<eT>::const_iterator& rhs) const
|
|
{
|
|
return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_row_iterator::operator!=(const typename SpMat<eT>::const_iterator& rhs) const
|
|
{
|
|
return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_row_iterator::operator==(const const_row_iterator& rhs) const
|
|
{
|
|
return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_row_iterator::operator!=(const const_row_iterator& rhs) const
|
|
{
|
|
return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_row_iterator::operator==(const typename SpMat<eT>::const_row_iterator& rhs) const
|
|
{
|
|
return (rhs.row() == row()) && (rhs.col() == iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
bool
|
|
SpSubview<eT>::const_row_iterator::operator!=(const typename SpMat<eT>::const_row_iterator& rhs) const
|
|
{
|
|
return (rhs.row() != row()) || (rhs.col() != iterator_base::internal_col);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// SpSubview<eT>::row_iterator implementation //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename eT>
|
|
inline
|
|
SpValProxy< SpSubview<eT> >
|
|
SpSubview<eT>::row_iterator::operator*()
|
|
{
|
|
return SpValProxy< SpSubview<eT> >(
|
|
const_row_iterator::internal_row,
|
|
iterator_base::internal_col,
|
|
access::rw(*iterator_base::M),
|
|
&access::rw(iterator_base::M->m.values[const_row_iterator::actual_pos]));
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::row_iterator&
|
|
SpSubview<eT>::row_iterator::operator++()
|
|
{
|
|
const_row_iterator::operator++();
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::row_iterator
|
|
SpSubview<eT>::row_iterator::operator++(int)
|
|
{
|
|
typename SpSubview<eT>::row_iterator tmp(*this);
|
|
|
|
++(*this);
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::row_iterator&
|
|
SpSubview<eT>::row_iterator::operator--()
|
|
{
|
|
const_row_iterator::operator--();
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
template<typename eT>
|
|
inline
|
|
typename SpSubview<eT>::row_iterator
|
|
SpSubview<eT>::row_iterator::operator--(int)
|
|
{
|
|
typename SpSubview<eT>::row_iterator tmp(*this);
|
|
|
|
--(*this);
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
//! @}
|