Initial Import.
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef BINARYHEAP_H_INCLUDED
|
||||
#define BINARYHEAP_H_INCLUDED
|
||||
|
||||
//Not compatible with non contiguous node ids
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <google/dense_hash_map>
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class ArrayStorage {
|
||||
public:
|
||||
|
||||
ArrayStorage( size_t size )
|
||||
: positions( new Key[size] ) {}
|
||||
|
||||
~ArrayStorage() {
|
||||
delete[] positions;
|
||||
}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return positions[node];
|
||||
}
|
||||
|
||||
void Clear() {}
|
||||
|
||||
private:
|
||||
Key* positions;
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class MapStorage {
|
||||
public:
|
||||
|
||||
MapStorage( size_t size = 0 ) {}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map< NodeID, Key > nodes;
|
||||
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class SparseStorage {
|
||||
public:
|
||||
|
||||
SparseStorage( size_t size = 0 ) { nodes.set_empty_key(UINT_MAX); }
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
google::dense_hash_map< NodeID, Key > nodes;
|
||||
};
|
||||
|
||||
template < typename NodeID, typename Key, typename Weight, typename Data, typename IndexStorage = ArrayStorage< NodeID, Key > >
|
||||
class BinaryHeap {
|
||||
private:
|
||||
BinaryHeap( const BinaryHeap& right );
|
||||
void operator=( const BinaryHeap& right );
|
||||
public:
|
||||
typedef Weight WeightType;
|
||||
typedef Data DataType;
|
||||
|
||||
BinaryHeap( size_t maxID )
|
||||
: nodeIndex( maxID ) {
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
heap.resize( 1 );
|
||||
insertedNodes.clear();
|
||||
heap[0].weight = 0;
|
||||
}
|
||||
|
||||
Key Size() const {
|
||||
return ( Key )( heap.size() - 1 );
|
||||
}
|
||||
|
||||
void Insert( NodeID node, Weight weight, const Data &data ) {
|
||||
HeapElement element;
|
||||
element.index = ( NodeID ) insertedNodes.size();
|
||||
element.weight = weight;
|
||||
const Key key = ( Key ) heap.size();
|
||||
heap.push_back( element );
|
||||
insertedNodes.push_back( HeapNode( node, key, weight, data ) );
|
||||
nodeIndex[node] = element.index;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
Data& GetData( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].data;
|
||||
}
|
||||
|
||||
Weight& GetKey( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].weight;
|
||||
}
|
||||
|
||||
bool WasRemoved( NodeID node ) {
|
||||
assert( WasInserted( node ) );
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].key == 0;
|
||||
}
|
||||
|
||||
bool WasInserted( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
if ( index >= ( Key ) insertedNodes.size() )
|
||||
return false;
|
||||
return insertedNodes[index].node == node;
|
||||
}
|
||||
|
||||
NodeID Min() const {
|
||||
assert( heap.size() > 1 );
|
||||
return insertedNodes[heap[1].index].node;
|
||||
}
|
||||
|
||||
NodeID DeleteMin() {
|
||||
assert( heap.size() > 1 );
|
||||
const Key removedIndex = heap[1].index;
|
||||
heap[1] = heap[heap.size()-1];
|
||||
heap.pop_back();
|
||||
if ( heap.size() > 1 )
|
||||
Downheap( 1 );
|
||||
insertedNodes[removedIndex].key = 0;
|
||||
CheckHeap();
|
||||
return insertedNodes[removedIndex].node;
|
||||
}
|
||||
|
||||
void DeleteAll() {
|
||||
for ( typename std::vector< HeapElement >::iterator i = heap.begin() + 1, iend = heap.end(); i != iend; ++i )
|
||||
insertedNodes[i->index].key = 0;
|
||||
heap.resize( 1 );
|
||||
heap[0].weight = 0;
|
||||
}
|
||||
|
||||
void DecreaseKey( NodeID node, Weight weight ) {
|
||||
const Key index = nodeIndex[node];
|
||||
Key key = insertedNodes[index].key;
|
||||
assert ( key != 0 );
|
||||
|
||||
insertedNodes[index].weight = weight;
|
||||
heap[key].weight = weight;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
private:
|
||||
class HeapNode {
|
||||
public:
|
||||
HeapNode() {
|
||||
}
|
||||
HeapNode( NodeID n, Key k, Weight w, Data d )
|
||||
: node( n ), key( k ), weight( w ), data( d ) {
|
||||
}
|
||||
|
||||
NodeID node;
|
||||
Key key;
|
||||
Weight weight;
|
||||
Data data;
|
||||
};
|
||||
struct HeapElement {
|
||||
Key index;
|
||||
Weight weight;
|
||||
};
|
||||
|
||||
std::vector< HeapNode > insertedNodes;
|
||||
std::vector< HeapElement > heap;
|
||||
IndexStorage nodeIndex;
|
||||
|
||||
void Downheap( Key key ) {
|
||||
const Key droppingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key << 1;
|
||||
while ( nextKey < ( Key ) heap.size() ) {
|
||||
const Key nextKeyOther = nextKey + 1;
|
||||
if ( ( nextKeyOther < ( Key ) heap.size() ) )
|
||||
if ( heap[nextKey].weight > heap[nextKeyOther].weight )
|
||||
nextKey = nextKeyOther;
|
||||
|
||||
if ( weight <= heap[nextKey].weight )
|
||||
break;
|
||||
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey <<= 1;
|
||||
}
|
||||
heap[key].index = droppingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[droppingIndex].key = key;
|
||||
}
|
||||
|
||||
void Upheap( Key key ) {
|
||||
const Key risingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key >> 1;
|
||||
while ( heap[nextKey].weight > weight ) {
|
||||
assert( nextKey != 0 );
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey >>= 1;
|
||||
}
|
||||
heap[key].index = risingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[risingIndex].key = key;
|
||||
}
|
||||
|
||||
void CheckHeap() {
|
||||
/*for ( Key i = 2; i < heap.size(); ++i ) {
|
||||
assert( heap[i].weight >= heap[i >> 1].weight );
|
||||
}*/
|
||||
}
|
||||
};
|
||||
|
||||
#endif //#ifndef BINARYHEAP_H_INCLUDED
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef CONTRACTIONCLEANUP_H_INCLUDED
|
||||
#define CONTRACTIONCLEANUP_H_INCLUDED
|
||||
|
||||
#ifdef _GLIBCXX_PARALLEL
|
||||
#include <parallel/algorithm>
|
||||
#else
|
||||
#include <algorithm>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include "Contractor.h"
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
class ContractionCleanup {
|
||||
private:
|
||||
|
||||
struct _HeapData {
|
||||
NodeID parent;
|
||||
_HeapData( NodeID p ) {
|
||||
parent = p;
|
||||
}
|
||||
};
|
||||
typedef BinaryHeap< NodeID, NodeID, int, _HeapData > _Heap;
|
||||
|
||||
struct _ThreadData {
|
||||
_Heap* _heapForward;
|
||||
_Heap* _heapBackward;
|
||||
_ThreadData( NodeID nodes ) {
|
||||
_heapBackward = new _Heap(nodes);
|
||||
_heapForward = new _Heap(nodes);
|
||||
}
|
||||
~_ThreadData()
|
||||
{
|
||||
delete _heapBackward;
|
||||
delete _heapForward;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
struct Edge {
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
struct EdgeData {
|
||||
int distance : 29;
|
||||
bool shortcut : 1;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
NodeID middle;
|
||||
} data;
|
||||
|
||||
//sorts by source and other attributes
|
||||
static bool CompareBySource( const Edge& left, const Edge& right ) {
|
||||
if ( left.source != right.source )
|
||||
return left.source < right.source;
|
||||
int l = ( left.data.forward ? -1 : 0 ) + ( left.data.backward ? -1 : 0 );
|
||||
int r = ( right.data.forward ? -1 : 0 ) + ( right.data.backward ? -1 : 0 );
|
||||
if ( l != r )
|
||||
return l < r;
|
||||
if ( left.target != right.target )
|
||||
return left.target < right.target;
|
||||
return left.data.distance < right.data.distance;
|
||||
}
|
||||
|
||||
bool operator== ( const Edge& right ) const {
|
||||
return ( source == right.source && target == right.target && data.distance == right.data.distance && data.shortcut == right.data.shortcut && data.forward == right.data.forward && data.backward == right.data.backward && data.middle == right.data.middle );
|
||||
}
|
||||
};
|
||||
|
||||
ContractionCleanup( int numNodes, const std::vector< Edge >& edges ) {
|
||||
_graph = edges;
|
||||
_numNodes = numNodes;
|
||||
}
|
||||
|
||||
~ContractionCleanup() {
|
||||
|
||||
}
|
||||
|
||||
void Run() {
|
||||
|
||||
double time = _Timestamp();
|
||||
|
||||
RemoveUselessShortcuts();
|
||||
|
||||
time = _Timestamp() - time;
|
||||
cout << "Postprocessing Time: " << time << " s" << endl;
|
||||
}
|
||||
|
||||
template< class Edge >
|
||||
void GetData( std::vector< Edge >& edges ) {
|
||||
for ( int edge = 0, endEdges = ( int ) _graph.size(); edge != endEdges; ++edge ) {
|
||||
Edge newEdge;
|
||||
newEdge.source = _graph[edge].source;
|
||||
newEdge.target = _graph[edge].target;
|
||||
|
||||
newEdge.data.distance = _graph[edge].data.distance;
|
||||
newEdge.data.shortcut = _graph[edge].data.shortcut;
|
||||
if ( newEdge.data.shortcut )
|
||||
newEdge.data.middle = _graph[edge].data.middle;
|
||||
newEdge.data.forward = _graph[edge].data.forward;
|
||||
newEdge.data.backward = _graph[edge].data.backward;
|
||||
edges.push_back( newEdge );
|
||||
}
|
||||
#ifdef _GLIBCXX_PARALLEL
|
||||
__gnu_parallel::sort( edges.begin(), edges.end() );
|
||||
#else
|
||||
sort( edges.begin(), edges.end() );
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
class AllowForwardEdge {
|
||||
public:
|
||||
bool operator()( const Edge& data ) const {
|
||||
return data.data.forward;
|
||||
}
|
||||
};
|
||||
|
||||
class AllowBackwardEdge {
|
||||
public:
|
||||
bool operator()( const Edge& data ) const {
|
||||
return data.data.backward;
|
||||
}
|
||||
};
|
||||
|
||||
double _Timestamp() {
|
||||
struct timeval tp;
|
||||
gettimeofday(&tp, NULL);
|
||||
return double(tp.tv_sec) + tp.tv_usec / 1000000.;
|
||||
}
|
||||
|
||||
void BuildOutgoingGraph() {
|
||||
//sort edges by source
|
||||
#ifdef _GLIBCXX_PARALLEL
|
||||
__gnu_parallel::sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
|
||||
#else
|
||||
sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
|
||||
#endif
|
||||
_firstEdge.resize( _numNodes + 1 );
|
||||
_firstEdge[0] = 0;
|
||||
for ( NodeID i = 0, node = 0; i < ( NodeID ) _graph.size(); i++ ) {
|
||||
while ( _graph[i].source != node )
|
||||
_firstEdge[++node] = i;
|
||||
if ( i == ( NodeID ) _graph.size() - 1 )
|
||||
while ( node < _numNodes )
|
||||
_firstEdge[++node] = ( int ) _graph.size();
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveUselessShortcuts() {
|
||||
int maxThreads = omp_get_max_threads();
|
||||
std::vector < _ThreadData* > threadData;
|
||||
for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( _numNodes ) );
|
||||
}
|
||||
|
||||
cout << "Scanning for useless shortcuts" << endl;
|
||||
BuildOutgoingGraph();
|
||||
#pragma omp parallel for
|
||||
for ( unsigned i = 0; i < ( unsigned ) _graph.size(); i++ ) {
|
||||
for ( unsigned edge = _firstEdge[_graph[i].source]; edge < _firstEdge[_graph[i].source + 1]; ++edge ) {
|
||||
if ( edge == i )
|
||||
continue;
|
||||
if ( _graph[edge].target != _graph[i].target )
|
||||
continue;
|
||||
if ( _graph[edge].data.distance < _graph[i].data.distance )
|
||||
continue;
|
||||
|
||||
_graph[edge].data.forward &= !_graph[i].data.forward;
|
||||
_graph[edge].data.backward &= !_graph[i].data.backward;
|
||||
}
|
||||
|
||||
if ( !_graph[i].data.forward && !_graph[i].data.backward )
|
||||
continue;
|
||||
|
||||
//only remove shortcuts
|
||||
if ( !_graph[i].data.shortcut )
|
||||
continue;
|
||||
|
||||
if ( _graph[i].data.forward ) {
|
||||
int result = _ComputeDistance( _graph[i].source, _graph[i].target, threadData[omp_get_thread_num()] );
|
||||
if ( result < _graph[i].data.distance ) {
|
||||
_graph[i].data.forward = false;
|
||||
Contractor::Witness temp;
|
||||
temp.source = _graph[i].source;
|
||||
temp.target = _graph[i].target;
|
||||
temp.middle = _graph[i].data.middle;
|
||||
}
|
||||
}
|
||||
if ( _graph[i].data.backward ) {
|
||||
int result = _ComputeDistance( _graph[i].target, _graph[i].source, threadData[omp_get_thread_num()] );
|
||||
|
||||
if ( result < _graph[i].data.distance ) {
|
||||
_graph[i].data.backward = false;
|
||||
Contractor::Witness temp;
|
||||
temp.source = _graph[i].target;
|
||||
temp.target = _graph[i].source;
|
||||
temp.middle = _graph[i].data.middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Removing edges" << endl;
|
||||
int usefull = 0;
|
||||
for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
|
||||
if ( !_graph[i].data.forward && !_graph[i].data.backward && _graph[i].data.shortcut )
|
||||
continue;
|
||||
_graph[usefull] = _graph[i];
|
||||
usefull++;
|
||||
}
|
||||
cout << "Removed " << _graph.size() - usefull << " useless shortcuts" << endl;
|
||||
_graph.resize( usefull );
|
||||
}
|
||||
|
||||
template< class EdgeAllowed, class StallEdgeAllowed > void _ComputeStep( _Heap* heapForward, _Heap* heapBackward, const EdgeAllowed& edgeAllowed, const StallEdgeAllowed& stallEdgeAllowed, NodeID* middle, int* targetDistance ) {
|
||||
|
||||
const NodeID node = heapForward->DeleteMin();
|
||||
const int distance = heapForward->GetKey( node );
|
||||
|
||||
if ( heapBackward->WasInserted( node ) ) {
|
||||
const int newDistance = heapBackward->GetKey( node ) + distance;
|
||||
if ( newDistance < *targetDistance ) {
|
||||
*middle = node;
|
||||
*targetDistance = newDistance;
|
||||
}
|
||||
}
|
||||
|
||||
if ( distance > *targetDistance ) {
|
||||
heapForward->DeleteAll();
|
||||
return;
|
||||
}
|
||||
for ( int edge = _firstEdge[node], endEdges = _firstEdge[node + 1]; edge != endEdges; ++edge ) {
|
||||
const NodeID to = _graph[edge].target;
|
||||
const int edgeWeight = _graph[edge].data.distance;
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
if ( edgeAllowed( _graph[edge] ) ) {
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !heapForward->WasInserted( to ) )
|
||||
heapForward->Insert( to, toDistance, node );
|
||||
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < heapForward->GetKey( to ) ) {
|
||||
heapForward->DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
heapForward->GetData( to ) = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int _ComputeDistance( NodeID source, NodeID target, _ThreadData * data, std::vector< NodeID >* path = NULL ) {
|
||||
data->_heapForward->Clear();
|
||||
data->_heapBackward->Clear();
|
||||
//insert source into heap
|
||||
data->_heapForward->Insert( source, 0, source );
|
||||
data->_heapBackward->Insert( target, 0, target );
|
||||
|
||||
int targetDistance = std::numeric_limits< int >::max();
|
||||
NodeID middle = 0;
|
||||
AllowForwardEdge forward;
|
||||
AllowBackwardEdge backward;
|
||||
|
||||
while ( data->_heapForward->Size() + data->_heapBackward->Size() > 0 ) {
|
||||
|
||||
if ( data->_heapForward->Size() > 0 ) {
|
||||
_ComputeStep( data->_heapForward, data->_heapBackward, forward, backward, &middle, &targetDistance );
|
||||
}
|
||||
|
||||
if ( data->_heapBackward->Size() > 0 ) {
|
||||
_ComputeStep( data->_heapBackward, data->_heapForward, backward, forward, &middle, &targetDistance );
|
||||
}
|
||||
}
|
||||
|
||||
if ( targetDistance == std::numeric_limits< int >::max() )
|
||||
return std::numeric_limits< unsigned >::max();
|
||||
|
||||
return targetDistance;
|
||||
}
|
||||
NodeID _numNodes;
|
||||
std::vector< Edge > _graph;
|
||||
std::vector< unsigned > _firstEdge;
|
||||
};
|
||||
|
||||
#endif // CONTRACTIONCLEANUP_H_INCLUDED
|
||||
@@ -0,0 +1,726 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef CONTRACTOR_H_INCLUDED
|
||||
#define CONTRACTOR_H_INCLUDED
|
||||
#ifdef _GLIBCXX_PARALLEL
|
||||
#include <parallel/algorithm>
|
||||
#else
|
||||
#include <algorithm>
|
||||
#endif
|
||||
#include "DynamicGraph.h"
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <limits>
|
||||
#include <omp.h>
|
||||
|
||||
class Contractor {
|
||||
|
||||
public:
|
||||
|
||||
struct Witness {
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
NodeID middle;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
struct _EdgeData {
|
||||
int distance;
|
||||
unsigned originalEdges : 29;
|
||||
bool shortcut : 1;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
NodeID middle;
|
||||
} data;
|
||||
|
||||
struct _HeapData {
|
||||
//short hops;
|
||||
//_HeapData() {
|
||||
// hops = 0;
|
||||
//}
|
||||
//_HeapData( int h ) {
|
||||
// hops = h;
|
||||
//}
|
||||
};
|
||||
|
||||
typedef DynamicGraph< _EdgeData > _DynamicGraph;
|
||||
typedef BinaryHeap< NodeID, NodeID, int, _HeapData > _Heap;
|
||||
typedef _DynamicGraph::InputEdge _ImportEdge;
|
||||
|
||||
struct _ThreadData {
|
||||
_Heap heap;
|
||||
std::vector< _ImportEdge > insertedEdges;
|
||||
std::vector< Witness > witnessList;
|
||||
_ThreadData( NodeID nodes ): heap( nodes ) {
|
||||
}
|
||||
};
|
||||
|
||||
struct _PriorityData {
|
||||
int depth;
|
||||
NodeID bias;
|
||||
_PriorityData() {
|
||||
depth = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct _ContractionInformation {
|
||||
int edgesDeleted;
|
||||
int edgesAdded;
|
||||
int originalEdgesDeleted;
|
||||
int originalEdgesAdded;
|
||||
_ContractionInformation() {
|
||||
edgesAdded = edgesDeleted = originalEdgesAdded = originalEdgesDeleted = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct _NodePartitionor {
|
||||
bool operator()( std::pair< NodeID, bool > nodeData ) {
|
||||
return !nodeData.second;
|
||||
}
|
||||
};
|
||||
|
||||
struct _LogItem {
|
||||
unsigned iteration;
|
||||
NodeID nodes;
|
||||
double contraction;
|
||||
double independent;
|
||||
double inserting;
|
||||
double removing;
|
||||
double updating;
|
||||
|
||||
_LogItem() {
|
||||
iteration = nodes = contraction = independent = inserting = removing = updating = 0;
|
||||
}
|
||||
|
||||
double GetTotalTime() const {
|
||||
return contraction + independent + inserting + removing + updating;
|
||||
}
|
||||
|
||||
void PrintStatistics( int interation ) const {
|
||||
cout << iteration << "\t" << nodes << "\t" << independent << "\t" << contraction << "\t" << inserting << "\t" << removing << "\t" << updating << endl;
|
||||
}
|
||||
};
|
||||
|
||||
class _LogData {
|
||||
public:
|
||||
|
||||
std::vector < _LogItem > iterations;
|
||||
|
||||
unsigned GetNIterations() {
|
||||
return ( unsigned ) iterations.size();
|
||||
}
|
||||
|
||||
_LogItem GetSum() const {
|
||||
_LogItem sum;
|
||||
sum.iteration = ( unsigned ) iterations.size();
|
||||
|
||||
for ( int i = 0, e = ( int ) iterations.size(); i < e; ++i ) {
|
||||
sum.nodes += iterations[i].nodes;
|
||||
sum.contraction += iterations[i].contraction;
|
||||
sum.independent += iterations[i].independent;
|
||||
sum.inserting += iterations[i].inserting;
|
||||
sum.removing += iterations[i].removing;
|
||||
sum.updating += iterations[i].updating;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
void PrintHeader() const {
|
||||
cout << "Iteration\tNodes\tIndependent\tContraction\tInserting\tRemoving\tUpdating" << endl;
|
||||
}
|
||||
|
||||
void PrintSummary() const {
|
||||
PrintHeader();
|
||||
GetSum().PrintStatistics(( int ) iterations.size() );
|
||||
}
|
||||
|
||||
void Print() const {
|
||||
PrintHeader();
|
||||
for ( int i = 0, e = ( int ) iterations.size(); i < e; ++i ) {
|
||||
iterations[i].PrintStatistics( i );
|
||||
}
|
||||
}
|
||||
|
||||
void Insert( const _LogItem& data ) {
|
||||
iterations.push_back( data );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
template< class InputEdge >
|
||||
Contractor( int nodes, std::vector< InputEdge >& inputEdges ) {
|
||||
std::vector< _ImportEdge > edges;
|
||||
edges.reserve( 2 * inputEdges.size() );
|
||||
for ( typename std::vector< InputEdge >::const_iterator i = inputEdges.begin(), e = inputEdges.end(); i != e; ++i ) {
|
||||
_ImportEdge edge;
|
||||
edge.source = i->source();
|
||||
edge.target = i->target();
|
||||
|
||||
edge.data.distance = std::max((int)i->weight(), 1 );
|
||||
assert( edge.data.distance > 0 );
|
||||
if ( edge.data.distance > 24 * 60 * 60 * 10 ) {
|
||||
cout << "Edge Weight too large -> May lead to invalid CH" << endl;
|
||||
continue;
|
||||
}
|
||||
if ( edge.data.distance <= 0 ) {
|
||||
cout << "Edge Weight too small -> May lead to invalid CH or Crashes"<< endl;
|
||||
continue;
|
||||
}
|
||||
edge.data.shortcut = false;
|
||||
edge.data.middle = 0;
|
||||
edge.data.forward = i->isForward();
|
||||
edge.data.backward = i->isBackward();
|
||||
edge.data.originalEdges = 1;
|
||||
edges.push_back( edge );
|
||||
std::swap( edge.source, edge.target );
|
||||
edge.data.forward = i->isBackward();
|
||||
edge.data.backward = i->isForward();
|
||||
edges.push_back( edge );
|
||||
}
|
||||
std::vector< InputEdge >().swap( inputEdges ); //free memory
|
||||
#ifdef _GLIBCXX_PARALLEL
|
||||
__gnu_parallel::sort( edges.begin(), edges.end() );
|
||||
#else
|
||||
sort( edges.begin(), edges.end() );
|
||||
#endif
|
||||
NodeID edge = 0;
|
||||
for ( NodeID i = 0; i < edges.size(); ) {
|
||||
const NodeID source = edges[i].source;
|
||||
const NodeID target = edges[i].target;
|
||||
//remove eigenloops
|
||||
if ( source == target ) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
_ImportEdge forwardEdge;
|
||||
_ImportEdge backwardEdge;
|
||||
forwardEdge.source = backwardEdge.source = source;
|
||||
forwardEdge.target = backwardEdge.target = target;
|
||||
forwardEdge.data.forward = backwardEdge.data.backward = true;
|
||||
forwardEdge.data.backward = backwardEdge.data.forward = false;
|
||||
forwardEdge.data.middle = backwardEdge.data.middle = 0;
|
||||
forwardEdge.data.shortcut = backwardEdge.data.shortcut = false;
|
||||
forwardEdge.data.originalEdges = backwardEdge.data.originalEdges = 1;
|
||||
forwardEdge.data.distance = backwardEdge.data.distance = std::numeric_limits< int >::max();
|
||||
//remove parallel edges
|
||||
while ( i < edges.size() && edges[i].source == source && edges[i].target == target ) {
|
||||
if ( edges[i].data.forward )
|
||||
forwardEdge.data.distance = std::min( edges[i].data.distance, forwardEdge.data.distance );
|
||||
if ( edges[i].data.backward )
|
||||
backwardEdge.data.distance = std::min( edges[i].data.distance, backwardEdge.data.distance );
|
||||
i++;
|
||||
}
|
||||
//merge edges (s,t) and (t,s) into bidirectional edge
|
||||
if ( forwardEdge.data.distance == backwardEdge.data.distance ) {
|
||||
if ( forwardEdge.data.distance != std::numeric_limits< int >::max() ) {
|
||||
forwardEdge.data.backward = true;
|
||||
edges[edge++] = forwardEdge;
|
||||
}
|
||||
} else { //insert seperate edges
|
||||
if ( forwardEdge.data.distance != std::numeric_limits< int >::max() ) {
|
||||
edges[edge++] = forwardEdge;
|
||||
}
|
||||
if ( backwardEdge.data.distance != std::numeric_limits< int >::max() ) {
|
||||
edges[edge++] = backwardEdge;
|
||||
}
|
||||
}
|
||||
}
|
||||
cout << "Removed " << edges.size() - edge << " edges of " << edges.size() << endl;
|
||||
edges.resize( edge );
|
||||
_graph = new _DynamicGraph( nodes, edges );
|
||||
|
||||
std::vector< _ImportEdge >().swap( edges );
|
||||
}
|
||||
|
||||
~Contractor() {
|
||||
delete _graph;
|
||||
}
|
||||
|
||||
template< class InputEdge >
|
||||
void checkForAllOrigEdges(std::vector< InputEdge >& inputEdges)
|
||||
{
|
||||
for(unsigned int i = 0; i < inputEdges.size(); i++)
|
||||
{
|
||||
bool found = false;
|
||||
_DynamicGraph::EdgeIterator eit = _graph->BeginEdges(inputEdges[i].source());
|
||||
for(;eit<_graph->EndEdges(inputEdges[i].source()); eit++)
|
||||
{
|
||||
if(_graph->GetEdgeData(eit).distance = inputEdges[i].weight())
|
||||
found = true;
|
||||
}
|
||||
eit = _graph->BeginEdges(inputEdges[i].target());
|
||||
for(;eit<_graph->EndEdges(inputEdges[i].target()); eit++)
|
||||
{
|
||||
if(_graph->GetEdgeData(eit).distance = inputEdges[i].weight())
|
||||
found = true;
|
||||
}
|
||||
assert(found);
|
||||
}
|
||||
}
|
||||
|
||||
void Run() {
|
||||
const NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||
_LogData log;
|
||||
|
||||
int maxThreads = omp_get_max_threads();
|
||||
std::vector < _ThreadData* > threadData;
|
||||
for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( numberOfNodes ) );
|
||||
}
|
||||
cout << numberOfNodes << " nodes, " << _graph->GetNumberOfEdges() << " edges" << endl;
|
||||
cout << "using " << maxThreads << " threads" << endl;
|
||||
|
||||
NodeID levelID = 0;
|
||||
NodeID iteration = 0;
|
||||
std::vector< std::pair< NodeID, bool > > remainingNodes( numberOfNodes );
|
||||
std::vector< double > nodePriority( numberOfNodes );
|
||||
std::vector< _PriorityData > nodeData( numberOfNodes );
|
||||
|
||||
//initialize the variables
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x )
|
||||
remainingNodes[x].first = x;
|
||||
std::random_shuffle( remainingNodes.begin(), remainingNodes.end() );
|
||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x )
|
||||
nodeData[remainingNodes[x].first].bias = x;
|
||||
|
||||
cout << "Initialise Elimination PQ... " << endl;
|
||||
_LogItem statistics0;
|
||||
statistics0.updating = _Timestamp();
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided )
|
||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x ) {
|
||||
nodePriority[x] = _Evaluate( data, &nodeData[x], x );
|
||||
}
|
||||
}
|
||||
cout << "done" << endl;
|
||||
|
||||
statistics0.updating = _Timestamp() - statistics0.updating;
|
||||
log.Insert( statistics0 );
|
||||
|
||||
log.PrintHeader();
|
||||
statistics0.PrintStatistics( 0 );
|
||||
|
||||
while ( levelID < numberOfNodes ) {
|
||||
_LogItem statistics;
|
||||
statistics.iteration = iteration++;
|
||||
const int last = ( int ) remainingNodes.size();
|
||||
|
||||
//determine independent node set
|
||||
double timeLast = _Timestamp();
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for ( int i = 0; i < last; ++i ) {
|
||||
const NodeID node = remainingNodes[i].first;
|
||||
remainingNodes[i].second = _IsIndependent( _graph, nodePriority, nodeData, node );
|
||||
}
|
||||
_NodePartitionor functor;
|
||||
const std::vector < std::pair < NodeID, bool > >::const_iterator first = stable_partition( remainingNodes.begin(), remainingNodes.end(), functor );
|
||||
const int firstIndependent = first - remainingNodes.begin();
|
||||
statistics.nodes = last - firstIndependent;
|
||||
statistics.independent += _Timestamp() - timeLast;
|
||||
timeLast = _Timestamp();
|
||||
|
||||
//contract independent nodes
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].first;
|
||||
_Contract< false > ( data, x );
|
||||
nodePriority[x] = -1;
|
||||
}
|
||||
std::sort( data->insertedEdges.begin(), data->insertedEdges.end() );
|
||||
}
|
||||
statistics.contraction += _Timestamp() - timeLast;
|
||||
timeLast = _Timestamp();
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].first;
|
||||
_DeleteIncommingEdges( data, x );
|
||||
}
|
||||
}
|
||||
statistics.removing += _Timestamp() - timeLast;
|
||||
timeLast = _Timestamp();
|
||||
|
||||
//insert new edges
|
||||
for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
_ThreadData& data = *threadData[threadNum];
|
||||
for ( int i = 0; i < ( int ) data.insertedEdges.size(); ++i ) {
|
||||
const _ImportEdge& edge = data.insertedEdges[i];
|
||||
bool found = false;
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( edge.source ) ; e < _graph->EndEdges( edge.source ) ; ++e ) {
|
||||
const NodeID target = _graph->GetTarget( e );
|
||||
if ( target != edge.target )
|
||||
continue;
|
||||
_EdgeData& data = _graph->GetEdgeData( e );
|
||||
if ( data.distance != edge.data.distance )
|
||||
continue;
|
||||
if ( data.shortcut != edge.data.shortcut )
|
||||
continue;
|
||||
if ( data.middle != edge.data.middle )
|
||||
continue;
|
||||
data.forward |= edge.data.forward;
|
||||
data.backward |= edge.data.backward;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if ( !found )
|
||||
_graph->InsertEdge( edge.source, edge.target, edge.data );
|
||||
}
|
||||
std::vector< _ImportEdge >().swap( data.insertedEdges );
|
||||
}
|
||||
statistics.inserting += _Timestamp() - timeLast;
|
||||
timeLast = _Timestamp();
|
||||
|
||||
//update priorities
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].first;
|
||||
_UpdateNeighbours( &nodePriority, &nodeData, data, x );
|
||||
}
|
||||
}
|
||||
statistics.updating += _Timestamp() - timeLast;
|
||||
timeLast = _Timestamp();
|
||||
|
||||
//output some statistics
|
||||
statistics.PrintStatistics( iteration + 1 );
|
||||
//LogVerbose( wxT( "Printed" ) );
|
||||
|
||||
//remove contracted nodes from the pool
|
||||
levelID += last - firstIndependent;
|
||||
remainingNodes.resize( firstIndependent );
|
||||
std::vector< std::pair< NodeID, bool > >( remainingNodes ).swap( remainingNodes );
|
||||
log.Insert( statistics );
|
||||
}
|
||||
|
||||
for ( int threadNum = 0; threadNum < maxThreads; threadNum++ ) {
|
||||
// _witnessList.insert( _witnessList.end(), threadData[threadNum]->witnessList.begin(), threadData[threadNum]->witnessList.end() );
|
||||
delete threadData[threadNum];
|
||||
}
|
||||
|
||||
log.PrintSummary();
|
||||
cout << "Total Time: " << log.GetSum().GetTotalTime()<< " s" << endl;
|
||||
cout << "checking sanity of generated data ..." << flush;
|
||||
_CheckCH<_EdgeData>();
|
||||
cout << "ok" << endl;
|
||||
}
|
||||
|
||||
template< class Edge >
|
||||
void GetEdges( std::vector< Edge >& edges ) {
|
||||
NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||
for ( NodeID node = 0; node < numberOfNodes; ++node ) {
|
||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge < endEdges; edge++ ) {
|
||||
const NodeID target = _graph->GetTarget( edge );
|
||||
const _EdgeData& data = _graph->GetEdgeData( edge );
|
||||
Edge newEdge;
|
||||
newEdge.source = node;
|
||||
newEdge.target = target;
|
||||
newEdge.data.distance = data.distance;
|
||||
newEdge.data.shortcut = data.shortcut;
|
||||
newEdge.data.middle = data.middle;
|
||||
newEdge.data.forward = data.forward;
|
||||
newEdge.data.backward = data.backward;
|
||||
edges.push_back( newEdge );
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
||||
double _Timestamp() {
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
bool _ConstructCH( _DynamicGraph* _graph );
|
||||
|
||||
void _Dijkstra( NodeID source, const int maxDistance, _ThreadData* data ){
|
||||
|
||||
_Heap& heap = data->heap;
|
||||
|
||||
int nodes = 0;
|
||||
while ( heap.Size() > 0 ) {
|
||||
const NodeID node = heap.DeleteMin();
|
||||
const int distance = heap.GetKey( node );
|
||||
//const int hops = heap.GetData( node ).hops;
|
||||
if ( nodes++ > 1000 )
|
||||
return;
|
||||
//if ( hops >= 5 )
|
||||
// return;
|
||||
//Destination settled?
|
||||
if ( distance > maxDistance )
|
||||
return;
|
||||
|
||||
//iterate over all edges of node
|
||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) {
|
||||
const _EdgeData& data = _graph->GetEdgeData( edge );
|
||||
if ( !data.forward )
|
||||
continue;
|
||||
const NodeID to = _graph->GetTarget( edge );
|
||||
const int toDistance = distance + data.distance;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !heap.WasInserted( to ) )
|
||||
heap.Insert( to, toDistance, _HeapData() );
|
||||
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < heap.GetKey( to ) ) {
|
||||
heap.DecreaseKey( to, toDistance );
|
||||
//heap.GetData( to ).hops = hops + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double _Evaluate( _ThreadData* data, _PriorityData* nodeData, NodeID node ){
|
||||
_ContractionInformation stats;
|
||||
|
||||
//perform simulated contraction
|
||||
_Contract< true > ( data, node, &stats );
|
||||
|
||||
// Result will contain the priority
|
||||
if ( stats.edgesDeleted == 0 || stats.originalEdgesDeleted == 0 )
|
||||
return 1 * nodeData->depth;
|
||||
return 2 * ((( double ) stats.edgesAdded ) / stats.edgesDeleted ) + 1 * ((( double ) stats.originalEdgesAdded ) / stats.originalEdgesDeleted ) + 1 * nodeData->depth;
|
||||
}
|
||||
|
||||
template< class Edge >
|
||||
bool _CheckCH()
|
||||
{
|
||||
NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||
for ( NodeID node = 0; node < numberOfNodes; ++node ) {
|
||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) {
|
||||
const NodeID start = node;
|
||||
const NodeID target = _graph->GetTarget( edge );
|
||||
const _EdgeData& data = _graph->GetEdgeData( edge );
|
||||
const NodeID middle = data.middle;
|
||||
assert(start != target);
|
||||
if(data.shortcut)
|
||||
{
|
||||
if(_graph->FindEdge(start, middle) == SPECIAL_EDGEID && _graph->FindEdge(middle, start) == SPECIAL_EDGEID)
|
||||
{
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
if(_graph->FindEdge(middle, target) == SPECIAL_EDGEID && _graph->FindEdge(target, middle) == SPECIAL_EDGEID)
|
||||
{
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
assert(data.middle == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template< bool Simulate > bool _Contract( _ThreadData* data, NodeID node, _ContractionInformation* stats = NULL ) {
|
||||
_Heap& heap = data->heap;
|
||||
//std::vector< Witness >& witnessList = data->witnessList;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator inEdge = _graph->BeginEdges( node ), endInEdges = _graph->EndEdges( node ); inEdge != endInEdges; ++inEdge ) {
|
||||
const _EdgeData& inData = _graph->GetEdgeData( inEdge );
|
||||
const NodeID source = _graph->GetTarget( inEdge );
|
||||
if ( Simulate ) {
|
||||
assert( stats != NULL );
|
||||
stats->edgesDeleted++;
|
||||
stats->originalEdgesDeleted += inData.originalEdges;
|
||||
}
|
||||
if ( !inData.backward )
|
||||
continue;
|
||||
|
||||
heap.Clear();
|
||||
heap.Insert( source, 0, _HeapData() );
|
||||
if ( node != source )
|
||||
heap.Insert( node, inData.distance, _HeapData() );
|
||||
int maxDistance = 0;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||
const _EdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||
if ( !outData.forward )
|
||||
continue;
|
||||
const NodeID target = _graph->GetTarget( outEdge );
|
||||
const int pathDistance = inData.distance + outData.distance;
|
||||
maxDistance = std::max( maxDistance, pathDistance );
|
||||
if ( !heap.WasInserted( target ) )
|
||||
heap.Insert( target, pathDistance, _HeapData() );
|
||||
else if ( pathDistance < heap.GetKey( target ) )
|
||||
heap.DecreaseKey( target, pathDistance );
|
||||
}
|
||||
|
||||
_Dijkstra( source, maxDistance, data );
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||
const _EdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||
if ( !outData.forward )
|
||||
continue;
|
||||
const NodeID target = _graph->GetTarget( outEdge );
|
||||
const int pathDistance = inData.distance + outData.distance;
|
||||
const int distance = heap.GetKey( target );
|
||||
|
||||
if ( pathDistance <= distance ) {
|
||||
if ( Simulate ) {
|
||||
assert( stats != NULL );
|
||||
stats->edgesAdded += 2;
|
||||
stats->originalEdgesAdded += 2 * ( outData.originalEdges + inData.originalEdges );
|
||||
} else {
|
||||
_ImportEdge newEdge;
|
||||
newEdge.source = source;
|
||||
newEdge.target = target;
|
||||
newEdge.data.distance = pathDistance;
|
||||
newEdge.data.forward = true;
|
||||
newEdge.data.backward = false;
|
||||
newEdge.data.middle = node;
|
||||
newEdge.data.shortcut = true;
|
||||
newEdge.data.originalEdges = outData.originalEdges + inData.originalEdges;
|
||||
data->insertedEdges.push_back( newEdge );
|
||||
std::swap( newEdge.source, newEdge.target );
|
||||
newEdge.data.forward = false;
|
||||
newEdge.data.backward = true;
|
||||
data->insertedEdges.push_back( newEdge );
|
||||
}
|
||||
}
|
||||
/*else if ( !Simulate ) {
|
||||
Witness witness;
|
||||
witness.source = source;
|
||||
witness.target = target;
|
||||
witness.middle = node;
|
||||
witnessList.push_back( witness );
|
||||
}*/
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _DeleteIncommingEdges( _ThreadData* data, NodeID node ) {
|
||||
std::vector < NodeID > neighbours;
|
||||
|
||||
//find all neighbours
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||
const NodeID u = _graph->GetTarget( e );
|
||||
if ( u == node )
|
||||
continue;
|
||||
neighbours.push_back( u );
|
||||
}
|
||||
//eliminate duplicate entries ( forward + backward edges )
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
for ( int i = 0, e = ( int ) neighbours.size(); i < e; ++i ) {
|
||||
const NodeID u = neighbours[i];
|
||||
//_DynamicGraph::EdgeIterator edge = _graph->FindEdge( u, node );
|
||||
//assert( edge != _graph->EndEdges( u ) );
|
||||
//while ( edge != _graph->EndEdges( u ) ) {
|
||||
// _graph->DeleteEdge( u, edge );
|
||||
// edge = _graph->FindEdge( u, node );
|
||||
//}
|
||||
_graph->DeleteEdgesTo( u, node );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _UpdateNeighbours( std::vector< double >* priorities, std::vector< _PriorityData >* nodeData, _ThreadData* data, NodeID node ) {
|
||||
std::vector < NodeID > neighbours;
|
||||
|
||||
//find all neighbours
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||
const NodeID u = _graph->GetTarget( e );
|
||||
if ( u == node )
|
||||
continue;
|
||||
neighbours.push_back( u );
|
||||
( *nodeData )[u].depth = std::max(( *nodeData )[node].depth + 1, ( *nodeData )[u].depth );
|
||||
}
|
||||
//eliminate duplicate entries ( forward + backward edges )
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
for ( int i = 0, e = ( int ) neighbours.size(); i < e; ++i ) {
|
||||
const NodeID u = neighbours[i];
|
||||
( *priorities )[u] = _Evaluate( data, &( *nodeData )[u], u );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _IsIndependent( const _DynamicGraph* _graph, const std::vector< double >& priorities, const std::vector< _PriorityData >& nodeData, NodeID node ) {
|
||||
const double priority = priorities[node];
|
||||
|
||||
std::vector< NodeID > neighbours;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||
const NodeID target = _graph->GetTarget( e );
|
||||
const double targetPriority = priorities[target];
|
||||
assert( targetPriority >= 0 );
|
||||
//found a neighbour with lower priority?
|
||||
if ( priority > targetPriority )
|
||||
return false;
|
||||
//tie breaking
|
||||
if ( priority == targetPriority && nodeData[node].bias < nodeData[target].bias )
|
||||
return false;
|
||||
neighbours.push_back( target );
|
||||
}
|
||||
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
//examine all neighbours that are at most 2 hops away
|
||||
for ( std::vector< NodeID >::const_iterator i = neighbours.begin(), lastNode = neighbours.end(); i != lastNode; ++i ) {
|
||||
const NodeID u = *i;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( u ) ; e < _graph->EndEdges( u ) ; ++e ) {
|
||||
const NodeID target = _graph->GetTarget( e );
|
||||
|
||||
const double targetPriority = priorities[target];
|
||||
assert( targetPriority >= 0 );
|
||||
//found a neighbour with lower priority?
|
||||
if ( priority > targetPriority )
|
||||
return false;
|
||||
//tie breaking
|
||||
if ( priority == targetPriority && nodeData[node].bias < nodeData[target].bias )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_DynamicGraph* _graph;
|
||||
};
|
||||
|
||||
#endif // CONTRACTOR_H_INCLUDED
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef DYNAMICGRAPH_H_INCLUDED
|
||||
#define DYNAMICGRAPH_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
// returns the smallest power of two that is at least as large as x
|
||||
static unsigned log2Rounded32( unsigned x ) {
|
||||
const unsigned bitPosition[32] = {
|
||||
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
|
||||
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
|
||||
};
|
||||
|
||||
//round up
|
||||
--x;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
++x;
|
||||
//x is now a power of 2
|
||||
|
||||
//each power of two is mapped to a unique 5 bit sequence with ( x * 0x077CB531U ) >> 27
|
||||
return bitPosition[( x * 0x077CB531U ) >> 27];
|
||||
}
|
||||
/*
|
||||
static unsigned log2Rounded64( unsigned long long x ) {
|
||||
int upperLog = log2Rounded32( x >> 32 );
|
||||
if ( upperLog > 0 )
|
||||
return upperLog;
|
||||
return log2Rounded32( x );
|
||||
}
|
||||
*/
|
||||
|
||||
template< typename EdgeData>
|
||||
class DynamicGraph {
|
||||
public:
|
||||
typedef NodeID NodeIterator;
|
||||
typedef NodeID EdgeIterator;
|
||||
|
||||
class InputEdge {
|
||||
public:
|
||||
EdgeData data;
|
||||
NodeIterator source;
|
||||
NodeIterator target;
|
||||
bool operator<( const InputEdge& right ) const {
|
||||
if ( source != right.source )
|
||||
return source < right.source;
|
||||
return target < right.target;
|
||||
}
|
||||
};
|
||||
|
||||
DynamicGraph( int nodes, std::vector< InputEdge > &graph ) {
|
||||
|
||||
std::sort( graph.begin(), graph.end() );
|
||||
_numNodes = nodes;
|
||||
_numEdges = ( EdgeIterator ) graph.size();
|
||||
_nodes.resize( _numNodes );
|
||||
EdgeIterator edge = 0;
|
||||
EdgeIterator position = 0;
|
||||
for ( NodeIterator node = 0; node < _numNodes; ++node ) {
|
||||
EdgeIterator lastEdge = edge;
|
||||
while ( edge < _numEdges && graph[edge].source == node ) {
|
||||
++edge;
|
||||
}
|
||||
_nodes[node].firstEdge = position;
|
||||
_nodes[node].edges = edge - lastEdge;
|
||||
_nodes[node].size = 1 << log2Rounded32( edge - lastEdge );
|
||||
position += _nodes[node].size;
|
||||
}
|
||||
_edges.resize( position );
|
||||
edge = 0;
|
||||
for ( NodeIterator node = 0; node < _numNodes; ++node ) {
|
||||
for ( EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node].firstEdge + _nodes[node].edges; i != e; ++i ) {
|
||||
_edges[i].target = graph[edge].target;
|
||||
_edges[i].data = graph[edge].data;
|
||||
assert(_edges[i].data.distance > 0);
|
||||
edge++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned GetNumberOfNodes() const {
|
||||
return _numNodes;
|
||||
}
|
||||
|
||||
unsigned GetNumberOfEdges() const {
|
||||
return _numEdges;
|
||||
}
|
||||
|
||||
unsigned GetOutDegree( const NodeIterator &n ) const {
|
||||
return _nodes[n].edges;
|
||||
}
|
||||
|
||||
NodeIterator GetTarget( const EdgeIterator &e ) const {
|
||||
return NodeIterator( _edges[e].target );
|
||||
}
|
||||
|
||||
EdgeData &GetEdgeData( const EdgeIterator &e ) {
|
||||
return _edges[e].data;
|
||||
}
|
||||
|
||||
const EdgeData &GetEdgeData( const EdgeIterator &e ) const {
|
||||
return _edges[e].data;
|
||||
}
|
||||
|
||||
EdgeIterator BeginEdges( const NodeIterator &n ) const {
|
||||
//assert( EndEdges( n ) - EdgeIterator( _nodes[n].firstEdge ) <= 100 );
|
||||
return EdgeIterator( _nodes[n].firstEdge );
|
||||
}
|
||||
|
||||
EdgeIterator EndEdges( const NodeIterator &n ) const {
|
||||
return EdgeIterator( _nodes[n].firstEdge + _nodes[n].edges );
|
||||
}
|
||||
|
||||
//adds an edge. Invalidates edge iterators for the source node
|
||||
EdgeIterator InsertEdge( const NodeIterator &from, const NodeIterator &to, const EdgeData &data ) {
|
||||
_StrNode &node = _nodes[from];
|
||||
if ( node.edges + 1 >= node.size ) {
|
||||
node.size *= 2;
|
||||
EdgeIterator newFirstEdge = ( EdgeIterator ) _edges.size();
|
||||
_edges.resize( _edges.size() + node.size );
|
||||
for ( unsigned i = 0; i < node.edges; ++i ) {
|
||||
_edges[newFirstEdge + i ] = _edges[node.firstEdge + i];
|
||||
}
|
||||
node.firstEdge = newFirstEdge;
|
||||
}
|
||||
_StrEdge &edge = _edges[node.firstEdge + node.edges];
|
||||
edge.target = to;
|
||||
edge.data = data;
|
||||
_numEdges++;
|
||||
node.edges++;
|
||||
return EdgeIterator( node.firstEdge + node.edges );
|
||||
}
|
||||
|
||||
//removes an edge. Invalidates edge iterators for the source node
|
||||
void DeleteEdge( const NodeIterator source, const EdgeIterator &e ) {
|
||||
_StrNode &node = _nodes[source];
|
||||
--_numEdges;
|
||||
--node.edges;
|
||||
const unsigned last = node.firstEdge + node.edges;
|
||||
//swap with last edge
|
||||
_edges[e] = _edges[last];
|
||||
}
|
||||
|
||||
//removes all edges (source,target)
|
||||
int DeleteEdgesTo( const NodeIterator source, const NodeIterator target ) {
|
||||
int deleted = 0;
|
||||
for ( EdgeIterator i = BeginEdges( source ), iend = EndEdges( source ); i < iend - deleted; ++i ) {
|
||||
if ( _edges[i].target == target ) {
|
||||
do {
|
||||
deleted++;
|
||||
_edges[i] = _edges[iend - deleted];
|
||||
} while ( i < iend - deleted && _edges[i].target == target );
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp atomic
|
||||
_numEdges -= deleted;
|
||||
_nodes[source].edges -= deleted;
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
//searches for a specific edge
|
||||
EdgeIterator FindEdge( const NodeIterator &from, const NodeIterator &to ) const {
|
||||
EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
EdgeWeight smallestWeight = UINT_MAX;
|
||||
for ( EdgeIterator edge = BeginEdges( from ); edge < EndEdges(from); edge++ )
|
||||
{
|
||||
const NodeID target = GetTarget(edge);
|
||||
const EdgeWeight weight = GetEdgeData(edge).distance;
|
||||
{
|
||||
if(target == to && weight < smallestWeight)
|
||||
{
|
||||
smallestEdge = edge; smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
return smallestEdge;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
struct _StrNode {
|
||||
//index of the first edge
|
||||
EdgeIterator firstEdge;
|
||||
//amount of edges
|
||||
unsigned edges;
|
||||
unsigned size;
|
||||
};
|
||||
|
||||
struct _StrEdge {
|
||||
NodeID target;
|
||||
EdgeData data;
|
||||
};
|
||||
|
||||
NodeIterator _numNodes;
|
||||
EdgeIterator _numEdges;
|
||||
|
||||
std::vector< _StrNode > _nodes;
|
||||
std::vector< _StrEdge > _edges;
|
||||
};
|
||||
|
||||
#endif // DYNAMICGRAPH_H_INCLUDED
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef CREATEGRAPH_H
|
||||
#define GRAPHLOADER_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
|
||||
#include <google/dense_hash_map>
|
||||
|
||||
#ifdef _GLIBCXX_PARALLEL
|
||||
#include <parallel/algorithm>
|
||||
#else
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
typedef google::dense_hash_map<NodeID, NodeID> ExternalNodeMap;
|
||||
|
||||
template<typename EdgeT>
|
||||
inline NodeID readOSMRGraphFromStream(istream &in, vector<EdgeT>& edgeList, vector<NodeInfo> * int2ExtNodeMap) {
|
||||
NodeID n, source, target, id;
|
||||
EdgeID m;
|
||||
int dir, xcoord, ycoord;// direction (0 = open, 1 = forward, 2+ = open)
|
||||
ExternalNodeMap ext2IntNodeMap;
|
||||
ext2IntNodeMap.set_empty_key(UINT_MAX);
|
||||
in >> n;
|
||||
VERBOSE(cout << "Importing n = " << n << " nodes ..." << flush;)
|
||||
for (NodeID i=0; i<n;i++) {
|
||||
in >> id >> ycoord >> xcoord;
|
||||
int2ExtNodeMap->push_back(NodeInfo(xcoord, ycoord, id));
|
||||
ext2IntNodeMap.insert(make_pair(id, i));
|
||||
}
|
||||
in >> m;
|
||||
VERBOSE(cout << " and " << m << " edges ..." << flush;)
|
||||
|
||||
edgeList.reserve(m);
|
||||
for (EdgeID i=0; i<m; i++) {
|
||||
EdgeWeight weight;
|
||||
int length;
|
||||
in >> source >> target >> length >> dir >> weight;
|
||||
|
||||
assert(length > 0);
|
||||
assert(weight > 0);
|
||||
assert(0<=dir && dir<=2);
|
||||
|
||||
bool forward = true;
|
||||
bool backward = true;
|
||||
if (dir == 1) backward = false;
|
||||
if (dir == 2) forward = false;
|
||||
|
||||
if(length == 0)
|
||||
{ cerr << "loaded null length edge" << endl; exit(1); }
|
||||
|
||||
// translate the external NodeIDs to internal IDs
|
||||
ExternalNodeMap::iterator intNodeID = ext2IntNodeMap.find(source);
|
||||
if( intNodeID == ext2IntNodeMap.end()) { cerr << "unresolved source NodeID: " << source << endl; exit(0); }
|
||||
source = intNodeID->second;
|
||||
intNodeID = ext2IntNodeMap.find(target);
|
||||
if(intNodeID == ext2IntNodeMap.end()) { cerr << "unresolved target NodeID : " << target << endl; exit(0); }
|
||||
target = intNodeID->second;
|
||||
|
||||
if(source == UINT_MAX || target == UINT_MAX) { cerr << "nonexisting source or target" << endl; exit(0); }
|
||||
|
||||
EdgeT inputEdge(source, target, weight, forward, backward);
|
||||
edgeList.push_back(inputEdge);
|
||||
}
|
||||
ext2IntNodeMap.clear();
|
||||
cout << "ok" << endl;
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif // CREATEGRAPH_H
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef SEARCHENGINE_H_
|
||||
#define SEARCHENGINE_H_
|
||||
|
||||
#include <climits>
|
||||
#include <deque>
|
||||
|
||||
#include "BinaryHeap.h"
|
||||
#include "DynamicGraph.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct _HeapData {
|
||||
NodeID parent;
|
||||
_HeapData( NodeID p ) : parent(p) { }
|
||||
};
|
||||
|
||||
typedef BinaryHeap< NodeID, int, int, _HeapData, MapStorage< NodeID, unsigned > > _Heap;
|
||||
|
||||
template<typename EdgeData, typename KDTST = NodeInformationHelpDesk>
|
||||
class SearchEngine {
|
||||
private:
|
||||
const DynamicGraph<EdgeData> * _graph;
|
||||
public:
|
||||
SearchEngine(DynamicGraph<EdgeData> * g, KDTST * k) : _graph(g), kdtree(k) {}
|
||||
~SearchEngine() {}
|
||||
|
||||
NodeInfo& getNodeInfo(NodeID id) const
|
||||
{
|
||||
return kdtree->getExternalNodeInfo(id);
|
||||
}
|
||||
|
||||
unsigned int numberOfNodes() const
|
||||
{
|
||||
return kdtree->getNumberOfNodes();
|
||||
}
|
||||
|
||||
unsigned int ComputeRoute(NodeID start, NodeID target, vector<NodeID> * path)
|
||||
{
|
||||
_Heap * _forwardHeap = new _Heap(kdtree->getNumberOfNodes());
|
||||
_Heap * _backwardHeap = new _Heap(kdtree->getNumberOfNodes());
|
||||
NodeID middle = ( NodeID ) 0;
|
||||
unsigned int _upperbound = std::numeric_limits<unsigned int>::max();
|
||||
_forwardHeap->Insert(start, 0, start);
|
||||
_backwardHeap->Insert(target, 0, target);
|
||||
|
||||
while(_forwardHeap->Size() + _backwardHeap->Size() > 0)
|
||||
{
|
||||
if ( _forwardHeap->Size() > 0 ) {
|
||||
_RoutingStep( _forwardHeap, _backwardHeap, true, &middle, &_upperbound );
|
||||
}
|
||||
if ( _backwardHeap->Size() > 0 ) {
|
||||
_RoutingStep( _backwardHeap, _forwardHeap, false, &middle, &_upperbound );
|
||||
}
|
||||
}
|
||||
|
||||
if ( _upperbound == std::numeric_limits< unsigned int >::max() )
|
||||
return _upperbound;
|
||||
|
||||
NodeID pathNode = middle;
|
||||
NodeID unpackEndNode = start;
|
||||
deque< NodeID > packedPath;
|
||||
|
||||
while ( pathNode != unpackEndNode ) {
|
||||
pathNode = _forwardHeap->GetData( pathNode ).parent;
|
||||
packedPath.push_front( pathNode );
|
||||
}
|
||||
|
||||
packedPath.push_back( middle );
|
||||
|
||||
pathNode = middle;
|
||||
unpackEndNode = target;
|
||||
|
||||
while ( pathNode != unpackEndNode ) {
|
||||
pathNode = _backwardHeap->GetData( pathNode ).parent;
|
||||
packedPath.push_back( pathNode );
|
||||
}
|
||||
|
||||
// for(deque<NodeID>::size_type i = 0; i < packedPath.size()-1; i++)
|
||||
// {
|
||||
// cout << packedPath[i] << endl;
|
||||
// }
|
||||
|
||||
// push start node explicitely
|
||||
path->push_back(packedPath[0]);
|
||||
for(deque<NodeID>::size_type i = 0; i < packedPath.size()-1; i++)
|
||||
{
|
||||
// path->push_back(*it);
|
||||
_UnpackEdge(packedPath[i], packedPath[i+1], path);
|
||||
}
|
||||
|
||||
packedPath.clear();
|
||||
delete _forwardHeap;
|
||||
delete _backwardHeap;
|
||||
|
||||
return _upperbound/10;
|
||||
}
|
||||
|
||||
unsigned int findNearestNodeForLatLon(const int lat, const int lon, NodeCoords<NodeID> * data) const
|
||||
{
|
||||
return kdtree->findNearestNodeIDForLatLon( lat, lon, data);
|
||||
}
|
||||
private:
|
||||
KDTST * kdtree;
|
||||
|
||||
void _RoutingStep(_Heap * _forwardHeap, _Heap *_backwardHeap, const bool& forwardDirection, NodeID * middle, unsigned int * _upperbound)
|
||||
{
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
const unsigned int distance = _forwardHeap->GetKey( node );
|
||||
if ( _backwardHeap->WasInserted( node ) ) {
|
||||
const unsigned int newDistance = _backwardHeap->GetKey( node ) + distance;
|
||||
if ( newDistance < *_upperbound ) {
|
||||
*middle = node;
|
||||
*_upperbound = newDistance;
|
||||
}
|
||||
}
|
||||
if ( distance > *_upperbound ) {
|
||||
_forwardHeap->DeleteAll();
|
||||
return;
|
||||
}
|
||||
for ( typename DynamicGraph<EdgeData>::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
||||
const NodeID to = _graph->GetTarget(edge);
|
||||
const int edgeWeight = _graph->GetEdgeData(edge).distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
if(forwardDirection ? _graph->GetEdgeData(edge).forward : _graph->GetEdgeData(edge).backward )
|
||||
{
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !_forwardHeap->WasInserted( to ) )
|
||||
{
|
||||
_forwardHeap->Insert( to, toDistance, node );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < _forwardHeap->GetKey( to ) ) {
|
||||
_forwardHeap->GetData( to ).parent = node;
|
||||
_forwardHeap->DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool _UnpackEdge( const NodeID source, const NodeID target, std::vector< NodeID >* path ) {
|
||||
assert(source != target);
|
||||
//find edge first.
|
||||
typename DynamicGraph<EdgeData>::EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
EdgeWeight smallestWeight = UINT_MAX;
|
||||
for(typename DynamicGraph<EdgeData>::EdgeIterator eit = _graph->BeginEdges(source); eit < _graph->EndEdges(source); eit++)
|
||||
{
|
||||
//const NodeID target = GetTarget(edge);
|
||||
const EdgeWeight weight = _graph->GetEdgeData(eit).distance;
|
||||
{
|
||||
if(_graph->GetTarget(eit) == target && weight < smallestWeight && _graph->GetEdgeData(eit).forward)
|
||||
{
|
||||
smallestEdge = eit; smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(smallestEdge == SPECIAL_EDGEID)
|
||||
{
|
||||
for(typename DynamicGraph<EdgeData>::EdgeIterator eit = _graph->BeginEdges(target); eit < _graph->EndEdges(target); eit++)
|
||||
{
|
||||
//const NodeID target = GetTarget(edge);
|
||||
const EdgeWeight weight = _graph->GetEdgeData(eit).distance;
|
||||
{
|
||||
if(_graph->GetTarget(eit) == source && weight < smallestWeight && _graph->GetEdgeData(eit).backward)
|
||||
{
|
||||
smallestEdge = eit; smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assert(smallestWeight != SPECIAL_EDGEID);
|
||||
|
||||
const EdgeData ed = _graph->GetEdgeData(smallestEdge);
|
||||
if(ed.shortcut)
|
||||
{//unpack
|
||||
const NodeID middle = ed.middle;
|
||||
_UnpackEdge(source, middle, path);
|
||||
_UnpackEdge(middle, target, path);
|
||||
return false;
|
||||
} else {
|
||||
assert(!ed.shortcut);
|
||||
path->push_back(target);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SEARCHENGINE_H_ */
|
||||
Reference in New Issue
Block a user