Chris@49: // Copyright (C) 2012 Ryan Curtin Chris@49: // Copyright (C) 2012 Conrad Sanderson Chris@49: // Chris@49: // This Source Code Form is subject to the terms of the Mozilla Public Chris@49: // License, v. 2.0. If a copy of the MPL was not distributed with this Chris@49: // file, You can obtain one at http://mozilla.org/MPL/2.0/. Chris@49: Chris@49: Chris@49: //! \addtogroup fn_n_unique Chris@49: //! @{ Chris@49: Chris@49: Chris@49: //! \brief Chris@49: //! Get the number of unique nonzero elements in two sparse matrices. Chris@49: //! This is very useful for determining the amount of memory necessary before Chris@49: //! a sparse matrix operation on two matrices. Chris@49: Chris@49: template Chris@49: inline Chris@49: uword Chris@49: n_unique Chris@49: ( Chris@49: const SpBase& x, Chris@49: const SpBase& y, Chris@49: const op_n_unique_type junk Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: const SpProxy pa(x.get_ref()); Chris@49: const SpProxy pb(y.get_ref()); Chris@49: Chris@49: return n_unique(pa,pb,junk); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: arma_hot Chris@49: inline Chris@49: uword Chris@49: n_unique Chris@49: ( Chris@49: const SpProxy& pa, Chris@49: const SpProxy& pb, Chris@49: const op_n_unique_type junk Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(junk); Chris@49: Chris@49: // Use iterators. Chris@49: typename SpProxy::const_iterator_type x_it = pa.begin(); Chris@49: typename SpProxy::const_iterator_type y_it = pb.begin(); Chris@49: Chris@49: uword total_n_nonzero = 0; Chris@49: Chris@49: while((x_it != pa.end()) || (y_it != pb.end())) Chris@49: { Chris@49: if(x_it == y_it) Chris@49: { Chris@49: if(op_n_unique_type::eval((*x_it), (*y_it)) != typename T1::elem_type(0)) Chris@49: { Chris@49: ++total_n_nonzero; Chris@49: } Chris@49: Chris@49: ++x_it; Chris@49: ++y_it; Chris@49: } Chris@49: else Chris@49: { Chris@49: 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 Chris@49: { Chris@49: if(op_n_unique_type::eval((*x_it), typename T1::elem_type(0)) != typename T1::elem_type(0)) Chris@49: { Chris@49: ++total_n_nonzero; Chris@49: } Chris@49: Chris@49: ++x_it; Chris@49: } Chris@49: else // x is closer to the end Chris@49: { Chris@49: if(op_n_unique_type::eval(typename T1::elem_type(0), (*y_it)) != typename T1::elem_type(0)) Chris@49: { Chris@49: ++total_n_nonzero; Chris@49: } Chris@49: Chris@49: ++y_it; Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: return total_n_nonzero; Chris@49: } Chris@49: Chris@49: Chris@49: // Simple operators. Chris@49: struct op_n_unique_add Chris@49: { Chris@49: template inline static eT eval(const eT& l, const eT& r) { return (l + r); } Chris@49: }; Chris@49: Chris@49: struct op_n_unique_sub Chris@49: { Chris@49: template inline static eT eval(const eT& l, const eT& r) { return (l - r); } Chris@49: }; Chris@49: Chris@49: struct op_n_unique_mul Chris@49: { Chris@49: template inline static eT eval(const eT& l, const eT& r) { return (l * r); } Chris@49: }; Chris@49: Chris@49: struct op_n_unique_count Chris@49: { Chris@49: template inline static eT eval(const eT& l, const eT& r) { return 1; } Chris@49: }; Chris@49: Chris@49: Chris@49: Chris@49: //! @}