// 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 //! @{ template inline SpSubview::~SpSubview() { arma_extra_debug_sigprint_this(this); } template inline SpSubview::SpSubview(const SpMat& in_m, const uword in_row1, const uword in_col1, const uword in_n_rows, const uword in_n_cols) : m(in_m) , aux_row1(in_row1) , aux_col1(in_col1) , n_rows(in_n_rows) , n_cols(in_n_cols) , n_elem(in_n_rows * in_n_cols) , n_nonzero(0) { arma_extra_debug_sigprint_this(this); m.sync_csc(); // There must be a O(1) way to do this uword lend = m.col_ptrs[in_col1 + in_n_cols]; uword lend_row = in_row1 + in_n_rows; uword count = 0; for(uword i = m.col_ptrs[in_col1]; i < lend; ++i) { const uword m_row_indices_i = m.row_indices[i]; const bool condition = (m_row_indices_i >= in_row1) && (m_row_indices_i < lend_row); count += condition ? uword(1) : uword(0); } access::rw(n_nonzero) = count; } template inline SpSubview::SpSubview(const SpSubview& in) : m (in.m ) , aux_row1 (in.aux_row1 ) , aux_col1 (in.aux_col1 ) , n_rows (in.n_rows ) , n_cols (in.n_cols ) , n_elem (in.n_elem ) , n_nonzero(in.n_nonzero) { arma_extra_debug_sigprint(arma_str::format("this = %x in = %x") % this % &in); } template inline SpSubview::SpSubview(SpSubview&& in) : m (in.m ) , aux_row1 (in.aux_row1 ) , aux_col1 (in.aux_col1 ) , n_rows (in.n_rows ) , n_cols (in.n_cols ) , n_elem (in.n_elem ) , n_nonzero(in.n_nonzero) { arma_extra_debug_sigprint(arma_str::format("this = %x in = %x") % this % &in); // for paranoia access::rw(in.aux_row1 ) = 0; access::rw(in.aux_col1 ) = 0; access::rw(in.n_rows ) = 0; access::rw(in.n_cols ) = 0; access::rw(in.n_elem ) = 0; access::rw(in.n_nonzero) = 0; } template inline const SpSubview& SpSubview::operator+=(const eT val) { arma_extra_debug_sigprint(); if(val == eT(0)) { return *this; } Mat tmp( (*this).n_rows, (*this).n_cols, arma_nozeros_indicator() ); tmp.fill(val); return (*this).operator=( (*this) + tmp ); } template inline const SpSubview& SpSubview::operator-=(const eT val) { arma_extra_debug_sigprint(); if(val == eT(0)) { return *this; } Mat tmp( (*this).n_rows, (*this).n_cols, arma_nozeros_indicator() ); tmp.fill(val); return (*this).operator=( (*this) - tmp ); } template inline const SpSubview& SpSubview::operator*=(const eT val) { arma_extra_debug_sigprint(); if(val == eT(0)) { (*this).zeros(); return *this; } if((n_elem == 0) || (n_nonzero == 0)) { return *this; } m.sync_csc(); m.invalidate_cache(); const uword lstart_row = aux_row1; const uword lend_row = aux_row1 + n_rows; const uword lstart_col = aux_col1; const uword lend_col = aux_col1 + n_cols; const uword* m_row_indices = m.row_indices; eT* m_values = access::rwp(m.values); bool has_zero = false; for(uword c = lstart_col; c < lend_col; ++c) { const uword r_start = m.col_ptrs[c ]; const uword r_end = m.col_ptrs[c + 1]; for(uword r = r_start; r < r_end; ++r) { const uword m_row_indices_r = m_row_indices[r]; if( (m_row_indices_r >= lstart_row) && (m_row_indices_r < lend_row) ) { eT& m_values_r = m_values[r]; m_values_r *= val; if(m_values_r == eT(0)) { has_zero = true; } } } } if(has_zero) { const uword old_m_n_nonzero = m.n_nonzero; access::rw(m).remove_zeros(); if(m.n_nonzero != old_m_n_nonzero) { access::rw(n_nonzero) = n_nonzero - (old_m_n_nonzero - m.n_nonzero); } } return *this; } template inline const SpSubview& SpSubview::operator/=(const eT val) { arma_extra_debug_sigprint(); arma_debug_check( (val == eT(0)), "element-wise division: division by zero" ); m.sync_csc(); m.invalidate_cache(); const uword lstart_row = aux_row1; const uword lend_row = aux_row1 + n_rows; const uword lstart_col = aux_col1; const uword lend_col = aux_col1 + n_cols; const uword* m_row_indices = m.row_indices; eT* m_values = access::rwp(m.values); bool has_zero = false; for(uword c = lstart_col; c < lend_col; ++c) { const uword r_start = m.col_ptrs[c ]; const uword r_end = m.col_ptrs[c + 1]; for(uword r = r_start; r < r_end; ++r) { const uword m_row_indices_r = m_row_indices[r]; if( (m_row_indices_r >= lstart_row) && (m_row_indices_r < lend_row) ) { eT& m_values_r = m_values[r]; m_values_r /= val; if(m_values_r == eT(0)) { has_zero = true; } } } } if(has_zero) { const uword old_m_n_nonzero = m.n_nonzero; access::rw(m).remove_zeros(); if(m.n_nonzero != old_m_n_nonzero) { access::rw(n_nonzero) = n_nonzero - (old_m_n_nonzero - m.n_nonzero); } } return *this; } template template inline const SpSubview& SpSubview::operator=(const Base& in) { arma_extra_debug_sigprint(); if(is_same_type< T1, Gen, gen_zeros> >::yes) { const Proxy P(in.get_ref()); arma_debug_assert_same_size(n_rows, n_cols, P.get_n_rows(), P.get_n_cols(), "insertion into sparse submatrix"); (*this).zeros(); return *this; } if(is_same_type< T1, Gen, gen_eye> >::yes) { const Proxy P(in.get_ref()); arma_debug_assert_same_size(n_rows, n_cols, P.get_n_rows(), P.get_n_cols(), "insertion into sparse submatrix"); (*this).eye(); return *this; } const quasi_unwrap U(in.get_ref()); arma_debug_assert_same_size(n_rows, n_cols, U.M.n_rows, U.M.n_cols, "insertion into sparse submatrix"); spglue_merge::subview_merge(*this, U.M); return *this; } template template inline const SpSubview& SpSubview::operator+=(const Base& x) { arma_extra_debug_sigprint(); return (*this).operator=( (*this) + x.get_ref() ); } template template inline const SpSubview& SpSubview::operator-=(const Base& x) { arma_extra_debug_sigprint(); return (*this).operator=( (*this) - x.get_ref() ); } template template inline const SpSubview& SpSubview::operator*=(const Base& x) { arma_extra_debug_sigprint(); SpMat tmp(*this); tmp *= x.get_ref(); return (*this).operator=(tmp); } template template inline const SpSubview& SpSubview::operator%=(const Base& x) { arma_extra_debug_sigprint(); SpSubview& sv = (*this); const quasi_unwrap U(x.get_ref()); const Mat& B = U.M; arma_debug_assert_same_size(sv.n_rows, sv.n_cols, B.n_rows, B.n_cols, "element-wise multiplication"); SpMat& sv_m = access::rw(sv.m); sv_m.sync_csc(); sv_m.invalidate_cache(); const uword m_row_start = sv.aux_row1; const uword m_row_end = sv.aux_row1 + sv.n_rows - 1; const uword m_col_start = sv.aux_col1; const uword m_col_end = sv.aux_col1 + sv.n_cols - 1; constexpr eT zero = eT(0); bool has_zero = false; uword count = 0; for(uword m_col = m_col_start; m_col <= m_col_end; ++m_col) { const uword sv_col = m_col - m_col_start; const uword index_start = sv_m.col_ptrs[m_col ]; const uword index_end = sv_m.col_ptrs[m_col + 1]; for(uword i=index_start; i < index_end; ++i) { const uword m_row = sv_m.row_indices[i]; if(m_row < m_row_start) { continue; } if(m_row > m_row_end ) { break; } const uword sv_row = m_row - m_row_start; eT& m_val = access::rw(sv_m.values[i]); const eT result = m_val * B.at(sv_row, sv_col); m_val = result; if(result == zero) { has_zero = true; } else { ++count; } } } if(has_zero) { sv_m.remove_zeros(); } access::rw(sv.n_nonzero) = count; return (*this); } template template inline const SpSubview& SpSubview::operator/=(const Base& x) { arma_extra_debug_sigprint(); const SpSubview& A = (*this); const quasi_unwrap U(x.get_ref()); const Mat& B = U.M; arma_debug_assert_same_size(A.n_rows, A.n_cols, B.n_rows, B.n_cols, "element-wise division"); bool result_ok = true; constexpr eT zero = eT(0); const uword B_n_rows = B.n_rows; const uword B_n_cols = B.n_cols; for(uword c=0; c < B_n_cols; ++c) { for(uword r=0; r < B_n_rows; ++r) { // a zero in B and A at the same location implies the division result is NaN; // hence a zero in A (not stored) needs to be changed into a non-zero // for efficiency, an element in B is checked before checking the corresponding element in A if((B.at(r,c) == zero) && (A.at(r,c) == zero)) { result_ok = false; break; } } if(result_ok == false) { break; } } if(result_ok) { const_iterator cit = A.begin(); const_iterator cit_end = A.end(); while(cit != cit_end) { const eT tmp = (*cit) / B.at(cit.row(), cit.col()); if(tmp == zero) { result_ok = false; break; } ++cit; } } if(result_ok) { iterator it = (*this).begin(); iterator it_end = (*this).end(); while(it != it_end) { (*it) /= B.at(it.row(), it.col()); ++it; } } else { (*this).operator=( (*this) / B ); } return (*this); } template inline const SpSubview& SpSubview::operator=(const SpSubview& x) { arma_extra_debug_sigprint(); return (*this).operator_equ_common(x); } template template inline const SpSubview& SpSubview::operator=(const SpBase& x) { arma_extra_debug_sigprint(); return (*this).operator_equ_common( x.get_ref() ); } template template inline const SpSubview& SpSubview::operator_equ_common(const SpBase& in) { arma_extra_debug_sigprint(); const unwrap_spmat U(in.get_ref()); arma_debug_assert_same_size(n_rows, n_cols, U.M.n_rows, U.M.n_cols, "insertion into sparse submatrix"); if(U.is_alias(m)) { const SpMat tmp(U.M); spglue_merge::subview_merge(*this, tmp); } else { spglue_merge::subview_merge(*this, U.M); } return *this; } template template inline const SpSubview& SpSubview::operator+=(const SpBase& x) { arma_extra_debug_sigprint(); // TODO: implement dedicated machinery return (*this).operator=( (*this) + x.get_ref() ); } template template inline const SpSubview& SpSubview::operator-=(const SpBase& x) { arma_extra_debug_sigprint(); // TODO: implement dedicated machinery return (*this).operator=( (*this) - x.get_ref() ); } template template inline const SpSubview& SpSubview::operator*=(const SpBase& x) { arma_extra_debug_sigprint(); return (*this).operator=( (*this) * x.get_ref() ); } template template inline const SpSubview& SpSubview::operator%=(const SpBase& x) { arma_extra_debug_sigprint(); // TODO: implement dedicated machinery return (*this).operator=( (*this) % x.get_ref() ); } template template inline const SpSubview& SpSubview::operator/=(const SpBase& x) { arma_extra_debug_sigprint(); // NOTE: use of this function is not advised; it is implemented only for completeness SpProxy p(x.get_ref()); arma_debug_assert_same_size(n_rows, n_cols, p.get_n_rows(), p.get_n_cols(), "element-wise division"); if(p.is_alias(m) == false) { for(uword lcol = 0; lcol < n_cols; ++lcol) for(uword lrow = 0; lrow < n_rows; ++lrow) { at(lrow,lcol) /= p.at(lrow,lcol); } } else { const SpMat tmp(p.Q); (*this).operator/=(tmp); } return *this; } //! apply a functor to each element template template inline void SpSubview::for_each(functor F) { arma_extra_debug_sigprint(); m.sync_csc(); m.invalidate_cache(); const uword lstart_row = aux_row1; const uword lend_row = aux_row1 + n_rows; const uword lstart_col = aux_col1; const uword lend_col = aux_col1 + n_cols; const uword* m_row_indices = m.row_indices; eT* m_values = access::rwp(m.values); bool has_zero = false; for(uword c = lstart_col; c < lend_col; ++c) { const uword r_start = m.col_ptrs[c ]; const uword r_end = m.col_ptrs[c + 1]; for(uword r = r_start; r < r_end; ++r) { const uword m_row_indices_r = m_row_indices[r]; if( (m_row_indices_r >= lstart_row) && (m_row_indices_r < lend_row) ) { eT& m_values_r = m_values[r]; F(m_values_r); if(m_values_r == eT(0)) { has_zero = true; } } } } if(has_zero) { const uword old_m_n_nonzero = m.n_nonzero; access::rw(m).remove_zeros(); if(m.n_nonzero != old_m_n_nonzero) { access::rw(n_nonzero) = n_nonzero - (old_m_n_nonzero - m.n_nonzero); } } } template template inline void SpSubview::for_each(functor F) const { arma_extra_debug_sigprint(); m.sync_csc(); const uword lstart_row = aux_row1; const uword lend_row = aux_row1 + n_rows; const uword lstart_col = aux_col1; const uword lend_col = aux_col1 + n_cols; const uword* m_row_indices = m.row_indices; for(uword c = lstart_col; c < lend_col; ++c) { const uword r_start = m.col_ptrs[c ]; const uword r_end = m.col_ptrs[c + 1]; for(uword r = r_start; r < r_end; ++r) { const uword m_row_indices_r = m_row_indices[r]; if( (m_row_indices_r >= lstart_row) && (m_row_indices_r < lend_row) ) { F(m.values[r]); } } } } //! transform each element using a functor template template inline void SpSubview::transform(functor F) { arma_extra_debug_sigprint(); m.sync_csc(); m.invalidate_cache(); const uword lstart_row = aux_row1; const uword lend_row = aux_row1 + n_rows; const uword lstart_col = aux_col1; const uword lend_col = aux_col1 + n_cols; const uword* m_row_indices = m.row_indices; eT* m_values = access::rwp(m.values); bool has_zero = false; for(uword c = lstart_col; c < lend_col; ++c) { const uword r_start = m.col_ptrs[c ]; const uword r_end = m.col_ptrs[c + 1]; for(uword r = r_start; r < r_end; ++r) { const uword m_row_indices_r = m_row_indices[r]; if( (m_row_indices_r >= lstart_row) && (m_row_indices_r < lend_row) ) { eT& m_values_r = m_values[r]; m_values_r = eT( F(m_values_r) ); if(m_values_r == eT(0)) { has_zero = true; } } } } if(has_zero) { const uword old_m_n_nonzero = m.n_nonzero; access::rw(m).remove_zeros(); if(m.n_nonzero != old_m_n_nonzero) { access::rw(n_nonzero) = n_nonzero - (old_m_n_nonzero - m.n_nonzero); } } } template inline void SpSubview::replace(const eT old_val, const eT new_val) { arma_extra_debug_sigprint(); if(old_val == eT(0)) { if(new_val != eT(0)) { Mat tmp(*this); tmp.replace(old_val, new_val); (*this).operator=(tmp); } return; } m.sync_csc(); m.invalidate_cache(); const uword lstart_row = aux_row1; const uword lend_row = aux_row1 + n_rows; const uword lstart_col = aux_col1; const uword lend_col = aux_col1 + n_cols; const uword* m_row_indices = m.row_indices; eT* m_values = access::rwp(m.values); if(arma_isnan(old_val)) { for(uword c = lstart_col; c < lend_col; ++c) { const uword r_start = m.col_ptrs[c ]; const uword r_end = m.col_ptrs[c + 1]; for(uword r = r_start; r < r_end; ++r) { const uword m_row_indices_r = m_row_indices[r]; if( (m_row_indices_r >= lstart_row) && (m_row_indices_r < lend_row) ) { eT& val = m_values[r]; val = (arma_isnan(val)) ? new_val : val; } } } } else { for(uword c = lstart_col; c < lend_col; ++c) { const uword r_start = m.col_ptrs[c ]; const uword r_end = m.col_ptrs[c + 1]; for(uword r = r_start; r < r_end; ++r) { const uword m_row_indices_r = m_row_indices[r]; if( (m_row_indices_r >= lstart_row) && (m_row_indices_r < lend_row) ) { eT& val = m_values[r]; val = (val == old_val) ? new_val : val; } } } } if(new_val == eT(0)) { access::rw(m).remove_zeros(); } } template inline void SpSubview::clean(const typename get_pod_type::result threshold) { arma_extra_debug_sigprint(); if((n_elem == 0) || (n_nonzero == 0)) { return; } // TODO: replace with a more efficient implementation SpMat tmp(*this); tmp.clean(threshold); if(is_cx::yes) { (*this).operator=(tmp); } else if(tmp.n_nonzero != n_nonzero) { (*this).operator=(tmp); } } template inline void SpSubview::clamp(const eT min_val, const eT max_val) { arma_extra_debug_sigprint(); if(is_cx::no) { arma_debug_check( (access::tmp_real(min_val) > access::tmp_real(max_val)), "SpSubview::clamp(): min_val must be less than max_val" ); } else { arma_debug_check( (access::tmp_real(min_val) > access::tmp_real(max_val)), "SpSubview::clamp(): real(min_val) must be less than real(max_val)" ); arma_debug_check( (access::tmp_imag(min_val) > access::tmp_imag(max_val)), "SpSubview::clamp(): imag(min_val) must be less than imag(max_val)" ); } if((n_elem == 0) || (n_nonzero == 0)) { return; } // TODO: replace with a more efficient implementation SpMat tmp(*this); tmp.clamp(min_val, max_val); (*this).operator=(tmp); } template inline void SpSubview::fill(const eT val) { arma_extra_debug_sigprint(); if(val != eT(0)) { Mat tmp( (*this).n_rows, (*this).n_cols, arma_nozeros_indicator() ); tmp.fill(val); (*this).operator=(tmp); } else { (*this).zeros(); } } template inline void SpSubview::zeros() { arma_extra_debug_sigprint(); if((n_elem == 0) || (n_nonzero == 0)) { return; } if((m.n_nonzero - n_nonzero) == 0) { access::rw(m).zeros(); access::rw(n_nonzero) = 0; return; } SpMat tmp(arma_reserve_indicator(), m.n_rows, m.n_cols, m.n_nonzero - n_nonzero); const uword sv_row_start = aux_row1; const uword sv_col_start = aux_col1; const uword sv_row_end = aux_row1 + n_rows - 1; const uword sv_col_end = aux_col1 + n_cols - 1; typename SpMat::const_iterator m_it = m.begin(); typename SpMat::const_iterator m_it_end = m.end(); uword tmp_count = 0; for(; m_it != m_it_end; ++m_it) { const uword m_it_row = m_it.row(); const uword m_it_col = m_it.col(); const bool inside_box = ((m_it_row >= sv_row_start) && (m_it_row <= sv_row_end)) && ((m_it_col >= sv_col_start) && (m_it_col <= sv_col_end)); if(inside_box == false) { access::rw(tmp.values[tmp_count]) = (*m_it); access::rw(tmp.row_indices[tmp_count]) = m_it_row; access::rw(tmp.col_ptrs[m_it_col + 1])++; ++tmp_count; } } for(uword i=0; i < tmp.n_cols; ++i) { access::rw(tmp.col_ptrs[i + 1]) += tmp.col_ptrs[i]; } access::rw(m).steal_mem(tmp); access::rw(n_nonzero) = 0; } template inline void SpSubview::ones() { arma_extra_debug_sigprint(); (*this).fill(eT(1)); } template inline void SpSubview::eye() { arma_extra_debug_sigprint(); SpMat tmp; tmp.eye( (*this).n_rows, (*this).n_cols ); (*this).operator=(tmp); } template inline void SpSubview::randu() { arma_extra_debug_sigprint(); Mat tmp( (*this).n_rows, (*this).n_cols, fill::randu ); (*this).operator=(tmp); } template inline void SpSubview::randn() { arma_extra_debug_sigprint(); Mat tmp( (*this).n_rows, (*this).n_cols, fill::randn ); (*this).operator=(tmp); } template inline SpSubview_MapMat_val SpSubview::operator[](const uword i) { const uword lrow = i % n_rows; const uword lcol = i / n_rows; return (*this).at(lrow, lcol); } template inline eT SpSubview::operator[](const uword i) const { const uword lrow = i % n_rows; const uword lcol = i / n_rows; return (*this).at(lrow, lcol); } template inline SpSubview_MapMat_val SpSubview::operator()(const uword i) { arma_debug_check_bounds( (i >= n_elem), "SpSubview::operator(): index out of bounds" ); const uword lrow = i % n_rows; const uword lcol = i / n_rows; return (*this).at(lrow, lcol); } template inline eT SpSubview::operator()(const uword i) const { arma_debug_check_bounds( (i >= n_elem), "SpSubview::operator(): index out of bounds" ); const uword lrow = i % n_rows; const uword lcol = i / n_rows; return (*this).at(lrow, lcol); } template inline SpSubview_MapMat_val SpSubview::operator()(const uword in_row, const uword in_col) { arma_debug_check_bounds( (in_row >= n_rows) || (in_col >= n_cols), "SpSubview::operator(): index out of bounds" ); return (*this).at(in_row, in_col); } template inline eT SpSubview::operator()(const uword in_row, const uword in_col) const { arma_debug_check_bounds( (in_row >= n_rows) || (in_col >= n_cols), "SpSubview::operator(): index out of bounds" ); return (*this).at(in_row, in_col); } template inline SpSubview_MapMat_val SpSubview::at(const uword i) { const uword lrow = i % n_rows; const uword lcol = i / n_cols; return (*this).at(lrow, lcol); } template inline eT SpSubview::at(const uword i) const { const uword lrow = i % n_rows; const uword lcol = i / n_cols; return (*this).at(lrow, lcol); } template inline SpSubview_MapMat_val SpSubview::at(const uword in_row, const uword in_col) { return SpSubview_MapMat_val((*this), m.cache, aux_row1 + in_row, aux_col1 + in_col); } template inline eT SpSubview::at(const uword in_row, const uword in_col) const { return m.at(aux_row1 + in_row, aux_col1 + in_col); } template inline bool SpSubview::check_overlap(const SpSubview& x) const { const SpSubview& t = *this; if(&t.m != &x.m) { return false; } else { if( (t.n_elem == 0) || (x.n_elem == 0) ) { return false; } else { const uword t_row_start = t.aux_row1; const uword t_row_end_p1 = t_row_start + t.n_rows; const uword t_col_start = t.aux_col1; const uword t_col_end_p1 = t_col_start + t.n_cols; const uword x_row_start = x.aux_row1; const uword x_row_end_p1 = x_row_start + x.n_rows; const uword x_col_start = x.aux_col1; const uword x_col_end_p1 = x_col_start + x.n_cols; const bool outside_rows = ( (x_row_start >= t_row_end_p1) || (t_row_start >= x_row_end_p1) ); const bool outside_cols = ( (x_col_start >= t_col_end_p1) || (t_col_start >= x_col_end_p1) ); return ( (outside_rows == false) && (outside_cols == false) ); } } } template inline bool SpSubview::is_vec() const { return ( (n_rows == 1) || (n_cols == 1) ); } template inline SpSubview_row SpSubview::row(const uword row_num) { arma_extra_debug_sigprint(); arma_debug_check_bounds(row_num >= n_rows, "SpSubview::row(): out of bounds"); return SpSubview_row(const_cast< SpMat& >(m), row_num + aux_row1, aux_col1, n_cols); } template inline const SpSubview_row SpSubview::row(const uword row_num) const { arma_extra_debug_sigprint(); arma_debug_check_bounds(row_num >= n_rows, "SpSubview::row(): out of bounds"); return SpSubview_row(m, row_num + aux_row1, aux_col1, n_cols); } template inline SpSubview_col SpSubview::col(const uword col_num) { arma_extra_debug_sigprint(); arma_debug_check_bounds(col_num >= n_cols, "SpSubview::col(): out of bounds"); return SpSubview_col(const_cast< SpMat& >(m), col_num + aux_col1, aux_row1, n_rows); } template inline const SpSubview_col SpSubview::col(const uword col_num) const { arma_extra_debug_sigprint(); arma_debug_check_bounds(col_num >= n_cols, "SpSubview::col(): out of bounds"); return SpSubview_col(m, col_num + aux_col1, aux_row1, n_rows); } template inline SpSubview SpSubview::rows(const uword in_row1, const uword in_row2) { arma_extra_debug_sigprint(); arma_debug_check_bounds ( (in_row1 > in_row2) || (in_row2 >= n_rows), "SpSubview::rows(): indices out of bounds or incorrectly used" ); return submat(in_row1, 0, in_row2, n_cols - 1); } template inline const SpSubview SpSubview::rows(const uword in_row1, const uword in_row2) const { arma_extra_debug_sigprint(); arma_debug_check_bounds ( (in_row1 > in_row2) || (in_row2 >= n_rows), "SpSubview::rows(): indices out of bounds or incorrectly used" ); return submat(in_row1, 0, in_row2, n_cols - 1); } template inline SpSubview SpSubview::cols(const uword in_col1, const uword in_col2) { arma_extra_debug_sigprint(); arma_debug_check_bounds ( (in_col1 > in_col2) || (in_col2 >= n_cols), "SpSubview::cols(): indices out of bounds or incorrectly used" ); return submat(0, in_col1, n_rows - 1, in_col2); } template inline const SpSubview SpSubview::cols(const uword in_col1, const uword in_col2) const { arma_extra_debug_sigprint(); arma_debug_check_bounds ( (in_col1 > in_col2) || (in_col2 >= n_cols), "SpSubview::cols(): indices out of bounds or incorrectly used" ); return submat(0, in_col1, n_rows - 1, in_col2); } template inline SpSubview SpSubview::submat(const uword in_row1, const uword in_col1, const uword in_row2, const uword in_col2) { arma_extra_debug_sigprint(); arma_debug_check_bounds ( (in_row1 > in_row2) || (in_col1 > in_col2) || (in_row2 >= n_rows) || (in_col2 >= n_cols), "SpSubview::submat(): indices out of bounds or incorrectly used" ); return access::rw(m).submat(in_row1 + aux_row1, in_col1 + aux_col1, in_row2 + aux_row1, in_col2 + aux_col1); } template inline const SpSubview SpSubview::submat(const uword in_row1, const uword in_col1, const uword in_row2, const uword in_col2) const { arma_extra_debug_sigprint(); arma_debug_check_bounds ( (in_row1 > in_row2) || (in_col1 > in_col2) || (in_row2 >= n_rows) || (in_col2 >= n_cols), "SpSubview::submat(): indices out of bounds or incorrectly used" ); return m.submat(in_row1 + aux_row1, in_col1 + aux_col1, in_row2 + aux_row1, in_col2 + aux_col1); } template inline SpSubview SpSubview::submat(const span& row_span, const span& col_span) { arma_extra_debug_sigprint(); const bool row_all = row_span.whole; const bool col_all = row_span.whole; const uword in_row1 = row_all ? 0 : row_span.a; const uword in_row2 = row_all ? n_rows : row_span.b; const uword in_col1 = col_all ? 0 : col_span.a; const uword in_col2 = col_all ? n_cols : col_span.b; arma_debug_check_bounds ( ( row_all ? false : ((in_row1 > in_row2) || (in_row2 >= n_rows))) || ( col_all ? false : ((in_col1 > in_col2) || (in_col2 >= n_cols))), "SpSubview::submat(): indices out of bounds or incorrectly used" ); return submat(in_row1, in_col1, in_row2, in_col2); } template inline const SpSubview SpSubview::submat(const span& row_span, const span& col_span) const { arma_extra_debug_sigprint(); const bool row_all = row_span.whole; const bool col_all = row_span.whole; const uword in_row1 = row_all ? 0 : row_span.a; const uword in_row2 = row_all ? n_rows - 1 : row_span.b; const uword in_col1 = col_all ? 0 : col_span.a; const uword in_col2 = col_all ? n_cols - 1 : col_span.b; arma_debug_check_bounds ( ( row_all ? false : ((in_row1 > in_row2) || (in_row2 >= n_rows))) || ( col_all ? false : ((in_col1 > in_col2) || (in_col2 >= n_cols))), "SpSubview::submat(): indices out of bounds or incorrectly used" ); return submat(in_row1, in_col1, in_row2, in_col2); } template inline SpSubview SpSubview::operator()(const uword row_num, const span& col_span) { arma_extra_debug_sigprint(); return submat(span(row_num, row_num), col_span); } template inline const SpSubview SpSubview::operator()(const uword row_num, const span& col_span) const { arma_extra_debug_sigprint(); return submat(span(row_num, row_num), col_span); } template inline SpSubview SpSubview::operator()(const span& row_span, const uword col_num) { arma_extra_debug_sigprint(); return submat(row_span, span(col_num, col_num)); } template inline const SpSubview SpSubview::operator()(const span& row_span, const uword col_num) const { arma_extra_debug_sigprint(); return submat(row_span, span(col_num, col_num)); } template inline SpSubview SpSubview::operator()(const span& row_span, const span& col_span) { arma_extra_debug_sigprint(); return submat(row_span, col_span); } template inline const SpSubview SpSubview::operator()(const span& row_span, const span& col_span) const { arma_extra_debug_sigprint(); return submat(row_span, col_span); } template inline void SpSubview::swap_rows(const uword in_row1, const uword in_row2) { arma_extra_debug_sigprint(); arma_debug_check((in_row1 >= n_rows) || (in_row2 >= n_rows), "SpSubview::swap_rows(): invalid row index"); const uword lstart_col = aux_col1; const uword lend_col = aux_col1 + n_cols; for(uword c = lstart_col; c < lend_col; ++c) { const eT val = access::rw(m).at(in_row1 + aux_row1, c); access::rw(m).at(in_row2 + aux_row1, c) = eT( access::rw(m).at(in_row1 + aux_row1, c) ); access::rw(m).at(in_row1 + aux_row1, c) = val; } } template inline void SpSubview::swap_cols(const uword in_col1, const uword in_col2) { arma_extra_debug_sigprint(); arma_debug_check((in_col1 >= n_cols) || (in_col2 >= n_cols), "SpSubview::swap_cols(): invalid column index"); const uword lstart_row = aux_row1; const uword lend_row = aux_row1 + n_rows; for(uword r = lstart_row; r < lend_row; ++r) { const eT val = access::rw(m).at(r, in_col1 + aux_col1); access::rw(m).at(r, in_col1 + aux_col1) = eT( access::rw(m).at(r, in_col2 + aux_col1) ); access::rw(m).at(r, in_col2 + aux_col1) = val; } } template inline typename SpSubview::iterator SpSubview::begin() { m.sync_csc(); return iterator(*this); } template inline typename SpSubview::const_iterator SpSubview::begin() const { m.sync_csc(); return const_iterator(*this); } template inline typename SpSubview::const_iterator SpSubview::cbegin() const { m.sync_csc(); return const_iterator(*this); } template inline typename SpSubview::iterator SpSubview::begin_col(const uword col_num) { m.sync_csc(); return iterator(*this, 0, col_num); } template inline typename SpSubview::const_iterator SpSubview::begin_col(const uword col_num) const { m.sync_csc(); return const_iterator(*this, 0, col_num); } template inline typename SpSubview::row_iterator SpSubview::begin_row(const uword row_num) { m.sync_csc(); return row_iterator(*this, row_num, 0); } template inline typename SpSubview::const_row_iterator SpSubview::begin_row(const uword row_num) const { m.sync_csc(); return const_row_iterator(*this, row_num, 0); } template inline typename SpSubview::iterator SpSubview::end() { m.sync_csc(); return iterator(*this, 0, n_cols, n_nonzero, m.n_nonzero - n_nonzero); } template inline typename SpSubview::const_iterator SpSubview::end() const { m.sync_csc(); return const_iterator(*this, 0, n_cols, n_nonzero, m.n_nonzero - n_nonzero); } template inline typename SpSubview::const_iterator SpSubview::cend() const { m.sync_csc(); return const_iterator(*this, 0, n_cols, n_nonzero, m.n_nonzero - n_nonzero); } template inline typename SpSubview::row_iterator SpSubview::end_row() { m.sync_csc(); return row_iterator(*this, n_nonzero); } template inline typename SpSubview::const_row_iterator SpSubview::end_row() const { m.sync_csc(); return const_row_iterator(*this, n_nonzero); } template inline typename SpSubview::row_iterator SpSubview::end_row(const uword row_num) { m.sync_csc(); return row_iterator(*this, row_num + 1, 0); } template inline typename SpSubview::const_row_iterator SpSubview::end_row(const uword row_num) const { m.sync_csc(); return const_row_iterator(*this, row_num + 1, 0); } template arma_inline bool SpSubview::is_alias(const SpMat& X) const { return m.is_alias(X); } template inline eT& SpSubview::insert_element(const uword in_row, const uword in_col, const eT in_val) { arma_extra_debug_sigprint(); // This may not actually insert an element. const uword old_n_nonzero = m.n_nonzero; eT& retval = access::rw(m).insert_element(in_row + aux_row1, in_col + aux_col1, in_val); // Update n_nonzero (if necessary). access::rw(n_nonzero) += (m.n_nonzero - old_n_nonzero); return retval; } template inline void SpSubview::delete_element(const uword in_row, const uword in_col) { arma_extra_debug_sigprint(); // This may not actually delete an element. const uword old_n_nonzero = m.n_nonzero; access::rw(m).delete_element(in_row + aux_row1, in_col + aux_col1); access::rw(n_nonzero) -= (old_n_nonzero - m.n_nonzero); } template inline void SpSubview::invalidate_cache() const { arma_extra_debug_sigprint(); m.invalidate_cache(); } // // // template inline SpSubview_col::SpSubview_col(const SpMat& in_m, const uword in_col) : SpSubview(in_m, 0, in_col, in_m.n_rows, 1) { arma_extra_debug_sigprint(); } template inline SpSubview_col::SpSubview_col(const SpMat& in_m, const uword in_col, const uword in_row1, const uword in_n_rows) : SpSubview(in_m, in_row1, in_col, in_n_rows, 1) { arma_extra_debug_sigprint(); } template inline void SpSubview_col::operator=(const SpSubview& x) { arma_extra_debug_sigprint(); SpSubview::operator=(x); } template inline void SpSubview_col::operator=(const SpSubview_col& x) { arma_extra_debug_sigprint(); SpSubview::operator=(x); // interprets 'SpSubview_col' as 'SpSubview' } template template inline void SpSubview_col::operator=(const SpBase& x) { arma_extra_debug_sigprint(); SpSubview::operator=(x); } template template inline void SpSubview_col::operator=(const Base& x) { arma_extra_debug_sigprint(); SpSubview::operator=(x); } template inline const SpOp,spop_htrans> SpSubview_col::t() const { return SpOp,spop_htrans>(*this); } template inline const SpOp,spop_htrans> SpSubview_col::ht() const { return SpOp,spop_htrans>(*this); } template inline const SpOp,spop_strans> SpSubview_col::st() const { return SpOp,spop_strans>(*this); } // // // template inline SpSubview_row::SpSubview_row(const SpMat& in_m, const uword in_row) : SpSubview(in_m, in_row, 0, 1, in_m.n_cols) { arma_extra_debug_sigprint(); } template inline SpSubview_row::SpSubview_row(const SpMat& in_m, const uword in_row, const uword in_col1, const uword in_n_cols) : SpSubview(in_m, in_row, in_col1, 1, in_n_cols) { arma_extra_debug_sigprint(); } template inline void SpSubview_row::operator=(const SpSubview& x) { arma_extra_debug_sigprint(); SpSubview::operator=(x); } template inline void SpSubview_row::operator=(const SpSubview_row& x) { arma_extra_debug_sigprint(); SpSubview::operator=(x); // interprets 'SpSubview_row' as 'SpSubview' } template template inline void SpSubview_row::operator=(const SpBase& x) { arma_extra_debug_sigprint(); SpSubview::operator=(x); } template template inline void SpSubview_row::operator=(const Base& x) { arma_extra_debug_sigprint(); SpSubview::operator=(x); } template inline const SpOp,spop_htrans> SpSubview_row::t() const { return SpOp,spop_htrans>(*this); } template inline const SpOp,spop_htrans> SpSubview_row::ht() const { return SpOp,spop_htrans>(*this); } template inline const SpOp,spop_strans> SpSubview_row::st() const { return SpOp,spop_strans>(*this); } //! @}