Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial Import.

  • Loading branch information...
commit d4a64d2168595aa0382cc1ab05f4ef786c429d71 1 parent a44a309
Dennis Luxen authored
View
7 AUTHORS.TXT
@@ -0,0 +1,7 @@
+The following people contributed code to the Open Source Routing Machine:
+
+Christian Vetter
+Dennis Luxen
+
+Note:
+http server ripped from Boost http example 3
View
253 Contractor/BinaryHeap.h
@@ -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
View
310 Contractor/ContractionCleanup.h
@@ -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
View
726 Contractor/Contractor.h
@@ -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
View
229 Contractor/DynamicGraph.h
@@ -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
View
97 Contractor/GraphLoader.h
@@ -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
View
212 Contractor/SearchEngine.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_ */
View
67 DataStructures/ImportEdge.h
@@ -0,0 +1,67 @@
+/*
+ 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 EDGE_H
+#define EDGE_H
+
+#include <cassert>
+
+class Edge
+{
+public:
+
+ bool operator< (const Edge& e) const {
+ if (source() == e.source()) {
+ if (target() == e.target()) {
+ if (weight() == e.weight()) {
+ return (isForward() && isBackward() &&
+ ((! e.isForward()) || (! e.isBackward())));
+ }
+ return (weight() < e.weight());
+ }
+ return (target() < e.target());
+ }
+ return (source() < e.source());
+ }
+
+ /** Default constructor. target and weight are set to 0.*/
+ Edge() { assert(false); } //shall not be used.
+
+ explicit Edge(NodeID s, NodeID t, EdgeWeight w, bool f, bool b) : _source(s), _target(t), _weight(w), forward(f), backward(b) { }
+
+ NodeID target() const {return _target; }
+ NodeID source() const {return _source;}
+ EdgeWeight weight() const {return _weight; }
+
+ bool isBackward() const { return backward; }
+
+ bool isForward() const { return forward; }
+
+private:
+ NodeID _source;
+ NodeID _target;
+ EdgeWeight _weight:30;
+ bool forward:1;
+ bool backward:1;
+};
+
+typedef Edge ImportEdge;
+
+#endif // EDGE_H
View
66 DataStructures/NodeCoords.h
@@ -0,0 +1,66 @@
+/*
+ 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 _NODE_COORDS_H
+#define _NODE_COORDS_H
+
+
+template<typename NodeT>
+struct NodeCoords {
+ NodeCoords(int _lat, int _lon, NodeT _id) : lat(_lat), lon(_lon), id(_id) {}
+ NodeCoords() : lat(UINT_MAX), lon(UINT_MAX), id(UINT_MAX) {}
+ int lat;
+ int lon;
+ unsigned int id;
+};
+
+struct duplet
+ {
+ typedef int value_type;
+
+ inline value_type operator[](int const N) const { return d[N]; }
+
+ inline bool operator==(duplet const& other) const
+ {
+ return this->d[0] == other.d[0] && this->d[1] == other.d[1];
+ }
+
+ inline bool operator!=(duplet const& other) const
+ {
+ return this->d[0] != other.d[0] || this->d[1] != other.d[1];
+ }
+
+ friend std::ostream & operator<<(std::ostream & o, duplet const& d)
+ {
+ return o << "(" << d[0] << "," << d[1] << ")";
+ }
+ duplet(unsigned _id, int x, int y)
+ {
+ id = _id;
+ d[0] = x;
+ d[1] = y;
+ }
+ unsigned int id;
+ value_type d[2];
+ };
+
+inline double return_dup( duplet d, int k ) { return d[k]; }
+
+#endif //_NODE_COORDS_H
View
141 DataStructures/NodeInformationHelpDesk.h
@@ -0,0 +1,141 @@
+/*
+ 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 KDTREE_H_
+#define NODEINFORMATIONHELPDESK_H_
+
+#include <omp.h>
+
+#include <climits>
+#include <cstdlib>
+
+#include <algorithm>
+#include <deque>
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <list>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "../typedefs.h"
+
+#include <kdtree++/kdtree.hpp>
+
+typedef KDTree::KDTree<2, duplet, std::pointer_to_binary_function<duplet,int,double> > duplet_tree_type;
+
+class NodeInformationHelpDesk{
+public:
+ ~NodeInformationHelpDesk();
+ NodeInformationHelpDesk() { int2ExtNodeMap = new vector<NodeInfo>();}
+ duplet_tree_type * initKDTree(ifstream& input);
+
+ NodeID getExternalNodeID(const NodeID node);
+ NodeInfo& getExternalNodeInfo(const NodeID node);
+ int getLatitudeOfNode(const NodeID node);
+ int getLongitudeOfNode(const NodeID node);
+
+ NodeID getNumberOfNodes() const { return int2ExtNodeMap->size(); }
+
+ inline NodeID findNearestNodeIDForLatLon(const int lat, const int lon, NodeCoords<NodeID> * data) const
+ {
+
+ duplet dup = *(kdtree->find_nearest(duplet(0, lat, lon)).first);
+ data->id = dup.id;
+ data->lat = dup.d[1];
+ data->lon = dup.d[0];
+ return data->id;
+ }
+private:
+ vector<NodeInfo> * int2ExtNodeMap;
+ duplet_tree_type * kdtree;
+};
+
+//////////////////
+//implementation//
+//////////////////
+
+NodeInformationHelpDesk::~NodeInformationHelpDesk(){
+ // delete graph;
+ // delete calc;
+ // delete c;
+}
+
+/* @brief: initialize kd-tree and internal->external node id map
+ *
+ */
+duplet_tree_type * NodeInformationHelpDesk::initKDTree(ifstream& in)
+{
+// NodeID i = 0;
+ while(!in.eof())
+ {
+ NodeInfo b;
+ in.read((char *)&b, sizeof(b));
+ int2ExtNodeMap->push_back(b);
+ // i++;
+ }
+ in.close();
+
+ duplet_tree_type * tree = new duplet_tree_type(std::ptr_fun(return_dup));
+ NodeID id = 0;
+ for(vector<NodeInfo>::iterator it = int2ExtNodeMap->begin(); it != int2ExtNodeMap->end(); it++)
+ {
+ duplet super_dupre(id, it->lat, it->lon);
+ tree->insert(super_dupre);
+ id++;
+ }
+ kdtree = tree;
+ return tree;
+}
+
+NodeID NodeInformationHelpDesk::getExternalNodeID(const NodeID node)
+{
+// google::dense_hash_map<NodeID, NodeInfo>::iterator temp = int2ExtNodeMap->find(node);
+// if(temp == int2ExtNodeMap->end())
+// return UINT_MAX;
+// return temp->second.id;
+ return int2ExtNodeMap->at(node).id;
+}
+
+NodeInfo& NodeInformationHelpDesk::getExternalNodeInfo(const NodeID node)
+{
+ return int2ExtNodeMap->at(node);
+}
+
+int NodeInformationHelpDesk::getLatitudeOfNode(const NodeID node)
+{
+// google::dense_hash_map<NodeID, NodeInfo>::iterator temp = int2ExtNodeMap->find(node);
+// if(temp == int2ExtNodeMap->end())
+// return UINT_MAX;
+// return temp->second.lat;
+ return int2ExtNodeMap->at(node).lat;
+}
+
+int NodeInformationHelpDesk::getLongitudeOfNode(const NodeID node)
+{
+// google::dense_hash_map<NodeID, NodeInfo>::iterator temp = int2ExtNodeMap->find(node);
+// if(temp == int2ExtNodeMap->end())
+// return UINT_MAX;
+// return temp->second.lon;
+ return int2ExtNodeMap->at(node).lon;
+}
+
+#endif /*KDTREE_H_*/
View
34 DataStructures/Util.h
@@ -0,0 +1,34 @@
+/*
+ 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 TIMEUTIL_H_
+#define TIMEUTIL_H_
+
+#include <sys/time.h>
+
+/** Returns a timestamp (now) in seconds (incl. a fractional part). */
+inline double get_timestamp()
+{
+ struct timeval tp;
+ gettimeofday(&tp, NULL);
+ return double(tp.tv_sec) + tp.tv_usec / 1000000.;
+}
+
+#endif /* TIMEUTIL_H_ */
View
5 Docs/3rdparty.txt
@@ -0,0 +1,5 @@
+Third Party Libraries:
+
+Boost 1.37+
+kdtree++ 0.7+ (0.62 does not work with g++ 4.0+)
+sparsehash 1.4+
View
37 Docs/FAQ.txt
@@ -0,0 +1,37 @@
+FAQ
+---
+
+Q: What platforms does OSMR run on?
+A: Virtually any Unix-like platform with g++ installed. It has been developed
+ under Linux and tested on MacOS X 10.6. It should run under Windows as well
+ though the code will need some adjustments.
+
+Q: What is the workflow to get the engine up and running
+A: Road network extraction->Preprocessing->Startup
+
+Q: What does OSRM stand for?
+A: It is an abbreviation for Open Source Routing Machine.
+
+Q: What does HSGR stand for?
+A: It is an abbreviation for Hierarchy Search GRaph.
+
+Q: What is the .nodes file?
+A: It is a map that translates between internal and external Node IDs. Remember
+ that external NodeIDs can be arbitrary and non-contigous. Internally the
+ nodes are numbered from 0 to n-1.
+
+Q: The routing engine crashes with a seg-fault
+A: Check the startup parameters.
+
+Q: Something about the route is odd. I know that there is a better path
+A: Most probably it is missing data in the OSM file.
+
+Q: I work for this company that would like to use the code, but we are hesistant
+ because of the license.
+A: Contact me. Probably, we can work something out.
+
+Q: How fast is this thing?
+A: Good question. Here is a number. The engine was able to handle more than
+ 2800 requests per Minute on the German road network with the travel time
+ metric on a Core 2 Duo. This also includes transfer of data across a
+ switched 100MBit/s LAN. So, I guess it's fair to say it's fast.
View
8 Docs/Todo.txt
@@ -0,0 +1,8 @@
+TODO
+----
+
+Start/Endpoints of queries can only start on nodes only. Instead of selecting the nearest node the nearest edge should be selected.
+
+The server part is mostly adapted from the boost http examples. It should be replaced with a self-written front-end
+
+The KD-Tree uses a lot of RAM. An own implementation might be better.
View
164 HttpServer/connection.h
@@ -0,0 +1,164 @@
+/*
+ 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 HTTP_SERVER3_CONNECTION_HPP
+#define HTTP_CONNECTION_HPP
+
+#include <vector>
+
+#include <boost/asio.hpp>
+#include <boost/array.hpp>
+#include <boost/bind.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include "reply.h"
+#include "request.h"
+#include "request_handler.h"
+#include "request_parser.h"
+
+namespace http {
+
+
+/// Represents a single connection from a client.
+class connection
+: public boost::enable_shared_from_this<connection>,
+private boost::noncopyable
+{
+public:
+ /// Construct a connection with the given io_service.
+ explicit connection(boost::asio::io_service& io_service,
+ request_handler& handler);
+
+ /// Get the socket associated with the connection.
+ boost::asio::ip::tcp::socket& socket();
+
+ /// Start the first asynchronous operation for the connection.
+ void start();
+
+private:
+ /// Handle completion of a read operation.
+ void handle_read(const boost::system::error_code& e,
+ std::size_t bytes_transferred);
+
+ /// Handle completion of a write operation.
+ void handle_write(const boost::system::error_code& e);
+
+ /// Strand to ensure the connection's handlers are not called concurrently.
+ boost::asio::io_service::strand strand_;
+
+ /// Socket for the connection.
+ boost::asio::ip::tcp::socket socket_;
+
+ /// The handler used to process the incoming request.
+ request_handler& request_handler_;
+
+ /// Buffer for incoming data.
+ boost::array<char, 8192> buffer_;
+
+ /// The incoming request.
+ request request_;
+
+ /// The parser for the incoming request.
+ request_parser request_parser_;
+
+ /// The reply to be sent back to the client.
+ reply reply_;
+};
+
+typedef boost::shared_ptr<connection> connection_ptr;
+
+
+connection::connection(boost::asio::io_service& io_service,
+ request_handler& handler)
+: strand_(io_service),
+ socket_(io_service),
+ request_handler_(handler)
+{
+}
+
+boost::asio::ip::tcp::socket& connection::socket()
+{
+ return socket_;
+}
+
+void connection::start()
+{
+ socket_.async_read_some(boost::asio::buffer(buffer_),
+ strand_.wrap(
+ boost::bind(&connection::handle_read, shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+}
+
+void connection::handle_read(const boost::system::error_code& e,
+ std::size_t bytes_transferred)
+{
+ if (!e)
+ {
+ boost::tribool result;
+ boost::tie(result, boost::tuples::ignore) = request_parser_.parse(
+ request_, buffer_.data(), buffer_.data() + bytes_transferred);
+
+ if (result)
+ {
+ request_handler_.handle_request(request_, reply_);
+ boost::asio::async_write(socket_, reply_.to_buffers(),
+ strand_.wrap(
+ boost::bind(&connection::handle_write, shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+ else if (!result)
+ {
+ reply_ = reply::stock_reply(reply::bad_request);
+ boost::asio::async_write(socket_, reply_.to_buffers(),
+ strand_.wrap(
+ boost::bind(&connection::handle_write, shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+ else
+ {
+ socket_.async_read_some(boost::asio::buffer(buffer_),
+ strand_.wrap(
+ boost::bind(&connection::handle_read, shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ }
+ }
+}
+
+void connection::handle_write(const boost::system::error_code& e)
+{
+ if (!e)
+ {
+ // Initiate graceful connection closure.
+ boost::system::error_code ignored_ec;
+ socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
+ }
+
+ // No new asynchronous operations are started. This means that all shared_ptr
+ // references to the connection object will disappear and the object will be
+ // destroyed automatically after this handler returns. The connection class's
+ // destructor closes the socket.
+}
+
+} // namespace http
+
+#endif /* CONNECTION_HPP_ */
View
37 HttpServer/header.h
@@ -0,0 +1,37 @@
+/*
+ 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 HTTP_HEADER_HPP
+#define HTTP_HEADER_HPP
+
+#include <string>
+
+namespace http {
+
+
+struct header
+{
+ std::string name;
+ std::string value;
+};
+
+}
+
+#endif
View
312 HttpServer/reply.h
@@ -0,0 +1,312 @@
+/*
+ open source routing machine
+ Copyright (C) Dennis Luxen, 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 HTTP_SERVER3_REPLY_HPP
+#define HTTP_SERVER3_REPLY_HPP
+
+#include <string>
+#include <vector>
+#include <boost/asio.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "header.h"
+
+namespace http {
+
+/// A reply to be sent to a client.
+struct reply
+{
+ /// The status of the reply.
+ enum status_type
+ {
+ ok = 200,
+ created = 201,
+ accepted = 202,
+ no_content = 204,
+ multiple_choices = 300,
+ moved_permanently = 301,
+ moved_temporarily = 302,
+ not_modified = 304,
+ bad_request = 400,
+ unauthorized = 401,
+ forbidden = 403,
+ not_found = 404,
+ internal_server_error = 500,
+ not_implemented = 501,
+ bad_gateway = 502,
+ service_unavailable = 503
+ } status;
+
+ /// The headers to be included in the reply.
+ std::vector<header> headers;
+
+ /// The content to be sent in the reply.
+ std::string content;
+
+ /// Convert the reply into a vector of buffers. The buffers do not own the
+ /// underlying memory blocks, therefore the reply object must remain valid and
+ /// not be changed until the write operation has completed.
+ std::vector<boost::asio::const_buffer> to_buffers();
+
+ /// Get a stock reply.
+ static reply stock_reply(status_type status);
+};
+
+namespace status_strings {
+
+const std::string ok =
+ "HTTP/1.0 200 OK\r\n";
+const std::string created =
+ "HTTP/1.0 201 Created\r\n";
+const std::string accepted =
+ "HTTP/1.0 202 Accepted\r\n";
+const std::string no_content =
+ "HTTP/1.0 204 No Content\r\n";
+const std::string multiple_choices =
+ "HTTP/1.0 300 Multiple Choices\r\n";
+const std::string moved_permanently =
+ "HTTP/1.0 301 Moved Permanently\r\n";
+const std::string moved_temporarily =
+ "HTTP/1.0 302 Moved Temporarily\r\n";
+const std::string not_modified =
+ "HTTP/1.0 304 Not Modified\r\n";
+const std::string bad_request =
+ "HTTP/1.0 400 Bad Request\r\n";
+const std::string unauthorized =
+ "HTTP/1.0 401 Unauthorized\r\n";
+const std::string forbidden =
+ "HTTP/1.0 403 Forbidden\r\n";
+const std::string not_found =
+ "HTTP/1.0 404 Not Found\r\n";
+const std::string internal_server_error =
+ "HTTP/1.0 500 Internal Server Error\r\n";
+const std::string not_implemented =
+ "HTTP/1.0 501 Not Implemented\r\n";
+const std::string bad_gateway =
+ "HTTP/1.0 502 Bad Gateway\r\n";
+const std::string service_unavailable =
+ "HTTP/1.0 503 Service Unavailable\r\n";
+
+boost::asio::const_buffer to_buffer(reply::status_type status)
+{
+ switch (status)
+ {
+ case reply::ok:
+ return boost::asio::buffer(ok);
+ case reply::created:
+ return boost::asio::buffer(created);
+ case reply::accepted:
+ return boost::asio::buffer(accepted);
+ case reply::no_content:
+ return boost::asio::buffer(no_content);
+ case reply::multiple_choices:
+ return boost::asio::buffer(multiple_choices);
+ case reply::moved_permanently:
+ return boost::asio::buffer(moved_permanently);
+ case reply::moved_temporarily:
+ return boost::asio::buffer(moved_temporarily);
+ case reply::not_modified:
+ return boost::asio::buffer(not_modified);
+ case reply::bad_request:
+ return boost::asio::buffer(bad_request);
+ case reply::unauthorized:
+ return boost::asio::buffer(unauthorized);
+ case reply::forbidden:
+ return boost::asio::buffer(forbidden);
+ case reply::not_found:
+ return boost::asio::buffer(not_found);
+ case reply::internal_server_error:
+ return boost::asio::buffer(internal_server_error);
+ case reply::not_implemented:
+ return boost::asio::buffer(not_implemented);
+ case reply::bad_gateway:
+ return boost::asio::buffer(bad_gateway);
+ case reply::service_unavailable:
+ return boost::asio::buffer(service_unavailable);
+ default:
+ return boost::asio::buffer(internal_server_error);
+ }
+}
+
+} // namespace status_strings
+
+namespace misc_strings {
+
+const char name_value_separator[] = { ':', ' ' };
+const char crlf[] = { '\r', '\n' };
+
+} // namespace misc_strings
+
+std::vector<boost::asio::const_buffer> reply::to_buffers()
+{
+ std::vector<boost::asio::const_buffer> buffers;
+ buffers.push_back(status_strings::to_buffer(status));
+ for (std::size_t i = 0; i < headers.size(); ++i)
+ {
+ header& h = headers[i];
+ buffers.push_back(boost::asio::buffer(h.name));
+ buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator));
+ buffers.push_back(boost::asio::buffer(h.value));
+ buffers.push_back(boost::asio::buffer(misc_strings::crlf));
+ }
+ buffers.push_back(boost::asio::buffer(misc_strings::crlf));
+ buffers.push_back(boost::asio::buffer(content));
+ return buffers;
+}
+
+namespace stock_replies {
+
+const char ok[] = "";
+const char created[] =
+ "<html>"
+ "<head><title>Created</title></head>"
+ "<body><h1>201 Created</h1></body>"
+ "</html>";
+const char accepted[] =
+ "<html>"
+ "<head><title>Accepted</title></head>"
+ "<body><h1>202 Accepted</h1></body>"
+ "</html>";
+const char no_content[] =
+ "<html>"
+ "<head><title>No Content</title></head>"
+ "<body><h1>204 Content</h1></body>"
+ "</html>";
+const char multiple_choices[] =
+ "<html>"
+ "<head><title>Multiple Choices</title></head>"
+ "<body><h1>300 Multiple Choices</h1></body>"
+ "</html>";
+const char moved_permanently[] =
+ "<html>"
+ "<head><title>Moved Permanently</title></head>"
+ "<body><h1>301 Moved Permanently</h1></body>"
+ "</html>";
+const char moved_temporarily[] =
+ "<html>"
+ "<head><title>Moved Temporarily</title></head>"
+ "<body><h1>302 Moved Temporarily</h1></body>"
+ "</html>";
+const char not_modified[] =
+ "<html>"
+ "<head><title>Not Modified</title></head>"
+ "<body><h1>304 Not Modified</h1></body>"
+ "</html>";
+const char bad_request[] =
+ "<html>"
+ "<head><title>Bad Request</title></head>"
+ "<body><h1>400 Bad Request</h1></body>"
+ "</html>";
+const char unauthorized[] =
+ "<html>"
+ "<head><title>Unauthorized</title></head>"
+ "<body><h1>401 Unauthorized</h1></body>"
+ "</html>";
+const char forbidden[] =
+ "<html>"
+ "<head><title>Forbidden</title></head>"
+ "<body><h1>403 Forbidden</h1></body>"
+ "</html>";
+const char not_found[] =
+ "<html>"
+ "<head><title>Not Found</title></head>"
+ "<body><h1>404 Not Found</h1></body>"
+ "</html>";
+const char internal_server_error[] =
+ "<html>"
+ "<head><title>Internal Server Error</title></head>"
+ "<body><h1>500 Internal Server Error</h1></body>"
+ "</html>";
+const char not_implemented[] =
+ "<html>"
+ "<head><title>Not Implemented</title></head>