inline arma_warn_unused typename enable_if2 <(is_arma_sparse_type<T1>::value) && (is_arma_sparse_type<T2>::value) && (is_same_type<typename T1::elem_type, typename T2::elem_type>::value), typename T1::elem_type >::result dot ( const SpBase<typename T1::elem_type, T1>& x, const SpBase<typename T2::elem_type, T2>& y ) { arma_extra_debug_sigprint(); const SpProxy<T1> pa(x.get_ref()); const SpProxy<T2> pb(y.get_ref()); arma_debug_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "dot()"); typedef typename T1::elem_type eT; if((&(x.get_ref()) == &(y.get_ref())) && (SpProxy<T1>::must_use_iterator == false)) { // We can do it directly! return op_dot::direct_dot_arma(pa.get_n_nonzero(), pa.get_values(), pa.get_values()); } else { // Iterate over both objects and see when they are the same eT result = eT(0); typename SpProxy<T1>::const_iterator_type a_it = pa.begin(); typename SpProxy<T2>::const_iterator_type b_it = pb.begin(); while((a_it.pos() < pa.get_n_nonzero()) && (b_it.pos() < pb.get_n_nonzero())) { if(a_it == b_it) { result += (*a_it) * (*b_it); ++a_it; ++b_it; } else if((a_it.col() < b_it.col()) || ((a_it.col() == b_it.col()) && (a_it.row() < b_it.row()))) { // a_it is "behind" ++a_it; } else { // b_it is "behind" ++b_it; } } return result; } }
arma_hot inline uword n_unique ( const SpProxy<T1>& pa, const SpProxy<T2>& pb, const op_n_unique_type junk ) { arma_extra_debug_sigprint(); arma_ignore(junk); typename SpProxy<T1>::const_iterator_type x_it = pa.begin(); typename SpProxy<T1>::const_iterator_type x_it_end = pa.end(); typename SpProxy<T2>::const_iterator_type y_it = pb.begin(); typename SpProxy<T2>::const_iterator_type y_it_end = pb.end(); uword total_n_nonzero = 0; while( (x_it != x_it_end) || (y_it != y_it_end) ) { if(x_it == y_it) { if(op_n_unique_type::eval((*x_it), (*y_it)) != typename T1::elem_type(0)) { ++total_n_nonzero; } ++x_it; ++y_it; } else { if((x_it.col() < y_it.col()) || ((x_it.col() == y_it.col()) && (x_it.row() < y_it.row()))) // if y is closer to the end { if(op_n_unique_type::eval((*x_it), typename T1::elem_type(0)) != typename T1::elem_type(0)) { ++total_n_nonzero; } ++x_it; } else // x is closer to the end { if(op_n_unique_type::eval(typename T1::elem_type(0), (*y_it)) != typename T1::elem_type(0)) { ++total_n_nonzero; } ++y_it; } } } return total_n_nonzero; }
inline arma_warn_unused bool is_finite(const SpBase<typename T1::elem_type,T1>& X) { arma_extra_debug_sigprint(); const SpProxy<T1> P(X.get_ref()); if(is_SpMat<typename SpProxy<T1>::stored_type>::value) { const unwrap_spmat<typename SpProxy<T1>::stored_type> tmp(P.Q); return tmp.M.is_finite(); } else { typename SpProxy<T1>::const_iterator_type it = P.begin(); typename SpProxy<T1>::const_iterator_type it_end = P.end(); while(it != it_end) { if(arma_isfinite(*it) == false) { return false; } ++it; } } return true; }
inline void op_nonzeros::apply_noalias(Mat<typename T1::elem_type>& out, const SpBase<typename T1::elem_type,T1>& X) { arma_extra_debug_sigprint(); typedef typename T1::elem_type eT; const SpProxy<T1> P(X.get_ref()); const uword N = P.get_n_nonzero(); out.set_size(N,1); if(N > 0) { if(is_SpMat<typename SpProxy<T1>::stored_type>::value) { const unwrap_spmat<typename SpProxy<T1>::stored_type> U(P.Q); arrayops::copy(out.memptr(), U.M.values, N); } else { eT* out_mem = out.memptr(); typename SpProxy<T1>::const_iterator_type it = P.begin(); for(uword i=0; i<N; ++i) { out_mem[i] = (*it); ++it; } } } }
inline arma_warn_unused typename enable_if2 <(is_arma_type<T1>::value) && (is_arma_sparse_type<T2>::value) && (is_same_type<typename T1::elem_type, typename T2::elem_type>::value), typename T1::elem_type >::result dot ( const Base<typename T1::elem_type, T1>& x, const SpBase<typename T2::elem_type, T2>& y ) { arma_extra_debug_sigprint(); const Proxy<T1> pa(x.get_ref()); const SpProxy<T2> pb(y.get_ref()); arma_debug_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "dot()"); typedef typename T1::elem_type eT; eT result = eT(0); typename SpProxy<T2>::const_iterator_type it = pb.begin(); // prefer_at_accessor won't save us operations while(it.pos() < pb.get_n_nonzero()) { result += (*it) * pa.at(it.row(), it.col()); ++it; } return result; }
inline typename enable_if2 < (is_arma_type<T1>::value && is_arma_sparse_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value), Mat<typename T1::elem_type> >::result operator- ( const T1& x, const T2& y ) { arma_extra_debug_sigprint(); Mat<typename T1::elem_type> result(x); const SpProxy<T2> pb(y.get_ref()); arma_debug_assert_same_size( result.n_rows, result.n_cols, pb.get_n_rows(), pb.get_n_cols(), "subtraction" ); typename SpProxy<T2>::const_iterator_type it = pb.begin(); typename SpProxy<T2>::const_iterator_type it_end = pb.end(); while(it != it_end) { result.at(it.row(), it.col()) -= (*it); ++it; } return result; }
arma_warn_unused inline Col<uword> find(const SpBase<typename T1::elem_type,T1>& X, const uword k = 0) { arma_extra_debug_sigprint(); const SpProxy<T1> P(X.get_ref()); const uword n_rows = P.get_n_rows(); const uword n_nz = P.get_n_nonzero(); Mat<uword> tmp(n_nz,1); uword* tmp_mem = tmp.memptr(); typename SpProxy<T1>::const_iterator_type it = P.begin(); for(uword i=0; i<n_nz; ++i) { const uword index = it.row() + it.col()*n_rows; tmp_mem[i] = index; ++it; } Col<uword> out; const uword count = (k == 0) ? uword(n_nz) : uword( (std::min)(n_nz, k) ); out.steal_mem_col(tmp, count); return out; }
arma_hot inline typename T1::elem_type dot_helper(const SpProxy<T1>& pa, const SpProxy<T2>& pb) { typedef typename T1::elem_type eT; // Iterate over both objects and see when they are the same eT result = eT(0); typename SpProxy<T1>::const_iterator_type a_it = pa.begin(); typename SpProxy<T1>::const_iterator_type a_end = pa.end(); typename SpProxy<T2>::const_iterator_type b_it = pb.begin(); typename SpProxy<T2>::const_iterator_type b_end = pb.end(); while((a_it != a_end) && (b_it != b_end)) { if(a_it == b_it) { result += (*a_it) * (*b_it); ++a_it; ++b_it; } else if((a_it.col() < b_it.col()) || ((a_it.col() == b_it.col()) && (a_it.row() < b_it.row()))) { // a_it is "behind" ++a_it; } else { // b_it is "behind" ++b_it; } } return result; }
arma_hot inline void spop_htrans::apply(SpMat<typename T1::elem_type>& out, const SpOp<T1,spop_htrans>& in, const typename arma_cx_only<typename T1::elem_type>::result* junk) { arma_extra_debug_sigprint(); arma_ignore(junk); typedef typename T1::elem_type eT; typedef typename umat::elem_type ueT; const SpProxy<T1> p(in.m); const uword N = p.get_n_nonzero(); if(N == uword(0)) { out.set_size(p.get_n_cols(), p.get_n_rows()); return; } umat locs(2, N); Col<eT> vals(N); eT* vals_ptr = vals.memptr(); typename SpProxy<T1>::const_iterator_type it = p.begin(); for(uword count = 0; count < N; ++count) { ueT* locs_ptr = locs.colptr(count); locs_ptr[0] = it.col(); locs_ptr[1] = it.row(); vals_ptr[count] = std::conj(*it); ++it; } SpMat<eT> tmp(locs, vals, p.get_n_cols(), p.get_n_rows()); out.steal_mem(tmp); }
inline typename enable_if2 < (is_arma_type<T1>::value && is_arma_sparse_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value), Mat<typename T1::elem_type> >::result operator/ ( const Base<typename T1::elem_type, T1>& x, const SpBase<typename T2::elem_type, T2>& y ) { arma_extra_debug_sigprint(); const Proxy<T1> pa(x.get_ref()); const SpProxy<T2> pb(y.get_ref()); arma_debug_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "element-wise division"); Mat<typename T1::elem_type> result(pa.get_n_rows(), pa.get_n_cols()); result.fill(Datum<typename T1::elem_type>::inf); // Now divide each element typename SpProxy<T2>::const_iterator_type it = pb.begin(); while(it.pos() < pb.get_n_nonzero()) { if(Proxy<T1>::prefer_at_accessor == false) { const uword index = (it.col() * result.n_rows) + it.row(); result[index] = pa[index] / (*it); } else { result.at(it.row(), it.col()) = pa.at(it.row(), it.col()) / (*it); } ++it; } return result; }
inline void op_sp_plus::apply(Mat<typename T1::elem_type>& out, const SpToDOp<T1,op_sp_plus>& in) { arma_extra_debug_sigprint(); // Note that T1 will be a sparse type, so we use SpProxy. const SpProxy<T1> proxy(in.m); out.set_size(proxy.get_n_rows(), proxy.get_n_cols()); out.fill(in.aux); typename SpProxy<T1>::const_iterator_type it = proxy.begin(); typename SpProxy<T1>::const_iterator_type it_end = proxy.end(); for(; it != it_end; ++it) { out.at(it.row(), it.col()) += (*it); } }
arma_warn_unused inline Col<uword> find_nonfinite(const SpBase<typename T1::elem_type,T1>& X) { arma_extra_debug_sigprint(); const SpProxy<T1> P(X.get_ref()); const uword n_rows = P.get_n_rows(); const uword n_nz = P.get_n_nonzero(); Mat<uword> tmp(n_nz,1); uword* tmp_mem = tmp.memptr(); typename SpProxy<T1>::const_iterator_type it = P.begin(); uword count = 0; for(uword i=0; i<n_nz; ++i) { if(arma_isfinite(*it) == false) { const uword index = it.row() + it.col()*n_rows; tmp_mem[count] = index; ++count; } ++it; } Col<uword> out; if(count > 0) { out.steal_mem_col(tmp, count); } return out; }
inline void spop_diagmat::apply_noalias(SpMat<typename T1::elem_type>& out, const SpProxy<T1>& p) { arma_extra_debug_sigprint(); const uword n_rows = p.get_n_rows(); const uword n_cols = p.get_n_cols(); const bool p_is_vec = (n_rows == 1) || (n_cols == 1); if(p_is_vec) // generate a diagonal matrix out of a vector { const uword N = (n_rows == 1) ? n_cols : n_rows; out.zeros(N, N); if(p.get_n_nonzero() == 0) { return; } typename SpProxy<T1>::const_iterator_type it = p.begin(); typename SpProxy<T1>::const_iterator_type it_end = p.end(); if(n_cols == 1) { while(it != it_end) { const uword row = it.row(); out.at(row,row) = (*it); ++it; } } else if(n_rows == 1) { while(it != it_end) { const uword col = it.col(); out.at(col,col) = (*it); ++it; } } } else // generate a diagonal matrix out of a matrix { arma_debug_check( (n_rows != n_cols), "diagmat(): given matrix is not square" ); out.zeros(n_rows, n_rows); if(p.get_n_nonzero() == 0) { return; } typename SpProxy<T1>::const_iterator_type it = p.begin(); typename SpProxy<T1>::const_iterator_type it_end = p.end(); while(it != it_end) { const uword row = it.row(); const uword col = it.col(); if(row == col) { out.at(row,row) = (*it); } ++it; } } }
inline const SpSubview<eT>& SpSubview<eT>::operator_equ_common(const SpBase<eT, T1>& in) { arma_extra_debug_sigprint(); // algorithm: // instead of directly inserting values into the matrix underlying the subview, // create a new matrix by merging the underlying matrix with the input object, // and then replacing the underlying matrix with the created matrix. // // the merging process requires pretending that the input object // has the same size as the underlying matrix. // while iterating through the elements of the input object, // this requires adjusting the row and column locations of each element, // as well as providing fake zero elements. // in effect there is a proxy for a proxy. const SpProxy< SpMat<eT> > pa((*this).m ); const SpProxy< T1 > pb(in.get_ref()); arma_debug_assert_same_size(n_rows, n_cols, pb.get_n_rows(), pb.get_n_cols(), "insertion into sparse submatrix"); const uword pa_start_row = (*this).aux_row1; const uword pa_start_col = (*this).aux_col1; const uword pa_end_row = pa_start_row + (*this).n_rows - 1; const uword pa_end_col = pa_start_col + (*this).n_cols - 1; const uword pa_n_rows = pa.get_n_rows(); SpMat<eT> out(pa.get_n_rows(), pa.get_n_cols()); const uword alt_count = pa.get_n_nonzero() - (*this).n_nonzero + pb.get_n_nonzero(); // Resize memory to correct size. out.mem_resize(alt_count); typename SpProxy< SpMat<eT> >::const_iterator_type x_it = pa.begin(); typename SpProxy< SpMat<eT> >::const_iterator_type x_end = pa.end(); typename SpProxy<T1>::const_iterator_type y_it = pb.begin(); typename SpProxy<T1>::const_iterator_type y_end = pb.end(); bool x_it_ok = (x_it != x_end); bool y_it_ok = (y_it != y_end); uword x_it_row = (x_it_ok) ? x_it.row() : 0; uword x_it_col = (x_it_ok) ? x_it.col() : 0; uword y_it_row = (y_it_ok) ? y_it.row() + pa_start_row : 0; uword y_it_col = (y_it_ok) ? y_it.col() + pa_start_col : 0; uword cur_val = 0; while(x_it_ok || y_it_ok) { const bool x_inside_box = (x_it_row >= pa_start_row) && (x_it_row <= pa_end_row) && (x_it_col >= pa_start_col) && (x_it_col <= pa_end_col); const bool y_inside_box = (y_it_row >= pa_start_row) && (y_it_row <= pa_end_row) && (y_it_col >= pa_start_col) && (y_it_col <= pa_end_col); const eT x_val = x_inside_box ? eT(0) : ( x_it_ok ? (*x_it) : eT(0) ); const eT y_val = y_inside_box ? ( y_it_ok ? (*y_it) : eT(0) ) : eT(0); if( (x_it_row == y_it_row) && (x_it_col == y_it_col) ) { if( (x_val != eT(0)) || (y_val != eT(0)) ) { access::rw(out.values[cur_val]) = (x_val != eT(0)) ? x_val : y_val; access::rw(out.row_indices[cur_val]) = x_it_row; ++access::rw(out.col_ptrs[x_it_col + 1]); ++cur_val; } if(x_it_ok) { ++x_it; if(x_it == x_end) { x_it_ok = false; } } if(x_it_ok) { x_it_row = x_it.row(); x_it_col = x_it.col(); } else { x_it_row++; if(x_it_row >= pa_n_rows) { x_it_row = 0; x_it_col++; } } if(y_it_ok) { ++y_it; if(y_it == y_end) { y_it_ok = false; } } if(y_it_ok) { y_it_row = y_it.row() + pa_start_row; y_it_col = y_it.col() + pa_start_col; } else { y_it_row++; if(y_it_row >= pa_n_rows) { y_it_row = 0; y_it_col++; } } } else { if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end { if(x_val != eT(0)) { access::rw(out.values[cur_val]) = x_val; access::rw(out.row_indices[cur_val]) = x_it_row; ++access::rw(out.col_ptrs[x_it_col + 1]); ++cur_val; } if(x_it_ok) { ++x_it; if(x_it == x_end) { x_it_ok = false; } } if(x_it_ok) { x_it_row = x_it.row(); x_it_col = x_it.col(); } else { x_it_row++; if(x_it_row >= pa_n_rows) { x_it_row = 0; x_it_col++; } } } else { if(y_val != eT(0)) { access::rw(out.values[cur_val]) = y_val; access::rw(out.row_indices[cur_val]) = y_it_row; ++access::rw(out.col_ptrs[y_it_col + 1]); ++cur_val; } if(y_it_ok) { ++y_it; if(y_it == y_end) { y_it_ok = false; } } if(y_it_ok) { y_it_row = y_it.row() + pa_start_row; y_it_col = y_it.col() + pa_start_col; } else { y_it_row++; if(y_it_row >= pa_n_rows) { y_it_row = 0; y_it_col++; } } } } } const uword out_n_cols = out.n_cols; uword* col_ptrs = access::rwp(out.col_ptrs); // Fix column pointers to be cumulative. for(uword c = 1; c <= out_n_cols; ++c) { col_ptrs[c] += col_ptrs[c - 1]; } access::rw((*this).m).steal_mem(out); access::rw(n_nonzero) = pb.get_n_nonzero(); return *this; }
inline const SpSubview<eT>& SpSubview<eT>::operator=(const Base<eT, T1>& in) { arma_extra_debug_sigprint(); // this is a modified version of SpSubview::operator_equ_common(const SpBase) const SpProxy< SpMat<eT> > pa((*this).m); const unwrap<T1> b_tmp(in.get_ref()); const Mat<eT>& b = b_tmp.M; arma_debug_assert_same_size(n_rows, n_cols, b.n_rows, b.n_cols, "insertion into sparse submatrix"); const uword pa_start_row = (*this).aux_row1; const uword pa_start_col = (*this).aux_col1; const uword pa_end_row = pa_start_row + (*this).n_rows - 1; const uword pa_end_col = pa_start_col + (*this).n_cols - 1; const uword pa_n_rows = pa.get_n_rows(); const uword b_n_elem = b.n_elem; const eT* b_mem = b.memptr(); uword box_count = 0; for(uword i=0; i<b_n_elem; ++i) { box_count += (b_mem[i] != eT(0)) ? uword(1) : uword(0); } SpMat<eT> out(pa.get_n_rows(), pa.get_n_cols()); const uword alt_count = pa.get_n_nonzero() - (*this).n_nonzero + box_count; // Resize memory to correct size. out.mem_resize(alt_count); typename SpProxy< SpMat<eT> >::const_iterator_type x_it = pa.begin(); typename SpProxy< SpMat<eT> >::const_iterator_type x_end = pa.end(); uword b_row = 0; uword b_col = 0; bool x_it_ok = (x_it != x_end); bool y_it_ok = ( (b_row < b.n_rows) && (b_col < b.n_cols) ); uword x_it_row = (x_it_ok) ? x_it.row() : 0; uword x_it_col = (x_it_ok) ? x_it.col() : 0; uword y_it_row = (y_it_ok) ? b_row + pa_start_row : 0; uword y_it_col = (y_it_ok) ? b_col + pa_start_col : 0; uword cur_val = 0; while(x_it_ok || y_it_ok) { const bool x_inside_box = (x_it_row >= pa_start_row) && (x_it_row <= pa_end_row) && (x_it_col >= pa_start_col) && (x_it_col <= pa_end_col); const bool y_inside_box = (y_it_row >= pa_start_row) && (y_it_row <= pa_end_row) && (y_it_col >= pa_start_col) && (y_it_col <= pa_end_col); const eT x_val = x_inside_box ? eT(0) : ( x_it_ok ? (*x_it) : eT(0) ); const eT y_val = y_inside_box ? ( y_it_ok ? b.at(b_row,b_col) : eT(0) ) : eT(0); if( (x_it_row == y_it_row) && (x_it_col == y_it_col) ) { if( (x_val != eT(0)) || (y_val != eT(0)) ) { access::rw(out.values[cur_val]) = (x_val != eT(0)) ? x_val : y_val; access::rw(out.row_indices[cur_val]) = x_it_row; ++access::rw(out.col_ptrs[x_it_col + 1]); ++cur_val; } if(x_it_ok) { ++x_it; if(x_it == x_end) { x_it_ok = false; } } if(x_it_ok) { x_it_row = x_it.row(); x_it_col = x_it.col(); } else { x_it_row++; if(x_it_row >= pa_n_rows) { x_it_row = 0; x_it_col++; } } if(y_it_ok) { b_row++; if(b_row >= b.n_rows) { b_row = 0; b_col++; } if( (b_row > b.n_rows) || (b_col > b.n_cols) ) { y_it_ok = false; } } if(y_it_ok) { y_it_row = b_row + pa_start_row; y_it_col = b_col + pa_start_col; } else { y_it_row++; if(y_it_row >= pa_n_rows) { y_it_row = 0; y_it_col++; } } } else { if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end { if(x_val != eT(0)) { access::rw(out.values[cur_val]) = x_val; access::rw(out.row_indices[cur_val]) = x_it_row; ++access::rw(out.col_ptrs[x_it_col + 1]); ++cur_val; } if(x_it_ok) { ++x_it; if(x_it == x_end) { x_it_ok = false; } } if(x_it_ok) { x_it_row = x_it.row(); x_it_col = x_it.col(); } else { x_it_row++; if(x_it_row >= pa_n_rows) { x_it_row = 0; x_it_col++; } } } else { if(y_val != eT(0)) { access::rw(out.values[cur_val]) = y_val; access::rw(out.row_indices[cur_val]) = y_it_row; ++access::rw(out.col_ptrs[y_it_col + 1]); ++cur_val; } if(y_it_ok) { b_row++; if(b_row >= b.n_rows) { b_row = 0; b_col++; } if( (b_row > b.n_rows) || (b_col > b.n_cols) ) { y_it_ok = false; } } if(y_it_ok) { y_it_row = b_row + pa_start_row; y_it_col = b_col + pa_start_col; } else { y_it_row++; if(y_it_row >= pa_n_rows) { y_it_row = 0; y_it_col++; } } } } } const uword out_n_cols = out.n_cols; uword* col_ptrs = access::rwp(out.col_ptrs); // Fix column pointers to be cumulative. for(uword c = 1; c <= out_n_cols; ++c) { col_ptrs[c] += col_ptrs[c - 1]; } access::rw((*this).m).steal_mem(out); access::rw(n_nonzero) = box_count; return *this; }
arma_hot inline void spglue_minus::apply_noalias(SpMat<eT>& out, const SpProxy<T1>& pa, const SpProxy<T2>& pb) { arma_extra_debug_sigprint(); arma_debug_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "subtraction"); if(pa.get_n_nonzero() == 0) { out = pb.Q; out *= eT(-1); return; } if(pb.get_n_nonzero() == 0) { out = pa.Q; return; } const uword max_n_nonzero = spglue_elem_helper::max_n_nonzero_plus(pa, pb); // Resize memory to upper bound out.reserve(pa.get_n_rows(), pa.get_n_cols(), max_n_nonzero); // Now iterate across both matrices. typename SpProxy<T1>::const_iterator_type x_it = pa.begin(); typename SpProxy<T1>::const_iterator_type x_end = pa.end(); typename SpProxy<T2>::const_iterator_type y_it = pb.begin(); typename SpProxy<T2>::const_iterator_type y_end = pb.end(); uword count = 0; while( (x_it != x_end) || (y_it != y_end) ) { eT out_val; const uword x_it_row = x_it.row(); const uword x_it_col = x_it.col(); const uword y_it_row = y_it.row(); const uword y_it_col = y_it.col(); bool use_y_loc = false; if(x_it == y_it) { out_val = (*x_it) - (*y_it); ++x_it; ++y_it; } else { if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end { out_val = (*x_it); ++x_it; } else { out_val = -(*y_it); // take the negative ++y_it; use_y_loc = true; } } if(out_val != eT(0)) { access::rw(out.values[count]) = out_val; const uword out_row = (use_y_loc == false) ? x_it_row : y_it_row; const uword out_col = (use_y_loc == false) ? x_it_col : y_it_col; access::rw(out.row_indices[count]) = out_row; access::rw(out.col_ptrs[out_col + 1])++; ++count; } } const uword out_n_cols = out.n_cols; uword* col_ptrs = access::rwp(out.col_ptrs); // Fix column pointers to be cumulative. for(uword c = 1; c <= out_n_cols; ++c) { col_ptrs[c] += col_ptrs[c - 1]; } if(count < max_n_nonzero) { if(count <= (max_n_nonzero/2)) { out.mem_resize(count); } else { // quick resize without reallocating memory and copying data access::rw( out.n_nonzero) = count; access::rw( out.values[count]) = eT(0); access::rw(out.row_indices[count]) = uword(0); } } }
arma_hot inline void spglue_times::apply_noalias(SpMat<eT>& c, const SpProxy<T1>& pa, const SpProxy<T2>& pb) { arma_extra_debug_sigprint(); const uword x_n_rows = pa.get_n_rows(); const uword x_n_cols = pa.get_n_cols(); const uword y_n_rows = pb.get_n_rows(); const uword y_n_cols = pb.get_n_cols(); arma_debug_assert_mul_size(x_n_rows, x_n_cols, y_n_rows, y_n_cols, "matrix multiplication"); // First we must determine the structure of the new matrix (column pointers). // This follows the algorithm described in 'Sparse Matrix Multiplication // Package (SMMP)' (R.E. Bank and C.C. Douglas, 2001). Their description of // "SYMBMM" does not include anything about memory allocation. In addition it // does not consider that there may be elements which space may be allocated // for but which evaluate to zero anyway. So we have to modify the algorithm // to work that way. For the "SYMBMM" implementation we will not determine // the row indices but instead just the column pointers. //SpMat<typename T1::elem_type> c(x_n_rows, y_n_cols); // Initializes col_ptrs to 0. c.zeros(x_n_rows, y_n_cols); //if( (pa.get_n_elem() == 0) || (pb.get_n_elem() == 0) ) if( (pa.get_n_nonzero() == 0) || (pb.get_n_nonzero() == 0) ) { return; } // Auxiliary storage which denotes when items have been found. podarray<uword> index(x_n_rows); index.fill(x_n_rows); // Fill with invalid links. typename SpProxy<T2>::const_iterator_type y_it = pb.begin(); typename SpProxy<T2>::const_iterator_type y_end = pb.end(); // SYMBMM: calculate column pointers for resultant matrix to obtain a good // upper bound on the number of nonzero elements. uword cur_col_length = 0; uword last_ind = x_n_rows + 1; do { const uword y_it_row = y_it.row(); // Look through the column that this point (*y_it) could affect. typename SpProxy<T1>::const_iterator_type x_it = pa.begin_col(y_it_row); while(x_it.col() == y_it_row) { // A point at x(i, j) and y(j, k) implies a point at c(i, k). if(index[x_it.row()] == x_n_rows) { index[x_it.row()] = last_ind; last_ind = x_it.row(); ++cur_col_length; } ++x_it; } const uword old_col = y_it.col(); ++y_it; // See if column incremented. if(old_col != y_it.col()) { // Set column pointer (this is not a cumulative count; that is done later). access::rw(c.col_ptrs[old_col + 1]) = cur_col_length; cur_col_length = 0; // Return index markers to zero. Use last_ind for traversal. while(last_ind != x_n_rows + 1) { const uword tmp = index[last_ind]; index[last_ind] = x_n_rows; last_ind = tmp; } } } while(y_it != y_end); // Accumulate column pointers. for(uword i = 0; i < c.n_cols; ++i) { access::rw(c.col_ptrs[i + 1]) += c.col_ptrs[i]; } // Now that we know a decent bound on the number of nonzero elements, allocate // the memory and fill it. c.mem_resize(c.col_ptrs[c.n_cols]); // Now the implementation of the NUMBMM algorithm. uword cur_pos = 0; // Current position in c matrix. podarray<eT> sums(x_n_rows); // Partial sums. sums.zeros(); // setting the size of 'sorted_indices' to x_n_rows is a better-than-nothing guess; // the correct minimum size is determined later podarray<uword> sorted_indices(x_n_rows); // last_ind is already set to x_n_rows, and cur_col_length is already set to 0. // We will loop through all columns as necessary. uword cur_col = 0; while(cur_col < c.n_cols) { // Skip to next column with elements in it. while((cur_col < c.n_cols) && (c.col_ptrs[cur_col] == c.col_ptrs[cur_col + 1])) { // Update current column pointer to actual number of nonzero elements up // to this point. access::rw(c.col_ptrs[cur_col]) = cur_pos; ++cur_col; } if(cur_col == c.n_cols) { break; } // Update current column pointer. access::rw(c.col_ptrs[cur_col]) = cur_pos; // Check all elements in this column. typename SpProxy<T2>::const_iterator_type y_col_it = pb.begin_col(cur_col); while(y_col_it.col() == cur_col) { // Check all elements in the column of the other matrix corresponding to // the row of this column. typename SpProxy<T1>::const_iterator_type x_col_it = pa.begin_col(y_col_it.row()); const eT y_value = (*y_col_it); while(x_col_it.col() == y_col_it.row()) { // A point at x(i, j) and y(j, k) implies a point at c(i, k). // Add to partial sum. const eT x_value = (*x_col_it); sums[x_col_it.row()] += (x_value * y_value); // Add point if it hasn't already been marked. if(index[x_col_it.row()] == x_n_rows) { index[x_col_it.row()] = last_ind; last_ind = x_col_it.row(); } ++x_col_it; } ++y_col_it; } // Now sort the indices that were used in this column. //podarray<uword> sorted_indices(c.col_ptrs[cur_col + 1] - c.col_ptrs[cur_col]); sorted_indices.set_min_size(c.col_ptrs[cur_col + 1] - c.col_ptrs[cur_col]); // .set_min_size() can only enlarge the array to the specified size, // hence if we request a smaller size than already allocated, // no new memory allocation is done uword cur_index = 0; while(last_ind != x_n_rows + 1) { const uword tmp = last_ind; // Check that it wasn't a "fake" nonzero element. if(sums[tmp] != eT(0)) { // Assign to next open position. sorted_indices[cur_index] = tmp; ++cur_index; } last_ind = index[tmp]; index[tmp] = x_n_rows; } // Now sort the indices. if (cur_index != 0) { op_sort::direct_sort_ascending(sorted_indices.memptr(), cur_index); for(uword k = 0; k < cur_index; ++k) { const uword row = sorted_indices[k]; access::rw(c.row_indices[cur_pos]) = row; access::rw(c.values[cur_pos]) = sums[row]; sums[row] = eT(0); ++cur_pos; } } // Move to next column. ++cur_col; } // Update last column pointer and resize to actual memory size. access::rw(c.col_ptrs[c.n_cols]) = cur_pos; c.mem_resize(cur_pos); }
arma_hot inline void spop_sum::apply(SpMat<typename T1::elem_type>& out, const SpOp<T1,spop_sum>& in) { arma_extra_debug_sigprint(); typedef typename T1::elem_type eT; const uword dim = in.aux_uword_a; arma_debug_check( (dim > 1), "sum(): parameter 'dim' must be 0 or 1" ); const SpProxy<T1> p(in.m); const uword p_n_rows = p.get_n_rows(); const uword p_n_cols = p.get_n_cols(); if(p.get_n_nonzero() == 0) { if(dim == 0) { out.zeros(1,p_n_cols); } if(dim == 1) { out.zeros(p_n_rows,1); } return; } if(dim == 0) // find the sum in each column { Row<eT> acc(p_n_cols, fill::zeros); if(SpProxy<T1>::must_use_iterator) { typename SpProxy<T1>::const_iterator_type it = p.begin(); typename SpProxy<T1>::const_iterator_type it_end = p.end(); while(it != it_end) { acc[it.col()] += (*it); ++it; } } else { for(uword col = 0; col < p_n_cols; ++col) { acc[col] = arrayops::accumulate ( &p.get_values()[p.get_col_ptrs()[col]], p.get_col_ptrs()[col + 1] - p.get_col_ptrs()[col] ); } } out = acc; } else if(dim == 1) // find the sum in each row { Col<eT> acc(p_n_rows, fill::zeros); typename SpProxy<T1>::const_iterator_type it = p.begin(); typename SpProxy<T1>::const_iterator_type it_end = p.end(); while(it != it_end) { acc[it.row()] += (*it); ++it; } out = acc; } }
arma_hot inline void spglue_minus::apply_noalias(SpMat<eT>& result, const SpProxy<T1>& pa, const SpProxy<T2>& pb) { arma_extra_debug_sigprint(); arma_debug_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "subtraction"); result.set_size(pa.get_n_rows(), pa.get_n_cols()); // Resize memory to correct size. result.mem_resize(n_unique(pa, pb, op_n_unique_sub())); // Now iterate across both matrices. typename SpProxy<T1>::const_iterator_type x_it = pa.begin(); typename SpProxy<T2>::const_iterator_type y_it = pb.begin(); uword cur_val = 0; while((x_it.pos() < pa.get_n_nonzero()) || (y_it.pos() < pb.get_n_nonzero())) { if(x_it == y_it) { const typename T1::elem_type val = (*x_it) - (*y_it); if (val != 0) { access::rw(result.values[cur_val]) = val; access::rw(result.row_indices[cur_val]) = x_it.row(); ++access::rw(result.col_ptrs[x_it.col() + 1]); ++cur_val; } ++x_it; ++y_it; } else { if((x_it.col() < y_it.col()) || ((x_it.col() == y_it.col()) && (x_it.row() < y_it.row()))) // if y is closer to the end { access::rw(result.values[cur_val]) = (*x_it); access::rw(result.row_indices[cur_val]) = x_it.row(); ++access::rw(result.col_ptrs[x_it.col() + 1]); ++cur_val; ++x_it; } else { access::rw(result.values[cur_val]) = -(*y_it); access::rw(result.row_indices[cur_val]) = y_it.row(); ++access::rw(result.col_ptrs[y_it.col() + 1]); ++cur_val; ++y_it; } } } // Fix column pointers to be cumulative. for(uword c = 1; c <= result.n_cols; ++c) { access::rw(result.col_ptrs[c]) += result.col_ptrs[c - 1]; } }
inline typename enable_if2 < (is_arma_sparse_type<T1>::value && is_arma_sparse_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value), SpMat<typename T1::elem_type> >::result operator% ( const SpBase<typename T1::elem_type, T1>& x, const SpBase<typename T2::elem_type, T2>& y ) { arma_extra_debug_sigprint(); typedef typename T1::elem_type eT; const SpProxy<T1> pa(x.get_ref()); const SpProxy<T2> pb(y.get_ref()); arma_debug_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "element-wise multiplication"); SpMat<typename T1::elem_type> result(pa.get_n_rows(), pa.get_n_cols()); if( (pa.get_n_nonzero() != 0) && (pb.get_n_nonzero() != 0) ) { // Resize memory to correct size. result.mem_resize(n_unique(x, y, op_n_unique_mul())); // Now iterate across both matrices. typename SpProxy<T1>::const_iterator_type x_it = pa.begin(); typename SpProxy<T2>::const_iterator_type y_it = pb.begin(); typename SpProxy<T1>::const_iterator_type x_end = pa.end(); typename SpProxy<T2>::const_iterator_type y_end = pb.end(); uword cur_val = 0; while((x_it != x_end) || (y_it != y_end)) { if(x_it == y_it) { const eT val = (*x_it) * (*y_it); if (val != eT(0)) { access::rw(result.values[cur_val]) = val; access::rw(result.row_indices[cur_val]) = x_it.row(); ++access::rw(result.col_ptrs[x_it.col() + 1]); ++cur_val; } ++x_it; ++y_it; } else { const uword x_it_row = x_it.row(); const uword x_it_col = x_it.col(); const uword y_it_row = y_it.row(); const uword y_it_col = y_it.col(); if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end { ++x_it; } else { ++y_it; } } } // Fix column pointers to be cumulative. for(uword c = 1; c <= result.n_cols; ++c) { access::rw(result.col_ptrs[c]) += result.col_ptrs[c - 1]; } } return result; }
inline void spop_mean::apply_noalias_fast ( SpMat<typename T1::elem_type>& out, const SpProxy<T1>& p, const uword dim ) { arma_extra_debug_sigprint(); typedef typename T1::elem_type eT; typedef typename T1::pod_type T; const uword p_n_rows = p.get_n_rows(); const uword p_n_cols = p.get_n_cols(); if( (p_n_rows == 0) || (p_n_cols == 0) || (p.get_n_nonzero() == 0) ) { if(dim == 0) { out.zeros((p_n_rows > 0) ? 1 : 0, p_n_cols); } if(dim == 1) { out.zeros(p_n_rows, (p_n_cols > 0) ? 1 : 0); } return; } if(dim == 0) // find the mean in each column { Row<eT> acc(p_n_cols, fill::zeros); if(SpProxy<T1>::must_use_iterator) { typename SpProxy<T1>::const_iterator_type it = p.begin(); typename SpProxy<T1>::const_iterator_type it_end = p.end(); while(it != it_end) { acc[it.col()] += (*it); ++it; } acc /= T(p_n_rows); } else { for(uword col = 0; col < p_n_cols; ++col) { acc[col] = arrayops::accumulate ( &p.get_values()[p.get_col_ptrs()[col]], p.get_col_ptrs()[col + 1] - p.get_col_ptrs()[col] ) / T(p_n_rows); } } out = acc; } else if(dim == 1) // find the mean in each row { Col<eT> acc(p_n_rows, fill::zeros); typename SpProxy<T1>::const_iterator_type it = p.begin(); typename SpProxy<T1>::const_iterator_type it_end = p.end(); while(it != it_end) { acc[it.row()] += (*it); ++it; } acc /= T(p_n_cols); out = acc; } if(out.is_finite() == false) { spop_mean::apply_noalias_slow(out, p, dim); } }
inline typename enable_if2 < (is_arma_type<T1>::value && is_arma_sparse_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value), SpMat<typename T1::elem_type> >::result operator% ( const Base<typename T1::elem_type, T1>& x, const SpBase<typename T2::elem_type, T2>& y ) { arma_extra_debug_sigprint(); const Proxy<T1> pa(x.get_ref()); const SpProxy<T2> pb(y.get_ref()); arma_debug_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "element-wise multiplication"); SpMat<typename T1::elem_type> result(pa.get_n_rows(), pa.get_n_cols()); if(Proxy<T1>::prefer_at_accessor == false) { // use direct operator[] access // count new size uword new_n_nonzero = 0; typename SpProxy<T2>::const_iterator_type it = pb.begin(); while(it.pos() < pb.get_n_nonzero()) { if(((*it) * pa[(it.col() * pa.get_n_rows()) + it.row()]) != 0) { ++new_n_nonzero; } ++it; } // Resize memory accordingly. result.mem_resize(new_n_nonzero); uword cur_val = 0; typename SpProxy<T2>::const_iterator_type it2 = pb.begin(); while(it2.pos() < pb.get_n_nonzero()) { const typename T1::elem_type val = (*it2) * pa[(it2.col() * pa.get_n_rows()) + it2.row()]; if(val != 0) { access::rw(result.values[cur_val]) = val; access::rw(result.row_indices[cur_val]) = it2.row(); ++access::rw(result.col_ptrs[it2.col() + 1]); ++cur_val; } ++it2; } } else { // use at() access // count new size uword new_n_nonzero = 0; typename SpProxy<T2>::const_iterator_type it = pb.begin(); while(it.pos() < pb.get_n_nonzero()) { if(((*it) * pa.at(it.row(), it.col())) != 0) { ++new_n_nonzero; } ++it; } // Resize memory accordingly. result.mem_resize(new_n_nonzero); uword cur_val = 0; typename SpProxy<T2>::const_iterator_type it2 = pb.begin(); while(it2.pos() < pb.get_n_nonzero()) { const typename T1::elem_type val = (*it2) * pa.at(it2.row(), it2.col()); if(val != 0) { access::rw(result.values[cur_val]) = val; access::rw(result.row_indices[cur_val]) = it2.row(); ++access::rw(result.col_ptrs[it2.col() + 1]); ++cur_val; } ++it2; } } // Fix column pointers. for(uword c = 1; c <= result.n_cols; ++c) { access::rw(result.col_ptrs[c]) += result.col_ptrs[c - 1]; } return result; }
arma_hot inline void spglue_plus::apply_noalias(SpMat<eT>& out, const SpProxy<T1>& pa, const SpProxy<T2>& pb) { arma_extra_debug_sigprint(); arma_debug_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "addition"); if( (pa.get_n_nonzero() != 0) && (pb.get_n_nonzero() != 0) ) { out.set_size(pa.get_n_rows(), pa.get_n_cols()); // Resize memory to correct size. out.mem_resize(n_unique(pa, pb, op_n_unique_add())); // Now iterate across both matrices. typename SpProxy<T1>::const_iterator_type x_it = pa.begin(); typename SpProxy<T2>::const_iterator_type y_it = pb.begin(); typename SpProxy<T1>::const_iterator_type x_end = pa.end(); typename SpProxy<T2>::const_iterator_type y_end = pb.end(); uword cur_val = 0; while( (x_it != x_end) || (y_it != y_end) ) { if(x_it == y_it) { const eT val = (*x_it) + (*y_it); if (val != eT(0)) { access::rw(out.values[cur_val]) = val; access::rw(out.row_indices[cur_val]) = x_it.row(); ++access::rw(out.col_ptrs[x_it.col() + 1]); ++cur_val; } ++x_it; ++y_it; } else { const uword x_it_row = x_it.row(); const uword x_it_col = x_it.col(); const uword y_it_row = y_it.row(); const uword y_it_col = y_it.col(); if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end { access::rw(out.values[cur_val]) = (*x_it); access::rw(out.row_indices[cur_val]) = x_it_row; ++access::rw(out.col_ptrs[x_it_col + 1]); ++cur_val; ++x_it; } else { access::rw(out.values[cur_val]) = (*y_it); access::rw(out.row_indices[cur_val]) = y_it_row; ++access::rw(out.col_ptrs[y_it_col + 1]); ++cur_val; ++y_it; } } } const uword out_n_cols = out.n_cols; uword* col_ptrs = access::rwp(out.col_ptrs); // Fix column pointers to be cumulative. for(uword c = 1; c <= out_n_cols; ++c) { col_ptrs[c] += col_ptrs[c - 1]; } } else { if(pa.get_n_nonzero() == 0) { out = pb.Q; return; } if(pb.get_n_nonzero() == 0) { out = pa.Q; return; } } }
inline typename enable_if2 < (is_arma_sparse_type<T1>::value && is_arma_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value), SpMat<typename T1::elem_type> >::result operator/ ( const SpBase<typename T1::elem_type, T1>& x, const Base<typename T2::elem_type, T2>& y ) { arma_extra_debug_sigprint(); const SpProxy<T1> pa(x.get_ref()); const Proxy<T2> pb(y.get_ref()); arma_debug_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "element-wise division"); SpMat<typename T1::elem_type> result(pa.get_n_rows(), pa.get_n_cols()); // The compiler should be smart enough to optimize out the inner if/else statement entirely typename SpProxy<T1>::const_iterator_type it = pa.begin(); uword new_n_nonzero; while(it.pos() < pa.get_n_nonzero()) { if(Proxy<T2>::prefer_at_accessor == false) { const typename T1::elem_type val = (*it) / pb[(it.col() * pb.get_n_rows()) + it.row()]; if(val != 0) { ++new_n_nonzero; } } else { const typename T1::elem_type val = (*it) / pb.at(it.row(), it.col()); if(val != 0) { ++new_n_nonzero; } } ++it; } result.mem_resize(new_n_nonzero); typename SpProxy<T1>::const_iterator_type it2 = pa.begin(); uword cur_pos = 0; while(it2.pos() < pa.get_n_nonzero()) { if(Proxy<T2>::prefer_at_accessor == false) { const typename T1::elem_type val = (*it2) / pb[(it2.col() * pb.get_n_rows()) + it2.row()]; if(val != 0) { access::rw(result.values[cur_pos]) = val; access::rw(result.row_indices[cur_pos]) = it2.row(); ++access::rw(result.col_ptrs[it2.col() + 1]); ++cur_pos; } } else { const typename T1::elem_type val = (*it2) / pb.at(it2.row(), it2.col()); if(val != 0) { access::rw(result.values[cur_pos]) = val; access::rw(result.row_indices[cur_pos]) = it2.row(); ++access::rw(result.col_ptrs[it2.col() + 1]); ++cur_pos; } } ++it2; } // Fix column pointers for(uword col = 1; col <= result.n_cols; ++col) { access::rw(result.col_ptrs[col]) += result.col_ptrs[col - 1]; } return result; }