在C / C ++中是否有一个accumarray()的例子

我们试图理解MATLAB的准确函数,想为我们的理解编写C / C ++代码。 有人可以用样本/伪代码帮助我们吗?

根据文件 ,

该函数处理输入如下:

  1. 找出潜艇中有多少独特的指数。 每个唯一索引定义输出数组中的bin。 subs中的最大索引值确定输出数组的大小。

  2. 找出每个索引重复的次数。

  3. 这确定了在输出数组中的每个bin处将累积多少个val元素。

  4. 创建一个输出数组。 输出数组的大小为max(subs)或大小为sz。

  5. 使用subs中索引的值将val中的条目累积到bin中,并将fun应用于每个bin中的条目。

  6. 在输出中填写未被subs引用的位置。 默认填充值为零; 使用fillval设置不同的值。

那么,转换为C ++(这是未经测试的代码),

template< typename sub_it, typename val_it, typename out_it, typename fun = std::plus< typename std::iterator_traits< val_it >::value_type >, typename T = typename fun::result_type > out_it accumarray( sub_it first_index, sub_it last_index, val_it first_value, // val_it last_value, -- 1 value per index out_it first_out, fun f = fun(), T fillval = T() ) { std::size_t sz = std::max_element( first_index, last_index ); // 1. Get size. std::vector< bool > used_indexes; // 2-3. remember which indexes are used std::fill_n( first_out, sz, T() ); // 4. initialize output while ( first_index != last_index ) { std::size_t index = * first_index; used_indexes[ index ] = true; // 2-3. remember that this index was used first_out[ index ] = f( first_out[ index ], * first_value ); // 5. accumulate ++ first_value; ++ first_index; } // If fill is different from zero, reinitialize untouched values if ( fillval != T() ) { out_it fill_it = first_out; for ( std::vector< bool >::iterator used_it = used_indexes.begin(); used_it != used_indexes.end(); ++ used_it ) { if ( * used_it ) * fill_it = fillval; } } return first_out + sz; } 

这有一些缺点,例如,对整个列向量重复调用累加函数而不是一次。 输出放在first_out引用的预分配存储中。 索引向量必须与值向量的大小相同。 但是应该很好地捕获大多数function。

非常感谢您的回复。 我们能够在C ++中完全理解和实现它(我们使用armadillo )。 这是代码:

 colvec TestProcessing::accumarray(icolvec cf, colvec T, double nf, int p) { /* ******* Description ******* here cf is the matrix of indices T is the values whose data is to be accumulted in the output array S. if T is not given (or is scaler)then accumarray simply converts to calculation of histogram of the input data nf is the the size of output Array nf >= max(cf) so pass the argument accordingly p is not used in the function ********************************/ colvec S; // output Array S.set_size(int(nf)); // preallocate the output array for(int i = 0 ; i < (int)nf ; i++) { // find the indices in cf corresponding to 1 to nf // and store in unsigned integer array q1 uvec q1 = find(cf == (i+1)); vec q ; double sum1 = 0 ; if(!q1.is_empty()) { q = T.elem(q1) ; // find the elements in T having indices in q1 // make sure q1 is not empty sum1 = arma::sum(q); // calculate the sum and store in output array S(i) = sum1; } // if q1 is empty array just put 0 at that particular location else { S(i) = 0 ; } } return S; } 

希望这对其他人也有帮助! 再次感谢所有贡献的人:)

这就是我想出的。 注意:我追求可读性(因为你想要最好地理解),而不是进行优化。 哦,我从来没有使用过MATLAB,我刚才看到了这个样本:

 val = 101:105; subs = [1; 2; 4; 2; 4] subs = 1 2 4 2 4 A = accumarray(subs, val) A = 101 % A(1) = val(1) = 101 206 % A(2) = val(2)+val(4) = 102+104 = 206 0 % A(3) = 0 208 % A(4) = val(3)+val(5) = 103+105 = 208 

无论如何,这是代码示例:

 #include  #include  #include  #include  class RangeValues { public: RangeValues(int startValue, int endValue) { int range = endValue - startValue; // Reserve all needed space up front values.resize(abs(range) + 1); unsigned int index = 0; for ( int i = startValue; i != endValue; iterateByDirection(range, i), ++index ) { values[index] = i; } } std::vector GetValues() const { return values; } private: void iterateByDirection(int range, int& value) { ( range < 0 ) ? --value : ++value; } private: std::vector values; }; typedef std::map accumMap; accumMap accumarray( const RangeValues& rangeVals ) { accumMap aMap; std::vector values = rangeVals.GetValues(); unsigned int index = 0; std::vector::const_iterator itr = values.begin(); for ( itr; itr != values.end(); ++itr, ++index ) { aMap[index] = (*itr); } return aMap; } int main() { // Our value range will be from -10 to 10 RangeValues values(-10, 10); accumMap aMap = accumarray(values); // Now iterate through and check out what values map to which indices. accumMap::const_iterator itr = aMap.begin(); for ( itr; itr != aMap.end(); ++itr ) { std::cout << "Index: " << itr->first << ", Value: " << itr->second << '\n'; } //Or much like the MATLAB Example: cout << aMap[5]; // -5, since out range was from -10 to 10 } 

除了Vicky Budhiraja“犰狳”的例子,这个是一个2D版本的accumarray使用类似语义而不是matlab函数:

 arma::mat accumarray (arma::mat& subs, arma::vec& val, arma::rowvec& sz) { arma::u32 ar = sz.col(0)(0); arma::u32 ac = sz.col(1)(0); arma::mat A; A.set_size(ar, ac); for (arma::u32 r = 0; r < ar; ++r) { for (arma::u32 c = 0; c < ac; ++c) { arma::uvec idx = arma::find(subs.col(0) == r && subs.col(1) == c); if (!idx.is_empty()) A(r, c) = arma::sum(val.elem(idx)); else A(r, c) = 0; } } return A; } 

sz输入是一个两列向量,包含:输出矩阵A的num rows / num cols。子矩阵是2列,具有相同的num行val。 num行的val基本上是sz.rows由sz.cols。

sz(大小)输入不是必需的,可以通过搜索子列中的max来轻松推断。

 arma::u32 sz_rows = arma::max(subs.col(0)) + 1; arma::u32 sz_cols = arma::max(subs.col(1)) + 1; 

要么

 arma::u32 sz_rows = arma::max(subs.col(0)) + 1; arma::u32 sz_cols = val.n_elem / sz_rows; 

输出矩阵现在是:

 arma::mat A (sz_rows, sz_cols); 

准确的function变成:

 arma::mat accumarray (arma::mat& subs, arma::vec& val) { arma::u32 sz_rows = arma::max(subs.col(0)) + 1; arma::u32 sz_cols = arma::max(subs.col(1)) + 1; arma::mat A (sz_rows, sz_cols); for (arma::u32 r = 0; r < sz_rows; ++r) { for (arma::u32 c = 0; c < sz_cols; ++c) { arma::uvec idx = arma::find(subs.col(0) == r && subs.col(1) == c); if (!idx.is_empty()) A(r, c) = arma::sum(val.elem(idx)); else A(r, c) = 0; } } return A; } 

例如 :

 arma::vec val = arma::regspace(101, 106); arma::mat subs; subs << 0 << 0 << arma::endr << 1 << 1 << arma::endr << 2 << 1 << arma::endr << 0 << 0 << arma::endr << 1 << 1 << arma::endr << 3 << 0 << arma::endr; arma::mat A = accumarray (subs, val); A.raw_print("A ="); 

产生这个结果:

 A = 205 0 0 207 0 103 106 0 

这个例子可以在这里找到: http ://fr.mathworks.com/help/matlab/ref/accumarray.html?requestedDomain = http://www.mathworks.com除了subs的索引,armadillo是0-based indice,其中matlab是1基。

不幸的是,以前的代码不适合大矩阵。 两个for-loop在中间的向量中找到是非常糟糕的事情。 代码很好理解这个概念,但可以像这样一个单循环优化:

 arma::mat accumarray(arma::mat& subs, arma::vec& val) { arma::u32 ar = arma::max(subs.col(0)) + 1; arma::u32 ac = arma::max(subs.col(1)) + 1; arma::mat A(ar, ac); A.zeros(); for (arma::u32 r = 0; r < subs.n_rows; ++r) A(subs(r, 0), subs(r, 1)) += val(r); return A; } 

唯一的变化是:

  • 用零来初始化输出矩阵。
  • 在subs行上循环以获得输出indice(s)
  • 累加val到输出(subs和val是行同步的)

函数的一维版本(向量)可以是:

 arma::vec accumarray (arma::ivec& subs, arma::vec& val) { arma::u32 num_elems = arma::max(subs) + 1; arma::vec A (num_elems); A.zeros(); for (arma::u32 r = 0; r < subs.n_rows; ++r) A(subs(r)) += val(r); return A; } 

用于测试1D版本:

 arma::vec val = arma::regspace(101, 105); arma::ivec subs; subs << 0 << 2 << 3 << 2 << 3; arma::vec A = accumarray(subs, val); A.raw_print("A ="); 

结果符合matlab示例(参见上一个链接)

 A = 101 0 206 208 

这不是matlab accumarray函数的严格副本。 例如,matlab函数允许输出尺寸由sz定义的vec / mat,该尺寸大于sub / val duo的intrinsec尺寸。

也许这可以成为添加到犰狳api的想法。 允许单个界面用于不同的维度和类型。