inline void op_sp_plus::apply(SpMat<typename T1::elem_type>& out, const SpToDOp<T1,op_sp_plus>& in) { arma_extra_debug_sigprint(); typedef typename T1::elem_type eT; // Note that T1 will be a sparse type, so we use SpProxy. const SpProxy<T1> proxy(in.m); const uword n_rows = proxy.get_n_rows(); const uword n_cols = proxy.get_n_cols(); out.set_size(n_rows, n_cols); const eT k = in.aux; // We have to loop over all the elements. for(uword c = 0; c < n_cols; ++c) for(uword r = 0; r < n_rows; ++r) { out.at(r, c) = proxy.at(r, c) + k; } }
inline void spop_repmat::apply(SpMat<typename T1::elem_type>& out, const SpOp<T1, spop_repmat>& in) { arma_extra_debug_sigprint(); typedef typename T1::elem_type eT; const unwrap_spmat<T1> U(in.m); const SpMat<eT>& X = U.M; const uword X_n_rows = X.n_rows; const uword X_n_cols = X.n_cols; const uword copies_per_row = in.aux_uword_a; const uword copies_per_col = in.aux_uword_b; // out.set_size(X_n_rows * copies_per_row, X_n_cols * copies_per_col); // // const uword out_n_rows = out.n_rows; // const uword out_n_cols = out.n_cols; // // if( (out_n_rows > 0) && (out_n_cols > 0) ) // { // for(uword col = 0; col < out_n_cols; col += X_n_cols) // for(uword row = 0; row < out_n_rows; row += X_n_rows) // { // out.submat(row, col, row+X_n_rows-1, col+X_n_cols-1) = X; // } // } SpMat<eT> tmp(X_n_rows * copies_per_row, X_n_cols); if(tmp.n_elem > 0) { for(uword row = 0; row < tmp.n_rows; row += X_n_rows) { tmp.submat(row, 0, row+X_n_rows-1, X_n_cols-1) = X; } } // tmp contains copies of the input matrix, so no need to check for aliasing out.set_size(X_n_rows * copies_per_row, X_n_cols * copies_per_col); const uword out_n_rows = out.n_rows; const uword out_n_cols = out.n_cols; if( (out_n_rows > 0) && (out_n_cols > 0) ) { for(uword col = 0; col < out_n_cols; col += X_n_cols) { out.submat(0, col, out_n_rows-1, col+X_n_cols-1) = tmp; } } }
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); }
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 void spop_mean::apply_noalias_slow ( SpMat<typename T1::elem_type>& out, const SpProxy<T1>& p, const uword dim ) { arma_extra_debug_sigprint(); typedef typename T1::elem_type eT; const uword p_n_rows = p.get_n_rows(); const uword p_n_cols = p.get_n_cols(); if(dim == 0) // find the mean in each column { arma_extra_debug_print("spop_mean::apply_noalias(): dim = 0"); out.set_size((p_n_rows > 0) ? 1 : 0, p_n_cols); if( (p_n_rows == 0) || (p.get_n_nonzero() == 0) ) { return; } for(uword col = 0; col < p_n_cols; ++col) { // Do we have to use an iterator or can we use memory directly? if(SpProxy<T1>::must_use_iterator) { typename SpProxy<T1>::const_iterator_type it = p.begin_col(col); typename SpProxy<T1>::const_iterator_type end = p.begin_col(col + 1); const uword n_zero = p_n_rows - (end.pos() - it.pos()); out.at(0,col) = spop_mean::iterator_mean(it, end, n_zero, eT(0)); } else { out.at(0,col) = spop_mean::direct_mean ( &p.get_values()[p.get_col_ptrs()[col]], p.get_col_ptrs()[col + 1] - p.get_col_ptrs()[col], p_n_rows ); } } } else if(dim == 1) // find the mean in each row { arma_extra_debug_print("spop_mean::apply_noalias(): dim = 1"); out.set_size(p_n_rows, (p_n_cols > 0) ? 1 : 0); if( (p_n_cols == 0) || (p.get_n_nonzero() == 0) ) { return; } for(uword row = 0; row < p_n_rows; ++row) { // We must use an iterator regardless of how it is stored. typename SpProxy<T1>::const_row_iterator_type it = p.begin_row(row); typename SpProxy<T1>::const_row_iterator_type end = p.end_row(row); const uword n_zero = p_n_cols - (end.pos() - it.pos()); out.at(row,0) = spop_mean::iterator_mean(it, end, n_zero, eT(0)); } } }
inline void spop_var::apply_noalias ( SpMat<typename T1::pod_type>& out_ref, const SpProxy<T1>& p, const uword norm_type, const uword dim ) { arma_extra_debug_sigprint(); typedef typename T1::elem_type in_eT; //typedef typename T1::pod_type out_eT; const uword p_n_rows = p.get_n_rows(); const uword p_n_cols = p.get_n_cols(); if(dim == 0) { arma_extra_debug_print("spop_var::apply(), dim = 0"); arma_debug_check((p_n_rows == 0), "var(): given object has zero rows"); out_ref.set_size(1, p_n_cols); for(uword col = 0; col < p_n_cols; ++col) { if(SpProxy<T1>::must_use_iterator == true) { // We must use an iterator; we can't access memory directly. typename SpProxy<T1>::const_iterator_type it = p.begin_col(col); typename SpProxy<T1>::const_iterator_type end = p.begin_col(col + 1); const uword n_zero = p.get_n_rows() - (end.pos() - it.pos()); // in_eT is used just to get the specialization right (complex / noncomplex) out_ref.at(col) = spop_var::iterator_var(it, end, n_zero, norm_type, in_eT(0)); } else { // We can use direct memory access to calculate the variance. out_ref.at(col) = spop_var::direct_var ( &p.get_values()[p.get_col_ptrs()[col]], p.get_col_ptrs()[col + 1] - p.get_col_ptrs()[col], p.get_n_rows(), norm_type ); } } } else if(dim == 1) { arma_extra_debug_print("spop_var::apply_noalias(), dim = 1"); arma_debug_check((p_n_cols == 0), "var(): given object has zero columns"); out_ref.set_size(p_n_rows, 1); for(uword row = 0; row < p_n_rows; ++row) { // We have to use an iterator here regardless of whether or not we can // directly access memory. typename SpProxy<T1>::const_row_iterator_type it = p.begin_row(row); typename SpProxy<T1>::const_row_iterator_type end = p.end_row(row); const uword n_zero = p.get_n_cols() - (end.pos() - it.pos()); out_ref.at(row) = spop_var::iterator_var(it, end, n_zero, norm_type, in_eT(0)); } } }
inline void spop_var::apply_noalias ( SpMat<typename T1::pod_type>& out, const SpProxy<T1>& p, const uword norm_type, const uword dim ) { arma_extra_debug_sigprint(); typedef typename T1::elem_type in_eT; //typedef typename T1::pod_type out_eT; const uword p_n_rows = p.get_n_rows(); const uword p_n_cols = p.get_n_cols(); // TODO: this is slow; rewrite based on the approach used by sparse mean() if(dim == 0) // find variance in each column { arma_extra_debug_print("spop_var::apply_noalias(): dim = 0"); out.set_size((p_n_rows > 0) ? 1 : 0, p_n_cols); if( (p_n_rows == 0) || (p.get_n_nonzero() == 0) ) { return; } for(uword col = 0; col < p_n_cols; ++col) { if(SpProxy<T1>::must_use_iterator) { // We must use an iterator; we can't access memory directly. typename SpProxy<T1>::const_iterator_type it = p.begin_col(col); typename SpProxy<T1>::const_iterator_type end = p.begin_col(col + 1); const uword n_zero = p_n_rows - (end.pos() - it.pos()); // in_eT is used just to get the specialization right (complex / noncomplex) out.at(0, col) = spop_var::iterator_var(it, end, n_zero, norm_type, in_eT(0)); } else { // We can use direct memory access to calculate the variance. out.at(0, col) = spop_var::direct_var ( &p.get_values()[p.get_col_ptrs()[col]], p.get_col_ptrs()[col + 1] - p.get_col_ptrs()[col], p_n_rows, norm_type ); } } } else if(dim == 1) // find variance in each row { arma_extra_debug_print("spop_var::apply_noalias(): dim = 1"); out.set_size(p_n_rows, (p_n_cols > 0) ? 1 : 0); if( (p_n_cols == 0) || (p.get_n_nonzero() == 0) ) { return; } for(uword row = 0; row < p_n_rows; ++row) { // We have to use an iterator here regardless of whether or not we can // directly access memory. typename SpProxy<T1>::const_row_iterator_type it = p.begin_row(row); typename SpProxy<T1>::const_row_iterator_type end = p.end_row(row); const uword n_zero = p_n_cols - (end.pos() - it.pos()); out.at(row, 0) = spop_var::iterator_var(it, end, n_zero, norm_type, in_eT(0)); } } }
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]; } }