# HG changeset patch # User Alpar Juttner # Date 2011-12-20 18:15:14 # Node ID 2b6bffe0e7e8fb2289e499ae0933a7d77cc7aab4 # Parent 7c4ba7daaf5fa14c7f71cdd46397629e1236f977 # Parent 633956ca94216c105406ba14c38f1c73199289a3 Merge diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -22,6 +22,7 @@ lemon/libemon.la lemon/stamp-h2 doc/Doxyfile +doc/references.dox cmake/version.cmake .dirstamp .libs/* diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,8 @@ CHECK_TYPE_SIZE("long long" LONG_LONG) SET(LEMON_HAVE_LONG_LONG ${HAVE_LONG_LONG}) +INCLUDE(FindPythonInterp) + ENABLE_TESTING() IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer") diff --git a/INSTALL b/INSTALL --- a/INSTALL +++ b/INSTALL @@ -173,3 +173,25 @@ --without-coin Disable COIN-OR support. + + +Makefile Variables +================== + +Some Makefile variables are reserved by the GNU Coding Standards for +the use of the "user" - the person building the package. For instance, +CXX and CXXFLAGS are such variables, and have the same meaning as +explained in the previous section. These variables can be set on the +command line when invoking `make' like this: +`make [VARIABLE=VALUE]...' + +WARNINGCXXFLAGS is a non-standard Makefile variable introduced by us +to hold several compiler flags related to warnings. Its default value +can be overridden when invoking `make'. For example to disable all +warning flags use `make WARNINGCXXFLAGS='. + +In order to turn off a single flag from the default set of warning +flags, you can use the CXXFLAGS variable, since this is passed after +WARNINGCXXFLAGS. For example to turn off `-Wold-style-cast' (which is +used by default when g++ is detected) you can use +`make CXXFLAGS="-g -O2 -Wno-old-style-cast"'. diff --git a/Makefile.am b/Makefile.am --- a/Makefile.am +++ b/Makefile.am @@ -44,6 +44,7 @@ include test/Makefile.am include doc/Makefile.am include tools/Makefile.am +include scripts/Makefile.am DIST_SUBDIRS = demo diff --git a/README b/README --- a/README +++ b/README @@ -17,6 +17,10 @@ Copying, distribution and modification conditions and terms. +NEWS + + News and version history. + INSTALL General building and installation instructions. @@ -33,6 +37,10 @@ Some example programs to make you easier to get familiar with LEMON. +scripts/ + + Scripts that make it easier to develop LEMON. + test/ Programs to check the integrity and correctness of LEMON. diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,7 @@ AC_PROG_LIBTOOL AC_CHECK_PROG([doxygen_found],[doxygen],[yes],[no]) +AC_CHECK_PROG([python_found],[python],[yes],[no]) AC_CHECK_PROG([gs_found],[gs],[yes],[no]) dnl Detect Intel compiler. @@ -82,6 +83,21 @@ fi AM_CONDITIONAL([WANT_TOOLS], [test x"$enable_tools" != x"no"]) +dnl Support for running test cases using valgrind. +use_valgrind=no +AC_ARG_ENABLE([valgrind], +AS_HELP_STRING([--enable-valgrind], [use valgrind when running tests]), + [use_valgrind=yes]) + +if [[ "$use_valgrind" = "yes" ]]; then + AC_CHECK_PROG(HAVE_VALGRIND, valgrind, yes, no) + + if [[ "$HAVE_VALGRIND" = "no" ]]; then + AC_MSG_ERROR([Valgrind not found in PATH.]) + fi +fi +AM_CONDITIONAL(USE_VALGRIND, [test "$use_valgrind" = "yes"]) + dnl Checks for header files. AC_CHECK_HEADERS(limits.h sys/time.h sys/times.h unistd.h) @@ -128,6 +144,7 @@ echo CBC support................... : $lx_cbc_found echo echo Build additional tools........ : $enable_tools +echo Use valgrind for tests........ : $use_valgrind echo echo The packace will be installed in echo -n ' ' diff --git a/demo/arg_parser_demo.cc b/demo/arg_parser_demo.cc --- a/demo/arg_parser_demo.cc +++ b/demo/arg_parser_demo.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -65,9 +65,18 @@ ap.other("infile", "The input file.") .other("..."); + // Throw an exception when problems occurs. The default behavior is to + // exit(1) on these cases, but this makes Valgrind falsely warn + // about memory leaks. + ap.throwOnProblems(); + // Perform the parsing process // (in case of any error it terminates the program) - ap.parse(); + // The try {} construct is necessary only if the ap.trowOnProblems() + // setting is in use. + try { + ap.parse(); + } catch (ArgParserException &) { return 1; } // Check each option if it has been given and print its value std::cout << "Parameters of '" << ap.commandName() << "':\n"; diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -17,7 +17,7 @@ @ONLY ) -IF(DOXYGEN_EXECUTABLE AND GHOSTSCRIPT_EXECUTABLE) +IF(DOXYGEN_EXECUTABLE AND PYTHONINTERP_FOUND AND GHOSTSCRIPT_EXECUTABLE) FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/) SET(GHOSTSCRIPT_OPTIONS -dNOPAUSE -dBATCH -q -dEPSCrop -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -sDEVICE=pngalpha) ADD_CUSTOM_TARGET(html @@ -28,14 +28,17 @@ COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/connected_components.png ${CMAKE_CURRENT_SOURCE_DIR}/images/connected_components.eps COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/edge_biconnected_components.png ${CMAKE_CURRENT_SOURCE_DIR}/images/edge_biconnected_components.eps COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/grid_graph.png ${CMAKE_CURRENT_SOURCE_DIR}/images/grid_graph.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/matching.png ${CMAKE_CURRENT_SOURCE_DIR}/images/matching.eps COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/node_biconnected_components.png ${CMAKE_CURRENT_SOURCE_DIR}/images/node_biconnected_components.eps COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/nodeshape_0.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_0.eps COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/nodeshape_1.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_1.eps COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/nodeshape_2.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_2.eps COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/nodeshape_3.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_3.eps COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/nodeshape_4.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_4.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/planar.png ${CMAKE_CURRENT_SOURCE_DIR}/images/planar.eps COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/strongly_connected_components.png ${CMAKE_CURRENT_SOURCE_DIR}/images/strongly_connected_components.eps COMMAND ${CMAKE_COMMAND} -E remove_directory html + COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/bib2dox.py ${CMAKE_CURRENT_SOURCE_DIR}/references.bib >references.dox COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -97,7 +97,8 @@ "@abs_top_srcdir@/demo" \ "@abs_top_srcdir@/tools" \ "@abs_top_srcdir@/test/test_tools.h" \ - "@abs_top_builddir@/doc/mainpage.dox" + "@abs_top_builddir@/doc/mainpage.dox" \ + "@abs_top_builddir@/doc/references.dox" INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.h \ *.cc \ diff --git a/doc/Makefile.am b/doc/Makefile.am --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -27,7 +27,9 @@ bipartite_partitions.eps \ connected_components.eps \ edge_biconnected_components.eps \ + matching.eps \ node_biconnected_components.eps \ + planar.eps \ strongly_connected_components.eps DOC_EPS_IMAGES = \ @@ -66,7 +68,19 @@ exit 1; \ fi -html-local: $(DOC_PNG_IMAGES) +references.dox: doc/references.bib + if test ${python_found} = yes; then \ + cd doc; \ + python @abs_top_srcdir@/scripts/bib2dox.py @abs_top_builddir@/$< >$@; \ + cd ..; \ + else \ + echo; \ + echo "Python not found."; \ + echo; \ + exit 1; \ + fi + +html-local: $(DOC_PNG_IMAGES) references.dox if test ${doxygen_found} = yes; then \ cd doc; \ doxygen Doxyfile; \ diff --git a/doc/groups.dox b/doc/groups.dox --- a/doc/groups.dox +++ b/doc/groups.dox @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -226,14 +226,6 @@ */ /** -@defgroup matrices Matrices -@ingroup datas -\brief Two dimensional data storages implemented in LEMON. - -This group contains two dimensional data storages implemented in LEMON. -*/ - -/** @defgroup paths Path Structures @ingroup datas \brief %Path structures implemented in LEMON. @@ -246,7 +238,36 @@ efficient to have e.g. the Dijkstra algorithm to store its result in any kind of path structure. -\sa lemon::concepts::Path +\sa \ref concepts::Path "Path concept" +*/ + +/** +@defgroup heaps Heap Structures +@ingroup datas +\brief %Heap structures implemented in LEMON. + +This group contains the heap structures implemented in LEMON. + +LEMON provides several heap classes. They are efficient implementations +of the abstract data type \e priority \e queue. They store items with +specified values called \e priorities in such a way that finding and +removing the item with minimum priority are efficient. +The basic operations are adding and erasing items, changing the priority +of an item, etc. + +Heaps are crucial in several algorithms, such as Dijkstra and Prim. +The heap implementations have the same interface, thus any of them can be +used easily in such algorithms. + +\sa \ref concepts::Heap "Heap concept" +*/ + +/** +@defgroup matrices Matrices +@ingroup datas +\brief Two dimensional data storages implemented in LEMON. + +This group contains two dimensional data storages implemented in LEMON. */ /** @@ -259,6 +280,28 @@ */ /** +@defgroup geomdat Geometric Data Structures +@ingroup auxdat +\brief Geometric data structures implemented in LEMON. + +This group contains geometric data structures implemented in LEMON. + + - \ref lemon::dim2::Point "dim2::Point" implements a two dimensional + vector with the usual operations. + - \ref lemon::dim2::Box "dim2::Box" can be used to determine the + rectangular bounding box of a set of \ref lemon::dim2::Point + "dim2::Point"'s. +*/ + +/** +@defgroup matrices Matrices +@ingroup auxdat +\brief Two dimensional data storages implemented in LEMON. + +This group contains two dimensional data storages implemented in LEMON. +*/ + +/** @defgroup algs Algorithms \brief This group contains the several algorithms implemented in LEMON. @@ -273,7 +316,8 @@ \brief Common graph search algorithms. This group contains the common graph search algorithms, namely -\e breadth-first \e search (BFS) and \e depth-first \e search (DFS). +\e breadth-first \e search (BFS) and \e depth-first \e search (DFS) +\ref clrs01algorithms. */ /** @@ -281,7 +325,8 @@ @ingroup algs \brief Algorithms for finding shortest paths. -This group contains the algorithms for finding shortest paths in digraphs. +This group contains the algorithms for finding shortest paths in digraphs +\ref clrs01algorithms. - \ref Dijkstra algorithm for finding shortest paths from a source node when all arc lengths are non-negative. @@ -298,12 +343,21 @@ */ /** +@defgroup spantree Minimum Spanning Tree Algorithms +@ingroup algs +\brief Algorithms for finding minimum cost spanning trees and arborescences. + +This group contains the algorithms for finding minimum cost spanning +trees and arborescences \ref clrs01algorithms. +*/ + +/** @defgroup max_flow Maximum Flow Algorithms @ingroup algs \brief Algorithms for finding maximum flows. This group contains the algorithms for finding maximum flows and -feasible circulations. +feasible circulations \ref clrs01algorithms, \ref amo93networkflows. The \e maximum \e flow \e problem is to find a flow of maximum value between a single source and a single target. Formally, there is a \f$G=(V,A)\f$ @@ -318,17 +372,21 @@ \f[ 0 \leq f(uv) \leq cap(uv) \quad \forall uv\in A \f] LEMON contains several algorithms for solving maximum flow problems: -- \ref EdmondsKarp Edmonds-Karp algorithm. -- \ref Preflow Goldberg-Tarjan's preflow push-relabel algorithm. -- \ref DinitzSleatorTarjan Dinitz's blocking flow algorithm with dynamic trees. -- \ref GoldbergTarjan Preflow push-relabel algorithm with dynamic trees. +- \ref EdmondsKarp Edmonds-Karp algorithm + \ref edmondskarp72theoretical. +- \ref Preflow Goldberg-Tarjan's preflow push-relabel algorithm + \ref goldberg88newapproach. +- \ref DinitzSleatorTarjan Dinitz's blocking flow algorithm with dynamic trees + \ref dinic70algorithm, \ref sleator83dynamic. +- \ref GoldbergTarjan !Preflow push-relabel algorithm with dynamic trees + \ref goldberg88newapproach, \ref sleator83dynamic. -In most cases the \ref Preflow "Preflow" algorithm provides the +In most cases the \ref Preflow algorithm provides the fastest method for computing a maximum flow. All implementations also provide functions to query the minimum cut, which is the dual problem of maximum flow. -\ref Circulation is a preflow push-relabel algorithm implemented directly +\ref Circulation is a preflow push-relabel algorithm implemented directly for finding feasible circulations, which is a somewhat different problem, but it is strongly related to maximum flow. For more information, see \ref Circulation. @@ -341,18 +399,20 @@ \brief Algorithms for finding minimum cost flows and circulations. This group contains the algorithms for finding minimum cost flows and -circulations. For more information about this problem and its dual -solution see \ref min_cost_flow "Minimum Cost Flow Problem". +circulations \ref amo93networkflows. For more information about this +problem and its dual solution, see \ref min_cost_flow +"Minimum Cost Flow Problem". LEMON contains several algorithms for this problem. - \ref NetworkSimplex Primal Network Simplex algorithm with various - pivot strategies. - - \ref CostScaling Push-Relabel and Augment-Relabel algorithms based on - cost scaling. - - \ref CapacityScaling Successive Shortest %Path algorithm with optional - capacity scaling. - - \ref CancelAndTighten The Cancel and Tighten algorithm. - - \ref CycleCanceling Cycle-Canceling algorithms. + pivot strategies \ref dantzig63linearprog, \ref kellyoneill91netsimplex. + - \ref CostScaling Cost Scaling algorithm based on push/augment and + relabel operations \ref goldberg90approximation, \ref goldberg97efficient, + \ref bunnagel98efficient. + - \ref CapacityScaling Capacity Scaling algorithm based on the successive + shortest path method \ref edmondskarp72theoretical. + - \ref CycleCanceling Cycle-Canceling algorithms, two of which are + strongly polynomial \ref klein67primal, \ref goldberg89cyclecanceling. In general NetworkSimplex is the most efficient implementation, but in special cases other algorithms could be faster. @@ -375,7 +435,7 @@ cut is the \f$X\f$ solution of the next optimization problem: \f[ \min_{X \subset V, X\not\in \{\emptyset, V\}} - \sum_{uv\in A, u\in X, v\not\in X}cap(uv) \f] + \sum_{uv\in A: u\in X, v\not\in X}cap(uv) \f] LEMON contains several algorithms related to minimum cut problems: @@ -391,27 +451,40 @@ */ /** -@defgroup graph_properties Connectivity and Other Graph Properties +@defgroup min_mean_cycle Minimum Mean Cycle Algorithms @ingroup algs -\brief Algorithms for discovering the graph properties +\brief Algorithms for finding minimum mean cycles. -This group contains the algorithms for discovering the graph properties -like connectivity, bipartiteness, euler property, simplicity etc. +This group contains the algorithms for finding minimum mean cycles +\ref clrs01algorithms, \ref amo93networkflows. -\image html edge_biconnected_components.png -\image latex edge_biconnected_components.eps "bi-edge-connected components" width=\textwidth -*/ +The \e minimum \e mean \e cycle \e problem is to find a directed cycle +of minimum mean length (cost) in a digraph. +The mean length of a cycle is the average length of its arcs, i.e. the +ratio between the total length of the cycle and the number of arcs on it. -/** -@defgroup planar Planarity Embedding and Drawing -@ingroup algs -\brief Algorithms for planarity checking, embedding and drawing +This problem has an important connection to \e conservative \e length +\e functions, too. A length function on the arcs of a digraph is called +conservative if and only if there is no directed cycle of negative total +length. For an arbitrary length function, the negative of the minimum +cycle mean is the smallest \f$\epsilon\f$ value so that increasing the +arc lengths uniformly by \f$\epsilon\f$ results in a conservative length +function. -This group contains the algorithms for planarity checking, -embedding and drawing. +LEMON contains three algorithms for solving the minimum mean cycle problem: +- \ref Karp "Karp"'s original algorithm \ref amo93networkflows, + \ref dasdan98minmeancycle. +- \ref HartmannOrlin "Hartmann-Orlin"'s algorithm, which is an improved + version of Karp's algorithm \ref dasdan98minmeancycle. +- \ref Howard "Howard"'s policy iteration algorithm + \ref dasdan98minmeancycle. -\image html planar.png -\image latex planar.eps "Plane graph" width=\textwidth +In practice, the Howard algorithm proved to be by far the most efficient +one, though the best known theoretical bound on its running time is +exponential. +Both Karp and HartmannOrlin algorithms run in time O(ne) and use space +O(n2+e), but the latter one is typically faster due to the +applied early termination scheme. */ /** @@ -449,18 +522,49 @@ - \ref MaxWeightedPerfectMatching Edmond's blossom shrinking algorithm for calculating maximum weighted perfect matching in general graphs. +- \ref MaxFractionalMatching Push-relabel algorithm for calculating + maximum cardinality fractional matching in general graphs. +- \ref MaxWeightedFractionalMatching Augmenting path algorithm for calculating + maximum weighted fractional matching in general graphs. +- \ref MaxWeightedPerfectFractionalMatching + Augmenting path algorithm for calculating maximum weighted + perfect fractional matching in general graphs. -\image html bipartite_matching.png -\image latex bipartite_matching.eps "Bipartite Matching" width=\textwidth +\image html matching.png +\image latex matching.eps "Min Cost Perfect Matching" width=\textwidth */ /** -@defgroup spantree Minimum Spanning Tree Algorithms +@defgroup graph_properties Connectivity and Other Graph Properties @ingroup algs -\brief Algorithms for finding minimum cost spanning trees and arborescences. +\brief Algorithms for discovering the graph properties -This group contains the algorithms for finding minimum cost spanning -trees and arborescences. +This group contains the algorithms for discovering the graph properties +like connectivity, bipartiteness, euler property, simplicity etc. + +\image html connected_components.png +\image latex connected_components.eps "Connected components" width=\textwidth +*/ + +/** +@defgroup planar Planarity Embedding and Drawing +@ingroup algs +\brief Algorithms for planarity checking, embedding and drawing + +This group contains the algorithms for planarity checking, +embedding and drawing. + +\image html planar.png +\image latex planar.eps "Plane graph" width=\textwidth +*/ + +/** +@defgroup approx Approximation Algorithms +@ingroup algs +\brief Approximation algorithms. + +This group contains the approximation and heuristic algorithms +implemented in LEMON. */ /** @@ -473,15 +577,6 @@ */ /** -@defgroup approx Approximation Algorithms -@ingroup algs -\brief Approximation algorithms. - -This group contains the approximation and heuristic algorithms -implemented in LEMON. -*/ - -/** @defgroup gen_opt_group General Optimization Tools \brief This group contains some general optimization frameworks implemented in LEMON. @@ -491,13 +586,16 @@ */ /** -@defgroup lp_group Lp and Mip Solvers +@defgroup lp_group LP and MIP Solvers @ingroup gen_opt_group -\brief Lp and Mip solver interfaces for LEMON. +\brief LP and MIP solver interfaces for LEMON. -This group contains Lp and Mip solver interfaces for LEMON. The -various LP solvers could be used in the same manner with this -interface. +This group contains LP and MIP solver interfaces for LEMON. +Various LP solvers could be used in the same manner with this +high-level interface. + +The currently supported solvers are \ref glpk, \ref clp, \ref cbc, +\ref cplex, \ref soplex. */ /** @@ -587,7 +685,7 @@ */ /** -@defgroup dimacs_group DIMACS format +@defgroup dimacs_group DIMACS Format @ingroup io_group \brief Read and write files in DIMACS format @@ -636,8 +734,8 @@ @ingroup concept \brief Skeleton and concept checking classes for graph structures -This group contains the skeletons and concept checking classes of LEMON's -graph structures and helper classes used to implement these. +This group contains the skeletons and concept checking classes of +graph structures. */ /** @@ -649,6 +747,15 @@ */ /** +@defgroup tools Standalone Utility Applications + +Some utility applications are listed here. + +The standard compilation procedure (./configure;make) will compile +them, as well. +*/ + +/** \anchor demoprograms @defgroup demos Demo Programs @@ -660,13 +767,4 @@ make check commands. */ -/** -@defgroup tools Standalone Utility Applications - -Some utility applications are listed here. - -The standard compilation procedure (./configure;make) will compile -them, as well. -*/ - } diff --git a/doc/images/matching.eps b/doc/images/matching.eps new file mode 100644 --- /dev/null +++ b/doc/images/matching.eps @@ -0,0 +1,130 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Creator: LEMON, graphToEps() +%%CreationDate: Sun Mar 14 09:08:34 2010 +%%BoundingBox: -353 -264 559 292 +%%EndComments +/lb { setlinewidth setrgbcolor newpath moveto + 4 2 roll 1 index 1 index curveto stroke } bind def +/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def +/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def +/sq { newpath 2 index 1 index add 2 index 2 index add moveto + 2 index 1 index sub 2 index 2 index add lineto + 2 index 1 index sub 2 index 2 index sub lineto + 2 index 1 index add 2 index 2 index sub lineto + closepath pop pop pop} bind def +/di { newpath 2 index 1 index add 2 index moveto + 2 index 2 index 2 index add lineto + 2 index 1 index sub 2 index lineto + 2 index 2 index 2 index sub lineto + closepath pop pop pop} bind def +/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill + setrgbcolor 1.1 div c fill + } bind def +/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill + setrgbcolor 1.1 div sq fill + } bind def +/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill + setrgbcolor 1.1 div di fill + } bind def +/nfemale { 0 0 0 setrgbcolor 3 index 0.0909091 1.5 mul mul setlinewidth + newpath 5 index 5 index moveto 5 index 5 index 5 index 3.01 mul sub + lineto 5 index 4 index .7 mul sub 5 index 5 index 2.2 mul sub moveto + 5 index 4 index .7 mul add 5 index 5 index 2.2 mul sub lineto stroke + 5 index 5 index 5 index c fill + setrgbcolor 1.1 div c fill + } bind def +/nmale { + 0 0 0 setrgbcolor 3 index 0.0909091 1.5 mul mul setlinewidth + newpath 5 index 5 index moveto + 5 index 4 index 1 mul 1.5 mul add + 5 index 5 index 3 sqrt 1.5 mul mul add + 1 index 1 index lineto + 1 index 1 index 7 index sub moveto + 1 index 1 index lineto + exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub lineto + stroke + 5 index 5 index 5 index c fill + setrgbcolor 1.1 div c fill + } bind def +/arrl 1 def +/arrw 0.3 def +/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def +/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def + /w exch def /len exch def + newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto + len w sub arrl sub dx dy lrl + arrw dy dx neg lrl + dx arrl w add mul dy w 2 div arrw add mul sub + dy arrl w add mul dx w 2 div arrw add mul add rlineto + dx arrl w add mul neg dy w 2 div arrw add mul sub + dy arrl w add mul neg dx w 2 div arrw add mul add rlineto + arrw dy dx neg lrl + len w sub arrl sub neg dx dy lrl + closepath fill } bind def +/cshow { 2 index 2 index moveto dup stringwidth pop + neg 2 div fosi .35 mul neg rmoveto show pop pop} def + +gsave +%Arcs: +gsave +140.321 266.249 -327.729 150.06 0 0 0 4.99223 l +82.1207 -238.726 -245.288 -110.743 0 0 0 4.99223 l +336.635 -229.036 533.603 13.109 0 0 0 4.99223 l +53.8598 -45.8071 -245.288 -110.743 0 0 0 4.99223 l +-75.5617 118.579 -327.729 150.06 0 0 0 4.99223 l +-327.729 150.06 -245.288 -110.743 1 0 0 11.9813 l +533.603 13.109 218.184 -84.2955 0 0 0 4.99223 l +39.87 175.035 141.163 67.2575 0 0 0 4.99223 l +53.8598 -45.8071 -75.5617 118.579 0 0 0 4.99223 l +-102.406 -141.267 82.1207 -238.726 0 0 0 4.99223 l +399.144 166.894 533.603 13.109 1 0 0 11.9813 l +39.87 175.035 140.321 266.249 1 0 0 11.9813 l +399.144 166.894 140.321 266.249 0 0 0 4.99223 l +399.144 166.894 141.163 67.2575 0 0 0 4.99223 l +53.8598 -45.8071 204.765 -173.77 0 0 0 4.99223 l +82.1207 -238.726 204.765 -173.77 0 0 0 4.99223 l +258.227 61.658 399.144 166.894 0 0 0 4.99223 l +53.8598 -45.8071 -102.406 -141.267 1 0 0 11.9813 l +175.073 -37.4477 141.163 67.2575 0 0 0 4.99223 l +258.227 61.658 380 0 0 0 0 4.99223 l +34.6739 40.8267 -75.5617 118.579 1 0 0 11.9813 l +380 0 533.603 13.109 0 0 0 4.99223 l +175.073 -37.4477 380 0 0 0 0 4.99223 l +218.184 -84.2955 204.765 -173.77 0 0 0 4.99223 l +53.8598 -45.8071 34.6739 40.8267 0 0 0 4.99223 l +167.905 -213.988 82.1207 -238.726 1 0 0 11.9813 l +336.635 -229.036 204.765 -173.77 1 0 0 11.9813 l +336.635 -229.036 167.905 -213.988 0 0 0 4.99223 l +329.08 -26.3098 218.184 -84.2955 0 0 0 4.99223 l +39.87 175.035 -75.5617 118.579 0 0 0 4.99223 l +53.8598 -45.8071 175.073 -37.4477 0 0 0 4.99223 l +34.6739 40.8267 141.163 67.2575 0 0 0 4.99223 l +258.227 61.658 141.163 67.2575 1 0 0 11.9813 l +175.073 -37.4477 218.184 -84.2955 1 0 0 11.9813 l +380 0 329.08 -26.3098 1 0 0 11.9813 l +grestore +%Nodes: +gsave +-245.288 -110.743 14.9767 1 1 1 nc +204.765 -173.77 14.9767 1 1 1 nc +-327.729 150.06 14.9767 1 1 1 nc +-75.5617 118.579 14.9767 1 1 1 nc +218.184 -84.2955 14.9767 1 1 1 nc +140.321 266.249 14.9767 1 1 1 nc +141.163 67.2575 14.9767 1 1 1 nc +82.1207 -238.726 14.9767 1 1 1 nc +329.08 -26.3098 14.9767 1 1 1 nc +-102.406 -141.267 14.9767 1 1 1 nc +533.603 13.109 14.9767 1 1 1 nc +167.905 -213.988 14.9767 1 1 1 nc +336.635 -229.036 14.9767 1 1 1 nc +380 0 14.9767 1 1 1 nc +399.144 166.894 14.9767 1 1 1 nc +34.6739 40.8267 14.9767 1 1 1 nc +39.87 175.035 14.9767 1 1 1 nc +175.073 -37.4477 14.9767 1 1 1 nc +53.8598 -45.8071 14.9767 1 1 1 nc +258.227 61.658 14.9767 1 1 1 nc +grestore +grestore +showpage diff --git a/doc/images/planar.eps b/doc/images/planar.eps new file mode 100644 --- /dev/null +++ b/doc/images/planar.eps @@ -0,0 +1,181 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Creator: LEMON, graphToEps() +%%CreationDate: Fri Oct 19 18:32:32 2007 +%%BoundingBox: 0 0 596 842 +%%DocumentPaperSizes: a4 +%%EndComments +/lb { setlinewidth setrgbcolor newpath moveto + 4 2 roll 1 index 1 index curveto stroke } bind def +/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def +/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def +/sq { newpath 2 index 1 index add 2 index 2 index add moveto + 2 index 1 index sub 2 index 2 index add lineto + 2 index 1 index sub 2 index 2 index sub lineto + 2 index 1 index add 2 index 2 index sub lineto + closepath pop pop pop} bind def +/di { newpath 2 index 1 index add 2 index moveto + 2 index 2 index 2 index add lineto + 2 index 1 index sub 2 index lineto + 2 index 2 index 2 index sub lineto + closepath pop pop pop} bind def +/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill + setrgbcolor 1.1 div c fill + } bind def +/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill + setrgbcolor 1.1 div sq fill + } bind def +/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill + setrgbcolor 1.1 div di fill + } bind def +/nfemale { 0 0 0 setrgbcolor 3 index 0.0909091 1.5 mul mul setlinewidth + newpath 5 index 5 index moveto 5 index 5 index 5 index 3.01 mul sub + lineto 5 index 4 index .7 mul sub 5 index 5 index 2.2 mul sub moveto + 5 index 4 index .7 mul add 5 index 5 index 2.2 mul sub lineto stroke + 5 index 5 index 5 index c fill + setrgbcolor 1.1 div c fill + } bind def +/nmale { + 0 0 0 setrgbcolor 3 index 0.0909091 1.5 mul mul setlinewidth + newpath 5 index 5 index moveto + 5 index 4 index 1 mul 1.5 mul add + 5 index 5 index 3 sqrt 1.5 mul mul add + 1 index 1 index lineto + 1 index 1 index 7 index sub moveto + 1 index 1 index lineto + exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub lineto + stroke + 5 index 5 index 5 index c fill + setrgbcolor 1.1 div c fill + } bind def +/arrl 1 def +/arrw 0.3 def +/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def +/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def + /w exch def /len exch def + newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto + len w sub arrl sub dx dy lrl + arrw dy dx neg lrl + dx arrl w add mul dy w 2 div arrw add mul sub + dy arrl w add mul dx w 2 div arrw add mul add rlineto + dx arrl w add mul neg dy w 2 div arrw add mul sub + dy arrl w add mul neg dx w 2 div arrw add mul add rlineto + arrw dy dx neg lrl + len w sub arrl sub neg dx dy lrl + closepath fill } bind def +/cshow { 2 index 2 index moveto dup stringwidth pop + neg 2 div fosi .35 mul neg rmoveto show pop pop} def + +gsave +15 138.307 translate +12.7843 dup scale +90 rotate +0.608112 -43.6081 translate +%Edges: +gsave +9 31 9.5 30.5 10 30 0 0 0 0.091217 lb +9 31 5.5 34.5 2 38 0 0 0 0.091217 lb +9 31 25.5 16 42 1 0 0 0 0.091217 lb +3 40 23 20.5 43 1 0 0 0 0.091217 lb +3 40 22.5 20.5 42 1 0 0 0 0.091217 lb +3 40 2.5 40.5 2 41 0 0 0 0.091217 lb +13 25 10.5 24.5 8 24 0 0 0 0.091217 lb +13 25 12 27 11 29 0 0 0 0.091217 lb +3 4 2.5 3 2 2 0 0 0 0.091217 lb +3 4 4.5 3 6 2 0 0 0 0.091217 lb +6 25 7 24.5 8 24 0 0 0 0.091217 lb +6 25 6 24.5 6 24 0 0 0 0.091217 lb +34 2 33.5 2 33 2 0 0 0 0.091217 lb +34 2 35 2 36 2 0 0 0 0.091217 lb +6 8 16 9 26 10 0 0 0 0.091217 lb +6 8 6 10.5 6 13 0 0 0 0.091217 lb +6 8 6 7.5 6 7 0 0 0 0.091217 lb +26 10 27.5 8.5 29 7 0 0 0 0.091217 lb +26 10 27.5 9 29 8 0 0 0 0.091217 lb +10 30 10.5 29.5 11 29 0 0 0 0.091217 lb +8 24 7 23.5 6 23 0 0 0 0.091217 lb +8 24 8 24.5 8 25 0 0 0 0.091217 lb +33 2 32.5 2 32 2 0 0 0 0.091217 lb +29 7 17.5 7 6 7 0 0 0 0.091217 lb +2 2 1.5 22 1 42 0 0 0 0.091217 lb +2 2 3.5 2 5 2 0 0 0 0.091217 lb +21 15 13.5 14.5 6 14 0 0 0 0.091217 lb +21 15 21 15.5 21 16 0 0 0 0.091217 lb +1 42 0.5 42.5 0 43 0 0 0 0.091217 lb +1 42 1.5 41.5 2 41 0 0 0 0.091217 lb +6 15 6 15.5 6 16 0 0 0 0.091217 lb +6 15 6 14.5 6 14 0 0 0 0.091217 lb +43 1 22 0.5 1 0 0 0 0 0.091217 lb +31 2 18.5 2 6 2 0 0 0 0.091217 lb +31 2 31.5 2 32 2 0 0 0 0.091217 lb +6 24 6 23.5 6 23 0 0 0 0.091217 lb +6 16 6 16.5 6 17 0 0 0 0.091217 lb +6 23 6 20 6 17 0 0 0 0.091217 lb +6 2 5.5 2 5 2 0 0 0 0.091217 lb +6 2 6 4.5 6 7 0 0 0 0.091217 lb +0 43 0.5 21.5 1 0 0 0 0 0.091217 lb +1 1 19.5 1.5 38 2 0 0 0 0.091217 lb +1 1 1 0.5 1 0 0 0 0 0.091217 lb +2 38 5.5 31.5 9 25 0 0 0 0.091217 lb +25 13 15.5 13 6 13 0 0 0 0.091217 lb +25 13 15.5 13.5 6 14 0 0 0 0.091217 lb +8 25 8.5 25 9 25 0 0 0 0.091217 lb +11 29 24.5 15.5 38 2 0 0 0 0.091217 lb +6 17 11.5 18 17 19 0 0 0 0.091217 lb +16 23 26.5 12.5 37 2 0 0 0 0.091217 lb +16 23 18.5 19.5 21 16 0 0 0 0.091217 lb +36 2 36.5 2 37 2 0 0 0 0.091217 lb +36 2 32.5 5 29 8 0 0 0 0.091217 lb +6 13 6 13.5 6 14 0 0 0 0.091217 lb +37 2 37.5 2 38 2 0 0 0 0.091217 lb +21 16 19 17.5 17 19 0 0 0 0.091217 lb +grestore +%Nodes: +gsave +29 8 0.304556 1 1 1 nc +2 41 0.304556 1 1 1 nc +6 7 0.304556 1 1 1 nc +5 2 0.304556 1 1 1 nc +17 19 0.304556 1 1 1 nc +21 16 0.304556 1 1 1 nc +1 0 0.304556 1 1 1 nc +9 25 0.304556 1 1 1 nc +6 14 0.304556 1 1 1 nc +42 1 0.304556 1 1 1 nc +38 2 0.304556 1 1 1 nc +37 2 0.304556 1 1 1 nc +6 13 0.304556 1 1 1 nc +36 2 0.304556 1 1 1 nc +16 23 0.304556 1 1 1 nc +6 17 0.304556 1 1 1 nc +11 29 0.304556 1 1 1 nc +8 25 0.304556 1 1 1 nc +32 2 0.304556 1 1 1 nc +25 13 0.304556 1 1 1 nc +2 38 0.304556 1 1 1 nc +1 1 0.304556 1 1 1 nc +0 43 0.304556 1 1 1 nc +6 2 0.304556 1 1 1 nc +6 23 0.304556 1 1 1 nc +6 16 0.304556 1 1 1 nc +6 24 0.304556 1 1 1 nc +31 2 0.304556 1 1 1 nc +43 1 0.304556 1 1 1 nc +6 15 0.304556 1 1 1 nc +1 42 0.304556 1 1 1 nc +21 15 0.304556 1 1 1 nc +2 2 0.304556 1 1 1 nc +29 7 0.304556 1 1 1 nc +33 2 0.304556 1 1 1 nc +8 24 0.304556 1 1 1 nc +10 30 0.304556 1 1 1 nc +26 10 0.304556 1 1 1 nc +6 8 0.304556 1 1 1 nc +34 2 0.304556 1 1 1 nc +6 25 0.304556 1 1 1 nc +3 4 0.304556 1 1 1 nc +13 25 0.304556 1 1 1 nc +3 40 0.304556 1 1 1 nc +9 31 0.304556 1 1 1 nc +grestore +grestore +showpage diff --git a/doc/mainpage.dox.in b/doc/mainpage.dox.in --- a/doc/mainpage.dox.in +++ b/doc/mainpage.dox.in @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -21,14 +21,11 @@ \section intro Introduction -\subsection whatis What is LEMON - -LEMON stands for Library for Efficient Modeling -and Optimization in Networks. -It is a C++ template -library aimed at combinatorial optimization tasks which -often involve in working -with graphs. +LEMON stands for Library for Efficient Modeling +and Optimization in Networks. +It is a C++ template library providing efficient implementations of common +data structures and algorithms with focus on combinatorial optimization +tasks connected mainly with graphs and networks. LEMON is an open source @@ -38,11 +35,24 @@ \ref license "license terms". -\subsection howtoread How to read the documentation +The project is maintained by the +Egerváry Research Group on +Combinatorial Optimization \ref egres +at the Operations Research Department of the +Eötvös Loránd University, +Budapest, Hungary. +LEMON is also a member of the COIN-OR +initiative \ref coinor. + +\section howtoread How to Read the Documentation If you would like to get to know the library, see LEMON Tutorial. +If you are interested in starting to use the library, see the Installation +Guide. + If you know what you are looking for, then try to find it under the Modules section. diff --git a/doc/min_cost_flow.dox b/doc/min_cost_flow.dox --- a/doc/min_cost_flow.dox +++ b/doc/min_cost_flow.dox @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -26,7 +26,7 @@ The \e minimum \e cost \e flow \e problem is to find a feasible flow of minimum total cost from a set of supply nodes to a set of demand nodes in a network with capacity constraints (lower and upper bounds) -and arc costs. +and arc costs \ref amo93networkflows. Formally, let \f$G=(V,A)\f$ be a digraph, \f$lower: A\rightarrow\mathbf{R}\f$, \f$upper: A\rightarrow\mathbf{R}\cup\{+\infty\}\f$ denote the lower and @@ -78,10 +78,10 @@ - if \f$lower(uv)=0\f$; + - \f$\pi(u)\geq 0\f$; - if \f$\sum_{uv\in A} f(uv) - \sum_{vu\in A} f(vu) \neq sup(u)\f$, then \f$\pi(u)=0\f$. diff --git a/doc/references.bib b/doc/references.bib new file mode 100644 --- /dev/null +++ b/doc/references.bib @@ -0,0 +1,301 @@ +%%%%% Defining LEMON %%%%% + +@misc{lemon, + key = {LEMON}, + title = {{LEMON} -- {L}ibrary for {E}fficient {M}odeling and + {O}ptimization in {N}etworks}, + howpublished = {\url{http://lemon.cs.elte.hu/}}, + year = 2009 +} + +@misc{egres, + key = {EGRES}, + title = {{EGRES} -- {E}gerv{\'a}ry {R}esearch {G}roup on + {C}ombinatorial {O}ptimization}, + url = {http://www.cs.elte.hu/egres/} +} + +@misc{coinor, + key = {COIN-OR}, + title = {{COIN-OR} -- {C}omputational {I}nfrastructure for + {O}perations {R}esearch}, + url = {http://www.coin-or.org/} +} + + +%%%%% Other libraries %%%%%% + +@misc{boost, + key = {Boost}, + title = {{B}oost {C++} {L}ibraries}, + url = {http://www.boost.org/} +} + +@book{bglbook, + author = {Jeremy G. Siek and Lee-Quan Lee and Andrew + Lumsdaine}, + title = {The Boost Graph Library: User Guide and Reference + Manual}, + publisher = {Addison-Wesley}, + year = 2002 +} + +@misc{leda, + key = {LEDA}, + title = {{LEDA} -- {L}ibrary of {E}fficient {D}ata {T}ypes and + {A}lgorithms}, + url = {http://www.algorithmic-solutions.com/} +} + +@book{ledabook, + author = {Kurt Mehlhorn and Stefan N{\"a}her}, + title = {{LEDA}: {A} platform for combinatorial and geometric + computing}, + isbn = {0-521-56329-1}, + publisher = {Cambridge University Press}, + address = {New York, NY, USA}, + year = 1999 +} + + +%%%%% Tools that LEMON depends on %%%%% + +@misc{cmake, + key = {CMake}, + title = {{CMake} -- {C}ross {P}latform {M}ake}, + url = {http://www.cmake.org/} +} + +@misc{doxygen, + key = {Doxygen}, + title = {{Doxygen} -- {S}ource code documentation generator + tool}, + url = {http://www.doxygen.org/} +} + + +%%%%% LP/MIP libraries %%%%% + +@misc{glpk, + key = {GLPK}, + title = {{GLPK} -- {GNU} {L}inear {P}rogramming {K}it}, + url = {http://www.gnu.org/software/glpk/} +} + +@misc{clp, + key = {Clp}, + title = {{Clp} -- {Coin-Or} {L}inear {P}rogramming}, + url = {http://projects.coin-or.org/Clp/} +} + +@misc{cbc, + key = {Cbc}, + title = {{Cbc} -- {Coin-Or} {B}ranch and {C}ut}, + url = {http://projects.coin-or.org/Cbc/} +} + +@misc{cplex, + key = {CPLEX}, + title = {{ILOG} {CPLEX}}, + url = {http://www.ilog.com/} +} + +@misc{soplex, + key = {SoPlex}, + title = {{SoPlex} -- {T}he {S}equential {O}bject-{O}riented + {S}implex}, + url = {http://soplex.zib.de/} +} + + +%%%%% General books %%%%% + +@book{amo93networkflows, + author = {Ravindra K. Ahuja and Thomas L. Magnanti and James + B. Orlin}, + title = {Network Flows: Theory, Algorithms, and Applications}, + publisher = {Prentice-Hall, Inc.}, + year = 1993, + month = feb, + isbn = {978-0136175490} +} + +@book{schrijver03combinatorial, + author = {Alexander Schrijver}, + title = {Combinatorial Optimization: Polyhedra and Efficiency}, + publisher = {Springer-Verlag}, + year = 2003, + isbn = {978-3540443896} +} + +@book{clrs01algorithms, + author = {Thomas H. Cormen and Charles E. Leiserson and Ronald + L. Rivest and Clifford Stein}, + title = {Introduction to Algorithms}, + publisher = {The MIT Press}, + year = 2001, + edition = {2nd} +} + +@book{stroustrup00cpp, + author = {Bjarne Stroustrup}, + title = {The C++ Programming Language}, + edition = {3rd}, + publisher = {Addison-Wesley Professional}, + isbn = 0201700735, + month = {February}, + year = 2000 +} + + +%%%%% Maximum flow algorithms %%%%% + +@article{edmondskarp72theoretical, + author = {Jack Edmonds and Richard M. Karp}, + title = {Theoretical improvements in algorithmic efficiency + for network flow problems}, + journal = {Journal of the ACM}, + year = 1972, + volume = 19, + number = 2, + pages = {248-264} +} + +@article{goldberg88newapproach, + author = {Andrew V. Goldberg and Robert E. Tarjan}, + title = {A new approach to the maximum flow problem}, + journal = {Journal of the ACM}, + year = 1988, + volume = 35, + number = 4, + pages = {921-940} +} + +@article{dinic70algorithm, + author = {E. A. Dinic}, + title = {Algorithm for solution of a problem of maximum flow + in a network with power estimation}, + journal = {Soviet Math. Doklady}, + year = 1970, + volume = 11, + pages = {1277-1280} +} + +@article{goldberg08partial, + author = {Andrew V. Goldberg}, + title = {The Partial Augment-Relabel Algorithm for the + Maximum Flow Problem}, + journal = {16th Annual European Symposium on Algorithms}, + year = 2008, + pages = {466-477} +} + +@article{sleator83dynamic, + author = {Daniel D. Sleator and Robert E. Tarjan}, + title = {A data structure for dynamic trees}, + journal = {Journal of Computer and System Sciences}, + year = 1983, + volume = 26, + number = 3, + pages = {362-391} +} + + +%%%%% Minimum mean cycle algorithms %%%%% + +@article{karp78characterization, + author = {Richard M. Karp}, + title = {A characterization of the minimum cycle mean in a + digraph}, + journal = {Discrete Math.}, + year = 1978, + volume = 23, + pages = {309-311} +} + +@article{dasdan98minmeancycle, + author = {Ali Dasdan and Rajesh K. Gupta}, + title = {Faster Maximum and Minimum Mean Cycle Alogrithms for + System Performance Analysis}, + journal = {IEEE Transactions on Computer-Aided Design of + Integrated Circuits and Systems}, + year = 1998, + volume = 17, + number = 10, + pages = {889-899} +} + + +%%%%% Minimum cost flow algorithms %%%%% + +@article{klein67primal, + author = {Morton Klein}, + title = {A primal method for minimal cost flows with + applications to the assignment and transportation + problems}, + journal = {Management Science}, + year = 1967, + volume = 14, + pages = {205-220} +} + +@article{goldberg89cyclecanceling, + author = {Andrew V. Goldberg and Robert E. Tarjan}, + title = {Finding minimum-cost circulations by canceling + negative cycles}, + journal = {Journal of the ACM}, + year = 1989, + volume = 36, + number = 4, + pages = {873-886} +} + +@article{goldberg90approximation, + author = {Andrew V. Goldberg and Robert E. Tarjan}, + title = {Finding Minimum-Cost Circulations by Successive + Approximation}, + journal = {Mathematics of Operations Research}, + year = 1990, + volume = 15, + number = 3, + pages = {430-466} +} + +@article{goldberg97efficient, + author = {Andrew V. Goldberg}, + title = {An Efficient Implementation of a Scaling + Minimum-Cost Flow Algorithm}, + journal = {Journal of Algorithms}, + year = 1997, + volume = 22, + number = 1, + pages = {1-29} +} + +@article{bunnagel98efficient, + author = {Ursula B{\"u}nnagel and Bernhard Korte and Jens + Vygen}, + title = {Efficient implementation of the {G}oldberg-{T}arjan + minimum-cost flow algorithm}, + journal = {Optimization Methods and Software}, + year = 1998, + volume = 10, + pages = {157-174} +} + +@book{dantzig63linearprog, + author = {George B. Dantzig}, + title = {Linear Programming and Extensions}, + publisher = {Princeton University Press}, + year = 1963 +} + +@mastersthesis{kellyoneill91netsimplex, + author = {Damian J. Kelly and Garrett M. O'Neill}, + title = {The Minimum Cost Flow Problem and The Network + Simplex Method}, + school = {University College}, + address = {Dublin, Ireland}, + year = 1991, + month = sep, +} diff --git a/lemon/Makefile.am b/lemon/Makefile.am --- a/lemon/Makefile.am +++ b/lemon/Makefile.am @@ -58,19 +58,25 @@ lemon/adaptors.h \ lemon/arg_parser.h \ lemon/assert.h \ + lemon/bellman_ford.h \ lemon/bfs.h \ lemon/bin_heap.h \ + lemon/binomial_heap.h \ lemon/bucket_heap.h \ + lemon/capacity_scaling.h \ lemon/cbc.h \ lemon/circulation.h \ lemon/clp.h \ lemon/color.h \ lemon/concept_check.h \ lemon/connectivity.h \ + lemon/core.h \ + lemon/cost_scaling.h \ lemon/counter.h \ - lemon/core.h \ lemon/cplex.h \ + lemon/cycle_canceling.h \ lemon/dfs.h \ + lemon/dheap.h \ lemon/dijkstra.h \ lemon/dim2.h \ lemon/dimacs.h \ @@ -79,12 +85,16 @@ lemon/error.h \ lemon/euler.h \ lemon/fib_heap.h \ + lemon/fractional_matching.h \ lemon/full_graph.h \ lemon/glpk.h \ lemon/gomory_hu.h \ lemon/graph_to_eps.h \ lemon/grid_graph.h \ + lemon/hartmann_orlin_mmc.h \ + lemon/howard_mmc.h \ lemon/hypercube_graph.h \ + lemon/karp_mmc.h \ lemon/kruskal.h \ lemon/hao_orlin.h \ lemon/lgf_reader.h \ @@ -99,13 +109,17 @@ lemon/min_cost_arborescence.h \ lemon/nauty_reader.h \ lemon/network_simplex.h \ + lemon/pairing_heap.h \ lemon/path.h \ + lemon/planarity.h \ lemon/preflow.h \ + lemon/quad_heap.h \ lemon/radix_heap.h \ lemon/radix_sort.h \ lemon/random.h \ lemon/smart_graph.h \ lemon/soplex.h \ + lemon/static_graph.h \ lemon/suurballe.h \ lemon/time_measure.h \ lemon/tolerance.h \ diff --git a/lemon/adaptors.h b/lemon/adaptors.h --- a/lemon/adaptors.h +++ b/lemon/adaptors.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -360,6 +360,9 @@ /// by adding or removing nodes or arcs, unless the \c GR template /// parameter is set to be \c const. /// + /// This class provides item counting in the same time as the adapted + /// digraph structure. + /// /// \tparam DGR The type of the adapted digraph. /// It must conform to the \ref concepts::Digraph "Digraph" concept. /// It can also be specified to be \c const. @@ -418,7 +421,7 @@ void initialize(DGR& digraph, NF& node_filter, AF& arc_filter) { Parent::initialize(digraph); _node_filter = &node_filter; - _arc_filter = &arc_filter; + _arc_filter = &arc_filter; } public: @@ -505,11 +508,11 @@ public: template - class NodeMap - : public SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> { + class NodeMap + : public SubMapExtender, + LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> { typedef SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> Parent; + LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> Parent; public: typedef V Value; @@ -532,9 +535,9 @@ }; template - class ArcMap + class ArcMap : public SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> { + LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> { typedef SubMapExtender, LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> Parent; @@ -579,7 +582,7 @@ void initialize(DGR& digraph, NF& node_filter, AF& arc_filter) { Parent::initialize(digraph); _node_filter = &node_filter; - _arc_filter = &arc_filter; + _arc_filter = &arc_filter; } public: @@ -648,10 +651,10 @@ } template - class NodeMap + class NodeMap : public SubMapExtender, LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> { - typedef SubMapExtender, + typedef SubMapExtender, LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> Parent; public: @@ -675,7 +678,7 @@ }; template - class ArcMap + class ArcMap : public SubMapExtender, LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> { typedef SubMapExtender, @@ -719,6 +722,8 @@ /// by adding or removing nodes or arcs, unless the \c GR template /// parameter is set to be \c const. /// + /// This class provides only linear time counting for nodes and arcs. + /// /// \tparam DGR The type of the adapted digraph. /// It must conform to the \ref concepts::Digraph "Digraph" concept. /// It can also be specified to be \c const. @@ -1016,10 +1021,10 @@ } template - class NodeMap + class NodeMap : public SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> { - typedef SubMapExtender, + typedef SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> Parent; public: @@ -1043,10 +1048,10 @@ }; template - class ArcMap + class ArcMap : public SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> { - typedef SubMapExtender, + typedef SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> Parent; public: @@ -1070,10 +1075,10 @@ }; template - class EdgeMap + class EdgeMap : public SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> { - typedef SubMapExtender, + typedef SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> Parent; public: @@ -1112,8 +1117,8 @@ protected: NF* _node_filter; EF* _edge_filter; - SubGraphBase() - : Parent(), _node_filter(0), _edge_filter(0) { } + SubGraphBase() + : Parent(), _node_filter(0), _edge_filter(0) { } void initialize(GR& graph, NF& node_filter, EF& edge_filter) { Parent::initialize(graph); @@ -1214,10 +1219,10 @@ } template - class NodeMap + class NodeMap : public SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> { - typedef SubMapExtender, + typedef SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> Parent; public: @@ -1241,10 +1246,10 @@ }; template - class ArcMap + class ArcMap : public SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> { - typedef SubMapExtender, + typedef SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> Parent; public: @@ -1268,11 +1273,11 @@ }; template - class EdgeMap + class EdgeMap : public SubMapExtender, LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> Parent; + typedef SubMapExtender, + LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> Parent; public: typedef V Value; @@ -1314,6 +1319,8 @@ /// by adding or removing nodes or edges, unless the \c GR template /// parameter is set to be \c const. /// + /// This class provides only linear time counting for nodes, edges and arcs. + /// /// \tparam GR The type of the adapted graph. /// It must conform to the \ref concepts::Graph "Graph" concept. /// It can also be specified to be \c const. @@ -1471,6 +1478,8 @@ /// by adding or removing nodes or arcs/edges, unless the \c GR template /// parameter is set to be \c const. /// + /// This class provides only linear time item counting. + /// /// \tparam GR The type of the adapted digraph or graph. /// It must conform to the \ref concepts::Digraph "Digraph" concept /// or the \ref concepts::Graph "Graph" concept. @@ -1495,7 +1504,7 @@ true> > { #endif typedef DigraphAdaptorExtender< - SubDigraphBase >, + SubDigraphBase >, true> > Parent; public: @@ -1516,7 +1525,7 @@ /// /// Creates a subgraph for the given digraph or graph with the /// given node filter map. - FilterNodes(GR& graph, NF& node_filter) + FilterNodes(GR& graph, NF& node_filter) : Parent(), const_true_map() { Parent::initialize(graph, node_filter, const_true_map); @@ -1554,11 +1563,11 @@ class FilterNodes >::type> : public GraphAdaptorExtender< - SubGraphBase >, + SubGraphBase >, true> > { typedef GraphAdaptorExtender< - SubGraphBase >, + SubGraphBase >, true> > Parent; public: @@ -1619,6 +1628,8 @@ /// by adding or removing nodes or arcs, unless the \c GR template /// parameter is set to be \c const. /// + /// This class provides only linear time counting for nodes and arcs. + /// /// \tparam DGR The type of the adapted digraph. /// It must conform to the \ref concepts::Digraph "Digraph" concept. /// It can also be specified to be \c const. @@ -1642,7 +1653,7 @@ AF, false> > { #endif typedef DigraphAdaptorExtender< - SubDigraphBase >, + SubDigraphBase >, AF, false> > Parent; public: @@ -1729,6 +1740,8 @@ /// by adding or removing nodes or edges, unless the \c GR template /// parameter is set to be \c const. /// + /// This class provides only linear time counting for nodes, edges and arcs. + /// /// \tparam GR The type of the adapted graph. /// It must conform to the \ref concepts::Graph "Graph" concept. /// It can also be specified to be \c const. @@ -1748,11 +1761,11 @@ typename EF = typename GR::template EdgeMap > class FilterEdges : public GraphAdaptorExtender< - SubGraphBase >, + SubGraphBase >, EF, false> > { #endif typedef GraphAdaptorExtender< - SubGraphBase >, + SubGraphBase >, EF, false> > Parent; public: @@ -1777,7 +1790,7 @@ /// /// Creates a subgraph for the given graph with the given edge /// filter map. - FilterEdges(GR& graph, EF& edge_filter) + FilterEdges(GR& graph, EF& edge_filter) : Parent(), const_true_map() { Parent::initialize(graph, const_true_map, edge_filter); } @@ -1845,7 +1858,7 @@ Edge _edge; bool _forward; - Arc(const Edge& edge, bool forward) + Arc(const Edge& edge, bool forward) : _edge(edge), _forward(forward) {} public: @@ -2085,7 +2098,7 @@ _forward(*adaptor._digraph), _backward(*adaptor._digraph) {} ArcMapBase(const UndirectorBase& adaptor, const V& value) - : _forward(*adaptor._digraph, value), + : _forward(*adaptor._digraph, value), _backward(*adaptor._digraph, value) {} void set(const Arc& a, const V& value) { @@ -2203,7 +2216,7 @@ typedef typename ItemSetTraits::ItemNotifier EdgeNotifier; EdgeNotifier& notifier(Edge) const { return _digraph->notifier(Edge()); } - + typedef EdgeNotifier ArcNotifier; ArcNotifier& notifier(Arc) const { return _digraph->notifier(Edge()); } @@ -2232,6 +2245,9 @@ /// by adding or removing nodes or edges, unless the \c GR template /// parameter is set to be \c const. /// + /// This class provides item counting in the same time as the adapted + /// digraph structure. + /// /// \tparam DGR The type of the adapted digraph. /// It must conform to the \ref concepts::Digraph "Digraph" concept. /// It can also be specified to be \c const. @@ -2535,6 +2551,9 @@ /// by adding or removing nodes or arcs, unless the \c GR template /// parameter is set to be \c const. /// + /// This class provides item counting in the same time as the adapted + /// graph structure. + /// /// \tparam GR The type of the adapted graph. /// It must conform to the \ref concepts::Graph "Graph" concept. /// It can also be specified to be \c const. @@ -2678,6 +2697,8 @@ /// arcs). /// This class conforms to the \ref concepts::Digraph "Digraph" concept. /// + /// This class provides only linear time counting for nodes and arcs. + /// /// \tparam DGR The type of the adapted digraph. /// It must conform to the \ref concepts::Digraph "Digraph" concept. /// It is implicitly \c const. @@ -2707,7 +2728,7 @@ typename CM = typename DGR::template ArcMap, typename FM = CM, typename TL = Tolerance > - class ResidualDigraph + class ResidualDigraph : public SubDigraph< Undirector, ConstMap >, @@ -2764,7 +2785,7 @@ /// digraph, the capacity map, the flow map, and a tolerance object. ResidualDigraph(const DGR& digraph, const CM& capacity, FM& flow, const TL& tolerance = Tolerance()) - : Parent(), _capacity(&capacity), _flow(&flow), + : Parent(), _capacity(&capacity), _flow(&flow), _graph(digraph), _node_filter(), _forward_filter(capacity, flow, tolerance), _backward_filter(capacity, flow, tolerance), @@ -2846,7 +2867,7 @@ typedef typename CapacityMap::Value Value; /// Constructor - ResidualCapacity(const ResidualDigraph& adaptor) + ResidualCapacity(const ResidualDigraph& adaptor) : _adaptor(&adaptor) {} /// Returns the value associated with the given residual arc @@ -3325,6 +3346,9 @@ /// costs/capacities of the original digraph to the \e bind \e arcs /// in the adaptor. /// + /// This class provides item counting in the same time as the adapted + /// digraph structure. + /// /// \tparam DGR The type of the adapted digraph. /// It must conform to the \ref concepts::Digraph "Digraph" concept. /// It is implicitly \c const. @@ -3423,7 +3447,7 @@ /// This map adaptor class adapts two node maps of the original digraph /// to get a node map of the split digraph. /// Its value type is inherited from the first node map type (\c IN). - /// \tparam IN The type of the node map for the in-nodes. + /// \tparam IN The type of the node map for the in-nodes. /// \tparam OUT The type of the node map for the out-nodes. template class CombinedNodeMap { diff --git a/lemon/arg_parser.cc b/lemon/arg_parser.cc --- a/lemon/arg_parser.cc +++ b/lemon/arg_parser.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -20,14 +20,23 @@ namespace lemon { + void ArgParser::_terminate(ArgParserException::Reason reason) const + { + if(_exit_on_problems) + exit(1); + else throw(ArgParserException(reason)); + } + + void ArgParser::_showHelp(void *p) { (static_cast(p))->showHelp(); - exit(1); + (static_cast(p))->_terminate(ArgParserException::HELP); } ArgParser::ArgParser(int argc, const char * const *argv) - :_argc(argc), _argv(argv), _command_name(argv[0]) { + :_argc(argc), _argv(argv), _command_name(argv[0]), + _exit_on_problems(true) { funcOption("-help","Print a short help message",_showHelp,this); synonym("help","-help"); synonym("h","-help"); @@ -342,7 +351,7 @@ for(std::vector::const_iterator i=_others_help.begin(); i!=_others_help.end();++i) showHelp(i); for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i); - exit(1); + _terminate(ArgParserException::HELP); } @@ -351,7 +360,7 @@ std::cerr << "\nUnknown option: " << arg << "\n"; std::cerr << "\nType '" << _command_name << " --help' to obtain a short summary on the usage.\n\n"; - exit(1); + _terminate(ArgParserException::UNKNOWN_OPT); } void ArgParser::requiresValue(std::string arg, OptType t) const @@ -414,7 +423,7 @@ if(!ok) { std::cerr << "\nType '" << _command_name << " --help' to obtain a short summary on the usage.\n\n"; - exit(1); + _terminate(ArgParserException::INVALID_OPT); } } diff --git a/lemon/arg_parser.h b/lemon/arg_parser.h --- a/lemon/arg_parser.h +++ b/lemon/arg_parser.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -34,6 +34,44 @@ namespace lemon { + ///Exception used by ArgParser + class ArgParserException : public Exception { + public: + enum Reason { + HELP, /// --help option was given + UNKNOWN_OPT, /// Unknown option was given + INVALID_OPT /// Invalid combination of options + }; + + private: + Reason _reason; + + public: + ///Constructor + ArgParserException(Reason r) throw() : _reason(r) {} + ///Virtual destructor + virtual ~ArgParserException() throw() {} + ///A short description of the exception + virtual const char* what() const throw() { + switch(_reason) + { + case HELP: + return "lemon::ArgParseException: ask for help"; + break; + case UNKNOWN_OPT: + return "lemon::ArgParseException: unknown option"; + break; + case INVALID_OPT: + return "lemon::ArgParseException: invalid combination of options"; + break; + } + return ""; + } + ///Return the reason for the failure + Reason reason() const {return _reason; } + }; + + ///Command line arguments parser ///\ingroup misc @@ -116,6 +154,10 @@ const std::string &help, void (*func)(void *),void *data); + bool _exit_on_problems; + + void _terminate(ArgParserException::Reason reason) const; + public: ///Constructor @@ -380,6 +422,11 @@ ///not starting with a '-' character. const std::vector &files() const { return _file_args; } + ///Throw instead of exit in case of problems + void throwOnProblems() + { + _exit_on_problems=false; + } }; } diff --git a/lemon/bellman_ford.h b/lemon/bellman_ford.h new file mode 100644 --- /dev/null +++ b/lemon/bellman_ford.h @@ -0,0 +1,1165 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_BELLMAN_FORD_H +#define LEMON_BELLMAN_FORD_H + +/// \ingroup shortest_path +/// \file +/// \brief Bellman-Ford algorithm. + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace lemon { + + /// \brief Default operation traits for the BellmanFord algorithm class. + /// + /// This operation traits class defines all computational operations + /// and constants that are used in the Bellman-Ford algorithm. + /// The default implementation is based on the \c numeric_limits class. + /// If the numeric type does not have infinity value, then the maximum + /// value is used as extremal infinity value. + /// + /// \see BellmanFordToleranceOperationTraits + template < + typename V, + bool has_inf = std::numeric_limits::has_infinity> + struct BellmanFordDefaultOperationTraits { + /// \brief Value type for the algorithm. + typedef V Value; + /// \brief Gives back the zero value of the type. + static Value zero() { + return static_cast(0); + } + /// \brief Gives back the positive infinity value of the type. + static Value infinity() { + return std::numeric_limits::infinity(); + } + /// \brief Gives back the sum of the given two elements. + static Value plus(const Value& left, const Value& right) { + return left + right; + } + /// \brief Gives back \c true only if the first value is less than + /// the second. + static bool less(const Value& left, const Value& right) { + return left < right; + } + }; + + template + struct BellmanFordDefaultOperationTraits { + typedef V Value; + static Value zero() { + return static_cast(0); + } + static Value infinity() { + return std::numeric_limits::max(); + } + static Value plus(const Value& left, const Value& right) { + if (left == infinity() || right == infinity()) return infinity(); + return left + right; + } + static bool less(const Value& left, const Value& right) { + return left < right; + } + }; + + /// \brief Operation traits for the BellmanFord algorithm class + /// using tolerance. + /// + /// This operation traits class defines all computational operations + /// and constants that are used in the Bellman-Ford algorithm. + /// The only difference between this implementation and + /// \ref BellmanFordDefaultOperationTraits is that this class uses + /// the \ref Tolerance "tolerance technique" in its \ref less() + /// function. + /// + /// \tparam V The value type. + /// \tparam eps The epsilon value for the \ref less() function. + /// By default, it is the epsilon value used by \ref Tolerance + /// "Tolerance". + /// + /// \see BellmanFordDefaultOperationTraits +#ifdef DOXYGEN + template +#else + template < + typename V, + V eps = Tolerance::def_epsilon> +#endif + struct BellmanFordToleranceOperationTraits { + /// \brief Value type for the algorithm. + typedef V Value; + /// \brief Gives back the zero value of the type. + static Value zero() { + return static_cast(0); + } + /// \brief Gives back the positive infinity value of the type. + static Value infinity() { + return std::numeric_limits::infinity(); + } + /// \brief Gives back the sum of the given two elements. + static Value plus(const Value& left, const Value& right) { + return left + right; + } + /// \brief Gives back \c true only if the first value is less than + /// the second. + static bool less(const Value& left, const Value& right) { + return left + eps < right; + } + }; + + /// \brief Default traits class of BellmanFord class. + /// + /// Default traits class of BellmanFord class. + /// \param GR The type of the digraph. + /// \param LEN The type of the length map. + template + struct BellmanFordDefaultTraits { + /// The type of the digraph the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that stores the arc lengths. + /// + /// The type of the map that stores the arc lengths. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. + typedef LEN LengthMap; + + /// The type of the arc lengths. + typedef typename LEN::Value Value; + + /// \brief Operation traits for Bellman-Ford algorithm. + /// + /// It defines the used operations and the infinity value for the + /// given \c Value type. + /// \see BellmanFordDefaultOperationTraits, + /// BellmanFordToleranceOperationTraits + typedef BellmanFordDefaultOperationTraits OperationTraits; + + /// \brief The type of the map that stores the last arcs of the + /// shortest paths. + /// + /// The type of the map that stores the last + /// arcs of the shortest paths. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename GR::template NodeMap PredMap; + + /// \brief Instantiates a \c PredMap. + /// + /// This function instantiates a \ref PredMap. + /// \param g is the digraph to which we would like to define the + /// \ref PredMap. + static PredMap *createPredMap(const GR& g) { + return new PredMap(g); + } + + /// \brief The type of the map that stores the distances of the nodes. + /// + /// The type of the map that stores the distances of the nodes. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename GR::template NodeMap DistMap; + + /// \brief Instantiates a \c DistMap. + /// + /// This function instantiates a \ref DistMap. + /// \param g is the digraph to which we would like to define the + /// \ref DistMap. + static DistMap *createDistMap(const GR& g) { + return new DistMap(g); + } + + }; + + /// \brief %BellmanFord algorithm class. + /// + /// \ingroup shortest_path + /// This class provides an efficient implementation of the Bellman-Ford + /// algorithm. The maximum time complexity of the algorithm is + /// O(ne). + /// + /// The Bellman-Ford algorithm solves the single-source shortest path + /// problem when the arcs can have negative lengths, but the digraph + /// should not contain directed cycles with negative total length. + /// If all arc costs are non-negative, consider to use the Dijkstra + /// algorithm instead, since it is more efficient. + /// + /// The arc lengths are passed to the algorithm using a + /// \ref concepts::ReadMap "ReadMap", so it is easy to change it to any + /// kind of length. The type of the length values is determined by the + /// \ref concepts::ReadMap::Value "Value" type of the length map. + /// + /// There is also a \ref bellmanFord() "function-type interface" for the + /// Bellman-Ford algorithm, which is convenient in the simplier cases and + /// it can be used easier. + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// The default type is \ref ListDigraph. + /// \tparam LEN A \ref concepts::ReadMap "readable" arc map that specifies + /// the lengths of the arcs. The default map type is + /// \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref BellmanFordDefaultTraits + /// "BellmanFordDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template , + typename TR=BellmanFordDefaultTraits > +#endif + class BellmanFord { + public: + + ///The type of the underlying digraph. + typedef typename TR::Digraph Digraph; + + /// \brief The type of the arc lengths. + typedef typename TR::LengthMap::Value Value; + /// \brief The type of the map that stores the arc lengths. + typedef typename TR::LengthMap LengthMap; + /// \brief The type of the map that stores the last + /// arcs of the shortest paths. + typedef typename TR::PredMap PredMap; + /// \brief The type of the map that stores the distances of the nodes. + typedef typename TR::DistMap DistMap; + /// The type of the paths. + typedef PredMapPath Path; + ///\brief The \ref BellmanFordDefaultOperationTraits + /// "operation traits class" of the algorithm. + typedef typename TR::OperationTraits OperationTraits; + + ///The \ref BellmanFordDefaultTraits "traits class" of the algorithm. + typedef TR Traits; + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt OutArcIt; + + // Pointer to the underlying digraph. + const Digraph *_gr; + // Pointer to the length map + const LengthMap *_length; + // Pointer to the map of predecessors arcs. + PredMap *_pred; + // Indicates if _pred is locally allocated (true) or not. + bool _local_pred; + // Pointer to the map of distances. + DistMap *_dist; + // Indicates if _dist is locally allocated (true) or not. + bool _local_dist; + + typedef typename Digraph::template NodeMap MaskMap; + MaskMap *_mask; + + std::vector _process; + + // Creates the maps if necessary. + void create_maps() { + if(!_pred) { + _local_pred = true; + _pred = Traits::createPredMap(*_gr); + } + if(!_dist) { + _local_dist = true; + _dist = Traits::createDistMap(*_gr); + } + if(!_mask) { + _mask = new MaskMap(*_gr); + } + } + + public : + + typedef BellmanFord Create; + + /// \name Named Template Parameters + + ///@{ + + template + struct SetPredMapTraits : public Traits { + typedef T PredMap; + static PredMap *createPredMap(const Digraph&) { + LEMON_ASSERT(false, "PredMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c PredMap type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c PredMap type. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetPredMap + : public BellmanFord< Digraph, LengthMap, SetPredMapTraits > { + typedef BellmanFord< Digraph, LengthMap, SetPredMapTraits > Create; + }; + + template + struct SetDistMapTraits : public Traits { + typedef T DistMap; + static DistMap *createDistMap(const Digraph&) { + LEMON_ASSERT(false, "DistMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c DistMap type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c DistMap type. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + struct SetDistMap + : public BellmanFord< Digraph, LengthMap, SetDistMapTraits > { + typedef BellmanFord< Digraph, LengthMap, SetDistMapTraits > Create; + }; + + template + struct SetOperationTraitsTraits : public Traits { + typedef T OperationTraits; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c OperationTraits type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c OperationTraits type. + /// For more information, see \ref BellmanFordDefaultOperationTraits. + template + struct SetOperationTraits + : public BellmanFord< Digraph, LengthMap, SetOperationTraitsTraits > { + typedef BellmanFord< Digraph, LengthMap, SetOperationTraitsTraits > + Create; + }; + + ///@} + + protected: + + BellmanFord() {} + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// \param g The digraph the algorithm runs on. + /// \param length The length map used by the algorithm. + BellmanFord(const Digraph& g, const LengthMap& length) : + _gr(&g), _length(&length), + _pred(0), _local_pred(false), + _dist(0), _local_dist(false), _mask(0) {} + + ///Destructor. + ~BellmanFord() { + if(_local_pred) delete _pred; + if(_local_dist) delete _dist; + if(_mask) delete _mask; + } + + /// \brief Sets the length map. + /// + /// Sets the length map. + /// \return (*this) + BellmanFord &lengthMap(const LengthMap &map) { + _length = ↦ + return *this; + } + + /// \brief Sets the map that stores the predecessor arcs. + /// + /// Sets the map that stores the predecessor arcs. + /// If you don't use this function before calling \ref run() + /// or \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + BellmanFord &predMap(PredMap &map) { + if(_local_pred) { + delete _pred; + _local_pred=false; + } + _pred = ↦ + return *this; + } + + /// \brief Sets the map that stores the distances of the nodes. + /// + /// Sets the map that stores the distances of the nodes calculated + /// by the algorithm. + /// If you don't use this function before calling \ref run() + /// or \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + BellmanFord &distMap(DistMap &map) { + if(_local_dist) { + delete _dist; + _local_dist=false; + } + _dist = ↦ + return *this; + } + + /// \name Execution Control + /// The simplest way to execute the Bellman-Ford algorithm is to use + /// one of the member functions called \ref run().\n + /// If you need better control on the execution, you have to call + /// \ref init() first, then you can add several source nodes + /// with \ref addSource(). Finally the actual path computation can be + /// performed with \ref start(), \ref checkedStart() or + /// \ref limitedStart(). + + ///@{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures. The optional parameter + /// is the initial distance of each node. + void init(const Value value = OperationTraits::infinity()) { + create_maps(); + for (NodeIt it(*_gr); it != INVALID; ++it) { + _pred->set(it, INVALID); + _dist->set(it, value); + } + _process.clear(); + if (OperationTraits::less(value, OperationTraits::infinity())) { + for (NodeIt it(*_gr); it != INVALID; ++it) { + _process.push_back(it); + _mask->set(it, true); + } + } else { + for (NodeIt it(*_gr); it != INVALID; ++it) { + _mask->set(it, false); + } + } + } + + /// \brief Adds a new source node. + /// + /// This function adds a new source node. The optional second parameter + /// is the initial distance of the node. + void addSource(Node source, Value dst = OperationTraits::zero()) { + _dist->set(source, dst); + if (!(*_mask)[source]) { + _process.push_back(source); + _mask->set(source, true); + } + } + + /// \brief Executes one round from the Bellman-Ford algorithm. + /// + /// If the algoritm calculated the distances in the previous round + /// exactly for the paths of at most \c k arcs, then this function + /// will calculate the distances exactly for the paths of at most + /// k+1 arcs. Performing \c k iterations using this function + /// calculates the shortest path distances exactly for the paths + /// consisting of at most \c k arcs. + /// + /// \warning The paths with limited arc number cannot be retrieved + /// easily with \ref path() or \ref predArc() functions. If you also + /// need the shortest paths and not only the distances, you should + /// store the \ref predMap() "predecessor map" after each iteration + /// and build the path manually. + /// + /// \return \c true when the algorithm have not found more shorter + /// paths. + /// + /// \see ActiveIt + bool processNextRound() { + for (int i = 0; i < int(_process.size()); ++i) { + _mask->set(_process[i], false); + } + std::vector nextProcess; + std::vector values(_process.size()); + for (int i = 0; i < int(_process.size()); ++i) { + values[i] = (*_dist)[_process[i]]; + } + for (int i = 0; i < int(_process.size()); ++i) { + for (OutArcIt it(*_gr, _process[i]); it != INVALID; ++it) { + Node target = _gr->target(it); + Value relaxed = OperationTraits::plus(values[i], (*_length)[it]); + if (OperationTraits::less(relaxed, (*_dist)[target])) { + _pred->set(target, it); + _dist->set(target, relaxed); + if (!(*_mask)[target]) { + _mask->set(target, true); + nextProcess.push_back(target); + } + } + } + } + _process.swap(nextProcess); + return _process.empty(); + } + + /// \brief Executes one weak round from the Bellman-Ford algorithm. + /// + /// If the algorithm calculated the distances in the previous round + /// at least for the paths of at most \c k arcs, then this function + /// will calculate the distances at least for the paths of at most + /// k+1 arcs. + /// This function does not make it possible to calculate the shortest + /// path distances exactly for paths consisting of at most \c k arcs, + /// this is why it is called weak round. + /// + /// \return \c true when the algorithm have not found more shorter + /// paths. + /// + /// \see ActiveIt + bool processNextWeakRound() { + for (int i = 0; i < int(_process.size()); ++i) { + _mask->set(_process[i], false); + } + std::vector nextProcess; + for (int i = 0; i < int(_process.size()); ++i) { + for (OutArcIt it(*_gr, _process[i]); it != INVALID; ++it) { + Node target = _gr->target(it); + Value relaxed = + OperationTraits::plus((*_dist)[_process[i]], (*_length)[it]); + if (OperationTraits::less(relaxed, (*_dist)[target])) { + _pred->set(target, it); + _dist->set(target, relaxed); + if (!(*_mask)[target]) { + _mask->set(target, true); + nextProcess.push_back(target); + } + } + } + } + _process.swap(nextProcess); + return _process.empty(); + } + + /// \brief Executes the algorithm. + /// + /// Executes the algorithm. + /// + /// This method runs the Bellman-Ford algorithm from the root node(s) + /// in order to compute the shortest path to each node. + /// + /// The algorithm computes + /// - the shortest path tree (forest), + /// - the distance of each node from the root(s). + /// + /// \pre init() must be called and at least one root node should be + /// added with addSource() before using this function. + void start() { + int num = countNodes(*_gr) - 1; + for (int i = 0; i < num; ++i) { + if (processNextWeakRound()) break; + } + } + + /// \brief Executes the algorithm and checks the negative cycles. + /// + /// Executes the algorithm and checks the negative cycles. + /// + /// This method runs the Bellman-Ford algorithm from the root node(s) + /// in order to compute the shortest path to each node and also checks + /// if the digraph contains cycles with negative total length. + /// + /// The algorithm computes + /// - the shortest path tree (forest), + /// - the distance of each node from the root(s). + /// + /// \return \c false if there is a negative cycle in the digraph. + /// + /// \pre init() must be called and at least one root node should be + /// added with addSource() before using this function. + bool checkedStart() { + int num = countNodes(*_gr); + for (int i = 0; i < num; ++i) { + if (processNextWeakRound()) return true; + } + return _process.empty(); + } + + /// \brief Executes the algorithm with arc number limit. + /// + /// Executes the algorithm with arc number limit. + /// + /// This method runs the Bellman-Ford algorithm from the root node(s) + /// in order to compute the shortest path distance for each node + /// using only the paths consisting of at most \c num arcs. + /// + /// The algorithm computes + /// - the limited distance of each node from the root(s), + /// - the predecessor arc for each node. + /// + /// \warning The paths with limited arc number cannot be retrieved + /// easily with \ref path() or \ref predArc() functions. If you also + /// need the shortest paths and not only the distances, you should + /// store the \ref predMap() "predecessor map" after each iteration + /// and build the path manually. + /// + /// \pre init() must be called and at least one root node should be + /// added with addSource() before using this function. + void limitedStart(int num) { + for (int i = 0; i < num; ++i) { + if (processNextRound()) break; + } + } + + /// \brief Runs the algorithm from the given root node. + /// + /// This method runs the Bellman-Ford algorithm from the given root + /// node \c s in order to compute the shortest path to each node. + /// + /// The algorithm computes + /// - the shortest path tree (forest), + /// - the distance of each node from the root(s). + /// + /// \note bf.run(s) is just a shortcut of the following code. + /// \code + /// bf.init(); + /// bf.addSource(s); + /// bf.start(); + /// \endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + /// \brief Runs the algorithm from the given root node with arc + /// number limit. + /// + /// This method runs the Bellman-Ford algorithm from the given root + /// node \c s in order to compute the shortest path distance for each + /// node using only the paths consisting of at most \c num arcs. + /// + /// The algorithm computes + /// - the limited distance of each node from the root(s), + /// - the predecessor arc for each node. + /// + /// \warning The paths with limited arc number cannot be retrieved + /// easily with \ref path() or \ref predArc() functions. If you also + /// need the shortest paths and not only the distances, you should + /// store the \ref predMap() "predecessor map" after each iteration + /// and build the path manually. + /// + /// \note bf.run(s, num) is just a shortcut of the following code. + /// \code + /// bf.init(); + /// bf.addSource(s); + /// bf.limitedStart(num); + /// \endcode + void run(Node s, int num) { + init(); + addSource(s); + limitedStart(num); + } + + ///@} + + /// \brief LEMON iterator for getting the active nodes. + /// + /// This class provides a common style LEMON iterator that traverses + /// the active nodes of the Bellman-Ford algorithm after the last + /// phase. These nodes should be checked in the next phase to + /// find augmenting arcs outgoing from them. + class ActiveIt { + public: + + /// \brief Constructor. + /// + /// Constructor for getting the active nodes of the given BellmanFord + /// instance. + ActiveIt(const BellmanFord& algorithm) : _algorithm(&algorithm) + { + _index = _algorithm->_process.size() - 1; + } + + /// \brief Invalid constructor. + /// + /// Invalid constructor. + ActiveIt(Invalid) : _algorithm(0), _index(-1) {} + + /// \brief Conversion to \c Node. + /// + /// Conversion to \c Node. + operator Node() const { + return _index >= 0 ? _algorithm->_process[_index] : INVALID; + } + + /// \brief Increment operator. + /// + /// Increment operator. + ActiveIt& operator++() { + --_index; + return *this; + } + + bool operator==(const ActiveIt& it) const { + return static_cast(*this) == static_cast(it); + } + bool operator!=(const ActiveIt& it) const { + return static_cast(*this) != static_cast(it); + } + bool operator<(const ActiveIt& it) const { + return static_cast(*this) < static_cast(it); + } + + private: + const BellmanFord* _algorithm; + int _index; + }; + + /// \name Query Functions + /// The result of the Bellman-Ford algorithm can be obtained using these + /// functions.\n + /// Either \ref run() or \ref init() should be called before using them. + + ///@{ + + /// \brief The shortest path to the given node. + /// + /// Gives back the shortest path to the given node from the root(s). + /// + /// \warning \c t should be reached from the root(s). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Path path(Node t) const + { + return Path(*_gr, *_pred, t); + } + + /// \brief The distance of the given node from the root(s). + /// + /// Returns the distance of the given node from the root(s). + /// + /// \warning If node \c v is not reached from the root(s), then + /// the return value of this function is undefined. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Value dist(Node v) const { return (*_dist)[v]; } + + /// \brief Returns the 'previous arc' of the shortest path tree for + /// the given node. + /// + /// This function returns the 'previous arc' of the shortest path + /// tree for node \c v, i.e. it returns the last arc of a + /// shortest path from a root to \c v. It is \c INVALID if \c v + /// is not reached from the root(s) or if \c v is a root. + /// + /// The shortest path tree used here is equal to the shortest path + /// tree used in \ref predNode() and \ref predMap(). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Arc predArc(Node v) const { return (*_pred)[v]; } + + /// \brief Returns the 'previous node' of the shortest path tree for + /// the given node. + /// + /// This function returns the 'previous node' of the shortest path + /// tree for node \c v, i.e. it returns the last but one node of + /// a shortest path from a root to \c v. It is \c INVALID if \c v + /// is not reached from the root(s) or if \c v is a root. + /// + /// The shortest path tree used here is equal to the shortest path + /// tree used in \ref predArc() and \ref predMap(). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Node predNode(Node v) const { + return (*_pred)[v] == INVALID ? INVALID : _gr->source((*_pred)[v]); + } + + /// \brief Returns a const reference to the node map that stores the + /// distances of the nodes. + /// + /// Returns a const reference to the node map that stores the distances + /// of the nodes calculated by the algorithm. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const DistMap &distMap() const { return *_dist;} + + /// \brief Returns a const reference to the node map that stores the + /// predecessor arcs. + /// + /// Returns a const reference to the node map that stores the predecessor + /// arcs, which form the shortest path tree (forest). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const PredMap &predMap() const { return *_pred; } + + /// \brief Checks if a node is reached from the root(s). + /// + /// Returns \c true if \c v is reached from the root(s). + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + bool reached(Node v) const { + return (*_dist)[v] != OperationTraits::infinity(); + } + + /// \brief Gives back a negative cycle. + /// + /// This function gives back a directed cycle with negative total + /// length if the algorithm has already found one. + /// Otherwise it gives back an empty path. + lemon::Path negativeCycle() const { + typename Digraph::template NodeMap state(*_gr, -1); + lemon::Path cycle; + for (int i = 0; i < int(_process.size()); ++i) { + if (state[_process[i]] != -1) continue; + for (Node v = _process[i]; (*_pred)[v] != INVALID; + v = _gr->source((*_pred)[v])) { + if (state[v] == i) { + cycle.addFront((*_pred)[v]); + for (Node u = _gr->source((*_pred)[v]); u != v; + u = _gr->source((*_pred)[u])) { + cycle.addFront((*_pred)[u]); + } + return cycle; + } + else if (state[v] >= 0) { + break; + } + state[v] = i; + } + } + return cycle; + } + + ///@} + }; + + /// \brief Default traits class of bellmanFord() function. + /// + /// Default traits class of bellmanFord() function. + /// \tparam GR The type of the digraph. + /// \tparam LEN The type of the length map. + template + struct BellmanFordWizardDefaultTraits { + /// The type of the digraph the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that stores the arc lengths. + /// + /// The type of the map that stores the arc lengths. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef LEN LengthMap; + + /// The type of the arc lengths. + typedef typename LEN::Value Value; + + /// \brief Operation traits for Bellman-Ford algorithm. + /// + /// It defines the used operations and the infinity value for the + /// given \c Value type. + /// \see BellmanFordDefaultOperationTraits, + /// BellmanFordToleranceOperationTraits + typedef BellmanFordDefaultOperationTraits OperationTraits; + + /// \brief The type of the map that stores the last + /// arcs of the shortest paths. + /// + /// The type of the map that stores the last arcs of the shortest paths. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename GR::template NodeMap PredMap; + + /// \brief Instantiates a \c PredMap. + /// + /// This function instantiates a \ref PredMap. + /// \param g is the digraph to which we would like to define the + /// \ref PredMap. + static PredMap *createPredMap(const GR &g) { + return new PredMap(g); + } + + /// \brief The type of the map that stores the distances of the nodes. + /// + /// The type of the map that stores the distances of the nodes. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + typedef typename GR::template NodeMap DistMap; + + /// \brief Instantiates a \c DistMap. + /// + /// This function instantiates a \ref DistMap. + /// \param g is the digraph to which we would like to define the + /// \ref DistMap. + static DistMap *createDistMap(const GR &g) { + return new DistMap(g); + } + + ///The type of the shortest paths. + + ///The type of the shortest paths. + ///It must meet the \ref concepts::Path "Path" concept. + typedef lemon::Path Path; + }; + + /// \brief Default traits class used by BellmanFordWizard. + /// + /// Default traits class used by BellmanFordWizard. + /// \tparam GR The type of the digraph. + /// \tparam LEN The type of the length map. + template + class BellmanFordWizardBase + : public BellmanFordWizardDefaultTraits { + + typedef BellmanFordWizardDefaultTraits Base; + protected: + // Type of the nodes in the digraph. + typedef typename Base::Digraph::Node Node; + + // Pointer to the underlying digraph. + void *_graph; + // Pointer to the length map + void *_length; + // Pointer to the map of predecessors arcs. + void *_pred; + // Pointer to the map of distances. + void *_dist; + //Pointer to the shortest path to the target node. + void *_path; + //Pointer to the distance of the target node. + void *_di; + + public: + /// Constructor. + + /// This constructor does not require parameters, it initiates + /// all of the attributes to default values \c 0. + BellmanFordWizardBase() : + _graph(0), _length(0), _pred(0), _dist(0), _path(0), _di(0) {} + + /// Constructor. + + /// This constructor requires two parameters, + /// others are initiated to \c 0. + /// \param gr The digraph the algorithm runs on. + /// \param len The length map. + BellmanFordWizardBase(const GR& gr, + const LEN& len) : + _graph(reinterpret_cast(const_cast(&gr))), + _length(reinterpret_cast(const_cast(&len))), + _pred(0), _dist(0), _path(0), _di(0) {} + + }; + + /// \brief Auxiliary class for the function-type interface of the + /// \ref BellmanFord "Bellman-Ford" algorithm. + /// + /// This auxiliary class is created to implement the + /// \ref bellmanFord() "function-type interface" of the + /// \ref BellmanFord "Bellman-Ford" algorithm. + /// It does not have own \ref run() method, it uses the + /// functions and features of the plain \ref BellmanFord. + /// + /// This class should only be used through the \ref bellmanFord() + /// function, which makes it easier to use the algorithm. + /// + /// \tparam TR The traits class that defines various types used by the + /// algorithm. + template + class BellmanFordWizard : public TR { + typedef TR Base; + + typedef typename TR::Digraph Digraph; + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::OutArcIt ArcIt; + + typedef typename TR::LengthMap LengthMap; + typedef typename LengthMap::Value Value; + typedef typename TR::PredMap PredMap; + typedef typename TR::DistMap DistMap; + typedef typename TR::Path Path; + + public: + /// Constructor. + BellmanFordWizard() : TR() {} + + /// \brief Constructor that requires parameters. + /// + /// Constructor that requires parameters. + /// These parameters will be the default values for the traits class. + /// \param gr The digraph the algorithm runs on. + /// \param len The length map. + BellmanFordWizard(const Digraph& gr, const LengthMap& len) + : TR(gr, len) {} + + /// \brief Copy constructor + BellmanFordWizard(const TR &b) : TR(b) {} + + ~BellmanFordWizard() {} + + /// \brief Runs the Bellman-Ford algorithm from the given source node. + /// + /// This method runs the Bellman-Ford algorithm from the given source + /// node in order to compute the shortest path to each node. + void run(Node s) { + BellmanFord + bf(*reinterpret_cast(Base::_graph), + *reinterpret_cast(Base::_length)); + if (Base::_pred) bf.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) bf.distMap(*reinterpret_cast(Base::_dist)); + bf.run(s); + } + + /// \brief Runs the Bellman-Ford algorithm to find the shortest path + /// between \c s and \c t. + /// + /// This method runs the Bellman-Ford algorithm from node \c s + /// in order to compute the shortest path to node \c t. + /// Actually, it computes the shortest path to each node, but using + /// this function you can retrieve the distance and the shortest path + /// for a single target node easier. + /// + /// \return \c true if \c t is reachable form \c s. + bool run(Node s, Node t) { + BellmanFord + bf(*reinterpret_cast(Base::_graph), + *reinterpret_cast(Base::_length)); + if (Base::_pred) bf.predMap(*reinterpret_cast(Base::_pred)); + if (Base::_dist) bf.distMap(*reinterpret_cast(Base::_dist)); + bf.run(s); + if (Base::_path) *reinterpret_cast(Base::_path) = bf.path(t); + if (Base::_di) *reinterpret_cast(Base::_di) = bf.dist(t); + return bf.reached(t); + } + + template + struct SetPredMapBase : public Base { + typedef T PredMap; + static PredMap *createPredMap(const Digraph &) { return 0; }; + SetPredMapBase(const TR &b) : TR(b) {} + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// the predecessor map. + /// + /// \ref named-templ-param "Named parameter" for setting + /// the map that stores the predecessor arcs of the nodes. + template + BellmanFordWizard > predMap(const T &t) { + Base::_pred=reinterpret_cast(const_cast(&t)); + return BellmanFordWizard >(*this); + } + + template + struct SetDistMapBase : public Base { + typedef T DistMap; + static DistMap *createDistMap(const Digraph &) { return 0; }; + SetDistMapBase(const TR &b) : TR(b) {} + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// the distance map. + /// + /// \ref named-templ-param "Named parameter" for setting + /// the map that stores the distances of the nodes calculated + /// by the algorithm. + template + BellmanFordWizard > distMap(const T &t) { + Base::_dist=reinterpret_cast(const_cast(&t)); + return BellmanFordWizard >(*this); + } + + template + struct SetPathBase : public Base { + typedef T Path; + SetPathBase(const TR &b) : TR(b) {} + }; + + /// \brief \ref named-func-param "Named parameter" for getting + /// the shortest path to the target node. + /// + /// \ref named-func-param "Named parameter" for getting + /// the shortest path to the target node. + template + BellmanFordWizard > path(const T &t) + { + Base::_path=reinterpret_cast(const_cast(&t)); + return BellmanFordWizard >(*this); + } + + /// \brief \ref named-func-param "Named parameter" for getting + /// the distance of the target node. + /// + /// \ref named-func-param "Named parameter" for getting + /// the distance of the target node. + BellmanFordWizard dist(const Value &d) + { + Base::_di=reinterpret_cast(const_cast(&d)); + return *this; + } + + }; + + /// \brief Function type interface for the \ref BellmanFord "Bellman-Ford" + /// algorithm. + /// + /// \ingroup shortest_path + /// Function type interface for the \ref BellmanFord "Bellman-Ford" + /// algorithm. + /// + /// This function also has several \ref named-templ-func-param + /// "named parameters", they are declared as the members of class + /// \ref BellmanFordWizard. + /// The following examples show how to use these parameters. + /// \code + /// // Compute shortest path from node s to each node + /// bellmanFord(g,length).predMap(preds).distMap(dists).run(s); + /// + /// // Compute shortest path from s to t + /// bool reached = bellmanFord(g,length).path(p).dist(d).run(s,t); + /// \endcode + /// \warning Don't forget to put the \ref BellmanFordWizard::run() "run()" + /// to the end of the parameter list. + /// \sa BellmanFordWizard + /// \sa BellmanFord + template + BellmanFordWizard > + bellmanFord(const GR& digraph, + const LEN& length) + { + return BellmanFordWizard >(digraph, length); + } + +} //END OF NAMESPACE LEMON + +#endif + diff --git a/lemon/bfs.h b/lemon/bfs.h --- a/lemon/bfs.h +++ b/lemon/bfs.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -47,7 +47,7 @@ /// ///The type of the map that stores the predecessor ///arcs of the shortest paths. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap PredMap; ///Instantiates a \c PredMap. @@ -62,7 +62,8 @@ ///The type of the map that indicates which nodes are processed. ///The type of the map that indicates which nodes are processed. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. typedef NullMap ProcessedMap; ///Instantiates a \c ProcessedMap. @@ -81,7 +82,8 @@ ///The type of the map that indicates which nodes are reached. ///The type of the map that indicates which nodes are reached. - ///It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. typedef typename Digraph::template NodeMap ReachedMap; ///Instantiates a \c ReachedMap. @@ -96,7 +98,7 @@ ///The type of the map that stores the distances of the nodes. ///The type of the map that stores the distances of the nodes. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap DistMap; ///Instantiates a \c DistMap. @@ -120,6 +122,11 @@ /// ///\tparam GR The type of the digraph the algorithm runs on. ///The default type is \ref ListDigraph. + ///\tparam TR The traits class that defines various types used by the + ///algorithm. By default, it is \ref BfsDefaultTraits + ///"BfsDefaultTraits". + ///In most cases, this parameter should not be set directly, + ///consider to use the named template parameters instead. #ifdef DOXYGEN template @@ -225,7 +232,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c PredMap type. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. template struct SetPredMap : public Bfs< Digraph, SetPredMapTraits > { typedef Bfs< Digraph, SetPredMapTraits > Create; @@ -245,7 +252,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c DistMap type. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. template struct SetDistMap : public Bfs< Digraph, SetDistMapTraits > { typedef Bfs< Digraph, SetDistMapTraits > Create; @@ -265,7 +272,8 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c ReachedMap type. - ///It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. template struct SetReachedMap : public Bfs< Digraph, SetReachedMapTraits > { typedef Bfs< Digraph, SetReachedMapTraits > Create; @@ -285,7 +293,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c ProcessedMap type. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. template struct SetProcessedMap : public Bfs< Digraph, SetProcessedMapTraits > { typedef Bfs< Digraph, SetProcessedMapTraits > Create; @@ -413,8 +421,8 @@ ///\name Execution Control ///The simplest way to execute the BFS algorithm is to use one of the ///member functions called \ref run(Node) "run()".\n - ///If you need more control on the execution, first you have to call - ///\ref init(), then you can add several source nodes with + ///If you need better control on the execution, you have to call + ///\ref init() first, then you can add several source nodes with ///\ref addSource(). Finally the actual path computation can be ///performed with one of the \ref start() functions. @@ -700,12 +708,8 @@ ///Runs the algorithm to visit all nodes in the digraph. - ///This method runs the %BFS algorithm in order to - ///compute the shortest path to each node. - /// - ///The algorithm computes - ///- the shortest path tree (forest), - ///- the distance of each node from the root(s). + ///This method runs the %BFS algorithm in order to visit all nodes + ///in the digraph. /// ///\note b.run(s) is just a shortcut of the following code. ///\code @@ -737,9 +741,9 @@ ///@{ - ///The shortest path to a node. + ///The shortest path to the given node. - ///Returns the shortest path to a node. + ///Returns the shortest path to the given node from the root(s). /// ///\warning \c t should be reached from the root(s). /// @@ -747,9 +751,9 @@ ///must be called before using this function. Path path(Node t) const { return Path(*G, *_pred, t); } - ///The distance of a node from the root(s). + ///The distance of the given node from the root(s). - ///Returns the distance of a node from the root(s). + ///Returns the distance of the given node from the root(s). /// ///\warning If node \c v is not reached from the root(s), then ///the return value of this function is undefined. @@ -758,29 +762,31 @@ ///must be called before using this function. int dist(Node v) const { return (*_dist)[v]; } - ///Returns the 'previous arc' of the shortest path tree for a node. - + ///\brief Returns the 'previous arc' of the shortest path tree for + ///the given node. + /// ///This function returns the 'previous arc' of the shortest path ///tree for the node \c v, i.e. it returns the last arc of a ///shortest path from a root to \c v. It is \c INVALID if \c v ///is not reached from the root(s) or if \c v is a root. /// ///The shortest path tree used here is equal to the shortest path - ///tree used in \ref predNode(). + ///tree used in \ref predNode() and \ref predMap(). /// ///\pre Either \ref run(Node) "run()" or \ref init() ///must be called before using this function. Arc predArc(Node v) const { return (*_pred)[v];} - ///Returns the 'previous node' of the shortest path tree for a node. - + ///\brief Returns the 'previous node' of the shortest path tree for + ///the given node. + /// ///This function returns the 'previous node' of the shortest path ///tree for the node \c v, i.e. it returns the last but one node - ///from a shortest path from a root to \c v. It is \c INVALID + ///of a shortest path from a root to \c v. It is \c INVALID ///if \c v is not reached from the root(s) or if \c v is a root. /// ///The shortest path tree used here is equal to the shortest path - ///tree used in \ref predArc(). + ///tree used in \ref predArc() and \ref predMap(). /// ///\pre Either \ref run(Node) "run()" or \ref init() ///must be called before using this function. @@ -801,13 +807,13 @@ ///predecessor arcs. /// ///Returns a const reference to the node map that stores the predecessor - ///arcs, which form the shortest path tree. + ///arcs, which form the shortest path tree (forest). /// ///\pre Either \ref run(Node) "run()" or \ref init() ///must be called before using this function. const PredMap &predMap() const { return *_pred;} - ///Checks if a node is reached from the root(s). + ///Checks if the given node is reached from the root(s). ///Returns \c true if \c v is reached from the root(s). /// @@ -833,7 +839,7 @@ /// ///The type of the map that stores the predecessor ///arcs of the shortest paths. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap PredMap; ///Instantiates a PredMap. @@ -848,8 +854,8 @@ ///The type of the map that indicates which nodes are processed. ///The type of the map that indicates which nodes are processed. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. - ///By default it is a NullMap. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. typedef NullMap ProcessedMap; ///Instantiates a ProcessedMap. @@ -868,7 +874,8 @@ ///The type of the map that indicates which nodes are reached. ///The type of the map that indicates which nodes are reached. - ///It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. typedef typename Digraph::template NodeMap ReachedMap; ///Instantiates a ReachedMap. @@ -883,7 +890,7 @@ ///The type of the map that stores the distances of the nodes. ///The type of the map that stores the distances of the nodes. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap DistMap; ///Instantiates a DistMap. @@ -898,18 +905,14 @@ ///The type of the shortest paths. ///The type of the shortest paths. - ///It must meet the \ref concepts::Path "Path" concept. + ///It must conform to the \ref concepts::Path "Path" concept. typedef lemon::Path Path; }; /// Default traits class used by BfsWizard - /// To make it easier to use Bfs algorithm - /// we have created a wizard class. - /// This \ref BfsWizard class needs default traits, - /// as well as the \ref Bfs class. - /// The \ref BfsWizardBase is a class to be the default traits of the - /// \ref BfsWizard class. + /// Default traits class used by BfsWizard. + /// \tparam GR The type of the digraph. template class BfsWizardBase : public BfsWizardDefaultTraits { @@ -937,7 +940,7 @@ public: /// Constructor. - /// This constructor does not require parameters, therefore it initiates + /// This constructor does not require parameters, it initiates /// all of the attributes to \c 0. BfsWizardBase() : _g(0), _reached(0), _processed(0), _pred(0), _dist(0), _path(0), _di(0) {} @@ -962,12 +965,14 @@ /// /// This class should only be used through the \ref bfs() function, /// which makes it easier to use the algorithm. + /// + /// \tparam TR The traits class that defines various types used by the + /// algorithm. template class BfsWizard : public TR { typedef TR Base; - ///The type of the digraph the algorithm runs on. typedef typename TR::Digraph Digraph; typedef typename Digraph::Node Node; @@ -975,16 +980,10 @@ typedef typename Digraph::Arc Arc; typedef typename Digraph::OutArcIt OutArcIt; - ///\brief The type of the map that stores the predecessor - ///arcs of the shortest paths. typedef typename TR::PredMap PredMap; - ///\brief The type of the map that stores the distances of the nodes. typedef typename TR::DistMap DistMap; - ///\brief The type of the map that indicates which nodes are reached. typedef typename TR::ReachedMap ReachedMap; - ///\brief The type of the map that indicates which nodes are processed. typedef typename TR::ProcessedMap ProcessedMap; - ///The type of the shortest paths typedef typename TR::Path Path; public: @@ -1054,8 +1053,8 @@ ///Runs BFS algorithm to visit all nodes in the digraph. - ///This method runs BFS algorithm in order to compute - ///the shortest path to each node. + ///This method runs BFS algorithm in order to visit all nodes + ///in the digraph. void run() { run(INVALID); @@ -1067,11 +1066,12 @@ static PredMap *createPredMap(const Digraph &) { return 0; }; SetPredMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting PredMap object. + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the predecessor map. /// - ///\ref named-func-param "Named parameter" - ///for setting PredMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the predecessor arcs of the nodes. template BfsWizard > predMap(const T &t) { @@ -1085,11 +1085,12 @@ static ReachedMap *createReachedMap(const Digraph &) { return 0; }; SetReachedMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting ReachedMap object. + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the reached map. /// - /// \ref named-func-param "Named parameter" - ///for setting ReachedMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are reached. template BfsWizard > reachedMap(const T &t) { @@ -1103,11 +1104,13 @@ static DistMap *createDistMap(const Digraph &) { return 0; }; SetDistMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting DistMap object. + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the distance map. /// - /// \ref named-func-param "Named parameter" - ///for setting DistMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the distances of the nodes calculated + ///by the algorithm. template BfsWizard > distMap(const T &t) { @@ -1121,11 +1124,12 @@ static ProcessedMap *createProcessedMap(const Digraph &) { return 0; }; SetProcessedMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting ProcessedMap object. + + ///\brief \ref named-func-param "Named parameter" for setting + ///the processed map. /// - /// \ref named-func-param "Named parameter" - ///for setting ProcessedMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are processed. template BfsWizard > processedMap(const T &t) { @@ -1264,7 +1268,8 @@ /// \brief The type of the map that indicates which nodes are reached. /// /// The type of the map that indicates which nodes are reached. - /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + /// It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. typedef typename Digraph::template NodeMap ReachedMap; /// \brief Instantiates a ReachedMap. @@ -1302,11 +1307,11 @@ /// \ref BfsVisitor "BfsVisitor" is an empty visitor, which /// does not observe the BFS events. If you want to observe the BFS /// events, you should implement your own visitor class. - /// \tparam TR Traits class to set various data types used by the - /// algorithm. The default traits class is - /// \ref BfsVisitDefaultTraits "BfsVisitDefaultTraits". - /// See \ref BfsVisitDefaultTraits for the documentation of - /// a BFS visit traits class. + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref BfsVisitDefaultTraits + /// "BfsVisitDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. #ifdef DOXYGEN template #else @@ -1425,8 +1430,8 @@ /// \name Execution Control /// The simplest way to execute the BFS algorithm is to use one of the /// member functions called \ref run(Node) "run()".\n - /// If you need more control on the execution, first you have to call - /// \ref init(), then you can add several source nodes with + /// If you need better control on the execution, you have to call + /// \ref init() first, then you can add several source nodes with /// \ref addSource(). Finally the actual path computation can be /// performed with one of the \ref start() functions. @@ -1698,12 +1703,8 @@ /// \brief Runs the algorithm to visit all nodes in the digraph. /// - /// This method runs the %BFS algorithm in order to - /// compute the shortest path to each node. - /// - /// The algorithm computes - /// - the shortest path tree (forest), - /// - the distance of each node from the root(s). + /// This method runs the %BFS algorithm in order to visit all nodes + /// in the digraph. /// /// \note b.run(s) is just a shortcut of the following code. ///\code @@ -1735,7 +1736,7 @@ ///@{ - /// \brief Checks if a node is reached from the root(s). + /// \brief Checks if the given node is reached from the root(s). /// /// Returns \c true if \c v is reached from the root(s). /// diff --git a/lemon/bin_heap.h b/lemon/bin_heap.h --- a/lemon/bin_heap.h +++ b/lemon/bin_heap.h @@ -19,9 +19,9 @@ #ifndef LEMON_BIN_HEAP_H #define LEMON_BIN_HEAP_H -///\ingroup auxdat +///\ingroup heaps ///\file -///\brief Binary Heap implementation. +///\brief Binary heap implementation. #include #include @@ -29,45 +29,41 @@ namespace lemon { - ///\ingroup auxdat + /// \ingroup heaps /// - ///\brief A Binary Heap implementation. + /// \brief Binary heap data structure. /// - ///This class implements the \e binary \e heap data structure. + /// This class implements the \e binary \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". /// - ///A \e heap is a data structure for storing items with specified values - ///called \e priorities in such a way that finding the item with minimum - ///priority is efficient. \c CMP specifies the ordering of the priorities. - ///In a heap one can change the priority of an item, add or erase an - ///item, etc. - /// - ///\tparam PR Type of the priority of the items. - ///\tparam IM A read and writable item map with int values, used internally - ///to handle the cross references. - ///\tparam CMP A functor class for the ordering of the priorities. - ///The default is \c std::less. - /// - ///\sa FibHeap - ///\sa Dijkstra + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. +#ifdef DOXYGEN + template +#else template > +#endif class BinHeap { + public: - public: - ///\e + /// Type of the item-int map. typedef IM ItemIntMap; - ///\e + /// Type of the priorities. typedef PR Prio; - ///\e + /// Type of the items stored in the heap. typedef typename ItemIntMap::Key Item; - ///\e + /// Type of the item-priority pairs. typedef std::pair Pair; - ///\e + /// Functor type for comparing the priorities. typedef CMP Compare; - /// \brief Type to represent the items states. + /// \brief Type to represent the states of the items. /// - /// Each Item element have a state associated to it. It may be "in heap", - /// "pre heap" or "post heap". The latter two are indifferent from the + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the /// heap's point of view, but may be useful to the user. /// /// The item-int map must be initialized in such way that it assigns @@ -84,42 +80,43 @@ ItemIntMap &_iim; public: - /// \brief The constructor. + + /// \brief Constructor. /// - /// The constructor. - /// \param map should be given to the constructor, since it is used - /// internally to handle the cross references. The value of the map - /// must be \c PRE_HEAP (-1) for every item. + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. explicit BinHeap(ItemIntMap &map) : _iim(map) {} - /// \brief The constructor. + /// \brief Constructor. /// - /// The constructor. - /// \param map should be given to the constructor, since it is used - /// internally to handle the cross references. The value of the map - /// should be PRE_HEAP (-1) for each element. - /// - /// \param comp The comparator function object. + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. BinHeap(ItemIntMap &map, const Compare &comp) : _iim(map), _comp(comp) {} - /// The number of items stored in the heap. + /// \brief The number of items stored in the heap. /// - /// \brief Returns the number of items stored in the heap. + /// This function returns the number of items stored in the heap. int size() const { return _data.size(); } - /// \brief Checks if the heap stores no items. + /// \brief Check if the heap is empty. /// - /// Returns \c true if and only if the heap stores no items. + /// This function returns \c true if the heap is empty. bool empty() const { return _data.empty(); } - /// \brief Make empty this heap. + /// \brief Make the heap empty. /// - /// Make empty this heap. It does not change the cross reference map. - /// If you want to reuse what is not surely empty you should first clear - /// the heap and after that you should set the cross reference map for - /// each item to \c PRE_HEAP. + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. void clear() { _data.clear(); } @@ -127,12 +124,12 @@ private: static int parent(int i) { return (i-1)/2; } - static int second_child(int i) { return 2*i+2; } + static int secondChild(int i) { return 2*i+2; } bool less(const Pair &p1, const Pair &p2) const { return _comp(p1.second, p2.second); } - int bubble_up(int hole, Pair p) { + int bubbleUp(int hole, Pair p) { int par = parent(hole); while( hole>0 && less(p,_data[par]) ) { move(_data[par],hole); @@ -143,8 +140,8 @@ return hole; } - int bubble_down(int hole, Pair p, int length) { - int child = second_child(hole); + int bubbleDown(int hole, Pair p, int length) { + int child = secondChild(hole); while(child < length) { if( less(_data[child-1], _data[child]) ) { --child; @@ -153,7 +150,7 @@ goto ok; move(_data[child], hole); hole = child; - child = second_child(hole); + child = secondChild(hole); } child--; if( child 0) { - bubble_down(0, _data[n], n); + bubbleDown(0, _data[n], n); } _data.pop_back(); } - /// \brief Deletes \c i from the heap. + /// \brief Remove the given item from the heap. /// - /// This method deletes item \c i from the heap. - /// \param i The item to erase. - /// \pre The item should be in the heap. + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. void erase(const Item &i) { int h = _iim[i]; int n = _data.size()-1; _iim.set(_data[h].first, POST_HEAP); if( h < n ) { - if ( bubble_up(h, _data[n]) == h) { - bubble_down(h, _data[n], n); + if ( bubbleUp(h, _data[n]) == h) { + bubbleDown(h, _data[n], n); } } _data.pop_back(); } - - /// \brief Returns the priority of \c i. + /// \brief The priority of the given item. /// - /// This function returns the priority of item \c i. + /// This function returns the priority of the given item. /// \param i The item. - /// \pre \c i must be in the heap. + /// \pre \e i must be in the heap. Prio operator[](const Item &i) const { int idx = _iim[i]; return _data[idx].second; } - /// \brief \c i gets to the heap with priority \c p independently - /// if \c i was already there. + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. /// - /// This method calls \ref push(\c i, \c p) if \c i is not stored - /// in the heap and sets the priority of \c i to \c p otherwise. + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. /// \param i The item. /// \param p The priority. void set(const Item &i, const Prio &p) { @@ -260,44 +261,42 @@ push(i,p); } else if( _comp(p, _data[idx].second) ) { - bubble_up(idx, Pair(i,p)); + bubbleUp(idx, Pair(i,p)); } else { - bubble_down(idx, Pair(i,p), _data.size()); + bubbleDown(idx, Pair(i,p), _data.size()); } } - /// \brief Decreases the priority of \c i to \c p. + /// \brief Decrease the priority of an item to the given value. /// - /// This method decreases the priority of item \c i to \c p. + /// This function decreases the priority of an item to the given value. /// \param i The item. /// \param p The priority. - /// \pre \c i must be stored in the heap with priority at least \c - /// p relative to \c Compare. + /// \pre \e i must be stored in the heap with priority at least \e p. void decrease(const Item &i, const Prio &p) { int idx = _iim[i]; - bubble_up(idx, Pair(i,p)); + bubbleUp(idx, Pair(i,p)); } - /// \brief Increases the priority of \c i to \c p. + /// \brief Increase the priority of an item to the given value. /// - /// This method sets the priority of item \c i to \c p. + /// This function increases the priority of an item to the given value. /// \param i The item. /// \param p The priority. - /// \pre \c i must be stored in the heap with priority at most \c - /// p relative to \c Compare. + /// \pre \e i must be stored in the heap with priority at most \e p. void increase(const Item &i, const Prio &p) { int idx = _iim[i]; - bubble_down(idx, Pair(i,p), _data.size()); + bubbleDown(idx, Pair(i,p), _data.size()); } - /// \brief Returns if \c item is in, has already been in, or has - /// never been in the heap. + /// \brief Return the state of an item. /// - /// This method returns PRE_HEAP if \c item has never been in the - /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP - /// otherwise. In the latter case it is possible that \c item will - /// get back to the heap again. + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. /// \param i The item. State state(const Item &i) const { int s = _iim[i]; @@ -306,11 +305,11 @@ return State(s); } - /// \brief Sets the state of the \c item in the heap. + /// \brief Set the state of an item in the heap. /// - /// Sets the state of the \c item in the heap. It can be used to - /// manually clear the heap when it is important to achive the - /// better time complexity. + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. /// \param i The item. /// \param st The state. It should not be \c IN_HEAP. void state(const Item& i, State st) { @@ -327,12 +326,13 @@ } } - /// \brief Replaces an item in the heap. + /// \brief Replace an item in the heap. /// - /// The \c i item is replaced with \c j item. The \c i item should - /// be in the heap, while the \c j should be out of the heap. The - /// \c i item will out of the heap and \c j will be in the heap - /// with the same prioriority as prevoiusly the \c i item. + /// This function replaces item \c i with item \c j. + /// Item \c i must be in the heap, while \c j must be out of the heap. + /// After calling this method, item \c i will be out of the + /// heap and \c j will be in the heap with the same prioriority + /// as item \c i had before. void replace(const Item& i, const Item& j) { int idx = _iim[i]; _iim.set(i, _iim[j]); diff --git a/lemon/binomial_heap.h b/lemon/binomial_heap.h new file mode 100644 --- /dev/null +++ b/lemon/binomial_heap.h @@ -0,0 +1,445 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_BINOMIAL_HEAP_H +#define LEMON_BINOMIAL_HEAP_H + +///\file +///\ingroup heaps +///\brief Binomial Heap implementation. + +#include +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + ///\brief Binomial heap data structure. + /// + /// This class implements the \e binomial \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// The methods \ref increase() and \ref erase() are not efficient + /// in a binomial heap. In case of many calls of these operations, + /// it is better to use other heap structure, e.g. \ref BinHeap + /// "binary heap". + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. +#ifdef DOXYGEN + template +#else + template > +#endif + class BinomialHeap { + public: + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + class Store; + + std::vector _data; + int _min, _head; + ItemIntMap &_iim; + Compare _comp; + int _num_items; + + public: + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit BinomialHeap(ItemIntMap &map) + : _min(0), _head(-1), _iim(map), _num_items(0) {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + BinomialHeap(ItemIntMap &map, const Compare &comp) + : _min(0), _head(-1), _iim(map), _comp(comp), _num_items(0) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _num_items; } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _num_items==0; } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { + _data.clear(); _min=0; _num_items=0; _head=-1; + } + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// \param item The item. + /// \param value The priority. + void set (const Item& item, const Prio& value) { + int i=_iim[item]; + if ( i >= 0 && _data[i].in ) { + if ( _comp(value, _data[i].prio) ) decrease(item, value); + if ( _comp(_data[i].prio, value) ) increase(item, value); + } else push(item, value); + } + + /// \brief Insert an item into the heap with the given priority. + /// + /// This function inserts the given item into the heap with the + /// given priority. + /// \param item The item to insert. + /// \param value The priority of the item. + /// \pre \e item must not be stored in the heap. + void push (const Item& item, const Prio& value) { + int i=_iim[item]; + if ( i<0 ) { + int s=_data.size(); + _iim.set( item,s ); + Store st; + st.name=item; + st.prio=value; + _data.push_back(st); + i=s; + } + else { + _data[i].parent=_data[i].right_neighbor=_data[i].child=-1; + _data[i].degree=0; + _data[i].in=true; + _data[i].prio=value; + } + + if( 0==_num_items ) { + _head=i; + _min=i; + } else { + merge(i); + if( _comp(_data[i].prio, _data[_min].prio) ) _min=i; + } + ++_num_items; + } + + /// \brief Return the item having minimum priority. + /// + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. + Item top() const { return _data[_min].name; } + + /// \brief The minimum priority. + /// + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + Prio prio() const { return _data[_min].prio; } + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param item The item. + /// \pre \e item must be in the heap. + const Prio& operator[](const Item& item) const { + return _data[_iim[item]].prio; + } + + /// \brief Remove the item having minimum priority. + /// + /// This function removes the item having minimum priority. + /// \pre The heap must be non-empty. + void pop() { + _data[_min].in=false; + + int head_child=-1; + if ( _data[_min].child!=-1 ) { + int child=_data[_min].child; + int neighb; + while( child!=-1 ) { + neighb=_data[child].right_neighbor; + _data[child].parent=-1; + _data[child].right_neighbor=head_child; + head_child=child; + child=neighb; + } + } + + if ( _data[_head].right_neighbor==-1 ) { + // there was only one root + _head=head_child; + } + else { + // there were more roots + if( _head!=_min ) { unlace(_min); } + else { _head=_data[_head].right_neighbor; } + merge(head_child); + } + _min=findMin(); + --_num_items; + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param item The item to delete. + /// \pre \e item must be in the heap. + void erase (const Item& item) { + int i=_iim[item]; + if ( i >= 0 && _data[i].in ) { + decrease( item, _data[_min].prio-1 ); + pop(); + } + } + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param item The item. + /// \param value The priority. + /// \pre \e item must be stored in the heap with priority at least \e value. + void decrease (Item item, const Prio& value) { + int i=_iim[item]; + int p=_data[i].parent; + _data[i].prio=value; + + while( p!=-1 && _comp(value, _data[p].prio) ) { + _data[i].name=_data[p].name; + _data[i].prio=_data[p].prio; + _data[p].name=item; + _data[p].prio=value; + _iim[_data[i].name]=i; + i=p; + p=_data[p].parent; + } + _iim[item]=i; + if ( _comp(value, _data[_min].prio) ) _min=i; + } + + /// \brief Increase the priority of an item to the given value. + /// + /// This function increases the priority of an item to the given value. + /// \param item The item. + /// \param value The priority. + /// \pre \e item must be stored in the heap with priority at most \e value. + void increase (Item item, const Prio& value) { + erase(item); + push(item, value); + } + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param item The item. + State state(const Item &item) const { + int i=_iim[item]; + if( i>=0 ) { + if ( _data[i].in ) i=0; + else i=-2; + } + return State(i); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) { + erase(i); + } + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + private: + + // Find the minimum of the roots + int findMin() { + if( _head!=-1 ) { + int min_loc=_head, min_val=_data[_head].prio; + for( int x=_data[_head].right_neighbor; x!=-1; + x=_data[x].right_neighbor ) { + if( _comp( _data[x].prio,min_val ) ) { + min_val=_data[x].prio; + min_loc=x; + } + } + return min_loc; + } + else return -1; + } + + // Merge the heap with another heap starting at the given position + void merge(int a) { + if( _head==-1 || a==-1 ) return; + if( _data[a].right_neighbor==-1 && + _data[a].degree<=_data[_head].degree ) { + _data[a].right_neighbor=_head; + _head=a; + } else { + interleave(a); + } + if( _data[_head].right_neighbor==-1 ) return; + + int x=_head; + int x_prev=-1, x_next=_data[x].right_neighbor; + while( x_next!=-1 ) { + if( _data[x].degree!=_data[x_next].degree || + ( _data[x_next].right_neighbor!=-1 && + _data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) { + x_prev=x; + x=x_next; + } + else { + if( _comp(_data[x_next].prio,_data[x].prio) ) { + if( x_prev==-1 ) { + _head=x_next; + } else { + _data[x_prev].right_neighbor=x_next; + } + fuse(x,x_next); + x=x_next; + } + else { + _data[x].right_neighbor=_data[x_next].right_neighbor; + fuse(x_next,x); + } + } + x_next=_data[x].right_neighbor; + } + } + + // Interleave the elements of the given list into the list of the roots + void interleave(int a) { + int p=_head, q=a; + int curr=_data.size(); + _data.push_back(Store()); + + while( p!=-1 || q!=-1 ) { + if( q==-1 || ( p!=-1 && _data[p].degree<_data[q].degree ) ) { + _data[curr].right_neighbor=p; + curr=p; + p=_data[p].right_neighbor; + } + else { + _data[curr].right_neighbor=q; + curr=q; + q=_data[q].right_neighbor; + } + } + + _head=_data.back().right_neighbor; + _data.pop_back(); + } + + // Lace node a under node b + void fuse(int a, int b) { + _data[a].parent=b; + _data[a].right_neighbor=_data[b].child; + _data[b].child=a; + + ++_data[b].degree; + } + + // Unlace node a (if it has siblings) + void unlace(int a) { + int neighb=_data[a].right_neighbor; + int other=_head; + + while( _data[other].right_neighbor!=a ) + other=_data[other].right_neighbor; + _data[other].right_neighbor=neighb; + } + + private: + + class Store { + friend class BinomialHeap; + + Item name; + int parent; + int right_neighbor; + int child; + int degree; + bool in; + Prio prio; + + Store() : parent(-1), right_neighbor(-1), child(-1), degree(0), + in(true) {} + }; + }; + +} //namespace lemon + +#endif //LEMON_BINOMIAL_HEAP_H + diff --git a/lemon/bits/array_map.h b/lemon/bits/array_map.h --- a/lemon/bits/array_map.h +++ b/lemon/bits/array_map.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -70,7 +70,7 @@ typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier; private: - + // The MapBase of the Map which imlements the core regisitry function. typedef typename Notifier::ObserverBase Parent; diff --git a/lemon/bits/default_map.h b/lemon/bits/default_map.h --- a/lemon/bits/default_map.h +++ b/lemon/bits/default_map.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -157,7 +157,7 @@ public: typedef DefaultMap<_Graph, _Item, _Value> Map; - + typedef typename Parent::GraphType GraphType; typedef typename Parent::Value Value; diff --git a/lemon/bits/edge_set_extender.h b/lemon/bits/edge_set_extender.h --- a/lemon/bits/edge_set_extender.h +++ b/lemon/bits/edge_set_extender.h @@ -1,8 +1,8 @@ -/* -*- C++ -*- +/* -*- mode: C++; indent-tabs-mode: nil; -*- * - * This file is a part of LEMON, a generic C++ optimization library + * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -63,11 +63,11 @@ Node oppositeNode(const Node &n, const Arc &e) const { if (n == Parent::source(e)) - return Parent::target(e); + return Parent::target(e); else if(n==Parent::target(e)) - return Parent::source(e); + return Parent::source(e); else - return INVALID; + return INVALID; } @@ -91,7 +91,7 @@ // Iterable extensions - class NodeIt : public Node { + class NodeIt : public Node { const Digraph* digraph; public: @@ -100,21 +100,21 @@ NodeIt(Invalid i) : Node(i) { } explicit NodeIt(const Digraph& _graph) : digraph(&_graph) { - _graph.first(static_cast(*this)); + _graph.first(static_cast(*this)); } - NodeIt(const Digraph& _graph, const Node& node) - : Node(node), digraph(&_graph) {} + NodeIt(const Digraph& _graph, const Node& node) + : Node(node), digraph(&_graph) {} - NodeIt& operator++() { - digraph->next(*this); - return *this; + NodeIt& operator++() { + digraph->next(*this); + return *this; } }; - class ArcIt : public Arc { + class ArcIt : public Arc { const Digraph* digraph; public: @@ -123,21 +123,21 @@ ArcIt(Invalid i) : Arc(i) { } explicit ArcIt(const Digraph& _graph) : digraph(&_graph) { - _graph.first(static_cast(*this)); + _graph.first(static_cast(*this)); } - ArcIt(const Digraph& _graph, const Arc& e) : - Arc(e), digraph(&_graph) { } + ArcIt(const Digraph& _graph, const Arc& e) : + Arc(e), digraph(&_graph) { } - ArcIt& operator++() { - digraph->next(*this); - return *this; + ArcIt& operator++() { + digraph->next(*this); + return *this; } }; - class OutArcIt : public Arc { + class OutArcIt : public Arc { const Digraph* digraph; public: @@ -145,23 +145,23 @@ OutArcIt(Invalid i) : Arc(i) { } - OutArcIt(const Digraph& _graph, const Node& node) - : digraph(&_graph) { - _graph.firstOut(*this, node); + OutArcIt(const Digraph& _graph, const Node& node) + : digraph(&_graph) { + _graph.firstOut(*this, node); } - OutArcIt(const Digraph& _graph, const Arc& arc) - : Arc(arc), digraph(&_graph) {} + OutArcIt(const Digraph& _graph, const Arc& arc) + : Arc(arc), digraph(&_graph) {} - OutArcIt& operator++() { - digraph->nextOut(*this); - return *this; + OutArcIt& operator++() { + digraph->nextOut(*this); + return *this; } }; - class InArcIt : public Arc { + class InArcIt : public Arc { const Digraph* digraph; public: @@ -169,17 +169,17 @@ InArcIt(Invalid i) : Arc(i) { } - InArcIt(const Digraph& _graph, const Node& node) - : digraph(&_graph) { - _graph.firstIn(*this, node); + InArcIt(const Digraph& _graph, const Node& node) + : digraph(&_graph) { + _graph.firstIn(*this, node); } - InArcIt(const Digraph& _graph, const Arc& arc) : - Arc(arc), digraph(&_graph) {} + InArcIt(const Digraph& _graph, const Arc& arc) : + Arc(arc), digraph(&_graph) {} - InArcIt& operator++() { - digraph->nextIn(*this); - return *this; + InArcIt& operator++() { + digraph->nextIn(*this); + return *this; } }; @@ -215,26 +215,26 @@ using Parent::first; // Mappable extension - + template - class ArcMap + class ArcMap : public MapExtender > { typedef MapExtender > Parent; public: - explicit ArcMap(const Digraph& _g) - : Parent(_g) {} - ArcMap(const Digraph& _g, const _Value& _v) - : Parent(_g, _v) {} + explicit ArcMap(const Digraph& _g) + : Parent(_g) {} + ArcMap(const Digraph& _g, const _Value& _v) + : Parent(_g, _v) {} ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); + return operator=(cmap); } template ArcMap& operator=(const CMap& cmap) { Parent::operator=(cmap); - return *this; + return *this; } }; @@ -247,7 +247,7 @@ notifier(Arc()).add(arc); return arc; } - + void clear() { notifier(Arc()).clear(); Parent::clear(); @@ -312,11 +312,11 @@ Node oppositeNode(const Node &n, const Edge &e) const { if( n == Parent::u(e)) - return Parent::v(e); + return Parent::v(e); else if( n == Parent::v(e)) - return Parent::u(e); + return Parent::u(e); else - return INVALID; + return INVALID; } Arc oppositeArc(const Arc &e) const { @@ -340,7 +340,7 @@ public: using Parent::notifier; - + ArcNotifier& notifier(Arc) const { return arc_notifier; } @@ -350,7 +350,7 @@ } - class NodeIt : public Node { + class NodeIt : public Node { const Graph* graph; public: @@ -359,21 +359,21 @@ NodeIt(Invalid i) : Node(i) { } explicit NodeIt(const Graph& _graph) : graph(&_graph) { - _graph.first(static_cast(*this)); + _graph.first(static_cast(*this)); } - NodeIt(const Graph& _graph, const Node& node) - : Node(node), graph(&_graph) {} + NodeIt(const Graph& _graph, const Node& node) + : Node(node), graph(&_graph) {} - NodeIt& operator++() { - graph->next(*this); - return *this; + NodeIt& operator++() { + graph->next(*this); + return *this; } }; - class ArcIt : public Arc { + class ArcIt : public Arc { const Graph* graph; public: @@ -382,21 +382,21 @@ ArcIt(Invalid i) : Arc(i) { } explicit ArcIt(const Graph& _graph) : graph(&_graph) { - _graph.first(static_cast(*this)); + _graph.first(static_cast(*this)); } - ArcIt(const Graph& _graph, const Arc& e) : - Arc(e), graph(&_graph) { } + ArcIt(const Graph& _graph, const Arc& e) : + Arc(e), graph(&_graph) { } - ArcIt& operator++() { - graph->next(*this); - return *this; + ArcIt& operator++() { + graph->next(*this); + return *this; } }; - class OutArcIt : public Arc { + class OutArcIt : public Arc { const Graph* graph; public: @@ -404,23 +404,23 @@ OutArcIt(Invalid i) : Arc(i) { } - OutArcIt(const Graph& _graph, const Node& node) - : graph(&_graph) { - _graph.firstOut(*this, node); + OutArcIt(const Graph& _graph, const Node& node) + : graph(&_graph) { + _graph.firstOut(*this, node); } - OutArcIt(const Graph& _graph, const Arc& arc) - : Arc(arc), graph(&_graph) {} + OutArcIt(const Graph& _graph, const Arc& arc) + : Arc(arc), graph(&_graph) {} - OutArcIt& operator++() { - graph->nextOut(*this); - return *this; + OutArcIt& operator++() { + graph->nextOut(*this); + return *this; } }; - class InArcIt : public Arc { + class InArcIt : public Arc { const Graph* graph; public: @@ -428,23 +428,23 @@ InArcIt(Invalid i) : Arc(i) { } - InArcIt(const Graph& _graph, const Node& node) - : graph(&_graph) { - _graph.firstIn(*this, node); + InArcIt(const Graph& _graph, const Node& node) + : graph(&_graph) { + _graph.firstIn(*this, node); } - InArcIt(const Graph& _graph, const Arc& arc) : - Arc(arc), graph(&_graph) {} + InArcIt(const Graph& _graph, const Arc& arc) : + Arc(arc), graph(&_graph) {} - InArcIt& operator++() { - graph->nextIn(*this); - return *this; + InArcIt& operator++() { + graph->nextIn(*this); + return *this; } }; - class EdgeIt : public Parent::Edge { + class EdgeIt : public Parent::Edge { const Graph* graph; public: @@ -453,15 +453,15 @@ EdgeIt(Invalid i) : Edge(i) { } explicit EdgeIt(const Graph& _graph) : graph(&_graph) { - _graph.first(static_cast(*this)); + _graph.first(static_cast(*this)); } - EdgeIt(const Graph& _graph, const Edge& e) : - Edge(e), graph(&_graph) { } + EdgeIt(const Graph& _graph, const Edge& e) : + Edge(e), graph(&_graph) { } - EdgeIt& operator++() { - graph->next(*this); - return *this; + EdgeIt& operator++() { + graph->next(*this); + return *this; } }; @@ -477,17 +477,17 @@ IncEdgeIt(Invalid i) : Edge(i), direction(false) { } IncEdgeIt(const Graph& _graph, const Node &n) : graph(&_graph) { - _graph.firstInc(*this, direction, n); + _graph.firstInc(*this, direction, n); } IncEdgeIt(const Graph& _graph, const Edge &ue, const Node &n) - : graph(&_graph), Edge(ue) { - direction = (_graph.source(ue) == n); + : graph(&_graph), Edge(ue) { + direction = (_graph.source(ue) == n); } IncEdgeIt& operator++() { - graph->nextInc(*this, direction); - return *this; + graph->nextInc(*this, direction); + return *this; } }; @@ -534,49 +534,49 @@ template - class ArcMap + class ArcMap : public MapExtender > { typedef MapExtender > Parent; public: - explicit ArcMap(const Graph& _g) - : Parent(_g) {} - ArcMap(const Graph& _g, const _Value& _v) - : Parent(_g, _v) {} + explicit ArcMap(const Graph& _g) + : Parent(_g) {} + ArcMap(const Graph& _g, const _Value& _v) + : Parent(_g, _v) {} ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); + return operator=(cmap); } template ArcMap& operator=(const CMap& cmap) { Parent::operator=(cmap); - return *this; + return *this; } }; template - class EdgeMap + class EdgeMap : public MapExtender > { typedef MapExtender > Parent; public: - explicit EdgeMap(const Graph& _g) - : Parent(_g) {} + explicit EdgeMap(const Graph& _g) + : Parent(_g) {} - EdgeMap(const Graph& _g, const _Value& _v) - : Parent(_g, _v) {} + EdgeMap(const Graph& _g, const _Value& _v) + : Parent(_g, _v) {} EdgeMap& operator=(const EdgeMap& cmap) { - return operator=(cmap); + return operator=(cmap); } template EdgeMap& operator=(const CMap& cmap) { Parent::operator=(cmap); - return *this; + return *this; } }; @@ -593,7 +593,7 @@ notifier(Arc()).add(arcs); return edge; } - + void clear() { notifier(Arc()).clear(); notifier(Edge()).clear(); @@ -619,7 +619,7 @@ edge_notifier.clear(); arc_notifier.clear(); } - + }; } diff --git a/lemon/bits/graph_extender.h b/lemon/bits/graph_extender.h --- a/lemon/bits/graph_extender.h +++ b/lemon/bits/graph_extender.h @@ -56,11 +56,11 @@ return Parent::maxArcId(); } - Node fromId(int id, Node) const { + static Node fromId(int id, Node) { return Parent::nodeFromId(id); } - Arc fromId(int id, Arc) const { + static Arc fromId(int id, Arc) { return Parent::arcFromId(id); } @@ -355,15 +355,15 @@ return Parent::maxEdgeId(); } - Node fromId(int id, Node) const { + static Node fromId(int id, Node) { return Parent::nodeFromId(id); } - Arc fromId(int id, Arc) const { + static Arc fromId(int id, Arc) { return Parent::arcFromId(id); } - Edge fromId(int id, Edge) const { + static Edge fromId(int id, Edge) { return Parent::edgeFromId(id); } diff --git a/lemon/bits/solver_bits.h b/lemon/bits/solver_bits.h --- a/lemon/bits/solver_bits.h +++ b/lemon/bits/solver_bits.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff --git a/lemon/bits/windows.cc b/lemon/bits/windows.cc --- a/lemon/bits/windows.cc +++ b/lemon/bits/windows.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -98,7 +98,7 @@ SYSTEMTIME time; GetSystemTime(&time); char buf1[11], buf2[9], buf3[5]; - if (GetDateFormat(MY_LOCALE, 0, &time, + if (GetDateFormat(MY_LOCALE, 0, &time, ("ddd MMM dd"), buf1, 11) && GetTimeFormat(MY_LOCALE, 0, &time, ("HH':'mm':'ss"), buf2, 9) && diff --git a/lemon/bucket_heap.h b/lemon/bucket_heap.h --- a/lemon/bucket_heap.h +++ b/lemon/bucket_heap.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -19,9 +19,9 @@ #ifndef LEMON_BUCKET_HEAP_H #define LEMON_BUCKET_HEAP_H -///\ingroup auxdat +///\ingroup heaps ///\file -///\brief Bucket Heap implementation. +///\brief Bucket heap implementation. #include #include @@ -53,35 +53,41 @@ } - /// \ingroup auxdat + /// \ingroup heaps /// - /// \brief A Bucket Heap implementation. + /// \brief Bucket heap data structure. /// - /// This class implements the \e bucket \e heap data structure. A \e heap - /// is a data structure for storing items with specified values called \e - /// priorities in such a way that finding the item with minimum priority is - /// efficient. The bucket heap is very simple implementation, it can store - /// only integer priorities and it stores for each priority in the - /// \f$ [0..C) \f$ range a list of items. So it should be used only when - /// the priorities are small. It is not intended to use as dijkstra heap. + /// This class implements the \e bucket \e heap data structure. + /// It practically conforms to the \ref concepts::Heap "heap concept", + /// but it has some limitations. /// - /// \param IM A read and write Item int map, used internally - /// to handle the cross references. - /// \param MIN If the given parameter is false then instead of the - /// minimum value the maximum can be retrivied with the top() and - /// prio() member functions. + /// The bucket heap is a very simple structure. It can store only + /// \c int priorities and it maintains a list of items for each priority + /// in the range [0..C). So it should only be used when the + /// priorities are small. It is not intended to use as a Dijkstra heap. + /// + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap. + /// The default is \e min-heap. If this parameter is set to \c false, + /// then the comparison is reversed, so the top(), prio() and pop() + /// functions deal with the item having maximum priority instead of the + /// minimum. + /// + /// \sa SimpleBucketHeap template class BucketHeap { public: - /// \e - typedef typename IM::Key Item; - /// \e + + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. typedef int Prio; - /// \e - typedef std::pair Pair; - /// \e - typedef IM ItemIntMap; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; private: @@ -89,10 +95,10 @@ public: - /// \brief Type to represent the items states. + /// \brief Type to represent the states of the items. /// - /// Each Item element have a state associated to it. It may be "in heap", - /// "pre heap" or "post heap". The latter two are indifferent from the + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the /// heap's point of view, but may be useful to the user. /// /// The item-int map must be initialized in such way that it assigns @@ -104,37 +110,39 @@ }; public: - /// \brief The constructor. + + /// \brief Constructor. /// - /// The constructor. - /// \param map should be given to the constructor, since it is used - /// internally to handle the cross references. The value of the map - /// should be PRE_HEAP (-1) for each element. + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. explicit BucketHeap(ItemIntMap &map) : _iim(map), _minimum(0) {} - /// The number of items stored in the heap. + /// \brief The number of items stored in the heap. /// - /// \brief Returns the number of items stored in the heap. + /// This function returns the number of items stored in the heap. int size() const { return _data.size(); } - /// \brief Checks if the heap stores no items. + /// \brief Check if the heap is empty. /// - /// Returns \c true if and only if the heap stores no items. + /// This function returns \c true if the heap is empty. bool empty() const { return _data.empty(); } - /// \brief Make empty this heap. + /// \brief Make the heap empty. /// - /// Make empty this heap. It does not change the cross reference - /// map. If you want to reuse a heap what is not surely empty you - /// should first clear the heap and after that you should set the - /// cross reference map for each item to \c PRE_HEAP. + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. void clear() { _data.clear(); _first.clear(); _minimum = 0; } private: - void relocate_last(int idx) { + void relocateLast(int idx) { if (idx + 1 < int(_data.size())) { _data[idx] = _data.back(); if (_data[idx].prev != -1) { @@ -174,19 +182,24 @@ } public: + /// \brief Insert a pair of item and priority into the heap. /// - /// Adds \c p.first to the heap with priority \c p.second. + /// This function inserts \c p.first to the heap with priority + /// \c p.second. /// \param p The pair to insert. + /// \pre \c p.first must not be stored in the heap. void push(const Pair& p) { push(p.first, p.second); } /// \brief Insert an item into the heap with the given priority. /// - /// Adds \c i to the heap with priority \c p. + /// This function inserts the given item into the heap with the + /// given priority. /// \param i The item to insert. /// \param p The priority of the item. + /// \pre \e i must not be stored in the heap. void push(const Item &i, const Prio &p) { int idx = _data.size(); _iim[i] = idx; @@ -197,10 +210,10 @@ } } - /// \brief Returns the item with minimum priority. + /// \brief Return the item having minimum priority. /// - /// This method returns the item with minimum priority. - /// \pre The heap must be nonempty. + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. Item top() const { while (_first[_minimum] == -1) { Direction::increase(_minimum); @@ -208,10 +221,10 @@ return _data[_first[_minimum]].item; } - /// \brief Returns the minimum priority. + /// \brief The minimum priority. /// - /// It returns the minimum priority. - /// \pre The heap must be nonempty. + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. Prio prio() const { while (_first[_minimum] == -1) { Direction::increase(_minimum); @@ -219,9 +232,9 @@ return _minimum; } - /// \brief Deletes the item with minimum priority. + /// \brief Remove the item having minimum priority. /// - /// This method deletes the item with minimum priority from the heap. + /// This function removes the item having minimum priority. /// \pre The heap must be non-empty. void pop() { while (_first[_minimum] == -1) { @@ -230,37 +243,38 @@ int idx = _first[_minimum]; _iim[_data[idx].item] = -2; unlace(idx); - relocate_last(idx); + relocateLast(idx); } - /// \brief Deletes \c i from the heap. + /// \brief Remove the given item from the heap. /// - /// This method deletes item \c i from the heap, if \c i was - /// already stored in the heap. - /// \param i The item to erase. + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. void erase(const Item &i) { int idx = _iim[i]; _iim[_data[idx].item] = -2; unlace(idx); - relocate_last(idx); + relocateLast(idx); } - - /// \brief Returns the priority of \c i. + /// \brief The priority of the given item. /// - /// This function returns the priority of item \c i. - /// \pre \c i must be in the heap. + /// This function returns the priority of the given item. /// \param i The item. + /// \pre \e i must be in the heap. Prio operator[](const Item &i) const { int idx = _iim[i]; return _data[idx].value; } - /// \brief \c i gets to the heap with priority \c p independently - /// if \c i was already there. + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. /// - /// This method calls \ref push(\c i, \c p) if \c i is not stored - /// in the heap and sets the priority of \c i to \c p otherwise. + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. /// \param i The item. /// \param p The priority. void set(const Item &i, const Prio &p) { @@ -274,13 +288,12 @@ } } - /// \brief Decreases the priority of \c i to \c p. + /// \brief Decrease the priority of an item to the given value. /// - /// This method decreases the priority of item \c i to \c p. - /// \pre \c i must be stored in the heap with priority at least \c - /// p relative to \c Compare. + /// This function decreases the priority of an item to the given value. /// \param i The item. /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at least \e p. void decrease(const Item &i, const Prio &p) { int idx = _iim[i]; unlace(idx); @@ -291,13 +304,12 @@ lace(idx); } - /// \brief Increases the priority of \c i to \c p. + /// \brief Increase the priority of an item to the given value. /// - /// This method sets the priority of item \c i to \c p. - /// \pre \c i must be stored in the heap with priority at most \c - /// p relative to \c Compare. + /// This function increases the priority of an item to the given value. /// \param i The item. /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at most \e p. void increase(const Item &i, const Prio &p) { int idx = _iim[i]; unlace(idx); @@ -305,13 +317,13 @@ lace(idx); } - /// \brief Returns if \c item is in, has already been in, or has - /// never been in the heap. + /// \brief Return the state of an item. /// - /// This method returns PRE_HEAP if \c item has never been in the - /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP - /// otherwise. In the latter case it is possible that \c item will - /// get back to the heap again. + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. /// \param i The item. State state(const Item &i) const { int idx = _iim[i]; @@ -319,11 +331,11 @@ return State(idx); } - /// \brief Sets the state of the \c item in the heap. + /// \brief Set the state of an item in the heap. /// - /// Sets the state of the \c item in the heap. It can be used to - /// manually clear the heap when it is important to achive the - /// better time complexity. + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. /// \param i The item. /// \param st The state. It should not be \c IN_HEAP. void state(const Item& i, State st) { @@ -359,33 +371,44 @@ }; // class BucketHeap - /// \ingroup auxdat + /// \ingroup heaps /// - /// \brief A Simplified Bucket Heap implementation. + /// \brief Simplified bucket heap data structure. /// /// This class implements a simplified \e bucket \e heap data - /// structure. It does not provide some functionality but it faster - /// and simplier data structure than the BucketHeap. The main - /// difference is that the BucketHeap stores for every key a double - /// linked list while this class stores just simple lists. In the - /// other way it does not support erasing each elements just the - /// minimal and it does not supports key increasing, decreasing. + /// structure. It does not provide some functionality, but it is + /// faster and simpler than BucketHeap. The main difference is + /// that BucketHeap stores a doubly-linked list for each key while + /// this class stores only simply-linked lists. It supports erasing + /// only for the item having minimum priority and it does not support + /// key increasing and decreasing. /// - /// \param IM A read and write Item int map, used internally - /// to handle the cross references. - /// \param MIN If the given parameter is false then instead of the - /// minimum value the maximum can be retrivied with the top() and - /// prio() member functions. + /// Note that this implementation does not conform to the + /// \ref concepts::Heap "heap concept" due to the lack of some + /// functionality. + /// + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap. + /// The default is \e min-heap. If this parameter is set to \c false, + /// then the comparison is reversed, so the top(), prio() and pop() + /// functions deal with the item having maximum priority instead of the + /// minimum. /// /// \sa BucketHeap template class SimpleBucketHeap { public: - typedef typename IM::Key Item; + + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. typedef int Prio; - typedef std::pair Pair; - typedef IM ItemIntMap; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; private: @@ -393,10 +416,10 @@ public: - /// \brief Type to represent the items states. + /// \brief Type to represent the states of the items. /// - /// Each Item element have a state associated to it. It may be "in heap", - /// "pre heap" or "post heap". The latter two are indifferent from the + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the /// heap's point of view, but may be useful to the user. /// /// The item-int map must be initialized in such way that it assigns @@ -409,48 +432,53 @@ public: - /// \brief The constructor. + /// \brief Constructor. /// - /// The constructor. - /// \param map should be given to the constructor, since it is used - /// internally to handle the cross references. The value of the map - /// should be PRE_HEAP (-1) for each element. + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. explicit SimpleBucketHeap(ItemIntMap &map) : _iim(map), _free(-1), _num(0), _minimum(0) {} - /// \brief Returns the number of items stored in the heap. + /// \brief The number of items stored in the heap. /// - /// The number of items stored in the heap. + /// This function returns the number of items stored in the heap. int size() const { return _num; } - /// \brief Checks if the heap stores no items. + /// \brief Check if the heap is empty. /// - /// Returns \c true if and only if the heap stores no items. + /// This function returns \c true if the heap is empty. bool empty() const { return _num == 0; } - /// \brief Make empty this heap. + /// \brief Make the heap empty. /// - /// Make empty this heap. It does not change the cross reference - /// map. If you want to reuse a heap what is not surely empty you - /// should first clear the heap and after that you should set the - /// cross reference map for each item to \c PRE_HEAP. + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. void clear() { _data.clear(); _first.clear(); _free = -1; _num = 0; _minimum = 0; } /// \brief Insert a pair of item and priority into the heap. /// - /// Adds \c p.first to the heap with priority \c p.second. + /// This function inserts \c p.first to the heap with priority + /// \c p.second. /// \param p The pair to insert. + /// \pre \c p.first must not be stored in the heap. void push(const Pair& p) { push(p.first, p.second); } /// \brief Insert an item into the heap with the given priority. /// - /// Adds \c i to the heap with priority \c p. + /// This function inserts the given item into the heap with the + /// given priority. /// \param i The item to insert. /// \param p The priority of the item. + /// \pre \e i must not be stored in the heap. void push(const Item &i, const Prio &p) { int idx; if (_free == -1) { @@ -471,10 +499,10 @@ ++_num; } - /// \brief Returns the item with minimum priority. + /// \brief Return the item having minimum priority. /// - /// This method returns the item with minimum priority. - /// \pre The heap must be nonempty. + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. Item top() const { while (_first[_minimum] == -1) { Direction::increase(_minimum); @@ -482,10 +510,10 @@ return _data[_first[_minimum]].item; } - /// \brief Returns the minimum priority. + /// \brief The minimum priority. /// - /// It returns the minimum priority. - /// \pre The heap must be nonempty. + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. Prio prio() const { while (_first[_minimum] == -1) { Direction::increase(_minimum); @@ -493,9 +521,9 @@ return _minimum; } - /// \brief Deletes the item with minimum priority. + /// \brief Remove the item having minimum priority. /// - /// This method deletes the item with minimum priority from the heap. + /// This function removes the item having minimum priority. /// \pre The heap must be non-empty. void pop() { while (_first[_minimum] == -1) { @@ -509,16 +537,15 @@ --_num; } - /// \brief Returns the priority of \c i. + /// \brief The priority of the given item. /// - /// This function returns the priority of item \c i. - /// \warning This operator is not a constant time function - /// because it scans the whole data structure to find the proper - /// value. - /// \pre \c i must be in the heap. + /// This function returns the priority of the given item. /// \param i The item. + /// \pre \e i must be in the heap. + /// \warning This operator is not a constant time function because + /// it scans the whole data structure to find the proper value. Prio operator[](const Item &i) const { - for (int k = 0; k < _first.size(); ++k) { + for (int k = 0; k < int(_first.size()); ++k) { int idx = _first[k]; while (idx != -1) { if (_data[idx].item == i) { @@ -530,13 +557,13 @@ return -1; } - /// \brief Returns if \c item is in, has already been in, or has - /// never been in the heap. + /// \brief Return the state of an item. /// - /// This method returns PRE_HEAP if \c item has never been in the - /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP - /// otherwise. In the latter case it is possible that \c item will - /// get back to the heap again. + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. /// \param i The item. State state(const Item &i) const { int idx = _iim[i]; diff --git a/lemon/capacity_scaling.h b/lemon/capacity_scaling.h new file mode 100644 --- /dev/null +++ b/lemon/capacity_scaling.h @@ -0,0 +1,990 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_CAPACITY_SCALING_H +#define LEMON_CAPACITY_SCALING_H + +/// \ingroup min_cost_flow_algs +/// +/// \file +/// \brief Capacity Scaling algorithm for finding a minimum cost flow. + +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of CapacityScaling algorithm. + /// + /// Default traits class of CapacityScaling algorithm. + /// \tparam GR Digraph type. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values. By default it is \c int. + /// \tparam C The number type used for costs and potentials. + /// By default it is the same as \c V. + template + struct CapacityScalingDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef V Value; + /// The type of the arc costs + typedef C Cost; + + /// \brief The type of the heap used for internal Dijkstra computations. + /// + /// The type of the heap used for internal Dijkstra computations. + /// It must conform to the \ref lemon::concepts::Heap "Heap" concept, + /// its priority type must be \c Cost and its cross reference type + /// must be \ref RangeMap "RangeMap". + typedef BinHeap > Heap; + }; + + /// \addtogroup min_cost_flow_algs + /// @{ + + /// \brief Implementation of the Capacity Scaling algorithm for + /// finding a \ref min_cost_flow "minimum cost flow". + /// + /// \ref CapacityScaling implements the capacity scaling version + /// of the successive shortest path algorithm for finding a + /// \ref min_cost_flow "minimum cost flow" \ref amo93networkflows, + /// \ref edmondskarp72theoretical. It is an efficient dual + /// solution method. + /// + /// Most of the parameters of the problem (except for the digraph) + /// can be given using separate functions, and the algorithm can be + /// executed using the \ref run() function. If some parameters are not + /// specified, then default values will be used. + /// + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values in the algorithm. By default, it is \c int. + /// \tparam C The number type used for costs and potentials in the + /// algorithm. By default, it is the same as \c V. + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref CapacityScalingDefaultTraits + /// "CapacityScalingDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. + /// + /// \warning Both number types must be signed and all input data must + /// be integer. + /// \warning This algorithm does not support negative costs for such + /// arcs that have infinite upper bound. +#ifdef DOXYGEN + template +#else + template < typename GR, typename V = int, typename C = V, + typename TR = CapacityScalingDefaultTraits > +#endif + class CapacityScaling + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef typename TR::Value Value; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// The type of the heap used for internal Dijkstra computations + typedef typename TR::Heap Heap; + + /// The \ref CapacityScalingDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + public: + + /// \brief Problem type constants for the \c run() function. + /// + /// Enum type containing the problem type constants that can be + /// returned by the \ref run() function of the algorithm. + enum ProblemType { + /// The problem has no feasible solution (flow). + INFEASIBLE, + /// The problem has optimal solution (i.e. it is feasible and + /// bounded), and the algorithm has found optimal flow and node + /// potentials (primal and dual solutions). + OPTIMAL, + /// The digraph contains an arc of negative cost and infinite + /// upper bound. It means that the objective function is unbounded + /// on that arc, however, note that it could actually be bounded + /// over the feasible flows, but this algroithm cannot handle + /// these cases. + UNBOUNDED + }; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typedef std::vector IntVector; + typedef std::vector ValueVector; + typedef std::vector CostVector; + typedef std::vector BoolVector; + // Note: vector is used instead of vector for efficiency reasons + + private: + + // Data related to the underlying digraph + const GR &_graph; + int _node_num; + int _arc_num; + int _res_arc_num; + int _root; + + // Parameters of the problem + bool _have_lower; + Value _sum_supply; + + // Data structures for storing the digraph + IntNodeMap _node_id; + IntArcMap _arc_idf; + IntArcMap _arc_idb; + IntVector _first_out; + BoolVector _forward; + IntVector _source; + IntVector _target; + IntVector _reverse; + + // Node and arc data + ValueVector _lower; + ValueVector _upper; + CostVector _cost; + ValueVector _supply; + + ValueVector _res_cap; + CostVector _pi; + ValueVector _excess; + IntVector _excess_nodes; + IntVector _deficit_nodes; + + Value _delta; + int _factor; + IntVector _pred; + + public: + + /// \brief Constant for infinite upper bounds (capacities). + /// + /// Constant for infinite upper bounds (capacities). + /// It is \c std::numeric_limits::infinity() if available, + /// \c std::numeric_limits::max() otherwise. + const Value INF; + + private: + + // Special implementation of the Dijkstra algorithm for finding + // shortest paths in the residual network of the digraph with + // respect to the reduced arc costs and modifying the node + // potentials according to the found distance labels. + class ResidualDijkstra + { + private: + + int _node_num; + bool _geq; + const IntVector &_first_out; + const IntVector &_target; + const CostVector &_cost; + const ValueVector &_res_cap; + const ValueVector &_excess; + CostVector &_pi; + IntVector &_pred; + + IntVector _proc_nodes; + CostVector _dist; + + public: + + ResidualDijkstra(CapacityScaling& cs) : + _node_num(cs._node_num), _geq(cs._sum_supply < 0), + _first_out(cs._first_out), _target(cs._target), _cost(cs._cost), + _res_cap(cs._res_cap), _excess(cs._excess), _pi(cs._pi), + _pred(cs._pred), _dist(cs._node_num) + {} + + int run(int s, Value delta = 1) { + RangeMap heap_cross_ref(_node_num, Heap::PRE_HEAP); + Heap heap(heap_cross_ref); + heap.push(s, 0); + _pred[s] = -1; + _proc_nodes.clear(); + + // Process nodes + while (!heap.empty() && _excess[heap.top()] > -delta) { + int u = heap.top(), v; + Cost d = heap.prio() + _pi[u], dn; + _dist[u] = heap.prio(); + _proc_nodes.push_back(u); + heap.pop(); + + // Traverse outgoing residual arcs + int last_out = _geq ? _first_out[u+1] : _first_out[u+1] - 1; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] < delta) continue; + v = _target[a]; + switch (heap.state(v)) { + case Heap::PRE_HEAP: + heap.push(v, d + _cost[a] - _pi[v]); + _pred[v] = a; + break; + case Heap::IN_HEAP: + dn = d + _cost[a] - _pi[v]; + if (dn < heap[v]) { + heap.decrease(v, dn); + _pred[v] = a; + } + break; + case Heap::POST_HEAP: + break; + } + } + } + if (heap.empty()) return -1; + + // Update potentials of processed nodes + int t = heap.top(); + Cost dt = heap.prio(); + for (int i = 0; i < int(_proc_nodes.size()); ++i) { + _pi[_proc_nodes[i]] += _dist[_proc_nodes[i]] - dt; + } + + return t; + } + + }; //class ResidualDijkstra + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetHeapTraits : public Traits { + typedef T Heap; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c Heap type. + /// + /// \ref named-templ-param "Named parameter" for setting \c Heap + /// type, which is used for internal Dijkstra computations. + /// It must conform to the \ref lemon::concepts::Heap "Heap" concept, + /// its priority type must be \c Cost and its cross reference type + /// must be \ref RangeMap "RangeMap". + template + struct SetHeap + : public CapacityScaling > { + typedef CapacityScaling > Create; + }; + + /// @} + + protected: + + CapacityScaling() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param graph The digraph the algorithm runs on. + CapacityScaling(const GR& graph) : + _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + { + // Check the number types + LEMON_ASSERT(std::numeric_limits::is_signed, + "The flow type of CapacityScaling must be signed"); + LEMON_ASSERT(std::numeric_limits::is_signed, + "The cost type of CapacityScaling must be signed"); + + // Reset data structures + reset(); + } + + /// \name Parameters + /// The parameters of the algorithm can be specified using these + /// functions. + + /// @{ + + /// \brief Set the lower bounds on the arcs. + /// + /// This function sets the lower bounds on the arcs. + /// If it is not used before calling \ref run(), the lower bounds + /// will be set to zero on all arcs. + /// + /// \param map An arc map storing the lower bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CapacityScaling& lowerMap(const LowerMap& map) { + _have_lower = true; + for (ArcIt a(_graph); a != INVALID; ++a) { + _lower[_arc_idf[a]] = map[a]; + _lower[_arc_idb[a]] = map[a]; + } + return *this; + } + + /// \brief Set the upper bounds (capacities) on the arcs. + /// + /// This function sets the upper bounds (capacities) on the arcs. + /// If it is not used before calling \ref run(), the upper bounds + /// will be set to \ref INF on all arcs (i.e. the flow value will be + /// unbounded from above). + /// + /// \param map An arc map storing the upper bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CapacityScaling& upperMap(const UpperMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _upper[_arc_idf[a]] = map[a]; + } + return *this; + } + + /// \brief Set the costs of the arcs. + /// + /// This function sets the costs of the arcs. + /// If it is not used before calling \ref run(), the costs + /// will be set to \c 1 on all arcs. + /// + /// \param map An arc map storing the costs. + /// Its \c Value type must be convertible to the \c Cost type + /// of the algorithm. + /// + /// \return (*this) + template + CapacityScaling& costMap(const CostMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _cost[_arc_idf[a]] = map[a]; + _cost[_arc_idb[a]] = -map[a]; + } + return *this; + } + + /// \brief Set the supply values of the nodes. + /// + /// This function sets the supply values of the nodes. + /// If neither this function nor \ref stSupply() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// \param map A node map storing the supply values. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CapacityScaling& supplyMap(const SupplyMap& map) { + for (NodeIt n(_graph); n != INVALID; ++n) { + _supply[_node_id[n]] = map[n]; + } + return *this; + } + + /// \brief Set single source and target nodes and a supply value. + /// + /// This function sets a single source node and a single target node + /// and the required flow value. + /// If neither this function nor \ref supplyMap() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// Using this function has the same effect as using \ref supplyMap() + /// with such a map in which \c k is assigned to \c s, \c -k is + /// assigned to \c t and all other nodes have zero supply value. + /// + /// \param s The source node. + /// \param t The target node. + /// \param k The required amount of flow from node \c s to node \c t + /// (i.e. the supply of \c s and the demand of \c t). + /// + /// \return (*this) + CapacityScaling& stSupply(const Node& s, const Node& t, Value k) { + for (int i = 0; i != _node_num; ++i) { + _supply[i] = 0; + } + _supply[_node_id[s]] = k; + _supply[_node_id[t]] = -k; + return *this; + } + + /// @} + + /// \name Execution control + /// The algorithm can be executed using \ref run(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// The paramters can be specified using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// For example, + /// \code + /// CapacityScaling cs(graph); + /// cs.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// This function can be called more than once. All the given parameters + /// are kept for the next call, unless \ref resetParams() or \ref reset() + /// is used, thus only the modified parameters have to be set again. + /// If the underlying digraph was also modified after the construction + /// of the class (or the last \ref reset() call), then the \ref reset() + /// function must be called. + /// + /// \param factor The capacity scaling factor. It must be larger than + /// one to use scaling. If it is less or equal to one, then scaling + /// will be disabled. + /// + /// \return \c INFEASIBLE if no feasible flow exists, + /// \n \c OPTIMAL if the problem has optimal solution + /// (i.e. it is feasible and bounded), and the algorithm has found + /// optimal flow and node potentials (primal and dual solutions), + /// \n \c UNBOUNDED if the digraph contains an arc of negative cost + /// and infinite upper bound. It means that the objective function + /// is unbounded on that arc, however, note that it could actually be + /// bounded over the feasible flows, but this algroithm cannot handle + /// these cases. + /// + /// \see ProblemType + /// \see resetParams(), reset() + ProblemType run(int factor = 4) { + _factor = factor; + ProblemType pt = init(); + if (pt != OPTIMAL) return pt; + return start(); + } + + /// \brief Reset all the parameters that have been given before. + /// + /// This function resets all the paramaters that have been given + /// before using functions \ref lowerMap(), \ref upperMap(), + /// \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// For example, + /// \code + /// CapacityScaling cs(graph); + /// + /// // First run + /// cs.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// + /// // Run again with modified cost map (resetParams() is not called, + /// // so only the cost map have to be set again) + /// cost[e] += 100; + /// cs.costMap(cost).run(); + /// + /// // Run again from scratch using resetParams() + /// // (the lower bounds will be set to zero on all arcs) + /// cs.resetParams(); + /// cs.upperMap(capacity).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// \return (*this) + /// + /// \see reset(), run() + CapacityScaling& resetParams() { + for (int i = 0; i != _node_num; ++i) { + _supply[i] = 0; + } + for (int j = 0; j != _res_arc_num; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _cost[j] = _forward[j] ? 1 : -1; + } + _have_lower = false; + return *this; + } + + /// \brief Reset the internal data structures and all the parameters + /// that have been given before. + /// + /// This function resets the internal data structures and all the + /// paramaters that have been given before using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// See \ref resetParams() for examples. + /// + /// \return (*this) + /// + /// \see resetParams(), run() + CapacityScaling& reset() { + // Resize vectors + _node_num = countNodes(_graph); + _arc_num = countArcs(_graph); + _res_arc_num = 2 * (_arc_num + _node_num); + _root = _node_num; + ++_node_num; + + _first_out.resize(_node_num + 1); + _forward.resize(_res_arc_num); + _source.resize(_res_arc_num); + _target.resize(_res_arc_num); + _reverse.resize(_res_arc_num); + + _lower.resize(_res_arc_num); + _upper.resize(_res_arc_num); + _cost.resize(_res_arc_num); + _supply.resize(_node_num); + + _res_cap.resize(_res_arc_num); + _pi.resize(_node_num); + _excess.resize(_node_num); + _pred.resize(_node_num); + + // Copy the graph + int i = 0, j = 0, k = 2 * _arc_num + _node_num - 1; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _node_id[n] = i; + } + i = 0; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _first_out[i] = j; + for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idf[a] = j; + _forward[j] = true; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idb[a] = j; + _forward[j] = false; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + _forward[j] = false; + _source[j] = i; + _target[j] = _root; + _reverse[j] = k; + _forward[k] = true; + _source[k] = _root; + _target[k] = i; + _reverse[k] = j; + ++j; ++k; + } + _first_out[i] = j; + _first_out[_node_num] = k; + for (ArcIt a(_graph); a != INVALID; ++a) { + int fi = _arc_idf[a]; + int bi = _arc_idb[a]; + _reverse[fi] = bi; + _reverse[bi] = fi; + } + + // Reset parameters + resetParams(); + return *this; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The \ref run() function must be called before using them. + + /// @{ + + /// \brief Return the total cost of the found flow. + /// + /// This function returns the total cost of the found flow. + /// Its complexity is O(e). + /// + /// \note The return type of the function can be specified as a + /// template parameter. For example, + /// \code + /// cs.totalCost(); + /// \endcode + /// It is useful if the total cost cannot be stored in the \c Cost + /// type of the algorithm, which is the default return type of the + /// function. + /// + /// \pre \ref run() must be called before using this function. + template + Number totalCost() const { + Number c = 0; + for (ArcIt a(_graph); a != INVALID; ++a) { + int i = _arc_idb[a]; + c += static_cast(_res_cap[i]) * + (-static_cast(_cost[i])); + } + return c; + } + +#ifndef DOXYGEN + Cost totalCost() const { + return totalCost(); + } +#endif + + /// \brief Return the flow on the given arc. + /// + /// This function returns the flow on the given arc. + /// + /// \pre \ref run() must be called before using this function. + Value flow(const Arc& a) const { + return _res_cap[_arc_idb[a]]; + } + + /// \brief Return the flow map (the primal solution). + /// + /// This function copies the flow value on each arc into the given + /// map. The \c Value type of the algorithm must be convertible to + /// the \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void flowMap(FlowMap &map) const { + for (ArcIt a(_graph); a != INVALID; ++a) { + map.set(a, _res_cap[_arc_idb[a]]); + } + } + + /// \brief Return the potential (dual value) of the given node. + /// + /// This function returns the potential (dual value) of the + /// given node. + /// + /// \pre \ref run() must be called before using this function. + Cost potential(const Node& n) const { + return _pi[_node_id[n]]; + } + + /// \brief Return the potential map (the dual solution). + /// + /// This function copies the potential (dual value) of each node + /// into the given map. + /// The \c Cost type of the algorithm must be convertible to the + /// \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void potentialMap(PotentialMap &map) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + map.set(n, _pi[_node_id[n]]); + } + } + + /// @} + + private: + + // Initialize the algorithm + ProblemType init() { + if (_node_num <= 1) return INFEASIBLE; + + // Check the sum of supply values + _sum_supply = 0; + for (int i = 0; i != _root; ++i) { + _sum_supply += _supply[i]; + } + if (_sum_supply > 0) return INFEASIBLE; + + // Initialize vectors + for (int i = 0; i != _root; ++i) { + _pi[i] = 0; + _excess[i] = _supply[i]; + } + + // Remove non-zero lower bounds + const Value MAX = std::numeric_limits::max(); + int last_out; + if (_have_lower) { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j]) { + Value c = _lower[j]; + if (c >= 0) { + _res_cap[j] = _upper[j] < MAX ? _upper[j] - c : INF; + } else { + _res_cap[j] = _upper[j] < MAX + c ? _upper[j] - c : INF; + } + _excess[i] -= c; + _excess[_target[j]] += c; + } else { + _res_cap[j] = 0; + } + } + } + } else { + for (int j = 0; j != _res_arc_num; ++j) { + _res_cap[j] = _forward[j] ? _upper[j] : 0; + } + } + + // Handle negative costs + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1] - 1; + for (int j = _first_out[i]; j != last_out; ++j) { + Value rc = _res_cap[j]; + if (_cost[j] < 0 && rc > 0) { + if (rc >= MAX) return UNBOUNDED; + _excess[i] -= rc; + _excess[_target[j]] += rc; + _res_cap[j] = 0; + _res_cap[_reverse[j]] += rc; + } + } + } + + // Handle GEQ supply type + if (_sum_supply < 0) { + _pi[_root] = 0; + _excess[_root] = -_sum_supply; + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int ra = _reverse[a]; + _res_cap[a] = -_sum_supply + 1; + _res_cap[ra] = 0; + _cost[a] = 0; + _cost[ra] = 0; + } + } else { + _pi[_root] = 0; + _excess[_root] = 0; + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int ra = _reverse[a]; + _res_cap[a] = 1; + _res_cap[ra] = 0; + _cost[a] = 0; + _cost[ra] = 0; + } + } + + // Initialize delta value + if (_factor > 1) { + // With scaling + Value max_sup = 0, max_dem = 0, max_cap = 0; + for (int i = 0; i != _root; ++i) { + Value ex = _excess[i]; + if ( ex > max_sup) max_sup = ex; + if (-ex > max_dem) max_dem = -ex; + int last_out = _first_out[i+1] - 1; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_res_cap[j] > max_cap) max_cap = _res_cap[j]; + } + } + max_sup = std::min(std::min(max_sup, max_dem), max_cap); + for (_delta = 1; 2 * _delta <= max_sup; _delta *= 2) ; + } else { + // Without scaling + _delta = 1; + } + + return OPTIMAL; + } + + ProblemType start() { + // Execute the algorithm + ProblemType pt; + if (_delta > 1) + pt = startWithScaling(); + else + pt = startWithoutScaling(); + + // Handle non-zero lower bounds + if (_have_lower) { + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + if (!_forward[j]) _res_cap[j] += _lower[j]; + } + } + + // Shift potentials if necessary + Cost pr = _pi[_root]; + if (_sum_supply < 0 || pr > 0) { + for (int i = 0; i != _node_num; ++i) { + _pi[i] -= pr; + } + } + + return pt; + } + + // Execute the capacity scaling algorithm + ProblemType startWithScaling() { + // Perform capacity scaling phases + int s, t; + ResidualDijkstra _dijkstra(*this); + while (true) { + // Saturate all arcs not satisfying the optimality condition + int last_out; + for (int u = 0; u != _node_num; ++u) { + last_out = _sum_supply < 0 ? + _first_out[u+1] : _first_out[u+1] - 1; + for (int a = _first_out[u]; a != last_out; ++a) { + int v = _target[a]; + Cost c = _cost[a] + _pi[u] - _pi[v]; + Value rc = _res_cap[a]; + if (c < 0 && rc >= _delta) { + _excess[u] -= rc; + _excess[v] += rc; + _res_cap[a] = 0; + _res_cap[_reverse[a]] += rc; + } + } + } + + // Find excess nodes and deficit nodes + _excess_nodes.clear(); + _deficit_nodes.clear(); + for (int u = 0; u != _node_num; ++u) { + Value ex = _excess[u]; + if (ex >= _delta) _excess_nodes.push_back(u); + if (ex <= -_delta) _deficit_nodes.push_back(u); + } + int next_node = 0, next_def_node = 0; + + // Find augmenting shortest paths + while (next_node < int(_excess_nodes.size())) { + // Check deficit nodes + if (_delta > 1) { + bool delta_deficit = false; + for ( ; next_def_node < int(_deficit_nodes.size()); + ++next_def_node ) { + if (_excess[_deficit_nodes[next_def_node]] <= -_delta) { + delta_deficit = true; + break; + } + } + if (!delta_deficit) break; + } + + // Run Dijkstra in the residual network + s = _excess_nodes[next_node]; + if ((t = _dijkstra.run(s, _delta)) == -1) { + if (_delta > 1) { + ++next_node; + continue; + } + return INFEASIBLE; + } + + // Augment along a shortest path from s to t + Value d = std::min(_excess[s], -_excess[t]); + int u = t; + int a; + if (d > _delta) { + while ((a = _pred[u]) != -1) { + if (_res_cap[a] < d) d = _res_cap[a]; + u = _source[a]; + } + } + u = t; + while ((a = _pred[u]) != -1) { + _res_cap[a] -= d; + _res_cap[_reverse[a]] += d; + u = _source[a]; + } + _excess[s] -= d; + _excess[t] += d; + + if (_excess[s] < _delta) ++next_node; + } + + if (_delta == 1) break; + _delta = _delta <= _factor ? 1 : _delta / _factor; + } + + return OPTIMAL; + } + + // Execute the successive shortest path algorithm + ProblemType startWithoutScaling() { + // Find excess nodes + _excess_nodes.clear(); + for (int i = 0; i != _node_num; ++i) { + if (_excess[i] > 0) _excess_nodes.push_back(i); + } + if (_excess_nodes.size() == 0) return OPTIMAL; + int next_node = 0; + + // Find shortest paths + int s, t; + ResidualDijkstra _dijkstra(*this); + while ( _excess[_excess_nodes[next_node]] > 0 || + ++next_node < int(_excess_nodes.size()) ) + { + // Run Dijkstra in the residual network + s = _excess_nodes[next_node]; + if ((t = _dijkstra.run(s)) == -1) return INFEASIBLE; + + // Augment along a shortest path from s to t + Value d = std::min(_excess[s], -_excess[t]); + int u = t; + int a; + if (d > 1) { + while ((a = _pred[u]) != -1) { + if (_res_cap[a] < d) d = _res_cap[a]; + u = _source[a]; + } + } + u = t; + while ((a = _pred[u]) != -1) { + _res_cap[a] -= d; + _res_cap[_reverse[a]] += d; + u = _source[a]; + } + _excess[s] -= d; + _excess[t] += d; + } + + return OPTIMAL; + } + + }; //class CapacityScaling + + ///@} + +} //namespace lemon + +#endif //LEMON_CAPACITY_SCALING_H diff --git a/lemon/cbc.cc b/lemon/cbc.cc --- a/lemon/cbc.cc +++ b/lemon/cbc.cc @@ -94,6 +94,18 @@ return _prob->numberRows() - 1; } + int CbcMip::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) { + std::vector indexes; + std::vector values; + + for(ExprIterator it = b; it != e; ++it) { + indexes.push_back(it->first); + values.push_back(it->second); + } + + _prob->addRow(values.size(), &indexes.front(), &values.front(), l, u); + return _prob->numberRows() - 1; + } void CbcMip::_eraseCol(int i) { _prob->deleteColumn(i); diff --git a/lemon/cbc.h b/lemon/cbc.h --- a/lemon/cbc.h +++ b/lemon/cbc.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -62,6 +62,7 @@ virtual int _addCol(); virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); virtual void _eraseCol(int i); virtual void _eraseRow(int i); @@ -120,7 +121,7 @@ int _message_level; - + }; diff --git a/lemon/circulation.h b/lemon/circulation.h --- a/lemon/circulation.h +++ b/lemon/circulation.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -59,8 +59,8 @@ /// \brief The type of supply map. /// - /// The type of the map that stores the signed supply values of the - /// nodes. + /// The type of the map that stores the signed supply values of the + /// nodes. /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. typedef SM SupplyMap; @@ -72,7 +72,11 @@ /// The type of the map that stores the flow values. /// It must conform to the \ref concepts::ReadWriteMap "ReadWriteMap" /// concept. +#ifdef DOXYGEN + typedef GR::ArcMap FlowMap; +#else typedef typename Digraph::template ArcMap FlowMap; +#endif /// \brief Instantiates a FlowMap. /// @@ -87,9 +91,12 @@ /// /// The elevator type used by the algorithm. /// - /// \sa Elevator - /// \sa LinkedElevator + /// \sa Elevator, LinkedElevator +#ifdef DOXYGEN + typedef lemon::Elevator Elevator; +#else typedef lemon::Elevator Elevator; +#endif /// \brief Instantiates an Elevator. /// @@ -134,7 +141,7 @@ \f[ \sum_{uv\in A} f(uv) - \sum_{vu\in A} f(vu) \geq sup(u) \quad \forall u\in V, \f] \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A. \f] - + The sum of the supply values, i.e. \f$\sum_{u\in V} sup(u)\f$ must be zero or negative in order to have a feasible solution (since the sum of the expressions on the left-hand side of the inequalities is zero). @@ -144,7 +151,7 @@ If \f$\sum_{u\in V} sup(u)\f$ is zero, then all the supply/demand constraints have to be satisfied with equality, i.e. all demands have to be satisfied and all supplies have to be used. - + If you need the opposite inequalities in the supply/demand constraints (i.e. the total demand is less than the total supply and all the demands have to be satisfied while there could be supplies that are not used), @@ -166,6 +173,11 @@ The default map type is \c LM. \tparam SM The type of the supply map. The default map type is \ref concepts::Digraph::NodeMap "GR::NodeMap". + \tparam TR The traits class that defines various types used by the + algorithm. By default, it is \ref CirculationDefaultTraits + "CirculationDefaultTraits". + In most cases, this parameter should not be set directly, + consider to use the named template parameters instead. */ #ifdef DOXYGEN template< typename GR, @@ -299,7 +311,7 @@ /// The Elevator should have standard constructor interface to be /// able to automatically created by the algorithm (i.e. the /// digraph and the maximum level should be passed to it). - /// However an external elevator object could also be passed to the + /// However, an external elevator object could also be passed to the /// algorithm with the \ref elevator(Elevator&) "elevator()" function /// before calling \ref run() or \ref init(). /// \sa SetElevator @@ -325,7 +337,7 @@ /// /// \param graph The digraph the algorithm runs on. /// \param lower The lower bounds for the flow values on the arcs. - /// \param upper The upper bounds (capacities) for the flow values + /// \param upper The upper bounds (capacities) for the flow values /// on the arcs. /// \param supply The signed supply values of the nodes. Circulation(const Digraph &graph, const LowerMap &lower, @@ -450,9 +462,10 @@ return *_level; } - /// \brief Sets the tolerance used by algorithm. + /// \brief Sets the tolerance used by the algorithm. /// - /// Sets the tolerance used by algorithm. + /// Sets the tolerance object used by the algorithm. + /// \return (*this) Circulation& tolerance(const Tolerance& tolerance) { _tol = tolerance; return *this; @@ -460,15 +473,16 @@ /// \brief Returns a const reference to the tolerance. /// - /// Returns a const reference to the tolerance. + /// Returns a const reference to the tolerance object used by + /// the algorithm. const Tolerance& tolerance() const { return _tol; } /// \name Execution Control /// The simplest way to execute the algorithm is to call \ref run().\n - /// If you need more control on the initial solution or the execution, - /// first you have to call one of the \ref init() functions, then + /// If you need better control on the initial solution or the execution, + /// you have to call one of the \ref init() functions first, then /// the \ref start() function. ///@{ diff --git a/lemon/clp.cc b/lemon/clp.cc --- a/lemon/clp.cc +++ b/lemon/clp.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -78,6 +78,19 @@ return _prob->numberRows() - 1; } + int ClpLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) { + std::vector indexes; + std::vector values; + + for(ExprIterator it = b; it != e; ++it) { + indexes.push_back(it->first); + values.push_back(it->second); + } + + _prob->addRow(values.size(), &indexes.front(), &values.front(), l, u); + return _prob->numberRows() - 1; + } + void ClpLp::_eraseCol(int c) { _col_names_ref.erase(_prob->getColumnName(c)); diff --git a/lemon/clp.h b/lemon/clp.h --- a/lemon/clp.h +++ b/lemon/clp.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -75,6 +75,7 @@ virtual int _addCol(); virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); virtual void _eraseCol(int i); virtual void _eraseRow(int i); @@ -137,7 +138,7 @@ virtual void _clear(); virtual void _messageLevel(MessageLevel); - + public: ///Solves LP with primal simplex method. diff --git a/lemon/concepts/digraph.h b/lemon/concepts/digraph.h --- a/lemon/concepts/digraph.h +++ b/lemon/concepts/digraph.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -35,46 +35,40 @@ /// /// \brief Class describing the concept of directed graphs. /// - /// This class describes the \ref concept "concept" of the - /// immutable directed digraphs. + /// This class describes the common interface of all directed + /// graphs (digraphs). /// - /// Note that actual digraph implementation like @ref ListDigraph or - /// @ref SmartDigraph may have several additional functionality. + /// Like all concept classes, it only provides an interface + /// without any sensible implementation. So any general algorithm for + /// directed graphs should compile with this class, but it will not + /// run properly, of course. + /// An actual digraph implementation like \ref ListDigraph or + /// \ref SmartDigraph may have additional functionality. /// - /// \sa concept + /// \sa Graph class Digraph { private: - ///Digraphs are \e not copy constructible. Use DigraphCopy() instead. + /// Diraphs are \e not copy constructible. Use DigraphCopy instead. + Digraph(const Digraph &) {} + /// \brief Assignment of a digraph to another one is \e not allowed. + /// Use DigraphCopy instead. + void operator=(const Digraph &) {} - ///Digraphs are \e not copy constructible. Use DigraphCopy() instead. - /// - Digraph(const Digraph &) {}; - ///\brief Assignment of \ref Digraph "Digraph"s to another ones are - ///\e not allowed. Use DigraphCopy() instead. + public: + /// Default constructor. + Digraph() { } - ///Assignment of \ref Digraph "Digraph"s to another ones are - ///\e not allowed. Use DigraphCopy() instead. - - void operator=(const Digraph &) {} - public: - ///\e - - /// Defalult constructor. - - /// Defalult constructor. - /// - Digraph() { } - /// Class for identifying a node of the digraph + /// The node type of the digraph /// This class identifies a node of the digraph. It also serves /// as a base class of the node iterators, - /// thus they will convert to this type. + /// thus they convert to this type. class Node { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the object to an undefined value. Node() { } /// Copy constructor. @@ -82,40 +76,39 @@ /// Node(const Node&) { } - /// Invalid constructor \& conversion. + /// %Invalid constructor \& conversion. - /// This constructor initializes the iterator to be invalid. + /// Initializes the object to be invalid. /// \sa Invalid for more details. Node(Invalid) { } /// Equality operator + /// Equality operator. + /// /// Two iterators are equal if and only if they point to the - /// same object or both are invalid. + /// same object or both are \c INVALID. bool operator==(Node) const { return true; } /// Inequality operator - /// \sa operator==(Node n) - /// + /// Inequality operator. bool operator!=(Node) const { return true; } /// Artificial ordering operator. - /// To allow the use of digraph descriptors as key type in std::map or - /// similar associative container we require this. + /// Artificial ordering operator. /// - /// \note This operator only have to define some strict ordering of - /// the items; this order has nothing to do with the iteration - /// ordering of the items. + /// \note This operator only has to define some strict ordering of + /// the nodes; this order has nothing to do with the iteration + /// ordering of the nodes. bool operator<(Node) const { return false; } - }; - /// This iterator goes through each node. + /// Iterator class for the nodes. - /// This iterator goes through each node. - /// Its usage is quite simple, for example you can count the number - /// of nodes in digraph \c g of type \c Digraph like this: + /// This iterator goes through each node of the digraph. + /// Its usage is quite simple, for example, you can count the number + /// of nodes in a digraph \c g of type \c %Digraph like this: ///\code /// int count=0; /// for (Digraph::NodeIt n(g); n!=INVALID; ++n) ++count; @@ -124,30 +117,28 @@ public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. NodeIt() { } /// Copy constructor. /// Copy constructor. /// NodeIt(const NodeIt& n) : Node(n) { } - /// Invalid constructor \& conversion. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. /// \sa Invalid for more details. NodeIt(Invalid) { } /// Sets the iterator to the first node. - /// Sets the iterator to the first node of \c g. + /// Sets the iterator to the first node of the given digraph. /// - NodeIt(const Digraph&) { } - /// Node -> NodeIt conversion. + explicit NodeIt(const Digraph&) { } + /// Sets the iterator to the given node. - /// Sets the iterator to the node of \c the digraph pointed by - /// the trivial iterator. - /// This feature necessitates that each time we - /// iterate the arc-set, the iteration order is the same. + /// Sets the iterator to the given node of the given digraph. + /// NodeIt(const Digraph&, const Node&) { } /// Next node. @@ -157,7 +148,7 @@ }; - /// Class for identifying an arc of the digraph + /// The arc type of the digraph /// This class identifies an arc of the digraph. It also serves /// as a base class of the arc iterators, @@ -166,207 +157,214 @@ public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the object to an undefined value. Arc() { } /// Copy constructor. /// Copy constructor. /// Arc(const Arc&) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. - /// + /// Initializes the object to be invalid. + /// \sa Invalid for more details. Arc(Invalid) { } /// Equality operator + /// Equality operator. + /// /// Two iterators are equal if and only if they point to the - /// same object or both are invalid. + /// same object or both are \c INVALID. bool operator==(Arc) const { return true; } /// Inequality operator - /// \sa operator==(Arc n) - /// + /// Inequality operator. bool operator!=(Arc) const { return true; } /// Artificial ordering operator. - /// To allow the use of digraph descriptors as key type in std::map or - /// similar associative container we require this. + /// Artificial ordering operator. /// - /// \note This operator only have to define some strict ordering of - /// the items; this order has nothing to do with the iteration - /// ordering of the items. + /// \note This operator only has to define some strict ordering of + /// the arcs; this order has nothing to do with the iteration + /// ordering of the arcs. bool operator<(Arc) const { return false; } }; - /// This iterator goes trough the outgoing arcs of a node. + /// Iterator class for the outgoing arcs of a node. /// This iterator goes trough the \e outgoing arcs of a certain node /// of a digraph. - /// Its usage is quite simple, for example you can count the number + /// Its usage is quite simple, for example, you can count the number /// of outgoing arcs of a node \c n - /// in digraph \c g of type \c Digraph as follows. + /// in a digraph \c g of type \c %Digraph as follows. ///\code /// int count=0; - /// for (Digraph::OutArcIt e(g, n); e!=INVALID; ++e) ++count; + /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count; ///\endcode - class OutArcIt : public Arc { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. OutArcIt() { } /// Copy constructor. /// Copy constructor. /// OutArcIt(const OutArcIt& e) : Arc(e) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + OutArcIt(Invalid) { } + /// Sets the iterator to the first outgoing arc. + + /// Sets the iterator to the first outgoing arc of the given node. /// - OutArcIt(Invalid) { } - /// This constructor sets the iterator to the first outgoing arc. + OutArcIt(const Digraph&, const Node&) { } + /// Sets the iterator to the given arc. - /// This constructor sets the iterator to the first outgoing arc of - /// the node. - OutArcIt(const Digraph&, const Node&) { } - /// Arc -> OutArcIt conversion - - /// Sets the iterator to the value of the trivial iterator. - /// This feature necessitates that each time we - /// iterate the arc-set, the iteration order is the same. + /// Sets the iterator to the given arc of the given digraph. + /// OutArcIt(const Digraph&, const Arc&) { } - ///Next outgoing arc + /// Next outgoing arc /// Assign the iterator to the next /// outgoing arc of the corresponding node. OutArcIt& operator++() { return *this; } }; - /// This iterator goes trough the incoming arcs of a node. + /// Iterator class for the incoming arcs of a node. /// This iterator goes trough the \e incoming arcs of a certain node /// of a digraph. - /// Its usage is quite simple, for example you can count the number - /// of outgoing arcs of a node \c n - /// in digraph \c g of type \c Digraph as follows. + /// Its usage is quite simple, for example, you can count the number + /// of incoming arcs of a node \c n + /// in a digraph \c g of type \c %Digraph as follows. ///\code /// int count=0; - /// for(Digraph::InArcIt e(g, n); e!=INVALID; ++e) ++count; + /// for(Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count; ///\endcode - class InArcIt : public Arc { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. InArcIt() { } /// Copy constructor. /// Copy constructor. /// InArcIt(const InArcIt& e) : Arc(e) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + InArcIt(Invalid) { } + /// Sets the iterator to the first incoming arc. + + /// Sets the iterator to the first incoming arc of the given node. /// - InArcIt(Invalid) { } - /// This constructor sets the iterator to first incoming arc. + InArcIt(const Digraph&, const Node&) { } + /// Sets the iterator to the given arc. - /// This constructor set the iterator to the first incoming arc of - /// the node. - InArcIt(const Digraph&, const Node&) { } - /// Arc -> InArcIt conversion - - /// Sets the iterator to the value of the trivial iterator \c e. - /// This feature necessitates that each time we - /// iterate the arc-set, the iteration order is the same. + /// Sets the iterator to the given arc of the given digraph. + /// InArcIt(const Digraph&, const Arc&) { } /// Next incoming arc - /// Assign the iterator to the next inarc of the corresponding node. - /// + /// Assign the iterator to the next + /// incoming arc of the corresponding node. InArcIt& operator++() { return *this; } }; - /// This iterator goes through each arc. - /// This iterator goes through each arc of a digraph. - /// Its usage is quite simple, for example you can count the number - /// of arcs in a digraph \c g of type \c Digraph as follows: + /// Iterator class for the arcs. + + /// This iterator goes through each arc of the digraph. + /// Its usage is quite simple, for example, you can count the number + /// of arcs in a digraph \c g of type \c %Digraph as follows: ///\code /// int count=0; - /// for(Digraph::ArcIt e(g); e!=INVALID; ++e) ++count; + /// for(Digraph::ArcIt a(g); a!=INVALID; ++a) ++count; ///\endcode class ArcIt : public Arc { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. ArcIt() { } /// Copy constructor. /// Copy constructor. /// ArcIt(const ArcIt& e) : Arc(e) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + ArcIt(Invalid) { } + /// Sets the iterator to the first arc. + + /// Sets the iterator to the first arc of the given digraph. /// - ArcIt(Invalid) { } - /// This constructor sets the iterator to the first arc. + explicit ArcIt(const Digraph& g) { ignore_unused_variable_warning(g); } + /// Sets the iterator to the given arc. - /// This constructor sets the iterator to the first arc of \c g. - ///@param g the digraph - ArcIt(const Digraph& g) { ignore_unused_variable_warning(g); } - /// Arc -> ArcIt conversion - - /// Sets the iterator to the value of the trivial iterator \c e. - /// This feature necessitates that each time we - /// iterate the arc-set, the iteration order is the same. + /// Sets the iterator to the given arc of the given digraph. + /// ArcIt(const Digraph&, const Arc&) { } - ///Next arc + /// Next arc /// Assign the iterator to the next arc. + /// ArcIt& operator++() { return *this; } }; - ///Gives back the target node of an arc. - ///Gives back the target node of an arc. + /// \brief The source node of the arc. /// - Node target(Arc) const { return INVALID; } - ///Gives back the source node of an arc. - - ///Gives back the source node of an arc. - /// + /// Returns the source node of the given arc. Node source(Arc) const { return INVALID; } - /// \brief Returns the ID of the node. + /// \brief The target node of the arc. + /// + /// Returns the target node of the given arc. + Node target(Arc) const { return INVALID; } + + /// \brief The ID of the node. + /// + /// Returns the ID of the given node. int id(Node) const { return -1; } - /// \brief Returns the ID of the arc. + /// \brief The ID of the arc. + /// + /// Returns the ID of the given arc. int id(Arc) const { return -1; } - /// \brief Returns the node with the given ID. + /// \brief The node with the given ID. /// - /// \pre The argument should be a valid node ID in the graph. + /// Returns the node with the given ID. + /// \pre The argument should be a valid node ID in the digraph. Node nodeFromId(int) const { return INVALID; } - /// \brief Returns the arc with the given ID. + /// \brief The arc with the given ID. /// - /// \pre The argument should be a valid arc ID in the graph. + /// Returns the arc with the given ID. + /// \pre The argument should be a valid arc ID in the digraph. Arc arcFromId(int) const { return INVALID; } - /// \brief Returns an upper bound on the node IDs. + /// \brief An upper bound on the node IDs. + /// + /// Returns an upper bound on the node IDs. int maxNodeId() const { return -1; } - /// \brief Returns an upper bound on the arc IDs. + /// \brief An upper bound on the arc IDs. + /// + /// Returns an upper bound on the arc IDs. int maxArcId() const { return -1; } void first(Node&) const {} @@ -392,50 +390,51 @@ // Dummy parameter. int maxId(Arc) const { return -1; } + /// \brief The opposite node on the arc. + /// + /// Returns the opposite node on the given arc. + Node oppositeNode(Node, Arc) const { return INVALID; } + /// \brief The base node of the iterator. /// - /// Gives back the base node of the iterator. - /// It is always the target of the pointed arc. - Node baseNode(const InArcIt&) const { return INVALID; } + /// Returns the base node of the given outgoing arc iterator + /// (i.e. the source node of the corresponding arc). + Node baseNode(OutArcIt) const { return INVALID; } /// \brief The running node of the iterator. /// - /// Gives back the running node of the iterator. - /// It is always the source of the pointed arc. - Node runningNode(const InArcIt&) const { return INVALID; } + /// Returns the running node of the given outgoing arc iterator + /// (i.e. the target node of the corresponding arc). + Node runningNode(OutArcIt) const { return INVALID; } /// \brief The base node of the iterator. /// - /// Gives back the base node of the iterator. - /// It is always the source of the pointed arc. - Node baseNode(const OutArcIt&) const { return INVALID; } + /// Returns the base node of the given incomming arc iterator + /// (i.e. the target node of the corresponding arc). + Node baseNode(InArcIt) const { return INVALID; } /// \brief The running node of the iterator. /// - /// Gives back the running node of the iterator. - /// It is always the target of the pointed arc. - Node runningNode(const OutArcIt&) const { return INVALID; } + /// Returns the running node of the given incomming arc iterator + /// (i.e. the source node of the corresponding arc). + Node runningNode(InArcIt) const { return INVALID; } - /// \brief The opposite node on the given arc. + /// \brief Standard graph map type for the nodes. /// - /// Gives back the opposite node on the given arc. - Node oppositeNode(const Node&, const Arc&) const { return INVALID; } - - /// \brief Reference map of the nodes to type \c T. - /// - /// Reference map of the nodes to type \c T. + /// Standard graph map type for the nodes. + /// It conforms to the ReferenceMap concept. template class NodeMap : public ReferenceMap { public: - ///\e - NodeMap(const Digraph&) { } - ///\e + /// Constructor + explicit NodeMap(const Digraph&) { } + /// Constructor with given initial value NodeMap(const Digraph&, T) { } private: ///Copy constructor - NodeMap(const NodeMap& nm) : + NodeMap(const NodeMap& nm) : ReferenceMap(nm) { } ///Assignment operator template @@ -445,17 +444,19 @@ } }; - /// \brief Reference map of the arcs to type \c T. + /// \brief Standard graph map type for the arcs. /// - /// Reference map of the arcs to type \c T. + /// Standard graph map type for the arcs. + /// It conforms to the ReferenceMap concept. template class ArcMap : public ReferenceMap { public: - ///\e - ArcMap(const Digraph&) { } - ///\e + /// Constructor + explicit ArcMap(const Digraph&) { } + /// Constructor with given initial value ArcMap(const Digraph&, T) { } + private: ///Copy constructor ArcMap(const ArcMap& em) : diff --git a/lemon/concepts/graph.h b/lemon/concepts/graph.h --- a/lemon/concepts/graph.h +++ b/lemon/concepts/graph.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -18,12 +18,14 @@ ///\ingroup graph_concepts ///\file -///\brief The concept of Undirected Graphs. +///\brief The concept of undirected graphs. #ifndef LEMON_CONCEPTS_GRAPH_H #define LEMON_CONCEPTS_GRAPH_H #include +#include +#include #include namespace lemon { @@ -31,63 +33,74 @@ /// \ingroup graph_concepts /// - /// \brief Class describing the concept of Undirected Graphs. + /// \brief Class describing the concept of undirected graphs. /// - /// This class describes the common interface of all Undirected - /// Graphs. + /// This class describes the common interface of all undirected + /// graphs. /// - /// As all concept describing classes it provides only interface - /// without any sensible implementation. So any algorithm for - /// undirected graph should compile with this class, but it will not + /// Like all concept classes, it only provides an interface + /// without any sensible implementation. So any general algorithm for + /// undirected graphs should compile with this class, but it will not /// run properly, of course. + /// An actual graph implementation like \ref ListGraph or + /// \ref SmartGraph may have additional functionality. /// - /// The LEMON undirected graphs also fulfill the concept of - /// directed graphs (\ref lemon::concepts::Digraph "Digraph - /// Concept"). Each edges can be seen as two opposite - /// directed arc and consequently the undirected graph can be - /// seen as the direceted graph of these directed arcs. The - /// Graph has the Edge inner class for the edges and - /// the Arc type for the directed arcs. The Arc type is - /// convertible to Edge or inherited from it so from a directed - /// arc we can get the represented edge. + /// The undirected graphs also fulfill the concept of \ref Digraph + /// "directed graphs", since each edge can also be regarded as two + /// oppositely directed arcs. + /// Undirected graphs provide an Edge type for the undirected edges and + /// an Arc type for the directed arcs. The Arc type is convertible to + /// Edge or inherited from it, i.e. the corresponding edge can be + /// obtained from an arc. + /// EdgeIt and EdgeMap classes can be used for the edges, while ArcIt + /// and ArcMap classes can be used for the arcs (just like in digraphs). + /// Both InArcIt and OutArcIt iterates on the same edges but with + /// opposite direction. IncEdgeIt also iterates on the same edges + /// as OutArcIt and InArcIt, but it is not convertible to Arc, + /// only to Edge. /// - /// In the sense of the LEMON each edge has a default - /// direction (it should be in every computer implementation, - /// because the order of edge's nodes defines an - /// orientation). With the default orientation we can define that - /// the directed arc is forward or backward directed. With the \c - /// direction() and \c direct() function we can get the direction - /// of the directed arc and we can direct an edge. + /// In LEMON, each undirected edge has an inherent orientation. + /// Thus it can defined if an arc is forward or backward oriented in + /// an undirected graph with respect to this default oriantation of + /// the represented edge. + /// With the direction() and direct() functions the direction + /// of an arc can be obtained and set, respectively. /// - /// The EdgeIt is an iterator for the edges. We can use - /// the EdgeMap to map values for the edges. The InArcIt and - /// OutArcIt iterates on the same edges but with opposite - /// direction. The IncEdgeIt iterates also on the same edges - /// as the OutArcIt and InArcIt but it is not convertible to Arc just - /// to Edge. + /// Only nodes and edges can be added to or removed from an undirected + /// graph and the corresponding arcs are added or removed automatically. + /// + /// \sa Digraph class Graph { + private: + /// Graphs are \e not copy constructible. Use DigraphCopy instead. + Graph(const Graph&) {} + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use DigraphCopy instead. + void operator=(const Graph&) {} + public: - /// \brief The undirected graph should be tagged by the - /// UndirectedTag. + /// Default constructor. + Graph() {} + + /// \brief Undirected graphs should be tagged with \c UndirectedTag. /// - /// The undirected graph should be tagged by the UndirectedTag. This - /// tag helps the enable_if technics to make compile time + /// Undirected graphs should be tagged with \c UndirectedTag. + /// + /// This tag helps the \c enable_if technics to make compile time /// specializations for undirected graphs. typedef True UndirectedTag; - /// \brief The base type of node iterators, - /// or in other words, the trivial node iterator. - /// - /// This is the base type of each node iterator, - /// thus each kind of node iterator converts to this. - /// More precisely each kind of node iterator should be inherited - /// from the trivial node iterator. + /// The node type of the graph + + /// This class identifies a node of the graph. It also serves + /// as a base class of the node iterators, + /// thus they convert to this type. class Node { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the object to an undefined value. Node() { } /// Copy constructor. @@ -95,40 +108,40 @@ /// Node(const Node&) { } - /// Invalid constructor \& conversion. + /// %Invalid constructor \& conversion. - /// This constructor initializes the iterator to be invalid. + /// Initializes the object to be invalid. /// \sa Invalid for more details. Node(Invalid) { } /// Equality operator + /// Equality operator. + /// /// Two iterators are equal if and only if they point to the - /// same object or both are invalid. + /// same object or both are \c INVALID. bool operator==(Node) const { return true; } /// Inequality operator - /// \sa operator==(Node n) - /// + /// Inequality operator. bool operator!=(Node) const { return true; } /// Artificial ordering operator. - /// To allow the use of graph descriptors as key type in std::map or - /// similar associative container we require this. + /// Artificial ordering operator. /// - /// \note This operator only have to define some strict ordering of + /// \note This operator only has to define some strict ordering of /// the items; this order has nothing to do with the iteration /// ordering of the items. bool operator<(Node) const { return false; } }; - /// This iterator goes through each node. + /// Iterator class for the nodes. - /// This iterator goes through each node. - /// Its usage is quite simple, for example you can count the number - /// of nodes in graph \c g of type \c Graph like this: + /// This iterator goes through each node of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of nodes in a graph \c g of type \c %Graph like this: ///\code /// int count=0; /// for (Graph::NodeIt n(g); n!=INVALID; ++n) ++count; @@ -137,30 +150,28 @@ public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. NodeIt() { } /// Copy constructor. /// Copy constructor. /// NodeIt(const NodeIt& n) : Node(n) { } - /// Invalid constructor \& conversion. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. /// \sa Invalid for more details. NodeIt(Invalid) { } /// Sets the iterator to the first node. - /// Sets the iterator to the first node of \c g. + /// Sets the iterator to the first node of the given digraph. /// - NodeIt(const Graph&) { } - /// Node -> NodeIt conversion. + explicit NodeIt(const Graph&) { } + /// Sets the iterator to the given node. - /// Sets the iterator to the node of \c the graph pointed by - /// the trivial iterator. - /// This feature necessitates that each time we - /// iterate the arc-set, the iteration order is the same. + /// Sets the iterator to the given node of the given digraph. + /// NodeIt(const Graph&, const Node&) { } /// Next node. @@ -170,54 +181,55 @@ }; - /// The base type of the edge iterators. + /// The edge type of the graph - /// The base type of the edge iterators. - /// + /// This class identifies an edge of the graph. It also serves + /// as a base class of the edge iterators, + /// thus they will convert to this type. class Edge { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the object to an undefined value. Edge() { } /// Copy constructor. /// Copy constructor. /// Edge(const Edge&) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. - /// + /// Initializes the object to be invalid. + /// \sa Invalid for more details. Edge(Invalid) { } /// Equality operator + /// Equality operator. + /// /// Two iterators are equal if and only if they point to the - /// same object or both are invalid. + /// same object or both are \c INVALID. bool operator==(Edge) const { return true; } /// Inequality operator - /// \sa operator==(Edge n) - /// + /// Inequality operator. bool operator!=(Edge) const { return true; } /// Artificial ordering operator. - /// To allow the use of graph descriptors as key type in std::map or - /// similar associative container we require this. + /// Artificial ordering operator. /// - /// \note This operator only have to define some strict ordering of - /// the items; this order has nothing to do with the iteration - /// ordering of the items. + /// \note This operator only has to define some strict ordering of + /// the edges; this order has nothing to do with the iteration + /// ordering of the edges. bool operator<(Edge) const { return false; } }; - /// This iterator goes through each edge. + /// Iterator class for the edges. - /// This iterator goes through each edge of a graph. - /// Its usage is quite simple, for example you can count the number - /// of edges in a graph \c g of type \c Graph as follows: + /// This iterator goes through each edge of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of edges in a graph \c g of type \c %Graph as follows: ///\code /// int count=0; /// for(Graph::EdgeIt e(g); e!=INVALID; ++e) ++count; @@ -226,290 +238,285 @@ public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. EdgeIt() { } /// Copy constructor. /// Copy constructor. /// EdgeIt(const EdgeIt& e) : Edge(e) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + EdgeIt(Invalid) { } + /// Sets the iterator to the first edge. + + /// Sets the iterator to the first edge of the given graph. /// - EdgeIt(Invalid) { } - /// This constructor sets the iterator to the first edge. + explicit EdgeIt(const Graph&) { } + /// Sets the iterator to the given edge. - /// This constructor sets the iterator to the first edge. - EdgeIt(const Graph&) { } - /// Edge -> EdgeIt conversion - - /// Sets the iterator to the value of the trivial iterator. - /// This feature necessitates that each time we - /// iterate the edge-set, the iteration order is the - /// same. + /// Sets the iterator to the given edge of the given graph. + /// EdgeIt(const Graph&, const Edge&) { } /// Next edge /// Assign the iterator to the next edge. + /// EdgeIt& operator++() { return *this; } }; - /// \brief This iterator goes trough the incident undirected - /// arcs of a node. - /// - /// This iterator goes trough the incident edges - /// of a certain node of a graph. You should assume that the - /// loop arcs will be iterated twice. - /// - /// Its usage is quite simple, for example you can compute the - /// degree (i.e. count the number of incident arcs of a node \c n - /// in graph \c g of type \c Graph as follows. + /// Iterator class for the incident edges of a node. + + /// This iterator goes trough the incident undirected edges + /// of a certain node of a graph. + /// Its usage is quite simple, for example, you can compute the + /// degree (i.e. the number of incident edges) of a node \c n + /// in a graph \c g of type \c %Graph as follows. /// ///\code /// int count=0; /// for(Graph::IncEdgeIt e(g, n); e!=INVALID; ++e) ++count; ///\endcode + /// + /// \warning Loop edges will be iterated twice. class IncEdgeIt : public Edge { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. IncEdgeIt() { } /// Copy constructor. /// Copy constructor. /// IncEdgeIt(const IncEdgeIt& e) : Edge(e) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + IncEdgeIt(Invalid) { } + /// Sets the iterator to the first incident edge. + + /// Sets the iterator to the first incident edge of the given node. /// - IncEdgeIt(Invalid) { } - /// This constructor sets the iterator to first incident arc. + IncEdgeIt(const Graph&, const Node&) { } + /// Sets the iterator to the given edge. - /// This constructor set the iterator to the first incident arc of - /// the node. - IncEdgeIt(const Graph&, const Node&) { } - /// Edge -> IncEdgeIt conversion + /// Sets the iterator to the given edge of the given graph. + /// + IncEdgeIt(const Graph&, const Edge&) { } + /// Next incident edge - /// Sets the iterator to the value of the trivial iterator \c e. - /// This feature necessitates that each time we - /// iterate the arc-set, the iteration order is the same. - IncEdgeIt(const Graph&, const Edge&) { } - /// Next incident arc - - /// Assign the iterator to the next incident arc + /// Assign the iterator to the next incident edge /// of the corresponding node. IncEdgeIt& operator++() { return *this; } }; - /// The directed arc type. + /// The arc type of the graph - /// The directed arc type. It can be converted to the - /// edge or it should be inherited from the undirected - /// edge. + /// This class identifies a directed arc of the graph. It also serves + /// as a base class of the arc iterators, + /// thus they will convert to this type. class Arc { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the object to an undefined value. Arc() { } /// Copy constructor. /// Copy constructor. /// Arc(const Arc&) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. - /// + /// Initializes the object to be invalid. + /// \sa Invalid for more details. Arc(Invalid) { } /// Equality operator + /// Equality operator. + /// /// Two iterators are equal if and only if they point to the - /// same object or both are invalid. + /// same object or both are \c INVALID. bool operator==(Arc) const { return true; } /// Inequality operator - /// \sa operator==(Arc n) - /// + /// Inequality operator. bool operator!=(Arc) const { return true; } /// Artificial ordering operator. - /// To allow the use of graph descriptors as key type in std::map or - /// similar associative container we require this. + /// Artificial ordering operator. /// - /// \note This operator only have to define some strict ordering of - /// the items; this order has nothing to do with the iteration - /// ordering of the items. + /// \note This operator only has to define some strict ordering of + /// the arcs; this order has nothing to do with the iteration + /// ordering of the arcs. bool operator<(Arc) const { return false; } - /// Converison to Edge + /// Converison to \c Edge + + /// Converison to \c Edge. + /// operator Edge() const { return Edge(); } }; - /// This iterator goes through each directed arc. - /// This iterator goes through each arc of a graph. - /// Its usage is quite simple, for example you can count the number - /// of arcs in a graph \c g of type \c Graph as follows: + /// Iterator class for the arcs. + + /// This iterator goes through each directed arc of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of arcs in a graph \c g of type \c %Graph as follows: ///\code /// int count=0; - /// for(Graph::ArcIt e(g); e!=INVALID; ++e) ++count; + /// for(Graph::ArcIt a(g); a!=INVALID; ++a) ++count; ///\endcode class ArcIt : public Arc { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. ArcIt() { } /// Copy constructor. /// Copy constructor. /// ArcIt(const ArcIt& e) : Arc(e) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + ArcIt(Invalid) { } + /// Sets the iterator to the first arc. + + /// Sets the iterator to the first arc of the given graph. /// - ArcIt(Invalid) { } - /// This constructor sets the iterator to the first arc. + explicit ArcIt(const Graph &g) { ignore_unused_variable_warning(g); } + /// Sets the iterator to the given arc. - /// This constructor sets the iterator to the first arc of \c g. - ///@param g the graph - ArcIt(const Graph &g) { ignore_unused_variable_warning(g); } - /// Arc -> ArcIt conversion - - /// Sets the iterator to the value of the trivial iterator \c e. - /// This feature necessitates that each time we - /// iterate the arc-set, the iteration order is the same. + /// Sets the iterator to the given arc of the given graph. + /// ArcIt(const Graph&, const Arc&) { } - ///Next arc + /// Next arc /// Assign the iterator to the next arc. + /// ArcIt& operator++() { return *this; } }; - /// This iterator goes trough the outgoing directed arcs of a node. + /// Iterator class for the outgoing arcs of a node. - /// This iterator goes trough the \e outgoing arcs of a certain node - /// of a graph. - /// Its usage is quite simple, for example you can count the number + /// This iterator goes trough the \e outgoing directed arcs of a + /// certain node of a graph. + /// Its usage is quite simple, for example, you can count the number /// of outgoing arcs of a node \c n - /// in graph \c g of type \c Graph as follows. + /// in a graph \c g of type \c %Graph as follows. ///\code /// int count=0; - /// for (Graph::OutArcIt e(g, n); e!=INVALID; ++e) ++count; + /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count; ///\endcode - class OutArcIt : public Arc { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. OutArcIt() { } /// Copy constructor. /// Copy constructor. /// OutArcIt(const OutArcIt& e) : Arc(e) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + OutArcIt(Invalid) { } + /// Sets the iterator to the first outgoing arc. + + /// Sets the iterator to the first outgoing arc of the given node. /// - OutArcIt(Invalid) { } - /// This constructor sets the iterator to the first outgoing arc. - - /// This constructor sets the iterator to the first outgoing arc of - /// the node. - ///@param n the node - ///@param g the graph OutArcIt(const Graph& n, const Node& g) { ignore_unused_variable_warning(n); ignore_unused_variable_warning(g); } - /// Arc -> OutArcIt conversion + /// Sets the iterator to the given arc. - /// Sets the iterator to the value of the trivial iterator. - /// This feature necessitates that each time we - /// iterate the arc-set, the iteration order is the same. + /// Sets the iterator to the given arc of the given graph. + /// OutArcIt(const Graph&, const Arc&) { } - ///Next outgoing arc + /// Next outgoing arc /// Assign the iterator to the next /// outgoing arc of the corresponding node. OutArcIt& operator++() { return *this; } }; - /// This iterator goes trough the incoming directed arcs of a node. + /// Iterator class for the incoming arcs of a node. - /// This iterator goes trough the \e incoming arcs of a certain node - /// of a graph. - /// Its usage is quite simple, for example you can count the number - /// of outgoing arcs of a node \c n - /// in graph \c g of type \c Graph as follows. + /// This iterator goes trough the \e incoming directed arcs of a + /// certain node of a graph. + /// Its usage is quite simple, for example, you can count the number + /// of incoming arcs of a node \c n + /// in a graph \c g of type \c %Graph as follows. ///\code /// int count=0; - /// for(Graph::InArcIt e(g, n); e!=INVALID; ++e) ++count; + /// for (Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count; ///\endcode - class InArcIt : public Arc { public: /// Default constructor - /// @warning The default constructor sets the iterator - /// to an undefined value. + /// Default constructor. + /// \warning It sets the iterator to an undefined value. InArcIt() { } /// Copy constructor. /// Copy constructor. /// InArcIt(const InArcIt& e) : Arc(e) { } - /// Initialize the iterator to be invalid. + /// %Invalid constructor \& conversion. - /// Initialize the iterator to be invalid. + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + InArcIt(Invalid) { } + /// Sets the iterator to the first incoming arc. + + /// Sets the iterator to the first incoming arc of the given node. /// - InArcIt(Invalid) { } - /// This constructor sets the iterator to first incoming arc. - - /// This constructor set the iterator to the first incoming arc of - /// the node. - ///@param n the node - ///@param g the graph InArcIt(const Graph& g, const Node& n) { ignore_unused_variable_warning(n); ignore_unused_variable_warning(g); } - /// Arc -> InArcIt conversion + /// Sets the iterator to the given arc. - /// Sets the iterator to the value of the trivial iterator \c e. - /// This feature necessitates that each time we - /// iterate the arc-set, the iteration order is the same. + /// Sets the iterator to the given arc of the given graph. + /// InArcIt(const Graph&, const Arc&) { } /// Next incoming arc - /// Assign the iterator to the next inarc of the corresponding node. - /// + /// Assign the iterator to the next + /// incoming arc of the corresponding node. InArcIt& operator++() { return *this; } }; - /// \brief Reference map of the nodes to type \c T. + /// \brief Standard graph map type for the nodes. /// - /// Reference map of the nodes to type \c T. + /// Standard graph map type for the nodes. + /// It conforms to the ReferenceMap concept. template class NodeMap : public ReferenceMap { public: - ///\e - NodeMap(const Graph&) { } - ///\e + /// Constructor + explicit NodeMap(const Graph&) { } + /// Constructor with given initial value NodeMap(const Graph&, T) { } private: @@ -524,18 +531,20 @@ } }; - /// \brief Reference map of the arcs to type \c T. + /// \brief Standard graph map type for the arcs. /// - /// Reference map of the arcs to type \c T. + /// Standard graph map type for the arcs. + /// It conforms to the ReferenceMap concept. template class ArcMap : public ReferenceMap { public: - ///\e - ArcMap(const Graph&) { } - ///\e + /// Constructor + explicit ArcMap(const Graph&) { } + /// Constructor with given initial value ArcMap(const Graph&, T) { } + private: ///Copy constructor ArcMap(const ArcMap& em) : @@ -548,18 +557,20 @@ } }; - /// Reference map of the edges to type \c T. - - /// Reference map of the edges to type \c T. + /// \brief Standard graph map type for the edges. + /// + /// Standard graph map type for the edges. + /// It conforms to the ReferenceMap concept. template class EdgeMap : public ReferenceMap { public: - ///\e - EdgeMap(const Graph&) { } - ///\e + /// Constructor + explicit EdgeMap(const Graph&) { } + /// Constructor with given initial value EdgeMap(const Graph&, T) { } + private: ///Copy constructor EdgeMap(const EdgeMap& em) : @@ -572,107 +583,124 @@ } }; - /// \brief Direct the given edge. + /// \brief The first node of the edge. /// - /// Direct the given edge. The returned arc source - /// will be the given node. - Arc direct(const Edge&, const Node&) const { - return INVALID; - } - - /// \brief Direct the given edge. + /// Returns the first node of the given edge. /// - /// Direct the given edge. The returned arc - /// represents the given edge and the direction comes - /// from the bool parameter. The source of the edge and - /// the directed arc is the same when the given bool is true. - Arc direct(const Edge&, bool) const { - return INVALID; - } - - /// \brief Returns true if the arc has default orientation. - /// - /// Returns whether the given directed arc is same orientation as - /// the corresponding edge's default orientation. - bool direction(Arc) const { return true; } - - /// \brief Returns the opposite directed arc. - /// - /// Returns the opposite directed arc. - Arc oppositeArc(Arc) const { return INVALID; } - - /// \brief Opposite node on an arc - /// - /// \return The opposite of the given node on the given edge. - Node oppositeNode(Node, Edge) const { return INVALID; } - - /// \brief First node of the edge. - /// - /// \return The first node of the given edge. - /// - /// Naturally edges don't have direction and thus - /// don't have source and target node. However we use \c u() and \c v() - /// methods to query the two nodes of the arc. The direction of the - /// arc which arises this way is called the inherent direction of the - /// edge, and is used to define the "default" direction - /// of the directed versions of the arcs. + /// Edges don't have source and target nodes, however, methods + /// u() and v() are used to query the two end-nodes of an edge. + /// The orientation of an edge that arises this way is called + /// the inherent direction, it is used to define the default + /// direction for the corresponding arcs. /// \sa v() /// \sa direction() Node u(Edge) const { return INVALID; } - /// \brief Second node of the edge. + /// \brief The second node of the edge. /// - /// \return The second node of the given edge. + /// Returns the second node of the given edge. /// - /// Naturally edges don't have direction and thus - /// don't have source and target node. However we use \c u() and \c v() - /// methods to query the two nodes of the arc. The direction of the - /// arc which arises this way is called the inherent direction of the - /// edge, and is used to define the "default" direction - /// of the directed versions of the arcs. + /// Edges don't have source and target nodes, however, methods + /// u() and v() are used to query the two end-nodes of an edge. + /// The orientation of an edge that arises this way is called + /// the inherent direction, it is used to define the default + /// direction for the corresponding arcs. /// \sa u() /// \sa direction() Node v(Edge) const { return INVALID; } - /// \brief Source node of the directed arc. + /// \brief The source node of the arc. + /// + /// Returns the source node of the given arc. Node source(Arc) const { return INVALID; } - /// \brief Target node of the directed arc. + /// \brief The target node of the arc. + /// + /// Returns the target node of the given arc. Node target(Arc) const { return INVALID; } - /// \brief Returns the id of the node. + /// \brief The ID of the node. + /// + /// Returns the ID of the given node. int id(Node) const { return -1; } - /// \brief Returns the id of the edge. + /// \brief The ID of the edge. + /// + /// Returns the ID of the given edge. int id(Edge) const { return -1; } - /// \brief Returns the id of the arc. + /// \brief The ID of the arc. + /// + /// Returns the ID of the given arc. int id(Arc) const { return -1; } - /// \brief Returns the node with the given id. + /// \brief The node with the given ID. /// - /// \pre The argument should be a valid node id in the graph. + /// Returns the node with the given ID. + /// \pre The argument should be a valid node ID in the graph. Node nodeFromId(int) const { return INVALID; } - /// \brief Returns the edge with the given id. + /// \brief The edge with the given ID. /// - /// \pre The argument should be a valid edge id in the graph. + /// Returns the edge with the given ID. + /// \pre The argument should be a valid edge ID in the graph. Edge edgeFromId(int) const { return INVALID; } - /// \brief Returns the arc with the given id. + /// \brief The arc with the given ID. /// - /// \pre The argument should be a valid arc id in the graph. + /// Returns the arc with the given ID. + /// \pre The argument should be a valid arc ID in the graph. Arc arcFromId(int) const { return INVALID; } - /// \brief Returns an upper bound on the node IDs. + /// \brief An upper bound on the node IDs. + /// + /// Returns an upper bound on the node IDs. int maxNodeId() const { return -1; } - /// \brief Returns an upper bound on the edge IDs. + /// \brief An upper bound on the edge IDs. + /// + /// Returns an upper bound on the edge IDs. int maxEdgeId() const { return -1; } - /// \brief Returns an upper bound on the arc IDs. + /// \brief An upper bound on the arc IDs. + /// + /// Returns an upper bound on the arc IDs. int maxArcId() const { return -1; } + /// \brief The direction of the arc. + /// + /// Returns \c true if the direction of the given arc is the same as + /// the inherent orientation of the represented edge. + bool direction(Arc) const { return true; } + + /// \brief Direct the edge. + /// + /// Direct the given edge. The returned arc + /// represents the given edge and its direction comes + /// from the bool parameter. If it is \c true, then the direction + /// of the arc is the same as the inherent orientation of the edge. + Arc direct(Edge, bool) const { + return INVALID; + } + + /// \brief Direct the edge. + /// + /// Direct the given edge. The returned arc represents the given + /// edge and its source node is the given node. + Arc direct(Edge, Node) const { + return INVALID; + } + + /// \brief The oppositely directed arc. + /// + /// Returns the oppositely directed arc representing the same edge. + Arc oppositeArc(Arc) const { return INVALID; } + + /// \brief The opposite node on the edge. + /// + /// Returns the opposite node on the given edge. + Node oppositeNode(Node, Edge) const { return INVALID; } + void first(Node&) const {} void next(Node&) const {} @@ -705,47 +733,39 @@ // Dummy parameter. int maxId(Arc) const { return -1; } - /// \brief Base node of the iterator + /// \brief The base node of the iterator. /// - /// Returns the base node (the source in this case) of the iterator - Node baseNode(OutArcIt e) const { - return source(e); - } - /// \brief Running node of the iterator + /// Returns the base node of the given incident edge iterator. + Node baseNode(IncEdgeIt) const { return INVALID; } + + /// \brief The running node of the iterator. /// - /// Returns the running node (the target in this case) of the - /// iterator - Node runningNode(OutArcIt e) const { - return target(e); - } + /// Returns the running node of the given incident edge iterator. + Node runningNode(IncEdgeIt) const { return INVALID; } - /// \brief Base node of the iterator + /// \brief The base node of the iterator. /// - /// Returns the base node (the target in this case) of the iterator - Node baseNode(InArcIt e) const { - return target(e); - } - /// \brief Running node of the iterator + /// Returns the base node of the given outgoing arc iterator + /// (i.e. the source node of the corresponding arc). + Node baseNode(OutArcIt) const { return INVALID; } + + /// \brief The running node of the iterator. /// - /// Returns the running node (the source in this case) of the - /// iterator - Node runningNode(InArcIt e) const { - return source(e); - } + /// Returns the running node of the given outgoing arc iterator + /// (i.e. the target node of the corresponding arc). + Node runningNode(OutArcIt) const { return INVALID; } - /// \brief Base node of the iterator + /// \brief The base node of the iterator. /// - /// Returns the base node of the iterator - Node baseNode(IncEdgeIt) const { - return INVALID; - } + /// Returns the base node of the given incomming arc iterator + /// (i.e. the target node of the corresponding arc). + Node baseNode(InArcIt) const { return INVALID; } - /// \brief Running node of the iterator + /// \brief The running node of the iterator. /// - /// Returns the running node of the iterator - Node runningNode(IncEdgeIt) const { - return INVALID; - } + /// Returns the running node of the given incomming arc iterator + /// (i.e. the source node of the corresponding arc). + Node runningNode(InArcIt) const { return INVALID; } template struct Constraints { diff --git a/lemon/concepts/graph_components.h b/lemon/concepts/graph_components.h --- a/lemon/concepts/graph_components.h +++ b/lemon/concepts/graph_components.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -18,7 +18,7 @@ ///\ingroup graph_concepts ///\file -///\brief The concept of graph components. +///\brief The concepts of graph components. #ifndef LEMON_CONCEPTS_GRAPH_COMPONENTS_H #define LEMON_CONCEPTS_GRAPH_COMPONENTS_H @@ -38,7 +38,7 @@ /// /// \note This class is a template class so that we can use it to /// create graph skeleton classes. The reason for this is that \c Node - /// and \c Arc (or \c Edge) types should \e not derive from the same + /// and \c Arc (or \c Edge) types should \e not derive from the same /// base class. For \c Node you should instantiate it with character /// \c 'n', for \c Arc with \c 'a' and for \c Edge with \c 'e'. #ifndef DOXYGEN @@ -89,10 +89,10 @@ /// \brief Ordering operator. /// /// This operator defines an ordering of the items. - /// It makes possible to use graph item types as key types in + /// It makes possible to use graph item types as key types in /// associative containers (e.g. \c std::map). /// - /// \note This operator only have to define some strict ordering of + /// \note This operator only has to define some strict ordering of /// the items; this order has nothing to do with the iteration /// ordering of the items. bool operator<(const GraphItem&) const { return false; } @@ -122,7 +122,7 @@ /// /// This class describes the base interface of directed graph types. /// All digraph %concepts have to conform to this class. - /// It just provides types for nodes and arcs and functions + /// It just provides types for nodes and arcs and functions /// to get the source and the target nodes of arcs. class BaseDigraphComponent { public: @@ -426,7 +426,7 @@ /// \brief Concept class for \c NodeIt, \c ArcIt and \c EdgeIt types. /// - /// This class describes the concept of \c NodeIt, \c ArcIt and + /// This class describes the concept of \c NodeIt, \c ArcIt and /// \c EdgeIt subtypes of digraph and graph types. template class GraphItemIt : public Item { @@ -466,7 +466,7 @@ /// This operator increments the iterator, i.e. assigns it to the /// next item. GraphItemIt& operator++() { return *this; } - + /// \brief Equality operator /// /// Equality operator. @@ -501,15 +501,15 @@ }; }; - /// \brief Concept class for \c InArcIt, \c OutArcIt and + /// \brief Concept class for \c InArcIt, \c OutArcIt and /// \c IncEdgeIt types. /// - /// This class describes the concept of \c InArcIt, \c OutArcIt + /// This class describes the concept of \c InArcIt, \c OutArcIt /// and \c IncEdgeIt subtypes of digraph and graph types. /// /// \note Since these iterator classes do not inherit from the same /// base class, there is an additional template parameter (selector) - /// \c sel. For \c InArcIt you should instantiate it with character + /// \c sel. For \c InArcIt you should instantiate it with character /// \c 'i', for \c OutArcIt with \c 'o' and for \c IncEdgeIt with \c 'e'. template @@ -1045,7 +1045,7 @@ , _Map>(); _Map m1(g); _Map m2(g,t); - + // Copy constructor // _Map m3(m); @@ -1068,7 +1068,7 @@ /// \brief Skeleton class for mappable directed graphs. /// /// This class describes the interface of mappable directed graphs. - /// It extends \ref BaseDigraphComponent with the standard digraph + /// It extends \ref BaseDigraphComponent with the standard digraph /// map classes, namely \c NodeMap and \c ArcMap. /// This concept is part of the Digraph concept. template @@ -1205,7 +1205,7 @@ /// \brief Skeleton class for mappable undirected graphs. /// /// This class describes the interface of mappable undirected graphs. - /// It extends \ref MappableDigraphComponent with the standard graph + /// It extends \ref MappableDigraphComponent with the standard graph /// map class for edges (\c EdgeMap). /// This concept is part of the Graph concept. template @@ -1290,7 +1290,7 @@ /// \brief Skeleton class for extendable directed graphs. /// /// This class describes the interface of extendable directed graphs. - /// It extends \ref BaseDigraphComponent with functions for adding + /// It extends \ref BaseDigraphComponent with functions for adding /// nodes and arcs to the digraph. /// This concept requires \ref AlterableDigraphComponent. template @@ -1334,7 +1334,7 @@ /// \brief Skeleton class for extendable undirected graphs. /// /// This class describes the interface of extendable undirected graphs. - /// It extends \ref BaseGraphComponent with functions for adding + /// It extends \ref BaseGraphComponent with functions for adding /// nodes and edges to the graph. /// This concept requires \ref AlterableGraphComponent. template @@ -1378,7 +1378,7 @@ /// \brief Skeleton class for erasable directed graphs. /// /// This class describes the interface of erasable directed graphs. - /// It extends \ref BaseDigraphComponent with functions for removing + /// It extends \ref BaseDigraphComponent with functions for removing /// nodes and arcs from the digraph. /// This concept requires \ref AlterableDigraphComponent. template @@ -1391,7 +1391,7 @@ /// \brief Erase a node from the digraph. /// - /// This function erases the given node from the digraph and all arcs + /// This function erases the given node from the digraph and all arcs /// connected to the node. void erase(const Node&) {} @@ -1417,7 +1417,7 @@ /// \brief Skeleton class for erasable undirected graphs. /// /// This class describes the interface of erasable undirected graphs. - /// It extends \ref BaseGraphComponent with functions for removing + /// It extends \ref BaseGraphComponent with functions for removing /// nodes and edges from the graph. /// This concept requires \ref AlterableGraphComponent. template diff --git a/lemon/concepts/heap.h b/lemon/concepts/heap.h --- a/lemon/concepts/heap.h +++ b/lemon/concepts/heap.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -16,13 +16,13 @@ * */ +#ifndef LEMON_CONCEPTS_HEAP_H +#define LEMON_CONCEPTS_HEAP_H + ///\ingroup concept ///\file ///\brief The concept of heaps. -#ifndef LEMON_CONCEPTS_HEAP_H -#define LEMON_CONCEPTS_HEAP_H - #include #include @@ -35,21 +35,27 @@ /// \brief The heap concept. /// - /// Concept class describing the main interface of heaps. A \e heap - /// is a data structure for storing items with specified values called - /// \e priorities in such a way that finding the item with minimum - /// priority is efficient. In a heap one can change the priority of an - /// item, add or erase an item, etc. + /// This concept class describes the main interface of heaps. + /// The various \ref heaps "heap structures" are efficient + /// implementations of the abstract data type \e priority \e queue. + /// They store items with specified values called \e priorities + /// in such a way that finding and removing the item with minimum + /// priority are efficient. The basic operations are adding and + /// erasing items, changing the priority of an item, etc. /// - /// \tparam PR Type of the priority of the items. - /// \tparam IM A read and writable item map with int values, used + /// Heaps are crucial in several algorithms, such as Dijkstra and Prim. + /// Any class that conforms to this concept can be used easily in such + /// algorithms. + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used /// internally to handle the cross references. - /// \tparam Comp A functor class for the ordering of the priorities. + /// \tparam CMP A functor class for comparing the priorities. /// The default is \c std::less. #ifdef DOXYGEN - template > + template #else - template + template > #endif class Heap { public: @@ -64,109 +70,157 @@ /// \brief Type to represent the states of the items. /// /// Each item has a state associated to it. It can be "in heap", - /// "pre heap" or "post heap". The later two are indifferent - /// from the point of view of the heap, but may be useful for - /// the user. + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. /// /// The item-int map must be initialized in such way that it assigns /// \c PRE_HEAP (-1) to any element to be put in the heap. enum State { IN_HEAP = 0, ///< = 0. The "in heap" state constant. - PRE_HEAP = -1, ///< = -1. The "pre heap" state constant. - POST_HEAP = -2 ///< = -2. The "post heap" state constant. + PRE_HEAP = -1, ///< = -1. The "pre-heap" state constant. + POST_HEAP = -2 ///< = -2. The "post-heap" state constant. }; - /// \brief The constructor. + /// \brief Constructor. /// - /// The constructor. + /// Constructor. /// \param map A map that assigns \c int values to keys of type /// \c Item. It is used internally by the heap implementations to /// handle the cross references. The assigned value must be - /// \c PRE_HEAP (-1) for every item. + /// \c PRE_HEAP (-1) for each item. +#ifdef DOXYGEN explicit Heap(ItemIntMap &map) {} +#else + explicit Heap(ItemIntMap&) {} +#endif + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to keys of type + /// \c Item. It is used internally by the heap implementations to + /// handle the cross references. The assigned value must be + /// \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. +#ifdef DOXYGEN + explicit Heap(ItemIntMap &map, const CMP &comp) {} +#else + explicit Heap(ItemIntMap&, const CMP&) {} +#endif /// \brief The number of items stored in the heap. /// - /// Returns the number of items stored in the heap. + /// This function returns the number of items stored in the heap. int size() const { return 0; } - /// \brief Checks if the heap is empty. + /// \brief Check if the heap is empty. /// - /// Returns \c true if the heap is empty. + /// This function returns \c true if the heap is empty. bool empty() const { return false; } - /// \brief Makes the heap empty. + /// \brief Make the heap empty. /// - /// Makes the heap empty. - void clear(); + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() {} - /// \brief Inserts an item into the heap with the given priority. + /// \brief Insert an item into the heap with the given priority. /// - /// Inserts the given item into the heap with the given priority. + /// This function inserts the given item into the heap with the + /// given priority. /// \param i The item to insert. /// \param p The priority of the item. + /// \pre \e i must not be stored in the heap. +#ifdef DOXYGEN void push(const Item &i, const Prio &p) {} +#else + void push(const Item&, const Prio&) {} +#endif - /// \brief Returns the item having minimum priority. + /// \brief Return the item having minimum priority. /// - /// Returns the item having minimum priority. + /// This function returns the item having minimum priority. /// \pre The heap must be non-empty. - Item top() const {} + Item top() const { return Item(); } /// \brief The minimum priority. /// - /// Returns the minimum priority. + /// This function returns the minimum priority. /// \pre The heap must be non-empty. - Prio prio() const {} + Prio prio() const { return Prio(); } - /// \brief Removes the item having minimum priority. + /// \brief Remove the item having minimum priority. /// - /// Removes the item having minimum priority. + /// This function removes the item having minimum priority. /// \pre The heap must be non-empty. void pop() {} - /// \brief Removes an item from the heap. + /// \brief Remove the given item from the heap. /// - /// Removes the given item from the heap if it is already stored. + /// This function removes the given item from the heap if it is + /// already stored. /// \param i The item to delete. + /// \pre \e i must be in the heap. +#ifdef DOXYGEN void erase(const Item &i) {} +#else + void erase(const Item&) {} +#endif - /// \brief The priority of an item. + /// \brief The priority of the given item. /// - /// Returns the priority of the given item. + /// This function returns the priority of the given item. /// \param i The item. - /// \pre \c i must be in the heap. + /// \pre \e i must be in the heap. +#ifdef DOXYGEN Prio operator[](const Item &i) const {} +#else + Prio operator[](const Item&) const { return Prio(); } +#endif - /// \brief Sets the priority of an item or inserts it, if it is + /// \brief Set the priority of an item or insert it, if it is /// not stored in the heap. /// /// This method sets the priority of the given item if it is - /// already stored in the heap. - /// Otherwise it inserts the given item with the given priority. + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. /// /// \param i The item. /// \param p The priority. +#ifdef DOXYGEN void set(const Item &i, const Prio &p) {} +#else + void set(const Item&, const Prio&) {} +#endif - /// \brief Decreases the priority of an item to the given value. + /// \brief Decrease the priority of an item to the given value. /// - /// Decreases the priority of an item to the given value. + /// This function decreases the priority of an item to the given value. /// \param i The item. /// \param p The priority. - /// \pre \c i must be stored in the heap with priority at least \c p. + /// \pre \e i must be stored in the heap with priority at least \e p. +#ifdef DOXYGEN void decrease(const Item &i, const Prio &p) {} +#else + void decrease(const Item&, const Prio&) {} +#endif - /// \brief Increases the priority of an item to the given value. + /// \brief Increase the priority of an item to the given value. /// - /// Increases the priority of an item to the given value. + /// This function increases the priority of an item to the given value. /// \param i The item. /// \param p The priority. - /// \pre \c i must be stored in the heap with priority at most \c p. + /// \pre \e i must be stored in the heap with priority at most \e p. +#ifdef DOXYGEN void increase(const Item &i, const Prio &p) {} +#else + void increase(const Item&, const Prio&) {} +#endif - /// \brief Returns if an item is in, has already been in, or has - /// never been in the heap. + /// \brief Return the state of an item. /// /// This method returns \c PRE_HEAP if the given item has never /// been in the heap, \c IN_HEAP if it is in the heap at the moment, @@ -174,16 +228,24 @@ /// In the latter case it is possible that the item will get back /// to the heap again. /// \param i The item. +#ifdef DOXYGEN State state(const Item &i) const {} +#else + State state(const Item&) const { return PRE_HEAP; } +#endif - /// \brief Sets the state of an item in the heap. + /// \brief Set the state of an item in the heap. /// - /// Sets the state of the given item in the heap. It can be used - /// to manually clear the heap when it is important to achive the - /// better time complexity. + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. /// \param i The item. /// \param st The state. It should not be \c IN_HEAP. +#ifdef DOXYGEN void state(const Item& i, State st) {} +#else + void state(const Item&, State) {} +#endif template diff --git a/lemon/concepts/path.h b/lemon/concepts/path.h --- a/lemon/concepts/path.h +++ b/lemon/concepts/path.h @@ -18,7 +18,7 @@ ///\ingroup concept ///\file -///\brief Classes for representing paths in digraphs. +///\brief The concept of paths /// #ifndef LEMON_CONCEPTS_PATH_H @@ -38,13 +38,22 @@ /// /// A skeleton structure for representing directed paths in a /// digraph. + /// In a sense, a path can be treated as a list of arcs. + /// LEMON path types just store this list. As a consequence, they cannot + /// enumerate the nodes on the path directly and a zero length path + /// cannot store its source node. + /// + /// The arcs of a path should be stored in the order of their directions, + /// i.e. the target node of each arc should be the same as the source + /// node of the next arc. This consistency could be checked using + /// \ref checkPath(). + /// The source and target nodes of a (consistent) path can be obtained + /// using \ref pathSource() and \ref pathTarget(). + /// + /// A path can be constructed from another path of any type using the + /// copy constructor or the assignment operator. + /// /// \tparam GR The digraph type in which the path is. - /// - /// In a sense, the path can be treated as a list of arcs. The - /// lemon path type stores just this list. As a consequence it - /// cannot enumerate the nodes in the path and the zero length - /// paths cannot store the source. - /// template class Path { public: @@ -59,18 +68,18 @@ /// \brief Default constructor Path() {} - /// \brief Template constructor + /// \brief Template copy constructor template Path(const CPath& cpath) {} - /// \brief Template assigment + /// \brief Template assigment operator template Path& operator=(const CPath& cpath) { ignore_unused_variable_warning(cpath); return *this; } - /// Length of the path ie. the number of arcs in the path. + /// Length of the path, i.e. the number of arcs on the path. int length() const { return 0;} /// Returns whether the path is empty. @@ -79,19 +88,19 @@ /// Resets the path to an empty path. void clear() {} - /// \brief LEMON style iterator for path arcs + /// \brief LEMON style iterator for enumerating the arcs of a path. /// - /// This class is used to iterate on the arcs of the paths. + /// LEMON style iterator class for enumerating the arcs of a path. class ArcIt { public: /// Default constructor ArcIt() {} /// Invalid constructor ArcIt(Invalid) {} - /// Constructor for first arc + /// Sets the iterator to the first arc of the given path ArcIt(const Path &) {} - /// Conversion to Arc + /// Conversion to \c Arc operator Arc() const { return INVALID; } /// Next arc @@ -192,24 +201,18 @@ /// \brief A skeleton structure for path dumpers. /// /// A skeleton structure for path dumpers. The path dumpers are - /// the generalization of the paths. The path dumpers can - /// enumerate the arcs of the path wheter in forward or in - /// backward order. In most time these classes are not used - /// directly rather it used to assign a dumped class to a real - /// path type. + /// the generalization of the paths, they can enumerate the arcs + /// of the path either in forward or in backward order. + /// These classes are typically not used directly, they are rather + /// used to be assigned to a real path type. /// /// The main purpose of this concept is that the shortest path - /// algorithms can enumerate easily the arcs in reverse order. - /// If we would like to give back a real path from these - /// algorithms then we should create a temporarly path object. In - /// LEMON such algorithms gives back a path dumper what can - /// assigned to a real path and the dumpers can be implemented as + /// algorithms can enumerate the arcs easily in reverse order. + /// In LEMON, such algorithms give back a (reverse) path dumper that + /// can be assigned to a real path. The dumpers can be implemented as /// an adaptor class to the predecessor map. /// /// \tparam GR The digraph type in which the path is. - /// - /// The paths can be constructed from any path type by a - /// template constructor or a template assignment operator. template class PathDumper { public: @@ -219,7 +222,7 @@ /// Arc type of the underlying digraph. typedef typename Digraph::Arc Arc; - /// Length of the path ie. the number of arcs in the path. + /// Length of the path, i.e. the number of arcs on the path. int length() const { return 0;} /// Returns whether the path is empty. @@ -227,25 +230,24 @@ /// \brief Forward or reverse dumping /// - /// If the RevPathTag is defined and true then reverse dumping - /// is provided in the path dumper. In this case instead of the - /// ArcIt the RevArcIt iterator should be implemented in the - /// dumper. + /// If this tag is defined to be \c True, then reverse dumping + /// is provided in the path dumper. In this case, \c RevArcIt + /// iterator should be implemented instead of \c ArcIt iterator. typedef False RevPathTag; - /// \brief LEMON style iterator for path arcs + /// \brief LEMON style iterator for enumerating the arcs of a path. /// - /// This class is used to iterate on the arcs of the paths. + /// LEMON style iterator class for enumerating the arcs of a path. class ArcIt { public: /// Default constructor ArcIt() {} /// Invalid constructor ArcIt(Invalid) {} - /// Constructor for first arc + /// Sets the iterator to the first arc of the given path ArcIt(const PathDumper&) {} - /// Conversion to Arc + /// Conversion to \c Arc operator Arc() const { return INVALID; } /// Next arc @@ -260,20 +262,21 @@ }; - /// \brief LEMON style iterator for path arcs + /// \brief LEMON style iterator for enumerating the arcs of a path + /// in reverse direction. /// - /// This class is used to iterate on the arcs of the paths in - /// reverse direction. + /// LEMON style iterator class for enumerating the arcs of a path + /// in reverse direction. class RevArcIt { public: /// Default constructor RevArcIt() {} /// Invalid constructor RevArcIt(Invalid) {} - /// Constructor for first arc + /// Sets the iterator to the last arc of the given path RevArcIt(const PathDumper &) {} - /// Conversion to Arc + /// Conversion to \c Arc operator Arc() const { return INVALID; } /// Next arc diff --git a/lemon/connectivity.h b/lemon/connectivity.h --- a/lemon/connectivity.h +++ b/lemon/connectivity.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -258,7 +258,7 @@ /// /// \return \c true if the digraph is strongly connected. /// \note By definition, the empty digraph is strongly connected. - /// + /// /// \see countStronglyConnectedComponents(), stronglyConnectedComponents() /// \see connected() template @@ -310,7 +310,7 @@ /// \ingroup graph_properties /// - /// \brief Count the number of strongly connected components of a + /// \brief Count the number of strongly connected components of a /// directed graph /// /// This function counts the number of strongly connected components of @@ -744,7 +744,7 @@ /// /// \brief Check whether an undirected graph is bi-node-connected. /// - /// This function checks whether the given undirected graph is + /// This function checks whether the given undirected graph is /// bi-node-connected, i.e. any two edges are on same circle. /// /// \return \c true if the graph bi-node-connected. @@ -758,7 +758,7 @@ /// \ingroup graph_properties /// - /// \brief Count the number of bi-node-connected components of an + /// \brief Count the number of bi-node-connected components of an /// undirected graph. /// /// This function counts the number of bi-node-connected components of @@ -812,7 +812,7 @@ /// \param graph The undirected graph. /// \retval compMap A writable edge map. The values will be set from 0 /// to the number of the bi-node-connected components minus one. Each - /// value of the map will be set exactly once, and the values of a + /// value of the map will be set exactly once, and the values of a /// certain component will be set continuously. /// \return The number of bi-node-connected components. /// @@ -858,7 +858,7 @@ /// the components. /// /// \param graph The undirected graph. - /// \retval cutMap A writable node map. The values will be set to + /// \retval cutMap A writable node map. The values will be set to /// \c true for the nodes that separate two or more components /// (exactly once for each cut node), and will not be changed for /// other nodes. @@ -1085,7 +1085,7 @@ /// /// \brief Check whether an undirected graph is bi-edge-connected. /// - /// This function checks whether the given undirected graph is + /// This function checks whether the given undirected graph is /// bi-edge-connected, i.e. any two nodes are connected with at least /// two edge-disjoint paths. /// @@ -1192,7 +1192,7 @@ /// \brief Find the bi-edge-connected cut edges in an undirected graph. /// /// This function finds the bi-edge-connected cut edges in the given - /// undirected graph. + /// undirected graph. /// /// The bi-edge-connected components are the classes of an equivalence /// relation on the nodes of an undirected graph. Two nodes are in the @@ -1349,7 +1349,7 @@ /// /// \param digraph The digraph. /// \retval order A readable and writable node map. The values will be - /// set from 0 to the number of the nodes in the digraph minus one. + /// set from 0 to the number of the nodes in the digraph minus one. /// Each value of the map will be set exactly once, and the values will /// be set descending order. /// \return \c false if the digraph is not DAG. diff --git a/lemon/core.h b/lemon/core.h --- a/lemon/core.h +++ b/lemon/core.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -1241,7 +1241,8 @@ protected: - class AutoNodeMap : public ItemSetTraits::template Map::Type { + class AutoNodeMap : public ItemSetTraits::template Map::Type + { typedef typename ItemSetTraits::template Map::Type Parent; public: @@ -1280,7 +1281,7 @@ } }; - protected: + protected: const Digraph &_g; AutoNodeMap _head; diff --git a/lemon/cost_scaling.h b/lemon/cost_scaling.h new file mode 100644 --- /dev/null +++ b/lemon/cost_scaling.h @@ -0,0 +1,1316 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_COST_SCALING_H +#define LEMON_COST_SCALING_H + +/// \ingroup min_cost_flow_algs +/// \file +/// \brief Cost scaling algorithm for finding a minimum cost flow. + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of CostScaling algorithm. + /// + /// Default traits class of CostScaling algorithm. + /// \tparam GR Digraph type. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values. By default it is \c int. + /// \tparam C The number type used for costs and potentials. + /// By default it is the same as \c V. +#ifdef DOXYGEN + template +#else + template < typename GR, typename V = int, typename C = V, + bool integer = std::numeric_limits::is_integer > +#endif + struct CostScalingDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef V Value; + /// The type of the arc costs + typedef C Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + }; + + // Default traits class for integer cost types + template + struct CostScalingDefaultTraits + { + typedef GR Digraph; + typedef V Value; + typedef C Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + }; + + + /// \addtogroup min_cost_flow_algs + /// @{ + + /// \brief Implementation of the Cost Scaling algorithm for + /// finding a \ref min_cost_flow "minimum cost flow". + /// + /// \ref CostScaling implements a cost scaling algorithm that performs + /// push/augment and relabel operations for finding a \ref min_cost_flow + /// "minimum cost flow" \ref amo93networkflows, \ref goldberg90approximation, + /// \ref goldberg97efficient, \ref bunnagel98efficient. + /// It is a highly efficient primal-dual solution method, which + /// can be viewed as the generalization of the \ref Preflow + /// "preflow push-relabel" algorithm for the maximum flow problem. + /// + /// Most of the parameters of the problem (except for the digraph) + /// can be given using separate functions, and the algorithm can be + /// executed using the \ref run() function. If some parameters are not + /// specified, then default values will be used. + /// + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values in the algorithm. By default, it is \c int. + /// \tparam C The number type used for costs and potentials in the + /// algorithm. By default, it is the same as \c V. + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref CostScalingDefaultTraits + /// "CostScalingDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. + /// + /// \warning Both number types must be signed and all input data must + /// be integer. + /// \warning This algorithm does not support negative costs for such + /// arcs that have infinite upper bound. + /// + /// \note %CostScaling provides three different internal methods, + /// from which the most efficient one is used by default. + /// For more information, see \ref Method. +#ifdef DOXYGEN + template +#else + template < typename GR, typename V = int, typename C = V, + typename TR = CostScalingDefaultTraits > +#endif + class CostScaling + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef typename TR::Value Value; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The \ref CostScalingDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + public: + + /// \brief Problem type constants for the \c run() function. + /// + /// Enum type containing the problem type constants that can be + /// returned by the \ref run() function of the algorithm. + enum ProblemType { + /// The problem has no feasible solution (flow). + INFEASIBLE, + /// The problem has optimal solution (i.e. it is feasible and + /// bounded), and the algorithm has found optimal flow and node + /// potentials (primal and dual solutions). + OPTIMAL, + /// The digraph contains an arc of negative cost and infinite + /// upper bound. It means that the objective function is unbounded + /// on that arc, however, note that it could actually be bounded + /// over the feasible flows, but this algroithm cannot handle + /// these cases. + UNBOUNDED + }; + + /// \brief Constants for selecting the internal method. + /// + /// Enum type containing constants for selecting the internal method + /// for the \ref run() function. + /// + /// \ref CostScaling provides three internal methods that differ mainly + /// in their base operations, which are used in conjunction with the + /// relabel operation. + /// By default, the so called \ref PARTIAL_AUGMENT + /// "Partial Augment-Relabel" method is used, which proved to be + /// the most efficient and the most robust on various test inputs. + /// However, the other methods can be selected using the \ref run() + /// function with the proper parameter. + enum Method { + /// Local push operations are used, i.e. flow is moved only on one + /// admissible arc at once. + PUSH, + /// Augment operations are used, i.e. flow is moved on admissible + /// paths from a node with excess to a node with deficit. + AUGMENT, + /// Partial augment operations are used, i.e. flow is moved on + /// admissible paths started from a node with excess, but the + /// lengths of these paths are limited. This method can be viewed + /// as a combined version of the previous two operations. + PARTIAL_AUGMENT + }; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typedef std::vector IntVector; + typedef std::vector ValueVector; + typedef std::vector CostVector; + typedef std::vector LargeCostVector; + typedef std::vector BoolVector; + // Note: vector is used instead of vector for efficiency reasons + + private: + + template + class StaticVectorMap { + public: + typedef KT Key; + typedef VT Value; + + StaticVectorMap(std::vector& v) : _v(v) {} + + const Value& operator[](const Key& key) const { + return _v[StaticDigraph::id(key)]; + } + + Value& operator[](const Key& key) { + return _v[StaticDigraph::id(key)]; + } + + void set(const Key& key, const Value& val) { + _v[StaticDigraph::id(key)] = val; + } + + private: + std::vector& _v; + }; + + typedef StaticVectorMap LargeCostNodeMap; + typedef StaticVectorMap LargeCostArcMap; + + private: + + // Data related to the underlying digraph + const GR &_graph; + int _node_num; + int _arc_num; + int _res_node_num; + int _res_arc_num; + int _root; + + // Parameters of the problem + bool _have_lower; + Value _sum_supply; + int _sup_node_num; + + // Data structures for storing the digraph + IntNodeMap _node_id; + IntArcMap _arc_idf; + IntArcMap _arc_idb; + IntVector _first_out; + BoolVector _forward; + IntVector _source; + IntVector _target; + IntVector _reverse; + + // Node and arc data + ValueVector _lower; + ValueVector _upper; + CostVector _scost; + ValueVector _supply; + + ValueVector _res_cap; + LargeCostVector _cost; + LargeCostVector _pi; + ValueVector _excess; + IntVector _next_out; + std::deque _active_nodes; + + // Data for scaling + LargeCost _epsilon; + int _alpha; + + IntVector _buckets; + IntVector _bucket_next; + IntVector _bucket_prev; + IntVector _rank; + int _max_rank; + + // Data for a StaticDigraph structure + typedef std::pair IntPair; + StaticDigraph _sgr; + std::vector _arc_vec; + std::vector _cost_vec; + LargeCostArcMap _cost_map; + LargeCostNodeMap _pi_map; + + public: + + /// \brief Constant for infinite upper bounds (capacities). + /// + /// Constant for infinite upper bounds (capacities). + /// It is \c std::numeric_limits::infinity() if available, + /// \c std::numeric_limits::max() otherwise. + const Value INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type, which is used for internal computations in the algorithm. + /// \c Cost must be convertible to \c LargeCost. + template + struct SetLargeCost + : public CostScaling > { + typedef CostScaling > Create; + }; + + /// @} + + protected: + + CostScaling() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param graph The digraph the algorithm runs on. + CostScaling(const GR& graph) : + _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), + _cost_map(_cost_vec), _pi_map(_pi), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + { + // Check the number types + LEMON_ASSERT(std::numeric_limits::is_signed, + "The flow type of CostScaling must be signed"); + LEMON_ASSERT(std::numeric_limits::is_signed, + "The cost type of CostScaling must be signed"); + + // Reset data structures + reset(); + } + + /// \name Parameters + /// The parameters of the algorithm can be specified using these + /// functions. + + /// @{ + + /// \brief Set the lower bounds on the arcs. + /// + /// This function sets the lower bounds on the arcs. + /// If it is not used before calling \ref run(), the lower bounds + /// will be set to zero on all arcs. + /// + /// \param map An arc map storing the lower bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CostScaling& lowerMap(const LowerMap& map) { + _have_lower = true; + for (ArcIt a(_graph); a != INVALID; ++a) { + _lower[_arc_idf[a]] = map[a]; + _lower[_arc_idb[a]] = map[a]; + } + return *this; + } + + /// \brief Set the upper bounds (capacities) on the arcs. + /// + /// This function sets the upper bounds (capacities) on the arcs. + /// If it is not used before calling \ref run(), the upper bounds + /// will be set to \ref INF on all arcs (i.e. the flow value will be + /// unbounded from above). + /// + /// \param map An arc map storing the upper bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CostScaling& upperMap(const UpperMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _upper[_arc_idf[a]] = map[a]; + } + return *this; + } + + /// \brief Set the costs of the arcs. + /// + /// This function sets the costs of the arcs. + /// If it is not used before calling \ref run(), the costs + /// will be set to \c 1 on all arcs. + /// + /// \param map An arc map storing the costs. + /// Its \c Value type must be convertible to the \c Cost type + /// of the algorithm. + /// + /// \return (*this) + template + CostScaling& costMap(const CostMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _scost[_arc_idf[a]] = map[a]; + _scost[_arc_idb[a]] = -map[a]; + } + return *this; + } + + /// \brief Set the supply values of the nodes. + /// + /// This function sets the supply values of the nodes. + /// If neither this function nor \ref stSupply() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// \param map A node map storing the supply values. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CostScaling& supplyMap(const SupplyMap& map) { + for (NodeIt n(_graph); n != INVALID; ++n) { + _supply[_node_id[n]] = map[n]; + } + return *this; + } + + /// \brief Set single source and target nodes and a supply value. + /// + /// This function sets a single source node and a single target node + /// and the required flow value. + /// If neither this function nor \ref supplyMap() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// Using this function has the same effect as using \ref supplyMap() + /// with such a map in which \c k is assigned to \c s, \c -k is + /// assigned to \c t and all other nodes have zero supply value. + /// + /// \param s The source node. + /// \param t The target node. + /// \param k The required amount of flow from node \c s to node \c t + /// (i.e. the supply of \c s and the demand of \c t). + /// + /// \return (*this) + CostScaling& stSupply(const Node& s, const Node& t, Value k) { + for (int i = 0; i != _res_node_num; ++i) { + _supply[i] = 0; + } + _supply[_node_id[s]] = k; + _supply[_node_id[t]] = -k; + return *this; + } + + /// @} + + /// \name Execution control + /// The algorithm can be executed using \ref run(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// The paramters can be specified using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// For example, + /// \code + /// CostScaling cs(graph); + /// cs.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// This function can be called more than once. All the given parameters + /// are kept for the next call, unless \ref resetParams() or \ref reset() + /// is used, thus only the modified parameters have to be set again. + /// If the underlying digraph was also modified after the construction + /// of the class (or the last \ref reset() call), then the \ref reset() + /// function must be called. + /// + /// \param method The internal method that will be used in the + /// algorithm. For more information, see \ref Method. + /// \param factor The cost scaling factor. It must be larger than one. + /// + /// \return \c INFEASIBLE if no feasible flow exists, + /// \n \c OPTIMAL if the problem has optimal solution + /// (i.e. it is feasible and bounded), and the algorithm has found + /// optimal flow and node potentials (primal and dual solutions), + /// \n \c UNBOUNDED if the digraph contains an arc of negative cost + /// and infinite upper bound. It means that the objective function + /// is unbounded on that arc, however, note that it could actually be + /// bounded over the feasible flows, but this algroithm cannot handle + /// these cases. + /// + /// \see ProblemType, Method + /// \see resetParams(), reset() + ProblemType run(Method method = PARTIAL_AUGMENT, int factor = 8) { + _alpha = factor; + ProblemType pt = init(); + if (pt != OPTIMAL) return pt; + start(method); + return OPTIMAL; + } + + /// \brief Reset all the parameters that have been given before. + /// + /// This function resets all the paramaters that have been given + /// before using functions \ref lowerMap(), \ref upperMap(), + /// \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// For example, + /// \code + /// CostScaling cs(graph); + /// + /// // First run + /// cs.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// + /// // Run again with modified cost map (resetParams() is not called, + /// // so only the cost map have to be set again) + /// cost[e] += 100; + /// cs.costMap(cost).run(); + /// + /// // Run again from scratch using resetParams() + /// // (the lower bounds will be set to zero on all arcs) + /// cs.resetParams(); + /// cs.upperMap(capacity).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// \return (*this) + /// + /// \see reset(), run() + CostScaling& resetParams() { + for (int i = 0; i != _res_node_num; ++i) { + _supply[i] = 0; + } + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _scost[j] = _forward[j] ? 1 : -1; + } + for (int j = limit; j != _res_arc_num; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _scost[j] = 0; + _scost[_reverse[j]] = 0; + } + _have_lower = false; + return *this; + } + + /// \brief Reset all the parameters that have been given before. + /// + /// This function resets all the paramaters that have been given + /// before using functions \ref lowerMap(), \ref upperMap(), + /// \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple run() calls. If this function is not + /// used, all the parameters given before are kept for the next + /// \ref run() call. + /// However, the underlying digraph must not be modified after this + /// class have been constructed, since it copies and extends the graph. + /// \return (*this) + CostScaling& reset() { + // Resize vectors + _node_num = countNodes(_graph); + _arc_num = countArcs(_graph); + _res_node_num = _node_num + 1; + _res_arc_num = 2 * (_arc_num + _node_num); + _root = _node_num; + + _first_out.resize(_res_node_num + 1); + _forward.resize(_res_arc_num); + _source.resize(_res_arc_num); + _target.resize(_res_arc_num); + _reverse.resize(_res_arc_num); + + _lower.resize(_res_arc_num); + _upper.resize(_res_arc_num); + _scost.resize(_res_arc_num); + _supply.resize(_res_node_num); + + _res_cap.resize(_res_arc_num); + _cost.resize(_res_arc_num); + _pi.resize(_res_node_num); + _excess.resize(_res_node_num); + _next_out.resize(_res_node_num); + + _arc_vec.reserve(_res_arc_num); + _cost_vec.reserve(_res_arc_num); + + // Copy the graph + int i = 0, j = 0, k = 2 * _arc_num + _node_num; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _node_id[n] = i; + } + i = 0; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _first_out[i] = j; + for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idf[a] = j; + _forward[j] = true; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idb[a] = j; + _forward[j] = false; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + _forward[j] = false; + _source[j] = i; + _target[j] = _root; + _reverse[j] = k; + _forward[k] = true; + _source[k] = _root; + _target[k] = i; + _reverse[k] = j; + ++j; ++k; + } + _first_out[i] = j; + _first_out[_res_node_num] = k; + for (ArcIt a(_graph); a != INVALID; ++a) { + int fi = _arc_idf[a]; + int bi = _arc_idb[a]; + _reverse[fi] = bi; + _reverse[bi] = fi; + } + + // Reset parameters + resetParams(); + return *this; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The \ref run() function must be called before using them. + + /// @{ + + /// \brief Return the total cost of the found flow. + /// + /// This function returns the total cost of the found flow. + /// Its complexity is O(e). + /// + /// \note The return type of the function can be specified as a + /// template parameter. For example, + /// \code + /// cs.totalCost(); + /// \endcode + /// It is useful if the total cost cannot be stored in the \c Cost + /// type of the algorithm, which is the default return type of the + /// function. + /// + /// \pre \ref run() must be called before using this function. + template + Number totalCost() const { + Number c = 0; + for (ArcIt a(_graph); a != INVALID; ++a) { + int i = _arc_idb[a]; + c += static_cast(_res_cap[i]) * + (-static_cast(_scost[i])); + } + return c; + } + +#ifndef DOXYGEN + Cost totalCost() const { + return totalCost(); + } +#endif + + /// \brief Return the flow on the given arc. + /// + /// This function returns the flow on the given arc. + /// + /// \pre \ref run() must be called before using this function. + Value flow(const Arc& a) const { + return _res_cap[_arc_idb[a]]; + } + + /// \brief Return the flow map (the primal solution). + /// + /// This function copies the flow value on each arc into the given + /// map. The \c Value type of the algorithm must be convertible to + /// the \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void flowMap(FlowMap &map) const { + for (ArcIt a(_graph); a != INVALID; ++a) { + map.set(a, _res_cap[_arc_idb[a]]); + } + } + + /// \brief Return the potential (dual value) of the given node. + /// + /// This function returns the potential (dual value) of the + /// given node. + /// + /// \pre \ref run() must be called before using this function. + Cost potential(const Node& n) const { + return static_cast(_pi[_node_id[n]]); + } + + /// \brief Return the potential map (the dual solution). + /// + /// This function copies the potential (dual value) of each node + /// into the given map. + /// The \c Cost type of the algorithm must be convertible to the + /// \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void potentialMap(PotentialMap &map) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + map.set(n, static_cast(_pi[_node_id[n]])); + } + } + + /// @} + + private: + + // Initialize the algorithm + ProblemType init() { + if (_res_node_num <= 1) return INFEASIBLE; + + // Check the sum of supply values + _sum_supply = 0; + for (int i = 0; i != _root; ++i) { + _sum_supply += _supply[i]; + } + if (_sum_supply > 0) return INFEASIBLE; + + + // Initialize vectors + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] = 0; + _excess[i] = _supply[i]; + } + + // Remove infinite upper bounds and check negative arcs + const Value MAX = std::numeric_limits::max(); + int last_out; + if (_have_lower) { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j]) { + Value c = _scost[j] < 0 ? _upper[j] : _lower[j]; + if (c >= MAX) return UNBOUNDED; + _excess[i] -= c; + _excess[_target[j]] += c; + } + } + } + } else { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j] && _scost[j] < 0) { + Value c = _upper[j]; + if (c >= MAX) return UNBOUNDED; + _excess[i] -= c; + _excess[_target[j]] += c; + } + } + } + } + Value ex, max_cap = 0; + for (int i = 0; i != _res_node_num; ++i) { + ex = _excess[i]; + _excess[i] = 0; + if (ex < 0) max_cap -= ex; + } + for (int j = 0; j != _res_arc_num; ++j) { + if (_upper[j] >= MAX) _upper[j] = max_cap; + } + + // Initialize the large cost vector and the epsilon parameter + _epsilon = 0; + LargeCost lc; + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + lc = static_cast(_scost[j]) * _res_node_num * _alpha; + _cost[j] = lc; + if (lc > _epsilon) _epsilon = lc; + } + } + _epsilon /= _alpha; + + // Initialize maps for Circulation and remove non-zero lower bounds + ConstMap low(0); + typedef typename Digraph::template ArcMap ValueArcMap; + typedef typename Digraph::template NodeMap ValueNodeMap; + ValueArcMap cap(_graph), flow(_graph); + ValueNodeMap sup(_graph); + for (NodeIt n(_graph); n != INVALID; ++n) { + sup[n] = _supply[_node_id[n]]; + } + if (_have_lower) { + for (ArcIt a(_graph); a != INVALID; ++a) { + int j = _arc_idf[a]; + Value c = _lower[j]; + cap[a] = _upper[j] - c; + sup[_graph.source(a)] -= c; + sup[_graph.target(a)] += c; + } + } else { + for (ArcIt a(_graph); a != INVALID; ++a) { + cap[a] = _upper[_arc_idf[a]]; + } + } + + _sup_node_num = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if (sup[n] > 0) ++_sup_node_num; + } + + // Find a feasible flow using Circulation + Circulation, ValueArcMap, ValueNodeMap> + circ(_graph, low, cap, sup); + if (!circ.flowMap(flow).run()) return INFEASIBLE; + + // Set residual capacities and handle GEQ supply type + if (_sum_supply < 0) { + for (ArcIt a(_graph); a != INVALID; ++a) { + Value fa = flow[a]; + _res_cap[_arc_idf[a]] = cap[a] - fa; + _res_cap[_arc_idb[a]] = fa; + sup[_graph.source(a)] -= fa; + sup[_graph.target(a)] += fa; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + _excess[_node_id[n]] = sup[n]; + } + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int u = _target[a]; + int ra = _reverse[a]; + _res_cap[a] = -_sum_supply + 1; + _res_cap[ra] = -_excess[u]; + _cost[a] = 0; + _cost[ra] = 0; + _excess[u] = 0; + } + } else { + for (ArcIt a(_graph); a != INVALID; ++a) { + Value fa = flow[a]; + _res_cap[_arc_idf[a]] = cap[a] - fa; + _res_cap[_arc_idb[a]] = fa; + } + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int ra = _reverse[a]; + _res_cap[a] = 0; + _res_cap[ra] = 0; + _cost[a] = 0; + _cost[ra] = 0; + } + } + + return OPTIMAL; + } + + // Execute the algorithm and transform the results + void start(Method method) { + // Maximum path length for partial augment + const int MAX_PATH_LENGTH = 4; + + // Initialize data structures for buckets + _max_rank = _alpha * _res_node_num; + _buckets.resize(_max_rank); + _bucket_next.resize(_res_node_num + 1); + _bucket_prev.resize(_res_node_num + 1); + _rank.resize(_res_node_num + 1); + + // Execute the algorithm + switch (method) { + case PUSH: + startPush(); + break; + case AUGMENT: + startAugment(_res_node_num - 1); + break; + case PARTIAL_AUGMENT: + startAugment(MAX_PATH_LENGTH); + break; + } + + // Compute node potentials for the original costs + _arc_vec.clear(); + _cost_vec.clear(); + for (int j = 0; j != _res_arc_num; ++j) { + if (_res_cap[j] > 0) { + _arc_vec.push_back(IntPair(_source[j], _target[j])); + _cost_vec.push_back(_scost[j]); + } + } + _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); + + typename BellmanFord + ::template SetDistMap::Create bf(_sgr, _cost_map); + bf.distMap(_pi_map); + bf.init(0); + bf.start(); + + // Handle non-zero lower bounds + if (_have_lower) { + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + if (!_forward[j]) _res_cap[j] += _lower[j]; + } + } + } + + // Initialize a cost scaling phase + void initPhase() { + // Saturate arcs not satisfying the optimality condition + for (int u = 0; u != _res_node_num; ++u) { + int last_out = _first_out[u+1]; + LargeCost pi_u = _pi[u]; + for (int a = _first_out[u]; a != last_out; ++a) { + int v = _target[a]; + if (_res_cap[a] > 0 && _cost[a] + pi_u - _pi[v] < 0) { + Value delta = _res_cap[a]; + _excess[u] -= delta; + _excess[v] += delta; + _res_cap[a] = 0; + _res_cap[_reverse[a]] += delta; + } + } + } + + // Find active nodes (i.e. nodes with positive excess) + for (int u = 0; u != _res_node_num; ++u) { + if (_excess[u] > 0) _active_nodes.push_back(u); + } + + // Initialize the next arcs + for (int u = 0; u != _res_node_num; ++u) { + _next_out[u] = _first_out[u]; + } + } + + // Early termination heuristic + bool earlyTermination() { + const double EARLY_TERM_FACTOR = 3.0; + + // Build a static residual graph + _arc_vec.clear(); + _cost_vec.clear(); + for (int j = 0; j != _res_arc_num; ++j) { + if (_res_cap[j] > 0) { + _arc_vec.push_back(IntPair(_source[j], _target[j])); + _cost_vec.push_back(_cost[j] + 1); + } + } + _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); + + // Run Bellman-Ford algorithm to check if the current flow is optimal + BellmanFord bf(_sgr, _cost_map); + bf.init(0); + bool done = false; + int K = int(EARLY_TERM_FACTOR * std::sqrt(double(_res_node_num))); + for (int i = 0; i < K && !done; ++i) { + done = bf.processNextWeakRound(); + } + return done; + } + + // Global potential update heuristic + void globalUpdate() { + int bucket_end = _root + 1; + + // Initialize buckets + for (int r = 0; r != _max_rank; ++r) { + _buckets[r] = bucket_end; + } + Value total_excess = 0; + for (int i = 0; i != _res_node_num; ++i) { + if (_excess[i] < 0) { + _rank[i] = 0; + _bucket_next[i] = _buckets[0]; + _bucket_prev[_buckets[0]] = i; + _buckets[0] = i; + } else { + total_excess += _excess[i]; + _rank[i] = _max_rank; + } + } + if (total_excess == 0) return; + + // Search the buckets + int r = 0; + for ( ; r != _max_rank; ++r) { + while (_buckets[r] != bucket_end) { + // Remove the first node from the current bucket + int u = _buckets[r]; + _buckets[r] = _bucket_next[u]; + + // Search the incomming arcs of u + LargeCost pi_u = _pi[u]; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + int ra = _reverse[a]; + if (_res_cap[ra] > 0) { + int v = _source[ra]; + int old_rank_v = _rank[v]; + if (r < old_rank_v) { + // Compute the new rank of v + LargeCost nrc = (_cost[ra] + _pi[v] - pi_u) / _epsilon; + int new_rank_v = old_rank_v; + if (nrc < LargeCost(_max_rank)) + new_rank_v = r + 1 + int(nrc); + + // Change the rank of v + if (new_rank_v < old_rank_v) { + _rank[v] = new_rank_v; + _next_out[v] = _first_out[v]; + + // Remove v from its old bucket + if (old_rank_v < _max_rank) { + if (_buckets[old_rank_v] == v) { + _buckets[old_rank_v] = _bucket_next[v]; + } else { + _bucket_next[_bucket_prev[v]] = _bucket_next[v]; + _bucket_prev[_bucket_next[v]] = _bucket_prev[v]; + } + } + + // Insert v to its new bucket + _bucket_next[v] = _buckets[new_rank_v]; + _bucket_prev[_buckets[new_rank_v]] = v; + _buckets[new_rank_v] = v; + } + } + } + } + + // Finish search if there are no more active nodes + if (_excess[u] > 0) { + total_excess -= _excess[u]; + if (total_excess <= 0) break; + } + } + if (total_excess <= 0) break; + } + + // Relabel nodes + for (int u = 0; u != _res_node_num; ++u) { + int k = std::min(_rank[u], r); + if (k > 0) { + _pi[u] -= _epsilon * k; + _next_out[u] = _first_out[u]; + } + } + } + + /// Execute the algorithm performing augment and relabel operations + void startAugment(int max_length) { + // Paramters for heuristics + const int EARLY_TERM_EPSILON_LIMIT = 1000; + const double GLOBAL_UPDATE_FACTOR = 3.0; + + const int global_update_freq = int(GLOBAL_UPDATE_FACTOR * + (_res_node_num + _sup_node_num * _sup_node_num)); + int next_update_limit = global_update_freq; + + int relabel_cnt = 0; + + // Perform cost scaling phases + std::vector path; + for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? + 1 : _epsilon / _alpha ) + { + // Early termination heuristic + if (_epsilon <= EARLY_TERM_EPSILON_LIMIT) { + if (earlyTermination()) break; + } + + // Initialize current phase + initPhase(); + + // Perform partial augment and relabel operations + while (true) { + // Select an active node (FIFO selection) + while (_active_nodes.size() > 0 && + _excess[_active_nodes.front()] <= 0) { + _active_nodes.pop_front(); + } + if (_active_nodes.size() == 0) break; + int start = _active_nodes.front(); + + // Find an augmenting path from the start node + path.clear(); + int tip = start; + while (_excess[tip] >= 0 && int(path.size()) < max_length) { + int u; + LargeCost min_red_cost, rc, pi_tip = _pi[tip]; + int last_out = _first_out[tip+1]; + for (int a = _next_out[tip]; a != last_out; ++a) { + u = _target[a]; + if (_res_cap[a] > 0 && _cost[a] + pi_tip - _pi[u] < 0) { + path.push_back(a); + _next_out[tip] = a; + tip = u; + goto next_step; + } + } + + // Relabel tip node + min_red_cost = std::numeric_limits::max(); + if (tip != start) { + int ra = _reverse[path.back()]; + min_red_cost = _cost[ra] + pi_tip - _pi[_target[ra]]; + } + for (int a = _first_out[tip]; a != last_out; ++a) { + rc = _cost[a] + pi_tip - _pi[_target[a]]; + if (_res_cap[a] > 0 && rc < min_red_cost) { + min_red_cost = rc; + } + } + _pi[tip] -= min_red_cost + _epsilon; + _next_out[tip] = _first_out[tip]; + ++relabel_cnt; + + // Step back + if (tip != start) { + tip = _source[path.back()]; + path.pop_back(); + } + + next_step: ; + } + + // Augment along the found path (as much flow as possible) + Value delta; + int pa, u, v = start; + for (int i = 0; i != int(path.size()); ++i) { + pa = path[i]; + u = v; + v = _target[pa]; + delta = std::min(_res_cap[pa], _excess[u]); + _res_cap[pa] -= delta; + _res_cap[_reverse[pa]] += delta; + _excess[u] -= delta; + _excess[v] += delta; + if (_excess[v] > 0 && _excess[v] <= delta) + _active_nodes.push_back(v); + } + + // Global update heuristic + if (relabel_cnt >= next_update_limit) { + globalUpdate(); + next_update_limit += global_update_freq; + } + } + } + } + + /// Execute the algorithm performing push and relabel operations + void startPush() { + // Paramters for heuristics + const int EARLY_TERM_EPSILON_LIMIT = 1000; + const double GLOBAL_UPDATE_FACTOR = 2.0; + + const int global_update_freq = int(GLOBAL_UPDATE_FACTOR * + (_res_node_num + _sup_node_num * _sup_node_num)); + int next_update_limit = global_update_freq; + + int relabel_cnt = 0; + + // Perform cost scaling phases + BoolVector hyper(_res_node_num, false); + LargeCostVector hyper_cost(_res_node_num); + for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? + 1 : _epsilon / _alpha ) + { + // Early termination heuristic + if (_epsilon <= EARLY_TERM_EPSILON_LIMIT) { + if (earlyTermination()) break; + } + + // Initialize current phase + initPhase(); + + // Perform push and relabel operations + while (_active_nodes.size() > 0) { + LargeCost min_red_cost, rc, pi_n; + Value delta; + int n, t, a, last_out = _res_arc_num; + + next_node: + // Select an active node (FIFO selection) + n = _active_nodes.front(); + last_out = _first_out[n+1]; + pi_n = _pi[n]; + + // Perform push operations if there are admissible arcs + if (_excess[n] > 0) { + for (a = _next_out[n]; a != last_out; ++a) { + if (_res_cap[a] > 0 && + _cost[a] + pi_n - _pi[_target[a]] < 0) { + delta = std::min(_res_cap[a], _excess[n]); + t = _target[a]; + + // Push-look-ahead heuristic + Value ahead = -_excess[t]; + int last_out_t = _first_out[t+1]; + LargeCost pi_t = _pi[t]; + for (int ta = _next_out[t]; ta != last_out_t; ++ta) { + if (_res_cap[ta] > 0 && + _cost[ta] + pi_t - _pi[_target[ta]] < 0) + ahead += _res_cap[ta]; + if (ahead >= delta) break; + } + if (ahead < 0) ahead = 0; + + // Push flow along the arc + if (ahead < delta && !hyper[t]) { + _res_cap[a] -= ahead; + _res_cap[_reverse[a]] += ahead; + _excess[n] -= ahead; + _excess[t] += ahead; + _active_nodes.push_front(t); + hyper[t] = true; + hyper_cost[t] = _cost[a] + pi_n - pi_t; + _next_out[n] = a; + goto next_node; + } else { + _res_cap[a] -= delta; + _res_cap[_reverse[a]] += delta; + _excess[n] -= delta; + _excess[t] += delta; + if (_excess[t] > 0 && _excess[t] <= delta) + _active_nodes.push_back(t); + } + + if (_excess[n] == 0) { + _next_out[n] = a; + goto remove_nodes; + } + } + } + _next_out[n] = a; + } + + // Relabel the node if it is still active (or hyper) + if (_excess[n] > 0 || hyper[n]) { + min_red_cost = hyper[n] ? -hyper_cost[n] : + std::numeric_limits::max(); + for (int a = _first_out[n]; a != last_out; ++a) { + rc = _cost[a] + pi_n - _pi[_target[a]]; + if (_res_cap[a] > 0 && rc < min_red_cost) { + min_red_cost = rc; + } + } + _pi[n] -= min_red_cost + _epsilon; + _next_out[n] = _first_out[n]; + hyper[n] = false; + ++relabel_cnt; + } + + // Remove nodes that are not active nor hyper + remove_nodes: + while ( _active_nodes.size() > 0 && + _excess[_active_nodes.front()] <= 0 && + !hyper[_active_nodes.front()] ) { + _active_nodes.pop_front(); + } + + // Global update heuristic + if (relabel_cnt >= next_update_limit) { + globalUpdate(); + for (int u = 0; u != _res_node_num; ++u) + hyper[u] = false; + next_update_limit += global_update_freq; + } + } + } + } + + }; //class CostScaling + + ///@} + +} //namespace lemon + +#endif //LEMON_COST_SCALING_H diff --git a/lemon/counter.h b/lemon/counter.h --- a/lemon/counter.h +++ b/lemon/counter.h @@ -212,7 +212,7 @@ /// 'Do nothing' version of Counter. - /// This class can be used in the same way as \ref Counter however it + /// This class can be used in the same way as \ref Counter, but it /// does not count at all and does not print report on destruction. /// /// Replacing a \ref Counter with a \ref NoCounter makes it possible diff --git a/lemon/cplex.cc b/lemon/cplex.cc --- a/lemon/cplex.cc +++ b/lemon/cplex.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -111,6 +111,39 @@ return i; } + int CplexBase::_addRow(Value lb, ExprIterator b, + ExprIterator e, Value ub) { + int i = CPXgetnumrows(cplexEnv(), _prob); + if (lb == -INF) { + const char s = 'L'; + CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0); + } else if (ub == INF) { + const char s = 'G'; + CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0); + } else if (lb == ub){ + const char s = 'E'; + CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0); + } else { + const char s = 'R'; + double len = ub - lb; + CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, &len, 0); + } + + std::vector indices; + std::vector rowlist; + std::vector values; + + for(ExprIterator it=b; it!=e; ++it) { + indices.push_back(it->first); + values.push_back(it->second); + rowlist.push_back(i); + } + + CPXchgcoeflist(cplexEnv(), _prob, values.size(), + &rowlist.front(), &indices.front(), &values.front()); + + return i; + } void CplexBase::_eraseCol(int i) { CPXdelcols(cplexEnv(), _prob, i, i); @@ -456,7 +489,7 @@ } void CplexBase::_applyMessageLevel() { - CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND, + CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND, _message_enabled ? CPX_ON : CPX_OFF); } diff --git a/lemon/cplex.h b/lemon/cplex.h --- a/lemon/cplex.h +++ b/lemon/cplex.h @@ -93,6 +93,7 @@ virtual int _addCol(); virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); virtual void _eraseCol(int i); virtual void _eraseRow(int i); diff --git a/lemon/cycle_canceling.h b/lemon/cycle_canceling.h new file mode 100644 --- /dev/null +++ b/lemon/cycle_canceling.h @@ -0,0 +1,1170 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_CYCLE_CANCELING_H +#define LEMON_CYCLE_CANCELING_H + +/// \ingroup min_cost_flow_algs +/// \file +/// \brief Cycle-canceling algorithms for finding a minimum cost flow. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \addtogroup min_cost_flow_algs + /// @{ + + /// \brief Implementation of cycle-canceling algorithms for + /// finding a \ref min_cost_flow "minimum cost flow". + /// + /// \ref CycleCanceling implements three different cycle-canceling + /// algorithms for finding a \ref min_cost_flow "minimum cost flow" + /// \ref amo93networkflows, \ref klein67primal, + /// \ref goldberg89cyclecanceling. + /// The most efficent one (both theoretically and practically) + /// is the \ref CANCEL_AND_TIGHTEN "Cancel and Tighten" algorithm, + /// thus it is the default method. + /// It is strongly polynomial, but in practice, it is typically much + /// slower than the scaling algorithms and NetworkSimplex. + /// + /// Most of the parameters of the problem (except for the digraph) + /// can be given using separate functions, and the algorithm can be + /// executed using the \ref run() function. If some parameters are not + /// specified, then default values will be used. + /// + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values in the algorithm. By default, it is \c int. + /// \tparam C The number type used for costs and potentials in the + /// algorithm. By default, it is the same as \c V. + /// + /// \warning Both number types must be signed and all input data must + /// be integer. + /// \warning This algorithm does not support negative costs for such + /// arcs that have infinite upper bound. + /// + /// \note For more information about the three available methods, + /// see \ref Method. +#ifdef DOXYGEN + template +#else + template +#endif + class CycleCanceling + { + public: + + /// The type of the digraph + typedef GR Digraph; + /// The type of the flow amounts, capacity bounds and supply values + typedef V Value; + /// The type of the arc costs + typedef C Cost; + + public: + + /// \brief Problem type constants for the \c run() function. + /// + /// Enum type containing the problem type constants that can be + /// returned by the \ref run() function of the algorithm. + enum ProblemType { + /// The problem has no feasible solution (flow). + INFEASIBLE, + /// The problem has optimal solution (i.e. it is feasible and + /// bounded), and the algorithm has found optimal flow and node + /// potentials (primal and dual solutions). + OPTIMAL, + /// The digraph contains an arc of negative cost and infinite + /// upper bound. It means that the objective function is unbounded + /// on that arc, however, note that it could actually be bounded + /// over the feasible flows, but this algroithm cannot handle + /// these cases. + UNBOUNDED + }; + + /// \brief Constants for selecting the used method. + /// + /// Enum type containing constants for selecting the used method + /// for the \ref run() function. + /// + /// \ref CycleCanceling provides three different cycle-canceling + /// methods. By default, \ref CANCEL_AND_TIGHTEN "Cancel and Tighten" + /// is used, which proved to be the most efficient and the most robust + /// on various test inputs. + /// However, the other methods can be selected using the \ref run() + /// function with the proper parameter. + enum Method { + /// A simple cycle-canceling method, which uses the + /// \ref BellmanFord "Bellman-Ford" algorithm with limited iteration + /// number for detecting negative cycles in the residual network. + SIMPLE_CYCLE_CANCELING, + /// The "Minimum Mean Cycle-Canceling" algorithm, which is a + /// well-known strongly polynomial method + /// \ref goldberg89cyclecanceling. It improves along a + /// \ref min_mean_cycle "minimum mean cycle" in each iteration. + /// Its running time complexity is O(n2m3log(n)). + MINIMUM_MEAN_CYCLE_CANCELING, + /// The "Cancel And Tighten" algorithm, which can be viewed as an + /// improved version of the previous method + /// \ref goldberg89cyclecanceling. + /// It is faster both in theory and in practice, its running time + /// complexity is O(n2m2log(n)). + CANCEL_AND_TIGHTEN + }; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(GR); + + typedef std::vector IntVector; + typedef std::vector DoubleVector; + typedef std::vector ValueVector; + typedef std::vector CostVector; + typedef std::vector BoolVector; + // Note: vector is used instead of vector for efficiency reasons + + private: + + template + class StaticVectorMap { + public: + typedef KT Key; + typedef VT Value; + + StaticVectorMap(std::vector& v) : _v(v) {} + + const Value& operator[](const Key& key) const { + return _v[StaticDigraph::id(key)]; + } + + Value& operator[](const Key& key) { + return _v[StaticDigraph::id(key)]; + } + + void set(const Key& key, const Value& val) { + _v[StaticDigraph::id(key)] = val; + } + + private: + std::vector& _v; + }; + + typedef StaticVectorMap CostNodeMap; + typedef StaticVectorMap CostArcMap; + + private: + + + // Data related to the underlying digraph + const GR &_graph; + int _node_num; + int _arc_num; + int _res_node_num; + int _res_arc_num; + int _root; + + // Parameters of the problem + bool _have_lower; + Value _sum_supply; + + // Data structures for storing the digraph + IntNodeMap _node_id; + IntArcMap _arc_idf; + IntArcMap _arc_idb; + IntVector _first_out; + BoolVector _forward; + IntVector _source; + IntVector _target; + IntVector _reverse; + + // Node and arc data + ValueVector _lower; + ValueVector _upper; + CostVector _cost; + ValueVector _supply; + + ValueVector _res_cap; + CostVector _pi; + + // Data for a StaticDigraph structure + typedef std::pair IntPair; + StaticDigraph _sgr; + std::vector _arc_vec; + std::vector _cost_vec; + IntVector _id_vec; + CostArcMap _cost_map; + CostNodeMap _pi_map; + + public: + + /// \brief Constant for infinite upper bounds (capacities). + /// + /// Constant for infinite upper bounds (capacities). + /// It is \c std::numeric_limits::infinity() if available, + /// \c std::numeric_limits::max() otherwise. + const Value INF; + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param graph The digraph the algorithm runs on. + CycleCanceling(const GR& graph) : + _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), + _cost_map(_cost_vec), _pi_map(_pi), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + { + // Check the number types + LEMON_ASSERT(std::numeric_limits::is_signed, + "The flow type of CycleCanceling must be signed"); + LEMON_ASSERT(std::numeric_limits::is_signed, + "The cost type of CycleCanceling must be signed"); + + // Reset data structures + reset(); + } + + /// \name Parameters + /// The parameters of the algorithm can be specified using these + /// functions. + + /// @{ + + /// \brief Set the lower bounds on the arcs. + /// + /// This function sets the lower bounds on the arcs. + /// If it is not used before calling \ref run(), the lower bounds + /// will be set to zero on all arcs. + /// + /// \param map An arc map storing the lower bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CycleCanceling& lowerMap(const LowerMap& map) { + _have_lower = true; + for (ArcIt a(_graph); a != INVALID; ++a) { + _lower[_arc_idf[a]] = map[a]; + _lower[_arc_idb[a]] = map[a]; + } + return *this; + } + + /// \brief Set the upper bounds (capacities) on the arcs. + /// + /// This function sets the upper bounds (capacities) on the arcs. + /// If it is not used before calling \ref run(), the upper bounds + /// will be set to \ref INF on all arcs (i.e. the flow value will be + /// unbounded from above). + /// + /// \param map An arc map storing the upper bounds. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CycleCanceling& upperMap(const UpperMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _upper[_arc_idf[a]] = map[a]; + } + return *this; + } + + /// \brief Set the costs of the arcs. + /// + /// This function sets the costs of the arcs. + /// If it is not used before calling \ref run(), the costs + /// will be set to \c 1 on all arcs. + /// + /// \param map An arc map storing the costs. + /// Its \c Value type must be convertible to the \c Cost type + /// of the algorithm. + /// + /// \return (*this) + template + CycleCanceling& costMap(const CostMap& map) { + for (ArcIt a(_graph); a != INVALID; ++a) { + _cost[_arc_idf[a]] = map[a]; + _cost[_arc_idb[a]] = -map[a]; + } + return *this; + } + + /// \brief Set the supply values of the nodes. + /// + /// This function sets the supply values of the nodes. + /// If neither this function nor \ref stSupply() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// \param map A node map storing the supply values. + /// Its \c Value type must be convertible to the \c Value type + /// of the algorithm. + /// + /// \return (*this) + template + CycleCanceling& supplyMap(const SupplyMap& map) { + for (NodeIt n(_graph); n != INVALID; ++n) { + _supply[_node_id[n]] = map[n]; + } + return *this; + } + + /// \brief Set single source and target nodes and a supply value. + /// + /// This function sets a single source node and a single target node + /// and the required flow value. + /// If neither this function nor \ref supplyMap() is used before + /// calling \ref run(), the supply of each node will be set to zero. + /// + /// Using this function has the same effect as using \ref supplyMap() + /// with such a map in which \c k is assigned to \c s, \c -k is + /// assigned to \c t and all other nodes have zero supply value. + /// + /// \param s The source node. + /// \param t The target node. + /// \param k The required amount of flow from node \c s to node \c t + /// (i.e. the supply of \c s and the demand of \c t). + /// + /// \return (*this) + CycleCanceling& stSupply(const Node& s, const Node& t, Value k) { + for (int i = 0; i != _res_node_num; ++i) { + _supply[i] = 0; + } + _supply[_node_id[s]] = k; + _supply[_node_id[t]] = -k; + return *this; + } + + /// @} + + /// \name Execution control + /// The algorithm can be executed using \ref run(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// The paramters can be specified using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// For example, + /// \code + /// CycleCanceling cc(graph); + /// cc.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// This function can be called more than once. All the given parameters + /// are kept for the next call, unless \ref resetParams() or \ref reset() + /// is used, thus only the modified parameters have to be set again. + /// If the underlying digraph was also modified after the construction + /// of the class (or the last \ref reset() call), then the \ref reset() + /// function must be called. + /// + /// \param method The cycle-canceling method that will be used. + /// For more information, see \ref Method. + /// + /// \return \c INFEASIBLE if no feasible flow exists, + /// \n \c OPTIMAL if the problem has optimal solution + /// (i.e. it is feasible and bounded), and the algorithm has found + /// optimal flow and node potentials (primal and dual solutions), + /// \n \c UNBOUNDED if the digraph contains an arc of negative cost + /// and infinite upper bound. It means that the objective function + /// is unbounded on that arc, however, note that it could actually be + /// bounded over the feasible flows, but this algroithm cannot handle + /// these cases. + /// + /// \see ProblemType, Method + /// \see resetParams(), reset() + ProblemType run(Method method = CANCEL_AND_TIGHTEN) { + ProblemType pt = init(); + if (pt != OPTIMAL) return pt; + start(method); + return OPTIMAL; + } + + /// \brief Reset all the parameters that have been given before. + /// + /// This function resets all the paramaters that have been given + /// before using functions \ref lowerMap(), \ref upperMap(), + /// \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// For example, + /// \code + /// CycleCanceling cs(graph); + /// + /// // First run + /// cc.lowerMap(lower).upperMap(upper).costMap(cost) + /// .supplyMap(sup).run(); + /// + /// // Run again with modified cost map (resetParams() is not called, + /// // so only the cost map have to be set again) + /// cost[e] += 100; + /// cc.costMap(cost).run(); + /// + /// // Run again from scratch using resetParams() + /// // (the lower bounds will be set to zero on all arcs) + /// cc.resetParams(); + /// cc.upperMap(capacity).costMap(cost) + /// .supplyMap(sup).run(); + /// \endcode + /// + /// \return (*this) + /// + /// \see reset(), run() + CycleCanceling& resetParams() { + for (int i = 0; i != _res_node_num; ++i) { + _supply[i] = 0; + } + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _cost[j] = _forward[j] ? 1 : -1; + } + for (int j = limit; j != _res_arc_num; ++j) { + _lower[j] = 0; + _upper[j] = INF; + _cost[j] = 0; + _cost[_reverse[j]] = 0; + } + _have_lower = false; + return *this; + } + + /// \brief Reset the internal data structures and all the parameters + /// that have been given before. + /// + /// This function resets the internal data structures and all the + /// paramaters that have been given before using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// See \ref resetParams() for examples. + /// + /// \return (*this) + /// + /// \see resetParams(), run() + CycleCanceling& reset() { + // Resize vectors + _node_num = countNodes(_graph); + _arc_num = countArcs(_graph); + _res_node_num = _node_num + 1; + _res_arc_num = 2 * (_arc_num + _node_num); + _root = _node_num; + + _first_out.resize(_res_node_num + 1); + _forward.resize(_res_arc_num); + _source.resize(_res_arc_num); + _target.resize(_res_arc_num); + _reverse.resize(_res_arc_num); + + _lower.resize(_res_arc_num); + _upper.resize(_res_arc_num); + _cost.resize(_res_arc_num); + _supply.resize(_res_node_num); + + _res_cap.resize(_res_arc_num); + _pi.resize(_res_node_num); + + _arc_vec.reserve(_res_arc_num); + _cost_vec.reserve(_res_arc_num); + _id_vec.reserve(_res_arc_num); + + // Copy the graph + int i = 0, j = 0, k = 2 * _arc_num + _node_num; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _node_id[n] = i; + } + i = 0; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _first_out[i] = j; + for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idf[a] = j; + _forward[j] = true; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) { + _arc_idb[a] = j; + _forward[j] = false; + _source[j] = i; + _target[j] = _node_id[_graph.runningNode(a)]; + } + _forward[j] = false; + _source[j] = i; + _target[j] = _root; + _reverse[j] = k; + _forward[k] = true; + _source[k] = _root; + _target[k] = i; + _reverse[k] = j; + ++j; ++k; + } + _first_out[i] = j; + _first_out[_res_node_num] = k; + for (ArcIt a(_graph); a != INVALID; ++a) { + int fi = _arc_idf[a]; + int bi = _arc_idb[a]; + _reverse[fi] = bi; + _reverse[bi] = fi; + } + + // Reset parameters + resetParams(); + return *this; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The \ref run() function must be called before using them. + + /// @{ + + /// \brief Return the total cost of the found flow. + /// + /// This function returns the total cost of the found flow. + /// Its complexity is O(e). + /// + /// \note The return type of the function can be specified as a + /// template parameter. For example, + /// \code + /// cc.totalCost(); + /// \endcode + /// It is useful if the total cost cannot be stored in the \c Cost + /// type of the algorithm, which is the default return type of the + /// function. + /// + /// \pre \ref run() must be called before using this function. + template + Number totalCost() const { + Number c = 0; + for (ArcIt a(_graph); a != INVALID; ++a) { + int i = _arc_idb[a]; + c += static_cast(_res_cap[i]) * + (-static_cast(_cost[i])); + } + return c; + } + +#ifndef DOXYGEN + Cost totalCost() const { + return totalCost(); + } +#endif + + /// \brief Return the flow on the given arc. + /// + /// This function returns the flow on the given arc. + /// + /// \pre \ref run() must be called before using this function. + Value flow(const Arc& a) const { + return _res_cap[_arc_idb[a]]; + } + + /// \brief Return the flow map (the primal solution). + /// + /// This function copies the flow value on each arc into the given + /// map. The \c Value type of the algorithm must be convertible to + /// the \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void flowMap(FlowMap &map) const { + for (ArcIt a(_graph); a != INVALID; ++a) { + map.set(a, _res_cap[_arc_idb[a]]); + } + } + + /// \brief Return the potential (dual value) of the given node. + /// + /// This function returns the potential (dual value) of the + /// given node. + /// + /// \pre \ref run() must be called before using this function. + Cost potential(const Node& n) const { + return static_cast(_pi[_node_id[n]]); + } + + /// \brief Return the potential map (the dual solution). + /// + /// This function copies the potential (dual value) of each node + /// into the given map. + /// The \c Cost type of the algorithm must be convertible to the + /// \c Value type of the map. + /// + /// \pre \ref run() must be called before using this function. + template + void potentialMap(PotentialMap &map) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + map.set(n, static_cast(_pi[_node_id[n]])); + } + } + + /// @} + + private: + + // Initialize the algorithm + ProblemType init() { + if (_res_node_num <= 1) return INFEASIBLE; + + // Check the sum of supply values + _sum_supply = 0; + for (int i = 0; i != _root; ++i) { + _sum_supply += _supply[i]; + } + if (_sum_supply > 0) return INFEASIBLE; + + + // Initialize vectors + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] = 0; + } + ValueVector excess(_supply); + + // Remove infinite upper bounds and check negative arcs + const Value MAX = std::numeric_limits::max(); + int last_out; + if (_have_lower) { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j]) { + Value c = _cost[j] < 0 ? _upper[j] : _lower[j]; + if (c >= MAX) return UNBOUNDED; + excess[i] -= c; + excess[_target[j]] += c; + } + } + } + } else { + for (int i = 0; i != _root; ++i) { + last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_forward[j] && _cost[j] < 0) { + Value c = _upper[j]; + if (c >= MAX) return UNBOUNDED; + excess[i] -= c; + excess[_target[j]] += c; + } + } + } + } + Value ex, max_cap = 0; + for (int i = 0; i != _res_node_num; ++i) { + ex = excess[i]; + if (ex < 0) max_cap -= ex; + } + for (int j = 0; j != _res_arc_num; ++j) { + if (_upper[j] >= MAX) _upper[j] = max_cap; + } + + // Initialize maps for Circulation and remove non-zero lower bounds + ConstMap low(0); + typedef typename Digraph::template ArcMap ValueArcMap; + typedef typename Digraph::template NodeMap ValueNodeMap; + ValueArcMap cap(_graph), flow(_graph); + ValueNodeMap sup(_graph); + for (NodeIt n(_graph); n != INVALID; ++n) { + sup[n] = _supply[_node_id[n]]; + } + if (_have_lower) { + for (ArcIt a(_graph); a != INVALID; ++a) { + int j = _arc_idf[a]; + Value c = _lower[j]; + cap[a] = _upper[j] - c; + sup[_graph.source(a)] -= c; + sup[_graph.target(a)] += c; + } + } else { + for (ArcIt a(_graph); a != INVALID; ++a) { + cap[a] = _upper[_arc_idf[a]]; + } + } + + // Find a feasible flow using Circulation + Circulation, ValueArcMap, ValueNodeMap> + circ(_graph, low, cap, sup); + if (!circ.flowMap(flow).run()) return INFEASIBLE; + + // Set residual capacities and handle GEQ supply type + if (_sum_supply < 0) { + for (ArcIt a(_graph); a != INVALID; ++a) { + Value fa = flow[a]; + _res_cap[_arc_idf[a]] = cap[a] - fa; + _res_cap[_arc_idb[a]] = fa; + sup[_graph.source(a)] -= fa; + sup[_graph.target(a)] += fa; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + excess[_node_id[n]] = sup[n]; + } + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int u = _target[a]; + int ra = _reverse[a]; + _res_cap[a] = -_sum_supply + 1; + _res_cap[ra] = -excess[u]; + _cost[a] = 0; + _cost[ra] = 0; + } + } else { + for (ArcIt a(_graph); a != INVALID; ++a) { + Value fa = flow[a]; + _res_cap[_arc_idf[a]] = cap[a] - fa; + _res_cap[_arc_idb[a]] = fa; + } + for (int a = _first_out[_root]; a != _res_arc_num; ++a) { + int ra = _reverse[a]; + _res_cap[a] = 1; + _res_cap[ra] = 0; + _cost[a] = 0; + _cost[ra] = 0; + } + } + + return OPTIMAL; + } + + // Build a StaticDigraph structure containing the current + // residual network + void buildResidualNetwork() { + _arc_vec.clear(); + _cost_vec.clear(); + _id_vec.clear(); + for (int j = 0; j != _res_arc_num; ++j) { + if (_res_cap[j] > 0) { + _arc_vec.push_back(IntPair(_source[j], _target[j])); + _cost_vec.push_back(_cost[j]); + _id_vec.push_back(j); + } + } + _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); + } + + // Execute the algorithm and transform the results + void start(Method method) { + // Execute the algorithm + switch (method) { + case SIMPLE_CYCLE_CANCELING: + startSimpleCycleCanceling(); + break; + case MINIMUM_MEAN_CYCLE_CANCELING: + startMinMeanCycleCanceling(); + break; + case CANCEL_AND_TIGHTEN: + startCancelAndTighten(); + break; + } + + // Compute node potentials + if (method != SIMPLE_CYCLE_CANCELING) { + buildResidualNetwork(); + typename BellmanFord + ::template SetDistMap::Create bf(_sgr, _cost_map); + bf.distMap(_pi_map); + bf.init(0); + bf.start(); + } + + // Handle non-zero lower bounds + if (_have_lower) { + int limit = _first_out[_root]; + for (int j = 0; j != limit; ++j) { + if (!_forward[j]) _res_cap[j] += _lower[j]; + } + } + } + + // Execute the "Simple Cycle Canceling" method + void startSimpleCycleCanceling() { + // Constants for computing the iteration limits + const int BF_FIRST_LIMIT = 2; + const double BF_LIMIT_FACTOR = 1.5; + + typedef StaticVectorMap FilterMap; + typedef FilterArcs ResDigraph; + typedef StaticVectorMap PredMap; + typedef typename BellmanFord + ::template SetDistMap + ::template SetPredMap::Create BF; + + // Build the residual network + _arc_vec.clear(); + _cost_vec.clear(); + for (int j = 0; j != _res_arc_num; ++j) { + _arc_vec.push_back(IntPair(_source[j], _target[j])); + _cost_vec.push_back(_cost[j]); + } + _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); + + FilterMap filter_map(_res_cap); + ResDigraph rgr(_sgr, filter_map); + std::vector cycle; + std::vector pred(_res_arc_num); + PredMap pred_map(pred); + BF bf(rgr, _cost_map); + bf.distMap(_pi_map).predMap(pred_map); + + int length_bound = BF_FIRST_LIMIT; + bool optimal = false; + while (!optimal) { + bf.init(0); + int iter_num = 0; + bool cycle_found = false; + while (!cycle_found) { + // Perform some iterations of the Bellman-Ford algorithm + int curr_iter_num = iter_num + length_bound <= _node_num ? + length_bound : _node_num - iter_num; + iter_num += curr_iter_num; + int real_iter_num = curr_iter_num; + for (int i = 0; i < curr_iter_num; ++i) { + if (bf.processNextWeakRound()) { + real_iter_num = i; + break; + } + } + if (real_iter_num < curr_iter_num) { + // Optimal flow is found + optimal = true; + break; + } else { + // Search for node disjoint negative cycles + std::vector state(_res_node_num, 0); + int id = 0; + for (int u = 0; u != _res_node_num; ++u) { + if (state[u] != 0) continue; + ++id; + int v = u; + for (; v != -1 && state[v] == 0; v = pred[v] == INVALID ? + -1 : rgr.id(rgr.source(pred[v]))) { + state[v] = id; + } + if (v != -1 && state[v] == id) { + // A negative cycle is found + cycle_found = true; + cycle.clear(); + StaticDigraph::Arc a = pred[v]; + Value d, delta = _res_cap[rgr.id(a)]; + cycle.push_back(rgr.id(a)); + while (rgr.id(rgr.source(a)) != v) { + a = pred_map[rgr.source(a)]; + d = _res_cap[rgr.id(a)]; + if (d < delta) delta = d; + cycle.push_back(rgr.id(a)); + } + + // Augment along the cycle + for (int i = 0; i < int(cycle.size()); ++i) { + int j = cycle[i]; + _res_cap[j] -= delta; + _res_cap[_reverse[j]] += delta; + } + } + } + } + + // Increase iteration limit if no cycle is found + if (!cycle_found) { + length_bound = static_cast(length_bound * BF_LIMIT_FACTOR); + } + } + } + } + + // Execute the "Minimum Mean Cycle Canceling" method + void startMinMeanCycleCanceling() { + typedef SimplePath SPath; + typedef typename SPath::ArcIt SPathArcIt; + typedef typename HowardMmc + ::template SetPath::Create MMC; + + SPath cycle; + MMC mmc(_sgr, _cost_map); + mmc.cycle(cycle); + buildResidualNetwork(); + while (mmc.findCycleMean() && mmc.cycleCost() < 0) { + // Find the cycle + mmc.findCycle(); + + // Compute delta value + Value delta = INF; + for (SPathArcIt a(cycle); a != INVALID; ++a) { + Value d = _res_cap[_id_vec[_sgr.id(a)]]; + if (d < delta) delta = d; + } + + // Augment along the cycle + for (SPathArcIt a(cycle); a != INVALID; ++a) { + int j = _id_vec[_sgr.id(a)]; + _res_cap[j] -= delta; + _res_cap[_reverse[j]] += delta; + } + + // Rebuild the residual network + buildResidualNetwork(); + } + } + + // Execute the "Cancel And Tighten" method + void startCancelAndTighten() { + // Constants for the min mean cycle computations + const double LIMIT_FACTOR = 1.0; + const int MIN_LIMIT = 5; + + // Contruct auxiliary data vectors + DoubleVector pi(_res_node_num, 0.0); + IntVector level(_res_node_num); + BoolVector reached(_res_node_num); + BoolVector processed(_res_node_num); + IntVector pred_node(_res_node_num); + IntVector pred_arc(_res_node_num); + std::vector stack(_res_node_num); + std::vector proc_vector(_res_node_num); + + // Initialize epsilon + double epsilon = 0; + for (int a = 0; a != _res_arc_num; ++a) { + if (_res_cap[a] > 0 && -_cost[a] > epsilon) + epsilon = -_cost[a]; + } + + // Start phases + Tolerance tol; + tol.epsilon(1e-6); + int limit = int(LIMIT_FACTOR * std::sqrt(double(_res_node_num))); + if (limit < MIN_LIMIT) limit = MIN_LIMIT; + int iter = limit; + while (epsilon * _res_node_num >= 1) { + // Find and cancel cycles in the admissible network using DFS + for (int u = 0; u != _res_node_num; ++u) { + reached[u] = false; + processed[u] = false; + } + int stack_head = -1; + int proc_head = -1; + for (int start = 0; start != _res_node_num; ++start) { + if (reached[start]) continue; + + // New start node + reached[start] = true; + pred_arc[start] = -1; + pred_node[start] = -1; + + // Find the first admissible outgoing arc + double p = pi[start]; + int a = _first_out[start]; + int last_out = _first_out[start+1]; + for (; a != last_out && (_res_cap[a] == 0 || + !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; + if (a == last_out) { + processed[start] = true; + proc_vector[++proc_head] = start; + continue; + } + stack[++stack_head] = a; + + while (stack_head >= 0) { + int sa = stack[stack_head]; + int u = _source[sa]; + int v = _target[sa]; + + if (!reached[v]) { + // A new node is reached + reached[v] = true; + pred_node[v] = u; + pred_arc[v] = sa; + p = pi[v]; + a = _first_out[v]; + last_out = _first_out[v+1]; + for (; a != last_out && (_res_cap[a] == 0 || + !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; + stack[++stack_head] = a == last_out ? -1 : a; + } else { + if (!processed[v]) { + // A cycle is found + int n, w = u; + Value d, delta = _res_cap[sa]; + for (n = u; n != v; n = pred_node[n]) { + d = _res_cap[pred_arc[n]]; + if (d <= delta) { + delta = d; + w = pred_node[n]; + } + } + + // Augment along the cycle + _res_cap[sa] -= delta; + _res_cap[_reverse[sa]] += delta; + for (n = u; n != v; n = pred_node[n]) { + int pa = pred_arc[n]; + _res_cap[pa] -= delta; + _res_cap[_reverse[pa]] += delta; + } + for (n = u; stack_head > 0 && n != w; n = pred_node[n]) { + --stack_head; + reached[n] = false; + } + u = w; + } + v = u; + + // Find the next admissible outgoing arc + p = pi[v]; + a = stack[stack_head] + 1; + last_out = _first_out[v+1]; + for (; a != last_out && (_res_cap[a] == 0 || + !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; + stack[stack_head] = a == last_out ? -1 : a; + } + + while (stack_head >= 0 && stack[stack_head] == -1) { + processed[v] = true; + proc_vector[++proc_head] = v; + if (--stack_head >= 0) { + // Find the next admissible outgoing arc + v = _source[stack[stack_head]]; + p = pi[v]; + a = stack[stack_head] + 1; + last_out = _first_out[v+1]; + for (; a != last_out && (_res_cap[a] == 0 || + !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; + stack[stack_head] = a == last_out ? -1 : a; + } + } + } + } + + // Tighten potentials and epsilon + if (--iter > 0) { + for (int u = 0; u != _res_node_num; ++u) { + level[u] = 0; + } + for (int i = proc_head; i > 0; --i) { + int u = proc_vector[i]; + double p = pi[u]; + int l = level[u] + 1; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + int v = _target[a]; + if (_res_cap[a] > 0 && tol.negative(_cost[a] + p - pi[v]) && + l > level[v]) level[v] = l; + } + } + + // Modify potentials + double q = std::numeric_limits::max(); + for (int u = 0; u != _res_node_num; ++u) { + int lu = level[u]; + double p, pu = pi[u]; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] == 0) continue; + int v = _target[a]; + int ld = lu - level[v]; + if (ld > 0) { + p = (_cost[a] + pu - pi[v] + epsilon) / (ld + 1); + if (p < q) q = p; + } + } + } + for (int u = 0; u != _res_node_num; ++u) { + pi[u] -= q * level[u]; + } + + // Modify epsilon + epsilon = 0; + for (int u = 0; u != _res_node_num; ++u) { + double curr, pu = pi[u]; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] == 0) continue; + curr = _cost[a] + pu - pi[_target[a]]; + if (-curr > epsilon) epsilon = -curr; + } + } + } else { + typedef HowardMmc MMC; + typedef typename BellmanFord + ::template SetDistMap::Create BF; + + // Set epsilon to the minimum cycle mean + buildResidualNetwork(); + MMC mmc(_sgr, _cost_map); + mmc.findCycleMean(); + epsilon = -mmc.cycleMean(); + Cost cycle_cost = mmc.cycleCost(); + int cycle_size = mmc.cycleSize(); + + // Compute feasible potentials for the current epsilon + for (int i = 0; i != int(_cost_vec.size()); ++i) { + _cost_vec[i] = cycle_size * _cost_vec[i] - cycle_cost; + } + BF bf(_sgr, _cost_map); + bf.distMap(_pi_map); + bf.init(0); + bf.start(); + for (int u = 0; u != _res_node_num; ++u) { + pi[u] = static_cast(_pi[u]) / cycle_size; + } + + iter = limit; + } + } + } + + }; //class CycleCanceling + + ///@} + +} //namespace lemon + +#endif //LEMON_CYCLE_CANCELING_H diff --git a/lemon/dfs.h b/lemon/dfs.h --- a/lemon/dfs.h +++ b/lemon/dfs.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -47,7 +47,7 @@ /// ///The type of the map that stores the predecessor ///arcs of the %DFS paths. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap PredMap; ///Instantiates a \c PredMap. @@ -62,7 +62,8 @@ ///The type of the map that indicates which nodes are processed. ///The type of the map that indicates which nodes are processed. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. typedef NullMap ProcessedMap; ///Instantiates a \c ProcessedMap. @@ -81,7 +82,8 @@ ///The type of the map that indicates which nodes are reached. ///The type of the map that indicates which nodes are reached. - ///It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. typedef typename Digraph::template NodeMap ReachedMap; ///Instantiates a \c ReachedMap. @@ -96,7 +98,7 @@ ///The type of the map that stores the distances of the nodes. ///The type of the map that stores the distances of the nodes. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap DistMap; ///Instantiates a \c DistMap. @@ -120,6 +122,11 @@ /// ///\tparam GR The type of the digraph the algorithm runs on. ///The default type is \ref ListDigraph. + ///\tparam TR The traits class that defines various types used by the + ///algorithm. By default, it is \ref DfsDefaultTraits + ///"DfsDefaultTraits". + ///In most cases, this parameter should not be set directly, + ///consider to use the named template parameters instead. #ifdef DOXYGEN template @@ -224,7 +231,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c PredMap type. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. template struct SetPredMap : public Dfs > { typedef Dfs > Create; @@ -244,7 +251,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c DistMap type. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. template struct SetDistMap : public Dfs< Digraph, SetDistMapTraits > { typedef Dfs > Create; @@ -264,7 +271,8 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c ReachedMap type. - ///It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. template struct SetReachedMap : public Dfs< Digraph, SetReachedMapTraits > { typedef Dfs< Digraph, SetReachedMapTraits > Create; @@ -284,7 +292,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c ProcessedMap type. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. template struct SetProcessedMap : public Dfs< Digraph, SetProcessedMapTraits > { typedef Dfs< Digraph, SetProcessedMapTraits > Create; @@ -411,8 +419,8 @@ ///\name Execution Control ///The simplest way to execute the DFS algorithm is to use one of the ///member functions called \ref run(Node) "run()".\n - ///If you need more control on the execution, first you have to call - ///\ref init(), then you can add a source node with \ref addSource() + ///If you need better control on the execution, you have to call + ///\ref init() first, then you can add a source node with \ref addSource() ///and perform the actual computation with \ref start(). ///This procedure can be repeated if there are nodes that have not ///been reached. @@ -632,12 +640,8 @@ ///Runs the algorithm to visit all nodes in the digraph. - ///This method runs the %DFS algorithm in order to compute the - ///%DFS path to each node. - /// - ///The algorithm computes - ///- the %DFS tree (forest), - ///- the distance of each node from the root(s) in the %DFS tree. + ///This method runs the %DFS algorithm in order to visit all nodes + ///in the digraph. /// ///\note d.run() is just a shortcut of the following code. ///\code @@ -669,9 +673,9 @@ ///@{ - ///The DFS path to a node. + ///The DFS path to the given node. - ///Returns the DFS path to a node. + ///Returns the DFS path to the given node from the root(s). /// ///\warning \c t should be reached from the root(s). /// @@ -679,9 +683,9 @@ ///must be called before using this function. Path path(Node t) const { return Path(*G, *_pred, t); } - ///The distance of a node from the root(s). + ///The distance of the given node from the root(s). - ///Returns the distance of a node from the root(s). + ///Returns the distance of the given node from the root(s). /// ///\warning If node \c v is not reached from the root(s), then ///the return value of this function is undefined. @@ -690,7 +694,7 @@ ///must be called before using this function. int dist(Node v) const { return (*_dist)[v]; } - ///Returns the 'previous arc' of the %DFS tree for a node. + ///Returns the 'previous arc' of the %DFS tree for the given node. ///This function returns the 'previous arc' of the %DFS tree for the ///node \c v, i.e. it returns the last arc of a %DFS path from a @@ -698,21 +702,21 @@ ///root(s) or if \c v is a root. /// ///The %DFS tree used here is equal to the %DFS tree used in - ///\ref predNode(). + ///\ref predNode() and \ref predMap(). /// ///\pre Either \ref run(Node) "run()" or \ref init() ///must be called before using this function. Arc predArc(Node v) const { return (*_pred)[v];} - ///Returns the 'previous node' of the %DFS tree. + ///Returns the 'previous node' of the %DFS tree for the given node. ///This function returns the 'previous node' of the %DFS ///tree for the node \c v, i.e. it returns the last but one node - ///from a %DFS path from a root to \c v. It is \c INVALID + ///of a %DFS path from a root to \c v. It is \c INVALID ///if \c v is not reached from the root(s) or if \c v is a root. /// ///The %DFS tree used here is equal to the %DFS tree used in - ///\ref predArc(). + ///\ref predArc() and \ref predMap(). /// ///\pre Either \ref run(Node) "run()" or \ref init() ///must be called before using this function. @@ -733,13 +737,13 @@ ///predecessor arcs. /// ///Returns a const reference to the node map that stores the predecessor - ///arcs, which form the DFS tree. + ///arcs, which form the DFS tree (forest). /// ///\pre Either \ref run(Node) "run()" or \ref init() ///must be called before using this function. const PredMap &predMap() const { return *_pred;} - ///Checks if a node is reached from the root(s). + ///Checks if the given node. node is reached from the root(s). ///Returns \c true if \c v is reached from the root(s). /// @@ -765,7 +769,7 @@ /// ///The type of the map that stores the predecessor ///arcs of the %DFS paths. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap PredMap; ///Instantiates a PredMap. @@ -780,8 +784,8 @@ ///The type of the map that indicates which nodes are processed. ///The type of the map that indicates which nodes are processed. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. - ///By default it is a NullMap. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. typedef NullMap ProcessedMap; ///Instantiates a ProcessedMap. @@ -800,7 +804,8 @@ ///The type of the map that indicates which nodes are reached. ///The type of the map that indicates which nodes are reached. - ///It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + ///It must conform to + ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. typedef typename Digraph::template NodeMap ReachedMap; ///Instantiates a ReachedMap. @@ -815,7 +820,7 @@ ///The type of the map that stores the distances of the nodes. ///The type of the map that stores the distances of the nodes. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap DistMap; ///Instantiates a DistMap. @@ -830,18 +835,14 @@ ///The type of the DFS paths. ///The type of the DFS paths. - ///It must meet the \ref concepts::Path "Path" concept. + ///It must conform to the \ref concepts::Path "Path" concept. typedef lemon::Path Path; }; /// Default traits class used by DfsWizard - /// To make it easier to use Dfs algorithm - /// we have created a wizard class. - /// This \ref DfsWizard class needs default traits, - /// as well as the \ref Dfs class. - /// The \ref DfsWizardBase is a class to be the default traits of the - /// \ref DfsWizard class. + /// Default traits class used by DfsWizard. + /// \tparam GR The type of the digraph. template class DfsWizardBase : public DfsWizardDefaultTraits { @@ -869,7 +870,7 @@ public: /// Constructor. - /// This constructor does not require parameters, therefore it initiates + /// This constructor does not require parameters, it initiates /// all of the attributes to \c 0. DfsWizardBase() : _g(0), _reached(0), _processed(0), _pred(0), _dist(0), _path(0), _di(0) {} @@ -894,12 +895,14 @@ /// /// This class should only be used through the \ref dfs() function, /// which makes it easier to use the algorithm. + /// + /// \tparam TR The traits class that defines various types used by the + /// algorithm. template class DfsWizard : public TR { typedef TR Base; - ///The type of the digraph the algorithm runs on. typedef typename TR::Digraph Digraph; typedef typename Digraph::Node Node; @@ -907,16 +910,10 @@ typedef typename Digraph::Arc Arc; typedef typename Digraph::OutArcIt OutArcIt; - ///\brief The type of the map that stores the predecessor - ///arcs of the DFS paths. typedef typename TR::PredMap PredMap; - ///\brief The type of the map that stores the distances of the nodes. typedef typename TR::DistMap DistMap; - ///\brief The type of the map that indicates which nodes are reached. typedef typename TR::ReachedMap ReachedMap; - ///\brief The type of the map that indicates which nodes are processed. typedef typename TR::ProcessedMap ProcessedMap; - ///The type of the DFS paths typedef typename TR::Path Path; public: @@ -986,8 +983,8 @@ ///Runs DFS algorithm to visit all nodes in the digraph. - ///This method runs DFS algorithm in order to compute - ///the DFS path to each node. + ///This method runs DFS algorithm in order to visit all nodes + ///in the digraph. void run() { run(INVALID); @@ -999,11 +996,12 @@ static PredMap *createPredMap(const Digraph &) { return 0; }; SetPredMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting PredMap object. + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the predecessor map. /// - ///\ref named-func-param "Named parameter" - ///for setting PredMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the predecessor arcs of the nodes. template DfsWizard > predMap(const T &t) { @@ -1017,11 +1015,12 @@ static ReachedMap *createReachedMap(const Digraph &) { return 0; }; SetReachedMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting ReachedMap object. + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the reached map. /// - /// \ref named-func-param "Named parameter" - ///for setting ReachedMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are reached. template DfsWizard > reachedMap(const T &t) { @@ -1035,11 +1034,13 @@ static DistMap *createDistMap(const Digraph &) { return 0; }; SetDistMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting DistMap object. + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the distance map. /// - /// \ref named-func-param "Named parameter" - ///for setting DistMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the distances of the nodes calculated + ///by the algorithm. template DfsWizard > distMap(const T &t) { @@ -1053,11 +1054,12 @@ static ProcessedMap *createProcessedMap(const Digraph &) { return 0; }; SetProcessedMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting ProcessedMap object. + + ///\brief \ref named-func-param "Named parameter" for setting + ///the processed map. /// - /// \ref named-func-param "Named parameter" - ///for setting ProcessedMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are processed. template DfsWizard > processedMap(const T &t) { @@ -1208,7 +1210,8 @@ /// \brief The type of the map that indicates which nodes are reached. /// /// The type of the map that indicates which nodes are reached. - /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + /// It must conform to the + /// \ref concepts::ReadWriteMap "ReadWriteMap" concept. typedef typename Digraph::template NodeMap ReachedMap; /// \brief Instantiates a ReachedMap. @@ -1246,11 +1249,11 @@ /// \ref DfsVisitor "DfsVisitor" is an empty visitor, which /// does not observe the DFS events. If you want to observe the DFS /// events, you should implement your own visitor class. - /// \tparam TR Traits class to set various data types used by the - /// algorithm. The default traits class is - /// \ref DfsVisitDefaultTraits "DfsVisitDefaultTraits". - /// See \ref DfsVisitDefaultTraits for the documentation of - /// a DFS visit traits class. + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref DfsVisitDefaultTraits + /// "DfsVisitDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. #ifdef DOXYGEN template #else @@ -1369,8 +1372,8 @@ /// \name Execution Control /// The simplest way to execute the DFS algorithm is to use one of the /// member functions called \ref run(Node) "run()".\n - /// If you need more control on the execution, first you have to call - /// \ref init(), then you can add a source node with \ref addSource() + /// If you need better control on the execution, you have to call + /// \ref init() first, then you can add a source node with \ref addSource() /// and perform the actual computation with \ref start(). /// This procedure can be repeated if there are nodes that have not /// been reached. @@ -1583,12 +1586,8 @@ /// \brief Runs the algorithm to visit all nodes in the digraph. - /// This method runs the %DFS algorithm in order to - /// compute the %DFS path to each node. - /// - /// The algorithm computes - /// - the %DFS tree (forest), - /// - the distance of each node from the root(s) in the %DFS tree. + /// This method runs the %DFS algorithm in order to visit all nodes + /// in the digraph. /// /// \note d.run() is just a shortcut of the following code. ///\code @@ -1620,7 +1619,7 @@ ///@{ - /// \brief Checks if a node is reached from the root(s). + /// \brief Checks if the given node is reached from the root(s). /// /// Returns \c true if \c v is reached from the root(s). /// diff --git a/lemon/dheap.h b/lemon/dheap.h new file mode 100644 --- /dev/null +++ b/lemon/dheap.h @@ -0,0 +1,352 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_DHEAP_H +#define LEMON_DHEAP_H + +///\ingroup heaps +///\file +///\brief D-ary heap implementation. + +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + ///\brief D-ary heap data structure. + /// + /// This class implements the \e D-ary \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// The \ref DHeap "D-ary heap" is a generalization of the + /// \ref BinHeap "binary heap" structure, its nodes have at most + /// \c D children, instead of two. + /// \ref BinHeap and \ref QuadHeap are specialized implementations + /// of this structure for D=2 and D=4, respectively. + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam D The degree of the heap, each node have at most \e D + /// children. The default is 16. Powers of two are suggested to use + /// so that the multiplications and divisions needed to traverse the + /// nodes of the heap could be performed faster. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. + /// + ///\sa BinHeap + ///\sa FouraryHeap +#ifdef DOXYGEN + template +#else + template > +#endif + class DHeap { + public: + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + std::vector _data; + Compare _comp; + ItemIntMap &_iim; + + public: + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit DHeap(ItemIntMap &map) : _iim(map) {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + DHeap(ItemIntMap &map, const Compare &comp) + : _iim(map), _comp(comp) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _data.size(); } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _data.empty(); } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { _data.clear(); } + + private: + int parent(int i) { return (i-1)/D; } + int firstChild(int i) { return D*i+1; } + + bool less(const Pair &p1, const Pair &p2) const { + return _comp(p1.second, p2.second); + } + + void bubbleUp(int hole, Pair p) { + int par = parent(hole); + while( hole>0 && less(p,_data[par]) ) { + move(_data[par],hole); + hole = par; + par = parent(hole); + } + move(p, hole); + } + + void bubbleDown(int hole, Pair p, int length) { + if( length>1 ) { + int child = firstChild(hole); + while( child+D<=length ) { + int min=child; + for (int i=1; i0) bubbleDown(0, _data[n], n); + _data.pop_back(); + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. + void erase(const Item &i) { + int h = _iim[i]; + int n = _data.size()-1; + _iim.set(_data[h].first, POST_HEAP); + if( h=0) s=0; + return State(s); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) erase(i); + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + /// \brief Replace an item in the heap. + /// + /// This function replaces item \c i with item \c j. + /// Item \c i must be in the heap, while \c j must be out of the heap. + /// After calling this method, item \c i will be out of the + /// heap and \c j will be in the heap with the same prioriority + /// as item \c i had before. + void replace(const Item& i, const Item& j) { + int idx=_iim[i]; + _iim.set(i, _iim[j]); + _iim.set(j, idx); + _data[idx].first=j; + } + + }; // class DHeap + +} // namespace lemon + +#endif // LEMON_DHEAP_H diff --git a/lemon/dijkstra.h b/lemon/dijkstra.h --- a/lemon/dijkstra.h +++ b/lemon/dijkstra.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -70,9 +70,9 @@ ///The type of the map that stores the arc lengths. ///The type of the map that stores the arc lengths. - ///It must meet the \ref concepts::ReadMap "ReadMap" concept. + ///It must conform to the \ref concepts::ReadMap "ReadMap" concept. typedef LEN LengthMap; - ///The type of the length of the arcs. + ///The type of the arc lengths. typedef typename LEN::Value Value; /// Operation traits for %Dijkstra algorithm. @@ -116,7 +116,7 @@ /// ///The type of the map that stores the predecessor ///arcs of the shortest paths. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap PredMap; ///Instantiates a \c PredMap. @@ -131,8 +131,8 @@ ///The type of the map that indicates which nodes are processed. ///The type of the map that indicates which nodes are processed. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. - ///By default it is a NullMap. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. typedef NullMap ProcessedMap; ///Instantiates a \c ProcessedMap. @@ -151,7 +151,7 @@ ///The type of the map that stores the distances of the nodes. ///The type of the map that stores the distances of the nodes. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap DistMap; ///Instantiates a \c DistMap. @@ -169,6 +169,10 @@ /// \ingroup shortest_path ///This class provides an efficient implementation of the %Dijkstra algorithm. /// + ///The %Dijkstra algorithm solves the single-source shortest path problem + ///when all arc lengths are non-negative. If there are negative lengths, + ///the BellmanFord algorithm should be used instead. + /// ///The arc lengths are passed to the algorithm using a ///\ref concepts::ReadMap "ReadMap", ///so it is easy to change it to any kind of length. @@ -188,6 +192,11 @@ ///relatively time consuming process to compute the arc lengths if ///it is necessary. The default map type is \ref ///concepts::Digraph::ArcMap "GR::ArcMap". + ///\tparam TR The traits class that defines various types used by the + ///algorithm. By default, it is \ref DijkstraDefaultTraits + ///"DijkstraDefaultTraits". + ///In most cases, this parameter should not be set directly, + ///consider to use the named template parameters instead. #ifdef DOXYGEN template #else @@ -201,8 +210,8 @@ ///The type of the digraph the algorithm runs on. typedef typename TR::Digraph Digraph; - ///The type of the length of the arcs. - typedef typename TR::LengthMap::Value Value; + ///The type of the arc lengths. + typedef typename TR::Value Value; ///The type of the map that stores the arc lengths. typedef typename TR::LengthMap LengthMap; ///\brief The type of the map that stores the predecessor arcs of the @@ -304,7 +313,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c PredMap type. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. template struct SetPredMap : public Dijkstra< Digraph, LengthMap, SetPredMapTraits > { @@ -325,7 +334,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c DistMap type. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. template struct SetDistMap : public Dijkstra< Digraph, LengthMap, SetDistMapTraits > { @@ -346,7 +355,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c ProcessedMap type. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. template struct SetProcessedMap : public Dijkstra< Digraph, LengthMap, SetProcessedMapTraits > { @@ -422,7 +431,7 @@ ///automatically created by the algorithm (i.e. the digraph should be ///passed to the constructor of the cross reference and the cross ///reference should be passed to the constructor of the heap). - ///However external heap and cross reference objects could also be + ///However, external heap and cross reference objects could also be ///passed to the algorithm using the \ref heap() function before ///calling \ref run(Node) "run()" or \ref init(). ///\sa SetHeap @@ -443,6 +452,7 @@ /// ///\ref named-templ-param "Named parameter" for setting ///\c OperationTraits type. + /// For more information, see \ref DijkstraDefaultOperationTraits. template struct SetOperationTraits : public Dijkstra > { @@ -584,8 +594,8 @@ ///\name Execution Control ///The simplest way to execute the %Dijkstra algorithm is to use ///one of the member functions called \ref run(Node) "run()".\n - ///If you need more control on the execution, first you have to call - ///\ref init(), then you can add several source nodes with + ///If you need better control on the execution, you have to call + ///\ref init() first, then you can add several source nodes with ///\ref addSource(). Finally the actual path computation can be ///performed with one of the \ref start() functions. @@ -801,14 +811,14 @@ ///\name Query Functions ///The results of the %Dijkstra algorithm can be obtained using these ///functions.\n - ///Either \ref run(Node) "run()" or \ref start() should be called + ///Either \ref run(Node) "run()" or \ref init() should be called ///before using them. ///@{ - ///The shortest path to a node. + ///The shortest path to the given node. - ///Returns the shortest path to a node. + ///Returns the shortest path to the given node from the root(s). /// ///\warning \c t should be reached from the root(s). /// @@ -816,9 +826,9 @@ ///must be called before using this function. Path path(Node t) const { return Path(*G, *_pred, t); } - ///The distance of a node from the root(s). + ///The distance of the given node from the root(s). - ///Returns the distance of a node from the root(s). + ///Returns the distance of the given node from the root(s). /// ///\warning If node \c v is not reached from the root(s), then ///the return value of this function is undefined. @@ -827,29 +837,31 @@ ///must be called before using this function. Value dist(Node v) const { return (*_dist)[v]; } - ///Returns the 'previous arc' of the shortest path tree for a node. - + ///\brief Returns the 'previous arc' of the shortest path tree for + ///the given node. + /// ///This function returns the 'previous arc' of the shortest path ///tree for the node \c v, i.e. it returns the last arc of a ///shortest path from a root to \c v. It is \c INVALID if \c v ///is not reached from the root(s) or if \c v is a root. /// ///The shortest path tree used here is equal to the shortest path - ///tree used in \ref predNode(). + ///tree used in \ref predNode() and \ref predMap(). /// ///\pre Either \ref run(Node) "run()" or \ref init() ///must be called before using this function. Arc predArc(Node v) const { return (*_pred)[v]; } - ///Returns the 'previous node' of the shortest path tree for a node. - + ///\brief Returns the 'previous node' of the shortest path tree for + ///the given node. + /// ///This function returns the 'previous node' of the shortest path ///tree for the node \c v, i.e. it returns the last but one node - ///from a shortest path from a root to \c v. It is \c INVALID + ///of a shortest path from a root to \c v. It is \c INVALID ///if \c v is not reached from the root(s) or if \c v is a root. /// ///The shortest path tree used here is equal to the shortest path - ///tree used in \ref predArc(). + ///tree used in \ref predArc() and \ref predMap(). /// ///\pre Either \ref run(Node) "run()" or \ref init() ///must be called before using this function. @@ -870,13 +882,13 @@ ///predecessor arcs. /// ///Returns a const reference to the node map that stores the predecessor - ///arcs, which form the shortest path tree. + ///arcs, which form the shortest path tree (forest). /// ///\pre Either \ref run(Node) "run()" or \ref init() ///must be called before using this function. const PredMap &predMap() const { return *_pred;} - ///Checks if a node is reached from the root(s). + ///Checks if the given node is reached from the root(s). ///Returns \c true if \c v is reached from the root(s). /// @@ -895,9 +907,9 @@ bool processed(Node v) const { return (*_heap_cross_ref)[v] == Heap::POST_HEAP; } - ///The current distance of a node from the root(s). + ///The current distance of the given node from the root(s). - ///Returns the current distance of a node from the root(s). + ///Returns the current distance of the given node from the root(s). ///It may be decreased in the following processes. /// ///\pre Either \ref run(Node) "run()" or \ref init() @@ -924,9 +936,9 @@ ///The type of the map that stores the arc lengths. ///The type of the map that stores the arc lengths. - ///It must meet the \ref concepts::ReadMap "ReadMap" concept. + ///It must conform to the \ref concepts::ReadMap "ReadMap" concept. typedef LEN LengthMap; - ///The type of the length of the arcs. + ///The type of the arc lengths. typedef typename LEN::Value Value; /// Operation traits for Dijkstra algorithm. @@ -973,7 +985,7 @@ /// ///The type of the map that stores the predecessor ///arcs of the shortest paths. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap PredMap; ///Instantiates a PredMap. @@ -988,8 +1000,8 @@ ///The type of the map that indicates which nodes are processed. ///The type of the map that indicates which nodes are processed. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. - ///By default it is a NullMap. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. + ///By default, it is a NullMap. typedef NullMap ProcessedMap; ///Instantiates a ProcessedMap. @@ -1008,7 +1020,7 @@ ///The type of the map that stores the distances of the nodes. ///The type of the map that stores the distances of the nodes. - ///It must meet the \ref concepts::WriteMap "WriteMap" concept. + ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. typedef typename Digraph::template NodeMap DistMap; ///Instantiates a DistMap. @@ -1023,18 +1035,15 @@ ///The type of the shortest paths. ///The type of the shortest paths. - ///It must meet the \ref concepts::Path "Path" concept. + ///It must conform to the \ref concepts::Path "Path" concept. typedef lemon::Path Path; }; /// Default traits class used by DijkstraWizard - /// To make it easier to use Dijkstra algorithm - /// we have created a wizard class. - /// This \ref DijkstraWizard class needs default traits, - /// as well as the \ref Dijkstra class. - /// The \ref DijkstraWizardBase is a class to be the default traits of the - /// \ref DijkstraWizard class. + /// Default traits class used by DijkstraWizard. + /// \tparam GR The type of the digraph. + /// \tparam LEN The type of the length map. template class DijkstraWizardBase : public DijkstraWizardDefaultTraits { @@ -1088,12 +1097,14 @@ /// /// This class should only be used through the \ref dijkstra() function, /// which makes it easier to use the algorithm. + /// + /// \tparam TR The traits class that defines various types used by the + /// algorithm. template class DijkstraWizard : public TR { typedef TR Base; - ///The type of the digraph the algorithm runs on. typedef typename TR::Digraph Digraph; typedef typename Digraph::Node Node; @@ -1101,20 +1112,12 @@ typedef typename Digraph::Arc Arc; typedef typename Digraph::OutArcIt OutArcIt; - ///The type of the map that stores the arc lengths. typedef typename TR::LengthMap LengthMap; - ///The type of the length of the arcs. typedef typename LengthMap::Value Value; - ///\brief The type of the map that stores the predecessor - ///arcs of the shortest paths. typedef typename TR::PredMap PredMap; - ///The type of the map that stores the distances of the nodes. typedef typename TR::DistMap DistMap; - ///The type of the map that indicates which nodes are processed. typedef typename TR::ProcessedMap ProcessedMap; - ///The type of the shortest paths typedef typename TR::Path Path; - ///The heap type used by the dijkstra algorithm. typedef typename TR::Heap Heap; public: @@ -1186,11 +1189,12 @@ static PredMap *createPredMap(const Digraph &) { return 0; }; SetPredMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting PredMap object. + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the predecessor map. /// - ///\ref named-func-param "Named parameter" - ///for setting PredMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the predecessor arcs of the nodes. template DijkstraWizard > predMap(const T &t) { @@ -1204,11 +1208,13 @@ static DistMap *createDistMap(const Digraph &) { return 0; }; SetDistMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting DistMap object. + + ///\brief \ref named-templ-param "Named parameter" for setting + ///the distance map. /// - ///\ref named-func-param "Named parameter" - ///for setting DistMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that stores the distances of the nodes calculated + ///by the algorithm. template DijkstraWizard > distMap(const T &t) { @@ -1222,11 +1228,12 @@ static ProcessedMap *createProcessedMap(const Digraph &) { return 0; }; SetProcessedMapBase(const TR &b) : TR(b) {} }; - ///\brief \ref named-func-param "Named parameter" - ///for setting ProcessedMap object. + + ///\brief \ref named-func-param "Named parameter" for setting + ///the processed map. /// - /// \ref named-func-param "Named parameter" - ///for setting ProcessedMap object. + ///\ref named-templ-param "Named parameter" function for setting + ///the map that indicates which nodes are processed. template DijkstraWizard > processedMap(const T &t) { @@ -1239,6 +1246,7 @@ typedef T Path; SetPathBase(const TR &b) : TR(b) {} }; + ///\brief \ref named-func-param "Named parameter" ///for getting the shortest path to the target node. /// diff --git a/lemon/dim2.h b/lemon/dim2.h --- a/lemon/dim2.h +++ b/lemon/dim2.h @@ -21,16 +21,9 @@ #include -///\ingroup misc +///\ingroup geomdat ///\file ///\brief A simple two dimensional vector and a bounding box implementation -/// -/// The class \ref lemon::dim2::Point "dim2::Point" implements -/// a two dimensional vector with the usual operations. -/// -/// The class \ref lemon::dim2::Box "dim2::Box" can be used to determine -/// the rectangular bounding box of a set of -/// \ref lemon::dim2::Point "dim2::Point"'s. namespace lemon { @@ -40,7 +33,7 @@ ///tools for handling two dimensional coordinates namespace dim2 { - /// \addtogroup misc + /// \addtogroup geomdat /// @{ /// Two dimensional vector (plain vector) diff --git a/lemon/dimacs.h b/lemon/dimacs.h --- a/lemon/dimacs.h +++ b/lemon/dimacs.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -61,7 +61,7 @@ ///Discover the type of a DIMACS file ///This function starts seeking the beginning of the given file for the - ///problem type and size info. + ///problem type and size info. ///The found data is returned in a special struct that can be evaluated ///and passed to the appropriate reader function. DimacsDescriptor dimacsType(std::istream& is) @@ -212,7 +212,7 @@ infty = std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : std::numeric_limits::max(); - + while (is >> c) { switch (c) { case 'c': // comment line @@ -237,7 +237,7 @@ getline(is, str); e = g.addArc(nodes[i], nodes[j]); capacity.set(e, _cap); - } + } else if (desc.type==DimacsDescriptor::MAX) { is >> i >> j >> _cap; getline(is, str); @@ -362,11 +362,11 @@ { g.addArc(s,t); } - + /// \brief DIMACS plain (di)graph reader function. /// /// This function reads a plain (di)graph without any designated nodes - /// and maps (e.g. a matching instance) from DIMACS format, i.e. from + /// and maps (e.g. a matching instance) from DIMACS format, i.e. from /// DIMACS files having a line starting with /// \code /// p mat @@ -392,7 +392,7 @@ for (int k = 1; k <= desc.nodeNum; ++k) { nodes[k] = g.addNode(); } - + while (is >> c) { switch (c) { case 'c': // comment line diff --git a/lemon/edge_set.h b/lemon/edge_set.h --- a/lemon/edge_set.h +++ b/lemon/edge_set.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -255,13 +255,14 @@ /// that node can be removed from the underlying graph, in this case /// all arcs incident to the given node is erased from the arc set. /// + /// This class fully conforms to the \ref concepts::Digraph + /// "Digraph" concept. + /// It provides only linear time counting for nodes and arcs. + /// /// \param GR The type of the graph which shares its node set with /// this class. Its interface must conform to the /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" /// concept. - /// - /// This class fully conforms to the \ref concepts::Digraph - /// "Digraph" concept. template class ListArcSet : public ArcSetExtender > { typedef ArcSetExtender > Parent; @@ -685,13 +686,14 @@ /// be removed from the underlying graph, in this case all edges /// incident to the given node is erased from the arc set. /// + /// This class fully conforms to the \ref concepts::Graph "Graph" + /// concept. + /// It provides only linear time counting for nodes, edges and arcs. + /// /// \param GR The type of the graph which shares its node set /// with this class. Its interface must conform to the /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" /// concept. - /// - /// This class fully conforms to the \ref concepts::Graph "Graph" - /// concept. template class ListEdgeSet : public EdgeSetExtender > { typedef EdgeSetExtender > Parent; @@ -867,7 +869,7 @@ arc.id = arcs.size() - 1; } - void next(Arc& arc) const { + static void next(Arc& arc) { --arc.id; } @@ -954,13 +956,14 @@ /// single-linked lists for enumerate outgoing and incoming /// arcs. Therefore the arcs cannot be erased from the arc sets. /// + /// This class fully conforms to the \ref concepts::Digraph "Digraph" + /// concept. + /// It provides only linear time counting for nodes and arcs. + /// /// \warning If a node is erased from the underlying graph and this /// node is the source or target of one arc in the arc set, then /// the arc set is invalidated, and it cannot be used anymore. The /// validity can be checked with the \c valid() member function. - /// - /// This class fully conforms to the \ref concepts::Digraph - /// "Digraph" concept. template class SmartArcSet : public ArcSetExtender > { typedef ArcSetExtender > Parent; @@ -1173,7 +1176,7 @@ arc.id = arcs.size() - 1; } - void next(Arc& arc) const { + static void next(Arc& arc) { --arc.id; } @@ -1181,7 +1184,7 @@ arc.id = arcs.size() / 2 - 1; } - void next(Edge& arc) const { + static void next(Edge& arc) { --arc.id; } @@ -1304,13 +1307,14 @@ /// single-linked lists for enumerate incident edges. Therefore the /// edges cannot be erased from the edge sets. /// + /// This class fully conforms to the \ref concepts::Graph "Graph" + /// concept. + /// It provides only linear time counting for nodes, edges and arcs. + /// /// \warning If a node is erased from the underlying graph and this /// node is incident to one edge in the edge set, then the edge set /// is invalidated, and it cannot be used anymore. The validity can /// be checked with the \c valid() member function. - /// - /// This class fully conforms to the \ref concepts::Graph - /// "Graph" concept. template class SmartEdgeSet : public EdgeSetExtender > { typedef EdgeSetExtender > Parent; diff --git a/lemon/euler.h b/lemon/euler.h --- a/lemon/euler.h +++ b/lemon/euler.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -26,7 +26,7 @@ /// \ingroup graph_properties /// \file -/// \brief Euler tour iterators and a function for checking the \e Eulerian +/// \brief Euler tour iterators and a function for checking the \e Eulerian /// property. /// ///This file provides Euler tour iterators and a function to check @@ -41,7 +41,7 @@ ///graph (if there exists) and it converts to the \c Arc type of the digraph. /// ///For example, if the given digraph has an Euler tour (i.e it has only one - ///non-trivial component and the in-degree is equal to the out-degree + ///non-trivial component and the in-degree is equal to the out-degree ///for all nodes), then the following code will put the arcs of \c g ///to the vector \c et according to an Euler tour of \c g. ///\code @@ -138,7 +138,7 @@ ///\e undirected graph (if there exists) and it converts to the \c Arc ///and \c Edge types of the graph. /// - ///For example, if the given graph has an Euler tour (i.e it has only one + ///For example, if the given graph has an Euler tour (i.e it has only one ///non-trivial component and the degree of each node is even), ///the following code will print the arc IDs according to an ///Euler tour of \c g. @@ -147,7 +147,7 @@ /// std::cout << g.id(Edge(e)) << std::eol; /// } ///\endcode - ///Although this iterator is for undirected graphs, it still returns + ///Although this iterator is for undirected graphs, it still returns ///arcs in order to indicate the direction of the tour. ///(But arcs convert to edges, of course.) /// @@ -233,7 +233,7 @@ /// Postfix incrementation. /// - ///\warning This incrementation returns an \c Arc (which converts to + ///\warning This incrementation returns an \c Arc (which converts to ///an \c Edge), not an \ref EulerIt, as one may expect. Arc operator++(int) { diff --git a/lemon/fib_heap.h b/lemon/fib_heap.h --- a/lemon/fib_heap.h +++ b/lemon/fib_heap.h @@ -20,53 +20,49 @@ #define LEMON_FIB_HEAP_H ///\file -///\ingroup auxdat -///\brief Fibonacci Heap implementation. +///\ingroup heaps +///\brief Fibonacci heap implementation. #include +#include #include #include namespace lemon { - /// \ingroup auxdat + /// \ingroup heaps /// - ///\brief Fibonacci Heap. + /// \brief Fibonacci heap data structure. /// - ///This class implements the \e Fibonacci \e heap data structure. A \e heap - ///is a data structure for storing items with specified values called \e - ///priorities in such a way that finding the item with minimum priority is - ///efficient. \c CMP specifies the ordering of the priorities. In a heap - ///one can change the priority of an item, add or erase an item, etc. + /// This class implements the \e Fibonacci \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". /// - ///The methods \ref increase and \ref erase are not efficient in a Fibonacci - ///heap. In case of many calls to these operations, it is better to use a - ///\ref BinHeap "binary heap". + /// The methods \ref increase() and \ref erase() are not efficient in a + /// Fibonacci heap. In case of many calls of these operations, it is + /// better to use other heap structure, e.g. \ref BinHeap "binary heap". /// - ///\param PRIO Type of the priority of the items. - ///\param IM A read and writable Item int map, used internally - ///to handle the cross references. - ///\param CMP A class for the ordering of the priorities. The - ///default is \c std::less. - /// - ///\sa BinHeap - ///\sa Dijkstra + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. #ifdef DOXYGEN - template + template #else - template > + template > #endif class FibHeap { public: - ///\e + + /// Type of the item-int map. typedef IM ItemIntMap; - ///\e - typedef PRIO Prio; - ///\e + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. typedef typename ItemIntMap::Key Item; - ///\e + /// Type of the item-priority pairs. typedef std::pair Pair; - ///\e + /// Functor type for comparing the priorities. typedef CMP Compare; private: @@ -80,10 +76,10 @@ public: - /// \brief Type to represent the items states. + /// \brief Type to represent the states of the items. /// - /// Each Item element have a state associated to it. It may be "in heap", - /// "pre heap" or "post heap". The latter two are indifferent from the + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the /// heap's point of view, but may be useful to the user. /// /// The item-int map must be initialized in such way that it assigns @@ -94,60 +90,54 @@ POST_HEAP = -2 ///< = -2. }; - /// \brief The constructor + /// \brief Constructor. /// - /// \c map should be given to the constructor, since it is - /// used internally to handle the cross references. + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. explicit FibHeap(ItemIntMap &map) : _minimum(0), _iim(map), _num() {} - /// \brief The constructor + /// \brief Constructor. /// - /// \c map should be given to the constructor, since it is used - /// internally to handle the cross references. \c comp is an - /// object for ordering of the priorities. + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. FibHeap(ItemIntMap &map, const Compare &comp) : _minimum(0), _iim(map), _comp(comp), _num() {} /// \brief The number of items stored in the heap. /// - /// Returns the number of items stored in the heap. + /// This function returns the number of items stored in the heap. int size() const { return _num; } - /// \brief Checks if the heap stores no items. + /// \brief Check if the heap is empty. /// - /// Returns \c true if and only if the heap stores no items. + /// This function returns \c true if the heap is empty. bool empty() const { return _num==0; } - /// \brief Make empty this heap. + /// \brief Make the heap empty. /// - /// Make empty this heap. It does not change the cross reference - /// map. If you want to reuse a heap what is not surely empty you - /// should first clear the heap and after that you should set the - /// cross reference map for each item to \c PRE_HEAP. + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. void clear() { _data.clear(); _minimum = 0; _num = 0; } - /// \brief \c item gets to the heap with priority \c value independently - /// if \c item was already there. + /// \brief Insert an item into the heap with the given priority. /// - /// This method calls \ref push(\c item, \c value) if \c item is not - /// stored in the heap and it calls \ref decrease(\c item, \c value) or - /// \ref increase(\c item, \c value) otherwise. - void set (const Item& item, const Prio& value) { - int i=_iim[item]; - if ( i >= 0 && _data[i].in ) { - if ( _comp(value, _data[i].prio) ) decrease(item, value); - if ( _comp(_data[i].prio, value) ) increase(item, value); - } else push(item, value); - } - - /// \brief Adds \c item to the heap with priority \c value. - /// - /// Adds \c item to the heap with priority \c value. - /// \pre \c item must not be stored in the heap. - void push (const Item& item, const Prio& value) { + /// This function inserts the given item into the heap with the + /// given priority. + /// \param item The item to insert. + /// \param prio The priority of the item. + /// \pre \e item must not be stored in the heap. + void push (const Item& item, const Prio& prio) { int i=_iim[item]; if ( i < 0 ) { int s=_data.size(); @@ -168,47 +158,37 @@ _data[i].right_neighbor=_data[_minimum].right_neighbor; _data[_minimum].right_neighbor=i; _data[i].left_neighbor=_minimum; - if ( _comp( value, _data[_minimum].prio) ) _minimum=i; + if ( _comp( prio, _data[_minimum].prio) ) _minimum=i; } else { _data[i].right_neighbor=_data[i].left_neighbor=i; _minimum=i; } - _data[i].prio=value; + _data[i].prio=prio; ++_num; } - /// \brief Returns the item with minimum priority relative to \c Compare. + /// \brief Return the item having minimum priority. /// - /// This method returns the item with minimum priority relative to \c - /// Compare. - /// \pre The heap must be nonempty. + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. Item top() const { return _data[_minimum].name; } - /// \brief Returns the minimum priority relative to \c Compare. + /// \brief The minimum priority. /// - /// It returns the minimum priority relative to \c Compare. - /// \pre The heap must be nonempty. - const Prio& prio() const { return _data[_minimum].prio; } + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + Prio prio() const { return _data[_minimum].prio; } - /// \brief Returns the priority of \c item. + /// \brief Remove the item having minimum priority. /// - /// It returns the priority of \c item. - /// \pre \c item must be in the heap. - const Prio& operator[](const Item& item) const { - return _data[_iim[item]].prio; - } - - /// \brief Deletes the item with minimum priority relative to \c Compare. - /// - /// This method deletes the item with minimum priority relative to \c - /// Compare from the heap. + /// This function removes the item having minimum priority. /// \pre The heap must be non-empty. void pop() { /*The first case is that there are only one root.*/ if ( _data[_minimum].left_neighbor==_minimum ) { _data[_minimum].in=false; if ( _data[_minimum].degree!=0 ) { - makeroot(_data[_minimum].child); + makeRoot(_data[_minimum].child); _minimum=_data[_minimum].child; balance(); } @@ -221,7 +201,7 @@ int child=_data[_minimum].child; int last_child=_data[child].left_neighbor; - makeroot(child); + makeRoot(child); _data[left].right_neighbor=child; _data[child].left_neighbor=left; @@ -234,10 +214,12 @@ --_num; } - /// \brief Deletes \c item from the heap. + /// \brief Remove the given item from the heap. /// - /// This method deletes \c item from the heap, if \c item was already - /// stored in the heap. It is quite inefficient in Fibonacci heaps. + /// This function removes the given item from the heap if it is + /// already stored. + /// \param item The item to delete. + /// \pre \e item must be in the heap. void erase (const Item& item) { int i=_iim[item]; @@ -252,43 +234,68 @@ } } - /// \brief Decreases the priority of \c item to \c value. + /// \brief The priority of the given item. /// - /// This method decreases the priority of \c item to \c value. - /// \pre \c item must be stored in the heap with priority at least \c - /// value relative to \c Compare. - void decrease (Item item, const Prio& value) { + /// This function returns the priority of the given item. + /// \param item The item. + /// \pre \e item must be in the heap. + Prio operator[](const Item& item) const { + return _data[_iim[item]].prio; + } + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// \param item The item. + /// \param prio The priority. + void set (const Item& item, const Prio& prio) { int i=_iim[item]; - _data[i].prio=value; + if ( i >= 0 && _data[i].in ) { + if ( _comp(prio, _data[i].prio) ) decrease(item, prio); + if ( _comp(_data[i].prio, prio) ) increase(item, prio); + } else push(item, prio); + } + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param item The item. + /// \param prio The priority. + /// \pre \e item must be stored in the heap with priority at least \e prio. + void decrease (const Item& item, const Prio& prio) { + int i=_iim[item]; + _data[i].prio=prio; int p=_data[i].parent; - if ( p!=-1 && _comp(value, _data[p].prio) ) { + if ( p!=-1 && _comp(prio, _data[p].prio) ) { cut(i,p); cascade(p); } - if ( _comp(value, _data[_minimum].prio) ) _minimum=i; + if ( _comp(prio, _data[_minimum].prio) ) _minimum=i; } - /// \brief Increases the priority of \c item to \c value. + /// \brief Increase the priority of an item to the given value. /// - /// This method sets the priority of \c item to \c value. Though - /// there is no precondition on the priority of \c item, this - /// method should be used only if it is indeed necessary to increase - /// (relative to \c Compare) the priority of \c item, because this - /// method is inefficient. - void increase (Item item, const Prio& value) { + /// This function increases the priority of an item to the given value. + /// \param item The item. + /// \param prio The priority. + /// \pre \e item must be stored in the heap with priority at most \e prio. + void increase (const Item& item, const Prio& prio) { erase(item); - push(item, value); + push(item, prio); } - - /// \brief Returns if \c item is in, has already been in, or has never - /// been in the heap. + /// \brief Return the state of an item. /// - /// This method returns PRE_HEAP if \c item has never been in the - /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP - /// otherwise. In the latter case it is possible that \c item will - /// get back to the heap again. + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param item The item. State state(const Item &item) const { int i=_iim[item]; if( i>=0 ) { @@ -298,11 +305,11 @@ return State(i); } - /// \brief Sets the state of the \c item in the heap. + /// \brief Set the state of an item in the heap. /// - /// Sets the state of the \c item in the heap. It can be used to - /// manually clear the heap when it is important to achive the - /// better time _complexity. + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. /// \param i The item. /// \param st The state. It should not be \c IN_HEAP. void state(const Item& i, State st) { @@ -365,7 +372,7 @@ } while ( s != m ); } - void makeroot(int c) { + void makeRoot(int c) { int s=c; do { _data[s].parent=-1; diff --git a/lemon/fractional_matching.h b/lemon/fractional_matching.h new file mode 100644 --- /dev/null +++ b/lemon/fractional_matching.h @@ -0,0 +1,2139 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_FRACTIONAL_MATCHING_H +#define LEMON_FRACTIONAL_MATCHING_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +///\ingroup matching +///\file +///\brief Fractional matching algorithms in general graphs. + +namespace lemon { + + /// \brief Default traits class of MaxFractionalMatching class. + /// + /// Default traits class of MaxFractionalMatching class. + /// \tparam GR Graph type. + template + struct MaxFractionalMatchingDefaultTraits { + + /// \brief The type of the graph the algorithm runs on. + typedef GR Graph; + + /// \brief The type of the map that stores the matching. + /// + /// The type of the map that stores the matching arcs. + /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + typedef typename Graph::template NodeMap MatchingMap; + + /// \brief Instantiates a MatchingMap. + /// + /// This function instantiates a \ref MatchingMap. + /// \param graph The graph for which we would like to define + /// the matching map. + static MatchingMap* createMatchingMap(const Graph& graph) { + return new MatchingMap(graph); + } + + /// \brief The elevator type used by MaxFractionalMatching algorithm. + /// + /// The elevator type used by MaxFractionalMatching algorithm. + /// + /// \sa Elevator + /// \sa LinkedElevator + typedef LinkedElevator Elevator; + + /// \brief Instantiates an Elevator. + /// + /// This function instantiates an \ref Elevator. + /// \param graph The graph for which we would like to define + /// the elevator. + /// \param max_level The maximum level of the elevator. + static Elevator* createElevator(const Graph& graph, int max_level) { + return new Elevator(graph, max_level); + } + }; + + /// \ingroup matching + /// + /// \brief Max cardinality fractional matching + /// + /// This class provides an implementation of fractional matching + /// algorithm based on push-relabel principle. + /// + /// The maximum cardinality fractional matching is a relaxation of the + /// maximum cardinality matching problem where the odd set constraints + /// are omitted. + /// It can be formulated with the following linear program. + /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] + /// \f[x_e \ge 0\quad \forall e\in E\f] + /// \f[\max \sum_{e\in E}x_e\f] + /// where \f$\delta(X)\f$ is the set of edges incident to a node in + /// \f$X\f$. The result can be represented as the union of a + /// matching with one value edges and a set of odd length cycles + /// with half value edges. + /// + /// The algorithm calculates an optimal fractional matching and a + /// barrier. The number of adjacents of any node set minus the size + /// of node set is a lower bound on the uncovered nodes in the + /// graph. For maximum matching a barrier is computed which + /// maximizes this difference. + /// + /// The algorithm can be executed with the run() function. After it + /// the matching (the primal solution) and the barrier (the dual + /// solution) can be obtained using the query functions. + /// + /// The primal solution is multiplied by + /// \ref MaxFractionalMatching::primalScale "2". + /// + /// \tparam GR The undirected graph type the algorithm runs on. +#ifdef DOXYGEN + template +#else + template > +#endif + class MaxFractionalMatching { + public: + + /// \brief The \ref MaxFractionalMatchingDefaultTraits "traits + /// class" of the algorithm. + typedef TR Traits; + /// The type of the graph the algorithm runs on. + typedef typename TR::Graph Graph; + /// The type of the matching map. + typedef typename TR::MatchingMap MatchingMap; + /// The type of the elevator. + typedef typename TR::Elevator Elevator; + + /// \brief Scaling factor for primal solution + /// + /// Scaling factor for primal solution. + static const int primalScale = 2; + + private: + + const Graph &_graph; + int _node_num; + bool _allow_loops; + int _empty_level; + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + bool _local_matching; + MatchingMap *_matching; + + bool _local_level; + Elevator *_level; + + typedef typename Graph::template NodeMap InDegMap; + InDegMap *_indeg; + + void createStructures() { + _node_num = countNodes(_graph); + + if (!_matching) { + _local_matching = true; + _matching = Traits::createMatchingMap(_graph); + } + if (!_level) { + _local_level = true; + _level = Traits::createElevator(_graph, _node_num); + } + if (!_indeg) { + _indeg = new InDegMap(_graph); + } + } + + void destroyStructures() { + if (_local_matching) { + delete _matching; + } + if (_local_level) { + delete _level; + } + if (_indeg) { + delete _indeg; + } + } + + void postprocessing() { + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_indeg)[n] != 0) continue; + _indeg->set(n, -1); + Node u = n; + while ((*_matching)[u] != INVALID) { + Node v = _graph.target((*_matching)[u]); + _indeg->set(v, -1); + Arc a = _graph.oppositeArc((*_matching)[u]); + u = _graph.target((*_matching)[v]); + _indeg->set(u, -1); + _matching->set(v, a); + } + } + + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_indeg)[n] != 1) continue; + _indeg->set(n, -1); + + int num = 1; + Node u = _graph.target((*_matching)[n]); + while (u != n) { + _indeg->set(u, -1); + u = _graph.target((*_matching)[u]); + ++num; + } + if (num % 2 == 0 && num > 2) { + Arc prev = _graph.oppositeArc((*_matching)[n]); + Node v = _graph.target((*_matching)[n]); + u = _graph.target((*_matching)[v]); + _matching->set(v, prev); + while (u != n) { + prev = _graph.oppositeArc((*_matching)[u]); + v = _graph.target((*_matching)[u]); + u = _graph.target((*_matching)[v]); + _matching->set(v, prev); + } + } + } + } + + public: + + typedef MaxFractionalMatching Create; + + ///\name Named Template Parameters + + ///@{ + + template + struct SetMatchingMapTraits : public Traits { + typedef T MatchingMap; + static MatchingMap *createMatchingMap(const Graph&) { + LEMON_ASSERT(false, "MatchingMap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// MatchingMap type + /// + /// \ref named-templ-param "Named parameter" for setting MatchingMap + /// type. + template + struct SetMatchingMap + : public MaxFractionalMatching > { + typedef MaxFractionalMatching > Create; + }; + + template + struct SetElevatorTraits : public Traits { + typedef T Elevator; + static Elevator *createElevator(const Graph&, int) { + LEMON_ASSERT(false, "Elevator is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// Elevator type + /// + /// \ref named-templ-param "Named parameter" for setting Elevator + /// type. If this named parameter is used, then an external + /// elevator object must be passed to the algorithm using the + /// \ref elevator(Elevator&) "elevator()" function before calling + /// \ref run() or \ref init(). + /// \sa SetStandardElevator + template + struct SetElevator + : public MaxFractionalMatching > { + typedef MaxFractionalMatching > Create; + }; + + template + struct SetStandardElevatorTraits : public Traits { + typedef T Elevator; + static Elevator *createElevator(const Graph& graph, int max_level) { + return new Elevator(graph, max_level); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// Elevator type with automatic allocation + /// + /// \ref named-templ-param "Named parameter" for setting Elevator + /// type with automatic allocation. + /// The Elevator should have standard constructor interface to be + /// able to automatically created by the algorithm (i.e. the + /// graph and the maximum level should be passed to it). + /// However an external elevator object could also be passed to the + /// algorithm with the \ref elevator(Elevator&) "elevator()" function + /// before calling \ref run() or \ref init(). + /// \sa SetElevator + template + struct SetStandardElevator + : public MaxFractionalMatching > { + typedef MaxFractionalMatching > Create; + }; + + /// @} + + protected: + + MaxFractionalMatching() {} + + public: + + /// \brief Constructor + /// + /// Constructor. + /// + MaxFractionalMatching(const Graph &graph, bool allow_loops = true) + : _graph(graph), _allow_loops(allow_loops), + _local_matching(false), _matching(0), + _local_level(false), _level(0), _indeg(0) + {} + + ~MaxFractionalMatching() { + destroyStructures(); + } + + /// \brief Sets the matching map. + /// + /// Sets the matching map. + /// If you don't use this function before calling \ref run() or + /// \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated map, + /// of course. + /// \return (*this) + MaxFractionalMatching& matchingMap(MatchingMap& map) { + if (_local_matching) { + delete _matching; + _local_matching = false; + } + _matching = ↦ + return *this; + } + + /// \brief Sets the elevator used by algorithm. + /// + /// Sets the elevator used by algorithm. + /// If you don't use this function before calling \ref run() or + /// \ref init(), an instance will be allocated automatically. + /// The destructor deallocates this automatically allocated elevator, + /// of course. + /// \return (*this) + MaxFractionalMatching& elevator(Elevator& elevator) { + if (_local_level) { + delete _level; + _local_level = false; + } + _level = &elevator; + return *this; + } + + /// \brief Returns a const reference to the elevator. + /// + /// Returns a const reference to the elevator. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const Elevator& elevator() const { + return *_level; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to use one of the + /// member functions called \c run(). \n + /// If you need more control on the execution, first + /// you must call \ref init() and then one variant of the start() + /// member. + + /// @{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures and sets the initial + /// matching. + void init() { + createStructures(); + + _level->initStart(); + for (NodeIt n(_graph); n != INVALID; ++n) { + _indeg->set(n, 0); + _matching->set(n, INVALID); + _level->initAddItem(n); + } + _level->initFinish(); + + _empty_level = _node_num; + for (NodeIt n(_graph); n != INVALID; ++n) { + for (OutArcIt a(_graph, n); a != INVALID; ++a) { + if (_graph.target(a) == n && !_allow_loops) continue; + _matching->set(n, a); + Node v = _graph.target((*_matching)[n]); + _indeg->set(v, (*_indeg)[v] + 1); + break; + } + } + + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_indeg)[n] == 0) { + _level->activate(n); + } + } + } + + /// \brief Starts the algorithm and computes a fractional matching + /// + /// The algorithm computes a maximum fractional matching. + /// + /// \param postprocess The algorithm computes first a matching + /// which is a union of a matching with one value edges, cycles + /// with half value edges and even length paths with half value + /// edges. If the parameter is true, then after the push-relabel + /// algorithm it postprocesses the matching to contain only + /// matching edges and half value odd cycles. + void start(bool postprocess = true) { + Node n; + while ((n = _level->highestActive()) != INVALID) { + int level = _level->highestActiveLevel(); + int new_level = _level->maxLevel(); + for (InArcIt a(_graph, n); a != INVALID; ++a) { + Node u = _graph.source(a); + if (n == u && !_allow_loops) continue; + Node v = _graph.target((*_matching)[u]); + if ((*_level)[v] < level) { + _indeg->set(v, (*_indeg)[v] - 1); + if ((*_indeg)[v] == 0) { + _level->activate(v); + } + _matching->set(u, a); + _indeg->set(n, (*_indeg)[n] + 1); + _level->deactivate(n); + goto no_more_push; + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + if (new_level + 1 < _level->maxLevel()) { + _level->liftHighestActive(new_level + 1); + } else { + _level->liftHighestActiveToTop(); + } + if (_level->emptyLevel(level)) { + _level->liftToTop(level); + } + no_more_push: + ; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] == INVALID) continue; + Node u = _graph.target((*_matching)[n]); + if ((*_indeg)[u] > 1) { + _indeg->set(u, (*_indeg)[u] - 1); + _matching->set(n, INVALID); + } + } + if (postprocess) { + postprocessing(); + } + } + + /// \brief Starts the algorithm and computes a perfect fractional + /// matching + /// + /// The algorithm computes a perfect fractional matching. If it + /// does not exists, then the algorithm returns false and the + /// matching is undefined and the barrier. + /// + /// \param postprocess The algorithm computes first a matching + /// which is a union of a matching with one value edges, cycles + /// with half value edges and even length paths with half value + /// edges. If the parameter is true, then after the push-relabel + /// algorithm it postprocesses the matching to contain only + /// matching edges and half value odd cycles. + bool startPerfect(bool postprocess = true) { + Node n; + while ((n = _level->highestActive()) != INVALID) { + int level = _level->highestActiveLevel(); + int new_level = _level->maxLevel(); + for (InArcIt a(_graph, n); a != INVALID; ++a) { + Node u = _graph.source(a); + if (n == u && !_allow_loops) continue; + Node v = _graph.target((*_matching)[u]); + if ((*_level)[v] < level) { + _indeg->set(v, (*_indeg)[v] - 1); + if ((*_indeg)[v] == 0) { + _level->activate(v); + } + _matching->set(u, a); + _indeg->set(n, (*_indeg)[n] + 1); + _level->deactivate(n); + goto no_more_push; + } else if (new_level > (*_level)[v]) { + new_level = (*_level)[v]; + } + } + + if (new_level + 1 < _level->maxLevel()) { + _level->liftHighestActive(new_level + 1); + } else { + _level->liftHighestActiveToTop(); + _empty_level = _level->maxLevel() - 1; + return false; + } + if (_level->emptyLevel(level)) { + _level->liftToTop(level); + _empty_level = level; + return false; + } + no_more_push: + ; + } + if (postprocess) { + postprocessing(); + } + return true; + } + + /// \brief Runs the algorithm + /// + /// Just a shortcut for the next code: + ///\code + /// init(); + /// start(); + ///\endcode + void run(bool postprocess = true) { + init(); + start(postprocess); + } + + /// \brief Runs the algorithm to find a perfect fractional matching + /// + /// Just a shortcut for the next code: + ///\code + /// init(); + /// startPerfect(); + ///\endcode + bool runPerfect(bool postprocess = true) { + init(); + return startPerfect(postprocess); + } + + ///@} + + /// \name Query Functions + /// The result of the %Matching algorithm can be obtained using these + /// functions.\n + /// Before the use of these functions, + /// either run() or start() must be called. + ///@{ + + + /// \brief Return the number of covered nodes in the matching. + /// + /// This function returns the number of covered nodes in the matching. + /// + /// \pre Either run() or start() must be called before using this function. + int matchingSize() const { + int num = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + ++num; + } + } + return num; + } + + /// \brief Returns a const reference to the matching map. + /// + /// Returns a const reference to the node map storing the found + /// fractional matching. This method can be called after + /// running the algorithm. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const MatchingMap& matchingMap() const { + return *_matching; + } + + /// \brief Return \c true if the given edge is in the matching. + /// + /// This function returns \c true if the given edge is in the + /// found matching. The result is scaled by \ref primalScale + /// "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + int matching(const Edge& edge) const { + return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) + + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); + } + + /// \brief Return the fractional matching arc (or edge) incident + /// to the given node. + /// + /// This function returns one of the fractional matching arc (or + /// edge) incident to the given node in the found matching or \c + /// INVALID if the node is not covered by the matching or if the + /// node is on an odd length cycle then it is the successor edge + /// on the cycle. + /// + /// \pre Either run() or start() must be called before using this function. + Arc matching(const Node& node) const { + return (*_matching)[node]; + } + + /// \brief Returns true if the node is in the barrier + /// + /// The barrier is a subset of the nodes. If the nodes in the + /// barrier have less adjacent nodes than the size of the barrier, + /// then at least as much nodes cannot be covered as the + /// difference of the two subsets. + bool barrier(const Node& node) const { + return (*_level)[node] >= _empty_level; + } + + /// @} + + }; + + /// \ingroup matching + /// + /// \brief Weighted fractional matching in general graphs + /// + /// This class provides an efficient implementation of fractional + /// matching algorithm. The implementation uses priority queues and + /// provides \f$O(nm\log n)\f$ time complexity. + /// + /// The maximum weighted fractional matching is a relaxation of the + /// maximum weighted matching problem where the odd set constraints + /// are omitted. + /// It can be formulated with the following linear program. + /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] + /// \f[x_e \ge 0\quad \forall e\in E\f] + /// \f[\max \sum_{e\in E}x_ew_e\f] + /// where \f$\delta(X)\f$ is the set of edges incident to a node in + /// \f$X\f$. The result must be the union of a matching with one + /// value edges and a set of odd length cycles with half value edges. + /// + /// The algorithm calculates an optimal fractional matching and a + /// proof of the optimality. The solution of the dual problem can be + /// used to check the result of the algorithm. The dual linear + /// problem is the following. + /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f] + /// \f[y_u \ge 0 \quad \forall u \in V\f] + /// \f[\min \sum_{u \in V}y_u \f] + /// + /// The algorithm can be executed with the run() function. + /// After it the matching (the primal solution) and the dual solution + /// can be obtained using the query functions. + /// + /// The primal solution is multiplied by + /// \ref MaxWeightedFractionalMatching::primalScale "2". + /// If the value type is integer, then the dual + /// solution is scaled by + /// \ref MaxWeightedFractionalMatching::dualScale "4". + /// + /// \tparam GR The undirected graph type the algorithm runs on. + /// \tparam WM The type edge weight map. The default type is + /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". +#ifdef DOXYGEN + template +#else + template > +#endif + class MaxWeightedFractionalMatching { + public: + + /// The graph type of the algorithm + typedef GR Graph; + /// The type of the edge weight map + typedef WM WeightMap; + /// The value type of the edge weights + typedef typename WeightMap::Value Value; + + /// The type of the matching map + typedef typename Graph::template NodeMap + MatchingMap; + + /// \brief Scaling factor for primal solution + /// + /// Scaling factor for primal solution. + static const int primalScale = 2; + + /// \brief Scaling factor for dual solution + /// + /// Scaling factor for dual solution. It is equal to 4 or 1 + /// according to the value type. + static const int dualScale = + std::numeric_limits::is_integer ? 4 : 1; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + typedef typename Graph::template NodeMap NodePotential; + + const Graph& _graph; + const WeightMap& _weight; + + MatchingMap* _matching; + NodePotential* _node_potential; + + int _node_num; + bool _allow_loops; + + enum Status { + EVEN = -1, MATCHED = 0, ODD = 1 + }; + + typedef typename Graph::template NodeMap StatusMap; + StatusMap* _status; + + typedef typename Graph::template NodeMap PredMap; + PredMap* _pred; + + typedef ExtendFindEnum TreeSet; + + IntNodeMap *_tree_set_index; + TreeSet *_tree_set; + + IntNodeMap *_delta1_index; + BinHeap *_delta1; + + IntNodeMap *_delta2_index; + BinHeap *_delta2; + + IntEdgeMap *_delta3_index; + BinHeap *_delta3; + + Value _delta_sum; + + void createStructures() { + _node_num = countNodes(_graph); + + if (!_matching) { + _matching = new MatchingMap(_graph); + } + if (!_node_potential) { + _node_potential = new NodePotential(_graph); + } + if (!_status) { + _status = new StatusMap(_graph); + } + if (!_pred) { + _pred = new PredMap(_graph); + } + if (!_tree_set) { + _tree_set_index = new IntNodeMap(_graph); + _tree_set = new TreeSet(*_tree_set_index); + } + if (!_delta1) { + _delta1_index = new IntNodeMap(_graph); + _delta1 = new BinHeap(*_delta1_index); + } + if (!_delta2) { + _delta2_index = new IntNodeMap(_graph); + _delta2 = new BinHeap(*_delta2_index); + } + if (!_delta3) { + _delta3_index = new IntEdgeMap(_graph); + _delta3 = new BinHeap(*_delta3_index); + } + } + + void destroyStructures() { + if (_matching) { + delete _matching; + } + if (_node_potential) { + delete _node_potential; + } + if (_status) { + delete _status; + } + if (_pred) { + delete _pred; + } + if (_tree_set) { + delete _tree_set_index; + delete _tree_set; + } + if (_delta1) { + delete _delta1_index; + delete _delta1; + } + if (_delta2) { + delete _delta2_index; + delete _delta2; + } + if (_delta3) { + delete _delta3_index; + delete _delta3; + } + } + + void matchedToEven(Node node, int tree) { + _tree_set->insert(node, tree); + _node_potential->set(node, (*_node_potential)[node] + _delta_sum); + _delta1->push(node, (*_node_potential)[node]); + + if (_delta2->state(node) == _delta2->IN_HEAP) { + _delta2->erase(node); + } + + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + if (node == v) { + if (_allow_loops && _graph.direction(a)) { + _delta3->push(a, rw / 2); + } + } else if ((*_status)[v] == EVEN) { + _delta3->push(a, rw / 2); + } else if ((*_status)[v] == MATCHED) { + if (_delta2->state(v) != _delta2->IN_HEAP) { + _pred->set(v, a); + _delta2->push(v, rw); + } else if ((*_delta2)[v] > rw) { + _pred->set(v, a); + _delta2->decrease(v, rw); + } + } + } + } + + void matchedToOdd(Node node, int tree) { + _tree_set->insert(node, tree); + _node_potential->set(node, (*_node_potential)[node] - _delta_sum); + + if (_delta2->state(node) == _delta2->IN_HEAP) { + _delta2->erase(node); + } + } + + void evenToMatched(Node node, int tree) { + _delta1->erase(node); + _node_potential->set(node, (*_node_potential)[node] - _delta_sum); + Arc min = INVALID; + Value minrw = std::numeric_limits::max(); + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + + if (node == v) { + if (_allow_loops && _graph.direction(a)) { + _delta3->erase(a); + } + } else if ((*_status)[v] == EVEN) { + _delta3->erase(a); + if (minrw > rw) { + min = _graph.oppositeArc(a); + minrw = rw; + } + } else if ((*_status)[v] == MATCHED) { + if ((*_pred)[v] == a) { + Arc mina = INVALID; + Value minrwa = std::numeric_limits::max(); + for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) { + Node va = _graph.target(aa); + if ((*_status)[va] != EVEN || + _tree_set->find(va) == tree) continue; + Value rwa = (*_node_potential)[v] + (*_node_potential)[va] - + dualScale * _weight[aa]; + if (minrwa > rwa) { + minrwa = rwa; + mina = aa; + } + } + if (mina != INVALID) { + _pred->set(v, mina); + _delta2->increase(v, minrwa); + } else { + _pred->set(v, INVALID); + _delta2->erase(v); + } + } + } + } + if (min != INVALID) { + _pred->set(node, min); + _delta2->push(node, minrw); + } else { + _pred->set(node, INVALID); + } + } + + void oddToMatched(Node node) { + _node_potential->set(node, (*_node_potential)[node] + _delta_sum); + Arc min = INVALID; + Value minrw = std::numeric_limits::max(); + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + if ((*_status)[v] != EVEN) continue; + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + + if (minrw > rw) { + min = _graph.oppositeArc(a); + minrw = rw; + } + } + if (min != INVALID) { + _pred->set(node, min); + _delta2->push(node, minrw); + } else { + _pred->set(node, INVALID); + } + } + + void alternatePath(Node even, int tree) { + Node odd; + + _status->set(even, MATCHED); + evenToMatched(even, tree); + + Arc prev = (*_matching)[even]; + while (prev != INVALID) { + odd = _graph.target(prev); + even = _graph.target((*_pred)[odd]); + _matching->set(odd, (*_pred)[odd]); + _status->set(odd, MATCHED); + oddToMatched(odd); + + prev = (*_matching)[even]; + _status->set(even, MATCHED); + _matching->set(even, _graph.oppositeArc((*_matching)[odd])); + evenToMatched(even, tree); + } + } + + void destroyTree(int tree) { + for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) { + if ((*_status)[n] == EVEN) { + _status->set(n, MATCHED); + evenToMatched(n, tree); + } else if ((*_status)[n] == ODD) { + _status->set(n, MATCHED); + oddToMatched(n); + } + } + _tree_set->eraseClass(tree); + } + + + void unmatchNode(const Node& node) { + int tree = _tree_set->find(node); + + alternatePath(node, tree); + destroyTree(tree); + + _matching->set(node, INVALID); + } + + + void augmentOnEdge(const Edge& edge) { + Node left = _graph.u(edge); + int left_tree = _tree_set->find(left); + + alternatePath(left, left_tree); + destroyTree(left_tree); + _matching->set(left, _graph.direct(edge, true)); + + Node right = _graph.v(edge); + int right_tree = _tree_set->find(right); + + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.direct(edge, false)); + } + + void augmentOnArc(const Arc& arc) { + Node left = _graph.source(arc); + _status->set(left, MATCHED); + _matching->set(left, arc); + _pred->set(left, arc); + + Node right = _graph.target(arc); + int right_tree = _tree_set->find(right); + + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.oppositeArc(arc)); + } + + void extendOnArc(const Arc& arc) { + Node base = _graph.target(arc); + int tree = _tree_set->find(base); + + Node odd = _graph.source(arc); + _tree_set->insert(odd, tree); + _status->set(odd, ODD); + matchedToOdd(odd, tree); + _pred->set(odd, arc); + + Node even = _graph.target((*_matching)[odd]); + _tree_set->insert(even, tree); + _status->set(even, EVEN); + matchedToEven(even, tree); + } + + void cycleOnEdge(const Edge& edge, int tree) { + Node nca = INVALID; + std::vector left_path, right_path; + + { + std::set left_set, right_set; + Node left = _graph.u(edge); + left_path.push_back(left); + left_set.insert(left); + + Node right = _graph.v(edge); + right_path.push_back(right); + right_set.insert(right); + + while (true) { + + if (left_set.find(right) != left_set.end()) { + nca = right; + break; + } + + if ((*_matching)[left] == INVALID) break; + + left = _graph.target((*_matching)[left]); + left_path.push_back(left); + left = _graph.target((*_pred)[left]); + left_path.push_back(left); + + left_set.insert(left); + + if (right_set.find(left) != right_set.end()) { + nca = left; + break; + } + + if ((*_matching)[right] == INVALID) break; + + right = _graph.target((*_matching)[right]); + right_path.push_back(right); + right = _graph.target((*_pred)[right]); + right_path.push_back(right); + + right_set.insert(right); + + } + + if (nca == INVALID) { + if ((*_matching)[left] == INVALID) { + nca = right; + while (left_set.find(nca) == left_set.end()) { + nca = _graph.target((*_matching)[nca]); + right_path.push_back(nca); + nca = _graph.target((*_pred)[nca]); + right_path.push_back(nca); + } + } else { + nca = left; + while (right_set.find(nca) == right_set.end()) { + nca = _graph.target((*_matching)[nca]); + left_path.push_back(nca); + nca = _graph.target((*_pred)[nca]); + left_path.push_back(nca); + } + } + } + } + + alternatePath(nca, tree); + Arc prev; + + prev = _graph.direct(edge, true); + for (int i = 0; left_path[i] != nca; i += 2) { + _matching->set(left_path[i], prev); + _status->set(left_path[i], MATCHED); + evenToMatched(left_path[i], tree); + + prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]); + _status->set(left_path[i + 1], MATCHED); + oddToMatched(left_path[i + 1]); + } + _matching->set(nca, prev); + + for (int i = 0; right_path[i] != nca; i += 2) { + _status->set(right_path[i], MATCHED); + evenToMatched(right_path[i], tree); + + _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]); + _status->set(right_path[i + 1], MATCHED); + oddToMatched(right_path[i + 1]); + } + + destroyTree(tree); + } + + void extractCycle(const Arc &arc) { + Node left = _graph.source(arc); + Node odd = _graph.target((*_matching)[left]); + Arc prev; + while (odd != left) { + Node even = _graph.target((*_matching)[odd]); + prev = (*_matching)[odd]; + odd = _graph.target((*_matching)[even]); + _matching->set(even, _graph.oppositeArc(prev)); + } + _matching->set(left, arc); + + Node right = _graph.target(arc); + int right_tree = _tree_set->find(right); + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.oppositeArc(arc)); + } + + public: + + /// \brief Constructor + /// + /// Constructor. + MaxWeightedFractionalMatching(const Graph& graph, const WeightMap& weight, + bool allow_loops = true) + : _graph(graph), _weight(weight), _matching(0), + _node_potential(0), _node_num(0), _allow_loops(allow_loops), + _status(0), _pred(0), + _tree_set_index(0), _tree_set(0), + + _delta1_index(0), _delta1(0), + _delta2_index(0), _delta2(0), + _delta3_index(0), _delta3(0), + + _delta_sum() {} + + ~MaxWeightedFractionalMatching() { + destroyStructures(); + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to use the + /// \ref run() member function. + + ///@{ + + /// \brief Initialize the algorithm + /// + /// This function initializes the algorithm. + void init() { + createStructures(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_delta1_index)[n] = _delta1->PRE_HEAP; + (*_delta2_index)[n] = _delta2->PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + + _delta1->clear(); + _delta2->clear(); + _delta3->clear(); + _tree_set->clear(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + Value max = 0; + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + if (_graph.target(e) == n && !_allow_loops) continue; + if ((dualScale * _weight[e]) / 2 > max) { + max = (dualScale * _weight[e]) / 2; + } + } + _node_potential->set(n, max); + _delta1->push(n, max); + + _tree_set->insert(n); + + _matching->set(n, INVALID); + _status->set(n, EVEN); + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + Node left = _graph.u(e); + Node right = _graph.v(e); + if (left == right && !_allow_loops) continue; + _delta3->push(e, ((*_node_potential)[left] + + (*_node_potential)[right] - + dualScale * _weight[e]) / 2); + } + } + + /// \brief Start the algorithm + /// + /// This function starts the algorithm. + /// + /// \pre \ref init() must be called before using this function. + void start() { + enum OpType { + D1, D2, D3 + }; + + int unmatched = _node_num; + while (unmatched > 0) { + Value d1 = !_delta1->empty() ? + _delta1->prio() : std::numeric_limits::max(); + + Value d2 = !_delta2->empty() ? + _delta2->prio() : std::numeric_limits::max(); + + Value d3 = !_delta3->empty() ? + _delta3->prio() : std::numeric_limits::max(); + + _delta_sum = d3; OpType ot = D3; + if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; } + if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } + + switch (ot) { + case D1: + { + Node n = _delta1->top(); + unmatchNode(n); + --unmatched; + } + break; + case D2: + { + Node n = _delta2->top(); + Arc a = (*_pred)[n]; + if ((*_matching)[n] == INVALID) { + augmentOnArc(a); + --unmatched; + } else { + Node v = _graph.target((*_matching)[n]); + if ((*_matching)[n] != + _graph.oppositeArc((*_matching)[v])) { + extractCycle(a); + --unmatched; + } else { + extendOnArc(a); + } + } + } break; + case D3: + { + Edge e = _delta3->top(); + + Node left = _graph.u(e); + Node right = _graph.v(e); + + int left_tree = _tree_set->find(left); + int right_tree = _tree_set->find(right); + + if (left_tree == right_tree) { + cycleOnEdge(e, left_tree); + --unmatched; + } else { + augmentOnEdge(e); + unmatched -= 2; + } + } break; + } + } + } + + /// \brief Run the algorithm. + /// + /// This method runs the \c %MaxWeightedFractionalMatching algorithm. + /// + /// \note mwfm.run() is just a shortcut of the following code. + /// \code + /// mwfm.init(); + /// mwfm.start(); + /// \endcode + void run() { + init(); + start(); + } + + /// @} + + /// \name Primal Solution + /// Functions to get the primal solution, i.e. the maximum weighted + /// matching.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the weight of the matching. + /// + /// This function returns the weight of the found matching. This + /// value is scaled by \ref primalScale "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value matchingWeight() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + sum += _weight[(*_matching)[n]]; + } + } + return sum * primalScale / 2; + } + + /// \brief Return the number of covered nodes in the matching. + /// + /// This function returns the number of covered nodes in the matching. + /// + /// \pre Either run() or start() must be called before using this function. + int matchingSize() const { + int num = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + ++num; + } + } + return num; + } + + /// \brief Return \c true if the given edge is in the matching. + /// + /// This function returns \c true if the given edge is in the + /// found matching. The result is scaled by \ref primalScale + /// "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + int matching(const Edge& edge) const { + return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) + + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); + } + + /// \brief Return the fractional matching arc (or edge) incident + /// to the given node. + /// + /// This function returns one of the fractional matching arc (or + /// edge) incident to the given node in the found matching or \c + /// INVALID if the node is not covered by the matching or if the + /// node is on an odd length cycle then it is the successor edge + /// on the cycle. + /// + /// \pre Either run() or start() must be called before using this function. + Arc matching(const Node& node) const { + return (*_matching)[node]; + } + + /// \brief Return a const reference to the matching map. + /// + /// This function returns a const reference to a node map that stores + /// the matching arc (or edge) incident to each node. + const MatchingMap& matchingMap() const { + return *_matching; + } + + /// @} + + /// \name Dual Solution + /// Functions to get the dual solution.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the value of the dual solution. + /// + /// This function returns the value of the dual solution. + /// It should be equal to the primal value scaled by \ref dualScale + /// "dual scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value dualValue() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + sum += nodeValue(n); + } + return sum; + } + + /// \brief Return the dual value (potential) of the given node. + /// + /// This function returns the dual value (potential) of the given node. + /// + /// \pre Either run() or start() must be called before using this function. + Value nodeValue(const Node& n) const { + return (*_node_potential)[n]; + } + + /// @} + + }; + + /// \ingroup matching + /// + /// \brief Weighted fractional perfect matching in general graphs + /// + /// This class provides an efficient implementation of fractional + /// matching algorithm. The implementation uses priority queues and + /// provides \f$O(nm\log n)\f$ time complexity. + /// + /// The maximum weighted fractional perfect matching is a relaxation + /// of the maximum weighted perfect matching problem where the odd + /// set constraints are omitted. + /// It can be formulated with the following linear program. + /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f] + /// \f[x_e \ge 0\quad \forall e\in E\f] + /// \f[\max \sum_{e\in E}x_ew_e\f] + /// where \f$\delta(X)\f$ is the set of edges incident to a node in + /// \f$X\f$. The result must be the union of a matching with one + /// value edges and a set of odd length cycles with half value edges. + /// + /// The algorithm calculates an optimal fractional matching and a + /// proof of the optimality. The solution of the dual problem can be + /// used to check the result of the algorithm. The dual linear + /// problem is the following. + /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f] + /// \f[\min \sum_{u \in V}y_u \f] + /// + /// The algorithm can be executed with the run() function. + /// After it the matching (the primal solution) and the dual solution + /// can be obtained using the query functions. + /// + /// The primal solution is multiplied by + /// \ref MaxWeightedPerfectFractionalMatching::primalScale "2". + /// If the value type is integer, then the dual + /// solution is scaled by + /// \ref MaxWeightedPerfectFractionalMatching::dualScale "4". + /// + /// \tparam GR The undirected graph type the algorithm runs on. + /// \tparam WM The type edge weight map. The default type is + /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". +#ifdef DOXYGEN + template +#else + template > +#endif + class MaxWeightedPerfectFractionalMatching { + public: + + /// The graph type of the algorithm + typedef GR Graph; + /// The type of the edge weight map + typedef WM WeightMap; + /// The value type of the edge weights + typedef typename WeightMap::Value Value; + + /// The type of the matching map + typedef typename Graph::template NodeMap + MatchingMap; + + /// \brief Scaling factor for primal solution + /// + /// Scaling factor for primal solution. + static const int primalScale = 2; + + /// \brief Scaling factor for dual solution + /// + /// Scaling factor for dual solution. It is equal to 4 or 1 + /// according to the value type. + static const int dualScale = + std::numeric_limits::is_integer ? 4 : 1; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + typedef typename Graph::template NodeMap NodePotential; + + const Graph& _graph; + const WeightMap& _weight; + + MatchingMap* _matching; + NodePotential* _node_potential; + + int _node_num; + bool _allow_loops; + + enum Status { + EVEN = -1, MATCHED = 0, ODD = 1 + }; + + typedef typename Graph::template NodeMap StatusMap; + StatusMap* _status; + + typedef typename Graph::template NodeMap PredMap; + PredMap* _pred; + + typedef ExtendFindEnum TreeSet; + + IntNodeMap *_tree_set_index; + TreeSet *_tree_set; + + IntNodeMap *_delta2_index; + BinHeap *_delta2; + + IntEdgeMap *_delta3_index; + BinHeap *_delta3; + + Value _delta_sum; + + void createStructures() { + _node_num = countNodes(_graph); + + if (!_matching) { + _matching = new MatchingMap(_graph); + } + if (!_node_potential) { + _node_potential = new NodePotential(_graph); + } + if (!_status) { + _status = new StatusMap(_graph); + } + if (!_pred) { + _pred = new PredMap(_graph); + } + if (!_tree_set) { + _tree_set_index = new IntNodeMap(_graph); + _tree_set = new TreeSet(*_tree_set_index); + } + if (!_delta2) { + _delta2_index = new IntNodeMap(_graph); + _delta2 = new BinHeap(*_delta2_index); + } + if (!_delta3) { + _delta3_index = new IntEdgeMap(_graph); + _delta3 = new BinHeap(*_delta3_index); + } + } + + void destroyStructures() { + if (_matching) { + delete _matching; + } + if (_node_potential) { + delete _node_potential; + } + if (_status) { + delete _status; + } + if (_pred) { + delete _pred; + } + if (_tree_set) { + delete _tree_set_index; + delete _tree_set; + } + if (_delta2) { + delete _delta2_index; + delete _delta2; + } + if (_delta3) { + delete _delta3_index; + delete _delta3; + } + } + + void matchedToEven(Node node, int tree) { + _tree_set->insert(node, tree); + _node_potential->set(node, (*_node_potential)[node] + _delta_sum); + + if (_delta2->state(node) == _delta2->IN_HEAP) { + _delta2->erase(node); + } + + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + if (node == v) { + if (_allow_loops && _graph.direction(a)) { + _delta3->push(a, rw / 2); + } + } else if ((*_status)[v] == EVEN) { + _delta3->push(a, rw / 2); + } else if ((*_status)[v] == MATCHED) { + if (_delta2->state(v) != _delta2->IN_HEAP) { + _pred->set(v, a); + _delta2->push(v, rw); + } else if ((*_delta2)[v] > rw) { + _pred->set(v, a); + _delta2->decrease(v, rw); + } + } + } + } + + void matchedToOdd(Node node, int tree) { + _tree_set->insert(node, tree); + _node_potential->set(node, (*_node_potential)[node] - _delta_sum); + + if (_delta2->state(node) == _delta2->IN_HEAP) { + _delta2->erase(node); + } + } + + void evenToMatched(Node node, int tree) { + _node_potential->set(node, (*_node_potential)[node] - _delta_sum); + Arc min = INVALID; + Value minrw = std::numeric_limits::max(); + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + + if (node == v) { + if (_allow_loops && _graph.direction(a)) { + _delta3->erase(a); + } + } else if ((*_status)[v] == EVEN) { + _delta3->erase(a); + if (minrw > rw) { + min = _graph.oppositeArc(a); + minrw = rw; + } + } else if ((*_status)[v] == MATCHED) { + if ((*_pred)[v] == a) { + Arc mina = INVALID; + Value minrwa = std::numeric_limits::max(); + for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) { + Node va = _graph.target(aa); + if ((*_status)[va] != EVEN || + _tree_set->find(va) == tree) continue; + Value rwa = (*_node_potential)[v] + (*_node_potential)[va] - + dualScale * _weight[aa]; + if (minrwa > rwa) { + minrwa = rwa; + mina = aa; + } + } + if (mina != INVALID) { + _pred->set(v, mina); + _delta2->increase(v, minrwa); + } else { + _pred->set(v, INVALID); + _delta2->erase(v); + } + } + } + } + if (min != INVALID) { + _pred->set(node, min); + _delta2->push(node, minrw); + } else { + _pred->set(node, INVALID); + } + } + + void oddToMatched(Node node) { + _node_potential->set(node, (*_node_potential)[node] + _delta_sum); + Arc min = INVALID; + Value minrw = std::numeric_limits::max(); + for (InArcIt a(_graph, node); a != INVALID; ++a) { + Node v = _graph.source(a); + if ((*_status)[v] != EVEN) continue; + Value rw = (*_node_potential)[node] + (*_node_potential)[v] - + dualScale * _weight[a]; + + if (minrw > rw) { + min = _graph.oppositeArc(a); + minrw = rw; + } + } + if (min != INVALID) { + _pred->set(node, min); + _delta2->push(node, minrw); + } else { + _pred->set(node, INVALID); + } + } + + void alternatePath(Node even, int tree) { + Node odd; + + _status->set(even, MATCHED); + evenToMatched(even, tree); + + Arc prev = (*_matching)[even]; + while (prev != INVALID) { + odd = _graph.target(prev); + even = _graph.target((*_pred)[odd]); + _matching->set(odd, (*_pred)[odd]); + _status->set(odd, MATCHED); + oddToMatched(odd); + + prev = (*_matching)[even]; + _status->set(even, MATCHED); + _matching->set(even, _graph.oppositeArc((*_matching)[odd])); + evenToMatched(even, tree); + } + } + + void destroyTree(int tree) { + for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) { + if ((*_status)[n] == EVEN) { + _status->set(n, MATCHED); + evenToMatched(n, tree); + } else if ((*_status)[n] == ODD) { + _status->set(n, MATCHED); + oddToMatched(n); + } + } + _tree_set->eraseClass(tree); + } + + void augmentOnEdge(const Edge& edge) { + Node left = _graph.u(edge); + int left_tree = _tree_set->find(left); + + alternatePath(left, left_tree); + destroyTree(left_tree); + _matching->set(left, _graph.direct(edge, true)); + + Node right = _graph.v(edge); + int right_tree = _tree_set->find(right); + + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.direct(edge, false)); + } + + void augmentOnArc(const Arc& arc) { + Node left = _graph.source(arc); + _status->set(left, MATCHED); + _matching->set(left, arc); + _pred->set(left, arc); + + Node right = _graph.target(arc); + int right_tree = _tree_set->find(right); + + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.oppositeArc(arc)); + } + + void extendOnArc(const Arc& arc) { + Node base = _graph.target(arc); + int tree = _tree_set->find(base); + + Node odd = _graph.source(arc); + _tree_set->insert(odd, tree); + _status->set(odd, ODD); + matchedToOdd(odd, tree); + _pred->set(odd, arc); + + Node even = _graph.target((*_matching)[odd]); + _tree_set->insert(even, tree); + _status->set(even, EVEN); + matchedToEven(even, tree); + } + + void cycleOnEdge(const Edge& edge, int tree) { + Node nca = INVALID; + std::vector left_path, right_path; + + { + std::set left_set, right_set; + Node left = _graph.u(edge); + left_path.push_back(left); + left_set.insert(left); + + Node right = _graph.v(edge); + right_path.push_back(right); + right_set.insert(right); + + while (true) { + + if (left_set.find(right) != left_set.end()) { + nca = right; + break; + } + + if ((*_matching)[left] == INVALID) break; + + left = _graph.target((*_matching)[left]); + left_path.push_back(left); + left = _graph.target((*_pred)[left]); + left_path.push_back(left); + + left_set.insert(left); + + if (right_set.find(left) != right_set.end()) { + nca = left; + break; + } + + if ((*_matching)[right] == INVALID) break; + + right = _graph.target((*_matching)[right]); + right_path.push_back(right); + right = _graph.target((*_pred)[right]); + right_path.push_back(right); + + right_set.insert(right); + + } + + if (nca == INVALID) { + if ((*_matching)[left] == INVALID) { + nca = right; + while (left_set.find(nca) == left_set.end()) { + nca = _graph.target((*_matching)[nca]); + right_path.push_back(nca); + nca = _graph.target((*_pred)[nca]); + right_path.push_back(nca); + } + } else { + nca = left; + while (right_set.find(nca) == right_set.end()) { + nca = _graph.target((*_matching)[nca]); + left_path.push_back(nca); + nca = _graph.target((*_pred)[nca]); + left_path.push_back(nca); + } + } + } + } + + alternatePath(nca, tree); + Arc prev; + + prev = _graph.direct(edge, true); + for (int i = 0; left_path[i] != nca; i += 2) { + _matching->set(left_path[i], prev); + _status->set(left_path[i], MATCHED); + evenToMatched(left_path[i], tree); + + prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]); + _status->set(left_path[i + 1], MATCHED); + oddToMatched(left_path[i + 1]); + } + _matching->set(nca, prev); + + for (int i = 0; right_path[i] != nca; i += 2) { + _status->set(right_path[i], MATCHED); + evenToMatched(right_path[i], tree); + + _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]); + _status->set(right_path[i + 1], MATCHED); + oddToMatched(right_path[i + 1]); + } + + destroyTree(tree); + } + + void extractCycle(const Arc &arc) { + Node left = _graph.source(arc); + Node odd = _graph.target((*_matching)[left]); + Arc prev; + while (odd != left) { + Node even = _graph.target((*_matching)[odd]); + prev = (*_matching)[odd]; + odd = _graph.target((*_matching)[even]); + _matching->set(even, _graph.oppositeArc(prev)); + } + _matching->set(left, arc); + + Node right = _graph.target(arc); + int right_tree = _tree_set->find(right); + alternatePath(right, right_tree); + destroyTree(right_tree); + _matching->set(right, _graph.oppositeArc(arc)); + } + + public: + + /// \brief Constructor + /// + /// Constructor. + MaxWeightedPerfectFractionalMatching(const Graph& graph, + const WeightMap& weight, + bool allow_loops = true) + : _graph(graph), _weight(weight), _matching(0), + _node_potential(0), _node_num(0), _allow_loops(allow_loops), + _status(0), _pred(0), + _tree_set_index(0), _tree_set(0), + + _delta2_index(0), _delta2(0), + _delta3_index(0), _delta3(0), + + _delta_sum() {} + + ~MaxWeightedPerfectFractionalMatching() { + destroyStructures(); + } + + /// \name Execution Control + /// The simplest way to execute the algorithm is to use the + /// \ref run() member function. + + ///@{ + + /// \brief Initialize the algorithm + /// + /// This function initializes the algorithm. + void init() { + createStructures(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_delta2_index)[n] = _delta2->PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + + _delta2->clear(); + _delta3->clear(); + _tree_set->clear(); + + for (NodeIt n(_graph); n != INVALID; ++n) { + Value max = - std::numeric_limits::max(); + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + if (_graph.target(e) == n && !_allow_loops) continue; + if ((dualScale * _weight[e]) / 2 > max) { + max = (dualScale * _weight[e]) / 2; + } + } + _node_potential->set(n, max); + + _tree_set->insert(n); + + _matching->set(n, INVALID); + _status->set(n, EVEN); + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + Node left = _graph.u(e); + Node right = _graph.v(e); + if (left == right && !_allow_loops) continue; + _delta3->push(e, ((*_node_potential)[left] + + (*_node_potential)[right] - + dualScale * _weight[e]) / 2); + } + } + + /// \brief Start the algorithm + /// + /// This function starts the algorithm. + /// + /// \pre \ref init() must be called before using this function. + bool start() { + enum OpType { + D2, D3 + }; + + int unmatched = _node_num; + while (unmatched > 0) { + Value d2 = !_delta2->empty() ? + _delta2->prio() : std::numeric_limits::max(); + + Value d3 = !_delta3->empty() ? + _delta3->prio() : std::numeric_limits::max(); + + _delta_sum = d3; OpType ot = D3; + if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } + + if (_delta_sum == std::numeric_limits::max()) { + return false; + } + + switch (ot) { + case D2: + { + Node n = _delta2->top(); + Arc a = (*_pred)[n]; + if ((*_matching)[n] == INVALID) { + augmentOnArc(a); + --unmatched; + } else { + Node v = _graph.target((*_matching)[n]); + if ((*_matching)[n] != + _graph.oppositeArc((*_matching)[v])) { + extractCycle(a); + --unmatched; + } else { + extendOnArc(a); + } + } + } break; + case D3: + { + Edge e = _delta3->top(); + + Node left = _graph.u(e); + Node right = _graph.v(e); + + int left_tree = _tree_set->find(left); + int right_tree = _tree_set->find(right); + + if (left_tree == right_tree) { + cycleOnEdge(e, left_tree); + --unmatched; + } else { + augmentOnEdge(e); + unmatched -= 2; + } + } break; + } + } + return true; + } + + /// \brief Run the algorithm. + /// + /// This method runs the \c %MaxWeightedPerfectFractionalMatching + /// algorithm. + /// + /// \note mwfm.run() is just a shortcut of the following code. + /// \code + /// mwpfm.init(); + /// mwpfm.start(); + /// \endcode + bool run() { + init(); + return start(); + } + + /// @} + + /// \name Primal Solution + /// Functions to get the primal solution, i.e. the maximum weighted + /// matching.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the weight of the matching. + /// + /// This function returns the weight of the found matching. This + /// value is scaled by \ref primalScale "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value matchingWeight() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + sum += _weight[(*_matching)[n]]; + } + } + return sum * primalScale / 2; + } + + /// \brief Return the number of covered nodes in the matching. + /// + /// This function returns the number of covered nodes in the matching. + /// + /// \pre Either run() or start() must be called before using this function. + int matchingSize() const { + int num = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + if ((*_matching)[n] != INVALID) { + ++num; + } + } + return num; + } + + /// \brief Return \c true if the given edge is in the matching. + /// + /// This function returns \c true if the given edge is in the + /// found matching. The result is scaled by \ref primalScale + /// "primal scale". + /// + /// \pre Either run() or start() must be called before using this function. + int matching(const Edge& edge) const { + return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) + + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); + } + + /// \brief Return the fractional matching arc (or edge) incident + /// to the given node. + /// + /// This function returns one of the fractional matching arc (or + /// edge) incident to the given node in the found matching or \c + /// INVALID if the node is not covered by the matching or if the + /// node is on an odd length cycle then it is the successor edge + /// on the cycle. + /// + /// \pre Either run() or start() must be called before using this function. + Arc matching(const Node& node) const { + return (*_matching)[node]; + } + + /// \brief Return a const reference to the matching map. + /// + /// This function returns a const reference to a node map that stores + /// the matching arc (or edge) incident to each node. + const MatchingMap& matchingMap() const { + return *_matching; + } + + /// @} + + /// \name Dual Solution + /// Functions to get the dual solution.\n + /// Either \ref run() or \ref start() function should be called before + /// using them. + + /// @{ + + /// \brief Return the value of the dual solution. + /// + /// This function returns the value of the dual solution. + /// It should be equal to the primal value scaled by \ref dualScale + /// "dual scale". + /// + /// \pre Either run() or start() must be called before using this function. + Value dualValue() const { + Value sum = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + sum += nodeValue(n); + } + return sum; + } + + /// \brief Return the dual value (potential) of the given node. + /// + /// This function returns the dual value (potential) of the given node. + /// + /// \pre Either run() or start() must be called before using this function. + Value nodeValue(const Node& n) const { + return (*_node_potential)[n]; + } + + /// @} + + }; + +} //END OF NAMESPACE LEMON + +#endif //LEMON_FRACTIONAL_MATCHING_H diff --git a/lemon/full_graph.h b/lemon/full_graph.h --- a/lemon/full_graph.h +++ b/lemon/full_graph.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -24,7 +24,7 @@ ///\ingroup graphs ///\file -///\brief FullGraph and FullDigraph classes. +///\brief FullDigraph and FullGraph classes. namespace lemon { @@ -51,7 +51,7 @@ typedef True ArcNumTag; Node operator()(int ix) const { return Node(ix); } - int index(const Node& node) const { return node._id; } + static int index(const Node& node) { return node._id; } Arc arc(const Node& s, const Node& t) const { return Arc(s._id * _node_num + t._id); @@ -148,24 +148,28 @@ /// \ingroup graphs /// - /// \brief A full digraph class. + /// \brief A directed full graph class. /// - /// This is a simple and fast directed full graph implementation. - /// From each node go arcs to each node (including the source node), - /// therefore the number of the arcs in the digraph is the square of - /// the node number. This digraph type is completely static, so you - /// can neither add nor delete either arcs or nodes, and it needs - /// constant space in memory. + /// FullDigraph is a simple and fast implmenetation of directed full + /// (complete) graphs. It contains an arc from each node to each node + /// (including a loop for each node), therefore the number of arcs + /// is the square of the number of nodes. + /// This class is completely static and it needs constant memory space. + /// Thus you can neither add nor delete nodes or arcs, however + /// the structure can be resized using resize(). /// - /// This class fully conforms to the \ref concepts::Digraph - /// "Digraph concept". + /// This type fully conforms to the \ref concepts::Digraph "Digraph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. /// - /// The \c FullDigraph and \c FullGraph classes are very similar, + /// This class provides constant time counting for nodes and arcs. + /// + /// \note FullDigraph and FullGraph classes are very similar, /// but there are two differences. While this class conforms only - /// to the \ref concepts::Digraph "Digraph" concept, the \c FullGraph - /// class conforms to the \ref concepts::Graph "Graph" concept, - /// moreover \c FullGraph does not contain a loop arc for each - /// node as \c FullDigraph does. + /// to the \ref concepts::Digraph "Digraph" concept, FullGraph + /// conforms to the \ref concepts::Graph "Graph" concept, + /// moreover FullGraph does not contain a loop for each + /// node as this class does. /// /// \sa FullGraph class FullDigraph : public ExtendedFullDigraphBase { @@ -173,7 +177,9 @@ public: - /// \brief Constructor + /// \brief Default constructor. + /// + /// Default constructor. The number of nodes and arcs will be zero. FullDigraph() { construct(0); } /// \brief Constructor @@ -184,8 +190,8 @@ /// \brief Resizes the digraph /// - /// Resizes the digraph. The function will fully destroy and - /// rebuild the digraph. This cause that the maps of the digraph will + /// This function resizes the digraph. It fully destroys and + /// rebuilds the structure, therefore the maps of the digraph will be /// reallocated automatically and the previous values will be lost. void resize(int n) { Parent::notifier(Arc()).clear(); @@ -197,24 +203,26 @@ /// \brief Returns the node with the given index. /// - /// Returns the node with the given index. Since it is a static - /// digraph its nodes can be indexed with integers from the range - /// [0..nodeNum()-1]. + /// Returns the node with the given index. Since this structure is + /// completely static, the nodes can be indexed with integers from + /// the range [0..nodeNum()-1]. + /// The index of a node is the same as its ID. /// \sa index() Node operator()(int ix) const { return Parent::operator()(ix); } /// \brief Returns the index of the given node. /// - /// Returns the index of the given node. Since it is a static - /// digraph its nodes can be indexed with integers from the range - /// [0..nodeNum()-1]. - /// \sa operator() - int index(const Node& node) const { return Parent::index(node); } + /// Returns the index of the given node. Since this structure is + /// completely static, the nodes can be indexed with integers from + /// the range [0..nodeNum()-1]. + /// The index of a node is the same as its ID. + /// \sa operator()() + static int index(const Node& node) { return Parent::index(node); } /// \brief Returns the arc connecting the given nodes. /// /// Returns the arc connecting the given nodes. - Arc arc(const Node& u, const Node& v) const { + Arc arc(Node u, Node v) const { return Parent::arc(u, v); } @@ -283,7 +291,7 @@ public: Node operator()(int ix) const { return Node(ix); } - int index(const Node& node) const { return node._id; } + static int index(const Node& node) { return node._id; } Edge edge(const Node& u, const Node& v) const { if (u._id < v._id) { @@ -520,21 +528,25 @@ /// /// \brief An undirected full graph class. /// - /// This is a simple and fast undirected full graph - /// implementation. From each node go edge to each other node, - /// therefore the number of edges in the graph is \f$n(n-1)/2\f$. - /// This graph type is completely static, so you can neither - /// add nor delete either edges or nodes, and it needs constant - /// space in memory. + /// FullGraph is a simple and fast implmenetation of undirected full + /// (complete) graphs. It contains an edge between every distinct pair + /// of nodes, therefore the number of edges is n(n-1)/2. + /// This class is completely static and it needs constant memory space. + /// Thus you can neither add nor delete nodes or edges, however + /// the structure can be resized using resize(). /// - /// This class fully conforms to the \ref concepts::Graph "Graph concept". + /// This type fully conforms to the \ref concepts::Graph "Graph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. /// - /// The \c FullGraph and \c FullDigraph classes are very similar, - /// but there are two differences. While the \c FullDigraph class + /// This class provides constant time counting for nodes, edges and arcs. + /// + /// \note FullDigraph and FullGraph classes are very similar, + /// but there are two differences. While FullDigraph /// conforms only to the \ref concepts::Digraph "Digraph" concept, /// this class conforms to the \ref concepts::Graph "Graph" concept, - /// moreover \c FullGraph does not contain a loop arc for each - /// node as \c FullDigraph does. + /// moreover this class does not contain a loop for each + /// node as FullDigraph does. /// /// \sa FullDigraph class FullGraph : public ExtendedFullGraphBase { @@ -542,7 +554,9 @@ public: - /// \brief Constructor + /// \brief Default constructor. + /// + /// Default constructor. The number of nodes and edges will be zero. FullGraph() { construct(0); } /// \brief Constructor @@ -553,8 +567,8 @@ /// \brief Resizes the graph /// - /// Resizes the graph. The function will fully destroy and - /// rebuild the graph. This cause that the maps of the graph will + /// This function resizes the graph. It fully destroys and + /// rebuilds the structure, therefore the maps of the graph will be /// reallocated automatically and the previous values will be lost. void resize(int n) { Parent::notifier(Arc()).clear(); @@ -568,31 +582,33 @@ /// \brief Returns the node with the given index. /// - /// Returns the node with the given index. Since it is a static - /// graph its nodes can be indexed with integers from the range - /// [0..nodeNum()-1]. + /// Returns the node with the given index. Since this structure is + /// completely static, the nodes can be indexed with integers from + /// the range [0..nodeNum()-1]. + /// The index of a node is the same as its ID. /// \sa index() Node operator()(int ix) const { return Parent::operator()(ix); } /// \brief Returns the index of the given node. /// - /// Returns the index of the given node. Since it is a static - /// graph its nodes can be indexed with integers from the range - /// [0..nodeNum()-1]. - /// \sa operator() - int index(const Node& node) const { return Parent::index(node); } + /// Returns the index of the given node. Since this structure is + /// completely static, the nodes can be indexed with integers from + /// the range [0..nodeNum()-1]. + /// The index of a node is the same as its ID. + /// \sa operator()() + static int index(const Node& node) { return Parent::index(node); } /// \brief Returns the arc connecting the given nodes. /// /// Returns the arc connecting the given nodes. - Arc arc(const Node& s, const Node& t) const { + Arc arc(Node s, Node t) const { return Parent::arc(s, t); } - /// \brief Returns the edge connects the given nodes. + /// \brief Returns the edge connecting the given nodes. /// - /// Returns the edge connects the given nodes. - Edge edge(const Node& u, const Node& v) const { + /// Returns the edge connecting the given nodes. + Edge edge(Node u, Node v) const { return Parent::edge(u, v); } diff --git a/lemon/glpk.cc b/lemon/glpk.cc --- a/lemon/glpk.cc +++ b/lemon/glpk.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -59,6 +59,42 @@ return i; } + int GlpkBase::_addRow(Value lo, ExprIterator b, + ExprIterator e, Value up) { + int i = glp_add_rows(lp, 1); + + if (lo == -INF) { + if (up == INF) { + glp_set_row_bnds(lp, i, GLP_FR, lo, up); + } else { + glp_set_row_bnds(lp, i, GLP_UP, lo, up); + } + } else { + if (up == INF) { + glp_set_row_bnds(lp, i, GLP_LO, lo, up); + } else if (lo != up) { + glp_set_row_bnds(lp, i, GLP_DB, lo, up); + } else { + glp_set_row_bnds(lp, i, GLP_FX, lo, up); + } + } + + std::vector indexes; + std::vector values; + + indexes.push_back(0); + values.push_back(0); + + for(ExprIterator it = b; it != e; ++it) { + indexes.push_back(it->first); + values.push_back(it->second); + } + + glp_set_mat_row(lp, i, values.size() - 1, + &indexes.front(), &values.front()); + return i; + } + void GlpkBase::_eraseCol(int i) { int ca[2]; ca[1] = i; diff --git a/lemon/glpk.h b/lemon/glpk.h --- a/lemon/glpk.h +++ b/lemon/glpk.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -30,7 +30,7 @@ namespace _solver_bits { class VoidPtr { private: - void *_ptr; + void *_ptr; public: VoidPtr() : _ptr(0) {} @@ -38,8 +38,8 @@ VoidPtr(T* ptr) : _ptr(reinterpret_cast(ptr)) {} template - VoidPtr& operator=(T* ptr) { - _ptr = reinterpret_cast(ptr); + VoidPtr& operator=(T* ptr) { + _ptr = reinterpret_cast(ptr); return *this; } @@ -65,6 +65,7 @@ virtual int _addCol(); virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); virtual void _eraseCol(int i); virtual void _eraseRow(int i); @@ -123,13 +124,13 @@ freeEnv(); } }; - + static FreeEnvHelper freeEnvHelper; protected: - + int _message_level; - + public: ///Pointer to the underlying GLPK data structure. diff --git a/lemon/gomory_hu.h b/lemon/gomory_hu.h --- a/lemon/gomory_hu.h +++ b/lemon/gomory_hu.h @@ -1,8 +1,8 @@ -/* -*- C++ -*- +/* -*- mode: C++; indent-tabs-mode: nil; -*- * - * This file is a part of LEMON, a generic C++ optimization library + * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -27,7 +27,7 @@ #include /// \ingroup min_cut -/// \file +/// \file /// \brief Gomory-Hu cut tree in graphs. namespace lemon { @@ -38,13 +38,13 @@ /// /// The Gomory-Hu tree is a tree on the node set of a given graph, but it /// may contain edges which are not in the original graph. It has the - /// property that the minimum capacity edge of the path between two nodes + /// property that the minimum capacity edge of the path between two nodes /// in this tree has the same weight as the minimum cut in the graph /// between these nodes. Moreover the components obtained by removing /// this edge from the tree determine the corresponding minimum cut. /// Therefore once this tree is computed, the minimum cut between any pair /// of nodes can easily be obtained. - /// + /// /// The algorithm calculates \e n-1 distinct minimum cuts (currently with /// the \ref Preflow algorithm), thus it has \f$O(n^3\sqrt{e})\f$ overall /// time complexity. It calculates a rooted Gomory-Hu tree. @@ -60,10 +60,10 @@ /// The default map type is \ref concepts::Graph::EdgeMap "GR::EdgeMap". #ifdef DOXYGEN template + typename CAP> #else template > + typename CAP = typename GR::template EdgeMap > #endif class GomoryHu { public: @@ -74,7 +74,7 @@ typedef CAP Capacity; /// The value type of capacities typedef typename Capacity::Value Value; - + private: TEMPLATE_GRAPH_TYPEDEFS(Graph); @@ -89,28 +89,28 @@ void createStructures() { if (!_pred) { - _pred = new typename Graph::template NodeMap(_graph); + _pred = new typename Graph::template NodeMap(_graph); } if (!_weight) { - _weight = new typename Graph::template NodeMap(_graph); + _weight = new typename Graph::template NodeMap(_graph); } if (!_order) { - _order = new typename Graph::template NodeMap(_graph); + _order = new typename Graph::template NodeMap(_graph); } } void destroyStructures() { if (_pred) { - delete _pred; + delete _pred; } if (_weight) { - delete _weight; + delete _weight; } if (_order) { - delete _order; + delete _order; } } - + public: /// \brief Constructor @@ -118,9 +118,9 @@ /// Constructor. /// \param graph The undirected graph the algorithm runs on. /// \param capacity The edge capacity map. - GomoryHu(const Graph& graph, const Capacity& capacity) + GomoryHu(const Graph& graph, const Capacity& capacity) : _graph(graph), _capacity(capacity), - _pred(0), _weight(0), _order(0) + _pred(0), _weight(0), _order(0) { checkConcept, Capacity>(); } @@ -134,7 +134,7 @@ } private: - + // Initialize the internal data structures void init() { createStructures(); @@ -145,7 +145,7 @@ (*_order)[n] = -1; } (*_pred)[_root] = INVALID; - (*_weight)[_root] = std::numeric_limits::max(); + (*_weight)[_root] = std::numeric_limits::max(); } @@ -154,50 +154,50 @@ Preflow fa(_graph, _capacity, _root, INVALID); for (NodeIt n(_graph); n != INVALID; ++n) { - if (n == _root) continue; + if (n == _root) continue; - Node pn = (*_pred)[n]; - fa.source(n); - fa.target(pn); + Node pn = (*_pred)[n]; + fa.source(n); + fa.target(pn); - fa.runMinCut(); + fa.runMinCut(); - (*_weight)[n] = fa.flowValue(); + (*_weight)[n] = fa.flowValue(); - for (NodeIt nn(_graph); nn != INVALID; ++nn) { - if (nn != n && fa.minCut(nn) && (*_pred)[nn] == pn) { - (*_pred)[nn] = n; - } - } - if ((*_pred)[pn] != INVALID && fa.minCut((*_pred)[pn])) { - (*_pred)[n] = (*_pred)[pn]; - (*_pred)[pn] = n; - (*_weight)[n] = (*_weight)[pn]; - (*_weight)[pn] = fa.flowValue(); - } + for (NodeIt nn(_graph); nn != INVALID; ++nn) { + if (nn != n && fa.minCut(nn) && (*_pred)[nn] == pn) { + (*_pred)[nn] = n; + } + } + if ((*_pred)[pn] != INVALID && fa.minCut((*_pred)[pn])) { + (*_pred)[n] = (*_pred)[pn]; + (*_pred)[pn] = n; + (*_weight)[n] = (*_weight)[pn]; + (*_weight)[pn] = fa.flowValue(); + } } (*_order)[_root] = 0; int index = 1; for (NodeIt n(_graph); n != INVALID; ++n) { - std::vector st; - Node nn = n; - while ((*_order)[nn] == -1) { - st.push_back(nn); - nn = (*_pred)[nn]; - } - while (!st.empty()) { - (*_order)[st.back()] = index++; - st.pop_back(); - } + std::vector st; + Node nn = n; + while ((*_order)[nn] == -1) { + st.push_back(nn); + nn = (*_pred)[nn]; + } + while (!st.empty()) { + (*_order)[st.back()] = index++; + st.pop_back(); + } } } public: ///\name Execution Control - + ///@{ /// \brief Run the Gomory-Hu algorithm. @@ -207,7 +207,7 @@ init(); start(); } - + /// @} ///\name Query Functions @@ -232,7 +232,7 @@ /// \brief Return the weight of the predecessor edge in the /// Gomory-Hu tree. /// - /// This function returns the weight of the predecessor edge of the + /// This function returns the weight of the predecessor edge of the /// given node in the Gomory-Hu tree. /// If \c node is the root of the tree, the result is undefined. /// @@ -254,7 +254,7 @@ /// \brief Return the minimum cut value between two nodes /// /// This function returns the minimum cut value between the nodes - /// \c s and \c t. + /// \c s and \c t. /// It finds the nearest common ancestor of the given nodes in the /// Gomory-Hu tree and calculates the minimum weight edge on the /// paths to the ancestor. @@ -263,15 +263,15 @@ Value minCutValue(const Node& s, const Node& t) const { Node sn = s, tn = t; Value value = std::numeric_limits::max(); - + while (sn != tn) { - if ((*_order)[sn] < (*_order)[tn]) { - if ((*_weight)[tn] <= value) value = (*_weight)[tn]; - tn = (*_pred)[tn]; - } else { - if ((*_weight)[sn] <= value) value = (*_weight)[sn]; - sn = (*_pred)[sn]; - } + if ((*_order)[sn] < (*_order)[tn]) { + if ((*_weight)[tn] <= value) value = (*_weight)[tn]; + tn = (*_pred)[tn]; + } else { + if ((*_weight)[sn] <= value) value = (*_weight)[sn]; + sn = (*_pred)[sn]; + } } return value; } @@ -294,33 +294,31 @@ /// /// \pre \ref run() must be called before using this function. template - Value minCutMap(const Node& s, ///< + Value minCutMap(const Node& s, const Node& t, - ///< CutMap& cutMap - ///< ) const { Node sn = s, tn = t; bool s_root=false; Node rn = INVALID; Value value = std::numeric_limits::max(); - + while (sn != tn) { - if ((*_order)[sn] < (*_order)[tn]) { - if ((*_weight)[tn] <= value) { - rn = tn; + if ((*_order)[sn] < (*_order)[tn]) { + if ((*_weight)[tn] <= value) { + rn = tn; s_root = false; - value = (*_weight)[tn]; - } - tn = (*_pred)[tn]; - } else { - if ((*_weight)[sn] <= value) { - rn = sn; + value = (*_weight)[tn]; + } + tn = (*_pred)[tn]; + } else { + if ((*_weight)[sn] <= value) { + rn = sn; s_root = true; - value = (*_weight)[sn]; - } - sn = (*_pred)[sn]; - } + value = (*_weight)[sn]; + } + sn = (*_pred)[sn]; + } } typename Graph::template NodeMap reached(_graph, false); @@ -331,18 +329,18 @@ std::vector st; for (NodeIt n(_graph); n != INVALID; ++n) { - st.clear(); + st.clear(); Node nn = n; - while (!reached[nn]) { - st.push_back(nn); - nn = (*_pred)[nn]; - } - while (!st.empty()) { - cutMap.set(st.back(), cutMap[nn]); - st.pop_back(); - } + while (!reached[nn]) { + st.push_back(nn); + nn = (*_pred)[nn]; + } + while (!st.empty()) { + cutMap.set(st.back(), cutMap[nn]); + st.pop_back(); + } } - + return value; } @@ -351,7 +349,7 @@ friend class MinCutNodeIt; /// Iterate on the nodes of a minimum cut - + /// This iterator class lists the nodes of a minimum cut found by /// GomoryHu. Before using it, you must allocate a GomoryHu class /// and call its \ref GomoryHu::run() "run()" method. @@ -359,10 +357,10 @@ /// This example counts the nodes in the minimum cut separating \c s from /// \c t. /// \code - /// GomoruHu gom(g, capacities); + /// GomoryHu gom(g, capacities); /// gom.run(); /// int cnt=0; - /// for(GomoruHu::MinCutNodeIt n(gom,s,t); n!=INVALID; ++n) ++cnt; + /// for(GomoryHu::MinCutNodeIt n(gom,s,t); n!=INVALID; ++n) ++cnt; /// \endcode class MinCutNodeIt { @@ -394,7 +392,7 @@ /// MinCutNodeIt(gomory, t, s, false); /// \endcode /// does not necessarily give the same set of nodes. - /// However it is ensured that + /// However, it is ensured that /// \code /// MinCutNodeIt(gomory, s, t, true); /// \endcode @@ -444,11 +442,11 @@ return n; } }; - + friend class MinCutEdgeIt; - + /// Iterate on the edges of a minimum cut - + /// This iterator class lists the edges of a minimum cut found by /// GomoryHu. Before using it, you must allocate a GomoryHu class /// and call its \ref GomoryHu::run() "run()" method. @@ -456,10 +454,10 @@ /// This example computes the value of the minimum cut separating \c s from /// \c t. /// \code - /// GomoruHu gom(g, capacities); + /// GomoryHu gom(g, capacities); /// gom.run(); /// int value=0; - /// for(GomoruHu::MinCutEdgeIt e(gom,s,t); e!=INVALID; ++e) + /// for(GomoryHu::MinCutEdgeIt e(gom,s,t); e!=INVALID; ++e) /// value+=capacities[e]; /// \endcode /// The result will be the same as the value returned by @@ -481,7 +479,7 @@ _arc_it=typename Graph::OutArcIt(_graph,_node_it); } } - + public: /// Constructor @@ -550,7 +548,7 @@ return *this; } /// Postfix incrementation - + /// Postfix incrementation. /// /// \warning This incrementation diff --git a/lemon/graph_to_eps.h b/lemon/graph_to_eps.h --- a/lemon/graph_to_eps.h +++ b/lemon/graph_to_eps.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -142,7 +142,7 @@ ///Constructor ///\param gr Reference to the graph to be printed. ///\param ost Reference to the output stream. - ///By default it is std::cout. + ///By default, it is std::cout. ///\param pros If it is \c true, then the \c ostream referenced by \c os ///will be explicitly deallocated by the destructor. DefaultGraphToEpsTraits(const GR &gr, std::ostream& ost = std::cout, @@ -512,7 +512,7 @@ ///Turn on/off pre-scaling - ///By default graphToEps() rescales the whole image in order to avoid + ///By default, graphToEps() rescales the whole image in order to avoid ///very big or very small bounding boxes. /// ///This (p)rescaling can be turned off with this function. @@ -1114,7 +1114,7 @@ ///Generates an EPS file from a graph. ///\param g Reference to the graph to be printed. ///\param os Reference to the output stream. -///By default it is std::cout. +///By default, it is std::cout. /// ///This function also has a lot of ///\ref named-templ-func-param "named parameters", @@ -1126,7 +1126,7 @@ /// .arcWidthScale(.4).run(); ///\endcode /// -///For more detailed examples see the \ref graph_to_eps_demo.cc demo file. +///For more detailed examples, see the \ref graph_to_eps_demo.cc demo file. /// ///\warning Don't forget to put the \ref GraphToEps::run() "run()" ///to the end of the parameter list. diff --git a/lemon/grid_graph.h b/lemon/grid_graph.h --- a/lemon/grid_graph.h +++ b/lemon/grid_graph.h @@ -470,18 +470,22 @@ /// /// \brief Grid graph class /// - /// This class implements a special graph type. The nodes of the - /// graph can be indexed by two integer \c (i,j) value where \c i is - /// in the \c [0..width()-1] range and j is in the \c - /// [0..height()-1] range. Two nodes are connected in the graph if - /// the indexes differ exactly on one position and exactly one is - /// the difference. The nodes of the graph can be indexed by position - /// with the \c operator()() function. The positions of the nodes can be - /// get with \c pos(), \c col() and \c row() members. The outgoing + /// GridGraph implements a special graph type. The nodes of the + /// graph can be indexed by two integer values \c (i,j) where \c i is + /// in the range [0..width()-1] and j is in the range + /// [0..height()-1]. Two nodes are connected in the graph if + /// the indices differ exactly on one position and the difference is + /// also exactly one. The nodes of the graph can be obtained by position + /// using the \c operator()() function and the indices of the nodes can + /// be obtained using \c pos(), \c col() and \c row() members. The outgoing /// arcs can be retrieved with the \c right(), \c up(), \c left() /// and \c down() functions, where the bottom-left corner is the /// origin. /// + /// This class is completely static and it needs constant memory space. + /// Thus you can neither add nor delete nodes or edges, however + /// the structure can be resized using resize(). + /// /// \image html grid_graph.png /// \image latex grid_graph.eps "Grid graph" width=\textwidth /// @@ -496,16 +500,21 @@ /// } ///\endcode /// - /// This graph type fully conforms to the \ref concepts::Graph - /// "Graph concept". + /// This type fully conforms to the \ref concepts::Graph "Graph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. class GridGraph : public ExtendedGridGraphBase { typedef ExtendedGridGraphBase Parent; public: - /// \brief Map to get the indices of the nodes as dim2::Point. + /// \brief Map to get the indices of the nodes as \ref dim2::Point + /// "dim2::Point". /// - /// Map to get the indices of the nodes as dim2::Point. + /// Map to get the indices of the nodes as \ref dim2::Point + /// "dim2::Point". class IndexMap { public: /// \brief The key type of the map @@ -514,13 +523,9 @@ typedef dim2::Point Value; /// \brief Constructor - /// - /// Constructor IndexMap(const GridGraph& graph) : _graph(graph) {} /// \brief The subscript operator - /// - /// The subscript operator. Value operator[](Key key) const { return _graph.pos(key); } @@ -540,13 +545,9 @@ typedef int Value; /// \brief Constructor - /// - /// Constructor ColMap(const GridGraph& graph) : _graph(graph) {} /// \brief The subscript operator - /// - /// The subscript operator. Value operator[](Key key) const { return _graph.col(key); } @@ -566,13 +567,9 @@ typedef int Value; /// \brief Constructor - /// - /// Constructor RowMap(const GridGraph& graph) : _graph(graph) {} /// \brief The subscript operator - /// - /// The subscript operator. Value operator[](Key key) const { return _graph.row(key); } @@ -583,15 +580,14 @@ /// \brief Constructor /// - /// Construct a grid graph with given size. + /// Construct a grid graph with the given size. GridGraph(int width, int height) { construct(width, height); } - /// \brief Resize the graph + /// \brief Resizes the graph /// - /// Resize the graph. The function will fully destroy and rebuild - /// the graph. This cause that the maps of the graph will - /// reallocated automatically and the previous values will be - /// lost. + /// This function resizes the graph. It fully destroys and + /// rebuilds the structure, therefore the maps of the graph will be + /// reallocated automatically and the previous values will be lost. void resize(int width, int height) { Parent::notifier(Arc()).clear(); Parent::notifier(Edge()).clear(); @@ -609,42 +605,42 @@ return Parent::operator()(i, j); } - /// \brief Gives back the column index of the node. + /// \brief The column index of the node. /// /// Gives back the column index of the node. int col(Node n) const { return Parent::col(n); } - /// \brief Gives back the row index of the node. + /// \brief The row index of the node. /// /// Gives back the row index of the node. int row(Node n) const { return Parent::row(n); } - /// \brief Gives back the position of the node. + /// \brief The position of the node. /// /// Gives back the position of the node, ie. the (col,row) pair. dim2::Point pos(Node n) const { return Parent::pos(n); } - /// \brief Gives back the number of the columns. + /// \brief The number of the columns. /// /// Gives back the number of the columns. int width() const { return Parent::width(); } - /// \brief Gives back the number of the rows. + /// \brief The number of the rows. /// /// Gives back the number of the rows. int height() const { return Parent::height(); } - /// \brief Gives back the arc goes right from the node. + /// \brief The arc goes right from the node. /// /// Gives back the arc goes right from the node. If there is not /// outgoing arc then it gives back INVALID. @@ -652,7 +648,7 @@ return Parent::right(n); } - /// \brief Gives back the arc goes left from the node. + /// \brief The arc goes left from the node. /// /// Gives back the arc goes left from the node. If there is not /// outgoing arc then it gives back INVALID. @@ -660,7 +656,7 @@ return Parent::left(n); } - /// \brief Gives back the arc goes up from the node. + /// \brief The arc goes up from the node. /// /// Gives back the arc goes up from the node. If there is not /// outgoing arc then it gives back INVALID. @@ -668,7 +664,7 @@ return Parent::up(n); } - /// \brief Gives back the arc goes down from the node. + /// \brief The arc goes down from the node. /// /// Gives back the arc goes down from the node. If there is not /// outgoing arc then it gives back INVALID. diff --git a/lemon/hao_orlin.h b/lemon/hao_orlin.h --- a/lemon/hao_orlin.h +++ b/lemon/hao_orlin.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -31,7 +31,7 @@ /// \ingroup min_cut /// \brief Implementation of the Hao-Orlin algorithm. /// -/// Implementation of the Hao-Orlin algorithm for finding a minimum cut +/// Implementation of the Hao-Orlin algorithm for finding a minimum cut /// in a digraph. namespace lemon { @@ -41,7 +41,7 @@ /// \brief Hao-Orlin algorithm for finding a minimum cut in a digraph. /// /// This class implements the Hao-Orlin algorithm for finding a minimum - /// value cut in a directed graph \f$D=(V,A)\f$. + /// value cut in a directed graph \f$D=(V,A)\f$. /// It takes a fixed node \f$ source \in V \f$ and /// consists of two phases: in the first phase it determines a /// minimum cut with \f$ source \f$ on the source-side (i.e. a set @@ -58,7 +58,7 @@ /// /// For an undirected graph you can run just the first phase of the /// algorithm or you can use the algorithm of Nagamochi and Ibaraki, - /// which solves the undirected problem in \f$ O(nm + n^2 \log n) \f$ + /// which solves the undirected problem in \f$ O(nm + n^2 \log n) \f$ /// time. It is implemented in the NagamochiIbaraki algorithm class. /// /// \tparam GR The type of the digraph the algorithm runs on. @@ -76,7 +76,7 @@ #endif class HaoOrlin { public: - + /// The digraph type of the algorithm typedef GR Digraph; /// The capacity map type of the algorithm @@ -165,6 +165,23 @@ } } + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// \return (*this) + HaoOrlin& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Returns a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + private: void activate(const Node& i) { @@ -847,7 +864,7 @@ /// \brief Initialize the internal data structures. /// /// This function initializes the internal data structures. It creates - /// the maps and some bucket structures for the algorithm. + /// the maps and some bucket structures for the algorithm. /// The given node is used as the source node for the push-relabel /// algorithm. void init(const Node& source) { @@ -927,7 +944,7 @@ /// \brief Run the algorithm. /// - /// This function runs the algorithm. It uses the given \c source node, + /// This function runs the algorithm. It uses the given \c source node, /// finds a proper \c target node and then calls the \ref init(), /// \ref calculateOut() and \ref calculateIn(). void run(const Node& s) { @@ -941,7 +958,7 @@ /// \name Query Functions /// The result of the %HaoOrlin algorithm /// can be obtained using these functions.\n - /// \ref run(), \ref calculateOut() or \ref calculateIn() + /// \ref run(), \ref calculateOut() or \ref calculateIn() /// should be called before using them. /// @{ @@ -950,7 +967,7 @@ /// /// This function returns the value of the minimum cut. /// - /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() + /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() /// must be called before using this function. Value minCutValue() const { return _min_cut; @@ -969,7 +986,7 @@ /// /// \return The value of the minimum cut. /// - /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() + /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() /// must be called before using this function. template Value minCutMap(CutMap& cutMap) const { diff --git a/lemon/hartmann_orlin_mmc.h b/lemon/hartmann_orlin_mmc.h new file mode 100644 --- /dev/null +++ b/lemon/hartmann_orlin_mmc.h @@ -0,0 +1,650 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_HARTMANN_ORLIN_MMC_H +#define LEMON_HARTMANN_ORLIN_MMC_H + +/// \ingroup min_mean_cycle +/// +/// \file +/// \brief Hartmann-Orlin's algorithm for finding a minimum mean cycle. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of HartmannOrlinMmc class. + /// + /// Default traits class of HartmannOrlinMmc class. + /// \tparam GR The type of the digraph. + /// \tparam CM The type of the cost map. + /// It must conform to the \ref concepts::Rea_data "Rea_data" concept. +#ifdef DOXYGEN + template +#else + template ::is_integer> +#endif + struct HartmannOrlinMmcDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the cost map + typedef CM CostMap; + /// The type of the arc costs + typedef typename CostMap::Value Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + + /// The tolerance type used for internal computations + typedef lemon::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + typedef lemon::Path Path; + }; + + // Default traits class for integer cost types + template + struct HartmannOrlinMmcDefaultTraits + { + typedef GR Digraph; + typedef CM CostMap; + typedef typename CostMap::Value Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + typedef lemon::Tolerance Tolerance; + typedef lemon::Path Path; + }; + + + /// \addtogroup min_mean_cycle + /// @{ + + /// \brief Implementation of the Hartmann-Orlin algorithm for finding + /// a minimum mean cycle. + /// + /// This class implements the Hartmann-Orlin algorithm for finding + /// a directed cycle of minimum mean cost in a digraph + /// \ref amo93networkflows, \ref dasdan98minmeancycle. + /// It is an improved version of \ref Karp "Karp"'s original algorithm, + /// it applies an efficient early termination scheme. + /// It runs in time O(ne) and uses space O(n2+e). + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CM The type of the cost map. The default + /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref HartmannOrlinMmcDefaultTraits + /// "HartmannOrlinMmcDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename CM = typename GR::template ArcMap, + typename TR = HartmannOrlinMmcDefaultTraits > +#endif + class HartmannOrlinMmc + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the cost map + typedef typename TR::CostMap CostMap; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The tolerance type + typedef typename TR::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// Using the \ref HartmannOrlinMmcDefaultTraits "default traits class", + /// it is \ref lemon::Path "Path". + typedef typename TR::Path Path; + + /// The \ref HartmannOrlinMmcDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + // Data sturcture for path data + struct PathData + { + LargeCost dist; + Arc pred; + PathData(LargeCost d, Arc p = INVALID) : + dist(d), pred(p) {} + }; + + typedef typename Digraph::template NodeMap > + PathDataNodeMap; + + private: + + // The digraph the algorithm runs on + const Digraph &_gr; + // The cost of the arcs + const CostMap &_cost; + + // Data for storing the strongly connected components + int _comp_num; + typename Digraph::template NodeMap _comp; + std::vector > _comp_nodes; + std::vector* _nodes; + typename Digraph::template NodeMap > _out_arcs; + + // Data for the found cycles + bool _curr_found, _best_found; + LargeCost _curr_cost, _best_cost; + int _curr_size, _best_size; + Node _curr_node, _best_node; + int _curr_level, _best_level; + + Path *_cycle_path; + bool _local_path; + + // Node map for storing path data + PathDataNodeMap _data; + // The processed nodes in the last round + std::vector _process; + + Tolerance _tolerance; + + // Infinite constant + const LargeCost INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + typedef lemon::Tolerance Tolerance; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type. It is used for internal computations in the algorithm. + template + struct SetLargeCost + : public HartmannOrlinMmc > { + typedef HartmannOrlinMmc > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting the \c %Path + /// type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + template + struct SetPath + : public HartmannOrlinMmc > { + typedef HartmannOrlinMmc > Create; + }; + + /// @} + + protected: + + HartmannOrlinMmc() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param cost The costs of the arcs. + HartmannOrlinMmc( const Digraph &digraph, + const CostMap &cost ) : + _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph), + _best_found(false), _best_cost(0), _best_size(1), + _cycle_path(NULL), _local_path(false), _data(digraph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + {} + + /// Destructor. + ~HartmannOrlinMmc() { + if (_local_path) delete _cycle_path; + } + + /// \brief Set the path structure for storing the found cycle. + /// + /// This function sets an external path structure for storing the + /// found cycle. + /// + /// If you don't call this function before calling \ref run() or + /// \ref findCycleMean(), it will allocate a local \ref Path "path" + /// structure. The destuctor deallocates this automatically + /// allocated object, of course. + /// + /// \note The algorithm calls only the \ref lemon::Path::addFront() + /// "addFront()" function of the given path structure. + /// + /// \return (*this) + HartmannOrlinMmc& cycle(Path &path) { + if (_local_path) { + delete _cycle_path; + _local_path = false; + } + _cycle_path = &path; + return *this; + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// + /// \return (*this) + HartmannOrlinMmc& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Return a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to call the \ref run() + /// function.\n + /// If you only need the minimum mean cost, you may call + /// \ref findCycleMean(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// It can be called more than once (e.g. if the underlying digraph + /// and/or the arc costs have been modified). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \note mmc.run() is just a shortcut of the following code. + /// \code + /// return mmc.findCycleMean() && mmc.findCycle(); + /// \endcode + bool run() { + return findCycleMean() && findCycle(); + } + + /// \brief Find the minimum cycle mean. + /// + /// This function finds the minimum mean cost of the directed + /// cycles in the digraph. + /// + /// \return \c true if a directed cycle exists in the digraph. + bool findCycleMean() { + // Initialization and find strongly connected components + init(); + findComponents(); + + // Find the minimum cycle mean in the components + for (int comp = 0; comp < _comp_num; ++comp) { + if (!initComponent(comp)) continue; + processRounds(); + + // Update the best cycle (global minimum mean cycle) + if ( _curr_found && (!_best_found || + _curr_cost * _best_size < _best_cost * _curr_size) ) { + _best_found = true; + _best_cost = _curr_cost; + _best_size = _curr_size; + _best_node = _curr_node; + _best_level = _curr_level; + } + } + return _best_found; + } + + /// \brief Find a minimum mean directed cycle. + /// + /// This function finds a directed cycle of minimum mean cost + /// in the digraph using the data computed by findCycleMean(). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \pre \ref findCycleMean() must be called before using this function. + bool findCycle() { + if (!_best_found) return false; + IntNodeMap reached(_gr, -1); + int r = _best_level + 1; + Node u = _best_node; + while (reached[u] < 0) { + reached[u] = --r; + u = _gr.source(_data[u][r].pred); + } + r = reached[u]; + Arc e = _data[u][r].pred; + _cycle_path->addFront(e); + _best_cost = _cost[e]; + _best_size = 1; + Node v; + while ((v = _gr.source(e)) != u) { + e = _data[v][--r].pred; + _cycle_path->addFront(e); + _best_cost += _cost[e]; + ++_best_size; + } + return true; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total cost of the found cycle. + /// + /// This function returns the total cost of the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + Cost cycleCost() const { + return static_cast(_best_cost); + } + + /// \brief Return the number of arcs on the found cycle. + /// + /// This function returns the number of arcs on the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + int cycleSize() const { + return _best_size; + } + + /// \brief Return the mean cost of the found cycle. + /// + /// This function returns the mean cost of the found cycle. + /// + /// \note alg.cycleMean() is just a shortcut of the + /// following code. + /// \code + /// return static_cast(alg.cycleCost()) / alg.cycleSize(); + /// \endcode + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + double cycleMean() const { + return static_cast(_best_cost) / _best_size; + } + + /// \brief Return the found cycle. + /// + /// This function returns a const reference to the path structure + /// storing the found cycle. + /// + /// \pre \ref run() or \ref findCycle() must be called before using + /// this function. + const Path& cycle() const { + return *_cycle_path; + } + + ///@} + + private: + + // Initialization + void init() { + if (!_cycle_path) { + _local_path = true; + _cycle_path = new Path; + } + _cycle_path->clear(); + _best_found = false; + _best_cost = 0; + _best_size = 1; + _cycle_path->clear(); + for (NodeIt u(_gr); u != INVALID; ++u) + _data[u].clear(); + } + + // Find strongly connected components and initialize _comp_nodes + // and _out_arcs + void findComponents() { + _comp_num = stronglyConnectedComponents(_gr, _comp); + _comp_nodes.resize(_comp_num); + if (_comp_num == 1) { + _comp_nodes[0].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + _comp_nodes[0].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + _out_arcs[n].push_back(a); + } + } + } else { + for (int i = 0; i < _comp_num; ++i) + _comp_nodes[i].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + int k = _comp[n]; + _comp_nodes[k].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); + } + } + } + } + + // Initialize path data for the current component + bool initComponent(int comp) { + _nodes = &(_comp_nodes[comp]); + int n = _nodes->size(); + if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { + return false; + } + for (int i = 0; i < n; ++i) { + _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); + } + return true; + } + + // Process all rounds of computing path data for the current component. + // _data[v][k] is the cost of a shortest directed walk from the root + // node to node v containing exactly k arcs. + void processRounds() { + Node start = (*_nodes)[0]; + _data[start][0] = PathData(0); + _process.clear(); + _process.push_back(start); + + int k, n = _nodes->size(); + int next_check = 4; + bool terminate = false; + for (k = 1; k <= n && int(_process.size()) < n && !terminate; ++k) { + processNextBuildRound(k); + if (k == next_check || k == n) { + terminate = checkTermination(k); + next_check = next_check * 3 / 2; + } + } + for ( ; k <= n && !terminate; ++k) { + processNextFullRound(k); + if (k == next_check || k == n) { + terminate = checkTermination(k); + next_check = next_check * 3 / 2; + } + } + } + + // Process one round and rebuild _process + void processNextBuildRound(int k) { + std::vector next; + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_process.size()); ++i) { + u = _process[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + if (_data[v][k].dist == INF) next.push_back(v); + _data[v][k] = PathData(d, e); + } + } + } + _process.swap(next); + } + + // Process one round using _nodes instead of _process + void processNextFullRound(int k) { + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_nodes->size()); ++i) { + u = (*_nodes)[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + _data[v][k] = PathData(d, e); + } + } + } + } + + // Check early termination + bool checkTermination(int k) { + typedef std::pair Pair; + typename GR::template NodeMap level(_gr, Pair(-1, 0)); + typename GR::template NodeMap pi(_gr); + int n = _nodes->size(); + LargeCost cost; + int size; + Node u; + + // Search for cycles that are already found + _curr_found = false; + for (int i = 0; i < n; ++i) { + u = (*_nodes)[i]; + if (_data[u][k].dist == INF) continue; + for (int j = k; j >= 0; --j) { + if (level[u].first == i && level[u].second > 0) { + // A cycle is found + cost = _data[u][level[u].second].dist - _data[u][j].dist; + size = level[u].second - j; + if (!_curr_found || cost * _curr_size < _curr_cost * size) { + _curr_cost = cost; + _curr_size = size; + _curr_node = u; + _curr_level = level[u].second; + _curr_found = true; + } + } + level[u] = Pair(i, j); + if (j != 0) { + u = _gr.source(_data[u][j].pred); + } + } + } + + // If at least one cycle is found, check the optimality condition + LargeCost d; + if (_curr_found && k < n) { + // Find node potentials + for (int i = 0; i < n; ++i) { + u = (*_nodes)[i]; + pi[u] = INF; + for (int j = 0; j <= k; ++j) { + if (_data[u][j].dist < INF) { + d = _data[u][j].dist * _curr_size - j * _curr_cost; + if (_tolerance.less(d, pi[u])) pi[u] = d; + } + } + } + + // Check the optimality condition for all arcs + bool done = true; + for (ArcIt a(_gr); a != INVALID; ++a) { + if (_tolerance.less(_cost[a] * _curr_size - _curr_cost, + pi[_gr.target(a)] - pi[_gr.source(a)]) ) { + done = false; + break; + } + } + return done; + } + return (k == n); + } + + }; //class HartmannOrlinMmc + + ///@} + +} //namespace lemon + +#endif //LEMON_HARTMANN_ORLIN_MMC_H diff --git a/lemon/howard_mmc.h b/lemon/howard_mmc.h new file mode 100644 --- /dev/null +++ b/lemon/howard_mmc.h @@ -0,0 +1,605 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_HOWARD_MMC_H +#define LEMON_HOWARD_MMC_H + +/// \ingroup min_mean_cycle +/// +/// \file +/// \brief Howard's algorithm for finding a minimum mean cycle. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of HowardMmc class. + /// + /// Default traits class of HowardMmc class. + /// \tparam GR The type of the digraph. + /// \tparam CM The type of the cost map. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. +#ifdef DOXYGEN + template +#else + template ::is_integer> +#endif + struct HowardMmcDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the cost map + typedef CM CostMap; + /// The type of the arc costs + typedef typename CostMap::Value Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + + /// The tolerance type used for internal computations + typedef lemon::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + typedef lemon::Path Path; + }; + + // Default traits class for integer cost types + template + struct HowardMmcDefaultTraits + { + typedef GR Digraph; + typedef CM CostMap; + typedef typename CostMap::Value Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + typedef lemon::Tolerance Tolerance; + typedef lemon::Path Path; + }; + + + /// \addtogroup min_mean_cycle + /// @{ + + /// \brief Implementation of Howard's algorithm for finding a minimum + /// mean cycle. + /// + /// This class implements Howard's policy iteration algorithm for finding + /// a directed cycle of minimum mean cost in a digraph + /// \ref amo93networkflows, \ref dasdan98minmeancycle. + /// This class provides the most efficient algorithm for the + /// minimum mean cycle problem, though the best known theoretical + /// bound on its running time is exponential. + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CM The type of the cost map. The default + /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref HowardMmcDefaultTraits + /// "HowardMmcDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename CM = typename GR::template ArcMap, + typename TR = HowardMmcDefaultTraits > +#endif + class HowardMmc + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the cost map + typedef typename TR::CostMap CostMap; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The tolerance type + typedef typename TR::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// Using the \ref HowardMmcDefaultTraits "default traits class", + /// it is \ref lemon::Path "Path". + typedef typename TR::Path Path; + + /// The \ref HowardMmcDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + // The digraph the algorithm runs on + const Digraph &_gr; + // The cost of the arcs + const CostMap &_cost; + + // Data for the found cycles + bool _curr_found, _best_found; + LargeCost _curr_cost, _best_cost; + int _curr_size, _best_size; + Node _curr_node, _best_node; + + Path *_cycle_path; + bool _local_path; + + // Internal data used by the algorithm + typename Digraph::template NodeMap _policy; + typename Digraph::template NodeMap _reached; + typename Digraph::template NodeMap _level; + typename Digraph::template NodeMap _dist; + + // Data for storing the strongly connected components + int _comp_num; + typename Digraph::template NodeMap _comp; + std::vector > _comp_nodes; + std::vector* _nodes; + typename Digraph::template NodeMap > _in_arcs; + + // Queue used for BFS search + std::vector _queue; + int _qfront, _qback; + + Tolerance _tolerance; + + // Infinite constant + const LargeCost INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + typedef lemon::Tolerance Tolerance; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type. It is used for internal computations in the algorithm. + template + struct SetLargeCost + : public HowardMmc > { + typedef HowardMmc > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting the \c %Path + /// type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + template + struct SetPath + : public HowardMmc > { + typedef HowardMmc > Create; + }; + + /// @} + + protected: + + HowardMmc() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param cost The costs of the arcs. + HowardMmc( const Digraph &digraph, + const CostMap &cost ) : + _gr(digraph), _cost(cost), _best_found(false), + _best_cost(0), _best_size(1), _cycle_path(NULL), _local_path(false), + _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph), + _comp(digraph), _in_arcs(digraph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + {} + + /// Destructor. + ~HowardMmc() { + if (_local_path) delete _cycle_path; + } + + /// \brief Set the path structure for storing the found cycle. + /// + /// This function sets an external path structure for storing the + /// found cycle. + /// + /// If you don't call this function before calling \ref run() or + /// \ref findCycleMean(), it will allocate a local \ref Path "path" + /// structure. The destuctor deallocates this automatically + /// allocated object, of course. + /// + /// \note The algorithm calls only the \ref lemon::Path::addBack() + /// "addBack()" function of the given path structure. + /// + /// \return (*this) + HowardMmc& cycle(Path &path) { + if (_local_path) { + delete _cycle_path; + _local_path = false; + } + _cycle_path = &path; + return *this; + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// + /// \return (*this) + HowardMmc& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Return a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to call the \ref run() + /// function.\n + /// If you only need the minimum mean cost, you may call + /// \ref findCycleMean(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// It can be called more than once (e.g. if the underlying digraph + /// and/or the arc costs have been modified). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \note mmc.run() is just a shortcut of the following code. + /// \code + /// return mmc.findCycleMean() && mmc.findCycle(); + /// \endcode + bool run() { + return findCycleMean() && findCycle(); + } + + /// \brief Find the minimum cycle mean. + /// + /// This function finds the minimum mean cost of the directed + /// cycles in the digraph. + /// + /// \return \c true if a directed cycle exists in the digraph. + bool findCycleMean() { + // Initialize and find strongly connected components + init(); + findComponents(); + + // Find the minimum cycle mean in the components + for (int comp = 0; comp < _comp_num; ++comp) { + // Find the minimum mean cycle in the current component + if (!buildPolicyGraph(comp)) continue; + while (true) { + findPolicyCycle(); + if (!computeNodeDistances()) break; + } + // Update the best cycle (global minimum mean cycle) + if ( _curr_found && (!_best_found || + _curr_cost * _best_size < _best_cost * _curr_size) ) { + _best_found = true; + _best_cost = _curr_cost; + _best_size = _curr_size; + _best_node = _curr_node; + } + } + return _best_found; + } + + /// \brief Find a minimum mean directed cycle. + /// + /// This function finds a directed cycle of minimum mean cost + /// in the digraph using the data computed by findCycleMean(). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \pre \ref findCycleMean() must be called before using this function. + bool findCycle() { + if (!_best_found) return false; + _cycle_path->addBack(_policy[_best_node]); + for ( Node v = _best_node; + (v = _gr.target(_policy[v])) != _best_node; ) { + _cycle_path->addBack(_policy[v]); + } + return true; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total cost of the found cycle. + /// + /// This function returns the total cost of the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + Cost cycleCost() const { + return static_cast(_best_cost); + } + + /// \brief Return the number of arcs on the found cycle. + /// + /// This function returns the number of arcs on the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + int cycleSize() const { + return _best_size; + } + + /// \brief Return the mean cost of the found cycle. + /// + /// This function returns the mean cost of the found cycle. + /// + /// \note alg.cycleMean() is just a shortcut of the + /// following code. + /// \code + /// return static_cast(alg.cycleCost()) / alg.cycleSize(); + /// \endcode + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + double cycleMean() const { + return static_cast(_best_cost) / _best_size; + } + + /// \brief Return the found cycle. + /// + /// This function returns a const reference to the path structure + /// storing the found cycle. + /// + /// \pre \ref run() or \ref findCycle() must be called before using + /// this function. + const Path& cycle() const { + return *_cycle_path; + } + + ///@} + + private: + + // Initialize + void init() { + if (!_cycle_path) { + _local_path = true; + _cycle_path = new Path; + } + _queue.resize(countNodes(_gr)); + _best_found = false; + _best_cost = 0; + _best_size = 1; + _cycle_path->clear(); + } + + // Find strongly connected components and initialize _comp_nodes + // and _in_arcs + void findComponents() { + _comp_num = stronglyConnectedComponents(_gr, _comp); + _comp_nodes.resize(_comp_num); + if (_comp_num == 1) { + _comp_nodes[0].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + _comp_nodes[0].push_back(n); + _in_arcs[n].clear(); + for (InArcIt a(_gr, n); a != INVALID; ++a) { + _in_arcs[n].push_back(a); + } + } + } else { + for (int i = 0; i < _comp_num; ++i) + _comp_nodes[i].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + int k = _comp[n]; + _comp_nodes[k].push_back(n); + _in_arcs[n].clear(); + for (InArcIt a(_gr, n); a != INVALID; ++a) { + if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a); + } + } + } + } + + // Build the policy graph in the given strongly connected component + // (the out-degree of every node is 1) + bool buildPolicyGraph(int comp) { + _nodes = &(_comp_nodes[comp]); + if (_nodes->size() < 1 || + (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) { + return false; + } + for (int i = 0; i < int(_nodes->size()); ++i) { + _dist[(*_nodes)[i]] = INF; + } + Node u, v; + Arc e; + for (int i = 0; i < int(_nodes->size()); ++i) { + v = (*_nodes)[i]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + if (_cost[e] < _dist[u]) { + _dist[u] = _cost[e]; + _policy[u] = e; + } + } + } + return true; + } + + // Find the minimum mean cycle in the policy graph + void findPolicyCycle() { + for (int i = 0; i < int(_nodes->size()); ++i) { + _level[(*_nodes)[i]] = -1; + } + LargeCost ccost; + int csize; + Node u, v; + _curr_found = false; + for (int i = 0; i < int(_nodes->size()); ++i) { + u = (*_nodes)[i]; + if (_level[u] >= 0) continue; + for (; _level[u] < 0; u = _gr.target(_policy[u])) { + _level[u] = i; + } + if (_level[u] == i) { + // A cycle is found + ccost = _cost[_policy[u]]; + csize = 1; + for (v = u; (v = _gr.target(_policy[v])) != u; ) { + ccost += _cost[_policy[v]]; + ++csize; + } + if ( !_curr_found || + (ccost * _curr_size < _curr_cost * csize) ) { + _curr_found = true; + _curr_cost = ccost; + _curr_size = csize; + _curr_node = u; + } + } + } + } + + // Contract the policy graph and compute node distances + bool computeNodeDistances() { + // Find the component of the main cycle and compute node distances + // using reverse BFS + for (int i = 0; i < int(_nodes->size()); ++i) { + _reached[(*_nodes)[i]] = false; + } + _qfront = _qback = 0; + _queue[0] = _curr_node; + _reached[_curr_node] = true; + _dist[_curr_node] = 0; + Node u, v; + Arc e; + while (_qfront <= _qback) { + v = _queue[_qfront++]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + if (_policy[u] == e && !_reached[u]) { + _reached[u] = true; + _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost; + _queue[++_qback] = u; + } + } + } + + // Connect all other nodes to this component and compute node + // distances using reverse BFS + _qfront = 0; + while (_qback < int(_nodes->size())-1) { + v = _queue[_qfront++]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + if (!_reached[u]) { + _reached[u] = true; + _policy[u] = e; + _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost; + _queue[++_qback] = u; + } + } + } + + // Improve node distances + bool improved = false; + for (int i = 0; i < int(_nodes->size()); ++i) { + v = (*_nodes)[i]; + for (int j = 0; j < int(_in_arcs[v].size()); ++j) { + e = _in_arcs[v][j]; + u = _gr.source(e); + LargeCost delta = _dist[v] + _cost[e] * _curr_size - _curr_cost; + if (_tolerance.less(delta, _dist[u])) { + _dist[u] = delta; + _policy[u] = e; + improved = true; + } + } + } + return improved; + } + + }; //class HowardMmc + + ///@} + +} //namespace lemon + +#endif //LEMON_HOWARD_MMC_H diff --git a/lemon/hypercube_graph.h b/lemon/hypercube_graph.h --- a/lemon/hypercube_graph.h +++ b/lemon/hypercube_graph.h @@ -262,7 +262,7 @@ return arc._id >> _dim; } - int index(Node node) const { + static int index(Node node) { return node._id; } @@ -282,17 +282,23 @@ /// /// \brief Hypercube graph class /// - /// This class implements a special graph type. The nodes of the graph - /// are indiced with integers with at most \c dim binary digits. + /// HypercubeGraph implements a special graph type. The nodes of the + /// graph are indexed with integers having at most \c dim binary digits. /// Two nodes are connected in the graph if and only if their indices /// differ only on one position in the binary form. + /// This class is completely static and it needs constant memory space. + /// Thus you can neither add nor delete nodes or edges, however, + /// the structure can be resized using resize(). + /// + /// This type fully conforms to the \ref concepts::Graph "Graph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. /// /// \note The type of the indices is chosen to \c int for efficiency /// reasons. Thus the maximum dimension of this implementation is 26 /// (assuming that the size of \c int is 32 bit). - /// - /// This graph type fully conforms to the \ref concepts::Graph - /// "Graph concept". class HypercubeGraph : public ExtendedHypercubeGraphBase { typedef ExtendedHypercubeGraphBase Parent; @@ -303,6 +309,21 @@ /// Constructs a hypercube graph with \c dim dimensions. HypercubeGraph(int dim) { construct(dim); } + /// \brief Resizes the graph + /// + /// This function resizes the graph. It fully destroys and + /// rebuilds the structure, therefore the maps of the graph will be + /// reallocated automatically and the previous values will be lost. + void resize(int dim) { + Parent::notifier(Arc()).clear(); + Parent::notifier(Edge()).clear(); + Parent::notifier(Node()).clear(); + construct(dim); + Parent::notifier(Node()).build(); + Parent::notifier(Edge()).build(); + Parent::notifier(Arc()).build(); + } + /// \brief The number of dimensions. /// /// Gives back the number of dimensions. @@ -320,7 +341,7 @@ /// \brief The dimension id of an edge. /// /// Gives back the dimension id of the given edge. - /// It is in the [0..dim-1] range. + /// It is in the range [0..dim-1]. int dimension(Edge edge) const { return Parent::dimension(edge); } @@ -328,7 +349,7 @@ /// \brief The dimension id of an arc. /// /// Gives back the dimension id of the given arc. - /// It is in the [0..dim-1] range. + /// It is in the range [0..dim-1]. int dimension(Arc arc) const { return Parent::dimension(arc); } @@ -337,7 +358,7 @@ /// /// Gives back the index of the given node. /// The lower bits of the integer describes the node. - int index(Node node) const { + static int index(Node node) { return Parent::index(node); } diff --git a/lemon/karp_mmc.h b/lemon/karp_mmc.h new file mode 100644 --- /dev/null +++ b/lemon/karp_mmc.h @@ -0,0 +1,590 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_KARP_MMC_H +#define LEMON_KARP_MMC_H + +/// \ingroup min_mean_cycle +/// +/// \file +/// \brief Karp's algorithm for finding a minimum mean cycle. + +#include +#include +#include +#include +#include +#include + +namespace lemon { + + /// \brief Default traits class of KarpMmc class. + /// + /// Default traits class of KarpMmc class. + /// \tparam GR The type of the digraph. + /// \tparam CM The type of the cost map. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. +#ifdef DOXYGEN + template +#else + template ::is_integer> +#endif + struct KarpMmcDefaultTraits + { + /// The type of the digraph + typedef GR Digraph; + /// The type of the cost map + typedef CM CostMap; + /// The type of the arc costs + typedef typename CostMap::Value Cost; + + /// \brief The large cost type used for internal computations + /// + /// The large cost type used for internal computations. + /// It is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + /// \c Cost must be convertible to \c LargeCost. + typedef double LargeCost; + + /// The tolerance type used for internal computations + typedef lemon::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + typedef lemon::Path Path; + }; + + // Default traits class for integer cost types + template + struct KarpMmcDefaultTraits + { + typedef GR Digraph; + typedef CM CostMap; + typedef typename CostMap::Value Cost; +#ifdef LEMON_HAVE_LONG_LONG + typedef long long LargeCost; +#else + typedef long LargeCost; +#endif + typedef lemon::Tolerance Tolerance; + typedef lemon::Path Path; + }; + + + /// \addtogroup min_mean_cycle + /// @{ + + /// \brief Implementation of Karp's algorithm for finding a minimum + /// mean cycle. + /// + /// This class implements Karp's algorithm for finding a directed + /// cycle of minimum mean cost in a digraph + /// \ref amo93networkflows, \ref dasdan98minmeancycle. + /// It runs in time O(ne) and uses space O(n2+e). + /// + /// \tparam GR The type of the digraph the algorithm runs on. + /// \tparam CM The type of the cost map. The default + /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref KarpMmcDefaultTraits + /// "KarpMmcDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename CM = typename GR::template ArcMap, + typename TR = KarpMmcDefaultTraits > +#endif + class KarpMmc + { + public: + + /// The type of the digraph + typedef typename TR::Digraph Digraph; + /// The type of the cost map + typedef typename TR::CostMap CostMap; + /// The type of the arc costs + typedef typename TR::Cost Cost; + + /// \brief The large cost type + /// + /// The large cost type used for internal computations. + /// By default, it is \c long \c long if the \c Cost type is integer, + /// otherwise it is \c double. + typedef typename TR::LargeCost LargeCost; + + /// The tolerance type + typedef typename TR::Tolerance Tolerance; + + /// \brief The path type of the found cycles + /// + /// The path type of the found cycles. + /// Using the \ref KarpMmcDefaultTraits "default traits class", + /// it is \ref lemon::Path "Path". + typedef typename TR::Path Path; + + /// The \ref KarpMmcDefaultTraits "traits class" of the algorithm + typedef TR Traits; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + + // Data sturcture for path data + struct PathData + { + LargeCost dist; + Arc pred; + PathData(LargeCost d, Arc p = INVALID) : + dist(d), pred(p) {} + }; + + typedef typename Digraph::template NodeMap > + PathDataNodeMap; + + private: + + // The digraph the algorithm runs on + const Digraph &_gr; + // The cost of the arcs + const CostMap &_cost; + + // Data for storing the strongly connected components + int _comp_num; + typename Digraph::template NodeMap _comp; + std::vector > _comp_nodes; + std::vector* _nodes; + typename Digraph::template NodeMap > _out_arcs; + + // Data for the found cycle + LargeCost _cycle_cost; + int _cycle_size; + Node _cycle_node; + + Path *_cycle_path; + bool _local_path; + + // Node map for storing path data + PathDataNodeMap _data; + // The processed nodes in the last round + std::vector _process; + + Tolerance _tolerance; + + // Infinite constant + const LargeCost INF; + + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetLargeCostTraits : public Traits { + typedef T LargeCost; + typedef lemon::Tolerance Tolerance; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c LargeCost type. + /// + /// \ref named-templ-param "Named parameter" for setting \c LargeCost + /// type. It is used for internal computations in the algorithm. + template + struct SetLargeCost + : public KarpMmc > { + typedef KarpMmc > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting the \c %Path + /// type of the found cycles. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addFront() function. + template + struct SetPath + : public KarpMmc > { + typedef KarpMmc > Create; + }; + + /// @} + + protected: + + KarpMmc() {} + + public: + + /// \brief Constructor. + /// + /// The constructor of the class. + /// + /// \param digraph The digraph the algorithm runs on. + /// \param cost The costs of the arcs. + KarpMmc( const Digraph &digraph, + const CostMap &cost ) : + _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph), + _cycle_cost(0), _cycle_size(1), _cycle_node(INVALID), + _cycle_path(NULL), _local_path(false), _data(digraph), + INF(std::numeric_limits::has_infinity ? + std::numeric_limits::infinity() : + std::numeric_limits::max()) + {} + + /// Destructor. + ~KarpMmc() { + if (_local_path) delete _cycle_path; + } + + /// \brief Set the path structure for storing the found cycle. + /// + /// This function sets an external path structure for storing the + /// found cycle. + /// + /// If you don't call this function before calling \ref run() or + /// \ref findCycleMean(), it will allocate a local \ref Path "path" + /// structure. The destuctor deallocates this automatically + /// allocated object, of course. + /// + /// \note The algorithm calls only the \ref lemon::Path::addFront() + /// "addFront()" function of the given path structure. + /// + /// \return (*this) + KarpMmc& cycle(Path &path) { + if (_local_path) { + delete _cycle_path; + _local_path = false; + } + _cycle_path = &path; + return *this; + } + + /// \brief Set the tolerance used by the algorithm. + /// + /// This function sets the tolerance object used by the algorithm. + /// + /// \return (*this) + KarpMmc& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief Return a const reference to the tolerance. + /// + /// This function returns a const reference to the tolerance object + /// used by the algorithm. + const Tolerance& tolerance() const { + return _tolerance; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to call the \ref run() + /// function.\n + /// If you only need the minimum mean cost, you may call + /// \ref findCycleMean(). + + /// @{ + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// It can be called more than once (e.g. if the underlying digraph + /// and/or the arc costs have been modified). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \note mmc.run() is just a shortcut of the following code. + /// \code + /// return mmc.findCycleMean() && mmc.findCycle(); + /// \endcode + bool run() { + return findCycleMean() && findCycle(); + } + + /// \brief Find the minimum cycle mean. + /// + /// This function finds the minimum mean cost of the directed + /// cycles in the digraph. + /// + /// \return \c true if a directed cycle exists in the digraph. + bool findCycleMean() { + // Initialization and find strongly connected components + init(); + findComponents(); + + // Find the minimum cycle mean in the components + for (int comp = 0; comp < _comp_num; ++comp) { + if (!initComponent(comp)) continue; + processRounds(); + updateMinMean(); + } + return (_cycle_node != INVALID); + } + + /// \brief Find a minimum mean directed cycle. + /// + /// This function finds a directed cycle of minimum mean cost + /// in the digraph using the data computed by findCycleMean(). + /// + /// \return \c true if a directed cycle exists in the digraph. + /// + /// \pre \ref findCycleMean() must be called before using this function. + bool findCycle() { + if (_cycle_node == INVALID) return false; + IntNodeMap reached(_gr, -1); + int r = _data[_cycle_node].size(); + Node u = _cycle_node; + while (reached[u] < 0) { + reached[u] = --r; + u = _gr.source(_data[u][r].pred); + } + r = reached[u]; + Arc e = _data[u][r].pred; + _cycle_path->addFront(e); + _cycle_cost = _cost[e]; + _cycle_size = 1; + Node v; + while ((v = _gr.source(e)) != u) { + e = _data[v][--r].pred; + _cycle_path->addFront(e); + _cycle_cost += _cost[e]; + ++_cycle_size; + } + return true; + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these + /// functions.\n + /// The algorithm should be executed before using them. + + /// @{ + + /// \brief Return the total cost of the found cycle. + /// + /// This function returns the total cost of the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + Cost cycleCost() const { + return static_cast(_cycle_cost); + } + + /// \brief Return the number of arcs on the found cycle. + /// + /// This function returns the number of arcs on the found cycle. + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + int cycleSize() const { + return _cycle_size; + } + + /// \brief Return the mean cost of the found cycle. + /// + /// This function returns the mean cost of the found cycle. + /// + /// \note alg.cycleMean() is just a shortcut of the + /// following code. + /// \code + /// return static_cast(alg.cycleCost()) / alg.cycleSize(); + /// \endcode + /// + /// \pre \ref run() or \ref findCycleMean() must be called before + /// using this function. + double cycleMean() const { + return static_cast(_cycle_cost) / _cycle_size; + } + + /// \brief Return the found cycle. + /// + /// This function returns a const reference to the path structure + /// storing the found cycle. + /// + /// \pre \ref run() or \ref findCycle() must be called before using + /// this function. + const Path& cycle() const { + return *_cycle_path; + } + + ///@} + + private: + + // Initialization + void init() { + if (!_cycle_path) { + _local_path = true; + _cycle_path = new Path; + } + _cycle_path->clear(); + _cycle_cost = 0; + _cycle_size = 1; + _cycle_node = INVALID; + for (NodeIt u(_gr); u != INVALID; ++u) + _data[u].clear(); + } + + // Find strongly connected components and initialize _comp_nodes + // and _out_arcs + void findComponents() { + _comp_num = stronglyConnectedComponents(_gr, _comp); + _comp_nodes.resize(_comp_num); + if (_comp_num == 1) { + _comp_nodes[0].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + _comp_nodes[0].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + _out_arcs[n].push_back(a); + } + } + } else { + for (int i = 0; i < _comp_num; ++i) + _comp_nodes[i].clear(); + for (NodeIt n(_gr); n != INVALID; ++n) { + int k = _comp[n]; + _comp_nodes[k].push_back(n); + _out_arcs[n].clear(); + for (OutArcIt a(_gr, n); a != INVALID; ++a) { + if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); + } + } + } + } + + // Initialize path data for the current component + bool initComponent(int comp) { + _nodes = &(_comp_nodes[comp]); + int n = _nodes->size(); + if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { + return false; + } + for (int i = 0; i < n; ++i) { + _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); + } + return true; + } + + // Process all rounds of computing path data for the current component. + // _data[v][k] is the cost of a shortest directed walk from the root + // node to node v containing exactly k arcs. + void processRounds() { + Node start = (*_nodes)[0]; + _data[start][0] = PathData(0); + _process.clear(); + _process.push_back(start); + + int k, n = _nodes->size(); + for (k = 1; k <= n && int(_process.size()) < n; ++k) { + processNextBuildRound(k); + } + for ( ; k <= n; ++k) { + processNextFullRound(k); + } + } + + // Process one round and rebuild _process + void processNextBuildRound(int k) { + std::vector next; + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_process.size()); ++i) { + u = _process[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + if (_data[v][k].dist == INF) next.push_back(v); + _data[v][k] = PathData(d, e); + } + } + } + _process.swap(next); + } + + // Process one round using _nodes instead of _process + void processNextFullRound(int k) { + Node u, v; + Arc e; + LargeCost d; + for (int i = 0; i < int(_nodes->size()); ++i) { + u = (*_nodes)[i]; + for (int j = 0; j < int(_out_arcs[u].size()); ++j) { + e = _out_arcs[u][j]; + v = _gr.target(e); + d = _data[u][k-1].dist + _cost[e]; + if (_tolerance.less(d, _data[v][k].dist)) { + _data[v][k] = PathData(d, e); + } + } + } + } + + // Update the minimum cycle mean + void updateMinMean() { + int n = _nodes->size(); + for (int i = 0; i < n; ++i) { + Node u = (*_nodes)[i]; + if (_data[u][n].dist == INF) continue; + LargeCost cost, max_cost = 0; + int size, max_size = 1; + bool found_curr = false; + for (int k = 0; k < n; ++k) { + if (_data[u][k].dist == INF) continue; + cost = _data[u][n].dist - _data[u][k].dist; + size = n - k; + if (!found_curr || cost * max_size > max_cost * size) { + found_curr = true; + max_cost = cost; + max_size = size; + } + } + if ( found_curr && (_cycle_node == INVALID || + max_cost * _cycle_size < _cycle_cost * max_size) ) { + _cycle_cost = max_cost; + _cycle_size = max_size; + _cycle_node = u; + } + } + } + + }; //class KarpMmc + + ///@} + +} //namespace lemon + +#endif //LEMON_KARP_MMC_H diff --git a/lemon/lgf_reader.h b/lemon/lgf_reader.h --- a/lemon/lgf_reader.h +++ b/lemon/lgf_reader.h @@ -427,7 +427,7 @@ /// run(); ///\endcode /// - /// By default the reader uses the first section in the file of the + /// By default, the reader uses the first section in the file of the /// proper type. If a section has an optional name, then it can be /// selected for reading by giving an optional name parameter to the /// \c nodes(), \c arcs() or \c attributes() functions. @@ -562,7 +562,7 @@ template friend DigraphReader digraphReader(TDGR& digraph, std::istream& is); template - friend DigraphReader digraphReader(TDGR& digraph, + friend DigraphReader digraphReader(TDGR& digraph, const std::string& fn); template friend DigraphReader digraphReader(TDGR& digraph, const char *fn); @@ -1194,14 +1194,14 @@ /// @} }; - + /// \ingroup lemon_io /// /// \brief Return a \ref DigraphReader class /// /// This function just returns a \ref DigraphReader class. /// - /// With this function a digraph can be read from an + /// With this function a digraph can be read from an /// \ref lgf-format "LGF" file or input stream with several maps and /// attributes. For example, there is network flow problem on a /// digraph, i.e. a digraph with a \e capacity map on the arcs and @@ -1256,7 +1256,7 @@ template class GraphReader; - + template GraphReader graphReader(TGR& graph, std::istream& is = std::cin); template @@ -1393,7 +1393,7 @@ template friend GraphReader graphReader(TGR& graph, std::istream& is); template - friend GraphReader graphReader(TGR& graph, const std::string& fn); + friend GraphReader graphReader(TGR& graph, const std::string& fn); template friend GraphReader graphReader(TGR& graph, const char *fn); @@ -2077,9 +2077,9 @@ /// /// \brief Return a \ref GraphReader class /// - /// This function just returns a \ref GraphReader class. + /// This function just returns a \ref GraphReader class. /// - /// With this function a graph can be read from an + /// With this function a graph can be read from an /// \ref lgf-format "LGF" file or input stream with several maps and /// attributes. For example, there is weighted matching problem on a /// graph, i.e. a graph with a \e weight map on the edges. This @@ -2235,7 +2235,7 @@ /// and the comment lines are filtered out, and the leading /// whitespaces are trimmed from each processed string. /// - /// For example let's see a section, which contain several + /// For example, let's see a section, which contain several /// integers, which should be inserted into a vector. ///\code /// @numbers diff --git a/lemon/lgf_writer.h b/lemon/lgf_writer.h --- a/lemon/lgf_writer.h +++ b/lemon/lgf_writer.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -351,7 +351,7 @@ class DigraphWriter; template - DigraphWriter digraphWriter(const TDGR& digraph, + DigraphWriter digraphWriter(const TDGR& digraph, std::ostream& os = std::cout); template DigraphWriter digraphWriter(const TDGR& digraph, const std::string& fn); @@ -504,7 +504,7 @@ private: template - friend DigraphWriter digraphWriter(const TDGR& digraph, + friend DigraphWriter digraphWriter(const TDGR& digraph, std::ostream& os); template friend DigraphWriter digraphWriter(const TDGR& digraph, @@ -917,7 +917,7 @@ /// /// \brief Return a \ref DigraphWriter class /// - /// This function just returns a \ref DigraphWriter class. + /// This function just returns a \ref DigraphWriter class. /// /// With this function a digraph can be write to a file or output /// stream in \ref lgf-format "LGF" format with several maps and @@ -957,7 +957,7 @@ /// \relates DigraphWriter /// \sa digraphWriter(const TDGR& digraph, std::ostream& os) template - DigraphWriter digraphWriter(const TDGR& digraph, + DigraphWriter digraphWriter(const TDGR& digraph, const std::string& fn) { DigraphWriter tmp(digraph, fn); return tmp; @@ -1101,11 +1101,11 @@ template friend GraphWriter graphWriter(const TGR& graph, std::ostream& os); template - friend GraphWriter graphWriter(const TGR& graph, + friend GraphWriter graphWriter(const TGR& graph, const std::string& fn); template friend GraphWriter graphWriter(const TGR& graph, const char *fn); - + GraphWriter(GraphWriter& other) : _os(other._os), local_os(other.local_os), _graph(other._graph), _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { @@ -1556,7 +1556,7 @@ /// /// \brief Return a \ref GraphWriter class /// - /// This function just returns a \ref GraphWriter class. + /// This function just returns a \ref GraphWriter class. /// /// With this function a graph can be write to a file or output /// stream in \ref lgf-format "LGF" format with several maps and diff --git a/lemon/list_graph.h b/lemon/list_graph.h --- a/lemon/list_graph.h +++ b/lemon/list_graph.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -21,7 +21,7 @@ ///\ingroup graphs ///\file -///\brief ListDigraph, ListGraph classes. +///\brief ListDigraph and ListGraph classes. #include #include @@ -32,6 +32,8 @@ namespace lemon { + class ListDigraph; + class ListDigraphBase { protected: @@ -62,6 +64,7 @@ class Node { friend class ListDigraphBase; + friend class ListDigraph; protected: int id; @@ -77,6 +80,7 @@ class Arc { friend class ListDigraphBase; + friend class ListDigraph; protected: int id; @@ -116,20 +120,20 @@ void first(Arc& arc) const { int n; for(n = first_node; - n!=-1 && nodes[n].first_in == -1; + n != -1 && nodes[n].first_out == -1; n = nodes[n].next) {} - arc.id = (n == -1) ? -1 : nodes[n].first_in; + arc.id = (n == -1) ? -1 : nodes[n].first_out; } void next(Arc& arc) const { - if (arcs[arc.id].next_in != -1) { - arc.id = arcs[arc.id].next_in; + if (arcs[arc.id].next_out != -1) { + arc.id = arcs[arc.id].next_out; } else { int n; - for(n = nodes[arcs[arc.id].target].next; - n!=-1 && nodes[n].first_in == -1; + for(n = nodes[arcs[arc.id].source].next; + n != -1 && nodes[n].first_out == -1; n = nodes[n].next) {} - arc.id = (n == -1) ? -1 : nodes[n].first_in; + arc.id = (n == -1) ? -1 : nodes[n].first_out; } } @@ -311,31 +315,27 @@ ///A general directed graph structure. - ///\ref ListDigraph is a simple and fast directed graph - ///implementation based on static linked lists that are stored in + ///\ref ListDigraph is a versatile and fast directed graph + ///implementation based on linked lists that are stored in ///\c std::vector structures. /// - ///It conforms to the \ref concepts::Digraph "Digraph concept" and it - ///also provides several useful additional functionalities. - ///Most of the member functions and nested classes are documented + ///This type fully conforms to the \ref concepts::Digraph "Digraph concept" + ///and it also provides several useful additional functionalities. + ///Most of its member functions and nested classes are documented ///only in the concept class. /// + ///This class provides only linear time counting for nodes and arcs. + /// ///\sa concepts::Digraph - + ///\sa ListGraph class ListDigraph : public ExtendedListDigraphBase { typedef ExtendedListDigraphBase Parent; private: - ///ListDigraph is \e not copy constructible. Use copyDigraph() instead. - - ///ListDigraph is \e not copy constructible. Use copyDigraph() instead. - /// + /// Digraphs are \e not copy constructible. Use DigraphCopy instead. ListDigraph(const ListDigraph &) :ExtendedListDigraphBase() {}; - ///\brief Assignment of ListDigraph to another one is \e not allowed. - ///Use copyDigraph() instead. - - ///Assignment of ListDigraph to another one is \e not allowed. - ///Use copyDigraph() instead. + /// \brief Assignment of a digraph to another one is \e not allowed. + /// Use DigraphCopy instead. void operator=(const ListDigraph &) {} public: @@ -347,71 +347,72 @@ ///Add a new node to the digraph. - ///Add a new node to the digraph. + ///This function adds a new node to the digraph. ///\return The new node. Node addNode() { return Parent::addNode(); } ///Add a new arc to the digraph. - ///Add a new arc to the digraph with source node \c s + ///This function adds a new arc to the digraph with source node \c s ///and target node \c t. ///\return The new arc. - Arc addArc(const Node& s, const Node& t) { + Arc addArc(Node s, Node t) { return Parent::addArc(s, t); } ///\brief Erase a node from the digraph. /// - ///Erase a node from the digraph. + ///This function erases the given node along with its outgoing and + ///incoming arcs from the digraph. /// - void erase(const Node& n) { Parent::erase(n); } + ///\note All iterators referencing the removed node or the connected + ///arcs are invalidated, of course. + void erase(Node n) { Parent::erase(n); } ///\brief Erase an arc from the digraph. /// - ///Erase an arc from the digraph. + ///This function erases the given arc from the digraph. /// - void erase(const Arc& a) { Parent::erase(a); } + ///\note All iterators referencing the removed arc are invalidated, + ///of course. + void erase(Arc a) { Parent::erase(a); } /// Node validity check - /// This function gives back true if the given node is valid, - /// ie. it is a real node of the graph. + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the digraph. /// - /// \warning A Node pointing to a removed item - /// could become valid again later if new nodes are - /// added to the graph. + /// \warning A removed node could become valid again if new nodes are + /// added to the digraph. bool valid(Node n) const { return Parent::valid(n); } /// Arc validity check - /// This function gives back true if the given arc is valid, - /// ie. it is a real arc of the graph. + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the digraph. /// - /// \warning An Arc pointing to a removed item - /// could become valid again later if new nodes are - /// added to the graph. + /// \warning A removed arc could become valid again if new arcs are + /// added to the digraph. bool valid(Arc a) const { return Parent::valid(a); } - /// Change the target of \c a to \c n + /// Change the target node of an arc - /// Change the target of \c a to \c n + /// This function changes the target node of the given arc \c a to \c n. /// - ///\note The ArcIts and OutArcIts referencing - ///the changed arc remain valid. However InArcIts are - ///invalidated. + ///\note \c ArcIt and \c OutArcIt iterators referencing the changed + ///arc remain valid, but \c InArcIt iterators are invalidated. /// ///\warning This functionality cannot be used together with the Snapshot ///feature. void changeTarget(Arc a, Node n) { Parent::changeTarget(a,n); } - /// Change the source of \c a to \c n + /// Change the source node of an arc - /// Change the source of \c a to \c n + /// This function changes the source node of the given arc \c a to \c n. /// - ///\note The InArcIts referencing the changed arc remain - ///valid. However the ArcIts and OutArcIts are - ///invalidated. + ///\note \c InArcIt iterators referencing the changed arc remain + ///valid, but \c ArcIt and \c OutArcIt iterators are invalidated. /// ///\warning This functionality cannot be used together with the Snapshot ///feature. @@ -419,94 +420,76 @@ Parent::changeSource(a,n); } - /// Invert the direction of an arc. + /// Reverse the direction of an arc. - ///\note The ArcIts referencing the changed arc remain - ///valid. However OutArcIts and InArcIts are - ///invalidated. + /// This function reverses the direction of the given arc. + ///\note \c ArcIt, \c OutArcIt and \c InArcIt iterators referencing + ///the changed arc are invalidated. /// ///\warning This functionality cannot be used together with the Snapshot ///feature. - void reverseArc(Arc e) { - Node t=target(e); - changeTarget(e,source(e)); - changeSource(e,t); + void reverseArc(Arc a) { + Node t=target(a); + changeTarget(a,source(a)); + changeSource(a,t); } - /// Reserve memory for nodes. - - /// Using this function it is possible to avoid the superfluous memory - /// allocation: if you know that the digraph you want to build will - /// be very large (e.g. it will contain millions of nodes and/or arcs) - /// then it is worth reserving space for this amount before starting - /// to build the digraph. - /// \sa reserveArc - void reserveNode(int n) { nodes.reserve(n); }; - - /// Reserve memory for arcs. - - /// Using this function it is possible to avoid the superfluous memory - /// allocation: if you know that the digraph you want to build will - /// be very large (e.g. it will contain millions of nodes and/or arcs) - /// then it is worth reserving space for this amount before starting - /// to build the digraph. - /// \sa reserveNode - void reserveArc(int m) { arcs.reserve(m); }; - ///Contract two nodes. - ///This function contracts two nodes. - ///Node \p b will be removed but instead of deleting - ///incident arcs, they will be joined to \p a. - ///The last parameter \p r controls whether to remove loops. \c true - ///means that loops will be removed. + ///This function contracts the given two nodes. + ///Node \c v is removed, but instead of deleting its + ///incident arcs, they are joined to node \c u. + ///If the last parameter \c r is \c true (this is the default value), + ///then the newly created loops are removed. /// - ///\note The ArcIts referencing a moved arc remain - ///valid. However InArcIts and OutArcIts - ///may be invalidated. + ///\note The moved arcs are joined to node \c u using changeSource() + ///or changeTarget(), thus \c ArcIt and \c OutArcIt iterators are + ///invalidated for the outgoing arcs of node \c v and \c InArcIt + ///iterators are invalidated for the incomming arcs of \c v. + ///Moreover all iterators referencing node \c v or the removed + ///loops are also invalidated. Other iterators remain valid. /// ///\warning This functionality cannot be used together with the Snapshot ///feature. - void contract(Node a, Node b, bool r = true) + void contract(Node u, Node v, bool r = true) { - for(OutArcIt e(*this,b);e!=INVALID;) { + for(OutArcIt e(*this,v);e!=INVALID;) { OutArcIt f=e; ++f; - if(r && target(e)==a) erase(e); - else changeSource(e,a); + if(r && target(e)==u) erase(e); + else changeSource(e,u); e=f; } - for(InArcIt e(*this,b);e!=INVALID;) { + for(InArcIt e(*this,v);e!=INVALID;) { InArcIt f=e; ++f; - if(r && source(e)==a) erase(e); - else changeTarget(e,a); + if(r && source(e)==u) erase(e); + else changeTarget(e,u); e=f; } - erase(b); + erase(v); } ///Split a node. - ///This function splits a node. First a new node is added to the digraph, - ///then the source of each outgoing arc of \c n is moved to this new node. - ///If \c connect is \c true (this is the default value), then a new arc - ///from \c n to the newly created node is also added. + ///This function splits the given node. First, a new node is added + ///to the digraph, then the source of each outgoing arc of node \c n + ///is moved to this new node. + ///If the second parameter \c connect is \c true (this is the default + ///value), then a new arc from node \c n to the newly created node + ///is also added. ///\return The newly created node. /// - ///\note The ArcIts referencing a moved arc remain - ///valid. However InArcIts and OutArcIts may - ///be invalidated. + ///\note All iterators remain valid. /// - ///\warning This functionality cannot be used in conjunction with the + ///\warning This functionality cannot be used together with the ///Snapshot feature. Node split(Node n, bool connect = true) { Node b = addNode(); - for(OutArcIt e(*this,n);e!=INVALID;) { - OutArcIt f=e; - ++f; - changeSource(e,b); - e=f; + nodes[b.id].first_out=nodes[n.id].first_out; + nodes[n.id].first_out=-1; + for(int i=nodes[b.id].first_out; i!=-1; i=arcs[i].next_out) { + arcs[i].source=b.id; } if (connect) addArc(n,b); return b; @@ -514,21 +497,53 @@ ///Split an arc. - ///This function splits an arc. First a new node \c b is added to - ///the digraph, then the original arc is re-targeted to \c - ///b. Finally an arc from \c b to the original target is added. + ///This function splits the given arc. First, a new node \c v is + ///added to the digraph, then the target node of the original arc + ///is set to \c v. Finally, an arc from \c v to the original target + ///is added. + ///\return The newly created node. /// - ///\return The newly created node. + ///\note \c InArcIt iterators referencing the original arc are + ///invalidated. Other iterators remain valid. /// ///\warning This functionality cannot be used together with the ///Snapshot feature. - Node split(Arc e) { - Node b = addNode(); - addArc(b,target(e)); - changeTarget(e,b); - return b; + Node split(Arc a) { + Node v = addNode(); + addArc(v,target(a)); + changeTarget(a,v); + return v; } + ///Clear the digraph. + + ///This function erases all nodes and arcs from the digraph. + /// + ///\note All iterators of the digraph are invalidated, of course. + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the digraph you want to build will + /// be large (e.g. it will contain millions of nodes and/or arcs), + /// then it is worth reserving space for this amount before starting + /// to build the digraph. + /// \sa reserveArc() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for arcs. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the digraph you want to build will + /// be large (e.g. it will contain millions of nodes and/or arcs), + /// then it is worth reserving space for this amount before starting + /// to build the digraph. + /// \sa reserveNode() + void reserveArc(int m) { arcs.reserve(m); }; + /// \brief Class to make a snapshot of the digraph and restore /// it later. /// @@ -537,9 +552,15 @@ /// The newly added nodes and arcs can be removed using the /// restore() function. /// - /// \warning Arc and node deletions and other modifications (e.g. - /// contracting, splitting, reversing arcs or nodes) cannot be + /// \note After a state is restored, you cannot restore a later state, + /// i.e. you cannot add the removed nodes and arcs again using + /// another Snapshot instance. + /// + /// \warning Node and arc deletions and other modifications (e.g. + /// reversing, contracting, splitting arcs or nodes) cannot be /// restored. These events invalidate the snapshot. + /// However, the arcs and nodes that were added to the digraph after + /// making the current snapshot can be removed without invalidating it. class Snapshot { protected: @@ -709,39 +730,40 @@ /// \brief Default constructor. /// /// Default constructor. - /// To actually make a snapshot you must call save(). + /// You have to call save() to actually make a snapshot. Snapshot() : digraph(0), node_observer_proxy(*this), arc_observer_proxy(*this) {} /// \brief Constructor that immediately makes a snapshot. /// - /// This constructor immediately makes a snapshot of the digraph. - /// \param _digraph The digraph we make a snapshot of. - Snapshot(ListDigraph &_digraph) + /// This constructor immediately makes a snapshot of the given digraph. + Snapshot(ListDigraph &gr) : node_observer_proxy(*this), arc_observer_proxy(*this) { - attach(_digraph); + attach(gr); } /// \brief Make a snapshot. /// - /// Make a snapshot of the digraph. - /// - /// This function can be called more than once. In case of a repeated + /// This function makes a snapshot of the given digraph. + /// It can be called more than once. In case of a repeated /// call, the previous snapshot gets lost. - /// \param _digraph The digraph we make the snapshot of. - void save(ListDigraph &_digraph) { + void save(ListDigraph &gr) { if (attached()) { detach(); clear(); } - attach(_digraph); + attach(gr); } /// \brief Undo the changes until the last snapshot. - // - /// Undo the changes until the last snapshot created by save(). + /// + /// This function undos the changes until the last snapshot + /// created by save() or Snapshot(ListDigraph&). + /// + /// \warning This method invalidates the snapshot, i.e. repeated + /// restoring is not supported unless you call save() again. void restore() { detach(); for(std::list::iterator it = added_arcs.begin(); @@ -755,9 +777,9 @@ clear(); } - /// \brief Gives back true when the snapshot is valid. + /// \brief Returns \c true if the snapshot is valid. /// - /// Gives back true when the snapshot is valid. + /// This function returns \c true if the snapshot is valid. bool valid() const { return attached(); } @@ -795,10 +817,6 @@ typedef ListGraphBase Graph; - class Node; - class Arc; - class Edge; - class Node { friend class ListGraphBase; protected: @@ -848,8 +866,6 @@ bool operator<(const Arc& arc) const {return id < arc.id;} }; - - ListGraphBase() : nodes(), first_node(-1), first_free_node(-1), arcs(), first_free_arc(-1) {} @@ -1164,31 +1180,27 @@ ///A general undirected graph structure. - ///\ref ListGraph is a simple and fast undirected graph - ///implementation based on static linked lists that are stored in + ///\ref ListGraph is a versatile and fast undirected graph + ///implementation based on linked lists that are stored in ///\c std::vector structures. /// - ///It conforms to the \ref concepts::Graph "Graph concept" and it - ///also provides several useful additional functionalities. - ///Most of the member functions and nested classes are documented + ///This type fully conforms to the \ref concepts::Graph "Graph concept" + ///and it also provides several useful additional functionalities. + ///Most of its member functions and nested classes are documented ///only in the concept class. /// + ///This class provides only linear time counting for nodes, edges and arcs. + /// ///\sa concepts::Graph - + ///\sa ListDigraph class ListGraph : public ExtendedListGraphBase { typedef ExtendedListGraphBase Parent; private: - ///ListGraph is \e not copy constructible. Use copyGraph() instead. - - ///ListGraph is \e not copy constructible. Use copyGraph() instead. - /// + /// Graphs are \e not copy constructible. Use GraphCopy instead. ListGraph(const ListGraph &) :ExtendedListGraphBase() {}; - ///\brief Assignment of ListGraph to another one is \e not allowed. - ///Use copyGraph() instead. - - ///Assignment of ListGraph to another one is \e not allowed. - ///Use copyGraph() instead. + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use GraphCopy instead. void operator=(const ListGraph &) {} public: /// Constructor @@ -1201,94 +1213,102 @@ /// \brief Add a new node to the graph. /// - /// Add a new node to the graph. + /// This function adds a new node to the graph. /// \return The new node. Node addNode() { return Parent::addNode(); } /// \brief Add a new edge to the graph. /// - /// Add a new edge to the graph with source node \c s - /// and target node \c t. + /// This function adds a new edge to the graph between nodes + /// \c u and \c v with inherent orientation from node \c u to + /// node \c v. /// \return The new edge. - Edge addEdge(const Node& s, const Node& t) { - return Parent::addEdge(s, t); + Edge addEdge(Node u, Node v) { + return Parent::addEdge(u, v); } - /// \brief Erase a node from the graph. + ///\brief Erase a node from the graph. /// - /// Erase a node from the graph. + /// This function erases the given node along with its incident arcs + /// from the graph. /// - void erase(const Node& n) { Parent::erase(n); } + /// \note All iterators referencing the removed node or the incident + /// edges are invalidated, of course. + void erase(Node n) { Parent::erase(n); } - /// \brief Erase an edge from the graph. + ///\brief Erase an edge from the graph. /// - /// Erase an edge from the graph. + /// This function erases the given edge from the graph. /// - void erase(const Edge& e) { Parent::erase(e); } + /// \note All iterators referencing the removed edge are invalidated, + /// of course. + void erase(Edge e) { Parent::erase(e); } /// Node validity check - /// This function gives back true if the given node is valid, - /// ie. it is a real node of the graph. + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the graph. /// - /// \warning A Node pointing to a removed item - /// could become valid again later if new nodes are + /// \warning A removed node could become valid again if new nodes are /// added to the graph. bool valid(Node n) const { return Parent::valid(n); } + /// Edge validity check + + /// This function gives back \c true if the given edge is valid, + /// i.e. it is a real edge of the graph. + /// + /// \warning A removed edge could become valid again if new edges are + /// added to the graph. + bool valid(Edge e) const { return Parent::valid(e); } /// Arc validity check - /// This function gives back true if the given arc is valid, - /// ie. it is a real arc of the graph. + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the graph. /// - /// \warning An Arc pointing to a removed item - /// could become valid again later if new edges are + /// \warning A removed arc could become valid again if new edges are /// added to the graph. bool valid(Arc a) const { return Parent::valid(a); } - /// Edge validity check - /// This function gives back true if the given edge is valid, - /// ie. it is a real arc of the graph. + /// \brief Change the first node of an edge. /// - /// \warning A Edge pointing to a removed item - /// could become valid again later if new edges are - /// added to the graph. - bool valid(Edge e) const { return Parent::valid(e); } - /// \brief Change the end \c u of \c e to \c n + /// This function changes the first node of the given edge \c e to \c n. /// - /// This function changes the end \c u of \c e to node \c n. - /// - ///\note The EdgeIts and ArcIts referencing the - ///changed edge are invalidated and if the changed node is the - ///base node of an iterator then this iterator is also - ///invalidated. + ///\note \c EdgeIt and \c ArcIt iterators referencing the + ///changed edge are invalidated and all other iterators whose + ///base node is the changed node are also invalidated. /// ///\warning This functionality cannot be used together with the ///Snapshot feature. void changeU(Edge e, Node n) { Parent::changeU(e,n); } - /// \brief Change the end \c v of \c e to \c n + /// \brief Change the second node of an edge. /// - /// This function changes the end \c v of \c e to \c n. + /// This function changes the second node of the given edge \c e to \c n. /// - ///\note The EdgeIts referencing the changed edge remain - ///valid, however ArcIts and if the changed node is the - ///base node of an iterator then this iterator is invalidated. + ///\note \c EdgeIt iterators referencing the changed edge remain + ///valid, but \c ArcIt iterators referencing the changed edge and + ///all other iterators whose base node is the changed node are also + ///invalidated. /// ///\warning This functionality cannot be used together with the ///Snapshot feature. void changeV(Edge e, Node n) { Parent::changeV(e,n); } + /// \brief Contract two nodes. /// - /// This function contracts two nodes. - /// Node \p b will be removed but instead of deleting - /// its neighboring arcs, they will be joined to \p a. - /// The last parameter \p r controls whether to remove loops. \c true - /// means that loops will be removed. + /// This function contracts the given two nodes. + /// Node \c b is removed, but instead of deleting + /// its incident edges, they are joined to node \c a. + /// If the last parameter \c r is \c true (this is the default value), + /// then the newly created loops are removed. /// - /// \note The ArcIts referencing a moved arc remain - /// valid. + /// \note The moved edges are joined to node \c a using changeU() + /// or changeV(), thus all edge and arc iterators whose base node is + /// \c b are invalidated. + /// Moreover all iterators referencing node \c b or the removed + /// loops are also invalidated. Other iterators remain valid. /// ///\warning This functionality cannot be used together with the ///Snapshot feature. @@ -1307,6 +1327,34 @@ erase(b); } + ///Clear the graph. + + ///This function erases all nodes and arcs from the graph. + /// + ///\note All iterators of the graph are invalidated, of course. + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveEdge() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for edges. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveNode() + void reserveEdge(int m) { arcs.reserve(2 * m); }; /// \brief Class to make a snapshot of the graph and restore /// it later. @@ -1316,9 +1364,15 @@ /// The newly added nodes and edges can be removed /// using the restore() function. /// - /// \warning Edge and node deletions and other modifications - /// (e.g. changing nodes of edges, contracting nodes) cannot be - /// restored. These events invalidate the snapshot. + /// \note After a state is restored, you cannot restore a later state, + /// i.e. you cannot add the removed nodes and edges again using + /// another Snapshot instance. + /// + /// \warning Node and edge deletions and other modifications + /// (e.g. changing the end-nodes of edges or contracting nodes) + /// cannot be restored. These events invalidate the snapshot. + /// However, the edges and nodes that were added to the graph after + /// making the current snapshot can be removed without invalidating it. class Snapshot { protected: @@ -1488,39 +1542,40 @@ /// \brief Default constructor. /// /// Default constructor. - /// To actually make a snapshot you must call save(). + /// You have to call save() to actually make a snapshot. Snapshot() : graph(0), node_observer_proxy(*this), edge_observer_proxy(*this) {} /// \brief Constructor that immediately makes a snapshot. /// - /// This constructor immediately makes a snapshot of the graph. - /// \param _graph The graph we make a snapshot of. - Snapshot(ListGraph &_graph) + /// This constructor immediately makes a snapshot of the given graph. + Snapshot(ListGraph &gr) : node_observer_proxy(*this), edge_observer_proxy(*this) { - attach(_graph); + attach(gr); } /// \brief Make a snapshot. /// - /// Make a snapshot of the graph. - /// - /// This function can be called more than once. In case of a repeated + /// This function makes a snapshot of the given graph. + /// It can be called more than once. In case of a repeated /// call, the previous snapshot gets lost. - /// \param _graph The graph we make the snapshot of. - void save(ListGraph &_graph) { + void save(ListGraph &gr) { if (attached()) { detach(); clear(); } - attach(_graph); + attach(gr); } /// \brief Undo the changes until the last snapshot. - // - /// Undo the changes until the last snapshot created by save(). + /// + /// This function undos the changes until the last snapshot + /// created by save() or Snapshot(ListGraph&). + /// + /// \warning This method invalidates the snapshot, i.e. repeated + /// restoring is not supported unless you call save() again. void restore() { detach(); for(std::list::iterator it = added_edges.begin(); @@ -1534,9 +1589,9 @@ clear(); } - /// \brief Gives back true when the snapshot is valid. + /// \brief Returns \c true if the snapshot is valid. /// - /// Gives back true when the snapshot is valid. + /// This function returns \c true if the snapshot is valid. bool valid() const { return attached(); } diff --git a/lemon/lp.h b/lemon/lp.h --- a/lemon/lp.h +++ b/lemon/lp.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -84,7 +84,7 @@ typedef SoplexLp Lp; #elif LEMON_HAVE_CLP # define DEFAULT_LP CLP - typedef ClpLp Lp; + typedef ClpLp Lp; #endif #endif diff --git a/lemon/lp_base.cc b/lemon/lp_base.cc --- a/lemon/lp_base.cc +++ b/lemon/lp_base.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff --git a/lemon/lp_base.h b/lemon/lp_base.h --- a/lemon/lp_base.h +++ b/lemon/lp_base.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -82,7 +82,7 @@ /// Verbose output. MESSAGE_VERBOSE }; - + ///The floating point type used by the solver typedef double Value; @@ -114,14 +114,14 @@ typedef Value ExprValue; typedef True LpCol; /// Default constructor - + /// \warning The default constructor sets the Col to an /// undefined value. Col() {} /// Invalid constructor \& conversion. - + /// This constructor initializes the Col to be invalid. - /// \sa Invalid for more details. + /// \sa Invalid for more details. Col(const Invalid&) : _id(-1) {} /// Equality operator @@ -146,7 +146,7 @@ ///Iterator for iterate over the columns of an LP problem - /// Its usage is quite simple, for example you can count the number + /// Its usage is quite simple, for example, you can count the number /// of columns in an LP \c lp: ///\code /// int count=0; @@ -156,12 +156,12 @@ const LpBase *_solver; public: /// Default constructor - + /// \warning The default constructor sets the iterator /// to an undefined value. ColIt() {} /// Sets the iterator to the first Col - + /// Sets the iterator to the first Col. /// ColIt(const LpBase &solver) : _solver(&solver) @@ -169,12 +169,12 @@ _solver->cols.firstItem(_id); } /// Invalid constructor \& conversion - + /// Initialize the iterator to be invalid. /// \sa Invalid for more details. ColIt(const Invalid&) : Col(INVALID) {} /// Next column - + /// Assign the iterator to the next column. /// ColIt &operator++() @@ -209,14 +209,14 @@ typedef Value ExprValue; typedef True LpRow; /// Default constructor - + /// \warning The default constructor sets the Row to an /// undefined value. Row() {} /// Invalid constructor \& conversion. - + /// This constructor initializes the Row to be invalid. - /// \sa Invalid for more details. + /// \sa Invalid for more details. Row(const Invalid&) : _id(-1) {} /// Equality operator @@ -224,7 +224,7 @@ /// the same LP row or both are invalid. bool operator==(Row r) const {return _id == r._id;} /// Inequality operator - + /// \sa operator==(Row r) /// bool operator!=(Row r) const {return _id != r._id;} @@ -241,7 +241,7 @@ ///Iterator for iterate over the rows of an LP problem - /// Its usage is quite simple, for example you can count the number + /// Its usage is quite simple, for example, you can count the number /// of rows in an LP \c lp: ///\code /// int count=0; @@ -251,12 +251,12 @@ const LpBase *_solver; public: /// Default constructor - + /// \warning The default constructor sets the iterator /// to an undefined value. RowIt() {} /// Sets the iterator to the first Row - + /// Sets the iterator to the first Row. /// RowIt(const LpBase &solver) : _solver(&solver) @@ -264,12 +264,12 @@ _solver->rows.firstItem(_id); } /// Invalid constructor \& conversion - + /// Initialize the iterator to be invalid. /// \sa Invalid for more details. RowIt(const Invalid&) : Row(INVALID) {} /// Next row - + /// Assign the iterator to the next row. /// RowIt &operator++() @@ -347,7 +347,7 @@ public: typedef True SolverExpr; /// Default constructor - + /// Construct an empty expression, the coefficients and /// the constant component are initialized to zero. Expr() : const_comp(0) {} @@ -448,9 +448,9 @@ } ///Iterator over the expression - - ///The iterator iterates over the terms of the expression. - /// + + ///The iterator iterates over the terms of the expression. + /// ///\code ///double s=0; ///for(LpBase::Expr::CoeffIt i(e);i!=INVALID;++i) @@ -464,7 +464,7 @@ public: /// Sets the iterator to the first term - + /// Sets the iterator to the first term of the expression. /// CoeffIt(Expr& e) @@ -481,7 +481,7 @@ /// Returns the coefficient of the term const Value& operator*() const { return _it->second; } /// Next term - + /// Assign the iterator to the next term. /// CoeffIt& operator++() { ++_it; return *this; } @@ -493,9 +493,9 @@ }; /// Const iterator over the expression - - ///The iterator iterates over the terms of the expression. - /// + + ///The iterator iterates over the terms of the expression. + /// ///\code ///double s=0; ///for(LpBase::Expr::ConstCoeffIt i(e);i!=INVALID;++i) @@ -509,7 +509,7 @@ public: /// Sets the iterator to the first term - + /// Sets the iterator to the first term of the expression. /// ConstCoeffIt(const Expr& e) @@ -524,7 +524,7 @@ const Value& operator*() const { return _it->second; } /// Next term - + /// Assign the iterator to the next term. /// ConstCoeffIt& operator++() { ++_it; return *this; } @@ -673,7 +673,7 @@ public: typedef True SolverExpr; /// Default constructor - + /// Construct an empty expression, the coefficients are /// initialized to zero. DualExpr() {} @@ -708,7 +708,7 @@ } } /// \brief Removes the coefficients which's absolute value does - /// not exceed \c epsilon. + /// not exceed \c epsilon. void simplify(Value epsilon = 0.0) { std::map::iterator it=comps.begin(); while (it != comps.end()) { @@ -757,9 +757,9 @@ } ///Iterator over the expression - - ///The iterator iterates over the terms of the expression. - /// + + ///The iterator iterates over the terms of the expression. + /// ///\code ///double s=0; ///for(LpBase::DualExpr::CoeffIt i(e);i!=INVALID;++i) @@ -773,7 +773,7 @@ public: /// Sets the iterator to the first term - + /// Sets the iterator to the first term of the expression. /// CoeffIt(DualExpr& e) @@ -791,7 +791,7 @@ const Value& operator*() const { return _it->second; } /// Next term - + /// Assign the iterator to the next term. /// CoeffIt& operator++() { ++_it; return *this; } @@ -803,9 +803,9 @@ }; ///Iterator over the expression - - ///The iterator iterates over the terms of the expression. - /// + + ///The iterator iterates over the terms of the expression. + /// ///\code ///double s=0; ///for(LpBase::DualExpr::ConstCoeffIt i(e);i!=INVALID;++i) @@ -819,7 +819,7 @@ public: /// Sets the iterator to the first term - + /// Sets the iterator to the first term of the expression. /// ConstCoeffIt(const DualExpr& e) @@ -834,7 +834,7 @@ const Value& operator*() const { return _it->second; } /// Next term - + /// Assign the iterator to the next term. /// ConstCoeffIt& operator++() { ++_it; return *this; } @@ -943,6 +943,14 @@ virtual int _addCol() = 0; virtual int _addRow() = 0; + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u) { + int row = _addRow(); + _setRowCoeffs(row, b, e); + _setRowLowerBound(row, l); + _setRowUpperBound(row, u); + return row; + } + virtual void _eraseCol(int col) = 0; virtual void _eraseRow(int row) = 0; @@ -1207,8 +1215,10 @@ ///\param u is the upper bound (\ref INF means no bound) ///\return The created row. Row addRow(Value l,const Expr &e, Value u) { - Row r=addRow(); - row(r,l,e,u); + Row r; + e.simplify(); + r._id = _addRowId(_addRow(l - *e, ExprIterator(e.comps.begin(), cols), + ExprIterator(e.comps.end(), cols), u - *e)); return r; } @@ -1217,8 +1227,12 @@ ///\param c is a linear expression (see \ref Constr) ///\return The created row. Row addRow(const Constr &c) { - Row r=addRow(); - row(r,c); + Row r; + c.expr().simplify(); + r._id = _addRowId(_addRow(c.lowerBounded()?c.lowerBound()-*c.expr():-INF, + ExprIterator(c.expr().comps.begin(), cols), + ExprIterator(c.expr().comps.end(), cols), + c.upperBounded()?c.upperBound()-*c.expr():INF)); return r; } ///Erase a column (i.e a variable) from the LP @@ -1803,10 +1817,10 @@ ///The basis status of variables enum VarStatus { /// The variable is in the basis - BASIC, + BASIC, /// The variable is free, but not basic FREE, - /// The variable has active lower bound + /// The variable has active lower bound LOWER, /// The variable has active upper bound UPPER, @@ -1885,7 +1899,7 @@ return res; } /// Returns a component of the primal ray - + /// The primal ray is solution of the modified primal problem, /// where we change each finite bound to 0, and we looking for a /// negative objective value in case of minimization, and positive @@ -1919,7 +1933,7 @@ } /// Returns a component of the dual ray - + /// The dual ray is solution of the modified primal problem, where /// we change each finite bound to 0 (i.e. the objective function /// coefficients in the primal problem), and we looking for a @@ -2061,7 +2075,7 @@ return res; } ///The value of the objective function - + ///\return ///- \ref INF or -\ref INF means either infeasibility or unboundedness /// of the problem, depending on whether we minimize or maximize. diff --git a/lemon/lp_skeleton.cc b/lemon/lp_skeleton.cc --- a/lemon/lp_skeleton.cc +++ b/lemon/lp_skeleton.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -32,6 +32,11 @@ return ++row_num; } + int SkeletonSolverBase::_addRow(Value, ExprIterator, ExprIterator, Value) + { + return ++row_num; + } + void SkeletonSolverBase::_eraseCol(int) {} void SkeletonSolverBase::_eraseRow(int) {} diff --git a/lemon/lp_skeleton.h b/lemon/lp_skeleton.h --- a/lemon/lp_skeleton.h +++ b/lemon/lp_skeleton.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -23,13 +23,13 @@ ///\file ///\brief Skeleton file to implement LP/MIP solver interfaces -/// +/// ///The classes in this file do nothing, but they can serve as skeletons when ///implementing an interface to new solvers. namespace lemon { ///A skeleton class to implement LP/MIP solver base interface - + ///This class does nothing, but it can serve as a skeleton when ///implementing an interface to new solvers. class SkeletonSolverBase : public virtual LpBase { @@ -45,6 +45,8 @@ /// \e virtual int _addRow(); /// \e + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); + /// \e virtual void _eraseCol(int i); /// \e virtual void _eraseRow(int i); diff --git a/lemon/maps.h b/lemon/maps.h --- a/lemon/maps.h +++ b/lemon/maps.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -29,8 +30,6 @@ ///\ingroup maps ///\brief Miscellaneous property maps -#include - namespace lemon { /// \addtogroup maps @@ -57,7 +56,7 @@ /// its type definitions, or if you have to provide a writable map, /// but data written to it is not required (i.e. it will be sent to /// /dev/null). - /// It conforms the \ref concepts::ReadWriteMap "ReadWriteMap" concept. + /// It conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" concept. /// /// \sa ConstMap template @@ -90,7 +89,7 @@ /// value to each key. /// /// In other aspects it is equivalent to \c NullMap. - /// So it conforms the \ref concepts::ReadWriteMap "ReadWriteMap" + /// So it conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" /// concept, but it absorbs the data written to it. /// /// The simplest way of using this map is through the constMap() @@ -159,7 +158,7 @@ /// value to each key. /// /// In other aspects it is equivalent to \c NullMap. - /// So it conforms the \ref concepts::ReadWriteMap "ReadWriteMap" + /// So it conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" /// concept, but it absorbs the data written to it. /// /// The simplest way of using this map is through the constMap() @@ -231,9 +230,9 @@ /// /// This map is essentially a wrapper for \c std::vector. It assigns /// values to integer keys from the range [0..size-1]. - /// It can be used with some data structures, for example - /// \c UnionFind, \c BinHeap, when the used items are small - /// integers. This map conforms the \ref concepts::ReferenceMap + /// It can be used together with some data structures, e.g. + /// heap types and \c UnionFind, when the used items are small + /// integers. This map conforms to the \ref concepts::ReferenceMap /// "ReferenceMap" concept. /// /// The simplest way of using this map is through the rangeMap() @@ -341,7 +340,7 @@ /// that you can specify a default value for the keys that are not /// stored actually. This value can be different from the default /// contructed value (i.e. \c %Value()). - /// This type conforms the \ref concepts::ReferenceMap "ReferenceMap" + /// This type conforms to the \ref concepts::ReferenceMap "ReferenceMap" /// concept. /// /// This map is useful if a default value should be assigned to most of @@ -349,9 +348,9 @@ /// keys (i.e. the map is "sparse"). /// The name of this type also refers to this important usage. /// - /// Apart form that this map can be used in many other cases since it + /// Apart form that, this map can be used in many other cases since it /// is based on \c std::map, which is a general associative container. - /// However keep in mind that it is usually not as efficient as other + /// However, keep in mind that it is usually not as efficient as other /// maps. /// /// The simplest way of using this map is through the sparseMap() @@ -707,7 +706,7 @@ /// "readable map" to another type using the default conversion. /// The \c Key type of it is inherited from \c M and the \c Value /// type is \c V. - /// This type conforms the \ref concepts::ReadMap "ReadMap" concept. + /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. /// /// The simplest way of using this map is through the convertMap() /// function. @@ -1786,22 +1785,22 @@ /// /// The most important usage of it is storing certain nodes or arcs /// that were marked \c true by an algorithm. - /// For example it makes easier to store the nodes in the processing + /// For example, it makes easier to store the nodes in the processing /// order of Dfs algorithm, as the following examples show. /// \code /// std::vector v; - /// dfs(g,s).processedMap(loggerBoolMap(std::back_inserter(v))).run(); + /// dfs(g).processedMap(loggerBoolMap(std::back_inserter(v))).run(s); /// \endcode /// \code /// std::vector v(countNodes(g)); - /// dfs(g,s).processedMap(loggerBoolMap(v.begin())).run(); + /// dfs(g).processedMap(loggerBoolMap(v.begin())).run(s); /// \endcode /// /// \note The container of the iterator must contain enough space /// for the elements or the iterator should be an inserter iterator. /// /// \note LoggerBoolMap is just \ref concepts::WriteMap "writable", so - /// it cannot be used when a readable map is needed, for example as + /// it cannot be used when a readable map is needed, for example, as /// \c ReachedMap for \c Bfs, \c Dfs and \c Dijkstra algorithms. /// /// \relates LoggerBoolMap @@ -1818,7 +1817,7 @@ /// \brief Provides an immutable and unique id for each item in a graph. /// /// IdMap provides a unique and immutable id for each item of the - /// same type (\c Node, \c Arc or \c Edge) in a graph. This id is + /// same type (\c Node, \c Arc or \c Edge) in a graph. This id is /// - \b unique: different items get different ids, /// - \b immutable: the id of an item does not change (even if you /// delete other nodes). @@ -1826,7 +1825,7 @@ /// Using this map you get access (i.e. can read) the inner id values of /// the items stored in the graph, which is returned by the \c id() /// function of the graph. This map can be inverted with its member - /// class \c InverseMap or with the \c operator() member. + /// class \c InverseMap or with the \c operator()() member. /// /// \tparam GR The graph type. /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or @@ -1866,9 +1865,11 @@ public: - /// \brief This class represents the inverse of its owner (IdMap). + /// \brief The inverse map type of IdMap. /// - /// This class represents the inverse of its owner (IdMap). + /// The inverse map type of IdMap. The subscript operator gives back + /// an item by its id. + /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. /// \see inverse() class InverseMap { public: @@ -1883,9 +1884,9 @@ /// Constructor for creating an id-to-item map. explicit InverseMap(const IdMap& map) : _graph(map._graph) {} - /// \brief Gives back the given item from its id. + /// \brief Gives back an item by its id. /// - /// Gives back the given item from its id. + /// Gives back an item by its id. Item operator[](int id) const { return _graph->fromId(id, Item());} private: @@ -1898,14 +1899,31 @@ InverseMap inverse() const { return InverseMap(*_graph);} }; + /// \brief Returns an \c IdMap class. + /// + /// This function just returns an \c IdMap class. + /// \relates IdMap + template + inline IdMap idMap(const GR& graph) { + return IdMap(graph); + } /// \brief General cross reference graph map type. /// This class provides simple invertable graph maps. /// It wraps a standard graph map (\c NodeMap, \c ArcMap or \c EdgeMap) /// and if a key is set to a new value, then stores it in the inverse map. - /// The values of the map can be accessed - /// with stl compatible forward iterator. + /// The graph items can be accessed by their values either using + /// \c InverseMap or \c operator()(), and the values of the map can be + /// accessed with an STL compatible forward iterator (\c ValueIt). + /// + /// This map is intended to be used when all associated values are + /// different (the map is actually invertable) or there are only a few + /// items with the same value. + /// Otherwise consider to use \c IterableValueMap, which is more + /// suitable and more efficient for such cases. It provides iterators + /// to traverse the items with the same associated value, but + /// it does not have \c InverseMap. /// /// This type is not reference map, so it cannot be modified with /// the subscript operator. @@ -1946,56 +1964,66 @@ /// \brief Forward iterator for values. /// - /// This iterator is an stl compatible forward + /// This iterator is an STL compatible forward /// iterator on the values of the map. The values can /// be accessed in the [beginValue, endValue) range. /// They are considered with multiplicity, so each value is /// traversed for each item it is assigned to. - class ValueIterator + class ValueIt : public std::iterator { friend class CrossRefMap; private: - ValueIterator(typename Container::const_iterator _it) + ValueIt(typename Container::const_iterator _it) : it(_it) {} public: - ValueIterator() {} - - ValueIterator& operator++() { ++it; return *this; } - ValueIterator operator++(int) { - ValueIterator tmp(*this); + /// Constructor + ValueIt() {} + + /// \e + ValueIt& operator++() { ++it; return *this; } + /// \e + ValueIt operator++(int) { + ValueIt tmp(*this); operator++(); return tmp; } + /// \e const Value& operator*() const { return it->first; } + /// \e const Value* operator->() const { return &(it->first); } - bool operator==(ValueIterator jt) const { return it == jt.it; } - bool operator!=(ValueIterator jt) const { return it != jt.it; } + /// \e + bool operator==(ValueIt jt) const { return it == jt.it; } + /// \e + bool operator!=(ValueIt jt) const { return it != jt.it; } private: typename Container::const_iterator it; }; + /// Alias for \c ValueIt + typedef ValueIt ValueIterator; + /// \brief Returns an iterator to the first value. /// - /// Returns an stl compatible iterator to the + /// Returns an STL compatible iterator to the /// first value of the map. The values of the /// map can be accessed in the [beginValue, endValue) /// range. - ValueIterator beginValue() const { - return ValueIterator(_inv_map.begin()); + ValueIt beginValue() const { + return ValueIt(_inv_map.begin()); } /// \brief Returns an iterator after the last value. /// - /// Returns an stl compatible iterator after the + /// Returns an STL compatible iterator after the /// last value of the map. The values of the /// map can be accessed in the [beginValue, endValue) /// range. - ValueIterator endValue() const { - return ValueIterator(_inv_map.end()); + ValueIt endValue() const { + return ValueIt(_inv_map.end()); } /// \brief Sets the value associated with the given key. @@ -2034,6 +2062,14 @@ return it != _inv_map.end() ? it->second : INVALID; } + /// \brief Returns the number of items with the given value. + /// + /// This function returns the number of items with the given value + /// associated with it. + int count(const Value &val) const { + return _inv_map.count(val); + } + protected: /// \brief Erase the key from the map and the inverse map. @@ -2083,10 +2119,12 @@ public: - /// \brief The inverse map type. + /// \brief The inverse map type of CrossRefMap. /// - /// The inverse of this map. The subscript operator of the map - /// gives back the item that was last assigned to the value. + /// The inverse map type of CrossRefMap. The subscript operator gives + /// back an item by its value. + /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. + /// \see inverse() class InverseMap { public: /// \brief Constructor @@ -2113,20 +2151,20 @@ const CrossRefMap& _inverted; }; - /// \brief It gives back the read-only inverse map. + /// \brief Gives back the inverse of the map. /// - /// It gives back the read-only inverse map. + /// Gives back the inverse of the CrossRefMap. InverseMap inverse() const { return InverseMap(*this); } }; - /// \brief Provides continuous and unique ID for the + /// \brief Provides continuous and unique id for the /// items of a graph. /// /// RangeIdMap provides a unique and continuous - /// ID for each item of a given type (\c Node, \c Arc or + /// id for each item of a given type (\c Node, \c Arc or /// \c Edge) in a graph. This id is /// - \b unique: different items get different ids, /// - \b continuous: the range of the ids is the set of integers @@ -2137,7 +2175,7 @@ /// Thus this id is not (necessarily) the same as what can get using /// the \c id() function of the graph or \ref IdMap. /// This map can be inverted with its member class \c InverseMap, - /// or with the \c operator() member. + /// or with the \c operator()() member. /// /// \tparam GR The graph type. /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or @@ -2265,16 +2303,16 @@ _inv_map[pi] = q; } - /// \brief Gives back the \e RangeId of the item + /// \brief Gives back the \e range \e id of the item /// - /// Gives back the \e RangeId of the item. + /// Gives back the \e range \e id of the item. int operator[](const Item& item) const { return Map::operator[](item); } - /// \brief Gives back the item belonging to a \e RangeId - /// - /// Gives back the item belonging to a \e RangeId. + /// \brief Gives back the item belonging to a \e range \e id + /// + /// Gives back the item belonging to the given \e range \e id. Item operator()(int id) const { return _inv_map[id]; } @@ -2288,7 +2326,9 @@ /// \brief The inverse map type of RangeIdMap. /// - /// The inverse map type of RangeIdMap. + /// The inverse map type of RangeIdMap. The subscript operator gives + /// back an item by its \e range \e id. + /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. class InverseMap { public: /// \brief Constructor @@ -2306,7 +2346,7 @@ /// \brief Subscript operator. /// /// Subscript operator. It gives back the item - /// that the descriptor currently belongs to. + /// that the given \e range \e id currently belongs to. Value operator[](const Key& key) const { return _inverted(key); } @@ -2324,12 +2364,932 @@ /// \brief Gives back the inverse of the map. /// - /// Gives back the inverse of the map. + /// Gives back the inverse of the RangeIdMap. const InverseMap inverse() const { return InverseMap(*this); } }; + /// \brief Returns a \c RangeIdMap class. + /// + /// This function just returns an \c RangeIdMap class. + /// \relates RangeIdMap + template + inline RangeIdMap rangeIdMap(const GR& graph) { + return RangeIdMap(graph); + } + + /// \brief Dynamic iterable \c bool map. + /// + /// This class provides a special graph map type which can store a + /// \c bool value for graph items (\c Node, \c Arc or \c Edge). + /// For both \c true and \c false values it is possible to iterate on + /// the keys mapped to the value. + /// + /// This type is a reference map, so it can be modified with the + /// subscript operator. + /// + /// \tparam GR The graph type. + /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or + /// \c GR::Edge). + /// + /// \see IterableIntMap, IterableValueMap + /// \see CrossRefMap + template + class IterableBoolMap + : protected ItemSetTraits::template Map::Type { + private: + typedef GR Graph; + + typedef typename ItemSetTraits::ItemIt KeyIt; + typedef typename ItemSetTraits::template Map::Type Parent; + + std::vector _array; + int _sep; + + public: + + /// Indicates that the map is reference map. + typedef True ReferenceMapTag; + + /// The key type + typedef K Key; + /// The value type + typedef bool Value; + /// The const reference type. + typedef const Value& ConstReference; + + private: + + int position(const Key& key) const { + return Parent::operator[](key); + } + + public: + + /// \brief Reference to the value of the map. + /// + /// This class is similar to the \c bool type. It can be converted to + /// \c bool and it provides the same operators. + class Reference { + friend class IterableBoolMap; + private: + Reference(IterableBoolMap& map, const Key& key) + : _key(key), _map(map) {} + public: + + Reference& operator=(const Reference& value) { + _map.set(_key, static_cast(value)); + return *this; + } + + operator bool() const { + return static_cast(_map)[_key]; + } + + Reference& operator=(bool value) { + _map.set(_key, value); + return *this; + } + Reference& operator&=(bool value) { + _map.set(_key, _map[_key] & value); + return *this; + } + Reference& operator|=(bool value) { + _map.set(_key, _map[_key] | value); + return *this; + } + Reference& operator^=(bool value) { + _map.set(_key, _map[_key] ^ value); + return *this; + } + private: + Key _key; + IterableBoolMap& _map; + }; + + /// \brief Constructor of the map with a default value. + /// + /// Constructor of the map with a default value. + explicit IterableBoolMap(const Graph& graph, bool def = false) + : Parent(graph) { + typename Parent::Notifier* nf = Parent::notifier(); + Key it; + for (nf->first(it); it != INVALID; nf->next(it)) { + Parent::set(it, _array.size()); + _array.push_back(it); + } + _sep = (def ? _array.size() : 0); + } + + /// \brief Const subscript operator of the map. + /// + /// Const subscript operator of the map. + bool operator[](const Key& key) const { + return position(key) < _sep; + } + + /// \brief Subscript operator of the map. + /// + /// Subscript operator of the map. + Reference operator[](const Key& key) { + return Reference(*this, key); + } + + /// \brief Set operation of the map. + /// + /// Set operation of the map. + void set(const Key& key, bool value) { + int pos = position(key); + if (value) { + if (pos < _sep) return; + Key tmp = _array[_sep]; + _array[_sep] = key; + Parent::set(key, _sep); + _array[pos] = tmp; + Parent::set(tmp, pos); + ++_sep; + } else { + if (pos >= _sep) return; + --_sep; + Key tmp = _array[_sep]; + _array[_sep] = key; + Parent::set(key, _sep); + _array[pos] = tmp; + Parent::set(tmp, pos); + } + } + + /// \brief Set all items. + /// + /// Set all items in the map. + /// \note Constant time operation. + void setAll(bool value) { + _sep = (value ? _array.size() : 0); + } + + /// \brief Returns the number of the keys mapped to \c true. + /// + /// Returns the number of the keys mapped to \c true. + int trueNum() const { + return _sep; + } + + /// \brief Returns the number of the keys mapped to \c false. + /// + /// Returns the number of the keys mapped to \c false. + int falseNum() const { + return _array.size() - _sep; + } + + /// \brief Iterator for the keys mapped to \c true. + /// + /// Iterator for the keys mapped to \c true. It works + /// like a graph item iterator, it can be converted to + /// the key type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid key, it will be equal to + /// \c INVALID. + class TrueIt : public Key { + public: + typedef Key Parent; + + /// \brief Creates an iterator. + /// + /// Creates an iterator. It iterates on the + /// keys mapped to \c true. + /// \param map The IterableBoolMap. + explicit TrueIt(const IterableBoolMap& map) + : Parent(map._sep > 0 ? map._array[map._sep - 1] : INVALID), + _map(&map) {} + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + TrueIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Increment operator. + /// + /// Increment operator. + TrueIt& operator++() { + int pos = _map->position(*this); + Parent::operator=(pos > 0 ? _map->_array[pos - 1] : INVALID); + return *this; + } + + private: + const IterableBoolMap* _map; + }; + + /// \brief Iterator for the keys mapped to \c false. + /// + /// Iterator for the keys mapped to \c false. It works + /// like a graph item iterator, it can be converted to + /// the key type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid key, it will be equal to + /// \c INVALID. + class FalseIt : public Key { + public: + typedef Key Parent; + + /// \brief Creates an iterator. + /// + /// Creates an iterator. It iterates on the + /// keys mapped to \c false. + /// \param map The IterableBoolMap. + explicit FalseIt(const IterableBoolMap& map) + : Parent(map._sep < int(map._array.size()) ? + map._array.back() : INVALID), _map(&map) {} + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + FalseIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Increment operator. + /// + /// Increment operator. + FalseIt& operator++() { + int pos = _map->position(*this); + Parent::operator=(pos > _map->_sep ? _map->_array[pos - 1] : INVALID); + return *this; + } + + private: + const IterableBoolMap* _map; + }; + + /// \brief Iterator for the keys mapped to a given value. + /// + /// Iterator for the keys mapped to a given value. It works + /// like a graph item iterator, it can be converted to + /// the key type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid key, it will be equal to + /// \c INVALID. + class ItemIt : public Key { + public: + typedef Key Parent; + + /// \brief Creates an iterator with a value. + /// + /// Creates an iterator with a value. It iterates on the + /// keys mapped to the given value. + /// \param map The IterableBoolMap. + /// \param value The value. + ItemIt(const IterableBoolMap& map, bool value) + : Parent(value ? + (map._sep > 0 ? + map._array[map._sep - 1] : INVALID) : + (map._sep < int(map._array.size()) ? + map._array.back() : INVALID)), _map(&map) {} + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + ItemIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Increment operator. + /// + /// Increment operator. + ItemIt& operator++() { + int pos = _map->position(*this); + int _sep = pos >= _map->_sep ? _map->_sep : 0; + Parent::operator=(pos > _sep ? _map->_array[pos - 1] : INVALID); + return *this; + } + + private: + const IterableBoolMap* _map; + }; + + protected: + + virtual void add(const Key& key) { + Parent::add(key); + Parent::set(key, _array.size()); + _array.push_back(key); + } + + virtual void add(const std::vector& keys) { + Parent::add(keys); + for (int i = 0; i < int(keys.size()); ++i) { + Parent::set(keys[i], _array.size()); + _array.push_back(keys[i]); + } + } + + virtual void erase(const Key& key) { + int pos = position(key); + if (pos < _sep) { + --_sep; + Parent::set(_array[_sep], pos); + _array[pos] = _array[_sep]; + Parent::set(_array.back(), _sep); + _array[_sep] = _array.back(); + _array.pop_back(); + } else { + Parent::set(_array.back(), pos); + _array[pos] = _array.back(); + _array.pop_back(); + } + Parent::erase(key); + } + + virtual void erase(const std::vector& keys) { + for (int i = 0; i < int(keys.size()); ++i) { + int pos = position(keys[i]); + if (pos < _sep) { + --_sep; + Parent::set(_array[_sep], pos); + _array[pos] = _array[_sep]; + Parent::set(_array.back(), _sep); + _array[_sep] = _array.back(); + _array.pop_back(); + } else { + Parent::set(_array.back(), pos); + _array[pos] = _array.back(); + _array.pop_back(); + } + } + Parent::erase(keys); + } + + virtual void build() { + Parent::build(); + typename Parent::Notifier* nf = Parent::notifier(); + Key it; + for (nf->first(it); it != INVALID; nf->next(it)) { + Parent::set(it, _array.size()); + _array.push_back(it); + } + _sep = 0; + } + + virtual void clear() { + _array.clear(); + _sep = 0; + Parent::clear(); + } + + }; + + + namespace _maps_bits { + template + struct IterableIntMapNode { + IterableIntMapNode() : value(-1) {} + IterableIntMapNode(int _value) : value(_value) {} + Item prev, next; + int value; + }; + } + + /// \brief Dynamic iterable integer map. + /// + /// This class provides a special graph map type which can store an + /// integer value for graph items (\c Node, \c Arc or \c Edge). + /// For each non-negative value it is possible to iterate on the keys + /// mapped to the value. + /// + /// This map is intended to be used with small integer values, for which + /// it is efficient, and supports iteration only for non-negative values. + /// If you need large values and/or iteration for negative integers, + /// consider to use \ref IterableValueMap instead. + /// + /// This type is a reference map, so it can be modified with the + /// subscript operator. + /// + /// \note The size of the data structure depends on the largest + /// value in the map. + /// + /// \tparam GR The graph type. + /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or + /// \c GR::Edge). + /// + /// \see IterableBoolMap, IterableValueMap + /// \see CrossRefMap + template + class IterableIntMap + : protected ItemSetTraits:: + template Map<_maps_bits::IterableIntMapNode >::Type { + public: + typedef typename ItemSetTraits:: + template Map<_maps_bits::IterableIntMapNode >::Type Parent; + + /// The key type + typedef K Key; + /// The value type + typedef int Value; + /// The graph type + typedef GR Graph; + + /// \brief Constructor of the map. + /// + /// Constructor of the map. It sets all values to -1. + explicit IterableIntMap(const Graph& graph) + : Parent(graph) {} + + /// \brief Constructor of the map with a given value. + /// + /// Constructor of the map with a given value. + explicit IterableIntMap(const Graph& graph, int value) + : Parent(graph, _maps_bits::IterableIntMapNode(value)) { + if (value >= 0) { + for (typename Parent::ItemIt it(*this); it != INVALID; ++it) { + lace(it); + } + } + } + + private: + + void unlace(const Key& key) { + typename Parent::Value& node = Parent::operator[](key); + if (node.value < 0) return; + if (node.prev != INVALID) { + Parent::operator[](node.prev).next = node.next; + } else { + _first[node.value] = node.next; + } + if (node.next != INVALID) { + Parent::operator[](node.next).prev = node.prev; + } + while (!_first.empty() && _first.back() == INVALID) { + _first.pop_back(); + } + } + + void lace(const Key& key) { + typename Parent::Value& node = Parent::operator[](key); + if (node.value < 0) return; + if (node.value >= int(_first.size())) { + _first.resize(node.value + 1, INVALID); + } + node.prev = INVALID; + node.next = _first[node.value]; + if (node.next != INVALID) { + Parent::operator[](node.next).prev = key; + } + _first[node.value] = key; + } + + public: + + /// Indicates that the map is reference map. + typedef True ReferenceMapTag; + + /// \brief Reference to the value of the map. + /// + /// This class is similar to the \c int type. It can + /// be converted to \c int and it has the same operators. + class Reference { + friend class IterableIntMap; + private: + Reference(IterableIntMap& map, const Key& key) + : _key(key), _map(map) {} + public: + + Reference& operator=(const Reference& value) { + _map.set(_key, static_cast(value)); + return *this; + } + + operator const int&() const { + return static_cast(_map)[_key]; + } + + Reference& operator=(int value) { + _map.set(_key, value); + return *this; + } + Reference& operator++() { + _map.set(_key, _map[_key] + 1); + return *this; + } + int operator++(int) { + int value = _map[_key]; + _map.set(_key, value + 1); + return value; + } + Reference& operator--() { + _map.set(_key, _map[_key] - 1); + return *this; + } + int operator--(int) { + int value = _map[_key]; + _map.set(_key, value - 1); + return value; + } + Reference& operator+=(int value) { + _map.set(_key, _map[_key] + value); + return *this; + } + Reference& operator-=(int value) { + _map.set(_key, _map[_key] - value); + return *this; + } + Reference& operator*=(int value) { + _map.set(_key, _map[_key] * value); + return *this; + } + Reference& operator/=(int value) { + _map.set(_key, _map[_key] / value); + return *this; + } + Reference& operator%=(int value) { + _map.set(_key, _map[_key] % value); + return *this; + } + Reference& operator&=(int value) { + _map.set(_key, _map[_key] & value); + return *this; + } + Reference& operator|=(int value) { + _map.set(_key, _map[_key] | value); + return *this; + } + Reference& operator^=(int value) { + _map.set(_key, _map[_key] ^ value); + return *this; + } + Reference& operator<<=(int value) { + _map.set(_key, _map[_key] << value); + return *this; + } + Reference& operator>>=(int value) { + _map.set(_key, _map[_key] >> value); + return *this; + } + + private: + Key _key; + IterableIntMap& _map; + }; + + /// The const reference type. + typedef const Value& ConstReference; + + /// \brief Gives back the maximal value plus one. + /// + /// Gives back the maximal value plus one. + int size() const { + return _first.size(); + } + + /// \brief Set operation of the map. + /// + /// Set operation of the map. + void set(const Key& key, const Value& value) { + unlace(key); + Parent::operator[](key).value = value; + lace(key); + } + + /// \brief Const subscript operator of the map. + /// + /// Const subscript operator of the map. + const Value& operator[](const Key& key) const { + return Parent::operator[](key).value; + } + + /// \brief Subscript operator of the map. + /// + /// Subscript operator of the map. + Reference operator[](const Key& key) { + return Reference(*this, key); + } + + /// \brief Iterator for the keys with the same value. + /// + /// Iterator for the keys with the same value. It works + /// like a graph item iterator, it can be converted to + /// the item type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid item, it will be equal to + /// \c INVALID. + class ItemIt : public Key { + public: + typedef Key Parent; + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + ItemIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Creates an iterator with a value. + /// + /// Creates an iterator with a value. It iterates on the + /// keys mapped to the given value. + /// \param map The IterableIntMap. + /// \param value The value. + ItemIt(const IterableIntMap& map, int value) : _map(&map) { + if (value < 0 || value >= int(_map->_first.size())) { + Parent::operator=(INVALID); + } else { + Parent::operator=(_map->_first[value]); + } + } + + /// \brief Increment operator. + /// + /// Increment operator. + ItemIt& operator++() { + Parent::operator=(_map->IterableIntMap::Parent:: + operator[](static_cast(*this)).next); + return *this; + } + + private: + const IterableIntMap* _map; + }; + + protected: + + virtual void erase(const Key& key) { + unlace(key); + Parent::erase(key); + } + + virtual void erase(const std::vector& keys) { + for (int i = 0; i < int(keys.size()); ++i) { + unlace(keys[i]); + } + Parent::erase(keys); + } + + virtual void clear() { + _first.clear(); + Parent::clear(); + } + + private: + std::vector _first; + }; + + namespace _maps_bits { + template + struct IterableValueMapNode { + IterableValueMapNode(Value _value = Value()) : value(_value) {} + Item prev, next; + Value value; + }; + } + + /// \brief Dynamic iterable map for comparable values. + /// + /// This class provides a special graph map type which can store a + /// comparable value for graph items (\c Node, \c Arc or \c Edge). + /// For each value it is possible to iterate on the keys mapped to + /// the value (\c ItemIt), and the values of the map can be accessed + /// with an STL compatible forward iterator (\c ValueIt). + /// The map stores a linked list for each value, which contains + /// the items mapped to the value, and the used values are stored + /// in balanced binary tree (\c std::map). + /// + /// \ref IterableBoolMap and \ref IterableIntMap are similar classes + /// specialized for \c bool and \c int values, respectively. + /// + /// This type is not reference map, so it cannot be modified with + /// the subscript operator. + /// + /// \tparam GR The graph type. + /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or + /// \c GR::Edge). + /// \tparam V The value type of the map. It can be any comparable + /// value type. + /// + /// \see IterableBoolMap, IterableIntMap + /// \see CrossRefMap + template + class IterableValueMap + : protected ItemSetTraits:: + template Map<_maps_bits::IterableValueMapNode >::Type { + public: + typedef typename ItemSetTraits:: + template Map<_maps_bits::IterableValueMapNode >::Type Parent; + + /// The key type + typedef K Key; + /// The value type + typedef V Value; + /// The graph type + typedef GR Graph; + + public: + + /// \brief Constructor of the map with a given value. + /// + /// Constructor of the map with a given value. + explicit IterableValueMap(const Graph& graph, + const Value& value = Value()) + : Parent(graph, _maps_bits::IterableValueMapNode(value)) { + for (typename Parent::ItemIt it(*this); it != INVALID; ++it) { + lace(it); + } + } + + protected: + + void unlace(const Key& key) { + typename Parent::Value& node = Parent::operator[](key); + if (node.prev != INVALID) { + Parent::operator[](node.prev).next = node.next; + } else { + if (node.next != INVALID) { + _first[node.value] = node.next; + } else { + _first.erase(node.value); + } + } + if (node.next != INVALID) { + Parent::operator[](node.next).prev = node.prev; + } + } + + void lace(const Key& key) { + typename Parent::Value& node = Parent::operator[](key); + typename std::map::iterator it = _first.find(node.value); + if (it == _first.end()) { + node.prev = node.next = INVALID; + _first.insert(std::make_pair(node.value, key)); + } else { + node.prev = INVALID; + node.next = it->second; + if (node.next != INVALID) { + Parent::operator[](node.next).prev = key; + } + it->second = key; + } + } + + public: + + /// \brief Forward iterator for values. + /// + /// This iterator is an STL compatible forward + /// iterator on the values of the map. The values can + /// be accessed in the [beginValue, endValue) range. + class ValueIt + : public std::iterator { + friend class IterableValueMap; + private: + ValueIt(typename std::map::const_iterator _it) + : it(_it) {} + public: + + /// Constructor + ValueIt() {} + + /// \e + ValueIt& operator++() { ++it; return *this; } + /// \e + ValueIt operator++(int) { + ValueIt tmp(*this); + operator++(); + return tmp; + } + + /// \e + const Value& operator*() const { return it->first; } + /// \e + const Value* operator->() const { return &(it->first); } + + /// \e + bool operator==(ValueIt jt) const { return it == jt.it; } + /// \e + bool operator!=(ValueIt jt) const { return it != jt.it; } + + private: + typename std::map::const_iterator it; + }; + + /// \brief Returns an iterator to the first value. + /// + /// Returns an STL compatible iterator to the + /// first value of the map. The values of the + /// map can be accessed in the [beginValue, endValue) + /// range. + ValueIt beginValue() const { + return ValueIt(_first.begin()); + } + + /// \brief Returns an iterator after the last value. + /// + /// Returns an STL compatible iterator after the + /// last value of the map. The values of the + /// map can be accessed in the [beginValue, endValue) + /// range. + ValueIt endValue() const { + return ValueIt(_first.end()); + } + + /// \brief Set operation of the map. + /// + /// Set operation of the map. + void set(const Key& key, const Value& value) { + unlace(key); + Parent::operator[](key).value = value; + lace(key); + } + + /// \brief Const subscript operator of the map. + /// + /// Const subscript operator of the map. + const Value& operator[](const Key& key) const { + return Parent::operator[](key).value; + } + + /// \brief Iterator for the keys with the same value. + /// + /// Iterator for the keys with the same value. It works + /// like a graph item iterator, it can be converted to + /// the item type of the map, incremented with \c ++ operator, and + /// if the iterator leaves the last valid item, it will be equal to + /// \c INVALID. + class ItemIt : public Key { + public: + typedef Key Parent; + + /// \brief Invalid constructor \& conversion. + /// + /// This constructor initializes the iterator to be invalid. + /// \sa Invalid for more details. + ItemIt(Invalid) : Parent(INVALID), _map(0) {} + + /// \brief Creates an iterator with a value. + /// + /// Creates an iterator with a value. It iterates on the + /// keys which have the given value. + /// \param map The IterableValueMap + /// \param value The value + ItemIt(const IterableValueMap& map, const Value& value) : _map(&map) { + typename std::map::const_iterator it = + map._first.find(value); + if (it == map._first.end()) { + Parent::operator=(INVALID); + } else { + Parent::operator=(it->second); + } + } + + /// \brief Increment operator. + /// + /// Increment Operator. + ItemIt& operator++() { + Parent::operator=(_map->IterableValueMap::Parent:: + operator[](static_cast(*this)).next); + return *this; + } + + + private: + const IterableValueMap* _map; + }; + + protected: + + virtual void add(const Key& key) { + Parent::add(key); + lace(key); + } + + virtual void add(const std::vector& keys) { + Parent::add(keys); + for (int i = 0; i < int(keys.size()); ++i) { + lace(keys[i]); + } + } + + virtual void erase(const Key& key) { + unlace(key); + Parent::erase(key); + } + + virtual void erase(const std::vector& keys) { + for (int i = 0; i < int(keys.size()); ++i) { + unlace(keys[i]); + } + Parent::erase(keys); + } + + virtual void build() { + Parent::build(); + for (typename Parent::ItemIt it(*this); it != INVALID; ++it) { + lace(it); + } + } + + virtual void clear() { + _first.clear(); + Parent::clear(); + } + + private: + std::map _first; + }; + /// \brief Map of the source nodes of arcs in a digraph. /// /// SourceMap provides access for the source node of each arc in a digraph, @@ -2340,9 +3300,9 @@ class SourceMap { public: - ///\e + /// The key type (the \c Arc type of the digraph). typedef typename GR::Arc Key; - ///\e + /// The value type (the \c Node type of the digraph). typedef typename GR::Node Value; /// \brief Constructor @@ -2381,9 +3341,9 @@ class TargetMap { public: - ///\e + /// The key type (the \c Arc type of the digraph). typedef typename GR::Arc Key; - ///\e + /// The value type (the \c Node type of the digraph). typedef typename GR::Node Value; /// \brief Constructor @@ -2423,8 +3383,10 @@ class ForwardMap { public: + /// The key type (the \c Edge type of the digraph). + typedef typename GR::Edge Key; + /// The value type (the \c Arc type of the digraph). typedef typename GR::Arc Value; - typedef typename GR::Edge Key; /// \brief Constructor /// @@ -2463,8 +3425,10 @@ class BackwardMap { public: + /// The key type (the \c Edge type of the digraph). + typedef typename GR::Edge Key; + /// The value type (the \c Arc type of the digraph). typedef typename GR::Arc Value; - typedef typename GR::Edge Key; /// \brief Constructor /// @@ -2499,10 +3463,10 @@ /// in constant time. On the other hand, the values are updated automatically /// whenever the digraph changes. /// - /// \warning Besides \c addNode() and \c addArc(), a digraph structure + /// \warning Besides \c addNode() and \c addArc(), a digraph structure /// may provide alternative ways to modify the digraph. /// The correct behavior of InDegMap is not guarantied if these additional - /// features are used. For example the functions + /// features are used. For example, the functions /// \ref ListDigraph::changeSource() "changeSource()", /// \ref ListDigraph::changeTarget() "changeTarget()" and /// \ref ListDigraph::reverseArc() "reverseArc()" @@ -2515,7 +3479,7 @@ ::ItemNotifier::ObserverBase { public: - + /// The graph type of InDegMap typedef GR Graph; typedef GR Digraph; @@ -2629,10 +3593,10 @@ /// in constant time. On the other hand, the values are updated automatically /// whenever the digraph changes. /// - /// \warning Besides \c addNode() and \c addArc(), a digraph structure + /// \warning Besides \c addNode() and \c addArc(), a digraph structure /// may provide alternative ways to modify the digraph. /// The correct behavior of OutDegMap is not guarantied if these additional - /// features are used. For example the functions + /// features are used. For example, the functions /// \ref ListDigraph::changeSource() "changeSource()", /// \ref ListDigraph::changeTarget() "changeTarget()" and /// \ref ListDigraph::reverseArc() "reverseArc()" @@ -2800,6 +3764,293 @@ return PotentialDifferenceMap(gr, potential); } + + /// \brief Copy the values of a graph map to another map. + /// + /// This function copies the values of a graph map to another graph map. + /// \c To::Key must be equal or convertible to \c From::Key and + /// \c From::Value must be equal or convertible to \c To::Value. + /// + /// For example, an edge map of \c int value type can be copied to + /// an arc map of \c double value type in an undirected graph, but + /// an arc map cannot be copied to an edge map. + /// Note that even a \ref ConstMap can be copied to a standard graph map, + /// but \ref mapFill() can also be used for this purpose. + /// + /// \param gr The graph for which the maps are defined. + /// \param from The map from which the values have to be copied. + /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. + /// \param to The map to which the values have to be copied. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + template + void mapCopy(const GR& gr, const From& from, To& to) { + typedef typename To::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + to.set(it, from[it]); + } + } + + /// \brief Compare two graph maps. + /// + /// This function compares the values of two graph maps. It returns + /// \c true if the maps assign the same value for all items in the graph. + /// The \c Key type of the maps (\c Node, \c Arc or \c Edge) must be equal + /// and their \c Value types must be comparable using \c %operator==(). + /// + /// \param gr The graph for which the maps are defined. + /// \param map1 The first map. + /// \param map2 The second map. + template + bool mapCompare(const GR& gr, const Map1& map1, const Map2& map2) { + typedef typename Map2::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + if (!(map1[it] == map2[it])) return false; + } + return true; + } + + /// \brief Return an item having minimum value of a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// minimum value of the given graph map. + /// If the item set is empty, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + template + typename Map::Key mapMin(const GR& gr, const Map& map) { + return mapMin(gr, map, std::less()); + } + + /// \brief Return an item having minimum value of a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// minimum value of the given graph map. + /// If the item set is empty, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param comp Comparison function object. + template + typename Map::Key mapMin(const GR& gr, const Map& map, const Comp& comp) { + typedef typename Map::Key Item; + typedef typename Map::Value Value; + typedef typename ItemSetTraits::ItemIt ItemIt; + + ItemIt min_item(gr); + if (min_item == INVALID) return INVALID; + Value min = map[min_item]; + for (ItemIt it(gr); it != INVALID; ++it) { + if (comp(map[it], min)) { + min = map[it]; + min_item = it; + } + } + return min_item; + } + + /// \brief Return an item having maximum value of a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// maximum value of the given graph map. + /// If the item set is empty, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + template + typename Map::Key mapMax(const GR& gr, const Map& map) { + return mapMax(gr, map, std::less()); + } + + /// \brief Return an item having maximum value of a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// maximum value of the given graph map. + /// If the item set is empty, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param comp Comparison function object. + template + typename Map::Key mapMax(const GR& gr, const Map& map, const Comp& comp) { + typedef typename Map::Key Item; + typedef typename Map::Value Value; + typedef typename ItemSetTraits::ItemIt ItemIt; + + ItemIt max_item(gr); + if (max_item == INVALID) return INVALID; + Value max = map[max_item]; + for (ItemIt it(gr); it != INVALID; ++it) { + if (comp(max, map[it])) { + max = map[it]; + max_item = it; + } + } + return max_item; + } + + /// \brief Return the minimum value of a graph map. + /// + /// This function returns the minimum value of the given graph map. + /// The corresponding item set of the graph must not be empty. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + template + typename Map::Value mapMinValue(const GR& gr, const Map& map) { + return map[mapMin(gr, map, std::less())]; + } + + /// \brief Return the minimum value of a graph map. + /// + /// This function returns the minimum value of the given graph map. + /// The corresponding item set of the graph must not be empty. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param comp Comparison function object. + template + typename Map::Value + mapMinValue(const GR& gr, const Map& map, const Comp& comp) { + return map[mapMin(gr, map, comp)]; + } + + /// \brief Return the maximum value of a graph map. + /// + /// This function returns the maximum value of the given graph map. + /// The corresponding item set of the graph must not be empty. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + template + typename Map::Value mapMaxValue(const GR& gr, const Map& map) { + return map[mapMax(gr, map, std::less())]; + } + + /// \brief Return the maximum value of a graph map. + /// + /// This function returns the maximum value of the given graph map. + /// The corresponding item set of the graph must not be empty. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param comp Comparison function object. + template + typename Map::Value + mapMaxValue(const GR& gr, const Map& map, const Comp& comp) { + return map[mapMax(gr, map, comp)]; + } + + /// \brief Return an item having a specified value in a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// the specified assigned value in the given graph map. + /// If no such item exists, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param val The value that have to be found. + template + typename Map::Key + mapFind(const GR& gr, const Map& map, const typename Map::Value& val) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + if (map[it] == val) return it; + } + return INVALID; + } + + /// \brief Return an item having value for which a certain predicate is + /// true in a graph map. + /// + /// This function returns an item (\c Node, \c Arc or \c Edge) having + /// such assigned value for which the specified predicate is true + /// in the given graph map. + /// If no such item exists, it returns \c INVALID. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param pred The predicate function object. + template + typename Map::Key + mapFindIf(const GR& gr, const Map& map, const Pred& pred) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + if (pred(map[it])) return it; + } + return INVALID; + } + + /// \brief Return the number of items having a specified value in a + /// graph map. + /// + /// This function returns the number of items (\c Node, \c Arc or \c Edge) + /// having the specified assigned value in the given graph map. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param val The value that have to be counted. + template + int mapCount(const GR& gr, const Map& map, const typename Map::Value& val) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + int cnt = 0; + for (ItemIt it(gr); it != INVALID; ++it) { + if (map[it] == val) ++cnt; + } + return cnt; + } + + /// \brief Return the number of items having values for which a certain + /// predicate is true in a graph map. + /// + /// This function returns the number of items (\c Node, \c Arc or \c Edge) + /// having such assigned values for which the specified predicate is true + /// in the given graph map. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. + /// \param pred The predicate function object. + template + int mapCountIf(const GR& gr, const Map& map, const Pred& pred) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + int cnt = 0; + for (ItemIt it(gr); it != INVALID; ++it) { + if (pred(map[it])) ++cnt; + } + return cnt; + } + + /// \brief Fill a graph map with a certain value. + /// + /// This function sets the specified value for all items (\c Node, + /// \c Arc or \c Edge) in the given graph map. + /// + /// \param gr The graph for which the map is defined. + /// \param map The graph map. It must conform to the + /// \ref concepts::WriteMap "WriteMap" concept. + /// \param val The value. + template + void mapFill(const GR& gr, Map& map, const typename Map::Value& val) { + typedef typename Map::Key Item; + typedef typename ItemSetTraits::ItemIt ItemIt; + + for (ItemIt it(gr); it != INVALID; ++it) { + map.set(it, val); + } + } + /// @} } diff --git a/lemon/matching.h b/lemon/matching.h --- a/lemon/matching.h +++ b/lemon/matching.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -16,8 +16,8 @@ * */ -#ifndef LEMON_MAX_MATCHING_H -#define LEMON_MAX_MATCHING_H +#ifndef LEMON_MATCHING_H +#define LEMON_MATCHING_H #include #include @@ -28,6 +28,7 @@ #include #include #include +#include ///\ingroup matching ///\file @@ -41,7 +42,7 @@ /// /// This class implements Edmonds' alternating forest matching algorithm /// for finding a maximum cardinality matching in a general undirected graph. - /// It can be started from an arbitrary initial matching + /// It can be started from an arbitrary initial matching /// (the default is the empty one). /// /// The dual solution of the problem is a map of the nodes to @@ -69,11 +70,11 @@ ///\brief Status constants for Gallai-Edmonds decomposition. /// - ///These constants are used for indicating the Gallai-Edmonds + ///These constants are used for indicating the Gallai-Edmonds ///decomposition of a graph. The nodes with status \c EVEN (or \c D) ///induce a subgraph with factor-critical components, the nodes with ///status \c ODD (or \c A) form the canonical barrier, and the nodes - ///with status \c MATCHED (or \c C) induce a subgraph having a + ///with status \c MATCHED (or \c C) induce a subgraph having a ///perfect matching. enum Status { EVEN = 1, ///< = 1. (\c D is an alias for \c EVEN.) @@ -512,7 +513,7 @@ } } - /// \brief Start Edmonds' algorithm with a heuristic improvement + /// \brief Start Edmonds' algorithm with a heuristic improvement /// for dense graphs /// /// This function runs Edmonds' algorithm with a heuristic of postponing @@ -534,8 +535,8 @@ /// \brief Run Edmonds' algorithm /// - /// This function runs Edmonds' algorithm. An additional heuristic of - /// postponing shrinks is used for relatively dense graphs + /// This function runs Edmonds' algorithm. An additional heuristic of + /// postponing shrinks is used for relatively dense graphs /// (for which m>=2*n holds). void run() { if (countEdges(_graph) < 2 * countNodes(_graph)) { @@ -556,7 +557,7 @@ /// \brief Return the size (cardinality) of the matching. /// - /// This function returns the size (cardinality) of the current matching. + /// This function returns the size (cardinality) of the current matching. /// After run() it returns the size of the maximum matching in the graph. int matchingSize() const { int size = 0; @@ -570,7 +571,7 @@ /// \brief Return \c true if the given edge is in the matching. /// - /// This function returns \c true if the given edge is in the current + /// This function returns \c true if the given edge is in the current /// matching. bool matching(const Edge& edge) const { return edge == (*_matching)[_graph.u(edge)]; @@ -579,7 +580,7 @@ /// \brief Return the matching arc (or edge) incident to the given node. /// /// This function returns the matching arc (or edge) incident to the - /// given node in the current matching or \c INVALID if the node is + /// given node in the current matching or \c INVALID if the node is /// not covered by the matching. Arc matching(const Node& n) const { return (*_matching)[n]; @@ -595,7 +596,7 @@ /// \brief Return the mate of the given node. /// - /// This function returns the mate of the given node in the current + /// This function returns the mate of the given node in the current /// matching or \c INVALID if the node is not covered by the matching. Node mate(const Node& n) const { return (*_matching)[n] != INVALID ? @@ -605,7 +606,7 @@ /// @} /// \name Dual Solution - /// Functions to get the dual solution, i.e. the Gallai-Edmonds + /// Functions to get the dual solution, i.e. the Gallai-Edmonds /// decomposition. /// @{ @@ -648,8 +649,8 @@ /// on extensive use of priority queues and provides /// \f$O(nm\log n)\f$ time complexity. /// - /// The maximum weighted matching problem is to find a subset of the - /// edges in an undirected graph with maximum overall weight for which + /// The maximum weighted matching problem is to find a subset of the + /// edges in an undirected graph with maximum overall weight for which /// each node has at most one incident edge. /// It can be formulated with the following linear program. /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] @@ -673,16 +674,16 @@ /** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}} \frac{\vert B \vert - 1}{2}z_B\f] */ /// - /// The algorithm can be executed with the run() function. + /// The algorithm can be executed with the run() function. /// After it the matching (the primal solution) and the dual solution - /// can be obtained using the query functions and the - /// \ref MaxWeightedMatching::BlossomIt "BlossomIt" nested class, - /// which is able to iterate on the nodes of a blossom. + /// can be obtained using the query functions and the + /// \ref MaxWeightedMatching::BlossomIt "BlossomIt" nested class, + /// which is able to iterate on the nodes of a blossom. /// If the value type is integer, then the dual solution is multiplied /// by \ref MaxWeightedMatching::dualScale "4". /// /// \tparam GR The undirected graph type the algorithm runs on. - /// \tparam WM The type edge weight map. The default type is + /// \tparam WM The type edge weight map. The default type is /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". #ifdef DOXYGEN template @@ -745,7 +746,7 @@ typedef RangeMap IntIntMap; enum Status { - EVEN = -1, MATCHED = 0, ODD = 1, UNMATCHED = -2 + EVEN = -1, MATCHED = 0, ODD = 1 }; typedef HeapUnionFind BlossomSet; @@ -797,6 +798,10 @@ BinHeap *_delta4; Value _delta_sum; + int _unmatched; + + typedef MaxWeightedFractionalMatching FractionalMatching; + FractionalMatching *_fractional; void createStructures() { _node_num = countNodes(_graph); @@ -863,9 +868,6 @@ } void destroyStructures() { - _node_num = countNodes(_graph); - _blossom_num = _node_num * 3 / 2; - if (_matching) { delete _matching; } @@ -941,10 +943,6 @@ if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { _delta3->push(e, rw / 2); } - } else if ((*_blossom_data)[vb].status == UNMATCHED) { - if (_delta3->state(e) != _delta3->IN_HEAP) { - _delta3->push(e, rw); - } } else { typename std::map::iterator it = (*_node_data)[vi].heap_index.find(tree); @@ -968,202 +966,6 @@ _delta2->push(vb, _blossom_set->classPrio(vb) - (*_blossom_data)[vb].offset); } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset){ - _delta2->decrease(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } - } - } - } - } - } - (*_blossom_data)[blossom].offset = 0; - } - - void matchedToOdd(int blossom) { - if (_delta2->state(blossom) == _delta2->IN_HEAP) { - _delta2->erase(blossom); - } - (*_blossom_data)[blossom].offset += _delta_sum; - if (!_blossom_set->trivial(blossom)) { - _delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 + - (*_blossom_data)[blossom].offset); - } - } - - void evenToMatched(int blossom, int tree) { - if (!_blossom_set->trivial(blossom)) { - (*_blossom_data)[blossom].pot += 2 * _delta_sum; - } - - for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); - n != INVALID; ++n) { - int ni = (*_node_index)[n]; - (*_node_data)[ni].pot -= _delta_sum; - - _delta1->erase(n); - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.source(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if (vb == blossom) { - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); - } - } else if ((*_blossom_data)[vb].status == EVEN) { - - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); - } - - int vt = _tree_set->find(vb); - - if (vt != tree) { - - Arc r = _graph.oppositeArc(e); - - typename std::map::iterator it = - (*_node_data)[ni].heap_index.find(vt); - - if (it != (*_node_data)[ni].heap_index.end()) { - if ((*_node_data)[ni].heap[it->second] > rw) { - (*_node_data)[ni].heap.replace(it->second, r); - (*_node_data)[ni].heap.decrease(r, rw); - it->second = r; - } - } else { - (*_node_data)[ni].heap.push(r, rw); - (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r)); - } - - if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) { - _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); - - if (_delta2->state(blossom) != _delta2->IN_HEAP) { - _delta2->push(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } else if ((*_delta2)[blossom] > - _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset){ - _delta2->decrease(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } - } - } - - } else if ((*_blossom_data)[vb].status == UNMATCHED) { - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); - } - } else { - - typename std::map::iterator it = - (*_node_data)[vi].heap_index.find(tree); - - if (it != (*_node_data)[vi].heap_index.end()) { - (*_node_data)[vi].heap.erase(it->second); - (*_node_data)[vi].heap_index.erase(it); - if ((*_node_data)[vi].heap.empty()) { - _blossom_set->increase(v, std::numeric_limits::max()); - } else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) { - _blossom_set->increase(v, (*_node_data)[vi].heap.prio()); - } - - if ((*_blossom_data)[vb].status == MATCHED) { - if (_blossom_set->classPrio(vb) == - std::numeric_limits::max()) { - _delta2->erase(vb); - } else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset) { - _delta2->increase(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } - } - } - } - } - } - } - - void oddToMatched(int blossom) { - (*_blossom_data)[blossom].offset -= _delta_sum; - - if (_blossom_set->classPrio(blossom) != - std::numeric_limits::max()) { - _delta2->push(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } - - if (!_blossom_set->trivial(blossom)) { - _delta4->erase(blossom); - } - } - - void oddToEven(int blossom, int tree) { - if (!_blossom_set->trivial(blossom)) { - _delta4->erase(blossom); - (*_blossom_data)[blossom].pot -= - 2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset); - } - - for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); - n != INVALID; ++n) { - int ni = (*_node_index)[n]; - - _blossom_set->increase(n, std::numeric_limits::max()); - - (*_node_data)[ni].heap.clear(); - (*_node_data)[ni].heap_index.clear(); - (*_node_data)[ni].pot += - 2 * _delta_sum - (*_blossom_data)[blossom].offset; - - _delta1->push(n, (*_node_data)[ni].pot); - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.source(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if ((*_blossom_data)[vb].status == EVEN) { - if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { - _delta3->push(e, rw / 2); - } - } else if ((*_blossom_data)[vb].status == UNMATCHED) { - if (_delta3->state(e) != _delta3->IN_HEAP) { - _delta3->push(e, rw); - } - } else { - - typename std::map::iterator it = - (*_node_data)[vi].heap_index.find(tree); - - if (it != (*_node_data)[vi].heap_index.end()) { - if ((*_node_data)[vi].heap[it->second] > rw) { - (*_node_data)[vi].heap.replace(it->second, e); - (*_node_data)[vi].heap.decrease(e, rw); - it->second = e; - } - } else { - (*_node_data)[vi].heap.push(e, rw); - (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); - } - - if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { - _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); - - if ((*_blossom_data)[vb].status == MATCHED) { - if (_delta2->state(vb) != _delta2->IN_HEAP) { - _delta2->push(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - (*_blossom_data)[vb].offset) { _delta2->decrease(vb, _blossom_set->classPrio(vb) - (*_blossom_data)[vb].offset); @@ -1176,43 +978,145 @@ (*_blossom_data)[blossom].offset = 0; } - - void matchedToUnmatched(int blossom) { + void matchedToOdd(int blossom) { if (_delta2->state(blossom) == _delta2->IN_HEAP) { _delta2->erase(blossom); } + (*_blossom_data)[blossom].offset += _delta_sum; + if (!_blossom_set->trivial(blossom)) { + _delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 + + (*_blossom_data)[blossom].offset); + } + } + + void evenToMatched(int blossom, int tree) { + if (!_blossom_set->trivial(blossom)) { + (*_blossom_data)[blossom].pot += 2 * _delta_sum; + } for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); n != INVALID; ++n) { int ni = (*_node_index)[n]; - - _blossom_set->increase(n, std::numeric_limits::max()); - - (*_node_data)[ni].heap.clear(); - (*_node_data)[ni].heap_index.clear(); - - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.target(e); + (*_node_data)[ni].pot -= _delta_sum; + + _delta1->erase(n); + + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.source(e); int vb = _blossom_set->find(v); int vi = (*_node_index)[v]; Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - dualScale * _weight[e]; - if ((*_blossom_data)[vb].status == EVEN) { - if (_delta3->state(e) != _delta3->IN_HEAP) { - _delta3->push(e, rw); + if (vb == blossom) { + if (_delta3->state(e) == _delta3->IN_HEAP) { + _delta3->erase(e); + } + } else if ((*_blossom_data)[vb].status == EVEN) { + + if (_delta3->state(e) == _delta3->IN_HEAP) { + _delta3->erase(e); + } + + int vt = _tree_set->find(vb); + + if (vt != tree) { + + Arc r = _graph.oppositeArc(e); + + typename std::map::iterator it = + (*_node_data)[ni].heap_index.find(vt); + + if (it != (*_node_data)[ni].heap_index.end()) { + if ((*_node_data)[ni].heap[it->second] > rw) { + (*_node_data)[ni].heap.replace(it->second, r); + (*_node_data)[ni].heap.decrease(r, rw); + it->second = r; + } + } else { + (*_node_data)[ni].heap.push(r, rw); + (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r)); + } + + if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) { + _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); + + if (_delta2->state(blossom) != _delta2->IN_HEAP) { + _delta2->push(blossom, _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset); + } else if ((*_delta2)[blossom] > + _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset){ + _delta2->decrease(blossom, _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset); + } + } + } + } else { + + typename std::map::iterator it = + (*_node_data)[vi].heap_index.find(tree); + + if (it != (*_node_data)[vi].heap_index.end()) { + (*_node_data)[vi].heap.erase(it->second); + (*_node_data)[vi].heap_index.erase(it); + if ((*_node_data)[vi].heap.empty()) { + _blossom_set->increase(v, std::numeric_limits::max()); + } else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) { + _blossom_set->increase(v, (*_node_data)[vi].heap.prio()); + } + + if ((*_blossom_data)[vb].status == MATCHED) { + if (_blossom_set->classPrio(vb) == + std::numeric_limits::max()) { + _delta2->erase(vb); + } else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset) { + _delta2->increase(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } + } } } } } } - void unmatchedToMatched(int blossom) { + void oddToMatched(int blossom) { + (*_blossom_data)[blossom].offset -= _delta_sum; + + if (_blossom_set->classPrio(blossom) != + std::numeric_limits::max()) { + _delta2->push(blossom, _blossom_set->classPrio(blossom) - + (*_blossom_data)[blossom].offset); + } + + if (!_blossom_set->trivial(blossom)) { + _delta4->erase(blossom); + } + } + + void oddToEven(int blossom, int tree) { + if (!_blossom_set->trivial(blossom)) { + _delta4->erase(blossom); + (*_blossom_data)[blossom].pot -= + 2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset); + } + for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); n != INVALID; ++n) { int ni = (*_node_index)[n]; + _blossom_set->increase(n, std::numeric_limits::max()); + + (*_node_data)[ni].heap.clear(); + (*_node_data)[ni].heap_index.clear(); + (*_node_data)[ni].pot += + 2 * _delta_sum - (*_blossom_data)[blossom].offset; + + _delta1->push(n, (*_node_data)[ni].pot); + for (InArcIt e(_graph, n); e != INVALID; ++e) { Node v = _graph.source(e); int vb = _blossom_set->find(v); @@ -1221,54 +1125,44 @@ Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - dualScale * _weight[e]; - if (vb == blossom) { - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); + if ((*_blossom_data)[vb].status == EVEN) { + if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { + _delta3->push(e, rw / 2); } - } else if ((*_blossom_data)[vb].status == EVEN) { - - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); - } - - int vt = _tree_set->find(vb); - - Arc r = _graph.oppositeArc(e); + } else { typename std::map::iterator it = - (*_node_data)[ni].heap_index.find(vt); - - if (it != (*_node_data)[ni].heap_index.end()) { - if ((*_node_data)[ni].heap[it->second] > rw) { - (*_node_data)[ni].heap.replace(it->second, r); - (*_node_data)[ni].heap.decrease(r, rw); - it->second = r; + (*_node_data)[vi].heap_index.find(tree); + + if (it != (*_node_data)[vi].heap_index.end()) { + if ((*_node_data)[vi].heap[it->second] > rw) { + (*_node_data)[vi].heap.replace(it->second, e); + (*_node_data)[vi].heap.decrease(e, rw); + it->second = e; } } else { - (*_node_data)[ni].heap.push(r, rw); - (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r)); + (*_node_data)[vi].heap.push(e, rw); + (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); } - if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) { - _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); - - if (_delta2->state(blossom) != _delta2->IN_HEAP) { - _delta2->push(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } else if ((*_delta2)[blossom] > _blossom_set->classPrio(blossom)- - (*_blossom_data)[blossom].offset){ - _delta2->decrease(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); + if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { + _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); + + if ((*_blossom_data)[vb].status == MATCHED) { + if (_delta2->state(vb) != _delta2->IN_HEAP) { + _delta2->push(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset) { + _delta2->decrease(vb, _blossom_set->classPrio(vb) - + (*_blossom_data)[vb].offset); + } } } - - } else if ((*_blossom_data)[vb].status == UNMATCHED) { - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); - } } } } + (*_blossom_data)[blossom].offset = 0; } void alternatePath(int even, int tree) { @@ -1313,39 +1207,42 @@ alternatePath(blossom, tree); destroyTree(tree); - (*_blossom_data)[blossom].status = UNMATCHED; (*_blossom_data)[blossom].base = node; - matchedToUnmatched(blossom); + (*_blossom_data)[blossom].next = INVALID; } - void augmentOnEdge(const Edge& edge) { int left = _blossom_set->find(_graph.u(edge)); int right = _blossom_set->find(_graph.v(edge)); - if ((*_blossom_data)[left].status == EVEN) { - int left_tree = _tree_set->find(left); - alternatePath(left, left_tree); - destroyTree(left_tree); - } else { - (*_blossom_data)[left].status = MATCHED; - unmatchedToMatched(left); - } - - if ((*_blossom_data)[right].status == EVEN) { - int right_tree = _tree_set->find(right); - alternatePath(right, right_tree); - destroyTree(right_tree); - } else { - (*_blossom_data)[right].status = MATCHED; - unmatchedToMatched(right); - } + int left_tree = _tree_set->find(left); + alternatePath(left, left_tree); + destroyTree(left_tree); + + int right_tree = _tree_set->find(right); + alternatePath(right, right_tree); + destroyTree(right_tree); (*_blossom_data)[left].next = _graph.direct(edge, true); (*_blossom_data)[right].next = _graph.direct(edge, false); } + void augmentOnArc(const Arc& arc) { + + int left = _blossom_set->find(_graph.source(arc)); + int right = _blossom_set->find(_graph.target(arc)); + + (*_blossom_data)[left].status = MATCHED; + + int right_tree = _tree_set->find(right); + alternatePath(right, right_tree); + destroyTree(right_tree); + + (*_blossom_data)[left].next = arc; + (*_blossom_data)[right].next = _graph.oppositeArc(arc); + } + void extendOnArc(const Arc& arc) { int base = _blossom_set->find(_graph.target(arc)); int tree = _tree_set->find(base); @@ -1548,7 +1445,7 @@ _tree_set->insert(sb, tree); (*_blossom_data)[sb].pred = pred; (*_blossom_data)[sb].next = - _graph.oppositeArc((*_blossom_data)[tb].next); + _graph.oppositeArc((*_blossom_data)[tb].next); pred = (*_blossom_data)[ub].next; @@ -1648,7 +1545,7 @@ } for (int i = 0; i < int(blossoms.size()); ++i) { - if ((*_blossom_data)[blossoms[i]].status == MATCHED) { + if ((*_blossom_data)[blossoms[i]].next != INVALID) { Value offset = (*_blossom_data)[blossoms[i]].offset; (*_blossom_data)[blossoms[i]].pot += 2 * offset; @@ -1686,10 +1583,16 @@ _delta3_index(0), _delta3(0), _delta4_index(0), _delta4(0), - _delta_sum() {} + _delta_sum(), _unmatched(0), + + _fractional(0) + {} ~MaxWeightedMatching() { destroyStructures(); + if (_fractional) { + delete _fractional; + } } /// \name Execution Control @@ -1720,7 +1623,9 @@ (*_delta2_index)[i] = _delta2->PRE_HEAP; (*_delta4_index)[i] = _delta4->PRE_HEAP; } - + + _unmatched = _node_num; + _delta1->clear(); _delta2->clear(); _delta3->clear(); @@ -1764,18 +1669,167 @@ } } + /// \brief Initialize the algorithm with fractional matching + /// + /// This function initializes the algorithm with a fractional + /// matching. This initialization is also called jumpstart heuristic. + void fractionalInit() { + createStructures(); + + _blossom_node_list.clear(); + _blossom_potential.clear(); + + if (_fractional == 0) { + _fractional = new FractionalMatching(_graph, _weight, false); + } + _fractional->run(); + + for (ArcIt e(_graph); e != INVALID; ++e) { + (*_node_heap_index)[e] = BinHeap::PRE_HEAP; + } + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_delta1_index)[n] = _delta1->PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + for (int i = 0; i < _blossom_num; ++i) { + (*_delta2_index)[i] = _delta2->PRE_HEAP; + (*_delta4_index)[i] = _delta4->PRE_HEAP; + } + + _unmatched = 0; + + _delta1->clear(); + _delta2->clear(); + _delta3->clear(); + _delta4->clear(); + _blossom_set->clear(); + _tree_set->clear(); + + int index = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + Value pot = _fractional->nodeValue(n); + (*_node_index)[n] = index; + (*_node_data)[index].pot = pot; + (*_node_data)[index].heap_index.clear(); + (*_node_data)[index].heap.clear(); + int blossom = + _blossom_set->insert(n, std::numeric_limits::max()); + + (*_blossom_data)[blossom].status = MATCHED; + (*_blossom_data)[blossom].pred = INVALID; + (*_blossom_data)[blossom].next = _fractional->matching(n); + if (_fractional->matching(n) == INVALID) { + (*_blossom_data)[blossom].base = n; + } + (*_blossom_data)[blossom].pot = 0; + (*_blossom_data)[blossom].offset = 0; + ++index; + } + + typename Graph::template NodeMap processed(_graph, false); + for (NodeIt n(_graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (_fractional->matching(n) == INVALID) continue; + int num = 1; + Node v = _graph.target(_fractional->matching(n)); + while (n != v) { + processed[v] = true; + v = _graph.target(_fractional->matching(v)); + ++num; + } + + if (num % 2 == 1) { + std::vector subblossoms(num); + + subblossoms[--num] = _blossom_set->find(n); + _delta1->push(n, _fractional->nodeValue(n)); + v = _graph.target(_fractional->matching(n)); + while (n != v) { + subblossoms[--num] = _blossom_set->find(v); + _delta1->push(v, _fractional->nodeValue(v)); + v = _graph.target(_fractional->matching(v)); + } + + int surface = + _blossom_set->join(subblossoms.begin(), subblossoms.end()); + (*_blossom_data)[surface].status = EVEN; + (*_blossom_data)[surface].pred = INVALID; + (*_blossom_data)[surface].next = INVALID; + (*_blossom_data)[surface].pot = 0; + (*_blossom_data)[surface].offset = 0; + + _tree_set->insert(surface); + ++_unmatched; + } + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + int si = (*_node_index)[_graph.u(e)]; + int sb = _blossom_set->find(_graph.u(e)); + int ti = (*_node_index)[_graph.v(e)]; + int tb = _blossom_set->find(_graph.v(e)); + if ((*_blossom_data)[sb].status == EVEN && + (*_blossom_data)[tb].status == EVEN && sb != tb) { + _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - + dualScale * _weight[e]) / 2); + } + } + + for (NodeIt n(_graph); n != INVALID; ++n) { + int nb = _blossom_set->find(n); + if ((*_blossom_data)[nb].status != MATCHED) continue; + int ni = (*_node_index)[n]; + + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.target(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if ((*_blossom_data)[vb].status == EVEN) { + + int vt = _tree_set->find(vb); + + typename std::map::iterator it = + (*_node_data)[ni].heap_index.find(vt); + + if (it != (*_node_data)[ni].heap_index.end()) { + if ((*_node_data)[ni].heap[it->second] > rw) { + (*_node_data)[ni].heap.replace(it->second, e); + (*_node_data)[ni].heap.decrease(e, rw); + it->second = e; + } + } else { + (*_node_data)[ni].heap.push(e, rw); + (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e)); + } + } + } + + if (!(*_node_data)[ni].heap.empty()) { + _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); + _delta2->push(nb, _blossom_set->classPrio(nb)); + } + } + } + /// \brief Start the algorithm /// /// This function starts the algorithm. /// - /// \pre \ref init() must be called before using this function. + /// \pre \ref init() or \ref fractionalInit() must be called + /// before using this function. void start() { enum OpType { D1, D2, D3, D4 }; - int unmatched = _node_num; - while (unmatched > 0) { + while (_unmatched > 0) { Value d1 = !_delta1->empty() ? _delta1->prio() : std::numeric_limits::max(); @@ -1788,26 +1842,30 @@ Value d4 = !_delta4->empty() ? _delta4->prio() : std::numeric_limits::max(); - _delta_sum = d1; OpType ot = D1; + _delta_sum = d3; OpType ot = D3; + if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; } if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } - if (d3 < _delta_sum) { _delta_sum = d3; ot = D3; } if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; } - switch (ot) { case D1: { Node n = _delta1->top(); unmatchNode(n); - --unmatched; + --_unmatched; } break; case D2: { int blossom = _delta2->top(); Node n = _blossom_set->classTop(blossom); - Arc e = (*_node_data)[(*_node_index)[n]].heap.top(); - extendOnArc(e); + Arc a = (*_node_data)[(*_node_index)[n]].heap.top(); + if ((*_blossom_data)[blossom].next == INVALID) { + augmentOnArc(a); + --_unmatched; + } else { + extendOnArc(a); + } } break; case D3: @@ -1820,26 +1878,14 @@ if (left_blossom == right_blossom) { _delta3->pop(); } else { - int left_tree; - if ((*_blossom_data)[left_blossom].status == EVEN) { - left_tree = _tree_set->find(left_blossom); - } else { - left_tree = -1; - ++unmatched; - } - int right_tree; - if ((*_blossom_data)[right_blossom].status == EVEN) { - right_tree = _tree_set->find(right_blossom); - } else { - right_tree = -1; - ++unmatched; - } + int left_tree = _tree_set->find(left_blossom); + int right_tree = _tree_set->find(right_blossom); if (left_tree == right_tree) { shrinkOnEdge(e, left_tree); } else { augmentOnEdge(e); - unmatched -= 2; + _unmatched -= 2; } } } break; @@ -1857,18 +1903,18 @@ /// /// \note mwm.run() is just a shortcut of the following code. /// \code - /// mwm.init(); + /// mwm.fractionalInit(); /// mwm.start(); /// \endcode void run() { - init(); + fractionalInit(); start(); } /// @} /// \name Primal Solution - /// Functions to get the primal solution, i.e. the maximum weighted + /// Functions to get the primal solution, i.e. the maximum weighted /// matching.\n /// Either \ref run() or \ref start() function should be called before /// using them. @@ -1887,7 +1933,7 @@ sum += _weight[(*_matching)[n]]; } } - return sum /= 2; + return sum / 2; } /// \brief Return the size (cardinality) of the matching. @@ -1907,7 +1953,7 @@ /// \brief Return \c true if the given edge is in the matching. /// - /// This function returns \c true if the given edge is in the found + /// This function returns \c true if the given edge is in the found /// matching. /// /// \pre Either run() or start() must be called before using this function. @@ -1918,7 +1964,7 @@ /// \brief Return the matching arc (or edge) incident to the given node. /// /// This function returns the matching arc (or edge) incident to the - /// given node in the found matching or \c INVALID if the node is + /// given node in the found matching or \c INVALID if the node is /// not covered by the matching. /// /// \pre Either run() or start() must be called before using this function. @@ -1936,7 +1982,7 @@ /// \brief Return the mate of the given node. /// - /// This function returns the mate of the given node in the found + /// This function returns the mate of the given node in the found /// matching or \c INVALID if the node is not covered by the matching. /// /// \pre Either run() or start() must be called before using this function. @@ -1956,8 +2002,8 @@ /// \brief Return the value of the dual solution. /// - /// This function returns the value of the dual solution. - /// It should be equal to the primal value scaled by \ref dualScale + /// This function returns the value of the dual solution. + /// It should be equal to the primal value scaled by \ref dualScale /// "dual scale". /// /// \pre Either run() or start() must be called before using this function. @@ -2012,9 +2058,9 @@ /// \brief Iterator for obtaining the nodes of a blossom. /// - /// This class provides an iterator for obtaining the nodes of the + /// This class provides an iterator for obtaining the nodes of the /// given blossom. It lists a subset of the nodes. - /// Before using this iterator, you must allocate a + /// Before using this iterator, you must allocate a /// MaxWeightedMatching class and execute it. class BlossomIt { public: @@ -2023,8 +2069,8 @@ /// /// Constructor to get the nodes of the given variable. /// - /// \pre Either \ref MaxWeightedMatching::run() "algorithm.run()" or - /// \ref MaxWeightedMatching::start() "algorithm.start()" must be + /// \pre Either \ref MaxWeightedMatching::run() "algorithm.run()" or + /// \ref MaxWeightedMatching::start() "algorithm.start()" must be /// called before initializing this iterator. BlossomIt(const MaxWeightedMatching& algorithm, int variable) : _algorithm(&algorithm) @@ -2077,8 +2123,8 @@ /// is based on extensive use of priority queues and provides /// \f$O(nm\log n)\f$ time complexity. /// - /// The maximum weighted perfect matching problem is to find a subset of - /// the edges in an undirected graph with maximum overall weight for which + /// The maximum weighted perfect matching problem is to find a subset of + /// the edges in an undirected graph with maximum overall weight for which /// each node has exactly one incident edge. /// It can be formulated with the following linear program. /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f] @@ -2101,16 +2147,16 @@ /** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}} \frac{\vert B \vert - 1}{2}z_B\f] */ /// - /// The algorithm can be executed with the run() function. + /// The algorithm can be executed with the run() function. /// After it the matching (the primal solution) and the dual solution - /// can be obtained using the query functions and the - /// \ref MaxWeightedPerfectMatching::BlossomIt "BlossomIt" nested class, - /// which is able to iterate on the nodes of a blossom. + /// can be obtained using the query functions and the + /// \ref MaxWeightedPerfectMatching::BlossomIt "BlossomIt" nested class, + /// which is able to iterate on the nodes of a blossom. /// If the value type is integer, then the dual solution is multiplied /// by \ref MaxWeightedMatching::dualScale "4". /// /// \tparam GR The undirected graph type the algorithm runs on. - /// \tparam WM The type edge weight map. The default type is + /// \tparam WM The type edge weight map. The default type is /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". #ifdef DOXYGEN template @@ -2221,6 +2267,11 @@ BinHeap *_delta4; Value _delta_sum; + int _unmatched; + + typedef MaxWeightedPerfectFractionalMatching + FractionalMatching; + FractionalMatching *_fractional; void createStructures() { _node_num = countNodes(_graph); @@ -2282,9 +2333,6 @@ } void destroyStructures() { - _node_num = countNodes(_graph); - _blossom_num = _node_num * 3 / 2; - if (_matching) { delete _matching; } @@ -2957,10 +3005,16 @@ _delta3_index(0), _delta3(0), _delta4_index(0), _delta4(0), - _delta_sum() {} + _delta_sum(), _unmatched(0), + + _fractional(0) + {} ~MaxWeightedPerfectMatching() { destroyStructures(); + if (_fractional) { + delete _fractional; + } } /// \name Execution Control @@ -2989,6 +3043,8 @@ (*_delta4_index)[i] = _delta4->PRE_HEAP; } + _unmatched = _node_num; + _delta2->clear(); _delta3->clear(); _delta4->clear(); @@ -3030,18 +3086,163 @@ } } + /// \brief Initialize the algorithm with fractional matching + /// + /// This function initializes the algorithm with a fractional + /// matching. This initialization is also called jumpstart heuristic. + void fractionalInit() { + createStructures(); + + _blossom_node_list.clear(); + _blossom_potential.clear(); + + if (_fractional == 0) { + _fractional = new FractionalMatching(_graph, _weight, false); + } + if (!_fractional->run()) { + _unmatched = -1; + return; + } + + for (ArcIt e(_graph); e != INVALID; ++e) { + (*_node_heap_index)[e] = BinHeap::PRE_HEAP; + } + for (EdgeIt e(_graph); e != INVALID; ++e) { + (*_delta3_index)[e] = _delta3->PRE_HEAP; + } + for (int i = 0; i < _blossom_num; ++i) { + (*_delta2_index)[i] = _delta2->PRE_HEAP; + (*_delta4_index)[i] = _delta4->PRE_HEAP; + } + + _unmatched = 0; + + _delta2->clear(); + _delta3->clear(); + _delta4->clear(); + _blossom_set->clear(); + _tree_set->clear(); + + int index = 0; + for (NodeIt n(_graph); n != INVALID; ++n) { + Value pot = _fractional->nodeValue(n); + (*_node_index)[n] = index; + (*_node_data)[index].pot = pot; + (*_node_data)[index].heap_index.clear(); + (*_node_data)[index].heap.clear(); + int blossom = + _blossom_set->insert(n, std::numeric_limits::max()); + + (*_blossom_data)[blossom].status = MATCHED; + (*_blossom_data)[blossom].pred = INVALID; + (*_blossom_data)[blossom].next = _fractional->matching(n); + (*_blossom_data)[blossom].pot = 0; + (*_blossom_data)[blossom].offset = 0; + ++index; + } + + typename Graph::template NodeMap processed(_graph, false); + for (NodeIt n(_graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (_fractional->matching(n) == INVALID) continue; + int num = 1; + Node v = _graph.target(_fractional->matching(n)); + while (n != v) { + processed[v] = true; + v = _graph.target(_fractional->matching(v)); + ++num; + } + + if (num % 2 == 1) { + std::vector subblossoms(num); + + subblossoms[--num] = _blossom_set->find(n); + v = _graph.target(_fractional->matching(n)); + while (n != v) { + subblossoms[--num] = _blossom_set->find(v); + v = _graph.target(_fractional->matching(v)); + } + + int surface = + _blossom_set->join(subblossoms.begin(), subblossoms.end()); + (*_blossom_data)[surface].status = EVEN; + (*_blossom_data)[surface].pred = INVALID; + (*_blossom_data)[surface].next = INVALID; + (*_blossom_data)[surface].pot = 0; + (*_blossom_data)[surface].offset = 0; + + _tree_set->insert(surface); + ++_unmatched; + } + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + int si = (*_node_index)[_graph.u(e)]; + int sb = _blossom_set->find(_graph.u(e)); + int ti = (*_node_index)[_graph.v(e)]; + int tb = _blossom_set->find(_graph.v(e)); + if ((*_blossom_data)[sb].status == EVEN && + (*_blossom_data)[tb].status == EVEN && sb != tb) { + _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - + dualScale * _weight[e]) / 2); + } + } + + for (NodeIt n(_graph); n != INVALID; ++n) { + int nb = _blossom_set->find(n); + if ((*_blossom_data)[nb].status != MATCHED) continue; + int ni = (*_node_index)[n]; + + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node v = _graph.target(e); + int vb = _blossom_set->find(v); + int vi = (*_node_index)[v]; + + Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - + dualScale * _weight[e]; + + if ((*_blossom_data)[vb].status == EVEN) { + + int vt = _tree_set->find(vb); + + typename std::map::iterator it = + (*_node_data)[ni].heap_index.find(vt); + + if (it != (*_node_data)[ni].heap_index.end()) { + if ((*_node_data)[ni].heap[it->second] > rw) { + (*_node_data)[ni].heap.replace(it->second, e); + (*_node_data)[ni].heap.decrease(e, rw); + it->second = e; + } + } else { + (*_node_data)[ni].heap.push(e, rw); + (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e)); + } + } + } + + if (!(*_node_data)[ni].heap.empty()) { + _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); + _delta2->push(nb, _blossom_set->classPrio(nb)); + } + } + } + /// \brief Start the algorithm /// /// This function starts the algorithm. /// - /// \pre \ref init() must be called before using this function. + /// \pre \ref init() or \ref fractionalInit() must be called before + /// using this function. bool start() { enum OpType { D2, D3, D4 }; - int unmatched = _node_num; - while (unmatched > 0) { + if (_unmatched == -1) return false; + + while (_unmatched > 0) { Value d2 = !_delta2->empty() ? _delta2->prio() : std::numeric_limits::max(); @@ -3051,8 +3252,8 @@ Value d4 = !_delta4->empty() ? _delta4->prio() : std::numeric_limits::max(); - _delta_sum = d2; OpType ot = D2; - if (d3 < _delta_sum) { _delta_sum = d3; ot = D3; } + _delta_sum = d3; OpType ot = D3; + if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; } if (_delta_sum == std::numeric_limits::max()) { @@ -3085,7 +3286,7 @@ shrinkOnEdge(e, left_tree); } else { augmentOnEdge(e); - unmatched -= 2; + _unmatched -= 2; } } } break; @@ -3104,18 +3305,18 @@ /// /// \note mwpm.run() is just a shortcut of the following code. /// \code - /// mwpm.init(); + /// mwpm.fractionalInit(); /// mwpm.start(); /// \endcode bool run() { - init(); + fractionalInit(); return start(); } /// @} /// \name Primal Solution - /// Functions to get the primal solution, i.e. the maximum weighted + /// Functions to get the primal solution, i.e. the maximum weighted /// perfect matching.\n /// Either \ref run() or \ref start() function should be called before /// using them. @@ -3134,12 +3335,12 @@ sum += _weight[(*_matching)[n]]; } } - return sum /= 2; + return sum / 2; } /// \brief Return \c true if the given edge is in the matching. /// - /// This function returns \c true if the given edge is in the found + /// This function returns \c true if the given edge is in the found /// matching. /// /// \pre Either run() or start() must be called before using this function. @@ -3150,7 +3351,7 @@ /// \brief Return the matching arc (or edge) incident to the given node. /// /// This function returns the matching arc (or edge) incident to the - /// given node in the found matching or \c INVALID if the node is + /// given node in the found matching or \c INVALID if the node is /// not covered by the matching. /// /// \pre Either run() or start() must be called before using this function. @@ -3168,7 +3369,7 @@ /// \brief Return the mate of the given node. /// - /// This function returns the mate of the given node in the found + /// This function returns the mate of the given node in the found /// matching or \c INVALID if the node is not covered by the matching. /// /// \pre Either run() or start() must be called before using this function. @@ -3187,8 +3388,8 @@ /// \brief Return the value of the dual solution. /// - /// This function returns the value of the dual solution. - /// It should be equal to the primal value scaled by \ref dualScale + /// This function returns the value of the dual solution. + /// It should be equal to the primal value scaled by \ref dualScale /// "dual scale". /// /// \pre Either run() or start() must be called before using this function. @@ -3243,9 +3444,9 @@ /// \brief Iterator for obtaining the nodes of a blossom. /// - /// This class provides an iterator for obtaining the nodes of the + /// This class provides an iterator for obtaining the nodes of the /// given blossom. It lists a subset of the nodes. - /// Before using this iterator, you must allocate a + /// Before using this iterator, you must allocate a /// MaxWeightedPerfectMatching class and execute it. class BlossomIt { public: @@ -3254,8 +3455,8 @@ /// /// Constructor to get the nodes of the given variable. /// - /// \pre Either \ref MaxWeightedPerfectMatching::run() "algorithm.run()" - /// or \ref MaxWeightedPerfectMatching::start() "algorithm.start()" + /// \pre Either \ref MaxWeightedPerfectMatching::run() "algorithm.run()" + /// or \ref MaxWeightedPerfectMatching::start() "algorithm.start()" /// must be called before initializing this iterator. BlossomIt(const MaxWeightedPerfectMatching& algorithm, int variable) : _algorithm(&algorithm) @@ -3301,4 +3502,4 @@ } //END OF NAMESPACE LEMON -#endif //LEMON_MAX_MATCHING_H +#endif //LEMON_MATCHING_H diff --git a/lemon/math.h b/lemon/math.h --- a/lemon/math.h +++ b/lemon/math.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -56,7 +56,7 @@ const long double SQRT1_2 = 0.7071067811865475244008443621048490L; ///Check whether the parameter is NaN or not - + ///This function checks whether the parameter is NaN or not. ///Is should be equivalent with std::isnan(), but it is not ///provided by all compilers. diff --git a/lemon/min_cost_arborescence.h b/lemon/min_cost_arborescence.h --- a/lemon/min_cost_arborescence.h +++ b/lemon/min_cost_arborescence.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -112,23 +112,24 @@ /// relatively time consuming process to compute the arc costs if /// it is necessary. The default map type is \ref /// concepts::Digraph::ArcMap "Digraph::ArcMap". - /// \param TR Traits class to set various data types used - /// by the algorithm. The default traits class is - /// \ref MinCostArborescenceDefaultTraits + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref MinCostArborescenceDefaultTraits /// "MinCostArborescenceDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. #ifndef DOXYGEN template , typename TR = MinCostArborescenceDefaultTraits > #else - template + template #endif class MinCostArborescence { public: - /// \brief The \ref MinCostArborescenceDefaultTraits "traits class" - /// of the algorithm. + /// \brief The \ref MinCostArborescenceDefaultTraits "traits class" + /// of the algorithm. typedef TR Traits; /// The type of the underlying digraph. typedef typename Traits::Digraph Digraph; @@ -435,7 +436,7 @@ /// /// \ref named-templ-param "Named parameter" for setting /// \c PredMap type. - /// It must meet the \ref concepts::WriteMap "WriteMap" concept, + /// It must meet the \ref concepts::WriteMap "WriteMap" concept, /// and its value type must be the \c Arc type of the digraph. template struct SetPredMap @@ -488,8 +489,8 @@ /// \name Execution Control /// The simplest way to execute the algorithm is to use /// one of the member functions called \c run(...). \n - /// If you need more control on the execution, - /// first you must call \ref init(), then you can add several + /// If you need better control on the execution, + /// you have to call \ref init() first, then you can add several /// source nodes with \ref addSource(). /// Finally \ref start() will perform the arborescence /// computation. diff --git a/lemon/network_simplex.h b/lemon/network_simplex.h --- a/lemon/network_simplex.h +++ b/lemon/network_simplex.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -40,15 +40,17 @@ /// for finding a \ref min_cost_flow "minimum cost flow". /// /// \ref NetworkSimplex implements the primal Network Simplex algorithm - /// for finding a \ref min_cost_flow "minimum cost flow". - /// This algorithm is a specialized version of the linear programming - /// simplex method directly for the minimum cost flow problem. - /// It is one of the most efficient solution methods. + /// for finding a \ref min_cost_flow "minimum cost flow" + /// \ref amo93networkflows, \ref dantzig63linearprog, + /// \ref kellyoneill91netsimplex. + /// This algorithm is a highly efficient specialized version of the + /// linear programming simplex method directly for the minimum cost + /// flow problem. /// - /// In general this class is the fastest implementation available - /// in LEMON for the minimum cost flow problem. - /// Moreover it supports both directions of the supply/demand inequality - /// constraints. For more information see \ref SupplyType. + /// In general, %NetworkSimplex is the fastest implementation available + /// in LEMON for this problem. + /// Moreover, it supports both directions of the supply/demand inequality + /// constraints. For more information, see \ref SupplyType. /// /// Most of the parameters of the problem (except for the digraph) /// can be given using separate functions, and the algorithm can be @@ -56,17 +58,17 @@ /// specified, then default values will be used. /// /// \tparam GR The digraph type the algorithm runs on. - /// \tparam V The value type used for flow amounts, capacity bounds - /// and supply values in the algorithm. By default it is \c int. - /// \tparam C The value type used for costs and potentials in the - /// algorithm. By default it is the same as \c V. + /// \tparam V The number type used for flow amounts, capacity bounds + /// and supply values in the algorithm. By default, it is \c int. + /// \tparam C The number type used for costs and potentials in the + /// algorithm. By default, it is the same as \c V. /// - /// \warning Both value types must be signed and all input data must + /// \warning Both number types must be signed and all input data must /// be integer. /// /// \note %NetworkSimplex provides five different pivot rule /// implementations, from which the most efficient one is used - /// by default. For more information see \ref PivotRule. + /// by default. For more information, see \ref PivotRule. template class NetworkSimplex { @@ -95,7 +97,7 @@ /// infinite upper bound. UNBOUNDED }; - + /// \brief Constants for selecting the type of the supply constraints. /// /// Enum type containing constants for selecting the supply type, @@ -113,7 +115,7 @@ /// supply/demand constraints in the definition of the problem. LEQ }; - + /// \brief Constants for selecting the pivot rule. /// /// Enum type containing constants for selecting the pivot rule for @@ -122,59 +124,62 @@ /// \ref NetworkSimplex provides five different pivot rule /// implementations that significantly affect the running time /// of the algorithm. - /// By default \ref BLOCK_SEARCH "Block Search" is used, which + /// By default, \ref BLOCK_SEARCH "Block Search" is used, which /// proved to be the most efficient and the most robust on various - /// test inputs according to our benchmark tests. - /// However another pivot rule can be selected using the \ref run() + /// test inputs. + /// However, another pivot rule can be selected using the \ref run() /// function with the proper parameter. enum PivotRule { - /// The First Eligible pivot rule. + /// The \e First \e Eligible pivot rule. /// The next eligible arc is selected in a wraparound fashion /// in every iteration. FIRST_ELIGIBLE, - /// The Best Eligible pivot rule. + /// The \e Best \e Eligible pivot rule. /// The best eligible arc is selected in every iteration. BEST_ELIGIBLE, - /// The Block Search pivot rule. + /// The \e Block \e Search pivot rule. /// A specified number of arcs are examined in every iteration /// in a wraparound fashion and the best eligible arc is selected /// from this block. BLOCK_SEARCH, - /// The Candidate List pivot rule. + /// The \e Candidate \e List pivot rule. /// In a major iteration a candidate list is built from eligible arcs /// in a wraparound fashion and in the following minor iterations /// the best eligible arc is selected from this list. CANDIDATE_LIST, - /// The Altering Candidate List pivot rule. + /// The \e Altering \e Candidate \e List pivot rule. /// It is a modified version of the Candidate List method. /// It keeps only the several best eligible arcs from the former /// candidate list and extends this list in every iteration. ALTERING_LIST }; - + private: TEMPLATE_DIGRAPH_TYPEDEFS(GR); - typedef std::vector ArcVector; - typedef std::vector NodeVector; typedef std::vector IntVector; - typedef std::vector BoolVector; typedef std::vector ValueVector; typedef std::vector CostVector; + typedef std::vector BoolVector; + // Note: vector is used instead of vector for efficiency reasons // State constants for arcs - enum ArcStateEnum { + enum ArcState { STATE_UPPER = -1, STATE_TREE = 0, STATE_LOWER = 1 }; + typedef std::vector StateVector; + // Note: vector is used instead of vector for + // efficiency reasons + private: // Data related to the underlying digraph @@ -194,6 +199,7 @@ IntArcMap _arc_id; IntVector _source; IntVector _target; + bool _arc_mixing; // Node and arc data ValueVector _lower; @@ -213,7 +219,7 @@ IntVector _last_succ; IntVector _dirty_revs; BoolVector _forward; - IntVector _state; + StateVector _state; int _root; // Temporary data used in the current pivot iteration @@ -222,8 +228,10 @@ int stem, par_stem, new_stem; Value delta; + const Value MAX; + public: - + /// \brief Constant for infinite upper bounds (capacities). /// /// Constant for infinite upper bounds (capacities). @@ -242,7 +250,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const IntVector &_state; + const StateVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -263,7 +271,7 @@ // Find next entering arc bool findEnteringArc() { Cost c; - for (int e = _next_arc; e < _search_arc_num; ++e) { + for (int e = _next_arc; e != _search_arc_num; ++e) { c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); if (c < 0) { _in_arc = e; @@ -271,7 +279,7 @@ return true; } } - for (int e = 0; e < _next_arc; ++e) { + for (int e = 0; e != _next_arc; ++e) { c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); if (c < 0) { _in_arc = e; @@ -294,7 +302,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const IntVector &_state; + const StateVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -311,7 +319,7 @@ // Find next entering arc bool findEnteringArc() { Cost c, min = 0; - for (int e = 0; e < _search_arc_num; ++e) { + for (int e = 0; e != _search_arc_num; ++e) { c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); if (c < min) { min = c; @@ -333,7 +341,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const IntVector &_state; + const StateVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -352,7 +360,7 @@ _next_arc(0) { // The main parameters of the pivot rule - const double BLOCK_SIZE_FACTOR = 0.5; + const double BLOCK_SIZE_FACTOR = 1.0; const int MIN_BLOCK_SIZE = 10; _block_size = std::max( int(BLOCK_SIZE_FACTOR * @@ -364,33 +372,32 @@ bool findEnteringArc() { Cost c, min = 0; int cnt = _block_size; - int e, min_arc = _next_arc; - for (e = _next_arc; e < _search_arc_num; ++e) { + int e; + for (e = _next_arc; e != _search_arc_num; ++e) { c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); if (c < min) { min = c; - min_arc = e; + _in_arc = e; } if (--cnt == 0) { - if (min < 0) break; + if (min < 0) goto search_end; cnt = _block_size; } } - if (min == 0 || cnt > 0) { - for (e = 0; e < _next_arc; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < min) { - min = c; - min_arc = e; - } - if (--cnt == 0) { - if (min < 0) break; - cnt = _block_size; - } + for (e = 0; e != _next_arc; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < min) { + min = c; + _in_arc = e; + } + if (--cnt == 0) { + if (min < 0) goto search_end; + cnt = _block_size; } } if (min >= 0) return false; - _in_arc = min_arc; + + search_end: _next_arc = e; return true; } @@ -407,7 +414,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const IntVector &_state; + const StateVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -428,7 +435,7 @@ _next_arc(0) { // The main parameters of the pivot rule - const double LIST_LENGTH_FACTOR = 1.0; + const double LIST_LENGTH_FACTOR = 0.25; const int MIN_LIST_LENGTH = 10; const double MINOR_LIMIT_FACTOR = 0.1; const int MIN_MINOR_LIMIT = 3; @@ -445,7 +452,7 @@ /// Find next entering arc bool findEnteringArc() { Cost min, c; - int e, min_arc = _next_arc; + int e; if (_curr_length > 0 && _minor_count < _minor_limit) { // Minor iteration: select the best eligible arc from the // current candidate list @@ -456,48 +463,44 @@ c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); if (c < min) { min = c; - min_arc = e; + _in_arc = e; } - if (c >= 0) { + else if (c >= 0) { _candidates[i--] = _candidates[--_curr_length]; } } - if (min < 0) { - _in_arc = min_arc; - return true; - } + if (min < 0) return true; } // Major iteration: build a new candidate list min = 0; _curr_length = 0; - for (e = _next_arc; e < _search_arc_num; ++e) { + for (e = _next_arc; e != _search_arc_num; ++e) { c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); if (c < 0) { _candidates[_curr_length++] = e; if (c < min) { min = c; - min_arc = e; + _in_arc = e; } - if (_curr_length == _list_length) break; + if (_curr_length == _list_length) goto search_end; } } - if (_curr_length < _list_length) { - for (e = 0; e < _next_arc; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < 0) { - _candidates[_curr_length++] = e; - if (c < min) { - min = c; - min_arc = e; - } - if (_curr_length == _list_length) break; + for (e = 0; e != _next_arc; ++e) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _candidates[_curr_length++] = e; + if (c < min) { + min = c; + _in_arc = e; } + if (_curr_length == _list_length) goto search_end; } } if (_curr_length == 0) return false; + + search_end: _minor_count = 1; - _in_arc = min_arc; _next_arc = e; return true; } @@ -514,7 +517,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const IntVector &_state; + const StateVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -549,7 +552,7 @@ _next_arc(0), _cand_cost(ns._search_arc_num), _sort_func(_cand_cost) { // The main parameters of the pivot rule - const double BLOCK_SIZE_FACTOR = 1.5; + const double BLOCK_SIZE_FACTOR = 1.0; const int MIN_BLOCK_SIZE = 10; const double HEAD_LENGTH_FACTOR = 0.1; const int MIN_HEAD_LENGTH = 3; @@ -567,7 +570,7 @@ bool findEnteringArc() { // Check the current candidate list int e; - for (int i = 0; i < _curr_length; ++i) { + for (int i = 0; i != _curr_length; ++i) { e = _candidates[i]; _cand_cost[e] = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); @@ -578,39 +581,35 @@ // Extend the list int cnt = _block_size; - int last_arc = 0; int limit = _head_length; - for (int e = _next_arc; e < _search_arc_num; ++e) { + for (e = _next_arc; e != _search_arc_num; ++e) { _cand_cost[e] = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); if (_cand_cost[e] < 0) { _candidates[_curr_length++] = e; - last_arc = e; } if (--cnt == 0) { - if (_curr_length > limit) break; + if (_curr_length > limit) goto search_end; limit = 0; cnt = _block_size; } } - if (_curr_length <= limit) { - for (int e = 0; e < _next_arc; ++e) { - _cand_cost[e] = _state[e] * - (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (_cand_cost[e] < 0) { - _candidates[_curr_length++] = e; - last_arc = e; - } - if (--cnt == 0) { - if (_curr_length > limit) break; - limit = 0; - cnt = _block_size; - } + for (e = 0; e != _next_arc; ++e) { + _cand_cost[e] = _state[e] * + (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (_cand_cost[e] < 0) { + _candidates[_curr_length++] = e; + } + if (--cnt == 0) { + if (_curr_length > limit) goto search_end; + limit = 0; + cnt = _block_size; } } if (_curr_length == 0) return false; - _next_arc = last_arc + 1; + + search_end: // Make heap of the candidate list (approximating a partial sort) make_heap( _candidates.begin(), _candidates.begin() + _curr_length, @@ -618,6 +617,7 @@ // Pop the first element of the heap _in_arc = _candidates[0]; + _next_arc = e; pop_heap( _candidates.begin(), _candidates.begin() + _curr_length, _sort_func ); _curr_length = std::min(_head_length, _curr_length - 1); @@ -633,69 +633,25 @@ /// The constructor of the class. /// /// \param graph The digraph the algorithm runs on. - NetworkSimplex(const GR& graph) : + /// \param arc_mixing Indicate if the arcs have to be stored in a + /// mixed order in the internal data structure. + /// In special cases, it could lead to better overall performance, + /// but it is usually slower. Therefore it is disabled by default. + NetworkSimplex(const GR& graph, bool arc_mixing = false) : _graph(graph), _node_id(graph), _arc_id(graph), + _arc_mixing(arc_mixing), + MAX(std::numeric_limits::max()), INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) + std::numeric_limits::infinity() : MAX) { - // Check the value types + // Check the number types LEMON_ASSERT(std::numeric_limits::is_signed, "The flow type of NetworkSimplex must be signed"); LEMON_ASSERT(std::numeric_limits::is_signed, "The cost type of NetworkSimplex must be signed"); - - // Resize vectors - _node_num = countNodes(_graph); - _arc_num = countArcs(_graph); - int all_node_num = _node_num + 1; - int max_arc_num = _arc_num + 2 * _node_num; - _source.resize(max_arc_num); - _target.resize(max_arc_num); - - _lower.resize(_arc_num); - _upper.resize(_arc_num); - _cap.resize(max_arc_num); - _cost.resize(max_arc_num); - _supply.resize(all_node_num); - _flow.resize(max_arc_num); - _pi.resize(all_node_num); - - _parent.resize(all_node_num); - _pred.resize(all_node_num); - _forward.resize(all_node_num); - _thread.resize(all_node_num); - _rev_thread.resize(all_node_num); - _succ_num.resize(all_node_num); - _last_succ.resize(all_node_num); - _state.resize(max_arc_num); - - // Copy the graph (store the arcs in a mixed order) - int i = 0; - for (NodeIt n(_graph); n != INVALID; ++n, ++i) { - _node_id[n] = i; - } - int k = std::max(int(std::sqrt(double(_arc_num))), 10); - i = 0; - for (ArcIt a(_graph); a != INVALID; ++a) { - _arc_id[a] = i; - _source[i] = _node_id[_graph.source(a)]; - _target[i] = _node_id[_graph.target(a)]; - if ((i += k) >= _arc_num) i = (i % k) + 1; - } - - // Initialize maps - for (int i = 0; i != _node_num; ++i) { - _supply[i] = 0; - } - for (int i = 0; i != _arc_num; ++i) { - _lower[i] = 0; - _upper[i] = INF; - _cost[i] = 1; - } - _have_lower = false; - _stype = GEQ; + // Reset data structures + reset(); } /// \name Parameters @@ -729,7 +685,7 @@ /// This function sets the upper bounds (capacities) on the arcs. /// If it is not used before calling \ref run(), the upper bounds /// will be set to \ref INF on all arcs (i.e. the flow value will be - /// unbounded from above on each arc). + /// unbounded from above). /// /// \param map An arc map storing the upper bounds. /// Its \c Value type must be convertible to the \c Value type @@ -768,7 +724,6 @@ /// This function sets the supply values of the nodes. /// If neither this function nor \ref stSupply() is used before /// calling \ref run(), the supply of each node will be set to zero. - /// (It makes sense only if non-zero lower bounds are given.) /// /// \param map A node map storing the supply values. /// Its \c Value type must be convertible to the \c Value type @@ -789,7 +744,6 @@ /// and the required flow value. /// If neither this function nor \ref supplyMap() is used before /// calling \ref run(), the supply of each node will be set to zero. - /// (It makes sense only if non-zero lower bounds are given.) /// /// Using this function has the same effect as using \ref supplyMap() /// with such a map in which \c k is assigned to \c s, \c -k is @@ -809,14 +763,14 @@ _supply[_node_id[t]] = -k; return *this; } - + /// \brief Set the type of the supply constraints. /// /// This function sets the type of the supply/demand constraints. /// If it is not used before calling \ref run(), the \ref GEQ supply /// type will be used. /// - /// For more information see \ref SupplyType. + /// For more information, see \ref SupplyType. /// /// \return (*this) NetworkSimplex& supplyType(SupplyType supply_type) { @@ -835,7 +789,7 @@ /// /// This function runs the algorithm. /// The paramters can be specified using functions \ref lowerMap(), - /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(), /// \ref supplyType(). /// For example, /// \code @@ -844,15 +798,15 @@ /// .supplyMap(sup).run(); /// \endcode /// - /// This function can be called more than once. All the parameters - /// that have been given are kept for the next call, unless - /// \ref reset() is called, thus only the modified parameters - /// have to be set again. See \ref reset() for examples. - /// However the underlying digraph must not be modified after this - /// class have been constructed, since it copies and extends the graph. + /// This function can be called more than once. All the given parameters + /// are kept for the next call, unless \ref resetParams() or \ref reset() + /// is used, thus only the modified parameters have to be set again. + /// If the underlying digraph was also modified after the construction + /// of the class (or the last \ref reset() call), then the \ref reset() + /// function must be called. /// /// \param pivot_rule The pivot rule that will be used during the - /// algorithm. For more information see \ref PivotRule. + /// algorithm. For more information, see \ref PivotRule. /// /// \return \c INFEASIBLE if no feasible flow exists, /// \n \c OPTIMAL if the problem has optimal solution @@ -863,6 +817,7 @@ /// cost and infinite upper bound. /// /// \see ProblemType, PivotRule + /// \see resetParams(), reset() ProblemType run(PivotRule pivot_rule = BLOCK_SEARCH) { if (!init()) return INFEASIBLE; return start(pivot_rule); @@ -874,11 +829,12 @@ /// before using functions \ref lowerMap(), \ref upperMap(), /// \ref costMap(), \ref supplyMap(), \ref stSupply(), \ref supplyType(). /// - /// It is useful for multiple run() calls. If this function is not - /// used, all the parameters given before are kept for the next - /// \ref run() call. - /// However the underlying digraph must not be modified after this - /// class have been constructed, since it copies and extends the graph. + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. /// /// For example, /// \code @@ -888,20 +844,22 @@ /// ns.lowerMap(lower).upperMap(upper).costMap(cost) /// .supplyMap(sup).run(); /// - /// // Run again with modified cost map (reset() is not called, + /// // Run again with modified cost map (resetParams() is not called, /// // so only the cost map have to be set again) /// cost[e] += 100; /// ns.costMap(cost).run(); /// - /// // Run again from scratch using reset() + /// // Run again from scratch using resetParams() /// // (the lower bounds will be set to zero on all arcs) - /// ns.reset(); + /// ns.resetParams(); /// ns.upperMap(capacity).costMap(cost) /// .supplyMap(sup).run(); /// \endcode /// /// \return (*this) - NetworkSimplex& reset() { + /// + /// \see reset(), run() + NetworkSimplex& resetParams() { for (int i = 0; i != _node_num; ++i) { _supply[i] = 0; } @@ -915,6 +873,83 @@ return *this; } + /// \brief Reset the internal data structures and all the parameters + /// that have been given before. + /// + /// This function resets the internal data structures and all the + /// paramaters that have been given before using functions \ref lowerMap(), + /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(), + /// \ref supplyType(). + /// + /// It is useful for multiple \ref run() calls. Basically, all the given + /// parameters are kept for the next \ref run() call, unless + /// \ref resetParams() or \ref reset() is used. + /// If the underlying digraph was also modified after the construction + /// of the class or the last \ref reset() call, then the \ref reset() + /// function must be used, otherwise \ref resetParams() is sufficient. + /// + /// See \ref resetParams() for examples. + /// + /// \return (*this) + /// + /// \see resetParams(), run() + NetworkSimplex& reset() { + // Resize vectors + _node_num = countNodes(_graph); + _arc_num = countArcs(_graph); + int all_node_num = _node_num + 1; + int max_arc_num = _arc_num + 2 * _node_num; + + _source.resize(max_arc_num); + _target.resize(max_arc_num); + + _lower.resize(_arc_num); + _upper.resize(_arc_num); + _cap.resize(max_arc_num); + _cost.resize(max_arc_num); + _supply.resize(all_node_num); + _flow.resize(max_arc_num); + _pi.resize(all_node_num); + + _parent.resize(all_node_num); + _pred.resize(all_node_num); + _forward.resize(all_node_num); + _thread.resize(all_node_num); + _rev_thread.resize(all_node_num); + _succ_num.resize(all_node_num); + _last_succ.resize(all_node_num); + _state.resize(max_arc_num); + + // Copy the graph + int i = 0; + for (NodeIt n(_graph); n != INVALID; ++n, ++i) { + _node_id[n] = i; + } + if (_arc_mixing) { + // Store the arcs in a mixed order + int k = std::max(int(std::sqrt(double(_arc_num))), 10); + int i = 0, j = 0; + for (ArcIt a(_graph); a != INVALID; ++a) { + _arc_id[a] = i; + _source[i] = _node_id[_graph.source(a)]; + _target[i] = _node_id[_graph.target(a)]; + if ((i += k) >= _arc_num) i = ++j; + } + } else { + // Store the arcs in the original order + int i = 0; + for (ArcIt a(_graph); a != INVALID; ++a, ++i) { + _arc_id[a] = i; + _source[i] = _node_id[_graph.source(a)]; + _target[i] = _node_id[_graph.target(a)]; + } + } + + // Reset parameters + resetParams(); + return *this; + } + /// @} /// \name Query Functions @@ -1024,9 +1059,9 @@ for (int i = 0; i != _arc_num; ++i) { Value c = _lower[i]; if (c >= 0) { - _cap[i] = _upper[i] < INF ? _upper[i] - c : INF; + _cap[i] = _upper[i] < MAX ? _upper[i] - c : INF; } else { - _cap[i] = _upper[i] < INF + c ? _upper[i] - c : INF; + _cap[i] = _upper[i] < MAX + c ? _upper[i] - c : INF; } _supply[_source[i]] -= c; _supply[_target[i]] += c; @@ -1054,7 +1089,7 @@ _flow[i] = 0; _state[i] = STATE_LOWER; } - + // Set data for the artificial root node _root = _node_num; _parent[_root] = -1; @@ -1218,7 +1253,7 @@ for (int u = first; u != join; u = _parent[u]) { e = _pred[u]; d = _forward[u] ? - _flow[e] : (_cap[e] == INF ? INF : _cap[e] - _flow[e]); + _flow[e] : (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]); if (d < delta) { delta = d; u_out = u; @@ -1228,8 +1263,8 @@ // Search the cycle along the path form the second node to the root for (int u = second; u != join; u = _parent[u]) { e = _pred[u]; - d = _forward[u] ? - (_cap[e] == INF ? INF : _cap[e] - _flow[e]) : _flow[e]; + d = _forward[u] ? + (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]) : _flow[e]; if (d <= delta) { delta = d; u_out = u; @@ -1330,7 +1365,7 @@ } // Update _rev_thread using the new _thread values - for (int i = 0; i < int(_dirty_revs.size()); ++i) { + for (int i = 0; i != int(_dirty_revs.size()); ++i) { u = _dirty_revs[i]; _rev_thread[_thread[u]] = u; } @@ -1402,6 +1437,100 @@ } } + // Heuristic initial pivots + bool initialPivots() { + Value curr, total = 0; + std::vector supply_nodes, demand_nodes; + for (NodeIt u(_graph); u != INVALID; ++u) { + curr = _supply[_node_id[u]]; + if (curr > 0) { + total += curr; + supply_nodes.push_back(u); + } + else if (curr < 0) { + demand_nodes.push_back(u); + } + } + if (_sum_supply > 0) total -= _sum_supply; + if (total <= 0) return true; + + IntVector arc_vector; + if (_sum_supply >= 0) { + if (supply_nodes.size() == 1 && demand_nodes.size() == 1) { + // Perform a reverse graph search from the sink to the source + typename GR::template NodeMap reached(_graph, false); + Node s = supply_nodes[0], t = demand_nodes[0]; + std::vector stack; + reached[t] = true; + stack.push_back(t); + while (!stack.empty()) { + Node u, v = stack.back(); + stack.pop_back(); + if (v == s) break; + for (InArcIt a(_graph, v); a != INVALID; ++a) { + if (reached[u = _graph.source(a)]) continue; + int j = _arc_id[a]; + if (_cap[j] >= total) { + arc_vector.push_back(j); + reached[u] = true; + stack.push_back(u); + } + } + } + } else { + // Find the min. cost incomming arc for each demand node + for (int i = 0; i != int(demand_nodes.size()); ++i) { + Node v = demand_nodes[i]; + Cost c, min_cost = std::numeric_limits::max(); + Arc min_arc = INVALID; + for (InArcIt a(_graph, v); a != INVALID; ++a) { + c = _cost[_arc_id[a]]; + if (c < min_cost) { + min_cost = c; + min_arc = a; + } + } + if (min_arc != INVALID) { + arc_vector.push_back(_arc_id[min_arc]); + } + } + } + } else { + // Find the min. cost outgoing arc for each supply node + for (int i = 0; i != int(supply_nodes.size()); ++i) { + Node u = supply_nodes[i]; + Cost c, min_cost = std::numeric_limits::max(); + Arc min_arc = INVALID; + for (OutArcIt a(_graph, u); a != INVALID; ++a) { + c = _cost[_arc_id[a]]; + if (c < min_cost) { + min_cost = c; + min_arc = a; + } + } + if (min_arc != INVALID) { + arc_vector.push_back(_arc_id[min_arc]); + } + } + } + + // Perform heuristic initial pivots + for (int i = 0; i != int(arc_vector.size()); ++i) { + in_arc = arc_vector[i]; + if (_state[in_arc] * (_cost[in_arc] + _pi[_source[in_arc]] - + _pi[_target[in_arc]]) >= 0) continue; + findJoinNode(); + bool change = findLeavingArc(); + if (delta >= MAX) return false; + changeFlow(change); + if (change) { + updateTreeStructure(); + updatePotential(); + } + } + return true; + } + // Execute the algorithm ProblemType start(PivotRule pivot_rule) { // Select the pivot rule implementation @@ -1424,18 +1553,21 @@ ProblemType start() { PivotRuleImpl pivot(*this); + // Perform heuristic initial pivots + if (!initialPivots()) return UNBOUNDED; + // Execute the Network Simplex algorithm while (pivot.findEnteringArc()) { findJoinNode(); bool change = findLeavingArc(); - if (delta >= INF) return UNBOUNDED; + if (delta >= MAX) return UNBOUNDED; changeFlow(change); if (change) { updateTreeStructure(); updatePotential(); } } - + // Check feasibility for (int e = _search_arc_num; e != _all_arc_num; ++e) { if (_flow[e] != 0) return INFEASIBLE; @@ -1452,7 +1584,7 @@ } } } - + // Shift potentials to meet the requirements of the GEQ/LEQ type // optimality conditions if (_sum_supply == 0) { diff --git a/lemon/pairing_heap.h b/lemon/pairing_heap.h new file mode 100644 --- /dev/null +++ b/lemon/pairing_heap.h @@ -0,0 +1,474 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_PAIRING_HEAP_H +#define LEMON_PAIRING_HEAP_H + +///\file +///\ingroup heaps +///\brief Pairing heap implementation. + +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + ///\brief Pairing Heap. + /// + /// This class implements the \e pairing \e heap data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// The methods \ref increase() and \ref erase() are not efficient + /// in a pairing heap. In case of many calls of these operations, + /// it is better to use other heap structure, e.g. \ref BinHeap + /// "binary heap". + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. +#ifdef DOXYGEN + template +#else + template > +#endif + class PairingHeap { + public: + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + class store; + + std::vector _data; + int _min; + ItemIntMap &_iim; + Compare _comp; + int _num_items; + + public: + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit PairingHeap(ItemIntMap &map) + : _min(0), _iim(map), _num_items(0) {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + PairingHeap(ItemIntMap &map, const Compare &comp) + : _min(0), _iim(map), _comp(comp), _num_items(0) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _num_items; } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _num_items==0; } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { + _data.clear(); + _min = 0; + _num_items = 0; + } + + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. + /// + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. + /// \param item The item. + /// \param value The priority. + void set (const Item& item, const Prio& value) { + int i=_iim[item]; + if ( i>=0 && _data[i].in ) { + if ( _comp(value, _data[i].prio) ) decrease(item, value); + if ( _comp(_data[i].prio, value) ) increase(item, value); + } else push(item, value); + } + + /// \brief Insert an item into the heap with the given priority. + /// + /// This function inserts the given item into the heap with the + /// given priority. + /// \param item The item to insert. + /// \param value The priority of the item. + /// \pre \e item must not be stored in the heap. + void push (const Item& item, const Prio& value) { + int i=_iim[item]; + if( i<0 ) { + int s=_data.size(); + _iim.set(item, s); + store st; + st.name=item; + _data.push_back(st); + i=s; + } else { + _data[i].parent=_data[i].child=-1; + _data[i].left_child=false; + _data[i].degree=0; + _data[i].in=true; + } + + _data[i].prio=value; + + if ( _num_items!=0 ) { + if ( _comp( value, _data[_min].prio) ) { + fuse(i,_min); + _min=i; + } + else fuse(_min,i); + } + else _min=i; + + ++_num_items; + } + + /// \brief Return the item having minimum priority. + /// + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. + Item top() const { return _data[_min].name; } + + /// \brief The minimum priority. + /// + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. + const Prio& prio() const { return _data[_min].prio; } + + /// \brief The priority of the given item. + /// + /// This function returns the priority of the given item. + /// \param item The item. + /// \pre \e item must be in the heap. + const Prio& operator[](const Item& item) const { + return _data[_iim[item]].prio; + } + + /// \brief Remove the item having minimum priority. + /// + /// This function removes the item having minimum priority. + /// \pre The heap must be non-empty. + void pop() { + std::vector trees; + int i=0, child_right = 0; + _data[_min].in=false; + + if( -1!=_data[_min].child ) { + i=_data[_min].child; + trees.push_back(i); + _data[i].parent = -1; + _data[_min].child = -1; + + int ch=-1; + while( _data[i].child!=-1 ) { + ch=_data[i].child; + if( _data[ch].left_child && i==_data[ch].parent ) { + break; + } else { + if( _data[ch].left_child ) { + child_right=_data[ch].parent; + _data[ch].parent = i; + --_data[i].degree; + } + else { + child_right=ch; + _data[i].child=-1; + _data[i].degree=0; + } + _data[child_right].parent = -1; + trees.push_back(child_right); + i = child_right; + } + } + + int num_child = trees.size(); + int other; + for( i=0; i=2) { + if ( _comp(_data[trees[i]].prio, _data[trees[i-2]].prio) ) { + other=trees[i]; + trees[i]=trees[i-2]; + trees[i-2]=other; + } + fuse( trees[i-2], trees[i] ); + i-=2; + } + _min = trees[0]; + } + else { + _min = _data[_min].child; + } + + if (_min >= 0) _data[_min].left_child = false; + --_num_items; + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param item The item to delete. + /// \pre \e item must be in the heap. + void erase (const Item& item) { + int i=_iim[item]; + if ( i>=0 && _data[i].in ) { + decrease( item, _data[_min].prio-1 ); + pop(); + } + } + + /// \brief Decrease the priority of an item to the given value. + /// + /// This function decreases the priority of an item to the given value. + /// \param item The item. + /// \param value The priority. + /// \pre \e item must be stored in the heap with priority at least \e value. + void decrease (Item item, const Prio& value) { + int i=_iim[item]; + _data[i].prio=value; + int p=_data[i].parent; + + if( _data[i].left_child && i!=_data[p].child ) { + p=_data[p].parent; + } + + if ( p!=-1 && _comp(value,_data[p].prio) ) { + cut(i,p); + if ( _comp(_data[_min].prio,value) ) { + fuse(_min,i); + } else { + fuse(i,_min); + _min=i; + } + } + } + + /// \brief Increase the priority of an item to the given value. + /// + /// This function increases the priority of an item to the given value. + /// \param item The item. + /// \param value The priority. + /// \pre \e item must be stored in the heap with priority at most \e value. + void increase (Item item, const Prio& value) { + erase(item); + push(item,value); + } + + /// \brief Return the state of an item. + /// + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. + /// \param item The item. + State state(const Item &item) const { + int i=_iim[item]; + if( i>=0 ) { + if( _data[i].in ) i=0; + else i=-2; + } + return State(i); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) erase(i); + _iim[i]=st; + break; + case IN_HEAP: + break; + } + } + + private: + + void cut(int a, int b) { + int child_a; + switch (_data[a].degree) { + case 2: + child_a = _data[_data[a].child].parent; + if( _data[a].left_child ) { + _data[child_a].left_child=true; + _data[b].child=child_a; + _data[child_a].parent=_data[a].parent; + } + else { + _data[child_a].left_child=false; + _data[child_a].parent=b; + if( a!=_data[b].child ) + _data[_data[b].child].parent=child_a; + else + _data[b].child=child_a; + } + --_data[a].degree; + _data[_data[a].child].parent=a; + break; + + case 1: + child_a = _data[a].child; + if( !_data[child_a].left_child ) { + --_data[a].degree; + if( _data[a].left_child ) { + _data[child_a].left_child=true; + _data[child_a].parent=_data[a].parent; + _data[b].child=child_a; + } + else { + _data[child_a].left_child=false; + _data[child_a].parent=b; + if( a!=_data[b].child ) + _data[_data[b].child].parent=child_a; + else + _data[b].child=child_a; + } + _data[a].child=-1; + } + else { + --_data[b].degree; + if( _data[a].left_child ) { + _data[b].child = + (1==_data[b].degree) ? _data[a].parent : -1; + } else { + if (1==_data[b].degree) + _data[_data[b].child].parent=b; + else + _data[b].child=-1; + } + } + break; + + case 0: + --_data[b].degree; + if( _data[a].left_child ) { + _data[b].child = + (0!=_data[b].degree) ? _data[a].parent : -1; + } else { + if( 0!=_data[b].degree ) + _data[_data[b].child].parent=b; + else + _data[b].child=-1; + } + break; + } + _data[a].parent=-1; + _data[a].left_child=false; + } + + void fuse(int a, int b) { + int child_a = _data[a].child; + int child_b = _data[b].child; + _data[a].child=b; + _data[b].parent=a; + _data[b].left_child=true; + + if( -1!=child_a ) { + _data[b].child=child_a; + _data[child_a].parent=b; + _data[child_a].left_child=false; + ++_data[b].degree; + + if( -1!=child_b ) { + _data[b].child=child_b; + _data[child_b].parent=child_a; + } + } + else { ++_data[a].degree; } + } + + class store { + friend class PairingHeap; + + Item name; + int parent; + int child; + bool left_child; + int degree; + bool in; + Prio prio; + + store() : parent(-1), child(-1), left_child(false), degree(0), in(true) {} + }; + }; + +} //namespace lemon + +#endif //LEMON_PAIRING_HEAP_H + diff --git a/lemon/path.h b/lemon/path.h --- a/lemon/path.h +++ b/lemon/path.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -966,20 +966,20 @@ } }; - + template ::value> struct PathCopySelector { static void copy(const From& from, To& to) { PathCopySelectorForward::copy(from, to); - } + } }; template struct PathCopySelector { static void copy(const From& from, To& to) { PathCopySelectorBackward::copy(from, to); - } + } }; } diff --git a/lemon/planarity.h b/lemon/planarity.h new file mode 100644 --- /dev/null +++ b/lemon/planarity.h @@ -0,0 +1,2755 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_PLANARITY_H +#define LEMON_PLANARITY_H + +/// \ingroup planar +/// \file +/// \brief Planarity checking, embedding, drawing and coloring + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lemon { + + namespace _planarity_bits { + + template + struct PlanarityVisitor : DfsVisitor { + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + typedef typename Graph::template NodeMap PredMap; + + typedef typename Graph::template EdgeMap TreeMap; + + typedef typename Graph::template NodeMap OrderMap; + typedef std::vector OrderList; + + typedef typename Graph::template NodeMap LowMap; + typedef typename Graph::template NodeMap AncestorMap; + + PlanarityVisitor(const Graph& graph, + PredMap& pred_map, TreeMap& tree_map, + OrderMap& order_map, OrderList& order_list, + AncestorMap& ancestor_map, LowMap& low_map) + : _graph(graph), _pred_map(pred_map), _tree_map(tree_map), + _order_map(order_map), _order_list(order_list), + _ancestor_map(ancestor_map), _low_map(low_map) {} + + void reach(const Node& node) { + _order_map[node] = _order_list.size(); + _low_map[node] = _order_list.size(); + _ancestor_map[node] = _order_list.size(); + _order_list.push_back(node); + } + + void discover(const Arc& arc) { + Node source = _graph.source(arc); + Node target = _graph.target(arc); + + _tree_map[arc] = true; + _pred_map[target] = arc; + } + + void examine(const Arc& arc) { + Node source = _graph.source(arc); + Node target = _graph.target(arc); + + if (_order_map[target] < _order_map[source] && !_tree_map[arc]) { + if (_low_map[source] > _order_map[target]) { + _low_map[source] = _order_map[target]; + } + if (_ancestor_map[source] > _order_map[target]) { + _ancestor_map[source] = _order_map[target]; + } + } + } + + void backtrack(const Arc& arc) { + Node source = _graph.source(arc); + Node target = _graph.target(arc); + + if (_low_map[source] > _low_map[target]) { + _low_map[source] = _low_map[target]; + } + } + + const Graph& _graph; + PredMap& _pred_map; + TreeMap& _tree_map; + OrderMap& _order_map; + OrderList& _order_list; + AncestorMap& _ancestor_map; + LowMap& _low_map; + }; + + template + struct NodeDataNode { + int prev, next; + int visited; + typename Graph::Arc first; + bool inverted; + }; + + template + struct NodeDataNode { + int prev, next; + int visited; + }; + + template + struct ChildListNode { + typedef typename Graph::Node Node; + Node first; + Node prev, next; + }; + + template + struct ArcListNode { + typename Graph::Arc prev, next; + }; + + template + class PlanarityChecking { + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + const Graph& _graph; + + private: + + typedef typename Graph::template NodeMap PredMap; + + typedef typename Graph::template EdgeMap TreeMap; + + typedef typename Graph::template NodeMap OrderMap; + typedef std::vector OrderList; + + typedef typename Graph::template NodeMap LowMap; + typedef typename Graph::template NodeMap AncestorMap; + + typedef _planarity_bits::NodeDataNode NodeDataNode; + typedef std::vector NodeData; + + typedef _planarity_bits::ChildListNode ChildListNode; + typedef typename Graph::template NodeMap ChildLists; + + typedef typename Graph::template NodeMap > MergeRoots; + + typedef typename Graph::template NodeMap EmbedArc; + + public: + + PlanarityChecking(const Graph& graph) : _graph(graph) {} + + bool run() { + typedef _planarity_bits::PlanarityVisitor Visitor; + + PredMap pred_map(_graph, INVALID); + TreeMap tree_map(_graph, false); + + OrderMap order_map(_graph, -1); + OrderList order_list; + + AncestorMap ancestor_map(_graph, -1); + LowMap low_map(_graph, -1); + + Visitor visitor(_graph, pred_map, tree_map, + order_map, order_list, ancestor_map, low_map); + DfsVisit visit(_graph, visitor); + visit.run(); + + ChildLists child_lists(_graph); + createChildLists(tree_map, order_map, low_map, child_lists); + + NodeData node_data(2 * order_list.size()); + + EmbedArc embed_arc(_graph, false); + + MergeRoots merge_roots(_graph); + + for (int i = order_list.size() - 1; i >= 0; --i) { + + Node node = order_list[i]; + + Node source = node; + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && tree_map[e]) { + initFace(target, node_data, order_map, order_list); + } + } + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && !tree_map[e]) { + embed_arc[target] = true; + walkUp(target, source, i, pred_map, low_map, + order_map, order_list, node_data, merge_roots); + } + } + + for (typename MergeRoots::Value::iterator it = + merge_roots[node].begin(); + it != merge_roots[node].end(); ++it) { + int rn = *it; + walkDown(rn, i, node_data, order_list, child_lists, + ancestor_map, low_map, embed_arc, merge_roots); + } + merge_roots[node].clear(); + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && !tree_map[e]) { + if (embed_arc[target]) { + return false; + } + } + } + } + + return true; + } + + private: + + void createChildLists(const TreeMap& tree_map, const OrderMap& order_map, + const LowMap& low_map, ChildLists& child_lists) { + + for (NodeIt n(_graph); n != INVALID; ++n) { + Node source = n; + + std::vector targets; + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && tree_map[e]) { + targets.push_back(target); + } + } + + if (targets.size() == 0) { + child_lists[source].first = INVALID; + } else if (targets.size() == 1) { + child_lists[source].first = targets[0]; + child_lists[targets[0]].prev = INVALID; + child_lists[targets[0]].next = INVALID; + } else { + radixSort(targets.begin(), targets.end(), mapToFunctor(low_map)); + for (int i = 1; i < int(targets.size()); ++i) { + child_lists[targets[i]].prev = targets[i - 1]; + child_lists[targets[i - 1]].next = targets[i]; + } + child_lists[targets.back()].next = INVALID; + child_lists[targets.front()].prev = INVALID; + child_lists[source].first = targets.front(); + } + } + } + + void walkUp(const Node& node, Node root, int rorder, + const PredMap& pred_map, const LowMap& low_map, + const OrderMap& order_map, const OrderList& order_list, + NodeData& node_data, MergeRoots& merge_roots) { + + int na, nb; + bool da, db; + + na = nb = order_map[node]; + da = true; db = false; + + while (true) { + + if (node_data[na].visited == rorder) break; + if (node_data[nb].visited == rorder) break; + + node_data[na].visited = rorder; + node_data[nb].visited = rorder; + + int rn = -1; + + if (na >= int(order_list.size())) { + rn = na; + } else if (nb >= int(order_list.size())) { + rn = nb; + } + + if (rn == -1) { + int nn; + + nn = da ? node_data[na].prev : node_data[na].next; + da = node_data[nn].prev != na; + na = nn; + + nn = db ? node_data[nb].prev : node_data[nb].next; + db = node_data[nn].prev != nb; + nb = nn; + + } else { + + Node rep = order_list[rn - order_list.size()]; + Node parent = _graph.source(pred_map[rep]); + + if (low_map[rep] < rorder) { + merge_roots[parent].push_back(rn); + } else { + merge_roots[parent].push_front(rn); + } + + if (parent != root) { + na = nb = order_map[parent]; + da = true; db = false; + } else { + break; + } + } + } + } + + void walkDown(int rn, int rorder, NodeData& node_data, + OrderList& order_list, ChildLists& child_lists, + AncestorMap& ancestor_map, LowMap& low_map, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + + std::vector > merge_stack; + + for (int di = 0; di < 2; ++di) { + bool rd = di == 0; + int pn = rn; + int n = rd ? node_data[rn].next : node_data[rn].prev; + + while (n != rn) { + + Node node = order_list[n]; + + if (embed_arc[node]) { + + // Merging components on the critical path + while (!merge_stack.empty()) { + + // Component root + int cn = merge_stack.back().first; + bool cd = merge_stack.back().second; + merge_stack.pop_back(); + + // Parent of component + int dn = merge_stack.back().first; + bool dd = merge_stack.back().second; + merge_stack.pop_back(); + + Node parent = order_list[dn]; + + // Erasing from merge_roots + merge_roots[parent].pop_front(); + + Node child = order_list[cn - order_list.size()]; + + // Erasing from child_lists + if (child_lists[child].prev != INVALID) { + child_lists[child_lists[child].prev].next = + child_lists[child].next; + } else { + child_lists[parent].first = child_lists[child].next; + } + + if (child_lists[child].next != INVALID) { + child_lists[child_lists[child].next].prev = + child_lists[child].prev; + } + + // Merging external faces + { + int en = cn; + cn = cd ? node_data[cn].prev : node_data[cn].next; + cd = node_data[cn].next == en; + + } + + if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn; + if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn; + + } + + bool d = pn == node_data[n].prev; + + if (node_data[n].prev == node_data[n].next && + node_data[n].inverted) { + d = !d; + } + + // Embedding arc into external face + if (rd) node_data[rn].next = n; else node_data[rn].prev = n; + if (d) node_data[n].prev = rn; else node_data[n].next = rn; + pn = rn; + + embed_arc[order_list[n]] = false; + } + + if (!merge_roots[node].empty()) { + + bool d = pn == node_data[n].prev; + + merge_stack.push_back(std::make_pair(n, d)); + + int rn = merge_roots[node].front(); + + int xn = node_data[rn].next; + Node xnode = order_list[xn]; + + int yn = node_data[rn].prev; + Node ynode = order_list[yn]; + + bool rd; + if (!external(xnode, rorder, child_lists, + ancestor_map, low_map)) { + rd = true; + } else if (!external(ynode, rorder, child_lists, + ancestor_map, low_map)) { + rd = false; + } else if (pertinent(xnode, embed_arc, merge_roots)) { + rd = true; + } else { + rd = false; + } + + merge_stack.push_back(std::make_pair(rn, rd)); + + pn = rn; + n = rd ? xn : yn; + + } else if (!external(node, rorder, child_lists, + ancestor_map, low_map)) { + int nn = (node_data[n].next != pn ? + node_data[n].next : node_data[n].prev); + + bool nd = n == node_data[nn].prev; + + if (nd) node_data[nn].prev = pn; + else node_data[nn].next = pn; + + if (n == node_data[pn].prev) node_data[pn].prev = nn; + else node_data[pn].next = nn; + + node_data[nn].inverted = + (node_data[nn].prev == node_data[nn].next && nd != rd); + + n = nn; + } + else break; + + } + + if (!merge_stack.empty() || n == rn) { + break; + } + } + } + + void initFace(const Node& node, NodeData& node_data, + const OrderMap& order_map, const OrderList& order_list) { + int n = order_map[node]; + int rn = n + order_list.size(); + + node_data[n].next = node_data[n].prev = rn; + node_data[rn].next = node_data[rn].prev = n; + + node_data[n].visited = order_list.size(); + node_data[rn].visited = order_list.size(); + + } + + bool external(const Node& node, int rorder, + ChildLists& child_lists, AncestorMap& ancestor_map, + LowMap& low_map) { + Node child = child_lists[node].first; + + if (child != INVALID) { + if (low_map[child] < rorder) return true; + } + + if (ancestor_map[node] < rorder) return true; + + return false; + } + + bool pertinent(const Node& node, const EmbedArc& embed_arc, + const MergeRoots& merge_roots) { + return !merge_roots[node].empty() || embed_arc[node]; + } + + }; + + } + + /// \ingroup planar + /// + /// \brief Planarity checking of an undirected simple graph + /// + /// This function implements the Boyer-Myrvold algorithm for + /// planarity checking of an undirected simple graph. It is a simplified + /// version of the PlanarEmbedding algorithm class because neither + /// the embedding nor the Kuratowski subdivisons are computed. + template + bool checkPlanarity(const GR& graph) { + _planarity_bits::PlanarityChecking pc(graph); + return pc.run(); + } + + /// \ingroup planar + /// + /// \brief Planar embedding of an undirected simple graph + /// + /// This class implements the Boyer-Myrvold algorithm for planar + /// embedding of an undirected simple graph. The planar embedding is an + /// ordering of the outgoing edges of the nodes, which is a possible + /// configuration to draw the graph in the plane. If there is not + /// such ordering then the graph contains a K5 (full graph + /// with 5 nodes) or a K3,3 (complete bipartite graph on + /// 3 Red and 3 Blue nodes) subdivision. + /// + /// The current implementation calculates either an embedding or a + /// Kuratowski subdivision. The running time of the algorithm is O(n). + /// + /// \see PlanarDrawing, checkPlanarity() + template + class PlanarEmbedding { + private: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + const Graph& _graph; + typename Graph::template ArcMap _embedding; + + typename Graph::template EdgeMap _kuratowski; + + private: + + typedef typename Graph::template NodeMap PredMap; + + typedef typename Graph::template EdgeMap TreeMap; + + typedef typename Graph::template NodeMap OrderMap; + typedef std::vector OrderList; + + typedef typename Graph::template NodeMap LowMap; + typedef typename Graph::template NodeMap AncestorMap; + + typedef _planarity_bits::NodeDataNode NodeDataNode; + typedef std::vector NodeData; + + typedef _planarity_bits::ChildListNode ChildListNode; + typedef typename Graph::template NodeMap ChildLists; + + typedef typename Graph::template NodeMap > MergeRoots; + + typedef typename Graph::template NodeMap EmbedArc; + + typedef _planarity_bits::ArcListNode ArcListNode; + typedef typename Graph::template ArcMap ArcLists; + + typedef typename Graph::template NodeMap FlipMap; + + typedef typename Graph::template NodeMap TypeMap; + + enum IsolatorNodeType { + HIGHX = 6, LOWX = 7, + HIGHY = 8, LOWY = 9, + ROOT = 10, PERTINENT = 11, + INTERNAL = 12 + }; + + public: + + /// \brief The map type for storing the embedding + /// + /// The map type for storing the embedding. + /// \see embeddingMap() + typedef typename Graph::template ArcMap EmbeddingMap; + + /// \brief Constructor + /// + /// Constructor. + /// \pre The graph must be simple, i.e. it should not + /// contain parallel or loop arcs. + PlanarEmbedding(const Graph& graph) + : _graph(graph), _embedding(_graph), _kuratowski(graph, false) {} + + /// \brief Run the algorithm. + /// + /// This function runs the algorithm. + /// \param kuratowski If this parameter is set to \c false, then the + /// algorithm does not compute a Kuratowski subdivision. + /// \return \c true if the graph is planar. + bool run(bool kuratowski = true) { + typedef _planarity_bits::PlanarityVisitor Visitor; + + PredMap pred_map(_graph, INVALID); + TreeMap tree_map(_graph, false); + + OrderMap order_map(_graph, -1); + OrderList order_list; + + AncestorMap ancestor_map(_graph, -1); + LowMap low_map(_graph, -1); + + Visitor visitor(_graph, pred_map, tree_map, + order_map, order_list, ancestor_map, low_map); + DfsVisit visit(_graph, visitor); + visit.run(); + + ChildLists child_lists(_graph); + createChildLists(tree_map, order_map, low_map, child_lists); + + NodeData node_data(2 * order_list.size()); + + EmbedArc embed_arc(_graph, INVALID); + + MergeRoots merge_roots(_graph); + + ArcLists arc_lists(_graph); + + FlipMap flip_map(_graph, false); + + for (int i = order_list.size() - 1; i >= 0; --i) { + + Node node = order_list[i]; + + node_data[i].first = INVALID; + + Node source = node; + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && tree_map[e]) { + initFace(target, arc_lists, node_data, + pred_map, order_map, order_list); + } + } + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && !tree_map[e]) { + embed_arc[target] = e; + walkUp(target, source, i, pred_map, low_map, + order_map, order_list, node_data, merge_roots); + } + } + + for (typename MergeRoots::Value::iterator it = + merge_roots[node].begin(); it != merge_roots[node].end(); ++it) { + int rn = *it; + walkDown(rn, i, node_data, arc_lists, flip_map, order_list, + child_lists, ancestor_map, low_map, embed_arc, merge_roots); + } + merge_roots[node].clear(); + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && !tree_map[e]) { + if (embed_arc[target] != INVALID) { + if (kuratowski) { + isolateKuratowski(e, node_data, arc_lists, flip_map, + order_map, order_list, pred_map, child_lists, + ancestor_map, low_map, + embed_arc, merge_roots); + } + return false; + } + } + } + } + + for (int i = 0; i < int(order_list.size()); ++i) { + + mergeRemainingFaces(order_list[i], node_data, order_list, order_map, + child_lists, arc_lists); + storeEmbedding(order_list[i], node_data, order_map, pred_map, + arc_lists, flip_map); + } + + return true; + } + + /// \brief Give back the successor of an arc + /// + /// This function gives back the successor of an arc. It makes + /// possible to query the cyclic order of the outgoing arcs from + /// a node. + Arc next(const Arc& arc) const { + return _embedding[arc]; + } + + /// \brief Give back the calculated embedding map + /// + /// This function gives back the calculated embedding map, which + /// contains the successor of each arc in the cyclic order of the + /// outgoing arcs of its source node. + const EmbeddingMap& embeddingMap() const { + return _embedding; + } + + /// \brief Give back \c true if the given edge is in the Kuratowski + /// subdivision + /// + /// This function gives back \c true if the given edge is in the found + /// Kuratowski subdivision. + /// \pre The \c run() function must be called with \c true parameter + /// before using this function. + bool kuratowski(const Edge& edge) const { + return _kuratowski[edge]; + } + + private: + + void createChildLists(const TreeMap& tree_map, const OrderMap& order_map, + const LowMap& low_map, ChildLists& child_lists) { + + for (NodeIt n(_graph); n != INVALID; ++n) { + Node source = n; + + std::vector targets; + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node target = _graph.target(e); + + if (order_map[source] < order_map[target] && tree_map[e]) { + targets.push_back(target); + } + } + + if (targets.size() == 0) { + child_lists[source].first = INVALID; + } else if (targets.size() == 1) { + child_lists[source].first = targets[0]; + child_lists[targets[0]].prev = INVALID; + child_lists[targets[0]].next = INVALID; + } else { + radixSort(targets.begin(), targets.end(), mapToFunctor(low_map)); + for (int i = 1; i < int(targets.size()); ++i) { + child_lists[targets[i]].prev = targets[i - 1]; + child_lists[targets[i - 1]].next = targets[i]; + } + child_lists[targets.back()].next = INVALID; + child_lists[targets.front()].prev = INVALID; + child_lists[source].first = targets.front(); + } + } + } + + void walkUp(const Node& node, Node root, int rorder, + const PredMap& pred_map, const LowMap& low_map, + const OrderMap& order_map, const OrderList& order_list, + NodeData& node_data, MergeRoots& merge_roots) { + + int na, nb; + bool da, db; + + na = nb = order_map[node]; + da = true; db = false; + + while (true) { + + if (node_data[na].visited == rorder) break; + if (node_data[nb].visited == rorder) break; + + node_data[na].visited = rorder; + node_data[nb].visited = rorder; + + int rn = -1; + + if (na >= int(order_list.size())) { + rn = na; + } else if (nb >= int(order_list.size())) { + rn = nb; + } + + if (rn == -1) { + int nn; + + nn = da ? node_data[na].prev : node_data[na].next; + da = node_data[nn].prev != na; + na = nn; + + nn = db ? node_data[nb].prev : node_data[nb].next; + db = node_data[nn].prev != nb; + nb = nn; + + } else { + + Node rep = order_list[rn - order_list.size()]; + Node parent = _graph.source(pred_map[rep]); + + if (low_map[rep] < rorder) { + merge_roots[parent].push_back(rn); + } else { + merge_roots[parent].push_front(rn); + } + + if (parent != root) { + na = nb = order_map[parent]; + da = true; db = false; + } else { + break; + } + } + } + } + + void walkDown(int rn, int rorder, NodeData& node_data, + ArcLists& arc_lists, FlipMap& flip_map, + OrderList& order_list, ChildLists& child_lists, + AncestorMap& ancestor_map, LowMap& low_map, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + + std::vector > merge_stack; + + for (int di = 0; di < 2; ++di) { + bool rd = di == 0; + int pn = rn; + int n = rd ? node_data[rn].next : node_data[rn].prev; + + while (n != rn) { + + Node node = order_list[n]; + + if (embed_arc[node] != INVALID) { + + // Merging components on the critical path + while (!merge_stack.empty()) { + + // Component root + int cn = merge_stack.back().first; + bool cd = merge_stack.back().second; + merge_stack.pop_back(); + + // Parent of component + int dn = merge_stack.back().first; + bool dd = merge_stack.back().second; + merge_stack.pop_back(); + + Node parent = order_list[dn]; + + // Erasing from merge_roots + merge_roots[parent].pop_front(); + + Node child = order_list[cn - order_list.size()]; + + // Erasing from child_lists + if (child_lists[child].prev != INVALID) { + child_lists[child_lists[child].prev].next = + child_lists[child].next; + } else { + child_lists[parent].first = child_lists[child].next; + } + + if (child_lists[child].next != INVALID) { + child_lists[child_lists[child].next].prev = + child_lists[child].prev; + } + + // Merging arcs + flipping + Arc de = node_data[dn].first; + Arc ce = node_data[cn].first; + + flip_map[order_list[cn - order_list.size()]] = cd != dd; + if (cd != dd) { + std::swap(arc_lists[ce].prev, arc_lists[ce].next); + ce = arc_lists[ce].prev; + std::swap(arc_lists[ce].prev, arc_lists[ce].next); + } + + { + Arc dne = arc_lists[de].next; + Arc cne = arc_lists[ce].next; + + arc_lists[de].next = cne; + arc_lists[ce].next = dne; + + arc_lists[dne].prev = ce; + arc_lists[cne].prev = de; + } + + if (dd) { + node_data[dn].first = ce; + } + + // Merging external faces + { + int en = cn; + cn = cd ? node_data[cn].prev : node_data[cn].next; + cd = node_data[cn].next == en; + + if (node_data[cn].prev == node_data[cn].next && + node_data[cn].inverted) { + cd = !cd; + } + } + + if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn; + if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn; + + } + + bool d = pn == node_data[n].prev; + + if (node_data[n].prev == node_data[n].next && + node_data[n].inverted) { + d = !d; + } + + // Add new arc + { + Arc arc = embed_arc[node]; + Arc re = node_data[rn].first; + + arc_lists[arc_lists[re].next].prev = arc; + arc_lists[arc].next = arc_lists[re].next; + arc_lists[arc].prev = re; + arc_lists[re].next = arc; + + if (!rd) { + node_data[rn].first = arc; + } + + Arc rev = _graph.oppositeArc(arc); + Arc e = node_data[n].first; + + arc_lists[arc_lists[e].next].prev = rev; + arc_lists[rev].next = arc_lists[e].next; + arc_lists[rev].prev = e; + arc_lists[e].next = rev; + + if (d) { + node_data[n].first = rev; + } + + } + + // Embedding arc into external face + if (rd) node_data[rn].next = n; else node_data[rn].prev = n; + if (d) node_data[n].prev = rn; else node_data[n].next = rn; + pn = rn; + + embed_arc[order_list[n]] = INVALID; + } + + if (!merge_roots[node].empty()) { + + bool d = pn == node_data[n].prev; + if (node_data[n].prev == node_data[n].next && + node_data[n].inverted) { + d = !d; + } + + merge_stack.push_back(std::make_pair(n, d)); + + int rn = merge_roots[node].front(); + + int xn = node_data[rn].next; + Node xnode = order_list[xn]; + + int yn = node_data[rn].prev; + Node ynode = order_list[yn]; + + bool rd; + if (!external(xnode, rorder, child_lists, ancestor_map, low_map)) { + rd = true; + } else if (!external(ynode, rorder, child_lists, + ancestor_map, low_map)) { + rd = false; + } else if (pertinent(xnode, embed_arc, merge_roots)) { + rd = true; + } else { + rd = false; + } + + merge_stack.push_back(std::make_pair(rn, rd)); + + pn = rn; + n = rd ? xn : yn; + + } else if (!external(node, rorder, child_lists, + ancestor_map, low_map)) { + int nn = (node_data[n].next != pn ? + node_data[n].next : node_data[n].prev); + + bool nd = n == node_data[nn].prev; + + if (nd) node_data[nn].prev = pn; + else node_data[nn].next = pn; + + if (n == node_data[pn].prev) node_data[pn].prev = nn; + else node_data[pn].next = nn; + + node_data[nn].inverted = + (node_data[nn].prev == node_data[nn].next && nd != rd); + + n = nn; + } + else break; + + } + + if (!merge_stack.empty() || n == rn) { + break; + } + } + } + + void initFace(const Node& node, ArcLists& arc_lists, + NodeData& node_data, const PredMap& pred_map, + const OrderMap& order_map, const OrderList& order_list) { + int n = order_map[node]; + int rn = n + order_list.size(); + + node_data[n].next = node_data[n].prev = rn; + node_data[rn].next = node_data[rn].prev = n; + + node_data[n].visited = order_list.size(); + node_data[rn].visited = order_list.size(); + + node_data[n].inverted = false; + node_data[rn].inverted = false; + + Arc arc = pred_map[node]; + Arc rev = _graph.oppositeArc(arc); + + node_data[rn].first = arc; + node_data[n].first = rev; + + arc_lists[arc].prev = arc; + arc_lists[arc].next = arc; + + arc_lists[rev].prev = rev; + arc_lists[rev].next = rev; + + } + + void mergeRemainingFaces(const Node& node, NodeData& node_data, + OrderList& order_list, OrderMap& order_map, + ChildLists& child_lists, ArcLists& arc_lists) { + while (child_lists[node].first != INVALID) { + int dd = order_map[node]; + Node child = child_lists[node].first; + int cd = order_map[child] + order_list.size(); + child_lists[node].first = child_lists[child].next; + + Arc de = node_data[dd].first; + Arc ce = node_data[cd].first; + + if (de != INVALID) { + Arc dne = arc_lists[de].next; + Arc cne = arc_lists[ce].next; + + arc_lists[de].next = cne; + arc_lists[ce].next = dne; + + arc_lists[dne].prev = ce; + arc_lists[cne].prev = de; + } + + node_data[dd].first = ce; + + } + } + + void storeEmbedding(const Node& node, NodeData& node_data, + OrderMap& order_map, PredMap& pred_map, + ArcLists& arc_lists, FlipMap& flip_map) { + + if (node_data[order_map[node]].first == INVALID) return; + + if (pred_map[node] != INVALID) { + Node source = _graph.source(pred_map[node]); + flip_map[node] = flip_map[node] != flip_map[source]; + } + + Arc first = node_data[order_map[node]].first; + Arc prev = first; + + Arc arc = flip_map[node] ? + arc_lists[prev].prev : arc_lists[prev].next; + + _embedding[prev] = arc; + + while (arc != first) { + Arc next = arc_lists[arc].prev == prev ? + arc_lists[arc].next : arc_lists[arc].prev; + prev = arc; arc = next; + _embedding[prev] = arc; + } + } + + + bool external(const Node& node, int rorder, + ChildLists& child_lists, AncestorMap& ancestor_map, + LowMap& low_map) { + Node child = child_lists[node].first; + + if (child != INVALID) { + if (low_map[child] < rorder) return true; + } + + if (ancestor_map[node] < rorder) return true; + + return false; + } + + bool pertinent(const Node& node, const EmbedArc& embed_arc, + const MergeRoots& merge_roots) { + return !merge_roots[node].empty() || embed_arc[node] != INVALID; + } + + int lowPoint(const Node& node, OrderMap& order_map, ChildLists& child_lists, + AncestorMap& ancestor_map, LowMap& low_map) { + int low_point; + + Node child = child_lists[node].first; + + if (child != INVALID) { + low_point = low_map[child]; + } else { + low_point = order_map[node]; + } + + if (low_point > ancestor_map[node]) { + low_point = ancestor_map[node]; + } + + return low_point; + } + + int findComponentRoot(Node root, Node node, ChildLists& child_lists, + OrderMap& order_map, OrderList& order_list) { + + int order = order_map[root]; + int norder = order_map[node]; + + Node child = child_lists[root].first; + while (child != INVALID) { + int corder = order_map[child]; + if (corder > order && corder < norder) { + order = corder; + } + child = child_lists[child].next; + } + return order + order_list.size(); + } + + Node findPertinent(Node node, OrderMap& order_map, NodeData& node_data, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + Node wnode =_graph.target(node_data[order_map[node]].first); + while (!pertinent(wnode, embed_arc, merge_roots)) { + wnode = _graph.target(node_data[order_map[wnode]].first); + } + return wnode; + } + + + Node findExternal(Node node, int rorder, OrderMap& order_map, + ChildLists& child_lists, AncestorMap& ancestor_map, + LowMap& low_map, NodeData& node_data) { + Node wnode =_graph.target(node_data[order_map[node]].first); + while (!external(wnode, rorder, child_lists, ancestor_map, low_map)) { + wnode = _graph.target(node_data[order_map[wnode]].first); + } + return wnode; + } + + void markCommonPath(Node node, int rorder, Node& wnode, Node& znode, + OrderList& order_list, OrderMap& order_map, + NodeData& node_data, ArcLists& arc_lists, + EmbedArc& embed_arc, MergeRoots& merge_roots, + ChildLists& child_lists, AncestorMap& ancestor_map, + LowMap& low_map) { + + Node cnode = node; + Node pred = INVALID; + + while (true) { + + bool pert = pertinent(cnode, embed_arc, merge_roots); + bool ext = external(cnode, rorder, child_lists, ancestor_map, low_map); + + if (pert && ext) { + if (!merge_roots[cnode].empty()) { + int cn = merge_roots[cnode].back(); + + if (low_map[order_list[cn - order_list.size()]] < rorder) { + Arc arc = node_data[cn].first; + _kuratowski.set(arc, true); + + pred = cnode; + cnode = _graph.target(arc); + + continue; + } + } + wnode = znode = cnode; + return; + + } else if (pert) { + wnode = cnode; + + while (!external(cnode, rorder, child_lists, ancestor_map, low_map)) { + Arc arc = node_data[order_map[cnode]].first; + + if (_graph.target(arc) == pred) { + arc = arc_lists[arc].next; + } + _kuratowski.set(arc, true); + + Node next = _graph.target(arc); + pred = cnode; cnode = next; + } + + znode = cnode; + return; + + } else if (ext) { + znode = cnode; + + while (!pertinent(cnode, embed_arc, merge_roots)) { + Arc arc = node_data[order_map[cnode]].first; + + if (_graph.target(arc) == pred) { + arc = arc_lists[arc].next; + } + _kuratowski.set(arc, true); + + Node next = _graph.target(arc); + pred = cnode; cnode = next; + } + + wnode = cnode; + return; + + } else { + Arc arc = node_data[order_map[cnode]].first; + + if (_graph.target(arc) == pred) { + arc = arc_lists[arc].next; + } + _kuratowski.set(arc, true); + + Node next = _graph.target(arc); + pred = cnode; cnode = next; + } + + } + + } + + void orientComponent(Node root, int rn, OrderMap& order_map, + PredMap& pred_map, NodeData& node_data, + ArcLists& arc_lists, FlipMap& flip_map, + TypeMap& type_map) { + node_data[order_map[root]].first = node_data[rn].first; + type_map[root] = 1; + + std::vector st, qu; + + st.push_back(root); + while (!st.empty()) { + Node node = st.back(); + st.pop_back(); + qu.push_back(node); + + Arc arc = node_data[order_map[node]].first; + + if (type_map[_graph.target(arc)] == 0) { + st.push_back(_graph.target(arc)); + type_map[_graph.target(arc)] = 1; + } + + Arc last = arc, pred = arc; + arc = arc_lists[arc].next; + while (arc != last) { + + if (type_map[_graph.target(arc)] == 0) { + st.push_back(_graph.target(arc)); + type_map[_graph.target(arc)] = 1; + } + + Arc next = arc_lists[arc].next != pred ? + arc_lists[arc].next : arc_lists[arc].prev; + pred = arc; arc = next; + } + + } + + type_map[root] = 2; + flip_map[root] = false; + + for (int i = 1; i < int(qu.size()); ++i) { + + Node node = qu[i]; + + while (type_map[node] != 2) { + st.push_back(node); + type_map[node] = 2; + node = _graph.source(pred_map[node]); + } + + bool flip = flip_map[node]; + + while (!st.empty()) { + node = st.back(); + st.pop_back(); + + flip_map[node] = flip != flip_map[node]; + flip = flip_map[node]; + + if (flip) { + Arc arc = node_data[order_map[node]].first; + std::swap(arc_lists[arc].prev, arc_lists[arc].next); + arc = arc_lists[arc].prev; + std::swap(arc_lists[arc].prev, arc_lists[arc].next); + node_data[order_map[node]].first = arc; + } + } + } + + for (int i = 0; i < int(qu.size()); ++i) { + + Arc arc = node_data[order_map[qu[i]]].first; + Arc last = arc, pred = arc; + + arc = arc_lists[arc].next; + while (arc != last) { + + if (arc_lists[arc].next == pred) { + std::swap(arc_lists[arc].next, arc_lists[arc].prev); + } + pred = arc; arc = arc_lists[arc].next; + } + + } + } + + void setFaceFlags(Node root, Node wnode, Node ynode, Node xnode, + OrderMap& order_map, NodeData& node_data, + TypeMap& type_map) { + Node node = _graph.target(node_data[order_map[root]].first); + + while (node != ynode) { + type_map[node] = HIGHY; + node = _graph.target(node_data[order_map[node]].first); + } + + while (node != wnode) { + type_map[node] = LOWY; + node = _graph.target(node_data[order_map[node]].first); + } + + node = _graph.target(node_data[order_map[wnode]].first); + + while (node != xnode) { + type_map[node] = LOWX; + node = _graph.target(node_data[order_map[node]].first); + } + type_map[node] = LOWX; + + node = _graph.target(node_data[order_map[xnode]].first); + while (node != root) { + type_map[node] = HIGHX; + node = _graph.target(node_data[order_map[node]].first); + } + + type_map[wnode] = PERTINENT; + type_map[root] = ROOT; + } + + void findInternalPath(std::vector& ipath, + Node wnode, Node root, TypeMap& type_map, + OrderMap& order_map, NodeData& node_data, + ArcLists& arc_lists) { + std::vector st; + + Node node = wnode; + + while (node != root) { + Arc arc = arc_lists[node_data[order_map[node]].first].next; + st.push_back(arc); + node = _graph.target(arc); + } + + while (true) { + Arc arc = st.back(); + if (type_map[_graph.target(arc)] == LOWX || + type_map[_graph.target(arc)] == HIGHX) { + break; + } + if (type_map[_graph.target(arc)] == 2) { + type_map[_graph.target(arc)] = 3; + + arc = arc_lists[_graph.oppositeArc(arc)].next; + st.push_back(arc); + } else { + st.pop_back(); + arc = arc_lists[arc].next; + + while (_graph.oppositeArc(arc) == st.back()) { + arc = st.back(); + st.pop_back(); + arc = arc_lists[arc].next; + } + st.push_back(arc); + } + } + + for (int i = 0; i < int(st.size()); ++i) { + if (type_map[_graph.target(st[i])] != LOWY && + type_map[_graph.target(st[i])] != HIGHY) { + for (; i < int(st.size()); ++i) { + ipath.push_back(st[i]); + } + } + } + } + + void setInternalFlags(std::vector& ipath, TypeMap& type_map) { + for (int i = 1; i < int(ipath.size()); ++i) { + type_map[_graph.source(ipath[i])] = INTERNAL; + } + } + + void findPilePath(std::vector& ppath, + Node root, TypeMap& type_map, OrderMap& order_map, + NodeData& node_data, ArcLists& arc_lists) { + std::vector st; + + st.push_back(_graph.oppositeArc(node_data[order_map[root]].first)); + st.push_back(node_data[order_map[root]].first); + + while (st.size() > 1) { + Arc arc = st.back(); + if (type_map[_graph.target(arc)] == INTERNAL) { + break; + } + if (type_map[_graph.target(arc)] == 3) { + type_map[_graph.target(arc)] = 4; + + arc = arc_lists[_graph.oppositeArc(arc)].next; + st.push_back(arc); + } else { + st.pop_back(); + arc = arc_lists[arc].next; + + while (!st.empty() && _graph.oppositeArc(arc) == st.back()) { + arc = st.back(); + st.pop_back(); + arc = arc_lists[arc].next; + } + st.push_back(arc); + } + } + + for (int i = 1; i < int(st.size()); ++i) { + ppath.push_back(st[i]); + } + } + + + int markExternalPath(Node node, OrderMap& order_map, + ChildLists& child_lists, PredMap& pred_map, + AncestorMap& ancestor_map, LowMap& low_map) { + int lp = lowPoint(node, order_map, child_lists, + ancestor_map, low_map); + + if (ancestor_map[node] != lp) { + node = child_lists[node].first; + _kuratowski[pred_map[node]] = true; + + while (ancestor_map[node] != lp) { + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + Node tnode = _graph.target(e); + if (order_map[tnode] > order_map[node] && low_map[tnode] == lp) { + node = tnode; + _kuratowski[e] = true; + break; + } + } + } + } + + for (OutArcIt e(_graph, node); e != INVALID; ++e) { + if (order_map[_graph.target(e)] == lp) { + _kuratowski[e] = true; + break; + } + } + + return lp; + } + + void markPertinentPath(Node node, OrderMap& order_map, + NodeData& node_data, ArcLists& arc_lists, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + while (embed_arc[node] == INVALID) { + int n = merge_roots[node].front(); + Arc arc = node_data[n].first; + + _kuratowski.set(arc, true); + + Node pred = node; + node = _graph.target(arc); + while (!pertinent(node, embed_arc, merge_roots)) { + arc = node_data[order_map[node]].first; + if (_graph.target(arc) == pred) { + arc = arc_lists[arc].next; + } + _kuratowski.set(arc, true); + pred = node; + node = _graph.target(arc); + } + } + _kuratowski.set(embed_arc[node], true); + } + + void markPredPath(Node node, Node snode, PredMap& pred_map) { + while (node != snode) { + _kuratowski.set(pred_map[node], true); + node = _graph.source(pred_map[node]); + } + } + + void markFacePath(Node ynode, Node xnode, + OrderMap& order_map, NodeData& node_data) { + Arc arc = node_data[order_map[ynode]].first; + Node node = _graph.target(arc); + _kuratowski.set(arc, true); + + while (node != xnode) { + arc = node_data[order_map[node]].first; + _kuratowski.set(arc, true); + node = _graph.target(arc); + } + } + + void markInternalPath(std::vector& path) { + for (int i = 0; i < int(path.size()); ++i) { + _kuratowski.set(path[i], true); + } + } + + void markPilePath(std::vector& path) { + for (int i = 0; i < int(path.size()); ++i) { + _kuratowski.set(path[i], true); + } + } + + void isolateKuratowski(Arc arc, NodeData& node_data, + ArcLists& arc_lists, FlipMap& flip_map, + OrderMap& order_map, OrderList& order_list, + PredMap& pred_map, ChildLists& child_lists, + AncestorMap& ancestor_map, LowMap& low_map, + EmbedArc& embed_arc, MergeRoots& merge_roots) { + + Node root = _graph.source(arc); + Node enode = _graph.target(arc); + + int rorder = order_map[root]; + + TypeMap type_map(_graph, 0); + + int rn = findComponentRoot(root, enode, child_lists, + order_map, order_list); + + Node xnode = order_list[node_data[rn].next]; + Node ynode = order_list[node_data[rn].prev]; + + // Minor-A + { + while (!merge_roots[xnode].empty() || !merge_roots[ynode].empty()) { + + if (!merge_roots[xnode].empty()) { + root = xnode; + rn = merge_roots[xnode].front(); + } else { + root = ynode; + rn = merge_roots[ynode].front(); + } + + xnode = order_list[node_data[rn].next]; + ynode = order_list[node_data[rn].prev]; + } + + if (root != _graph.source(arc)) { + orientComponent(root, rn, order_map, pred_map, + node_data, arc_lists, flip_map, type_map); + markFacePath(root, root, order_map, node_data); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + Node lwnode = findPertinent(ynode, order_map, node_data, + embed_arc, merge_roots); + + markPertinentPath(lwnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + + return; + } + } + + orientComponent(root, rn, order_map, pred_map, + node_data, arc_lists, flip_map, type_map); + + Node wnode = findPertinent(ynode, order_map, node_data, + embed_arc, merge_roots); + setFaceFlags(root, wnode, ynode, xnode, order_map, node_data, type_map); + + + //Minor-B + if (!merge_roots[wnode].empty()) { + int cn = merge_roots[wnode].back(); + Node rep = order_list[cn - order_list.size()]; + if (low_map[rep] < rorder) { + markFacePath(root, root, order_map, node_data); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + + Node lwnode, lznode; + markCommonPath(wnode, rorder, lwnode, lznode, order_list, + order_map, node_data, arc_lists, embed_arc, + merge_roots, child_lists, ancestor_map, low_map); + + markPertinentPath(lwnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + int zlp = markExternalPath(lznode, order_map, child_lists, + pred_map, ancestor_map, low_map); + + int minlp = xlp < ylp ? xlp : ylp; + if (zlp < minlp) minlp = zlp; + + int maxlp = xlp > ylp ? xlp : ylp; + if (zlp > maxlp) maxlp = zlp; + + markPredPath(order_list[maxlp], order_list[minlp], pred_map); + + return; + } + } + + Node pxnode, pynode; + std::vector ipath; + findInternalPath(ipath, wnode, root, type_map, order_map, + node_data, arc_lists); + setInternalFlags(ipath, type_map); + pynode = _graph.source(ipath.front()); + pxnode = _graph.target(ipath.back()); + + wnode = findPertinent(pynode, order_map, node_data, + embed_arc, merge_roots); + + // Minor-C + { + if (type_map[_graph.source(ipath.front())] == HIGHY) { + if (type_map[_graph.target(ipath.back())] == HIGHX) { + markFacePath(xnode, pxnode, order_map, node_data); + } + markFacePath(root, xnode, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markInternalPath(ipath); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + return; + } + + if (type_map[_graph.target(ipath.back())] == HIGHX) { + markFacePath(ynode, root, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markInternalPath(ipath); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + return; + } + } + + std::vector ppath; + findPilePath(ppath, root, type_map, order_map, node_data, arc_lists); + + // Minor-D + if (!ppath.empty()) { + markFacePath(ynode, xnode, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markPilePath(ppath); + markInternalPath(ipath); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + return; + } + + // Minor-E* + { + + if (!external(wnode, rorder, child_lists, ancestor_map, low_map)) { + Node znode = findExternal(pynode, rorder, order_map, + child_lists, ancestor_map, + low_map, node_data); + + if (type_map[znode] == LOWY) { + markFacePath(root, xnode, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markInternalPath(ipath); + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int zlp = markExternalPath(znode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[xlp < zlp ? xlp : zlp], pred_map); + } else { + markFacePath(ynode, root, order_map, node_data); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + markInternalPath(ipath); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int zlp = markExternalPath(znode, order_map, child_lists, + pred_map, ancestor_map, low_map); + markPredPath(root, order_list[ylp < zlp ? ylp : zlp], pred_map); + } + return; + } + + int xlp = markExternalPath(xnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int ylp = markExternalPath(ynode, order_map, child_lists, + pred_map, ancestor_map, low_map); + int wlp = markExternalPath(wnode, order_map, child_lists, + pred_map, ancestor_map, low_map); + + if (wlp > xlp && wlp > ylp) { + markFacePath(root, root, order_map, node_data); + markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); + return; + } + + markInternalPath(ipath); + markPertinentPath(wnode, order_map, node_data, arc_lists, + embed_arc, merge_roots); + + if (xlp > ylp && xlp > wlp) { + markFacePath(root, pynode, order_map, node_data); + markFacePath(wnode, xnode, order_map, node_data); + markPredPath(root, order_list[ylp < wlp ? ylp : wlp], pred_map); + return; + } + + if (ylp > xlp && ylp > wlp) { + markFacePath(pxnode, root, order_map, node_data); + markFacePath(ynode, wnode, order_map, node_data); + markPredPath(root, order_list[xlp < wlp ? xlp : wlp], pred_map); + return; + } + + if (pynode != ynode) { + markFacePath(pxnode, wnode, order_map, node_data); + + int minlp = xlp < ylp ? xlp : ylp; + if (wlp < minlp) minlp = wlp; + + int maxlp = xlp > ylp ? xlp : ylp; + if (wlp > maxlp) maxlp = wlp; + + markPredPath(order_list[maxlp], order_list[minlp], pred_map); + return; + } + + if (pxnode != xnode) { + markFacePath(wnode, pynode, order_map, node_data); + + int minlp = xlp < ylp ? xlp : ylp; + if (wlp < minlp) minlp = wlp; + + int maxlp = xlp > ylp ? xlp : ylp; + if (wlp > maxlp) maxlp = wlp; + + markPredPath(order_list[maxlp], order_list[minlp], pred_map); + return; + } + + markFacePath(root, root, order_map, node_data); + int minlp = xlp < ylp ? xlp : ylp; + if (wlp < minlp) minlp = wlp; + markPredPath(root, order_list[minlp], pred_map); + return; + } + + } + + }; + + namespace _planarity_bits { + + template + void makeConnected(Graph& graph, EmbeddingMap& embedding) { + DfsVisitor null_visitor; + DfsVisit > dfs(graph, null_visitor); + dfs.init(); + + typename Graph::Node u = INVALID; + for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { + if (!dfs.reached(n)) { + dfs.addSource(n); + dfs.start(); + if (u == INVALID) { + u = n; + } else { + typename Graph::Node v = n; + + typename Graph::Arc ue = typename Graph::OutArcIt(graph, u); + typename Graph::Arc ve = typename Graph::OutArcIt(graph, v); + + typename Graph::Arc e = graph.direct(graph.addEdge(u, v), true); + + if (ue != INVALID) { + embedding[e] = embedding[ue]; + embedding[ue] = e; + } else { + embedding[e] = e; + } + + if (ve != INVALID) { + embedding[graph.oppositeArc(e)] = embedding[ve]; + embedding[ve] = graph.oppositeArc(e); + } else { + embedding[graph.oppositeArc(e)] = graph.oppositeArc(e); + } + } + } + } + } + + template + void makeBiNodeConnected(Graph& graph, EmbeddingMap& embedding) { + typename Graph::template ArcMap processed(graph); + + std::vector arcs; + for (typename Graph::ArcIt e(graph); e != INVALID; ++e) { + arcs.push_back(e); + } + + IterableBoolMap visited(graph, false); + + for (int i = 0; i < int(arcs.size()); ++i) { + typename Graph::Arc pp = arcs[i]; + if (processed[pp]) continue; + + typename Graph::Arc e = embedding[graph.oppositeArc(pp)]; + processed[e] = true; + visited.set(graph.source(e), true); + + typename Graph::Arc p = e, l = e; + e = embedding[graph.oppositeArc(e)]; + + while (e != l) { + processed[e] = true; + + if (visited[graph.source(e)]) { + + typename Graph::Arc n = + graph.direct(graph.addEdge(graph.source(p), + graph.target(e)), true); + embedding[n] = p; + embedding[graph.oppositeArc(pp)] = n; + + embedding[graph.oppositeArc(n)] = + embedding[graph.oppositeArc(e)]; + embedding[graph.oppositeArc(e)] = + graph.oppositeArc(n); + + p = n; + e = embedding[graph.oppositeArc(n)]; + } else { + visited.set(graph.source(e), true); + pp = p; + p = e; + e = embedding[graph.oppositeArc(e)]; + } + } + visited.setAll(false); + } + } + + + template + void makeMaxPlanar(Graph& graph, EmbeddingMap& embedding) { + + typename Graph::template NodeMap degree(graph); + + for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { + degree[n] = countIncEdges(graph, n); + } + + typename Graph::template ArcMap processed(graph); + IterableBoolMap visited(graph, false); + + std::vector arcs; + for (typename Graph::ArcIt e(graph); e != INVALID; ++e) { + arcs.push_back(e); + } + + for (int i = 0; i < int(arcs.size()); ++i) { + typename Graph::Arc e = arcs[i]; + + if (processed[e]) continue; + processed[e] = true; + + typename Graph::Arc mine = e; + int mind = degree[graph.source(e)]; + + int face_size = 1; + + typename Graph::Arc l = e; + e = embedding[graph.oppositeArc(e)]; + while (l != e) { + processed[e] = true; + + ++face_size; + + if (degree[graph.source(e)] < mind) { + mine = e; + mind = degree[graph.source(e)]; + } + + e = embedding[graph.oppositeArc(e)]; + } + + if (face_size < 4) { + continue; + } + + typename Graph::Node s = graph.source(mine); + for (typename Graph::OutArcIt e(graph, s); e != INVALID; ++e) { + visited.set(graph.target(e), true); + } + + typename Graph::Arc oppe = INVALID; + + e = embedding[graph.oppositeArc(mine)]; + e = embedding[graph.oppositeArc(e)]; + while (graph.target(e) != s) { + if (visited[graph.source(e)]) { + oppe = e; + break; + } + e = embedding[graph.oppositeArc(e)]; + } + visited.setAll(false); + + if (oppe == INVALID) { + + e = embedding[graph.oppositeArc(mine)]; + typename Graph::Arc pn = mine, p = e; + + e = embedding[graph.oppositeArc(e)]; + while (graph.target(e) != s) { + typename Graph::Arc n = + graph.direct(graph.addEdge(s, graph.source(e)), true); + + embedding[n] = pn; + embedding[graph.oppositeArc(n)] = e; + embedding[graph.oppositeArc(p)] = graph.oppositeArc(n); + + pn = n; + + p = e; + e = embedding[graph.oppositeArc(e)]; + } + + embedding[graph.oppositeArc(e)] = pn; + + } else { + + mine = embedding[graph.oppositeArc(mine)]; + s = graph.source(mine); + oppe = embedding[graph.oppositeArc(oppe)]; + typename Graph::Node t = graph.source(oppe); + + typename Graph::Arc ce = graph.direct(graph.addEdge(s, t), true); + embedding[ce] = mine; + embedding[graph.oppositeArc(ce)] = oppe; + + typename Graph::Arc pn = ce, p = oppe; + e = embedding[graph.oppositeArc(oppe)]; + while (graph.target(e) != s) { + typename Graph::Arc n = + graph.direct(graph.addEdge(s, graph.source(e)), true); + + embedding[n] = pn; + embedding[graph.oppositeArc(n)] = e; + embedding[graph.oppositeArc(p)] = graph.oppositeArc(n); + + pn = n; + + p = e; + e = embedding[graph.oppositeArc(e)]; + + } + embedding[graph.oppositeArc(e)] = pn; + + pn = graph.oppositeArc(ce), p = mine; + e = embedding[graph.oppositeArc(mine)]; + while (graph.target(e) != t) { + typename Graph::Arc n = + graph.direct(graph.addEdge(t, graph.source(e)), true); + + embedding[n] = pn; + embedding[graph.oppositeArc(n)] = e; + embedding[graph.oppositeArc(p)] = graph.oppositeArc(n); + + pn = n; + + p = e; + e = embedding[graph.oppositeArc(e)]; + + } + embedding[graph.oppositeArc(e)] = pn; + } + } + } + + } + + /// \ingroup planar + /// + /// \brief Schnyder's planar drawing algorithm + /// + /// The planar drawing algorithm calculates positions for the nodes + /// in the plane. These coordinates satisfy that if the edges are + /// represented with straight lines, then they will not intersect + /// each other. + /// + /// Scnyder's algorithm embeds the graph on an \c (n-2)x(n-2) size grid, + /// i.e. each node will be located in the \c [0..n-2]x[0..n-2] square. + /// The time complexity of the algorithm is O(n). + /// + /// \see PlanarEmbedding + template + class PlanarDrawing { + public: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + /// \brief The point type for storing coordinates + typedef dim2::Point Point; + /// \brief The map type for storing the coordinates of the nodes + typedef typename Graph::template NodeMap PointMap; + + + /// \brief Constructor + /// + /// Constructor + /// \pre The graph must be simple, i.e. it should not + /// contain parallel or loop arcs. + PlanarDrawing(const Graph& graph) + : _graph(graph), _point_map(graph) {} + + private: + + template + void drawing(const AuxGraph& graph, + const AuxEmbeddingMap& next, + PointMap& point_map) { + TEMPLATE_GRAPH_TYPEDEFS(AuxGraph); + + typename AuxGraph::template ArcMap prev(graph); + + for (NodeIt n(graph); n != INVALID; ++n) { + Arc e = OutArcIt(graph, n); + + Arc p = e, l = e; + + e = next[e]; + while (e != l) { + prev[e] = p; + p = e; + e = next[e]; + } + prev[e] = p; + } + + Node anode, bnode, cnode; + + { + Arc e = ArcIt(graph); + anode = graph.source(e); + bnode = graph.target(e); + cnode = graph.target(next[graph.oppositeArc(e)]); + } + + IterableBoolMap proper(graph, false); + typename AuxGraph::template NodeMap conn(graph, -1); + + conn[anode] = conn[bnode] = -2; + { + for (OutArcIt e(graph, anode); e != INVALID; ++e) { + Node m = graph.target(e); + if (conn[m] == -1) { + conn[m] = 1; + } + } + conn[cnode] = 2; + + for (OutArcIt e(graph, bnode); e != INVALID; ++e) { + Node m = graph.target(e); + if (conn[m] == -1) { + conn[m] = 1; + } else if (conn[m] != -2) { + conn[m] += 1; + Arc pe = graph.oppositeArc(e); + if (conn[graph.target(next[pe])] == -2) { + conn[m] -= 1; + } + if (conn[graph.target(prev[pe])] == -2) { + conn[m] -= 1; + } + + proper.set(m, conn[m] == 1); + } + } + } + + + typename AuxGraph::template ArcMap angle(graph, -1); + + while (proper.trueNum() != 0) { + Node n = typename IterableBoolMap::TrueIt(proper); + proper.set(n, false); + conn[n] = -2; + + for (OutArcIt e(graph, n); e != INVALID; ++e) { + Node m = graph.target(e); + if (conn[m] == -1) { + conn[m] = 1; + } else if (conn[m] != -2) { + conn[m] += 1; + Arc pe = graph.oppositeArc(e); + if (conn[graph.target(next[pe])] == -2) { + conn[m] -= 1; + } + if (conn[graph.target(prev[pe])] == -2) { + conn[m] -= 1; + } + + proper.set(m, conn[m] == 1); + } + } + + { + Arc e = OutArcIt(graph, n); + Arc p = e, l = e; + + e = next[e]; + while (e != l) { + + if (conn[graph.target(e)] == -2 && conn[graph.target(p)] == -2) { + Arc f = e; + angle[f] = 0; + f = next[graph.oppositeArc(f)]; + angle[f] = 1; + f = next[graph.oppositeArc(f)]; + angle[f] = 2; + } + + p = e; + e = next[e]; + } + + if (conn[graph.target(e)] == -2 && conn[graph.target(p)] == -2) { + Arc f = e; + angle[f] = 0; + f = next[graph.oppositeArc(f)]; + angle[f] = 1; + f = next[graph.oppositeArc(f)]; + angle[f] = 2; + } + } + } + + typename AuxGraph::template NodeMap apred(graph, INVALID); + typename AuxGraph::template NodeMap bpred(graph, INVALID); + typename AuxGraph::template NodeMap cpred(graph, INVALID); + + typename AuxGraph::template NodeMap apredid(graph, -1); + typename AuxGraph::template NodeMap bpredid(graph, -1); + typename AuxGraph::template NodeMap cpredid(graph, -1); + + for (ArcIt e(graph); e != INVALID; ++e) { + if (angle[e] == angle[next[e]]) { + switch (angle[e]) { + case 2: + apred[graph.target(e)] = graph.source(e); + apredid[graph.target(e)] = graph.id(graph.source(e)); + break; + case 1: + bpred[graph.target(e)] = graph.source(e); + bpredid[graph.target(e)] = graph.id(graph.source(e)); + break; + case 0: + cpred[graph.target(e)] = graph.source(e); + cpredid[graph.target(e)] = graph.id(graph.source(e)); + break; + } + } + } + + cpred[anode] = INVALID; + cpred[bnode] = INVALID; + + std::vector aorder, border, corder; + + { + typename AuxGraph::template NodeMap processed(graph, false); + std::vector st; + for (NodeIt n(graph); n != INVALID; ++n) { + if (!processed[n] && n != bnode && n != cnode) { + st.push_back(n); + processed[n] = true; + Node m = apred[n]; + while (m != INVALID && !processed[m]) { + st.push_back(m); + processed[m] = true; + m = apred[m]; + } + while (!st.empty()) { + aorder.push_back(st.back()); + st.pop_back(); + } + } + } + } + + { + typename AuxGraph::template NodeMap processed(graph, false); + std::vector st; + for (NodeIt n(graph); n != INVALID; ++n) { + if (!processed[n] && n != cnode && n != anode) { + st.push_back(n); + processed[n] = true; + Node m = bpred[n]; + while (m != INVALID && !processed[m]) { + st.push_back(m); + processed[m] = true; + m = bpred[m]; + } + while (!st.empty()) { + border.push_back(st.back()); + st.pop_back(); + } + } + } + } + + { + typename AuxGraph::template NodeMap processed(graph, false); + std::vector st; + for (NodeIt n(graph); n != INVALID; ++n) { + if (!processed[n] && n != anode && n != bnode) { + st.push_back(n); + processed[n] = true; + Node m = cpred[n]; + while (m != INVALID && !processed[m]) { + st.push_back(m); + processed[m] = true; + m = cpred[m]; + } + while (!st.empty()) { + corder.push_back(st.back()); + st.pop_back(); + } + } + } + } + + typename AuxGraph::template NodeMap atree(graph, 0); + for (int i = aorder.size() - 1; i >= 0; --i) { + Node n = aorder[i]; + atree[n] = 1; + for (OutArcIt e(graph, n); e != INVALID; ++e) { + if (apred[graph.target(e)] == n) { + atree[n] += atree[graph.target(e)]; + } + } + } + + typename AuxGraph::template NodeMap btree(graph, 0); + for (int i = border.size() - 1; i >= 0; --i) { + Node n = border[i]; + btree[n] = 1; + for (OutArcIt e(graph, n); e != INVALID; ++e) { + if (bpred[graph.target(e)] == n) { + btree[n] += btree[graph.target(e)]; + } + } + } + + typename AuxGraph::template NodeMap apath(graph, 0); + apath[bnode] = apath[cnode] = 1; + typename AuxGraph::template NodeMap apath_btree(graph, 0); + apath_btree[bnode] = btree[bnode]; + for (int i = 1; i < int(aorder.size()); ++i) { + Node n = aorder[i]; + apath[n] = apath[apred[n]] + 1; + apath_btree[n] = btree[n] + apath_btree[apred[n]]; + } + + typename AuxGraph::template NodeMap bpath_atree(graph, 0); + bpath_atree[anode] = atree[anode]; + for (int i = 1; i < int(border.size()); ++i) { + Node n = border[i]; + bpath_atree[n] = atree[n] + bpath_atree[bpred[n]]; + } + + typename AuxGraph::template NodeMap cpath(graph, 0); + cpath[anode] = cpath[bnode] = 1; + typename AuxGraph::template NodeMap cpath_atree(graph, 0); + cpath_atree[anode] = atree[anode]; + typename AuxGraph::template NodeMap cpath_btree(graph, 0); + cpath_btree[bnode] = btree[bnode]; + for (int i = 1; i < int(corder.size()); ++i) { + Node n = corder[i]; + cpath[n] = cpath[cpred[n]] + 1; + cpath_atree[n] = atree[n] + cpath_atree[cpred[n]]; + cpath_btree[n] = btree[n] + cpath_btree[cpred[n]]; + } + + typename AuxGraph::template NodeMap third(graph); + for (NodeIt n(graph); n != INVALID; ++n) { + point_map[n].x = + bpath_atree[n] + cpath_atree[n] - atree[n] - cpath[n] + 1; + point_map[n].y = + cpath_btree[n] + apath_btree[n] - btree[n] - apath[n] + 1; + } + + } + + public: + + /// \brief Calculate the node positions + /// + /// This function calculates the node positions on the plane. + /// \return \c true if the graph is planar. + bool run() { + PlanarEmbedding pe(_graph); + if (!pe.run()) return false; + + run(pe); + return true; + } + + /// \brief Calculate the node positions according to a + /// combinatorical embedding + /// + /// This function calculates the node positions on the plane. + /// The given \c embedding map should contain a valid combinatorical + /// embedding, i.e. a valid cyclic order of the arcs. + /// It can be computed using PlanarEmbedding. + template + void run(const EmbeddingMap& embedding) { + typedef SmartEdgeSet AuxGraph; + + if (3 * countNodes(_graph) - 6 == countEdges(_graph)) { + drawing(_graph, embedding, _point_map); + return; + } + + AuxGraph aux_graph(_graph); + typename AuxGraph::template ArcMap + aux_embedding(aux_graph); + + { + + typename Graph::template EdgeMap + ref(_graph); + + for (EdgeIt e(_graph); e != INVALID; ++e) { + ref[e] = aux_graph.addEdge(_graph.u(e), _graph.v(e)); + } + + for (EdgeIt e(_graph); e != INVALID; ++e) { + Arc ee = embedding[_graph.direct(e, true)]; + aux_embedding[aux_graph.direct(ref[e], true)] = + aux_graph.direct(ref[ee], _graph.direction(ee)); + ee = embedding[_graph.direct(e, false)]; + aux_embedding[aux_graph.direct(ref[e], false)] = + aux_graph.direct(ref[ee], _graph.direction(ee)); + } + } + _planarity_bits::makeConnected(aux_graph, aux_embedding); + _planarity_bits::makeBiNodeConnected(aux_graph, aux_embedding); + _planarity_bits::makeMaxPlanar(aux_graph, aux_embedding); + drawing(aux_graph, aux_embedding, _point_map); + } + + /// \brief The coordinate of the given node + /// + /// This function returns the coordinate of the given node. + Point operator[](const Node& node) const { + return _point_map[node]; + } + + /// \brief Return the grid embedding in a node map + /// + /// This function returns the grid embedding in a node map of + /// \c dim2::Point coordinates. + const PointMap& coords() const { + return _point_map; + } + + private: + + const Graph& _graph; + PointMap _point_map; + + }; + + namespace _planarity_bits { + + template + class KempeFilter { + public: + typedef typename ColorMap::Key Key; + typedef bool Value; + + KempeFilter(const ColorMap& color_map, + const typename ColorMap::Value& first, + const typename ColorMap::Value& second) + : _color_map(color_map), _first(first), _second(second) {} + + Value operator[](const Key& key) const { + return _color_map[key] == _first || _color_map[key] == _second; + } + + private: + const ColorMap& _color_map; + typename ColorMap::Value _first, _second; + }; + } + + /// \ingroup planar + /// + /// \brief Coloring planar graphs + /// + /// The graph coloring problem is the coloring of the graph nodes + /// so that there are no adjacent nodes with the same color. The + /// planar graphs can always be colored with four colors, which is + /// proved by Appel and Haken. Their proofs provide a quadratic + /// time algorithm for four coloring, but it could not be used to + /// implement an efficient algorithm. The five and six coloring can be + /// made in linear time, but in this class, the five coloring has + /// quadratic worst case time complexity. The two coloring (if + /// possible) is solvable with a graph search algorithm and it is + /// implemented in \ref bipartitePartitions() function in LEMON. To + /// decide whether a planar graph is three colorable is NP-complete. + /// + /// This class contains member functions for calculate colorings + /// with five and six colors. The six coloring algorithm is a simple + /// greedy coloring on the backward minimum outgoing order of nodes. + /// This order can be computed by selecting the node with least + /// outgoing arcs to unprocessed nodes in each phase. This order + /// guarantees that when a node is chosen for coloring it has at + /// most five already colored adjacents. The five coloring algorithm + /// use the same method, but if the greedy approach fails to color + /// with five colors, i.e. the node has five already different + /// colored neighbours, it swaps the colors in one of the connected + /// two colored sets with the Kempe recoloring method. + template + class PlanarColoring { + public: + + TEMPLATE_GRAPH_TYPEDEFS(Graph); + + /// \brief The map type for storing color indices + typedef typename Graph::template NodeMap IndexMap; + /// \brief The map type for storing colors + /// + /// The map type for storing colors. + /// \see Palette, Color + typedef ComposeMap ColorMap; + + /// \brief Constructor + /// + /// Constructor. + /// \pre The graph must be simple, i.e. it should not + /// contain parallel or loop arcs. + PlanarColoring(const Graph& graph) + : _graph(graph), _color_map(graph), _palette(0) { + _palette.add(Color(1,0,0)); + _palette.add(Color(0,1,0)); + _palette.add(Color(0,0,1)); + _palette.add(Color(1,1,0)); + _palette.add(Color(1,0,1)); + _palette.add(Color(0,1,1)); + } + + /// \brief Return the node map of color indices + /// + /// This function returns the node map of color indices. The values are + /// in the range \c [0..4] or \c [0..5] according to the coloring method. + IndexMap colorIndexMap() const { + return _color_map; + } + + /// \brief Return the node map of colors + /// + /// This function returns the node map of colors. The values are among + /// five or six distinct \ref lemon::Color "colors". + ColorMap colorMap() const { + return composeMap(_palette, _color_map); + } + + /// \brief Return the color index of the node + /// + /// This function returns the color index of the given node. The value is + /// in the range \c [0..4] or \c [0..5] according to the coloring method. + int colorIndex(const Node& node) const { + return _color_map[node]; + } + + /// \brief Return the color of the node + /// + /// This function returns the color of the given node. The value is among + /// five or six distinct \ref lemon::Color "colors". + Color color(const Node& node) const { + return _palette[_color_map[node]]; + } + + + /// \brief Calculate a coloring with at most six colors + /// + /// This function calculates a coloring with at most six colors. The time + /// complexity of this variant is linear in the size of the graph. + /// \return \c true if the algorithm could color the graph with six colors. + /// If the algorithm fails, then the graph is not planar. + /// \note This function can return \c true if the graph is not + /// planar, but it can be colored with at most six colors. + bool runSixColoring() { + + typename Graph::template NodeMap heap_index(_graph, -1); + BucketHeap > heap(heap_index); + + for (NodeIt n(_graph); n != INVALID; ++n) { + _color_map[n] = -2; + heap.push(n, countOutArcs(_graph, n)); + } + + std::vector order; + + while (!heap.empty()) { + Node n = heap.top(); + heap.pop(); + _color_map[n] = -1; + order.push_back(n); + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node t = _graph.runningNode(e); + if (_color_map[t] == -2) { + heap.decrease(t, heap[t] - 1); + } + } + } + + for (int i = order.size() - 1; i >= 0; --i) { + std::vector forbidden(6, false); + for (OutArcIt e(_graph, order[i]); e != INVALID; ++e) { + Node t = _graph.runningNode(e); + if (_color_map[t] != -1) { + forbidden[_color_map[t]] = true; + } + } + for (int k = 0; k < 6; ++k) { + if (!forbidden[k]) { + _color_map[order[i]] = k; + break; + } + } + if (_color_map[order[i]] == -1) { + return false; + } + } + return true; + } + + private: + + bool recolor(const Node& u, const Node& v) { + int ucolor = _color_map[u]; + int vcolor = _color_map[v]; + typedef _planarity_bits::KempeFilter KempeFilter; + KempeFilter filter(_color_map, ucolor, vcolor); + + typedef FilterNodes KempeGraph; + KempeGraph kempe_graph(_graph, filter); + + std::vector comp; + Bfs bfs(kempe_graph); + bfs.init(); + bfs.addSource(u); + while (!bfs.emptyQueue()) { + Node n = bfs.nextNode(); + if (n == v) return false; + comp.push_back(n); + bfs.processNextNode(); + } + + int scolor = ucolor + vcolor; + for (int i = 0; i < static_cast(comp.size()); ++i) { + _color_map[comp[i]] = scolor - _color_map[comp[i]]; + } + + return true; + } + + template + void kempeRecoloring(const Node& node, const EmbeddingMap& embedding) { + std::vector nodes; + nodes.reserve(4); + + for (Arc e = OutArcIt(_graph, node); e != INVALID; e = embedding[e]) { + Node t = _graph.target(e); + if (_color_map[t] != -1) { + nodes.push_back(t); + if (nodes.size() == 4) break; + } + } + + int color = _color_map[nodes[0]]; + if (recolor(nodes[0], nodes[2])) { + _color_map[node] = color; + } else { + color = _color_map[nodes[1]]; + recolor(nodes[1], nodes[3]); + _color_map[node] = color; + } + } + + public: + + /// \brief Calculate a coloring with at most five colors + /// + /// This function calculates a coloring with at most five + /// colors. The worst case time complexity of this variant is + /// quadratic in the size of the graph. + /// \param embedding This map should contain a valid combinatorical + /// embedding, i.e. a valid cyclic order of the arcs. + /// It can be computed using PlanarEmbedding. + template + void runFiveColoring(const EmbeddingMap& embedding) { + + typename Graph::template NodeMap heap_index(_graph, -1); + BucketHeap > heap(heap_index); + + for (NodeIt n(_graph); n != INVALID; ++n) { + _color_map[n] = -2; + heap.push(n, countOutArcs(_graph, n)); + } + + std::vector order; + + while (!heap.empty()) { + Node n = heap.top(); + heap.pop(); + _color_map[n] = -1; + order.push_back(n); + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Node t = _graph.runningNode(e); + if (_color_map[t] == -2) { + heap.decrease(t, heap[t] - 1); + } + } + } + + for (int i = order.size() - 1; i >= 0; --i) { + std::vector forbidden(5, false); + for (OutArcIt e(_graph, order[i]); e != INVALID; ++e) { + Node t = _graph.runningNode(e); + if (_color_map[t] != -1) { + forbidden[_color_map[t]] = true; + } + } + for (int k = 0; k < 5; ++k) { + if (!forbidden[k]) { + _color_map[order[i]] = k; + break; + } + } + if (_color_map[order[i]] == -1) { + kempeRecoloring(order[i], embedding); + } + } + } + + /// \brief Calculate a coloring with at most five colors + /// + /// This function calculates a coloring with at most five + /// colors. The worst case time complexity of this variant is + /// quadratic in the size of the graph. + /// \return \c true if the graph is planar. + bool runFiveColoring() { + PlanarEmbedding pe(_graph); + if (!pe.run()) return false; + + runFiveColoring(pe.embeddingMap()); + return true; + } + + private: + + const Graph& _graph; + IndexMap _color_map; + Palette _palette; + }; + +} + +#endif diff --git a/lemon/preflow.h b/lemon/preflow.h --- a/lemon/preflow.h +++ b/lemon/preflow.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -52,7 +52,11 @@ /// /// The type of the map that stores the flow values. /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. +#ifdef DOXYGEN + typedef GR::ArcMap FlowMap; +#else typedef typename Digraph::template ArcMap FlowMap; +#endif /// \brief Instantiates a FlowMap. /// @@ -67,9 +71,12 @@ /// /// The elevator type used by Preflow algorithm. /// - /// \sa Elevator - /// \sa LinkedElevator - typedef LinkedElevator Elevator; + /// \sa Elevator, LinkedElevator +#ifdef DOXYGEN + typedef lemon::Elevator Elevator; +#else + typedef lemon::Elevator Elevator; +#endif /// \brief Instantiates an Elevator. /// @@ -95,9 +102,10 @@ /// /// This class provides an implementation of Goldberg-Tarjan's \e preflow /// \e push-relabel algorithm producing a \ref max_flow - /// "flow of maximum value" in a digraph. + /// "flow of maximum value" in a digraph \ref clrs01algorithms, + /// \ref amo93networkflows, \ref goldberg88newapproach. /// The preflow algorithms are the fastest known maximum - /// flow algorithms. The current implementation use a mixture of the + /// flow algorithms. The current implementation uses a mixture of the /// \e "highest label" and the \e "bound decrease" heuristics. /// The worst case time complexity of the algorithm is \f$O(n^2\sqrt{e})\f$. /// @@ -105,9 +113,17 @@ /// the maximum flow value and the minimum cut is obtained. The /// second phase constructs a feasible maximum flow on each arc. /// + /// \warning This implementation cannot handle infinite or very large + /// capacities (e.g. the maximum value of \c CAP::Value). + /// /// \tparam GR The type of the digraph the algorithm runs on. /// \tparam CAP The type of the capacity map. The default map /// type is \ref concepts::Digraph::ArcMap "GR::ArcMap". + /// \tparam TR The traits class that defines various types used by the + /// algorithm. By default, it is \ref PreflowDefaultTraits + /// "PreflowDefaultTraits". + /// In most cases, this parameter should not be set directly, + /// consider to use the named template parameters instead. #ifdef DOXYGEN template #else @@ -257,7 +273,7 @@ /// The Elevator should have standard constructor interface to be /// able to automatically created by the algorithm (i.e. the /// digraph and the maximum level should be passed to it). - /// However an external elevator object could also be passed to the + /// However, an external elevator object could also be passed to the /// algorithm with the \ref elevator(Elevator&) "elevator()" function /// before calling \ref run() or \ref init(). /// \sa SetElevator @@ -371,9 +387,10 @@ return *_level; } - /// \brief Sets the tolerance used by algorithm. + /// \brief Sets the tolerance used by the algorithm. /// - /// Sets the tolerance used by algorithm. + /// Sets the tolerance object used by the algorithm. + /// \return (*this) Preflow& tolerance(const Tolerance& tolerance) { _tolerance = tolerance; return *this; @@ -381,7 +398,8 @@ /// \brief Returns a const reference to the tolerance. /// - /// Returns a const reference to the tolerance. + /// Returns a const reference to the tolerance object used by + /// the algorithm. const Tolerance& tolerance() const { return _tolerance; } @@ -389,8 +407,8 @@ /// \name Execution Control /// The simplest way to execute the preflow algorithm is to use /// \ref run() or \ref runMinCut().\n - /// If you need more control on the initial solution or the execution, - /// first you have to call one of the \ref init() functions, then + /// If you need better control on the initial solution or the execution, + /// you have to call one of the \ref init() functions first, then /// \ref startFirstPhase() and if you need it \ref startSecondPhase(). ///@{ diff --git a/lemon/quad_heap.h b/lemon/quad_heap.h new file mode 100644 --- /dev/null +++ b/lemon/quad_heap.h @@ -0,0 +1,343 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_QUAD_HEAP_H +#define LEMON_QUAD_HEAP_H + +///\ingroup heaps +///\file +///\brief Fourary (quaternary) heap implementation. + +#include +#include +#include + +namespace lemon { + + /// \ingroup heaps + /// + ///\brief Fourary (quaternary) heap data structure. + /// + /// This class implements the \e Fourary (\e quaternary) \e heap + /// data structure. + /// It fully conforms to the \ref concepts::Heap "heap concept". + /// + /// The fourary heap is a specialization of the \ref DHeap "D-ary heap" + /// for D=4. It is similar to the \ref BinHeap "binary heap", + /// but its nodes have at most four children, instead of two. + /// + /// \tparam PR Type of the priorities of the items. + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. + /// \tparam CMP A functor class for comparing the priorities. + /// The default is \c std::less. + /// + ///\sa BinHeap + ///\sa DHeap +#ifdef DOXYGEN + template +#else + template > +#endif + class QuadHeap { + public: + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. + typedef PR Prio; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; + /// Type of the item-priority pairs. + typedef std::pair Pair; + /// Functor type for comparing the priorities. + typedef CMP Compare; + + /// \brief Type to represent the states of the items. + /// + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the + /// heap's point of view, but may be useful to the user. + /// + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. + enum State { + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. + }; + + private: + std::vector _data; + Compare _comp; + ItemIntMap &_iim; + + public: + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + explicit QuadHeap(ItemIntMap &map) : _iim(map) {} + + /// \brief Constructor. + /// + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param comp The function object used for comparing the priorities. + QuadHeap(ItemIntMap &map, const Compare &comp) + : _iim(map), _comp(comp) {} + + /// \brief The number of items stored in the heap. + /// + /// This function returns the number of items stored in the heap. + int size() const { return _data.size(); } + + /// \brief Check if the heap is empty. + /// + /// This function returns \c true if the heap is empty. + bool empty() const { return _data.empty(); } + + /// \brief Make the heap empty. + /// + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + void clear() { _data.clear(); } + + private: + static int parent(int i) { return (i-1)/4; } + static int firstChild(int i) { return 4*i+1; } + + bool less(const Pair &p1, const Pair &p2) const { + return _comp(p1.second, p2.second); + } + + void bubbleUp(int hole, Pair p) { + int par = parent(hole); + while( hole>0 && less(p,_data[par]) ) { + move(_data[par],hole); + hole = par; + par = parent(hole); + } + move(p, hole); + } + + void bubbleDown(int hole, Pair p, int length) { + if( length>1 ) { + int child = firstChild(hole); + while( child+30) bubbleDown(0, _data[n], n); + _data.pop_back(); + } + + /// \brief Remove the given item from the heap. + /// + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. + void erase(const Item &i) { + int h = _iim[i]; + int n = _data.size()-1; + _iim.set(_data[h].first, POST_HEAP); + if( h=0) s=0; + return State(s); + } + + /// \brief Set the state of an item in the heap. + /// + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. + /// \param i The item. + /// \param st The state. It should not be \c IN_HEAP. + void state(const Item& i, State st) { + switch (st) { + case POST_HEAP: + case PRE_HEAP: + if (state(i) == IN_HEAP) erase(i); + _iim[i] = st; + break; + case IN_HEAP: + break; + } + } + + /// \brief Replace an item in the heap. + /// + /// This function replaces item \c i with item \c j. + /// Item \c i must be in the heap, while \c j must be out of the heap. + /// After calling this method, item \c i will be out of the + /// heap and \c j will be in the heap with the same prioriority + /// as item \c i had before. + void replace(const Item& i, const Item& j) { + int idx = _iim[i]; + _iim.set(i, _iim[j]); + _iim.set(j, idx); + _data[idx].first = j; + } + + }; // class QuadHeap + +} // namespace lemon + +#endif // LEMON_FOURARY_HEAP_H diff --git a/lemon/radix_heap.h b/lemon/radix_heap.h --- a/lemon/radix_heap.h +++ b/lemon/radix_heap.h @@ -19,9 +19,9 @@ #ifndef LEMON_RADIX_HEAP_H #define LEMON_RADIX_HEAP_H -///\ingroup auxdat +///\ingroup heaps ///\file -///\brief Radix Heap implementation. +///\brief Radix heap implementation. #include #include @@ -29,56 +29,54 @@ namespace lemon { - /// \ingroup auxdata + /// \ingroup heaps /// - /// \brief A Radix Heap implementation. + /// \brief Radix heap data structure. /// - /// This class implements the \e radix \e heap data structure. A \e heap - /// is a data structure for storing items with specified values called \e - /// priorities in such a way that finding the item with minimum priority is - /// efficient. This heap type can store only items with \e int priority. - /// In a heap one can change the priority of an item, add or erase an - /// item, but the priority cannot be decreased under the last removed - /// item's priority. + /// This class implements the \e radix \e heap data structure. + /// It practically conforms to the \ref concepts::Heap "heap concept", + /// but it has some limitations due its special implementation. + /// The type of the priorities must be \c int and the priority of an + /// item cannot be decreased under the priority of the last removed item. /// - /// \param IM A read and writable Item int map, used internally - /// to handle the cross references. - /// - /// \see BinHeap - /// \see Dijkstra + /// \tparam IM A read-writable item map with \c int values, used + /// internally to handle the cross references. template class RadixHeap { public: - typedef typename IM::Key Item; + + /// Type of the item-int map. + typedef IM ItemIntMap; + /// Type of the priorities. typedef int Prio; - typedef IM ItemIntMap; + /// Type of the items stored in the heap. + typedef typename ItemIntMap::Key Item; /// \brief Exception thrown by RadixHeap. /// - /// This Exception is thrown when a smaller priority - /// is inserted into the \e RadixHeap then the last time erased. + /// This exception is thrown when an item is inserted into a + /// RadixHeap with a priority smaller than the last erased one. /// \see RadixHeap - - class UnderFlowPriorityError : public Exception { + class PriorityUnderflowError : public Exception { public: virtual const char* what() const throw() { - return "lemon::RadixHeap::UnderFlowPriorityError"; + return "lemon::RadixHeap::PriorityUnderflowError"; } }; - /// \brief Type to represent the items states. + /// \brief Type to represent the states of the items. /// - /// Each Item element have a state associated to it. It may be "in heap", - /// "pre heap" or "post heap". The latter two are indifferent from the + /// Each item has a state associated to it. It can be "in heap", + /// "pre-heap" or "post-heap". The latter two are indifferent from the /// heap's point of view, but may be useful to the user. /// - /// The ItemIntMap \e should be initialized in such way that it maps - /// PRE_HEAP (-1) to any element to be put in the heap... + /// The item-int map must be initialized in such way that it assigns + /// \c PRE_HEAP (-1) to any element to be put in the heap. enum State { - IN_HEAP = 0, - PRE_HEAP = -1, - POST_HEAP = -2 + IN_HEAP = 0, ///< = 0. + PRE_HEAP = -1, ///< = -1. + POST_HEAP = -2 ///< = -2. }; private: @@ -96,52 +94,55 @@ RadixBox(int _min, int _size) : first(-1), min(_min), size(_size) {} }; - std::vector data; - std::vector boxes; + std::vector _data; + std::vector _boxes; ItemIntMap &_iim; + public: - public: - /// \brief The constructor. + /// \brief Constructor. /// - /// The constructor. - /// - /// \param map It should be given to the constructor, since it is used - /// internally to handle the cross references. The value of the map - /// should be PRE_HEAP (-1) for each element. - /// - /// \param minimal The initial minimal value of the heap. - /// \param capacity It determines the initial capacity of the heap. - RadixHeap(ItemIntMap &map, int minimal = 0, int capacity = 0) - : _iim(map) { - boxes.push_back(RadixBox(minimal, 1)); - boxes.push_back(RadixBox(minimal + 1, 1)); - while (lower(boxes.size() - 1, capacity + minimal - 1)) { + /// Constructor. + /// \param map A map that assigns \c int values to the items. + /// It is used internally to handle the cross references. + /// The assigned value must be \c PRE_HEAP (-1) for each item. + /// \param minimum The initial minimum value of the heap. + /// \param capacity The initial capacity of the heap. + RadixHeap(ItemIntMap &map, int minimum = 0, int capacity = 0) + : _iim(map) + { + _boxes.push_back(RadixBox(minimum, 1)); + _boxes.push_back(RadixBox(minimum + 1, 1)); + while (lower(_boxes.size() - 1, capacity + minimum - 1)) { extend(); } } - /// The number of items stored in the heap. + /// \brief The number of items stored in the heap. /// - /// \brief Returns the number of items stored in the heap. - int size() const { return data.size(); } - /// \brief Checks if the heap stores no items. + /// This function returns the number of items stored in the heap. + int size() const { return _data.size(); } + + /// \brief Check if the heap is empty. /// - /// Returns \c true if and only if the heap stores no items. - bool empty() const { return data.empty(); } + /// This function returns \c true if the heap is empty. + bool empty() const { return _data.empty(); } - /// \brief Make empty this heap. + /// \brief Make the heap empty. /// - /// Make empty this heap. It does not change the cross reference - /// map. If you want to reuse a heap what is not surely empty you - /// should first clear the heap and after that you should set the - /// cross reference map for each item to \c PRE_HEAP. - void clear(int minimal = 0, int capacity = 0) { - data.clear(); boxes.clear(); - boxes.push_back(RadixBox(minimal, 1)); - boxes.push_back(RadixBox(minimal + 1, 1)); - while (lower(boxes.size() - 1, capacity + minimal - 1)) { + /// This functon makes the heap empty. + /// It does not change the cross reference map. If you want to reuse + /// a heap that is not surely empty, you should first clear it and + /// then you should set the cross reference map to \c PRE_HEAP + /// for each item. + /// \param minimum The minimum value of the heap. + /// \param capacity The capacity of the heap. + void clear(int minimum = 0, int capacity = 0) { + _data.clear(); _boxes.clear(); + _boxes.push_back(RadixBox(minimum, 1)); + _boxes.push_back(RadixBox(minimum + 1, 1)); + while (lower(_boxes.size() - 1, capacity + minimum - 1)) { extend(); } } @@ -149,255 +150,259 @@ private: bool upper(int box, Prio pr) { - return pr < boxes[box].min; + return pr < _boxes[box].min; } bool lower(int box, Prio pr) { - return pr >= boxes[box].min + boxes[box].size; + return pr >= _boxes[box].min + _boxes[box].size; } - /// \brief Remove item from the box list. + // Remove item from the box list void remove(int index) { - if (data[index].prev >= 0) { - data[data[index].prev].next = data[index].next; + if (_data[index].prev >= 0) { + _data[_data[index].prev].next = _data[index].next; } else { - boxes[data[index].box].first = data[index].next; + _boxes[_data[index].box].first = _data[index].next; } - if (data[index].next >= 0) { - data[data[index].next].prev = data[index].prev; + if (_data[index].next >= 0) { + _data[_data[index].next].prev = _data[index].prev; } } - /// \brief Insert item into the box list. + // Insert item into the box list void insert(int box, int index) { - if (boxes[box].first == -1) { - boxes[box].first = index; - data[index].next = data[index].prev = -1; + if (_boxes[box].first == -1) { + _boxes[box].first = index; + _data[index].next = _data[index].prev = -1; } else { - data[index].next = boxes[box].first; - data[boxes[box].first].prev = index; - data[index].prev = -1; - boxes[box].first = index; + _data[index].next = _boxes[box].first; + _data[_boxes[box].first].prev = index; + _data[index].prev = -1; + _boxes[box].first = index; } - data[index].box = box; + _data[index].box = box; } - /// \brief Add a new box to the box list. + // Add a new box to the box list void extend() { - int min = boxes.back().min + boxes.back().size; - int bs = 2 * boxes.back().size; - boxes.push_back(RadixBox(min, bs)); + int min = _boxes.back().min + _boxes.back().size; + int bs = 2 * _boxes.back().size; + _boxes.push_back(RadixBox(min, bs)); } - /// \brief Move an item up into the proper box. - void bubble_up(int index) { - if (!lower(data[index].box, data[index].prio)) return; + // Move an item up into the proper box. + void bubbleUp(int index) { + if (!lower(_data[index].box, _data[index].prio)) return; remove(index); - int box = findUp(data[index].box, data[index].prio); + int box = findUp(_data[index].box, _data[index].prio); insert(box, index); } - /// \brief Find up the proper box for the item with the given prio. + // Find up the proper box for the item with the given priority int findUp(int start, int pr) { while (lower(start, pr)) { - if (++start == int(boxes.size())) { + if (++start == int(_boxes.size())) { extend(); } } return start; } - /// \brief Move an item down into the proper box. - void bubble_down(int index) { - if (!upper(data[index].box, data[index].prio)) return; + // Move an item down into the proper box + void bubbleDown(int index) { + if (!upper(_data[index].box, _data[index].prio)) return; remove(index); - int box = findDown(data[index].box, data[index].prio); + int box = findDown(_data[index].box, _data[index].prio); insert(box, index); } - /// \brief Find up the proper box for the item with the given prio. + // Find down the proper box for the item with the given priority int findDown(int start, int pr) { while (upper(start, pr)) { - if (--start < 0) throw UnderFlowPriorityError(); + if (--start < 0) throw PriorityUnderflowError(); } return start; } - /// \brief Find the first not empty box. + // Find the first non-empty box int findFirst() { int first = 0; - while (boxes[first].first == -1) ++first; + while (_boxes[first].first == -1) ++first; return first; } - /// \brief Gives back the minimal prio of the box. + // Gives back the minimum priority of the given box int minValue(int box) { - int min = data[boxes[box].first].prio; - for (int k = boxes[box].first; k != -1; k = data[k].next) { - if (data[k].prio < min) min = data[k].prio; + int min = _data[_boxes[box].first].prio; + for (int k = _boxes[box].first; k != -1; k = _data[k].next) { + if (_data[k].prio < min) min = _data[k].prio; } return min; } - /// \brief Rearrange the items of the heap and makes the - /// first box not empty. + // Rearrange the items of the heap and make the first box non-empty void moveDown() { int box = findFirst(); if (box == 0) return; int min = minValue(box); for (int i = 0; i <= box; ++i) { - boxes[i].min = min; - min += boxes[i].size; + _boxes[i].min = min; + min += _boxes[i].size; } - int curr = boxes[box].first, next; + int curr = _boxes[box].first, next; while (curr != -1) { - next = data[curr].next; - bubble_down(curr); + next = _data[curr].next; + bubbleDown(curr); curr = next; } } - void relocate_last(int index) { - if (index != int(data.size()) - 1) { - data[index] = data.back(); - if (data[index].prev != -1) { - data[data[index].prev].next = index; + void relocateLast(int index) { + if (index != int(_data.size()) - 1) { + _data[index] = _data.back(); + if (_data[index].prev != -1) { + _data[_data[index].prev].next = index; } else { - boxes[data[index].box].first = index; + _boxes[_data[index].box].first = index; } - if (data[index].next != -1) { - data[data[index].next].prev = index; + if (_data[index].next != -1) { + _data[_data[index].next].prev = index; } - _iim[data[index].item] = index; + _iim[_data[index].item] = index; } - data.pop_back(); + _data.pop_back(); } public: /// \brief Insert an item into the heap with the given priority. /// - /// Adds \c i to the heap with priority \c p. + /// This function inserts the given item into the heap with the + /// given priority. /// \param i The item to insert. /// \param p The priority of the item. + /// \pre \e i must not be stored in the heap. + /// \warning This method may throw an \c UnderFlowPriorityException. void push(const Item &i, const Prio &p) { - int n = data.size(); + int n = _data.size(); _iim.set(i, n); - data.push_back(RadixItem(i, p)); - while (lower(boxes.size() - 1, p)) { + _data.push_back(RadixItem(i, p)); + while (lower(_boxes.size() - 1, p)) { extend(); } - int box = findDown(boxes.size() - 1, p); + int box = findDown(_boxes.size() - 1, p); insert(box, n); } - /// \brief Returns the item with minimum priority. + /// \brief Return the item having minimum priority. /// - /// This method returns the item with minimum priority. - /// \pre The heap must be nonempty. + /// This function returns the item having minimum priority. + /// \pre The heap must be non-empty. Item top() const { const_cast&>(*this).moveDown(); - return data[boxes[0].first].item; + return _data[_boxes[0].first].item; } - /// \brief Returns the minimum priority. + /// \brief The minimum priority. /// - /// It returns the minimum priority. - /// \pre The heap must be nonempty. + /// This function returns the minimum priority. + /// \pre The heap must be non-empty. Prio prio() const { const_cast&>(*this).moveDown(); - return data[boxes[0].first].prio; + return _data[_boxes[0].first].prio; } - /// \brief Deletes the item with minimum priority. + /// \brief Remove the item having minimum priority. /// - /// This method deletes the item with minimum priority. + /// This function removes the item having minimum priority. /// \pre The heap must be non-empty. void pop() { moveDown(); - int index = boxes[0].first; - _iim[data[index].item] = POST_HEAP; + int index = _boxes[0].first; + _iim[_data[index].item] = POST_HEAP; remove(index); - relocate_last(index); + relocateLast(index); } - /// \brief Deletes \c i from the heap. + /// \brief Remove the given item from the heap. /// - /// This method deletes item \c i from the heap, if \c i was - /// already stored in the heap. - /// \param i The item to erase. + /// This function removes the given item from the heap if it is + /// already stored. + /// \param i The item to delete. + /// \pre \e i must be in the heap. void erase(const Item &i) { int index = _iim[i]; _iim[i] = POST_HEAP; remove(index); - relocate_last(index); + relocateLast(index); } - /// \brief Returns the priority of \c i. + /// \brief The priority of the given item. /// - /// This function returns the priority of item \c i. - /// \pre \c i must be in the heap. + /// This function returns the priority of the given item. /// \param i The item. + /// \pre \e i must be in the heap. Prio operator[](const Item &i) const { int idx = _iim[i]; - return data[idx].prio; + return _data[idx].prio; } - /// \brief \c i gets to the heap with priority \c p independently - /// if \c i was already there. + /// \brief Set the priority of an item or insert it, if it is + /// not stored in the heap. /// - /// This method calls \ref push(\c i, \c p) if \c i is not stored - /// in the heap and sets the priority of \c i to \c p otherwise. - /// It may throw an \e UnderFlowPriorityException. + /// This method sets the priority of the given item if it is + /// already stored in the heap. Otherwise it inserts the given + /// item into the heap with the given priority. /// \param i The item. /// \param p The priority. + /// \pre \e i must be in the heap. + /// \warning This method may throw an \c UnderFlowPriorityException. void set(const Item &i, const Prio &p) { int idx = _iim[i]; if( idx < 0 ) { push(i, p); } - else if( p >= data[idx].prio ) { - data[idx].prio = p; - bubble_up(idx); + else if( p >= _data[idx].prio ) { + _data[idx].prio = p; + bubbleUp(idx); } else { - data[idx].prio = p; - bubble_down(idx); + _data[idx].prio = p; + bubbleDown(idx); } } - - /// \brief Decreases the priority of \c i to \c p. + /// \brief Decrease the priority of an item to the given value. /// - /// This method decreases the priority of item \c i to \c p. - /// \pre \c i must be stored in the heap with priority at least \c p, and - /// \c should be greater or equal to the last removed item's priority. + /// This function decreases the priority of an item to the given value. /// \param i The item. /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at least \e p. + /// \warning This method may throw an \c UnderFlowPriorityException. void decrease(const Item &i, const Prio &p) { int idx = _iim[i]; - data[idx].prio = p; - bubble_down(idx); + _data[idx].prio = p; + bubbleDown(idx); } - /// \brief Increases the priority of \c i to \c p. + /// \brief Increase the priority of an item to the given value. /// - /// This method sets the priority of item \c i to \c p. - /// \pre \c i must be stored in the heap with priority at most \c p + /// This function increases the priority of an item to the given value. /// \param i The item. /// \param p The priority. + /// \pre \e i must be stored in the heap with priority at most \e p. void increase(const Item &i, const Prio &p) { int idx = _iim[i]; - data[idx].prio = p; - bubble_up(idx); + _data[idx].prio = p; + bubbleUp(idx); } - /// \brief Returns if \c item is in, has already been in, or has - /// never been in the heap. + /// \brief Return the state of an item. /// - /// This method returns PRE_HEAP if \c item has never been in the - /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP - /// otherwise. In the latter case it is possible that \c item will - /// get back to the heap again. + /// This method returns \c PRE_HEAP if the given item has never + /// been in the heap, \c IN_HEAP if it is in the heap at the moment, + /// and \c POST_HEAP otherwise. + /// In the latter case it is possible that the item will get back + /// to the heap again. /// \param i The item. State state(const Item &i) const { int s = _iim[i]; @@ -405,11 +410,11 @@ return State(s); } - /// \brief Sets the state of the \c item in the heap. + /// \brief Set the state of an item in the heap. /// - /// Sets the state of the \c item in the heap. It can be used to - /// manually clear the heap when it is important to achive the - /// better time complexity. + /// This function sets the state of the given item in the heap. + /// It can be used to manually clear the heap when it is important + /// to achive better time complexity. /// \param i The item. /// \param st The state. It should not be \c IN_HEAP. void state(const Item& i, State st) { diff --git a/lemon/smart_graph.h b/lemon/smart_graph.h --- a/lemon/smart_graph.h +++ b/lemon/smart_graph.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -32,10 +32,7 @@ namespace lemon { class SmartDigraph; - ///Base of SmartDigraph - ///Base of SmartDigraph - /// class SmartDigraphBase { protected: @@ -187,28 +184,28 @@ /// ///\brief A smart directed graph class. /// - ///This is a simple and fast digraph implementation. - ///It is also quite memory efficient, but at the price - ///that it does support only limited (only stack-like) - ///node and arc deletions. - ///It fully conforms to the \ref concepts::Digraph "Digraph concept". + ///\ref SmartDigraph is a simple and fast digraph implementation. + ///It is also quite memory efficient but at the price + ///that it does not support node and arc deletion + ///(except for the Snapshot feature). /// - ///\sa concepts::Digraph. + ///This type fully conforms to the \ref concepts::Digraph "Digraph concept" + ///and it also provides some additional functionalities. + ///Most of its member functions and nested classes are documented + ///only in the concept class. + /// + ///This class provides constant time counting for nodes and arcs. + /// + ///\sa concepts::Digraph + ///\sa SmartGraph class SmartDigraph : public ExtendedSmartDigraphBase { typedef ExtendedSmartDigraphBase Parent; private: - - ///SmartDigraph is \e not copy constructible. Use DigraphCopy() instead. - - ///SmartDigraph is \e not copy constructible. Use DigraphCopy() instead. - /// + /// Digraphs are \e not copy constructible. Use DigraphCopy instead. SmartDigraph(const SmartDigraph &) : ExtendedSmartDigraphBase() {}; - ///\brief Assignment of SmartDigraph to another one is \e not allowed. - ///Use DigraphCopy() instead. - - ///Assignment of SmartDigraph to another one is \e not allowed. - ///Use DigraphCopy() instead. + /// \brief Assignment of a digraph to another one is \e not allowed. + /// Use DigraphCopy instead. void operator=(const SmartDigraph &) {} public: @@ -221,79 +218,49 @@ ///Add a new node to the digraph. - /// Add a new node to the digraph. - /// \return The new node. + ///This function adds a new node to the digraph. + ///\return The new node. Node addNode() { return Parent::addNode(); } ///Add a new arc to the digraph. - ///Add a new arc to the digraph with source node \c s + ///This function adds a new arc to the digraph with source node \c s ///and target node \c t. ///\return The new arc. - Arc addArc(const Node& s, const Node& t) { + Arc addArc(Node s, Node t) { return Parent::addArc(s, t); } - /// \brief Using this it is possible to avoid the superfluous memory - /// allocation. - - /// Using this it is possible to avoid the superfluous memory - /// allocation: if you know that the digraph you want to build will - /// be very large (e.g. it will contain millions of nodes and/or arcs) - /// then it is worth reserving space for this amount before starting - /// to build the digraph. - /// \sa reserveArc - void reserveNode(int n) { nodes.reserve(n); }; - - /// \brief Using this it is possible to avoid the superfluous memory - /// allocation. - - /// Using this it is possible to avoid the superfluous memory - /// allocation: if you know that the digraph you want to build will - /// be very large (e.g. it will contain millions of nodes and/or arcs) - /// then it is worth reserving space for this amount before starting - /// to build the digraph. - /// \sa reserveNode - void reserveArc(int m) { arcs.reserve(m); }; - /// \brief Node validity check /// - /// This function gives back true if the given node is valid, - /// ie. it is a real node of the graph. + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the digraph. /// /// \warning A removed node (using Snapshot) could become valid again - /// when new nodes are added to the graph. + /// if new nodes are added to the digraph. bool valid(Node n) const { return Parent::valid(n); } /// \brief Arc validity check /// - /// This function gives back true if the given arc is valid, - /// ie. it is a real arc of the graph. + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the digraph. /// /// \warning A removed arc (using Snapshot) could become valid again - /// when new arcs are added to the graph. + /// if new arcs are added to the graph. bool valid(Arc a) const { return Parent::valid(a); } - ///Clear the digraph. - - ///Erase all the nodes and arcs from the digraph. - /// - void clear() { - Parent::clear(); - } - ///Split a node. - ///This function splits a node. First a new node is added to the digraph, - ///then the source of each outgoing arc of \c n is moved to this new node. - ///If \c connect is \c true (this is the default value), then a new arc - ///from \c n to the newly created node is also added. + ///This function splits the given node. First, a new node is added + ///to the digraph, then the source of each outgoing arc of node \c n + ///is moved to this new node. + ///If the second parameter \c connect is \c true (this is the default + ///value), then a new arc from node \c n to the newly created node + ///is also added. ///\return The newly created node. /// - ///\note The Arcs - ///referencing a moved arc remain - ///valid. However InArc's and OutArc's - ///may be invalidated. + ///\note All iterators remain valid. + /// ///\warning This functionality cannot be used together with the Snapshot ///feature. Node split(Node n, bool connect = true) @@ -308,6 +275,34 @@ return b; } + ///Clear the digraph. + + ///This function erases all nodes and arcs from the digraph. + /// + void clear() { + Parent::clear(); + } + + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the digraph you want to build will + /// be large (e.g. it will contain millions of nodes and/or arcs), + /// then it is worth reserving space for this amount before starting + /// to build the digraph. + /// \sa reserveArc() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for arcs. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the digraph you want to build will + /// be large (e.g. it will contain millions of nodes and/or arcs), + /// then it is worth reserving space for this amount before starting + /// to build the digraph. + /// \sa reserveNode() + void reserveArc(int m) { arcs.reserve(m); }; + public: class Snapshot; @@ -332,20 +327,23 @@ public: - ///Class to make a snapshot of the digraph and to restrore to it later. + ///Class to make a snapshot of the digraph and to restore it later. - ///Class to make a snapshot of the digraph and to restrore to it later. + ///Class to make a snapshot of the digraph and to restore it later. /// ///The newly added nodes and arcs can be removed using the - ///restore() function. - ///\note After you restore a state, you cannot restore - ///a later state, in other word you cannot add again the arcs deleted - ///by restore() using another one Snapshot instance. + ///restore() function. This is the only way for deleting nodes and/or + ///arcs from a SmartDigraph structure. /// - ///\warning If you do not use correctly the snapshot that can cause - ///either broken program, invalid state of the digraph, valid but - ///not the restored digraph or no change. Because the runtime performance - ///the validity of the snapshot is not stored. + ///\note After a state is restored, you cannot restore a later state, + ///i.e. you cannot add the removed nodes and arcs again using + ///another Snapshot instance. + /// + ///\warning Node splitting cannot be restored. + ///\warning The validity of the snapshot is not stored due to + ///performance reasons. If you do not use the snapshot correctly, + ///it can cause broken program, invalid or not restored state of + ///the digraph or no change. class Snapshot { SmartDigraph *_graph; @@ -357,39 +355,32 @@ ///Default constructor. ///Default constructor. - ///To actually make a snapshot you must call save(). - /// + ///You have to call save() to actually make a snapshot. Snapshot() : _graph(0) {} ///Constructor that immediately makes a snapshot - ///This constructor immediately makes a snapshot of the digraph. - ///\param graph The digraph we make a snapshot of. - Snapshot(SmartDigraph &graph) : _graph(&graph) { + ///This constructor immediately makes a snapshot of the given digraph. + /// + Snapshot(SmartDigraph &gr) : _graph(&gr) { node_num=_graph->nodes.size(); arc_num=_graph->arcs.size(); } ///Make a snapshot. - ///Make a snapshot of the digraph. - /// - ///This function can be called more than once. In case of a repeated + ///This function makes a snapshot of the given digraph. + ///It can be called more than once. In case of a repeated ///call, the previous snapshot gets lost. - ///\param graph The digraph we make the snapshot of. - void save(SmartDigraph &graph) - { - _graph=&graph; + void save(SmartDigraph &gr) { + _graph=&gr; node_num=_graph->nodes.size(); arc_num=_graph->arcs.size(); } ///Undo the changes until a snapshot. - ///Undo the changes until a snapshot created by save(). - /// - ///\note After you restored a state, you cannot restore - ///a later state, in other word you cannot add again the arcs deleted - ///by restore(). + ///This function undos the changes until the last snapshot + ///created by save() or Snapshot(SmartDigraph&). void restore() { _graph->restoreSnapshot(*this); @@ -508,7 +499,7 @@ node._id = nodes.size() - 1; } - void next(Node& node) const { + static void next(Node& node) { --node._id; } @@ -516,7 +507,7 @@ arc._id = arcs.size() - 1; } - void next(Arc& arc) const { + static void next(Arc& arc) { --arc._id; } @@ -524,7 +515,7 @@ arc._id = arcs.size() / 2 - 1; } - void next(Edge& arc) const { + static void next(Edge& arc) { --arc._id; } @@ -621,29 +612,28 @@ /// /// \brief A smart undirected graph class. /// - /// This is a simple and fast graph implementation. - /// It is also quite memory efficient, but at the price - /// that it does support only limited (only stack-like) - /// node and arc deletions. - /// It fully conforms to the \ref concepts::Graph "Graph concept". + /// \ref SmartGraph is a simple and fast graph implementation. + /// It is also quite memory efficient but at the price + /// that it does not support node and edge deletion + /// (except for the Snapshot feature). /// - /// \sa concepts::Graph. + /// This type fully conforms to the \ref concepts::Graph "Graph concept" + /// and it also provides some additional functionalities. + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes, edges and arcs. + /// + /// \sa concepts::Graph + /// \sa SmartDigraph class SmartGraph : public ExtendedSmartGraphBase { typedef ExtendedSmartGraphBase Parent; private: - - ///SmartGraph is \e not copy constructible. Use GraphCopy() instead. - - ///SmartGraph is \e not copy constructible. Use GraphCopy() instead. - /// + /// Graphs are \e not copy constructible. Use GraphCopy instead. SmartGraph(const SmartGraph &) : ExtendedSmartGraphBase() {}; - - ///\brief Assignment of SmartGraph to another one is \e not allowed. - ///Use GraphCopy() instead. - - ///Assignment of SmartGraph to another one is \e not allowed. - ///Use GraphCopy() instead. + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use GraphCopy instead. void operator=(const SmartGraph &) {} public: @@ -654,56 +644,77 @@ /// SmartGraph() {} - ///Add a new node to the graph. - - /// Add a new node to the graph. + /// \brief Add a new node to the graph. + /// + /// This function adds a new node to the graph. /// \return The new node. Node addNode() { return Parent::addNode(); } - ///Add a new edge to the graph. - - ///Add a new edge to the graph with node \c s - ///and \c t. - ///\return The new edge. - Edge addEdge(const Node& s, const Node& t) { - return Parent::addEdge(s, t); + /// \brief Add a new edge to the graph. + /// + /// This function adds a new edge to the graph between nodes + /// \c u and \c v with inherent orientation from node \c u to + /// node \c v. + /// \return The new edge. + Edge addEdge(Node u, Node v) { + return Parent::addEdge(u, v); } /// \brief Node validity check /// - /// This function gives back true if the given node is valid, - /// ie. it is a real node of the graph. + /// This function gives back \c true if the given node is valid, + /// i.e. it is a real node of the graph. /// /// \warning A removed node (using Snapshot) could become valid again - /// when new nodes are added to the graph. + /// if new nodes are added to the graph. bool valid(Node n) const { return Parent::valid(n); } + /// \brief Edge validity check + /// + /// This function gives back \c true if the given edge is valid, + /// i.e. it is a real edge of the graph. + /// + /// \warning A removed edge (using Snapshot) could become valid again + /// if new edges are added to the graph. + bool valid(Edge e) const { return Parent::valid(e); } + /// \brief Arc validity check /// - /// This function gives back true if the given arc is valid, - /// ie. it is a real arc of the graph. + /// This function gives back \c true if the given arc is valid, + /// i.e. it is a real arc of the graph. /// /// \warning A removed arc (using Snapshot) could become valid again - /// when new edges are added to the graph. + /// if new edges are added to the graph. bool valid(Arc a) const { return Parent::valid(a); } - /// \brief Edge validity check - /// - /// This function gives back true if the given edge is valid, - /// ie. it is a real edge of the graph. - /// - /// \warning A removed edge (using Snapshot) could become valid again - /// when new edges are added to the graph. - bool valid(Edge e) const { return Parent::valid(e); } - ///Clear the graph. - ///Erase all the nodes and edges from the graph. + ///This function erases all nodes and arcs from the graph. /// void clear() { Parent::clear(); } + /// Reserve memory for nodes. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveEdge() + void reserveNode(int n) { nodes.reserve(n); }; + + /// Reserve memory for edges. + + /// Using this function, it is possible to avoid superfluous memory + /// allocation: if you know that the graph you want to build will + /// be large (e.g. it will contain millions of nodes and/or edges), + /// then it is worth reserving space for this amount before starting + /// to build the graph. + /// \sa reserveNode() + void reserveEdge(int m) { arcs.reserve(2 * m); }; + public: class Snapshot; @@ -742,21 +753,22 @@ public: - ///Class to make a snapshot of the digraph and to restrore to it later. + ///Class to make a snapshot of the graph and to restore it later. - ///Class to make a snapshot of the digraph and to restrore to it later. + ///Class to make a snapshot of the graph and to restore it later. /// - ///The newly added nodes and arcs can be removed using the - ///restore() function. + ///The newly added nodes and edges can be removed using the + ///restore() function. This is the only way for deleting nodes and/or + ///edges from a SmartGraph structure. /// - ///\note After you restore a state, you cannot restore - ///a later state, in other word you cannot add again the arcs deleted - ///by restore() using another one Snapshot instance. + ///\note After a state is restored, you cannot restore a later state, + ///i.e. you cannot add the removed nodes and edges again using + ///another Snapshot instance. /// - ///\warning If you do not use correctly the snapshot that can cause - ///either broken program, invalid state of the digraph, valid but - ///not the restored digraph or no change. Because the runtime performance - ///the validity of the snapshot is not stored. + ///\warning The validity of the snapshot is not stored due to + ///performance reasons. If you do not use the snapshot correctly, + ///it can cause broken program, invalid or not restored state of + ///the graph or no change. class Snapshot { SmartGraph *_graph; @@ -768,36 +780,30 @@ ///Default constructor. ///Default constructor. - ///To actually make a snapshot you must call save(). - /// + ///You have to call save() to actually make a snapshot. Snapshot() : _graph(0) {} ///Constructor that immediately makes a snapshot - ///This constructor immediately makes a snapshot of the digraph. - ///\param graph The digraph we make a snapshot of. - Snapshot(SmartGraph &graph) { - graph.saveSnapshot(*this); + /// This constructor immediately makes a snapshot of the given graph. + /// + Snapshot(SmartGraph &gr) { + gr.saveSnapshot(*this); } ///Make a snapshot. - ///Make a snapshot of the graph. - /// - ///This function can be called more than once. In case of a repeated + ///This function makes a snapshot of the given graph. + ///It can be called more than once. In case of a repeated ///call, the previous snapshot gets lost. - ///\param graph The digraph we make the snapshot of. - void save(SmartGraph &graph) + void save(SmartGraph &gr) { - graph.saveSnapshot(*this); + gr.saveSnapshot(*this); } - ///Undo the changes until a snapshot. + ///Undo the changes until the last snapshot. - ///Undo the changes until a snapshot created by save(). - /// - ///\note After you restored a state, you cannot restore - ///a later state, in other word you cannot add again the arcs deleted - ///by restore(). + ///This function undos the changes until the last snapshot + ///created by save() or Snapshot(SmartGraph&). void restore() { _graph->restoreSnapshot(*this); diff --git a/lemon/soplex.cc b/lemon/soplex.cc --- a/lemon/soplex.cc +++ b/lemon/soplex.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -91,6 +91,19 @@ return soplex->nRows() - 1; } + int SoplexLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) { + soplex::DSVector v; + for (ExprIterator it = b; it != e; ++it) { + v.add(it->first, it->second); + } + soplex::LPRow r(l, v, u); + soplex->addRow(r); + + _row_names.push_back(std::string()); + + return soplex->nRows() - 1; + } + void SoplexLp::_eraseCol(int i) { soplex->removeCol(i); @@ -274,7 +287,7 @@ SoplexLp::SolveExitStatus SoplexLp::_solve() { _clear_temporals(); - + _applyMessageLevel(); soplex::SPxSolver::Status status = soplex->solve(); diff --git a/lemon/soplex.h b/lemon/soplex.h --- a/lemon/soplex.h +++ b/lemon/soplex.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -84,6 +84,7 @@ virtual int _addCol(); virtual int _addRow(); + virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); virtual void _eraseCol(int i); virtual void _eraseRow(int i); diff --git a/lemon/static_graph.h b/lemon/static_graph.h new file mode 100644 --- /dev/null +++ b/lemon/static_graph.h @@ -0,0 +1,476 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef LEMON_STATIC_GRAPH_H +#define LEMON_STATIC_GRAPH_H + +///\ingroup graphs +///\file +///\brief StaticDigraph class. + +#include +#include + +namespace lemon { + + class StaticDigraphBase { + public: + + StaticDigraphBase() + : built(false), node_num(0), arc_num(0), + node_first_out(NULL), node_first_in(NULL), + arc_source(NULL), arc_target(NULL), + arc_next_in(NULL), arc_next_out(NULL) {} + + ~StaticDigraphBase() { + if (built) { + delete[] node_first_out; + delete[] node_first_in; + delete[] arc_source; + delete[] arc_target; + delete[] arc_next_out; + delete[] arc_next_in; + } + } + + class Node { + friend class StaticDigraphBase; + protected: + int id; + Node(int _id) : id(_id) {} + public: + Node() {} + Node (Invalid) : id(-1) {} + bool operator==(const Node& node) const { return id == node.id; } + bool operator!=(const Node& node) const { return id != node.id; } + bool operator<(const Node& node) const { return id < node.id; } + }; + + class Arc { + friend class StaticDigraphBase; + protected: + int id; + Arc(int _id) : id(_id) {} + public: + Arc() { } + Arc (Invalid) : id(-1) {} + bool operator==(const Arc& arc) const { return id == arc.id; } + bool operator!=(const Arc& arc) const { return id != arc.id; } + bool operator<(const Arc& arc) const { return id < arc.id; } + }; + + Node source(const Arc& e) const { return Node(arc_source[e.id]); } + Node target(const Arc& e) const { return Node(arc_target[e.id]); } + + void first(Node& n) const { n.id = node_num - 1; } + static void next(Node& n) { --n.id; } + + void first(Arc& e) const { e.id = arc_num - 1; } + static void next(Arc& e) { --e.id; } + + void firstOut(Arc& e, const Node& n) const { + e.id = node_first_out[n.id] != node_first_out[n.id + 1] ? + node_first_out[n.id] : -1; + } + void nextOut(Arc& e) const { e.id = arc_next_out[e.id]; } + + void firstIn(Arc& e, const Node& n) const { e.id = node_first_in[n.id]; } + void nextIn(Arc& e) const { e.id = arc_next_in[e.id]; } + + static int id(const Node& n) { return n.id; } + static Node nodeFromId(int id) { return Node(id); } + int maxNodeId() const { return node_num - 1; } + + static int id(const Arc& e) { return e.id; } + static Arc arcFromId(int id) { return Arc(id); } + int maxArcId() const { return arc_num - 1; } + + typedef True NodeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return node_num; } + int arcNum() const { return arc_num; } + + private: + + template + class ArcLess { + public: + typedef typename Digraph::Arc Arc; + + ArcLess(const Digraph &_graph, const NodeRefMap& _nodeRef) + : digraph(_graph), nodeRef(_nodeRef) {} + + bool operator()(const Arc& left, const Arc& right) const { + return nodeRef[digraph.target(left)] < nodeRef[digraph.target(right)]; + } + private: + const Digraph& digraph; + const NodeRefMap& nodeRef; + }; + + public: + + typedef True BuildTag; + + void clear() { + if (built) { + delete[] node_first_out; + delete[] node_first_in; + delete[] arc_source; + delete[] arc_target; + delete[] arc_next_out; + delete[] arc_next_in; + } + built = false; + node_num = 0; + arc_num = 0; + } + + template + void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) { + typedef typename Digraph::Node GNode; + typedef typename Digraph::Arc GArc; + + built = true; + + node_num = countNodes(digraph); + arc_num = countArcs(digraph); + + node_first_out = new int[node_num + 1]; + node_first_in = new int[node_num]; + + arc_source = new int[arc_num]; + arc_target = new int[arc_num]; + arc_next_out = new int[arc_num]; + arc_next_in = new int[arc_num]; + + int node_index = 0; + for (typename Digraph::NodeIt n(digraph); n != INVALID; ++n) { + nodeRef[n] = Node(node_index); + node_first_in[node_index] = -1; + ++node_index; + } + + ArcLess arcLess(digraph, nodeRef); + + int arc_index = 0; + for (typename Digraph::NodeIt n(digraph); n != INVALID; ++n) { + int source = nodeRef[n].id; + std::vector arcs; + for (typename Digraph::OutArcIt e(digraph, n); e != INVALID; ++e) { + arcs.push_back(e); + } + if (!arcs.empty()) { + node_first_out[source] = arc_index; + std::sort(arcs.begin(), arcs.end(), arcLess); + for (typename std::vector::iterator it = arcs.begin(); + it != arcs.end(); ++it) { + int target = nodeRef[digraph.target(*it)].id; + arcRef[*it] = Arc(arc_index); + arc_source[arc_index] = source; + arc_target[arc_index] = target; + arc_next_in[arc_index] = node_first_in[target]; + node_first_in[target] = arc_index; + arc_next_out[arc_index] = arc_index + 1; + ++arc_index; + } + arc_next_out[arc_index - 1] = -1; + } else { + node_first_out[source] = arc_index; + } + } + node_first_out[node_num] = arc_num; + } + + template + void build(int n, ArcListIterator first, ArcListIterator last) { + built = true; + + node_num = n; + arc_num = std::distance(first, last); + + node_first_out = new int[node_num + 1]; + node_first_in = new int[node_num]; + + arc_source = new int[arc_num]; + arc_target = new int[arc_num]; + arc_next_out = new int[arc_num]; + arc_next_in = new int[arc_num]; + + for (int i = 0; i != node_num; ++i) { + node_first_in[i] = -1; + } + + int arc_index = 0; + for (int i = 0; i != node_num; ++i) { + node_first_out[i] = arc_index; + for ( ; first != last && (*first).first == i; ++first) { + int j = (*first).second; + LEMON_ASSERT(j >= 0 && j < node_num, + "Wrong arc list for StaticDigraph::build()"); + arc_source[arc_index] = i; + arc_target[arc_index] = j; + arc_next_in[arc_index] = node_first_in[j]; + node_first_in[j] = arc_index; + arc_next_out[arc_index] = arc_index + 1; + ++arc_index; + } + if (arc_index > node_first_out[i]) + arc_next_out[arc_index - 1] = -1; + } + LEMON_ASSERT(first == last, + "Wrong arc list for StaticDigraph::build()"); + node_first_out[node_num] = arc_num; + } + + protected: + + void fastFirstOut(Arc& e, const Node& n) const { + e.id = node_first_out[n.id]; + } + + static void fastNextOut(Arc& e) { + ++e.id; + } + void fastLastOut(Arc& e, const Node& n) const { + e.id = node_first_out[n.id + 1]; + } + + protected: + bool built; + int node_num; + int arc_num; + int *node_first_out; + int *node_first_in; + int *arc_source; + int *arc_target; + int *arc_next_in; + int *arc_next_out; + }; + + typedef DigraphExtender ExtendedStaticDigraphBase; + + + /// \ingroup graphs + /// + /// \brief A static directed graph class. + /// + /// \ref StaticDigraph is a highly efficient digraph implementation, + /// but it is fully static. + /// It stores only two \c int values for each node and only four \c int + /// values for each arc. Moreover it provides faster item iteration than + /// \ref ListDigraph and \ref SmartDigraph, especially using \c OutArcIt + /// iterators, since its arcs are stored in an appropriate order. + /// However it only provides build() and clear() functions and does not + /// support any other modification of the digraph. + /// + /// Since this digraph structure is completely static, its nodes and arcs + /// can be indexed with integers from the ranges [0..nodeNum()-1] + /// and [0..arcNum()-1], respectively. + /// The index of an item is the same as its ID, it can be obtained + /// using the corresponding \ref index() or \ref concepts::Digraph::id() + /// "id()" function. A node or arc with a certain index can be obtained + /// using node() or arc(). + /// + /// This type fully conforms to the \ref concepts::Digraph "Digraph concept". + /// Most of its member functions and nested classes are documented + /// only in the concept class. + /// + /// This class provides constant time counting for nodes and arcs. + /// + /// \sa concepts::Digraph + class StaticDigraph : public ExtendedStaticDigraphBase { + public: + + typedef ExtendedStaticDigraphBase Parent; + + public: + + /// \brief Constructor + /// + /// Default constructor. + StaticDigraph() : Parent() {} + + /// \brief The node with the given index. + /// + /// This function returns the node with the given index. + /// \sa index() + static Node node(int ix) { return Parent::nodeFromId(ix); } + + /// \brief The arc with the given index. + /// + /// This function returns the arc with the given index. + /// \sa index() + static Arc arc(int ix) { return Parent::arcFromId(ix); } + + /// \brief The index of the given node. + /// + /// This function returns the index of the the given node. + /// \sa node() + static int index(Node node) { return Parent::id(node); } + + /// \brief The index of the given arc. + /// + /// This function returns the index of the the given arc. + /// \sa arc() + static int index(Arc arc) { return Parent::id(arc); } + + /// \brief Number of nodes. + /// + /// This function returns the number of nodes. + int nodeNum() const { return node_num; } + + /// \brief Number of arcs. + /// + /// This function returns the number of arcs. + int arcNum() const { return arc_num; } + + /// \brief Build the digraph copying another digraph. + /// + /// This function builds the digraph copying another digraph of any + /// kind. It can be called more than once, but in such case, the whole + /// structure and all maps will be cleared and rebuilt. + /// + /// This method also makes possible to copy a digraph to a StaticDigraph + /// structure using \ref DigraphCopy. + /// + /// \param digraph An existing digraph to be copied. + /// \param nodeRef The node references will be copied into this map. + /// Its key type must be \c Digraph::Node and its value type must be + /// \c StaticDigraph::Node. + /// It must conform to the \ref concepts::ReadWriteMap "ReadWriteMap" + /// concept. + /// \param arcRef The arc references will be copied into this map. + /// Its key type must be \c Digraph::Arc and its value type must be + /// \c StaticDigraph::Arc. + /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. + /// + /// \note If you do not need the arc references, then you could use + /// \ref NullMap for the last parameter. However the node references + /// are required by the function itself, thus they must be readable + /// from the map. + template + void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) { + if (built) Parent::clear(); + Parent::build(digraph, nodeRef, arcRef); + } + + /// \brief Build the digraph from an arc list. + /// + /// This function builds the digraph from the given arc list. + /// It can be called more than once, but in such case, the whole + /// structure and all maps will be cleared and rebuilt. + /// + /// The list of the arcs must be given in the range [begin, end) + /// specified by STL compatible itartors whose \c value_type must be + /// std::pair. + /// Each arc must be specified by a pair of integer indices + /// from the range [0..n-1]. The pairs must be in a + /// non-decreasing order with respect to their first values. + /// If the k-th pair in the list is (i,j), then + /// arc(k-1) will connect node(i) to node(j). + /// + /// \param n The number of nodes. + /// \param begin An iterator pointing to the beginning of the arc list. + /// \param end An iterator pointing to the end of the arc list. + /// + /// For example, a simple digraph can be constructed like this. + /// \code + /// std::vector > arcs; + /// arcs.push_back(std::make_pair(0,1)); + /// arcs.push_back(std::make_pair(0,2)); + /// arcs.push_back(std::make_pair(1,3)); + /// arcs.push_back(std::make_pair(1,2)); + /// arcs.push_back(std::make_pair(3,0)); + /// StaticDigraph gr; + /// gr.build(4, arcs.begin(), arcs.end()); + /// \endcode + template + void build(int n, ArcListIterator begin, ArcListIterator end) { + if (built) Parent::clear(); + StaticDigraphBase::build(n, begin, end); + notifier(Node()).build(); + notifier(Arc()).build(); + } + + /// \brief Clear the digraph. + /// + /// This function erases all nodes and arcs from the digraph. + void clear() { + Parent::clear(); + } + + protected: + + using Parent::fastFirstOut; + using Parent::fastNextOut; + using Parent::fastLastOut; + + public: + + class OutArcIt : public Arc { + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const StaticDigraph& digraph, const Node& node) { + digraph.fastFirstOut(*this, node); + digraph.fastLastOut(last, node); + if (last == *this) *this = INVALID; + } + + OutArcIt(const StaticDigraph& digraph, const Arc& arc) : Arc(arc) { + if (arc != INVALID) { + digraph.fastLastOut(last, digraph.source(arc)); + } + } + + OutArcIt& operator++() { + StaticDigraph::fastNextOut(*this); + if (last == *this) *this = INVALID; + return *this; + } + + private: + Arc last; + }; + + Node baseNode(const OutArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + + Node runningNode(const OutArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + + Node baseNode(const InArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + + Node runningNode(const InArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + + }; + +} + +#endif diff --git a/lemon/suurballe.h b/lemon/suurballe.h --- a/lemon/suurballe.h +++ b/lemon/suurballe.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -29,10 +29,54 @@ #include #include #include +#include #include namespace lemon { + /// \brief Default traits class of Suurballe algorithm. + /// + /// Default traits class of Suurballe algorithm. + /// \tparam GR The digraph type the algorithm runs on. + /// \tparam LEN The type of the length map. + /// The default value is GR::ArcMap. +#ifdef DOXYGEN + template +#else + template < typename GR, + typename LEN = typename GR::template ArcMap > +#endif + struct SuurballeDefaultTraits + { + /// The type of the digraph. + typedef GR Digraph; + /// The type of the length map. + typedef LEN LengthMap; + /// The type of the lengths. + typedef typename LEN::Value Length; + /// The type of the flow map. + typedef typename GR::template ArcMap FlowMap; + /// The type of the potential map. + typedef typename GR::template NodeMap PotentialMap; + + /// \brief The path type + /// + /// The type used for storing the found arc-disjoint paths. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + typedef lemon::Path Path; + + /// The cross reference type used for the heap. + typedef typename GR::template NodeMap HeapCrossRef; + + /// \brief The heap type used for internal Dijkstra computations. + /// + /// The type of the heap used for internal Dijkstra computations. + /// It must conform to the \ref lemon::concepts::Heap "Heap" concept + /// and its priority type must be \c Length. + typedef BinHeap Heap; + }; + /// \addtogroup shortest_path /// @{ @@ -46,7 +90,7 @@ /// Note that this problem is a special case of the \ref min_cost_flow /// "minimum cost flow problem". This implementation is actually an /// efficient specialized version of the \ref CapacityScaling - /// "Successive Shortest Path" algorithm directly for this problem. + /// "successive shortest path" algorithm directly for this problem. /// Therefore this class provides query functions for flow values and /// node potentials (the dual solution) just like the minimum cost flow /// algorithms. @@ -57,13 +101,14 @@ /// /// \warning Length values should be \e non-negative. /// - /// \note For finding node-disjoint paths this algorithm can be used + /// \note For finding \e node-disjoint paths, this algorithm can be used /// along with the \ref SplitNodes adaptor. #ifdef DOXYGEN - template + template #else template < typename GR, - typename LEN = typename GR::template ArcMap > + typename LEN = typename GR::template ArcMap, + typename TR = SuurballeDefaultTraits > #endif class Suurballe { @@ -74,26 +119,26 @@ public: - /// The type of the digraph the algorithm runs on. - typedef GR Digraph; + /// The type of the digraph. + typedef typename TR::Digraph Digraph; /// The type of the length map. - typedef LEN LengthMap; + typedef typename TR::LengthMap LengthMap; /// The type of the lengths. - typedef typename LengthMap::Value Length; -#ifdef DOXYGEN + typedef typename TR::Length Length; + /// The type of the flow map. - typedef GR::ArcMap FlowMap; + typedef typename TR::FlowMap FlowMap; /// The type of the potential map. - typedef GR::NodeMap PotentialMap; -#else - /// The type of the flow map. - typedef typename Digraph::template ArcMap FlowMap; - /// The type of the potential map. - typedef typename Digraph::template NodeMap PotentialMap; -#endif + typedef typename TR::PotentialMap PotentialMap; + /// The type of the path structures. + typedef typename TR::Path Path; + /// The cross reference type used for the heap. + typedef typename TR::HeapCrossRef HeapCrossRef; + /// The heap type used for internal Dijkstra computations. + typedef typename TR::Heap Heap; - /// The type of the path structures. - typedef SimplePath Path; + /// The \ref SuurballeDefaultTraits "traits class" of the algorithm. + typedef TR Traits; private: @@ -104,44 +149,38 @@ // distance of the nodes. class ResidualDijkstra { - typedef typename Digraph::template NodeMap HeapCrossRef; - typedef BinHeap Heap; + private: + + const Digraph &_graph; + const LengthMap &_length; + const FlowMap &_flow; + PotentialMap &_pi; + PredMap &_pred; + Node _s; + Node _t; + + PotentialMap _dist; + std::vector _proc_nodes; + + public: + + // Constructor + ResidualDijkstra(Suurballe &srb) : + _graph(srb._graph), _length(srb._length), + _flow(*srb._flow), _pi(*srb._potential), _pred(srb._pred), + _s(srb._s), _t(srb._t), _dist(_graph) {} + + // Run the algorithm and return true if a path is found + // from the source node to the target node. + bool run(int cnt) { + return cnt == 0 ? startFirst() : start(); + } private: - // The digraph the algorithm runs on - const Digraph &_graph; - - // The main maps - const FlowMap &_flow; - const LengthMap &_length; - PotentialMap &_potential; - - // The distance map - PotentialMap _dist; - // The pred arc map - PredMap &_pred; - // The processed (i.e. permanently labeled) nodes - std::vector _proc_nodes; - - Node _s; - Node _t; - - public: - - /// Constructor. - ResidualDijkstra( const Digraph &graph, - const FlowMap &flow, - const LengthMap &length, - PotentialMap &potential, - PredMap &pred, - Node s, Node t ) : - _graph(graph), _flow(flow), _length(length), _potential(potential), - _dist(graph), _pred(pred), _s(s), _t(t) {} - - /// \brief Run the algorithm. It returns \c true if a path is found - /// from the source node to the target node. - bool run() { + // Execute the algorithm for the first time (the flow and potential + // functions have to be identically zero). + bool startFirst() { HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP); Heap heap(heap_cross_ref); heap.push(_s, 0); @@ -151,29 +190,74 @@ // Process nodes while (!heap.empty() && heap.top() != _t) { Node u = heap.top(), v; - Length d = heap.prio() + _potential[u], nd; + Length d = heap.prio(), dn; _dist[u] = heap.prio(); + _proc_nodes.push_back(u); heap.pop(); + + // Traverse outgoing arcs + for (OutArcIt e(_graph, u); e != INVALID; ++e) { + v = _graph.target(e); + switch(heap.state(v)) { + case Heap::PRE_HEAP: + heap.push(v, d + _length[e]); + _pred[v] = e; + break; + case Heap::IN_HEAP: + dn = d + _length[e]; + if (dn < heap[v]) { + heap.decrease(v, dn); + _pred[v] = e; + } + break; + case Heap::POST_HEAP: + break; + } + } + } + if (heap.empty()) return false; + + // Update potentials of processed nodes + Length t_dist = heap.prio(); + for (int i = 0; i < int(_proc_nodes.size()); ++i) + _pi[_proc_nodes[i]] = _dist[_proc_nodes[i]] - t_dist; + return true; + } + + // Execute the algorithm. + bool start() { + HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP); + Heap heap(heap_cross_ref); + heap.push(_s, 0); + _pred[_s] = INVALID; + _proc_nodes.clear(); + + // Process nodes + while (!heap.empty() && heap.top() != _t) { + Node u = heap.top(), v; + Length d = heap.prio() + _pi[u], dn; + _dist[u] = heap.prio(); _proc_nodes.push_back(u); + heap.pop(); // Traverse outgoing arcs for (OutArcIt e(_graph, u); e != INVALID; ++e) { if (_flow[e] == 0) { v = _graph.target(e); switch(heap.state(v)) { - case Heap::PRE_HEAP: - heap.push(v, d + _length[e] - _potential[v]); - _pred[v] = e; - break; - case Heap::IN_HEAP: - nd = d + _length[e] - _potential[v]; - if (nd < heap[v]) { - heap.decrease(v, nd); + case Heap::PRE_HEAP: + heap.push(v, d + _length[e] - _pi[v]); _pred[v] = e; - } - break; - case Heap::POST_HEAP: - break; + break; + case Heap::IN_HEAP: + dn = d + _length[e] - _pi[v]; + if (dn < heap[v]) { + heap.decrease(v, dn); + _pred[v] = e; + } + break; + case Heap::POST_HEAP: + break; } } } @@ -183,19 +267,19 @@ if (_flow[e] == 1) { v = _graph.source(e); switch(heap.state(v)) { - case Heap::PRE_HEAP: - heap.push(v, d - _length[e] - _potential[v]); - _pred[v] = e; - break; - case Heap::IN_HEAP: - nd = d - _length[e] - _potential[v]; - if (nd < heap[v]) { - heap.decrease(v, nd); + case Heap::PRE_HEAP: + heap.push(v, d - _length[e] - _pi[v]); _pred[v] = e; - } - break; - case Heap::POST_HEAP: - break; + break; + case Heap::IN_HEAP: + dn = d - _length[e] - _pi[v]; + if (dn < heap[v]) { + heap.decrease(v, dn); + _pred[v] = e; + } + break; + case Heap::POST_HEAP: + break; } } } @@ -205,12 +289,89 @@ // Update potentials of processed nodes Length t_dist = heap.prio(); for (int i = 0; i < int(_proc_nodes.size()); ++i) - _potential[_proc_nodes[i]] += _dist[_proc_nodes[i]] - t_dist; + _pi[_proc_nodes[i]] += _dist[_proc_nodes[i]] - t_dist; return true; } }; //class ResidualDijkstra + public: + + /// \name Named Template Parameters + /// @{ + + template + struct SetFlowMapTraits : public Traits { + typedef T FlowMap; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c FlowMap type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c FlowMap type. + template + struct SetFlowMap + : public Suurballe > { + typedef Suurballe > Create; + }; + + template + struct SetPotentialMapTraits : public Traits { + typedef T PotentialMap; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c PotentialMap type. + /// + /// \ref named-templ-param "Named parameter" for setting + /// \c PotentialMap type. + template + struct SetPotentialMap + : public Suurballe > { + typedef Suurballe > Create; + }; + + template + struct SetPathTraits : public Traits { + typedef T Path; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c %Path type. + /// + /// \ref named-templ-param "Named parameter" for setting \c %Path type. + /// It must conform to the \ref lemon::concepts::Path "Path" concept + /// and it must have an \c addBack() function. + template + struct SetPath + : public Suurballe > { + typedef Suurballe > Create; + }; + + template + struct SetHeapTraits : public Traits { + typedef H Heap; + typedef CR HeapCrossRef; + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// \c Heap and \c HeapCrossRef types. + /// + /// \ref named-templ-param "Named parameter" for setting \c Heap + /// and \c HeapCrossRef types with automatic allocation. + /// They will be used for internal Dijkstra computations. + /// The heap type must conform to the \ref lemon::concepts::Heap "Heap" + /// concept and its priority type must be \c Length. + template > + struct SetHeap + : public Suurballe > { + typedef Suurballe > Create; + }; + + /// @} + private: // The digraph the algorithm runs on @@ -226,19 +387,25 @@ bool _local_potential; // The source node - Node _source; + Node _s; // The target node - Node _target; + Node _t; // Container to store the found paths - std::vector< SimplePath > paths; + std::vector _paths; int _path_num; // The pred arc map PredMap _pred; - // Implementation of the Dijkstra algorithm for finding augmenting - // shortest paths in the residual network - ResidualDijkstra *_dijkstra; + + // Data for full init + PotentialMap *_init_dist; + PredMap *_init_pred; + bool _full_init; + + protected: + + Suurballe() {} public: @@ -251,14 +418,16 @@ Suurballe( const Digraph &graph, const LengthMap &length ) : _graph(graph), _length(length), _flow(0), _local_flow(false), - _potential(0), _local_potential(false), _pred(graph) + _potential(0), _local_potential(false), _pred(graph), + _init_dist(0), _init_pred(0) {} /// Destructor. ~Suurballe() { if (_local_flow) delete _flow; if (_local_potential) delete _potential; - delete _dijkstra; + delete _init_dist; + delete _init_pred; } /// \brief Set the flow map. @@ -303,10 +472,13 @@ /// \name Execution Control /// The simplest way to execute the algorithm is to call the run() - /// function. - /// \n + /// function.\n + /// If you need to execute the algorithm many times using the same + /// source node, then you may call fullInit() once and start() + /// for each target node.\n /// If you only need the flow that is the union of the found - /// arc-disjoint paths, you may call init() and findFlow(). + /// arc-disjoint paths, then you may call findFlow() instead of + /// start(). /// @{ @@ -326,23 +498,21 @@ /// just a shortcut of the following code. /// \code /// s.init(s); - /// s.findFlow(t, k); - /// s.findPaths(); + /// s.start(t, k); /// \endcode int run(const Node& s, const Node& t, int k = 2) { init(s); - findFlow(t, k); - findPaths(); + start(t, k); return _path_num; } /// \brief Initialize the algorithm. /// - /// This function initializes the algorithm. + /// This function initializes the algorithm with the given source node. /// /// \param s The source node. void init(const Node& s) { - _source = s; + _s = s; // Initialize maps if (!_flow) { @@ -353,8 +523,63 @@ _potential = new PotentialMap(_graph); _local_potential = true; } - for (ArcIt e(_graph); e != INVALID; ++e) (*_flow)[e] = 0; - for (NodeIt n(_graph); n != INVALID; ++n) (*_potential)[n] = 0; + _full_init = false; + } + + /// \brief Initialize the algorithm and perform Dijkstra. + /// + /// This function initializes the algorithm and performs a full + /// Dijkstra search from the given source node. It makes consecutive + /// executions of \ref start() "start(t, k)" faster, since they + /// have to perform %Dijkstra only k-1 times. + /// + /// This initialization is usually worth using instead of \ref init() + /// if the algorithm is executed many times using the same source node. + /// + /// \param s The source node. + void fullInit(const Node& s) { + // Initialize maps + init(s); + if (!_init_dist) { + _init_dist = new PotentialMap(_graph); + } + if (!_init_pred) { + _init_pred = new PredMap(_graph); + } + + // Run a full Dijkstra + typename Dijkstra + ::template SetStandardHeap + ::template SetDistMap + ::template SetPredMap + ::Create dijk(_graph, _length); + dijk.distMap(*_init_dist).predMap(*_init_pred); + dijk.run(s); + + _full_init = true; + } + + /// \brief Execute the algorithm. + /// + /// This function executes the algorithm. + /// + /// \param t The target node. + /// \param k The number of paths to be found. + /// + /// \return \c k if there are at least \c k arc-disjoint paths from + /// \c s to \c t in the digraph. Otherwise it returns the number of + /// arc-disjoint paths found. + /// + /// \note Apart from the return value, s.start(t, k) is + /// just a shortcut of the following code. + /// \code + /// s.findFlow(t, k); + /// s.findPaths(); + /// \endcode + int start(const Node& t, int k = 2) { + findFlow(t, k); + findPaths(); + return _path_num; } /// \brief Execute the algorithm to find an optimal flow. @@ -372,20 +597,39 @@ /// /// \pre \ref init() must be called before using this function. int findFlow(const Node& t, int k = 2) { - _target = t; - _dijkstra = - new ResidualDijkstra( _graph, *_flow, _length, *_potential, _pred, - _source, _target ); + _t = t; + ResidualDijkstra dijkstra(*this); + + // Initialization + for (ArcIt e(_graph); e != INVALID; ++e) { + (*_flow)[e] = 0; + } + if (_full_init) { + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_potential)[n] = (*_init_dist)[n]; + } + Node u = _t; + Arc e; + while ((e = (*_init_pred)[u]) != INVALID) { + (*_flow)[e] = 1; + u = _graph.source(e); + } + _path_num = 1; + } else { + for (NodeIt n(_graph); n != INVALID; ++n) { + (*_potential)[n] = 0; + } + _path_num = 0; + } // Find shortest paths - _path_num = 0; while (_path_num < k) { // Run Dijkstra - if (!_dijkstra->run()) break; + if (!dijkstra.run(_path_num)) break; ++_path_num; // Set the flow along the found shortest path - Node u = _target; + Node u = _t; Arc e; while ((e = _pred[u]) != INVALID) { if (u == _graph.target(e)) { @@ -402,8 +646,8 @@ /// \brief Compute the paths from the flow. /// - /// This function computes the paths from the found minimum cost flow, - /// which is the union of some arc-disjoint paths. + /// This function computes arc-disjoint paths from the found minimum + /// cost flow, which is the union of them. /// /// \pre \ref init() and \ref findFlow() must be called before using /// this function. @@ -411,15 +655,15 @@ FlowMap res_flow(_graph); for(ArcIt a(_graph); a != INVALID; ++a) res_flow[a] = (*_flow)[a]; - paths.clear(); - paths.resize(_path_num); + _paths.clear(); + _paths.resize(_path_num); for (int i = 0; i < _path_num; ++i) { - Node n = _source; - while (n != _target) { + Node n = _s; + while (n != _t) { OutArcIt e(_graph, n); for ( ; res_flow[e] == 0; ++e) ; n = _graph.target(e); - paths[i].addBack(e); + _paths[i].addBack(e); res_flow[e] = 0; } } @@ -518,7 +762,7 @@ /// \pre \ref run() or \ref findPaths() must be called before using /// this function. const Path& path(int i) const { - return paths[i]; + return _paths[i]; } /// @} diff --git a/lemon/time_measure.h b/lemon/time_measure.h --- a/lemon/time_measure.h +++ b/lemon/time_measure.h @@ -375,7 +375,7 @@ ///This function returns the number of stop() exections that is ///necessary to really stop the timer. - ///For example the timer + ///For example, the timer ///is running if and only if the return value is \c true ///(i.e. greater than ///zero). diff --git a/lemon/unionfind.h b/lemon/unionfind.h --- a/lemon/unionfind.h +++ b/lemon/unionfind.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -43,7 +43,7 @@ /// the find operation uses path compression. /// This is a very simple but efficient implementation, providing /// only four methods: join (union), find, insert and size. - /// For more features see the \ref UnionFindEnum class. + /// For more features, see the \ref UnionFindEnum class. /// /// It is primarily used in Kruskal algorithm for finding minimal /// cost spanning tree in a graph. diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100644 --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,7 @@ +EXTRA_DIST += \ + scripts/bib2dox.py \ + scripts/bootstrap.sh \ + scripts/chg-len.py \ + scripts/mk-release.sh \ + scripts/unify-sources.sh \ + scripts/valgrind-wrapper.sh diff --git a/scripts/bib2dox.py b/scripts/bib2dox.py new file mode 100755 --- /dev/null +++ b/scripts/bib2dox.py @@ -0,0 +1,816 @@ +#! /usr/bin/env python +""" + BibTeX to Doxygen converter + Usage: python bib2dox.py bibfile.bib > bibfile.dox + + This file is a part of LEMON, a generic C++ optimization library. + + ********************************************************************** + + This code is the modification of the BibTeX to XML converter + by Vidar Bronken Gundersen et al. + See the original copyright notices below. + + ********************************************************************** + + Decoder for bibliographic data, BibTeX + Usage: python bibtex2xml.py bibfile.bib > bibfile.xml + + v.8 + (c)2002-06-23 Vidar Bronken Gundersen + http://bibtexml.sf.net/ + Reuse approved as long as this notification is kept. + Licence: GPL. + + Contributions/thanks to: + Egon Willighagen, http://sf.net/projects/jreferences/ + Richard Mahoney (for providing a test case) + + Editted by Sara Sprenkle to be more robust and handle more bibtex features. + (c) 2003-01-15 + + 1. Changed bibtex: tags to bibxml: tags. + 2. Use xmlns:bibxml="http://bibtexml.sf.net/" + 3. Allow spaces between @type and first { + 4. "author" fields with multiple authors split by " and " + are put in separate xml "bibxml:author" tags. + 5. Option for Titles: words are capitalized + only if first letter in title or capitalized inside braces + 6. Removes braces from within field values + 7. Ignores comments in bibtex file (including @comment{ or % ) + 8. Replaces some special latex tags, e.g., replaces ~ with ' ' + 9. Handles bibtex @string abbreviations + --> includes bibtex's default abbreviations for months + --> does concatenation of abbr # " more " and " more " # abbr + 10. Handles @type( ... ) or @type{ ... } + 11. The keywords field is split on , or ; and put into separate xml + "bibxml:keywords" tags + 12. Ignores @preamble + + Known Limitations + 1. Does not transform Latex encoding like math mode and special + latex symbols. + 2. Does not parse author fields into first and last names. + E.g., It does not do anything special to an author whose name is + in the form LAST_NAME, FIRST_NAME + In "author" tag, will show up as + LAST_NAME, FIRST_NAME + 3. Does not handle "crossref" fields other than to print + ... + 4. Does not inform user of the input's format errors. You just won't + be able to transform the file later with XSL + + You will have to manually edit the XML output if you need to handle + these (and unknown) limitations. + +""" + +import string, re + +# set of valid name characters +valid_name_chars = '[\w\-:]' + +# +# define global regular expression variables +# +author_rex = re.compile('\s+and\s+') +rembraces_rex = re.compile('[{}]') +capitalize_rex = re.compile('({[^}]*})') + +# used by bibtexkeywords(data) +keywords_rex = re.compile('[,;]') + +# used by concat_line(line) +concatsplit_rex = re.compile('\s*#\s*') + +# split on {, }, or " in verify_out_of_braces +delimiter_rex = re.compile('([{}"])',re.I) + +field_rex = re.compile('\s*(\w*)\s*=\s*(.*)') +data_rex = re.compile('\s*(\w*)\s*=\s*([^,]*),?') + +url_rex = re.compile('\\\url\{([^}]*)\}') + +# +# styles for html formatting +# +divstyle = 'margin-top: -4ex; margin-left: 8em;' + +# +# return the string parameter without braces +# +def transformurls(str): + return url_rex.sub(r'\1', str) + +# +# return the string parameter without braces +# +def removebraces(str): + return rembraces_rex.sub('', str) + +# +# latex-specific replacements +# (do this after braces were removed) +# +def latexreplacements(line): + line = string.replace(line, '~', ' ') + line = string.replace(line, '\\\'a', 'á') + line = string.replace(line, '\\"a', 'ä') + line = string.replace(line, '\\\'e', 'é') + line = string.replace(line, '\\"e', 'ë') + line = string.replace(line, '\\\'i', 'í') + line = string.replace(line, '\\"i', 'ï') + line = string.replace(line, '\\\'o', 'ó') + line = string.replace(line, '\\"o', 'ö') + line = string.replace(line, '\\\'u', 'ú') + line = string.replace(line, '\\"u', 'ü') + line = string.replace(line, '\\H o', 'õ') + line = string.replace(line, '\\H u', 'ü') # ũ does not exist + line = string.replace(line, '\\\'A', 'Á') + line = string.replace(line, '\\"A', 'Ä') + line = string.replace(line, '\\\'E', 'É') + line = string.replace(line, '\\"E', 'Ë') + line = string.replace(line, '\\\'I', 'Í') + line = string.replace(line, '\\"I', 'Ï') + line = string.replace(line, '\\\'O', 'Ó') + line = string.replace(line, '\\"O', 'Ö') + line = string.replace(line, '\\\'U', 'Ú') + line = string.replace(line, '\\"U', 'Ü') + line = string.replace(line, '\\H O', 'Õ') + line = string.replace(line, '\\H U', 'Ü') # Ũ does not exist + + return line + +# +# copy characters form a string decoding html expressions (&xyz;) +# +def copychars(str, ifrom, count): + result = '' + i = ifrom + c = 0 + html_spec = False + while (i < len(str)) and (c < count): + if str[i] == '&': + html_spec = True; + if i+1 < len(str): + result += str[i+1] + c += 1 + i += 2 + else: + if not html_spec: + if ((str[i] >= 'A') and (str[i] <= 'Z')) or \ + ((str[i] >= 'a') and (str[i] <= 'z')): + result += str[i] + c += 1 + elif str[i] == ';': + html_spec = False; + i += 1 + + return result + + +# +# Handle a list of authors (separated by 'and'). +# It gives back an array of the follwing values: +# - num: the number of authors, +# - list: the list of the author names, +# - text: the bibtex text (separated by commas and/or 'and') +# - abbrev: abbreviation that can be used for indicate the +# bibliography entries +# +def bibtexauthor(data): + result = {} + bibtex = '' + result['list'] = author_rex.split(data) + result['num'] = len(result['list']) + for i, author in enumerate(result['list']): + # general transformations + author = latexreplacements(removebraces(author.strip())) + # transform "Xyz, A. B." to "A. B. Xyz" + pos = author.find(',') + if pos != -1: + author = author[pos+1:].strip() + ' ' + author[:pos].strip() + result['list'][i] = author + bibtex += author + '#' + bibtex = bibtex[:-1] + if result['num'] > 1: + ix = bibtex.rfind('#') + if result['num'] == 2: + bibtex = bibtex[:ix] + ' and ' + bibtex[ix+1:] + else: + bibtex = bibtex[:ix] + ', and ' + bibtex[ix+1:] + bibtex = bibtex.replace('#', ', ') + result['text'] = bibtex + + result['abbrev'] = '' + for author in result['list']: + pos = author.rfind(' ') + 1 + count = 1 + if result['num'] == 1: + count = 3 + result['abbrev'] += copychars(author, pos, count) + + return result + + +# +# data = title string +# @return the capitalized title (first letter is capitalized), rest are capitalized +# only if capitalized inside braces +# +def capitalizetitle(data): + title_list = capitalize_rex.split(data) + title = '' + count = 0 + for phrase in title_list: + check = string.lstrip(phrase) + + # keep phrase's capitalization the same + if check.find('{') == 0: + title += removebraces(phrase) + else: + # first word --> capitalize first letter (after spaces) + if count == 0: + title += check.capitalize() + else: + title += phrase.lower() + count = count + 1 + + return title + + +# +# @return the bibtex for the title +# @param data --> title string +# braces are removed from title +# +def bibtextitle(data, entrytype): + if entrytype in ('book', 'inbook'): + title = removebraces(data.strip()) + else: + title = removebraces(capitalizetitle(data.strip())) + bibtex = title + return bibtex + + +# +# function to compare entry lists +# +def entry_cmp(x, y): + return cmp(x[0], y[0]) + + +# +# print the XML for the transformed "filecont_source" +# +def bibtexdecoder(filecont_source): + filecont = [] + file = [] + + # want @{, + pubtype_rex = re.compile('@(\w*)\s*{\s*(.*),') + endtype_rex = re.compile('}\s*$') + endtag_rex = re.compile('^\s*}\s*$') + + bracefield_rex = re.compile('\s*(\w*)\s*=\s*(.*)') + bracedata_rex = re.compile('\s*(\w*)\s*=\s*{(.*)},?') + + quotefield_rex = re.compile('\s*(\w*)\s*=\s*(.*)') + quotedata_rex = re.compile('\s*(\w*)\s*=\s*"(.*)",?') + + for line in filecont_source: + line = line[:-1] + + # encode character entities + line = string.replace(line, '&', '&') + line = string.replace(line, '<', '<') + line = string.replace(line, '>', '>') + + # start entry: publication type (store for later use) + if pubtype_rex.match(line): + # want @{, + entrycont = {} + entry = [] + entrytype = pubtype_rex.sub('\g<1>',line) + entrytype = string.lower(entrytype) + entryid = pubtype_rex.sub('\g<2>', line) + + # end entry if just a } + elif endtype_rex.match(line): + # generate doxygen code for the entry + + # enty type related formattings + if entrytype in ('book', 'inbook'): + entrycont['title'] = '' + entrycont['title'] + '' + if not entrycont.has_key('author'): + entrycont['author'] = entrycont['editor'] + entrycont['author']['text'] += ', editors' + elif entrytype == 'article': + entrycont['journal'] = '' + entrycont['journal'] + '' + elif entrytype in ('inproceedings', 'incollection', 'conference'): + entrycont['booktitle'] = '' + entrycont['booktitle'] + '' + elif entrytype == 'techreport': + if not entrycont.has_key('type'): + entrycont['type'] = 'Technical report' + elif entrytype == 'mastersthesis': + entrycont['type'] = 'Master\'s thesis' + elif entrytype == 'phdthesis': + entrycont['type'] = 'PhD thesis' + + for eline in entrycont: + if eline != '': + eline = latexreplacements(eline) + + if entrycont.has_key('pages') and (entrycont['pages'] != ''): + entrycont['pages'] = string.replace(entrycont['pages'], '--', '-') + + if entrycont.has_key('author') and (entrycont['author'] != ''): + entry.append(entrycont['author']['text'] + '.') + if entrycont.has_key('title') and (entrycont['title'] != ''): + entry.append(entrycont['title'] + '.') + if entrycont.has_key('journal') and (entrycont['journal'] != ''): + entry.append(entrycont['journal'] + ',') + if entrycont.has_key('booktitle') and (entrycont['booktitle'] != ''): + entry.append('In ' + entrycont['booktitle'] + ',') + if entrycont.has_key('type') and (entrycont['type'] != ''): + eline = entrycont['type'] + if entrycont.has_key('number') and (entrycont['number'] != ''): + eline += ' ' + entrycont['number'] + eline += ',' + entry.append(eline) + if entrycont.has_key('institution') and (entrycont['institution'] != ''): + entry.append(entrycont['institution'] + ',') + if entrycont.has_key('publisher') and (entrycont['publisher'] != ''): + entry.append(entrycont['publisher'] + ',') + if entrycont.has_key('school') and (entrycont['school'] != ''): + entry.append(entrycont['school'] + ',') + if entrycont.has_key('address') and (entrycont['address'] != ''): + entry.append(entrycont['address'] + ',') + if entrycont.has_key('edition') and (entrycont['edition'] != ''): + entry.append(entrycont['edition'] + ' edition,') + if entrycont.has_key('howpublished') and (entrycont['howpublished'] != ''): + entry.append(entrycont['howpublished'] + ',') + if entrycont.has_key('volume') and (entrycont['volume'] != ''): + eline = entrycont['volume']; + if entrycont.has_key('number') and (entrycont['number'] != ''): + eline += '(' + entrycont['number'] + ')' + if entrycont.has_key('pages') and (entrycont['pages'] != ''): + eline += ':' + entrycont['pages'] + eline += ',' + entry.append(eline) + else: + if entrycont.has_key('pages') and (entrycont['pages'] != ''): + entry.append('pages ' + entrycont['pages'] + ',') + if entrycont.has_key('year') and (entrycont['year'] != ''): + if entrycont.has_key('month') and (entrycont['month'] != ''): + entry.append(entrycont['month'] + ' ' + entrycont['year'] + '.') + else: + entry.append(entrycont['year'] + '.') + if entrycont.has_key('note') and (entrycont['note'] != ''): + entry.append(entrycont['note'] + '.') + if entrycont.has_key('url') and (entrycont['url'] != ''): + entry.append(entrycont['url'] + '.') + + # generate keys for sorting and for the output + sortkey = '' + bibkey = '' + if entrycont.has_key('author'): + for author in entrycont['author']['list']: + sortkey += copychars(author, author.rfind(' ')+1, len(author)) + bibkey = entrycont['author']['abbrev'] + else: + bibkey = 'x' + if entrycont.has_key('year'): + sortkey += entrycont['year'] + bibkey += entrycont['year'][-2:] + if entrycont.has_key('title'): + sortkey += entrycont['title'] + if entrycont.has_key('key'): + sortkey = entrycont['key'] + sortkey + bibkey = entrycont['key'] + entry.insert(0, sortkey) + entry.insert(1, bibkey) + entry.insert(2, entryid) + + # add the entry to the file contents + filecont.append(entry) + + else: + # field, publication info + field = '' + data = '' + + # field = {data} entries + if bracedata_rex.match(line): + field = bracefield_rex.sub('\g<1>', line) + field = string.lower(field) + data = bracedata_rex.sub('\g<2>', line) + + # field = "data" entries + elif quotedata_rex.match(line): + field = quotefield_rex.sub('\g<1>', line) + field = string.lower(field) + data = quotedata_rex.sub('\g<2>', line) + + # field = data entries + elif data_rex.match(line): + field = field_rex.sub('\g<1>', line) + field = string.lower(field) + data = data_rex.sub('\g<2>', line) + + if field == 'url': + data = '\\url{' + data.strip() + '}' + + if field in ('author', 'editor'): + entrycont[field] = bibtexauthor(data) + line = '' + elif field == 'title': + line = bibtextitle(data, entrytype) + elif field != '': + line = removebraces(transformurls(data.strip())) + + if line != '': + line = latexreplacements(line) + entrycont[field] = line + + + # sort entries + filecont.sort(entry_cmp) + + # count the bibtex keys + keytable = {} + counttable = {} + for entry in filecont: + bibkey = entry[1] + if not keytable.has_key(bibkey): + keytable[bibkey] = 1 + else: + keytable[bibkey] += 1 + + for bibkey in keytable.keys(): + counttable[bibkey] = 0 + + # generate output + for entry in filecont: + # generate output key form the bibtex key + bibkey = entry[1] + entryid = entry[2] + if keytable[bibkey] == 1: + outkey = bibkey + else: + outkey = bibkey + chr(97 + counttable[bibkey]) + counttable[bibkey] += 1 + + # append the entry code to the output + file.append('\\section ' + entryid + ' [' + outkey + ']') + file.append('
') + for line in entry[3:]: + file.append(line) + file.append('
') + file.append('') + + return file + + +# +# return 1 iff abbr is in line but not inside braces or quotes +# assumes that abbr appears only once on the line (out of braces and quotes) +# +def verify_out_of_braces(line, abbr): + + phrase_split = delimiter_rex.split(line) + + abbr_rex = re.compile( '\\b' + abbr + '\\b', re.I) + + open_brace = 0 + open_quote = 0 + + for phrase in phrase_split: + if phrase == "{": + open_brace = open_brace + 1 + elif phrase == "}": + open_brace = open_brace - 1 + elif phrase == '"': + if open_quote == 1: + open_quote = 0 + else: + open_quote = 1 + elif abbr_rex.search(phrase): + if open_brace == 0 and open_quote == 0: + return 1 + + return 0 + + +# +# a line in the form phrase1 # phrase2 # ... # phrasen +# is returned as phrase1 phrase2 ... phrasen +# with the correct punctuation +# Bug: Doesn't always work with multiple abbreviations plugged in +# +def concat_line(line): + # only look at part after equals + field = field_rex.sub('\g<1>',line) + rest = field_rex.sub('\g<2>',line) + + concat_line = field + ' =' + + pound_split = concatsplit_rex.split(rest) + + phrase_count = 0 + length = len(pound_split) + + for phrase in pound_split: + phrase = phrase.strip() + if phrase_count != 0: + if phrase.startswith('"') or phrase.startswith('{'): + phrase = phrase[1:] + elif phrase.startswith('"'): + phrase = phrase.replace('"','{',1) + + if phrase_count != length-1: + if phrase.endswith('"') or phrase.endswith('}'): + phrase = phrase[:-1] + else: + if phrase.endswith('"'): + phrase = phrase[:-1] + phrase = phrase + "}" + elif phrase.endswith('",'): + phrase = phrase[:-2] + phrase = phrase + "}," + + # if phrase did have \#, add the \# back + if phrase.endswith('\\'): + phrase = phrase + "#" + concat_line = concat_line + ' ' + phrase + + phrase_count = phrase_count + 1 + + return concat_line + + +# +# substitute abbreviations into filecont +# @param filecont_source - string of data from file +# +def bibtex_replace_abbreviations(filecont_source): + filecont = filecont_source.splitlines() + + # These are defined in bibtex, so we'll define them too + abbr_list = ['jan','feb','mar','apr','may','jun', + 'jul','aug','sep','oct','nov','dec'] + value_list = ['January','February','March','April', + 'May','June','July','August','September', + 'October','November','December'] + + abbr_rex = [] + total_abbr_count = 0 + + front = '\\b' + back = '(,?)\\b' + + for x in abbr_list: + abbr_rex.append( re.compile( front + abbr_list[total_abbr_count] + back, re.I ) ) + total_abbr_count = total_abbr_count + 1 + + + abbrdef_rex = re.compile('\s*@string\s*{\s*('+ valid_name_chars +'*)\s*=(.*)', + re.I) + + comment_rex = re.compile('@comment\s*{',re.I) + preamble_rex = re.compile('@preamble\s*{',re.I) + + waiting_for_end_string = 0 + i = 0 + filecont2 = '' + + for line in filecont: + if line == ' ' or line == '': + continue + + if waiting_for_end_string: + if re.search('}',line): + waiting_for_end_string = 0 + continue + + if abbrdef_rex.search(line): + abbr = abbrdef_rex.sub('\g<1>', line) + + if abbr_list.count(abbr) == 0: + val = abbrdef_rex.sub('\g<2>', line) + abbr_list.append(abbr) + value_list.append(string.strip(val)) + abbr_rex.append( re.compile( front + abbr_list[total_abbr_count] + back, re.I ) ) + total_abbr_count = total_abbr_count + 1 + waiting_for_end_string = 1 + continue + + if comment_rex.search(line): + waiting_for_end_string = 1 + continue + + if preamble_rex.search(line): + waiting_for_end_string = 1 + continue + + + # replace subsequent abbreviations with the value + abbr_count = 0 + + for x in abbr_list: + + if abbr_rex[abbr_count].search(line): + if verify_out_of_braces(line,abbr_list[abbr_count]) == 1: + line = abbr_rex[abbr_count].sub( value_list[abbr_count] + '\g<1>', line) + # Check for # concatenations + if concatsplit_rex.search(line): + line = concat_line(line) + abbr_count = abbr_count + 1 + + + filecont2 = filecont2 + line + '\n' + i = i+1 + + + # Do one final pass over file + + # make sure that didn't end up with {" or }" after the substitution + filecont2 = filecont2.replace('{"','{{') + filecont2 = filecont2.replace('"}','}}') + + afterquotevalue_rex = re.compile('"\s*,\s*') + afterbrace_rex = re.compile('"\s*}') + afterbracevalue_rex = re.compile('(=\s*{[^=]*)},\s*') + + # add new lines to data that changed because of abbreviation substitutions + filecont2 = afterquotevalue_rex.sub('",\n', filecont2) + filecont2 = afterbrace_rex.sub('"\n}', filecont2) + filecont2 = afterbracevalue_rex.sub('\g<1>},\n', filecont2) + + return filecont2 + +# +# convert @type( ... ) to @type{ ... } +# +def no_outer_parens(filecont): + + # do checking for open parens + # will convert to braces + paren_split = re.split('([(){}])',filecont) + + open_paren_count = 0 + open_type = 0 + look_next = 0 + + # rebuild filecont + filecont = '' + + at_rex = re.compile('@\w*') + + for phrase in paren_split: + if look_next == 1: + if phrase == '(': + phrase = '{' + open_paren_count = open_paren_count + 1 + else: + open_type = 0 + look_next = 0 + + if phrase == '(': + open_paren_count = open_paren_count + 1 + + elif phrase == ')': + open_paren_count = open_paren_count - 1 + if open_type == 1 and open_paren_count == 0: + phrase = '}' + open_type = 0 + + elif at_rex.search( phrase ): + open_type = 1 + look_next = 1 + + filecont = filecont + phrase + + return filecont + + +# +# make all whitespace into just one space +# format the bibtex file into a usable form. +# +def bibtexwasher(filecont_source): + + space_rex = re.compile('\s+') + comment_rex = re.compile('\s*%') + + filecont = [] + + # remove trailing and excessive whitespace + # ignore comments + for line in filecont_source: + line = string.strip(line) + line = space_rex.sub(' ', line) + # ignore comments + if not comment_rex.match(line) and line != '': + filecont.append(' '+ line) + + filecont = string.join(filecont, '') + + # the file is in one long string + + filecont = no_outer_parens(filecont) + + # + # split lines according to preferred syntax scheme + # + filecont = re.sub('(=\s*{[^=]*)},', '\g<1>},\n', filecont) + + # add new lines after commas that are after values + filecont = re.sub('"\s*,', '",\n', filecont) + filecont = re.sub('=\s*([\w\d]+)\s*,', '= \g<1>,\n', filecont) + filecont = re.sub('(@\w*)\s*({(\s*)[^,\s]*)\s*,', + '\n\n\g<1>\g<2>,\n', filecont) + + # add new lines after } + filecont = re.sub('"\s*}','"\n}\n', filecont) + filecont = re.sub('}\s*,','},\n', filecont) + + + filecont = re.sub('@(\w*)', '\n@\g<1>', filecont) + + # character encoding, reserved latex characters + filecont = re.sub('{\\\&}', '&', filecont) + filecont = re.sub('\\\&', '&', filecont) + + # do checking for open braces to get format correct + open_brace_count = 0 + brace_split = re.split('([{}])',filecont) + + # rebuild filecont + filecont = '' + + for phrase in brace_split: + if phrase == '{': + open_brace_count = open_brace_count + 1 + elif phrase == '}': + open_brace_count = open_brace_count - 1 + if open_brace_count == 0: + filecont = filecont + '\n' + + filecont = filecont + phrase + + filecont2 = bibtex_replace_abbreviations(filecont) + + # gather + filecont = filecont2.splitlines() + i=0 + j=0 # count the number of blank lines + for line in filecont: + # ignore blank lines + if line == '' or line == ' ': + j = j+1 + continue + filecont[i] = line + '\n' + i = i+1 + + # get rid of the extra stuff at the end of the array + # (The extra stuff are duplicates that are in the array because + # blank lines were removed.) + length = len( filecont) + filecont[length-j:length] = [] + + return filecont + + +def filehandler(filepath): + try: + fd = open(filepath, 'r') + filecont_source = fd.readlines() + fd.close() + except: + print 'Could not open file:', filepath + washeddata = bibtexwasher(filecont_source) + outdata = bibtexdecoder(washeddata) + print '/**' + print '\page references References' + print + for line in outdata: + print line + print '*/' + + +# main program + +def main(): + import sys + if sys.argv[1:]: + filepath = sys.argv[1] + else: + print "No input file" + sys.exit() + filehandler(filepath) + +if __name__ == "__main__": main() + + +# end python script diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh new file mode 100755 --- /dev/null +++ b/scripts/bootstrap.sh @@ -0,0 +1,157 @@ +#!/bin/bash +# +# This file is a part of LEMON, a generic C++ optimization library. +# +# Copyright (C) 2003-2009 +# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport +# (Egervary Research Group on Combinatorial Optimization, EGRES). +# +# Permission to use, modify and distribute this software is granted +# provided that this copyright notice appears in all copies. For +# precise terms see the accompanying LICENSE file. +# +# This software is provided "AS IS" with no warranty of any kind, +# express or implied, and with no claim as to its suitability for any +# purpose. + + +if [ ! -f ~/.lemon-bootstrap ]; then + echo 'Create ~/.lemon-bootstrap'. + cat >~/.lemon-bootstrap <>~/.lemon-bootstrap + echo $3 >>~/.lemon-bootstrap + echo $1=$2 >>~/.lemon-bootstrap + fi +} + +augment_config LEMON_INSTALL_PREFIX /usr/local \ + "# LEMON installation prefix" + +augment_config GLPK_PREFIX /usr/local/ \ + "# GLPK installation root prefix" + +augment_config COIN_OR_PREFIX /usr/local/coin-or \ + "# COIN-OR installation root prefix (used for CLP/CBC)" + +augment_config SOPLEX_PREFIX /usr/local/soplex \ + "# Soplex build prefix" + + +function ask() { +echo -n "$1 [$2]? " +read _an +if [ "x$_an" == "x" ]; then + ret="$2" +else + ret=$_an +fi +} + +function yesorno() { + ret='rossz' + while [ "$ret" != "y" -a "$ret" != "n" -a "$ret" != "yes" -a "$ret" != "no" ]; do + ask "$1" "$2" + done + if [ "$ret" != "y" -a "$ret" != "yes" ]; then + return 1 + else + return 0 + fi +} + +if yesorno "External build" "n" +then + CONFIGURE_PATH=".." +else + CONFIGURE_PATH="." + if yesorno "Autoreconf" "y" + then + AUTORE=yes + else + AUTORE=no + fi +fi + +if yesorno "Optimize" "n" +then + opt_flags=' -O2' +else + opt_flags='' +fi + +if yesorno "Stop on warning" "y" +then + werror_flags=' -Werror' +else + werror_flags='' +fi + +cxx_flags="CXXFLAGS=-ggdb$opt_flags$werror_flags" + +if yesorno "Check with valgrind" "n" +then + valgrind_flags=' --enable-valgrind' +else + valgrind_flags='' +fi + +if [ -f ${GLPK_PREFIX}/include/glpk.h ]; then + if yesorno "Use GLPK" "y" + then + glpk_flag="--with-glpk=$GLPK_PREFIX" + else + glpk_flag="--without-glpk" + fi +else + glpk_flag="--without-glpk" +fi + +if [ -f ${COIN_OR_PREFIX}/include/coin/config_coinutils.h ]; then + if yesorno "Use COIN-OR (CBC/CLP)" "n" + then + coin_flag="--with-coin=$COIN_OR_PREFIX" + else + coin_flag="--without-coin" + fi +else + coin_flag="--without-coin" +fi + +if [ -f ${SOPLEX_PREFIX}/src/soplex.h ]; then + if yesorno "Use Soplex" "n" + then + soplex_flag="--with-soplex=$SOPLEX_PREFIX" + else + soplex_flag="--without-soplex" + fi +else + soplex_flag="--without-soplex" +fi + +if [ "x$AUTORE" == "xyes" ]; then + autoreconf -vif; +fi +${CONFIGURE_PATH}/configure --prefix=$LEMON_INSTALL_PREFIX \ +$valgrind_flags \ +"$cxx_flags" \ +$glpk_flag \ +$coin_flag \ +$soplex_flag \ +$* diff --git a/scripts/chg-len.py b/scripts/chg-len.py --- a/scripts/chg-len.py +++ b/scripts/chg-len.py @@ -1,4 +1,18 @@ #! /usr/bin/env python +# +# This file is a part of LEMON, a generic C++ optimization library. +# +# Copyright (C) 2003-2009 +# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport +# (Egervary Research Group on Combinatorial Optimization, EGRES). +# +# Permission to use, modify and distribute this software is granted +# provided that this copyright notice appears in all copies. For +# precise terms see the accompanying LICENSE file. +# +# This software is provided "AS IS" with no warranty of any kind, +# express or implied, and with no claim as to its suitability for any +# purpose. import sys diff --git a/scripts/mk-release.sh b/scripts/mk-release.sh --- a/scripts/mk-release.sh +++ b/scripts/mk-release.sh @@ -1,4 +1,18 @@ #!/bin/bash +# +# This file is a part of LEMON, a generic C++ optimization library. +# +# Copyright (C) 2003-2009 +# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport +# (Egervary Research Group on Combinatorial Optimization, EGRES). +# +# Permission to use, modify and distribute this software is granted +# provided that this copyright notice appears in all copies. For +# precise terms see the accompanying LICENSE file. +# +# This software is provided "AS IS" with no warranty of any kind, +# express or implied, and with no claim as to its suitability for any +# purpose. set -e diff --git a/scripts/unify-sources.sh b/scripts/unify-sources.sh --- a/scripts/unify-sources.sh +++ b/scripts/unify-sources.sh @@ -1,4 +1,18 @@ #!/bin/bash +# +# This file is a part of LEMON, a generic C++ optimization library. +# +# Copyright (C) 2003-2009 +# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport +# (Egervary Research Group on Combinatorial Optimization, EGRES). +# +# Permission to use, modify and distribute this software is granted +# provided that this copyright notice appears in all copies. For +# precise terms see the accompanying LICENSE file. +# +# This software is provided "AS IS" with no warranty of any kind, +# express or implied, and with no claim as to its suitability for any +# purpose. YEAR=`date +%Y` HGROOT=`hg root` diff --git a/scripts/valgrind-wrapper.sh b/scripts/valgrind-wrapper.sh new file mode 100755 --- /dev/null +++ b/scripts/valgrind-wrapper.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# Run in valgrind, with leak checking enabled + +valgrind -q --leak-check=full "$@" 2> .valgrind-log + +# Save the test result + +result="$?" + +# Valgrind should generate no error messages + +log_contents="`cat .valgrind-log`" + +if [ "$log_contents" != "" ]; then + cat .valgrind-log >&2 + result=1 +fi + +rm -f .valgrind-log + +exit $result diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,6 +13,7 @@ SET(TESTS adaptors_test + bellman_ford_test bfs_test circulation_test connectivity_test @@ -24,6 +25,7 @@ edge_set_test error_test euler_test + fractional_matching_test gomory_hu_test graph_copy_test graph_test @@ -36,7 +38,9 @@ matching_test min_cost_arborescence_test min_cost_flow_test + min_mean_cycle_test path_test + planarity_test preflow_test radix_sort_test random_test diff --git a/test/Makefile.am b/test/Makefile.am --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,3 +1,7 @@ +if USE_VALGRIND +TESTS_ENVIRONMENT=$(top_srcdir)/scripts/valgrind-wrapper.sh +endif + EXTRA_DIST += \ test/CMakeLists.txt @@ -7,6 +11,7 @@ check_PROGRAMS += \ test/adaptors_test \ + test/bellman_ford_test \ test/bfs_test \ test/circulation_test \ test/connectivity_test \ @@ -18,6 +23,7 @@ test/edge_set_test \ test/error_test \ test/euler_test \ + test/fractional_matching_test \ test/gomory_hu_test \ test/graph_copy_test \ test/graph_test \ @@ -30,7 +36,9 @@ test/matching_test \ test/min_cost_arborescence_test \ test/min_cost_flow_test \ + test/min_mean_cycle_test \ test/path_test \ + test/planarity_test \ test/preflow_test \ test/radix_sort_test \ test/random_test \ @@ -53,6 +61,7 @@ XFAIL_TESTS += test/test_tools_fail$(EXEEXT) test_adaptors_test_SOURCES = test/adaptors_test.cc +test_bellman_ford_test_SOURCES = test/bellman_ford_test.cc test_bfs_test_SOURCES = test/bfs_test.cc test_circulation_test_SOURCES = test/circulation_test.cc test_counter_test_SOURCES = test/counter_test.cc @@ -64,6 +73,7 @@ test_edge_set_test_SOURCES = test/edge_set_test.cc test_error_test_SOURCES = test/error_test.cc test_euler_test_SOURCES = test/euler_test.cc +test_fractional_matching_test_SOURCES = test/fractional_matching_test.cc test_gomory_hu_test_SOURCES = test/gomory_hu_test.cc test_graph_copy_test_SOURCES = test/graph_copy_test.cc test_graph_test_SOURCES = test/graph_test.cc @@ -78,7 +88,9 @@ test_matching_test_SOURCES = test/matching_test.cc test_min_cost_arborescence_test_SOURCES = test/min_cost_arborescence_test.cc test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc +test_min_mean_cycle_test_SOURCES = test/min_mean_cycle_test.cc test_path_test_SOURCES = test/path_test.cc +test_planarity_test_SOURCES = test/planarity_test.cc test_preflow_test_SOURCES = test/preflow_test.cc test_radix_sort_test_SOURCES = test/radix_sort_test.cc test_suurballe_test_SOURCES = test/suurballe_test.cc diff --git a/test/adaptors_test.cc b/test/adaptors_test.cc --- a/test/adaptors_test.cc +++ b/test/adaptors_test.cc @@ -1371,51 +1371,43 @@ GridGraph::Node n4 = graph(1,1); GridGraph::EdgeMap dir_map(graph); - dir_map[graph.right(n1)] = graph.u(graph.right(n1)) == n1; - dir_map[graph.up(n1)] = graph.u(graph.up(n1)) != n1; - dir_map[graph.left(n4)] = graph.u(graph.left(n4)) != n4; - dir_map[graph.down(n4)] = graph.u(graph.down(n4)) != n4; + dir_map[graph.right(n1)] = graph.u(graph.right(n1)) != n1; + dir_map[graph.up(n1)] = graph.u(graph.up(n1)) == n1; + dir_map[graph.left(n4)] = graph.u(graph.left(n4)) == n4; + dir_map[graph.down(n4)] = graph.u(graph.down(n4)) == n4; // Apply several adaptors on the grid graph - typedef SplitNodes< ReverseDigraph< const Orienter< - const GridGraph, GridGraph::EdgeMap > > > - RevSplitGridGraph; - typedef ReverseDigraph SplitGridGraph; + typedef SplitNodes > > + SplitGridGraph; typedef Undirector USplitGridGraph; - typedef Undirector UUSplitGridGraph; - checkConcept(); checkConcept(); checkConcept(); - checkConcept(); - RevSplitGridGraph rev_adaptor = - splitNodes(reverseDigraph(orienter(graph, dir_map))); - SplitGridGraph adaptor = reverseDigraph(rev_adaptor); + SplitGridGraph adaptor = splitNodes(orienter(graph, dir_map)); USplitGridGraph uadaptor = undirector(adaptor); - UUSplitGridGraph uuadaptor = undirector(uadaptor); // Check adaptor checkGraphNodeList(adaptor, 8); checkGraphArcList(adaptor, 8); checkGraphConArcList(adaptor, 8); - checkGraphOutArcList(adaptor, rev_adaptor.inNode(n1), 1); - checkGraphOutArcList(adaptor, rev_adaptor.outNode(n1), 1); - checkGraphOutArcList(adaptor, rev_adaptor.inNode(n2), 2); - checkGraphOutArcList(adaptor, rev_adaptor.outNode(n2), 1); - checkGraphOutArcList(adaptor, rev_adaptor.inNode(n3), 1); - checkGraphOutArcList(adaptor, rev_adaptor.outNode(n3), 1); - checkGraphOutArcList(adaptor, rev_adaptor.inNode(n4), 0); - checkGraphOutArcList(adaptor, rev_adaptor.outNode(n4), 1); + checkGraphOutArcList(adaptor, adaptor.inNode(n1), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n1), 1); + checkGraphOutArcList(adaptor, adaptor.inNode(n2), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n2), 0); + checkGraphOutArcList(adaptor, adaptor.inNode(n3), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n3), 1); + checkGraphOutArcList(adaptor, adaptor.inNode(n4), 1); + checkGraphOutArcList(adaptor, adaptor.outNode(n4), 2); - checkGraphInArcList(adaptor, rev_adaptor.inNode(n1), 1); - checkGraphInArcList(adaptor, rev_adaptor.outNode(n1), 1); - checkGraphInArcList(adaptor, rev_adaptor.inNode(n2), 1); - checkGraphInArcList(adaptor, rev_adaptor.outNode(n2), 0); - checkGraphInArcList(adaptor, rev_adaptor.inNode(n3), 1); - checkGraphInArcList(adaptor, rev_adaptor.outNode(n3), 1); - checkGraphInArcList(adaptor, rev_adaptor.inNode(n4), 1); - checkGraphInArcList(adaptor, rev_adaptor.outNode(n4), 2); + checkGraphInArcList(adaptor, adaptor.inNode(n1), 1); + checkGraphInArcList(adaptor, adaptor.outNode(n1), 1); + checkGraphInArcList(adaptor, adaptor.inNode(n2), 2); + checkGraphInArcList(adaptor, adaptor.outNode(n2), 1); + checkGraphInArcList(adaptor, adaptor.inNode(n3), 1); + checkGraphInArcList(adaptor, adaptor.outNode(n3), 1); + checkGraphInArcList(adaptor, adaptor.inNode(n4), 0); + checkGraphInArcList(adaptor, adaptor.outNode(n4), 1); checkNodeIds(adaptor); checkArcIds(adaptor); @@ -1438,29 +1430,14 @@ checkGraphEdgeMap(uadaptor); checkGraphArcMap(uadaptor); - checkGraphIncEdgeArcLists(uadaptor, rev_adaptor.inNode(n1), 2); - checkGraphIncEdgeArcLists(uadaptor, rev_adaptor.outNode(n1), 2); - checkGraphIncEdgeArcLists(uadaptor, rev_adaptor.inNode(n2), 3); - checkGraphIncEdgeArcLists(uadaptor, rev_adaptor.outNode(n2), 1); - checkGraphIncEdgeArcLists(uadaptor, rev_adaptor.inNode(n3), 2); - checkGraphIncEdgeArcLists(uadaptor, rev_adaptor.outNode(n3), 2); - checkGraphIncEdgeArcLists(uadaptor, rev_adaptor.inNode(n4), 1); - checkGraphIncEdgeArcLists(uadaptor, rev_adaptor.outNode(n4), 3); - - // Check uuadaptor - checkGraphNodeList(uuadaptor, 8); - checkGraphEdgeList(uuadaptor, 16); - checkGraphArcList(uuadaptor, 32); - checkGraphConEdgeList(uuadaptor, 16); - checkGraphConArcList(uuadaptor, 32); - - checkNodeIds(uuadaptor); - checkEdgeIds(uuadaptor); - checkArcIds(uuadaptor); - - checkGraphNodeMap(uuadaptor); - checkGraphEdgeMap(uuadaptor); - checkGraphArcMap(uuadaptor); + checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n1), 2); + checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n1), 2); + checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n2), 3); + checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n2), 1); + checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n3), 2); + checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n3), 2); + checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n4), 1); + checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n4), 3); } int main(int, const char **) { diff --git a/test/bellman_ford_test.cc b/test/bellman_ford_test.cc new file mode 100644 --- /dev/null +++ b/test/bellman_ford_test.cc @@ -0,0 +1,286 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "graph_test.h" +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "@arcs\n" + " length\n" + "0 1 3\n" + "1 2 -3\n" + "1 2 -5\n" + "1 3 -2\n" + "0 2 -1\n" + "1 2 -4\n" + "0 3 2\n" + "4 2 -5\n" + "2 3 1\n" + "@attributes\n" + "source 0\n" + "target 3\n"; + + +void checkBellmanFordCompile() +{ + typedef int Value; + typedef concepts::Digraph Digraph; + typedef concepts::ReadMap LengthMap; + typedef BellmanFord BF; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + + Digraph gr; + Node s, t, n; + Arc e; + Value l; + int k=3; + bool b; + BF::DistMap d(gr); + BF::PredMap p(gr); + LengthMap length; + concepts::Path pp; + + { + BF bf_test(gr,length); + const BF& const_bf_test = bf_test; + + bf_test.run(s); + bf_test.run(s,k); + + bf_test.init(); + bf_test.addSource(s); + bf_test.addSource(s, 1); + b = bf_test.processNextRound(); + b = bf_test.processNextWeakRound(); + + bf_test.start(); + bf_test.checkedStart(); + bf_test.limitedStart(k); + + l = const_bf_test.dist(t); + e = const_bf_test.predArc(t); + s = const_bf_test.predNode(t); + b = const_bf_test.reached(t); + d = const_bf_test.distMap(); + p = const_bf_test.predMap(); + pp = const_bf_test.path(t); + pp = const_bf_test.negativeCycle(); + + for (BF::ActiveIt it(const_bf_test); it != INVALID; ++it) {} + } + { + BF::SetPredMap > + ::SetDistMap > + ::SetOperationTraits > + ::SetOperationTraits > + ::Create bf_test(gr,length); + + LengthMap length_map; + concepts::ReadWriteMap pred_map; + concepts::ReadWriteMap dist_map; + + bf_test + .lengthMap(length_map) + .predMap(pred_map) + .distMap(dist_map); + + bf_test.run(s); + bf_test.run(s,k); + + bf_test.init(); + bf_test.addSource(s); + bf_test.addSource(s, 1); + b = bf_test.processNextRound(); + b = bf_test.processNextWeakRound(); + + bf_test.start(); + bf_test.checkedStart(); + bf_test.limitedStart(k); + + l = bf_test.dist(t); + e = bf_test.predArc(t); + s = bf_test.predNode(t); + b = bf_test.reached(t); + pp = bf_test.path(t); + pp = bf_test.negativeCycle(); + } +} + +void checkBellmanFordFunctionCompile() +{ + typedef int Value; + typedef concepts::Digraph Digraph; + typedef Digraph::Arc Arc; + typedef Digraph::Node Node; + typedef concepts::ReadMap LengthMap; + + Digraph g; + bool b; + bellmanFord(g,LengthMap()).run(Node()); + b = bellmanFord(g,LengthMap()).run(Node(),Node()); + bellmanFord(g,LengthMap()) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .run(Node()); + b=bellmanFord(g,LengthMap()) + .predMap(concepts::ReadWriteMap()) + .distMap(concepts::ReadWriteMap()) + .path(concepts::Path()) + .dist(Value()) + .run(Node(),Node()); +} + + +template +void checkBellmanFord() { + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + typedef typename Digraph::template ArcMap LengthMap; + + Digraph gr; + Node s, t; + LengthMap length(gr); + + std::istringstream input(test_lgf); + digraphReader(gr, input). + arcMap("length", length). + node("source", s). + node("target", t). + run(); + + BellmanFord + bf(gr, length); + bf.run(s); + Path p = bf.path(t); + + check(bf.reached(t) && bf.dist(t) == -1, "Bellman-Ford found a wrong path."); + check(p.length() == 3, "path() found a wrong path."); + check(checkPath(gr, p), "path() found a wrong path."); + check(pathSource(gr, p) == s, "path() found a wrong path."); + check(pathTarget(gr, p) == t, "path() found a wrong path."); + + ListPath path; + Value dist; + bool reached = bellmanFord(gr,length).path(path).dist(dist).run(s,t); + + check(reached && dist == -1, "Bellman-Ford found a wrong path."); + check(path.length() == 3, "path() found a wrong path."); + check(checkPath(gr, path), "path() found a wrong path."); + check(pathSource(gr, path) == s, "path() found a wrong path."); + check(pathTarget(gr, path) == t, "path() found a wrong path."); + + for(ArcIt e(gr); e!=INVALID; ++e) { + Node u=gr.source(e); + Node v=gr.target(e); + check(!bf.reached(u) || (bf.dist(v) - bf.dist(u) <= length[e]), + "Wrong output. dist(target)-dist(source)-arc_length=" << + bf.dist(v) - bf.dist(u) - length[e]); + } + + for(NodeIt v(gr); v!=INVALID; ++v) { + if (bf.reached(v)) { + check(v==s || bf.predArc(v)!=INVALID, "Wrong tree."); + if (bf.predArc(v)!=INVALID ) { + Arc e=bf.predArc(v); + Node u=gr.source(e); + check(u==bf.predNode(v),"Wrong tree."); + check(bf.dist(v) - bf.dist(u) == length[e], + "Wrong distance! Difference: " << + bf.dist(v) - bf.dist(u) - length[e]); + } + } + } +} + +void checkBellmanFordNegativeCycle() { + DIGRAPH_TYPEDEFS(SmartDigraph); + + SmartDigraph gr; + IntArcMap length(gr); + + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + Node n3 = gr.addNode(); + Node n4 = gr.addNode(); + + Arc a1 = gr.addArc(n1, n2); + Arc a2 = gr.addArc(n2, n2); + + length[a1] = 2; + length[a2] = -1; + + { + BellmanFord bf(gr, length); + bf.run(n1); + StaticPath p = bf.negativeCycle(); + check(p.length() == 1 && p.front() == p.back() && p.front() == a2, + "Wrong negative cycle."); + } + + length[a2] = 0; + + { + BellmanFord bf(gr, length); + bf.run(n1); + check(bf.negativeCycle().empty(), + "Negative cycle should not be found."); + } + + length[gr.addArc(n1, n3)] = 5; + length[gr.addArc(n4, n3)] = 1; + length[gr.addArc(n2, n4)] = 2; + length[gr.addArc(n3, n2)] = -4; + + { + BellmanFord bf(gr, length); + bf.init(); + bf.addSource(n1); + for (int i = 0; i < 4; ++i) { + check(bf.negativeCycle().empty(), + "Negative cycle should not be found."); + bf.processNextRound(); + } + StaticPath p = bf.negativeCycle(); + check(p.length() == 3, "Wrong negative cycle."); + check(length[p.nth(0)] + length[p.nth(1)] + length[p.nth(2)] == -1, + "Wrong negative cycle."); + } +} + +int main() { + checkBellmanFord(); + checkBellmanFord(); + checkBellmanFordNegativeCycle(); + return 0; +} diff --git a/test/bfs_test.cc b/test/bfs_test.cc --- a/test/bfs_test.cc +++ b/test/bfs_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -83,7 +83,7 @@ n = const_bfs_test.nextNode(); b = const_bfs_test.emptyQueue(); i = const_bfs_test.queueSize(); - + bfs_test.start(); bfs_test.start(t); bfs_test.start(nm); @@ -104,12 +104,12 @@ ::SetStandardProcessedMap ::SetProcessedMap > ::Create bfs_test(G); - + concepts::ReadWriteMap pred_map; concepts::ReadWriteMap dist_map; concepts::ReadWriteMap reached_map; concepts::WriteMap processed_map; - + bfs_test .predMap(pred_map) .distMap(dist_map) @@ -119,7 +119,7 @@ bfs_test.run(s); bfs_test.run(s,t); bfs_test.run(); - + bfs_test.init(); bfs_test.addSource(s); n = bfs_test.processNextNode(); @@ -128,7 +128,7 @@ n = bfs_test.nextNode(); b = bfs_test.emptyQueue(); i = bfs_test.queueSize(); - + bfs_test.start(); bfs_test.start(t); bfs_test.start(nm); diff --git a/test/circulation_test.cc b/test/circulation_test.cc --- a/test/circulation_test.cc +++ b/test/circulation_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -81,13 +81,18 @@ ::Create CirculationType; CirculationType circ_test(g, lcap, ucap, supply); const CirculationType& const_circ_test = circ_test; - + circ_test .lowerMap(lcap) .upperMap(ucap) .supplyMap(supply) .flowMap(flow); + const CirculationType::Elevator& elev = const_circ_test.elevator(); + circ_test.elevator(const_cast(elev)); + CirculationType::Tolerance tol = const_circ_test.tolerance(); + circ_test.tolerance(tol); + circ_test.init(); circ_test.greedyInit(); circ_test.start(); @@ -97,7 +102,7 @@ const FlowMap& fm = const_circ_test.flowMap(); b = const_circ_test.barrier(n); const_circ_test.barrierMap(bar); - + ignore_unused_variable_warning(fm); } diff --git a/test/connectivity_test.cc b/test/connectivity_test.cc --- a/test/connectivity_test.cc +++ b/test/connectivity_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -29,12 +29,12 @@ { typedef ListDigraph Digraph; typedef Undirector Graph; - + { Digraph d; Digraph::NodeMap order(d); Graph g(d); - + check(stronglyConnected(d), "The empty digraph is strongly connected"); check(countStronglyConnectedComponents(d) == 0, "The empty digraph has 0 strongly connected component"); @@ -48,7 +48,7 @@ check(biEdgeConnected(g), "The empty graph is bi-edge-connected"); check(countBiEdgeConnectedComponents(g) == 0, "The empty graph has 0 bi-edge-connected component"); - + check(dag(d), "The empty digraph is DAG."); check(checkedTopologicalSort(d, order), "The empty digraph is DAG."); check(loopFree(d), "The empty digraph is loop-free."); @@ -82,7 +82,7 @@ check(biEdgeConnected(g), "This graph is bi-edge-connected"); check(countBiEdgeConnectedComponents(g) == 1, "This graph has 1 bi-edge-connected component"); - + check(dag(d), "This digraph is DAG."); check(checkedTopologicalSort(d, order), "This digraph is DAG."); check(loopFree(d), "This digraph is loop-free."); @@ -101,14 +101,14 @@ Digraph d; Digraph::NodeMap order(d); Graph g(d); - + Digraph::Node n1 = d.addNode(); Digraph::Node n2 = d.addNode(); Digraph::Node n3 = d.addNode(); Digraph::Node n4 = d.addNode(); Digraph::Node n5 = d.addNode(); Digraph::Node n6 = d.addNode(); - + d.addArc(n1, n3); d.addArc(n3, n2); d.addArc(n2, n1); @@ -136,23 +136,23 @@ check(loopFree(g), "This graph is loop-free."); check(!parallelFree(g), "This graph is not parallel-free."); check(!simpleGraph(g), "This graph is not simple."); - + d.addArc(n3, n3); - + check(!loopFree(d), "This digraph is not loop-free."); check(!loopFree(g), "This graph is not loop-free."); check(!simpleGraph(d), "This digraph is not simple."); - + d.addArc(n3, n2); - + check(!parallelFree(d), "This digraph is not parallel-free."); } - + { Digraph d; Digraph::ArcMap cutarcs(d, false); Graph g(d); - + Digraph::Node n1 = d.addNode(); Digraph::Node n2 = d.addNode(); Digraph::Node n3 = d.addNode(); @@ -172,7 +172,7 @@ d.addArc(n1, n8); d.addArc(n6, n7); d.addArc(n7, n6); - + check(!stronglyConnected(d), "This digraph is not strongly connected"); check(countStronglyConnectedComponents(d) == 3, "This digraph has 3 strongly connected components"); @@ -235,7 +235,7 @@ // (T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein) Digraph d; Digraph::NodeMap order(d); - + Digraph::Node belt = d.addNode(); Digraph::Node trousers = d.addNode(); Digraph::Node necktie = d.addNode(); @@ -255,7 +255,7 @@ d.addArc(shirt, belt); d.addArc(shirt, necktie); d.addArc(necktie, coat); - + check(dag(d), "This digraph is DAG."); topologicalSort(d, order); for (Digraph::ArcIt a(d); a != INVALID; ++a) { @@ -267,7 +267,7 @@ { ListGraph g; ListGraph::NodeMap map(g); - + ListGraph::Node n1 = g.addNode(); ListGraph::Node n2 = g.addNode(); ListGraph::Node n3 = g.addNode(); @@ -283,10 +283,10 @@ g.addEdge(n4, n6); g.addEdge(n4, n7); g.addEdge(n5, n7); - + check(bipartite(g), "This graph is bipartite"); check(bipartitePartitions(g, map), "This graph is bipartite"); - + check(map[n1] == map[n2] && map[n1] == map[n6] && map[n1] == map[n7], "Wrong bipartitePartitions()"); check(map[n3] == map[n4] && map[n3] == map[n5], diff --git a/test/dfs_test.cc b/test/dfs_test.cc --- a/test/dfs_test.cc +++ b/test/dfs_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -86,7 +86,7 @@ e = const_dfs_test.nextArc(); b = const_dfs_test.emptyQueue(); i = const_dfs_test.queueSize(); - + dfs_test.start(); dfs_test.start(t); dfs_test.start(am); @@ -112,7 +112,7 @@ concepts::ReadWriteMap dist_map; concepts::ReadWriteMap reached_map; concepts::WriteMap processed_map; - + dfs_test .predMap(pred_map) .distMap(dist_map) @@ -129,7 +129,7 @@ e = dfs_test.nextArc(); b = dfs_test.emptyQueue(); i = dfs_test.queueSize(); - + dfs_test.start(); dfs_test.start(t); dfs_test.start(am); diff --git a/test/digraph_test.cc b/test/digraph_test.cc --- a/test/digraph_test.cc +++ b/test/digraph_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "test_tools.h" @@ -35,6 +36,9 @@ checkGraphNodeList(G, 0); checkGraphArcList(G, 0); + G.reserveNode(3); + G.reserveArc(4); + Node n1 = G.addNode(), n2 = G.addNode(), @@ -283,6 +287,14 @@ G.addArc(G.addNode(), G.addNode()); snapshot.restore(); + snapshot.save(G); + + checkGraphNodeList(G, 4); + checkGraphArcList(G, 4); + + G.addArc(G.addNode(), G.addNode()); + + snapshot.restore(); checkGraphNodeList(G, 4); checkGraphArcList(G, 4); @@ -317,6 +329,10 @@ checkConcept, SmartDigraph>(); checkConcept, SmartDigraph>(); } + { // Checking StaticDigraph + checkConcept(); + checkConcept, StaticDigraph>(); + } { // Checking FullDigraph checkConcept(); } @@ -372,10 +388,122 @@ check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); } +void checkStaticDigraph() { + SmartDigraph g; + SmartDigraph::NodeMap nref(g); + SmartDigraph::ArcMap aref(g); + + StaticDigraph G; + + checkGraphNodeList(G, 0); + checkGraphArcList(G, 0); + + G.build(g, nref, aref); + + checkGraphNodeList(G, 0); + checkGraphArcList(G, 0); + + SmartDigraph::Node + n1 = g.addNode(), + n2 = g.addNode(), + n3 = g.addNode(); + + G.build(g, nref, aref); + + checkGraphNodeList(G, 3); + checkGraphArcList(G, 0); + + SmartDigraph::Arc a1 = g.addArc(n1, n2); + + G.build(g, nref, aref); + + check(G.source(aref[a1]) == nref[n1] && G.target(aref[a1]) == nref[n2], + "Wrong arc or wrong references"); + checkGraphNodeList(G, 3); + checkGraphArcList(G, 1); + + checkGraphOutArcList(G, nref[n1], 1); + checkGraphOutArcList(G, nref[n2], 0); + checkGraphOutArcList(G, nref[n3], 0); + + checkGraphInArcList(G, nref[n1], 0); + checkGraphInArcList(G, nref[n2], 1); + checkGraphInArcList(G, nref[n3], 0); + + checkGraphConArcList(G, 1); + + SmartDigraph::Arc + a2 = g.addArc(n2, n1), + a3 = g.addArc(n2, n3), + a4 = g.addArc(n2, n3); + + digraphCopy(g, G).nodeRef(nref).run(); + + checkGraphNodeList(G, 3); + checkGraphArcList(G, 4); + + checkGraphOutArcList(G, nref[n1], 1); + checkGraphOutArcList(G, nref[n2], 3); + checkGraphOutArcList(G, nref[n3], 0); + + checkGraphInArcList(G, nref[n1], 1); + checkGraphInArcList(G, nref[n2], 1); + checkGraphInArcList(G, nref[n3], 2); + + checkGraphConArcList(G, 4); + + std::vector > arcs; + arcs.push_back(std::make_pair(0,1)); + arcs.push_back(std::make_pair(0,2)); + arcs.push_back(std::make_pair(1,3)); + arcs.push_back(std::make_pair(1,2)); + arcs.push_back(std::make_pair(3,0)); + arcs.push_back(std::make_pair(3,3)); + arcs.push_back(std::make_pair(4,2)); + arcs.push_back(std::make_pair(4,3)); + arcs.push_back(std::make_pair(4,1)); + + G.build(6, arcs.begin(), arcs.end()); + + checkGraphNodeList(G, 6); + checkGraphArcList(G, 9); + + checkGraphOutArcList(G, G.node(0), 2); + checkGraphOutArcList(G, G.node(1), 2); + checkGraphOutArcList(G, G.node(2), 0); + checkGraphOutArcList(G, G.node(3), 2); + checkGraphOutArcList(G, G.node(4), 3); + checkGraphOutArcList(G, G.node(5), 0); + + checkGraphInArcList(G, G.node(0), 1); + checkGraphInArcList(G, G.node(1), 2); + checkGraphInArcList(G, G.node(2), 3); + checkGraphInArcList(G, G.node(3), 3); + checkGraphInArcList(G, G.node(4), 0); + checkGraphInArcList(G, G.node(5), 0); + + checkGraphConArcList(G, 9); + + checkNodeIds(G); + checkArcIds(G); + checkGraphNodeMap(G); + checkGraphArcMap(G); + + int n = G.nodeNum(); + int m = G.arcNum(); + check(G.index(G.node(n-1)) == n-1, "Wrong index."); + check(G.index(G.arc(m-1)) == m-1, "Wrong index."); +} + void checkFullDigraph(int num) { typedef FullDigraph Digraph; DIGRAPH_TYPEDEFS(Digraph); + Digraph G(num); + check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size"); + + G.resize(num); + check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size"); checkGraphNodeList(G, num); checkGraphArcList(G, num * num); @@ -419,6 +547,9 @@ checkDigraphSnapshot(); checkDigraphValidity(); } + { // Checking StaticDigraph + checkStaticDigraph(); + } { // Checking FullDigraph checkFullDigraph(8); } diff --git a/test/dijkstra_test.cc b/test/dijkstra_test.cc --- a/test/dijkstra_test.cc +++ b/test/dijkstra_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -85,7 +85,7 @@ n = const_dijkstra_test.nextNode(); b = const_dijkstra_test.emptyQueue(); i = const_dijkstra_test.queueSize(); - + dijkstra_test.start(); dijkstra_test.start(t); dijkstra_test.start(nm); @@ -109,7 +109,7 @@ ::SetOperationTraits > ::SetHeap > > ::SetStandardHeap > > - ::SetHeap >, + ::SetHeap >, concepts::ReadWriteMap > ::Create dijkstra_test(G,length); @@ -119,7 +119,7 @@ concepts::WriteMap processed_map; concepts::ReadWriteMap heap_cross_ref; BinHeap > heap(heap_cross_ref); - + dijkstra_test .lengthMap(length_map) .predMap(pred_map) @@ -136,7 +136,7 @@ n = dijkstra_test.nextNode(); b = dijkstra_test.emptyQueue(); i = dijkstra_test.queueSize(); - + dijkstra_test.start(); dijkstra_test.start(t); dijkstra_test.start(nm); diff --git a/test/edge_set_test.cc b/test/edge_set_test.cc --- a/test/edge_set_test.cc +++ b/test/edge_set_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff --git a/test/euler_test.cc b/test/euler_test.cc --- a/test/euler_test.cc +++ b/test/euler_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -85,11 +85,11 @@ { typedef ListDigraph Digraph; typedef Undirector Graph; - + { Digraph d; Graph g(d); - + checkDiEulerIt(d); checkDiEulerIt(g); checkEulerIt(g); @@ -128,7 +128,7 @@ Digraph::Node n1 = d.addNode(); Digraph::Node n2 = d.addNode(); Digraph::Node n3 = d.addNode(); - + d.addArc(n1, n2); d.addArc(n2, n1); d.addArc(n2, n3); @@ -153,7 +153,7 @@ Digraph::Node n4 = d.addNode(); Digraph::Node n5 = d.addNode(); Digraph::Node n6 = d.addNode(); - + d.addArc(n1, n2); d.addArc(n2, n4); d.addArc(n1, n3); @@ -189,7 +189,7 @@ Digraph::Node n3 = d.addNode(); Digraph::Node n4 = d.addNode(); Digraph::Node n5 = d.addNode(); - + d.addArc(n1, n2); d.addArc(n2, n3); d.addArc(n3, n1); @@ -211,7 +211,7 @@ Digraph::Node n1 = d.addNode(); Digraph::Node n2 = d.addNode(); Digraph::Node n3 = d.addNode(); - + d.addArc(n1, n2); d.addArc(n2, n3); diff --git a/test/fractional_matching_test.cc b/test/fractional_matching_test.cc new file mode 100644 --- /dev/null +++ b/test/fractional_matching_test.cc @@ -0,0 +1,525 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "test_tools.h" + +using namespace std; +using namespace lemon; + +GRAPH_TYPEDEFS(SmartGraph); + + +const int lgfn = 4; +const std::string lgf[lgfn] = { + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@edges\n" + " label weight\n" + "7 4 0 984\n" + "0 7 1 73\n" + "7 1 2 204\n" + "2 3 3 583\n" + "2 7 4 565\n" + "2 1 5 582\n" + "0 4 6 551\n" + "2 5 7 385\n" + "1 5 8 561\n" + "5 3 9 484\n" + "7 5 10 904\n" + "3 6 11 47\n" + "7 6 12 888\n" + "3 0 13 747\n" + "6 1 14 310\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@edges\n" + " label weight\n" + "2 5 0 710\n" + "0 5 1 241\n" + "2 4 2 856\n" + "2 6 3 762\n" + "4 1 4 747\n" + "6 1 5 962\n" + "4 7 6 723\n" + "1 7 7 661\n" + "2 3 8 376\n" + "1 0 9 416\n" + "6 7 10 391\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@edges\n" + " label weight\n" + "6 2 0 553\n" + "0 7 1 653\n" + "6 3 2 22\n" + "4 7 3 846\n" + "7 2 4 981\n" + "7 6 5 250\n" + "5 2 6 539\n", + + "@nodes\n" + "label\n" + "0\n" + "@edges\n" + " label weight\n" + "0 0 0 100\n" +}; + +void checkMaxFractionalMatchingCompile() +{ + typedef concepts::Graph Graph; + typedef Graph::Node Node; + typedef Graph::Edge Edge; + + Graph g; + Node n; + Edge e; + + MaxFractionalMatching mat_test(g); + const MaxFractionalMatching& + const_mat_test = mat_test; + + mat_test.init(); + mat_test.start(); + mat_test.start(true); + mat_test.startPerfect(); + mat_test.startPerfect(true); + mat_test.run(); + mat_test.run(true); + mat_test.runPerfect(); + mat_test.runPerfect(true); + + const_mat_test.matchingSize(); + const_mat_test.matching(e); + const_mat_test.matching(n); + const MaxFractionalMatching::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + + const_mat_test.barrier(n); +} + +void checkMaxWeightedFractionalMatchingCompile() +{ + typedef concepts::Graph Graph; + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef Graph::EdgeMap WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedFractionalMatching mat_test(g, w); + const MaxWeightedFractionalMatching& + const_mat_test = mat_test; + + mat_test.init(); + mat_test.start(); + mat_test.run(); + + const_mat_test.matchingWeight(); + const_mat_test.matchingSize(); + const_mat_test.matching(e); + const_mat_test.matching(n); + const MaxWeightedFractionalMatching::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + + const_mat_test.dualValue(); + const_mat_test.nodeValue(n); +} + +void checkMaxWeightedPerfectFractionalMatchingCompile() +{ + typedef concepts::Graph Graph; + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef Graph::EdgeMap WeightMap; + + Graph g; + Node n; + Edge e; + WeightMap w(g); + + MaxWeightedPerfectFractionalMatching mat_test(g, w); + const MaxWeightedPerfectFractionalMatching& + const_mat_test = mat_test; + + mat_test.init(); + mat_test.start(); + mat_test.run(); + + const_mat_test.matchingWeight(); + const_mat_test.matching(e); + const_mat_test.matching(n); + const MaxWeightedPerfectFractionalMatching::MatchingMap& mmap = + const_mat_test.matchingMap(); + e = mmap[n]; + + const_mat_test.dualValue(); + const_mat_test.nodeValue(n); +} + +void checkFractionalMatching(const SmartGraph& graph, + const MaxFractionalMatching& mfm, + bool allow_loops = true) { + int pv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + int indeg = 0; + for (InArcIt a(graph, n); a != INVALID; ++a) { + if (mfm.matching(graph.source(a)) == a) { + ++indeg; + } + } + if (mfm.matching(n) != INVALID) { + check(indeg == 1, "Invalid matching"); + ++pv; + } else { + check(indeg == 0, "Invalid matching"); + } + } + check(pv == mfm.matchingSize(), "Wrong matching size"); + + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + check((e == mfm.matching(graph.u(e)) ? 1 : 0) + + (e == mfm.matching(graph.v(e)) ? 1 : 0) == + mfm.matching(e), "Invalid matching"); + } + + SmartGraph::NodeMap processed(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (mfm.matching(n) == INVALID) continue; + int num = 1; + Node v = graph.target(mfm.matching(n)); + while (v != n) { + processed[v] = true; + ++num; + v = graph.target(mfm.matching(v)); + } + check(num == 2 || num % 2 == 1, "Wrong cycle size"); + check(allow_loops || num != 1, "Wrong cycle size"); + } + + int anum = 0, bnum = 0; + SmartGraph::NodeMap neighbours(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (!mfm.barrier(n)) continue; + ++anum; + for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) { + Node u = graph.source(a); + if (!allow_loops && u == n) continue; + if (!neighbours[u]) { + neighbours[u] = true; + ++bnum; + } + } + } + check(anum - bnum + mfm.matchingSize() == countNodes(graph), + "Wrong barrier"); +} + +void checkPerfectFractionalMatching(const SmartGraph& graph, + const MaxFractionalMatching& mfm, + bool perfect, bool allow_loops = true) { + if (perfect) { + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + int indeg = 0; + for (InArcIt a(graph, n); a != INVALID; ++a) { + if (mfm.matching(graph.source(a)) == a) { + ++indeg; + } + } + check(mfm.matching(n) != INVALID, "Invalid matching"); + check(indeg == 1, "Invalid matching"); + } + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + check((e == mfm.matching(graph.u(e)) ? 1 : 0) + + (e == mfm.matching(graph.v(e)) ? 1 : 0) == + mfm.matching(e), "Invalid matching"); + } + } else { + int anum = 0, bnum = 0; + SmartGraph::NodeMap neighbours(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (!mfm.barrier(n)) continue; + ++anum; + for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) { + Node u = graph.source(a); + if (!allow_loops && u == n) continue; + if (!neighbours[u]) { + neighbours[u] = true; + ++bnum; + } + } + } + check(anum - bnum > 0, "Wrong barrier"); + } +} + +void checkWeightedFractionalMatching(const SmartGraph& graph, + const SmartGraph::EdgeMap& weight, + const MaxWeightedFractionalMatching& mwfm, + bool allow_loops = true) { + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + if (graph.u(e) == graph.v(e) && !allow_loops) continue; + int rw = mwfm.nodeValue(graph.u(e)) + mwfm.nodeValue(graph.v(e)) + - weight[e] * mwfm.dualScale; + + check(rw >= 0, "Negative reduced weight"); + check(rw == 0 || !mwfm.matching(e), + "Non-zero reduced weight on matching edge"); + } + + int pv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + int indeg = 0; + for (InArcIt a(graph, n); a != INVALID; ++a) { + if (mwfm.matching(graph.source(a)) == a) { + ++indeg; + } + } + check(indeg <= 1, "Invalid matching"); + if (mwfm.matching(n) != INVALID) { + check(mwfm.nodeValue(n) >= 0, "Invalid node value"); + check(indeg == 1, "Invalid matching"); + pv += weight[mwfm.matching(n)]; + SmartGraph::Node o = graph.target(mwfm.matching(n)); + } else { + check(mwfm.nodeValue(n) == 0, "Invalid matching"); + check(indeg == 0, "Invalid matching"); + } + } + + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + check((e == mwfm.matching(graph.u(e)) ? 1 : 0) + + (e == mwfm.matching(graph.v(e)) ? 1 : 0) == + mwfm.matching(e), "Invalid matching"); + } + + int dv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + dv += mwfm.nodeValue(n); + } + + check(pv * mwfm.dualScale == dv * 2, "Wrong duality"); + + SmartGraph::NodeMap processed(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (mwfm.matching(n) == INVALID) continue; + int num = 1; + Node v = graph.target(mwfm.matching(n)); + while (v != n) { + processed[v] = true; + ++num; + v = graph.target(mwfm.matching(v)); + } + check(num == 2 || num % 2 == 1, "Wrong cycle size"); + check(allow_loops || num != 1, "Wrong cycle size"); + } + + return; +} + +void checkWeightedPerfectFractionalMatching(const SmartGraph& graph, + const SmartGraph::EdgeMap& weight, + const MaxWeightedPerfectFractionalMatching& mwpfm, + bool allow_loops = true) { + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + if (graph.u(e) == graph.v(e) && !allow_loops) continue; + int rw = mwpfm.nodeValue(graph.u(e)) + mwpfm.nodeValue(graph.v(e)) + - weight[e] * mwpfm.dualScale; + + check(rw >= 0, "Negative reduced weight"); + check(rw == 0 || !mwpfm.matching(e), + "Non-zero reduced weight on matching edge"); + } + + int pv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + int indeg = 0; + for (InArcIt a(graph, n); a != INVALID; ++a) { + if (mwpfm.matching(graph.source(a)) == a) { + ++indeg; + } + } + check(mwpfm.matching(n) != INVALID, "Invalid perfect matching"); + check(indeg == 1, "Invalid perfect matching"); + pv += weight[mwpfm.matching(n)]; + SmartGraph::Node o = graph.target(mwpfm.matching(n)); + } + + for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { + check((e == mwpfm.matching(graph.u(e)) ? 1 : 0) + + (e == mwpfm.matching(graph.v(e)) ? 1 : 0) == + mwpfm.matching(e), "Invalid matching"); + } + + int dv = 0; + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + dv += mwpfm.nodeValue(n); + } + + check(pv * mwpfm.dualScale == dv * 2, "Wrong duality"); + + SmartGraph::NodeMap processed(graph, false); + for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { + if (processed[n]) continue; + processed[n] = true; + if (mwpfm.matching(n) == INVALID) continue; + int num = 1; + Node v = graph.target(mwpfm.matching(n)); + while (v != n) { + processed[v] = true; + ++num; + v = graph.target(mwpfm.matching(v)); + } + check(num == 2 || num % 2 == 1, "Wrong cycle size"); + check(allow_loops || num != 1, "Wrong cycle size"); + } + + return; +} + + +int main() { + + for (int i = 0; i < lgfn; ++i) { + SmartGraph graph; + SmartGraph::EdgeMap weight(graph); + + istringstream lgfs(lgf[i]); + graphReader(graph, lgfs). + edgeMap("weight", weight).run(); + + bool perfect_with_loops; + { + MaxFractionalMatching mfm(graph, true); + mfm.run(); + checkFractionalMatching(graph, mfm, true); + perfect_with_loops = mfm.matchingSize() == countNodes(graph); + } + + bool perfect_without_loops; + { + MaxFractionalMatching mfm(graph, false); + mfm.run(); + checkFractionalMatching(graph, mfm, false); + perfect_without_loops = mfm.matchingSize() == countNodes(graph); + } + + { + MaxFractionalMatching mfm(graph, true); + bool result = mfm.runPerfect(); + checkPerfectFractionalMatching(graph, mfm, result, true); + check(result == perfect_with_loops, "Wrong perfect matching"); + } + + { + MaxFractionalMatching mfm(graph, false); + bool result = mfm.runPerfect(); + checkPerfectFractionalMatching(graph, mfm, result, false); + check(result == perfect_without_loops, "Wrong perfect matching"); + } + + { + MaxWeightedFractionalMatching mwfm(graph, weight, true); + mwfm.run(); + checkWeightedFractionalMatching(graph, weight, mwfm, true); + } + + { + MaxWeightedFractionalMatching mwfm(graph, weight, false); + mwfm.run(); + checkWeightedFractionalMatching(graph, weight, mwfm, false); + } + + { + MaxWeightedPerfectFractionalMatching mwpfm(graph, weight, + true); + bool perfect = mwpfm.run(); + check(perfect == (mwpfm.matchingSize() == countNodes(graph)), + "Perfect matching found"); + check(perfect == perfect_with_loops, "Wrong perfect matching"); + + if (perfect) { + checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, true); + } + } + + { + MaxWeightedPerfectFractionalMatching mwpfm(graph, weight, + false); + bool perfect = mwpfm.run(); + check(perfect == (mwpfm.matchingSize() == countNodes(graph)), + "Perfect matching found"); + check(perfect == perfect_without_loops, "Wrong perfect matching"); + + if (perfect) { + checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, false); + } + } + + } + + return 0; +} diff --git a/test/gomory_hu_test.cc b/test/gomory_hu_test.cc --- a/test/gomory_hu_test.cc +++ b/test/gomory_hu_test.cc @@ -1,3 +1,21 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + #include #include "test_tools.h" @@ -33,7 +51,7 @@ "@attributes\n" "source 0\n" "target 3\n"; - + void checkGomoryHuCompile() { typedef int Value; @@ -69,7 +87,7 @@ typedef Graph::NodeMap BoolNodeMap; int cutValue(const Graph& graph, const BoolNodeMap& cut, - const IntEdgeMap& capacity) { + const IntEdgeMap& capacity) { int sum = 0; for (EdgeIt e(graph); e != INVALID; ++e) { @@ -107,7 +125,7 @@ int sum=0; for(GomoryHu::MinCutEdgeIt a(ght, u, v);a!=INVALID;++a) - sum+=capacity[a]; + sum+=capacity[a]; check(sum == ght.minCutValue(u, v), "Problem with MinCutEdgeIt"); sum=0; @@ -118,6 +136,6 @@ check(sum == countNodes(graph), "Problem with MinCutNodeIt"); } } - + return 0; } diff --git a/test/graph_test.cc b/test/graph_test.cc --- a/test/graph_test.cc +++ b/test/graph_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -38,6 +38,9 @@ checkGraphEdgeList(G, 0); checkGraphArcList(G, 0); + G.reserveNode(3); + G.reserveEdge(3); + Node n1 = G.addNode(), n2 = G.addNode(), @@ -256,6 +259,15 @@ G.addEdge(G.addNode(), G.addNode()); snapshot.restore(); + snapshot.save(G); + + checkGraphNodeList(G, 4); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + G.addEdge(G.addNode(), G.addNode()); + + snapshot.restore(); checkGraphNodeList(G, 4); checkGraphEdgeList(G, 3); @@ -267,6 +279,13 @@ GRAPH_TYPEDEFS(Graph); Graph G(num); + check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2, + "Wrong size"); + + G.resize(num); + check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2, + "Wrong size"); + checkGraphNodeList(G, num); checkGraphEdgeList(G, num * (num - 1) / 2); @@ -411,6 +430,10 @@ check(G.width() == width, "Wrong column number"); check(G.height() == height, "Wrong row number"); + G.resize(width, height); + check(G.width() == width, "Wrong column number"); + check(G.height() == height, "Wrong row number"); + for (int i = 0; i < width; ++i) { for (int j = 0; j < height; ++j) { check(G.col(G(i, j)) == i, "Wrong column"); @@ -486,6 +509,11 @@ GRAPH_TYPEDEFS(HypercubeGraph); HypercubeGraph G(dim); + check(G.dimension() == dim, "Wrong dimension"); + + G.resize(dim); + check(G.dimension() == dim, "Wrong dimension"); + checkGraphNodeList(G, 1 << dim); checkGraphEdgeList(G, dim * (1 << (dim-1))); checkGraphArcList(G, dim * (1 << dim)); diff --git a/test/hao_orlin_test.cc b/test/hao_orlin_test.cc --- a/test/hao_orlin_test.cc +++ b/test/hao_orlin_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -83,7 +83,7 @@ } template -typename CapMap::Value +typename CapMap::Value cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut) { typename CapMap::Value sum = 0; @@ -110,7 +110,7 @@ HaoOrlin ho(graph, cap1); ho.run(); ho.minCutMap(cut); - + check(ho.minCutValue() == 1, "Wrong cut value"); check(ho.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value"); } @@ -126,19 +126,19 @@ HaoOrlin ho(graph, cap3); ho.run(); ho.minCutMap(cut); - + check(ho.minCutValue() == 1, "Wrong cut value"); check(ho.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value"); } - + typedef Undirector UGraph; UGraph ugraph(graph); - + { HaoOrlin > ho(ugraph, cap1); ho.run(); ho.minCutMap(cut); - + check(ho.minCutValue() == 2, "Wrong cut value"); check(ho.minCutValue() == cutValue(ugraph, cap1, cut), "Wrong cut value"); } @@ -146,7 +146,7 @@ HaoOrlin > ho(ugraph, cap2); ho.run(); ho.minCutMap(cut); - + check(ho.minCutValue() == 5, "Wrong cut value"); check(ho.minCutValue() == cutValue(ugraph, cap2, cut), "Wrong cut value"); } @@ -154,7 +154,7 @@ HaoOrlin > ho(ugraph, cap3); ho.run(); ho.minCutMap(cut); - + check(ho.minCutValue() == 5, "Wrong cut value"); check(ho.minCutValue() == cutValue(ugraph, cap3, cut), "Wrong cut value"); } diff --git a/test/heap_test.cc b/test/heap_test.cc --- a/test/heap_test.cc +++ b/test/heap_test.cc @@ -25,14 +25,17 @@ #include #include - #include #include #include #include +#include +#include #include +#include #include +#include #include #include "test_tools.h" @@ -89,18 +92,16 @@ template void heapSortTest() { RangeMap map(test_len, -1); - Heap heap(map); std::vector v(test_len); - for (int i = 0; i < test_len; ++i) { v[i] = test_seq[i]; heap.push(i, v[i]); } std::sort(v.begin(), v.end()); for (int i = 0; i < test_len; ++i) { - check(v[i] == heap.prio() ,"Wrong order in heap sort."); + check(v[i] == heap.prio(), "Wrong order in heap sort."); heap.pop(); } } @@ -112,7 +113,6 @@ Heap heap(map); std::vector v(test_len); - for (int i = 0; i < test_len; ++i) { v[i] = test_seq[i]; heap.push(i, v[i]); @@ -123,13 +123,11 @@ } std::sort(v.begin(), v.end()); for (int i = 0; i < test_len; ++i) { - check(v[i] == heap.prio() ,"Wrong order in heap increase test."); + check(v[i] == heap.prio(), "Wrong order in heap increase test."); heap.pop(); } } - - template void dijkstraHeapTest(const Digraph& digraph, const IntArcMap& length, Node source) { @@ -144,7 +142,7 @@ Node t = digraph.target(a); if (dijkstra.reached(s)) { check( dijkstra.dist(t) - dijkstra.dist(s) <= length[a], - "Error in a shortest path tree!"); + "Error in shortest path tree."); } } @@ -153,7 +151,7 @@ Arc a = dijkstra.predArc(n); Node s = digraph.source(a); check( dijkstra.dist(n) - dijkstra.dist(s) == length[a], - "Error in a shortest path tree!"); + "Error in shortest path tree."); } } @@ -175,6 +173,7 @@ node("source", source). run(); + // BinHeap { typedef BinHeap IntHeap; checkConcept, IntHeap>(); @@ -186,6 +185,93 @@ dijkstraHeapTest(digraph, length, source); } + // QuadHeap + { + typedef QuadHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef QuadHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // DHeap + { + typedef DHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef DHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // FibHeap + { + typedef FibHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef FibHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // PairingHeap + { + typedef PairingHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef PairingHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // RadixHeap + { + typedef RadixHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef RadixHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // BinomialHeap + { + typedef BinomialHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef BinomialHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + } + + // BucketHeap, SimpleBucketHeap + { + typedef BucketHeap IntHeap; + checkConcept, IntHeap>(); + heapSortTest(); + heapIncreaseTest(); + + typedef BucketHeap NodeHeap; + checkConcept, NodeHeap>(); + dijkstraHeapTest(digraph, length, source); + + typedef SimpleBucketHeap SimpleIntHeap; + heapSortTest(); + } + { typedef FibHeap IntHeap; checkConcept, IntHeap>(); diff --git a/test/maps_test.cc b/test/maps_test.cc --- a/test/maps_test.cc +++ b/test/maps_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include "test_tools.h" @@ -34,9 +38,22 @@ struct B {}; class C { - int x; + int _x; public: - C(int _x) : x(_x) {} + C(int x) : _x(x) {} + int get() const { return _x; } +}; +inline bool operator<(C c1, C c2) { return c1.get() < c2.get(); } +inline bool operator==(C c1, C c2) { return c1.get() == c2.get(); } + +C createC(int x) { return C(x); } + +template +class Less { + T _t; +public: + Less(T t): _t(t) {} + bool operator()(const T& t) const { return t < _t; } }; class F { @@ -53,6 +70,14 @@ int binc(int a, B) { return a+1; } +template +class Sum { + T& _sum; +public: + Sum(T& sum) : _sum(sum) {} + void operator()(const T& t) { _sum += t; } +}; + typedef ReadMap DoubleMap; typedef ReadWriteMap DoubleWriteMap; typedef ReferenceMap DoubleRefMap; @@ -200,7 +225,8 @@ B b = functorToMap(F())[A()]; checkConcept, MapToFunctor > >(); - MapToFunctor > map = MapToFunctor >(ReadMap()); + MapToFunctor > map = + MapToFunctor >(ReadMap()); check(functorToMap(&func)[A()] == 3, "Something is wrong with FunctorToMap"); @@ -329,6 +355,10 @@ // LoggerBoolMap { typedef std::vector vec; + checkConcept, LoggerBoolMap >(); + checkConcept, + LoggerBoolMap > >(); + vec v1; vec v2(10); LoggerBoolMap > @@ -348,8 +378,158 @@ for ( LoggerBoolMap::Iterator it = map2.begin(); it != map2.end(); ++it ) check(v1[i++] == *it, "Something is wrong with LoggerBoolMap"); + + typedef ListDigraph Graph; + DIGRAPH_TYPEDEFS(Graph); + Graph gr; + + Node n0 = gr.addNode(); + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + Node n3 = gr.addNode(); + + gr.addArc(n3, n0); + gr.addArc(n3, n2); + gr.addArc(n0, n2); + gr.addArc(n2, n1); + gr.addArc(n0, n1); + + { + std::vector v; + dfs(gr).processedMap(loggerBoolMap(std::back_inserter(v))).run(); + + check(v.size()==4 && v[0]==n1 && v[1]==n2 && v[2]==n0 && v[3]==n3, + "Something is wrong with LoggerBoolMap"); + } + { + std::vector v(countNodes(gr)); + dfs(gr).processedMap(loggerBoolMap(v.begin())).run(); + + check(v.size()==4 && v[0]==n1 && v[1]==n2 && v[2]==n0 && v[3]==n3, + "Something is wrong with LoggerBoolMap"); + } } - + + // IdMap, RangeIdMap + { + typedef ListDigraph Graph; + DIGRAPH_TYPEDEFS(Graph); + + checkConcept, IdMap >(); + checkConcept, IdMap >(); + checkConcept, RangeIdMap >(); + checkConcept, RangeIdMap >(); + + Graph gr; + IdMap nmap(gr); + IdMap amap(gr); + RangeIdMap nrmap(gr); + RangeIdMap armap(gr); + + Node n0 = gr.addNode(); + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + + Arc a0 = gr.addArc(n0, n1); + Arc a1 = gr.addArc(n0, n2); + Arc a2 = gr.addArc(n2, n1); + Arc a3 = gr.addArc(n2, n0); + + check(nmap[n0] == gr.id(n0) && nmap(gr.id(n0)) == n0, "Wrong IdMap"); + check(nmap[n1] == gr.id(n1) && nmap(gr.id(n1)) == n1, "Wrong IdMap"); + check(nmap[n2] == gr.id(n2) && nmap(gr.id(n2)) == n2, "Wrong IdMap"); + + check(amap[a0] == gr.id(a0) && amap(gr.id(a0)) == a0, "Wrong IdMap"); + check(amap[a1] == gr.id(a1) && amap(gr.id(a1)) == a1, "Wrong IdMap"); + check(amap[a2] == gr.id(a2) && amap(gr.id(a2)) == a2, "Wrong IdMap"); + check(amap[a3] == gr.id(a3) && amap(gr.id(a3)) == a3, "Wrong IdMap"); + + check(nmap.inverse()[gr.id(n0)] == n0, "Wrong IdMap::InverseMap"); + check(amap.inverse()[gr.id(a0)] == a0, "Wrong IdMap::InverseMap"); + + check(nrmap.size() == 3 && armap.size() == 4, + "Wrong RangeIdMap::size()"); + + check(nrmap[n0] == 0 && nrmap(0) == n0, "Wrong RangeIdMap"); + check(nrmap[n1] == 1 && nrmap(1) == n1, "Wrong RangeIdMap"); + check(nrmap[n2] == 2 && nrmap(2) == n2, "Wrong RangeIdMap"); + + check(armap[a0] == 0 && armap(0) == a0, "Wrong RangeIdMap"); + check(armap[a1] == 1 && armap(1) == a1, "Wrong RangeIdMap"); + check(armap[a2] == 2 && armap(2) == a2, "Wrong RangeIdMap"); + check(armap[a3] == 3 && armap(3) == a3, "Wrong RangeIdMap"); + + check(nrmap.inverse()[0] == n0, "Wrong RangeIdMap::InverseMap"); + check(armap.inverse()[0] == a0, "Wrong RangeIdMap::InverseMap"); + + gr.erase(n1); + + if (nrmap[n0] == 1) nrmap.swap(n0, n2); + nrmap.swap(n2, n0); + if (armap[a1] == 1) armap.swap(a1, a3); + armap.swap(a3, a1); + + check(nrmap.size() == 2 && armap.size() == 2, + "Wrong RangeIdMap::size()"); + + check(nrmap[n0] == 1 && nrmap(1) == n0, "Wrong RangeIdMap"); + check(nrmap[n2] == 0 && nrmap(0) == n2, "Wrong RangeIdMap"); + + check(armap[a1] == 1 && armap(1) == a1, "Wrong RangeIdMap"); + check(armap[a3] == 0 && armap(0) == a3, "Wrong RangeIdMap"); + + check(nrmap.inverse()[0] == n2, "Wrong RangeIdMap::InverseMap"); + check(armap.inverse()[0] == a3, "Wrong RangeIdMap::InverseMap"); + } + + // SourceMap, TargetMap, ForwardMap, BackwardMap, InDegMap, OutDegMap + { + typedef ListGraph Graph; + GRAPH_TYPEDEFS(Graph); + + checkConcept, SourceMap >(); + checkConcept, TargetMap >(); + checkConcept, ForwardMap >(); + checkConcept, BackwardMap >(); + checkConcept, InDegMap >(); + checkConcept, OutDegMap >(); + + Graph gr; + Node n0 = gr.addNode(); + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + + gr.addEdge(n0,n1); + gr.addEdge(n1,n2); + gr.addEdge(n0,n2); + gr.addEdge(n2,n1); + gr.addEdge(n1,n2); + gr.addEdge(n0,n1); + + for (EdgeIt e(gr); e != INVALID; ++e) { + check(forwardMap(gr)[e] == gr.direct(e, true), "Wrong ForwardMap"); + check(backwardMap(gr)[e] == gr.direct(e, false), "Wrong BackwardMap"); + } + + check(mapCompare(gr, + sourceMap(orienter(gr, constMap(true))), + targetMap(orienter(gr, constMap(false)))), + "Wrong SourceMap or TargetMap"); + + typedef Orienter > Digraph; + Digraph dgr(gr, constMap(true)); + OutDegMap odm(dgr); + InDegMap idm(dgr); + + check(odm[n0] == 3 && odm[n1] == 2 && odm[n2] == 1, "Wrong OutDegMap"); + check(idm[n0] == 0 && idm[n1] == 3 && idm[n2] == 3, "Wrong InDegMap"); + + gr.addEdge(n2, n0); + + check(odm[n0] == 3 && odm[n1] == 2 && odm[n2] == 2, "Wrong OutDegMap"); + check(idm[n0] == 1 && idm[n1] == 3 && idm[n2] == 3, "Wrong InDegMap"); + } + // CrossRefMap { typedef ListDigraph Graph; @@ -357,16 +537,83 @@ checkConcept, CrossRefMap >(); - + checkConcept, + CrossRefMap >(); + checkConcept, + CrossRefMap >(); + + Graph gr; + typedef CrossRefMap CRMap; + CRMap map(gr); + + Node n0 = gr.addNode(); + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + + map.set(n0, 'A'); + map.set(n1, 'B'); + map.set(n2, 'C'); + + check(map[n0] == 'A' && map('A') == n0 && map.inverse()['A'] == n0, + "Wrong CrossRefMap"); + check(map[n1] == 'B' && map('B') == n1 && map.inverse()['B'] == n1, + "Wrong CrossRefMap"); + check(map[n2] == 'C' && map('C') == n2 && map.inverse()['C'] == n2, + "Wrong CrossRefMap"); + check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1, + "Wrong CrossRefMap::count()"); + + CRMap::ValueIt it = map.beginValue(); + check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && + it == map.endValue(), "Wrong value iterator"); + + map.set(n2, 'A'); + + check(map[n0] == 'A' && map[n1] == 'B' && map[n2] == 'A', + "Wrong CrossRefMap"); + check(map('A') == n0 && map.inverse()['A'] == n0, "Wrong CrossRefMap"); + check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); + check(map('C') == INVALID && map.inverse()['C'] == INVALID, + "Wrong CrossRefMap"); + check(map.count('A') == 2 && map.count('B') == 1 && map.count('C') == 0, + "Wrong CrossRefMap::count()"); + + it = map.beginValue(); + check(*it++ == 'A' && *it++ == 'A' && *it++ == 'B' && + it == map.endValue(), "Wrong value iterator"); + + map.set(n0, 'C'); + + check(map[n0] == 'C' && map[n1] == 'B' && map[n2] == 'A', + "Wrong CrossRefMap"); + check(map('A') == n2 && map.inverse()['A'] == n2, "Wrong CrossRefMap"); + check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); + check(map('C') == n0 && map.inverse()['C'] == n0, "Wrong CrossRefMap"); + check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1, + "Wrong CrossRefMap::count()"); + + it = map.beginValue(); + check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && + it == map.endValue(), "Wrong value iterator"); + } + + // CrossRefMap + { + typedef SmartDigraph Graph; + DIGRAPH_TYPEDEFS(Graph); + + checkConcept, + CrossRefMap >(); + Graph gr; typedef CrossRefMap CRMap; typedef CRMap::ValueIterator ValueIt; CRMap map(gr); - + Node n0 = gr.addNode(); Node n1 = gr.addNode(); Node n2 = gr.addNode(); - + map.set(n0, 'A'); map.set(n1, 'B'); map.set(n2, 'C'); @@ -384,5 +631,373 @@ it == map.endValue(), "Wrong value iterator"); } + // Iterable bool map + { + typedef SmartGraph Graph; + typedef SmartGraph::Node Item; + + typedef IterableBoolMap Ibm; + checkConcept, Ibm>(); + + const int num = 10; + Graph g; + Ibm map0(g, true); + std::vector items; + for (int i = 0; i < num; ++i) { + items.push_back(g.addNode()); + } + + Ibm map1(g, true); + int n = 0; + for (Ibm::TrueIt it(map1); it != INVALID; ++it) { + check(map1[static_cast(it)], "Wrong TrueIt"); + ++n; + } + check(n == num, "Wrong number"); + + n = 0; + for (Ibm::ItemIt it(map1, true); it != INVALID; ++it) { + check(map1[static_cast(it)], "Wrong ItemIt for true"); + ++n; + } + check(n == num, "Wrong number"); + check(Ibm::FalseIt(map1) == INVALID, "Wrong FalseIt"); + check(Ibm::ItemIt(map1, false) == INVALID, "Wrong ItemIt for false"); + + map1[items[5]] = true; + + n = 0; + for (Ibm::ItemIt it(map1, true); it != INVALID; ++it) { + check(map1[static_cast(it)], "Wrong ItemIt for true"); + ++n; + } + check(n == num, "Wrong number"); + + map1[items[num / 2]] = false; + check(map1[items[num / 2]] == false, "Wrong map value"); + + n = 0; + for (Ibm::TrueIt it(map1); it != INVALID; ++it) { + check(map1[static_cast(it)], "Wrong TrueIt for true"); + ++n; + } + check(n == num - 1, "Wrong number"); + + n = 0; + for (Ibm::FalseIt it(map1); it != INVALID; ++it) { + check(!map1[static_cast(it)], "Wrong FalseIt for true"); + ++n; + } + check(n == 1, "Wrong number"); + + map1[items[0]] = false; + check(map1[items[0]] == false, "Wrong map value"); + + map1[items[num - 1]] = false; + check(map1[items[num - 1]] == false, "Wrong map value"); + + n = 0; + for (Ibm::TrueIt it(map1); it != INVALID; ++it) { + check(map1[static_cast(it)], "Wrong TrueIt for true"); + ++n; + } + check(n == num - 3, "Wrong number"); + check(map1.trueNum() == num - 3, "Wrong number"); + + n = 0; + for (Ibm::FalseIt it(map1); it != INVALID; ++it) { + check(!map1[static_cast(it)], "Wrong FalseIt for true"); + ++n; + } + check(n == 3, "Wrong number"); + check(map1.falseNum() == 3, "Wrong number"); + } + + // Iterable int map + { + typedef SmartGraph Graph; + typedef SmartGraph::Node Item; + typedef IterableIntMap Iim; + + checkConcept, Iim>(); + + const int num = 10; + Graph g; + Iim map0(g, 0); + std::vector items; + for (int i = 0; i < num; ++i) { + items.push_back(g.addNode()); + } + + Iim map1(g); + check(map1.size() == 0, "Wrong size"); + + for (int i = 0; i < num; ++i) { + map1[items[i]] = i; + } + check(map1.size() == num, "Wrong size"); + + for (int i = 0; i < num; ++i) { + Iim::ItemIt it(map1, i); + check(static_cast(it) == items[i], "Wrong value"); + ++it; + check(static_cast(it) == INVALID, "Wrong value"); + } + + for (int i = 0; i < num; ++i) { + map1[items[i]] = i % 2; + } + check(map1.size() == 2, "Wrong size"); + + int n = 0; + for (Iim::ItemIt it(map1, 0); it != INVALID; ++it) { + check(map1[static_cast(it)] == 0, "Wrong value"); + ++n; + } + check(n == (num + 1) / 2, "Wrong number"); + + for (Iim::ItemIt it(map1, 1); it != INVALID; ++it) { + check(map1[static_cast(it)] == 1, "Wrong value"); + ++n; + } + check(n == num, "Wrong number"); + + } + + // Iterable value map + { + typedef SmartGraph Graph; + typedef SmartGraph::Node Item; + typedef IterableValueMap Ivm; + + checkConcept, Ivm>(); + + const int num = 10; + Graph g; + Ivm map0(g, 0.0); + std::vector items; + for (int i = 0; i < num; ++i) { + items.push_back(g.addNode()); + } + + Ivm map1(g, 0.0); + check(distance(map1.beginValue(), map1.endValue()) == 1, "Wrong size"); + check(*map1.beginValue() == 0.0, "Wrong value"); + + for (int i = 0; i < num; ++i) { + map1.set(items[i], static_cast(i)); + } + check(distance(map1.beginValue(), map1.endValue()) == num, "Wrong size"); + + for (int i = 0; i < num; ++i) { + Ivm::ItemIt it(map1, static_cast(i)); + check(static_cast(it) == items[i], "Wrong value"); + ++it; + check(static_cast(it) == INVALID, "Wrong value"); + } + + for (Ivm::ValueIt vit = map1.beginValue(); + vit != map1.endValue(); ++vit) { + check(map1[static_cast(Ivm::ItemIt(map1, *vit))] == *vit, + "Wrong ValueIt"); + } + + for (int i = 0; i < num; ++i) { + map1.set(items[i], static_cast(i % 2)); + } + check(distance(map1.beginValue(), map1.endValue()) == 2, "Wrong size"); + + int n = 0; + for (Ivm::ItemIt it(map1, 0.0); it != INVALID; ++it) { + check(map1[static_cast(it)] == 0.0, "Wrong value"); + ++n; + } + check(n == (num + 1) / 2, "Wrong number"); + + for (Ivm::ItemIt it(map1, 1.0); it != INVALID; ++it) { + check(map1[static_cast(it)] == 1.0, "Wrong value"); + ++n; + } + check(n == num, "Wrong number"); + + } + + // Graph map utilities: + // mapMin(), mapMax(), mapMinValue(), mapMaxValue() + // mapFind(), mapFindIf(), mapCount(), mapCountIf() + // mapCopy(), mapCompare(), mapFill() + { + DIGRAPH_TYPEDEFS(SmartDigraph); + + SmartDigraph g; + Node n1 = g.addNode(); + Node n2 = g.addNode(); + Node n3 = g.addNode(); + + SmartDigraph::NodeMap map1(g); + SmartDigraph::ArcMap map2(g); + ConstMap cmap1 = A(); + ConstMap cmap2 = C(0); + + map1[n1] = 10; + map1[n2] = 5; + map1[n3] = 12; + + // mapMin(), mapMax(), mapMinValue(), mapMaxValue() + check(mapMin(g, map1) == n2, "Wrong mapMin()"); + check(mapMax(g, map1) == n3, "Wrong mapMax()"); + check(mapMin(g, map1, std::greater()) == n3, "Wrong mapMin()"); + check(mapMax(g, map1, std::greater()) == n2, "Wrong mapMax()"); + check(mapMinValue(g, map1) == 5, "Wrong mapMinValue()"); + check(mapMaxValue(g, map1) == 12, "Wrong mapMaxValue()"); + + check(mapMin(g, map2) == INVALID, "Wrong mapMin()"); + check(mapMax(g, map2) == INVALID, "Wrong mapMax()"); + + check(mapMin(g, cmap1) != INVALID, "Wrong mapMin()"); + check(mapMax(g, cmap2) == INVALID, "Wrong mapMax()"); + + Arc a1 = g.addArc(n1, n2); + Arc a2 = g.addArc(n1, n3); + Arc a3 = g.addArc(n2, n3); + Arc a4 = g.addArc(n3, n1); + + map2[a1] = 'b'; + map2[a2] = 'a'; + map2[a3] = 'b'; + map2[a4] = 'c'; + + // mapMin(), mapMax(), mapMinValue(), mapMaxValue() + check(mapMin(g, map2) == a2, "Wrong mapMin()"); + check(mapMax(g, map2) == a4, "Wrong mapMax()"); + check(mapMin(g, map2, std::greater()) == a4, "Wrong mapMin()"); + check(mapMax(g, map2, std::greater()) == a2, "Wrong mapMax()"); + check(mapMinValue(g, map2, std::greater()) == 'c', + "Wrong mapMinValue()"); + check(mapMaxValue(g, map2, std::greater()) == 'a', + "Wrong mapMaxValue()"); + + check(mapMin(g, cmap1) != INVALID, "Wrong mapMin()"); + check(mapMax(g, cmap2) != INVALID, "Wrong mapMax()"); + check(mapMaxValue(g, cmap2) == C(0), "Wrong mapMaxValue()"); + + check(mapMin(g, composeMap(functorToMap(&createC), map2)) == a2, + "Wrong mapMin()"); + check(mapMax(g, composeMap(functorToMap(&createC), map2)) == a4, + "Wrong mapMax()"); + check(mapMinValue(g, composeMap(functorToMap(&createC), map2)) == C('a'), + "Wrong mapMinValue()"); + check(mapMaxValue(g, composeMap(functorToMap(&createC), map2)) == C('c'), + "Wrong mapMaxValue()"); + + // mapFind(), mapFindIf() + check(mapFind(g, map1, 5) == n2, "Wrong mapFind()"); + check(mapFind(g, map1, 6) == INVALID, "Wrong mapFind()"); + check(mapFind(g, map2, 'a') == a2, "Wrong mapFind()"); + check(mapFind(g, map2, 'e') == INVALID, "Wrong mapFind()"); + check(mapFind(g, cmap2, C(0)) == ArcIt(g), "Wrong mapFind()"); + check(mapFind(g, cmap2, C(1)) == INVALID, "Wrong mapFind()"); + + check(mapFindIf(g, map1, Less(7)) == n2, + "Wrong mapFindIf()"); + check(mapFindIf(g, map1, Less(5)) == INVALID, + "Wrong mapFindIf()"); + check(mapFindIf(g, map2, Less('d')) == ArcIt(g), + "Wrong mapFindIf()"); + check(mapFindIf(g, map2, Less('a')) == INVALID, + "Wrong mapFindIf()"); + + // mapCount(), mapCountIf() + check(mapCount(g, map1, 5) == 1, "Wrong mapCount()"); + check(mapCount(g, map1, 6) == 0, "Wrong mapCount()"); + check(mapCount(g, map2, 'a') == 1, "Wrong mapCount()"); + check(mapCount(g, map2, 'b') == 2, "Wrong mapCount()"); + check(mapCount(g, map2, 'e') == 0, "Wrong mapCount()"); + check(mapCount(g, cmap2, C(0)) == 4, "Wrong mapCount()"); + check(mapCount(g, cmap2, C(1)) == 0, "Wrong mapCount()"); + + check(mapCountIf(g, map1, Less(11)) == 2, + "Wrong mapCountIf()"); + check(mapCountIf(g, map1, Less(13)) == 3, + "Wrong mapCountIf()"); + check(mapCountIf(g, map1, Less(5)) == 0, + "Wrong mapCountIf()"); + check(mapCountIf(g, map2, Less('d')) == 4, + "Wrong mapCountIf()"); + check(mapCountIf(g, map2, Less('c')) == 3, + "Wrong mapCountIf()"); + check(mapCountIf(g, map2, Less('a')) == 0, + "Wrong mapCountIf()"); + + // MapIt, ConstMapIt +/* +These tests can be used after applying bugfix #330 + typedef SmartDigraph::NodeMap::MapIt MapIt; + typedef SmartDigraph::NodeMap::ConstMapIt ConstMapIt; + check(*std::min_element(MapIt(map1), MapIt(INVALID)) == 5, + "Wrong NodeMap<>::MapIt"); + check(*std::max_element(ConstMapIt(map1), ConstMapIt(INVALID)) == 12, + "Wrong NodeMap<>::MapIt"); + + int sum = 0; + std::for_each(MapIt(map1), MapIt(INVALID), Sum(sum)); + check(sum == 27, "Wrong NodeMap<>::MapIt"); + std::for_each(ConstMapIt(map1), ConstMapIt(INVALID), Sum(sum)); + check(sum == 54, "Wrong NodeMap<>::ConstMapIt"); +*/ + + // mapCopy(), mapCompare(), mapFill() + check(mapCompare(g, map1, map1), "Wrong mapCompare()"); + check(mapCompare(g, cmap2, cmap2), "Wrong mapCompare()"); + check(mapCompare(g, map1, shiftMap(map1, 0)), "Wrong mapCompare()"); + check(mapCompare(g, map2, scaleMap(map2, 1)), "Wrong mapCompare()"); + check(!mapCompare(g, map1, shiftMap(map1, 1)), "Wrong mapCompare()"); + + SmartDigraph::NodeMap map3(g, 0); + SmartDigraph::ArcMap map4(g, 'a'); + + check(!mapCompare(g, map1, map3), "Wrong mapCompare()"); + check(!mapCompare(g, map2, map4), "Wrong mapCompare()"); + + mapCopy(g, map1, map3); + mapCopy(g, map2, map4); + + check(mapCompare(g, map1, map3), "Wrong mapCompare() or mapCopy()"); + check(mapCompare(g, map2, map4), "Wrong mapCompare() or mapCopy()"); + + Undirector ug(g); + Undirector::EdgeMap umap1(ug, 'x'); + Undirector::ArcMap umap2(ug, 3.14); + + check(!mapCompare(g, map2, umap1), "Wrong mapCompare() or mapCopy()"); + check(!mapCompare(g, umap1, map2), "Wrong mapCompare() or mapCopy()"); + check(!mapCompare(ug, map2, umap1), "Wrong mapCompare() or mapCopy()"); + check(!mapCompare(ug, umap1, map2), "Wrong mapCompare() or mapCopy()"); + + mapCopy(g, map2, umap1); + + check(mapCompare(g, map2, umap1), "Wrong mapCompare() or mapCopy()"); + check(mapCompare(g, umap1, map2), "Wrong mapCompare() or mapCopy()"); + check(mapCompare(ug, map2, umap1), "Wrong mapCompare() or mapCopy()"); + check(mapCompare(ug, umap1, map2), "Wrong mapCompare() or mapCopy()"); + + mapCopy(g, map2, umap1); + mapCopy(g, umap1, map2); + mapCopy(ug, map2, umap1); + mapCopy(ug, umap1, map2); + + check(!mapCompare(ug, umap1, umap2), "Wrong mapCompare() or mapCopy()"); + mapCopy(ug, umap1, umap2); + check(mapCompare(ug, umap1, umap2), "Wrong mapCompare() or mapCopy()"); + + check(!mapCompare(g, map1, constMap(2)), "Wrong mapCompare()"); + mapFill(g, map1, 2); + check(mapCompare(g, constMap(2), map1), "Wrong mapFill()"); + + check(!mapCompare(g, map2, constMap('z')), "Wrong mapCompare()"); + mapCopy(g, constMap('z'), map2); + check(mapCompare(g, constMap('z'), map2), "Wrong mapCopy()"); + } + return 0; } diff --git a/test/matching_test.cc b/test/matching_test.cc --- a/test/matching_test.cc +++ b/test/matching_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -134,7 +134,7 @@ mat_test.startSparse(); mat_test.startDense(); mat_test.run(); - + const_mat_test.matchingSize(); const_mat_test.matching(e); const_mat_test.matching(n); @@ -143,7 +143,7 @@ e = mmap[n]; const_mat_test.mate(n); - MaxMatching::Status stat = + MaxMatching::Status stat = const_mat_test.status(n); const MaxMatching::StatusMap& smap = const_mat_test.statusMap(); @@ -170,7 +170,7 @@ mat_test.init(); mat_test.start(); mat_test.run(); - + const_mat_test.matchingWeight(); const_mat_test.matchingSize(); const_mat_test.matching(e); @@ -179,7 +179,7 @@ const_mat_test.matchingMap(); e = mmap[n]; const_mat_test.mate(n); - + int k = 0; const_mat_test.dualValue(); const_mat_test.nodeValue(n); @@ -207,7 +207,7 @@ mat_test.init(); mat_test.start(); mat_test.run(); - + const_mat_test.matchingWeight(); const_mat_test.matching(e); const_mat_test.matching(n); @@ -215,7 +215,7 @@ const_mat_test.matchingMap(); e = mmap[n]; const_mat_test.mate(n); - + int k = 0; const_mat_test.dualValue(); const_mat_test.nodeValue(n); @@ -401,22 +401,46 @@ graphReader(graph, lgfs). edgeMap("weight", weight).run(); - MaxMatching mm(graph); - mm.run(); - checkMatching(graph, mm); + bool perfect; + { + MaxMatching mm(graph); + mm.run(); + checkMatching(graph, mm); + perfect = 2 * mm.matchingSize() == countNodes(graph); + } - MaxWeightedMatching mwm(graph, weight); - mwm.run(); - checkWeightedMatching(graph, weight, mwm); + { + MaxWeightedMatching mwm(graph, weight); + mwm.run(); + checkWeightedMatching(graph, weight, mwm); + } - MaxWeightedPerfectMatching mwpm(graph, weight); - bool perfect = mwpm.run(); + { + MaxWeightedMatching mwm(graph, weight); + mwm.init(); + mwm.start(); + checkWeightedMatching(graph, weight, mwm); + } - check(perfect == (mm.matchingSize() * 2 == countNodes(graph)), - "Perfect matching found"); + { + MaxWeightedPerfectMatching mwpm(graph, weight); + bool result = mwpm.run(); - if (perfect) { - checkWeightedPerfectMatching(graph, weight, mwpm); + check(result == perfect, "Perfect matching found"); + if (perfect) { + checkWeightedPerfectMatching(graph, weight, mwpm); + } + } + + { + MaxWeightedPerfectMatching mwpm(graph, weight); + mwpm.init(); + bool result = mwpm.start(); + + check(result == perfect, "Perfect matching found"); + if (perfect) { + checkWeightedPerfectMatching(graph, weight, mwpm); + } } } diff --git a/test/min_cost_arborescence_test.cc b/test/min_cost_arborescence_test.cc --- a/test/min_cost_arborescence_test.cc +++ b/test/min_cost_arborescence_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2008 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -110,7 +110,7 @@ n = mcarb_test.processNextNode(); b = const_mcarb_test.emptyQueue(); i = const_mcarb_test.queueSize(); - + c = const_mcarb_test.arborescenceCost(); b = const_mcarb_test.arborescence(e); e = const_mcarb_test.pred(n); @@ -120,12 +120,12 @@ const_mcarb_test.predMap(); b = const_mcarb_test.reached(n); b = const_mcarb_test.processed(n); - + i = const_mcarb_test.dualNum(); c = const_mcarb_test.dualValue(); i = const_mcarb_test.dualSize(i); c = const_mcarb_test.dualValue(i); - + ignore_unused_variable_warning(am); ignore_unused_variable_warning(pm); } diff --git a/test/min_cost_flow_test.cc b/test/min_cost_flow_test.cc --- a/test/min_cost_flow_test.cc +++ b/test/min_cost_flow_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -24,14 +24,19 @@ #include #include +#include +#include +#include #include +#include #include #include "test_tools.h" using namespace lemon; +// Test networks char test_lgf[] = "@nodes\n" "label sup1 sup2 sup3 sup4 sup5 sup6\n" @@ -47,7 +52,7 @@ " 10 -2 0 0 0 -7 -2\n" " 11 0 0 0 0 -10 0\n" " 12 -20 -27 0 -30 -30 -20\n" - "\n" + "\n" "@arcs\n" " cost cap low1 low2 low3\n" " 1 2 70 11 0 8 8\n" @@ -76,6 +81,58 @@ "source 1\n" "target 12\n"; +char test_neg1_lgf[] = + "@nodes\n" + "label sup\n" + " 1 100\n" + " 2 0\n" + " 3 0\n" + " 4 -100\n" + " 5 0\n" + " 6 0\n" + " 7 0\n" + "@arcs\n" + " cost low1 low2\n" + "1 2 100 0 0\n" + "1 3 30 0 0\n" + "2 4 20 0 0\n" + "3 4 80 0 0\n" + "3 2 50 0 0\n" + "5 3 10 0 0\n" + "5 6 80 0 1000\n" + "6 7 30 0 -1000\n" + "7 5 -120 0 0\n"; + +char test_neg2_lgf[] = + "@nodes\n" + "label sup\n" + " 1 100\n" + " 2 -300\n" + "@arcs\n" + " cost\n" + "1 2 -1\n"; + + +// Test data +typedef ListDigraph Digraph; +DIGRAPH_TYPEDEFS(ListDigraph); + +Digraph gr; +Digraph::ArcMap c(gr), l1(gr), l2(gr), l3(gr), u(gr); +Digraph::NodeMap s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr); +ConstMap cc(1), cu(std::numeric_limits::max()); +Node v, w; + +Digraph neg1_gr; +Digraph::ArcMap neg1_c(neg1_gr), neg1_l1(neg1_gr), neg1_l2(neg1_gr); +ConstMap neg1_u1(std::numeric_limits::max()), neg1_u2(5000); +Digraph::NodeMap neg1_s(neg1_gr); + +Digraph neg2_gr; +Digraph::ArcMap neg2_c(neg2_gr); +ConstMap neg2_l(0), neg2_u(1000); +Digraph::NodeMap neg2_s(neg2_gr); + enum SupplyType { EQ, @@ -83,6 +140,7 @@ LEQ }; + // Check the interface of an MCF algorithm template class McfClassConcept @@ -93,13 +151,13 @@ struct Constraints { void constraints() { checkConcept(); - + const Constraints& me = *this; MCF mcf(me.g); const MCF& const_mcf = mcf; - b = mcf.reset() + b = mcf.reset().resetParams() .lowerMap(me.lower) .upperMap(me.upper) .costMap(me.cost) @@ -122,7 +180,7 @@ typedef concepts::ReadMap CAM; typedef concepts::WriteMap FlowMap; typedef concepts::WriteMap PotMap; - + GR g; VAM lower; VAM upper; @@ -176,7 +234,7 @@ template < typename GR, typename LM, typename UM, typename CM, typename SM, typename FM, typename PM > bool checkPotential( const GR& gr, const LM& lower, const UM& upper, - const CM& cost, const SM& supply, const FM& flow, + const CM& cost, const SM& supply, const FM& flow, const PM& pi, SupplyType type ) { TEMPLATE_DIGRAPH_TYPEDEFS(GR); @@ -189,7 +247,7 @@ (red_cost > 0 && flow[e] == lower[e]) || (red_cost < 0 && flow[e] == upper[e]); } - + for (NodeIt n(gr); opt && n != INVALID; ++n) { typename SM::Value sum = 0; for (OutArcIt e(gr, n); e != INVALID; ++e) @@ -202,7 +260,7 @@ opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0); } } - + return opt; } @@ -227,7 +285,7 @@ red_supply[gr.target(a)] += lower[a]; } } - + for (NodeIt n(gr); n != INVALID; ++n) { dual_cost -= red_supply[n] * pi[n]; } @@ -236,7 +294,7 @@ cost[a] + pi[gr.source(a)] - pi[gr.target(a)]; dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0); } - + return dual_cost == total; } @@ -268,30 +326,99 @@ } } +template < typename MCF, typename Param > +void runMcfGeqTests( Param param, + const std::string &test_str = "", + bool full_neg_cost_support = false ) +{ + MCF mcf1(gr), mcf2(neg1_gr), mcf3(neg2_gr); + + // Basic tests + mcf1.upperMap(u).costMap(c).supplyMap(s1); + checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s1, + mcf1.OPTIMAL, true, 5240, test_str + "-1"); + mcf1.stSupply(v, w, 27); + checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s2, + mcf1.OPTIMAL, true, 7620, test_str + "-2"); + mcf1.lowerMap(l2).supplyMap(s1); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s1, + mcf1.OPTIMAL, true, 5970, test_str + "-3"); + mcf1.stSupply(v, w, 27); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s2, + mcf1.OPTIMAL, true, 8010, test_str + "-4"); + mcf1.resetParams().supplyMap(s1); + checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s1, + mcf1.OPTIMAL, true, 74, test_str + "-5"); + mcf1.lowerMap(l2).stSupply(v, w, 27); + checkMcf(mcf1, mcf1.run(param), gr, l2, cu, cc, s2, + mcf1.OPTIMAL, true, 94, test_str + "-6"); + mcf1.reset(); + checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s3, + mcf1.OPTIMAL, true, 0, test_str + "-7"); + mcf1.lowerMap(l2).upperMap(u); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, cc, s3, + mcf1.INFEASIBLE, false, 0, test_str + "-8"); + mcf1.lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4); + checkMcf(mcf1, mcf1.run(param), gr, l3, u, c, s4, + mcf1.OPTIMAL, true, 6360, test_str + "-9"); + + // Tests for the GEQ form + mcf1.resetParams().upperMap(u).costMap(c).supplyMap(s5); + checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s5, + mcf1.OPTIMAL, true, 3530, test_str + "-10", GEQ); + mcf1.lowerMap(l2); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5, + mcf1.OPTIMAL, true, 4540, test_str + "-11", GEQ); + mcf1.supplyMap(s6); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6, + mcf1.INFEASIBLE, false, 0, test_str + "-12", GEQ); + + // Tests with negative costs + mcf2.lowerMap(neg1_l1).costMap(neg1_c).supplyMap(neg1_s); + checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u1, neg1_c, neg1_s, + mcf2.UNBOUNDED, false, 0, test_str + "-13"); + mcf2.upperMap(neg1_u2); + checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u2, neg1_c, neg1_s, + mcf2.OPTIMAL, true, -40000, test_str + "-14"); + mcf2.resetParams().lowerMap(neg1_l2).costMap(neg1_c).supplyMap(neg1_s); + checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l2, neg1_u1, neg1_c, neg1_s, + mcf2.UNBOUNDED, false, 0, test_str + "-15"); + + mcf3.costMap(neg2_c).supplyMap(neg2_s); + if (full_neg_cost_support) { + checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s, + mcf3.OPTIMAL, true, -300, test_str + "-16", GEQ); + } else { + checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s, + mcf3.UNBOUNDED, false, 0, test_str + "-17", GEQ); + } + mcf3.upperMap(neg2_u); + checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s, + mcf3.OPTIMAL, true, -300, test_str + "-18", GEQ); +} + +template < typename MCF, typename Param > +void runMcfLeqTests( Param param, + const std::string &test_str = "" ) +{ + // Tests for the LEQ form + MCF mcf1(gr); + mcf1.supplyType(mcf1.LEQ); + mcf1.upperMap(u).costMap(c).supplyMap(s6); + checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s6, + mcf1.OPTIMAL, true, 5080, test_str + "-19", LEQ); + mcf1.lowerMap(l2); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6, + mcf1.OPTIMAL, true, 5930, test_str + "-20", LEQ); + mcf1.supplyMap(s5); + checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5, + mcf1.INFEASIBLE, false, 0, test_str + "-21", LEQ); +} + + int main() { - // Check the interfaces - { - typedef concepts::Digraph GR; - checkConcept< McfClassConcept, - NetworkSimplex >(); - checkConcept< McfClassConcept, - NetworkSimplex >(); - checkConcept< McfClassConcept, - NetworkSimplex >(); - } - - // Run various MCF tests - typedef ListDigraph Digraph; - DIGRAPH_TYPEDEFS(ListDigraph); - - // Read the test digraph - Digraph gr; - Digraph::ArcMap c(gr), l1(gr), l2(gr), l3(gr), u(gr); - Digraph::NodeMap s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr); - ConstMap cc(1), cu(std::numeric_limits::max()); - Node v, w; - + // Read the test networks std::istringstream input(test_lgf); DigraphReader(gr, input) .arcMap("cost", c) @@ -308,142 +435,107 @@ .node("source", v) .node("target", w) .run(); - - // Build test digraphs with negative costs - Digraph neg_gr; - Node n1 = neg_gr.addNode(); - Node n2 = neg_gr.addNode(); - Node n3 = neg_gr.addNode(); - Node n4 = neg_gr.addNode(); - Node n5 = neg_gr.addNode(); - Node n6 = neg_gr.addNode(); - Node n7 = neg_gr.addNode(); - - Arc a1 = neg_gr.addArc(n1, n2); - Arc a2 = neg_gr.addArc(n1, n3); - Arc a3 = neg_gr.addArc(n2, n4); - Arc a4 = neg_gr.addArc(n3, n4); - Arc a5 = neg_gr.addArc(n3, n2); - Arc a6 = neg_gr.addArc(n5, n3); - Arc a7 = neg_gr.addArc(n5, n6); - Arc a8 = neg_gr.addArc(n6, n7); - Arc a9 = neg_gr.addArc(n7, n5); - - Digraph::ArcMap neg_c(neg_gr), neg_l1(neg_gr, 0), neg_l2(neg_gr, 0); - ConstMap neg_u1(std::numeric_limits::max()), neg_u2(5000); - Digraph::NodeMap neg_s(neg_gr, 0); - - neg_l2[a7] = 1000; - neg_l2[a8] = -1000; - - neg_s[n1] = 100; - neg_s[n4] = -100; - - neg_c[a1] = 100; - neg_c[a2] = 30; - neg_c[a3] = 20; - neg_c[a4] = 80; - neg_c[a5] = 50; - neg_c[a6] = 10; - neg_c[a7] = 80; - neg_c[a8] = 30; - neg_c[a9] = -120; - Digraph negs_gr; - Digraph::NodeMap negs_s(negs_gr); - Digraph::ArcMap negs_c(negs_gr); - ConstMap negs_l(0), negs_u(1000); - n1 = negs_gr.addNode(); - n2 = negs_gr.addNode(); - negs_s[n1] = 100; - negs_s[n2] = -300; - negs_c[negs_gr.addArc(n1, n2)] = -1; + std::istringstream neg_inp1(test_neg1_lgf); + DigraphReader(neg1_gr, neg_inp1) + .arcMap("cost", neg1_c) + .arcMap("low1", neg1_l1) + .arcMap("low2", neg1_l2) + .nodeMap("sup", neg1_s) + .run(); + std::istringstream neg_inp2(test_neg2_lgf); + DigraphReader(neg2_gr, neg_inp2) + .arcMap("cost", neg2_c) + .nodeMap("sup", neg2_s) + .run(); - // A. Test NetworkSimplex with the default pivot rule + // Check the interface of NetworkSimplex { - NetworkSimplex mcf(gr); - - // Check the equality form - mcf.upperMap(u).costMap(c); - checkMcf(mcf, mcf.supplyMap(s1).run(), - gr, l1, u, c, s1, mcf.OPTIMAL, true, 5240, "#A1"); - checkMcf(mcf, mcf.stSupply(v, w, 27).run(), - gr, l1, u, c, s2, mcf.OPTIMAL, true, 7620, "#A2"); - mcf.lowerMap(l2); - checkMcf(mcf, mcf.supplyMap(s1).run(), - gr, l2, u, c, s1, mcf.OPTIMAL, true, 5970, "#A3"); - checkMcf(mcf, mcf.stSupply(v, w, 27).run(), - gr, l2, u, c, s2, mcf.OPTIMAL, true, 8010, "#A4"); - mcf.reset(); - checkMcf(mcf, mcf.supplyMap(s1).run(), - gr, l1, cu, cc, s1, mcf.OPTIMAL, true, 74, "#A5"); - checkMcf(mcf, mcf.lowerMap(l2).stSupply(v, w, 27).run(), - gr, l2, cu, cc, s2, mcf.OPTIMAL, true, 94, "#A6"); - mcf.reset(); - checkMcf(mcf, mcf.run(), - gr, l1, cu, cc, s3, mcf.OPTIMAL, true, 0, "#A7"); - checkMcf(mcf, mcf.lowerMap(l2).upperMap(u).run(), - gr, l2, u, cc, s3, mcf.INFEASIBLE, false, 0, "#A8"); - mcf.reset().lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4); - checkMcf(mcf, mcf.run(), - gr, l3, u, c, s4, mcf.OPTIMAL, true, 6360, "#A9"); - - // Check the GEQ form - mcf.reset().upperMap(u).costMap(c).supplyMap(s5); - checkMcf(mcf, mcf.run(), - gr, l1, u, c, s5, mcf.OPTIMAL, true, 3530, "#A10", GEQ); - mcf.supplyType(mcf.GEQ); - checkMcf(mcf, mcf.lowerMap(l2).run(), - gr, l2, u, c, s5, mcf.OPTIMAL, true, 4540, "#A11", GEQ); - mcf.supplyMap(s6); - checkMcf(mcf, mcf.run(), - gr, l2, u, c, s6, mcf.INFEASIBLE, false, 0, "#A12", GEQ); - - // Check the LEQ form - mcf.reset().supplyType(mcf.LEQ); - mcf.upperMap(u).costMap(c).supplyMap(s6); - checkMcf(mcf, mcf.run(), - gr, l1, u, c, s6, mcf.OPTIMAL, true, 5080, "#A13", LEQ); - checkMcf(mcf, mcf.lowerMap(l2).run(), - gr, l2, u, c, s6, mcf.OPTIMAL, true, 5930, "#A14", LEQ); - mcf.supplyMap(s5); - checkMcf(mcf, mcf.run(), - gr, l2, u, c, s5, mcf.INFEASIBLE, false, 0, "#A15", LEQ); - - // Check negative costs - NetworkSimplex neg_mcf(neg_gr); - neg_mcf.lowerMap(neg_l1).costMap(neg_c).supplyMap(neg_s); - checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l1, neg_u1, - neg_c, neg_s, neg_mcf.UNBOUNDED, false, 0, "#A16"); - neg_mcf.upperMap(neg_u2); - checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l1, neg_u2, - neg_c, neg_s, neg_mcf.OPTIMAL, true, -40000, "#A17"); - neg_mcf.reset().lowerMap(neg_l2).costMap(neg_c).supplyMap(neg_s); - checkMcf(neg_mcf, neg_mcf.run(), neg_gr, neg_l2, neg_u1, - neg_c, neg_s, neg_mcf.UNBOUNDED, false, 0, "#A18"); - - NetworkSimplex negs_mcf(negs_gr); - negs_mcf.costMap(negs_c).supplyMap(negs_s); - checkMcf(negs_mcf, negs_mcf.run(), negs_gr, negs_l, negs_u, - negs_c, negs_s, negs_mcf.OPTIMAL, true, -300, "#A19", GEQ); + typedef concepts::Digraph GR; + checkConcept< McfClassConcept, + NetworkSimplex >(); + checkConcept< McfClassConcept, + NetworkSimplex >(); + checkConcept< McfClassConcept, + NetworkSimplex >(); } - // B. Test NetworkSimplex with each pivot rule + // Check the interface of CapacityScaling { - NetworkSimplex mcf(gr); - mcf.supplyMap(s1).costMap(c).upperMap(u).lowerMap(l2); + typedef concepts::Digraph GR; + checkConcept< McfClassConcept, + CapacityScaling >(); + checkConcept< McfClassConcept, + CapacityScaling >(); + checkConcept< McfClassConcept, + CapacityScaling >(); + typedef CapacityScaling:: + SetHeap > >::Create CAS; + checkConcept< McfClassConcept, CAS >(); + } - checkMcf(mcf, mcf.run(NetworkSimplex::FIRST_ELIGIBLE), - gr, l2, u, c, s1, mcf.OPTIMAL, true, 5970, "#B1"); - checkMcf(mcf, mcf.run(NetworkSimplex::BEST_ELIGIBLE), - gr, l2, u, c, s1, mcf.OPTIMAL, true, 5970, "#B2"); - checkMcf(mcf, mcf.run(NetworkSimplex::BLOCK_SEARCH), - gr, l2, u, c, s1, mcf.OPTIMAL, true, 5970, "#B3"); - checkMcf(mcf, mcf.run(NetworkSimplex::CANDIDATE_LIST), - gr, l2, u, c, s1, mcf.OPTIMAL, true, 5970, "#B4"); - checkMcf(mcf, mcf.run(NetworkSimplex::ALTERING_LIST), - gr, l2, u, c, s1, mcf.OPTIMAL, true, 5970, "#B5"); + // Check the interface of CostScaling + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept, + CostScaling >(); + checkConcept< McfClassConcept, + CostScaling >(); + checkConcept< McfClassConcept, + CostScaling >(); + typedef CostScaling:: + SetLargeCost::Create COS; + checkConcept< McfClassConcept, COS >(); + } + + // Check the interface of CycleCanceling + { + typedef concepts::Digraph GR; + checkConcept< McfClassConcept, + CycleCanceling >(); + checkConcept< McfClassConcept, + CycleCanceling >(); + checkConcept< McfClassConcept, + CycleCanceling >(); + } + + // Test NetworkSimplex + { + typedef NetworkSimplex MCF; + runMcfGeqTests(MCF::FIRST_ELIGIBLE, "NS-FE", true); + runMcfLeqTests(MCF::FIRST_ELIGIBLE, "NS-FE"); + runMcfGeqTests(MCF::BEST_ELIGIBLE, "NS-BE", true); + runMcfLeqTests(MCF::BEST_ELIGIBLE, "NS-BE"); + runMcfGeqTests(MCF::BLOCK_SEARCH, "NS-BS", true); + runMcfLeqTests(MCF::BLOCK_SEARCH, "NS-BS"); + runMcfGeqTests(MCF::CANDIDATE_LIST, "NS-CL", true); + runMcfLeqTests(MCF::CANDIDATE_LIST, "NS-CL"); + runMcfGeqTests(MCF::ALTERING_LIST, "NS-AL", true); + runMcfLeqTests(MCF::ALTERING_LIST, "NS-AL"); + } + + // Test CapacityScaling + { + typedef CapacityScaling MCF; + runMcfGeqTests(0, "SSP"); + runMcfGeqTests(2, "CAS"); + } + + // Test CostScaling + { + typedef CostScaling MCF; + runMcfGeqTests(MCF::PUSH, "COS-PR"); + runMcfGeqTests(MCF::AUGMENT, "COS-AR"); + runMcfGeqTests(MCF::PARTIAL_AUGMENT, "COS-PAR"); + } + + // Test CycleCanceling + { + typedef CycleCanceling MCF; + runMcfGeqTests(MCF::SIMPLE_CYCLE_CANCELING, "SCC"); + runMcfGeqTests(MCF::MINIMUM_MEAN_CYCLE_CANCELING, "MMCC"); + runMcfGeqTests(MCF::CANCEL_AND_TIGHTEN, "CAT"); } return 0; diff --git a/test/min_mean_cycle_test.cc b/test/min_mean_cycle_test.cc new file mode 100644 --- /dev/null +++ b/test/min_mean_cycle_test.cc @@ -0,0 +1,216 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "test_tools.h" + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "@arcs\n" + " len1 len2 len3 len4 c1 c2 c3 c4\n" + "1 2 1 1 1 1 0 0 0 0\n" + "2 4 5 5 5 5 1 0 0 0\n" + "2 3 8 8 8 8 0 0 0 0\n" + "3 2 -2 0 0 0 1 0 0 0\n" + "3 4 4 4 4 4 0 0 0 0\n" + "3 7 -4 -4 -4 -4 0 0 0 0\n" + "4 1 2 2 2 2 0 0 0 0\n" + "4 3 3 3 3 3 1 0 0 0\n" + "4 4 3 3 0 0 0 0 1 0\n" + "5 2 4 4 4 4 0 0 0 0\n" + "5 6 3 3 3 3 0 1 0 0\n" + "6 5 2 2 2 2 0 1 0 0\n" + "6 4 -1 -1 -1 -1 0 0 0 0\n" + "6 7 1 1 1 1 0 0 0 0\n" + "7 7 4 4 4 -1 0 0 0 1\n"; + + +// Check the interface of an MMC algorithm +template +struct MmcClassConcept +{ + template + struct Constraints { + void constraints() { + const Constraints& me = *this; + + typedef typename MMC + ::template SetPath > + ::template SetLargeCost + ::Create MmcAlg; + MmcAlg mmc(me.g, me.cost); + const MmcAlg& const_mmc = mmc; + + typename MmcAlg::Tolerance tol = const_mmc.tolerance(); + mmc.tolerance(tol); + + b = mmc.cycle(p).run(); + b = mmc.findCycleMean(); + b = mmc.findCycle(); + + v = const_mmc.cycleCost(); + i = const_mmc.cycleSize(); + d = const_mmc.cycleMean(); + p = const_mmc.cycle(); + } + + typedef concepts::ReadMap CM; + + GR g; + CM cost; + ListPath p; + Cost v; + int i; + double d; + bool b; + }; +}; + +// Perform a test with the given parameters +template +void checkMmcAlg(const SmartDigraph& gr, + const SmartDigraph::ArcMap& lm, + const SmartDigraph::ArcMap& cm, + int cost, int size) { + MMC alg(gr, lm); + alg.findCycleMean(); + check(alg.cycleMean() == static_cast(cost) / size, + "Wrong cycle mean"); + alg.findCycle(); + check(alg.cycleCost() == cost && alg.cycleSize() == size, + "Wrong path"); + SmartDigraph::ArcMap cycle(gr, 0); + for (typename MMC::Path::ArcIt a(alg.cycle()); a != INVALID; ++a) { + ++cycle[a]; + } + for (SmartDigraph::ArcIt a(gr); a != INVALID; ++a) { + check(cm[a] == cycle[a], "Wrong path"); + } +} + +// Class for comparing types +template +struct IsSameType { + static const int result = 0; +}; + +template +struct IsSameType { + static const int result = 1; +}; + + +int main() { + #ifdef LEMON_HAVE_LONG_LONG + typedef long long long_int; + #else + typedef long long_int; + #endif + + // Check the interface + { + typedef concepts::Digraph GR; + + // KarpMmc + checkConcept< MmcClassConcept, + KarpMmc > >(); + checkConcept< MmcClassConcept, + KarpMmc > >(); + + // HartmannOrlinMmc + checkConcept< MmcClassConcept, + HartmannOrlinMmc > >(); + checkConcept< MmcClassConcept, + HartmannOrlinMmc > >(); + + // HowardMmc + checkConcept< MmcClassConcept, + HowardMmc > >(); + checkConcept< MmcClassConcept, + HowardMmc > >(); + + check((IsSameType > + ::LargeCost, long_int>::result == 1), "Wrong LargeCost type"); + check((IsSameType > + ::LargeCost, double>::result == 1), "Wrong LargeCost type"); + } + + // Run various tests + { + typedef SmartDigraph GR; + DIGRAPH_TYPEDEFS(GR); + + GR gr; + IntArcMap l1(gr), l2(gr), l3(gr), l4(gr); + IntArcMap c1(gr), c2(gr), c3(gr), c4(gr); + + std::istringstream input(test_lgf); + digraphReader(gr, input). + arcMap("len1", l1). + arcMap("len2", l2). + arcMap("len3", l3). + arcMap("len4", l4). + arcMap("c1", c1). + arcMap("c2", c2). + arcMap("c3", c3). + arcMap("c4", c4). + run(); + + // Karp + checkMmcAlg >(gr, l1, c1, 6, 3); + checkMmcAlg >(gr, l2, c2, 5, 2); + checkMmcAlg >(gr, l3, c3, 0, 1); + checkMmcAlg >(gr, l4, c4, -1, 1); + + // HartmannOrlin + checkMmcAlg >(gr, l1, c1, 6, 3); + checkMmcAlg >(gr, l2, c2, 5, 2); + checkMmcAlg >(gr, l3, c3, 0, 1); + checkMmcAlg >(gr, l4, c4, -1, 1); + + // Howard + checkMmcAlg >(gr, l1, c1, 6, 3); + checkMmcAlg >(gr, l2, c2, 5, 2); + checkMmcAlg >(gr, l3, c3, 0, 1); + checkMmcAlg >(gr, l4, c4, -1, 1); + } + + return 0; +} diff --git a/test/planarity_test.cc b/test/planarity_test.cc new file mode 100644 --- /dev/null +++ b/test/planarity_test.cc @@ -0,0 +1,262 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#include + +#include + +#include +#include +#include +#include + +#include "test_tools.h" + +using namespace lemon; +using namespace lemon::dim2; + +const int lgfn = 4; +const std::string lgf[lgfn] = { + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "@edges\n" + " label\n" + "0 1 0\n" + "0 2 0\n" + "0 3 0\n" + "0 4 0\n" + "1 2 0\n" + "1 3 0\n" + "1 4 0\n" + "2 3 0\n" + "2 4 0\n" + "3 4 0\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "@edges\n" + " label\n" + "0 1 0\n" + "0 2 0\n" + "0 3 0\n" + "0 4 0\n" + "1 2 0\n" + "1 3 0\n" + "2 3 0\n" + "2 4 0\n" + "3 4 0\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "@edges\n" + " label\n" + "0 3 0\n" + "0 4 0\n" + "0 5 0\n" + "1 3 0\n" + "1 4 0\n" + "1 5 0\n" + "2 3 0\n" + "2 4 0\n" + "2 5 0\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "@edges\n" + " label\n" + "0 3 0\n" + "0 4 0\n" + "0 5 0\n" + "1 3 0\n" + "1 4 0\n" + "1 5 0\n" + "2 3 0\n" + "2 5 0\n" +}; + + + +typedef SmartGraph Graph; +GRAPH_TYPEDEFS(Graph); + +typedef PlanarEmbedding PE; +typedef PlanarDrawing PD; +typedef PlanarColoring PC; + +void checkEmbedding(const Graph& graph, PE& pe) { + int face_num = 0; + + Graph::ArcMap face(graph, -1); + + for (ArcIt a(graph); a != INVALID; ++a) { + if (face[a] == -1) { + Arc b = a; + while (face[b] == -1) { + face[b] = face_num; + b = pe.next(graph.oppositeArc(b)); + } + check(face[b] == face_num, "Wrong face"); + ++face_num; + } + } + check(face_num + countNodes(graph) - countConnectedComponents(graph) == + countEdges(graph) + 1, "Euler test does not passed"); +} + +void checkKuratowski(const Graph& graph, PE& pe) { + std::map degs; + for (NodeIt n(graph); n != INVALID; ++n) { + int deg = 0; + for (IncEdgeIt e(graph, n); e != INVALID; ++e) { + if (pe.kuratowski(e)) { + ++deg; + } + } + ++degs[deg]; + } + for (std::map::iterator it = degs.begin(); it != degs.end(); ++it) { + check(it->first == 0 || it->first == 2 || + (it->first == 3 && it->second == 6) || + (it->first == 4 && it->second == 5), + "Wrong degree in Kuratowski graph"); + } + + // Not full test + check((degs[3] == 0) != (degs[4] == 0), "Wrong Kuratowski graph"); +} + +bool intersect(Point e1, Point e2, Point f1, Point f2) { + int l, r; + if (std::min(e1.x, e2.x) > std::max(f1.x, f2.x)) return false; + if (std::max(e1.x, e2.x) < std::min(f1.x, f2.x)) return false; + if (std::min(e1.y, e2.y) > std::max(f1.y, f2.y)) return false; + if (std::max(e1.y, e2.y) < std::min(f1.y, f2.y)) return false; + + l = (e2.x - e1.x) * (f1.y - e1.y) - (e2.y - e1.y) * (f1.x - e1.x); + r = (e2.x - e1.x) * (f2.y - e1.y) - (e2.y - e1.y) * (f2.x - e1.x); + if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false; + l = (f2.x - f1.x) * (e1.y - f1.y) - (f2.y - f1.y) * (e1.x - f1.x); + r = (f2.x - f1.x) * (e2.y - f1.y) - (f2.y - f1.y) * (e2.x - f1.x); + if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false; + return true; +} + +bool collinear(Point p, Point q, Point r) { + int v; + v = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x); + if (v != 0) return false; + v = (q.x - p.x) * (r.x - p.x) + (q.y - p.y) * (r.y - p.y); + if (v < 0) return false; + return true; +} + +void checkDrawing(const Graph& graph, PD& pd) { + for (Graph::NodeIt n(graph); n != INVALID; ++n) { + Graph::NodeIt m(n); + for (++m; m != INVALID; ++m) { + check(pd[m] != pd[n], "Two nodes with identical coordinates"); + } + } + + for (Graph::EdgeIt e(graph); e != INVALID; ++e) { + for (Graph::EdgeIt f(e); f != e; ++f) { + Point e1 = pd[graph.u(e)]; + Point e2 = pd[graph.v(e)]; + Point f1 = pd[graph.u(f)]; + Point f2 = pd[graph.v(f)]; + + if (graph.u(e) == graph.u(f)) { + check(!collinear(e1, e2, f2), "Wrong drawing"); + } else if (graph.u(e) == graph.v(f)) { + check(!collinear(e1, e2, f1), "Wrong drawing"); + } else if (graph.v(e) == graph.u(f)) { + check(!collinear(e2, e1, f2), "Wrong drawing"); + } else if (graph.v(e) == graph.v(f)) { + check(!collinear(e2, e1, f1), "Wrong drawing"); + } else { + check(!intersect(e1, e2, f1, f2), "Wrong drawing"); + } + } + } +} + +void checkColoring(const Graph& graph, PC& pc, int num) { + for (NodeIt n(graph); n != INVALID; ++n) { + check(pc.colorIndex(n) >= 0 && pc.colorIndex(n) < num, + "Wrong coloring"); + } + for (EdgeIt e(graph); e != INVALID; ++e) { + check(pc.colorIndex(graph.u(e)) != pc.colorIndex(graph.v(e)), + "Wrong coloring"); + } +} + +int main() { + + for (int i = 0; i < lgfn; ++i) { + std::istringstream lgfs(lgf[i]); + + SmartGraph graph; + graphReader(graph, lgfs).run(); + + check(simpleGraph(graph), "Test graphs must be simple"); + + PE pe(graph); + bool planar = pe.run(); + check(checkPlanarity(graph) == planar, "Planarity checking failed"); + + if (planar) { + checkEmbedding(graph, pe); + + PlanarDrawing pd(graph); + pd.run(pe.embeddingMap()); + checkDrawing(graph, pd); + + PlanarColoring pc(graph); + pc.runFiveColoring(pe.embeddingMap()); + checkColoring(graph, pc, 5); + + } else { + checkKuratowski(graph, pe); + } + } + + return 0; +} diff --git a/test/preflow_test.cc b/test/preflow_test.cc --- a/test/preflow_test.cc +++ b/test/preflow_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -95,6 +95,11 @@ PreflowType preflow_test(g, cap, n, n); const PreflowType& const_preflow_test = preflow_test; + const PreflowType::Elevator& elev = const_preflow_test.elevator(); + preflow_test.elevator(const_cast(elev)); + PreflowType::Tolerance tol = const_preflow_test.tolerance(); + preflow_test.tolerance(tol); + preflow_test .capacityMap(cap) .flowMap(flow) @@ -113,7 +118,7 @@ const FlowMap& fm = const_preflow_test.flowMap(); b = const_preflow_test.minCut(n); const_preflow_test.minCutMap(cut); - + ignore_unused_variable_warning(fm); } diff --git a/test/suurballe_test.cc b/test/suurballe_test.cc --- a/test/suurballe_test.cc +++ b/test/suurballe_test.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -23,6 +23,7 @@ #include #include #include +#include #include "test_tools.h" @@ -80,8 +81,14 @@ typedef Digraph::Node Node; typedef Digraph::Arc Arc; typedef concepts::ReadMap LengthMap; - - typedef Suurballe SuurballeType; + + typedef Suurballe ST; + typedef Suurballe + ::SetFlowMap + ::SetPotentialMap + ::SetPath > + ::SetHeap > > + ::Create SuurballeType; Digraph g; Node n; @@ -101,10 +108,13 @@ k = suurb_test.run(n, n); k = suurb_test.run(n, n, k); suurb_test.init(n); + suurb_test.fullInit(n); + suurb_test.start(n); + suurb_test.start(n, k); k = suurb_test.findFlow(n); k = suurb_test.findFlow(n, k); suurb_test.findPaths(); - + int f; VType c; c = const_suurb_test.totalLength(); @@ -116,7 +126,7 @@ const_suurb_test.potentialMap(); k = const_suurb_test.pathNum(); Path p = const_suurb_test.path(k); - + ignore_unused_variable_warning(fm); ignore_unused_variable_warning(pm); } @@ -195,9 +205,11 @@ node("target", t). run(); - // Find 2 paths + // Check run() { Suurballe suurballe(digraph, length); + + // Find 2 paths check(suurballe.run(s, t) == 2, "Wrong number of paths"); check(checkFlow(digraph, suurballe.flowMap(), s, t, 2), "The flow is not feasible"); @@ -207,11 +219,8 @@ "Wrong potentials"); for (int i = 0; i < suurballe.pathNum(); ++i) check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); - } - // Find 3 paths - { - Suurballe suurballe(digraph, length); + // Find 3 paths check(suurballe.run(s, t, 3) == 3, "Wrong number of paths"); check(checkFlow(digraph, suurballe.flowMap(), s, t, 3), "The flow is not feasible"); @@ -221,11 +230,8 @@ "Wrong potentials"); for (int i = 0; i < suurballe.pathNum(); ++i) check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); - } - // Find 5 paths (only 3 can be found) - { - Suurballe suurballe(digraph, length); + // Find 5 paths (only 3 can be found) check(suurballe.run(s, t, 5) == 3, "Wrong number of paths"); check(checkFlow(digraph, suurballe.flowMap(), s, t, 3), "The flow is not feasible"); @@ -237,5 +243,23 @@ check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); } + // Check fullInit() + start() + { + Suurballe suurballe(digraph, length); + suurballe.fullInit(s); + + // Find 2 paths + check(suurballe.start(t) == 2, "Wrong number of paths"); + check(suurballe.totalLength() == 510, "The flow is not optimal"); + + // Find 3 paths + check(suurballe.start(t, 3) == 3, "Wrong number of paths"); + check(suurballe.totalLength() == 1040, "The flow is not optimal"); + + // Find 5 paths (only 3 can be found) + check(suurballe.start(t, 5) == 3, "Wrong number of paths"); + check(suurballe.totalLength() == 1040, "The flow is not optimal"); + } + return 0; } diff --git a/test/test_tools.h b/test/test_tools.h --- a/test/test_tools.h +++ b/test/test_tools.h @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -37,10 +37,14 @@ ///\code check(0==1,"This is obviously false.");\endcode will ///print something like this (and then exits). ///\verbatim file_name.cc:123: error: This is obviously false. \endverbatim -#define check(rc, msg) \ - if(!(rc)) { \ - std::cerr << __FILE__ ":" << __LINE__ << ": error: " << msg << std::endl; \ - abort(); \ - } else { } \ +#define check(rc, msg) \ + { \ + if(!(rc)) { \ + std::cerr << __FILE__ ":" << __LINE__ << ": error: " \ + << msg << std::endl; \ + abort(); \ + } else { } \ + } \ + #endif diff --git a/tools/dimacs-solver.cc b/tools/dimacs-solver.cc --- a/tools/dimacs-solver.cc +++ b/tools/dimacs-solver.cc @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2010 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -88,10 +88,10 @@ ti.restart(); pre.run(); if(report) std::cerr << "Run Preflow: " << ti << '\n'; - if(report) std::cerr << "\nMax flow value: " << pre.flowValue() << '\n'; + if(report) std::cerr << "\nMax flow value: " << pre.flowValue() << '\n'; } -template +template void solve_min(ArgParser &ap, std::istream &is, std::ostream &, Value infty, DimacsDescriptor &desc) { @@ -127,7 +127,8 @@ if (report) { std::cerr << "Run NetworkSimplex: " << ti << "\n\n"; std::cerr << "Feasible flow: " << (res ? "found" : "not found") << '\n'; - if (res) std::cerr << "Min flow cost: " << ns.totalCost() << '\n'; + if (res) std::cerr << "Min flow cost: " + << ns.template totalCost() << '\n'; } } @@ -147,11 +148,11 @@ mat.run(); if(report) std::cerr << "Run MaxMatching: " << ti << '\n'; if(report) std::cerr << "\nCardinality of max matching: " - << mat.matchingSize() << '\n'; + << mat.matchingSize() << '\n'; } -template +template void solve(ArgParser &ap, std::istream &is, std::ostream &os, DimacsDescriptor &desc) { @@ -165,11 +166,11 @@ << std::endl; exit(1); } - + switch(desc.type) { case DimacsDescriptor::MIN: - solve_min(ap,is,os,infty,desc); + solve_min(ap,is,os,infty,desc); break; case DimacsDescriptor::MAX: solve_max(ap,is,os,infty,desc); @@ -237,7 +238,7 @@ std::ostream& os = (ap.files().size()<2 ? std::cout : output); DimacsDescriptor desc = dimacsType(is); - + if(!ap.given("q")) { std::cout << "Problem type: "; @@ -262,16 +263,18 @@ std::cout << "\nNum of arcs: " << desc.edgeNum; std::cout << "\n\n"; } - + if(ap.given("double")) - solve(ap,is,os,desc); + solve(ap,is,os,desc); else if(ap.given("ldouble")) - solve(ap,is,os,desc); + solve(ap,is,os,desc); #ifdef LEMON_HAVE_LONG_LONG else if(ap.given("long")) - solve(ap,is,os,desc); + solve(ap,is,os,desc); + else solve(ap,is,os,desc); +#else + else solve(ap,is,os,desc); #endif - else solve(ap,is,os,desc); return 0; } diff --git a/tools/lemon-0.x-to-1.x.sh b/tools/lemon-0.x-to-1.x.sh --- a/tools/lemon-0.x-to-1.x.sh +++ b/tools/lemon-0.x-to-1.x.sh @@ -35,10 +35,10 @@ -e "s/IncEdgeIt/_In_cEd_geIt_label_/g"\ -e "s/Edge\>/_Ar_c_label_/g"\ -e "s/\/_ar_c_label_/g"\ - -e "s/_edge\>/_ar_c_label_/g"\ + -e "s/_edge\>/__ar_c_label_/g"\ -e "s/Edges\>/_Ar_c_label_s/g"\ -e "s/\/_ar_c_label_s/g"\ - -e "s/_edges\>/_ar_c_label_s/g"\ + -e "s/_edges\>/__ar_c_label_s/g"\ -e "s/\([Ee]\)dge\([a-z]\)/_\1d_ge_label_\2/g"\ -e "s/\([a-z]\)edge/\1_ed_ge_label_/g"\ -e "s/Edge/_Ar_c_label_/g"\ @@ -68,6 +68,11 @@ -e "s/_blu_e_label_/blue/g"\ -e "s/_GR_APH_TY_PEDE_FS_label_/GRAPH_TYPEDEFS/g"\ -e "s/_DIGR_APH_TY_PEDE_FS_label_/DIGRAPH_TYPEDEFS/g"\ + -e "s/\/adaptors.h/g"\ + -e "s/\/core.h/g"\ + -e "s/\/lgf_reader.h/g"\ + -e "s/\/lgf_writer.h/g"\ + -e "s/\/connectivity.h/g"\ -e "s/DigraphToEps/GraphToEps/g"\ -e "s/digraphToEps/graphToEps/g"\ -e "s/\/SetPredMap/g"\