如何将其累积在减少(或其他平行的STL算法)中?
我正在为课程项目开发C ++中的Barnes -Hut模拟。 在这里您可以找到算法的详细说明。
我简要说明以后将使用的数据类型。
- 一个主体由
正文
数据类型表示,该型号是一个结构,其中包含vector2f
表示位置的结构,而质量的浮点数为float)。 - Quadtree中的节点由
节点
datatype表示。当然,节点结构包含一些数据,这些数据可能是:1)其四个孩子,对应于其四个子界。这只保存节点是树中的叉子。 2)它的身体。仅当节点是树的叶子时,才能保持。 3)空。当节点不包含任何主体时,这会成立。 因此,数据是std ::变体
。
我编写了递归功能,该功能计算出作用于身体的净力。它在输入中获取node
(在第一个调用,Quadtree的根)和body
我们要查询,并返回vector2f
表示代表作用在身体上的净力。 当然,该功能需要访问变体并派遣到正确的lambda。
Vector2f compute_approximate_net_force_on_body(const Node& node,
const Body& body) {
const auto visit_empty = [](const Empty&) -> Vector2f { return {0, 0}; };
const auto visit_body = [body](const Body& visited) -> Vector2f {
return compute_gravitational_force(visited, body);
};
const auto visit_region = [&](const Subquadrants& subquadrants) -> Vector2f {
float distance = (body.m_position - node.center_of_mass()).norm();
if (node.length() / distance < OMEGA) {
// Approximation
return bh::compute_gravitational_force(
{node.center_of_mass(), node.total_mass()}, body);
} else {
return std::accumulate(
subquadrants.begin(), subquadrants.end(), Vector2f{0, 0},
[body](const Vector2f& total, const std::shared_ptr<Node>& curr) {
return (total + compute_approximate_net_force_on_body(*curr, body))
.eval();
});
}
};
return std::visit(overloaded{visit_empty, visit_body, visit_region},
node.data());
}
有趣的部分是累积
的部分。从本质上讲,它以相同的节点和四个节点的子细分递归调用算法,并将结果累积到vector2f
中。
由于这四个呼叫是完全独立的,所以我认为我可以平行计算。最初,我将累积的
转换为redable
,但后来发现这是行不通的,因为
- 二进制操作函数的签名类型必须相同(我的不是);
- 二进制操作必须是关联和交换性的(我的不是)。
我正在寻找有关如何使用STL库并平行递归调用的建议。如果可能的话,C ++标准必须为C ++ 17或以下。我想到的一种方法是使用std :: async
和std :: Future
,但它不如累积的 。还有其他吗?
谢谢您的见解。
I am developing a Barnes–Hut simulation in C++ for a course project. Here you can find a detailed explanation of the algorithm.
I briefly explain the datatypes I will use later.
- A body is represented by the
Body
datatype, which is a struct containing aVector2f
representing the position, and a float for the mass). - A node in the quadtree is represented by the
Node
datatype. Of course, the node struct contains some data, which can be: 1) Its four children, corresponding to its four subquadrants. This holds only the node is a fork in the tree. 2) Its body. This holds only when the node is a leaf of the tree. 3) Empty. This holds when the node does not contain any body. Therefore, data is astd::variant
.
I wrote the recursive function that calculates the net force acting on a body. It takes in input a Node
(at the first call, the quadtree's root) and the Body
we want to query, and returns a Vector2f
representing the net force acting on the body.
Of course, the function needs to visit the variant and dispatch to the correct lambda.
Vector2f compute_approximate_net_force_on_body(const Node& node,
const Body& body) {
const auto visit_empty = [](const Empty&) -> Vector2f { return {0, 0}; };
const auto visit_body = [body](const Body& visited) -> Vector2f {
return compute_gravitational_force(visited, body);
};
const auto visit_region = [&](const Subquadrants& subquadrants) -> Vector2f {
float distance = (body.m_position - node.center_of_mass()).norm();
if (node.length() / distance < OMEGA) {
// Approximation
return bh::compute_gravitational_force(
{node.center_of_mass(), node.total_mass()}, body);
} else {
return std::accumulate(
subquadrants.begin(), subquadrants.end(), Vector2f{0, 0},
[body](const Vector2f& total, const std::shared_ptr<Node>& curr) {
return (total + compute_approximate_net_force_on_body(*curr, body))
.eval();
});
}
};
return std::visit(overloaded{visit_empty, visit_body, visit_region},
node.data());
}
The interesting part is the one with accumulate
. Essentially, it invokes the algorithm recursively, with the same node and the four node's subquadrants, and accumulates the result into a Vector2f
.
Since that the four calls are completely independent, I thought that I could make the computation parallel. Initially, I converted the accumulate
into a reduce
, but I later discovered that this can't work because
- the types of the signature of the binary operation function must be identical (mine are not);
- The binary operation must be associative and commutative (mine is not).
I am looking for suggestions on how to parallelize the recursive calls, possibly using the STL library. If possible, the C++ standard must be C++17 or below. One approach that I have in mind is to use std::async
and std::future
, but it is less elegant than the accumulate-like one. Are there any other else?
Thank you for your insights.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论