Ticket #266: suurballe-1a9b60b22a8d.patch
File suurballe-1a9b60b22a8d.patch, 21.9 KB (added by , 16 years ago) |
---|
-
lemon/suurballe.h
# HG changeset patch # User Peter Kovacs <kpeter@inf.elte.hu> # Date 1240618361 -7200 # Node ID 1a9b60b22a8d6c051cf64b01e5ed028bc4e47386 # Parent b95898314e095d3b9f994b1a1068518f25016745 Modify the interface of Suurballe (#266, #181) - Move the parameters s and t from the constructor to the run() function. It makes the interface capable for multiple run(s,t,k) calls (possible improvement in the future) and it is more similar to Dijkstra. - Simliarly init() and findFlow(k) were replaced by init(s) and findFlow(t,k). The separation of parameters s and t is for the future plans of supporting multiple targets with one source node. For more information see #181. - LEMON_ASSERT for the Length type (check if it is integer). - Doc improvements. - Rearrange query functions. - Extend test file. diff --git a/lemon/suurballe.h b/lemon/suurballe.h
a b 42 42 /// finding arc-disjoint paths having minimum total length (cost) 43 43 /// from a given source node to a given target node in a digraph. 44 44 /// 45 /// In fact, this implementation is the specialization of the 46 /// \ref CapacityScaling "successive shortest path" algorithm. 45 /// Note that this problem is a special case of the \ref min_cost_flow 46 /// "minimum cost flow problem". This implementation is actually an 47 /// efficient specialized version of the \ref CapacityScaling 48 /// "Successive Shortest Path" algorithm directly for this problem. 49 /// Therefore this class provides query functions for flow values and 50 /// node potentials (the dual solution) just like the minimum cost flow 51 /// algorithms. 47 52 /// 48 53 /// \tparam GR The digraph type the algorithm runs on. 49 /// The default value is \c ListDigraph. 50 /// \tparam LEN The type of the length (cost) map. 51 /// The default value is <tt>Digraph::ArcMap<int></tt>. 54 /// \tparam LEN The type of the length map. 55 /// The default value is <tt>GR::ArcMap<int></tt>. 52 56 /// 53 57 /// \warning Length values should be \e non-negative \e integers. 54 58 /// 55 59 /// \note For finding node-disjoint paths this algorithm can be used 56 /// with \ref SplitNodes.60 /// along with the \ref SplitNodes adaptor. 57 61 #ifdef DOXYGEN 58 62 template <typename GR, typename LEN> 59 63 #else 60 template < typename GR = ListDigraph,64 template < typename GR, 61 65 typename LEN = typename GR::template ArcMap<int> > 62 66 #endif 63 67 class Suurballe … … 75 79 typedef LEN LengthMap; 76 80 /// The type of the lengths. 77 81 typedef typename LengthMap::Value Length; 82 #ifdef DOXYGEN 83 /// The type of the flow map. 84 typedef GR::ArcMap<int> FlowMap; 85 /// The type of the potential map. 86 typedef GR::NodeMap<Length> PotentialMap; 87 #else 78 88 /// The type of the flow map. 79 89 typedef typename Digraph::template ArcMap<int> FlowMap; 80 90 /// The type of the potential map. 81 91 typedef typename Digraph::template NodeMap<Length> PotentialMap; 92 #endif 93 82 94 /// The type of the path structures. 83 typedef SimplePath< Digraph> Path;95 typedef SimplePath<GR> Path; 84 96 85 97 private: 86 98 87 /// \brief Special implementation of the Dijkstra algorithm 88 /// for finding shortest paths in the residual network. 89 /// 90 /// \ref ResidualDijkstra is a special implementation of the 91 /// \ref Dijkstra algorithm for finding shortest paths in the 92 /// residual network of the digraph with respect to the reduced arc 93 /// lengths and modifying the node potentials according to the 94 /// distance of the nodes. 99 // ResidualDijkstra is a special implementation of the 100 // Dijkstra algorithm for finding shortest paths in the 101 // residual network with respect to the reduced arc lengths 102 // and modifying the node potentials according to the 103 // distance of the nodes. 95 104 class ResidualDijkstra 96 105 { 97 106 typedef typename Digraph::template NodeMap<int> HeapCrossRef; … … 120 129 public: 121 130 122 131 /// Constructor. 123 ResidualDijkstra( const Digraph & digraph,132 ResidualDijkstra( const Digraph &graph, 124 133 const FlowMap &flow, 125 134 const LengthMap &length, 126 135 PotentialMap &potential, 127 136 PredMap &pred, 128 137 Node s, Node t ) : 129 _graph( digraph), _flow(flow), _length(length), _potential(potential),130 _dist( digraph), _pred(pred), _s(s), _t(t) {}138 _graph(graph), _flow(flow), _length(length), _potential(potential), 139 _dist(graph), _pred(pred), _s(s), _t(t) {} 131 140 132 141 /// \brief Run the algorithm. It returns \c true if a path is found 133 142 /// from the source node to the target node. … … 236 245 /// 237 246 /// Constructor. 238 247 /// 239 /// \param digraph The digraph the algorithm runs on.248 /// \param graph The digraph the algorithm runs on. 240 249 /// \param length The length (cost) values of the arcs. 241 /// \param s The source node.242 /// \param t The target node.243 Suurballe( const Digraph &digraph,244 const LengthMap &length,245 Node s, Node t ) :246 _graph(digraph), _length(length), _flow(0), _local_flow(false),247 _potential(0), _local_potential(false), _source(s), _target(t),248 _pred(digraph) {}250 Suurballe( const Digraph &graph, 251 const LengthMap &length ) : 252 _graph(graph), _length(length), _flow(0), _local_flow(false), 253 _potential(0), _local_potential(false), _pred(graph) 254 { 255 LEMON_ASSERT(std::numeric_limits<Length>::is_integer, 256 "The length type of Suurballe must be integer"); 257 } 249 258 250 259 /// Destructor. 251 260 ~Suurballe() { … … 257 266 /// \brief Set the flow map. 258 267 /// 259 268 /// This function sets the flow map. 269 /// If it is not used before calling \ref run() or \ref init(), 270 /// an instance will be allocated automatically. The destructor 271 /// deallocates this automatically allocated map, of course. 260 272 /// 261 /// The found flow contains only 0 and 1 values . It is the union of262 /// the found arc-disjoint paths.273 /// The found flow contains only 0 and 1 values, since it is the 274 /// union of the found arc-disjoint paths. 263 275 /// 264 276 /// \return <tt>(*this)</tt> 265 277 Suurballe& flowMap(FlowMap &map) { … … 274 286 /// \brief Set the potential map. 275 287 /// 276 288 /// This function sets the potential map. 289 /// If it is not used before calling \ref run() or \ref init(), 290 /// an instance will be allocated automatically. The destructor 291 /// deallocates this automatically allocated map, of course. 277 292 /// 278 /// The potentials provide the dual solution of the underlying279 /// minimum cost flow problem.293 /// The node potentials provide the dual solution of the underlying 294 /// \ref min_cost_flow "minimum cost flow problem". 280 295 /// 281 296 /// \return <tt>(*this)</tt> 282 297 Suurballe& potentialMap(PotentialMap &map) { … … 301 316 /// 302 317 /// This function runs the algorithm. 303 318 /// 319 /// \param s The source node. 320 /// \param t The target node. 304 321 /// \param k The number of paths to be found. 305 322 /// 306 323 /// \return \c k if there are at least \c k arc-disjoint paths from 307 324 /// \c s to \c t in the digraph. Otherwise it returns the number of 308 325 /// arc-disjoint paths found. 309 326 /// 310 /// \note Apart from the return value, <tt>s.run( k)</tt> is just a311 /// shortcut of the following code.327 /// \note Apart from the return value, <tt>s.run(s, t, k)</tt> is 328 /// just a shortcut of the following code. 312 329 /// \code 313 /// s.init( );314 /// s.findFlow( k);330 /// s.init(s); 331 /// s.findFlow(t, k); 315 332 /// s.findPaths(); 316 333 /// \endcode 317 int run( int k = 2) {318 init( );319 findFlow( k);334 int run(const Node& s, const Node& t, int k = 2) { 335 init(s); 336 findFlow(t, k); 320 337 findPaths(); 321 338 return _path_num; 322 339 } … … 324 341 /// \brief Initialize the algorithm. 325 342 /// 326 343 /// This function initializes the algorithm. 327 void init() { 344 /// 345 /// \param s The source node. 346 void init(const Node& s) { 347 _source = s; 348 328 349 // Initialize maps 329 350 if (!_flow) { 330 351 _flow = new FlowMap(_graph); … … 336 357 } 337 358 for (ArcIt e(_graph); e != INVALID; ++e) (*_flow)[e] = 0; 338 359 for (NodeIt n(_graph); n != INVALID; ++n) (*_potential)[n] = 0; 339 340 _dijkstra = new ResidualDijkstra( _graph, *_flow, _length,341 *_potential, _pred,342 _source, _target );343 360 } 344 361 345 /// \brief Execute the successive shortest path algorithm to find 346 /// an optimal flow. 362 /// \brief Execute the algorithm to find an optimal flow. 347 363 /// 348 364 /// This function executes the successive shortest path algorithm to 349 /// find a minimum cost flow, which is the union of \c k or less365 /// find a minimum cost flow, which is the union of \c k (or less) 350 366 /// arc-disjoint paths. 351 367 /// 368 /// \param t The target node. 369 /// \param k The number of paths to be found. 370 /// 352 371 /// \return \c k if there are at least \c k arc-disjoint paths from 353 /// \c s to \c t in the digraph. Otherwise it returns the number of354 /// arc-disjoint paths found.372 /// the source node to the given node \c t in the digraph. 373 /// Otherwise it returns the number of arc-disjoint paths found. 355 374 /// 356 375 /// \pre \ref init() must be called before using this function. 357 int findFlow(int k = 2) { 376 int findFlow(const Node& t, int k = 2) { 377 _target = t; 378 _dijkstra = 379 new ResidualDijkstra( _graph, *_flow, _length, *_potential, _pred, 380 _source, _target ); 381 358 382 // Find shortest paths 359 383 _path_num = 0; 360 384 while (_path_num < k) { … … 380 404 381 405 /// \brief Compute the paths from the flow. 382 406 /// 383 /// This function computes the paths from the flow. 407 /// This function computes the paths from the found minimum cost flow, 408 /// which is the union of some arc-disjoint paths. 384 409 /// 385 410 /// \pre \ref init() and \ref findFlow() must be called before using 386 411 /// this function. 387 412 void findPaths() { 388 // Create the residual flow map (the union of the paths not found389 // so far)390 413 FlowMap res_flow(_graph); 391 414 for(ArcIt a(_graph); a != INVALID; ++a) res_flow[a] = (*_flow)[a]; 392 415 … … 413 436 414 437 /// @{ 415 438 416 /// \brief Return a const reference to the arc map storing the 439 /// \brief Return the total length of the found paths. 440 /// 441 /// This function returns the total length of the found paths, i.e. 442 /// the total cost of the found flow. 443 /// The complexity of the function is O(e). 444 /// 445 /// \pre \ref run() or \ref findFlow() must be called before using 446 /// this function. 447 Length totalLength() const { 448 Length c = 0; 449 for (ArcIt e(_graph); e != INVALID; ++e) 450 c += (*_flow)[e] * _length[e]; 451 return c; 452 } 453 454 /// \brief Return the flow value on the given arc. 455 /// 456 /// This function returns the flow value on the given arc. 457 /// It is \c 1 if the arc is involved in one of the found arc-disjoint 458 /// paths, otherwise it is \c 0. 459 /// 460 /// \pre \ref run() or \ref findFlow() must be called before using 461 /// this function. 462 int flow(const Arc& arc) const { 463 return (*_flow)[arc]; 464 } 465 466 /// \brief Return a const reference to an arc map storing the 417 467 /// found flow. 418 468 /// 419 /// This function returns a const reference to thearc map storing469 /// This function returns a const reference to an arc map storing 420 470 /// the flow that is the union of the found arc-disjoint paths. 421 471 /// 422 472 /// \pre \ref run() or \ref findFlow() must be called before using … … 425 475 return *_flow; 426 476 } 427 477 428 /// \brief Return a const reference to the node map storing the429 /// found potentials (the dual solution).430 ///431 /// This function returns a const reference to the node map storing432 /// the found potentials that provide the dual solution of the433 /// underlying minimum cost flow problem.434 ///435 /// \pre \ref run() or \ref findFlow() must be called before using436 /// this function.437 const PotentialMap& potentialMap() const {438 return *_potential;439 }440 441 /// \brief Return the flow on the given arc.442 ///443 /// This function returns the flow on the given arc.444 /// It is \c 1 if the arc is involved in one of the found paths,445 /// otherwise it is \c 0.446 ///447 /// \pre \ref run() or \ref findFlow() must be called before using448 /// this function.449 int flow(const Arc& arc) const {450 return (*_flow)[arc];451 }452 453 478 /// \brief Return the potential of the given node. 454 479 /// 455 480 /// This function returns the potential of the given node. 481 /// The node potentials provide the dual solution of the 482 /// underlying \ref min_cost_flow "minimum cost flow problem". 456 483 /// 457 484 /// \pre \ref run() or \ref findFlow() must be called before using 458 485 /// this function. … … 460 487 return (*_potential)[node]; 461 488 } 462 489 463 /// \brief Return the total length (cost) of the found paths (flow). 490 /// \brief Return a const reference to a node map storing the 491 /// found potentials (the dual solution). 464 492 /// 465 /// This function returns the total length (cost) of the found paths 466 /// (flow). The complexity of the function is O(e). 493 /// This function returns a const reference to a node map storing 494 /// the found potentials that provide the dual solution of the 495 /// underlying \ref min_cost_flow "minimum cost flow problem". 467 496 /// 468 497 /// \pre \ref run() or \ref findFlow() must be called before using 469 498 /// this function. 470 Length totalLength() const { 471 Length c = 0; 472 for (ArcIt e(_graph); e != INVALID; ++e) 473 c += (*_flow)[e] * _length[e]; 474 return c; 499 const PotentialMap& potentialMap() const { 500 return *_potential; 475 501 } 476 502 477 503 /// \brief Return the number of the found paths. … … 488 514 /// 489 515 /// This function returns a const reference to the specified path. 490 516 /// 491 /// \param i The function returns the \c i-th path.517 /// \param i The function returns the <tt>i</tt>-th path. 492 518 /// \c i must be between \c 0 and <tt>%pathNum()-1</tt>. 493 519 /// 494 520 /// \pre \ref run() or \ref findPaths() must be called before using -
test/suurballe_test.cc
diff --git a/test/suurballe_test.cc b/test/suurballe_test.cc
a b 22 22 #include <lemon/lgf_reader.h> 23 23 #include <lemon/path.h> 24 24 #include <lemon/suurballe.h> 25 #include <lemon/concepts/digraph.h> 25 26 26 27 #include "test_tools.h" 27 28 … … 29 30 30 31 char test_lgf[] = 31 32 "@nodes\n" 32 "label supply1 supply2 supply3\n"33 "1 0 20 27\n"34 "2 0 -4 0\n"35 "3 0 0 0\n"36 "4 0 0 0\n"37 "5 0 9 0\n"38 "6 0 -6 0\n"39 "7 0 0 0\n"40 "8 0 0 0\n"41 "9 0 3 0\n"42 "10 0 -2 0\n"43 "11 0 0 0\n"44 "12 0 -20 -27\n"33 "label\n" 34 "1\n" 35 "2\n" 36 "3\n" 37 "4\n" 38 "5\n" 39 "6\n" 40 "7\n" 41 "8\n" 42 "9\n" 43 "10\n" 44 "11\n" 45 "12\n" 45 46 "@arcs\n" 46 " cost capacity lower1 lower2\n"47 " 1 2 70 11 0 8\n"48 " 1 3 150 3 0 1\n"49 " 1 4 80 15 0 2\n"50 " 2 8 80 12 0 0\n"51 " 3 5 140 5 0 3\n"52 " 4 6 60 10 0 1\n"53 " 4 7 80 2 0 0\n"54 " 4 8 110 3 0 0\n"55 " 5 7 60 14 0 0\n"56 " 5 11 120 12 0 0\n"57 " 6 3 0 3 0 0\n"58 " 6 9 140 4 0 0\n"59 " 6 10 90 8 0 0\n"60 " 7 1 30 5 0 0\n"61 " 8 12 60 16 0 4\n"62 " 9 12 50 6 0 0\n"63 "10 12 70 13 0 5\n"64 "10 2 100 7 0 0\n"65 "10 7 60 10 0 0\n"66 "11 10 20 14 0 6\n"67 "12 11 30 10 0 0\n"47 " length\n" 48 " 1 2 70\n" 49 " 1 3 150\n" 50 " 1 4 80\n" 51 " 2 8 80\n" 52 " 3 5 140\n" 53 " 4 6 60\n" 54 " 4 7 80\n" 55 " 4 8 110\n" 56 " 5 7 60\n" 57 " 5 11 120\n" 58 " 6 3 0\n" 59 " 6 9 140\n" 60 " 6 10 90\n" 61 " 7 1 30\n" 62 " 8 12 60\n" 63 " 9 12 50\n" 64 "10 12 70\n" 65 "10 2 100\n" 66 "10 7 60\n" 67 "11 10 20\n" 68 "12 11 30\n" 68 69 "@attributes\n" 69 70 "source 1\n" 70 71 "target 12\n" 71 72 "@end\n"; 72 73 74 // Check the interface of Suurballe 75 void checkSuurballeCompile() 76 { 77 typedef int VType; 78 typedef concepts::Digraph Digraph; 79 80 typedef Digraph::Node Node; 81 typedef Digraph::Arc Arc; 82 typedef concepts::ReadMap<Arc, VType> LengthMap; 83 84 typedef Suurballe<Digraph, LengthMap> SuurballeType; 85 86 Digraph g; 87 Node n; 88 Arc e; 89 LengthMap len; 90 SuurballeType::FlowMap flow(g); 91 SuurballeType::PotentialMap pi(g); 92 93 SuurballeType suurb_test(g, len); 94 const SuurballeType& const_suurb_test = suurb_test; 95 96 suurb_test 97 .flowMap(flow) 98 .potentialMap(pi); 99 100 int k; 101 k = suurb_test.run(n, n); 102 k = suurb_test.run(n, n, k); 103 suurb_test.init(n); 104 k = suurb_test.findFlow(n); 105 k = suurb_test.findFlow(n, k); 106 suurb_test.findPaths(); 107 108 int f; 109 VType c; 110 c = const_suurb_test.totalLength(); 111 f = const_suurb_test.flow(e); 112 const SuurballeType::FlowMap& fm = 113 const_suurb_test.flowMap(); 114 c = const_suurb_test.potential(n); 115 const SuurballeType::PotentialMap& pm = 116 const_suurb_test.potentialMap(); 117 k = const_suurb_test.pathNum(); 118 Path<Digraph> p = const_suurb_test.path(k); 119 120 ignore_unused_variable_warning(fm); 121 ignore_unused_variable_warning(pm); 122 } 123 73 124 // Check the feasibility of the flow 74 125 template <typename Digraph, typename FlowMap> 75 126 bool checkFlow( const Digraph& gr, const FlowMap& flow, … … 118 169 bool checkPath( const Digraph& gr, const Path& path, 119 170 typename Digraph::Node s, typename Digraph::Node t) 120 171 { 121 // Check the "Complementary Slackness" optimality condition122 172 TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); 123 173 Node n = s; 124 174 for (int i = 0; i < path.length(); ++i) { … … 136 186 // Read the test digraph 137 187 ListDigraph digraph; 138 188 ListDigraph::ArcMap<int> length(digraph); 139 Node s ource, target;189 Node s, t; 140 190 141 191 std::istringstream input(test_lgf); 142 192 DigraphReader<ListDigraph>(digraph, input). 143 arcMap(" cost", length).144 node("source", s ource).145 node("target", t arget).193 arcMap("length", length). 194 node("source", s). 195 node("target", t). 146 196 run(); 147 197 148 198 // Find 2 paths 149 199 { 150 Suurballe<ListDigraph> suurballe(digraph, length , source, target);151 check(suurballe.run( 2) == 2, "Wrong number of paths");152 check(checkFlow(digraph, suurballe.flowMap(), s ource, target, 2),200 Suurballe<ListDigraph> suurballe(digraph, length); 201 check(suurballe.run(s, t) == 2, "Wrong number of paths"); 202 check(checkFlow(digraph, suurballe.flowMap(), s, t, 2), 153 203 "The flow is not feasible"); 154 204 check(suurballe.totalLength() == 510, "The flow is not optimal"); 155 205 check(checkOptimality(digraph, length, suurballe.flowMap(), 156 206 suurballe.potentialMap()), 157 207 "Wrong potentials"); 158 208 for (int i = 0; i < suurballe.pathNum(); ++i) 159 check(checkPath(digraph, suurballe.path(i), source, target), 160 "Wrong path"); 209 check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); 161 210 } 162 211 163 212 // Find 3 paths 164 213 { 165 Suurballe<ListDigraph> suurballe(digraph, length , source, target);166 check(suurballe.run( 3) == 3, "Wrong number of paths");167 check(checkFlow(digraph, suurballe.flowMap(), s ource, target, 3),214 Suurballe<ListDigraph> suurballe(digraph, length); 215 check(suurballe.run(s, t, 3) == 3, "Wrong number of paths"); 216 check(checkFlow(digraph, suurballe.flowMap(), s, t, 3), 168 217 "The flow is not feasible"); 169 218 check(suurballe.totalLength() == 1040, "The flow is not optimal"); 170 219 check(checkOptimality(digraph, length, suurballe.flowMap(), 171 220 suurballe.potentialMap()), 172 221 "Wrong potentials"); 173 222 for (int i = 0; i < suurballe.pathNum(); ++i) 174 check(checkPath(digraph, suurballe.path(i), source, target), 175 "Wrong path"); 223 check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); 176 224 } 177 225 178 226 // Find 5 paths (only 3 can be found) 179 227 { 180 Suurballe<ListDigraph> suurballe(digraph, length , source, target);181 check(suurballe.run( 5) == 3, "Wrong number of paths");182 check(checkFlow(digraph, suurballe.flowMap(), s ource, target, 3),228 Suurballe<ListDigraph> suurballe(digraph, length); 229 check(suurballe.run(s, t, 5) == 3, "Wrong number of paths"); 230 check(checkFlow(digraph, suurballe.flowMap(), s, t, 3), 183 231 "The flow is not feasible"); 184 232 check(suurballe.totalLength() == 1040, "The flow is not optimal"); 185 233 check(checkOptimality(digraph, length, suurballe.flowMap(), 186 234 suurballe.potentialMap()), 187 235 "Wrong potentials"); 188 236 for (int i = 0; i < suurballe.pathNum(); ++i) 189 check(checkPath(digraph, suurballe.path(i), source, target), 190 "Wrong path"); 237 check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); 191 238 } 192 239 193 240 return 0; -
tools/lgf-gen.cc
diff --git a/tools/lgf-gen.cc b/tools/lgf-gen.cc
a b 480 480 Node b=g.v(*ei); 481 481 g.erase(*ei); 482 482 ConstMap<Arc,int> cegy(1); 483 Suurballe<ListGraph,ConstMap<Arc,int> > sur(g,cegy ,a,b);484 int k=sur.run( 2);483 Suurballe<ListGraph,ConstMap<Arc,int> > sur(g,cegy); 484 int k=sur.run(a,b,2); 485 485 if(k<2 || sur.totalLength()>d) 486 486 g.addEdge(a,b); 487 487 else cnt++; … … 511 511 Edge ne; 512 512 if(e==INVALID) { 513 513 ConstMap<Arc,int> cegy(1); 514 Suurballe<ListGraph,ConstMap<Arc,int> > 515 sur(g,cegy,pi->a,pi->b); 516 int k=sur.run(2); 514 Suurballe<ListGraph,ConstMap<Arc,int> > sur(g,cegy); 515 int k=sur.run(pi->a,pi->b,2); 517 516 if(k<2 || sur.totalLength()>d) 518 517 { 519 518 ne=g.addEdge(pi->a,pi->b);