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 spop_var Chris@49: //! @{ Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: void Chris@49: spop_var::apply(SpMat& out, const mtSpOp& in) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: //typedef typename T1::elem_type in_eT; Chris@49: typedef typename T1::pod_type out_eT; Chris@49: Chris@49: const uword norm_type = in.aux_uword_a; Chris@49: const uword dim = in.aux_uword_b; Chris@49: Chris@49: arma_debug_check((norm_type > 1), "var(): incorrect usage. norm_type must be 0 or 1"); Chris@49: arma_debug_check((dim > 1), "var(): incorrect usage. dim must be 0 or 1"); Chris@49: Chris@49: SpProxy p(in.m); Chris@49: Chris@49: if(p.is_alias(out) == false) Chris@49: { Chris@49: spop_var::apply_noalias(out, p, norm_type, dim); Chris@49: } Chris@49: else Chris@49: { Chris@49: SpMat tmp; Chris@49: Chris@49: spop_var::apply_noalias(tmp, p, norm_type, dim); Chris@49: Chris@49: out.steal_mem(tmp); Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: void Chris@49: spop_var::apply_noalias Chris@49: ( Chris@49: SpMat& out_ref, Chris@49: const SpProxy& p, Chris@49: const uword norm_type, Chris@49: const uword dim Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: typedef typename T1::elem_type in_eT; Chris@49: //typedef typename T1::pod_type out_eT; Chris@49: Chris@49: const uword p_n_rows = p.get_n_rows(); Chris@49: const uword p_n_cols = p.get_n_cols(); Chris@49: Chris@49: if(dim == 0) Chris@49: { Chris@49: arma_extra_debug_print("spop_var::apply(), dim = 0"); Chris@49: Chris@49: arma_debug_check((p_n_rows == 0), "var(): given object has zero rows"); Chris@49: Chris@49: out_ref.set_size(1, p_n_cols); Chris@49: Chris@49: for(uword col = 0; col < p_n_cols; ++col) Chris@49: { Chris@49: if(SpProxy::must_use_iterator == true) Chris@49: { Chris@49: // We must use an iterator; we can't access memory directly. Chris@49: typename SpProxy::const_iterator_type it = p.begin_col(col); Chris@49: typename SpProxy::const_iterator_type end = p.begin_col(col + 1); Chris@49: Chris@49: const uword n_zero = p.get_n_rows() - (end.pos() - it.pos()); Chris@49: Chris@49: // in_eT is used just to get the specialization right (complex / noncomplex) Chris@49: out_ref.at(col) = spop_var::iterator_var(it, end, n_zero, norm_type, in_eT(0)); Chris@49: } Chris@49: else Chris@49: { Chris@49: // We can use direct memory access to calculate the variance. Chris@49: out_ref.at(col) = spop_var::direct_var Chris@49: ( Chris@49: &p.get_values()[p.get_col_ptrs()[col]], Chris@49: p.get_col_ptrs()[col + 1] - p.get_col_ptrs()[col], Chris@49: p.get_n_rows(), Chris@49: norm_type Chris@49: ); Chris@49: } Chris@49: } Chris@49: } Chris@49: else if(dim == 1) Chris@49: { Chris@49: arma_extra_debug_print("spop_var::apply_noalias(), dim = 1"); Chris@49: Chris@49: arma_debug_check((p_n_cols == 0), "var(): given object has zero columns"); Chris@49: Chris@49: out_ref.set_size(p_n_rows, 1); Chris@49: Chris@49: for(uword row = 0; row < p_n_rows; ++row) Chris@49: { Chris@49: // We have to use an iterator here regardless of whether or not we can Chris@49: // directly access memory. Chris@49: typename SpProxy::const_row_iterator_type it = p.begin_row(row); Chris@49: typename SpProxy::const_row_iterator_type end = p.end_row(row); Chris@49: Chris@49: const uword n_zero = p.get_n_cols() - (end.pos() - it.pos()); Chris@49: Chris@49: out_ref.at(row) = spop_var::iterator_var(it, end, n_zero, norm_type, in_eT(0)); Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: typename T1::pod_type Chris@49: spop_var::var_vec Chris@49: ( Chris@49: const T1& X, Chris@49: const uword norm_type Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: arma_debug_check((norm_type > 1), "var(): incorrect usage. norm_type must be 0 or 1."); Chris@49: Chris@49: // conditionally unwrap it into a temporary and then directly operate. Chris@49: Chris@49: const unwrap_spmat tmp(X); Chris@49: Chris@49: return direct_var(tmp.M.values, tmp.M.n_nonzero, tmp.M.n_elem, norm_type); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: eT Chris@49: spop_var::direct_var Chris@49: ( Chris@49: const eT* const X, Chris@49: const uword length, Chris@49: const uword N, Chris@49: const uword norm_type Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: if(length >= 2 && N >= 2) Chris@49: { Chris@49: const eT acc1 = spop_mean::direct_mean(X, length, N); Chris@49: Chris@49: eT acc2 = eT(0); Chris@49: eT acc3 = eT(0); Chris@49: Chris@49: uword i, j; Chris@49: Chris@49: for(i = 0, j = 1; j < length; i += 2, j += 2) Chris@49: { Chris@49: const eT Xi = X[i]; Chris@49: const eT Xj = X[j]; Chris@49: Chris@49: const eT tmpi = acc1 - Xi; Chris@49: const eT tmpj = acc1 - Xj; Chris@49: Chris@49: acc2 += tmpi * tmpi + tmpj * tmpj; Chris@49: acc3 += tmpi + tmpj; Chris@49: } Chris@49: Chris@49: if(i < length) Chris@49: { Chris@49: const eT Xi = X[i]; Chris@49: Chris@49: const eT tmpi = acc1 - Xi; Chris@49: Chris@49: acc2 += tmpi * tmpi; Chris@49: acc3 += tmpi; Chris@49: } Chris@49: Chris@49: // Now add in all zero elements. Chris@49: acc2 += (N - length) * (acc1 * acc1); Chris@49: acc3 += (N - length) * acc1; Chris@49: Chris@49: const eT norm_val = (norm_type == 0) ? eT(N - 1) : eT(N); Chris@49: const eT var_val = (acc2 - (acc3 * acc3) / eT(N)) / norm_val; Chris@49: Chris@49: return var_val; Chris@49: } Chris@49: else if(length == 1 && N > 1) // if N == 1, then variance is zero. Chris@49: { Chris@49: const eT mean = X[0] / eT(N); Chris@49: const eT val = mean - X[0]; Chris@49: Chris@49: const eT acc2 = (val * val) + (N - length) * (mean * mean); Chris@49: const eT acc3 = val + (N - length) * mean; Chris@49: Chris@49: const eT norm_val = (norm_type == 0) ? eT(N - 1) : eT(N); Chris@49: const eT var_val = (acc2 - (acc3 * acc3) / eT(N)) / norm_val; Chris@49: Chris@49: return var_val; Chris@49: } Chris@49: else Chris@49: { Chris@49: return eT(0); Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: T Chris@49: spop_var::direct_var Chris@49: ( Chris@49: const std::complex* const X, Chris@49: const uword length, Chris@49: const uword N, Chris@49: const uword norm_type Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: typedef typename std::complex eT; Chris@49: Chris@49: if(length >= 2 && N >= 2) Chris@49: { Chris@49: const eT acc1 = spop_mean::direct_mean(X, length, N); Chris@49: Chris@49: T acc2 = T(0); Chris@49: eT acc3 = eT(0); Chris@49: Chris@49: for (uword i = 0; i < length; ++i) Chris@49: { Chris@49: const eT tmp = acc1 - X[i]; Chris@49: Chris@49: acc2 += std::norm(tmp); Chris@49: acc3 += tmp; Chris@49: } Chris@49: Chris@49: // Add zero elements to sums Chris@49: acc2 += std::norm(acc1) * T(N - length); Chris@49: acc3 += acc1 * T(N - length); Chris@49: Chris@49: const T norm_val = (norm_type == 0) ? T(N - 1) : T(N); Chris@49: const T var_val = (acc2 - std::norm(acc3) / T(N)) / norm_val; Chris@49: Chris@49: return var_val; Chris@49: } Chris@49: else if(length == 1 && N > 1) // if N == 1, then variance is zero. Chris@49: { Chris@49: const eT mean = X[0] / T(N); Chris@49: const eT val = mean - X[0]; Chris@49: Chris@49: const T acc2 = std::norm(val) + (N - length) * std::norm(mean); Chris@49: const eT acc3 = val + T(N - length) * mean; Chris@49: Chris@49: const T norm_val = (norm_type == 0) ? T(N - 1) : T(N); Chris@49: const T var_val = (acc2 - std::norm(acc3) / T(N)) / norm_val; Chris@49: Chris@49: return var_val; Chris@49: } Chris@49: else Chris@49: { Chris@49: return T(0); // All elements are zero Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: eT Chris@49: spop_var::iterator_var Chris@49: ( Chris@49: T1& it, Chris@49: const T1& end, Chris@49: const uword n_zero, Chris@49: const uword norm_type, Chris@49: const eT junk1, Chris@49: const typename arma_not_cx::result* junk2 Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(junk1); Chris@49: arma_ignore(junk2); Chris@49: Chris@49: T1 new_it(it); // for mean Chris@49: // T1 backup_it(it); // in case we have to call robust iterator_var Chris@49: eT mean = spop_mean::iterator_mean(new_it, end, n_zero, eT(0)); Chris@49: Chris@49: eT acc2 = eT(0); Chris@49: eT acc3 = eT(0); Chris@49: Chris@49: const uword it_begin_pos = it.pos(); Chris@49: Chris@49: while (it != end) Chris@49: { Chris@49: const eT tmp = mean - (*it); Chris@49: Chris@49: acc2 += (tmp * tmp); Chris@49: acc3 += (tmp); Chris@49: Chris@49: ++it; Chris@49: } Chris@49: Chris@49: const uword n_nonzero = (it.pos() - it_begin_pos); Chris@49: if (n_nonzero == 0) Chris@49: { Chris@49: return eT(0); Chris@49: } Chris@49: Chris@49: if (n_nonzero + n_zero == 1) Chris@49: { Chris@49: return eT(0); // only one element Chris@49: } Chris@49: Chris@49: // Add in entries for zeros. Chris@49: acc2 += eT(n_zero) * (mean * mean); Chris@49: acc3 += eT(n_zero) * mean; Chris@49: Chris@49: const eT norm_val = (norm_type == 0) ? eT(n_zero + n_nonzero - 1) : eT(n_zero + n_nonzero); Chris@49: const eT var_val = (acc2 - (acc3 * acc3) / eT(n_nonzero + n_zero)) / norm_val; Chris@49: Chris@49: return var_val; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: typename get_pod_type::result Chris@49: spop_var::iterator_var Chris@49: ( Chris@49: T1& it, Chris@49: const T1& end, Chris@49: const uword n_zero, Chris@49: const uword norm_type, Chris@49: const eT junk1, Chris@49: const typename arma_cx_only::result* junk2 Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(junk1); Chris@49: arma_ignore(junk2); Chris@49: Chris@49: typedef typename get_pod_type::result T; Chris@49: Chris@49: T1 new_it(it); // for mean Chris@49: // T1 backup_it(it); // in case we have to call robust iterator_var Chris@49: eT mean = spop_mean::iterator_mean(new_it, end, n_zero, eT(0)); Chris@49: Chris@49: T acc2 = T(0); Chris@49: eT acc3 = eT(0); Chris@49: Chris@49: const uword it_begin_pos = it.pos(); Chris@49: Chris@49: while (it != end) Chris@49: { Chris@49: eT tmp = mean - (*it); Chris@49: Chris@49: acc2 += std::norm(tmp); Chris@49: acc3 += (tmp); Chris@49: Chris@49: ++it; Chris@49: } Chris@49: Chris@49: const uword n_nonzero = (it.pos() - it_begin_pos); Chris@49: if (n_nonzero == 0) Chris@49: { Chris@49: return T(0); Chris@49: } Chris@49: Chris@49: if (n_nonzero + n_zero == 1) Chris@49: { Chris@49: return T(0); // only one element Chris@49: } Chris@49: Chris@49: // Add in entries for zero elements. Chris@49: acc2 += T(n_zero) * std::norm(mean); Chris@49: acc3 += T(n_zero) * mean; Chris@49: Chris@49: const T norm_val = (norm_type == 0) ? T(n_zero + n_nonzero - 1) : T(n_zero + n_nonzero); Chris@49: const T var_val = (acc2 - std::norm(acc3) / T(n_nonzero + n_zero)) / norm_val; Chris@49: Chris@49: return var_val; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! @}