inline
void
glue_min::apply(Cube<eT>& out, const ProxyCube<T1>& PA, const ProxyCube<T2>& PB)
  {
  arma_extra_debug_sigprint();
  
  const uword n_rows   = PA.get_n_rows();
  const uword n_cols   = PA.get_n_cols();
  const uword n_slices = PA.get_n_slices();
  
  arma_debug_assert_same_size(n_rows, n_cols, n_slices, PB.get_n_rows(), PB.get_n_cols(), PB.get_n_slices(), "min(): given cubes must have the same size");
  
  out.set_size(n_rows, n_cols, n_slices);
  
  eT* out_mem = out.memptr();
  
  if( (ProxyCube<T1>::use_at == false) && (ProxyCube<T2>::use_at == false) )
    {
    typename ProxyCube<T1>::ea_type A = PA.get_ea();
    typename ProxyCube<T2>::ea_type B = PB.get_ea();
    
    const uword N = PA.get_n_elem();
    
    for(uword i=0; i<N; ++i)
      {
      out_mem[i] = (std::min)(A[i], B[i]);
      }
    }
  else
    {
    for(uword slice=0; slice < n_slices; ++slice)
    for(uword   col=0;   col < n_cols;   ++col  )
    for(uword   row=0;   row < n_rows;   ++row  )
      {
      *out_mem = (std::min)( PA.at(row,col,slice), PB.at(row,col,slice) );
      
      ++out_mem;
      }
    }
  }
inline
void
subview_cube<eT>::operator/= (const Base<eT,T1>& in)
  {
  arma_extra_debug_sigprint();
  
  const unwrap<T1> tmp(in.get_ref());
  
  const Mat<eT>&          x = tmp.M;
        subview_cube<eT>& t = *this;
  
  arma_debug_assert_same_size(t, x, "element-wise cube division");
  
  const u32 t_n_rows     = t.n_rows;
  const u32 t_n_cols     = t.n_cols;
  const u32 t_aux_slice1 = t.aux_slice1;
  
  for(u32 col = 0; col < t_n_cols; ++col)
    {
    arrayops::inplace_div( t.slice_colptr(t_aux_slice1, col), x.colptr(col), t_n_rows );
    }
  }
inline
void
spglue_minus_mixed::dense_minus_sparse(Mat< typename promote_type<typename T1::elem_type, typename T2::elem_type >::result>& out, const T1& X, const T2& Y)
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT1;
  typedef typename T2::elem_type eT2;
  
  typedef typename promote_type<eT1,eT2>::result out_eT;
  
  promote_type<eT1,eT2>::check();
  
  if(is_same_type<eT1,out_eT>::no)
    {
    out = conv_to< Mat<out_eT> >::from(X);
    }
  else
    {
    const quasi_unwrap<T1> UA(X);
    
    const Mat<eT1>& A = UA.M;
    
    out = reinterpret_cast< const Mat<out_eT>& >(A);
    }
  
  const SpProxy<T2> pb(Y);
  
  arma_debug_assert_same_size( out.n_rows, out.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)
    {
    out.at(it.row(), it.col()) -= out_eT(*it);
    ++it;
    }
  }
inline
void
subview_cube<eT>::operator= (const Base<eT,T1>& in)
  {
  arma_extra_debug_sigprint();
  
  const unwrap<T1> tmp(in.get_ref());
  
  const Mat<eT>&          x = tmp.M;
        subview_cube<eT>& t = *this;
  
  arma_debug_assert_same_size(t, x, "copy into subcube");
  
  const u32 t_n_rows     = t.n_rows;
  const u32 t_n_cols     = t.n_cols;
  const u32 t_aux_slice1 = t.aux_slice1;
  
  for(u32 col = 0; col < t_n_cols; ++col)
    {
    syslib:copy_elem( t.slice_colptr(t_aux_slice1, col), x.colptr(col), t_n_rows );
    }
  }
Example #5
0
inline
void
subview_cube<eT>::operator/= (const subview_cube<eT>& x_in)
  {
  arma_extra_debug_sigprint();
  
  const bool overlap = check_overlap(x_in);
  
        Cube<eT>*         tmp_cube         = overlap ? new Cube<eT>(x_in.m) : 0;
  const subview_cube<eT>* tmp_subview_cube = overlap ? new subview_cube<eT>(*tmp_cube, x_in.aux_row1, x_in.aux_col1, x_in.aux_slice1, x_in.aux_row2, x_in.aux_col2, x_in.aux_slice2) : 0;
  const subview_cube<eT>& x                = overlap ? (*tmp_subview_cube) : x_in;
  
  subview_cube<eT>& t = *this;
  
  arma_debug_assert_same_size(t, x, "element-wise cube division");
  
  
  for(u32 slice = 0; slice < t.n_slices; ++slice)
    {
    for(u32 col = 0; col < t.n_cols; ++col)
      {
            eT* t_coldata = t.slice_colptr(slice,col);
      const eT* x_coldata = x.slice_colptr(slice,col);
      
      for(u32 row = 0; row < t.n_rows; ++row)
        {
        t_coldata[row] /= x_coldata[row];
        }
      }
    }
    
  if(overlap)
    {
    delete tmp_subview_cube;
    delete tmp_cube;
    }
  
  }
Example #6
0
inline
void
glue_min::apply(Mat<eT>& out, const Proxy<T1>& PA, const Proxy<T2>& PB)
  {
  arma_extra_debug_sigprint();
  
  const uword n_rows = PA.get_n_rows();
  const uword n_cols = PA.get_n_cols();
  
  arma_debug_assert_same_size(n_rows, n_cols, PB.get_n_rows(), PB.get_n_cols(), "element-wise minimum");
  
  out.set_size(n_rows, n_cols);
  
  eT* out_mem = out.memptr();
  
  if( (Proxy<T1>::use_at == false) && (Proxy<T2>::use_at == false) )
    {
    typename Proxy<T1>::ea_type A = PA.get_ea();
    typename Proxy<T2>::ea_type B = PB.get_ea();
    
    const uword N = PA.get_n_elem();
    
    for(uword i=0; i<N; ++i)
      {
      out_mem[i] = (std::min)(A[i], B[i]);
      }
    }
  else
    {
    for(uword col=0; col < n_cols; ++col)
    for(uword row=0; row < n_rows; ++row)
      {
      *out_mem = (std::min)( PA.at(row,col), PB.at(row,col) );
      
      ++out_mem;
      }
    }
  }
Example #7
0
arma_warn_unused
arma_hot
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),
   typename T1::elem_type
  >::result
dot
  (
  const T1& x,
  const T2& y
  )
  {
  arma_extra_debug_sigprint();
  
  const   Proxy<T1> pa(x);
  const SpProxy<T2> pb(y);
  
  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();
  typename SpProxy<T2>::const_iterator_type it_end = pb.end();
  
  // prefer_at_accessor won't save us operations
  while(it != it_end)
    {
    result += (*it) * pa.at(it.row(), it.col());
    ++it;
    }
  
  return result;
  }
Example #8
0
inline
void
subview_cube<eT>::operator%= (const Base<eT,T1>& in)
  {
  arma_extra_debug_sigprint();
  
  const unwrap<T1> tmp(in.get_ref());
  
  const Mat<eT>&          x = tmp.M;
        subview_cube<eT>& t = *this;
  
  arma_debug_assert_same_size(t, x, "cube schur product");
  
  for(u32 col = 0; col<t.n_cols; ++col)
    {
          eT* t_coldata = t.slice_colptr(t.aux_slice1, col);
    const eT* x_coldata = x.colptr(col);
    
    for(u32 row = 0; row<t.n_rows; ++row)
      {
      t_coldata[row] *= x_coldata[row];
      }
    }
  }
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);
      }
    }
  }
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
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 T1& x,
  const T2& y
  )
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT;
  
  const   Proxy<T1> pa(x);
  const SpProxy<T2> pb(y);
  
  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<eT> result(pa.get_n_rows(), pa.get_n_cols());
  
  // count new size
  uword new_n_nonzero = 0;
  
  typename SpProxy<T2>::const_iterator_type it     = pb.begin();
  typename SpProxy<T2>::const_iterator_type it_end = pb.end();
  
  while(it != it_end)
    {
    if( ((*it) * pa.at(it.row(), it.col())) != eT(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 != it_end)
    {
    const uword it2_row = it2.row();
    const uword it2_col = it2.col();
    
    const eT val = (*it2) * pa.at(it2_row, it2_col);
    
    if(val != eT(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;
  }
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;
  }
Example #13
0
inline
void
glue_mixed_plus::apply(Mat<typename eT_promoter<T1,T2>::eT>& out, const mtGlue<typename eT_promoter<T1,T2>::eT, T1, T2, glue_mixed_plus>& X)
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT1;
  typedef typename T2::elem_type eT2;
  
  typedef typename promote_type<eT1,eT2>::result out_eT;
  
  promote_type<eT1,eT2>::check();
  
  const Proxy<T1> A(X.A);
  const Proxy<T2> B(X.B);
  
  arma_debug_assert_same_size(A, B, "addition");
  
  const uword n_rows = A.get_n_rows();
  const uword n_cols = A.get_n_cols();
  
  out.set_size(n_rows, n_cols);
  
        out_eT* out_mem = out.memptr();
  const uword   n_elem  = out.n_elem;
    
  const bool prefer_at_accessor = (Proxy<T1>::prefer_at_accessor || Proxy<T2>::prefer_at_accessor);
  
  if(prefer_at_accessor == false)
    {
    typename Proxy<T1>::ea_type AA = A.get_ea();
    typename Proxy<T2>::ea_type BB = B.get_ea();
    
    if(memory::is_aligned(out_mem))
      {
      memory::mark_as_aligned(out_mem);
      
      for(uword i=0; i<n_elem; ++i)
        {
        out_mem[i] = upgrade_val<eT1,eT2>::apply(AA[i]) + upgrade_val<eT1,eT2>::apply(BB[i]);
        }
      }
    else
      {
      for(uword i=0; i<n_elem; ++i)
        {
        out_mem[i] = upgrade_val<eT1,eT2>::apply(AA[i]) + upgrade_val<eT1,eT2>::apply(BB[i]);
        }
      }
    }
  else
    {
    uword i = 0;
    
    for(uword col=0; col < n_cols; ++col)
    for(uword row=0; row < n_rows; ++row)
      {
      out_mem[i] = upgrade_val<eT1,eT2>::apply(A.at(row,col)) + upgrade_val<eT1,eT2>::apply(B.at(row,col));
      ++i;
      }
    }
  }
inline
void
running_stat_vec_aux::update_stats(running_stat_vec< std::complex<T> >& x, const Mat< std::complex<T> >& sample)
  {
  arma_extra_debug_sigprint();
  
  typedef typename std::complex<T> eT;
  
  const T N = x.counter.value();
  
  if(N > T(0))
    {
    arma_debug_assert_same_size(x.r_mean, sample, "running_stat_vec(): dimensionality mismatch");
    
    const u32 n_elem           = sample.n_elem;
    const eT* sample_mem       = sample.memptr();
          eT* r_mean_mem       = x.r_mean.memptr();
           T* r_var_mem        = x.r_var.memptr();
          eT* min_val_mem      = x.min_val.memptr();
          eT* max_val_mem      = x.max_val.memptr();
           T* min_val_norm_mem = x.min_val_norm.memptr();
           T* max_val_norm_mem = x.max_val_norm.memptr();
    
    const T  N_plus_1   = x.counter.value_plus_1();
    const T  N_minus_1  = x.counter.value_minus_1();
    
    if(x.calc_cov == true)
      {
      Mat<eT>& tmp1 = x.tmp1;
      Mat<eT>& tmp2 = x.tmp2;
      
      tmp1 = sample - x.r_mean;
      
      if(sample.n_cols == 1)
        {
        tmp2 = conj(tmp1)*trans(tmp1);
        }
      else
        {
        tmp2 = trans(conj(tmp1))*tmp1;
        }
      
      x.r_cov *= (N_minus_1/N);
      x.r_cov += tmp2 / N_plus_1;
      }
    
    
    for(u32 i=0; i<n_elem; ++i)
      {
      const eT& val      = sample_mem[i];
      const  T  val_norm = std::norm(val);
      
      if(val_norm < min_val_norm_mem[i])
        {
        min_val_norm_mem[i] = val_norm;
        min_val_mem[i]      = val;
        }
      
      if(val_norm > max_val_norm_mem[i])
        {
        max_val_norm_mem[i] = val_norm;
        max_val_mem[i]      = val;
        }
      
      const eT& r_mean_val = r_mean_mem[i];
      
      r_var_mem[i] = N_minus_1/N * r_var_mem[i] + std::norm(val - r_mean_val)/N_plus_1;
      
      r_mean_mem[i] = r_mean_val + (val - r_mean_val)/N_plus_1;
      }
    
    }
  else
    {
    arma_debug_check( (sample.is_vec() == false), "running_stat_vec(): given sample is not a vector");
    
    x.r_mean.set_size(sample.n_rows, sample.n_cols);
    
    x.r_var.zeros(sample.n_rows, sample.n_cols);
    
    if(x.calc_cov == true)
      {
      x.r_cov.zeros(sample.n_elem, sample.n_elem);
      }
    
    x.min_val.set_size(sample.n_rows, sample.n_cols);
    x.max_val.set_size(sample.n_rows, sample.n_cols);
    
    x.min_val_norm.set_size(sample.n_rows, sample.n_cols);
    x.max_val_norm.set_size(sample.n_rows, sample.n_cols);
    
    
    const u32 n_elem           = sample.n_elem;
    const eT* sample_mem       = sample.memptr();
          eT* r_mean_mem       = x.r_mean.memptr();
          eT* min_val_mem      = x.min_val.memptr();
          eT* max_val_mem      = x.max_val.memptr();
           T* min_val_norm_mem = x.min_val_norm.memptr();
           T* max_val_norm_mem = x.max_val_norm.memptr();
    
    for(u32 i=0; i<n_elem; ++i)
      {
      const eT& val      = sample_mem[i];
      const  T  val_norm = std::norm(val);
      
      r_mean_mem[i]  = val;
      min_val_mem[i] = val;
      max_val_mem[i] = val;
      
      min_val_norm_mem[i] = val_norm;
      max_val_norm_mem[i] = val_norm;
      }
    }
  
  x.counter++;
  }
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;
  }
Example #16
0
inline
bool
op_any::any_vec_helper
  (
  const mtGlue<uword, T1, T2, glue_type>& X,
  const typename arma_glue_rel_only<glue_type>::result       junk1,
  const typename arma_not_cx<typename T1::elem_type>::result junk2,
  const typename arma_not_cx<typename T2::elem_type>::result junk3
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk1);
  arma_ignore(junk2);
  arma_ignore(junk3);
  
  typedef typename T1::elem_type eT1;
  typedef typename T2::elem_type eT2;
  
  typedef typename Proxy<T1>::ea_type ea_type1;
  typedef typename Proxy<T2>::ea_type ea_type2;
  
  const Proxy<T1> A(X.A);
  const Proxy<T2> B(X.B);
  
  arma_debug_assert_same_size(A, B, "relational operator");
  
  const bool prefer_at_accessor = Proxy<T1>::prefer_at_accessor || Proxy<T2>::prefer_at_accessor;
  
  if(prefer_at_accessor == false)
    {
    ea_type1 PA = A.get_ea();
    ea_type2 PB = B.get_ea();
    
    const uword n_elem = A.get_n_elem();
    
    for(uword i=0; i<n_elem; ++i)
      {
      const eT1 tmp1 = PA[i];
      const eT2 tmp2 = PB[i];
      
           if(is_same_type<glue_type, glue_rel_lt    >::yes)  { if(tmp1 <  tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_gt    >::yes)  { if(tmp1 >  tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_lteq  >::yes)  { if(tmp1 <= tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_gteq  >::yes)  { if(tmp1 >= tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_eq    >::yes)  { if(tmp1 == tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_noteq >::yes)  { if(tmp1 != tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_and   >::yes)  { if(tmp1 && tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_or    >::yes)  { if(tmp1 || tmp2) { return true; } }
      }
    }
  else
    {
    const uword n_rows = A.get_n_rows();
    const uword n_cols = A.get_n_cols();
    
    for(uword col=0; col < n_cols; ++col)
    for(uword row=0; row < n_rows; ++row)
      {
      const eT1 tmp1 = A.at(row,col);
      const eT2 tmp2 = B.at(row,col);
      
           if(is_same_type<glue_type, glue_rel_lt    >::yes)  { if(tmp1 <  tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_gt    >::yes)  { if(tmp1 >  tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_lteq  >::yes)  { if(tmp1 <= tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_gteq  >::yes)  { if(tmp1 >= tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_eq    >::yes)  { if(tmp1 == tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_noteq >::yes)  { if(tmp1 != tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_and   >::yes)  { if(tmp1 && tmp2) { return true; } }
      else if(is_same_type<glue_type, glue_rel_or    >::yes)  { if(tmp1 || tmp2) { return true; } }
      }
    }
  
  return false;
  }
inline
void
subview_elem2<eT,T1,T2>::inplace_op(const Base<eT,expr>& x)
  {
  arma_extra_debug_sigprint();
  
  Mat<eT>& m_local = const_cast< Mat<eT>& >(m);
  
  const uword m_n_rows = m_local.n_rows;
  const uword m_n_cols = m_local.n_cols;
  
  const unwrap_check<expr> tmp(x.get_ref(), m_local);
  const Mat<eT>& X       = tmp.M;
  
  if( (all_rows == false) && (all_cols == false) )
    {
    const unwrap_check_mixed<T1> tmp1(base_ri.get_ref(), m_local);
    const unwrap_check_mixed<T2> tmp2(base_ci.get_ref(), m_local);
    
    const umat& ri = tmp1.M;
    const umat& ci = tmp2.M;
    
    arma_debug_check
      (
      ( ri.is_vec() == false ) || ( ci.is_vec() == false ),
      "Mat::elem(): given object is not a vector"
      );
    
    const uword* ri_mem    = ri.memptr();
    const uword  ri_n_elem = ri.n_elem;
    
    const uword* ci_mem    = ci.memptr();
    const uword  ci_n_elem = ci.n_elem;
    
    arma_debug_assert_same_size( ri_n_elem, ci_n_elem, X.n_rows, X.n_cols, "Mat::elem()" );
    
    for(uword ci_count=0; ci_count < ci_n_elem; ++ci_count)
      {
      const uword col = ci_mem[ci_count];
      
      arma_debug_check( (col > m_n_cols), "Mat::elem(): index out of bounds" );
      
      for(uword ri_count=0; ri_count < ri_n_elem; ++ri_count)
        {
        const uword row = ri_mem[ri_count];
        
        arma_debug_check( (row > m_n_rows), "Mat::elem(): index out of bounds" );
        
             if(is_same_type<op_type, op_subview_elem_equ          >::value == true) { m_local.at(row,col)  = X.at(ri_count, ci_count); }
        else if(is_same_type<op_type, op_subview_elem_inplace_plus >::value == true) { m_local.at(row,col) += X.at(ri_count, ci_count); }
        else if(is_same_type<op_type, op_subview_elem_inplace_minus>::value == true) { m_local.at(row,col) -= X.at(ri_count, ci_count); }
        else if(is_same_type<op_type, op_subview_elem_inplace_schur>::value == true) { m_local.at(row,col) *= X.at(ri_count, ci_count); }
        else if(is_same_type<op_type, op_subview_elem_inplace_div  >::value == true) { m_local.at(row,col) /= X.at(ri_count, ci_count); }
        }
      }
    }
  else
  if( (all_rows == true) && (all_cols == false) )
    {
    const unwrap_check_mixed<T2> tmp2(base_ci.get_ref(), m_local);
    
    const umat& ci = tmp2.M;
    
    arma_debug_check
      (
      ( ci.is_vec() == false ),
      "Mat::elem(): given object is not a vector"
      );
    
    const uword* ci_mem    = ci.memptr();
    const uword  ci_n_elem = ci.n_elem;
    
    arma_debug_assert_same_size( m_n_rows, ci_n_elem, X.n_rows, X.n_cols, "Mat::elem()" );
    
    for(uword ci_count=0; ci_count < ci_n_elem; ++ci_count)
      {
      const uword col = ci_mem[ci_count];
      
      arma_debug_check( (col > m_n_cols), "Mat::elem(): index out of bounds" );
      
            eT* m_colptr = m_local.colptr(col);
      const eT* X_colptr = X.colptr(ci_count);
      
           if(is_same_type<op_type, op_subview_elem_equ          >::value == true) { arrayops::copy         (m_colptr, X_colptr, m_n_rows); }
      else if(is_same_type<op_type, op_subview_elem_inplace_plus >::value == true) { arrayops::inplace_plus (m_colptr, X_colptr, m_n_rows); }
      else if(is_same_type<op_type, op_subview_elem_inplace_minus>::value == true) { arrayops::inplace_minus(m_colptr, X_colptr, m_n_rows); }
      else if(is_same_type<op_type, op_subview_elem_inplace_schur>::value == true) { arrayops::inplace_mul  (m_colptr, X_colptr, m_n_rows); }
      else if(is_same_type<op_type, op_subview_elem_inplace_div  >::value == true) { arrayops::inplace_div  (m_colptr, X_colptr, m_n_rows); }
      }
    }
  else
  if( (all_rows == false) && (all_cols == true) )
    {
    const unwrap_check_mixed<T1> tmp1(base_ri.get_ref(), m_local);
    
    const umat& ri = tmp1.M;
    
    arma_debug_check
      (
      ( ri.is_vec() == false ),
      "Mat::elem(): given object is not a vector"
      );
    
    const uword* ri_mem    = ri.memptr();
    const uword  ri_n_elem = ri.n_elem;
    
    arma_debug_assert_same_size( ri_n_elem, m_n_cols, X.n_rows, X.n_cols, "Mat::elem()" );
    
    for(uword col=0; col < m_n_cols; ++col)
      {
      for(uword ri_count=0; ri_count < ri_n_elem; ++ri_count)
        {
        const uword row = ri_mem[ri_count];
        
        arma_debug_check( (row > m_n_rows), "Mat::elem(): index out of bounds" );
      
             if(is_same_type<op_type, op_subview_elem_equ          >::value == true) { m_local.at(row,col)  = X.at(ri_count, col); }
        else if(is_same_type<op_type, op_subview_elem_inplace_plus >::value == true) { m_local.at(row,col) += X.at(ri_count, col); }
        else if(is_same_type<op_type, op_subview_elem_inplace_minus>::value == true) { m_local.at(row,col) -= X.at(ri_count, col); }
        else if(is_same_type<op_type, op_subview_elem_inplace_schur>::value == true) { m_local.at(row,col) *= X.at(ri_count, col); }
        else if(is_same_type<op_type, op_subview_elem_inplace_div  >::value == true) { m_local.at(row,col) /= X.at(ri_count, col); }
        }
      }
    }
  }
inline
void
running_stat_vec_aux::update_stats
  (
  running_stat_vec<obj_type>& x,
  const                  Mat<typename running_stat_vec<obj_type>::eT>& sample,
  const typename arma_not_cx<typename running_stat_vec<obj_type>::eT>::result* junk
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  typedef typename running_stat_vec<obj_type>::eT eT;
  typedef typename running_stat_vec<obj_type>::T   T;
  
  const T N = x.counter.value();
  
  if(N > T(0))
    {
    arma_debug_assert_same_size(x.r_mean, sample, "running_stat_vec(): dimensionality mismatch");
    
    const uword n_elem      = sample.n_elem;
    const eT*   sample_mem  = sample.memptr();
          eT*   r_mean_mem  = x.r_mean.memptr();
           T*   r_var_mem   = x.r_var.memptr();
          eT*   min_val_mem = x.min_val.memptr();
          eT*   max_val_mem = x.max_val.memptr();
    
    const T  N_plus_1   = x.counter.value_plus_1();
    const T  N_minus_1  = x.counter.value_minus_1();
    
    if(x.calc_cov == true)
      {
      Mat<eT>& tmp1 = x.tmp1;
      Mat<eT>& tmp2 = x.tmp2;
      
      tmp1 = sample - x.r_mean;
      
      if(sample.n_cols == 1)
        {
        tmp2 = tmp1*trans(tmp1);
        }
      else
        {
        tmp2 = trans(tmp1)*tmp1;
        }
      
      x.r_cov *= (N_minus_1/N);
      x.r_cov += tmp2 / N_plus_1;
      }
    
    
    for(uword i=0; i<n_elem; ++i)
      {
      const eT val = sample_mem[i];
      
      if(val < min_val_mem[i])
        {
        min_val_mem[i] = val;
        }
      
      if(val > max_val_mem[i])
        {
        max_val_mem[i] = val;
        }
        
      const eT r_mean_val = r_mean_mem[i];
      const eT tmp        = val - r_mean_val;
    
      r_var_mem[i] = N_minus_1/N * r_var_mem[i] + (tmp*tmp)/N_plus_1;
      
      r_mean_mem[i] = r_mean_val + (val - r_mean_val)/N_plus_1;
      }
    }
  else
    {
    arma_debug_check( (sample.is_vec() == false), "running_stat_vec(): given sample is not a vector");
    
    x.r_mean.set_size(sample.n_rows, sample.n_cols);
    
    x.r_var.zeros(sample.n_rows, sample.n_cols);
    
    if(x.calc_cov == true)
      {
      x.r_cov.zeros(sample.n_elem, sample.n_elem);
      }
    
    x.min_val.set_size(sample.n_rows, sample.n_cols);
    x.max_val.set_size(sample.n_rows, sample.n_cols);
    
    
    const uword n_elem      = sample.n_elem;
    const eT*   sample_mem  = sample.memptr();
          eT*   r_mean_mem  = x.r_mean.memptr();
          eT*   min_val_mem = x.min_val.memptr();
          eT*   max_val_mem = x.max_val.memptr();
          
    
    for(uword i=0; i<n_elem; ++i)
      {
      const eT val = sample_mem[i];
      
       r_mean_mem[i] = val;
      min_val_mem[i] = val;
      max_val_mem[i] = val;
      }
    }
  
  x.counter++;
  }
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_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];
    }
  }
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;
  }