Example #1
0
inline
void
op_trimat::apply_htrans
  (
        Mat<eT>& out,
  const Mat<eT>& A,
  const bool     upper,
  const typename arma_cx_only<eT>::result* junk
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  arma_debug_check( (A.is_square() == false), "trimatu()/trimatl(): given matrix must be square sized" );
  
  const uword N = A.n_rows;
  
  if(&out != &A)
    {
    out.copy_size(A);
    }
  
  if(upper)
    {
    // Upper triangular: but since we're transposing, we're taking the lower
    // triangular and putting it in the upper half.
    for(uword row = 0; row < N; ++row)
      {
      eT* out_colptr = out.colptr(row);
      
      for(uword col = 0; col <= row; ++col)
        {
        //out.at(col, row) = std::conj( A.at(row, col) );
        out_colptr[col] = std::conj( A.at(row, col) );
        }
      }
    }
  else
    {
    // Lower triangular: but since we're transposing, we're taking the upper
    // triangular and putting it in the lower half.
    for(uword row = 0; row < N; ++row)
      {
      for(uword col = row; col < N; ++col)
        {
        out.at(col, row) = std::conj( A.at(row, col) );
        }
      }
    }
  
  op_trimat::fill_zeros(out, upper);
  }
Example #2
0
inline
void
op_var::apply(Mat< typename get_pod_type<eT>::result >& out, const Mat<eT>& X, const u32 norm_type, const u32 dim)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_check( (X.n_elem == 0), "var(): given matrix has no elements" );
  
  arma_debug_check( (norm_type > 1), "var(): incorrect usage. norm_type must be 0 or 1");
  arma_debug_check( (dim > 1),       "var(): incorrect usage. dim must be 0 or 1"      );
  
  
  if(dim == 0)
    {
    arma_extra_debug_print("op_var::apply(), dim = 0");
    
    out.set_size(1, X.n_cols);
    
    for(u32 col=0; col<X.n_cols; ++col)
      {
      out[col] = op_var::direct_var( X.colptr(col), X.n_rows, norm_type );
      }
    }
  else
  if(dim == 1)
    {
    arma_extra_debug_print("op_var::apply(), dim = 1");
    
    const u32 n_rows = X.n_rows;
    const u32 n_cols = X.n_cols;
    
    out.set_size(n_rows, 1);
    
    podarray<eT> tmp(n_cols);
    
    eT* tmp_mem = tmp.memptr();
    
    for(u32 row=0; row<n_rows; ++row)
      {
      for(u32 col=0; col<n_cols; ++col)
        {
        tmp_mem[col] = X.at(row,col);
        }
      
      out[row] = op_var::direct_var(tmp_mem, n_cols, norm_type);
      }
    
    }
  
  }
Example #3
0
inline
void
op_prod::apply_noalias(Mat<eT>& out, const Mat<eT>& X, const uword dim)
  {
  arma_extra_debug_sigprint();
  
  const uword X_n_rows = X.n_rows;
  const uword X_n_cols = X.n_cols;
    
  if(dim == 0)  // traverse across rows (i.e. find the product in each column)
    {
    out.set_size(1, X_n_cols);
    
    eT* out_mem = out.memptr();
    
    for(uword col=0; col < X_n_cols; ++col)
      {
      out_mem[col] = arrayops::product(X.colptr(col), X_n_rows);
      }
    }
  else  // traverse across columns (i.e. find the product in each row)
    {
    out.ones(X_n_rows, 1);
    
    eT* out_mem = out.memptr();
    
    for(uword col=0; col < X_n_cols; ++col)
      {
      const eT* X_col_mem = X.colptr(col);
      
      for(uword row=0; row < X_n_rows; ++row)
        {
        out_mem[row] *= X_col_mem[row];
        }
      }
    }
  }
arma_hot
inline
void
op_strans::apply(Mat<eT>& out, const TA& A)
  {
  arma_extra_debug_sigprint();
  
  if(&out != &A)
    {
    op_strans::apply_noalias(out, A);
    }
  else
    {
    const uword n_rows = A.n_rows;
    const uword n_cols = A.n_cols;
    
    if(n_rows == n_cols)
      {
      arma_extra_debug_print("op_strans::apply(): doing in-place transpose of a square matrix");
      
      const uword N = n_rows;
      
      for(uword k=0; k < N; ++k)
        {
        eT* colptr = out.colptr(k);
        
        uword i,j;
        
        for(i=(k+1), j=(k+2); j < N; i+=2, j+=2)
          {
          std::swap(out.at(k,i), colptr[i]);
          std::swap(out.at(k,j), colptr[j]);
          }
        
        if(i < N)
          {
          std::swap(out.at(k,i), colptr[i]);
          }
        }
      }
    else
      {
      Mat<eT> tmp;
      op_strans::apply_noalias(tmp, A);
      
      out.steal_mem(tmp);
      }
    }
  }
Example #5
0
 arma_hot
 inline
 static
 void
 apply
   (
         Mat<eT>& C,
   const TA&      A,
   const TB&      B,
   const eT       alpha = eT(1),
   const eT       beta  = eT(0)
   )
   {
   arma_extra_debug_sigprint();
   
   switch(A.n_rows)
     {
     case  4:  gemv_emul_tinysq<do_trans_A, use_alpha, use_beta>::apply( C.colptr(3), A, B.colptr(3), alpha, beta );
     case  3:  gemv_emul_tinysq<do_trans_A, use_alpha, use_beta>::apply( C.colptr(2), A, B.colptr(2), alpha, beta );
     case  2:  gemv_emul_tinysq<do_trans_A, use_alpha, use_beta>::apply( C.colptr(1), A, B.colptr(1), alpha, beta );
     case  1:  gemv_emul_tinysq<do_trans_A, use_alpha, use_beta>::apply( C.colptr(0), A, B.colptr(0), alpha, beta );
     default:  ;
     }
   }
inline
void
subview_cube<eT>::schur_inplace(Mat<eT>& out, const subview_cube<eT>& in)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_assert_same_size(out, in, "matrix schur product");
  
  const u32 in_n_rows     = in.n_rows;
  const u32 in_n_cols     = in.n_cols;
  const u32 in_aux_slice1 = in.aux_slice1;
  
  for(u32 col = 0; col < in_n_cols; ++col)
    {
    arrayops::inplace_mul( out.colptr(col), in.slice_colptr(in_aux_slice1, col), in_n_rows );
    }
  }
inline
void
subview_cube<eT>::div_inplace(Mat<eT>& out, const subview_cube<eT>& in)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_assert_same_size(out, in, "matrix element-wise division");
  
  const u32 in_n_rows     = in.n_rows;
  const u32 in_n_cols     = in.n_cols;
  const u32 in_aux_slice1 = in.aux_slice1;
  
  for(u32 col = 0; col < in_n_cols; ++col)
    {
    arrayops::inplace_div( out.colptr(col), in.slice_colptr(in_aux_slice1, col), in_n_rows );
    }
  }
inline
void
op_htrans::apply(Mat< std::complex<T> >& out, const Mat< std::complex<T> >& A)
  {
  arma_extra_debug_sigprint();
  
  typedef typename std::complex<T> eT;

  if(&out != &A)
    {
    op_htrans::apply_noalias(out, A);
    }
  else
    {
    if(out.n_rows == out.n_cols)
      {
      arma_extra_debug_print("doing in-place hermitian transpose of a square matrix");
      
      const u32 n_rows = out.n_rows;
      const u32 n_cols = out.n_cols;
      
      for(u32 col=0; col<n_cols; ++col)
        {
        eT* coldata = out.colptr(col);
        
        out.at(col,col) = std::conj( out.at(col,col) );
        
        for(u32 row=(col+1); row<n_rows; ++row)
          {
          const eT val1 = std::conj(coldata[row]);
          const eT val2 = std::conj(out.at(col,row));
          
          out.at(col,row) = val1;
          coldata[row]    = val2;
          }
        }
      }
    else
      {
      const Mat<eT> A_copy = A;
      op_htrans::apply_noalias(out, A_copy);
      }
    }
  
  }
Example #9
0
static inline void pwhichmax_core(Mat<double> posteriors, Vec<int> clusters, int nthreads){
	int ncol = posteriors.ncol;
	int nrow = posteriors.nrow;
	#pragma omp parallel for num_threads(nthreads)
	for (int col = 0; col < ncol; ++col){
		double* postCol = posteriors.colptr(col);
		double max = *postCol;
		int whichmax = 1;
		for (int row = 1; row < nrow; ++row){
			++postCol;
			if (*postCol > max){
				max = *postCol;
				whichmax = row + 1;
			}
		}
		clusters[col] = whichmax;
	}
}
inline
void
subview_cube<eT>::extract(Mat<eT>& out, const subview_cube<eT>& in)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_check( (in.n_slices != 1), "subview_cube::extract(): given subcube doesn't have exactly one slice" );
  
  const u32 n_rows     = in.n_rows;
  const u32 n_cols     = in.n_cols;
  const u32 aux_slice1 = in.aux_slice1;
  
  out.set_size(n_rows, n_cols);
  
  for(u32 col = 0; col < n_cols; ++col)
    {
    syslib::copy_elem( out.colptr(col), in.slice_colptr(aux_slice1, col), n_rows );
    }
  }
Example #11
0
inline
void
op_min::apply_noalias(Mat<eT>& out, const Mat<eT>& X, const uword dim, const typename arma_cx_only<eT>::result* junk)
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  const uword X_n_rows = X.n_rows;
  const uword X_n_cols = X.n_cols;
  
  if(dim == 0)
    {
    arma_extra_debug_print("op_min::apply(): dim = 0");
    
    out.set_size((X_n_rows > 0) ? 1 : 0, X_n_cols);
    
    if(X_n_rows == 0)  { return; }
    
    eT* out_mem = out.memptr();
    
    for(uword col=0; col<X_n_cols; ++col)
      {
      out_mem[col] = op_min::direct_min( X.colptr(col), X_n_rows );
      }
    }
  else
  if(dim == 1)
    {
    arma_extra_debug_print("op_min::apply(): dim = 1");
    
    out.set_size(X_n_rows, (X_n_cols > 0) ? 1 : 0);
    
    if(X_n_cols == 0)  { return; }
    
    eT* out_mem = out.memptr();
    
    for(uword row=0; row<X_n_rows; ++row)
      {
      out_mem[row] = op_min::direct_min( X, row );
      }
    }
  }
Example #12
0
inline
void
subview_cube<eT>::div_inplace(Mat<eT>& out, const subview_cube<eT>& in)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_assert_same_size(out, in, "matrix element-wise division");
  
  for(u32 col = 0; col < in.n_cols; ++col)
    {
    const eT* in_coldata  = in.slice_colptr(in.aux_slice1, col);
          eT* out_coldata = out.colptr(col);
    
    for(u32 row = 0; row < in.n_rows; ++row)
      {
      out_coldata[row] /= in_coldata[row];
      }
    }
    
  }
Example #13
0
inline
void
subview_cube<eT>::extract(Mat<eT>& out, const subview_cube<eT>& in)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_check( (in.n_slices != 1), "subview_cube::extract(): given subcube doesn't have exactly one slice" );
  
  out.set_size(in.n_rows, in.n_cols);
  
  for(u32 col = 0; col < in.n_cols; ++col)
    {
    const eT* in_coldata  = in.slice_colptr(in.aux_slice1, col);
          eT* out_coldata = out.colptr(col);
    
    for(u32 row = 0; row < in.n_rows; ++row)
      {
      out_coldata[row] = in_coldata[row];
      }
    }
  }
Example #14
0
inline
void
op_fliplr::apply_proxy_noalias(Mat<typename T1::elem_type>& out, const Proxy<T1>& P)
  {
  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();
  
  const uword P_n_cols_m1 = P_n_cols - 1;
  
  out.set_size(P_n_rows, P_n_cols);
  
  if( ((T1::is_row) || (P_n_rows == 1)) && (Proxy<T1>::use_at == false) )
    {
    eT* out_mem = out.memptr();
    
    const typename Proxy<T1>::ea_type P_ea = P.get_ea();
    
    for(uword col=0; col < P_n_cols; ++col)
      {
      out_mem[P_n_cols_m1 - col] = P_ea[col];
      }
    }
  else
    {
    for(uword col=0; col < P_n_cols; ++col)
      {
      eT* out_colmem = out.colptr(P_n_cols_m1 - col);
      
      for(uword row=0; row < P_n_rows; ++row)
        {
        out_colmem[row] = P.at(row,col);
        }
      }
    }
  }
Example #15
0
inline
void
glue_toeplitz::apply(Mat<typename T1::elem_type>& out, const Glue<T1, T2, glue_toeplitz>& in)
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT;
  
  if( ((void*)(&in.A)) == ((void*)(&in.B)) )
    {
    arma_extra_debug_print("glue_toeplitz::apply(): one argument version");
    
    const unwrap_check<T1>  tmp(in.A, out);
    const Mat<eT>& A      = tmp.M;
    
    arma_debug_check( (A.is_vec() == false), "toeplitz(): input argument must be a vector" );
    
    const u32 N     = A.n_elem;
    const eT* A_mem = A.memptr();
    
    out.set_size(N,N);
    
    for(u32 col=0; col<N; ++col)
      {
      eT* col_mem = out.colptr(col);
      
      u32 i;
      
      i = col;
      for(u32 row=0; row<col; ++row, --i)
        {
        col_mem[row] = A_mem[i];
        }
      
      i = 0;
      for(u32 row=col; row<N; ++row, ++i)
        {
        col_mem[row] = A_mem[i];
        }      
      }
    }
  else
    {
    arma_extra_debug_print("glue_toeplitz::apply(): two argument version");
    
    const unwrap_check<T1> tmp1(in.A, out);
    const unwrap_check<T2> tmp2(in.B, out);
    
    const Mat<eT>& A = tmp1.M;
    const Mat<eT>& B = tmp2.M;
    
    arma_debug_check( ( (A.is_vec() == false) || (B.is_vec() == false) ), "toeplitz(): input arguments must be vectors" );
    
    const u32 A_N = A.n_elem;
    const u32 B_N = B.n_elem;
    
    const eT* A_mem = A.memptr();
    const eT* B_mem = B.memptr();
    
    out.set_size(A_N, B_N);
    
    for(u32 col=0; col<B_N; ++col)
      {
      eT* col_mem = out.colptr(col);
      
      u32 i = 0;
      for(u32 row=col; row<A_N; ++row, ++i)
        {
        col_mem[row] = A_mem[i];
        }
      }
    
    for(u32 row=0; row<A_N; ++row)
      {
      u32 i = 1;
      for(u32 col=(row+1); col<B_N; ++col, ++i)
        {
        out.at(row,col) = B_mem[i];
        }
      }
    
    }
  
  
  }
inline
void
subview_cube<eT>::div_inplace(Mat<eT>& out, const subview_cube<eT>& in)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_assert_cube_as_mat(out, in, "element-wise division", true);
  
  const uword in_n_rows   = in.n_rows;
  const uword in_n_cols   = in.n_cols;
  const uword in_n_slices = in.n_slices;
  
  const uword out_n_rows    = out.n_rows;
  const uword out_n_cols    = out.n_cols;
  const uword out_vec_state = out.vec_state;
  
  if(in_n_slices == 1)
    {
    for(uword col=0; col < in_n_cols; ++col)
      {
      arrayops::inplace_div( out.colptr(col), in.slice_colptr(0, col), in_n_rows );
      }
    }
  else
    {
    if(out_vec_state == 0)
      {
      if( (in_n_rows == out_n_rows) && (in_n_cols == 1) && (in_n_slices == out_n_cols) )
        {
        for(uword i=0; i < in_n_slices; ++i)
          {
          arrayops::inplace_div( out.colptr(i), in.slice_colptr(i, 0), in_n_rows );
          }
        }
      else
      if( (in_n_rows == 1) && (in_n_cols == out_n_rows) && (in_n_slices == out_n_cols) )
        {
        const Cube<eT>& Q = in.m;
        
        const uword in_aux_row1   = in.aux_row1;
        const uword in_aux_col1   = in.aux_col1;
        const uword in_aux_slice1 = in.aux_slice1;
        
        for(uword slice=0; slice < in_n_slices; ++slice)
          {
          const uword mod_slice = in_aux_slice1 + slice;
          
          eT* out_colptr = out.colptr(slice);
          
          uword i,j;
          for(i=0, j=1; j < in_n_cols; i+=2, j+=2)
            {
            const eT tmp_i = Q.at(in_aux_row1, in_aux_col1 + i, mod_slice);
            const eT tmp_j = Q.at(in_aux_row1, in_aux_col1 + j, mod_slice);
            
            out_colptr[i] /= tmp_i;
            out_colptr[j] /= tmp_j;
            }
          
          if(i < in_n_cols)
            {
            out_colptr[i] /= Q.at(in_aux_row1, in_aux_col1 + i, mod_slice);
            }
          }
        }
      }
    else
      {
      eT* out_mem = out.memptr();
      
      const Cube<eT>& Q = in.m;
      
      const uword in_aux_row1   = in.aux_row1;
      const uword in_aux_col1   = in.aux_col1;
      const uword in_aux_slice1 = in.aux_slice1;
      
      for(uword i=0; i<in_n_slices; ++i)
        {
        out_mem[i] /= Q.at(in_aux_row1, in_aux_col1, in_aux_slice1 + i);
        }
      }
    }
  }
inline
void
subview_cube<eT>::extract(Mat<eT>& out, const subview_cube<eT>& in)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_assert_cube_as_mat(out, in, "copy into matrix", false);
  
  const uword in_n_rows   = in.n_rows;
  const uword in_n_cols   = in.n_cols;
  const uword in_n_slices = in.n_slices;
  
  const uword out_vec_state = out.vec_state;
  
  if(in_n_slices == 1)
    {
    out.set_size(in_n_rows, in_n_cols);
    
    for(uword col=0; col < in_n_cols; ++col)
      {
      arrayops::copy( out.colptr(col), in.slice_colptr(0, col), in_n_rows );
      }
    }
  else
    {
    if(out_vec_state == 0)
      {
      if(in_n_cols == 1)
        {
        out.set_size(in_n_rows, in_n_slices);
        
        for(uword i=0; i < in_n_slices; ++i)
          {
          arrayops::copy( out.colptr(i), in.slice_colptr(i, 0), in_n_rows );
          }
        }
      else
      if(in_n_rows == 1)
        {
        const Cube<eT>& Q = in.m;
        
        const uword in_aux_row1   = in.aux_row1;
        const uword in_aux_col1   = in.aux_col1;
        const uword in_aux_slice1 = in.aux_slice1;
        
        out.set_size(in_n_cols, in_n_slices);
        
        for(uword slice=0; slice < in_n_slices; ++slice)
          {
          const uword mod_slice = in_aux_slice1 + slice;
          
          eT* out_colptr = out.colptr(slice);
          
          uword i,j;
          for(i=0, j=1; j < in_n_cols; i+=2, j+=2)
            {
            const eT tmp_i = Q.at(in_aux_row1, in_aux_col1 + i, mod_slice);
            const eT tmp_j = Q.at(in_aux_row1, in_aux_col1 + j, mod_slice);
            
            out_colptr[i] = tmp_i;
            out_colptr[j] = tmp_j;
            }
          
          if(i < in_n_cols)
            {
            out_colptr[i] = Q.at(in_aux_row1, in_aux_col1 + i, mod_slice);
            }
          }
        }
      }
    else
      {
      out.set_size(in_n_slices);
      
      eT* out_mem = out.memptr();
      
      const Cube<eT>& Q = in.m;
      
      const uword in_aux_row1   = in.aux_row1;
      const uword in_aux_col1   = in.aux_col1;
      const uword in_aux_slice1 = in.aux_slice1;
      
      for(uword i=0; i<in_n_slices; ++i)
        {
        out_mem[i] = Q.at(in_aux_row1, in_aux_col1, in_aux_slice1 + i);
        }
      }
    }
  }
Example #18
0
inline
void
op_trimat::apply_htrans
  (
        Mat<eT>& out,
  const Mat<eT>& A,
  const bool     upper,
  const typename arma_not_cx<eT>::result* junk
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  // This specialisation is for trimatl(trans(X)) = trans(trimatu(X)) and also
  // trimatu(trans(X)) = trans(trimatl(X)).  We want to avoid the creation of an
  // extra temporary.
  
  // It doesn't matter if the input and output matrices are the same; we will
  // pull data from the upper or lower triangular to the lower or upper
  // triangular (respectively) and then set the rest to 0, so overwriting issues
  // aren't present.
  
  arma_debug_check( (A.is_square() == false), "trimatu()/trimatl(): given matrix must be square sized" );
  
  const uword N = A.n_rows;
  
  if(&out != &A)
    {
    out.copy_size(A);
    }
  
  // We can't really get away with any array copy operations here,
  // unfortunately...
  
  if(upper)
    {
    // Upper triangular: but since we're transposing, we're taking the lower
    // triangular and putting it in the upper half.
    for(uword row = 0; row < N; ++row)
      {
      eT* out_colptr = out.colptr(row);
      
      for(uword col = 0; col <= row; ++col)
        {
        //out.at(col, row) = A.at(row, col);
        out_colptr[col] = A.at(row, col);
        }
      }
    }
  else
    {
    // Lower triangular: but since we're transposing, we're taking the upper
    // triangular and putting it in the lower half.
    for(uword row = 0; row < N; ++row)
      {
      for(uword col = row; col < N; ++col)
        {
        out.at(col, row) = A.at(row, col);
        }
      }
    }
  
  op_trimat::fill_zeros(out, upper);
  }
inline
void
op_fft_cx::apply_noalias(Mat<typename T1::elem_type>& out, const Proxy<T1>& P, const uword a, const uword b)
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT;
  
  const uword n_rows = P.get_n_rows();
  const uword n_cols = P.get_n_cols();
  const uword n_elem = P.get_n_elem();
  
  const bool is_vec = ( (n_rows == 1) || (n_cols == 1) );
  
  const uword N_orig = (is_vec) ? n_elem : n_rows;
  const uword N_user = (b == 0) ? a      : N_orig;
  
  fft_engine<eT,inverse> worker(N_user);
  
  if(is_vec)
    {
    (n_cols == 1) ? out.set_size(N_user, 1) : out.set_size(1, N_user);
    
    if( (out.n_elem == 0) || (N_orig == 0) )
      {
      out.zeros();
      return;
      }
    
    if( (N_user == 1) && (N_orig >= 1) )
      {
      out[0] = P[0];
      return;
      }
    
    if( (N_user > N_orig) || (is_Mat<typename Proxy<T1>::stored_type>::value == false) )
      {
      podarray<eT> data(N_user);
      
      eT* data_mem = data.memptr();
      
      if(N_user > N_orig)  { arrayops::fill_zeros( &data_mem[N_orig], (N_user - N_orig) ); }
      
      op_fft_cx::copy_vec( data_mem, P, (std::min)(N_user, N_orig) );
      
      worker.run( out.memptr(), data_mem );
      }
    else
      {
      const unwrap< typename Proxy<T1>::stored_type > tmp(P.Q);
      
      worker.run( out.memptr(), tmp.M.memptr() );
      }
    }
  else
    {
    // process each column seperately
    
    out.set_size(N_user, n_cols);
    
    if( (out.n_elem == 0) || (N_orig == 0) )
      {
      out.zeros();
      return;
      }
    
    if( (N_user == 1) && (N_orig >= 1) )
      {
      for(uword col=0; col < n_cols; ++col)  { out.at(0,col) = P.at(0,col); }
      
      return;
      }
    
    if( (N_user > N_orig) || (is_Mat<typename Proxy<T1>::stored_type>::value == false) )
      {
      podarray<eT> data(N_user);
      
      eT* data_mem = data.memptr();
      
      if(N_user > N_orig)  { arrayops::fill_zeros( &data_mem[N_orig], (N_user - N_orig) ); }
      
      const uword N = (std::min)(N_user, N_orig);
      
      for(uword col=0; col < n_cols; ++col)
        {
        for(uword i=0; i < N; ++i)  { data_mem[i] = P.at(i, col); }
        
        worker.run( out.colptr(col), data_mem );
        }
      }
    else
      {
      const unwrap< typename Proxy<T1>::stored_type > tmp(P.Q);
      
      for(uword col=0; col < n_cols; ++col)
        {
        worker.run( out.colptr(col), tmp.M.colptr(col) );
        }
      }
    }
    
  
  // correct the scaling for the inverse transform
  if(inverse == true)
    {
    typedef typename get_pod_type<eT>::result T;
    
    const T k = T(1) / T(N_user);
    
    eT* out_mem = out.memptr();
    
    const uword out_n_elem = out.n_elem;
    
    for(uword i=0; i < out_n_elem; ++i)  { out_mem[i] *= k; }
    }
  }
inline
void
op_fft_real::apply( Mat< std::complex<typename T1::pod_type> >& out, const mtOp<std::complex<typename T1::pod_type>,T1,op_fft_real>& in )
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::pod_type         in_eT;
  typedef typename std::complex<in_eT> out_eT;
  
  const Proxy<T1> P(in.m);
  
  const uword n_rows = P.get_n_rows();
  const uword n_cols = P.get_n_cols();
  const uword n_elem = P.get_n_elem();
  
  const bool is_vec = ( (n_rows == 1) || (n_cols == 1) );
  
  const uword N_orig = (is_vec)              ? n_elem         : n_rows;
  const uword N_user = (in.aux_uword_b == 0) ? in.aux_uword_a : N_orig;
  
  fft_engine<out_eT,false> worker(N_user);
  
  // no need to worry about aliasing, as we're going from a real object to complex complex, which by definition cannot alias
  
  if(is_vec)
    {
    (n_cols == 1) ? out.set_size(N_user, 1) : out.set_size(1, N_user);
    
    if( (out.n_elem == 0) || (N_orig == 0) )
      {
      out.zeros();
      return;
      }
    
    if( (N_user == 1) && (N_orig >= 1) )
      {
      out[0] = out_eT( P[0] );
      return;
      }
    
    podarray<out_eT> data(N_user);
    
    out_eT* data_mem = data.memptr();
    
    if(N_user > N_orig)  { arrayops::fill_zeros( &data_mem[N_orig], (N_user - N_orig) ); }
    
    const uword N = (std::min)(N_user, N_orig);
    
    if(Proxy<T1>::use_at == false)
      {
      typename Proxy<T1>::ea_type X = P.get_ea();
      
      for(uword i=0; i < N; ++i)  { data_mem[i] = out_eT( X[i], in_eT(0) ); }
      }
    else
      {
      if(n_cols == 1)
        {
        for(uword i=0; i < N; ++i)  { data_mem[i] = out_eT( P.at(i,0), in_eT(0) ); }
        }
      else
        {
        for(uword i=0; i < N; ++i)  { data_mem[i] = out_eT( P.at(0,i), in_eT(0) ); }
        }
      }
    
    worker.run( out.memptr(), data_mem );
    }
  else
    {
    // process each column seperately
    
    out.set_size(N_user, n_cols);
    
    if( (out.n_elem == 0) || (N_orig == 0) )
      {
      out.zeros();
      return;
      }
    
    if( (N_user == 1) && (N_orig >= 1) )
      {
      for(uword col=0; col < n_cols; ++col)  { out.at(0,col) = out_eT( P.at(0,col) ); }
      
      return;
      }
    
    podarray<out_eT> data(N_user);
    
    out_eT* data_mem = data.memptr();
    
    if(N_user > N_orig)  { arrayops::fill_zeros( &data_mem[N_orig], (N_user - N_orig) ); }
    
    const uword N = (std::min)(N_user, N_orig);
    
    for(uword col=0; col < n_cols; ++col)
      {
      for(uword i=0; i < N; ++i)  { data_mem[i] = P.at(i, col); }
      
      worker.run( out.colptr(col), data_mem );
      }
    }
  }
inline
void
op_symmat::apply
  (
        Mat<typename T1::elem_type>& out,
  const Op<T1,op_symmat>&            in,
  const typename arma_not_cx<typename T1::elem_type>::result* junk
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  typedef typename T1::elem_type eT;
  
  const unwrap<T1> tmp(in.m);
  const Mat<eT>& A = tmp.M;
  
  arma_debug_check( (A.is_square() == false), "symmatu()/symmatl(): given matrix must be square" );
  
  const u32  N     = A.n_rows;
  const bool upper = (in.aux_u32_a == 0);
  
  if(&out != &A)
    {
    out.copy_size(A);
    
    if(upper)
      {
      // upper triangular: copy the diagonal and the elements above the diagonal
      
      for(u32 i=0; i<N; ++i)
        {
        const eT* A_data   = A.colptr(i);
              eT* out_data = out.colptr(i);
        
        arrayops::copy( out_data, A_data, i+1 );
        }
      }
    else
      {
      // lower triangular: copy the diagonal and the elements below the diagonal
      
      for(u32 i=0; i<N; ++i)
        {
        const eT* A_data   = A.colptr(i);
              eT* out_data = out.colptr(i);
        
        arrayops::copy( &out_data[i], &A_data[i], N-i );
        }
      }
    }
  
  
  if(upper)
    {
    // reflect elements across the diagonal from upper triangle to lower triangle
    
    for(u32 col=1; col < N; ++col)
      {
      const eT* coldata = out.colptr(col);
      
      for(u32 row=0; row < col; ++row)
        {
        out.at(col,row) = coldata[row];
        }
      }
    }
  else
    {
    // reflect elements across the diagonal from lower triangle to upper triangle
    
    for(u32 col=0; col < N; ++col)
      {
      const eT* coldata = out.colptr(col);
      
      for(u32 row=(col+1); row < N; ++row)
        {
        out.at(col,row) = coldata[row];
        }
      }
    }
  }
inline
void
op_cumprod::apply_noalias(Mat<eT>& out, const Mat<eT>& X, const uword dim)
  {
  arma_extra_debug_sigprint();
  
  uword n_rows = X.n_rows;
  uword n_cols = X.n_cols;
  
  out.set_size(n_rows,n_cols);
  
  if(out.n_elem == 0)  { return; }
  
  if(dim == 0)
    {
    if(n_cols == 1)
      {
      const eT*   X_mem =   X.memptr();
            eT* out_mem = out.memptr();
      
      eT acc = eT(1);
      
      for(uword row=0; row < n_rows; ++row)
        {
        acc *= X_mem[row];
        
        out_mem[row] = acc;
        }
      }
    else
      {
      for(uword col=0; col < n_cols; ++col)
        {
        const eT*   X_colmem =   X.colptr(col);
              eT* out_colmem = out.colptr(col);
        
        eT acc = eT(1);
        
        for(uword row=0; row < n_rows; ++row)
          {
          acc *= X_colmem[row];
          
          out_colmem[row] = acc;
          }
        }
      }
    }
  else
  if(dim == 1)
    {
    if(n_rows == 1)
      {
      const eT*   X_mem =   X.memptr();
            eT* out_mem = out.memptr();
      
      eT acc = eT(1);
      
      for(uword col=0; col < n_cols; ++col)
        {
        acc *= X_mem[col];
        
        out_mem[col] = acc;
        }
      }
    else
      {
      if(n_cols > 0)
        {
        arrayops::copy( out.colptr(0), X.colptr(0), n_rows );
        
        for(uword col=1; col < n_cols; ++col)
          {
          const eT* out_colmem_prev = out.colptr(col-1);
                eT* out_colmem      = out.colptr(col  );
          const eT*   X_colmem      =   X.colptr(col  );
          
          for(uword row=0; row < n_rows; ++row)
            {
            out_colmem[row] = out_colmem_prev[row] * X_colmem[row];
            }
          }
        }
      }
    }
  }
inline
void
op_symmat_cx::apply(Mat<typename T1::elem_type>& out, const Op<T1,op_symmat_cx>& in)
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT;
  
  const unwrap<T1>   tmp(in.m);
  const Mat<eT>& A = tmp.M;
  
  arma_debug_check( (A.is_square() == false), "symmatu()/symmatl(): given matrix must be square sized" );
  
  const uword N  = A.n_rows;
  
  const bool upper   = (in.aux_uword_a == 0);
  const bool do_conj = (in.aux_uword_b == 1);
  
  if(&out != &A)
    {
    out.copy_size(A);
    
    if(upper)
      {
      // upper triangular: copy the diagonal and the elements above the diagonal
      
      for(uword i=0; i<N; ++i)
        {
        const eT* A_data   = A.colptr(i);
              eT* out_data = out.colptr(i);
        
        arrayops::copy( out_data, A_data, i+1 );
        }
      }
    else
      {
      // lower triangular: copy the diagonal and the elements below the diagonal
      
      for(uword i=0; i<N; ++i)
        {
        const eT* A_data   = A.colptr(i);
              eT* out_data = out.colptr(i);
        
        arrayops::copy( &out_data[i], &A_data[i], N-i );
        }
      }
    }
  
  
  if(do_conj)
    {
    if(upper)
      {
      // reflect elements across the diagonal from upper triangle to lower triangle
      
      for(uword col=1; col < N; ++col)
        {
        const eT* coldata = out.colptr(col);
        
        for(uword row=0; row < col; ++row)
          {
          out.at(col,row) = std::conj(coldata[row]);
          }
        }
      }
    else
      {
      // reflect elements across the diagonal from lower triangle to upper triangle
      
      for(uword col=0; col < N; ++col)
        {
        const eT* coldata = out.colptr(col);
        
        for(uword row=(col+1); row < N; ++row)
          {
          out.at(col,row) = std::conj(coldata[row]);
          }
        }
      }
    }
  else  // don't do complex conjugation
    {
    if(upper)
      {
      // reflect elements across the diagonal from upper triangle to lower triangle
      
      for(uword col=1; col < N; ++col)
        {
        const eT* coldata = out.colptr(col);
        
        for(uword row=0; row < col; ++row)
          {
          out.at(col,row) = coldata[row];
          }
        }
      }
    else
      {
      // reflect elements across the diagonal from lower triangle to upper triangle
      
      for(uword col=0; col < N; ++col)
        {
        const eT* coldata = out.colptr(col);
        
        for(uword row=(col+1); row < N; ++row)
          {
          out.at(col,row) = coldata[row];
          }
        }
      }
    }
  }
inline
void
subview_cube<eT>::div_inplace(Mat<eT>& out, const subview_cube<eT>& in)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_assert_cube_as_mat(out, in, "element-wise division", true);
  
  const u32 in_n_rows   = in.n_rows;
  const u32 in_n_cols   = in.n_cols;
  const u32 in_n_slices = in.n_slices;
  
  const u32 out_n_rows    = out.n_rows;
  const u32 out_n_cols    = out.n_cols;
  const u32 out_vec_state = out.vec_state;
  
  if(in_n_slices == 1)
    {
    for(u32 col=0; col < in_n_cols; ++col)
      {
      arrayops::inplace_div( out.colptr(col), in.slice_colptr(0, col), in_n_rows );
      }
    }
  else
    {
    if(out_vec_state == 0)
      {
      if( (in_n_rows == out_n_rows) && (in_n_cols == 1) && (in_n_slices == out_n_cols) )
        {
        for(u32 i=0; i < in_n_slices; ++i)
          {
          arrayops::inplace_div( out.colptr(i), in.slice_colptr(i, 0), in_n_rows );
          }
        }
      else
      if( (in_n_rows == 1) && (in_n_cols == out_n_cols) && (in_n_slices == out_n_rows) )
        {
        const Cube<eT>& Q = in.m;
        
        const u32 in_aux_row1   = in.aux_row1;
        const u32 in_aux_col1   = in.aux_col1;
        const u32 in_aux_slice1 = in.aux_slice1;
        
        for(u32 col=0; col < in_n_cols; ++col)
          {
          eT* out_colptr = out.colptr(col);
          
          for(u32 i=0; i < in_n_slices; ++i)
            {
            out_colptr[i] /= Q.at(in_aux_row1, in_aux_col1 + col, in_aux_slice1 + i);
            }
          }
        }
      }
    else
      {
      eT* out_mem = out.memptr();
      
      const Cube<eT>& Q = in.m;
      
      const u32 in_aux_row1   = in.aux_row1;
      const u32 in_aux_col1   = in.aux_col1;
      const u32 in_aux_slice1 = in.aux_slice1;
      
      for(u32 i=0; i<in_n_slices; ++i)
        {
        out_mem[i] /= Q.at(in_aux_row1, in_aux_col1, in_aux_slice1 + i);
        }
      }
    }
  }
Example #25
0
inline
void
op_flipud::apply_direct(Mat<eT>& out, const Mat<eT>& X)
  {
  arma_extra_debug_sigprint();
  
  const uword X_n_rows = X.n_rows;
  const uword X_n_cols = X.n_cols;
  
  const uword X_n_rows_m1 = X_n_rows - 1;
  
  if(&out != &X)
    {
    out.set_size(X_n_rows, X_n_cols);
    
    if(X_n_cols == 1)
      {
      const eT*   X_mem =   X.memptr();
            eT* out_mem = out.memptr();
      
      for(uword row=0; row < X_n_rows; ++row)
        {
        out_mem[X_n_rows_m1 - row] = X_mem[row];
        }
      }
    else
      {
      for(uword col=0; col < X_n_cols; ++col)
        {
        const eT*   X_colmem =   X.colptr(col);
              eT* out_colmem = out.colptr(col);
        
        for(uword row=0; row < X_n_rows; ++row)
          {
          out_colmem[X_n_rows_m1 - row] = X_colmem[row];
          }
        }
      }
    }
  else  // in-place operation
    {
    const uword N = X_n_rows / 2;
    
    if(X_n_cols == 1)
      {
      eT* out_mem = out.memptr();
      
      for(uword row=0; row < N; ++row)
        {
        std::swap(out_mem[X_n_rows_m1 - row], out_mem[row]);
        }
      }
    else
      {
      for(uword col=0; col < X_n_cols; ++col)
        {
        eT* out_colmem = out.colptr(col);
        
        for(uword row=0; row < N; ++row)
          {
          std::swap(out_colmem[X_n_rows_m1 - row], out_colmem[row]);
          }
        }
      }
    }
  }
inline
void
glue_histc::apply(Mat<uword>& out, const mtGlue<uword,T1,T2,glue_histc>& in)
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT;
  
  const uword dim = in.aux_uword;
  
  const unwrap_check_mixed<T1> tmp1(in.A, out);
  const unwrap_check_mixed<T2> tmp2(in.B, out);
  
  const Mat<eT>& X = tmp1.M;
  const Mat<eT>& E = tmp2.M;
  
  arma_debug_check
    (
    (E.is_vec() == false),
    "histc(): parameter 'edges' must be a vector"
    );
  
  arma_debug_check
    (
    (dim > 1),
    "histc(): parameter 'dim' must be 0 or 1"
    );
  
  const uword X_n_elem = X.n_elem;
  const uword X_n_rows = X.n_rows;
  const uword X_n_cols = X.n_cols;
  
  const uword E_n_elem = E.n_elem;
  
  if( E_n_elem == 0 )
    {
    out.reset();
    return;
    }
  
  
  // for vectors we are currently ignoring the "dim" parameter
  
  uword out_n_rows = 0;
  uword out_n_cols = 0;
  
  if(X.is_vec())
    {
    if(X.is_rowvec())
      {
      out_n_rows = 1;
      out_n_cols = E_n_elem;
      }
    else
    if(X.is_colvec())
      {
      out_n_rows = E_n_elem;
      out_n_cols = 1;
      }
    }
  else
    {
    if(dim == 0)
      {
      out_n_rows = E_n_elem;
      out_n_cols = X_n_cols;
      }
    else
    if(dim == 1)
      {
      out_n_rows = X_n_rows;
      out_n_cols = E_n_elem;
      }
    }
  
  out.zeros(out_n_rows, out_n_cols);
  
  const eT* E_mem = E.memptr();

  if(X.is_vec() == true)
    {
          uword* out_mem = out.memptr();
    const eT*    X_mem   = X.memptr();
    
    for(uword j=0; j<X_n_elem; ++j)
      {
      const eT val = X_mem[j];
      
      for(uword i=0; i<E_n_elem-1; ++i)
        {
        if( (E_mem[i] <= val) && (val < E_mem[i+1]) )
          {
          out_mem[i]++;
          break;
          }
        else
        if(val == E_mem[E_n_elem-1])
          {
          // in general, the above == operation doesn't make sense for floating point values (due to precision issues),
          // but is included for compatibility with Matlab and Octave.
          // Matlab folks must have been smoking something strong.
          out_mem[E_n_elem-1]++;
          break;
          }
        }
      }
    }
  else
  if(dim == 0)
    {
    for(uword col=0; col<X_n_cols; ++col)
      {
            uword* out_coldata = out.colptr(col);
      const eT*    X_coldata   = X.colptr(col);
      
      for(uword row=0; row<X_n_rows; ++row)
        {
        const eT val = X_coldata[row];
        
        for(uword i=0; i<E_n_elem-1; ++i)
          {
          if( (E_mem[i] <= val) && (val < E_mem[i+1]) )
            {
            out_coldata[i]++;
            break;
            }
          else
          if(val == E_mem[E_n_elem-1])
            {
            out_coldata[E_n_elem-1]++;
            break;
            }
          }
        }
      }
    }
  else
  if(dim == 1)
    {
    for(uword row=0; row<X_n_rows; ++row)
      {
      for(uword col=0; col<X_n_cols; ++col)
        {
        const eT val = X.at(row,col);
        
        for(uword i=0; i<E_n_elem-1; ++i)
          {
          if( (E_mem[i] <= val) && (val < E_mem[i+1]) )
            {
            out.at(row,i)++;
            break;
            }
          else
          if(val == E_mem[E_n_elem-1])
            {
            out.at(row,E_n_elem-1)++;
            break;
            }
          }
        }
      }
    }
  }
inline
void
op_sort::apply(Mat<typename T1::elem_type>& out, const Op<T1,op_sort>& in)
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT;
  
  const unwrap_check<T1>   tmp(in.m, out);
  const Mat<eT>&       X = tmp.M;
  
  const uword sort_type = in.aux_uword_a;
  const uword dim       = in.aux_uword_b;
  
  arma_debug_check( (sort_type > 1),          "sort(): incorrect usage. sort_type must be 0 or 1");
  arma_debug_check( (dim > 1),                "sort(): incorrect usage. dim must be 0 or 1"      );
  arma_debug_check( (X.is_finite() == false), "sort(): given object has non-finite elements"     );
  
  if( (X.n_rows * X.n_cols) <= 1 )
    {
    out = X;
    return;
    }
  
  
  if(dim == 0)  // sort the contents of each column
    {
    arma_extra_debug_print("op_sort::apply(), dim = 0");
    
    out = X;
    
    const uword n_rows = out.n_rows;
    const uword n_cols = out.n_cols;
      
    for(uword col=0; col < n_cols; ++col)
      {
      op_sort::direct_sort( out.colptr(col), n_rows, sort_type );
      }
    }
  else
  if(dim == 1)  // sort the contents of each row
    {
    if(X.n_rows == 1)  // a row vector
      {
      arma_extra_debug_print("op_sort::apply(), dim = 1, vector specific");
      
      out = X;
      op_sort::direct_sort(out.memptr(), out.n_elem, sort_type);
      }
    else  // not a row vector
      {
      arma_extra_debug_print("op_sort::apply(), dim = 1, generic");
      
      out.copy_size(X);
      
      const uword n_rows = out.n_rows;
      const uword n_cols = out.n_cols;
      
      podarray<eT> tmp_array(n_cols);
      
      for(uword row=0; row < n_rows; ++row)
        {
        op_sort::copy_row(tmp_array.memptr(), X, row);
        
        op_sort::direct_sort( tmp_array.memptr(), n_cols, sort_type );
        
        op_sort::copy_row(out, tmp_array.memptr(), row);
        }
      }
    }
  
  }
Example #28
0
 arma_hot
 inline
 static
 void
 apply( eT* y, const Mat<eT>& A, const eT* x, const eT alpha = eT(1), const eT beta = eT(0) )
   {
   arma_extra_debug_sigprint();
   
   const u32 A_n_rows = A.n_rows;
   const u32 A_n_cols = A.n_cols;
   
   if(do_trans_A == false)
     {
     for(u32 row=0; row < A_n_rows; ++row)
       {
       
       eT acc = eT(0);
       for(u32 col=0; col < A_n_cols; ++col)
         {
         acc += A.at(row,col) * x[col];
         }
         
       if( (use_alpha == false) && (use_beta == false) )
         {
         y[row] = acc;
         }
       else
       if( (use_alpha == true) && (use_beta == false) )
         {
         y[row] = alpha * acc;
         }
       else
       if( (use_alpha == false) && (use_beta == true) )
         {
         y[row] = acc + beta*y[row];
         }
       else
       if( (use_alpha == true) && (use_beta == true) )
         {
         y[row] = alpha*acc + beta*y[row];
         }
       }
     }
   else
   if(do_trans_A == true)
     {
     for(u32 col=0; col < A_n_cols; ++col)
       {
       // col is interpreted as row when storing the results in 'y'
       
       
       // const eT* A_coldata = A.colptr(col);
       // 
       // eT acc = eT(0);
       // for(u32 row=0; row < A_n_rows; ++row)
       //   {
       //   acc += A_coldata[row] * x[row];
       //   }
       
       const eT acc = op_dot::direct_dot_arma(A_n_rows, A.colptr(col), x);
       
       if( (use_alpha == false) && (use_beta == false) )
         {
         y[col] = acc;
         }
       else
       if( (use_alpha == true) && (use_beta == false) )
         {
         y[col] = alpha * acc;
         }
       else
       if( (use_alpha == false) && (use_beta == true) )
         {
         y[col] = acc + beta*y[col];
         }
       else
       if( (use_alpha == true) && (use_beta == true) )
         {
         y[col] = alpha*acc + beta*y[col];
         }
       
       }
     }
   }
inline
void
glue_hist::apply(Mat<uword>& out, const mtGlue<uword,T1,T2,glue_hist>& in)
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT;
  
  const uword dim = in.aux_uword;
  
  const unwrap_check_mixed<T1> tmp1(in.A, out);
  const unwrap_check_mixed<T2> tmp2(in.B, out);
  
  const Mat<eT>& X = tmp1.M;
  const Mat<eT>& C = tmp2.M;
  
  
  arma_debug_check
    (
    (C.is_vec() == false),
    "hist(): parameter 'centers' must be a vector"
    );
  
  arma_debug_check
    (
    (dim > 1),
    "hist(): parameter 'dim' must be 0 or 1"
    );
  
  const uword X_n_rows = X.n_rows;
  const uword X_n_cols = X.n_cols;
  const uword X_n_elem = X.n_elem;
  
  const uword C_n_elem = C.n_elem;
  
  if( C_n_elem == 0 )
    {
    out.reset();
    return;
    }
  
  // for vectors we are currently ignoring the "dim" parameter
  
  uword out_n_rows = 0;
  uword out_n_cols = 0;
  
  if(X.is_vec())
    {
    if(X.is_rowvec())
      {
      out_n_rows = 1;
      out_n_cols = C_n_elem;
      }
    else
    if(X.is_colvec())
      {
      out_n_rows = C_n_elem;
      out_n_cols = 1;
      }
    }
  else
    {
    if(dim == 0)
      {
      out_n_rows = C_n_elem;
      out_n_cols = X_n_cols;
      }
    else
    if(dim == 1)
      {
      out_n_rows = X_n_rows;
      out_n_cols = C_n_elem;
      }
    }
  
  out.zeros(out_n_rows, out_n_cols);
  
  
  const eT* C_mem    = C.memptr();
  const eT  center_0 = C_mem[0];
  
  if(X.is_vec())
    {
    const eT*    X_mem   = X.memptr();
          uword* out_mem = out.memptr();
    
    for(uword i=0; i < X_n_elem; ++i)
      {
      const eT val = X_mem[i];
      
      if(is_finite(val))
        {
        eT    opt_dist  = (val >= center_0) ? (val - center_0) : (center_0 - val);
        uword opt_index = 0;
        
        for(uword j=1; j < C_n_elem; ++j)
          {
          const eT center = C_mem[j];
          const eT dist   = (val >= center) ? (val - center) : (center - val);
          
          if(dist < opt_dist)
            {
            opt_dist  = dist;
            opt_index = j;
            }
          else
            {
            break;
            }
          }
        
        out_mem[opt_index]++;
        }
      else
        {
        // -inf
        if(val < eT(0)) { out_mem[0]++; }
        
        // +inf
        if(val > eT(0)) { out_mem[C_n_elem-1]++; }
        
        // ignore NaN
        }
      }
    }
  else
    {
    if(dim == 0)
      {
      for(uword col=0; col < X_n_cols; ++col)
        {
        const eT*    X_coldata   = X.colptr(col);
              uword* out_coldata = out.colptr(col);
        
        for(uword row=0; row < X_n_rows; ++row)
          {
          const eT val = X_coldata[row];
          
          if(arma_isfinite(val))
            {
            eT    opt_dist  = (center_0 >= val) ? (center_0 - val) : (val - center_0);
            uword opt_index = 0;
            
            for(uword j=1; j < C_n_elem; ++j)
              {
              const eT center = C_mem[j];
              const eT dist   = (center >= val) ? (center - val) : (val - center);
              
              if(dist < opt_dist)
                {
                opt_dist  = dist;
                opt_index = j;
                }
              else
                {
                break;
                }
              }
            
            out_coldata[opt_index]++;
            }
          else
            {
            // -inf
            if(val < eT(0)) { out_coldata[0]++; }
            
            // +inf
            if(val > eT(0)) { out_coldata[C_n_elem-1]++; }
            
            // ignore NaN
            }
          }
        }
      }
    else
    if(dim == 1)
      {
      for(uword row=0; row < X_n_rows; ++row)
        {
        for(uword col=0; col < X_n_cols; ++col)
          {
          const eT val = X.at(row,col);
          
          if(arma_isfinite(val))
            {
            eT    opt_dist  = (center_0 >= val) ? (center_0 - val) : (val - center_0);
            uword opt_index = 0;
            
            for(uword j=1; j < C_n_elem; ++j)
              {
              const eT center = C_mem[j];
              const eT dist   = (center >= val) ? (center - val) : (val - center);
              
              if(dist < opt_dist)
                {
                opt_dist  = dist;
                opt_index = j;
                }
              else
                {
                break;
                }
              }
            
            out.at(row,opt_index)++;
            }
          else
            {
            // -inf
            if(val < eT(0)) { out.at(row,0)++; }
            
            // +inf
            if(val > eT(0)) { out.at(row,C_n_elem-1)++; }
            
            // ignore NaN
            }
          }
        }
      }
    }
  }
inline
void
subview_cube<eT>::extract(Mat<eT>& out, const subview_cube<eT>& in)
  {
  arma_extra_debug_sigprint();
  
  arma_debug_assert_cube_as_mat(out, in, "copy into matrix", false);
  
  const u32 in_n_rows   = in.n_rows;
  const u32 in_n_cols   = in.n_cols;
  const u32 in_n_slices = in.n_slices;
  
  const u32 out_vec_state = out.vec_state;
  
  if(in_n_slices == 1)
    {
    out.set_size(in_n_rows, in_n_cols);
    
    for(u32 col=0; col < in_n_cols; ++col)
      {
      arrayops::copy( out.colptr(col), in.slice_colptr(0, col), in_n_rows );
      }
    }
  else
    {
    if(out_vec_state == 0)
      {
      if(in_n_cols == 1)
        {
        out.set_size(in_n_rows, in_n_slices);
        
        for(u32 i=0; i < in_n_slices; ++i)
          {
          arrayops::copy( out.colptr(i), in.slice_colptr(i, 0), in_n_rows );
          }
        }
      else
      if(in_n_rows == 1)
        {
        out.set_size(in_n_slices, in_n_cols);
        
        const Cube<eT>& Q = in.m;
        
        const u32 in_aux_row1   = in.aux_row1;
        const u32 in_aux_col1   = in.aux_col1;
        const u32 in_aux_slice1 = in.aux_slice1;
        
        for(u32 col=0; col < in_n_cols; ++col)
          {
          eT* out_colptr = out.colptr(col);
          
          for(u32 i=0; i < in_n_slices; ++i)
            {
            out_colptr[i] = Q.at(in_aux_row1, in_aux_col1 + col, in_aux_slice1 + i);
            }
          }
        }
      }
    else
      {
      out.set_size(in_n_slices);
      
      eT* out_mem = out.memptr();
      
      const Cube<eT>& Q = in.m;
      
      const u32 in_aux_row1   = in.aux_row1;
      const u32 in_aux_col1   = in.aux_col1;
      const u32 in_aux_slice1 = in.aux_slice1;
      
      for(u32 i=0; i<in_n_slices; ++i)
        {
        out_mem[i] = Q.at(in_aux_row1, in_aux_col1, in_aux_slice1 + i);
        }
      }
    }
  }