我想知道是否可以使用std :: transform进行2D矩阵乘法?矩阵存储为2d矢量说:
data.begin()
我试图简单地将Finder -> Go to Folder -> Go
传递给转换函数,但这不起作用。有人可以提供一些建议或读物吗?谢谢!
答案 0 :(得分:1)
你接近这个错误的方式。 std::transform
旨在作为线性操作,其中每个元素独立于其他元素进行转换。虽然技术上可以在用std::transform
迭代矩阵的同时读取其他矩阵元素,但这不是一个好主意 - 设计明智和性能明智。
此外,最好让整个矩阵的数据在内存中连续,而不是在不同的地方分配n个单独的向量。此外,矩阵数据有时以列主要方式而非主要方式访问。所以 - 为什么要像这样持有你的矩阵?将所有数据保存在标准库数据类型的简单组合中本身并不是更好。
答案 1 :(得分:0)
以下是一些帮助您入门的基本代码:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<vector<int>> data(3);
data[0] = vector<int>{1, 2, 4};
data[1] = vector<int>{1, 2, 3};
data[2] = vector<int>{1, 2, 3};
vector<vector<int>> data2(3);
data2[0] = vector<int>{1, 2};
data2[1] = vector<int>{1, 2};
data2[2] = vector<int>{1, 2};
vector<vector<int>> result(3);
std::transform(data.begin(), data.end(), result.begin(),
[data2](vector<int> row) -> vector<int> {
vector<int> ret;
for (int i = 0; i < data2[0].size(); i++) {
int rowcolsum = 0;
for (int k = 0; k < row.size(); k++) {
rowcolsum += row[k] * data2[k][i];
}
ret.push_back(rowcolsum);
}
return ret;
});
printf("%d, %d\n", result[0][0], result[0][1]);
printf("%d, %d\n", result[1][0], result[1][1]);
printf("%d, %d\n", result[1][0], result[1][1]);
}
请注意,此代码无效,并不是我建议你这样做的。但是,由于您使用std::transform
请求了解决方案,这就是我提供的解决方案,尽管在这种情况下使用率很低。其他答案可以指导您进行矩阵乘法的更好,更好的方法。如果您需要使用矩阵,我强烈建议使用专用于该功能的库,而不是自己实现。
答案 2 :(得分:0)
std::transform
不是正确的算法。如果你真的想要,你可以transform
一系列索引(std::pair<std::size_t, std::size_t>
)而不是我使用的显式循环。
using Matrix = std::vector<std::vector<double>>;
using Slice = std::vector<double>;
// Either a row or a column
Matrix operator*(Matrix lhs, Matrix rhs)
{
auto rowN = [](const Matrix & mat, std::size_t n) -> Slice
{
return mat[n];
// copy of the nth row
}
auto colN = [](const Matrix & mat, std::size_t n) -> Slice
{
Slice result(mat.size());
std::transform(mat.begin(), mat.end(), result.begin(), [n](auto & vec){ return vec[n]; });
// have to copy each row's nth element to get nth column
return result;
}
Matrix result(lhs.size(), { rhs.size(), 0 });
// may be the wrong way round, can't recall. Doesn't matter for square matrices
for (std::size_t r = 0; r < lhs.size(); r++)
{
auto row = rowN(lhs, r);
for (std::size_t c = 0; c < rhs.size(); c++)
{
auto col = colN(rhs, c);
result[r][c] = std::inner_product(row.begin(), row.end(), col.begin(), 0.);
}
}
}
我可能已经完成了转置,但是使用源矩阵中的列交换行很简单。您还可以缓存colN
的结果,该结果用于交换空间。
答案 3 :(得分:0)
您可以使用inner_product
¹和transform
简洁地实现矩阵乘法,并使用0个不必要的数据副本(与其他解决方案不同):
#include <boost/range/numeric.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <vector>
#include <iostream>
template<class T>
using Matrix = std::vector<std::vector<T>>;
template<class T>
Matrix<T> dot(Matrix<T> const& a, Matrix<T> const& b) {
using boost::adaptors::transformed;
auto rows = a.size();
auto cols = b[0].size();
Matrix<T> result(rows, std::vector<T>(cols));
for(decltype(rows) r = 0; r < rows; ++r)
for(decltype(cols) c = 0; c < cols; ++c)
result[r][c] = inner_product(a[r], b | transformed([c](auto& row) { return row[c]; }), T{});
return result;
}
用法:
template<class T>
void print_matrix(Matrix<T> const& a) {
for(auto& r : a) {
for(auto& c : r)
std::cout << c << ' ';
std::cout << '\n';
}
std::cout << '\n';
}
int main() {
Matrix<int> a{
{1,2,3},
{4,5,6}
};
Matrix<int> b{
{1,2},
{3,4},
{5,6}
};
auto r = dot(a, b);
print_matrix(a);
print_matrix(b);
print_matrix(r);
}
输出:
1 2 3
4 5 6
1 2
3 4
5 6
22 28
49 64
矩阵的更有效存储是std::vector<T>(rows * cols)
。
¹矩阵乘法结果单元格值是输入的相应行和列的内积。
如果碰巧经常乘以一个矩阵,那么转置该矩阵以避免遍历行以提取列是最有效的。这也使内部产品操作易于矢量化,因为两个输入都变为普通数组(行·行与行·col)。