1
0
Fork 0

Use new PriorityQueue, compiles, does not work.

This commit is contained in:
Max Neunhoeffer 2015-04-24 08:43:51 -07:00 committed by Michael Hackstein
parent 3fc8243432
commit e508a1697d
3 changed files with 210 additions and 214 deletions

View File

@ -45,8 +45,6 @@ using namespace std;
using namespace triagens::basics;
using namespace triagens::arango;
std::mutex m;
class SimpleEdgeExpander {
private:
@ -100,13 +98,8 @@ class SimpleEdgeExpander {
return edgeIdPrefix.append(key);
};
void operator() ( Traverser::VertexId source,
Traverser::Direction dir,
vector<Traverser::Neighbor>& result
) {
//std::lock_guard<std::mutex> guard(m);
// cout << "Hallole: " << id << endl;
void operator() (Traverser::VertexId source,
vector<Traverser::Step>& result) {
std::vector<TRI_doc_mptr_copy_t> edges;
// Process Vertex Id!
size_t split;
@ -133,19 +126,19 @@ class SimpleEdgeExpander {
// cout << edges.size() << endl;
}
std::unordered_map<Traverser::VertexId, Traverser::Neighbor> candidates;
std::unordered_map<Traverser::VertexId, Traverser::Step> candidates;
Traverser::VertexId from;
Traverser::VertexId to;
std::unordered_map<Traverser::VertexId, Traverser::Neighbor>::const_iterator cand;
std::unordered_map<Traverser::VertexId, Traverser::Step>::const_iterator cand;
if (usesDist) {
for (size_t j = 0; j < edges.size(); ++j) {
from = extractFromId(edges[j]);
to = extractFromId(edges[j]);
to = extractToId(edges[j]);
if (from != source) {
candidates.find(from);
if (cand == candidates.end()) {
// Add weight
candidates.emplace(from, Traverser::Neighbor(from, edges[j]._id, 1));
candidates.emplace(from, Traverser::Step(to, from, 1, extractEdgeId(edges[j])));
} else {
// Compare weight
}
@ -153,7 +146,7 @@ class SimpleEdgeExpander {
candidates.find(to);
if (cand == candidates.end()) {
// Add weight
candidates.emplace(to, Traverser::Neighbor(to, edges[j]._id, 1));
candidates.emplace(to, Traverser::Step(from, to, 1, extractEdgeId(edges[j])));
} else {
// Compare weight
}
@ -166,12 +159,12 @@ class SimpleEdgeExpander {
if (from != source) {
candidates.find(from);
if (cand == candidates.end()) {
candidates.emplace(from, Traverser::Neighbor(from, edges[j]._id, 1));
candidates.emplace(from, Traverser::Step(to, from, 1, extractEdgeId(edges[j])));
}
} else if (to != source) {
candidates.find(to);
if (cand == candidates.end()) {
candidates.emplace(to, Traverser::Neighbor(to, edges[j]._id, 1));
candidates.emplace(to, Traverser::Step(from, to, 1, extractEdgeId(edges[j])));
}
}
}
@ -329,7 +322,7 @@ void TRI_RunDijkstraSearch (const v8::FunctionCallbackInfo<v8::Value>& args) {
SimpleEdgeExpander backwardExpander(TRI_EDGE_IN, ecol, edgeCollectionName, &resolver2, "B");
Traverser traverser(forwardExpander, backwardExpander);
unique_ptr<Traverser::Path> path(traverser.ShortestPath(startVertex, targetVertex));
unique_ptr<Traverser::Path> path(traverser.shortestPath(startVertex, targetVertex));
if (path.get() == nullptr) {
res = trx.finish(res);
v8::EscapableHandleScope scope(isolate);

View File

@ -23,6 +23,7 @@
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Michael Hackstein
/// @author Max Neunhoeffer
/// @author Copyright 2014-2015, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
@ -58,59 +59,73 @@ class Searcher : public Thread {
private:
void insertNeighbor (Traverser::ThreadInfo& info,
Traverser::VertexId& neighbor,
void insertNeighbor (Traverser::VertexId& neighbor,
Traverser::VertexId& predecessor,
Traverser::EdgeId& edge,
Traverser::EdgeWeight weight) {
std::lock_guard<std::mutex> guard(info.mutex);
auto it = info.lookup.find(neighbor);
std::lock_guard<std::mutex> guard(_myInfo._mutex);
Traverser::Step* s = _myInfo._pq.lookup(neighbor);
// Not found, so insert it:
if (it == info.lookup.end()) {
info.lookup.emplace(
neighbor,
Traverser::LookupInfo(weight, edge, predecessor)
);
info.queue.insert(
Traverser::QueueInfo(neighbor, weight)
);
if (s == nullptr) {
_myInfo._pq.insert(neighbor,
Traverser::Step(neighbor, predecessor,
weight, edge));
return;
}
if (it->second.done) {
if (s->_done) {
return;
}
if (it->second.weight > weight) {
Traverser::QueueInfo q(neighbor, it->second.weight);
info.queue.erase(q);
q.weight = weight;
info.queue.insert(q);
it->second.weight = weight;
if (s->_weight > weight) {
_myInfo._pq.lowerWeight(neighbor, weight);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Lookup a neighbor in the list of our peer.
/// @brief Lookup our current vertex in the data of our peer.
////////////////////////////////////////////////////////////////////////////////
void lookupPeer (Traverser::ThreadInfo& info,
Traverser::VertexId& neighbor,
void lookupPeer (Traverser::VertexId& vertex,
Traverser::EdgeWeight weight) {
std::lock_guard<std::mutex> guard(info.mutex);
auto it = info.lookup.find(neighbor);
if (it == info.lookup.end()) {
std::lock_guard<std::mutex> guard(_peerInfo._mutex);
Traverser::Step* s = _peerInfo._pq.lookup(vertex);
if (s == nullptr) {
// Not found, nothing more to do
return;
}
Traverser::EdgeWeight total = it->second.weight + weight;
if (total < _traverser->highscore) {
_traverser->highscore = total;
Traverser::EdgeWeight total = s->_weight + weight;
// Update the highscore:
std::lock_guard<std::mutex> guard2(_traverser->_resultMutex);
if (!_traverser->_highscoreSet || total < _traverser->_highscore) {
_traverser->_highscoreSet = true;
_traverser->_highscore = total;
}
if (it->second.done && total <= _traverser->highscore) {
std::lock_guard<std::mutex> guard(_traverser->resultMutex);
_traverser->intermediate = neighbor;
_traverser->bingo = true;
// Now the highscore is set!
// Did we find a solution together with the other thread?
if (s->_done) {
if (total <= _traverser->_highscore) {
_traverser->_intermediate = vertex;
_traverser->_bingo = true;
}
// We found a way, but somebody else found a better way, so
// this is not the shortest path
return;
}
// Did we find a solution on our own? This is for the single thread
// case and for the case that the other thread is too slow to even
// finish its own start vertex!
if (s->_weight == 0) {
// We have found the target, we have finished all vertices with
// a smaller weight than this one (and did not succeed), so this
// must be a best solution:
_traverser->_intermediate = vertex;
_traverser->_bingo = true;
}
}
@ -123,30 +138,27 @@ class Searcher : public Thread {
virtual void run () {
auto nextVertexIt = _myInfo.queue.begin();
std::vector<Traverser::Neighbor> neighbors;
Traverser::VertexId v;
Traverser::Step s;
bool b = _myInfo._pq.popMinimal(v, s, true);
std::vector<Traverser::Step> neighbors;
// Iterate while no bingo found and
// there still is a vertex on the stack.
while (!_traverser->bingo && nextVertexIt != _myInfo.queue.end()) {
auto nextVertex = *nextVertexIt;
_myInfo.queue.erase(nextVertexIt);
while (!_traverser->_bingo && b) {
neighbors.clear();
_expander(nextVertex.vertex, neighbors);
_expander(v, neighbors);
for (auto& neighbor : neighbors) {
insertNeighbor(_myInfo, neighbor.neighbor, nextVertex.vertex,
neighbor.edge, nextVertex.weight + neighbor.weight);
insertNeighbor(neighbor._vertex, v, neighbor._edge,
s._weight + neighbor._weight);
}
lookupPeer(_peerInfo, nextVertex.vertex, nextVertex.weight);
_myInfo.mutex.lock();
// Can move nextVertexLookup up?
auto nextVertexLookup = _myInfo.lookup.find(nextVertex.vertex);
lookupPeer(v, s._weight);
TRI_ASSERT(nextVertexLookup != _myInfo.lookup.end());
nextVertexLookup->second.done = true;
_myInfo.mutex.unlock();
nextVertexIt = _myInfo.queue.begin();
std::lock_guard<std::mutex> guard(_myInfo._mutex);
Traverser::Step* s2 = _myInfo._pq.lookup(v);
s2->_done = true;
b = _myInfo._pq.popMinimal(v, s, true);
}
}
};
@ -155,62 +167,60 @@ class Searcher : public Thread {
/// @brief return the shortest path between the start and target vertex.
////////////////////////////////////////////////////////////////////////////////
Traverser::Path* Traverser::ShortestPath (VertexId const& start,
VertexId const& target) {
Traverser::Path* Traverser::shortestPath (VertexId const& start,
VertexId const& target) {
// For the result:
std::deque<VertexId> r_vertices;
std::deque<VertexId> r_edges;
highscore = 1e50;
bingo = false;
_highscoreSet = false;
_highscore = 0;
_bingo = false;
// Forward with initialization:
_forwardLookup.clear();
_forwardLookup.emplace(start, LookupInfo(0, "", ""));
_forwardQueue.clear();
_forwardQueue.insert(QueueInfo(start, 0));
ThreadInfo forwardInfo(_forwardLookup, _forwardQueue, _forwardMutex);
string empty;
ThreadInfo forward;
forward._pq.insert(start, Step(start, empty, 0, empty));
_backwardLookup.clear();
_backwardLookup.emplace(target, LookupInfo(0, "", ""));
_backwardQueue.clear();
_backwardQueue.insert(QueueInfo(target, 0));
ThreadInfo backwardInfo(_backwardLookup, _backwardQueue, _backwardMutex);
// backward with initialization:
ThreadInfo backward;
backward._pq.insert(target, Step(target, empty, 0, empty));
Searcher forwardSearcher(this, forwardInfo, backwardInfo, start,
_forwardExpander, "X");
Searcher backwardSearcher(this, backwardInfo, forwardInfo, target,
_backwardExpander, "Y");
// Now the searcher threads:
Searcher forwardSearcher(this, forward, backward, start,
_forwardExpander, "Forward");
Searcher backwardSearcher(this, backward, forward, target,
_backwardExpander, "Backward");
forwardSearcher.start();
backwardSearcher.start();
forwardSearcher.join();
backwardSearcher.join();
if (!bingo || intermediate == "") {
if (!_bingo || _intermediate == "") {
return nullptr;
}
auto pathLookup = _forwardLookup.find(intermediate);
Step* s = forward._pq.lookup(_intermediate);
r_vertices.push_back(_intermediate);
// FORWARD Go path back from intermediate -> start.
// Insert all vertices and edges at front of vector
// Do NOT! insert the intermediate vertex
TRI_ASSERT(pathLookup != _forwardLookup.end());
r_vertices.push_back(intermediate);
while (pathLookup->second.predecessor != "") {
r_edges.push_front(pathLookup->second.edge);
r_vertices.push_front(pathLookup->second.predecessor);
pathLookup = _forwardLookup.find(pathLookup->second.predecessor);
while (s->_predecessor != "") {
r_edges.push_front(s->_edge);
r_vertices.push_front(s->_predecessor);
s = forward._pq.lookup(s->_predecessor);
}
// BACKWARD Go path back from intermediate -> target.
// Insert all vertices and edges at back of vector
// Also insert the intermediate vertex
pathLookup = _backwardLookup.find(intermediate);
TRI_ASSERT(pathLookup != _backwardLookup.end());
while (pathLookup->second.predecessor != "") {
r_edges.push_back(pathLookup->second.edge);
r_vertices.push_back(pathLookup->second.predecessor);
pathLookup = _backwardLookup.find(pathLookup->second.predecessor);
s = backward._pq.lookup(_intermediate);
while (s->_predecessor != "") {
r_edges.push_back(s->_edge);
r_vertices.push_back(s->_predecessor);
s = backward._pq.lookup(s->_predecessor);
}
Path* res = new Path(r_vertices, r_edges, highscore);
return res;
return new Path(r_vertices, r_edges, _highscore);
};

View File

@ -34,8 +34,6 @@
#include <mutex>
class Searcher;
namespace triagens {
namespace basics {
@ -158,21 +156,22 @@ namespace triagens {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief lookup
/// @brief lookup, note that the resulting pointer is only valid until the
/// the next modification of the data structure happens (insert or lowerWeight
/// or popMinimal). The weight in the Value type must not be modified other
/// than via lowerWeight, otherwise the queue order could be violated.
////////////////////////////////////////////////////////////////////////////////
Value const* lookup (Key const& k) {
Value* lookup (Key const& k) {
auto it = _lookup.find(k);
if (it == _lookup.end()) {
return nullptr;
}
if (it->second >= 0) { // still in the queue
return const_cast<Value const*>
(&(_heap[static_cast<size_t>(it->second) - _popped]));
return &(_heap[static_cast<size_t>(it->second) - _popped]);
}
else { // already in the history
return const_cast<Value const*>
(&(_history[static_cast<size_t>(-it->second) - 1]));
return &(_history[static_cast<size_t>(-it->second) - 1]);
}
}
@ -201,19 +200,24 @@ namespace triagens {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief getMinimal
/// @brief getMinimal, note that the resulting pointer is only valid until the
/// the next modification of the data structure happens (insert or lowerWeight
/// or popMinimal). The weight in the Value type must not be modified other
/// than via lowerWeight, otherwise the queue order could be violated.
////////////////////////////////////////////////////////////////////////////////
Value const* getMinimal() {
Value* getMinimal() {
if (_heap.empty()) {
return nullptr;
}
return const_cast<Value const*>(&(_heap[0]));
return &(_heap[0]);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief popMinimal, returns true if something was returned and false
/// if the structure is empty. Key and Value are stored in k and v.
/// If keepForLookup is true then the Value is kept for lookup in the
/// hash table but removed from the priority queue.
////////////////////////////////////////////////////////////////////////////////
bool popMinimal (Key& k, Value& v, bool keepForLookup = false) {
@ -358,15 +362,6 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
void removeFromHeap (bool keepForLookup) {
if (_heap.size() == 1) {
_heap.clear();
_popped = 0;
_lookup.clear();
_isHeap = false;
_maxWeight = 0;
return;
}
auto it = _lookup.find(_heap[0].getKey());
TRI_ASSERT(it != _lookup.end());
if (keepForLookup) {
@ -377,6 +372,14 @@ namespace triagens {
else {
_lookup.erase(it);
}
if (_heap.size() == 1) {
_heap.clear();
_popped = 0;
_isHeap = false;
_maxWeight = 0;
return;
}
// Move one in front:
_heap[0] = _heap.back();
_heap.pop_back();
it = _lookup.find(_heap[0].getKey());
@ -438,23 +441,29 @@ namespace triagens {
class Traverser {
friend class ::Searcher;
// -----------------------------------------------------------------------------
// --SECTION-- data structures
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- path
// --SECTION-- types
// -----------------------------------------------------------------------------
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief types for vertices, edges and weights
////////////////////////////////////////////////////////////////////////////////
typedef std::string VertexId;
typedef std::string EdgeId;
typedef double EdgeWeight;
////////////////////////////////////////////////////////////////////////////////
/// @brief Path, type for the result
////////////////////////////////////////////////////////////////////////////////
// Convention vertices.size() -1 === edges.size()
// path is vertices[0] , edges[0], vertices[1] etc.
struct Path {
@ -462,29 +471,43 @@ namespace triagens {
std::deque<EdgeId> edges;
EdgeWeight weight;
Path (
std::deque<VertexId> vertices,
std::deque<EdgeId> edges,
EdgeWeight weight
) : vertices(vertices),
edges(edges),
weight(weight) {
Path (std::deque<VertexId> vertices, std::deque<EdgeId> edges,
EdgeWeight weight)
: vertices(vertices), edges(edges), weight(weight) {
};
};
struct Neighbor {
VertexId neighbor;
EdgeId edge;
EdgeWeight weight;
////////////////////////////////////////////////////////////////////////////////
/// @brief Step, one position with a predecessor and the edge
////////////////////////////////////////////////////////////////////////////////
Neighbor (
VertexId neighbor,
EdgeId edge,
EdgeWeight weight
) : neighbor(neighbor),
edge(edge),
weight(weight) {
};
struct Step {
VertexId _vertex;
VertexId _predecessor;
EdgeWeight _weight;
EdgeId _edge;
bool _done;
Step () : _done(false) {
}
Step (VertexId const& vert, VertexId const& pred,
EdgeWeight weig, EdgeId const& edge)
: _vertex(vert), _predecessor(pred), _weight(weig), _edge(edge),
_done(false) {
}
EdgeWeight weight () const {
return _weight;
}
void setWeight (EdgeWeight w) {
_weight = w;
}
VertexId const& getKey () const {
return _vertex;
}
};
////////////////////////////////////////////////////////////////////////////////
@ -493,7 +516,11 @@ namespace triagens {
typedef enum {FORWARD, BACKWARD} Direction;
typedef std::function<void(VertexId source, std::vector<Neighbor>& result)>
////////////////////////////////////////////////////////////////////////////////
/// @brief callback to find neighbours
////////////////////////////////////////////////////////////////////////////////
typedef std::function<void(VertexId V, std::vector<Step>& result)>
ExpanderFunction;
// -----------------------------------------------------------------------------
@ -504,12 +531,12 @@ namespace triagens {
/// @brief create the Traverser
////////////////////////////////////////////////////////////////////////////////
Traverser (
ExpanderFunction forwardExpander,
ExpanderFunction backwardExpander
) : highscore(1e50),
bingo(false),
intermediate(""),
Traverser (ExpanderFunction forwardExpander,
ExpanderFunction backwardExpander)
: _highscoreSet(false),
_highscore(0),
_bingo(false),
_intermediate(""),
_forwardExpander(forwardExpander),
_backwardExpander(backwardExpander) {
};
@ -517,16 +544,14 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////
~Traverser () {
// TODO: Implement!!
};
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief Find the shortest path between start and target.
/// Only edges having the given direction are followed.
@ -535,91 +560,59 @@ namespace triagens {
// Caller has to free the result
// nullptr indicates there is no path
Path* ShortestPath (
Path* shortestPath (
VertexId const& start,
VertexId const& target
);
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// --SECTION-- public data
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief Function to compute all neighbors of a given vertex
/// @brief lowest total weight for a complete path found
////////////////////////////////////////////////////////////////////////////////
private:
bool _highscoreSet;
std::atomic<EdgeWeight> highscore;
std::atomic<bool> bingo;
std::mutex resultMutex;
VertexId intermediate;
////////////////////////////////////////////////////////////////////////////////
/// @brief lowest total weight for a complete path found
////////////////////////////////////////////////////////////////////////////////
struct LookupInfo {
EdgeWeight weight;
bool done;
EdgeId edge;
VertexId predecessor;
EdgeWeight _highscore;
LookupInfo (
EdgeWeight weight,
EdgeId edge,
VertexId predecessor
) : weight(weight),
done(false),
edge(edge),
predecessor(predecessor) {
};
};
////////////////////////////////////////////////////////////////////////////////
/// @brief _bingo, flag that indicates termination
////////////////////////////////////////////////////////////////////////////////
struct QueueInfo {
EdgeWeight weight;
VertexId vertex;
std::atomic<bool> _bingo;
QueueInfo (
VertexId vertex,
EdgeWeight weight
) : weight(weight),
vertex(vertex) {
};
////////////////////////////////////////////////////////////////////////////////
/// @brief _resultMutex, this is used to protect access to the result data
////////////////////////////////////////////////////////////////////////////////
friend bool operator< (QueueInfo const& a, QueueInfo const& b) {
if (a.weight == b.weight) {
return a.vertex < b.vertex;
}
return a.weight < b.weight;
};
std::mutex _resultMutex;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief _intermediate, one vertex on the shortest path found
////////////////////////////////////////////////////////////////////////////////
VertexId _intermediate;
// -----------------------------------------------------------------------------
// --SECTION-- private data
// -----------------------------------------------------------------------------
typedef triagens::basics::PriorityQueue<VertexId, Step, EdgeWeight>
PQueue;
// TODO: Destructor?!
struct ThreadInfo {
std::unordered_map<VertexId, LookupInfo>& lookup;
std::set<QueueInfo, std::less<QueueInfo>>& queue;
std::mutex& mutex;
ThreadInfo (
std::unordered_map<VertexId, LookupInfo>& lookup,
std::set<QueueInfo, std::less<QueueInfo>>& queue,
std::mutex& mutex
) : lookup(lookup),
queue(queue),
mutex(mutex) {
};
PQueue _pq;
std::mutex _mutex;
};
ExpanderFunction _forwardExpander;
ExpanderFunction _backwardExpander;
// ShortestPath will create these variables
std::unordered_map<VertexId, LookupInfo> _forwardLookup;
std::set<QueueInfo, std::less<QueueInfo>> _forwardQueue;
std::mutex _forwardMutex;
std::unordered_map<VertexId, LookupInfo> _backwardLookup;
std::set<QueueInfo, std::less<QueueInfo>> _backwardQueue;
std::mutex _backwardMutex;
};
}
}