Initial Import.

This commit is contained in:
Dennis Luxen
2010-07-09 09:05:40 +00:00
parent a44a309de5
commit d4a64d2168
28 changed files with 5010 additions and 0 deletions
+253
View File
@@ -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
+310
View File
@@ -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
+726
View File
@@ -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
+229
View File
@@ -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
+97
View File
@@ -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
+212
View File
@@ -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_ */