2010-07-09 05:05:40 -04:00
|
|
|
/*
|
|
|
|
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.
|
2010-08-24 09:50:58 -04:00
|
|
|
*/
|
2010-07-09 05:05:40 -04:00
|
|
|
|
|
|
|
#ifndef CONTRACTIONCLEANUP_H_INCLUDED
|
|
|
|
#define CONTRACTIONCLEANUP_H_INCLUDED
|
|
|
|
|
|
|
|
#ifdef _GLIBCXX_PARALLEL
|
|
|
|
#include <parallel/algorithm>
|
|
|
|
#else
|
|
|
|
#include <algorithm>
|
|
|
|
#endif
|
2011-09-28 11:22:03 -04:00
|
|
|
#ifndef _WIN32
|
2010-07-09 05:05:40 -04:00
|
|
|
#include <sys/time.h>
|
2011-09-28 11:22:03 -04:00
|
|
|
#endif
|
2010-07-09 05:05:40 -04:00
|
|
|
#include "Contractor.h"
|
|
|
|
|
|
|
|
class ContractionCleanup {
|
|
|
|
private:
|
|
|
|
|
2011-08-04 13:07:51 -04:00
|
|
|
struct _CleanupHeapData {
|
2011-03-15 11:20:14 -04:00
|
|
|
NodeID parent;
|
2011-08-04 13:07:51 -04:00
|
|
|
_CleanupHeapData( NodeID p ) {
|
2011-03-15 11:20:14 -04:00
|
|
|
parent = p;
|
|
|
|
}
|
|
|
|
};
|
2011-08-04 13:07:51 -04:00
|
|
|
typedef BinaryHeap< NodeID, NodeID, int, _CleanupHeapData > _Heap;
|
2011-12-10 12:26:33 -05:00
|
|
|
|
2011-03-15 11:20:14 -04:00
|
|
|
struct _ThreadData {
|
|
|
|
_Heap* _heapForward;
|
|
|
|
_Heap* _heapBackward;
|
|
|
|
_ThreadData( NodeID nodes ) {
|
|
|
|
_heapBackward = new _Heap(nodes);
|
|
|
|
_heapForward = new _Heap(nodes);
|
|
|
|
}
|
2011-12-10 12:26:33 -05:00
|
|
|
~_ThreadData() {
|
2011-03-15 11:20:14 -04:00
|
|
|
delete _heapBackward;
|
|
|
|
delete _heapForward;
|
|
|
|
}
|
|
|
|
};
|
2010-07-09 05:05:40 -04:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2011-03-15 11:20:14 -04:00
|
|
|
struct Edge {
|
|
|
|
NodeID source;
|
|
|
|
NodeID target;
|
|
|
|
struct EdgeData {
|
2011-12-10 12:26:33 -05:00
|
|
|
NodeID via;
|
|
|
|
unsigned nameID;
|
|
|
|
int distance;
|
|
|
|
short turnInstruction;
|
|
|
|
bool shortcut:1;
|
|
|
|
bool forward:1;
|
|
|
|
bool backward:1;
|
2011-03-15 11:20:14 -04:00
|
|
|
} 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 {
|
2011-11-14 13:36:31 -05:00
|
|
|
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
|
2011-12-01 08:48:06 -05:00
|
|
|
&& data.via == right.data.via && data.nameID == right.data.nameID
|
2011-11-14 13:36:31 -05:00
|
|
|
);
|
2011-03-15 11:20:14 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
ContractionCleanup( int numNodes, const std::vector< Edge >& edges ) {
|
|
|
|
_graph = edges;
|
|
|
|
_numNodes = numNodes;
|
|
|
|
}
|
|
|
|
|
|
|
|
~ContractionCleanup() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Run() {
|
|
|
|
RemoveUselessShortcuts();
|
|
|
|
}
|
|
|
|
|
|
|
|
template< class EdgeT >
|
|
|
|
void GetData( std::vector< EdgeT >& edges ) {
|
|
|
|
for ( int edge = 0, endEdges = ( int ) _graph.size(); edge != endEdges; ++edge ) {
|
2011-08-04 13:07:51 -04:00
|
|
|
if(_graph[edge].data.forward || _graph[edge].data.backward) {
|
|
|
|
EdgeT newEdge;
|
|
|
|
newEdge.source = _graph[edge].source;
|
|
|
|
newEdge.target = _graph[edge].target;
|
|
|
|
newEdge.data = _graph[edge].data;
|
|
|
|
edges.push_back( newEdge );
|
|
|
|
}
|
2011-03-15 11:20:14 -04:00
|
|
|
}
|
2010-07-09 05:05:40 -04:00
|
|
|
#ifdef _GLIBCXX_PARALLEL
|
2011-03-15 11:20:14 -04:00
|
|
|
__gnu_parallel::sort( edges.begin(), edges.end() );
|
2010-07-09 05:05:40 -04:00
|
|
|
#else
|
2011-03-15 11:20:14 -04:00
|
|
|
sort( edges.begin(), edges.end() );
|
2010-07-09 05:05:40 -04:00
|
|
|
#endif
|
2011-03-15 11:20:14 -04:00
|
|
|
}
|
2010-07-09 05:05:40 -04:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
2011-03-15 11:20:14 -04:00
|
|
|
double _Timestamp() {
|
|
|
|
struct timeval tp;
|
|
|
|
gettimeofday(&tp, NULL);
|
|
|
|
return double(tp.tv_sec) + tp.tv_usec / 1000000.;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BuildOutgoingGraph() {
|
|
|
|
//sort edges by source
|
2010-07-09 05:05:40 -04:00
|
|
|
#ifdef _GLIBCXX_PARALLEL
|
2011-03-15 11:20:14 -04:00
|
|
|
__gnu_parallel::sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
|
2010-07-09 05:05:40 -04:00
|
|
|
#else
|
2011-03-15 11:20:14 -04:00
|
|
|
sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
|
2010-07-09 05:05:40 -04:00
|
|
|
#endif
|
2011-03-15 11:20:14 -04:00
|
|
|
try {
|
|
|
|
_firstEdge.resize( _numNodes + 1 );
|
|
|
|
} catch(...) {
|
2011-12-02 10:38:10 -05:00
|
|
|
ERR("Not enough RAM on machine");
|
2011-08-04 13:07:51 -04:00
|
|
|
return;
|
2011-03-15 11:20:14 -04:00
|
|
|
}
|
|
|
|
_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 ) );
|
|
|
|
}
|
|
|
|
|
2011-12-02 10:38:10 -05:00
|
|
|
INFO("Scanning for useless shortcuts");
|
2011-03-15 11:20:14 -04:00
|
|
|
BuildOutgoingGraph();
|
2010-07-09 05:05:40 -04:00
|
|
|
#pragma omp parallel for
|
2011-10-05 12:02:26 -04:00
|
|
|
for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
|
2011-03-15 11:20:14 -04:00
|
|
|
for ( unsigned edge = _firstEdge[_graph[i].source]; edge < _firstEdge[_graph[i].source + 1]; ++edge ) {
|
2011-10-10 09:00:08 -04:00
|
|
|
if ( edge == (unsigned)i )
|
2011-03-15 11:20:14 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-02 10:38:10 -05:00
|
|
|
INFO("Removing edges");
|
2011-08-04 13:07:51 -04:00
|
|
|
int useful = 0;
|
2011-03-15 11:20:14 -04:00
|
|
|
for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
|
|
|
|
if ( !_graph[i].data.forward && !_graph[i].data.backward && _graph[i].data.shortcut )
|
|
|
|
continue;
|
2011-08-04 13:07:51 -04:00
|
|
|
_graph[useful] = _graph[i];
|
|
|
|
useful++;
|
2011-03-15 11:20:14 -04:00
|
|
|
}
|
2011-12-02 10:38:10 -05:00
|
|
|
INFO("Removed " << _graph.size() - useful << " useless shortcuts");
|
2011-08-04 13:07:51 -04:00
|
|
|
_graph.resize( useful );
|
|
|
|
|
2011-03-15 11:20:14 -04:00
|
|
|
for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
|
|
|
delete threadData[threadNum];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-04 13:07:51 -04:00
|
|
|
void _ComputeStep( _Heap* heapForward, _Heap* heapBackward, bool forwardDirection, NodeID* middle, int* targetDistance ) {
|
2011-03-15 11:20:14 -04:00
|
|
|
|
|
|
|
const NodeID node = heapForward->DeleteMin();
|
|
|
|
const int distance = heapForward->GetKey( node );
|
|
|
|
|
2011-12-02 10:38:10 -05:00
|
|
|
if ( distance > *targetDistance ) {
|
|
|
|
heapForward->DeleteAll();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-03-15 11:20:14 -04:00
|
|
|
if ( heapBackward->WasInserted( node ) ) {
|
|
|
|
const int newDistance = heapBackward->GetKey( node ) + distance;
|
|
|
|
if ( newDistance < *targetDistance ) {
|
|
|
|
*middle = node;
|
|
|
|
*targetDistance = newDistance;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-02 10:38:10 -05:00
|
|
|
for ( int edge = _firstEdge[node], endEdges = _firstEdge[node + 1]; edge != endEdges; ++edge ) {
|
2011-03-15 11:20:14 -04:00
|
|
|
const NodeID to = _graph[edge].target;
|
|
|
|
const int edgeWeight = _graph[edge].data.distance;
|
|
|
|
assert( edgeWeight > 0 );
|
|
|
|
const int toDistance = distance + edgeWeight;
|
|
|
|
|
2011-08-04 13:07:51 -04:00
|
|
|
if ( (forwardDirection ? _graph[edge].data.forward : _graph[edge].data.backward ) ) {
|
2011-03-15 11:20:14 -04:00
|
|
|
//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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-02 10:38:10 -05:00
|
|
|
int _ComputeDistance( NodeID source, NodeID target, _ThreadData * data ) {
|
2011-03-15 11:20:14 -04:00
|
|
|
data->_heapForward->Clear();
|
|
|
|
data->_heapBackward->Clear();
|
|
|
|
//insert source into heap
|
|
|
|
data->_heapForward->Insert( source, 0, source );
|
|
|
|
data->_heapBackward->Insert( target, 0, target );
|
|
|
|
|
2011-12-02 10:38:10 -05:00
|
|
|
int targetDistance = std::numeric_limits< int >::max();
|
|
|
|
NodeID middle = std::numeric_limits<NodeID>::max();
|
2011-03-15 11:20:14 -04:00
|
|
|
|
|
|
|
while ( data->_heapForward->Size() + data->_heapBackward->Size() > 0 ) {
|
|
|
|
if ( data->_heapForward->Size() > 0 ) {
|
2011-08-04 13:07:51 -04:00
|
|
|
_ComputeStep( data->_heapForward, data->_heapBackward, true, &middle, &targetDistance );
|
2011-03-15 11:20:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( data->_heapBackward->Size() > 0 ) {
|
2011-08-04 13:07:51 -04:00
|
|
|
_ComputeStep( data->_heapBackward, data->_heapForward, false, &middle, &targetDistance );
|
2011-03-15 11:20:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return targetDistance;
|
|
|
|
}
|
|
|
|
NodeID _numNodes;
|
|
|
|
std::vector< Edge > _graph;
|
|
|
|
std::vector< unsigned > _firstEdge;
|
2010-07-09 05:05:40 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // CONTRACTIONCLEANUP_H_INCLUDED
|