Changes in / [1174:a26b90a17c81:1176:36fa2fee7144] in lemon
- Files:
-
- 8 added
- 17 deleted
- 32 edited
Legend:
- Unmodified
- Added
- Removed
-
AUTHORS
r1072 r1148 1 The authors of the 1.x seriesare1 The main developers of release series 1.x are 2 2 3 3 * Balazs Dezso <deba@inf.elte.hu> … … 6 6 * Akos Ladanyi <ladanyi@tmit.bme.hu> 7 7 8 For more details on the actual contribution, please visit the history9 of the main LEMON source repository: http://lemon.cs.elte.hu/hg/lemon8 For more complete list of contributors, please visit the history of 9 the LEMON source code repository: http://lemon.cs.elte.hu/hg/lemon 10 10 11 Moreover, this version is heavily based on the 0.x series of12 LEMON. Hereis the list of people who contributed to those versions.11 Moreover, this version is heavily based on version 0.x of LEMON. Here 12 is the list of people who contributed to those versions. 13 13 14 14 * Mihaly Barasz <klao@cs.elte.hu> -
CMakeLists.txt
r1159 r1162 13 13 ELSE() 14 14 EXECUTE_PROCESS( 15 COMMAND ${PYTHON_EXECUTABLE} ./scripts/chg-len.py 15 COMMAND 16 hg log -r. --template "{latesttag}" 16 17 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 17 OUTPUT_VARIABLE HG_REVISION_ PATH18 OUTPUT_VARIABLE HG_REVISION_TAG 18 19 ERROR_QUIET 19 20 OUTPUT_STRIP_TRAILING_WHITESPACE 20 21 ) 21 22 EXECUTE_PROCESS( 22 COMMAND hg id -i 23 COMMAND 24 hg log -r. --template "{latesttagdistance}" 23 25 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 24 OUTPUT_VARIABLE HG_REVISION 26 OUTPUT_VARIABLE HG_REVISION_DIST 25 27 ERROR_QUIET 26 28 OUTPUT_STRIP_TRAILING_WHITESPACE 27 29 ) 28 IF(HG_REVISION STREQUAL "") 30 EXECUTE_PROCESS( 31 COMMAND 32 hg log -r. --template "{node|short}" 33 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 34 OUTPUT_VARIABLE HG_REVISION_ID 35 ERROR_QUIET 36 OUTPUT_STRIP_TRAILING_WHITESPACE 37 ) 38 39 IF(HG_REVISION_TAG STREQUAL "") 29 40 SET(HG_REVISION_ID "hg-tip") 30 41 ELSE() 31 IF(HG_REVISION_PATH STREQUAL "") 32 SET(HG_REVISION_ID ${HG_REVISION}) 42 IF(HG_REVISION_TAG STREQUAL "null") 43 SET(HG_REVISION_TAG "trunk") 44 ELSEIF(HG_REVISION_TAG MATCHES "^r") 45 STRING(SUBSTRING ${HG_REVISION_TAG} 1 -1 HG_REVISION_TAG) 46 ENDIF() 47 IF(HG_REVISION_DIST STREQUAL "0") 48 SET(HG_REVISION ${HG_REVISION_TAG}) 33 49 ELSE() 34 SET(HG_REVISION_ID ${HG_REVISION_PATH}.${HG_REVISION}) 50 SET(HG_REVISION 51 "${HG_REVISION_TAG}+${HG_REVISION_DIST}-${HG_REVISION_ID}") 35 52 ENDIF() 36 53 ENDIF() 37 SET(LEMON_VERSION ${HG_REVISION_ID} CACHE STRING "LEMON version string.") 54 55 SET(LEMON_VERSION ${HG_REVISION} CACHE STRING "LEMON version string.") 38 56 ENDIF() 39 57 … … 115 133 SET(LEMON_HAVE_LONG_LONG ${HAVE_LONG_LONG}) 116 134 117 INCLUDE(FindPythonInterp) 135 INCLUDE(FindThreads) 136 137 IF(NOT LEMON_THREADING) 138 IF(CMAKE_USE_PTHREADS_INIT) 139 SET(LEMON_THREADING "Pthread") 140 ELSEIF(CMAKE_USE_WIN32_THREADS_INIT) 141 SET(LEMON_THREADING "Win32") 142 ELSE() 143 SET(LEMON_THREADING "None") 144 ENDIF() 145 ENDIF() 146 147 SET( LEMON_THREADING "${LEMON_THREADING}" CACHE STRING 148 "Choose the threading library, options are: Pthread Win32 None." 149 FORCE ) 150 151 IF(LEMON_THREADING STREQUAL "Pthread") 152 SET(LEMON_USE_PTHREAD TRUE) 153 ELSEIF(LEMON_THREADING STREQUAL "Win32") 154 SET(LEMON_USE_WIN32_THREADS TRUE) 155 ENDIF() 118 156 119 157 ENABLE_TESTING() … … 127 165 ADD_SUBDIRECTORY(lemon) 128 166 IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) 167 ADD_SUBDIRECTORY(contrib) 129 168 ADD_SUBDIRECTORY(demo) 130 169 ADD_SUBDIRECTORY(tools) … … 150 189 ENDIF() 151 190 191 CONFIGURE_FILE( 192 ${PROJECT_SOURCE_DIR}/cmake/version.cmake.in 193 ${PROJECT_BINARY_DIR}/cmake/version.cmake 194 @ONLY 195 ) 196 197 SET(ARCHIVE_BASE_NAME ${CMAKE_PROJECT_NAME}) 198 STRING(TOLOWER ${ARCHIVE_BASE_NAME} ARCHIVE_BASE_NAME) 199 SET(ARCHIVE_NAME ${ARCHIVE_BASE_NAME}-${PROJECT_VERSION}) 200 ADD_CUSTOM_TARGET(dist 201 COMMAND cmake -E remove_directory ${ARCHIVE_NAME} 202 COMMAND hg archive ${ARCHIVE_NAME} 203 COMMAND cmake -E copy cmake/version.cmake ${ARCHIVE_NAME}/cmake/version.cmake 204 COMMAND tar -czf ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_NAME} 205 COMMAND zip -r ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.zip ${ARCHIVE_NAME} 206 COMMAND cmake -E copy_directory doc/html ${ARCHIVE_NAME}/doc/html 207 COMMAND tar -czf ${ARCHIVE_NAME}.tar.gz ${ARCHIVE_NAME} 208 COMMAND zip -r ${ARCHIVE_NAME}.zip ${ARCHIVE_NAME} 209 COMMAND cmake -E copy_directory doc/html ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} 210 COMMAND tar -czf ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} 211 COMMAND zip -r ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.zip ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} 212 COMMAND cmake -E remove_directory ${ARCHIVE_NAME} 213 COMMAND cmake -E remove_directory ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} 214 DEPENDS html 215 WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) 216 217 # CPACK config (Basically for NSIS) 152 218 IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) 153 219 SET(CPACK_PACKAGE_NAME ${PROJECT_NAME}) -
INSTALL
r890 r1148 2 2 ========================= 3 3 4 Since you are reading this I assume you already obtained one of the release 5 tarballs and successfully extracted it. The latest version of LEMON is 6 available at our web page (http://lemon.cs.elte.hu/). 4 This file contains instructions for building and installing LEMON from 5 source on Linux. The process on Windows is similar. 7 6 8 LEMON provides two different build environments, one is based on "autotool", 9 while the other is based on "cmake". This file contains instructions only for 10 the former one, which is the recommended build environment on Linux, Mac OSX 11 and other unices or if you use Cygwin on Windows. For cmake installation 12 instructions visit http://lemon.cs.elte.hu. 7 Note that it is not necessary to install LEMON in order to use 8 it. Instead, you can easily integrate it with your own code 9 directly. For instructions, see 10 https://lemon.cs.elte.hu/trac/lemon/wiki/HowToCompile 11 13 12 14 13 In order to install LEMON from the extracted source tarball you have to 15 14 issue the following commands: 16 15 17 1. `cd lemon-x.y.z'16 1. Step into the root of the source directory. 18 17 19 This command changes to the directory which was created when you 20 extracted the sources. The x.y.z part is a version number. 18 $ cd lemon-x.y.z 21 19 22 2. `./configure'20 2. Create a build subdirectory and step into it. 23 21 24 This command runs the configure shell script, which does some checks and25 creates the makefiles.22 $ mkdir build 23 $ cd build 26 24 27 3. `make'25 3. Perform system checks and create the makefiles. 28 26 29 This command compiles the non-template part of LEMON into libemon.a 30 file. It also compiles the programs in the tools subdirectory by 31 default. 27 $ cmake .. 32 28 33 4. `make check'29 4. Build LEMON. 34 30 35 This step is optional, but recommended. It runs the test programs that 36 we developed for LEMON to check whether the library works properly on 37 your platform. 31 $ make 38 32 39 5. `make install' 33 This command compiles the non-template part of LEMON into 34 libemon.a file. It also compiles the programs in the 'tools' and 35 'demo' subdirectories. 36 37 5. [Optional] Compile and run the self-tests. 38 39 $ make check 40 41 5. [Optional] Generate the user documentation. 42 43 $ make html 44 45 The release tarballs already include the documentation. 46 47 Note that for this step you need to have the following tools 48 installed: Python, Doxygen, Graphviz, Ghostscript, LaTeX. 49 50 6. [Optional] Install LEMON 51 52 $ make install 40 53 41 54 This command installs LEMON under /usr/local (you will need root 42 privileges to be able to do that). If you want to install it to some 43 other location, then pass the --prefix=DIRECTORY flag to configure in 44 step 2. For example: `./configure --prefix=/home/username/lemon'. 45 46 6. `make install-html' 47 48 This command installs the documentation under share/doc/lemon/docs. The 49 generated documentation is included in the tarball. If you want to 50 generate it yourself, then run `make html'. Note that for this you need 51 to have the following programs installed: Doxygen, Graphviz, Ghostscript, 52 Latex. 53 55 privileges to be able to do that). If you want to install it to 56 some other location, then pass the 57 -DCMAKE_INSTALL_PREFIX=DIRECTORY flag to cmake in Step 3. 58 For example: 59 60 $ cmake -DCMAKE_INSTALL_PREFIX=/home/username/lemon' 54 61 55 62 Configure Options and Variables 56 63 =============================== 57 64 58 In step 2 you can customize the actions of configure by setting variables 59 and passing options to it. This can be done like this: 60 `./configure [OPTION]... [VARIABLE=VALUE]...' 65 In Step 3, you can customize the build process by passing options to CMAKE. 61 66 62 Below you will find some useful variables and options (see `./configure --help' 63 for more): 67 $ cmake [OPTIONS] .. 64 68 65 CXX='comp' 69 You find a list of the most useful options below. 66 70 67 Change the C++ compiler to 'comp'. 68 69 CXXFLAGS='flags' 70 71 Pass the 'flags' to the compiler. For example CXXFLAGS='-O3 -march=pentium-m' 72 turns on generation of aggressively optimized Pentium-M specific code. 73 74 --prefix=PREFIX 71 -DCMAKE_INSTALL_PREFIX=PREFIX 75 72 76 73 Set the installation prefix to PREFIX. By default it is /usr/local. 77 74 78 - -enable-tools75 -DCMAKE_BUILD_TYPE=[Release|Debug|Maintainer|...] 79 76 80 Build the programs in the tools subdirectory (default).77 This sets the compiler options. The choices are the following 81 78 82 --disable-tools 79 'Release': A strong optimization is turned on (-O3 with gcc). This 80 is the default setting and we strongly recommend using this for 81 the final compilation. 83 82 84 Do not build the programs in the tools subdirectory. 83 'Debug': Optimization is turned off and debug info is added (-O0 84 -ggdb with gcc). If is recommended during the development. 85 85 86 --with-glpk[=PREFIX] 86 'Maintainer': The same as 'Debug' but the compiler warnings are 87 converted to errors (-Werror with gcc). In addition, 'make' will 88 also automatically compile and execute the test codes. It is the 89 best way of ensuring that LEMON codebase is clean and safe. 87 90 88 Enable GLPK support (default). You should specify the prefix too if 89 you installed GLPK to some non-standard location (e.g. your home 90 directory). If it is not found, GLPK support will be disabled. 91 'RelWithDebInfo': Optimized build with debug info. 91 92 92 --with-glpk-includedir=DIR 93 'MinSizeRel': Size optimized build (-Os with gcc) 93 94 94 The directory where the GLPK header files are located. This is only 95 useful when the GLPK headers and libraries are not under the same 96 prefix (which is unlikely). 95 -DTEST_WITH_VALGRIND=YES 97 96 98 --with-glpk-libdir=DIR 97 Using this, the test codes will be executed using valgrind. It is a 98 very effective way of identifying indexing problems and memory leaks. 99 99 100 The directory where the GLPK libraries are located. This is only 101 useful when the GLPK headers and libraries are not under the same 102 prefix (which is unlikely). 100 -DCMAKE_CXX_COMPILER=path-to-compiler 103 101 104 --without-glpk 102 Change the compiler to be used. 105 103 106 Disable GLPK support. 104 -DBUILD_SHARED_LIBS=TRUE 107 105 108 --with-cplex[=PREFIX] 106 Build shared library instead of static one. Think twice if you 107 really want to use this option. 109 108 110 Enable CPLEX support (default). You should specify the prefix too 111 if you installed CPLEX to some non-standard location 112 (e.g. /opt/ilog/cplex75). If it is not found, CPLEX support will be 113 disabled. 109 -DGLPK_ROOT_DIR=DIRECTORY 110 -DCOIN_ROOT_DIR=DIRECTORY 111 -DCPLEX_ROOT_DIR=DIRECTORY 114 112 115 --with-cplex-includedir=DIR 116 117 The directory where the CPLEX header files are located. This is 118 only useful when the CPLEX headers and libraries are not under the 119 same prefix (e.g. /usr/local/cplex/cplex75/include). 120 121 --with-cplex-libdir=DIR 122 123 The directory where the CPLEX libraries are located. This is only 124 useful when the CPLEX headers and libraries are not under the same 125 prefix (e.g. 126 /usr/local/cplex/cplex75/lib/i86_linux2_glibc2.2_gcc3.0/static_pic_mt). 127 128 --without-cplex 129 130 Disable CPLEX support. 131 132 --with-soplex[=PREFIX] 133 134 Enable SoPlex support (default). You should specify the prefix too if 135 you installed SoPlex to some non-standard location (e.g. your home 136 directory). If it is not found, SoPlex support will be disabled. 137 138 --with-soplex-includedir=DIR 139 140 The directory where the SoPlex header files are located. This is only 141 useful when the SoPlex headers and libraries are not under the same 142 prefix (which is unlikely). 143 144 --with-soplex-libdir=DIR 145 146 The directory where the SoPlex libraries are located. This is only 147 useful when the SoPlex headers and libraries are not under the same 148 prefix (which is unlikely). 149 150 --without-soplex 151 152 Disable SoPlex support. 153 154 --with-coin[=PREFIX] 155 156 Enable support for COIN-OR solvers (CLP and CBC). You should 157 specify the prefix too. (by default, COIN-OR tools install 158 themselves to the source code directory). This command enables the 159 solvers that are actually found. 160 161 --with-coin-includedir=DIR 162 163 The directory where the COIN-OR header files are located. This is 164 only useful when the COIN-OR headers and libraries are not under 165 the same prefix (which is unlikely). 166 167 --with-coin-libdir=DIR 168 169 The directory where the COIN-OR libraries are located. This is only 170 useful when the COIN-OR headers and libraries are not under the 171 same prefix (which is unlikely). 172 173 --without-coin 174 175 Disable COIN-OR support. 176 113 Install root directory prefixes of optional third party libraries. 177 114 178 115 Makefile Variables 179 116 ================== 180 117 181 Some Makefile variables are reserved by the GNU Coding Standards for 182 the use of the "user" - the person building the package. For instance, 183 CXX and CXXFLAGS are such variables, and have the same meaning as 184 explained in the previous section. These variables can be set on the 185 command line when invoking `make' like this: 186 `make [VARIABLE=VALUE]...' 118 make VERBOSE=1 187 119 188 WARNINGCXXFLAGS is a non-standard Makefile variable introduced by us 189 to hold several compiler flags related to warnings. Its default value 190 can be overridden when invoking `make'. For example to disable all 191 warning flags use `make WARNINGCXXFLAGS='. 192 193 In order to turn off a single flag from the default set of warning 194 flags, you can use the CXXFLAGS variable, since this is passed after 195 WARNINGCXXFLAGS. For example to turn off `-Wold-style-cast' (which is 196 used by default when g++ is detected) you can use 197 `make CXXFLAGS="-g -O2 -Wno-old-style-cast"'. 120 This results in a more verbose output by showing the full 121 compiler and linker commands. -
LICENSE
r959 r1148 2 2 copyright/license. 3 3 4 Copyright (C) 2003-201 0Egervary Jeno Kombinatorikus Optimalizalasi4 Copyright (C) 2003-2012 Egervary Jeno Kombinatorikus Optimalizalasi 5 5 Kutatocsoport (Egervary Combinatorial Optimization Research Group, 6 6 EGRES). -
cmake/version.cmake.in
r725 r1135 1 SET(LEMON_VERSION "@ PACKAGE_VERSION@" CACHE STRING "LEMON version string.")1 SET(LEMON_VERSION "@LEMON_VERSION@" CACHE STRING "LEMON version string.") -
doc/CMakeLists.txt
r1107 r1135 17 17 @ONLY 18 18 ) 19 20 # Copy doc from source (if exists) 21 IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/html AND 22 NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/html/index.html) 23 MESSAGE(STATUS "Copy doc from source tree") 24 EXECUTE_PROCESS( 25 COMMAND cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/html ${CMAKE_CURRENT_BINARY_DIR}/html 26 ) 27 ENDIF() 19 28 20 29 IF(DOXYGEN_EXECUTABLE AND PYTHONINTERP_FOUND AND GHOSTSCRIPT_EXECUTABLE) -
doc/Doxyfile.in
r1107 r1111 96 96 "@abs_top_srcdir@/lemon/concepts" \ 97 97 "@abs_top_srcdir@/demo" \ 98 "@abs_top_srcdir@/contrib" \ 98 99 "@abs_top_srcdir@/tools" \ 99 100 "@abs_top_srcdir@/test/test_tools.h" \ -
doc/coding_style.dox
r463 r1023 99 99 \subsection pri-loc-var Private member variables 100 100 101 Private member variables should start with underscore 101 Private member variables should start with underscore. 102 102 103 103 \code 104 _start_with_underscore s104 _start_with_underscore 105 105 \endcode 106 106 -
doc/dirs.dox
r463 r1031 32 32 documentation. 33 33 */ 34 35 /** 36 \dir contrib 37 \brief Directory for user contributed source codes. 38 39 You can place your own C++ code using LEMON into this directory, which 40 will compile to an executable along with LEMON when you build the 41 library. This is probably the easiest way of compiling short to medium 42 codes, for this does require neither a LEMON installed system-wide nor 43 adding several paths to the compiler. 44 45 Please have a look at <tt>contrib/CMakeLists.txt</tt> for 46 instruction on how to add your own files into the build process. */ 34 47 35 48 /** -
doc/groups.dox
r959 r1165 407 407 strongly polynomial \ref klein67primal, \ref goldberg89cyclecanceling. 408 408 409 In general NetworkSimplex is the most efficient implementation, 410 but in special cases other algorithms could be faster. 409 In general, \ref NetworkSimplex and \ref CostScaling are the most efficient 410 implementations. 411 \ref NetworkSimplex is usually the fastest on relatively small graphs (up to 412 several thousands of nodes) and on dense graphs, while \ref CostScaling is 413 typically more efficient on large graphs (e.g. hundreds of thousands of 414 nodes or above), especially if they are sparse. 415 However, other algorithms could be faster in special cases. 411 416 For example, if the total supply and/or capacities are rather small, 412 CapacityScaling is usually the fastest algorithm (without effective scaling). 417 \ref CapacityScaling is usually the fastest algorithm (without effective scaling). 418 419 These classes are intended to be used with integer-valued input data 420 (capacities, supply values, and costs), except for \ref CapacityScaling, 421 which is capable of handling real-valued arc costs (other numerical 422 data are required to be integer). 413 423 */ 414 424 … … 449 459 450 460 This group contains the algorithms for finding minimum mean cycles 451 \ref clrs01algorithms, \ref amo93networkflows.461 \ref amo93networkflows, \ref karp78characterization. 452 462 453 463 The \e minimum \e mean \e cycle \e problem is to find a directed cycle … … 465 475 466 476 LEMON contains three algorithms for solving the minimum mean cycle problem: 467 - \ref KarpMmc Karp's original algorithm \ref amo93networkflows, 468 \ref dasdan98minmeancycle. 477 - \ref KarpMmc Karp's original algorithm \ref karp78characterization. 469 478 - \ref HartmannOrlinMmc Hartmann-Orlin's algorithm, which is an improved 470 version of Karp's algorithm \ref dasdan98minmeancycle.479 version of Karp's algorithm \ref hartmann93finding. 471 480 - \ref HowardMmc Howard's policy iteration algorithm 472 \ref dasdan98minmeancycle .473 474 In practice, the \ref HowardMmc "Howard" algorithm provedto be by far the481 \ref dasdan98minmeancycle, \ref dasdan04experimental. 482 483 In practice, the \ref HowardMmc "Howard" algorithm turned out to be by far the 475 484 most efficient one, though the best known theoretical bound on its running 476 485 time is exponential. … … 540 549 541 550 /** 542 @defgroup planar Planar ityEmbedding and Drawing551 @defgroup planar Planar Embedding and Drawing 543 552 @ingroup algs 544 553 \brief Algorithms for planarity checking, embedding and drawing … … 552 561 553 562 /** 554 @defgroup approx Approximation Algorithms563 @defgroup approx_algs Approximation Algorithms 555 564 @ingroup algs 556 565 \brief Approximation algorithms. … … 558 567 This group contains the approximation and heuristic algorithms 559 568 implemented in LEMON. 569 570 <b>Maximum Clique Problem</b> 571 - \ref GrossoLocatelliPullanMc An efficient heuristic algorithm of 572 Grosso, Locatelli, and Pullan. 560 573 */ 561 574 -
doc/min_cost_flow.dox
r956 r1164 102 102 \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A \f] 103 103 104 However if the sum of the supply values is zero, then these two problems104 However, if the sum of the supply values is zero, then these two problems 105 105 are equivalent. 106 106 The \ref min_cost_flow_algs "algorithms" in LEMON support the general -
doc/references.bib
r802 r1164 5 5 title = {{LEMON} -- {L}ibrary for {E}fficient {M}odeling and 6 6 {O}ptimization in {N}etworks}, 7 howpublished = {\url{http://lemon.cs.elte.hu/}}, 8 year = 2009 7 howpublished = {\url{http://lemon.cs.elte.hu/}} 9 8 } 10 9 … … 212 211 volume = 23, 213 212 pages = {309-311} 213 } 214 215 @article{hartmann93finding, 216 author = {Mark Hartmann and James B. Orlin}, 217 title = {Finding minimum cost to time ratio cycles with small 218 integral transit times}, 219 journal = {Networks}, 220 year = 1993, 221 volume = 23, 222 pages = {567-574} 214 223 } 215 224 … … 226 235 } 227 236 237 @article{dasdan04experimental, 238 author = {Ali Dasdan}, 239 title = {Experimental analysis of the fastest optimum cycle 240 ratio and mean algorithms}, 241 journal = {ACM Trans. Des. Autom. Electron. Syst.}, 242 year = 2004, 243 volume = 9, 244 issue = 4, 245 pages = {385-418} 246 } 247 228 248 229 249 %%%%% Minimum cost flow algorithms %%%%% … … 298 318 address = {Dublin, Ireland}, 299 319 year = 1991, 300 month = sep, 301 } 320 month = sep 321 } 322 323 %%%%% Other algorithms %%%%% 324 325 @article{grosso08maxclique, 326 author = {Andrea Grosso and Marco Locatelli and Wayne Pullan}, 327 title = {Simple ingredients leading to very efficient 328 heuristics for the maximum clique problem}, 329 journal = {Journal of Heuristics}, 330 year = 2008, 331 volume = 14, 332 number = 6, 333 pages = {587--612} 334 } -
lemon/CMakeLists.txt
r1113 r1133 5 5 6 6 CONFIGURE_FILE( 7 ${CMAKE_CURRENT_SOURCE_DIR}/config.h. cmake7 ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in 8 8 ${CMAKE_CURRENT_BINARY_DIR}/config.h 9 9 ) 10 10 11 11 CONFIGURE_FILE( 12 ${CMAKE_CURRENT_SOURCE_DIR}/lemon.pc. cmake12 ${CMAKE_CURRENT_SOURCE_DIR}/lemon.pc.in 13 13 ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc 14 14 @ONLY -
lemon/bits/alteration_notifier.h
r463 r1131 24 24 25 25 #include <lemon/core.h> 26 #include <lemon/bits/lock.h> 26 27 27 28 //\ingroup graphbits … … 252 253 typedef std::list<ObserverBase*> Observers; 253 254 Observers _observers; 254 255 lemon::bits::Lock _lock; 255 256 256 257 public: … … 333 334 334 335 void attach(ObserverBase& observer) { 336 _lock.lock(); 335 337 observer._index = _observers.insert(_observers.begin(), &observer); 336 338 observer._notifier = this; 339 _lock.unlock(); 337 340 } 338 341 339 342 void detach(ObserverBase& observer) { 343 _lock.lock(); 340 344 _observers.erase(observer._index); 341 345 observer._index = _observers.end(); 342 346 observer._notifier = 0; 347 _lock.unlock(); 343 348 } 344 349 -
lemon/bits/windows.cc
r1055 r1163 131 131 #endif 132 132 } 133 134 WinLock::WinLock() { 135 #ifdef WIN32 136 CRITICAL_SECTION *lock = new CRITICAL_SECTION; 137 InitializeCriticalSection(lock); 138 _repr = lock; 139 #else 140 _repr = 0; //Just to avoid 'unused variable' warning with clang 141 #endif 142 } 143 144 WinLock::~WinLock() { 145 #ifdef WIN32 146 CRITICAL_SECTION *lock = static_cast<CRITICAL_SECTION*>(_repr); 147 DeleteCriticalSection(lock); 148 delete lock; 149 #endif 150 } 151 152 void WinLock::lock() { 153 #ifdef WIN32 154 CRITICAL_SECTION *lock = static_cast<CRITICAL_SECTION*>(_repr); 155 EnterCriticalSection(lock); 156 #endif 157 } 158 159 void WinLock::unlock() { 160 #ifdef WIN32 161 CRITICAL_SECTION *lock = static_cast<CRITICAL_SECTION*>(_repr); 162 LeaveCriticalSection(lock); 163 #endif 164 } 133 165 } 134 166 } -
lemon/bits/windows.h
r576 r1131 29 29 std::string getWinFormattedDate(); 30 30 int getWinRndSeed(); 31 32 class WinLock { 33 public: 34 WinLock(); 35 ~WinLock(); 36 void lock(); 37 void unlock(); 38 private: 39 void *_repr; 40 }; 31 41 } 32 42 } -
lemon/capacity_scaling.h
r956 r1166 71 71 /// solution method. 72 72 /// 73 /// This algorithm is typically slower than \ref CostScaling and 74 /// \ref NetworkSimplex, but in special cases, it can be more 75 /// efficient than them. 76 /// (For more information, see \ref min_cost_flow_algs "the module page".) 77 /// 73 78 /// Most of the parameters of the problem (except for the digraph) 74 79 /// can be given using separate functions, and the algorithm can be … … 87 92 /// consider to use the named template parameters instead. 88 93 /// 89 /// \warning Both number types must be signed and all input data must 90 /// be integer. 91 /// \warning This algorithm does not support negative costs for such 92 /// arcs that have infinite upper bound. 94 /// \warning Both \c V and \c C must be signed number types. 95 /// \warning Capacity bounds and supply values must be integer, but 96 /// arc costs can be arbitrary real numbers. 97 /// \warning This algorithm does not support negative costs for 98 /// arcs having infinite upper bound. 93 99 #ifdef DOXYGEN 94 100 template <typename GR, typename V, typename C, typename TR> … … 423 429 /// 424 430 /// Using this function has the same effect as using \ref supplyMap() 425 /// with sucha map in which \c k is assigned to \c s, \c -k is431 /// with a map in which \c k is assigned to \c s, \c -k is 426 432 /// assigned to \c t and all other nodes have zero supply value. 427 433 /// … … 676 682 } 677 683 678 /// \brief Return the flow map (the primal solution). 684 /// \brief Copy the flow values (the primal solution) into the 685 /// given map. 679 686 /// 680 687 /// This function copies the flow value on each arc into the given … … 700 707 } 701 708 702 /// \brief Return the potential map (the dual solution). 709 /// \brief Copy the potential values (the dual solution) into the 710 /// given map. 703 711 /// 704 712 /// This function copies the potential (dual value) of each node -
lemon/config.h.in
r725 r1133 1 /* The version string */ 2 #undef LEMON_VERSION 3 4 /* Define to 1 if you have long long */ 5 #undef LEMON_HAVE_LONG_LONG 6 7 /* Define to 1 if you have any LP solver. */ 8 #undef LEMON_HAVE_LP 9 10 /* Define to 1 if you have any MIP solver. */ 11 #undef LEMON_HAVE_MIP 12 13 /* Define to 1 if you have CPLEX. */ 14 #undef LEMON_HAVE_CPLEX 15 16 /* Define to 1 if you have GLPK. */ 17 #undef LEMON_HAVE_GLPK 18 19 /* Define to 1 if you have SOPLEX */ 20 #undef LEMON_HAVE_SOPLEX 21 22 /* Define to 1 if you have CLP */ 23 #undef LEMON_HAVE_CLP 24 25 /* Define to 1 if you have CBC */ 26 #undef LEMON_HAVE_CBC 1 #define LEMON_VERSION "@PROJECT_VERSION@" 2 #cmakedefine LEMON_HAVE_LONG_LONG 1 3 #cmakedefine LEMON_HAVE_LP 1 4 #cmakedefine LEMON_HAVE_MIP 1 5 #cmakedefine LEMON_HAVE_GLPK 1 6 #cmakedefine LEMON_HAVE_CPLEX 1 7 #cmakedefine LEMON_HAVE_CLP 1 8 #cmakedefine LEMON_HAVE_CBC 1 9 #cmakedefine LEMON_USE_PTHREAD 1 10 #cmakedefine LEMON_USE_WIN32_THREADS 1 -
lemon/core.h
r1159 r1162 447 447 448 448 } 449 450 /// \brief Check whether a graph is undirected. 451 /// 452 /// This function returns \c true if the given graph is undirected. 453 #ifdef DOXYGEN 454 template <typename GR> 455 bool undirected(const GR& g) { return false; } 456 #else 457 template <typename GR> 458 typename enable_if<UndirectedTagIndicator<GR>, bool>::type 459 undirected(const GR&) { 460 return true; 461 } 462 template <typename GR> 463 typename disable_if<UndirectedTagIndicator<GR>, bool>::type 464 undirected(const GR&) { 465 return false; 466 } 467 #endif 449 468 450 469 /// \brief Class to copy a digraph. -
lemon/cost_scaling.h
r1041 r1165 98 98 /// "preflow push-relabel" algorithm for the maximum flow problem. 99 99 /// 100 /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest 101 /// implementations available in LEMON for solving this problem. 102 /// (For more information, see \ref min_cost_flow_algs "the module page".) 103 /// 100 104 /// Most of the parameters of the problem (except for the digraph) 101 105 /// can be given using separate functions, and the algorithm can be … … 114 118 /// consider to use the named template parameters instead. 115 119 /// 116 /// \warning Both number types must be signed and all input data must 120 /// \warning Both \c V and \c C must be signed number types. 121 /// \warning All input data (capacities, supply values, and costs) must 117 122 /// be integer. 118 /// \warning This algorithm does not support negative costs for such119 /// arcs that haveinfinite upper bound.123 /// \warning This algorithm does not support negative costs for 124 /// arcs having infinite upper bound. 120 125 /// 121 126 /// \note %CostScaling provides three different internal methods, … … 179 184 /// relabel operation. 180 185 /// By default, the so called \ref PARTIAL_AUGMENT 181 /// "Partial Augment-Relabel" method is used, which provedto be186 /// "Partial Augment-Relabel" method is used, which turned out to be 182 187 /// the most efficient and the most robust on various test inputs. 183 188 /// However, the other methods can be selected using the \ref run() … … 234 239 }; 235 240 236 typedef StaticVectorMap<StaticDigraph::Node, LargeCost> LargeCostNodeMap;237 241 typedef StaticVectorMap<StaticDigraph::Arc, LargeCost> LargeCostArcMap; 238 242 … … 285 289 int _max_rank; 286 290 287 // Data for a StaticDigraph structure288 typedef std::pair<int, int> IntPair;289 StaticDigraph _sgr;290 std::vector<IntPair> _arc_vec;291 std::vector<LargeCost> _cost_vec;292 LargeCostArcMap _cost_map;293 LargeCostNodeMap _pi_map;294 295 291 public: 296 292 … … 339 335 CostScaling(const GR& graph) : 340 336 _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), 341 _cost_map(_cost_vec), _pi_map(_pi),342 337 INF(std::numeric_limits<Value>::has_infinity ? 343 338 std::numeric_limits<Value>::infinity() : … … 448 443 /// 449 444 /// Using this function has the same effect as using \ref supplyMap() 450 /// with sucha map in which \c k is assigned to \c s, \c -k is445 /// with a map in which \c k is assigned to \c s, \c -k is 451 446 /// assigned to \c t and all other nodes have zero supply value. 452 447 /// … … 494 489 /// \param method The internal method that will be used in the 495 490 /// algorithm. For more information, see \ref Method. 496 /// \param factor The cost scaling factor. It must be larger than one.491 /// \param factor The cost scaling factor. It must be at least two. 497 492 /// 498 493 /// \return \c INFEASIBLE if no feasible flow exists, … … 508 503 /// \see ProblemType, Method 509 504 /// \see resetParams(), reset() 510 ProblemType run(Method method = PARTIAL_AUGMENT, int factor = 8) { 505 ProblemType run(Method method = PARTIAL_AUGMENT, int factor = 16) { 506 LEMON_ASSERT(factor >= 2, "The scaling factor must be at least 2"); 511 507 _alpha = factor; 512 508 ProblemType pt = init(); … … 572 568 } 573 569 574 /// \brief Reset all the parameters that have been given before. 575 /// 576 /// This function resets all the paramaters that have been given 577 /// before using functions \ref lowerMap(), \ref upperMap(), 578 /// \ref costMap(), \ref supplyMap(), \ref stSupply(). 579 /// 580 /// It is useful for multiple run() calls. If this function is not 581 /// used, all the parameters given before are kept for the next 582 /// \ref run() call. 583 /// However, the underlying digraph must not be modified after this 584 /// class have been constructed, since it copies and extends the graph. 570 /// \brief Reset the internal data structures and all the parameters 571 /// that have been given before. 572 /// 573 /// This function resets the internal data structures and all the 574 /// paramaters that have been given before using functions \ref lowerMap(), 575 /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). 576 /// 577 /// It is useful for multiple \ref run() calls. By default, all the given 578 /// parameters are kept for the next \ref run() call, unless 579 /// \ref resetParams() or \ref reset() is used. 580 /// If the underlying digraph was also modified after the construction 581 /// of the class or the last \ref reset() call, then the \ref reset() 582 /// function must be used, otherwise \ref resetParams() is sufficient. 583 /// 584 /// See \ref resetParams() for examples. 585 /// 585 586 /// \return <tt>(*this)</tt> 587 /// 588 /// \see resetParams(), run() 586 589 CostScaling& reset() { 587 590 // Resize vectors … … 608 611 _excess.resize(_res_node_num); 609 612 _next_out.resize(_res_node_num); 610 611 _arc_vec.reserve(_res_arc_num);612 _cost_vec.reserve(_res_arc_num);613 613 614 614 // Copy the graph … … 706 706 } 707 707 708 /// \brief Return the flow map (the primal solution). 708 /// \brief Copy the flow values (the primal solution) into the 709 /// given map. 709 710 /// 710 711 /// This function copies the flow value on each arc into the given … … 730 731 } 731 732 732 /// \brief Return the potential map (the dual solution). 733 /// \brief Copy the potential values (the dual solution) into the 734 /// given map. 733 735 /// 734 736 /// This function copies the potential (dual value) of each node … … 887 889 } 888 890 889 return OPTIMAL;890 }891 892 // Execute the algorithm and transform the results893 void start(Method method) {894 // Maximum path length for partial augment895 const int MAX_PATH_LENGTH = 4;896 897 891 // Initialize data structures for buckets 898 892 _max_rank = _alpha * _res_node_num; … … 902 896 _rank.resize(_res_node_num + 1); 903 897 904 // Execute the algorithm 898 return OPTIMAL; 899 } 900 901 // Execute the algorithm and transform the results 902 void start(Method method) { 903 const int MAX_PARTIAL_PATH_LENGTH = 4; 904 905 905 switch (method) { 906 906 case PUSH: … … 911 911 break; 912 912 case PARTIAL_AUGMENT: 913 startAugment(MAX_PA TH_LENGTH);913 startAugment(MAX_PARTIAL_PATH_LENGTH); 914 914 break; 915 915 } 916 916 917 // Compute node potentials for the original costs 918 _arc_vec.clear(); 919 _cost_vec.clear(); 920 for (int j = 0; j != _res_arc_num; ++j) { 921 if (_res_cap[j] > 0) { 922 _arc_vec.push_back(IntPair(_source[j], _target[j])); 923 _cost_vec.push_back(_scost[j]); 924 } 925 } 926 _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); 927 928 typename BellmanFord<StaticDigraph, LargeCostArcMap> 929 ::template SetDistMap<LargeCostNodeMap>::Create bf(_sgr, _cost_map); 930 bf.distMap(_pi_map); 931 bf.init(0); 932 bf.start(); 917 // Compute node potentials (dual solution) 918 for (int i = 0; i != _res_node_num; ++i) { 919 _pi[i] = static_cast<Cost>(_pi[i] / (_res_node_num * _alpha)); 920 } 921 bool optimal = true; 922 for (int i = 0; optimal && i != _res_node_num; ++i) { 923 LargeCost pi_i = _pi[i]; 924 int last_out = _first_out[i+1]; 925 for (int j = _first_out[i]; j != last_out; ++j) { 926 if (_res_cap[j] > 0 && _scost[j] + pi_i - _pi[_target[j]] < 0) { 927 optimal = false; 928 break; 929 } 930 } 931 } 932 933 if (!optimal) { 934 // Compute node potentials for the original costs with BellmanFord 935 // (if it is necessary) 936 typedef std::pair<int, int> IntPair; 937 StaticDigraph sgr; 938 std::vector<IntPair> arc_vec; 939 std::vector<LargeCost> cost_vec; 940 LargeCostArcMap cost_map(cost_vec); 941 942 arc_vec.clear(); 943 cost_vec.clear(); 944 for (int j = 0; j != _res_arc_num; ++j) { 945 if (_res_cap[j] > 0) { 946 int u = _source[j], v = _target[j]; 947 arc_vec.push_back(IntPair(u, v)); 948 cost_vec.push_back(_scost[j] + _pi[u] - _pi[v]); 949 } 950 } 951 sgr.build(_res_node_num, arc_vec.begin(), arc_vec.end()); 952 953 typename BellmanFord<StaticDigraph, LargeCostArcMap>::Create 954 bf(sgr, cost_map); 955 bf.init(0); 956 bf.start(); 957 958 for (int i = 0; i != _res_node_num; ++i) { 959 _pi[i] += bf.dist(sgr.node(i)); 960 } 961 } 962 963 // Shift potentials to meet the requirements of the GEQ type 964 // optimality conditions 965 LargeCost max_pot = _pi[_root]; 966 for (int i = 0; i != _res_node_num; ++i) { 967 if (_pi[i] > max_pot) max_pot = _pi[i]; 968 } 969 if (max_pot != 0) { 970 for (int i = 0; i != _res_node_num; ++i) { 971 _pi[i] -= max_pot; 972 } 973 } 933 974 934 975 // Handle non-zero lower bounds … … 948 989 LargeCost pi_u = _pi[u]; 949 990 for (int a = _first_out[u]; a != last_out; ++a) { 950 int v = _target[a]; 951 if (_res_cap[a] > 0 && _cost[a] + pi_u - _pi[v] < 0) { 952 Value delta = _res_cap[a]; 953 _excess[u] -= delta; 954 _excess[v] += delta; 955 _res_cap[a] = 0; 956 _res_cap[_reverse[a]] += delta; 991 Value delta = _res_cap[a]; 992 if (delta > 0) { 993 int v = _target[a]; 994 if (_cost[a] + pi_u - _pi[v] < 0) { 995 _excess[u] -= delta; 996 _excess[v] += delta; 997 _res_cap[a] = 0; 998 _res_cap[_reverse[a]] += delta; 999 } 957 1000 } 958 1001 } … … 970 1013 } 971 1014 972 // Early termination heuristic 973 bool earlyTermination() { 974 const double EARLY_TERM_FACTOR = 3.0; 975 976 // Build a static residual graph 977 _arc_vec.clear(); 978 _cost_vec.clear(); 979 for (int j = 0; j != _res_arc_num; ++j) { 980 if (_res_cap[j] > 0) { 981 _arc_vec.push_back(IntPair(_source[j], _target[j])); 982 _cost_vec.push_back(_cost[j] + 1); 983 } 984 } 985 _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); 986 987 // Run Bellman-Ford algorithm to check if the current flow is optimal 988 BellmanFord<StaticDigraph, LargeCostArcMap> bf(_sgr, _cost_map); 989 bf.init(0); 990 bool done = false; 991 int K = int(EARLY_TERM_FACTOR * std::sqrt(double(_res_node_num))); 992 for (int i = 0; i < K && !done; ++i) { 993 done = bf.processNextWeakRound(); 994 } 995 return done; 1015 // Price (potential) refinement heuristic 1016 bool priceRefinement() { 1017 1018 // Stack for stroing the topological order 1019 IntVector stack(_res_node_num); 1020 int stack_top; 1021 1022 // Perform phases 1023 while (topologicalSort(stack, stack_top)) { 1024 1025 // Compute node ranks in the acyclic admissible network and 1026 // store the nodes in buckets 1027 for (int i = 0; i != _res_node_num; ++i) { 1028 _rank[i] = 0; 1029 } 1030 const int bucket_end = _root + 1; 1031 for (int r = 0; r != _max_rank; ++r) { 1032 _buckets[r] = bucket_end; 1033 } 1034 int top_rank = 0; 1035 for ( ; stack_top >= 0; --stack_top) { 1036 int u = stack[stack_top], v; 1037 int rank_u = _rank[u]; 1038 1039 LargeCost rc, pi_u = _pi[u]; 1040 int last_out = _first_out[u+1]; 1041 for (int a = _first_out[u]; a != last_out; ++a) { 1042 if (_res_cap[a] > 0) { 1043 v = _target[a]; 1044 rc = _cost[a] + pi_u - _pi[v]; 1045 if (rc < 0) { 1046 LargeCost nrc = static_cast<LargeCost>((-rc - 0.5) / _epsilon); 1047 if (nrc < LargeCost(_max_rank)) { 1048 int new_rank_v = rank_u + static_cast<int>(nrc); 1049 if (new_rank_v > _rank[v]) { 1050 _rank[v] = new_rank_v; 1051 } 1052 } 1053 } 1054 } 1055 } 1056 1057 if (rank_u > 0) { 1058 top_rank = std::max(top_rank, rank_u); 1059 int bfirst = _buckets[rank_u]; 1060 _bucket_next[u] = bfirst; 1061 _bucket_prev[bfirst] = u; 1062 _buckets[rank_u] = u; 1063 } 1064 } 1065 1066 // Check if the current flow is epsilon-optimal 1067 if (top_rank == 0) { 1068 return true; 1069 } 1070 1071 // Process buckets in top-down order 1072 for (int rank = top_rank; rank > 0; --rank) { 1073 while (_buckets[rank] != bucket_end) { 1074 // Remove the first node from the current bucket 1075 int u = _buckets[rank]; 1076 _buckets[rank] = _bucket_next[u]; 1077 1078 // Search the outgoing arcs of u 1079 LargeCost rc, pi_u = _pi[u]; 1080 int last_out = _first_out[u+1]; 1081 int v, old_rank_v, new_rank_v; 1082 for (int a = _first_out[u]; a != last_out; ++a) { 1083 if (_res_cap[a] > 0) { 1084 v = _target[a]; 1085 old_rank_v = _rank[v]; 1086 1087 if (old_rank_v < rank) { 1088 1089 // Compute the new rank of node v 1090 rc = _cost[a] + pi_u - _pi[v]; 1091 if (rc < 0) { 1092 new_rank_v = rank; 1093 } else { 1094 LargeCost nrc = rc / _epsilon; 1095 new_rank_v = 0; 1096 if (nrc < LargeCost(_max_rank)) { 1097 new_rank_v = rank - 1 - static_cast<int>(nrc); 1098 } 1099 } 1100 1101 // Change the rank of node v 1102 if (new_rank_v > old_rank_v) { 1103 _rank[v] = new_rank_v; 1104 1105 // Remove v from its old bucket 1106 if (old_rank_v > 0) { 1107 if (_buckets[old_rank_v] == v) { 1108 _buckets[old_rank_v] = _bucket_next[v]; 1109 } else { 1110 int pv = _bucket_prev[v], nv = _bucket_next[v]; 1111 _bucket_next[pv] = nv; 1112 _bucket_prev[nv] = pv; 1113 } 1114 } 1115 1116 // Insert v into its new bucket 1117 int nv = _buckets[new_rank_v]; 1118 _bucket_next[v] = nv; 1119 _bucket_prev[nv] = v; 1120 _buckets[new_rank_v] = v; 1121 } 1122 } 1123 } 1124 } 1125 1126 // Refine potential of node u 1127 _pi[u] -= rank * _epsilon; 1128 } 1129 } 1130 1131 } 1132 1133 return false; 1134 } 1135 1136 // Find and cancel cycles in the admissible network and 1137 // determine topological order using DFS 1138 bool topologicalSort(IntVector &stack, int &stack_top) { 1139 const int MAX_CYCLE_CANCEL = 1; 1140 1141 BoolVector reached(_res_node_num, false); 1142 BoolVector processed(_res_node_num, false); 1143 IntVector pred(_res_node_num); 1144 for (int i = 0; i != _res_node_num; ++i) { 1145 _next_out[i] = _first_out[i]; 1146 } 1147 stack_top = -1; 1148 1149 int cycle_cnt = 0; 1150 for (int start = 0; start != _res_node_num; ++start) { 1151 if (reached[start]) continue; 1152 1153 // Start DFS search from this start node 1154 pred[start] = -1; 1155 int tip = start, v; 1156 while (true) { 1157 // Check the outgoing arcs of the current tip node 1158 reached[tip] = true; 1159 LargeCost pi_tip = _pi[tip]; 1160 int a, last_out = _first_out[tip+1]; 1161 for (a = _next_out[tip]; a != last_out; ++a) { 1162 if (_res_cap[a] > 0) { 1163 v = _target[a]; 1164 if (_cost[a] + pi_tip - _pi[v] < 0) { 1165 if (!reached[v]) { 1166 // A new node is reached 1167 reached[v] = true; 1168 pred[v] = tip; 1169 _next_out[tip] = a; 1170 tip = v; 1171 a = _next_out[tip]; 1172 last_out = _first_out[tip+1]; 1173 break; 1174 } 1175 else if (!processed[v]) { 1176 // A cycle is found 1177 ++cycle_cnt; 1178 _next_out[tip] = a; 1179 1180 // Find the minimum residual capacity along the cycle 1181 Value d, delta = _res_cap[a]; 1182 int u, delta_node = tip; 1183 for (u = tip; u != v; ) { 1184 u = pred[u]; 1185 d = _res_cap[_next_out[u]]; 1186 if (d <= delta) { 1187 delta = d; 1188 delta_node = u; 1189 } 1190 } 1191 1192 // Augment along the cycle 1193 _res_cap[a] -= delta; 1194 _res_cap[_reverse[a]] += delta; 1195 for (u = tip; u != v; ) { 1196 u = pred[u]; 1197 int ca = _next_out[u]; 1198 _res_cap[ca] -= delta; 1199 _res_cap[_reverse[ca]] += delta; 1200 } 1201 1202 // Check the maximum number of cycle canceling 1203 if (cycle_cnt >= MAX_CYCLE_CANCEL) { 1204 return false; 1205 } 1206 1207 // Roll back search to delta_node 1208 if (delta_node != tip) { 1209 for (u = tip; u != delta_node; u = pred[u]) { 1210 reached[u] = false; 1211 } 1212 tip = delta_node; 1213 a = _next_out[tip] + 1; 1214 last_out = _first_out[tip+1]; 1215 break; 1216 } 1217 } 1218 } 1219 } 1220 } 1221 1222 // Step back to the previous node 1223 if (a == last_out) { 1224 processed[tip] = true; 1225 stack[++stack_top] = tip; 1226 tip = pred[tip]; 1227 if (tip < 0) { 1228 // Finish DFS from the current start node 1229 break; 1230 } 1231 ++_next_out[tip]; 1232 } 1233 } 1234 1235 } 1236 1237 return (cycle_cnt == 0); 996 1238 } 997 1239 998 1240 // Global potential update heuristic 999 1241 void globalUpdate() { 1000 int bucket_end = _root + 1;1242 const int bucket_end = _root + 1; 1001 1243 1002 1244 // Initialize buckets … … 1005 1247 } 1006 1248 Value total_excess = 0; 1249 int b0 = bucket_end; 1007 1250 for (int i = 0; i != _res_node_num; ++i) { 1008 1251 if (_excess[i] < 0) { 1009 1252 _rank[i] = 0; 1010 _bucket_next[i] = _buckets[0];1011 _bucket_prev[ _buckets[0]] = i;1012 _buckets[0]= i;1253 _bucket_next[i] = b0; 1254 _bucket_prev[b0] = i; 1255 b0 = i; 1013 1256 } else { 1014 1257 total_excess += _excess[i]; … … 1017 1260 } 1018 1261 if (total_excess == 0) return; 1262 _buckets[0] = b0; 1019 1263 1020 1264 // Search the buckets … … 1038 1282 LargeCost nrc = (_cost[ra] + _pi[v] - pi_u) / _epsilon; 1039 1283 int new_rank_v = old_rank_v; 1040 if (nrc < LargeCost(_max_rank)) 1041 new_rank_v = r + 1 + int(nrc); 1284 if (nrc < LargeCost(_max_rank)) { 1285 new_rank_v = r + 1 + static_cast<int>(nrc); 1286 } 1042 1287 1043 1288 // Change the rank of v … … 1051 1296 _buckets[old_rank_v] = _bucket_next[v]; 1052 1297 } else { 1053 _bucket_next[_bucket_prev[v]] = _bucket_next[v]; 1054 _bucket_prev[_bucket_next[v]] = _bucket_prev[v]; 1298 int pv = _bucket_prev[v], nv = _bucket_next[v]; 1299 _bucket_next[pv] = nv; 1300 _bucket_prev[nv] = pv; 1055 1301 } 1056 1302 } 1057 1303 1058 // Insert v to its new bucket 1059 _bucket_next[v] = _buckets[new_rank_v]; 1060 _bucket_prev[_buckets[new_rank_v]] = v; 1304 // Insert v into its new bucket 1305 int nv = _buckets[new_rank_v]; 1306 _bucket_next[v] = nv; 1307 _bucket_prev[nv] = v; 1061 1308 _buckets[new_rank_v] = v; 1062 1309 } … … 1087 1334 void startAugment(int max_length) { 1088 1335 // Paramters for heuristics 1089 const int EARLY_TERM_EPSILON_LIMIT = 1000; 1090 const double GLOBAL_UPDATE_FACTOR = 3.0; 1091 1092 const int global_update_freq = int(GLOBAL_UPDATE_FACTOR * 1336 const int PRICE_REFINEMENT_LIMIT = 2; 1337 const double GLOBAL_UPDATE_FACTOR = 1.0; 1338 const int global_update_skip = static_cast<int>(GLOBAL_UPDATE_FACTOR * 1093 1339 (_res_node_num + _sup_node_num * _sup_node_num)); 1094 int next_update_limit = global_update_freq; 1095 1340 int next_global_update_limit = global_update_skip; 1341 1342 // Perform cost scaling phases 1343 IntVector path; 1344 BoolVector path_arc(_res_arc_num, false); 1096 1345 int relabel_cnt = 0; 1097 1098 // Perform cost scaling phases 1099 std::vector<int> path; 1346 int eps_phase_cnt = 0; 1100 1347 for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? 1101 1348 1 : _epsilon / _alpha ) 1102 1349 { 1103 // Early termination heuristic 1104 if (_epsilon <= EARLY_TERM_EPSILON_LIMIT) { 1105 if (earlyTermination()) break; 1350 ++eps_phase_cnt; 1351 1352 // Price refinement heuristic 1353 if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) { 1354 if (priceRefinement()) continue; 1106 1355 } 1107 1356 … … 1120 1369 1121 1370 // Find an augmenting path from the start node 1122 path.clear();1123 1371 int tip = start; 1124 while ( _excess[tip] >= 0 && int(path.size()) < max_length) {1372 while (int(path.size()) < max_length && _excess[tip] >= 0) { 1125 1373 int u; 1126 LargeCost min_red_cost, rc, pi_tip = _pi[tip]; 1374 LargeCost rc, min_red_cost = std::numeric_limits<LargeCost>::max(); 1375 LargeCost pi_tip = _pi[tip]; 1127 1376 int last_out = _first_out[tip+1]; 1128 1377 for (int a = _next_out[tip]; a != last_out; ++a) { 1129 u = _target[a]; 1130 if (_res_cap[a] > 0 && _cost[a] + pi_tip - _pi[u] < 0) { 1131 path.push_back(a); 1132 _next_out[tip] = a; 1133 tip = u; 1134 goto next_step; 1378 if (_res_cap[a] > 0) { 1379 u = _target[a]; 1380 rc = _cost[a] + pi_tip - _pi[u]; 1381 if (rc < 0) { 1382 path.push_back(a); 1383 _next_out[tip] = a; 1384 if (path_arc[a]) { 1385 goto augment; // a cycle is found, stop path search 1386 } 1387 tip = u; 1388 path_arc[a] = true; 1389 goto next_step; 1390 } 1391 else if (rc < min_red_cost) { 1392 min_red_cost = rc; 1393 } 1135 1394 } 1136 1395 } 1137 1396 1138 1397 // Relabel tip node 1139 min_red_cost = std::numeric_limits<LargeCost>::max();1140 1398 if (tip != start) { 1141 1399 int ra = _reverse[path.back()]; 1142 min_red_cost = _cost[ra] + pi_tip - _pi[_target[ra]]; 1400 min_red_cost = 1401 std::min(min_red_cost, _cost[ra] + pi_tip - _pi[_target[ra]]); 1143 1402 } 1403 last_out = _next_out[tip]; 1144 1404 for (int a = _first_out[tip]; a != last_out; ++a) { 1145 rc = _cost[a] + pi_tip - _pi[_target[a]]; 1146 if (_res_cap[a] > 0 && rc < min_red_cost) { 1147 min_red_cost = rc; 1405 if (_res_cap[a] > 0) { 1406 rc = _cost[a] + pi_tip - _pi[_target[a]]; 1407 if (rc < min_red_cost) { 1408 min_red_cost = rc; 1409 } 1148 1410 } 1149 1411 } … … 1154 1416 // Step back 1155 1417 if (tip != start) { 1156 tip = _source[path.back()]; 1418 int pa = path.back(); 1419 path_arc[pa] = false; 1420 tip = _source[pa]; 1157 1421 path.pop_back(); 1158 1422 } … … 1162 1426 1163 1427 // Augment along the found path (as much flow as possible) 1428 augment: 1164 1429 Value delta; 1165 1430 int pa, u, v = start; … … 1168 1433 u = v; 1169 1434 v = _target[pa]; 1435 path_arc[pa] = false; 1170 1436 delta = std::min(_res_cap[pa], _excess[u]); 1171 1437 _res_cap[pa] -= delta; … … 1173 1439 _excess[u] -= delta; 1174 1440 _excess[v] += delta; 1175 if (_excess[v] > 0 && _excess[v] <= delta) 1441 if (_excess[v] > 0 && _excess[v] <= delta) { 1176 1442 _active_nodes.push_back(v); 1177 } 1443 } 1444 } 1445 path.clear(); 1178 1446 1179 1447 // Global update heuristic 1180 if (relabel_cnt >= next_ update_limit) {1448 if (relabel_cnt >= next_global_update_limit) { 1181 1449 globalUpdate(); 1182 next_update_limit += global_update_freq; 1183 } 1184 } 1185 } 1450 next_global_update_limit += global_update_skip; 1451 } 1452 } 1453 1454 } 1455 1186 1456 } 1187 1457 … … 1189 1459 void startPush() { 1190 1460 // Paramters for heuristics 1191 const int EARLY_TERM_EPSILON_LIMIT = 1000;1461 const int PRICE_REFINEMENT_LIMIT = 2; 1192 1462 const double GLOBAL_UPDATE_FACTOR = 2.0; 1193 1463 1194 const int global_update_ freq = int(GLOBAL_UPDATE_FACTOR *1464 const int global_update_skip = static_cast<int>(GLOBAL_UPDATE_FACTOR * 1195 1465 (_res_node_num + _sup_node_num * _sup_node_num)); 1196 int next_update_limit = global_update_freq; 1197 1198 int relabel_cnt = 0; 1466 int next_global_update_limit = global_update_skip; 1199 1467 1200 1468 // Perform cost scaling phases 1201 1469 BoolVector hyper(_res_node_num, false); 1202 1470 LargeCostVector hyper_cost(_res_node_num); 1471 int relabel_cnt = 0; 1472 int eps_phase_cnt = 0; 1203 1473 for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? 1204 1474 1 : _epsilon / _alpha ) 1205 1475 { 1206 // Early termination heuristic 1207 if (_epsilon <= EARLY_TERM_EPSILON_LIMIT) { 1208 if (earlyTermination()) break; 1476 ++eps_phase_cnt; 1477 1478 // Price refinement heuristic 1479 if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) { 1480 if (priceRefinement()) continue; 1209 1481 } 1210 1482 … … 1278 1550 std::numeric_limits<LargeCost>::max(); 1279 1551 for (int a = _first_out[n]; a != last_out; ++a) { 1280 rc = _cost[a] + pi_n - _pi[_target[a]]; 1281 if (_res_cap[a] > 0 && rc < min_red_cost) { 1282 min_red_cost = rc; 1552 if (_res_cap[a] > 0) { 1553 rc = _cost[a] + pi_n - _pi[_target[a]]; 1554 if (rc < min_red_cost) { 1555 min_red_cost = rc; 1556 } 1283 1557 } 1284 1558 } … … 1298 1572 1299 1573 // Global update heuristic 1300 if (relabel_cnt >= next_ update_limit) {1574 if (relabel_cnt >= next_global_update_limit) { 1301 1575 globalUpdate(); 1302 1576 for (int u = 0; u != _res_node_num; ++u) 1303 1577 hyper[u] = false; 1304 next_ update_limit += global_update_freq;1578 next_global_update_limit += global_update_skip; 1305 1579 } 1306 1580 } -
lemon/cycle_canceling.h
r956 r1165 49 49 /// \ref amo93networkflows, \ref klein67primal, 50 50 /// \ref goldberg89cyclecanceling. 51 /// The most efficent one (both theoretically and practically) 52 /// is the \ref CANCEL_AND_TIGHTEN "Cancel and Tighten" algorithm, 53 /// thus it is the default method. 54 /// It is strongly polynomial, but in practice, it is typically much 55 /// slower than the scaling algorithms and NetworkSimplex. 51 /// The most efficent one is the \ref CANCEL_AND_TIGHTEN 52 /// "Cancel-and-Tighten" algorithm, thus it is the default method. 53 /// It runs in strongly polynomial time, but in practice, it is typically 54 /// orders of magnitude slower than the scaling algorithms and 55 /// \ref NetworkSimplex. 56 /// (For more information, see \ref min_cost_flow_algs "the module page".) 56 57 /// 57 58 /// Most of the parameters of the problem (except for the digraph) … … 66 67 /// algorithm. By default, it is the same as \c V. 67 68 /// 68 /// \warning Both number types must be signed and all input data must 69 /// \warning Both \c V and \c C must be signed number types. 70 /// \warning All input data (capacities, supply values, and costs) must 69 71 /// be integer. 70 /// \warning This algorithm does not support negative costs for such71 /// arcs that haveinfinite upper bound.72 /// \warning This algorithm does not support negative costs for 73 /// arcs having infinite upper bound. 72 74 /// 73 75 /// \note For more information about the three available methods, … … 116 118 /// 117 119 /// \ref CycleCanceling provides three different cycle-canceling 118 /// methods. By default, \ref CANCEL_AND_TIGHTEN "Cancel and Tighten" 119 /// is used, which proved to be the most efficient and the most robust 120 /// on various test inputs. 120 /// methods. By default, \ref CANCEL_AND_TIGHTEN "Cancel-and-Tighten" 121 /// is used, which is by far the most efficient and the most robust. 121 122 /// However, the other methods can be selected using the \ref run() 122 123 /// function with the proper parameter. 123 124 enum Method { 124 125 /// A simple cycle-canceling method, which uses the 125 /// \ref BellmanFord "Bellman-Ford" algorithm with limited iteration 126 /// number for detecting negative cycles in the residual network. 126 /// \ref BellmanFord "Bellman-Ford" algorithm for detecting negative 127 /// cycles in the residual network. 128 /// The number of Bellman-Ford iterations is bounded by a successively 129 /// increased limit. 127 130 SIMPLE_CYCLE_CANCELING, 128 131 /// The "Minimum Mean Cycle-Canceling" algorithm, which is a … … 130 133 /// \ref goldberg89cyclecanceling. It improves along a 131 134 /// \ref min_mean_cycle "minimum mean cycle" in each iteration. 132 /// Its running time complexity is O(n<sup>2</sup> m<sup>3</sup>log(n)).135 /// Its running time complexity is O(n<sup>2</sup>e<sup>3</sup>log(n)). 133 136 MINIMUM_MEAN_CYCLE_CANCELING, 134 /// The "Cancel AndTighten" algorithm, which can be viewed as an137 /// The "Cancel-and-Tighten" algorithm, which can be viewed as an 135 138 /// improved version of the previous method 136 139 /// \ref goldberg89cyclecanceling. 137 140 /// It is faster both in theory and in practice, its running time 138 /// complexity is O(n<sup>2</sup> m<sup>2</sup>log(n)).141 /// complexity is O(n<sup>2</sup>e<sup>2</sup>log(n)). 139 142 CANCEL_AND_TIGHTEN 140 143 }; … … 350 353 /// 351 354 /// Using this function has the same effect as using \ref supplyMap() 352 /// with sucha map in which \c k is assigned to \c s, \c -k is355 /// with a map in which \c k is assigned to \c s, \c -k is 353 356 /// assigned to \c t and all other nodes have zero supply value. 354 357 /// … … 611 614 } 612 615 613 /// \brief Return the flow map (the primal solution). 616 /// \brief Copy the flow values (the primal solution) into the 617 /// given map. 614 618 /// 615 619 /// This function copies the flow value on each arc into the given … … 635 639 } 636 640 637 /// \brief Return the potential map (the dual solution). 641 /// \brief Copy the potential values (the dual solution) into the 642 /// given map. 638 643 /// 639 644 /// This function copies the potential (dual value) of each node … … 955 960 } 956 961 957 // Execute the "Cancel AndTighten" method962 // Execute the "Cancel-and-Tighten" method 958 963 void startCancelAndTighten() { 959 964 // Constants for the min mean cycle computations -
lemon/euler.h
r956 r1023 37 37 ///Euler tour iterator for digraphs. 38 38 39 /// \ingroup graph_prop 39 /// \ingroup graph_properties 40 40 ///This iterator provides an Euler tour (Eulerian circuit) of a \e directed 41 41 ///graph (if there exists) and it converts to the \c Arc type of the digraph. -
lemon/hao_orlin.h
r956 r1019 54 54 /// preflow push-relabel algorithm. Our implementation calculates 55 55 /// the minimum cut in \f$ O(n^2\sqrt{m}) \f$ time (we use the 56 /// highest-label rule), or in \f$O(nm)\f$ for unit capacities. The57 /// purpose of such algorithm is e.g.testing network reliability.56 /// highest-label rule), or in \f$O(nm)\f$ for unit capacities. A notable 57 /// use of this algorithm is testing network reliability. 58 58 /// 59 59 /// For an undirected graph you can run just the first phase of the … … 913 913 /// source-side (i.e. a set \f$ X\subsetneq V \f$ with 914 914 /// \f$ source \in X \f$ and minimal outgoing capacity). 915 /// It updates the stored cut if (and only if) the newly found one 916 /// is better. 915 917 /// 916 918 /// \pre \ref init() must be called before using this function. … … 925 927 /// sink-side (i.e. a set \f$ X\subsetneq V \f$ with 926 928 /// \f$ source \notin X \f$ and minimal outgoing capacity). 929 /// It updates the stored cut if (and only if) the newly found one 930 /// is better. 927 931 /// 928 932 /// \pre \ref init() must be called before using this function. … … 934 938 /// \brief Run the algorithm. 935 939 /// 936 /// This function runs the algorithm. It finds nodes \c source and937 /// \c target arbitrarily andthen calls \ref init(), \ref calculateOut()940 /// This function runs the algorithm. It chooses source node, 941 /// then calls \ref init(), \ref calculateOut() 938 942 /// and \ref calculateIn(). 939 943 void run() { … … 945 949 /// \brief Run the algorithm. 946 950 /// 947 /// This function runs the algorithm. It uses the given \c source node,948 /// finds a proper \c target node and then calls the \ref init(),949 /// \ref calculateOut() and \ref calculateIn().951 /// This function runs the algorithm. It calls \ref init(), 952 /// \ref calculateOut() and \ref calculateIn() with the given 953 /// source node. 950 954 void run(const Node& s) { 951 955 init(s); … … 966 970 /// \brief Return the value of the minimum cut. 967 971 /// 968 /// This function returns the value of the minimum cut. 972 /// This function returns the value of the best cut found by the 973 /// previously called \ref run(), \ref calculateOut() or \ref 974 /// calculateIn(). 969 975 /// 970 976 /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() … … 977 983 /// \brief Return a minimum cut. 978 984 /// 979 /// This function sets \c cutMap to the characteristic vector of a 980 /// minimum value cut: it will give a non-empty set \f$ X\subsetneq V \f$ 981 /// with minimal outgoing capacity (i.e. \c cutMap will be \c true exactly 985 /// This function gives the best cut found by the 986 /// previously called \ref run(), \ref calculateOut() or \ref 987 /// calculateIn(). 988 /// 989 /// It sets \c cutMap to the characteristic vector of the found 990 /// minimum value cut - a non-empty set \f$ X\subsetneq V \f$ 991 /// of minimum outgoing capacity (i.e. \c cutMap will be \c true exactly 982 992 /// for the nodes of \f$ X \f$). 983 993 /// -
lemon/hartmann_orlin_mmc.h
r959 r1164 99 99 /// This class implements the Hartmann-Orlin algorithm for finding 100 100 /// a directed cycle of minimum mean cost in a digraph 101 /// \ref amo93networkflows, \ref dasdan98minmeancycle.101 /// \ref hartmann93finding, \ref dasdan98minmeancycle. 102 102 /// It is an improved version of \ref KarpMmc "Karp"'s original algorithm, 103 103 /// it applies an efficient early termination scheme. -
lemon/howard_mmc.h
r956 r1164 99 99 /// This class implements Howard's policy iteration algorithm for finding 100 100 /// a directed cycle of minimum mean cost in a digraph 101 /// \ref amo93networkflows, \ref dasdan98minmeancycle.101 /// \ref dasdan98minmeancycle, \ref dasdan04experimental. 102 102 /// This class provides the most efficient algorithm for the 103 103 /// minimum mean cycle problem, though the best known theoretical -
lemon/karp_mmc.h
r956 r1164 99 99 /// This class implements Karp's algorithm for finding a directed 100 100 /// cycle of minimum mean cost in a digraph 101 /// \ref amo93networkflows, \ref dasdan98minmeancycle.101 /// \ref karp78characterization, \ref dasdan98minmeancycle. 102 102 /// It runs in time O(ne) and uses space O(n<sup>2</sup>+e). 103 103 /// -
lemon/kruskal.h
r631 r1025 31 31 ///\file 32 32 ///\brief Kruskal's algorithm to compute a minimum cost spanning tree 33 ///34 ///Kruskal's algorithm to compute a minimum cost spanning tree.35 ///36 33 37 34 namespace lemon { -
lemon/lemon.pc.in
r705 r1133 1 prefix=@ prefix@2 exec_prefix=@ exec_prefix@3 libdir=@ libdir@4 includedir=@ includedir@1 prefix=@CMAKE_INSTALL_PREFIX@ 2 exec_prefix=@CMAKE_INSTALL_PREFIX@/bin 3 libdir=@CMAKE_INSTALL_PREFIX@/lib 4 includedir=@CMAKE_INSTALL_PREFIX@/include 5 5 6 Name: @P ACKAGE_NAME@6 Name: @PROJECT_NAME@ 7 7 Description: Library for Efficient Modeling and Optimization in Networks 8 Version: @P ACKAGE_VERSION@8 Version: @PROJECT_VERSION@ 9 9 Libs: -L${libdir} -lemon @GLPK_LIBS@ @CPLEX_LIBS@ @SOPLEX_LIBS@ @CLP_LIBS@ @CBC_LIBS@ 10 10 Cflags: -I${includedir} -
lemon/network_simplex.h
r978 r1166 48 48 /// flow problem. 49 49 /// 50 /// In general, %NetworkSimplex is the fastest implementation available 51 /// in LEMON for this problem. 52 /// Moreover, it supports both directions of the supply/demand inequality 53 /// constraints. For more information, see \ref SupplyType. 50 /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest 51 /// implementations available in LEMON for solving this problem. 52 /// (For more information, see \ref min_cost_flow_algs "the module page".) 53 /// Furthermore, this class supports both directions of the supply/demand 54 /// inequality constraints. For more information, see \ref SupplyType. 54 55 /// 55 56 /// Most of the parameters of the problem (except for the digraph) … … 64 65 /// algorithm. By default, it is the same as \c V. 65 66 /// 66 /// \warning Both number types must be signed and all input data must 67 /// \warning Both \c V and \c C must be signed number types. 68 /// \warning All input data (capacities, supply values, and costs) must 67 69 /// be integer. 68 70 /// … … 122 124 /// the \ref run() function. 123 125 /// 124 /// \ref NetworkSimplex provides five different pivot rule125 /// implementations that significantly affectthe running time126 /// \ref NetworkSimplex provides five different implementations for 127 /// the pivot strategy that significantly affects the running time 126 128 /// of the algorithm. 127 /// By default, \ref BLOCK_SEARCH "Block Search" is used, which 128 /// proved to be the most efficient and the most robust on various 129 /// test inputs. 130 /// However, another pivot rule can be selected using the \ref run() 131 /// function with the proper parameter. 129 /// According to experimental tests conducted on various problem 130 /// instances, \ref BLOCK_SEARCH "Block Search" and 131 /// \ref ALTERING_LIST "Altering Candidate List" rules turned out 132 /// to be the most efficient. 133 /// Since \ref BLOCK_SEARCH "Block Search" is a simpler strategy that 134 /// seemed to be slightly more robust, it is used by default. 135 /// However, another pivot rule can easily be selected using the 136 /// \ref run() function with the proper parameter. 132 137 enum PivotRule { 133 138 … … 155 160 /// The \e Altering \e Candidate \e List pivot rule. 156 161 /// It is a modified version of the Candidate List method. 157 /// It keeps only the severalbest eligible arcs from the former162 /// It keeps only a few of the best eligible arcs from the former 158 163 /// candidate list and extends this list in every iteration. 159 164 ALTERING_LIST … … 167 172 typedef std::vector<Value> ValueVector; 168 173 typedef std::vector<Cost> CostVector; 169 typedef std::vector<char> BoolVector; 170 // Note: vector<char> is used instead of vector<bool> for efficiency reasons 174 typedef std::vector<signed char> CharVector; 175 // Note: vector<signed char> is used instead of vector<ArcState> and 176 // vector<ArcDirection> for efficiency reasons 171 177 172 178 // State constants for arcs … … 177 183 }; 178 184 179 typedef std::vector<signed char> StateVector; 180 // Note: vector<signed char> is used instead of vector<ArcState> for 181 // efficiency reasons 185 // Direction constants for tree arcs 186 enum ArcDirection { 187 DIR_DOWN = -1, 188 DIR_UP = 1 189 }; 182 190 183 191 private: … … 218 226 IntVector _succ_num; 219 227 IntVector _last_succ; 228 CharVector _pred_dir; 229 CharVector _state; 220 230 IntVector _dirty_revs; 221 BoolVector _forward;222 StateVector _state;223 231 int _root; 224 232 225 233 // Temporary data used in the current pivot iteration 226 234 int in_arc, join, u_in, v_in, u_out, v_out; 227 int first, second, right, last;228 int stem, par_stem, new_stem;229 235 Value delta; 230 236 … … 251 257 const IntVector &_target; 252 258 const CostVector &_cost; 253 const StateVector &_state;259 const CharVector &_state; 254 260 const CostVector &_pi; 255 261 int &_in_arc; … … 303 309 const IntVector &_target; 304 310 const CostVector &_cost; 305 const StateVector &_state;311 const CharVector &_state; 306 312 const CostVector &_pi; 307 313 int &_in_arc; … … 342 348 const IntVector &_target; 343 349 const CostVector &_cost; 344 const StateVector &_state;350 const CharVector &_state; 345 351 const CostVector &_pi; 346 352 int &_in_arc; … … 415 421 const IntVector &_target; 416 422 const CostVector &_cost; 417 const StateVector &_state;423 const CharVector &_state; 418 424 const CostVector &_pi; 419 425 int &_in_arc; … … 518 524 const IntVector &_target; 519 525 const CostVector &_cost; 520 const StateVector &_state;526 const CharVector &_state; 521 527 const CostVector &_pi; 522 528 int &_in_arc; … … 537 543 SortFunc(const CostVector &map) : _map(map) {} 538 544 bool operator()(int left, int right) { 539 return _map[left] >_map[right];545 return _map[left] < _map[right]; 540 546 } 541 547 }; … … 555 561 const double BLOCK_SIZE_FACTOR = 1.0; 556 562 const int MIN_BLOCK_SIZE = 10; 557 const double HEAD_LENGTH_FACTOR = 0. 1;563 const double HEAD_LENGTH_FACTOR = 0.01; 558 564 const int MIN_HEAD_LENGTH = 3; 559 565 … … 571 577 // Check the current candidate list 572 578 int e; 579 Cost c; 573 580 for (int i = 0; i != _curr_length; ++i) { 574 581 e = _candidates[i]; 575 _cand_cost[e] = _state[e] * 576 (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 577 if (_cand_cost[e] >= 0) { 582 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 583 if (c < 0) { 584 _cand_cost[e] = c; 585 } else { 578 586 _candidates[i--] = _candidates[--_curr_length]; 579 587 } … … 585 593 586 594 for (e = _next_arc; e != _search_arc_num; ++e) { 587 _cand_cost[e] = _state[e] *588 (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);589 if (_cand_cost[e] < 0) {595 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 596 if (c < 0) { 597 _cand_cost[e] = c; 590 598 _candidates[_curr_length++] = e; 591 599 } … … 597 605 } 598 606 for (e = 0; e != _next_arc; ++e) { 599 _cand_cost[e] = _state[e] *600 (_cost[e] + _pi[_source[e]] - _pi[_target[e]]);601 if (_cand_cost[e] < 0) {607 c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); 608 if (c < 0) { 609 _cand_cost[e] = c; 602 610 _candidates[_curr_length++] = e; 603 611 } … … 612 620 search_end: 613 621 614 // Make heap of the candidate list (approximating a partial sort) 615 make_heap( _candidates.begin(), _candidates.begin() + _curr_length, 616 _sort_func ); 617 618 // Pop the first element of the heap 622 // Perform partial sort operation on the candidate list 623 int new_length = std::min(_head_length + 1, _curr_length); 624 std::partial_sort(_candidates.begin(), _candidates.begin() + new_length, 625 _candidates.begin() + _curr_length, _sort_func); 626 627 // Select the entering arc and remove it from the list 619 628 _in_arc = _candidates[0]; 620 629 _next_arc = e; 621 pop_heap( _candidates.begin(), _candidates.begin() + _curr_length, 622 _sort_func ); 623 _curr_length = std::min(_head_length, _curr_length - 1); 630 _candidates[0] = _candidates[new_length - 1]; 631 _curr_length = new_length - 1; 624 632 return true; 625 633 } … … 634 642 /// 635 643 /// \param graph The digraph the algorithm runs on. 636 /// \param arc_mixing Indicate if the arcs have tobe stored in a644 /// \param arc_mixing Indicate if the arcs will be stored in a 637 645 /// mixed order in the internal data structure. 638 /// In special cases, it could lead to better overall performance, 639 /// but it is usually slower. Therefore it is disabled by default. 640 NetworkSimplex(const GR& graph, bool arc_mixing = false) : 646 /// In general, it leads to similar performance as using the original 647 /// arc order, but it makes the algorithm more robust and in special 648 /// cases, even significantly faster. Therefore, it is enabled by default. 649 NetworkSimplex(const GR& graph, bool arc_mixing = true) : 641 650 _graph(graph), _node_id(graph), _arc_id(graph), 642 651 _arc_mixing(arc_mixing), … … 731 740 /// 732 741 /// \return <tt>(*this)</tt> 742 /// 743 /// \sa supplyType() 733 744 template<typename SupplyMap> 734 745 NetworkSimplex& supplyMap(const SupplyMap& map) { … … 747 758 /// 748 759 /// Using this function has the same effect as using \ref supplyMap() 749 /// with sucha map in which \c k is assigned to \c s, \c -k is760 /// with a map in which \c k is assigned to \c s, \c -k is 750 761 /// assigned to \c t and all other nodes have zero supply value. 751 762 /// … … 914 925 _parent.resize(all_node_num); 915 926 _pred.resize(all_node_num); 916 _ forward.resize(all_node_num);927 _pred_dir.resize(all_node_num); 917 928 _thread.resize(all_node_num); 918 929 _rev_thread.resize(all_node_num); … … 928 939 if (_arc_mixing) { 929 940 // Store the arcs in a mixed order 930 int k = std::max(int(std::sqrt(double(_arc_num))), 10);941 const int skip = std::max(_arc_num / _node_num, 3); 931 942 int i = 0, j = 0; 932 943 for (ArcIt a(_graph); a != INVALID; ++a) { … … 934 945 _source[i] = _node_id[_graph.source(a)]; 935 946 _target[i] = _node_id[_graph.target(a)]; 936 if ((i += k) >= _arc_num) i = ++j;947 if ((i += skip) >= _arc_num) i = ++j; 937 948 } 938 949 } else { … … 1000 1011 } 1001 1012 1002 /// \brief Return the flow map (the primal solution). 1013 /// \brief Copy the flow values (the primal solution) into the 1014 /// given map. 1003 1015 /// 1004 1016 /// This function copies the flow value on each arc into the given … … 1024 1036 } 1025 1037 1026 /// \brief Return the potential map (the dual solution). 1038 /// \brief Copy the potential values (the dual solution) into the 1039 /// given map. 1027 1040 /// 1028 1041 /// This function copies the potential (dual value) of each node … … 1117 1130 _state[e] = STATE_TREE; 1118 1131 if (_supply[u] >= 0) { 1119 _ forward[u] = true;1132 _pred_dir[u] = DIR_UP; 1120 1133 _pi[u] = 0; 1121 1134 _source[e] = u; … … 1124 1137 _cost[e] = 0; 1125 1138 } else { 1126 _ forward[u] = false;1139 _pred_dir[u] = DIR_DOWN; 1127 1140 _pi[u] = ART_COST; 1128 1141 _source[e] = _root; … … 1144 1157 _last_succ[u] = u; 1145 1158 if (_supply[u] >= 0) { 1146 _ forward[u] = true;1159 _pred_dir[u] = DIR_UP; 1147 1160 _pi[u] = 0; 1148 1161 _pred[u] = e; … … 1154 1167 _state[e] = STATE_TREE; 1155 1168 } else { 1156 _ forward[u] = false;1169 _pred_dir[u] = DIR_DOWN; 1157 1170 _pi[u] = ART_COST; 1158 1171 _pred[u] = f; … … 1185 1198 _last_succ[u] = u; 1186 1199 if (_supply[u] <= 0) { 1187 _ forward[u] = false;1200 _pred_dir[u] = DIR_DOWN; 1188 1201 _pi[u] = 0; 1189 1202 _pred[u] = e; … … 1195 1208 _state[e] = STATE_TREE; 1196 1209 } else { 1197 _ forward[u] = true;1210 _pred_dir[u] = DIR_UP; 1198 1211 _pi[u] = -ART_COST; 1199 1212 _pred[u] = f; … … 1238 1251 // Initialize first and second nodes according to the direction 1239 1252 // of the cycle 1253 int first, second; 1240 1254 if (_state[in_arc] == STATE_LOWER) { 1241 1255 first = _source[in_arc]; … … 1247 1261 delta = _cap[in_arc]; 1248 1262 int result = 0; 1249 Value d;1263 Value c, d; 1250 1264 int e; 1251 1265 1252 // Search the cycle along the path form the first node to the root1266 // Search the cycle form the first node to the join node 1253 1267 for (int u = first; u != join; u = _parent[u]) { 1254 1268 e = _pred[u]; 1255 d = _forward[u] ? 1256 _flow[e] : (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]); 1269 d = _flow[e]; 1270 if (_pred_dir[u] == DIR_DOWN) { 1271 c = _cap[e]; 1272 d = c >= MAX ? INF : c - d; 1273 } 1257 1274 if (d < delta) { 1258 1275 delta = d; … … 1261 1278 } 1262 1279 } 1263 // Search the cycle along the path form the second node to the root 1280 1281 // Search the cycle form the second node to the join node 1264 1282 for (int u = second; u != join; u = _parent[u]) { 1265 1283 e = _pred[u]; 1266 d = _forward[u] ? 1267 (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]) : _flow[e]; 1284 d = _flow[e]; 1285 if (_pred_dir[u] == DIR_UP) { 1286 c = _cap[e]; 1287 d = c >= MAX ? INF : c - d; 1288 } 1268 1289 if (d <= delta) { 1269 1290 delta = d; … … 1290 1311 _flow[in_arc] += val; 1291 1312 for (int u = _source[in_arc]; u != join; u = _parent[u]) { 1292 _flow[_pred[u]] += _forward[u] ? -val :val;1313 _flow[_pred[u]] -= _pred_dir[u] * val; 1293 1314 } 1294 1315 for (int u = _target[in_arc]; u != join; u = _parent[u]) { 1295 _flow[_pred[u]] += _ forward[u] ? val : -val;1316 _flow[_pred[u]] += _pred_dir[u] * val; 1296 1317 } 1297 1318 } … … 1308 1329 // Update the tree structure 1309 1330 void updateTreeStructure() { 1310 int u, w;1311 1331 int old_rev_thread = _rev_thread[u_out]; 1312 1332 int old_succ_num = _succ_num[u_out]; … … 1314 1334 v_out = _parent[u_out]; 1315 1335 1316 u = _last_succ[u_in]; // the last successor of u_in 1317 right = _thread[u]; // the node after it 1318 1319 // Handle the case when old_rev_thread equals to v_in 1320 // (it also means that join and v_out coincide) 1321 if (old_rev_thread == v_in) { 1322 last = _thread[_last_succ[u_out]]; 1336 // Check if u_in and u_out coincide 1337 if (u_in == u_out) { 1338 // Update _parent, _pred, _pred_dir 1339 _parent[u_in] = v_in; 1340 _pred[u_in] = in_arc; 1341 _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; 1342 1343 // Update _thread and _rev_thread 1344 if (_thread[v_in] != u_out) { 1345 int after = _thread[old_last_succ]; 1346 _thread[old_rev_thread] = after; 1347 _rev_thread[after] = old_rev_thread; 1348 after = _thread[v_in]; 1349 _thread[v_in] = u_out; 1350 _rev_thread[u_out] = v_in; 1351 _thread[old_last_succ] = after; 1352 _rev_thread[after] = old_last_succ; 1353 } 1323 1354 } else { 1324 last = _thread[v_in]; 1325 } 1326 1327 // Update _thread and _parent along the stem nodes (i.e. the nodes 1328 // between u_in and u_out, whose parent have to be changed) 1329 _thread[v_in] = stem = u_in; 1330 _dirty_revs.clear(); 1331 _dirty_revs.push_back(v_in); 1332 par_stem = v_in; 1333 while (stem != u_out) { 1334 // Insert the next stem node into the thread list 1335 new_stem = _parent[stem]; 1336 _thread[u] = new_stem; 1337 _dirty_revs.push_back(u); 1338 1339 // Remove the subtree of stem from the thread list 1340 w = _rev_thread[stem]; 1341 _thread[w] = right; 1342 _rev_thread[right] = w; 1343 1344 // Change the parent node and shift stem nodes 1345 _parent[stem] = par_stem; 1346 par_stem = stem; 1347 stem = new_stem; 1348 1349 // Update u and right 1350 u = _last_succ[stem] == _last_succ[par_stem] ? 1351 _rev_thread[par_stem] : _last_succ[stem]; 1352 right = _thread[u]; 1353 } 1354 _parent[u_out] = par_stem; 1355 _thread[u] = last; 1356 _rev_thread[last] = u; 1357 _last_succ[u_out] = u; 1358 1359 // Remove the subtree of u_out from the thread list except for 1360 // the case when old_rev_thread equals to v_in 1361 // (it also means that join and v_out coincide) 1362 if (old_rev_thread != v_in) { 1363 _thread[old_rev_thread] = right; 1364 _rev_thread[right] = old_rev_thread; 1365 } 1366 1367 // Update _rev_thread using the new _thread values 1368 for (int i = 0; i != int(_dirty_revs.size()); ++i) { 1369 u = _dirty_revs[i]; 1370 _rev_thread[_thread[u]] = u; 1371 } 1372 1373 // Update _pred, _forward, _last_succ and _succ_num for the 1374 // stem nodes from u_out to u_in 1375 int tmp_sc = 0, tmp_ls = _last_succ[u_out]; 1376 u = u_out; 1377 while (u != u_in) { 1378 w = _parent[u]; 1379 _pred[u] = _pred[w]; 1380 _forward[u] = !_forward[w]; 1381 tmp_sc += _succ_num[u] - _succ_num[w]; 1382 _succ_num[u] = tmp_sc; 1383 _last_succ[w] = tmp_ls; 1384 u = w; 1385 } 1386 _pred[u_in] = in_arc; 1387 _forward[u_in] = (u_in == _source[in_arc]); 1388 _succ_num[u_in] = old_succ_num; 1389 1390 // Set limits for updating _last_succ form v_in and v_out 1391 // towards the root 1392 int up_limit_in = -1; 1393 int up_limit_out = -1; 1394 if (_last_succ[join] == v_in) { 1395 up_limit_out = join; 1396 } else { 1397 up_limit_in = join; 1355 // Handle the case when old_rev_thread equals to v_in 1356 // (it also means that join and v_out coincide) 1357 int thread_continue = old_rev_thread == v_in ? 1358 _thread[old_last_succ] : _thread[v_in]; 1359 1360 // Update _thread and _parent along the stem nodes (i.e. the nodes 1361 // between u_in and u_out, whose parent have to be changed) 1362 int stem = u_in; // the current stem node 1363 int par_stem = v_in; // the new parent of stem 1364 int next_stem; // the next stem node 1365 int last = _last_succ[u_in]; // the last successor of stem 1366 int before, after = _thread[last]; 1367 _thread[v_in] = u_in; 1368 _dirty_revs.clear(); 1369 _dirty_revs.push_back(v_in); 1370 while (stem != u_out) { 1371 // Insert the next stem node into the thread list 1372 next_stem = _parent[stem]; 1373 _thread[last] = next_stem; 1374 _dirty_revs.push_back(last); 1375 1376 // Remove the subtree of stem from the thread list 1377 before = _rev_thread[stem]; 1378 _thread[before] = after; 1379 _rev_thread[after] = before; 1380 1381 // Change the parent node and shift stem nodes 1382 _parent[stem] = par_stem; 1383 par_stem = stem; 1384 stem = next_stem; 1385 1386 // Update last and after 1387 last = _last_succ[stem] == _last_succ[par_stem] ? 1388 _rev_thread[par_stem] : _last_succ[stem]; 1389 after = _thread[last]; 1390 } 1391 _parent[u_out] = par_stem; 1392 _thread[last] = thread_continue; 1393 _rev_thread[thread_continue] = last; 1394 _last_succ[u_out] = last; 1395 1396 // Remove the subtree of u_out from the thread list except for 1397 // the case when old_rev_thread equals to v_in 1398 if (old_rev_thread != v_in) { 1399 _thread[old_rev_thread] = after; 1400 _rev_thread[after] = old_rev_thread; 1401 } 1402 1403 // Update _rev_thread using the new _thread values 1404 for (int i = 0; i != int(_dirty_revs.size()); ++i) { 1405 int u = _dirty_revs[i]; 1406 _rev_thread[_thread[u]] = u; 1407 } 1408 1409 // Update _pred, _pred_dir, _last_succ and _succ_num for the 1410 // stem nodes from u_out to u_in 1411 int tmp_sc = 0, tmp_ls = _last_succ[u_out]; 1412 for (int u = u_out, p = _parent[u]; u != u_in; u = p, p = _parent[u]) { 1413 _pred[u] = _pred[p]; 1414 _pred_dir[u] = -_pred_dir[p]; 1415 tmp_sc += _succ_num[u] - _succ_num[p]; 1416 _succ_num[u] = tmp_sc; 1417 _last_succ[p] = tmp_ls; 1418 } 1419 _pred[u_in] = in_arc; 1420 _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; 1421 _succ_num[u_in] = old_succ_num; 1398 1422 } 1399 1423 1400 1424 // Update _last_succ from v_in towards the root 1401 for (u = v_in; u != up_limit_in && _last_succ[u] == v_in; 1402 u = _parent[u]) { 1403 _last_succ[u] = _last_succ[u_out]; 1404 } 1425 int up_limit_out = _last_succ[join] == v_in ? join : -1; 1426 int last_succ_out = _last_succ[u_out]; 1427 for (int u = v_in; u != -1 && _last_succ[u] == v_in; u = _parent[u]) { 1428 _last_succ[u] = last_succ_out; 1429 } 1430 1405 1431 // Update _last_succ from v_out towards the root 1406 1432 if (join != old_rev_thread && v_in != old_rev_thread) { 1407 for ( u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ;1433 for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; 1408 1434 u = _parent[u]) { 1409 1435 _last_succ[u] = old_rev_thread; 1410 1436 } 1411 } else { 1412 for (u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; 1437 } 1438 else if (last_succ_out != old_last_succ) { 1439 for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; 1413 1440 u = _parent[u]) { 1414 _last_succ[u] = _last_succ[u_out];1441 _last_succ[u] = last_succ_out; 1415 1442 } 1416 1443 } 1417 1444 1418 1445 // Update _succ_num from v_in to join 1419 for ( u = v_in; u != join; u = _parent[u]) {1446 for (int u = v_in; u != join; u = _parent[u]) { 1420 1447 _succ_num[u] += old_succ_num; 1421 1448 } 1422 1449 // Update _succ_num from v_out to join 1423 for ( u = v_out; u != join; u = _parent[u]) {1450 for (int u = v_out; u != join; u = _parent[u]) { 1424 1451 _succ_num[u] -= old_succ_num; 1425 1452 } 1426 1453 } 1427 1454 1428 // Update potentials 1455 // Update potentials in the subtree that has been moved 1429 1456 void updatePotential() { 1430 Cost sigma = _forward[u_in] ? 1431 _pi[v_in] - _pi[u_in] - _cost[_pred[u_in]] : 1432 _pi[v_in] - _pi[u_in] + _cost[_pred[u_in]]; 1433 // Update potentials in the subtree, which has been moved 1457 Cost sigma = _pi[v_in] - _pi[u_in] - 1458 _pred_dir[u_in] * _cost[in_arc]; 1434 1459 int end = _thread[_last_succ[u_in]]; 1435 1460 for (int u = u_in; u != end; u = _thread[u]) { -
lemon/path.h
r1146 r1162 44 44 /// 45 45 /// In a sense, the path can be treated as a list of arcs. The 46 /// lemonpath type stores just this list. As a consequence, it46 /// LEMON path type stores just this list. As a consequence, it 47 47 /// cannot enumerate the nodes of the path and the source node of 48 48 /// a zero length path is undefined. … … 149 149 void clear() { head.clear(); tail.clear(); } 150 150 151 /// \brief The n th arc.151 /// \brief The n-th arc. 152 152 /// 153 153 /// \pre \c n is in the <tt>[0..length() - 1]</tt> range. … … 157 157 } 158 158 159 /// \brief Initialize arc iterator to point to the n th arc159 /// \brief Initialize arc iterator to point to the n-th arc 160 160 /// 161 161 /// \pre \c n is in the <tt>[0..length() - 1]</tt> range. … … 245 245 /// 246 246 /// In a sense, the path can be treated as a list of arcs. The 247 /// lemonpath type stores just this list. As a consequence it247 /// LEMON path type stores just this list. As a consequence it 248 248 /// cannot enumerate the nodes in the path and the zero length paths 249 249 /// cannot store the source. … … 354 354 void clear() { data.clear(); } 355 355 356 /// \brief The n th arc.356 /// \brief The n-th arc. 357 357 /// 358 358 /// \pre \c n is in the <tt>[0..length() - 1]</tt> range. … … 361 361 } 362 362 363 /// \brief Initializes arc iterator to point to the n th arc.363 /// \brief Initializes arc iterator to point to the n-th arc. 364 364 ArcIt nthIt(int n) const { 365 365 return ArcIt(*this, n); … … 422 422 /// 423 423 /// In a sense, the path can be treated as a list of arcs. The 424 /// lemonpath type stores just this list. As a consequence it424 /// LEMON path type stores just this list. As a consequence it 425 425 /// cannot enumerate the nodes in the path and the zero length paths 426 426 /// cannot store the source. … … 544 544 }; 545 545 546 /// \brief The n th arc.547 /// 548 /// This function looks for the n th arc in O(n) time.546 /// \brief The n-th arc. 547 /// 548 /// This function looks for the n-th arc in O(n) time. 549 549 /// \pre \c n is in the <tt>[0..length() - 1]</tt> range. 550 550 const Arc& nth(int n) const { … … 556 556 } 557 557 558 /// \brief Initializes arc iterator to point to the n th arc.558 /// \brief Initializes arc iterator to point to the n-th arc. 559 559 ArcIt nthIt(int n) const { 560 560 Node *node = first; … … 775 775 /// 776 776 /// In a sense, the path can be treated as a list of arcs. The 777 /// lemonpath type stores just this list. As a consequence it777 /// LEMON path type stores just this list. As a consequence it 778 778 /// cannot enumerate the nodes in the path and the source node of 779 779 /// a zero length path is undefined. … … 884 884 }; 885 885 886 /// \brief The n th arc.886 /// \brief The n-th arc. 887 887 /// 888 888 /// \pre \c n is in the <tt>[0..length() - 1]</tt> range. … … 891 891 } 892 892 893 /// \brief The arc iterator pointing to the n th arc.893 /// \brief The arc iterator pointing to the n-th arc. 894 894 ArcIt nthIt(int n) const { 895 895 return ArcIt(*this, n); … … 1095 1095 /// 1096 1096 /// In a sense, the path can be treated as a list of arcs. The 1097 /// lemonpath type stores only this list. As a consequence, it1097 /// LEMON path type stores only this list. As a consequence, it 1098 1098 /// cannot enumerate the nodes in the path and the zero length paths 1099 1099 /// cannot have a source node. -
test/CMakeLists.txt
r1159 r1162 38 38 maps_test 39 39 matching_test 40 max_cardinality_search_test 41 max_clique_test 40 42 min_cost_arborescence_test 41 43 min_cost_flow_test 42 44 min_mean_cycle_test 45 nagamochi_ibaraki_test 43 46 path_test 44 47 planarity_test -
test/graph_copy_test.cc
r984 r989 19 19 #include <lemon/smart_graph.h> 20 20 #include <lemon/list_graph.h> 21 #include <lemon/static_graph.h> 21 22 #include <lemon/lgf_reader.h> 22 23 #include <lemon/error.h> … … 27 28 using namespace lemon; 28 29 30 template <typename GR> 29 31 void digraph_copy_test() { 30 32 const int nn = 10; … … 52 54 } 53 55 } 54 56 55 57 // Test digraph copy 56 ListDigraphto;57 ListDigraph::NodeMap<int> tnm(to);58 ListDigraph::ArcMap<int> tam(to);59 ListDigraph::Node tn;60 ListDigraph::Arc ta;61 62 SmartDigraph::NodeMap< ListDigraph::Node> nr(from);63 SmartDigraph::ArcMap< ListDigraph::Arc> er(from);64 65 ListDigraph::NodeMap<SmartDigraph::Node> ncr(to);66 ListDigraph::ArcMap<SmartDigraph::Arc> ecr(to);58 GR to; 59 typename GR::template NodeMap<int> tnm(to); 60 typename GR::template ArcMap<int> tam(to); 61 typename GR::Node tn; 62 typename GR::Arc ta; 63 64 SmartDigraph::NodeMap<typename GR::Node> nr(from); 65 SmartDigraph::ArcMap<typename GR::Arc> er(from); 66 67 typename GR::template NodeMap<SmartDigraph::Node> ncr(to); 68 typename GR::template ArcMap<SmartDigraph::Arc> ecr(to); 67 69 68 70 digraphCopy(from, to). … … 87 89 } 88 90 89 for ( ListDigraph::NodeIt it(to); it != INVALID; ++it) {91 for (typename GR::NodeIt it(to); it != INVALID; ++it) { 90 92 check(nr[ncr[it]] == it, "Wrong copy."); 91 93 } 92 94 93 for ( ListDigraph::ArcIt it(to); it != INVALID; ++it) {95 for (typename GR::ArcIt it(to); it != INVALID; ++it) { 94 96 check(er[ecr[it]] == it, "Wrong copy."); 95 97 } … … 104 106 } 105 107 108 template <typename GR> 106 109 void graph_copy_test() { 107 110 const int nn = 10; … … 136 139 137 140 // Test graph copy 138 ListGraphto;139 ListGraph::NodeMap<int> tnm(to);140 ListGraph::ArcMap<int> tam(to);141 ListGraph::EdgeMap<int> tem(to);142 ListGraph::Node tn;143 ListGraph::Arc ta;144 ListGraph::Edge te;145 146 SmartGraph::NodeMap< ListGraph::Node> nr(from);147 SmartGraph::ArcMap< ListGraph::Arc> ar(from);148 SmartGraph::EdgeMap< ListGraph::Edge> er(from);149 150 ListGraph::NodeMap<SmartGraph::Node> ncr(to);151 ListGraph::ArcMap<SmartGraph::Arc> acr(to);152 ListGraph::EdgeMap<SmartGraph::Edge> ecr(to);141 GR to; 142 typename GR::template NodeMap<int> tnm(to); 143 typename GR::template ArcMap<int> tam(to); 144 typename GR::template EdgeMap<int> tem(to); 145 typename GR::Node tn; 146 typename GR::Arc ta; 147 typename GR::Edge te; 148 149 SmartGraph::NodeMap<typename GR::Node> nr(from); 150 SmartGraph::ArcMap<typename GR::Arc> ar(from); 151 SmartGraph::EdgeMap<typename GR::Edge> er(from); 152 153 typename GR::template NodeMap<SmartGraph::Node> ncr(to); 154 typename GR::template ArcMap<SmartGraph::Arc> acr(to); 155 typename GR::template EdgeMap<SmartGraph::Edge> ecr(to); 153 156 154 157 graphCopy(from, to). … … 185 188 } 186 189 187 for ( ListGraph::NodeIt it(to); it != INVALID; ++it) {190 for (typename GR::NodeIt it(to); it != INVALID; ++it) { 188 191 check(nr[ncr[it]] == it, "Wrong copy."); 189 192 } 190 193 191 for ( ListGraph::ArcIt it(to); it != INVALID; ++it) {194 for (typename GR::ArcIt it(to); it != INVALID; ++it) { 192 195 check(ar[acr[it]] == it, "Wrong copy."); 193 196 } 194 for ( ListGraph::EdgeIt it(to); it != INVALID; ++it) {197 for (typename GR::EdgeIt it(to); it != INVALID; ++it) { 195 198 check(er[ecr[it]] == it, "Wrong copy."); 196 199 } … … 209 212 210 213 int main() { 211 digraph_copy_test(); 212 graph_copy_test(); 214 digraph_copy_test<SmartDigraph>(); 215 digraph_copy_test<ListDigraph>(); 216 digraph_copy_test<StaticDigraph>(); 217 graph_copy_test<SmartGraph>(); 218 graph_copy_test<ListGraph>(); 213 219 214 220 return 0;
Note: See TracChangeset
for help on using the changeset viewer.