【发布时间】:2014-12-08 19:17:53
【问题描述】:
我一直致力于状态空间探索,最初使用地图来存储世界状态的分配,例如 map<Variable *, int>,其中变量是世界中的对象,其域从 0 到 n,其中 n 是有限的。该实现的性能非常快,但我注意到它不能很好地随着状态空间的大小而扩展。我将状态更改为使用 vector<int> 代替,我使用变量的 id 在向量中查找其索引。内存使用率大大提高,但求解器的效率已经下降(从
原来我是这样生成节点的:
State * SuccessorGen::generate_successor(const Operator &op, map<Variable *, int> &var_assignment){
map<Variable *, int> values;
values.insert(var_assignment.begin(), var_assignment.end());
vector<Operator::Effect> effect = op.get_effect();
vector<Operator::Effect>::const_iterator eff_it = effect.begin();
for (; eff_it != effect.end(); eff_it++){
values[eff_it->var] = eff_it->after;
}
return new State(values);
}
在我的新实现中:
State* SuccessorGen::generate_successor(const Operator &op, const vector<int> &assignment){
vector<int> child;
child = assignment;
vector<Operator::Effect> effect = op.get_effect();
vector<Operator::Effect>::const_iterator eff_it = effect.begin();
for (; eff_it != effect.end(); eff_it++){
Variable *v = eff_it->var;
int id = v->get_id();
child[id] = eff_it->after;
}
return new State(child);
}
(目标检查类似,只是循环遍历目标分配而不是操作符效果。)
这些向量操作真的比使用地图慢很多吗?是否有一个同样高效的 STL 容器我可以使用它具有较低的开销?变量的数量相对较少(
编辑:
我尝试通过所有运算符计时一个循环以查看时间比较,效果列表和分配矢量版本在 0.3 秒内运行一个循环,而地图版本是 0.4 秒多一点。当我评论地图的那部分时,地图大致相同,但矢量跃升到接近 0.5 秒。我添加了child.reserve(assignment.size()),但没有任何改变。
编辑 2:
根据 user63710 的回答,我也一直在挖掘其余代码,并注意到启发式计算中发生了一些非常奇怪的事情。矢量版本工作正常,但对于地图我使用这条线Node *n = new Node(i, transition.value, label_cost); open_list.push(n);,但是一旦循环完成填充队列,节点就会完全搞砸。节点是一个简单的结构:
struct Node{
// Source Value, Destination Value
int from;
int to;
int distance;
Node(int &f, int &t, int &d) : from(f), to(t), distance(d){}
};
它没有使用from, to, distance,而是将from 和to 替换为带有一些随机数的id,并且该搜索没有执行应有的操作,并且返回的速度比应有的快得多。当我调整地图版本以将地图转换为矢量并运行时:
Node n(i, transition.value, label_cost); open_list.push(n);
性能大约等于向量的性能。这样就解决了我的主要问题,但这让我想知道为什么使用 Node *n 会得到与 Node n() 相反的这种行为?
【问题讨论】:
-
你也尝试过 unordered_map 吗?您的向量是否已排序?如果您确保始终对向量进行排序,您可以更快地完成操作。
-
您是否有任何其他信息说明导致减速的原因?总是使用
g++ -pg和gprof进行编译。否则,我假设get_id()的计算成本不高,eff_it->var->get_id()生成的 id 是顺序的还是随机的? -
我不希望向量排序为值的索引对应于特定变量,即 var0 位于索引 0 等。ID 是在解析输入时生成的,因此在加载 var0 时变量有一个私有 int,这就是返回的内容。
-
var_assignment 和 assignment 是否有相同数量的元素?您的
assignment向量中是否有任何未使用的id? -
是的,两者都具有相同数量的元素,并且
assignment向量的大小与元素数量相同,并且永远不会改变。所有状态的矢量/地图大小相同。
标签: c++ performance vector