J
Jeremy Murphy
Hi everyone,
I recently implemented A* for some research, and because I need both the pqinterface AND an iterable interface to the open list, I (somewhat naively)started using std::set. Now that the basic implementation is done, out ofcuriosity more than anything else, I decided to go back and try std:
riority_queue for the special case problem where I don't need to iterate over the open list. (I also realized that the boost::heap pq implementations allow iterating, albeit with poor efficiency.)
To my surprise and horror, when I used std:
riority_queue in place of std::set, the time and space performance is abysmally bad. So bad that I can'timagine why. For example, a problem of size n = 17 takes ~3 s and ~24 MB using std::set versus ~10 s and ~400 MB using std:
riority_queue. At n = 20, the pq implementation actually tries to allocate > 3 GB of RAM and usually gets OOM-killed.
I am stumped as to what is going on, because the solver yields identical answers and debugging output for both implementations. I have tried both std::vector and std::deque as the underlying container.
Now here I have to apologize that my minimal working example is not very minimal at all. I tried to recreate the behaviour without all the A* business, but with no success. Here is a link to the library in question:
http://code.google.com/p/policy-based-search/
There are two example problems, of which the TSP is the only serious one and is where the problem is observable. The master branch is std::set, the pq_interface branch uses std:
riority_queue. The TSP example requires one parameter, the problem size, e.g.: ./TSP 17.
I don't really expect people to have time to delve through my code, but if you do I would of course be incredibly humbled and appreciative. (I sincerely hope that you don't need to understand the TSP example itself and that just inspecting the library will suffice.) Even if you just have some ideas off the top of your head as to why std:
riority_queue would behave like this, that would help. So that you don't have to go looking at the code tounderstand the basics, the queue element type is a 'search node' and is defined roughly as:
struct Node {
Node(std::vector<unsigned int> S, std::shared_ptr<Node> P) : state(S), parent(P) {}
std::vector<unsigned int> state;
std::shared_ptr<Node> parent;
};
and the queue is then defined:
typedef std::shared_ptr<Node> Element;
typedef std:
riority_queue<Element, vector<Element>, Comp> PriorityQueue;
Roughly, the algorithm pushes a bunch of nodes (relative to problem size), pops one, repeats. Sorry about the length of my explanation, I tried to say only what I thought necessary, but that amounted to a lot.
Thanks inadvance for any advice, small or large. Cheers.
Jeremy
I recently implemented A* for some research, and because I need both the pqinterface AND an iterable interface to the open list, I (somewhat naively)started using std::set. Now that the basic implementation is done, out ofcuriosity more than anything else, I decided to go back and try std:
To my surprise and horror, when I used std:
I am stumped as to what is going on, because the solver yields identical answers and debugging output for both implementations. I have tried both std::vector and std::deque as the underlying container.
Now here I have to apologize that my minimal working example is not very minimal at all. I tried to recreate the behaviour without all the A* business, but with no success. Here is a link to the library in question:
http://code.google.com/p/policy-based-search/
There are two example problems, of which the TSP is the only serious one and is where the problem is observable. The master branch is std::set, the pq_interface branch uses std:
I don't really expect people to have time to delve through my code, but if you do I would of course be incredibly humbled and appreciative. (I sincerely hope that you don't need to understand the TSP example itself and that just inspecting the library will suffice.) Even if you just have some ideas off the top of your head as to why std:
struct Node {
Node(std::vector<unsigned int> S, std::shared_ptr<Node> P) : state(S), parent(P) {}
std::vector<unsigned int> state;
std::shared_ptr<Node> parent;
};
and the queue is then defined:
typedef std::shared_ptr<Node> Element;
typedef std:
Roughly, the algorithm pushes a bunch of nodes (relative to problem size), pops one, repeats. Sorry about the length of my explanation, I tried to say only what I thought necessary, but that amounted to a lot.
Jeremy