SVN checkout 11/12/2010
[monav:monav.git] / plugins / contractionhierarchies / contractioncleanup.h
1 /*
2 Copyright 2010  Christian Vetter veaac.fdirct@gmail.com
3
4 This file is part of MoNav.
5
6 MoNav is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 MoNav is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with MoNav.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef CONTRACTIONCLEANUP_H_INCLUDED
21 #define CONTRACTIONCLEANUP_H_INCLUDED
22
23 #include <QTime>
24 #include <queue>
25 #include <stack>
26 #include "contractor.h"
27
28 class ContractionCleanup {
29         private:
30
31                 struct _HeapData {
32                         NodeID parent;
33                         _HeapData( NodeID p ) {
34                                 parent = p;
35                         }
36                 };
37
38                 class _Node {
39
40                         public:
41
42                                 NodeID id;
43                                 int depth;
44                                 NodeID mappedID;
45
46                                 static bool CompareByID( const _Node& left, const _Node& right ) {
47                                         return left.id < right.id;
48                                 }
49
50                                 static bool CompareByDepth( const _Node& left, const _Node& right ) {
51                                         return left.depth < right.depth;
52                                 }
53
54                                 static bool CompareByRemappedID( const _Node& left, const _Node& right ) {
55                                         return left.mappedID < right.mappedID;
56                                 }
57
58                 };
59
60                 class _Comp {
61                         public:
62                                 bool operator() ( const _Node& left, const _Node& right ) {
63                                         return left.mappedID < right.mappedID;
64                                 }
65                 };
66
67                 struct _Witness {
68                         int edge;
69                         int safe;
70                         NodeID affectedNode;
71
72                         bool operator< ( const _Witness& right ) const {
73                                 if ( edge != right.edge )
74                                         return edge < right.edge;
75                                 if ( affectedNode != right.affectedNode )
76                                         return affectedNode < right.affectedNode;
77                                 return safe < right.safe;
78                         }
79
80                         bool operator== ( const _Witness& right ) const {
81                                 return edge == right.edge && affectedNode == right.affectedNode;
82                         }
83                 };
84
85                 typedef BinaryHeap< NodeID, NodeID, int, _HeapData > _Heap;
86
87         public:
88
89                 struct Edge {
90                         NodeID source;
91                         NodeID target;
92                         struct EdgeData {
93                                 int distance : 29;
94                                 bool shortcut : 1;
95                                 bool forward : 1;
96                                 bool backward : 1;
97                                 union {
98                                         NodeID middle;
99                                         unsigned id;
100                                 };
101                         } data;
102
103                         //sorts by source and other attributes
104                         static bool CompareBySource( const Edge& left, const Edge& right ) {
105                                 if ( left.source != right.source )
106                                         return left.source < right.source;
107                                 int l = ( left.data.forward ? -1 : 0 ) + ( left.data.backward ? -1 : 0 );
108                                 int r = ( right.data.forward ? -1 : 0 ) + ( right.data.backward ? -1 : 0 );
109                                 if ( l != r )
110                                         return l < r;
111                                 if ( left.target != right.target )
112                                         return left.target < right.target;
113                                 return left.data.distance < right.data.distance;
114                         }
115
116                         //sorts by target
117                         static bool CompareByTarget( const Edge& left, const Edge& right ) {
118                                 return left.target < right.target;
119                         }
120
121                         bool operator== ( const Edge& right ) const {
122                                 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 );
123                         }
124                 };
125
126
127                 ContractionCleanup( int numNodes, const std::vector< Edge >& edges, const std::vector< Edge >& loops, const std::vector< Contractor::Witness >& witnessList ) {
128                         _graph = edges;
129                         _loops = loops;
130                         _witnessList = witnessList;
131                         _numNodes = numNodes;
132                         _heapForward = new _Heap( numNodes );
133                         _heapBackward = new _Heap( numNodes );
134                 }
135
136                 ~ContractionCleanup() {
137
138                 }
139
140                 void Run() {
141
142                         double time = _Timestamp();
143
144                         RemoveUselessShortcuts();
145
146                         ReorderNodes();
147
148                         //DistributeWitnessData();
149
150                         time = _Timestamp() - time;
151                         qDebug( "Postprocessing Time: %lf s", time );
152                 }
153
154                 template< class OutputEdge >
155                 void GetData( std::vector< OutputEdge >* edges, std::vector< NodeID >* map ) {
156                         std::sort( _remap.begin(), _remap.end(), _Node::CompareByID );
157
158                         for ( NodeID node = 0; node < _numNodes; ++node )
159                                 map->push_back( _remap[node].mappedID );
160
161                         convertEdges( edges, _graph );
162                         convertEdges( edges, _loops );
163
164                         std::sort( edges->begin(), edges->end() );
165                 }
166
167         private:
168
169                 template< class OutputEdge >
170                 void convertEdges( std::vector< OutputEdge >* to, const std::vector< Edge >& from )
171                 {
172                         for ( unsigned edge = 0, endEdges = from.size(); edge != endEdges; ++edge ) {
173                                 OutputEdge newEdge;
174                                 newEdge.source = _remap[from[edge].source].mappedID;
175                                 newEdge.target = _remap[from[edge].target].mappedID;
176                                 assert( newEdge.source >= newEdge.target );
177                                 newEdge.data.distance = from[edge].data.distance;
178                                 newEdge.data.shortcut = from[edge].data.shortcut;
179                                 if ( newEdge.data.shortcut )
180                                         newEdge.data.middle = _remap[from[edge].data.middle].mappedID;
181                                 else
182                                         newEdge.data.id = from[edge].data.id;
183                                 newEdge.data.forward = from[edge].data.forward;
184                                 newEdge.data.backward = from[edge].data.backward;
185                                 to->push_back( newEdge );
186                         }
187                 }
188
189                 class AllowForwardEdge {
190                         public:
191                                 bool operator()( const Edge& data ) const {
192                                         return data.data.forward;
193                                 }
194                 };
195
196                 class AllowBackwardEdge {
197                         public:
198                                 bool operator()( const Edge& data ) const {
199                                         return data.data.backward;
200                                 }
201                 };
202
203                 double _Timestamp() {
204                         static QTime timer;
205                         static bool first = true;
206                         if ( first )
207                         {
208                                 first = false;
209                                 timer.start();
210                         }
211                         return ( double ) timer.elapsed() / 1000;
212                 }
213
214                 void BuildOutgoingGraph() {
215                         //sort edges by source
216                         std::sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
217                         _firstEdge.resize( _numNodes + 1 );
218                         _firstEdge[0] = 0;
219                         for ( NodeID i = 0, node = 0; i < ( NodeID ) _graph.size(); i++ ) {
220                                 while ( _graph[i].source != node )
221                                         _firstEdge[++node] = i;
222                                 if ( i == ( NodeID ) _graph.size() - 1 )
223                                         while ( node < _numNodes )
224                                                 _firstEdge[++node] = ( int ) _graph.size();
225                         }
226                 }
227
228                 void BuildIncomingGraph() {
229                         //sort edges and compute _firstEdge for the reverse _graph
230                         sort( _graph.begin(), _graph.end(), Edge::CompareByTarget );
231                         _firstEdge.resize( _numNodes + 1 );
232                         _firstEdge[0] = 0;
233                         for ( NodeID i = 0, node = 0; i < ( NodeID ) _graph.size(); i++ ) {
234                                 while ( _graph[i].target != node )
235                                         _firstEdge[++node] = i;
236                                 if ( i == ( NodeID ) _graph.size() - 1 )
237                                         while ( node < _numNodes )
238                                                 _firstEdge[++node] = ( int ) _graph.size();
239                         }
240                 }
241
242                 void RemoveUselessShortcuts() {
243
244                         qDebug( "Scanning for useless shortcuts" );
245                         BuildOutgoingGraph();
246                         int numUseless = 0;
247                         for ( unsigned i = 0; i < ( unsigned ) _graph.size(); i++ ) {
248
249                                 for ( unsigned edge = _firstEdge[_graph[i].source]; edge < _firstEdge[_graph[i].source + 1]; ++edge ) {
250                                         if ( _graph[edge].target != _graph[i].target )
251                                                 continue;
252                                         if ( _graph[edge].data.distance < _graph[i].data.distance )
253                                                 continue;
254                                         if ( edge == i )
255                                                 continue;
256                                         if ( !_graph[edge].data.shortcut )
257                                                 continue;
258
259
260                                         _graph[edge].data.forward &= !_graph[i].data.forward;
261                                         _graph[edge].data.backward &= !_graph[i].data.backward;
262                                 }
263
264                                 if ( !_graph[i].data.forward && !_graph[i].data.backward )
265                                         continue;
266
267                                 //only remove shortcuts
268                                 if ( !_graph[i].data.shortcut )
269                                         continue;
270
271                                 if ( _graph[i].data.forward ) {
272                                         int result = _ComputeDistance( _graph[i].source, _graph[i].target );
273
274                                         if ( result < _graph[i].data.distance ) {
275                                                 numUseless++;
276                                                 _graph[i].data.forward = false;
277                                                 //Contractor::Witness temp;
278                                                 //temp.source = _graph[i].source;
279                                                 //temp.target = _graph[i].target;
280                                                 //temp.middle = _graph[i].data.middle;
281                                                 //_witnessList.push_back( temp );
282                                         }
283                                 }
284                                 if ( _graph[i].data.backward ) {
285                                         int result = _ComputeDistance( _graph[i].target, _graph[i].source );
286
287                                         if ( result < _graph[i].data.distance ) {
288                                                 numUseless++;
289                                                 _graph[i].data.backward = false;
290                                                 //Contractor::Witness temp;
291                                                 //temp.source = _graph[i].target;
292                                                 //temp.target = _graph[i].source;
293                                                 //temp.middle = _graph[i].data.middle;
294                                                 //_witnessList.push_back( temp );
295                                         }
296                                 }
297                         }
298                         qDebug( "Found %d useless shortcut directions", numUseless );
299
300                         qDebug( "Removing edges" );
301                         int usefull = 0;
302                         for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
303                                 if ( !_graph[i].data.forward && !_graph[i].data.backward /*&& _graph[i].data.shortcut */ ) // remove original edges which are too long
304                                         continue;
305                                 _graph[usefull] = _graph[i];
306                                 usefull++;
307                         }
308                         qDebug( "Removed %d useless shortcuts", ( int ) _graph.size() - usefull );
309                         _graph.resize( usefull );
310                 }
311
312                 void ReorderNodes() {
313                         BuildOutgoingGraph();
314                         _remap.resize( _numNodes );
315                         for ( NodeID node = 0; node < _numNodes; ++node ) {
316                                 _remap[node].id = node;
317                         }
318
319                         qDebug( "Compute Node Depth" );
320                         {
321                                 std::queue< NodeID > q;
322                                 std::vector< unsigned > inDegree( _numNodes, 0 );
323                                 for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
324                                         inDegree[_graph[i].target]++;
325                                 }
326                                 for ( NodeID i = 0; i < _numNodes; i++ ) {
327                                         if ( inDegree[i] == 0 )
328                                                 q.push( i );
329                                 }
330                                 assert( !q.empty() );
331                                 NodeID lastNode = q.back();
332                                 int depth = 0;
333                                 while ( !q.empty() ) {
334                                         NodeID node = q.front();
335                                         q.pop();
336                                         _remap[node].depth = depth;
337                                         for ( unsigned i = _firstEdge[node], e = _firstEdge[node + 1]; i < e; i++ ) {
338                                                 const NodeID target = _graph[i].target;
339                                                 assert( inDegree[target] != 0 );
340                                                 inDegree[target]--;
341                                                 if ( inDegree[target] == 0 )
342                                                         q.push( target );
343                                         }
344                                         if ( node == lastNode ) {
345                                                 if ( !q.empty() )
346                                                         lastNode = q.back();
347                                                 depth++;
348                                         }
349                                 }
350                         }
351
352
353                         BuildIncomingGraph();
354                         qDebug( "Sort Nodes Topologically Depths First" );
355                         {
356                                 std::stack< unsigned > s;
357                                 std::vector< unsigned > outDegree( _numNodes, 0 );
358                                 for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
359                                         outDegree[_graph[i].source]++;
360                                 }
361                                 for ( NodeID i = 0; i < _numNodes; i++ ) {
362                                         if ( outDegree[i] == 0 )
363                                                 s.push( i );
364                                 }
365                                 NodeID newID = 0;
366                                 while ( !s.empty() ) {
367                                         unsigned n = s.top();
368                                         s.pop();
369                                         _remap[n].mappedID = newID++;
370                                         for ( unsigned i = _firstEdge[n], e = _firstEdge[n + 1]; i < e; i++ ) {
371                                                 const NodeID target = _graph[i].source;
372                                                 assert( outDegree[target] != 0 );
373                                                 outDegree[target]--;
374                                                 if ( outDegree[target] == 0 )
375                                                         s.push( target );
376                                         }
377                                 }
378                                 assert( newID == _numNodes );
379                         }
380
381                         qDebug( "Sort Nodes into buckets according to hierarchy depths" );
382                         {
383                                 //sort by level
384                                 sort( _remap.begin(), _remap.end(), _Node::CompareByDepth );
385
386                                 //sort buckets by original id
387                                 for ( NodeID i = 0; _numNodes - i > 16; ) {
388                                         NodeID bucketSize = ( _numNodes - i ) * 15 / 16;
389                                         NodeID position = i + bucketSize;
390                                         while ( position + 1 < _numNodes && _remap[position].depth == _remap[position + 1].depth )
391                                                 ++position;
392                                         sort( _remap.begin() + i, _remap.begin() + position, _Node::CompareByRemappedID );
393                                         i = position;
394                                 }
395
396                                 //sort by original id
397                                 for ( NodeID i = 0; i < _numNodes; i++ ) {
398                                         _remap[i].mappedID = i;
399                                 }
400                                 sort( _remap.begin(), _remap.end(), _Node::CompareByID );
401                         }
402
403                         //topological sorting
404                         qDebug( "Sort Nodes Topologically by computed order" );
405                         {
406                                 std::priority_queue< _Node, std::vector< _Node >, _Comp > q;
407                                 std::vector< unsigned > outDegree( _numNodes, 0 );
408                                 for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
409                                         outDegree[_graph[i].source]++;
410                                 }
411                                 for ( NodeID i = 0; i < _numNodes; i++ ) {
412                                         if ( outDegree[i] == 0 )
413                                                 q.push( _remap[i] );
414                                 }
415                                 NodeID newID = 0;
416                                 while ( !q.empty() ) {
417                                         _Node n = q.top();
418                                         q.pop();
419                                         _remap[n.id].mappedID = newID++;
420                                         for ( int i = _firstEdge[n.id], e = _firstEdge[n.id + 1]; i < e; i++ ) {
421                                                 const NodeID target = _graph[i].source;
422                                                 assert( outDegree[target] != 0 );
423                                                 outDegree[target]--;
424                                                 if ( outDegree[target] == 0 )
425                                                         q.push( _remap[target] );
426                                         }
427                                 }
428                                 assert( newID == _numNodes );
429                         }
430
431                         std::sort( _remap.begin(), _remap.end(), _Node::CompareByID );
432                 }
433
434                 void RemoveDuplicatedWitnesses() {
435                         qDebug( "Delete Duplicate Entries to save Memory" );
436                         if ( !_distributedWitnessData.empty() ) {
437                                 int oldSize = _distributedWitnessData.size();
438                                 sort( _distributedWitnessData.begin(), _distributedWitnessData.end() );
439                                 _distributedWitnessData.resize( std::unique( _distributedWitnessData.begin(), _distributedWitnessData.end() ) - _distributedWitnessData.begin() );
440                                 qDebug( "Deleted %d of %d" , ( int ) ( oldSize - _distributedWitnessData.size() ), oldSize );
441                         }
442                 }
443
444                 void DistributeWitnessData() {
445                         qDebug( "Distributing witness data" );
446                         BuildOutgoingGraph();
447                         int numDeletedWitness = 0;
448                         for ( unsigned i = _witnessList.size() - 1, e = _witnessList.size(); i < e; i-- ) {
449
450                                 //save some memory by removing duplicate data during the processing.
451                                 if ( i == e / 4 || i == e / 2 || i == e / 4 * 3 ) {
452                                         RemoveDuplicatedWitnesses();
453                                 }
454
455                                 //witness obsolet?
456                                 bool foundForwardEdge = false, foundBackwardEdge = false;
457                                 int weight = 0;
458                                 for ( int j = _firstEdge[_witnessList[i].middle], e = _firstEdge[_witnessList[i].middle + 1]; j < e; j++ ) {
459                                         if ( _graph[j].target == _witnessList[i].source && _graph[j].data.backward ) {
460                                                 foundBackwardEdge = true;
461                                                 weight += _graph[j].data.distance;
462                                         }
463                                         if ( _graph[j].target == _witnessList[i].target && _graph[j].data.forward ) {
464                                                 foundForwardEdge = true;
465                                                 weight += _graph[j].data.distance;
466                                         }
467                                 }
468                                 if ( !foundForwardEdge || !foundBackwardEdge ) {
469                                         numDeletedWitness++;
470                                         continue;
471                                 }
472
473                                 std::vector< NodeID > path;
474                                 int result = _ComputeDistance( _witnessList[i].source, _witnessList[i].target, &path );
475
476                                 for ( int j = 0; j < ( int ) path.size() - 1; j++ ) {
477                                         int actDepth = _remap[path[j]].depth;
478                                         int nextDepth = _remap[path[j + 1]].depth;
479                                         assert( actDepth != nextDepth );
480                                         _Witness temp;
481                                         temp.affectedNode = _witnessList[i].middle;
482                                         temp.safe = weight - result;
483                                         assert( temp.safe > 0 );
484                                         if ( nextDepth > actDepth ) {
485                                                 for ( unsigned edge = _firstEdge[path[j]], e = _firstEdge[path[j] + 1]; edge < e; edge++ ) {
486                                                         if ( _graph[edge].target == path[j + 1] && _graph[edge].data.forward ) {
487                                                                 temp.edge = edge;
488                                                                 break;
489                                                         }
490                                                         assert( edge != e - 1 );
491                                                 }
492                                         } else {
493                                                 for ( unsigned edge = _firstEdge[path[j + 1]], e = _firstEdge[path[j + 1] + 1]; edge < e; edge++ ) {
494                                                         if ( _graph[edge].target == path[j] && _graph[edge].data.backward ) {
495                                                                 temp.edge = edge;
496                                                                 break;
497                                                         }
498                                                         assert( edge != e - 1 );
499                                                 }
500                                         }
501                                         _distributedWitnessData.push_back( temp );
502                                 }
503
504                                 path.clear();
505                         }
506                         std::vector< Contractor::Witness >().swap( _witnessList );
507
508                         RemoveDuplicatedWitnesses();
509
510                         qDebug( "%d Edge _Witness Entries, %lf per Edge", ( int ) _witnessList.size(), _witnessList.size() * 1.0f / _graph.size() );
511
512                         _witnessIndex.resize( _graph.size() + 1 );
513                         _witnessIndex[0] = 0;
514                         double safeFactor = 0;
515                         for ( int i = 0, position = 0; i < ( int ) _graph.size(); i++ ) {
516                                 while ( _distributedWitnessData[position].edge == i && position < ( int ) _distributedWitnessData.size() ) {
517                                         safeFactor += _distributedWitnessData[position].safe;
518                                         position++;
519                                 }
520                                 _witnessIndex[i + 1] = position;
521                         }
522                         qDebug( "Average witness safty buffer: %lf", safeFactor / _distributedWitnessData.size() );
523
524                 }
525
526                 template< class EdgeAllowed > void _ComputeStep( _Heap* heapForward, _Heap* heapBackward, const EdgeAllowed& edgeAllowed, NodeID* middle, int* targetDistance ) {
527
528                         const NodeID node = heapForward->DeleteMin();
529                         const int distance = heapForward->GetKey( node );
530
531                         if ( heapBackward->WasInserted( node ) ) {
532                                 const int newDistance = heapBackward->GetKey( node ) + distance;
533                                 if ( newDistance < *targetDistance ) {
534                                         *middle = node;
535                                         *targetDistance = newDistance;
536                                 }
537                         }
538
539                         if ( distance > *targetDistance ) {
540                                 heapForward->DeleteAll();
541                                 return;
542                         }
543                         for ( int edge = _firstEdge[node], endEdges = _firstEdge[node + 1]; edge != endEdges; ++edge ) {
544                                 const NodeID to = _graph[edge].target;
545                                 const int edgeWeight = _graph[edge].data.distance;
546                                 assert( edgeWeight > 0 );
547                                 const int toDistance = distance + edgeWeight;
548
549                                 if ( edgeAllowed( _graph[edge] ) ) {
550                                         //New Node discovered -> Add to Heap + Node Info Storage
551                                         if ( !heapForward->WasInserted( to ) )
552                                                 heapForward->Insert( to, toDistance, node );
553
554                                         //Found a shorter Path -> Update distance
555                                         else if ( toDistance < heapForward->GetKey( to ) ) {
556                                                 heapForward->DecreaseKey( to, toDistance );
557                                                 //new parent
558                                                 heapForward->GetData( to ) = node;
559                                         }
560                                 }
561                         }
562                 }
563
564                 int _ComputeDistance( NodeID source, NodeID target, std::vector< NodeID >* path = NULL ) {
565                         _heapForward->Clear();
566                         _heapBackward->Clear();
567                         //insert source into heap
568                         _heapForward->Insert( source, 0, source );
569                         _heapBackward->Insert( target, 0, target );
570
571                         int targetDistance = std::numeric_limits< int >::max();
572                         NodeID middle = 0;
573                         AllowForwardEdge forward;
574                         AllowBackwardEdge backward;
575
576                         while ( _heapForward->Size() + _heapBackward->Size() > 0 ) {
577
578                                 if ( _heapForward->Size() > 0 ) {
579                                         _ComputeStep( _heapForward, _heapBackward, forward, &middle, &targetDistance );
580                                 }
581
582                                 if ( _heapBackward->Size() > 0 ) {
583                                         _ComputeStep( _heapBackward, _heapForward, backward, &middle, &targetDistance );
584                                 }
585
586                         }
587
588                         if ( targetDistance == std::numeric_limits< int >::max() )
589                                 return std::numeric_limits< unsigned >::max();
590
591                         if ( path == NULL )
592                                 return targetDistance;
593
594                         NodeID pathNode = middle;
595                         std::stack< NodeID > stack;
596
597                         while ( pathNode != source ) {
598                                 NodeID parent = _heapForward->GetData( pathNode ).parent;
599                                 stack.push( pathNode );
600                                 pathNode = parent;
601                         }
602                         stack.push( pathNode );
603                         path->push_back( source );
604
605                         while ( stack.size() > 1 ) {
606                                 const NodeID node = stack.top();
607                                 stack.pop();
608                                 _UnpackEdge( node, stack.top(), true, path );
609                         }
610
611                         pathNode = middle;
612                         while ( pathNode != target ) {
613                                 NodeID parent = _heapBackward->GetData( pathNode ).parent;
614                                 _UnpackEdge( parent, pathNode, false, path );
615                                 pathNode = parent;
616                         }
617
618                         return targetDistance;
619                 }
620
621                 bool _UnpackEdge( const NodeID source, const NodeID target, bool forward, std::vector< NodeID >* path ) {
622                         int edge = _firstEdge[source];
623
624                         for ( int endEdge = _firstEdge[source + 1]; edge != endEdge; ++edge ) {
625                                 if ( _graph[edge].target == target ) {
626                                         if ( forward && _graph[edge].data.forward )
627                                                 break;
628                                         if ( ( !forward ) && _graph[edge].data.backward )
629                                                 break;
630                                 }
631                         }
632                         assert( edge != ( int ) _firstEdge[source + 1] );
633
634                         if ( !_graph[edge].data.shortcut ) {
635                                 if ( forward )
636                                         path->push_back( target );
637                                 else
638                                         path->push_back( source );
639                                 return true;
640                         }
641
642                         const NodeID middle = _graph[edge].data.middle;
643
644                         if ( forward ) {
645                                 _UnpackEdge( middle, source, false, path );
646                                 _UnpackEdge( middle, target, true, path );
647                                 return true;
648                         } else {
649                                 _UnpackEdge( middle, target, false, path );
650                                 _UnpackEdge( middle, source, true, path );
651                                 return true;
652                         }
653                 }
654
655                 NodeID _numNodes;
656                 std::vector< Edge > _graph;
657                 std::vector< Edge > _loops;
658                 std::vector< unsigned > _firstEdge;
659                 std::vector< _Node > _remap;
660                 std::vector< Contractor::Witness > _witnessList;
661                 std::vector< _Witness > _distributedWitnessData;
662                 std::vector< unsigned > _witnessIndex;
663                 _Heap* _heapForward;
664                 _Heap* _heapBackward;
665 };
666
667 #endif // CONTRACTIONCLEANUP_H_INCLUDED