vector < vector < int >> 在第一维上的点积
Posted
技术标签:
【中文标题】vector < vector < int >> 在第一维上的点积【英文标题】:dot product of vector < vector < int > > over the first dimension 【发布时间】:2013-03-04 22:27:03 【问题描述】:我有
vector < vector < int > > data_mat ( 3, vector < int > (4) );
vector < int > data_vec ( 3 );
其中data_mat
可以被认为是一个矩阵,data_vec
是一个列向量,我正在寻找一种方法来计算data_mat
的每一列与data_vec
的内积,并存储它在另一个vector < int > data_out (4)
。
示例http://liveworkspace.org/code/2bW3X5%241 使用for_each
和transform
,可用于计算矩阵的列和:
sum=vector<int> (data_mat[0].size());
for_each(data_mat.begin(), data_mat.end(),
[&](const std::vector<int>& c)
std::transform(c.begin(), c.end(), sum.begin(), sum.begin(),
[](int d1, double d2)
return d1 + d2;
);
);
是否有可能以类似的方式(或以稍微不同的方式使用 STL 函数)计算矩阵列与向量的列点积?
问题是 'd2 = d1 + d2' 技巧在列内积情况下在这里不起作用 - 如果有办法包含 d3 以及可以解决它(d3 = d3 + d1 * d2 ) 但transform
中似乎不存在三元函数。
【问题讨论】:
inner_product
?
Npte,如果你想做严肃的数学,那么可能是时候转储 stl 并使用像 GSL 这样的 C 库了。 stl竟然会搞这种事情让我很吃惊,速度差大概是2个数量级……
我不确定我是否理解您想要实现的目标。你说的是点积,但我在这里看不到乘法
我没有点积的代码,如列和代码示例下方的文本中所述(请参阅文本中的乘法)。 AFAIK 没有办法在变换中做 d3 + d1 * d2;
。
好吧,不需要去任何 C 库,STL 没问题,但是 Matt 至少是正确的,如果你想做严肃的数学,那么至少放弃这个非常不合适的向量向量并使用适当的矩阵数据结构(存储其内部数据连续)。谁告诉你动态数组的动态数组是表示二维数组的好方法完全错误。不过,除此之外,这仍然是一个有趣的问题。
【参考方案1】:
事实上,您几乎可以一对一地使用现有的列求和方法。您不需要三元 std::transform
作为内部循环,因为在对矩阵行求和之前缩放矩阵行的因子对于每一行都是恒定的,因为它是列向量中的行值并且与矩阵行一起迭代因此外部的std::for_each
。
所以我们需要做的是遍历矩阵的行,并将每个完整的行乘以列向量中的相应值,然后将缩放后的行添加到和向量中。但不幸的是,为此我们需要一个std::for_each
函数,它同时迭代两个范围,即矩阵的行和列向量的行。为了实现这一点,我们可以使用通常的一元 std::for_each
并使用额外的迭代器手动对列向量进行迭代:
std::vector<int> sum(data_mat[0].size());
auto vec_iter = data_vec.begin();
std::for_each(data_mat.begin(), data_mat.end(),
[&](const std::vector<int>& row)
int vec_value = *vec_iter++; //manually advance vector row
std::transform(row.begin(), row.end(), sum.begin(), sum.begin(),
[=](int a, int b) return a*vec_value + b; );
);
std::for_each
内的额外手动迭代并不是标准库算法的惯用用法,但不幸的是,我们没有可以使用的二进制 std::for_each
。
另一种选择是使用std::transform
作为外部循环(它可以迭代两个范围),但我们并没有在每次外部迭代中真正计算单个值以返回,所以我们只需要返回一些虚拟来自外部 lambda 的值并通过使用某种虚拟输出迭代器将其丢弃。这也不是最干净的解决方案:
//output iterator that just discards any output
struct discard_iterator : std::iterator<std::output_iterator_tag,
void, void, void, void>
discard_iterator& operator*() return *this;
discard_iterator& operator++() return *this;
discard_iterator& operator++(int) return *this;
template<typename T> discard_iterator& operator=(T&&) return *this;
;
//iterate over rows of matrix and vector, misusing transform as binary for_each
std::vector<int> sum(data_mat[0].size());
std::transform(data_mat.begin(), data_mat.end(),
data_vec.begin(), discard_iterator(),
[&](const std::vector<int>& row, int vec_value)
return std::transform(row.begin(), row.end(),
sum.begin(), sum.begin(),
[=](int a, int b)
return a*vec_value + b;
);
);
编辑:虽然这已经在 cmets 中讨论过,并且我理解(并欣赏)这个问题的理论性质,但我仍然会建议在实践中动态数组的动态数组是一种非常好的方式来表示这样一个结构良好定义的二维数组,如矩阵。具有适当运算符的适当矩阵数据结构(连续存储其内容)几乎总是更好的选择。但是由于它们的通用性,您仍然可以使用标准库算法来处理这种自定义数据结构(甚至可以让矩阵类型提供自己的迭代器)。
【讨论】:
谢谢!我没有想到创建一个额外的向量并从“内部”访问它的想法。在我要演示的应用程序中,行是编号的图像,列是像素索引——在这种情况下,事情实际上并不算太糟糕,因为大块仍然是连续的。即便如此,如果您对数据有足够的了解来定义内积,那么受益于这些知识的数据结构总是更有效。 @alle_meije 是的,这没有意义。但是等等,我会重新设计它,最后我们甚至不需要一个临时向量,而是一个二进制for_each
。
@alle_meije 好的,更新了答案。 std::for_each
不能同时迭代两个范围这一事实并不能实现完全干净和流线型的 STL 解决方案,但它使我们不再需要我的第一个(不正确的)解决方案使用的额外临时向量。
这太棒了!谢谢 Christian,我暗中喜欢手动篡改“官方”迭代器的外观:)。
这是我使用代码的程序:github.com/amwink/bias/blob/master/cpp/fastecm/fastecm.cpp以上是关于vector < vector < int >> 在第一维上的点积的主要内容,如果未能解决你的问题,请参考以下文章