# HG changeset patch
# User Peter Kovacs <kpeter@inf.elte.hu>
# Date 1255647976 -7200
# Node ID ec0b1b423b8b100883ab1ef766204eb978363c80
# Parent 30c77d1c0cba549cb3f5309642d576cfa9c16534
Rework and improve Suurballe (#323)
- Improve the implementation: use a specific, faster variant of
residual Dijkstra for the first search.
- Some reorganizatiopn to make the code simpler.
- Small doc improvements.
diff --git a/lemon/suurballe.h b/lemon/suurballe.h
|
a
|
b
|
|
| 46 | 46 | /// Note that this problem is a special case of the \ref min_cost_flow |
| 47 | 47 | /// "minimum cost flow problem". This implementation is actually an |
| 48 | 48 | /// efficient specialized version of the \ref CapacityScaling |
| 49 | | /// "Successive Shortest Path" algorithm directly for this problem. |
| | 49 | /// "successive shortest path" algorithm directly for this problem. |
| 50 | 50 | /// Therefore this class provides query functions for flow values and |
| 51 | 51 | /// node potentials (the dual solution) just like the minimum cost flow |
| 52 | 52 | /// algorithms. |
| … |
… |
|
| 57 | 57 | /// |
| 58 | 58 | /// \warning Length values should be \e non-negative. |
| 59 | 59 | /// |
| 60 | | /// \note For finding node-disjoint paths this algorithm can be used |
| | 60 | /// \note For finding \e node-disjoint paths, this algorithm can be used |
| 61 | 61 | /// along with the \ref SplitNodes adaptor. |
| 62 | 62 | #ifdef DOXYGEN |
| 63 | 63 | template <typename GR, typename LEN> |
| … |
… |
|
| 109 | 109 | |
| 110 | 110 | private: |
| 111 | 111 | |
| 112 | | // The digraph the algorithm runs on |
| 113 | 112 | const Digraph &_graph; |
| 114 | | |
| 115 | | // The main maps |
| | 113 | const LengthMap &_length; |
| 116 | 114 | const FlowMap &_flow; |
| 117 | | const LengthMap &_length; |
| 118 | | PotentialMap &_potential; |
| 119 | | |
| 120 | | // The distance map |
| 121 | | PotentialMap _dist; |
| 122 | | // The pred arc map |
| | 115 | PotentialMap &_pi; |
| 123 | 116 | PredMap &_pred; |
| 124 | | // The processed (i.e. permanently labeled) nodes |
| 125 | | std::vector<Node> _proc_nodes; |
| 126 | | |
| 127 | 117 | Node _s; |
| 128 | 118 | Node _t; |
| | 119 | |
| | 120 | PotentialMap _dist; |
| | 121 | std::vector<Node> _proc_nodes; |
| 129 | 122 | |
| 130 | 123 | public: |
| 131 | 124 | |
| 132 | | /// Constructor. |
| 133 | | ResidualDijkstra( const Digraph &graph, |
| 134 | | const FlowMap &flow, |
| 135 | | const LengthMap &length, |
| 136 | | PotentialMap &potential, |
| 137 | | PredMap &pred, |
| 138 | | Node s, Node t ) : |
| 139 | | _graph(graph), _flow(flow), _length(length), _potential(potential), |
| 140 | | _dist(graph), _pred(pred), _s(s), _t(t) {} |
| | 125 | // Constructor |
| | 126 | ResidualDijkstra(Suurballe &srb) : |
| | 127 | _graph(srb._graph), _length(srb._length), |
| | 128 | _flow(*srb._flow), _pi(*srb._potential), _pred(srb._pred), |
| | 129 | _s(srb._s), _t(srb._t), _dist(_graph) {} |
| | 130 | |
| | 131 | // Run the algorithm and return true if a path is found |
| | 132 | // from the source node to the target node. |
| | 133 | bool run(int cnt) { |
| | 134 | return cnt == 0 ? startFirst() : start(); |
| | 135 | } |
| 141 | 136 | |
| 142 | | /// \brief Run the algorithm. It returns \c true if a path is found |
| 143 | | /// from the source node to the target node. |
| 144 | | bool run() { |
| | 137 | private: |
| | 138 | |
| | 139 | // Execute the algorithm for the first time (the flow and potential |
| | 140 | // functions have to be identically zero). |
| | 141 | bool startFirst() { |
| 145 | 142 | HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP); |
| 146 | 143 | Heap heap(heap_cross_ref); |
| 147 | 144 | heap.push(_s, 0); |
| … |
… |
|
| 151 | 148 | // Process nodes |
| 152 | 149 | while (!heap.empty() && heap.top() != _t) { |
| 153 | 150 | Node u = heap.top(), v; |
| 154 | | Length d = heap.prio() + _potential[u], nd; |
| | 151 | Length d = heap.prio(), dn; |
| 155 | 152 | _dist[u] = heap.prio(); |
| | 153 | _proc_nodes.push_back(u); |
| 156 | 154 | heap.pop(); |
| | 155 | |
| | 156 | // Traverse outgoing arcs |
| | 157 | for (OutArcIt e(_graph, u); e != INVALID; ++e) { |
| | 158 | v = _graph.target(e); |
| | 159 | switch(heap.state(v)) { |
| | 160 | case Heap::PRE_HEAP: |
| | 161 | heap.push(v, d + _length[e]); |
| | 162 | _pred[v] = e; |
| | 163 | break; |
| | 164 | case Heap::IN_HEAP: |
| | 165 | dn = d + _length[e]; |
| | 166 | if (dn < heap[v]) { |
| | 167 | heap.decrease(v, dn); |
| | 168 | _pred[v] = e; |
| | 169 | } |
| | 170 | break; |
| | 171 | case Heap::POST_HEAP: |
| | 172 | break; |
| | 173 | } |
| | 174 | } |
| | 175 | } |
| | 176 | if (heap.empty()) return false; |
| | 177 | |
| | 178 | // Update potentials of processed nodes |
| | 179 | Length t_dist = heap.prio(); |
| | 180 | for (int i = 0; i < int(_proc_nodes.size()); ++i) |
| | 181 | _pi[_proc_nodes[i]] = _dist[_proc_nodes[i]] - t_dist; |
| | 182 | return true; |
| | 183 | } |
| | 184 | |
| | 185 | // Execute the algorithm. |
| | 186 | bool start() { |
| | 187 | HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP); |
| | 188 | Heap heap(heap_cross_ref); |
| | 189 | heap.push(_s, 0); |
| | 190 | _pred[_s] = INVALID; |
| | 191 | _proc_nodes.clear(); |
| | 192 | |
| | 193 | // Process nodes |
| | 194 | while (!heap.empty() && heap.top() != _t) { |
| | 195 | Node u = heap.top(), v; |
| | 196 | Length d = heap.prio() + _pi[u], dn; |
| | 197 | _dist[u] = heap.prio(); |
| 157 | 198 | _proc_nodes.push_back(u); |
| | 199 | heap.pop(); |
| 158 | 200 | |
| 159 | 201 | // Traverse outgoing arcs |
| 160 | 202 | for (OutArcIt e(_graph, u); e != INVALID; ++e) { |
| 161 | 203 | if (_flow[e] == 0) { |
| 162 | 204 | v = _graph.target(e); |
| 163 | 205 | switch(heap.state(v)) { |
| 164 | | case Heap::PRE_HEAP: |
| 165 | | heap.push(v, d + _length[e] - _potential[v]); |
| 166 | | _pred[v] = e; |
| 167 | | break; |
| 168 | | case Heap::IN_HEAP: |
| 169 | | nd = d + _length[e] - _potential[v]; |
| 170 | | if (nd < heap[v]) { |
| 171 | | heap.decrease(v, nd); |
| | 206 | case Heap::PRE_HEAP: |
| | 207 | heap.push(v, d + _length[e] - _pi[v]); |
| 172 | 208 | _pred[v] = e; |
| 173 | | } |
| 174 | | break; |
| 175 | | case Heap::POST_HEAP: |
| 176 | | break; |
| | 209 | break; |
| | 210 | case Heap::IN_HEAP: |
| | 211 | dn = d + _length[e] - _pi[v]; |
| | 212 | if (dn < heap[v]) { |
| | 213 | heap.decrease(v, dn); |
| | 214 | _pred[v] = e; |
| | 215 | } |
| | 216 | break; |
| | 217 | case Heap::POST_HEAP: |
| | 218 | break; |
| 177 | 219 | } |
| 178 | 220 | } |
| 179 | 221 | } |
| … |
… |
|
| 183 | 225 | if (_flow[e] == 1) { |
| 184 | 226 | v = _graph.source(e); |
| 185 | 227 | switch(heap.state(v)) { |
| 186 | | case Heap::PRE_HEAP: |
| 187 | | heap.push(v, d - _length[e] - _potential[v]); |
| 188 | | _pred[v] = e; |
| 189 | | break; |
| 190 | | case Heap::IN_HEAP: |
| 191 | | nd = d - _length[e] - _potential[v]; |
| 192 | | if (nd < heap[v]) { |
| 193 | | heap.decrease(v, nd); |
| | 228 | case Heap::PRE_HEAP: |
| | 229 | heap.push(v, d - _length[e] - _pi[v]); |
| 194 | 230 | _pred[v] = e; |
| 195 | | } |
| 196 | | break; |
| 197 | | case Heap::POST_HEAP: |
| 198 | | break; |
| | 231 | break; |
| | 232 | case Heap::IN_HEAP: |
| | 233 | dn = d - _length[e] - _pi[v]; |
| | 234 | if (dn < heap[v]) { |
| | 235 | heap.decrease(v, dn); |
| | 236 | _pred[v] = e; |
| | 237 | } |
| | 238 | break; |
| | 239 | case Heap::POST_HEAP: |
| | 240 | break; |
| 199 | 241 | } |
| 200 | 242 | } |
| 201 | 243 | } |
| … |
… |
|
| 205 | 247 | // Update potentials of processed nodes |
| 206 | 248 | Length t_dist = heap.prio(); |
| 207 | 249 | for (int i = 0; i < int(_proc_nodes.size()); ++i) |
| 208 | | _potential[_proc_nodes[i]] += _dist[_proc_nodes[i]] - t_dist; |
| | 250 | _pi[_proc_nodes[i]] += _dist[_proc_nodes[i]] - t_dist; |
| 209 | 251 | return true; |
| 210 | 252 | } |
| 211 | 253 | |
| … |
… |
|
| 226 | 268 | bool _local_potential; |
| 227 | 269 | |
| 228 | 270 | // The source node |
| 229 | | Node _source; |
| | 271 | Node _s; |
| 230 | 272 | // The target node |
| 231 | | Node _target; |
| | 273 | Node _t; |
| 232 | 274 | |
| 233 | 275 | // Container to store the found paths |
| 234 | | std::vector< SimplePath<Digraph> > paths; |
| | 276 | std::vector<Path> _paths; |
| 235 | 277 | int _path_num; |
| 236 | 278 | |
| 237 | 279 | // The pred arc map |
| 238 | 280 | PredMap _pred; |
| 239 | | // Implementation of the Dijkstra algorithm for finding augmenting |
| 240 | | // shortest paths in the residual network |
| 241 | | ResidualDijkstra *_dijkstra; |
| 242 | 281 | |
| 243 | 282 | public: |
| 244 | 283 | |
| … |
… |
|
| 258 | 297 | ~Suurballe() { |
| 259 | 298 | if (_local_flow) delete _flow; |
| 260 | 299 | if (_local_potential) delete _potential; |
| 261 | | delete _dijkstra; |
| 262 | 300 | } |
| 263 | 301 | |
| 264 | 302 | /// \brief Set the flow map. |
| … |
… |
|
| 342 | 380 | /// |
| 343 | 381 | /// \param s The source node. |
| 344 | 382 | void init(const Node& s) { |
| 345 | | _source = s; |
| | 383 | _s = s; |
| 346 | 384 | |
| 347 | 385 | // Initialize maps |
| 348 | 386 | if (!_flow) { |
| … |
… |
|
| 372 | 410 | /// |
| 373 | 411 | /// \pre \ref init() must be called before using this function. |
| 374 | 412 | int findFlow(const Node& t, int k = 2) { |
| 375 | | _target = t; |
| 376 | | _dijkstra = |
| 377 | | new ResidualDijkstra( _graph, *_flow, _length, *_potential, _pred, |
| 378 | | _source, _target ); |
| | 413 | _t = t; |
| | 414 | ResidualDijkstra dijkstra(*this); |
| 379 | 415 | |
| 380 | 416 | // Find shortest paths |
| 381 | 417 | _path_num = 0; |
| 382 | 418 | while (_path_num < k) { |
| 383 | 419 | // Run Dijkstra |
| 384 | | if (!_dijkstra->run()) break; |
| | 420 | if (!dijkstra.run(_path_num)) break; |
| 385 | 421 | ++_path_num; |
| 386 | 422 | |
| 387 | 423 | // Set the flow along the found shortest path |
| 388 | | Node u = _target; |
| | 424 | Node u = _t; |
| 389 | 425 | Arc e; |
| 390 | 426 | while ((e = _pred[u]) != INVALID) { |
| 391 | 427 | if (u == _graph.target(e)) { |
| … |
… |
|
| 402 | 438 | |
| 403 | 439 | /// \brief Compute the paths from the flow. |
| 404 | 440 | /// |
| 405 | | /// This function computes the paths from the found minimum cost flow, |
| 406 | | /// which is the union of some arc-disjoint paths. |
| | 441 | /// This function computes arc-disjoint paths from the found minimum |
| | 442 | /// cost flow, which is the union of them. |
| 407 | 443 | /// |
| 408 | 444 | /// \pre \ref init() and \ref findFlow() must be called before using |
| 409 | 445 | /// this function. |
| … |
… |
|
| 411 | 447 | FlowMap res_flow(_graph); |
| 412 | 448 | for(ArcIt a(_graph); a != INVALID; ++a) res_flow[a] = (*_flow)[a]; |
| 413 | 449 | |
| 414 | | paths.clear(); |
| 415 | | paths.resize(_path_num); |
| | 450 | _paths.clear(); |
| | 451 | _paths.resize(_path_num); |
| 416 | 452 | for (int i = 0; i < _path_num; ++i) { |
| 417 | | Node n = _source; |
| 418 | | while (n != _target) { |
| | 453 | Node n = _s; |
| | 454 | while (n != _t) { |
| 419 | 455 | OutArcIt e(_graph, n); |
| 420 | 456 | for ( ; res_flow[e] == 0; ++e) ; |
| 421 | 457 | n = _graph.target(e); |
| 422 | | paths[i].addBack(e); |
| | 458 | _paths[i].addBack(e); |
| 423 | 459 | res_flow[e] = 0; |
| 424 | 460 | } |
| 425 | 461 | } |
| … |
… |
|
| 518 | 554 | /// \pre \ref run() or \ref findPaths() must be called before using |
| 519 | 555 | /// this function. |
| 520 | 556 | const Path& path(int i) const { |
| 521 | | return paths[i]; |
| | 557 | return _paths[i]; |
| 522 | 558 | } |
| 523 | 559 | |
| 524 | 560 | /// @} |