# HG changeset patch # User Alpar Juttner # Date 1539796447 -7200 # Node ID 3c00344f49c951d5076dd2c4b7a2389603aba66c # Parent cd72eae05bdf90c221a085e0ec4b68436218b2e3# Parent 6b79d93e812f3d99e00e90bd5c7a5d04f05f6cc1 Merge diff -r cd72eae05bdf -r 3c00344f49c9 AUTHORS --- a/AUTHORS Mon Jul 16 16:21:40 2018 +0200 +++ b/AUTHORS Wed Oct 17 19:14:07 2018 +0200 @@ -1,15 +1,15 @@ -The authors of the 1.x series are +The main developers of release series 1.x are * Balazs Dezso * Alpar Juttner * Peter Kovacs * Akos Ladanyi -For more details on the actual contribution, please visit the history -of the main LEMON source repository: http://lemon.cs.elte.hu/hg/lemon +For more complete list of contributors, please visit the history of +the LEMON source code repository: http://lemon.cs.elte.hu/hg/lemon -Moreover, this version is heavily based on the 0.x series of -LEMON. Here is the list of people who contributed to those versions. +Moreover, this version is heavily based on version 0.x of LEMON. Here +is the list of people who contributed to those versions. * Mihaly Barasz * Johanna Becker diff -r cd72eae05bdf -r 3c00344f49c9 CMakeLists.txt --- a/CMakeLists.txt Mon Jul 16 16:21:40 2018 +0200 +++ b/CMakeLists.txt Wed Oct 17 19:14:07 2018 +0200 @@ -1,4 +1,13 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +IF(POLICY CMP0048) + CMAKE_POLICY(SET CMP0048 OLD) +ENDIF(POLICY CMP0048) + +IF(POLICY CMP0026) + #This is for copying the dll's needed by glpk (in lp_test and mip_test) + CMAKE_POLICY(SET CMP0026 OLD) +ENDIF(POLICY CMP0026) SET(PROJECT_NAME "LEMON") PROJECT(${PROJECT_NAME}) @@ -12,29 +21,47 @@ SET(LEMON_VERSION $ENV{LEMON_VERSION} CACHE STRING "LEMON version string.") ELSE() EXECUTE_PROCESS( - COMMAND ${PYTHON_EXECUTABLE} ./scripts/chg-len.py + COMMAND + hg log -r. --template "{latesttag}" WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE HG_REVISION_PATH + OUTPUT_VARIABLE HG_REVISION_TAG ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) EXECUTE_PROCESS( - COMMAND hg id -i + COMMAND + hg log -r. --template "{latesttagdistance}" WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE HG_REVISION + OUTPUT_VARIABLE HG_REVISION_DIST ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) - IF(HG_REVISION STREQUAL "") + EXECUTE_PROCESS( + COMMAND + hg log -r. --template "{node|short}" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE HG_REVISION_ID + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + IF(HG_REVISION_TAG STREQUAL "") SET(HG_REVISION_ID "hg-tip") ELSE() - IF(HG_REVISION_PATH STREQUAL "") - SET(HG_REVISION_ID ${HG_REVISION}) + IF(HG_REVISION_TAG STREQUAL "null") + SET(HG_REVISION_TAG "trunk") + ELSEIF(HG_REVISION_TAG MATCHES "^r") + STRING(SUBSTRING ${HG_REVISION_TAG} 1 -1 HG_REVISION_TAG) + ENDIF() + IF(HG_REVISION_DIST STREQUAL "0") + SET(HG_REVISION ${HG_REVISION_TAG}) ELSE() - SET(HG_REVISION_ID ${HG_REVISION_PATH}.${HG_REVISION}) + SET(HG_REVISION + "${HG_REVISION_TAG}+${HG_REVISION_DIST}-${HG_REVISION_ID}") ENDIF() ENDIF() - SET(LEMON_VERSION ${HG_REVISION_ID} CACHE STRING "LEMON version string.") + + SET(LEMON_VERSION ${HG_REVISION} CACHE STRING "LEMON version string.") ENDIF() SET(PROJECT_VERSION ${LEMON_VERSION}) @@ -43,9 +70,84 @@ FIND_PACKAGE(Doxygen) FIND_PACKAGE(Ghostscript) -FIND_PACKAGE(GLPK 4.33) -FIND_PACKAGE(CPLEX) -FIND_PACKAGE(COIN) + +IF(WIN32) + SET(LEMON_WIN32 TRUE) +ENDIF(WIN32) + +SET(LEMON_ENABLE_GLPK YES CACHE STRING "Enable GLPK solver backend.") +SET(LEMON_ENABLE_ILOG YES CACHE STRING "Enable ILOG (CPLEX) solver backend.") +SET(LEMON_ENABLE_COIN YES CACHE STRING "Enable COIN solver backend.") +SET(LEMON_ENABLE_SOPLEX YES CACHE STRING "Enable SoPlex solver backend.") + +IF(LEMON_ENABLE_GLPK) + FIND_PACKAGE(GLPK 4.33) + IF(GLPK_FOUND) + SET(LEMON_HAVE_LP TRUE) + SET(LEMON_HAVE_MIP TRUE) + SET(LEMON_HAVE_GLPK TRUE) + ENDIF(GLPK_FOUND) +ENDIF(LEMON_ENABLE_GLPK) +IF(LEMON_ENABLE_ILOG) + FIND_PACKAGE(ILOG) + IF(ILOG_FOUND) + SET(LEMON_HAVE_LP TRUE) + SET(LEMON_HAVE_MIP TRUE) + SET(LEMON_HAVE_CPLEX TRUE) + ENDIF(ILOG_FOUND) +ENDIF(LEMON_ENABLE_ILOG) +IF(LEMON_ENABLE_COIN) + FIND_PACKAGE(COIN) + IF(COIN_FOUND) + SET(LEMON_HAVE_LP TRUE) + SET(LEMON_HAVE_MIP TRUE) + SET(LEMON_HAVE_CLP TRUE) + SET(LEMON_HAVE_CBC TRUE) + ENDIF(COIN_FOUND) +ENDIF(LEMON_ENABLE_COIN) +IF(LEMON_ENABLE_SOPLEX) + FIND_PACKAGE(SOPLEX) + IF(SOPLEX_FOUND) + SET(LEMON_HAVE_LP TRUE) + SET(LEMON_HAVE_SOPLEX TRUE) + ENDIF(SOPLEX_FOUND) +ENDIF(LEMON_ENABLE_SOPLEX) + +IF(ILOG_FOUND) + SET(DEFAULT_LP "CPLEX") + SET(DEFAULT_MIP "CPLEX") +ELSEIF(COIN_FOUND) + SET(DEFAULT_LP "CLP") + SET(DEFAULT_MIP "CBC") +ELSEIF(GLPK_FOUND) + SET(DEFAULT_LP "GLPK") + SET(DEFAULT_MIP "GLPK") +ELSEIF(SOPLEX_FOUND) + SET(DEFAULT_LP "SOPLEX") +ENDIF() + +IF(NOT LEMON_DEFAULT_LP OR + (NOT ILOG_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CPLEX")) OR + (NOT COIN_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CLP")) OR + (NOT GLPK_FOUND AND (LEMON_DEFAULT_LP STREQUAL "GLPK")) OR + (NOT SOPLEX_FOUND AND (LEMON_DEFAULT_LP STREQUAL "SOPLEX"))) + SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING + "Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)" FORCE) +ELSE() + SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING + "Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)") +ENDIF() +IF(NOT LEMON_DEFAULT_MIP OR + (NOT ILOG_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CPLEX")) OR + (NOT COIN_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CBC")) OR + (NOT GLPK_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "GLPK"))) + SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING + "Default MIP solver backend (GLPK, CPLEX or CBC)" FORCE) +ELSE() + SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING + "Default MIP solver backend (GLPK, CPLEX or CBC)") +ENDIF() + IF(DEFINED ENV{LEMON_CXX_WARNING}) SET(CXX_WARNING $ENV{LEMON_CXX_WARNING}) @@ -56,10 +158,13 @@ SET(CMAKE_C_FLAGS_DEBUG CACHE STRING "-ggdb") ELSEIF(MSVC) # This part is unnecessary 'casue the same is set by the lemon/core.h. - # Still keep it as an example. - SET(CXX_WARNING "/wd4250 /wd4355 /wd4503 /wd4800 /wd4996") + # Still kept as an example. + + # SET(CXX_WARNING "/wd4250 /wd4267 /wd4355 /wd4503 /wd4800 /wd4996") + # Suppressed warnings: # C4250: 'class1' : inherits 'class2::member' via dominance + # C4267: conversion from 'size_t' to 'type', possible loss of data # C4355: 'this' : used in base member initializer list # C4503: 'function' : decorated name length exceeded, name was truncated # C4800: 'type' : forcing value to bool 'true' or 'false' @@ -73,20 +178,39 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LEMON_CXX_WARNING_FLAGS}") -SET( CMAKE_CXX_FLAGS_MAINTAINER "-Werror -ggdb -O0" CACHE STRING +IF(MSVC) + SET(CMAKE_CXX_FLAGS "/bigobj ${CMAKE_CXX_FLAGS}") + SET( CMAKE_CXX_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING "Flags used by the C++ compiler during maintainer builds." - FORCE ) -SET( CMAKE_C_FLAGS_MAINTAINER "-Werror -O0" CACHE STRING + ) + SET( CMAKE_C_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING "Flags used by the C compiler during maintainer builds." - FORCE ) -SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER - "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING + ) + SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER + "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING "Flags used for linking binaries during maintainer builds." - FORCE ) -SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER - "-Wl,--warn-unresolved-symbols,--warn-once" CACHE STRING + ) + SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER + "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING "Flags used by the shared libraries linker during maintainer builds." - FORCE ) + ) +ELSE() + SET( CMAKE_CXX_FLAGS_MAINTAINER "-Werror -ggdb -O0" CACHE STRING + "Flags used by the C++ compiler during maintainer builds." + ) + SET( CMAKE_C_FLAGS_MAINTAINER "-Werror -O0" CACHE STRING + "Flags used by the C compiler during maintainer builds." + ) + SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER + "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING + "Flags used for linking binaries during maintainer builds." + ) + SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER + "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING + "Flags used by the shared libraries linker during maintainer builds." + ) +ENDIF() + MARK_AS_ADVANCED( CMAKE_CXX_FLAGS_MAINTAINER CMAKE_C_FLAGS_MAINTAINER @@ -114,7 +238,27 @@ CHECK_TYPE_SIZE("long long" LONG_LONG) SET(LEMON_HAVE_LONG_LONG ${HAVE_LONG_LONG}) -INCLUDE(FindPythonInterp) +INCLUDE(FindThreads) + +IF(NOT LEMON_THREADING) + IF(CMAKE_USE_PTHREADS_INIT) + SET(LEMON_THREADING "Pthread") + ELSEIF(CMAKE_USE_WIN32_THREADS_INIT) + SET(LEMON_THREADING "Win32") + ELSE() + SET(LEMON_THREADING "None") + ENDIF() +ENDIF() + +SET( LEMON_THREADING "${LEMON_THREADING}" CACHE STRING + "Choose the threading library, options are: Pthread Win32 None." + FORCE ) + +IF(LEMON_THREADING STREQUAL "Pthread") + SET(LEMON_USE_PTHREAD TRUE) +ELSEIF(LEMON_THREADING STREQUAL "Win32") + SET(LEMON_USE_WIN32_THREADS TRUE) +ENDIF() ENABLE_TESTING() @@ -126,6 +270,7 @@ ADD_SUBDIRECTORY(lemon) IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) + ADD_SUBDIRECTORY(contrib) ADD_SUBDIRECTORY(demo) ADD_SUBDIRECTORY(tools) ADD_SUBDIRECTORY(doc) @@ -149,6 +294,33 @@ ) ENDIF() +CONFIGURE_FILE( + ${PROJECT_SOURCE_DIR}/cmake/version.cmake.in + ${PROJECT_BINARY_DIR}/cmake/version.cmake + @ONLY +) + +SET(ARCHIVE_BASE_NAME ${CMAKE_PROJECT_NAME}) +STRING(TOLOWER ${ARCHIVE_BASE_NAME} ARCHIVE_BASE_NAME) +SET(ARCHIVE_NAME ${ARCHIVE_BASE_NAME}-${PROJECT_VERSION}) +ADD_CUSTOM_TARGET(dist + COMMAND cmake -E remove_directory ${ARCHIVE_NAME} + COMMAND hg archive ${ARCHIVE_NAME} + COMMAND cmake -E copy cmake/version.cmake ${ARCHIVE_NAME}/cmake/version.cmake + COMMAND tar -czf ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_NAME} + COMMAND zip -r ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.zip ${ARCHIVE_NAME} + COMMAND cmake -E copy_directory doc/html ${ARCHIVE_NAME}/doc/html + COMMAND tar -czf ${ARCHIVE_NAME}.tar.gz ${ARCHIVE_NAME} + COMMAND zip -r ${ARCHIVE_NAME}.zip ${ARCHIVE_NAME} + COMMAND cmake -E copy_directory doc/html ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} + COMMAND tar -czf ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} + COMMAND zip -r ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.zip ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} + COMMAND cmake -E remove_directory ${ARCHIVE_NAME} + COMMAND cmake -E remove_directory ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} + DEPENDS html + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + +# CPACK config (Basically for NSIS) IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) SET(CPACK_PACKAGE_NAME ${PROJECT_NAME}) SET(CPACK_PACKAGE_VENDOR "EGRES") diff -r cd72eae05bdf -r 3c00344f49c9 INSTALL --- a/INSTALL Mon Jul 16 16:21:40 2018 +0200 +++ b/INSTALL Wed Oct 17 19:14:07 2018 +0200 @@ -1,197 +1,167 @@ Installation Instructions ========================= -Since you are reading this I assume you already obtained one of the release -tarballs and successfully extracted it. The latest version of LEMON is -available at our web page (http://lemon.cs.elte.hu/). +This file contains instructions for building and installing LEMON from +source on Linux. The process on Windows is similar. -LEMON provides two different build environments, one is based on "autotool", -while the other is based on "cmake". This file contains instructions only for -the former one, which is the recommended build environment on Linux, Mac OSX -and other unices or if you use Cygwin on Windows. For cmake installation -instructions visit http://lemon.cs.elte.hu. +Note that it is not necessary to install LEMON in order to use +it. Instead, you can easily integrate it with your own code +directly. For instructions, see +https://lemon.cs.elte.hu/trac/lemon/wiki/HowToCompile + In order to install LEMON from the extracted source tarball you have to issue the following commands: - 1. `cd lemon-x.y.z' + 1. Step into the root of the source directory. - This command changes to the directory which was created when you - extracted the sources. The x.y.z part is a version number. + $ cd lemon-x.y.z - 2. `./configure' + 2. Create a build subdirectory and step into it. - This command runs the configure shell script, which does some checks and - creates the makefiles. + $ mkdir build + $ cd build - 3. `make' + 3. Perform system checks and create the makefiles. - This command compiles the non-template part of LEMON into libemon.a - file. It also compiles the programs in the tools subdirectory by - default. + $ cmake .. - 4. `make check' + 4. Build LEMON. - This step is optional, but recommended. It runs the test programs that - we developed for LEMON to check whether the library works properly on - your platform. + $ make - 5. `make install' + This command compiles the non-template part of LEMON into + libemon.a file. It also compiles the programs in the 'tools' and + 'demo' subdirectories. + + 5. [Optional] Compile and run the self-tests. + + $ make check + + 5. [Optional] Generate the user documentation. + + $ make html + + The release tarballs already include the documentation. + + Note that for this step you need to have the following tools + installed: Python, Doxygen, Graphviz, Ghostscript, LaTeX. + + 6. [Optional] Install LEMON + + $ make install This command installs LEMON under /usr/local (you will need root - privileges to be able to do that). If you want to install it to some - other location, then pass the --prefix=DIRECTORY flag to configure in - step 2. For example: `./configure --prefix=/home/username/lemon'. - - 6. `make install-html' - - This command installs the documentation under share/doc/lemon/docs. The - generated documentation is included in the tarball. If you want to - generate it yourself, then run `make html'. Note that for this you need - to have the following programs installed: Doxygen, Graphviz, Ghostscript, - Latex. - + privileges to be able to do that). If you want to install it to + some other location, then pass the + -DCMAKE_INSTALL_PREFIX=DIRECTORY flag to cmake in Step 3. + For example: + + $ cmake -DCMAKE_INSTALL_PREFIX=/home/username/lemon' Configure Options and Variables =============================== -In step 2 you can customize the actions of configure by setting variables -and passing options to it. This can be done like this: -`./configure [OPTION]... [VARIABLE=VALUE]...' +In Step 3, you can customize the build process by passing options to CMAKE. -Below you will find some useful variables and options (see `./configure --help' -for more): +$ cmake [OPTIONS] .. -CXX='comp' +You find a list of the most useful options below. - Change the C++ compiler to 'comp'. - -CXXFLAGS='flags' - - Pass the 'flags' to the compiler. For example CXXFLAGS='-O3 -march=pentium-m' - turns on generation of aggressively optimized Pentium-M specific code. - ---prefix=PREFIX +-DCMAKE_INSTALL_PREFIX=PREFIX Set the installation prefix to PREFIX. By default it is /usr/local. ---enable-tools +-DCMAKE_BUILD_TYPE=[Release|Debug|Maintainer|...] - Build the programs in the tools subdirectory (default). + This sets the compiler options. The choices are the following ---disable-tools + 'Release': A strong optimization is turned on (-O3 with gcc). This + is the default setting and we strongly recommend using this for + the final compilation. - Do not build the programs in the tools subdirectory. + 'Debug': Optimization is turned off and debug info is added (-O0 + -ggdb with gcc). If is recommended during the development. ---with-glpk[=PREFIX] + 'Maintainer': The same as 'Debug' but the compiler warnings are + converted to errors (-Werror with gcc). In addition, 'make' will + also automatically compile and execute the test codes. It is the + best way of ensuring that LEMON codebase is clean and safe. - Enable GLPK support (default). You should specify the prefix too if - you installed GLPK to some non-standard location (e.g. your home - directory). If it is not found, GLPK support will be disabled. + 'RelWithDebInfo': Optimized build with debug info. ---with-glpk-includedir=DIR + 'MinSizeRel': Size optimized build (-Os with gcc) - The directory where the GLPK header files are located. This is only - useful when the GLPK headers and libraries are not under the same - prefix (which is unlikely). +-DTEST_WITH_VALGRIND=YES ---with-glpk-libdir=DIR + Using this, the test codes will be executed using valgrind. It is a + very effective way of identifying indexing problems and memory leaks. - The directory where the GLPK libraries are located. This is only - useful when the GLPK headers and libraries are not under the same - prefix (which is unlikely). +-DCMAKE_CXX_COMPILER=path-to-compiler ---without-glpk + Change the compiler to be used. - Disable GLPK support. +-DBUILD_SHARED_LIBS=TRUE ---with-cplex[=PREFIX] + Build shared library instead of static one. Think twice if you + really want to use this option. - Enable CPLEX support (default). You should specify the prefix too - if you installed CPLEX to some non-standard location - (e.g. /opt/ilog/cplex75). If it is not found, CPLEX support will be - disabled. +-DLEMON_DOC_SOURCE_BROWSER=YES ---with-cplex-includedir=DIR + Include the browsable cross referenced LEMON source code into the + doc. It makes the doc quite bloated, but may be useful for + developing LEMON itself. - The directory where the CPLEX header files are located. This is - only useful when the CPLEX headers and libraries are not under the - same prefix (e.g. /usr/local/cplex/cplex75/include). +-DLEMON_DOC_USE_MATHJAX=YES ---with-cplex-libdir=DIR + Use MathJax (http://mathjax.org) for rendering the math formulae in + the doc. It of much higher quality compared to the default LaTeX + generated static images and it allows copy&paste of the formulae to + LaTeX, Open Office, MS Word etc. documents. - The directory where the CPLEX libraries are located. This is only - useful when the CPLEX headers and libraries are not under the same - prefix (e.g. - /usr/local/cplex/cplex75/lib/i86_linux2_glibc2.2_gcc3.0/static_pic_mt). + On the other hand, it needs either Internet access or a locally + installed version of MathJax to properly render the doc. ---without-cplex +-DLEMON_DOC_MATHJAX_RELPATH=DIRECTORY + + The location of the MathJax library. It defaults to + http://www.mathjax.org/mathjax, which necessitates Internet access + for proper rendering. The easiest way to make it usable offline is + to set this parameter to 'mathjax' and copy all files of the MathJax + library into the 'doc/html/mathjax' subdirectory of the build + location. - Disable CPLEX support. + See http://docs.mathjax.org/en/latest/installation.html for more details. ---with-soplex[=PREFIX] + +-DLEMON_ENABLE_GLPK=NO +-DLEMON_ENABLE_COIN=NO +-DLEMON_ENABLE_ILOG=NO - Enable SoPlex support (default). You should specify the prefix too if - you installed SoPlex to some non-standard location (e.g. your home - directory). If it is not found, SoPlex support will be disabled. + Enable optional third party libraries. They are all enabled by default. ---with-soplex-includedir=DIR +-DLEMON_DEFAULT_LP=GLPK - The directory where the SoPlex header files are located. This is only - useful when the SoPlex headers and libraries are not under the same - prefix (which is unlikely). + Sets the default LP solver backend. The supported values are + CPLEX, CLP and GLPK. By default, it is set to the first one which + is enabled and succesfully discovered. ---with-soplex-libdir=DIR +-DLEMON_DEFAULT_MIP=GLPK - The directory where the SoPlex libraries are located. This is only - useful when the SoPlex headers and libraries are not under the same - prefix (which is unlikely). + Sets the default MIP solver backend. The supported values are + CPLEX, CBC and GLPK. By default, it is set to the first one which + is enabled and succesfully discovered. ---without-soplex +-DGLPK_ROOT_DIR=DIRECTORY +-DCOIN_ROOT_DIR=DIRECTORY +-DILOG_ROOT_DIR=DIRECTORY - Disable SoPlex support. - ---with-coin[=PREFIX] - - Enable support for COIN-OR solvers (CLP and CBC). You should - specify the prefix too. (by default, COIN-OR tools install - themselves to the source code directory). This command enables the - solvers that are actually found. - ---with-coin-includedir=DIR - - The directory where the COIN-OR header files are located. This is - only useful when the COIN-OR headers and libraries are not under - the same prefix (which is unlikely). - ---with-coin-libdir=DIR - - The directory where the COIN-OR libraries are located. This is only - useful when the COIN-OR headers and libraries are not under the - same prefix (which is unlikely). - ---without-coin - - Disable COIN-OR support. - + Root directory prefixes of optional third party libraries. 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]...' +make VERBOSE=1 -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"'. + This results in a more verbose output by showing the full + compiler and linker commands. \ No newline at end of file diff -r cd72eae05bdf -r 3c00344f49c9 LICENSE --- a/LICENSE Mon Jul 16 16:21:40 2018 +0200 +++ b/LICENSE Wed Oct 17 19:14:07 2018 +0200 @@ -1,7 +1,7 @@ LEMON code without an explicit copyright notice is covered by the following copyright/license. -Copyright (C) 2003-2010 Egervary Jeno Kombinatorikus Optimalizalasi +Copyright (C) 2003-2012 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport (Egervary Combinatorial Optimization Research Group, EGRES). diff -r cd72eae05bdf -r 3c00344f49c9 Makefile.am --- a/Makefile.am Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 - -AM_CXXFLAGS = $(WARNINGCXXFLAGS) - -AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) -LDADD = $(top_builddir)/lemon/libemon.la - -EXTRA_DIST = \ - AUTHORS \ - LICENSE \ - m4/lx_check_cplex.m4 \ - m4/lx_check_glpk.m4 \ - m4/lx_check_soplex.m4 \ - m4/lx_check_coin.m4 \ - CMakeLists.txt \ - cmake/FindGhostscript.cmake \ - cmake/FindCPLEX.cmake \ - cmake/FindGLPK.cmake \ - cmake/FindCOIN.cmake \ - cmake/LEMONConfig.cmake.in \ - cmake/version.cmake.in \ - cmake/version.cmake \ - cmake/nsis/lemon.ico \ - cmake/nsis/uninstall.ico - -pkgconfigdir = $(libdir)/pkgconfig -lemondir = $(pkgincludedir) -bitsdir = $(lemondir)/bits -conceptdir = $(lemondir)/concepts -pkgconfig_DATA = -lib_LTLIBRARIES = -lemon_HEADERS = -bits_HEADERS = -concept_HEADERS = -noinst_HEADERS = -noinst_PROGRAMS = -bin_PROGRAMS = -check_PROGRAMS = -dist_bin_SCRIPTS = -TESTS = -XFAIL_TESTS = - -include lemon/Makefile.am -include test/Makefile.am -include doc/Makefile.am -include tools/Makefile.am -include scripts/Makefile.am - -DIST_SUBDIRS = demo - -demo: - $(MAKE) $(AM_MAKEFLAGS) -C demo - -MRPROPERFILES = \ - aclocal.m4 \ - config.h.in \ - config.h.in~ \ - configure \ - Makefile.in \ - build-aux/config.guess \ - build-aux/config.sub \ - build-aux/depcomp \ - build-aux/install-sh \ - build-aux/ltmain.sh \ - build-aux/missing \ - doc/doxygen.log - -mrproper: - $(MAKE) $(AM_MAKEFLAGS) maintainer-clean - -rm -f $(MRPROPERFILES) - -dist-bz2: dist - zcat $(PACKAGE)-$(VERSION).tar.gz | \ - bzip2 --best -c > $(PACKAGE)-$(VERSION).tar.bz2 - -distcheck-bz2: distcheck - zcat $(PACKAGE)-$(VERSION).tar.gz | \ - bzip2 --best -c > $(PACKAGE)-$(VERSION).tar.bz2 - -.PHONY: demo mrproper dist-bz2 distcheck-bz2 diff -r cd72eae05bdf -r 3c00344f49c9 NEWS --- a/NEWS Mon Jul 16 16:21:40 2018 +0200 +++ b/NEWS Wed Oct 17 19:14:07 2018 +0200 @@ -1,3 +1,101 @@ +2013-08-10 Version 1.3 released + + This is major feature release + + * New data structures + + #69 : Bipartite graph concepts and implementations + + * New algorithms + + #177: Port Edmonds-Karp algorithm + #380, #405: Heuristic algorithm for the max clique problem + #386: Heuristic algorithms for symmetric TSP + ----: Nagamochi-Ibaraki algorithm [5087694945e4] + #397, #56: Max. cardinality search + + * Other new features + + #223: Thread safe graph and graph map implementations + #442: Different TimeStamp print formats + #457: File export functionality to LpBase + #362: Bidirectional iterator support for radixSort() + + * Implementation improvements + + ----: Network Simplex + #391: Better update process, pivot rule and arc mixing + #435: Improved Altering List pivot rule + #417: Various fine tunings in CostScaling + #438: Optional iteration limit in HowardMmc + #436: Ensure strongly polynomial running time for CycleCanceling + while keeping the same performance + ----: Make the CBC interface be compatible with latest CBC releases + [ee581a0ecfbf] + + * CMAKE has become the default build environment (#434) + + ----: Autotool support has been dropped + ----: Improved LP/MIP configuration + #465: Enable/disable options for LP/MIP backends + #446: Better CPLEX discovery + #460: Add cmake config to find SoPlex + ----: Allow CPACK configuration on all platforms + #390: Add 'Maintainer' CMAKE build type + #388: Add 'check' target. + #401: Add contrib dir + #389: Better version string setting in CMAKE + #433: Support shared library build + #416: Support testing with valgrind + + * Doc improvements + + #395: SOURCE_BROWSER Doxygen switch is configurable from CMAKE + update-external-tags CMAKE target + #455: Optionally use MathJax for rendering the math formulae + #402, #437, #459, #456, #463: Various doc improvements + + * Bugfixes (compared to release 1.2): + + #432: Add missing doc/template.h and doc/references.bib to release + tarball + ----: Intel C++ compatibility fixes + #441: Fix buggy reinitialization in _solver_bits::VarIndex::clear() + #444: Bugfix in path copy constructors and assignment operators + #447: Bugfix in AllArcLookUp<> + #448: Bugfix in adaptor_test.cc + #449: Fix clang compilation warnings and errors + #440: Fix a bug + remove redundant typedefs in dimacs-solver + #453: Avoid GCC 4.7 compiler warnings + #445: Fix missing initialization in CplexEnv::CplexEnv() + #428: Add missing lemon/lemon.pc.cmake to the release tarball + #393: Create and install lemon.pc + #429: Fix VS warnings + #430: Fix LpBase::Constr two-side limit bug + #392: Bug fix in Dfs::start(s,t) + #414: Fix wrong initialization in Preflow + #418: Better Win CodeBlock/MinGW support + #419: Build environment improvements + - Build of mip_test and lp_test precede the running of the tests + - Also search for coin libs under ${COIN_ROOT_DIR}/lib/coin + - Do not look for COIN_VOL libraries + #382: Allow lgf file without Arc maps + #417: Bug fix in CostScaling + #366: Fix Pred[Matrix]MapPath::empty() + #371: Bug fix in (di)graphCopy() + The target graph is cleared before adding nodes and arcs/edges. + #364: Add missing UndirectedTags + #368: Fix the usage of std::numeric_limits<>::min() in Network Simplex + #372: Fix a critical bug in preflow + #461: Bugfix in assert.h + #470: Fix compilation issues related to various gcc versions + #446: Fix #define indicating CPLEX availability + #294: Add explicit namespace to + ignore_unused_variable_warning() usages + #420: Bugfix in IterableValueMap + #439: Bugfix in biNodeConnected() + + 2010-03-19 Version 1.2 released This is major feature release diff -r cd72eae05bdf -r 3c00344f49c9 cmake/FindCOIN.cmake --- a/cmake/FindCOIN.cmake Mon Jul 16 16:21:40 2018 +0200 +++ b/cmake/FindCOIN.cmake Wed Oct 17 19:14:07 2018 +0200 @@ -65,6 +65,12 @@ HINTS ${COIN_ROOT_DIR}/lib ) +FIND_LIBRARY(COIN_PTHREADS_LIBRARY + NAMES pthreads libpthreads + HINTS ${COIN_ROOT_DIR}/lib/coin + HINTS ${COIN_ROOT_DIR}/lib +) + INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(COIN DEFAULT_MSG COIN_INCLUDE_DIR @@ -82,14 +88,17 @@ IF(COIN_FOUND) SET(COIN_INCLUDE_DIRS ${COIN_INCLUDE_DIR}) - SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARY};${COIN_COIN_UTILS_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY}") + SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARY};${COIN_COIN_UTILS_LIBRARY}") IF(COIN_ZLIB_LIBRARY) SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_ZLIB_LIBRARY}") ENDIF(COIN_ZLIB_LIBRARY) IF(COIN_BZ2_LIBRARY) SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_BZ2_LIBRARY}") ENDIF(COIN_BZ2_LIBRARY) - SET(COIN_CBC_LIBRARIES "${COIN_CBC_LIBRARY};${COIN_CBC_SOLVER_LIBRARY};${COIN_CGL_LIBRARY};${COIN_OSI_LIBRARY};${COIN_OSI_CBC_LIBRARY};${COIN_OSI_CLP_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY};${COIN_CLP_LIBRARIES}") + IF(COIN_PTHREADS_LIBRARY) + SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_PTHREADS_LIBRARY}") + ENDIF(COIN_PTHREADS_LIBRARY) + SET(COIN_CBC_LIBRARIES "${COIN_CBC_LIBRARY};${COIN_CBC_SOLVER_LIBRARY};${COIN_CGL_LIBRARY};${COIN_OSI_LIBRARY};${COIN_OSI_CBC_LIBRARY};${COIN_OSI_CLP_LIBRARY};${COIN_CLP_LIBRARIES}") SET(COIN_LIBRARIES ${COIN_CBC_LIBRARIES}) ENDIF(COIN_FOUND) @@ -108,10 +117,3 @@ COIN_ZLIB_LIBRARY COIN_BZ2_LIBRARY ) - -IF(COIN_FOUND) - SET(LEMON_HAVE_LP TRUE) - SET(LEMON_HAVE_MIP TRUE) - SET(LEMON_HAVE_CLP TRUE) - SET(LEMON_HAVE_CBC TRUE) -ENDIF(COIN_FOUND) diff -r cd72eae05bdf -r 3c00344f49c9 cmake/FindCPLEX.cmake --- a/cmake/FindCPLEX.cmake Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -SET(CPLEX_ROOT_DIR "" CACHE PATH "CPLEX root directory") - -FIND_PATH(CPLEX_INCLUDE_DIR - ilcplex/cplex.h - PATHS "C:/ILOG/CPLEX/include" - PATHS "/opt/ilog/cplex/include" - HINTS ${CPLEX_ROOT_DIR}/include -) -FIND_LIBRARY(CPLEX_LIBRARY - cplex - PATHS "C:/ILOG/CPLEX/lib/msvc7/stat_mda" - PATHS "/opt/ilog/cplex/bin" - HINTS ${CPLEX_ROOT_DIR}/bin - HINTS ${CPLEX_ROOT_DIR}/lib -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPLEX DEFAULT_MSG CPLEX_LIBRARY CPLEX_INCLUDE_DIR) - -FIND_PATH(CPLEX_BIN_DIR - cplex.dll - PATHS "C:/ILOG/CPLEX/bin/x86_win32" - HINTS ${CPLEX_ROOT_DIR}/bin -) - -IF(CPLEX_FOUND) - SET(CPLEX_INCLUDE_DIRS ${CPLEX_INCLUDE_DIR}) - SET(CPLEX_LIBRARIES ${CPLEX_LIBRARY}) - IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") - SET(CPLEX_LIBRARIES "${CPLEX_LIBRARIES};m;pthread") - ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") -ENDIF(CPLEX_FOUND) - -MARK_AS_ADVANCED(CPLEX_LIBRARY CPLEX_INCLUDE_DIR CPLEX_BIN_DIR) - -IF(CPLEX_FOUND) - SET(LEMON_HAVE_LP TRUE) - SET(LEMON_HAVE_MIP TRUE) - SET(LEMON_HAVE_CPLEX TRUE) -ENDIF(CPLEX_FOUND) diff -r cd72eae05bdf -r 3c00344f49c9 cmake/FindGLPK.cmake --- a/cmake/FindGLPK.cmake Mon Jul 16 16:21:40 2018 +0200 +++ b/cmake/FindGLPK.cmake Wed Oct 17 19:14:07 2018 +0200 @@ -53,9 +53,3 @@ ENDIF(GLPK_FOUND) MARK_AS_ADVANCED(GLPK_LIBRARY GLPK_INCLUDE_DIR GLPK_BIN_DIR) - -IF(GLPK_FOUND) - SET(LEMON_HAVE_LP TRUE) - SET(LEMON_HAVE_MIP TRUE) - SET(LEMON_HAVE_GLPK TRUE) -ENDIF(GLPK_FOUND) diff -r cd72eae05bdf -r 3c00344f49c9 cmake/FindILOG.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake/FindILOG.cmake Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,106 @@ +FIND_PATH(ILOG_ROOT_DIR + NAMES cplex + DOC "CPLEX STUDIO root directory" + PATHS /opt/ibm/ILOG /usr/local/ibm/ILOG /usr/local/ILOG /usr/local/ilog + PATHS "$ENV{HOME}/ILOG" "$ENV{HOME}/.local/ILOG" + PATHS "$ENV{HOME}/ibm/ILOG" "$ENV{HOME}/.local/ibm/ILOG" + PATHS "C:/Program Files/IBM/ILOG" + PATH_SUFFIXES "CPLEX_Studio126" "CPLEX_Studio125" + "CPLEX_Studio124" "CPLEX_Studio123" "CPLEX_Studio122" + NO_DEFAULT_PATH +) + +IF(WIN32) + IF(MSVC_VERSION STREQUAL "1400") + SET(ILOG_WIN_COMPILER "windows_vs2005") + ELSEIF(MSVC_VERSION STREQUAL "1500") + SET(ILOG_WIN_COMPILER "windows_vs2008") + ELSEIF(MSVC_VERSION STREQUAL "1600") + SET(ILOG_WIN_COMPILER "windows_vs2010") + ELSE() + SET(ILOG_WIN_COMPILER "windows_vs2008") + ENDIF() + IF(CMAKE_CL_64) + SET(ILOG_WIN_COMPILER "x64_${ILOG_WIN_COMPILER}") + SET(ILOG_WIN_PLATFORM "x64_win32") + ELSE() + SET(ILOG_WIN_COMPILER "x86_${ILOG_WIN_COMPILER}") + SET(ILOG_WIN_PLATFORM "x86_win32") + ENDIF() +ENDIF() + +FIND_PATH(ILOG_CPLEX_ROOT_DIR + NAMES include/ilcplex + HINTS ${ILOG_ROOT_DIR}/cplex ${ILOG_ROOT_DIR}/cplex121 + ${ILOG_ROOT_DIR}/cplex122 ${ILOG_ROOT_DIR}/cplex123 + DOC "CPLEX root directory" + NO_DEFAULT_PATH +) + +FIND_PATH(ILOG_CONCERT_ROOT_DIR + NAMES include/ilconcert + HINTS ${ILOG_ROOT_DIR}/concert ${ILOG_ROOT_DIR}/concert29 + DOC "CONCERT root directory" + NO_DEFAULT_PATH +) + +FIND_PATH(ILOG_CPLEX_INCLUDE_DIR + ilcplex/cplex.h + HINTS ${ILOG_CPLEX_ROOT_DIR}/include + NO_DEFAULT_PATH +) + +FIND_PATH(ILOG_CONCERT_INCLUDE_DIR + ilconcert/ilobasic.h + HINTS ${ILOG_CONCERT_ROOT_DIR}/include + NO_DEFAULT_PATH +) + +FIND_LIBRARY(ILOG_CPLEX_LIBRARY + cplex cplex121 cplex122 cplex123 cplex124 + HINTS ${ILOG_CPLEX_ROOT_DIR}/lib/x86_sles10_4.1/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/x86_linux/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_linux/static_pic + ${ILOG_CPLEX_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda + NO_DEFAULT_PATH + ) + +FIND_LIBRARY(ILOG_CONCERT_LIBRARY + concert + HINTS ${ILOG_CONCERT_ROOT_DIR}/lib/x86_sles10_4.1/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/x86_linux/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_linux/static_pic + ${ILOG_CONCERT_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda + NO_DEFAULT_PATH + ) + +FIND_FILE(ILOG_CPLEX_DLL + cplex121.dll cplex122.dll cplex123.dll cplex124.dll + HINTS ${ILOG_CPLEX_ROOT_DIR}/bin/${ILOG_WIN_PLATFORM} + NO_DEFAULT_PATH + ) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(ILOG + DEFAULT_MSG ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR + ) + +IF(ILOG_FOUND) + SET(ILOG_INCLUDE_DIRS ${ILOG_CPLEX_INCLUDE_DIR} ${ILOG_CONCERT_INCLUDE_DIR}) + SET(ILOG_LIBRARIES ${ILOG_CPLEX_LIBRARY} ${ILOG_CONCERT_LIBRARY}) + IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") + # SET(CPLEX_LIBRARIES "${CPLEX_LIBRARIES};m;pthread") + SET(ILOG_LIBRARIES ${ILOG_LIBRARIES} "m" "pthread") + ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") +ENDIF(ILOG_FOUND) + +MARK_AS_ADVANCED( + ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR ILOG_CPLEX_DLL + ILOG_CONCERT_LIBRARY ILOG_CONCERT_INCLUDE_DIR ILOG_CONCERT_DLL + ) diff -r cd72eae05bdf -r 3c00344f49c9 cmake/FindSOPLEX.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake/FindSOPLEX.cmake Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,23 @@ +SET(SOPLEX_ROOT_DIR "" CACHE PATH "SoPlex root directory") + +FIND_PATH(SOPLEX_INCLUDE_DIR + soplex.h + HINTS ${SOPLEX_ROOT_DIR}/src +) +FIND_LIBRARY(SOPLEX_LIBRARY + soplex + HINTS ${SOPLEX_ROOT_DIR}/lib +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SOPLEX DEFAULT_MSG SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR) + +IF(SOPLEX_FOUND) + SET(SOPLEX_INCLUDE_DIRS ${SOPLEX_INCLUDE_DIR}) + SET(SOPLEX_LIBRARIES ${SOPLEX_LIBRARY}) + IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") + SET(SOPLEX_LIBRARIES "${SOPLEX_LIBRARIES};z") + ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") +ENDIF(SOPLEX_FOUND) + +MARK_AS_ADVANCED(SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR) diff -r cd72eae05bdf -r 3c00344f49c9 cmake/version.cmake.in --- a/cmake/version.cmake.in Mon Jul 16 16:21:40 2018 +0200 +++ b/cmake/version.cmake.in Wed Oct 17 19:14:07 2018 +0200 @@ -1,1 +1,1 @@ -SET(LEMON_VERSION "@PACKAGE_VERSION@" CACHE STRING "LEMON version string.") +SET(LEMON_VERSION "@LEMON_VERSION@" CACHE STRING "LEMON version string.") diff -r cd72eae05bdf -r 3c00344f49c9 configure.ac --- a/configure.ac Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. - -dnl Version information. -m4_define([lemon_version_number], - [m4_normalize(esyscmd([echo ${LEMON_VERSION}]))]) -dnl m4_define([lemon_version_number], []) -m4_define([lemon_hg_path], [m4_normalize(esyscmd([./scripts/chg-len.py]))]) -m4_define([lemon_hg_revision], [m4_normalize(esyscmd([hg id -i 2> /dev/null]))]) -m4_define([lemon_version], [ifelse(lemon_version_number(), - [], - [ifelse(lemon_hg_revision(), - [], - [hg-tip], - [lemon_hg_path().lemon_hg_revision()])], - [lemon_version_number()])]) - -AC_PREREQ([2.59]) -AC_INIT([LEMON], [lemon_version()], [lemon-user@lemon.cs.elte.hu], [lemon]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects nostdinc]) -AC_CONFIG_SRCDIR([lemon/list_graph.h]) -AC_CONFIG_HEADERS([config.h lemon/config.h]) - -AC_DEFINE([LEMON_VERSION], [lemon_version()], [The version string]) - -dnl Do compilation tests using the C++ compiler. -AC_LANG([C++]) - -dnl Check the existence of long long type. -AC_CHECK_TYPE(long long, [long_long_found=yes], [long_long_found=no]) -if test x"$long_long_found" = x"yes"; then - AC_DEFINE([LEMON_HAVE_LONG_LONG], [1], [Define to 1 if you have long long.]) -fi - -dnl Checks for programs. -AC_PROG_CXX -AC_PROG_CXXCPP -AC_PROG_INSTALL -AC_DISABLE_SHARED -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. -AC_MSG_CHECKING([whether we are using the Intel C++ compiler]) -AC_COMPILE_IFELSE([#ifndef __INTEL_COMPILER -choke me -#endif], [ICC=[yes]], [ICC=[no]]) -if test x"$ICC" = x"yes"; then - AC_MSG_RESULT([yes]) -else - AC_MSG_RESULT([no]) -fi - -dnl Set custom compiler flags when using g++. -if test "$GXX" = yes -a "$ICC" = no; then - WARNINGCXXFLAGS="-Wall -W -Wall -W -Wunused -Wformat=2 -Wctor-dtor-privacy -Wnon-virtual-dtor -Wno-char-subscripts -Wwrite-strings -Wno-char-subscripts -Wreturn-type -Wcast-qual -Wcast-align -Wsign-promo -Woverloaded-virtual -ansi -fno-strict-aliasing -Wold-style-cast -Wno-unknown-pragmas" -fi -AC_SUBST([WARNINGCXXFLAGS]) - -dnl Checks for libraries. -LX_CHECK_GLPK -LX_CHECK_CPLEX -LX_CHECK_SOPLEX -LX_CHECK_COIN - -AM_CONDITIONAL([HAVE_LP], [test x"$lx_lp_found" = x"yes"]) -AM_CONDITIONAL([HAVE_MIP], [test x"$lx_mip_found" = x"yes"]) - -dnl Disable/enable building the binary tools. -AC_ARG_ENABLE([tools], -AS_HELP_STRING([--enable-tools], [build additional tools @<:@default@:>@]) -AS_HELP_STRING([--disable-tools], [do not build additional tools]), - [], [enable_tools=yes]) -AC_MSG_CHECKING([whether to build the additional tools]) -if test x"$enable_tools" != x"no"; then - AC_MSG_RESULT([yes]) -else - AC_MSG_RESULT([no]) -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) - -dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_INLINE -AC_TYPE_SIZE_T -AC_HEADER_TIME -AC_STRUCT_TM - -dnl Checks for library functions. -AC_HEADER_STDC -AC_CHECK_FUNCS(gettimeofday times ctime_r) - -dnl Add dependencies on files generated by configure. -AC_SUBST([CONFIG_STATUS_DEPENDENCIES], - ['$(top_srcdir)/doc/Doxyfile.in $(top_srcdir)/doc/mainpage.dox.in $(top_srcdir)/lemon/lemon.pc.in $(top_srcdir)/cmake/version.cmake.in']) - -AC_CONFIG_FILES([ -Makefile -demo/Makefile -cmake/version.cmake -doc/Doxyfile -doc/mainpage.dox -lemon/lemon.pc -]) - -AC_OUTPUT - -echo -echo '****************************** SUMMARY ******************************' -echo -echo Package version............... : $PACKAGE-$VERSION -echo -echo C++ compiler.................. : $CXX -echo C++ compiles flags............ : $WARNINGCXXFLAGS $CXXFLAGS -echo -echo Compiler supports long long... : $long_long_found -echo -echo GLPK support.................. : $lx_glpk_found -echo CPLEX support................. : $lx_cplex_found -echo SOPLEX support................ : $lx_soplex_found -echo CLP support................... : $lx_clp_found -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 ' ' -echo $prefix. -echo -echo '*********************************************************************' - -echo -echo Configure complete, now type \'make\' and then \'make install\'. -echo diff -r cd72eae05bdf -r 3c00344f49c9 contrib/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/CMakeLists.txt Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,19 @@ +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR} +) + +LINK_DIRECTORIES( + ${PROJECT_BINARY_DIR}/lemon +) + +# Uncomment (and adjust) the following two lines. 'myprog' is the name +# of the final executable ('.exe' will automatically be added to the +# name on Windows) and 'myprog-main.cc' is the source code it is +# compiled from. You can add more source files separated by +# whitespaces. Moreover, you can add multiple similar blocks if you +# want to build more than one executables. + +# ADD_EXECUTABLE(myprog myprog-main.cc) +# TARGET_LINK_LIBRARIES(myprog lemon) + diff -r cd72eae05bdf -r 3c00344f49c9 demo/Makefile.am --- a/demo/Makefile.am Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -AM_CXXFLAGS = $(WARNINGCXXFLAGS) - -AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) -LDADD = $(top_builddir)/lemon/libemon.la - -EXTRA_DIST = \ - CMakeLists.txt \ - digraph.lgf - -noinst_PROGRAMS = \ - arg_parser_demo \ - graph_to_eps_demo \ - lgf_demo - -arg_parser_demo_SOURCES = arg_parser_demo.cc -graph_to_eps_demo_SOURCES = graph_to_eps_demo.cc -lgf_demo_SOURCES = lgf_demo.cc diff -r cd72eae05bdf -r 3c00344f49c9 doc/CMakeLists.txt --- a/doc/CMakeLists.txt Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/CMakeLists.txt Wed Oct 17 19:14:07 2018 +0200 @@ -4,6 +4,13 @@ SET(abs_top_builddir ${PROJECT_BINARY_DIR}) SET(LEMON_DOC_SOURCE_BROWSER "NO" CACHE STRING "Include source into the doc (YES/NO).") +SET(LEMON_DOC_USE_MATHJAX "NO" CACHE STRING "Use MathJax to display math formulae (YES/NO).") +SET(LEMON_DOC_MATHJAX_RELPATH "http://www.mathjax.org/mathjax" CACHE STRING "MathJax library location.") + +SET(LEMON_DOC_LIBSTDC++_URL + "http://gcc.gnu.org/onlinedocs/gcc-4.7.3/libstdc++/api" + CACHE STRING "GCC libstdc++ doxygen doc url.") + CONFIGURE_FILE( ${PROJECT_SOURCE_DIR}/doc/Doxyfile.in @@ -17,28 +24,38 @@ @ONLY ) +# Copy doc from source (if exists) +IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/html AND + NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/html/index.html) + MESSAGE(STATUS "Copy doc from source tree") + EXECUTE_PROCESS( + COMMAND cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/html ${CMAKE_CURRENT_BINARY_DIR}/html + ) +ENDIF() + 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 COMMAND ${CMAKE_COMMAND} -E remove_directory gen-images COMMAND ${CMAKE_COMMAND} -E make_directory gen-images - COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/bipartite_matching.png ${CMAKE_CURRENT_SOURCE_DIR}/images/bipartite_matching.eps - COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r18 -sOutputFile=gen-images/bipartite_partitions.png ${CMAKE_CURRENT_SOURCE_DIR}/images/bipartite_partitions.eps - 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 ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r20 -sOutputFile=gen-images/grid_graph.png ${CMAKE_CURRENT_SOURCE_DIR}/images/grid_graph.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r32 -sOutputFile=gen-images/adaptors2.png ${CMAKE_CURRENT_SOURCE_DIR}/images/adaptors2.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r32 -sOutputFile=gen-images/connected_components.png ${CMAKE_CURRENT_SOURCE_DIR}/images/connected_components.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r32 -sOutputFile=gen-images/strongly_connected_components.png ${CMAKE_CURRENT_SOURCE_DIR}/images/strongly_connected_components.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r32 -sOutputFile=gen-images/node_biconnected_components.png ${CMAKE_CURRENT_SOURCE_DIR}/images/node_biconnected_components.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r32 -sOutputFile=gen-images/edge_biconnected_components.png ${CMAKE_CURRENT_SOURCE_DIR}/images/edge_biconnected_components.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r32 -sOutputFile=gen-images/bipartite_partitions.png ${CMAKE_CURRENT_SOURCE_DIR}/images/bipartite_partitions.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r24 -sOutputFile=gen-images/matching.png ${CMAKE_CURRENT_SOURCE_DIR}/images/matching.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r24 -sOutputFile=gen-images/bipartite_matching.png ${CMAKE_CURRENT_SOURCE_DIR}/images/bipartite_matching.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r40 -sOutputFile=gen-images/planar.png ${CMAKE_CURRENT_SOURCE_DIR}/images/planar.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r24 -sOutputFile=gen-images/tsp.png ${CMAKE_CURRENT_SOURCE_DIR}/images/tsp.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r8 -sOutputFile=gen-images/nodeshape_0.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_0.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r8 -sOutputFile=gen-images/nodeshape_1.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_1.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r8 -sOutputFile=gen-images/nodeshape_2.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_2.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r8 -sOutputFile=gen-images/nodeshape_3.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_3.eps + COMMAND ${GHOSTSCRIPT_EXECUTABLE} ${GHOSTSCRIPT_OPTIONS} -r8 -sOutputFile=gen-images/nodeshape_4.png ${CMAKE_CURRENT_SOURCE_DIR}/images/nodeshape_4.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} ) @@ -63,12 +80,7 @@ IF(WGET_FOUND) ADD_CUSTOM_TARGET(update-external-tags - COMMAND ${CMAKE_COMMAND} -E make_directory dl - # COMMAND ${CMAKE_COMMAND} -E copy libstdc++.tag dl - COMMAND ${WGET_EXECUTABLE} wget -P dl -N libstdc++.tag.tmp http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/libstdc++.tag - COMMAND ${CMAKE_COMMAND} -E rename dl/libstdc++.tag libstdc++.tag - COMMAND ${CMAKE_COMMAND} -E remove dl/libstdc++.tag - COMMAND ${CMAKE_COMMAND} -E remove_directory dl + COMMAND ${WGET_EXECUTABLE} -N ${LEMON_DOC_LIBSTDC++_URL}/libstdc++.tag WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) ENDIF() diff -r cd72eae05bdf -r 3c00344f49c9 doc/Doxyfile.in --- a/doc/Doxyfile.in Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/Doxyfile.in Wed Oct 17 19:14:07 2018 +0200 @@ -77,6 +77,7 @@ SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = "@abs_top_srcdir@/doc/DoxygenLayout.xml" +CITE_BIB_FILES = "@abs_top_srcdir@/doc/references.bib" #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- @@ -95,10 +96,10 @@ "@abs_top_srcdir@/lemon/bits" \ "@abs_top_srcdir@/lemon/concepts" \ "@abs_top_srcdir@/demo" \ + "@abs_top_srcdir@/contrib" \ "@abs_top_srcdir@/tools" \ "@abs_top_srcdir@/test/test_tools.h" \ - "@abs_top_builddir@/doc/mainpage.dox" \ - "@abs_top_builddir@/doc/references.dox" + "@abs_top_builddir@/doc/mainpage.dox" INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.h \ *.cc \ @@ -181,8 +182,8 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES -USE_MATHJAX = NO -MATHJAX_RELPATH = http://www.mathjax.org/mathjax +USE_MATHJAX = @LEMON_DOC_USE_MATHJAX@ +MATHJAX_RELPATH = @LEMON_DOC_MATHJAX_RELPATH@ SEARCHENGINE = YES SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- @@ -252,7 +253,7 @@ #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- -TAGFILES = "@abs_top_builddir@/doc/libstdc++.tag = http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/ " +TAGFILES = "@abs_top_builddir@/doc/libstdc++.tag = @LEMON_DOC_LIBSTDC++_URL@" GENERATE_TAGFILE = html/lemon.tag ALLEXTERNALS = NO EXTERNAL_GROUPS = NO diff -r cd72eae05bdf -r 3c00344f49c9 doc/DoxygenLayout.xml --- a/doc/DoxygenLayout.xml Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/DoxygenLayout.xml Wed Oct 17 19:14:07 2018 +0200 @@ -17,7 +17,6 @@ - diff -r cd72eae05bdf -r 3c00344f49c9 doc/Makefile.am --- a/doc/Makefile.am Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -EXTRA_DIST += \ - doc/Doxyfile.in \ - doc/DoxygenLayout.xml \ - doc/coding_style.dox \ - doc/dirs.dox \ - doc/groups.dox \ - doc/lgf.dox \ - doc/license.dox \ - doc/mainpage.dox \ - doc/migration.dox \ - doc/min_cost_flow.dox \ - doc/named-param.dox \ - doc/namespaces.dox \ - doc/references.bib \ - doc/template.h \ - doc/html \ - doc/CMakeLists.txt - -DOC_EPS_IMAGES18 = \ - grid_graph.eps \ - nodeshape_0.eps \ - nodeshape_1.eps \ - nodeshape_2.eps \ - nodeshape_3.eps \ - nodeshape_4.eps - -DOC_EPS_IMAGES27 = \ - bipartite_matching.eps \ - 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 = \ - $(DOC_EPS_IMAGES18) \ - $(DOC_EPS_IMAGES27) - -DOC_PNG_IMAGES = \ - $(DOC_EPS_IMAGES:%.eps=doc/gen-images/%.png) - -EXTRA_DIST += $(DOC_EPS_IMAGES:%=doc/images/%) - -doc/html: - $(MAKE) $(AM_MAKEFLAGS) html - -GS_COMMAND=gs -dNOPAUSE -dBATCH -q -dEPSCrop -dTextAlphaBits=4 -dGraphicsAlphaBits=4 - -$(DOC_EPS_IMAGES18:%.eps=doc/gen-images/%.png): doc/gen-images/%.png: doc/images/%.eps - -mkdir doc/gen-images - if test ${gs_found} = yes; then \ - $(GS_COMMAND) -sDEVICE=pngalpha -r18 -sOutputFile=$@ $<; \ - else \ - echo; \ - echo "Ghostscript not found."; \ - echo; \ - exit 1; \ - fi - -$(DOC_EPS_IMAGES27:%.eps=doc/gen-images/%.png): doc/gen-images/%.png: doc/images/%.eps - -mkdir doc/gen-images - if test ${gs_found} = yes; then \ - $(GS_COMMAND) -sDEVICE=pngalpha -r27 -sOutputFile=$@ $<; \ - else \ - echo; \ - echo "Ghostscript not found."; \ - echo; \ - exit 1; \ - fi - -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; \ - cd ..; \ - else \ - echo; \ - echo "Doxygen not found."; \ - echo; \ - exit 1; \ - fi - -clean-local: - -rm -rf doc/html - -rm -f doc/doxygen.log - -rm -f $(DOC_PNG_IMAGES) - -rm -rf doc/gen-images - -update-external-tags: - wget -O doc/libstdc++.tag.tmp http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/libstdc++.tag && \ - mv doc/libstdc++.tag.tmp doc/libstdc++.tag || \ - rm doc/libstdc++.tag.tmp - -install-html-local: doc/html - @$(NORMAL_INSTALL) - $(mkinstalldirs) $(DESTDIR)$(htmldir)/html - for p in doc/html/*.{html,css,png,map,gif,tag} ; do \ - f="`echo $$p | sed -e 's|^.*/||'`"; \ - echo " $(INSTALL_DATA) $$p $(DESTDIR)$(htmldir)/html/$$f"; \ - $(INSTALL_DATA) $$p $(DESTDIR)$(htmldir)/html/$$f; \ - done - -uninstall-local: - @$(NORMAL_UNINSTALL) - for p in doc/html/*.{html,css,png,map,gif,tag} ; do \ - f="`echo $$p | sed -e 's|^.*/||'`"; \ - echo " rm -f $(DESTDIR)$(htmldir)/html/$$f"; \ - rm -f $(DESTDIR)$(htmldir)/html/$$f; \ - done - -.PHONY: update-external-tags diff -r cd72eae05bdf -r 3c00344f49c9 doc/coding_style.dox --- a/doc/coding_style.dox Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/coding_style.dox Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -98,10 +98,10 @@ \subsection pri-loc-var Private member variables -Private member variables should start with underscore +Private member variables should start with underscore. \code -_start_with_underscores +_start_with_underscore \endcode \subsection cs-excep Exceptions diff -r cd72eae05bdf -r 3c00344f49c9 doc/dirs.dox --- a/doc/dirs.dox Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/dirs.dox Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -33,6 +33,19 @@ */ /** +\dir contrib +\brief Directory for user contributed source codes. + +You can place your own C++ code using LEMON into this directory, which +will compile to an executable along with LEMON when you build the +library. This is probably the easiest way of compiling short to medium +codes, for this does require neither a LEMON installed system-wide nor +adding several paths to the compiler. + +Please have a look at contrib/CMakeLists.txt for +instruction on how to add your own files into the build process. */ + +/** \dir test \brief Test programs. diff -r cd72eae05bdf -r 3c00344f49c9 doc/groups.dox --- a/doc/groups.dox Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/groups.dox Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -112,6 +112,14 @@ obtained. For other examples, the interested user is referred to the detailed documentation of particular adaptors. +Since the adaptor classes conform to the \ref graph_concepts "graph concepts", +an adaptor can even be applied to another one. +The following image illustrates a situation when a \ref SubDigraph adaptor +is applied on a digraph and \ref Undirector is applied on the subgraph. + +\image html adaptors2.png +\image latex adaptors2.eps "Using graph adaptors" width=\textwidth + The behavior of graph adaptors can be very different. Some of them keep capabilities of the original graph while in other cases this would be meaningless. This means that the concepts that they meet depend @@ -309,7 +317,7 @@ This group contains the common graph search algorithms, namely \e breadth-first \e search (BFS) and \e depth-first \e search (DFS) -\ref clrs01algorithms. +\cite clrs01algorithms. */ /** @@ -318,7 +326,7 @@ \brief Algorithms for finding shortest paths. This group contains the algorithms for finding shortest paths in digraphs -\ref clrs01algorithms. +\cite clrs01algorithms. - \ref Dijkstra algorithm for finding shortest paths from a source node when all arc lengths are non-negative. @@ -340,7 +348,7 @@ \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. +trees and arborescences \cite clrs01algorithms. */ /** @@ -349,7 +357,7 @@ \brief Algorithms for finding maximum flows. This group contains the algorithms for finding maximum flows and -feasible circulations \ref clrs01algorithms, \ref amo93networkflows. +feasible circulations \cite clrs01algorithms, \cite 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$ @@ -365,13 +373,13 @@ LEMON contains several algorithms for solving maximum flow problems: - \ref EdmondsKarp Edmonds-Karp algorithm - \ref edmondskarp72theoretical. + \cite edmondskarp72theoretical. - \ref Preflow Goldberg-Tarjan's preflow push-relabel algorithm - \ref goldberg88newapproach. + \cite goldberg88newapproach. - \ref DinitzSleatorTarjan Dinitz's blocking flow algorithm with dynamic trees - \ref dinic70algorithm, \ref sleator83dynamic. + \cite dinic70algorithm, \cite sleator83dynamic. - \ref GoldbergTarjan !Preflow push-relabel algorithm with dynamic trees - \ref goldberg88newapproach, \ref sleator83dynamic. + \cite goldberg88newapproach, \cite sleator83dynamic. In most cases the \ref Preflow algorithm provides the fastest method for computing a maximum flow. All implementations @@ -391,25 +399,41 @@ \brief Algorithms for finding minimum cost flows and circulations. This group contains the algorithms for finding minimum cost flows and -circulations \ref amo93networkflows. For more information about this -problem and its dual solution, see \ref min_cost_flow +circulations \cite 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 dantzig63linearprog, \ref kellyoneill91netsimplex. + pivot strategies \cite dantzig63linearprog, \cite kellyoneill91netsimplex. - \ref CostScaling Cost Scaling algorithm based on push/augment and - relabel operations \ref goldberg90approximation, \ref goldberg97efficient, - \ref bunnagel98efficient. + relabel operations \cite goldberg90approximation, \cite goldberg97efficient, + \cite bunnagel98efficient. - \ref CapacityScaling Capacity Scaling algorithm based on the successive - shortest path method \ref edmondskarp72theoretical. + shortest path method \cite edmondskarp72theoretical. - \ref CycleCanceling Cycle-Canceling algorithms, two of which are - strongly polynomial \ref klein67primal, \ref goldberg89cyclecanceling. + strongly polynomial \cite klein67primal, \cite goldberg89cyclecanceling. -In general NetworkSimplex is the most efficient implementation, -but in special cases other algorithms could be faster. +In general, \ref NetworkSimplex and \ref CostScaling are the most efficient +implementations. +\ref NetworkSimplex is usually the fastest on relatively small graphs (up to +several thousands of nodes) and on dense graphs, while \ref CostScaling is +typically more efficient on large graphs (e.g. hundreds of thousands of +nodes or above), especially if they are sparse. +However, other algorithms could be faster in special cases. For example, if the total supply and/or capacities are rather small, -CapacityScaling is usually the fastest algorithm (without effective scaling). +\ref CapacityScaling is usually the fastest algorithm +(without effective scaling). + +These classes are intended to be used with integer-valued input data +(capacities, supply values, and costs), except for \ref CapacityScaling, +which is capable of handling real-valued arc costs (other numerical +data are required to be integer). + +For more details about these implementations and for a comprehensive +experimental study, see the paper \cite KiralyKovacs12MCF. +It also compares these codes to other publicly available +minimum cost flow solvers. */ /** @@ -448,7 +472,7 @@ \brief Algorithms for finding minimum mean cycles. This group contains the algorithms for finding minimum mean cycles -\ref clrs01algorithms, \ref amo93networkflows. +\cite amo93networkflows, \cite karp78characterization. The \e minimum \e mean \e cycle \e problem is to find a directed cycle of minimum mean length (cost) in a digraph. @@ -464,19 +488,17 @@ function. LEMON contains three algorithms for solving the minimum mean cycle problem: -- \ref KarpMmc Karp's original algorithm \ref amo93networkflows, - \ref dasdan98minmeancycle. +- \ref KarpMmc Karp's original algorithm \cite karp78characterization. - \ref HartmannOrlinMmc Hartmann-Orlin's algorithm, which is an improved - version of Karp's algorithm \ref dasdan98minmeancycle. + version of Karp's algorithm \cite hartmann93finding. - \ref HowardMmc Howard's policy iteration algorithm - \ref dasdan98minmeancycle. + \cite dasdan98minmeancycle, \cite dasdan04experimental. -In practice, the \ref HowardMmc "Howard" algorithm proved to be by far the +In practice, the \ref HowardMmc "Howard" algorithm turned out to be by far the most efficient one, though the best known theoretical bound on its running time is exponential. Both \ref KarpMmc "Karp" and \ref HartmannOrlinMmc "Hartmann-Orlin" 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. +run in time O(nm) and use space O(n2+m). */ /** @@ -539,7 +561,7 @@ */ /** -@defgroup planar Planarity Embedding and Drawing +@defgroup planar Planar Embedding and Drawing @ingroup algs \brief Algorithms for planarity checking, embedding and drawing @@ -551,12 +573,52 @@ */ /** -@defgroup approx Approximation Algorithms +@defgroup tsp Traveling Salesman Problem +@ingroup algs +\brief Algorithms for the symmetric traveling salesman problem + +This group contains basic heuristic algorithms for the the symmetric +\e traveling \e salesman \e problem (TSP). +Given an \ref FullGraph "undirected full graph" with a cost map on its edges, +the problem is to find a shortest possible tour that visits each node exactly +once (i.e. the minimum cost Hamiltonian cycle). + +These TSP algorithms are intended to be used with a \e metric \e cost +\e function, i.e. the edge costs should satisfy the triangle inequality. +Otherwise the algorithms could yield worse results. + +LEMON provides five well-known heuristics for solving symmetric TSP: + - \ref NearestNeighborTsp Neareast neighbor algorithm + - \ref GreedyTsp Greedy algorithm + - \ref InsertionTsp Insertion heuristic (with four selection methods) + - \ref ChristofidesTsp Christofides algorithm + - \ref Opt2Tsp 2-opt algorithm + +\ref NearestNeighborTsp, \ref GreedyTsp, and \ref InsertionTsp are the fastest +solution methods. Furthermore, \ref InsertionTsp is usually quite effective. + +\ref ChristofidesTsp is somewhat slower, but it has the best guaranteed +approximation factor: 3/2. + +\ref Opt2Tsp usually provides the best results in practice, but +it is the slowest method. It can also be used to improve given tours, +for example, the results of other algorithms. + +\image html tsp.png +\image latex tsp.eps "Traveling salesman problem" width=\textwidth +*/ + +/** +@defgroup approx_algs Approximation Algorithms @ingroup algs \brief Approximation algorithms. This group contains the approximation and heuristic algorithms implemented in LEMON. + +Maximum Clique Problem + - \ref GrossoLocatelliPullanMc An efficient heuristic algorithm of + Grosso, Locatelli, and Pullan. */ /** @@ -586,8 +648,8 @@ 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. +The currently supported solvers are \cite glpk, \cite clp, \cite cbc, +\cite cplex, \cite soplex. */ /** @@ -674,6 +736,8 @@ This group contains general \c EPS drawing methods and special graph exporting tools. + +\image html graph_to_eps.png */ /** diff -r cd72eae05bdf -r 3c00344f49c9 doc/images/adaptors1.eps --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/images/adaptors1.eps Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,303 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: adaptors1.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5 +%%CreationDate: Sun Feb 21 18:51:21 2010 +%%For: Peter@KOVACSPETER (Péter,U-KOVACSPETER\Peter,S-1-5-21-1774138250-1299389707-1938712334-1001) +%%BoundingBox: 0 0 787 372 +%Magnification: 1.0000 +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +newpath 0 372 moveto 0 0 lineto 787 0 lineto 787 372 lineto closepath clip newpath +-14.2 385.4 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit +0 slj 0 slc + 0.06299 0.06299 sc +% +% Fig objects follow +% +% +% here starts figure with depth 60 +% Polyline +0 slj +0 slc +15.000 slw +gs clippath +6319 5229 m 6442 5564 l 6527 5533 l 6403 5198 l 6403 5198 l 6424 5383 l 6319 5229 l cp +eoclip +n 5850 3825 m + 6480 5535 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 6319 5229 m 6424 5383 l 6403 5198 l 6319 5229 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +5417 4044 m 5746 3905 l 5711 3822 l 5382 3961 l 5382 3961 l 5566 3933 l 5417 4044 l cp +eoclip +n 1575 5625 m + 5715 3870 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 5417 4044 m 5566 3933 l 5382 3961 l 5417 4044 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +3897 3780 m 3540 3780 l 3540 3870 l 3897 3870 l 3897 3870 l 3717 3825 l 3897 3780 l cp +eoclip +n 5625 3825 m + 3555 3825 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 3897 3780 m 3717 3825 l 3897 3870 l 3897 3780 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +3075 4188 m 3327 3936 l 3263 3872 l 3011 4124 l 3011 4124 l 3171 4029 l 3075 4188 l cp +eoclip +n 1575 5625 m + 3285 3915 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 3075 4188 m 3171 4029 l 3011 4124 l 3075 4188 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +3528 2520 m 3885 2520 l 3885 2430 l 3528 2430 l 3528 2430 l 3708 2475 l 3528 2520 l cp +eoclip +n 1800 2475 m + 3870 2475 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 3528 2520 m 3708 2475 l 3528 2430 l 3528 2520 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +4304 2156 m 4052 2408 l 4116 2472 l 4368 2220 l 4368 2220 l 4209 2316 l 4304 2156 l cp +eoclip +n 5850 675 m + 4095 2430 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 4304 2156 m 4209 2316 l 4368 2220 l 4304 2156 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +6319 2079 m 6442 2414 l 6527 2383 l 6403 2048 l 6403 2048 l 6424 2233 l 6319 2079 l cp +eoclip +n 5850 675 m + 6480 2385 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 6319 2079 m 6424 2233 l 6403 2048 l 6319 2079 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +5417 894 m 5746 755 l 5711 672 l 5382 811 l 5382 811 l 5566 783 l 5417 894 l cp +eoclip +n 1575 2475 m + 5715 720 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 5417 894 m 5566 783 l 5382 811 l 5417 894 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +3528 5670 m 3885 5670 l 3885 5580 l 3528 5580 l 3528 5580 l 3708 5625 l 3528 5670 l cp +eoclip +n 1800 5625 m + 3870 5625 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 3528 5670 m 3708 5625 l 3528 5580 l 3528 5670 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +4572 5580 m 4215 5580 l 4215 5670 l 4572 5670 l 4572 5670 l 4392 5625 l 4572 5580 l cp +eoclip +n 6300 5625 m + 4230 5625 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 4572 5580 m 4392 5625 l 4572 5670 l 4572 5580 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +4304 5306 m 4052 5558 l 4116 5622 l 4368 5370 l 4368 5370 l 4209 5466 l 4304 5306 l cp +eoclip +n 5850 3825 m + 4095 5580 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 4304 5306 m 4209 5466 l 4368 5370 l 4304 5306 l cp gs 0.00 setgray ef gr col0 s +% here ends figure; +% +% here starts figure with depth 50 +% Ellipse +15.000 slw +n 3375 3825 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 5850 3825 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Polyline +0 slj +0 slc +n 247 2947 m 2947 247 l 9697 247 l 6997 2947 l + 247 2947 l cp gs col0 s gr +% Polyline +n 247 6097 m 2947 3397 l 9697 3397 l 6997 6097 l + 247 6097 l cp gs col0 s gr +% Ellipse +n 1575 2475 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 4050 2475 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 6525 2475 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 5850 675 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 1575 5625 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 4050 5625 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 6525 5625 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% here ends figure; +% +% here starts figure with depth 40 +/Helvetica ff 480.00 scf sf +8280 2610 m +gs 1 -1 sc (SubDigraph adaptor) col0 sh gr +% Polyline +0 slj +0 slc +7.500 slw + [15 45] 45 sd +n 4050 2610 m + 4050 5625 l gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 5850 810 m + 5850 3825 l gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 6525 2610 m + 6525 5625 l gs col0 s gr [] 0 sd +/Helvetica ff 480.00 scf sf +8280 5760 m +gs 1 -1 sc (Original digraph) col0 sh gr +% Polyline + [15 45] 45 sd +n 1575 2610 m + 1575 5625 l gs col0 s gr [] 0 sd +% here ends figure; +$F2psEnd +rs +showpage +%%Trailer +%EOF diff -r cd72eae05bdf -r 3c00344f49c9 doc/images/adaptors2.eps --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/images/adaptors2.eps Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,349 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: adaptors2.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5 +%%CreationDate: Sun Feb 21 18:51:31 2010 +%%For: Peter@KOVACSPETER (Péter,U-KOVACSPETER\Peter,S-1-5-21-1774138250-1299389707-1938712334-1001) +%%BoundingBox: 0 0 787 570 +%Magnification: 1.0000 +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +newpath 0 570 moveto 0 0 lineto 787 0 lineto 787 570 lineto closepath clip newpath +-14.2 583.9 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit +0 slj 0 slc + 0.06299 0.06299 sc +% +% Fig objects follow +% +% +% here starts figure with depth 60 +% Polyline +0 slj +0 slc +15.000 slw +gs clippath +5417 4044 m 5746 3905 l 5711 3822 l 5382 3961 l 5382 3961 l 5566 3933 l 5417 4044 l cp +eoclip +n 1575 5625 m + 5715 3870 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 5417 4044 m 5566 3933 l 5382 3961 l 5417 4044 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +5417 7194 m 5746 7055 l 5711 6972 l 5382 7111 l 5382 7111 l 5566 7083 l 5417 7194 l cp +eoclip +n 1575 8775 m + 5715 7020 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 5417 7194 m 5566 7083 l 5382 7111 l 5417 7194 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +6319 8379 m 6442 8714 l 6527 8683 l 6403 8348 l 6403 8348 l 6424 8533 l 6319 8379 l cp +eoclip +n 5850 6975 m + 6480 8685 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 6319 8379 m 6424 8533 l 6403 8348 l 6319 8379 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +4304 8456 m 4052 8708 l 4116 8772 l 4368 8520 l 4368 8520 l 4209 8616 l 4304 8456 l cp +eoclip +n 5850 6975 m + 4095 8730 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 4304 8456 m 4209 8616 l 4368 8520 l 4304 8456 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +4572 8730 m 4215 8730 l 4215 8820 l 4572 8820 l 4572 8820 l 4392 8775 l 4572 8730 l cp +eoclip +n 6300 8775 m + 4230 8775 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 4572 8730 m 4392 8775 l 4572 8820 l 4572 8730 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +3528 8820 m 3885 8820 l 3885 8730 l 3528 8730 l 3528 8730 l 3708 8775 l 3528 8820 l cp +eoclip +n 1800 8775 m + 3870 8775 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 3528 8820 m 3708 8775 l 3528 8730 l 3528 8820 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +n 1800 2475 m + 3870 2475 l gs col0 s gr +% Polyline +n 1575 2475 m + 5715 720 l gs col0 s gr +% Polyline +n 5850 675 m + 4095 2430 l gs col0 s gr +% Polyline +n 5850 675 m + 6480 2385 l gs col0 s gr +% Polyline +gs clippath +3075 7338 m 3327 7086 l 3263 7022 l 3011 7274 l 3011 7274 l 3171 7179 l 3075 7338 l cp +eoclip +n 1575 8775 m + 3285 7065 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 3075 7338 m 3171 7179 l 3011 7274 l 3075 7338 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +3528 5670 m 3885 5670 l 3885 5580 l 3528 5580 l 3528 5580 l 3708 5625 l 3528 5670 l cp +eoclip +n 1800 5625 m + 3870 5625 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 3528 5670 m 3708 5625 l 3528 5580 l 3528 5670 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +4304 5306 m 4052 5558 l 4116 5622 l 4368 5370 l 4368 5370 l 4209 5466 l 4304 5306 l cp +eoclip +n 5850 3825 m + 4095 5580 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 4304 5306 m 4209 5466 l 4368 5370 l 4304 5306 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +6319 5229 m 6442 5564 l 6527 5533 l 6403 5198 l 6403 5198 l 6424 5383 l 6319 5229 l cp +eoclip +n 5850 3825 m + 6480 5535 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 6319 5229 m 6424 5383 l 6403 5198 l 6319 5229 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +3897 6930 m 3540 6930 l 3540 7020 l 3897 7020 l 3897 7020 l 3717 6975 l 3897 6930 l cp +eoclip +n 5625 6975 m + 3555 6975 l gs col0 s gr gr + +% arrowhead +75.000 slw +n 3897 6930 m 3717 6975 l 3897 7020 l 3897 6930 l cp gs 0.00 setgray ef gr col0 s +% here ends figure; +% +% here starts figure with depth 50 +% Polyline +0 slj +0 slc +15.000 slw +n 247 6097 m 2947 3397 l 9697 3397 l 6997 6097 l + 247 6097 l cp gs col0 s gr +% Polyline +n 247 9247 m 2947 6547 l 9697 6547 l 6997 9247 l + 247 9247 l cp gs col0 s gr +% Ellipse +n 4050 2475 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 6525 2475 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 1575 2475 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 5850 675 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 1575 5625 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 4050 5625 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 6525 5625 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 5850 3825 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 1575 8775 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 4050 8775 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 3375 6975 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 6525 8775 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Ellipse +n 5850 6975 225 112 0 360 DrawEllipse gs 1.00 setgray ef gr gs col0 s gr + +% Polyline +n 247 2947 m 2947 247 l 9697 247 l 6997 2947 l + 247 2947 l cp gs col0 s gr +% here ends figure; +% +% here starts figure with depth 40 +/Helvetica ff 480.00 scf sf +8280 8910 m +gs 1 -1 sc (Original digraph) col0 sh gr +% Polyline +0 slj +0 slc +7.500 slw + [15 45] 45 sd +n 5850 810 m + 5850 3825 l gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 6525 2610 m + 6525 5625 l gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 4050 2610 m + 4050 5625 l gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 1575 2610 m + 1575 5625 l gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 5850 3960 m + 5850 6975 l gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 6525 5760 m + 6525 8775 l gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 4050 5760 m + 4050 8775 l gs col0 s gr [] 0 sd +/Helvetica ff 480.00 scf sf +8280 2610 m +gs 1 -1 sc (Undirector adaptor) col0 sh gr +/Helvetica ff 480.00 scf sf +8280 5760 m +gs 1 -1 sc (SubDigraph adaptor) col0 sh gr +% Polyline + [15 45] 45 sd +n 1575 5760 m + 1575 8775 l gs col0 s gr [] 0 sd +% here ends figure; +$F2psEnd +rs +showpage +%%Trailer +%EOF diff -r cd72eae05bdf -r 3c00344f49c9 doc/images/bipartite_partitions.eps --- a/doc/images/bipartite_partitions.eps Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/images/bipartite_partitions.eps Wed Oct 17 19:14:07 2018 +0200 @@ -1,6 +1,6 @@ %!PS-Adobe-2.0 EPSF-2.0 %%Creator: LEMON, graphToEps() -%%CreationDate: Tue Nov 15 16:51:43 2005 +%%CreationDate: Fri Mar 8 00:18:43 2013 %%BoundingBox: 0 0 842 596 %%EndComments /lb { setlinewidth setrgbcolor newpath moveto @@ -53,62 +53,62 @@ 1197.47 -613.138 translate %Edges: gsave -513.857 -446.322 296.569 -487.43 79.2808 -528.539 0 0 0 2 lb -513.857 -446.322 575.52 -315.655 637.183 -184.989 0 0 0 2 lb -393.468 566.711 494.771 434.577 596.074 302.442 0 0 0 2 lb -393.468 566.711 155.625 579.925 -82.2171 593.138 0 0 0 2 lb -393.468 566.711 251.056 450.726 108.644 334.741 0 0 0 2 lb -869.153 52.8539 732.613 177.648 596.074 302.442 0 0 0 2 lb -869.153 52.8539 753.168 -66.0676 637.183 -184.989 0 0 0 2 lb --82.2171 593.138 -91.0261 346.487 -99.8351 99.8351 0 0 0 2 lb --663.61 546.157 -753.168 394.936 -842.726 243.715 0 0 0 2 lb --663.61 546.157 -574.052 437.513 -484.494 328.869 0 0 0 2 lb --1077.63 161.498 -960.178 202.606 -842.726 243.715 0 0 0 2 lb --1077.63 161.498 -968.987 66.0674 -860.344 -29.3633 0 0 0 2 lb --1177.47 -234.906 -1029.18 -381.722 -880.898 -528.539 0 0 0 2 lb --1177.47 -234.906 -1018.91 -132.135 -860.344 -29.3633 0 0 0 2 lb --880.898 -528.539 -744.359 -387.595 -607.82 -246.651 0 0 0 2 lb --499.175 -499.175 -355.295 -475.685 -211.415 -452.194 0 0 0 2 lb --499.175 -499.175 -553.498 -372.913 -607.82 -246.651 0 0 0 2 lb --499.175 -499.175 -386.587 -315.087 -274 -131 0 0 0 2 lb -79.2808 -528.539 -66.0671 -490.366 -211.415 -452.194 0 0 0 2 lb -637.183 -184.989 421.363 -253.993 205.543 -322.996 0 0 0 2 lb -205.543 -322.996 162.966 -226.097 120.389 -129.198 0 0 0 2 lb -399.34 88.0898 259.865 -20.5541 120.389 -129.198 0 0 0 2 lb -399.34 88.0898 253.992 211.415 108.644 334.741 0 0 0 2 lb --842.726 243.715 -471.281 171.775 -99.8351 99.8351 0 0 0 2 lb --842.726 243.715 -558.363 56.3575 -274 -131 0 0 0 2 lb --860.344 -29.3633 -734.082 -138.007 -607.82 -246.651 0 0 0 2 lb --211.415 -452.194 -45.513 -290.696 120.389 -129.198 0 0 0 2 lb --99.8351 99.8351 4.40445 217.288 108.644 334.741 0 0 0 2 lb --99.8351 99.8351 -292.165 214.352 -484.494 328.869 0 0 0 2 lb -120.389 -129.198 -76.8055 -130.099 -274 -131 0 0 0 2 lb +513.857 -446.322 296.569 -487.43 79.2808 -528.539 0 0 0 7.00153 lb +513.857 -446.322 575.52 -315.656 637.183 -184.989 0 0 0 7.00153 lb +393.468 566.711 494.771 434.577 596.074 302.442 0 0 0 7.00153 lb +393.468 566.711 155.625 579.925 -82.2171 593.138 0 0 0 7.00153 lb +393.468 566.711 251.056 450.726 108.644 334.741 0 0 0 7.00153 lb +869.153 52.8539 732.613 177.648 596.074 302.442 0 0 0 7.00153 lb +869.153 52.8539 753.168 -66.0676 637.183 -184.989 0 0 0 7.00153 lb +-82.2171 593.138 -91.0261 346.487 -99.8351 99.8351 0 0 0 7.00153 lb +-663.61 546.157 -753.168 394.936 -842.726 243.715 0 0 0 7.00153 lb +-663.61 546.157 -574.052 437.513 -484.494 328.869 0 0 0 7.00153 lb +-1077.63 161.498 -960.178 202.606 -842.726 243.715 0 0 0 7.00153 lb +-1077.63 161.498 -968.987 66.0674 -860.344 -29.3633 0 0 0 7.00153 lb +-1177.47 -234.906 -1029.18 -381.722 -880.898 -528.539 0 0 0 7.00153 lb +-1177.47 -234.906 -1018.91 -132.135 -860.344 -29.3633 0 0 0 7.00153 lb +-880.898 -528.539 -744.359 -387.595 -607.82 -246.651 0 0 0 7.00153 lb +-499.175 -499.175 -355.295 -475.685 -211.415 -452.194 0 0 0 7.00153 lb +-499.175 -499.175 -553.498 -372.913 -607.82 -246.651 0 0 0 7.00153 lb +-499.175 -499.175 -386.587 -315.087 -274 -131 0 0 0 7.00153 lb +79.2808 -528.539 -66.0671 -490.366 -211.415 -452.194 0 0 0 7.00153 lb +637.183 -184.989 421.363 -253.993 205.543 -322.996 0 0 0 7.00153 lb +205.543 -322.996 162.966 -226.097 120.389 -129.198 0 0 0 7.00153 lb +399.34 88.0898 259.865 -20.5541 120.389 -129.198 0 0 0 7.00153 lb +399.34 88.0898 253.992 211.415 108.644 334.741 0 0 0 7.00153 lb +-842.726 243.715 -471.281 171.775 -99.8351 99.8351 0 0 0 7.00153 lb +-842.726 243.715 -558.363 56.3575 -274 -131 0 0 0 7.00153 lb +-860.344 -29.3633 -734.082 -138.007 -607.82 -246.651 0 0 0 7.00153 lb +-211.415 -452.194 -45.513 -290.696 120.389 -129.198 0 0 0 7.00153 lb +-99.8351 99.8351 4.40445 217.288 108.644 334.741 0 0 0 7.00153 lb +-99.8351 99.8351 -292.165 214.352 -484.494 328.869 0 0 0 7.00153 lb +120.389 -129.198 -76.8055 -130.099 -274 -131 0 0 0 7.00153 lb grestore %Nodes: gsave --274 -131 20 1 0 0 nc --607.82 -246.651 20 1 0 0 nc --484.494 328.869 20 0 0 1 nc -108.644 334.741 20 0 0 1 nc -120.389 -129.198 20 0 0 1 nc --99.8351 99.8351 20 1 0 0 nc --211.415 -452.194 20 1 0 0 nc --860.344 -29.3633 20 0 0 1 nc --842.726 243.715 20 0 0 1 nc -399.34 88.0898 20 1 0 0 nc -205.543 -322.996 20 1 0 0 nc -637.183 -184.989 20 0 0 1 nc -79.2808 -528.539 20 0 0 1 nc --499.175 -499.175 20 0 0 1 nc --880.898 -528.539 20 0 0 1 nc --1177.47 -234.906 20 1 0 0 nc --1077.63 161.498 20 1 0 0 nc --663.61 546.157 20 1 0 0 nc --82.2171 593.138 20 0 0 1 nc -596.074 302.442 20 0 0 1 nc -869.153 52.8539 20 1 0 0 nc -393.468 566.711 20 1 0 0 nc -513.857 -446.322 20 1 0 0 nc +-274 -131 23.3384 1 0 0 nc +-607.82 -246.651 23.3384 1 0 0 nc +-484.494 328.869 23.3384 0 0 1 nc +108.644 334.741 23.3384 0 0 1 nc +120.389 -129.198 23.3384 0 0 1 nc +-99.8351 99.8351 23.3384 1 0 0 nc +-211.415 -452.194 23.3384 1 0 0 nc +-860.344 -29.3633 23.3384 0 0 1 nc +-842.726 243.715 23.3384 0 0 1 nc +399.34 88.0898 23.3384 1 0 0 nc +205.543 -322.996 23.3384 1 0 0 nc +637.183 -184.989 23.3384 0 0 1 nc +79.2808 -528.539 23.3384 0 0 1 nc +-499.175 -499.175 23.3384 0 0 1 nc +-880.898 -528.539 23.3384 0 0 1 nc +-1177.47 -234.906 23.3384 1 0 0 nc +-1077.63 161.498 23.3384 1 0 0 nc +-663.61 546.157 23.3384 1 0 0 nc +-82.2171 593.138 23.3384 0 0 1 nc +596.074 302.442 23.3384 0 0 1 nc +869.153 52.8539 23.3384 1 0 0 nc +393.468 566.711 23.3384 1 0 0 nc +513.857 -446.322 23.3384 1 0 0 nc grestore grestore showpage diff -r cd72eae05bdf -r 3c00344f49c9 doc/images/connected_components.eps --- a/doc/images/connected_components.eps Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/images/connected_components.eps Wed Oct 17 19:14:07 2018 +0200 @@ -1,6 +1,6 @@ %!PS-Adobe-2.0 EPSF-2.0 %%Creator: LEMON, graphToEps() -%%CreationDate: Fri Nov 4 13:47:12 2005 +%%CreationDate: Fri Mar 8 00:18:43 2013 %%BoundingBox: 0 0 842 596 %%EndComments /lb { setlinewidth setrgbcolor newpath moveto @@ -53,107 +53,107 @@ 860.856 -588.349 translate %Edges: gsave -574.035 177.301 622.149 225.748 670.264 274.195 0 0 0 2 lb -694.579 115.483 682.421 194.839 670.264 274.195 0 0 0 2 lb -280.402 10.3938 246.402 -6.60595 212.403 -23.6057 0 0 0 2 lb -280.402 10.3938 283.493 -18.9695 286.584 -48.3327 0 0 0 2 lb -212.403 -23.6057 249.493 -35.9692 286.584 -48.3327 0 0 0 2 lb -286.584 -48.3327 326.765 -79.2414 366.947 -110.15 0 0 0 2 lb -286.584 -48.3327 278.857 -111.695 271.13 -175.058 0 0 0 2 lb -438.037 -88.514 417.946 -142.604 397.855 -196.694 0 0 0 2 lb -438.037 -88.514 402.492 -99.332 366.947 -110.15 0 0 0 2 lb -397.855 -196.694 382.401 -153.422 366.947 -110.15 0 0 0 2 lb -366.947 -110.15 319.038 -142.604 271.13 -175.058 0 0 0 2 lb -271.13 -175.058 274.221 -213.694 277.311 -252.33 0 0 0 2 lb -271.13 -175.058 238.675 -190.512 206.221 -205.967 0 0 0 2 lb -277.311 -252.33 241.766 -229.149 206.221 -205.967 0 0 0 2 lb --840.856 -246.718 -804.351 -66.7145 -767.847 113.289 0 0 0 2 lb --579.033 445.603 -673.44 279.446 -767.847 113.289 0 0 0 2 lb --579.033 445.603 -524.906 302.104 -470.779 158.605 0 0 0 2 lb --767.847 113.289 -619.313 135.947 -470.779 158.605 0 0 0 2 lb -906.312 201.403 946.592 42.798 986.873 -115.807 0 0 0 2 lb -906.312 201.403 834.562 91.8901 762.812 -17.6227 0 0 0 2 lb -986.873 -115.807 874.842 -66.7148 762.812 -17.6227 0 0 0 2 lb --470.779 158.605 -390.218 50.3508 -309.657 -57.9033 0 0 0 2 lb -422.945 521.129 208.955 541.269 -5.03507 561.41 0 0 0 2 lb -422.945 521.129 376.371 417.911 329.797 314.692 0 0 0 2 lb -422.945 521.129 474.554 276.928 526.164 32.7279 0 0 0 2 lb --5.03507 561.41 -36.5042 440.568 -67.9734 319.727 0 0 0 2 lb -329.797 314.692 130.912 317.209 -67.9734 319.727 0 0 0 2 lb --67.9734 319.727 229.095 176.227 526.164 32.7279 0 0 0 2 lb -762.812 -17.6227 644.488 7.5526 526.164 32.7279 0 0 0 2 lb -762.812 -17.6227 746.448 -162.381 730.084 -307.139 0 0 0 2 lb -526.164 32.7279 470.779 -128.394 415.393 -289.516 0 0 0 2 lb -730.084 -307.139 572.738 -298.327 415.393 -289.516 0 0 0 2 lb -415.393 -289.516 173.71 -318.468 -67.9734 -347.42 0 0 0 2 lb --67.9734 -347.42 -188.815 -202.662 -309.657 -57.9033 0 0 0 2 lb --67.9734 -347.42 -195.758 -390.692 -323.543 -433.964 0 0 0 2 lb --309.657 -57.9033 -424.775 -160.272 -539.894 -262.64 0 0 0 2 lb --323.543 -433.964 -431.719 -348.302 -539.894 -262.64 0 0 0 2 lb --26.6953 -19.9585 44.8558 -96.8093 116.407 -173.66 0 0 0 2 lb --26.6953 -19.9585 87.2563 9.19185 201.208 38.3422 0 0 0 2 lb --26.6953 -19.9585 -144.622 43.6422 -262.548 107.243 0 0 0 2 lb --26.6953 -19.9585 -20.0703 56.8923 -13.4452 133.743 0 0 0 2 lb -116.407 -173.66 158.808 -67.6589 201.208 38.3422 0 0 0 2 lb --262.548 107.243 -137.997 120.493 -13.4452 133.743 0 0 0 2 lb --262.548 107.243 -221.472 176.144 -180.397 245.045 0 0 0 2 lb --13.4452 133.743 -96.9211 189.394 -180.397 245.045 0 0 0 2 lb --180.397 245.045 -142.256 345.099 -132.697 451.748 0 0 0 2 lb --180.397 245.045 -170.838 351.694 -132.697 451.748 0 0 0 2 lb --416.25 345.746 -274.474 398.747 -132.697 451.748 0 0 0 2 lb --416.25 345.746 -393.725 457.048 -371.2 568.349 0 0 0 2 lb --132.697 451.748 -251.948 510.048 -371.2 568.349 0 0 0 2 lb -670.264 274.195 629.188 409.347 588.113 544.499 0 0 0 2 lb -670.264 274.195 797.466 341.771 924.667 409.347 0 0 0 2 lb -588.113 544.499 756.39 476.923 924.667 409.347 0 0 0 2 lb --689.204 -237.261 -614.799 -102.648 -567.302 43.6423 0 0 0 2 lb --689.204 -237.261 -641.707 -90.9706 -567.302 43.6423 0 0 0 2 lb +574.035 177.301 622.149 225.748 670.264 274.195 0 0 0 6.25356 lb +694.579 115.483 682.421 194.839 670.264 274.195 0 0 0 6.25356 lb +280.402 10.3938 246.402 -6.60595 212.403 -23.6057 0 0 0 6.25356 lb +280.402 10.3938 283.493 -18.9695 286.584 -48.3327 0 0 0 6.25356 lb +212.403 -23.6057 249.493 -35.9692 286.584 -48.3327 0 0 0 6.25356 lb +286.584 -48.3327 326.765 -79.2414 366.947 -110.15 0 0 0 6.25356 lb +286.584 -48.3327 278.857 -111.695 271.13 -175.058 0 0 0 6.25356 lb +438.037 -88.514 417.946 -142.604 397.855 -196.694 0 0 0 6.25356 lb +438.037 -88.514 402.492 -99.332 366.947 -110.15 0 0 0 6.25356 lb +397.855 -196.694 382.401 -153.422 366.947 -110.15 0 0 0 6.25356 lb +366.947 -110.15 319.038 -142.604 271.13 -175.058 0 0 0 6.25356 lb +271.13 -175.058 274.221 -213.694 277.311 -252.33 0 0 0 6.25356 lb +271.13 -175.058 238.675 -190.512 206.221 -205.967 0 0 0 6.25356 lb +277.311 -252.33 241.766 -229.149 206.221 -205.967 0 0 0 6.25356 lb +-840.856 -246.718 -804.351 -66.7145 -767.847 113.289 0 0 0 6.25356 lb +-579.033 445.603 -673.44 279.446 -767.847 113.289 0 0 0 6.25356 lb +-579.033 445.603 -524.906 302.104 -470.779 158.605 0 0 0 6.25356 lb +-767.847 113.289 -619.313 135.947 -470.779 158.605 0 0 0 6.25356 lb +906.312 201.403 946.592 42.798 986.873 -115.807 0 0 0 6.25356 lb +906.312 201.403 834.562 91.8901 762.812 -17.6227 0 0 0 6.25356 lb +986.873 -115.807 874.842 -66.7148 762.812 -17.6227 0 0 0 6.25356 lb +-470.779 158.605 -390.218 50.3508 -309.657 -57.9033 0 0 0 6.25356 lb +422.945 521.129 208.955 541.269 -5.03507 561.41 0 0 0 6.25356 lb +422.945 521.129 376.371 417.911 329.797 314.692 0 0 0 6.25356 lb +422.945 521.129 474.554 276.928 526.164 32.7279 0 0 0 6.25356 lb +-5.03507 561.41 -36.5042 440.568 -67.9734 319.727 0 0 0 6.25356 lb +329.797 314.692 130.912 317.209 -67.9734 319.727 0 0 0 6.25356 lb +-67.9734 319.727 229.095 176.227 526.164 32.7279 0 0 0 6.25356 lb +762.812 -17.6227 644.488 7.5526 526.164 32.7279 0 0 0 6.25356 lb +762.812 -17.6227 746.448 -162.381 730.084 -307.139 0 0 0 6.25356 lb +526.164 32.7279 470.779 -128.394 415.393 -289.516 0 0 0 6.25356 lb +730.084 -307.139 572.738 -298.327 415.393 -289.516 0 0 0 6.25356 lb +415.393 -289.516 173.71 -318.468 -67.9734 -347.42 0 0 0 6.25356 lb +-67.9734 -347.42 -188.815 -202.662 -309.657 -57.9033 0 0 0 6.25356 lb +-67.9734 -347.42 -195.758 -390.692 -323.543 -433.964 0 0 0 6.25356 lb +-309.657 -57.9033 -424.775 -160.272 -539.894 -262.64 0 0 0 6.25356 lb +-323.543 -433.964 -431.719 -348.302 -539.894 -262.64 0 0 0 6.25356 lb +-26.6953 -19.9585 44.8558 -96.8093 116.407 -173.66 0 0 0 6.25356 lb +-26.6953 -19.9585 87.2563 9.19185 201.208 38.3422 0 0 0 6.25356 lb +-26.6953 -19.9585 -144.622 43.6422 -262.548 107.243 0 0 0 6.25356 lb +-26.6953 -19.9585 -20.0703 56.8923 -13.4452 133.743 0 0 0 6.25356 lb +116.407 -173.66 158.808 -67.6589 201.208 38.3422 0 0 0 6.25356 lb +-262.548 107.243 -137.997 120.493 -13.4452 133.743 0 0 0 6.25356 lb +-262.548 107.243 -221.472 176.144 -180.397 245.045 0 0 0 6.25356 lb +-13.4452 133.743 -96.9211 189.394 -180.397 245.045 0 0 0 6.25356 lb +-180.397 245.045 -113.509 338.465 -132.697 451.748 0 0 0 6.25356 lb +-180.397 245.045 -199.585 358.328 -132.697 451.748 0 0 0 6.25356 lb +-416.25 345.746 -274.474 398.747 -132.697 451.748 0 0 0 6.25356 lb +-416.25 345.746 -393.725 457.048 -371.2 568.349 0 0 0 6.25356 lb +-132.697 451.748 -251.948 510.048 -371.2 568.349 0 0 0 6.25356 lb +670.264 274.195 629.188 409.347 588.113 544.499 0 0 0 6.25356 lb +670.264 274.195 797.466 341.771 924.667 409.347 0 0 0 6.25356 lb +588.113 544.499 756.39 476.923 924.667 409.347 0 0 0 6.25356 lb +-689.204 -237.261 -587.735 -114.393 -567.302 43.6423 0 0 0 6.25356 lb +-689.204 -237.261 -668.771 -79.2259 -567.302 43.6423 0 0 0 6.25356 lb grestore %Nodes: gsave --567.302 43.6423 20 0 0 0 nc --689.204 -237.261 20 0 0 0 nc -924.667 409.347 20 1 0 0 nc -588.113 544.499 20 1 0 0 nc -670.264 274.195 20 1 0 0 nc --371.2 568.349 20 0 1 0 nc --132.697 451.748 20 0 1 0 nc --416.25 345.746 20 0 1 0 nc --180.397 245.045 20 0 1 0 nc --13.4452 133.743 20 0 1 0 nc --262.548 107.243 20 0 1 0 nc -201.208 38.3422 20 0 1 0 nc -116.407 -173.66 20 0 1 0 nc --26.6953 -19.9585 20 0 1 0 nc --539.894 -262.64 20 0 0 1 nc --323.543 -433.964 20 0 0 1 nc --309.657 -57.9033 20 0 0 1 nc --67.9734 -347.42 20 0 0 1 nc -415.393 -289.516 20 0 0 1 nc -730.084 -307.139 20 0 0 1 nc -526.164 32.7279 20 0 0 1 nc -762.812 -17.6227 20 0 0 1 nc --67.9734 319.727 20 0 0 1 nc -329.797 314.692 20 0 0 1 nc --5.03507 561.41 20 0 0 1 nc -422.945 521.129 20 0 0 1 nc --470.779 158.605 20 0 0 1 nc -986.873 -115.807 20 0 0 1 nc -906.312 201.403 20 0 0 1 nc --767.847 113.289 20 0 0 1 nc --579.033 445.603 20 0 0 1 nc --840.856 -246.718 20 0 0 1 nc -206.221 -205.967 20 1 1 0 nc -277.311 -252.33 20 1 1 0 nc -271.13 -175.058 20 1 1 0 nc -366.947 -110.15 20 1 1 0 nc -397.855 -196.694 20 1 1 0 nc -438.037 -88.514 20 1 1 0 nc -286.584 -48.3327 20 1 1 0 nc -212.403 -23.6057 20 1 1 0 nc -280.402 10.3938 20 1 1 0 nc -694.579 115.483 20 1 0 0 nc -574.035 177.301 20 1 0 0 nc +-567.302 43.6423 20.8452 0 0 0 nc +-689.204 -237.261 20.8452 0 0 0 nc +924.667 409.347 20.8452 1 0 0 nc +588.113 544.499 20.8452 1 0 0 nc +670.264 274.195 20.8452 1 0 0 nc +-371.2 568.349 20.8452 0 1 0 nc +-132.697 451.748 20.8452 0 1 0 nc +-416.25 345.746 20.8452 0 1 0 nc +-180.397 245.045 20.8452 0 1 0 nc +-13.4452 133.743 20.8452 0 1 0 nc +-262.548 107.243 20.8452 0 1 0 nc +201.208 38.3422 20.8452 0 1 0 nc +116.407 -173.66 20.8452 0 1 0 nc +-26.6953 -19.9585 20.8452 0 1 0 nc +-539.894 -262.64 20.8452 0 0 1 nc +-323.543 -433.964 20.8452 0 0 1 nc +-309.657 -57.9033 20.8452 0 0 1 nc +-67.9734 -347.42 20.8452 0 0 1 nc +415.393 -289.516 20.8452 0 0 1 nc +730.084 -307.139 20.8452 0 0 1 nc +526.164 32.7279 20.8452 0 0 1 nc +762.812 -17.6227 20.8452 0 0 1 nc +-67.9734 319.727 20.8452 0 0 1 nc +329.797 314.692 20.8452 0 0 1 nc +-5.03507 561.41 20.8452 0 0 1 nc +422.945 521.129 20.8452 0 0 1 nc +-470.779 158.605 20.8452 0 0 1 nc +986.873 -115.807 20.8452 0 0 1 nc +906.312 201.403 20.8452 0 0 1 nc +-767.847 113.289 20.8452 0 0 1 nc +-579.033 445.603 20.8452 0 0 1 nc +-840.856 -246.718 20.8452 0 0 1 nc +206.221 -205.967 20.8452 1 1 0 nc +277.311 -252.33 20.8452 1 1 0 nc +271.13 -175.058 20.8452 1 1 0 nc +366.947 -110.15 20.8452 1 1 0 nc +397.855 -196.694 20.8452 1 1 0 nc +438.037 -88.514 20.8452 1 1 0 nc +286.584 -48.3327 20.8452 1 1 0 nc +212.403 -23.6057 20.8452 1 1 0 nc +280.402 10.3938 20.8452 1 1 0 nc +694.579 115.483 20.8452 1 0 0 nc +574.035 177.301 20.8452 1 0 0 nc grestore grestore showpage diff -r cd72eae05bdf -r 3c00344f49c9 doc/images/edge_biconnected_components.eps --- a/doc/images/edge_biconnected_components.eps Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/images/edge_biconnected_components.eps Wed Oct 17 19:14:07 2018 +0200 @@ -1,6 +1,6 @@ %!PS-Adobe-2.0 EPSF-2.0 %%Creator: LEMON, graphToEps() -%%CreationDate: Fri Nov 4 13:47:12 2005 +%%CreationDate: Fri Mar 8 00:18:43 2013 %%BoundingBox: 0 0 842 596 %%EndComments /lb { setlinewidth setrgbcolor newpath moveto @@ -53,107 +53,107 @@ 860.856 -588.349 translate %Edges: gsave -574.035 177.301 622.149 225.748 670.264 274.195 1 0 0 2 lb -694.579 115.483 682.421 194.839 670.264 274.195 1 0 0 2 lb -280.402 10.3938 246.402 -6.60595 212.403 -23.6057 0 0 1 2 lb -280.402 10.3938 283.493 -18.9695 286.584 -48.3327 0 0 1 2 lb -212.403 -23.6057 249.493 -35.9692 286.584 -48.3327 0 0 1 2 lb -286.584 -48.3327 326.765 -79.2414 366.947 -110.15 0 0 1 2 lb -286.584 -48.3327 278.857 -111.695 271.13 -175.058 0 0 1 2 lb -438.037 -88.514 417.946 -142.604 397.855 -196.694 0 0 1 2 lb -438.037 -88.514 402.492 -99.332 366.947 -110.15 0 0 1 2 lb -397.855 -196.694 382.401 -153.422 366.947 -110.15 0 0 1 2 lb -366.947 -110.15 319.038 -142.604 271.13 -175.058 0 0 1 2 lb -271.13 -175.058 274.221 -213.694 277.311 -252.33 0 0 1 2 lb -271.13 -175.058 238.675 -190.512 206.221 -205.967 0 0 1 2 lb -277.311 -252.33 241.766 -229.149 206.221 -205.967 0 0 1 2 lb --840.856 -246.718 -804.351 -66.7145 -767.847 113.289 1 0 0 2 lb --579.033 445.603 -673.44 279.446 -767.847 113.289 0 0 1 2 lb --579.033 445.603 -524.906 302.104 -470.779 158.605 0 0 1 2 lb --767.847 113.289 -619.313 135.947 -470.779 158.605 0 0 1 2 lb -906.312 201.403 946.592 42.798 986.873 -115.807 0 0 1 2 lb -906.312 201.403 834.562 91.8901 762.812 -17.6227 0 0 1 2 lb -986.873 -115.807 874.842 -66.7148 762.812 -17.6227 0 0 1 2 lb --470.779 158.605 -390.218 50.3508 -309.657 -57.9033 1 0 0 2 lb -422.945 521.129 208.955 541.269 -5.03507 561.41 0 0 1 2 lb -422.945 521.129 376.371 417.911 329.797 314.692 0 0 1 2 lb -422.945 521.129 474.554 276.928 526.164 32.7279 0 0 1 2 lb --5.03507 561.41 -36.5042 440.568 -67.9734 319.727 0 0 1 2 lb -329.797 314.692 130.912 317.209 -67.9734 319.727 0 0 1 2 lb --67.9734 319.727 229.095 176.227 526.164 32.7279 0 0 1 2 lb -762.812 -17.6227 644.488 7.5526 526.164 32.7279 0 0 1 2 lb -762.812 -17.6227 746.448 -162.381 730.084 -307.139 0 0 1 2 lb -526.164 32.7279 470.779 -128.394 415.393 -289.516 0 0 1 2 lb -730.084 -307.139 572.738 -298.327 415.393 -289.516 0 0 1 2 lb -415.393 -289.516 173.71 -318.468 -67.9734 -347.42 1 0 0 2 lb --67.9734 -347.42 -188.815 -202.662 -309.657 -57.9033 0 0 1 2 lb --67.9734 -347.42 -195.758 -390.692 -323.543 -433.964 0 0 1 2 lb --309.657 -57.9033 -424.775 -160.272 -539.894 -262.64 0 0 1 2 lb --323.543 -433.964 -431.719 -348.302 -539.894 -262.64 0 0 1 2 lb --26.6953 -19.9585 44.8558 -96.8093 116.407 -173.66 0 0 1 2 lb --26.6953 -19.9585 87.2563 9.19185 201.208 38.3422 0 0 1 2 lb --26.6953 -19.9585 -144.622 43.6422 -262.548 107.243 0 0 1 2 lb --26.6953 -19.9585 -20.0703 56.8923 -13.4452 133.743 0 0 1 2 lb -116.407 -173.66 158.808 -67.6589 201.208 38.3422 0 0 1 2 lb --262.548 107.243 -137.997 120.493 -13.4452 133.743 0 0 1 2 lb --262.548 107.243 -221.472 176.144 -180.397 245.045 0 0 1 2 lb --13.4452 133.743 -96.9211 189.394 -180.397 245.045 0 0 1 2 lb --180.397 245.045 -142.256 345.099 -132.697 451.748 0 0 1 2 lb --180.397 245.045 -170.838 351.694 -132.697 451.748 0 0 1 2 lb --416.25 345.746 -274.474 398.747 -132.697 451.748 0 0 1 2 lb --416.25 345.746 -393.725 457.048 -371.2 568.349 0 0 1 2 lb --132.697 451.748 -251.948 510.048 -371.2 568.349 0 0 1 2 lb -670.264 274.195 629.188 409.347 588.113 544.499 0 0 1 2 lb -670.264 274.195 797.466 341.771 924.667 409.347 0 0 1 2 lb -588.113 544.499 756.39 476.923 924.667 409.347 0 0 1 2 lb --689.204 -237.261 -614.799 -102.648 -567.302 43.6423 0 0 1 2 lb --689.204 -237.261 -641.707 -90.9706 -567.302 43.6423 0 0 1 2 lb +574.035 177.301 622.149 225.748 670.264 274.195 1 0 0 6.25356 lb +694.579 115.483 682.421 194.839 670.264 274.195 1 0 0 6.25356 lb +280.402 10.3938 246.402 -6.60595 212.403 -23.6057 0 0 1 6.25356 lb +280.402 10.3938 283.493 -18.9695 286.584 -48.3327 0 0 1 6.25356 lb +212.403 -23.6057 249.493 -35.9692 286.584 -48.3327 0 0 1 6.25356 lb +286.584 -48.3327 326.765 -79.2414 366.947 -110.15 0 0 1 6.25356 lb +286.584 -48.3327 278.857 -111.695 271.13 -175.058 0 0 1 6.25356 lb +438.037 -88.514 417.946 -142.604 397.855 -196.694 0 0 1 6.25356 lb +438.037 -88.514 402.492 -99.332 366.947 -110.15 0 0 1 6.25356 lb +397.855 -196.694 382.401 -153.422 366.947 -110.15 0 0 1 6.25356 lb +366.947 -110.15 319.038 -142.604 271.13 -175.058 0 0 1 6.25356 lb +271.13 -175.058 274.221 -213.694 277.311 -252.33 0 0 1 6.25356 lb +271.13 -175.058 238.675 -190.512 206.221 -205.967 0 0 1 6.25356 lb +277.311 -252.33 241.766 -229.149 206.221 -205.967 0 0 1 6.25356 lb +-840.856 -246.718 -804.351 -66.7145 -767.847 113.289 1 0 0 6.25356 lb +-579.033 445.603 -673.44 279.446 -767.847 113.289 0 0 1 6.25356 lb +-579.033 445.603 -524.906 302.104 -470.779 158.605 0 0 1 6.25356 lb +-767.847 113.289 -619.313 135.947 -470.779 158.605 0 0 1 6.25356 lb +906.312 201.403 946.592 42.798 986.873 -115.807 0 0 1 6.25356 lb +906.312 201.403 834.562 91.8901 762.812 -17.6227 0 0 1 6.25356 lb +986.873 -115.807 874.842 -66.7148 762.812 -17.6227 0 0 1 6.25356 lb +-470.779 158.605 -390.218 50.3508 -309.657 -57.9033 1 0 0 6.25356 lb +422.945 521.129 208.955 541.269 -5.03507 561.41 0 0 1 6.25356 lb +422.945 521.129 376.371 417.911 329.797 314.692 0 0 1 6.25356 lb +422.945 521.129 474.554 276.928 526.164 32.7279 0 0 1 6.25356 lb +-5.03507 561.41 -36.5042 440.568 -67.9734 319.727 0 0 1 6.25356 lb +329.797 314.692 130.912 317.209 -67.9734 319.727 0 0 1 6.25356 lb +-67.9734 319.727 229.095 176.227 526.164 32.7279 0 0 1 6.25356 lb +762.812 -17.6227 644.488 7.5526 526.164 32.7279 0 0 1 6.25356 lb +762.812 -17.6227 746.448 -162.381 730.084 -307.139 0 0 1 6.25356 lb +526.164 32.7279 470.779 -128.394 415.393 -289.516 0 0 1 6.25356 lb +730.084 -307.139 572.738 -298.327 415.393 -289.516 0 0 1 6.25356 lb +415.393 -289.516 173.71 -318.468 -67.9734 -347.42 1 0 0 6.25356 lb +-67.9734 -347.42 -188.815 -202.662 -309.657 -57.9033 0 0 1 6.25356 lb +-67.9734 -347.42 -195.758 -390.692 -323.543 -433.964 0 0 1 6.25356 lb +-309.657 -57.9033 -424.775 -160.272 -539.894 -262.64 0 0 1 6.25356 lb +-323.543 -433.964 -431.719 -348.302 -539.894 -262.64 0 0 1 6.25356 lb +-26.6953 -19.9585 44.8558 -96.8093 116.407 -173.66 0 0 1 6.25356 lb +-26.6953 -19.9585 87.2563 9.19185 201.208 38.3422 0 0 1 6.25356 lb +-26.6953 -19.9585 -144.622 43.6422 -262.548 107.243 0 0 1 6.25356 lb +-26.6953 -19.9585 -20.0703 56.8923 -13.4452 133.743 0 0 1 6.25356 lb +116.407 -173.66 158.808 -67.6589 201.208 38.3422 0 0 1 6.25356 lb +-262.548 107.243 -137.997 120.493 -13.4452 133.743 0 0 1 6.25356 lb +-262.548 107.243 -221.472 176.144 -180.397 245.045 0 0 1 6.25356 lb +-13.4452 133.743 -96.9211 189.394 -180.397 245.045 0 0 1 6.25356 lb +-180.397 245.045 -113.509 338.465 -132.697 451.748 0 0 1 6.25356 lb +-180.397 245.045 -199.585 358.328 -132.697 451.748 0 0 1 6.25356 lb +-416.25 345.746 -274.474 398.747 -132.697 451.748 0 0 1 6.25356 lb +-416.25 345.746 -393.725 457.048 -371.2 568.349 0 0 1 6.25356 lb +-132.697 451.748 -251.948 510.048 -371.2 568.349 0 0 1 6.25356 lb +670.264 274.195 629.188 409.347 588.113 544.499 0 0 1 6.25356 lb +670.264 274.195 797.466 341.771 924.667 409.347 0 0 1 6.25356 lb +588.113 544.499 756.39 476.923 924.667 409.347 0 0 1 6.25356 lb +-689.204 -237.261 -587.735 -114.393 -567.302 43.6423 0 0 1 6.25356 lb +-689.204 -237.261 -668.771 -79.2259 -567.302 43.6423 0 0 1 6.25356 lb grestore %Nodes: gsave --567.302 43.6423 20 0 0 0 nc --689.204 -237.261 20 0 0 0 nc -924.667 409.347 20 0 0 1 nc -588.113 544.499 20 0 0 1 nc -670.264 274.195 20 0 0 1 nc --371.2 568.349 20 1 1 0 nc --132.697 451.748 20 1 1 0 nc --416.25 345.746 20 1 1 0 nc --180.397 245.045 20 1 1 0 nc --13.4452 133.743 20 1 1 0 nc --262.548 107.243 20 1 1 0 nc -201.208 38.3422 20 1 1 0 nc -116.407 -173.66 20 1 1 0 nc --26.6953 -19.9585 20 1 1 0 nc --539.894 -262.64 20 0 0.5 0 nc --323.543 -433.964 20 0 0.5 0 nc --309.657 -57.9033 20 0 0.5 0 nc --67.9734 -347.42 20 0 0.5 0 nc -415.393 -289.516 20 0.5 0 0 nc -730.084 -307.139 20 0.5 0 0 nc -526.164 32.7279 20 0.5 0 0 nc -762.812 -17.6227 20 0.5 0 0 nc --67.9734 319.727 20 0.5 0 0 nc -329.797 314.692 20 0.5 0 0 nc --5.03507 561.41 20 0.5 0 0 nc -422.945 521.129 20 0.5 0 0 nc --470.779 158.605 20 0 1 1 nc -986.873 -115.807 20 0.5 0 0 nc -906.312 201.403 20 0.5 0 0 nc --767.847 113.289 20 0 1 1 nc --579.033 445.603 20 0 1 1 nc --840.856 -246.718 20 1 0 1 nc -206.221 -205.967 20 0 0 0.5 nc -277.311 -252.33 20 0 0 0.5 nc -271.13 -175.058 20 0 0 0.5 nc -366.947 -110.15 20 0 0 0.5 nc -397.855 -196.694 20 0 0 0.5 nc -438.037 -88.514 20 0 0 0.5 nc -286.584 -48.3327 20 0 0 0.5 nc -212.403 -23.6057 20 0 0 0.5 nc -280.402 10.3938 20 0 0 0.5 nc -694.579 115.483 20 1 0 0 nc -574.035 177.301 20 0 1 0 nc +-567.302 43.6423 20.8452 0 0 0 nc +-689.204 -237.261 20.8452 0 0 0 nc +924.667 409.347 20.8452 0 0 1 nc +588.113 544.499 20.8452 0 0 1 nc +670.264 274.195 20.8452 0 0 1 nc +-371.2 568.349 20.8452 1 1 0 nc +-132.697 451.748 20.8452 1 1 0 nc +-416.25 345.746 20.8452 1 1 0 nc +-180.397 245.045 20.8452 1 1 0 nc +-13.4452 133.743 20.8452 1 1 0 nc +-262.548 107.243 20.8452 1 1 0 nc +201.208 38.3422 20.8452 1 1 0 nc +116.407 -173.66 20.8452 1 1 0 nc +-26.6953 -19.9585 20.8452 1 1 0 nc +-539.894 -262.64 20.8452 0 0.5 0 nc +-323.543 -433.964 20.8452 0 0.5 0 nc +-309.657 -57.9033 20.8452 0 0.5 0 nc +-67.9734 -347.42 20.8452 0 0.5 0 nc +415.393 -289.516 20.8452 0.5 0 0 nc +730.084 -307.139 20.8452 0.5 0 0 nc +526.164 32.7279 20.8452 0.5 0 0 nc +762.812 -17.6227 20.8452 0.5 0 0 nc +-67.9734 319.727 20.8452 0.5 0 0 nc +329.797 314.692 20.8452 0.5 0 0 nc +-5.03507 561.41 20.8452 0.5 0 0 nc +422.945 521.129 20.8452 0.5 0 0 nc +-470.779 158.605 20.8452 0 1 1 nc +986.873 -115.807 20.8452 0.5 0 0 nc +906.312 201.403 20.8452 0.5 0 0 nc +-767.847 113.289 20.8452 0 1 1 nc +-579.033 445.603 20.8452 0 1 1 nc +-840.856 -246.718 20.8452 1 0 1 nc +206.221 -205.967 20.8452 0 0 0.5 nc +277.311 -252.33 20.8452 0 0 0.5 nc +271.13 -175.058 20.8452 0 0 0.5 nc +366.947 -110.15 20.8452 0 0 0.5 nc +397.855 -196.694 20.8452 0 0 0.5 nc +438.037 -88.514 20.8452 0 0 0.5 nc +286.584 -48.3327 20.8452 0 0 0.5 nc +212.403 -23.6057 20.8452 0 0 0.5 nc +280.402 10.3938 20.8452 0 0 0.5 nc +694.579 115.483 20.8452 1 0 0 nc +574.035 177.301 20.8452 0 1 0 nc grestore grestore showpage diff -r cd72eae05bdf -r 3c00344f49c9 doc/images/graph_to_eps.png Binary file doc/images/graph_to_eps.png has changed diff -r cd72eae05bdf -r 3c00344f49c9 doc/images/node_biconnected_components.eps --- a/doc/images/node_biconnected_components.eps Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/images/node_biconnected_components.eps Wed Oct 17 19:14:07 2018 +0200 @@ -1,6 +1,6 @@ %!PS-Adobe-2.0 EPSF-2.0 %%Creator: LEMON, graphToEps() -%%CreationDate: Fri Nov 4 13:47:12 2005 +%%CreationDate: Fri Mar 8 00:18:43 2013 %%BoundingBox: 0 0 842 596 %%EndComments /lb { setlinewidth setrgbcolor newpath moveto @@ -53,107 +53,107 @@ 860.856 -588.349 translate %Edges: gsave -574.035 177.301 622.149 225.748 670.264 274.195 0 1 0 5 lb -694.579 115.483 682.421 194.839 670.264 274.195 1 0 0 5 lb -280.402 10.3938 246.402 -6.60595 212.403 -23.6057 1 1 0.5 5 lb -280.402 10.3938 283.493 -18.9695 286.584 -48.3327 1 1 0.5 5 lb -212.403 -23.6057 249.493 -35.9692 286.584 -48.3327 1 1 0.5 5 lb -286.584 -48.3327 326.765 -79.2414 366.947 -110.15 1 0.5 1 5 lb -286.584 -48.3327 278.857 -111.695 271.13 -175.058 1 0.5 1 5 lb -438.037 -88.514 417.946 -142.604 397.855 -196.694 0.5 0.5 1 5 lb -438.037 -88.514 402.492 -99.332 366.947 -110.15 0.5 0.5 1 5 lb -397.855 -196.694 382.401 -153.422 366.947 -110.15 0.5 0.5 1 5 lb -366.947 -110.15 319.038 -142.604 271.13 -175.058 1 0.5 1 5 lb -271.13 -175.058 274.221 -213.694 277.311 -252.33 0.5 1 1 5 lb -271.13 -175.058 238.675 -190.512 206.221 -205.967 0.5 1 1 5 lb -277.311 -252.33 241.766 -229.149 206.221 -205.967 0.5 1 1 5 lb --840.856 -246.718 -804.351 -66.7145 -767.847 113.289 0 0.5 0 5 lb --579.033 445.603 -673.44 279.446 -767.847 113.289 0 0 0.5 5 lb --579.033 445.603 -524.906 302.104 -470.779 158.605 0 0 0.5 5 lb --767.847 113.289 -619.313 135.947 -470.779 158.605 0 0 0.5 5 lb -906.312 201.403 946.592 42.798 986.873 -115.807 0 0.5 0.5 5 lb -906.312 201.403 834.562 91.8901 762.812 -17.6227 0 0.5 0.5 5 lb -986.873 -115.807 874.842 -66.7148 762.812 -17.6227 0 0.5 0.5 5 lb --470.779 158.605 -390.218 50.3508 -309.657 -57.9033 0.5 0.5 0 5 lb -422.945 521.129 208.955 541.269 -5.03507 561.41 0.5 0 0.5 5 lb -422.945 521.129 376.371 417.911 329.797 314.692 0.5 0 0.5 5 lb -422.945 521.129 474.554 276.928 526.164 32.7279 0.5 0 0.5 5 lb --5.03507 561.41 -36.5042 440.568 -67.9734 319.727 0.5 0 0.5 5 lb -329.797 314.692 130.912 317.209 -67.9734 319.727 0.5 0 0.5 5 lb --67.9734 319.727 229.095 176.227 526.164 32.7279 0.5 0 0.5 5 lb -762.812 -17.6227 644.488 7.5526 526.164 32.7279 0.5 0.5 0.5 5 lb -762.812 -17.6227 746.448 -162.381 730.084 -307.139 0.5 0.5 0.5 5 lb -526.164 32.7279 470.779 -128.394 415.393 -289.516 0.5 0.5 0.5 5 lb -730.084 -307.139 572.738 -298.327 415.393 -289.516 0.5 0.5 0.5 5 lb -415.393 -289.516 173.71 -318.468 -67.9734 -347.42 1 0.5 0.5 5 lb --67.9734 -347.42 -188.815 -202.662 -309.657 -57.9033 0.5 1 0.5 5 lb --67.9734 -347.42 -195.758 -390.692 -323.543 -433.964 0.5 1 0.5 5 lb --309.657 -57.9033 -424.775 -160.272 -539.894 -262.64 0.5 1 0.5 5 lb --323.543 -433.964 -431.719 -348.302 -539.894 -262.64 0.5 1 0.5 5 lb --26.6953 -19.9585 44.8558 -96.8093 116.407 -173.66 1 1 0 5 lb --26.6953 -19.9585 87.2563 9.19185 201.208 38.3422 1 1 0 5 lb --26.6953 -19.9585 -144.622 43.6422 -262.548 107.243 1 0 1 5 lb --26.6953 -19.9585 -20.0703 56.8923 -13.4452 133.743 1 0 1 5 lb -116.407 -173.66 158.808 -67.6589 201.208 38.3422 1 1 0 5 lb --262.548 107.243 -137.997 120.493 -13.4452 133.743 1 0 1 5 lb --262.548 107.243 -221.472 176.144 -180.397 245.045 1 0 1 5 lb --13.4452 133.743 -96.9211 189.394 -180.397 245.045 1 0 1 5 lb --180.397 245.045 -140.307 344.649 -132.697 451.748 0 1 1 5 lb --180.397 245.045 -172.787 352.144 -132.697 451.748 0 1 1 5 lb --416.25 345.746 -274.474 398.747 -132.697 451.748 0.5 0 0 5 lb --416.25 345.746 -393.725 457.048 -371.2 568.349 0.5 0 0 5 lb --132.697 451.748 -251.948 510.048 -371.2 568.349 0.5 0 0 5 lb -670.264 274.195 629.188 409.347 588.113 544.499 0 0 1 5 lb -670.264 274.195 797.466 341.771 924.667 409.347 0 0 1 5 lb -588.113 544.499 756.39 476.923 924.667 409.347 0 0 1 5 lb --689.204 -237.261 -612.964 -103.444 -567.302 43.6423 0 0 0 5 lb --689.204 -237.261 -643.542 -90.1744 -567.302 43.6423 0 0 0 5 lb +574.035 177.301 622.149 225.748 670.264 274.195 0 1 0 6.25356 lb +694.579 115.483 682.421 194.839 670.264 274.195 1 0 0 6.25356 lb +280.402 10.3938 246.402 -6.60595 212.403 -23.6057 1 1 0.5 6.25356 lb +280.402 10.3938 283.493 -18.9695 286.584 -48.3327 1 1 0.5 6.25356 lb +212.403 -23.6057 249.493 -35.9692 286.584 -48.3327 1 1 0.5 6.25356 lb +286.584 -48.3327 326.765 -79.2414 366.947 -110.15 1 0.5 1 6.25356 lb +286.584 -48.3327 278.857 -111.695 271.13 -175.058 1 0.5 1 6.25356 lb +438.037 -88.514 417.946 -142.604 397.855 -196.694 0.5 0.5 1 6.25356 lb +438.037 -88.514 402.492 -99.332 366.947 -110.15 0.5 0.5 1 6.25356 lb +397.855 -196.694 382.401 -153.422 366.947 -110.15 0.5 0.5 1 6.25356 lb +366.947 -110.15 319.038 -142.604 271.13 -175.058 1 0.5 1 6.25356 lb +271.13 -175.058 274.221 -213.694 277.311 -252.33 0.5 1 1 6.25356 lb +271.13 -175.058 238.675 -190.512 206.221 -205.967 0.5 1 1 6.25356 lb +277.311 -252.33 241.766 -229.149 206.221 -205.967 0.5 1 1 6.25356 lb +-840.856 -246.718 -804.351 -66.7145 -767.847 113.289 0 0.5 0 6.25356 lb +-579.033 445.603 -673.44 279.446 -767.847 113.289 0 0 0.5 6.25356 lb +-579.033 445.603 -524.906 302.104 -470.779 158.605 0 0 0.5 6.25356 lb +-767.847 113.289 -619.313 135.947 -470.779 158.605 0 0 0.5 6.25356 lb +906.312 201.403 946.592 42.798 986.873 -115.807 0 0.5 0.5 6.25356 lb +906.312 201.403 834.562 91.8901 762.812 -17.6227 0 0.5 0.5 6.25356 lb +986.873 -115.807 874.842 -66.7148 762.812 -17.6227 0 0.5 0.5 6.25356 lb +-470.779 158.605 -390.218 50.3508 -309.657 -57.9033 0.5 0.5 0 6.25356 lb +422.945 521.129 208.955 541.269 -5.03507 561.41 0.5 0 0.5 6.25356 lb +422.945 521.129 376.371 417.911 329.797 314.692 0.5 0 0.5 6.25356 lb +422.945 521.129 474.554 276.928 526.164 32.7279 0.5 0 0.5 6.25356 lb +-5.03507 561.41 -36.5042 440.568 -67.9734 319.727 0.5 0 0.5 6.25356 lb +329.797 314.692 130.912 317.209 -67.9734 319.727 0.5 0 0.5 6.25356 lb +-67.9734 319.727 229.095 176.227 526.164 32.7279 0.5 0 0.5 6.25356 lb +762.812 -17.6227 644.488 7.5526 526.164 32.7279 0.5 0.5 0.5 6.25356 lb +762.812 -17.6227 746.448 -162.381 730.084 -307.139 0.5 0.5 0.5 6.25356 lb +526.164 32.7279 470.779 -128.394 415.393 -289.516 0.5 0.5 0.5 6.25356 lb +730.084 -307.139 572.738 -298.327 415.393 -289.516 0.5 0.5 0.5 6.25356 lb +415.393 -289.516 173.71 -318.468 -67.9734 -347.42 1 0.5 0.5 6.25356 lb +-67.9734 -347.42 -188.815 -202.662 -309.657 -57.9033 0.5 1 0.5 6.25356 lb +-67.9734 -347.42 -195.758 -390.692 -323.543 -433.964 0.5 1 0.5 6.25356 lb +-309.657 -57.9033 -424.775 -160.272 -539.894 -262.64 0.5 1 0.5 6.25356 lb +-323.543 -433.964 -431.719 -348.302 -539.894 -262.64 0.5 1 0.5 6.25356 lb +-26.6953 -19.9585 44.8558 -96.8093 116.407 -173.66 1 1 0 6.25356 lb +-26.6953 -19.9585 87.2563 9.19185 201.208 38.3422 1 1 0 6.25356 lb +-26.6953 -19.9585 -144.622 43.6422 -262.548 107.243 1 0 1 6.25356 lb +-26.6953 -19.9585 -20.0703 56.8923 -13.4452 133.743 1 0 1 6.25356 lb +116.407 -173.66 158.808 -67.6589 201.208 38.3422 1 1 0 6.25356 lb +-262.548 107.243 -137.997 120.493 -13.4452 133.743 1 0 1 6.25356 lb +-262.548 107.243 -221.472 176.144 -180.397 245.045 1 0 1 6.25356 lb +-13.4452 133.743 -96.9211 189.394 -180.397 245.045 1 0 1 6.25356 lb +-180.397 245.045 -113.509 338.465 -132.697 451.748 0 1 1 6.25356 lb +-180.397 245.045 -199.585 358.328 -132.697 451.748 0 1 1 6.25356 lb +-416.25 345.746 -274.474 398.747 -132.697 451.748 0.5 0 0 6.25356 lb +-416.25 345.746 -393.725 457.048 -371.2 568.349 0.5 0 0 6.25356 lb +-132.697 451.748 -251.948 510.048 -371.2 568.349 0.5 0 0 6.25356 lb +670.264 274.195 629.188 409.347 588.113 544.499 0 0 1 6.25356 lb +670.264 274.195 797.466 341.771 924.667 409.347 0 0 1 6.25356 lb +588.113 544.499 756.39 476.923 924.667 409.347 0 0 1 6.25356 lb +-689.204 -237.261 -587.735 -114.393 -567.302 43.6423 0 0 0 6.25356 lb +-689.204 -237.261 -668.771 -79.2259 -567.302 43.6423 0 0 0 6.25356 lb grestore %Nodes: gsave --567.302 43.6423 20 0 0 1 nc --689.204 -237.261 20 0 0 1 nc -924.667 409.347 20 0 0 1 nc -588.113 544.499 20 0 0 1 nc -670.264 274.195 20 1 0 0 nc --371.2 568.349 20 0 0 1 nc --132.697 451.748 20 1 0 0 nc --416.25 345.746 20 0 0 1 nc --180.397 245.045 20 1 0 0 nc --13.4452 133.743 20 0 0 1 nc --262.548 107.243 20 0 0 1 nc -201.208 38.3422 20 0 0 1 nc -116.407 -173.66 20 0 0 1 nc --26.6953 -19.9585 20 1 0 0 nc --539.894 -262.64 20 0 0 1 nc --323.543 -433.964 20 0 0 1 nc --309.657 -57.9033 20 1 0 0 nc --67.9734 -347.42 20 1 0 0 nc -415.393 -289.516 20 1 0 0 nc -730.084 -307.139 20 0 0 1 nc -526.164 32.7279 20 1 0 0 nc -762.812 -17.6227 20 1 0 0 nc --67.9734 319.727 20 0 0 1 nc -329.797 314.692 20 0 0 1 nc --5.03507 561.41 20 0 0 1 nc -422.945 521.129 20 0 0 1 nc --470.779 158.605 20 1 0 0 nc -986.873 -115.807 20 0 0 1 nc -906.312 201.403 20 0 0 1 nc --767.847 113.289 20 1 0 0 nc --579.033 445.603 20 0 0 1 nc --840.856 -246.718 20 0 0 1 nc -206.221 -205.967 20 0 0 1 nc -277.311 -252.33 20 0 0 1 nc -271.13 -175.058 20 1 0 0 nc -366.947 -110.15 20 1 0 0 nc -397.855 -196.694 20 0 0 1 nc -438.037 -88.514 20 0 0 1 nc -286.584 -48.3327 20 1 0 0 nc -212.403 -23.6057 20 0 0 1 nc -280.402 10.3938 20 0 0 1 nc -694.579 115.483 20 0 0 1 nc -574.035 177.301 20 0 0 1 nc +-567.302 43.6423 20.8452 0 0 1 nc +-689.204 -237.261 20.8452 0 0 1 nc +924.667 409.347 20.8452 0 0 1 nc +588.113 544.499 20.8452 0 0 1 nc +670.264 274.195 20.8452 1 0 0 nc +-371.2 568.349 20.8452 0 0 1 nc +-132.697 451.748 20.8452 1 0 0 nc +-416.25 345.746 20.8452 0 0 1 nc +-180.397 245.045 20.8452 1 0 0 nc +-13.4452 133.743 20.8452 0 0 1 nc +-262.548 107.243 20.8452 0 0 1 nc +201.208 38.3422 20.8452 0 0 1 nc +116.407 -173.66 20.8452 0 0 1 nc +-26.6953 -19.9585 20.8452 1 0 0 nc +-539.894 -262.64 20.8452 0 0 1 nc +-323.543 -433.964 20.8452 0 0 1 nc +-309.657 -57.9033 20.8452 1 0 0 nc +-67.9734 -347.42 20.8452 1 0 0 nc +415.393 -289.516 20.8452 1 0 0 nc +730.084 -307.139 20.8452 0 0 1 nc +526.164 32.7279 20.8452 1 0 0 nc +762.812 -17.6227 20.8452 1 0 0 nc +-67.9734 319.727 20.8452 0 0 1 nc +329.797 314.692 20.8452 0 0 1 nc +-5.03507 561.41 20.8452 0 0 1 nc +422.945 521.129 20.8452 0 0 1 nc +-470.779 158.605 20.8452 1 0 0 nc +986.873 -115.807 20.8452 0 0 1 nc +906.312 201.403 20.8452 0 0 1 nc +-767.847 113.289 20.8452 1 0 0 nc +-579.033 445.603 20.8452 0 0 1 nc +-840.856 -246.718 20.8452 0 0 1 nc +206.221 -205.967 20.8452 0 0 1 nc +277.311 -252.33 20.8452 0 0 1 nc +271.13 -175.058 20.8452 1 0 0 nc +366.947 -110.15 20.8452 1 0 0 nc +397.855 -196.694 20.8452 0 0 1 nc +438.037 -88.514 20.8452 0 0 1 nc +286.584 -48.3327 20.8452 1 0 0 nc +212.403 -23.6057 20.8452 0 0 1 nc +280.402 10.3938 20.8452 0 0 1 nc +694.579 115.483 20.8452 0 0 1 nc +574.035 177.301 20.8452 0 0 1 nc grestore grestore showpage diff -r cd72eae05bdf -r 3c00344f49c9 doc/images/strongly_connected_components.eps --- a/doc/images/strongly_connected_components.eps Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/images/strongly_connected_components.eps Wed Oct 17 19:14:07 2018 +0200 @@ -1,6 +1,6 @@ %!PS-Adobe-2.0 EPSF-2.0 %%Creator: LEMON, graphToEps() -%%CreationDate: Fri Nov 4 13:47:12 2005 +%%CreationDate: Fri Mar 8 00:22:15 2013 %%BoundingBox: 0 0 842 596 %%EndComments /lb { setlinewidth setrgbcolor newpath moveto @@ -53,128 +53,128 @@ 695.963 -397.916 translate %Edges: gsave -2 setlinewidth 0 0 1 setrgbcolor newpath +4.56973 setlinewidth 0 0 1 setrgbcolor newpath 218.178 27.2723 moveto -192.373 -40.1551 188.622 -49.9556 169.228 -100.631 curveto stroke -newpath 164.939 -111.838 moveto 165.492 -99.2013 lineto 172.964 -102.061 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +195.849 -31.0725 190.033 -46.2697 176.306 -82.1369 curveto stroke +newpath 163.235 -116.291 moveto 165.206 -77.8889 lineto 187.405 -86.3849 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath 44.8044 15.5841 moveto -119.293 20.6059 129.775 21.3125 186.25 25.1199 curveto stroke -newpath 198.223 25.927 moveto 186.519 21.1289 lineto 185.981 29.1108 lineto closepath fill -2 setlinewidth 1 0 0 setrgbcolor newpath +109.705 19.9594 126.016 21.0591 166.493 23.7879 curveto stroke +newpath 202.98 26.2477 moveto 167.292 11.9299 lineto 165.694 35.6458 lineto closepath fill +4.56973 setlinewidth 1 0 0 setrgbcolor newpath 218.178 27.2723 moveto -285.395 -87.4449 290.763 -96.6058 348.102 -194.464 curveto stroke -newpath 354.169 -204.818 moveto 344.651 -196.487 lineto 351.554 -192.442 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +281.264 -80.3935 289.87 -95.0808 338.092 -177.379 curveto stroke +newpath 356.579 -208.932 moveto 327.837 -183.388 lineto 348.346 -171.371 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath 157.79 -130.517 moveto -108.71 -67.0521 102.27 -58.7243 64.3804 -9.72954 curveto stroke -newpath 57.0394 -0.236898 moveto 67.5446 -7.28254 lineto 61.2162 -12.1765 lineto closepath fill -2 setlinewidth 1 0 0 setrgbcolor newpath +114.446 -74.4692 104.358 -61.4239 76.4943 -25.394 curveto stroke +newpath 54.1228 3.53455 moveto 85.8959 -18.1234 lineto 67.0928 -32.6646 lineto closepath fill +4.56973 setlinewidth 1 0 0 setrgbcolor newpath -105.193 -261.035 moveto --35.6576 -132.801 -30.5923 -123.459 29.5506 -12.5464 curveto stroke -newpath 35.2708 -1.99743 moveto 33.0669 -14.4531 lineto 26.0343 -10.6397 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-39.4801 -139.85 -31.344 -124.846 20.1113 -29.9539 curveto stroke +newpath 37.5434 2.19358 moveto 30.559 -35.6192 lineto 9.66361 -24.2886 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -465.576 -42.8564 moveto --559.078 -25.5413 -569.47 -23.6169 -644.498 -9.72286 curveto stroke -newpath -656.297 -7.5378 moveto -643.77 -5.78973 lineto -645.226 -13.656 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-550.335 -27.1603 -566.8 -24.1113 -625.027 -13.3286 curveto stroke +newpath -660.985 -6.66971 moveto -622.863 -1.64245 lineto -627.191 -25.0148 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -574.666 -153.893 moveto --528.842 -107.252 -521.515 -99.794 -488.002 -65.683 curveto stroke -newpath -479.592 -57.123 moveto -485.149 -68.4863 lineto -490.856 -62.8797 lineto closepath fill -2 setlinewidth 1 0 0 setrgbcolor newpath +-535.911 -114.447 -524.692 -103.027 -501.88 -79.8085 curveto stroke +newpath -476.251 -53.7222 moveto -493.402 -88.1377 lineto -510.358 -71.4793 lineto closepath fill +4.56973 setlinewidth 1 0 0 setrgbcolor newpath -490.901 120.777 moveto --480.122 51.1328 -478.519 40.7713 -470.47 -11.2329 curveto stroke -newpath -468.635 -23.0917 moveto -474.423 -11.8447 lineto -466.517 -10.6212 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-481.623 60.8277 -479.143 44.8049 -473.499 8.33636 curveto stroke +newpath -467.906 -27.8032 moveto -485.244 6.51862 lineto -461.754 10.1541 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -675.963 -3.89604 moveto --632.116 -68.8235 -626.228 -77.5422 -592.575 -127.374 curveto stroke -newpath -585.859 -137.319 moveto -595.89 -129.612 lineto -589.26 -125.135 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-637.405 -60.9909 -628.201 -74.6206 -603.658 -110.963 curveto stroke +newpath -583.191 -141.27 moveto -613.507 -117.615 lineto -593.808 -104.312 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -490.901 120.777 moveto --435.445 215.844 -430.107 224.995 -384.3 303.522 curveto stroke -newpath -378.253 313.887 moveto -380.845 301.507 lineto -387.755 305.537 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-439.75 208.465 -431.238 223.057 -394.278 286.417 curveto stroke +newpath -375.851 318.006 moveto -384.012 280.429 lineto -404.543 292.406 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -266.879 114.933 moveto --367.067 117.547 -377.642 117.822 -458.912 119.943 curveto stroke -newpath -470.908 120.255 moveto -458.807 123.941 lineto -459.016 115.944 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-358.311 117.318 -375.109 117.756 -439.117 119.426 curveto stroke +newpath -475.674 120.38 moveto -438.807 131.307 lineto -439.426 107.545 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -368.176 331.163 moveto --322.511 233.685 -318.018 224.095 -280.454 143.911 curveto stroke -newpath -275.364 133.044 moveto -284.076 142.214 lineto -276.832 145.608 lineto closepath fill -2 setlinewidth 1 0 0 setrgbcolor newpath +-326.156 241.466 -318.997 226.186 -288.855 161.843 curveto stroke +newpath -273.341 128.727 moveto -299.617 156.801 lineto -278.092 166.885 lineto closepath fill +4.56973 setlinewidth 1 0 0 setrgbcolor newpath -266.879 114.933 moveto --224.004 235.52 -220.448 245.52 -184.094 347.765 curveto stroke -newpath -180.074 359.072 moveto -180.325 346.425 lineto -187.863 349.105 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-226.764 227.755 -221.069 243.774 -190.728 329.107 curveto stroke +newpath -178.477 363.564 moveto -179.53 325.126 lineto -201.926 333.089 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -251.294 -335.059 moveto --189.25 -303.624 -179.902 -298.887 -133.738 -275.498 curveto stroke -newpath -123.034 -270.074 moveto -131.93 -279.066 lineto -135.546 -271.93 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-198.044 -308.079 -183.61 -300.766 -151.402 -284.448 curveto stroke +newpath -118.781 -267.92 moveto -146.031 -295.049 lineto -156.774 -273.846 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -389.604 -136.361 moveto --327.15 -226.083 -321.098 -234.777 -269.576 -308.795 curveto stroke -newpath -262.72 -318.644 moveto -272.859 -311.081 lineto -266.293 -306.51 lineto closepath fill -2 setlinewidth 1 0 0 setrgbcolor newpath +-332.039 -219.059 -322.392 -232.919 -280.889 -292.543 curveto stroke +newpath -259.996 -322.557 moveto -290.643 -299.333 lineto -271.134 -285.753 lineto closepath fill +4.56973 setlinewidth 1 0 0 setrgbcolor newpath 5.84406 175.322 moveto --76.0754 267.926 -83.1051 275.873 -152.172 353.948 curveto stroke -newpath -160.122 362.936 moveto -149.176 356.598 lineto -155.168 351.298 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-70.5724 261.706 -81.8227 274.423 -139.051 339.116 curveto stroke +newpath -163.281 366.507 moveto -130.149 346.991 lineto -147.953 331.242 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath 169.478 311.683 moveto -96.8003 251.119 88.6819 244.353 30.4273 195.808 curveto stroke -newpath 21.2086 188.126 moveto 27.8666 198.881 lineto 32.988 192.735 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +103.641 256.819 90.7821 246.103 45.6398 208.485 curveto stroke +newpath 17.546 185.074 moveto 38.0313 217.615 lineto 53.2483 199.355 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath 342.851 111.037 moveto -263.766 202.563 256.831 210.589 190.4 287.47 curveto stroke -newpath 182.554 296.55 moveto 193.427 290.085 lineto 187.373 284.855 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +269.224 196.246 258.132 209.083 203.347 272.486 curveto stroke +newpath 179.437 300.157 moveto 212.34 280.257 lineto 194.354 264.716 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath 5.84406 175.322 moveto -163.16 145.314 173.605 143.321 311.418 117.033 curveto stroke -newpath 323.205 114.784 moveto 310.668 113.104 lineto 312.167 120.962 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +155.419 146.79 172.221 143.585 291.966 120.743 curveto stroke +newpath 327.888 113.891 moveto 289.739 109.069 lineto 294.193 132.418 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath 342.851 111.037 moveto -497.255 2.58683 505.964 -3.53033 643.932 -100.436 curveto stroke -newpath 653.752 -107.334 moveto 641.633 -103.71 lineto 646.231 -97.163 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +490.978 6.99574 505.015 -2.86383 627.727 -89.0547 curveto stroke +newpath 657.653 -110.074 moveto 620.896 -98.7802 lineto 634.558 -79.3291 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath 364.28 -222.074 moveto -354.298 -66.9063 353.616 -56.2971 344.905 79.1029 curveto stroke -newpath 344.135 91.0781 moveto 348.897 79.3597 lineto 340.914 78.8461 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +354.807 -74.8128 353.709 -57.7536 346.177 59.3416 curveto stroke +newpath 343.829 95.836 moveto 358.037 60.1045 lineto 334.316 58.5786 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath 670.118 -118.829 moveto -528.037 -166.793 517.967 -170.192 394.599 -211.839 curveto stroke -newpath 383.229 -215.677 moveto 393.32 -208.049 lineto 395.878 -215.629 lineto closepath fill -2 setlinewidth 1 0 0 setrgbcolor newpath +535.595 -164.241 519.412 -169.704 413.361 -205.505 curveto stroke +newpath 378.712 -217.202 moveto 409.559 -194.245 lineto 417.162 -216.766 lineto closepath fill +4.56973 setlinewidth 1 0 0 setrgbcolor newpath -105.193 -261.035 moveto -118.401 -242.479 129.015 -241.598 332.39 -224.721 curveto stroke -newpath 344.348 -223.728 moveto 332.72 -228.707 lineto 332.059 -220.734 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +110.939 -243.099 128.069 -241.677 312.655 -226.358 curveto stroke +newpath 349.1 -223.334 moveto 313.638 -238.202 lineto 311.672 -214.514 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -105.193 -261.035 moveto --160.867 -161.176 -166.028 -151.918 -212.336 -68.858 curveto stroke -newpath -218.179 -58.3769 moveto -208.842 -66.9102 lineto -215.829 -70.8058 lineto closepath fill -2 setlinewidth 0 0 1 setrgbcolor newpath +-156.746 -168.566 -164.987 -153.784 -202.693 -86.1539 curveto stroke +newpath -220.5 -54.2129 moveto -192.312 -80.3665 lineto -213.073 -91.9413 lineto closepath fill +4.56973 setlinewidth 0 0 1 setrgbcolor newpath -227.918 -40.9084 moveto --298.35 -82.4884 -307.42 -87.8432 -362.048 -120.093 curveto stroke -newpath -372.381 -126.193 moveto -364.081 -116.648 lineto -360.014 -123.537 lineto closepath fill +-290.327 -77.7521 -304.558 -86.1532 -344.995 -110.026 curveto stroke +newpath -376.487 -128.617 moveto -351.037 -99.7914 lineto -338.953 -120.26 lineto closepath fill grestore %Nodes: gsave --389.604 -136.361 20 0 1 0 nc --227.918 -40.9084 20 0 1 0 nc --105.193 -261.035 20 0 1 0 nc -364.28 -222.074 20 1 1 0 nc -670.118 -118.829 20 1 1 0 nc -342.851 111.037 20 1 1 0 nc -5.84406 175.322 20 1 1 0 nc -169.478 311.683 20 1 1 0 nc --173.374 377.916 20 1 0 1 nc --251.294 -335.059 20 0 1 0 nc --266.879 114.933 20 0 0 0 nc --368.176 331.163 20 0 0 0 nc --490.901 120.777 20 0 0 0 nc --574.666 -153.893 20 1 0 0 nc --675.963 -3.89604 20 1 0 0 nc --465.576 -42.8564 20 1 0 0 nc -44.8044 15.5841 20 0 0 1 nc -157.79 -130.517 20 0 0 1 nc -218.178 27.2723 20 0 0 1 nc +-389.604 -136.361 15.2324 0 1 0 nc +-227.918 -40.9084 15.2324 0 1 0 nc +-105.193 -261.035 15.2324 0 1 0 nc +364.28 -222.074 15.2324 1 1 0 nc +670.118 -118.829 15.2324 1 1 0 nc +342.851 111.037 15.2324 1 1 0 nc +5.84406 175.322 15.2324 1 1 0 nc +169.478 311.683 15.2324 1 1 0 nc +-173.374 377.916 15.2324 1 0 1 nc +-251.294 -335.059 15.2324 0 1 0 nc +-266.879 114.933 15.2324 0 0 0 nc +-368.176 331.163 15.2324 0 0 0 nc +-490.901 120.777 15.2324 0 0 0 nc +-574.666 -153.893 15.2324 1 0 0 nc +-675.963 -3.89604 15.2324 1 0 0 nc +-465.576 -42.8564 15.2324 1 0 0 nc +44.8044 15.5841 15.2324 0 0 1 nc +157.79 -130.517 15.2324 0 0 1 nc +218.178 27.2723 15.2324 0 0 1 nc grestore grestore showpage diff -r cd72eae05bdf -r 3c00344f49c9 doc/images/tsp.eps --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/images/tsp.eps Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,229 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Creator: LEMON, graphToEps() +%%CreationDate: Tue Jun 15 00:58:57 2010 +%%BoundingBox: 31 41 649 709 +%%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 +10 dup scale +%Arcs: +gsave +27 68 37 69 0 0 1 0.513798 l +37 69 27 68 0 0 1 0.513798 l +8 52 5 64 0 0 1 0.513798 l +5 64 8 52 0 0 1 0.513798 l +16 57 25 55 0 0 1 0.513798 l +25 55 16 57 0 0 1 0.513798 l +43 67 37 69 0 0 1 0.513798 l +37 69 43 67 0 0 1 0.513798 l +42 57 43 67 0 0 1 0.513798 l +43 67 42 57 0 0 1 0.513798 l +62 42 61 33 0 0 1 0.513798 l +61 33 62 42 0 0 1 0.513798 l +62 42 58 48 0 0 1 0.513798 l +58 48 62 42 0 0 1 0.513798 l +58 27 61 33 0 0 1 0.513798 l +61 33 58 27 0 0 1 0.513798 l +57 58 62 63 0 0 1 0.513798 l +62 63 57 58 0 0 1 0.513798 l +13 13 21 10 0 0 1 0.513798 l +21 10 13 13 0 0 1 0.513798 l +13 13 5 6 0 0 1 0.513798 l +5 6 13 13 0 0 1 0.513798 l +17 33 7 38 0 0 1 0.513798 l +7 38 17 33 0 0 1 0.513798 l +46 10 59 15 0 0 1 0.513798 l +59 15 46 10 0 0 1 0.513798 l +46 10 39 10 0 0 1 0.513798 l +39 10 46 10 0 0 1 0.513798 l +27 23 21 10 0 0 1 0.513798 l +21 10 27 23 0 0 1 0.513798 l +52 41 56 37 0 0 1 0.513798 l +56 37 52 41 0 0 1 0.513798 l +62 63 63 69 0 0 1 0.513798 l +63 69 62 63 0 0 1 0.513798 l +36 16 39 10 0 0 1 0.513798 l +39 10 36 16 0 0 1 0.513798 l +36 16 30 15 0 0 1 0.513798 l +30 15 36 16 0 0 1 0.513798 l +12 42 7 38 0 0 1 0.513798 l +7 38 12 42 0 0 1 0.513798 l +12 42 8 52 0 0 1 0.513798 l +8 52 12 42 0 0 1 0.513798 l +32 22 30 15 0 0 1 0.513798 l +30 15 32 22 0 0 1 0.513798 l +5 25 10 17 0 0 1 0.513798 l +10 17 5 25 0 0 1 0.513798 l +5 25 17 33 0 0 1 0.513798 l +17 33 5 25 0 0 1 0.513798 l +45 35 48 28 0 0 1 0.513798 l +48 28 45 35 0 0 1 0.513798 l +31 32 25 32 0 0 1 0.513798 l +25 32 31 32 0 0 1 0.513798 l +31 32 32 39 0 0 1 0.513798 l +32 39 31 32 0 0 1 0.513798 l +42 41 38 46 0 0 1 0.513798 l +38 46 42 41 0 0 1 0.513798 l +42 41 52 41 0 0 1 0.513798 l +52 41 42 41 0 0 1 0.513798 l +5 6 10 17 0 0 1 0.513798 l +10 17 5 6 0 0 1 0.513798 l +51 21 59 15 0 0 1 0.513798 l +59 15 51 21 0 0 1 0.513798 l +51 21 58 27 0 0 1 0.513798 l +58 27 51 21 0 0 1 0.513798 l +52 33 56 37 0 0 1 0.513798 l +56 37 52 33 0 0 1 0.513798 l +52 33 48 28 0 0 1 0.513798 l +48 28 52 33 0 0 1 0.513798 l +31 62 25 55 0 0 1 0.513798 l +25 55 31 62 0 0 1 0.513798 l +31 62 27 68 0 0 1 0.513798 l +27 68 31 62 0 0 1 0.513798 l +17 63 5 64 0 0 1 0.513798 l +5 64 17 63 0 0 1 0.513798 l +17 63 16 57 0 0 1 0.513798 l +16 57 17 63 0 0 1 0.513798 l +21 47 30 40 0 0 1 0.513798 l +30 40 21 47 0 0 1 0.513798 l +21 47 30 48 0 0 1 0.513798 l +30 48 21 47 0 0 1 0.513798 l +40 30 45 35 0 0 1 0.513798 l +45 35 40 30 0 0 1 0.513798 l +40 30 32 22 0 0 1 0.513798 l +32 22 40 30 0 0 1 0.513798 l +32 39 30 40 0 0 1 0.513798 l +30 40 32 39 0 0 1 0.513798 l +20 26 25 32 0 0 1 0.513798 l +25 32 20 26 0 0 1 0.513798 l +20 26 27 23 0 0 1 0.513798 l +27 23 20 26 0 0 1 0.513798 l +52 64 63 69 0 0 1 0.513798 l +63 69 52 64 0 0 1 0.513798 l +52 64 42 57 0 0 1 0.513798 l +42 57 52 64 0 0 1 0.513798 l +49 49 58 48 0 0 1 0.513798 l +58 48 49 49 0 0 1 0.513798 l +49 49 57 58 0 0 1 0.513798 l +57 58 49 49 0 0 1 0.513798 l +37 52 38 46 0 0 1 0.513798 l +38 46 37 52 0 0 1 0.513798 l +37 52 30 48 0 0 1 0.513798 l +30 48 37 52 0 0 1 0.513798 l +grestore +%Nodes: +gsave +30 40 0.856329 1 1 1 nc +56 37 0.856329 1 1 1 nc +48 28 0.856329 1 1 1 nc +25 55 0.856329 1 1 1 nc +25 32 0.856329 1 1 1 nc +32 39 0.856329 1 1 1 nc +39 10 0.856329 1 1 1 nc +30 15 0.856329 1 1 1 nc +5 64 0.856329 1 1 1 nc +21 10 0.856329 1 1 1 nc +10 17 0.856329 1 1 1 nc +5 6 0.856329 1 1 1 nc +59 15 0.856329 1 1 1 nc +45 35 0.856329 1 1 1 nc +32 22 0.856329 1 1 1 nc +63 69 0.856329 1 1 1 nc +62 63 0.856329 1 1 1 nc +61 33 0.856329 1 1 1 nc +46 10 0.856329 1 1 1 nc +38 46 0.856329 1 1 1 nc +37 69 0.856329 1 1 1 nc +58 27 0.856329 1 1 1 nc +58 48 0.856329 1 1 1 nc +43 67 0.856329 1 1 1 nc +30 48 0.856329 1 1 1 nc +27 68 0.856329 1 1 1 nc +7 38 0.856329 1 1 1 nc +8 52 0.856329 1 1 1 nc +16 57 0.856329 1 1 1 nc +42 57 0.856329 1 1 1 nc +62 42 0.856329 1 1 1 nc +57 58 0.856329 1 1 1 nc +13 13 0.856329 1 1 1 nc +17 33 0.856329 1 1 1 nc +27 23 0.856329 1 1 1 nc +52 41 0.856329 1 1 1 nc +36 16 0.856329 1 1 1 nc +12 42 0.856329 1 1 1 nc +5 25 0.856329 1 1 1 nc +31 32 0.856329 1 1 1 nc +42 41 0.856329 1 1 1 nc +51 21 0.856329 1 1 1 nc +52 33 0.856329 1 1 1 nc +31 62 0.856329 1 1 1 nc +17 63 0.856329 1 1 1 nc +21 47 0.856329 1 1 1 nc +40 30 0.856329 1 1 1 nc +20 26 0.856329 1 1 1 nc +52 64 0.856329 1 1 1 nc +49 49 0.856329 1 1 1 nc +37 52 0.856329 1 1 1 nc +grestore +grestore +showpage diff -r cd72eae05bdf -r 3c00344f49c9 doc/lgf.dox --- a/doc/lgf.dox Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/lgf.dox Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -63,11 +63,28 @@ 3 (40,10) 10 "Third node" \endcode -The \c \@arcs section is very similar to the \c \@nodes section, it -again starts with a header line describing the names of the maps, but -the \c "label" map is not obligatory here. The following lines -describe the arcs. The first two tokens of each line are the source -and the target node of the arc, respectively, then come the map +The \e LGF files can also contain bipartite graphs, in this case a +\c \@red_nodes and a \c \@blue_nodes sections describe the node set of the +graph. If a map is in both of these sections, then it can be used as a +regular node map. + +\code + @red_nodes + label only_red_map name + 1 "cherry" "John" + 2 "Santa Claus" "Jack" + 3 "blood" "Jason" + @blue_nodes + label name + 4 "Elisabeth" + 5 "Eve" +\endcode + +The \c \@arcs section is very similar to the \c \@nodes section, +it again starts with a header line describing the names of the maps, +but the \c "label" map is not obligatory here. The following lines +describe the arcs. The first two tokens of each line are +the source and the target node of the arc, respectively, then come the map values. The source and target tokens must be node labels. \code diff -r cd72eae05bdf -r 3c00344f49c9 doc/mainpage.dox.in --- a/doc/mainpage.dox.in Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/mainpage.dox.in Wed Oct 17 19:14:07 2018 +0200 @@ -25,7 +25,7 @@ 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. +tasks connected mainly with graphs and networks \cite DezsoJuttnerKovacs11Lemon. LEMON is an open source @@ -37,12 +37,12 @@ The project is maintained by the Egerváry Research Group on -Combinatorial Optimization \ref egres +Combinatorial Optimization \cite 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. +initiative \cite coinor. \section howtoread How to Read the Documentation diff -r cd72eae05bdf -r 3c00344f49c9 doc/min_cost_flow.dox --- a/doc/min_cost_flow.dox Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/min_cost_flow.dox Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * 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 \ref amo93networkflows. +and arc costs \cite 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 @@ -101,7 +101,7 @@ sup(u) \quad \forall u\in V \f] \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A \f] -However if the sum of the supply values is zero, then these two problems +However, if the sum of the supply values is zero, then these two problems are equivalent. The \ref min_cost_flow_algs "algorithms" in LEMON support the general form, so if you need the equality form, you have to ensure this additional diff -r cd72eae05bdf -r 3c00344f49c9 doc/references.bib --- a/doc/references.bib Mon Jul 16 16:21:40 2018 +0200 +++ b/doc/references.bib Wed Oct 17 19:14:07 2018 +0200 @@ -4,8 +4,7 @@ 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 + howpublished = {\url{http://lemon.cs.elte.hu/}} } @misc{egres, @@ -23,6 +22,28 @@ } +%%%%% Papers related to LEMON %%%%% + +@article{DezsoJuttnerKovacs11Lemon, + author = {B. Dezs{\H o} and A. J\"uttner and P. Kov\'acs}, + title = {{LEMON} -- an open source {C++} graph template library}, + journal = {Electronic Notes in Theoretical Computer Science}, + volume = {264}, + pages = {23--45}, + year = {2011}, + note = {Proc. 2nd Workshop on Generative Technologies} +} + +@article{KiralyKovacs12MCF, + author = {Z. Kir\'aly and P. Kov\'acs}, + title = {Efficient implementations of minimum-cost flow algorithms}, + journal = {Acta Universitatis Sapientiae, Informatica}, + year = {2012}, + volume = {4}, + pages = {67--118} +} + + %%%%% Other libraries %%%%%% @misc{boost, @@ -213,6 +234,16 @@ pages = {309-311} } +@article{hartmann93finding, + author = {Mark Hartmann and James B. Orlin}, + title = {Finding minimum cost to time ratio cycles with small + integral transit times}, + journal = {Networks}, + year = 1993, + volume = 23, + pages = {567-574} +} + @article{dasdan98minmeancycle, author = {Ali Dasdan and Rajesh K. Gupta}, title = {Faster Maximum and Minimum Mean Cycle Alogrithms for @@ -225,6 +256,17 @@ pages = {889-899} } +@article{dasdan04experimental, + author = {Ali Dasdan}, + title = {Experimental analysis of the fastest optimum cycle + ratio and mean algorithms}, + journal = {ACM Trans. Des. Autom. Electron. Syst.}, + year = 2004, + volume = 9, + issue = 4, + pages = {385-418} +} + %%%%% Minimum cost flow algorithms %%%%% @@ -297,5 +339,18 @@ school = {University College}, address = {Dublin, Ireland}, year = 1991, - month = sep, + month = sep } + +%%%%% Other algorithms %%%%% + +@article{grosso08maxclique, + author = {Andrea Grosso and Marco Locatelli and Wayne Pullan}, + title = {Simple ingredients leading to very efficient + heuristics for the maximum clique problem}, + journal = {Journal of Heuristics}, + year = 2008, + volume = 14, + number = 6, + pages = {587--612} +} diff -r cd72eae05bdf -r 3c00344f49c9 lemon/CMakeLists.txt --- a/lemon/CMakeLists.txt Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/CMakeLists.txt Wed Oct 17 19:14:07 2018 +0200 @@ -4,12 +4,12 @@ ) CONFIGURE_FILE( - ${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h ) CONFIGURE_FILE( - ${CMAKE_CURRENT_SOURCE_DIR}/lemon.pc.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/lemon.pc.in ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc @ONLY ) @@ -36,7 +36,7 @@ IF(LEMON_HAVE_CPLEX) SET(LEMON_SOURCES ${LEMON_SOURCES} cplex.cc) - INCLUDE_DIRECTORIES(${CPLEX_INCLUDE_DIRS}) + INCLUDE_DIRECTORIES(${ILOG_INCLUDE_DIRS}) ENDIF() IF(LEMON_HAVE_CLP) @@ -49,9 +49,19 @@ INCLUDE_DIRECTORIES(${COIN_INCLUDE_DIRS}) ENDIF() +IF(LEMON_HAVE_SOPLEX) + SET(LEMON_SOURCES ${LEMON_SOURCES} soplex.cc) + INCLUDE_DIRECTORIES(${SOPLEX_INCLUDE_DIRS}) +ENDIF() + ADD_LIBRARY(lemon ${LEMON_SOURCES}) + +TARGET_LINK_LIBRARIES(lemon + ${GLPK_LIBRARIES} ${COIN_LIBRARIES} ${ILOG_LIBRARIES} ${SOPLEX_LIBRARIES} + ) + IF(UNIX) - SET_TARGET_PROPERTIES(lemon PROPERTIES OUTPUT_NAME emon) + SET_TARGET_PROPERTIES(lemon PROPERTIES OUTPUT_NAME emon VERSION ${LEMON_VERSION} SOVERSION ${LEMON_VERSION}) ENDIF() INSTALL( diff -r cd72eae05bdf -r 3c00344f49c9 lemon/Makefile.am --- a/lemon/Makefile.am Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -EXTRA_DIST += \ - lemon/lemon.pc.in \ - lemon/lemon.pc.cmake \ - lemon/CMakeLists.txt \ - lemon/config.h.cmake - -pkgconfig_DATA += lemon/lemon.pc - -lib_LTLIBRARIES += lemon/libemon.la - -lemon_libemon_la_SOURCES = \ - lemon/arg_parser.cc \ - lemon/base.cc \ - lemon/color.cc \ - lemon/lp_base.cc \ - lemon/lp_skeleton.cc \ - lemon/random.cc \ - lemon/bits/windows.cc - -nodist_lemon_HEADERS = lemon/config.h - -lemon_libemon_la_CXXFLAGS = \ - $(AM_CXXFLAGS) \ - $(GLPK_CFLAGS) \ - $(CPLEX_CFLAGS) \ - $(SOPLEX_CXXFLAGS) \ - $(CLP_CXXFLAGS) \ - $(CBC_CXXFLAGS) - -lemon_libemon_la_LDFLAGS = \ - $(GLPK_LIBS) \ - $(CPLEX_LIBS) \ - $(SOPLEX_LIBS) \ - $(CLP_LIBS) \ - $(CBC_LIBS) - -if HAVE_GLPK -lemon_libemon_la_SOURCES += lemon/glpk.cc -endif - -if HAVE_CPLEX -lemon_libemon_la_SOURCES += lemon/cplex.cc -endif - -if HAVE_SOPLEX -lemon_libemon_la_SOURCES += lemon/soplex.cc -endif - -if HAVE_CLP -lemon_libemon_la_SOURCES += lemon/clp.cc -endif - -if HAVE_CBC -lemon_libemon_la_SOURCES += lemon/cbc.cc -endif - -lemon_HEADERS += \ - 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/cplex.h \ - lemon/cycle_canceling.h \ - lemon/dfs.h \ - lemon/dheap.h \ - lemon/dijkstra.h \ - lemon/dim2.h \ - lemon/dimacs.h \ - lemon/edge_set.h \ - lemon/elevator.h \ - 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 \ - lemon/lgf_writer.h \ - lemon/list_graph.h \ - lemon/lp.h \ - lemon/lp_base.h \ - lemon/lp_skeleton.h \ - lemon/maps.h \ - lemon/matching.h \ - lemon/math.h \ - 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 \ - lemon/unionfind.h \ - lemon/bits/windows.h - -bits_HEADERS += \ - lemon/bits/alteration_notifier.h \ - lemon/bits/array_map.h \ - lemon/bits/bezier.h \ - lemon/bits/default_map.h \ - lemon/bits/edge_set_extender.h \ - lemon/bits/enable_if.h \ - lemon/bits/graph_adaptor_extender.h \ - lemon/bits/graph_extender.h \ - lemon/bits/map_extender.h \ - lemon/bits/path_dump.h \ - lemon/bits/solver_bits.h \ - lemon/bits/traits.h \ - lemon/bits/variant.h \ - lemon/bits/vector_map.h - -concept_HEADERS += \ - lemon/concepts/digraph.h \ - lemon/concepts/graph.h \ - lemon/concepts/graph_components.h \ - lemon/concepts/heap.h \ - lemon/concepts/maps.h \ - lemon/concepts/path.h diff -r cd72eae05bdf -r 3c00344f49c9 lemon/adaptors.h --- a/lemon/adaptors.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/adaptors.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/arg_parser.cc --- a/lemon/arg_parser.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/arg_parser.cc Wed Oct 17 19:14:07 2018 +0200 @@ -221,9 +221,9 @@ const std::string &opt) { Opts::iterator o = _opts.find(opt); - Opts::iterator s = _opts.find(syn); LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'"); - LEMON_ASSERT(s==_opts.end(), "Option already used: '"+syn+"'"); + LEMON_ASSERT(_opts.find(syn)==_opts.end(), + "Option already used: '"+syn+"'"); ParData p; p.help=opt; p.mandatory=false; diff -r cd72eae05bdf -r 3c00344f49c9 lemon/arg_parser.h --- a/lemon/arg_parser.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/arg_parser.h Wed Oct 17 19:14:07 2018 +0200 @@ -26,6 +26,7 @@ #include #include #include +#include #include ///\ingroup misc diff -r cd72eae05bdf -r 3c00344f49c9 lemon/assert.h --- a/lemon/assert.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/assert.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -199,7 +199,7 @@ LEMON_FUNCTION_NAME, \ ::lemon::_assert_bits::cstringify(msg), \ #exp), 0))) -# if LEMON_ENABLE_DEBUG +# if defined LEMON_ENABLE_DEBUG # define LEMON_DEBUG(exp, msg) \ (static_cast (!!(exp) ? 0 : ( \ LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ diff -r cd72eae05bdf -r 3c00344f49c9 lemon/base.cc --- a/lemon/base.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/base.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -21,6 +21,7 @@ #include #include +#include namespace lemon { float Tolerance::def_epsilon = static_cast(1e-4); @@ -31,4 +32,6 @@ const Invalid INVALID = Invalid(); #endif + TimeStamp::Format TimeStamp::_format = TimeStamp::NORMAL; + } //namespace lemon diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bellman_ford.h --- a/lemon/bellman_ford.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bellman_ford.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -149,7 +149,7 @@ /// \ingroup shortest_path /// This class provides an efficient implementation of the Bellman-Ford /// algorithm. The maximum time complexity of the algorithm is - /// O(ne). + /// O(nm). /// /// The Bellman-Ford algorithm solves the single-source shortest path /// problem when the arcs can have negative lengths, but the digraph @@ -200,11 +200,12 @@ typedef typename TR::DistMap DistMap; /// The type of the paths. typedef PredMapPath Path; - ///\brief The \ref BellmanFordDefaultOperationTraits + ///\brief The \ref lemon::BellmanFordDefaultOperationTraits /// "operation traits class" of the algorithm. typedef typename TR::OperationTraits OperationTraits; - ///The \ref BellmanFordDefaultTraits "traits class" of the algorithm. + ///\brief The \ref lemon::BellmanFordDefaultTraits "traits class" + ///of the algorithm. typedef TR Traits; private: diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bfs.h --- a/lemon/bfs.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bfs.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -152,7 +152,7 @@ ///The type of the paths. typedef PredMapPath Path; - ///The \ref BfsDefaultTraits "traits class" of the algorithm. + ///The \ref lemon::BfsDefaultTraits "traits class" of the algorithm. typedef TR Traits; private: diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bin_heap.h --- a/lemon/bin_heap.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bin_heap.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/alteration_notifier.h --- a/lemon/bits/alteration_notifier.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/alteration_notifier.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -23,6 +23,7 @@ #include #include +#include //\ingroup graphbits //\file @@ -251,7 +252,7 @@ typedef std::list Observers; Observers _observers; - + lemon::bits::Lock _lock; public: @@ -332,14 +333,18 @@ protected: void attach(ObserverBase& observer) { + _lock.lock(); observer._index = _observers.insert(_observers.begin(), &observer); observer._notifier = this; + _lock.unlock(); } void detach(ObserverBase& observer) { + _lock.lock(); _observers.erase(observer._index); observer._index = _observers.end(); observer._notifier = 0; + _lock.unlock(); } public: diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/array_map.h --- a/lemon/bits/array_map.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/array_map.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/bezier.h --- a/lemon/bits/bezier.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/bezier.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/default_map.h --- a/lemon/bits/default_map.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/default_map.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/edge_set_extender.h --- a/lemon/bits/edge_set_extender.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/edge_set_extender.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/graph_adaptor_extender.h --- a/lemon/bits/graph_adaptor_extender.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/graph_adaptor_extender.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/graph_extender.h --- a/lemon/bits/graph_extender.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/graph_extender.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -746,6 +746,587 @@ }; + // \ingroup _graphbits + // + // \brief Extender for the BpGraphs + template + class BpGraphExtender : public Base { + typedef Base Parent; + + public: + + typedef BpGraphExtender BpGraph; + + typedef True UndirectedTag; + + typedef typename Parent::Node Node; + typedef typename Parent::RedNode RedNode; + typedef typename Parent::BlueNode BlueNode; + typedef typename Parent::Arc Arc; + typedef typename Parent::Edge Edge; + + // BpGraph extension + + using Parent::first; + using Parent::next; + using Parent::id; + + int maxId(Node) const { + return Parent::maxNodeId(); + } + + int maxId(RedNode) const { + return Parent::maxRedId(); + } + + int maxId(BlueNode) const { + return Parent::maxBlueId(); + } + + int maxId(Arc) const { + return Parent::maxArcId(); + } + + int maxId(Edge) const { + return Parent::maxEdgeId(); + } + + static Node fromId(int id, Node) { + return Parent::nodeFromId(id); + } + + static Arc fromId(int id, Arc) { + return Parent::arcFromId(id); + } + + static Edge fromId(int id, Edge) { + return Parent::edgeFromId(id); + } + + Node u(Edge e) const { return this->redNode(e); } + Node v(Edge e) const { return this->blueNode(e); } + + Node oppositeNode(const Node &n, const Edge &e) const { + if( n == u(e)) + return v(e); + else if( n == v(e)) + return u(e); + else + return INVALID; + } + + Arc oppositeArc(const Arc &arc) const { + return Parent::direct(arc, !Parent::direction(arc)); + } + + using Parent::direct; + Arc direct(const Edge &edge, const Node &node) const { + return Parent::direct(edge, Parent::redNode(edge) == node); + } + + RedNode asRedNode(const Node& node) const { + if (node == INVALID || Parent::blue(node)) { + return INVALID; + } else { + return Parent::asRedNodeUnsafe(node); + } + } + + BlueNode asBlueNode(const Node& node) const { + if (node == INVALID || Parent::red(node)) { + return INVALID; + } else { + return Parent::asBlueNodeUnsafe(node); + } + } + + // Alterable extension + + typedef AlterationNotifier NodeNotifier; + typedef AlterationNotifier RedNodeNotifier; + typedef AlterationNotifier BlueNodeNotifier; + typedef AlterationNotifier ArcNotifier; + typedef AlterationNotifier EdgeNotifier; + + + protected: + + mutable NodeNotifier node_notifier; + mutable RedNodeNotifier red_node_notifier; + mutable BlueNodeNotifier blue_node_notifier; + mutable ArcNotifier arc_notifier; + mutable EdgeNotifier edge_notifier; + + public: + + NodeNotifier& notifier(Node) const { + return node_notifier; + } + + RedNodeNotifier& notifier(RedNode) const { + return red_node_notifier; + } + + BlueNodeNotifier& notifier(BlueNode) const { + return blue_node_notifier; + } + + ArcNotifier& notifier(Arc) const { + return arc_notifier; + } + + EdgeNotifier& notifier(Edge) const { + return edge_notifier; + } + + + + class NodeIt : public Node { + const BpGraph* _graph; + public: + + NodeIt() {} + + NodeIt(Invalid i) : Node(i) { } + + explicit NodeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + NodeIt(const BpGraph& graph, const Node& node) + : Node(node), _graph(&graph) {} + + NodeIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + class RedNodeIt : public RedNode { + const BpGraph* _graph; + public: + + RedNodeIt() {} + + RedNodeIt(Invalid i) : RedNode(i) { } + + explicit RedNodeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + RedNodeIt(const BpGraph& graph, const RedNode& node) + : RedNode(node), _graph(&graph) {} + + RedNodeIt& operator++() { + _graph->next(static_cast(*this)); + return *this; + } + + }; + + class BlueNodeIt : public BlueNode { + const BpGraph* _graph; + public: + + BlueNodeIt() {} + + BlueNodeIt(Invalid i) : BlueNode(i) { } + + explicit BlueNodeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + BlueNodeIt(const BpGraph& graph, const BlueNode& node) + : BlueNode(node), _graph(&graph) {} + + BlueNodeIt& operator++() { + _graph->next(static_cast(*this)); + return *this; + } + + }; + + + class ArcIt : public Arc { + const BpGraph* _graph; + public: + + ArcIt() { } + + ArcIt(Invalid i) : Arc(i) { } + + explicit ArcIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + ArcIt(const BpGraph& graph, const Arc& arc) : + Arc(arc), _graph(&graph) { } + + ArcIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + + class OutArcIt : public Arc { + const BpGraph* _graph; + public: + + OutArcIt() { } + + OutArcIt(Invalid i) : Arc(i) { } + + OutArcIt(const BpGraph& graph, const Node& node) + : _graph(&graph) { + _graph->firstOut(*this, node); + } + + OutArcIt(const BpGraph& graph, const Arc& arc) + : Arc(arc), _graph(&graph) {} + + OutArcIt& operator++() { + _graph->nextOut(*this); + return *this; + } + + }; + + + class InArcIt : public Arc { + const BpGraph* _graph; + public: + + InArcIt() { } + + InArcIt(Invalid i) : Arc(i) { } + + InArcIt(const BpGraph& graph, const Node& node) + : _graph(&graph) { + _graph->firstIn(*this, node); + } + + InArcIt(const BpGraph& graph, const Arc& arc) : + Arc(arc), _graph(&graph) {} + + InArcIt& operator++() { + _graph->nextIn(*this); + return *this; + } + + }; + + + class EdgeIt : public Parent::Edge { + const BpGraph* _graph; + public: + + EdgeIt() { } + + EdgeIt(Invalid i) : Edge(i) { } + + explicit EdgeIt(const BpGraph& graph) : _graph(&graph) { + _graph->first(static_cast(*this)); + } + + EdgeIt(const BpGraph& graph, const Edge& edge) : + Edge(edge), _graph(&graph) { } + + EdgeIt& operator++() { + _graph->next(*this); + return *this; + } + + }; + + class IncEdgeIt : public Parent::Edge { + friend class BpGraphExtender; + const BpGraph* _graph; + bool _direction; + public: + + IncEdgeIt() { } + + IncEdgeIt(Invalid i) : Edge(i), _direction(false) { } + + IncEdgeIt(const BpGraph& graph, const Node &node) : _graph(&graph) { + _graph->firstInc(*this, _direction, node); + } + + IncEdgeIt(const BpGraph& graph, const Edge &edge, const Node &node) + : _graph(&graph), Edge(edge) { + _direction = (_graph->source(edge) == node); + } + + IncEdgeIt& operator++() { + _graph->nextInc(*this, _direction); + return *this; + } + }; + + // \brief Base node of the iterator + // + // Returns the base node (ie. the source in this case) of the iterator + Node baseNode(const OutArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the target in this case) of the + // iterator + Node runningNode(const OutArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + + // \brief Base node of the iterator + // + // Returns the base node (ie. the target in this case) of the iterator + Node baseNode(const InArcIt &arc) const { + return Parent::target(static_cast(arc)); + } + // \brief Running node of the iterator + // + // Returns the running node (ie. the source in this case) of the + // iterator + Node runningNode(const InArcIt &arc) const { + return Parent::source(static_cast(arc)); + } + + // Base node of the iterator + // + // Returns the base node of the iterator + Node baseNode(const IncEdgeIt &edge) const { + return edge._direction ? this->u(edge) : this->v(edge); + } + // Running node of the iterator + // + // Returns the running node of the iterator + Node runningNode(const IncEdgeIt &edge) const { + return edge._direction ? this->v(edge) : this->u(edge); + } + + // Mappable extension + + template + class NodeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit NodeMap(const BpGraph& bpgraph) + : Parent(bpgraph) {} + NodeMap(const BpGraph& bpgraph, const _Value& value) + : Parent(bpgraph, value) {} + + private: + NodeMap& operator=(const NodeMap& cmap) { + return operator=(cmap); + } + + template + NodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class RedNodeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit RedNodeMap(const BpGraph& bpgraph) + : Parent(bpgraph) {} + RedNodeMap(const BpGraph& bpgraph, const _Value& value) + : Parent(bpgraph, value) {} + + private: + RedNodeMap& operator=(const RedNodeMap& cmap) { + return operator=(cmap); + } + + template + RedNodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class BlueNodeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit BlueNodeMap(const BpGraph& bpgraph) + : Parent(bpgraph) {} + BlueNodeMap(const BpGraph& bpgraph, const _Value& value) + : Parent(bpgraph, value) {} + + private: + BlueNodeMap& operator=(const BlueNodeMap& cmap) { + return operator=(cmap); + } + + template + BlueNodeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + template + class ArcMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit ArcMap(const BpGraph& graph) + : Parent(graph) {} + ArcMap(const BpGraph& graph, const _Value& value) + : Parent(graph, value) {} + + private: + ArcMap& operator=(const ArcMap& cmap) { + return operator=(cmap); + } + + template + ArcMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + }; + + + template + class EdgeMap + : public MapExtender > { + typedef MapExtender > Parent; + + public: + explicit EdgeMap(const BpGraph& graph) + : Parent(graph) {} + + EdgeMap(const BpGraph& graph, const _Value& value) + : Parent(graph, value) {} + + private: + EdgeMap& operator=(const EdgeMap& cmap) { + return operator=(cmap); + } + + template + EdgeMap& operator=(const CMap& cmap) { + Parent::operator=(cmap); + return *this; + } + + }; + + // Alteration extension + + RedNode addRedNode() { + RedNode node = Parent::addRedNode(); + notifier(RedNode()).add(node); + notifier(Node()).add(node); + return node; + } + + BlueNode addBlueNode() { + BlueNode node = Parent::addBlueNode(); + notifier(BlueNode()).add(node); + notifier(Node()).add(node); + return node; + } + + Edge addEdge(const RedNode& from, const BlueNode& to) { + Edge edge = Parent::addEdge(from, to); + notifier(Edge()).add(edge); + std::vector av; + av.push_back(Parent::direct(edge, true)); + av.push_back(Parent::direct(edge, false)); + notifier(Arc()).add(av); + return edge; + } + + void clear() { + notifier(Arc()).clear(); + notifier(Edge()).clear(); + notifier(Node()).clear(); + notifier(BlueNode()).clear(); + notifier(RedNode()).clear(); + Parent::clear(); + } + + template + void build(const BpGraph& graph, NodeRefMap& nodeRef, + EdgeRefMap& edgeRef) { + Parent::build(graph, nodeRef, edgeRef); + notifier(RedNode()).build(); + notifier(BlueNode()).build(); + notifier(Node()).build(); + notifier(Edge()).build(); + notifier(Arc()).build(); + } + + void erase(const Node& node) { + Arc arc; + Parent::firstOut(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstOut(arc, node); + } + + Parent::firstIn(arc, node); + while (arc != INVALID ) { + erase(arc); + Parent::firstIn(arc, node); + } + + if (Parent::red(node)) { + notifier(RedNode()).erase(this->asRedNodeUnsafe(node)); + } else { + notifier(BlueNode()).erase(this->asBlueNodeUnsafe(node)); + } + + notifier(Node()).erase(node); + Parent::erase(node); + } + + void erase(const Edge& edge) { + std::vector av; + av.push_back(Parent::direct(edge, true)); + av.push_back(Parent::direct(edge, false)); + notifier(Arc()).erase(av); + notifier(Edge()).erase(edge); + Parent::erase(edge); + } + + BpGraphExtender() { + red_node_notifier.setContainer(*this); + blue_node_notifier.setContainer(*this); + node_notifier.setContainer(*this); + arc_notifier.setContainer(*this); + edge_notifier.setContainer(*this); + } + + ~BpGraphExtender() { + edge_notifier.clear(); + arc_notifier.clear(); + node_notifier.clear(); + blue_node_notifier.clear(); + red_node_notifier.clear(); + } + + }; + } #endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/lock.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/bits/lock.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,65 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_BITS_LOCK_H +#define LEMON_BITS_LOCK_H + +#include +#if defined(LEMON_USE_PTHREAD) +#include +#elif defined(LEMON_USE_WIN32_THREADS) +#include +#endif + +namespace lemon { + namespace bits { + +#if defined(LEMON_USE_PTHREAD) + class Lock { + public: + Lock() { + pthread_mutex_init(&_lock, 0); + } + ~Lock() { + pthread_mutex_destroy(&_lock); + } + void lock() { + pthread_mutex_lock(&_lock); + } + void unlock() { + pthread_mutex_unlock(&_lock); + } + + private: + pthread_mutex_t _lock; + }; +#elif defined(LEMON_USE_WIN32_THREADS) + class Lock : public WinLock {}; +#else + class Lock { + public: + Lock() {} + ~Lock() {} + void lock() {} + void unlock() {} + }; +#endif + } +} + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/map_extender.h --- a/lemon/bits/map_extender.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/map_extender.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/path_dump.h --- a/lemon/bits/path_dump.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/path_dump.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/solver_bits.h --- a/lemon/bits/solver_bits.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/solver_bits.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/traits.h --- a/lemon/bits/traits.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/traits.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -151,6 +151,88 @@ }; + template + struct RedNodeNotifierIndicator { + typedef InvalidType Type; + }; + template + struct RedNodeNotifierIndicator< + GR, + typename enable_if::type + > { + typedef typename GR::RedNodeNotifier Type; + }; + + template + class ItemSetTraits { + public: + + typedef GR BpGraph; + typedef GR Graph; + typedef GR Digraph; + + typedef typename GR::RedNode Item; + typedef typename GR::RedNodeIt ItemIt; + + typedef typename RedNodeNotifierIndicator::Type ItemNotifier; + + template + class Map : public GR::template RedNodeMap { + typedef typename GR::template RedNodeMap Parent; + + public: + typedef typename GR::template RedNodeMap Type; + typedef typename Parent::Value Value; + + Map(const GR& _bpgraph) : Parent(_bpgraph) {} + Map(const GR& _bpgraph, const Value& _value) + : Parent(_bpgraph, _value) {} + + }; + + }; + + template + struct BlueNodeNotifierIndicator { + typedef InvalidType Type; + }; + template + struct BlueNodeNotifierIndicator< + GR, + typename enable_if::type + > { + typedef typename GR::BlueNodeNotifier Type; + }; + + template + class ItemSetTraits { + public: + + typedef GR BpGraph; + typedef GR Graph; + typedef GR Digraph; + + typedef typename GR::BlueNode Item; + typedef typename GR::BlueNodeIt ItemIt; + + typedef typename BlueNodeNotifierIndicator::Type ItemNotifier; + + template + class Map : public GR::template BlueNodeMap { + typedef typename GR::template BlueNodeMap Parent; + + public: + typedef typename GR::template BlueNodeMap Type; + typedef typename Parent::Value Value; + + Map(const GR& _bpgraph) : Parent(_bpgraph) {} + Map(const GR& _bpgraph, const Value& _value) + : Parent(_bpgraph, _value) {} + + }; + + }; + template struct MapTraits { typedef False ReferenceMapTag; diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/windows.cc --- a/lemon/bits/windows.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/windows.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -21,7 +21,11 @@ #include -#ifdef WIN32 +#if defined(LEMON_WIN32) && defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wold-style-cast" +#endif + +#ifdef LEMON_WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif @@ -40,7 +44,7 @@ #else #include #include -#ifndef WIN32 +#ifndef LEMON_WIN32 #include #endif #include @@ -55,7 +59,7 @@ double &utime, double &stime, double &cutime, double &cstime) { -#ifdef WIN32 +#ifdef LEMON_WIN32 static const double ch = 4294967296.0e-7; static const double cl = 1.0e-7; @@ -94,11 +98,11 @@ std::string getWinFormattedDate() { std::ostringstream os; -#ifdef WIN32 +#ifdef LEMON_WIN32 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) && @@ -120,7 +124,7 @@ int getWinRndSeed() { -#ifdef WIN32 +#ifdef LEMON_WIN32 FILETIME time; GetSystemTimeAsFileTime(&time); return GetCurrentProcessId() + time.dwHighDateTime + time.dwLowDateTime; @@ -130,5 +134,37 @@ return getpid() + tv.tv_sec + tv.tv_usec; #endif } + + WinLock::WinLock() { +#ifdef LEMON_WIN32 + CRITICAL_SECTION *lock = new CRITICAL_SECTION; + InitializeCriticalSection(lock); + _repr = lock; +#else + _repr = 0; //Just to avoid 'unused variable' warning with clang +#endif + } + + WinLock::~WinLock() { +#ifdef LEMON_WIN32 + CRITICAL_SECTION *lock = static_cast(_repr); + DeleteCriticalSection(lock); + delete lock; +#endif + } + + void WinLock::lock() { +#ifdef LEMON_WIN32 + CRITICAL_SECTION *lock = static_cast(_repr); + EnterCriticalSection(lock); +#endif + } + + void WinLock::unlock() { +#ifdef LEMON_WIN32 + CRITICAL_SECTION *lock = static_cast(_repr); + LeaveCriticalSection(lock); +#endif + } } } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/bits/windows.h --- a/lemon/bits/windows.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/bits/windows.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -19,6 +19,7 @@ #ifndef LEMON_BITS_WINDOWS_H #define LEMON_BITS_WINDOWS_H +#include #include namespace lemon { @@ -28,6 +29,16 @@ double &cutime, double &cstime); std::string getWinFormattedDate(); int getWinRndSeed(); + + class WinLock { + public: + WinLock(); + ~WinLock(); + void lock(); + void unlock();\ + private: + void *_repr; + }; } } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/capacity_scaling.h --- a/lemon/capacity_scaling.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/capacity_scaling.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -27,6 +27,7 @@ #include #include #include +#include #include namespace lemon { @@ -66,9 +67,16 @@ /// /// \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. + /// \ref min_cost_flow "minimum cost flow" \cite amo93networkflows, + /// \cite edmondskarp72theoretical. It is an efficient dual + /// solution method, which runs in polynomial time + /// \f$O(m\log U (n+m)\log n)\f$, where U denotes the maximum + /// of node supply and arc capacity values. + /// + /// This algorithm is typically slower than \ref CostScaling and + /// \ref NetworkSimplex, but in special cases, it can be more + /// efficient than them. + /// (For more information, see \ref min_cost_flow_algs "the module page".) /// /// Most of the parameters of the problem (except for the digraph) /// can be given using separate functions, and the algorithm can be @@ -86,10 +94,11 @@ /// 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. + /// \warning Both \c V and \c C must be signed number types. + /// \warning Capacity bounds and supply values must be integer, but + /// arc costs can be arbitrary real numbers. + /// \warning This algorithm does not support negative costs for + /// arcs having infinite upper bound. #ifdef DOXYGEN template #else @@ -110,7 +119,8 @@ /// The type of the heap used for internal Dijkstra computations typedef typename TR::Heap Heap; - /// The \ref CapacityScalingDefaultTraits "traits class" of the algorithm + /// \brief The \ref lemon::CapacityScalingDefaultTraits "traits class" + /// of the algorithm typedef TR Traits; public: @@ -154,7 +164,7 @@ int _root; // Parameters of the problem - bool _have_lower; + bool _has_lower; Value _sum_supply; // Data structures for storing the digraph @@ -347,10 +357,9 @@ /// \return (*this) template CapacityScaling& lowerMap(const LowerMap& map) { - _have_lower = true; + _has_lower = true; for (ArcIt a(_graph); a != INVALID; ++a) { _lower[_arc_idf[a]] = map[a]; - _lower[_arc_idb[a]] = map[a]; } return *this; } @@ -422,7 +431,7 @@ /// 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 + /// with 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. @@ -534,7 +543,7 @@ _upper[j] = INF; _cost[j] = _forward[j] ? 1 : -1; } - _have_lower = false; + _has_lower = false; return *this; } @@ -637,7 +646,7 @@ /// \brief Return the total cost of the found flow. /// /// This function returns the total cost of the found flow. - /// Its complexity is O(e). + /// Its complexity is O(m). /// /// \note The return type of the function can be specified as a /// template parameter. For example, @@ -675,7 +684,8 @@ return _res_cap[_arc_idb[a]]; } - /// \brief Return the flow map (the primal solution). + /// \brief Copy the flow values (the primal solution) into the + /// given map. /// /// This function copies the flow value on each arc into the given /// map. The \c Value type of the algorithm must be convertible to @@ -699,7 +709,8 @@ return _pi[_node_id[n]]; } - /// \brief Return the potential map (the dual solution). + /// \brief Copy the potential values (the dual solution) into the + /// given map. /// /// This function copies the potential (dual value) of each node /// into the given map. @@ -729,6 +740,11 @@ } if (_sum_supply > 0) return INFEASIBLE; + // Check lower and upper bounds + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + + // Initialize vectors for (int i = 0; i != _root; ++i) { _pi[i] = 0; @@ -738,7 +754,7 @@ // Remove non-zero lower bounds const Value MAX = std::numeric_limits::max(); int last_out; - if (_have_lower) { + if (_has_lower) { for (int i = 0; i != _root; ++i) { last_out = _first_out[i+1]; for (int j = _first_out[i]; j != last_out; ++j) { @@ -823,6 +839,15 @@ return OPTIMAL; } + // Check if the upper bound is greater than or equal to the lower bound + // on each forward arc. + bool checkBoundMaps() { + for (int j = 0; j != _res_arc_num; ++j) { + if (_forward[j] && _upper[j] < _lower[j]) return false; + } + return true; + } + ProblemType start() { // Execute the algorithm ProblemType pt; @@ -832,10 +857,10 @@ pt = startWithoutScaling(); // Handle non-zero lower bounds - if (_have_lower) { + if (_has_lower) { int limit = _first_out[_root]; for (int j = 0; j != limit; ++j) { - if (!_forward[j]) _res_cap[j] += _lower[j]; + if (_forward[j]) _res_cap[_reverse[j]] += _lower[j]; } } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/cbc.cc --- a/lemon/cbc.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/cbc.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/cbc.h --- a/lemon/cbc.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/cbc.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -16,7 +16,6 @@ * */ -// -*- C++ -*- #ifndef LEMON_CBC_H #define LEMON_CBC_H diff -r cd72eae05bdf -r 3c00344f49c9 lemon/christofides_tsp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/christofides_tsp.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,254 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_CHRISTOFIDES_TSP_H +#define LEMON_CHRISTOFIDES_TSP_H + +/// \ingroup tsp +/// \file +/// \brief Christofides algorithm for symmetric TSP + +#include +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief Christofides algorithm for symmetric TSP. + /// + /// ChristofidesTsp implements Christofides' heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This a well-known approximation method for the TSP problem with + /// metric cost function. + /// It has a guaranteed approximation factor of 3/2 (i.e. it finds a tour + /// whose total cost is at most 3/2 of the optimum), but it usually + /// provides better solutions in practice. + /// This implementation runs in O(n3log(n)) time. + /// + /// The algorithm starts with a \ref spantree "minimum cost spanning tree" and + /// finds a \ref MaxWeightedPerfectMatching "minimum cost perfect matching" + /// in the subgraph induced by the nodes that have odd degree in the + /// spanning tree. + /// Finally, it constructs the tour from the \ref EulerIt "Euler traversal" + /// of the union of the spanning tree and the matching. + /// During this last step, the algorithm simply skips the visited nodes + /// (i.e. creates shortcuts) assuming that the triangle inequality holds + /// for the cost function. + /// + /// \tparam CM Type of the cost map. + /// + /// \warning CM::Value must be a signed number type. + template + class ChristofidesTsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + std::vector _path; + Cost _sum; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + ChristofidesTsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. + /// + /// \return The total cost of the found tour. + Cost run() { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + else if (_gr.nodeNum() == 2) { + _path.push_back(_gr(0)); + _path.push_back(_gr(1)); + return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; + } + + // Compute min. cost spanning tree + std::vector tree; + kruskal(_gr, _cost, std::back_inserter(tree)); + + FullGraph::NodeMap deg(_gr, 0); + for (int i = 0; i != int(tree.size()); ++i) { + Edge e = tree[i]; + ++deg[_gr.u(e)]; + ++deg[_gr.v(e)]; + } + + // Copy the induced subgraph of odd nodes + std::vector odd_nodes; + for (NodeIt u(_gr); u != INVALID; ++u) { + if (deg[u] % 2 == 1) odd_nodes.push_back(u); + } + + SmartGraph sgr; + SmartGraph::EdgeMap scost(sgr); + for (int i = 0; i != int(odd_nodes.size()); ++i) { + sgr.addNode(); + } + for (int i = 0; i != int(odd_nodes.size()); ++i) { + for (int j = 0; j != int(odd_nodes.size()); ++j) { + if (j == i) continue; + SmartGraph::Edge e = + sgr.addEdge(sgr.nodeFromId(i), sgr.nodeFromId(j)); + scost[e] = -_cost[_gr.edge(odd_nodes[i], odd_nodes[j])]; + } + } + + // Compute min. cost perfect matching + MaxWeightedPerfectMatching > + mwpm(sgr, scost); + mwpm.run(); + + for (SmartGraph::EdgeIt e(sgr); e != INVALID; ++e) { + if (mwpm.matching(e)) { + tree.push_back( _gr.edge(odd_nodes[sgr.id(sgr.u(e))], + odd_nodes[sgr.id(sgr.v(e))]) ); + } + } + + // Join the spanning tree and the matching + sgr.clear(); + for (int i = 0; i != _gr.nodeNum(); ++i) { + sgr.addNode(); + } + for (int i = 0; i != int(tree.size()); ++i) { + int ui = _gr.id(_gr.u(tree[i])), + vi = _gr.id(_gr.v(tree[i])); + sgr.addEdge(sgr.nodeFromId(ui), sgr.nodeFromId(vi)); + } + + // Compute the tour from the Euler traversal + SmartGraph::NodeMap visited(sgr, false); + for (EulerIt e(sgr); e != INVALID; ++e) { + SmartGraph::Node n = sgr.target(e); + if (!visited[n]) { + _path.push_back(_gr(sgr.id(n))); + visited[n] = true; + } + } + + _sum = _cost[_gr.edge(_path.back(), _path.front())]; + for (int i = 0; i < int(_path.size())-1; ++i) { + _sum += _cost[_gr.edge(_path[i], _path[i+1])]; + } + + return _sum; + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _path; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_path.begin(), _path.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_path.size()) - 1; ++i) { + path.addBack(_gr.arc(_path[i], _path[i+1])); + } + if (int(_path.size()) >= 2) { + path.addBack(_gr.arc(_path.back(), _path.front())); + } + } + + /// @} + + }; + +}; // namespace lemon + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/circulation.h --- a/lemon/circulation.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/circulation.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -195,7 +195,8 @@ class Circulation { public: - ///The \ref CirculationDefaultTraits "traits class" of the algorithm. + /// \brief The \ref lemon::CirculationDefaultTraits "traits class" + /// of the algorithm. typedef TR Traits; ///The type of the digraph the algorithm runs on. typedef typename Traits::Digraph Digraph; diff -r cd72eae05bdf -r 3c00344f49c9 lemon/clp.cc --- a/lemon/clp.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/clp.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/clp.h --- a/lemon/clp.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/clp.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/concept_check.h --- a/lemon/concept_check.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/concept_check.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -58,7 +58,7 @@ { #if !defined(NDEBUG) void (Concept::*x)() = & Concept::constraints; - ignore_unused_variable_warning(x); + ::lemon::ignore_unused_variable_warning(x); #endif } @@ -68,7 +68,7 @@ #if !defined(NDEBUG) typedef typename Concept::template Constraints ConceptCheck; void (ConceptCheck::*x)() = & ConceptCheck::constraints; - ignore_unused_variable_warning(x); + ::lemon::ignore_unused_variable_warning(x); #endif } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/concepts/bpgraph.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/concepts/bpgraph.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,1029 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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. + * + */ + +///\ingroup graph_concepts +///\file +///\brief The concept of undirected graphs. + +#ifndef LEMON_CONCEPTS_BPGRAPH_H +#define LEMON_CONCEPTS_BPGRAPH_H + +#include +#include +#include +#include + +namespace lemon { + namespace concepts { + + /// \ingroup graph_concepts + /// + /// \brief Class describing the concept of undirected bipartite graphs. + /// + /// This class describes the common interface of all undirected + /// bipartite graphs. + /// + /// Like all concept classes, it only provides an interface + /// without any sensible implementation. So any general algorithm for + /// undirected bipartite graphs should compile with this class, + /// but it will not run properly, of course. + /// An actual graph implementation like \ref ListBpGraph or + /// \ref SmartBpGraph may have additional functionality. + /// + /// The bipartite graphs also fulfill the concept of \ref Graph + /// "undirected graphs". Bipartite graphs provide a bipartition of + /// the node set, namely a red and blue set of the nodes. The + /// nodes can be iterated with the RedNodeIt and BlueNodeIt in the + /// two node sets. With RedNodeMap and BlueNodeMap values can be + /// assigned to the nodes in the two sets. + /// + /// The edges of the graph cannot connect two nodes of the same + /// set. The edges inherent orientation is from the red nodes to + /// the blue nodes. + /// + /// \sa Graph + class BpGraph { + private: + /// BpGraphs are \e not copy constructible. Use bpGraphCopy instead. + BpGraph(const BpGraph&) {} + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use bpGraphCopy instead. + void operator=(const BpGraph&) {} + + public: + /// Default constructor. + BpGraph() {} + + /// \brief Undirected graphs should be tagged with \c UndirectedTag. + /// + /// 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; + + /// 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 + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Node() { } + /// Copy constructor. + + /// Copy constructor. + /// + Node(const Node&) { } + + /// %Invalid constructor \& conversion. + + /// 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 \c INVALID. + bool operator==(Node) const { return true; } + + /// Inequality operator + + /// Inequality operator. + bool operator!=(Node) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \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; } + + }; + + /// Class to represent red nodes. + + /// This class represents the red nodes of the graph. It does + /// not supposed to be used directly, because the nodes can be + /// represented as Node instances. This class can be used as + /// template parameter for special map classes. + class RedNode : public Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + RedNode() { } + /// Copy constructor. + + /// Copy constructor. + /// + RedNode(const RedNode&) : Node() { } + + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + RedNode(Invalid) { } + + }; + + /// Class to represent blue nodes. + + /// This class represents the blue nodes of the graph. It does + /// not supposed to be used directly, because the nodes can be + /// represented as Node instances. This class can be used as + /// template parameter for special map classes. + class BlueNode : public Node { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the object to an undefined value. + BlueNode() { } + /// Copy constructor. + + /// Copy constructor. + /// + BlueNode(const BlueNode&) : Node() { } + + /// %Invalid constructor \& conversion. + + /// Initializes the object to be invalid. + /// \sa Invalid for more details. + BlueNode(Invalid) { } + + }; + + /// Iterator class for the red nodes. + + /// This iterator goes through each red node of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of red nodes in a graph \c g of type \c %BpGraph like this: + ///\code + /// int count=0; + /// for (BpGraph::RedNodeIt n(g); n!=INVALID; ++n) ++count; + ///\endcode + class RedNodeIt : public RedNode { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + RedNodeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + RedNodeIt(const RedNodeIt& n) : RedNode(n) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + RedNodeIt(Invalid) { } + /// Sets the iterator to the first red node. + + /// Sets the iterator to the first red node of the given + /// digraph. + explicit RedNodeIt(const BpGraph&) { } + /// Sets the iterator to the given red node. + + /// Sets the iterator to the given red node of the given + /// digraph. + RedNodeIt(const BpGraph&, const RedNode&) { } + /// Next node. + + /// Assign the iterator to the next red node. + /// + RedNodeIt& operator++() { return *this; } + }; + + /// Iterator class for the blue nodes. + + /// This iterator goes through each blue node of the graph. + /// Its usage is quite simple, for example, you can count the number + /// of blue nodes in a graph \c g of type \c %BpGraph like this: + ///\code + /// int count=0; + /// for (BpGraph::BlueNodeIt n(g); n!=INVALID; ++n) ++count; + ///\endcode + class BlueNodeIt : public BlueNode { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + BlueNodeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + BlueNodeIt(const BlueNodeIt& n) : BlueNode(n) { } + /// %Invalid constructor \& conversion. + + /// Initializes the iterator to be invalid. + /// \sa Invalid for more details. + BlueNodeIt(Invalid) { } + /// Sets the iterator to the first blue node. + + /// Sets the iterator to the first blue node of the given + /// digraph. + explicit BlueNodeIt(const BpGraph&) { } + /// Sets the iterator to the given blue node. + + /// Sets the iterator to the given blue node of the given + /// digraph. + BlueNodeIt(const BpGraph&, const BlueNode&) { } + /// Next node. + + /// Assign the iterator to the next blue node. + /// + BlueNodeIt& operator++() { return *this; } + }; + + /// Iterator class for the nodes. + + /// 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 %BpGraph like this: + ///\code + /// int count=0; + /// for (BpGraph::NodeIt n(g); n!=INVALID; ++n) ++count; + ///\endcode + class NodeIt : public Node { + public: + /// Default constructor + + /// 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. + + /// 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 the given digraph. + /// + explicit NodeIt(const BpGraph&) { } + /// Sets the iterator to the given node. + + /// Sets the iterator to the given node of the given digraph. + /// + NodeIt(const BpGraph&, const Node&) { } + /// Next node. + + /// Assign the iterator to the next node. + /// + NodeIt& operator++() { return *this; } + }; + + + /// The edge type of the graph + + /// 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 + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Edge() { } + /// Copy constructor. + + /// Copy constructor. + /// + Edge(const Edge&) { } + /// %Invalid constructor \& conversion. + + /// 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 \c INVALID. + bool operator==(Edge) const { return true; } + /// Inequality operator + + /// Inequality operator. + bool operator!=(Edge) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \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; } + }; + + /// Iterator class for the edges. + + /// 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 %BpGraph as follows: + ///\code + /// int count=0; + /// for(BpGraph::EdgeIt e(g); e!=INVALID; ++e) ++count; + ///\endcode + class EdgeIt : public Edge { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + EdgeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + EdgeIt(const EdgeIt& e) : Edge(e) { } + /// %Invalid constructor \& conversion. + + /// 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. + /// + explicit EdgeIt(const BpGraph&) { } + /// Sets the iterator to the given edge. + + /// Sets the iterator to the given edge of the given graph. + /// + EdgeIt(const BpGraph&, const Edge&) { } + /// Next edge + + /// Assign the iterator to the next edge. + /// + EdgeIt& operator++() { return *this; } + }; + + /// 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 %BpGraph as follows. + /// + ///\code + /// int count=0; + /// for(BpGraph::IncEdgeIt e(g, n); e!=INVALID; ++e) ++count; + ///\endcode + /// + /// \warning Loop edges will be iterated twice. + class IncEdgeIt : public Edge { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + IncEdgeIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + IncEdgeIt(const IncEdgeIt& e) : Edge(e) { } + /// %Invalid constructor \& conversion. + + /// 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(const BpGraph&, const Node&) { } + /// Sets the iterator to the given edge. + + /// Sets the iterator to the given edge of the given graph. + /// + IncEdgeIt(const BpGraph&, const Edge&) { } + /// Next incident edge + + /// Assign the iterator to the next incident edge + /// of the corresponding node. + IncEdgeIt& operator++() { return *this; } + }; + + /// The arc type of the graph + + /// 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 + + /// Default constructor. + /// \warning It sets the object to an undefined value. + Arc() { } + /// Copy constructor. + + /// Copy constructor. + /// + Arc(const Arc&) { } + /// %Invalid constructor \& conversion. + + /// 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 \c INVALID. + bool operator==(Arc) const { return true; } + /// Inequality operator + + /// Inequality operator. + bool operator!=(Arc) const { return true; } + + /// Artificial ordering operator. + + /// Artificial ordering operator. + /// + /// \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 \c Edge + + /// Converison to \c Edge. + /// + operator Edge() const { return Edge(); } + }; + + /// 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 %BpGraph as follows: + ///\code + /// int count=0; + /// for(BpGraph::ArcIt a(g); a!=INVALID; ++a) ++count; + ///\endcode + class ArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + ArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + ArcIt(const ArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// 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. + /// + explicit ArcIt(const BpGraph &g) + { + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given graph. + /// + ArcIt(const BpGraph&, const Arc&) { } + /// Next arc + + /// Assign the iterator to the next arc. + /// + ArcIt& operator++() { return *this; } + }; + + /// Iterator class for the outgoing arcs of a node. + + /// 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 a graph \c g of type \c %BpGraph as follows. + ///\code + /// int count=0; + /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count; + ///\endcode + class OutArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + OutArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + OutArcIt(const OutArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// 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(const BpGraph& n, const Node& g) { + ::lemon::ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given graph. + /// + OutArcIt(const BpGraph&, const Arc&) { } + /// Next outgoing arc + + /// Assign the iterator to the next + /// outgoing arc of the corresponding node. + OutArcIt& operator++() { return *this; } + }; + + /// Iterator class for the incoming arcs of a node. + + /// 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 %BpGraph as follows. + ///\code + /// int count=0; + /// for (Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count; + ///\endcode + class InArcIt : public Arc { + public: + /// Default constructor + + /// Default constructor. + /// \warning It sets the iterator to an undefined value. + InArcIt() { } + /// Copy constructor. + + /// Copy constructor. + /// + InArcIt(const InArcIt& e) : Arc(e) { } + /// %Invalid constructor \& conversion. + + /// 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(const BpGraph& g, const Node& n) { + ::lemon::ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(g); + } + /// Sets the iterator to the given arc. + + /// Sets the iterator to the given arc of the given graph. + /// + InArcIt(const BpGraph&, const Arc&) { } + /// Next incoming arc + + /// Assign the iterator to the next + /// incoming arc of the corresponding node. + InArcIt& operator++() { return *this; } + }; + + /// \brief Standard graph map type for the nodes. + /// + /// Standard graph map type for the nodes. + /// It conforms to the ReferenceMap concept. + template + class NodeMap : public ReferenceMap + { + public: + + /// Constructor + explicit NodeMap(const BpGraph&) { } + /// Constructor with given initial value + NodeMap(const BpGraph&, T) { } + + private: + ///Copy constructor + NodeMap(const NodeMap& nm) : + ReferenceMap(nm) { } + ///Assignment operator + template + NodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the red nodes. + /// + /// Standard graph map type for the red nodes. + /// It conforms to the ReferenceMap concept. + template + class RedNodeMap : public ReferenceMap + { + public: + + /// Constructor + explicit RedNodeMap(const BpGraph&) { } + /// Constructor with given initial value + RedNodeMap(const BpGraph&, T) { } + + private: + ///Copy constructor + RedNodeMap(const RedNodeMap& nm) : + ReferenceMap(nm) { } + ///Assignment operator + template + RedNodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the blue nodes. + /// + /// Standard graph map type for the blue nodes. + /// It conforms to the ReferenceMap concept. + template + class BlueNodeMap : public ReferenceMap + { + public: + + /// Constructor + explicit BlueNodeMap(const BpGraph&) { } + /// Constructor with given initial value + BlueNodeMap(const BpGraph&, T) { } + + private: + ///Copy constructor + BlueNodeMap(const BlueNodeMap& nm) : + ReferenceMap(nm) { } + ///Assignment operator + template + BlueNodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Standard graph map type for the arcs. + /// + /// Standard graph map type for the arcs. + /// It conforms to the ReferenceMap concept. + template + class ArcMap : public ReferenceMap + { + public: + + /// Constructor + explicit ArcMap(const BpGraph&) { } + /// Constructor with given initial value + ArcMap(const BpGraph&, T) { } + + private: + ///Copy constructor + ArcMap(const ArcMap& em) : + ReferenceMap(em) { } + ///Assignment operator + template + ArcMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \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: + + /// Constructor + explicit EdgeMap(const BpGraph&) { } + /// Constructor with given initial value + EdgeMap(const BpGraph&, T) { } + + private: + ///Copy constructor + EdgeMap(const EdgeMap& em) : + ReferenceMap(em) {} + ///Assignment operator + template + EdgeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + }; + + /// \brief Gives back %true for red nodes. + /// + /// Gives back %true for red nodes. + bool red(const Node&) const { return true; } + + /// \brief Gives back %true for blue nodes. + /// + /// Gives back %true for blue nodes. + bool blue(const Node&) const { return true; } + + /// \brief Converts the node to red node object. + /// + /// This function converts unsafely the node to red node + /// object. It should be called only if the node is from the red + /// partition or INVALID. + RedNode asRedNodeUnsafe(const Node&) const { return RedNode(); } + + /// \brief Converts the node to blue node object. + /// + /// This function converts unsafely the node to blue node + /// object. It should be called only if the node is from the red + /// partition or INVALID. + BlueNode asBlueNodeUnsafe(const Node&) const { return BlueNode(); } + + /// \brief Converts the node to red node object. + /// + /// This function converts safely the node to red node + /// object. If the node is not from the red partition, then it + /// returns INVALID. + RedNode asRedNode(const Node&) const { return RedNode(); } + + /// \brief Converts the node to blue node object. + /// + /// This function converts unsafely the node to blue node + /// object. If the node is not from the blue partition, then it + /// returns INVALID. + BlueNode asBlueNode(const Node&) const { return BlueNode(); } + + /// \brief Gives back the red end node of the edge. + /// + /// Gives back the red end node of the edge. + RedNode redNode(const Edge&) const { return RedNode(); } + + /// \brief Gives back the blue end node of the edge. + /// + /// Gives back the blue end node of the edge. + BlueNode blueNode(const Edge&) const { return BlueNode(); } + + /// \brief The first node of the edge. + /// + /// It is a synonim for the \c redNode(). + Node u(Edge) const { return INVALID; } + + /// \brief The second node of the edge. + /// + /// It is a synonim for the \c blueNode(). + Node v(Edge) const { return INVALID; } + + /// \brief The source node of the arc. + /// + /// Returns the source node of the given arc. + Node source(Arc) const { return INVALID; } + + /// \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 The red ID of the node. + /// + /// Returns the red ID of the given node. + int id(RedNode) const { return -1; } + + /// \brief The blue ID of the node. + /// + /// Returns the blue ID of the given node. + int id(BlueNode) const { return -1; } + + /// \brief The ID of the edge. + /// + /// Returns the ID of the given edge. + int id(Edge) const { return -1; } + + /// \brief The ID of the arc. + /// + /// Returns the ID of the given arc. + int id(Arc) const { return -1; } + + /// \brief The node with the given ID. + /// + /// 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 The edge with the given ID. + /// + /// 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 The arc with the given ID. + /// + /// 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 An upper bound on the node IDs. + /// + /// Returns an upper bound on the node IDs. + int maxNodeId() const { return -1; } + + /// \brief An upper bound on the red IDs. + /// + /// Returns an upper bound on the red IDs. + int maxRedId() const { return -1; } + + /// \brief An upper bound on the blue IDs. + /// + /// Returns an upper bound on the blue IDs. + int maxBlueId() const { return -1; } + + /// \brief An upper bound on the edge IDs. + /// + /// Returns an upper bound on the edge IDs. + int maxEdgeId() const { return -1; } + + /// \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 given arc goes from a red node to a blue node. + 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 source of the node + /// will be a red node. + 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 {} + + void firstRed(RedNode&) const {} + void nextRed(RedNode&) const {} + + void firstBlue(BlueNode&) const {} + void nextBlue(BlueNode&) const {} + + void first(Edge&) const {} + void next(Edge&) const {} + + void first(Arc&) const {} + void next(Arc&) const {} + + void firstOut(Arc&, Node) const {} + void nextOut(Arc&) const {} + + void firstIn(Arc&, Node) const {} + void nextIn(Arc&) const {} + + void firstInc(Edge &, bool &, const Node &) const {} + void nextInc(Edge &, bool &) const {} + + // The second parameter is dummy. + Node fromId(int, Node) const { return INVALID; } + // The second parameter is dummy. + Edge fromId(int, Edge) const { return INVALID; } + // The second parameter is dummy. + Arc fromId(int, Arc) const { return INVALID; } + + // Dummy parameter. + int maxId(Node) const { return -1; } + // Dummy parameter. + int maxId(RedNode) const { return -1; } + // Dummy parameter. + int maxId(BlueNode) const { return -1; } + // Dummy parameter. + int maxId(Edge) const { return -1; } + // Dummy parameter. + int maxId(Arc) const { return -1; } + + /// \brief The base 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 of the given incident edge iterator. + Node runningNode(IncEdgeIt) const { return INVALID; } + + /// \brief The base 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 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. + /// + /// Returns the base node of the given incoming arc iterator + /// (i.e. the target node of the corresponding arc). + Node baseNode(InArcIt) const { return INVALID; } + + /// \brief The running node of the iterator. + /// + /// Returns the running node of the given incoming arc iterator + /// (i.e. the source node of the corresponding arc). + Node runningNode(InArcIt) const { return INVALID; } + + template + struct Constraints { + void constraints() { + checkConcept(); + checkConcept, _BpGraph>(); + checkConcept, _BpGraph>(); + checkConcept, _BpGraph>(); + } + }; + + }; + + } + +} + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/concepts/digraph.h --- a/lemon/concepts/digraph.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/concepts/digraph.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -312,7 +312,9 @@ /// Sets the iterator to the first arc of the given digraph. /// - explicit ArcIt(const Digraph& g) { ignore_unused_variable_warning(g); } + explicit ArcIt(const Digraph& g) { + ::lemon::ignore_unused_variable_warning(g); + } /// Sets the iterator to the given arc. /// Sets the iterator to the given arc of the given digraph. @@ -409,13 +411,13 @@ /// \brief The base node of the iterator. /// - /// Returns the base node of the given incomming arc iterator + /// Returns the base node of the given incoming arc iterator /// (i.e. the target node of the corresponding arc). Node baseNode(InArcIt) const { return INVALID; } /// \brief The running node of the iterator. /// - /// Returns the running node of the given incomming arc iterator + /// Returns the running node of the given incoming arc iterator /// (i.e. the source node of the corresponding arc). Node runningNode(InArcIt) const { return INVALID; } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/concepts/graph.h --- a/lemon/concepts/graph.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/concepts/graph.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -72,10 +72,10 @@ /// \sa Digraph class Graph { private: - /// Graphs are \e not copy constructible. Use DigraphCopy instead. + /// Graphs are \e not copy constructible. Use GraphCopy instead. Graph(const Graph&) {} /// \brief Assignment of a graph to another one is \e not allowed. - /// Use DigraphCopy instead. + /// Use GraphCopy instead. void operator=(const Graph&) {} public: @@ -396,7 +396,9 @@ /// Sets the iterator to the first arc of the given graph. /// - explicit ArcIt(const Graph &g) { ignore_unused_variable_warning(g); } + explicit ArcIt(const Graph &g) { + ::lemon::ignore_unused_variable_warning(g); + } /// Sets the iterator to the given arc. /// Sets the iterator to the given arc of the given graph. @@ -442,8 +444,8 @@ /// Sets the iterator to the first outgoing arc of the given node. /// OutArcIt(const Graph& n, const Node& g) { - ignore_unused_variable_warning(n); - ignore_unused_variable_warning(g); + ::lemon::ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(g); } /// Sets the iterator to the given arc. @@ -490,8 +492,8 @@ /// Sets the iterator to the first incoming arc of the given node. /// InArcIt(const Graph& g, const Node& n) { - ignore_unused_variable_warning(n); - ignore_unused_variable_warning(g); + ::lemon::ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(g); } /// Sets the iterator to the given arc. @@ -757,13 +759,13 @@ /// \brief The base node of the iterator. /// - /// Returns the base node of the given incomming arc iterator + /// Returns the base node of the given incoming arc iterator /// (i.e. the target node of the corresponding arc). Node baseNode(InArcIt) const { return INVALID; } /// \brief The running node of the iterator. /// - /// Returns the running node of the given incomming arc iterator + /// Returns the running node of the given incoming arc iterator /// (i.e. the source node of the corresponding arc). Node runningNode(InArcIt) const { return INVALID; } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/concepts/graph_components.h --- a/lemon/concepts/graph_components.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/concepts/graph_components.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -108,6 +108,8 @@ i1 = i2 = i3; bool b; + ::lemon::ignore_unused_variable_warning(b); + b = (ia == ib) && (ia != ib); b = (ia == INVALID) && (ib != INVALID); b = (ia < ib); @@ -287,7 +289,7 @@ e = graph.oppositeArc(e); ue = e; bool d = graph.direction(e); - ignore_unused_variable_warning(d); + ::lemon::ignore_unused_variable_warning(d); } } @@ -297,6 +299,172 @@ }; + /// \brief Base skeleton class for undirected bipartite graphs. + /// + /// This class describes the base interface of undirected + /// bipartite graph types. All bipartite graph %concepts have to + /// conform to this class. It extends the interface of \ref + /// BaseGraphComponent with an \c Edge type and functions to get + /// the end nodes of edges, to convert from arcs to edges and to + /// get both direction of edges. + class BaseBpGraphComponent : public BaseGraphComponent { + public: + + typedef BaseBpGraphComponent BpGraph; + + typedef BaseDigraphComponent::Node Node; + typedef BaseDigraphComponent::Arc Arc; + + /// \brief Class to represent red nodes. + /// + /// This class represents the red nodes of the graph. The red + /// nodes can also be used as normal nodes. + class RedNode : public Node { + typedef Node Parent; + + public: + /// \brief Default constructor. + /// + /// Default constructor. + /// \warning The default constructor is not required to set + /// the item to some well-defined value. So you should consider it + /// as uninitialized. + RedNode() {} + + /// \brief Copy constructor. + /// + /// Copy constructor. + RedNode(const RedNode &) : Parent() {} + + /// \brief Constructor for conversion from \c INVALID. + /// + /// Constructor for conversion from \c INVALID. + /// It initializes the item to be invalid. + /// \sa Invalid for more details. + RedNode(Invalid) {} + }; + + /// \brief Class to represent blue nodes. + /// + /// This class represents the blue nodes of the graph. The blue + /// nodes can also be used as normal nodes. + class BlueNode : public Node { + typedef Node Parent; + + public: + /// \brief Default constructor. + /// + /// Default constructor. + /// \warning The default constructor is not required to set + /// the item to some well-defined value. So you should consider it + /// as uninitialized. + BlueNode() {} + + /// \brief Copy constructor. + /// + /// Copy constructor. + BlueNode(const BlueNode &) : Parent() {} + + /// \brief Constructor for conversion from \c INVALID. + /// + /// Constructor for conversion from \c INVALID. + /// It initializes the item to be invalid. + /// \sa Invalid for more details. + BlueNode(Invalid) {} + + /// \brief Constructor for conversion from a node. + /// + /// Constructor for conversion from a node. The conversion can + /// be invalid, since the Node can be member of the red + /// set. + BlueNode(const Node&) {} + }; + + /// \brief Gives back %true for red nodes. + /// + /// Gives back %true for red nodes. + bool red(const Node&) const { return true; } + + /// \brief Gives back %true for blue nodes. + /// + /// Gives back %true for blue nodes. + bool blue(const Node&) const { return true; } + + /// \brief Gives back the red end node of the edge. + /// + /// Gives back the red end node of the edge. + RedNode redNode(const Edge&) const { return RedNode(); } + + /// \brief Gives back the blue end node of the edge. + /// + /// Gives back the blue end node of the edge. + BlueNode blueNode(const Edge&) const { return BlueNode(); } + + /// \brief Converts the node to red node object. + /// + /// This function converts unsafely the node to red node + /// object. It should be called only if the node is from the red + /// partition or INVALID. + RedNode asRedNodeUnsafe(const Node&) const { return RedNode(); } + + /// \brief Converts the node to blue node object. + /// + /// This function converts unsafely the node to blue node + /// object. It should be called only if the node is from the red + /// partition or INVALID. + BlueNode asBlueNodeUnsafe(const Node&) const { return BlueNode(); } + + /// \brief Converts the node to red node object. + /// + /// This function converts safely the node to red node + /// object. If the node is not from the red partition, then it + /// returns INVALID. + RedNode asRedNode(const Node&) const { return RedNode(); } + + /// \brief Converts the node to blue node object. + /// + /// This function converts unsafely the node to blue node + /// object. If the node is not from the blue partition, then it + /// returns INVALID. + BlueNode asBlueNode(const Node&) const { return BlueNode(); } + + template + struct Constraints { + typedef typename _BpGraph::Node Node; + typedef typename _BpGraph::RedNode RedNode; + typedef typename _BpGraph::BlueNode BlueNode; + typedef typename _BpGraph::Arc Arc; + typedef typename _BpGraph::Edge Edge; + + void constraints() { + checkConcept(); + checkConcept, RedNode>(); + checkConcept, BlueNode>(); + { + Node n; + RedNode rn; + BlueNode bn; + Node rnan = rn; + Node bnan = bn; + Edge e; + bool b; + b = bpgraph.red(rnan); + b = bpgraph.blue(bnan); + rn = bpgraph.redNode(e); + bn = bpgraph.blueNode(e); + rn = bpgraph.asRedNodeUnsafe(rnan); + bn = bpgraph.asBlueNodeUnsafe(bnan); + rn = bpgraph.asRedNode(rnan); + bn = bpgraph.asBlueNode(bnan); + ::lemon::ignore_unused_variable_warning(b); + } + } + + const _BpGraph& bpgraph; + }; + + }; + /// \brief Skeleton class for \e idable directed graphs. /// /// This class describes the interface of \e idable directed graphs. @@ -366,9 +534,9 @@ arc = digraph.arcFromId(eid); nid = digraph.maxNodeId(); - ignore_unused_variable_warning(nid); + ::lemon::ignore_unused_variable_warning(nid); eid = digraph.maxArcId(); - ignore_unused_variable_warning(eid); + ::lemon::ignore_unused_variable_warning(eid); } const _Digraph& digraph; @@ -421,7 +589,7 @@ ueid = graph.id(edge); edge = graph.edgeFromId(ueid); ueid = graph.maxEdgeId(); - ignore_unused_variable_warning(ueid); + ::lemon::ignore_unused_variable_warning(ueid); } const _Graph& graph; @@ -429,6 +597,70 @@ }; }; + /// \brief Skeleton class for \e idable undirected bipartite graphs. + /// + /// This class describes the interface of \e idable undirected + /// bipartite graphs. It extends \ref IDableGraphComponent with + /// the core ID functions of undirected bipartite graphs. Beside + /// the regular node ids, this class also provides ids within the + /// the red and blue sets of the nodes. This concept is part of + /// the BpGraph concept. + template + class IDableBpGraphComponent : public IDableGraphComponent { + public: + + typedef BAS Base; + typedef IDableGraphComponent Parent; + typedef typename Base::Node Node; + typedef typename Base::RedNode RedNode; + typedef typename Base::BlueNode BlueNode; + + using Parent::id; + + /// \brief Return a unique integer id for the given node in the red set. + /// + /// Return a unique integer id for the given node in the red set. + int id(const RedNode&) const { return -1; } + + /// \brief Return a unique integer id for the given node in the blue set. + /// + /// Return a unique integer id for the given node in the blue set. + int id(const BlueNode&) const { return -1; } + + /// \brief Return an integer greater or equal to the maximum + /// node id in the red set. + /// + /// Return an integer greater or equal to the maximum + /// node id in the red set. + int maxRedId() const { return -1; } + + /// \brief Return an integer greater or equal to the maximum + /// node id in the blue set. + /// + /// Return an integer greater or equal to the maximum + /// node id in the blue set. + int maxBlueId() const { return -1; } + + template + struct Constraints { + + void constraints() { + checkConcept, _BpGraph>(); + typename _BpGraph::Node node; + typename _BpGraph::RedNode red; + typename _BpGraph::BlueNode blue; + int rid = bpgraph.id(red); + int bid = bpgraph.id(blue); + rid = bpgraph.maxRedId(); + bid = bpgraph.maxBlueId(); + ::lemon::ignore_unused_variable_warning(rid); + ::lemon::ignore_unused_variable_warning(bid); + } + + const _BpGraph& bpgraph; + }; + }; + /// \brief Concept class for \c NodeIt, \c ArcIt and \c EdgeIt types. /// /// This class describes the concept of \c NodeIt, \c ArcIt and @@ -494,8 +726,8 @@ _GraphItemIt it2; _GraphItemIt it3 = it1; _GraphItemIt it4 = INVALID; - ignore_unused_variable_warning(it3); - ignore_unused_variable_warning(it4); + ::lemon::ignore_unused_variable_warning(it3); + ::lemon::ignore_unused_variable_warning(it4); it2 = ++it1; ++it2 = it1; @@ -585,8 +817,8 @@ _GraphIncIt it2; _GraphIncIt it3 = it1; _GraphIncIt it4 = INVALID; - ignore_unused_variable_warning(it3); - ignore_unused_variable_warning(it4); + ::lemon::ignore_unused_variable_warning(it3); + ::lemon::ignore_unused_variable_warning(it4); it2 = ++it1; ++it2 = it1; @@ -643,15 +875,15 @@ /// This function gives back the next arc in the iteration order. void next(Arc&) const {} - /// \brief Return the first arc incomming to the given node. + /// \brief Return the first arc incoming to the given node. /// - /// This function gives back the first arc incomming to the + /// This function gives back the first arc incoming to the /// given node. void firstIn(Arc&, const Node&) const {} - /// \brief Return the next arc incomming to the given node. + /// \brief Return the next arc incoming to the given node. /// - /// This function gives back the next arc incomming to the + /// This function gives back the next arc incoming to the /// given node. void nextIn(Arc&) const {} @@ -768,7 +1000,7 @@ n = digraph.runningNode(iait); n = digraph.baseNode(oait); n = digraph.runningNode(oait); - ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(n); } } @@ -902,6 +1134,97 @@ }; }; + /// \brief Skeleton class for iterable undirected bipartite graphs. + /// + /// This class describes the interface of iterable undirected + /// bipartite graphs. It extends \ref IterableGraphComponent with + /// the core iterable interface of undirected bipartite graphs. + /// This concept is part of the BpGraph concept. + template + class IterableBpGraphComponent : public IterableGraphComponent { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::RedNode RedNode; + typedef typename Base::BlueNode BlueNode; + typedef typename Base::Arc Arc; + typedef typename Base::Edge Edge; + + typedef IterableBpGraphComponent BpGraph; + + using IterableGraphComponent::first; + using IterableGraphComponent::next; + + /// \name Base Iteration + /// + /// This interface provides functions for iteration on red and blue nodes. + /// + /// @{ + + /// \brief Return the first red node. + /// + /// This function gives back the first red node in the iteration order. + void first(RedNode&) const {} + + /// \brief Return the next red node. + /// + /// This function gives back the next red node in the iteration order. + void next(RedNode&) const {} + + /// \brief Return the first blue node. + /// + /// This function gives back the first blue node in the iteration order. + void first(BlueNode&) const {} + + /// \brief Return the next blue node. + /// + /// This function gives back the next blue node in the iteration order. + void next(BlueNode&) const {} + + + /// @} + + /// \name Class Based Iteration + /// + /// This interface provides iterator classes for red and blue nodes. + /// + /// @{ + + /// \brief This iterator goes through each red node. + /// + /// This iterator goes through each red node. + typedef GraphItemIt RedNodeIt; + + /// \brief This iterator goes through each blue node. + /// + /// This iterator goes through each blue node. + typedef GraphItemIt BlueNodeIt; + + /// @} + + template + struct Constraints { + void constraints() { + checkConcept, _BpGraph>(); + + typename _BpGraph::RedNode rn(INVALID); + bpgraph.first(rn); + bpgraph.next(rn); + typename _BpGraph::BlueNode bn(INVALID); + bpgraph.first(bn); + bpgraph.next(bn); + + checkConcept, + typename _BpGraph::RedNodeIt>(); + checkConcept, + typename _BpGraph::BlueNodeIt>(); + } + + const _BpGraph& bpgraph; + }; + }; + /// \brief Skeleton class for alterable directed graphs. /// /// This class describes the interface of alterable directed @@ -927,18 +1250,21 @@ typedef AlterationNotifier ArcNotifier; + mutable NodeNotifier node_notifier; + mutable ArcNotifier arc_notifier; + /// \brief Return the node alteration notifier. /// /// This function gives back the node alteration notifier. NodeNotifier& notifier(Node) const { - return NodeNotifier(); + return node_notifier; } /// \brief Return the arc alteration notifier. /// /// This function gives back the arc alteration notifier. ArcNotifier& notifier(Arc) const { - return ArcNotifier(); + return arc_notifier; } template @@ -951,8 +1277,8 @@ typename _Digraph::ArcNotifier& en = digraph.notifier(typename _Digraph::Arc()); - ignore_unused_variable_warning(nn); - ignore_unused_variable_warning(en); + ::lemon::ignore_unused_variable_warning(nn); + ::lemon::ignore_unused_variable_warning(en); } const _Digraph& digraph; @@ -974,6 +1300,7 @@ public: typedef BAS Base; + typedef AlterableDigraphComponent Parent; typedef typename Base::Edge Edge; @@ -981,11 +1308,15 @@ typedef AlterationNotifier EdgeNotifier; + mutable EdgeNotifier edge_notifier; + + using Parent::notifier; + /// \brief Return the edge alteration notifier. /// /// This function gives back the edge alteration notifier. EdgeNotifier& notifier(Edge) const { - return EdgeNotifier(); + return edge_notifier; } template @@ -994,7 +1325,7 @@ checkConcept, _Graph>(); typename _Graph::EdgeNotifier& uen = graph.notifier(typename _Graph::Edge()); - ignore_unused_variable_warning(uen); + ::lemon::ignore_unused_variable_warning(uen); } const _Graph& graph; @@ -1002,6 +1333,68 @@ }; }; + /// \brief Skeleton class for alterable undirected bipartite graphs. + /// + /// This class describes the interface of alterable undirected + /// bipartite graphs. It extends \ref AlterableGraphComponent with + /// the alteration notifier interface of bipartite graphs. It + /// implements an observer-notifier pattern for the red and blue + /// nodes. More obsevers can be registered into the notifier and + /// whenever an alteration occured in the graph all the observers + /// will be notified about it. + template + class AlterableBpGraphComponent : public AlterableGraphComponent { + public: + + typedef BAS Base; + typedef AlterableGraphComponent Parent; + typedef typename Base::RedNode RedNode; + typedef typename Base::BlueNode BlueNode; + + + /// Red node alteration notifier class. + typedef AlterationNotifier + RedNodeNotifier; + + /// Blue node alteration notifier class. + typedef AlterationNotifier + BlueNodeNotifier; + + mutable RedNodeNotifier red_node_notifier; + mutable BlueNodeNotifier blue_node_notifier; + + using Parent::notifier; + + /// \brief Return the red node alteration notifier. + /// + /// This function gives back the red node alteration notifier. + RedNodeNotifier& notifier(RedNode) const { + return red_node_notifier; + } + + /// \brief Return the blue node alteration notifier. + /// + /// This function gives back the blue node alteration notifier. + BlueNodeNotifier& notifier(BlueNode) const { + return blue_node_notifier; + } + + template + struct Constraints { + void constraints() { + checkConcept, _BpGraph>(); + typename _BpGraph::RedNodeNotifier& rnn + = bpgraph.notifier(typename _BpGraph::RedNode()); + typename _BpGraph::BlueNodeNotifier& bnn + = bpgraph.notifier(typename _BpGraph::BlueNode()); + ::lemon::ignore_unused_variable_warning(rnn); + ::lemon::ignore_unused_variable_warning(bnn); + } + + const _BpGraph& bpgraph; + }; + }; + /// \brief Concept class for standard graph maps. /// /// This class describes the concept of standard graph maps, i.e. @@ -1068,9 +1461,9 @@ // ReadMap cmap; // m3 = cmap; - ignore_unused_variable_warning(m1); - ignore_unused_variable_warning(m2); - // ignore_unused_variable_warning(m3); + ::lemon::ignore_unused_variable_warning(m1); + ::lemon::ignore_unused_variable_warning(m2); + // ::lemon::ignore_unused_variable_warning(m3); } const _Map &m; @@ -1305,6 +1698,150 @@ }; }; + /// \brief Skeleton class for mappable undirected bipartite graphs. + /// + /// This class describes the interface of mappable undirected + /// bipartite graphs. It extends \ref MappableGraphComponent with + /// the standard graph map class for red and blue nodes (\c + /// RedNodeMap and BlueNodeMap). This concept is part of the + /// BpGraph concept. + template + class MappableBpGraphComponent : public MappableGraphComponent { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + + typedef MappableBpGraphComponent BpGraph; + + /// \brief Standard graph map for the red nodes. + /// + /// Standard graph map for the red nodes. + /// It conforms to the ReferenceMap concept. + template + class RedNodeMap : public GraphMap { + typedef GraphMap Parent; + + public: + /// \brief Construct a new map. + /// + /// Construct a new map for the graph. + explicit RedNodeMap(const MappableBpGraphComponent& graph) + : Parent(graph) {} + + /// \brief Construct a new map with default value. + /// + /// Construct a new map for the graph and initalize the values. + RedNodeMap(const MappableBpGraphComponent& graph, const V& value) + : Parent(graph, value) {} + + private: + /// \brief Copy constructor. + /// + /// Copy Constructor. + RedNodeMap(const RedNodeMap& nm) : Parent(nm) {} + + /// \brief Assignment operator. + /// + /// Assignment operator. + template + RedNodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + + }; + + /// \brief Standard graph map for the blue nodes. + /// + /// Standard graph map for the blue nodes. + /// It conforms to the ReferenceMap concept. + template + class BlueNodeMap : public GraphMap { + typedef GraphMap Parent; + + public: + /// \brief Construct a new map. + /// + /// Construct a new map for the graph. + explicit BlueNodeMap(const MappableBpGraphComponent& graph) + : Parent(graph) {} + + /// \brief Construct a new map with default value. + /// + /// Construct a new map for the graph and initalize the values. + BlueNodeMap(const MappableBpGraphComponent& graph, const V& value) + : Parent(graph, value) {} + + private: + /// \brief Copy constructor. + /// + /// Copy Constructor. + BlueNodeMap(const BlueNodeMap& nm) : Parent(nm) {} + + /// \brief Assignment operator. + /// + /// Assignment operator. + template + BlueNodeMap& operator=(const CMap&) { + checkConcept, CMap>(); + return *this; + } + + }; + + + template + struct Constraints { + + struct Dummy { + int value; + Dummy() : value(0) {} + Dummy(int _v) : value(_v) {} + }; + + void constraints() { + checkConcept, _BpGraph>(); + + { // int map test + typedef typename _BpGraph::template RedNodeMap + IntRedNodeMap; + checkConcept, + IntRedNodeMap >(); + } { // bool map test + typedef typename _BpGraph::template RedNodeMap + BoolRedNodeMap; + checkConcept, + BoolRedNodeMap >(); + } { // Dummy map test + typedef typename _BpGraph::template RedNodeMap + DummyRedNodeMap; + checkConcept, + DummyRedNodeMap >(); + } + + { // int map test + typedef typename _BpGraph::template BlueNodeMap + IntBlueNodeMap; + checkConcept, + IntBlueNodeMap >(); + } { // bool map test + typedef typename _BpGraph::template BlueNodeMap + BoolBlueNodeMap; + checkConcept, + BoolBlueNodeMap >(); + } { // Dummy map test + typedef typename _BpGraph::template BlueNodeMap + DummyBlueNodeMap; + checkConcept, + DummyBlueNodeMap >(); + } + } + + const _BpGraph& bpgraph; + }; + }; + /// \brief Skeleton class for extendable directed graphs. /// /// This class describes the interface of extendable directed graphs. @@ -1395,6 +1932,65 @@ }; }; + /// \brief Skeleton class for extendable undirected bipartite graphs. + /// + /// This class describes the interface of extendable undirected + /// bipartite graphs. It extends \ref BaseGraphComponent with + /// functions for adding nodes and edges to the graph. This + /// concept requires \ref AlterableBpGraphComponent. + template + class ExtendableBpGraphComponent : public BAS { + public: + + typedef BAS Base; + typedef typename Base::Node Node; + typedef typename Base::RedNode RedNode; + typedef typename Base::BlueNode BlueNode; + typedef typename Base::Edge Edge; + + /// \brief Add a new red node to the digraph. + /// + /// This function adds a red new node to the digraph. + RedNode addRedNode() { + return INVALID; + } + + /// \brief Add a new blue node to the digraph. + /// + /// This function adds a blue new node to the digraph. + BlueNode addBlueNode() { + return INVALID; + } + + /// \brief Add a new edge connecting the given two nodes. + /// + /// This function adds a new edge connecting the given two nodes + /// of the graph. The first node has to be a red node, and the + /// second one a blue node. + Edge addEdge(const RedNode&, const BlueNode&) { + return INVALID; + } + Edge addEdge(const BlueNode&, const RedNode&) { + return INVALID; + } + + template + struct Constraints { + void constraints() { + checkConcept(); + typename _BpGraph::RedNode red_node; + typename _BpGraph::BlueNode blue_node; + red_node = bpgraph.addRedNode(); + blue_node = bpgraph.addBlueNode(); + typename _BpGraph::Edge edge; + edge = bpgraph.addEdge(red_node, blue_node); + edge = bpgraph.addEdge(blue_node, red_node); + } + + _BpGraph& bpgraph; + }; + }; + /// \brief Skeleton class for erasable directed graphs. /// /// This class describes the interface of erasable directed graphs. @@ -1475,6 +2071,15 @@ }; }; + /// \brief Skeleton class for erasable undirected graphs. + /// + /// This class describes the interface of erasable undirected + /// bipartite graphs. It extends \ref BaseBpGraphComponent with + /// functions for removing nodes and edges from the graph. This + /// concept requires \ref AlterableBpGraphComponent. + template + class ErasableBpGraphComponent : public ErasableGraphComponent {}; + /// \brief Skeleton class for clearable directed graphs. /// /// This class describes the interface of clearable directed graphs. @@ -1511,27 +2116,16 @@ /// the graph. /// This concept requires \ref AlterableGraphComponent. template - class ClearableGraphComponent : public ClearableDigraphComponent { - public: + class ClearableGraphComponent : public ClearableDigraphComponent {}; - typedef BAS Base; - - /// \brief Erase all nodes and edges from the graph. - /// - /// This function erases all nodes and edges from the graph. - void clear() {} - - template - struct Constraints { - void constraints() { - checkConcept(); - graph.clear(); - } - - _Graph& graph; - Constraints() {} - }; - }; + /// \brief Skeleton class for clearable undirected biparite graphs. + /// + /// This class describes the interface of clearable undirected + /// bipartite graphs. It extends \ref BaseBpGraphComponent with a + /// function for clearing the graph. This concept requires \ref + /// AlterableBpGraphComponent. + template + class ClearableBpGraphComponent : public ClearableGraphComponent {}; } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/concepts/heap.h --- a/lemon/concepts/heap.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/concepts/heap.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -260,27 +260,27 @@ Prio prio; item=Item(); prio=Prio(); - ignore_unused_variable_warning(item); - ignore_unused_variable_warning(prio); + ::lemon::ignore_unused_variable_warning(item); + ::lemon::ignore_unused_variable_warning(prio); OwnItem own_item; OwnPrio own_prio; OwnState own_state; own_item=Item(); own_prio=Prio(); - ignore_unused_variable_warning(own_item); - ignore_unused_variable_warning(own_prio); - ignore_unused_variable_warning(own_state); + ::lemon::ignore_unused_variable_warning(own_item); + ::lemon::ignore_unused_variable_warning(own_prio); + ::lemon::ignore_unused_variable_warning(own_state); _Heap heap1(map); _Heap heap2 = heap1; - ignore_unused_variable_warning(heap1); - ignore_unused_variable_warning(heap2); + ::lemon::ignore_unused_variable_warning(heap1); + ::lemon::ignore_unused_variable_warning(heap2); int s = heap.size(); - ignore_unused_variable_warning(s); + ::lemon::ignore_unused_variable_warning(s); bool e = heap.empty(); - ignore_unused_variable_warning(e); + ::lemon::ignore_unused_variable_warning(e); prio = heap.prio(); item = heap.top(); diff -r cd72eae05bdf -r 3c00344f49c9 lemon/concepts/maps.h --- a/lemon/concepts/maps.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/concepts/maps.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -60,10 +60,10 @@ typename _ReadMap::Value own_val = m[own_key]; own_val = m[own_key]; - ignore_unused_variable_warning(key); - ignore_unused_variable_warning(val); - ignore_unused_variable_warning(own_key); - ignore_unused_variable_warning(own_val); + ::lemon::ignore_unused_variable_warning(key); + ::lemon::ignore_unused_variable_warning(val); + ::lemon::ignore_unused_variable_warning(own_key); + ::lemon::ignore_unused_variable_warning(own_val); } const Key& key; const typename _ReadMap::Key& own_key; @@ -100,10 +100,10 @@ m.set(key, val); m.set(own_key, own_val); - ignore_unused_variable_warning(key); - ignore_unused_variable_warning(val); - ignore_unused_variable_warning(own_key); - ignore_unused_variable_warning(own_val); + ::lemon::ignore_unused_variable_warning(key); + ::lemon::ignore_unused_variable_warning(val); + ::lemon::ignore_unused_variable_warning(own_key); + ::lemon::ignore_unused_variable_warning(own_val); } const Key& key; const Value& val; diff -r cd72eae05bdf -r 3c00344f49c9 lemon/concepts/path.h --- a/lemon/concepts/path.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/concepts/path.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -75,7 +75,7 @@ /// \brief Template assigment operator template Path& operator=(const CPath& cpath) { - ignore_unused_variable_warning(cpath); + ::lemon::ignore_unused_variable_warning(cpath); return *this; } @@ -135,12 +135,12 @@ e = (i != ii); e = (i < ii); - ignore_unused_variable_warning(l); - ignore_unused_variable_warning(pp); - ignore_unused_variable_warning(e); - ignore_unused_variable_warning(id); - ignore_unused_variable_warning(ii); - ignore_unused_variable_warning(ed); + ::lemon::ignore_unused_variable_warning(l); + ::lemon::ignore_unused_variable_warning(pp); + ::lemon::ignore_unused_variable_warning(e); + ::lemon::ignore_unused_variable_warning(id); + ::lemon::ignore_unused_variable_warning(ii); + ::lemon::ignore_unused_variable_warning(ed); } }; @@ -162,10 +162,10 @@ e = (i == INVALID); e = (i != INVALID); - ignore_unused_variable_warning(l); - ignore_unused_variable_warning(e); - ignore_unused_variable_warning(id); - ignore_unused_variable_warning(ed); + ::lemon::ignore_unused_variable_warning(l); + ::lemon::ignore_unused_variable_warning(e); + ::lemon::ignore_unused_variable_warning(id); + ::lemon::ignore_unused_variable_warning(ed); } _Path& p; PathDumperConstraints() {} @@ -188,10 +188,10 @@ e = (i == INVALID); e = (i != INVALID); - ignore_unused_variable_warning(l); - ignore_unused_variable_warning(e); - ignore_unused_variable_warning(id); - ignore_unused_variable_warning(ed); + ::lemon::ignore_unused_variable_warning(l); + ::lemon::ignore_unused_variable_warning(e); + ::lemon::ignore_unused_variable_warning(id); + ::lemon::ignore_unused_variable_warning(ed); } _Path& p; PathDumperConstraints() {} diff -r cd72eae05bdf -r 3c00344f49c9 lemon/config.h.cmake --- a/lemon/config.h.cmake Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -#define LEMON_VERSION "@PROJECT_VERSION@" -#cmakedefine LEMON_HAVE_LONG_LONG 1 -#cmakedefine LEMON_HAVE_LP 1 -#cmakedefine LEMON_HAVE_MIP 1 -#cmakedefine LEMON_HAVE_GLPK 1 -#cmakedefine LEMON_HAVE_CPLEX 1 -#cmakedefine LEMON_HAVE_CLP 1 -#cmakedefine LEMON_HAVE_CBC 1 diff -r cd72eae05bdf -r 3c00344f49c9 lemon/config.h.in --- a/lemon/config.h.in Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/config.h.in Wed Oct 17 19:14:07 2018 +0200 @@ -1,26 +1,29 @@ -/* The version string */ -#undef LEMON_VERSION +#ifndef LEMON_CONFIG_H +#define LEMON_CONFIG_H -/* Define to 1 if you have long long */ -#undef LEMON_HAVE_LONG_LONG +#define LEMON_VERSION "@PROJECT_VERSION@" +#cmakedefine LEMON_HAVE_LONG_LONG 1 -/* Define to 1 if you have any LP solver. */ -#undef LEMON_HAVE_LP +#cmakedefine LEMON_WIN32 1 -/* Define to 1 if you have any MIP solver. */ -#undef LEMON_HAVE_MIP +#cmakedefine LEMON_HAVE_LP 1 +#cmakedefine LEMON_HAVE_MIP 1 +#cmakedefine LEMON_HAVE_GLPK 1 +#cmakedefine LEMON_HAVE_CPLEX 1 +#cmakedefine LEMON_HAVE_SOPLEX 1 +#cmakedefine LEMON_HAVE_CLP 1 +#cmakedefine LEMON_HAVE_CBC 1 -/* Define to 1 if you have CPLEX. */ -#undef LEMON_HAVE_CPLEX +#define LEMON_CPLEX_ 1 +#define LEMON_CLP_ 2 +#define LEMON_GLPK_ 3 +#define LEMON_SOPLEX_ 4 +#define LEMON_CBC_ 5 -/* Define to 1 if you have GLPK. */ -#undef LEMON_HAVE_GLPK +#cmakedefine LEMON_DEFAULT_LP LEMON_@LEMON_DEFAULT_LP@_ +#cmakedefine LEMON_DEFAULT_MIP LEMON_@LEMON_DEFAULT_MIP@_ -/* Define to 1 if you have SOPLEX */ -#undef LEMON_HAVE_SOPLEX +#cmakedefine LEMON_USE_PTHREAD 1 +#cmakedefine LEMON_USE_WIN32_THREADS 1 -/* Define to 1 if you have CLP */ -#undef LEMON_HAVE_CLP - -/* Define to 1 if you have CBC */ -#undef LEMON_HAVE_CBC +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/connectivity.h --- a/lemon/connectivity.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/connectivity.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -745,14 +745,37 @@ /// \brief Check whether an undirected graph is bi-node-connected. /// /// This function checks whether the given undirected graph is - /// bi-node-connected, i.e. any two edges are on same circle. + /// bi-node-connected, i.e. a connected graph without articulation + /// node. /// /// \return \c true if the graph bi-node-connected. - /// \note By definition, the empty graph is bi-node-connected. + /// + /// \note By definition, + /// \li a graph consisting of zero or one node is bi-node-connected, + /// \li a graph consisting of two isolated nodes + /// is \e not bi-node-connected and + /// \li a graph consisting of two nodes connected by an edge + /// is bi-node-connected. /// /// \see countBiNodeConnectedComponents(), biNodeConnectedComponents() template bool biNodeConnected(const Graph& graph) { + bool hasNonIsolated = false, hasIsolated = false; + for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { + if (typename Graph::OutArcIt(graph, n) == INVALID) { + if (hasIsolated || hasNonIsolated) { + return false; + } else { + hasIsolated = true; + } + } else { + if (hasIsolated) { + return false; + } else { + hasNonIsolated = true; + } + } + } return countBiNodeConnectedComponents(graph) <= 1; } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/core.h --- a/lemon/core.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/core.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -19,6 +19,29 @@ #ifndef LEMON_CORE_H #define LEMON_CORE_H +///\file +///\brief LEMON core utilities. +/// +///This header file contains core utilities for LEMON. +///It is automatically included by all graph types, therefore it usually +///do not have to be included directly. + +// Disable the following warnings when compiling with MSVC: +// C4250: 'class1' : inherits 'class2::member' via dominance +// C4267: conversion from 'size_t' to 'type', possible loss of data +// C4355: 'this' : used in base member initializer list +// C4503: 'function' : decorated name length exceeded, name was truncated +// C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning) +// C4996: 'function': was declared deprecated +#ifdef _MSC_VER +#pragma warning( disable : 4250 4267 4355 4503 4800 4996 ) +#endif + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +// Needed by the [DI]GRAPH_TYPEDEFS marcos for gcc 4.8 +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#endif + #include #include @@ -27,22 +50,7 @@ #include #include -// Disable the following warnings when compiling with MSVC: -// C4250: 'class1' : inherits 'class2::member' via dominance -// C4355: 'this' : used in base member initializer list -// C4503: 'function' : decorated name length exceeded, name was truncated -// C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning) -// C4996: 'function': was declared deprecated -#ifdef _MSC_VER -#pragma warning( disable : 4250 4355 4503 4800 4996 ) -#endif -///\file -///\brief LEMON core utilities. -/// -///This header file contains core utilities for LEMON. -///It is automatically included by all graph types, therefore it usually -///do not have to be included directly. namespace lemon { @@ -148,6 +156,49 @@ typedef typename Graph::template EdgeMap IntEdgeMap; \ typedef typename Graph::template EdgeMap DoubleEdgeMap + ///Create convenience typedefs for the bipartite graph types and iterators + + ///This \c \#define creates the same convenient type definitions as + ///defined by \ref GRAPH_TYPEDEFS(BpGraph) and ten more, namely it + ///creates \c RedNode, \c RedNodeIt, \c BoolRedNodeMap, + ///\c IntRedNodeMap, \c DoubleRedNodeMap, \c BlueNode, \c BlueNodeIt, + ///\c BoolBlueNodeMap, \c IntBlueNodeMap, \c DoubleBlueNodeMap. + /// + ///\note If the graph type is a dependent type, ie. the graph type depend + ///on a template parameter, then use \c TEMPLATE_BPGRAPH_TYPEDEFS() + ///macro. +#define BPGRAPH_TYPEDEFS(BpGraph) \ + GRAPH_TYPEDEFS(BpGraph); \ + typedef BpGraph::RedNode RedNode; \ + typedef BpGraph::RedNodeIt RedNodeIt; \ + typedef BpGraph::RedNodeMap BoolRedNodeMap; \ + typedef BpGraph::RedNodeMap IntRedNodeMap; \ + typedef BpGraph::RedNodeMap DoubleRedNodeMap; \ + typedef BpGraph::BlueNode BlueNode; \ + typedef BpGraph::BlueNodeIt BlueNodeIt; \ + typedef BpGraph::BlueNodeMap BoolBlueNodeMap; \ + typedef BpGraph::BlueNodeMap IntBlueNodeMap; \ + typedef BpGraph::BlueNodeMap DoubleBlueNodeMap + + ///Create convenience typedefs for the bipartite graph types and iterators + + ///\see BPGRAPH_TYPEDEFS + /// + ///\note Use this macro, if the graph type is a dependent type, + ///ie. the graph type depend on a template parameter. +#define TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph) \ + TEMPLATE_GRAPH_TYPEDEFS(BpGraph); \ + typedef typename BpGraph::RedNode RedNode; \ + typedef typename BpGraph::RedNodeIt RedNodeIt; \ + typedef typename BpGraph::template RedNodeMap BoolRedNodeMap; \ + typedef typename BpGraph::template RedNodeMap IntRedNodeMap; \ + typedef typename BpGraph::template RedNodeMap DoubleRedNodeMap; \ + typedef typename BpGraph::BlueNode BlueNode; \ + typedef typename BpGraph::BlueNodeIt BlueNodeIt; \ + typedef typename BpGraph::template BlueNodeMap BoolBlueNodeMap; \ + typedef typename BpGraph::template BlueNodeMap IntBlueNodeMap; \ + typedef typename BpGraph::template BlueNodeMap DoubleBlueNodeMap + /// \brief Function to count the items in a graph. /// /// This function counts the items (nodes, arcs etc.) in a graph. @@ -199,6 +250,74 @@ return _core_bits::CountNodesSelector::count(g); } + namespace _graph_utils_bits { + + template + struct CountRedNodesSelector { + static int count(const Graph &g) { + return countItems(g); + } + }; + + template + struct CountRedNodesSelector< + Graph, typename + enable_if::type> + { + static int count(const Graph &g) { + return g.redNum(); + } + }; + } + + /// \brief Function to count the red nodes in the graph. + /// + /// This function counts the red nodes in the graph. + /// The complexity of the function is O(n) but for some + /// graph structures it is specialized to run in O(1). + /// + /// If the graph contains a \e redNum() member function and a + /// \e NodeNumTag tag then this function calls directly the member + /// function to query the cardinality of the node set. + template + inline int countRedNodes(const Graph& g) { + return _graph_utils_bits::CountRedNodesSelector::count(g); + } + + namespace _graph_utils_bits { + + template + struct CountBlueNodesSelector { + static int count(const Graph &g) { + return countItems(g); + } + }; + + template + struct CountBlueNodesSelector< + Graph, typename + enable_if::type> + { + static int count(const Graph &g) { + return g.blueNum(); + } + }; + } + + /// \brief Function to count the blue nodes in the graph. + /// + /// This function counts the blue nodes in the graph. + /// The complexity of the function is O(n) but for some + /// graph structures it is specialized to run in O(1). + /// + /// If the graph contains a \e blueNum() member function and a + /// \e NodeNumTag tag then this function calls directly the member + /// function to query the cardinality of the node set. + template + inline int countBlueNodes(const Graph& g) { + return _graph_utils_bits::CountBlueNodesSelector::count(g); + } + // Arc counting: namespace _core_bits { @@ -440,13 +559,70 @@ { template static void copy(const From& from, Graph &to, - NodeRefMap& nodeRefMap, EdgeRefMap& edgeRefMap) { + NodeRefMap& nodeRefMap, + EdgeRefMap& edgeRefMap) { to.build(from, nodeRefMap, edgeRefMap); } }; + template + struct BpGraphCopySelector { + template + static void copy(const From& from, BpGraph &to, + RedNodeRefMap& redNodeRefMap, + BlueNodeRefMap& blueNodeRefMap, + EdgeRefMap& edgeRefMap) { + to.clear(); + for (typename From::RedNodeIt it(from); it != INVALID; ++it) { + redNodeRefMap[it] = to.addRedNode(); + } + for (typename From::BlueNodeIt it(from); it != INVALID; ++it) { + blueNodeRefMap[it] = to.addBlueNode(); + } + for (typename From::EdgeIt it(from); it != INVALID; ++it) { + edgeRefMap[it] = to.addEdge(redNodeRefMap[from.redNode(it)], + blueNodeRefMap[from.blueNode(it)]); + } + } + }; + + template + struct BpGraphCopySelector< + BpGraph, + typename enable_if::type> + { + template + static void copy(const From& from, BpGraph &to, + RedNodeRefMap& redNodeRefMap, + BlueNodeRefMap& blueNodeRefMap, + EdgeRefMap& edgeRefMap) { + to.build(from, redNodeRefMap, blueNodeRefMap, edgeRefMap); + } + }; + } + /// \brief Check whether a graph is undirected. + /// + /// This function returns \c true if the given graph is undirected. +#ifdef DOXYGEN + template + bool undirected(const GR& g) { return false; } +#else + template + typename enable_if, bool>::type + undirected(const GR&) { + return true; + } + template + typename disable_if, bool>::type + undirected(const GR&) { + return false; + } +#endif + /// \brief Class to copy a digraph. /// /// Class to copy a digraph to another digraph (duplicate a digraph). The @@ -972,6 +1148,454 @@ return GraphCopy(from, to); } + /// \brief Class to copy a bipartite graph. + /// + /// Class to copy a bipartite graph to another graph (duplicate a + /// graph). The simplest way of using it is through the + /// \c bpGraphCopy() function. + /// + /// This class not only make a copy of a bipartite graph, but it can + /// create references and cross references between the nodes, edges + /// and arcs of the two graphs, and it can copy maps for using with + /// the newly created graph. + /// + /// To make a copy from a graph, first an instance of BpGraphCopy + /// should be created, then the data belongs to the graph should + /// assigned to copy. In the end, the \c run() member should be + /// called. + /// + /// The next code copies a graph with several data: + ///\code + /// BpGraphCopy cg(orig_graph, new_graph); + /// // Create references for the nodes + /// OrigBpGraph::NodeMap nr(orig_graph); + /// cg.nodeRef(nr); + /// // Create cross references (inverse) for the edges + /// NewBpGraph::EdgeMap ecr(new_graph); + /// cg.edgeCrossRef(ecr); + /// // Copy a red node map + /// OrigBpGraph::RedNodeMap ormap(orig_graph); + /// NewBpGraph::RedNodeMap nrmap(new_graph); + /// cg.redNodeMap(ormap, nrmap); + /// // Copy a node + /// OrigBpGraph::Node on; + /// NewBpGraph::Node nn; + /// cg.node(on, nn); + /// // Execute copying + /// cg.run(); + ///\endcode + template + class BpGraphCopy { + private: + + typedef typename From::Node Node; + typedef typename From::RedNode RedNode; + typedef typename From::BlueNode BlueNode; + typedef typename From::NodeIt NodeIt; + typedef typename From::Arc Arc; + typedef typename From::ArcIt ArcIt; + typedef typename From::Edge Edge; + typedef typename From::EdgeIt EdgeIt; + + typedef typename To::Node TNode; + typedef typename To::RedNode TRedNode; + typedef typename To::BlueNode TBlueNode; + typedef typename To::Arc TArc; + typedef typename To::Edge TEdge; + + typedef typename From::template RedNodeMap RedNodeRefMap; + typedef typename From::template BlueNodeMap BlueNodeRefMap; + typedef typename From::template EdgeMap EdgeRefMap; + + struct NodeRefMap { + NodeRefMap(const From& from, const RedNodeRefMap& red_node_ref, + const BlueNodeRefMap& blue_node_ref) + : _from(from), _red_node_ref(red_node_ref), + _blue_node_ref(blue_node_ref) {} + + typedef typename From::Node Key; + typedef typename To::Node Value; + + Value operator[](const Key& key) const { + if (_from.red(key)) { + return _red_node_ref[_from.asRedNodeUnsafe(key)]; + } else { + return _blue_node_ref[_from.asBlueNodeUnsafe(key)]; + } + } + + const From& _from; + const RedNodeRefMap& _red_node_ref; + const BlueNodeRefMap& _blue_node_ref; + }; + + struct ArcRefMap { + ArcRefMap(const From& from, const To& to, const EdgeRefMap& edge_ref) + : _from(from), _to(to), _edge_ref(edge_ref) {} + + typedef typename From::Arc Key; + typedef typename To::Arc Value; + + Value operator[](const Key& key) const { + return _to.direct(_edge_ref[key], _from.direction(key)); + } + + const From& _from; + const To& _to; + const EdgeRefMap& _edge_ref; + }; + + public: + + /// \brief Constructor of BpGraphCopy. + /// + /// Constructor of BpGraphCopy for copying the content of the + /// \c from graph into the \c to graph. + BpGraphCopy(const From& from, To& to) + : _from(from), _to(to) {} + + /// \brief Destructor of BpGraphCopy + /// + /// Destructor of BpGraphCopy. + ~BpGraphCopy() { + for (int i = 0; i < int(_node_maps.size()); ++i) { + delete _node_maps[i]; + } + for (int i = 0; i < int(_red_maps.size()); ++i) { + delete _red_maps[i]; + } + for (int i = 0; i < int(_blue_maps.size()); ++i) { + delete _blue_maps[i]; + } + for (int i = 0; i < int(_arc_maps.size()); ++i) { + delete _arc_maps[i]; + } + for (int i = 0; i < int(_edge_maps.size()); ++i) { + delete _edge_maps[i]; + } + } + + /// \brief Copy the node references into the given map. + /// + /// This function copies the node references into the given map. + /// The parameter should be a map, whose key type is the Node type of + /// the source graph, while the value type is the Node type of the + /// destination graph. + template + BpGraphCopy& nodeRef(NodeRef& map) { + _node_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the node cross references into the given map. + /// + /// This function copies the node cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Node type of the destination graph, while the value type is + /// the Node type of the source graph. + template + BpGraphCopy& nodeCrossRef(NodeCrossRef& map) { + _node_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given node map. + /// + /// This function makes a copy of the given node map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Node type of the + /// destination graph, and the key type of the original map \c map + /// should be the Node type of the source graph. + template + BpGraphCopy& nodeMap(const FromMap& map, ToMap& tmap) { + _node_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given node. + /// + /// This function makes a copy of the given node. + BpGraphCopy& node(const Node& node, TNode& tnode) { + _node_maps.push_back(new _core_bits::ItemCopy(node, tnode)); + return *this; + } + + /// \brief Copy the red node references into the given map. + /// + /// This function copies the red node references into the given + /// map. The parameter should be a map, whose key type is the + /// Node type of the source graph with the red item set, while the + /// value type is the Node type of the destination graph. + template + BpGraphCopy& redRef(RedRef& map) { + _red_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the red node cross references into the given map. + /// + /// This function copies the red node cross references (reverse + /// references) into the given map. The parameter should be a map, + /// whose key type is the Node type of the destination graph with + /// the red item set, while the value type is the Node type of the + /// source graph. + template + BpGraphCopy& redCrossRef(RedCrossRef& map) { + _red_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given red node map. + /// + /// This function makes a copy of the given red node map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Node type of + /// the destination graph with the red items, and the key type of + /// the original map \c map should be the Node type of the source + /// graph. + template + BpGraphCopy& redNodeMap(const FromMap& map, ToMap& tmap) { + _red_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given red node. + /// + /// This function makes a copy of the given red node. + BpGraphCopy& redNode(const RedNode& node, TRedNode& tnode) { + _red_maps.push_back(new _core_bits::ItemCopy(node, tnode)); + return *this; + } + + /// \brief Copy the blue node references into the given map. + /// + /// This function copies the blue node references into the given + /// map. The parameter should be a map, whose key type is the + /// Node type of the source graph with the blue item set, while the + /// value type is the Node type of the destination graph. + template + BpGraphCopy& blueRef(BlueRef& map) { + _blue_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the blue node cross references into the given map. + /// + /// This function copies the blue node cross references (reverse + /// references) into the given map. The parameter should be a map, + /// whose key type is the Node type of the destination graph with + /// the blue item set, while the value type is the Node type of the + /// source graph. + template + BpGraphCopy& blueCrossRef(BlueCrossRef& map) { + _blue_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given blue node map. + /// + /// This function makes a copy of the given blue node map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Node type of + /// the destination graph with the blue items, and the key type of + /// the original map \c map should be the Node type of the source + /// graph. + template + BpGraphCopy& blueNodeMap(const FromMap& map, ToMap& tmap) { + _blue_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given blue node. + /// + /// This function makes a copy of the given blue node. + BpGraphCopy& blueNode(const BlueNode& node, TBlueNode& tnode) { + _blue_maps.push_back(new _core_bits::ItemCopy(node, tnode)); + return *this; + } + + /// \brief Copy the arc references into the given map. + /// + /// This function copies the arc references into the given map. + /// The parameter should be a map, whose key type is the Arc type of + /// the source graph, while the value type is the Arc type of the + /// destination graph. + template + BpGraphCopy& arcRef(ArcRef& map) { + _arc_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the arc cross references into the given map. + /// + /// This function copies the arc cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Arc type of the destination graph, while the value type is + /// the Arc type of the source graph. + template + BpGraphCopy& arcCrossRef(ArcCrossRef& map) { + _arc_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given arc map. + /// + /// This function makes a copy of the given arc map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Arc type of the + /// destination graph, and the key type of the original map \c map + /// should be the Arc type of the source graph. + template + BpGraphCopy& arcMap(const FromMap& map, ToMap& tmap) { + _arc_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given arc. + /// + /// This function makes a copy of the given arc. + BpGraphCopy& arc(const Arc& arc, TArc& tarc) { + _arc_maps.push_back(new _core_bits::ItemCopy(arc, tarc)); + return *this; + } + + /// \brief Copy the edge references into the given map. + /// + /// This function copies the edge references into the given map. + /// The parameter should be a map, whose key type is the Edge type of + /// the source graph, while the value type is the Edge type of the + /// destination graph. + template + BpGraphCopy& edgeRef(EdgeRef& map) { + _edge_maps.push_back(new _core_bits::RefCopy(map)); + return *this; + } + + /// \brief Copy the edge cross references into the given map. + /// + /// This function copies the edge cross references (reverse references) + /// into the given map. The parameter should be a map, whose key type + /// is the Edge type of the destination graph, while the value type is + /// the Edge type of the source graph. + template + BpGraphCopy& edgeCrossRef(EdgeCrossRef& map) { + _edge_maps.push_back(new _core_bits::CrossRefCopy(map)); + return *this; + } + + /// \brief Make a copy of the given edge map. + /// + /// This function makes a copy of the given edge map for the newly + /// created graph. + /// The key type of the new map \c tmap should be the Edge type of the + /// destination graph, and the key type of the original map \c map + /// should be the Edge type of the source graph. + template + BpGraphCopy& edgeMap(const FromMap& map, ToMap& tmap) { + _edge_maps.push_back(new _core_bits::MapCopy(map, tmap)); + return *this; + } + + /// \brief Make a copy of the given edge. + /// + /// This function makes a copy of the given edge. + BpGraphCopy& edge(const Edge& edge, TEdge& tedge) { + _edge_maps.push_back(new _core_bits::ItemCopy(edge, tedge)); + return *this; + } + + /// \brief Execute copying. + /// + /// This function executes the copying of the graph along with the + /// copying of the assigned data. + void run() { + RedNodeRefMap redNodeRefMap(_from); + BlueNodeRefMap blueNodeRefMap(_from); + NodeRefMap nodeRefMap(_from, redNodeRefMap, blueNodeRefMap); + EdgeRefMap edgeRefMap(_from); + ArcRefMap arcRefMap(_from, _to, edgeRefMap); + _core_bits::BpGraphCopySelector:: + copy(_from, _to, redNodeRefMap, blueNodeRefMap, edgeRefMap); + for (int i = 0; i < int(_node_maps.size()); ++i) { + _node_maps[i]->copy(_from, nodeRefMap); + } + for (int i = 0; i < int(_red_maps.size()); ++i) { + _red_maps[i]->copy(_from, redNodeRefMap); + } + for (int i = 0; i < int(_blue_maps.size()); ++i) { + _blue_maps[i]->copy(_from, blueNodeRefMap); + } + for (int i = 0; i < int(_edge_maps.size()); ++i) { + _edge_maps[i]->copy(_from, edgeRefMap); + } + for (int i = 0; i < int(_arc_maps.size()); ++i) { + _arc_maps[i]->copy(_from, arcRefMap); + } + } + + private: + + const From& _from; + To& _to; + + std::vector<_core_bits::MapCopyBase* > + _node_maps; + + std::vector<_core_bits::MapCopyBase* > + _red_maps; + + std::vector<_core_bits::MapCopyBase* > + _blue_maps; + + std::vector<_core_bits::MapCopyBase* > + _arc_maps; + + std::vector<_core_bits::MapCopyBase* > + _edge_maps; + + }; + + /// \brief Copy a graph to another graph. + /// + /// This function copies a graph to another graph. + /// The complete usage of it is detailed in the BpGraphCopy class, + /// but a short example shows a basic work: + ///\code + /// graphCopy(src, trg).nodeRef(nr).edgeCrossRef(ecr).run(); + ///\endcode + /// + /// After the copy the \c nr map will contain the mapping from the + /// nodes of the \c from graph to the nodes of the \c to graph and + /// \c ecr will contain the mapping from the edges of the \c to graph + /// to the edges of the \c from graph. + /// + /// \see BpGraphCopy + template + BpGraphCopy + bpGraphCopy(const From& from, To& to) { + return BpGraphCopy(from, to); + } + namespace _core_bits { template diff -r cd72eae05bdf -r 3c00344f49c9 lemon/cost_scaling.h --- a/lemon/cost_scaling.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/cost_scaling.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -91,11 +91,18 @@ /// /// \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. + /// "minimum cost flow" \cite amo93networkflows, + /// \cite goldberg90approximation, + /// \cite goldberg97efficient, \cite 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. + /// It is a polynomial algorithm, its running time complexity is + /// \f$O(n^2m\log(nK))\f$, where K denotes the maximum arc cost. + /// + /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest + /// implementations available in LEMON for solving this problem. + /// (For more information, see \ref min_cost_flow_algs "the module page".) /// /// Most of the parameters of the problem (except for the digraph) /// can be given using separate functions, and the algorithm can be @@ -113,10 +120,11 @@ /// 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 + /// \warning Both \c V and \c C must be signed number types. + /// \warning All input data (capacities, supply values, and costs) must /// be integer. - /// \warning This algorithm does not support negative costs for such - /// arcs that have infinite upper bound. + /// \warning This algorithm does not support negative costs for + /// arcs having infinite upper bound. /// /// \note %CostScaling provides three different internal methods, /// from which the most efficient one is used by default. @@ -145,7 +153,8 @@ /// otherwise it is \c double. typedef typename TR::LargeCost LargeCost; - /// The \ref CostScalingDefaultTraits "traits class" of the algorithm + /// \brief The \ref lemon::CostScalingDefaultTraits "traits class" + /// of the algorithm typedef TR Traits; public: @@ -178,7 +187,7 @@ /// 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 + /// "Partial Augment-Relabel" method is used, which turned out 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. @@ -205,7 +214,8 @@ typedef std::vector CostVector; typedef std::vector LargeCostVector; typedef std::vector BoolVector; - // Note: vector is used instead of vector for efficiency reasons + // Note: vector is used instead of vector + // for efficiency reasons private: @@ -233,7 +243,6 @@ std::vector& _v; }; - typedef StaticVectorMap LargeCostNodeMap; typedef StaticVectorMap LargeCostArcMap; private: @@ -247,7 +256,7 @@ int _root; // Parameters of the problem - bool _have_lower; + bool _has_lower; Value _sum_supply; int _sup_node_num; @@ -284,14 +293,6 @@ 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). @@ -338,7 +339,6 @@ /// \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()) @@ -372,10 +372,9 @@ /// \return (*this) template CostScaling& lowerMap(const LowerMap& map) { - _have_lower = true; + _has_lower = true; for (ArcIt a(_graph); a != INVALID; ++a) { _lower[_arc_idf[a]] = map[a]; - _lower[_arc_idb[a]] = map[a]; } return *this; } @@ -447,7 +446,7 @@ /// 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 + /// with 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. @@ -493,7 +492,7 @@ /// /// \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. + /// \param factor The cost scaling factor. It must be at least two. /// /// \return \c INFEASIBLE if no feasible flow exists, /// \n \c OPTIMAL if the problem has optimal solution @@ -507,7 +506,8 @@ /// /// \see ProblemType, Method /// \see resetParams(), reset() - ProblemType run(Method method = PARTIAL_AUGMENT, int factor = 8) { + ProblemType run(Method method = PARTIAL_AUGMENT, int factor = 16) { + LEMON_ASSERT(factor >= 2, "The scaling factor must be at least 2"); _alpha = factor; ProblemType pt = init(); if (pt != OPTIMAL) return pt; @@ -567,22 +567,29 @@ _scost[j] = 0; _scost[_reverse[j]] = 0; } - _have_lower = false; + _has_lower = false; return *this; } - /// \brief Reset all the parameters that have been given before. + /// \brief Reset the internal data structures and 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(). + /// 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 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. By default, 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() CostScaling& reset() { // Resize vectors _node_num = countNodes(_graph); @@ -608,9 +615,6 @@ _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) { @@ -667,7 +671,7 @@ /// \brief Return the total cost of the found flow. /// /// This function returns the total cost of the found flow. - /// Its complexity is O(e). + /// Its complexity is O(m). /// /// \note The return type of the function can be specified as a /// template parameter. For example, @@ -705,7 +709,8 @@ return _res_cap[_arc_idb[a]]; } - /// \brief Return the flow map (the primal solution). + /// \brief Copy the flow values (the primal solution) into the + /// given map. /// /// This function copies the flow value on each arc into the given /// map. The \c Value type of the algorithm must be convertible to @@ -729,7 +734,8 @@ return static_cast(_pi[_node_id[n]]); } - /// \brief Return the potential map (the dual solution). + /// \brief Copy the potential values (the dual solution) into the + /// given map. /// /// This function copies the potential (dual value) of each node /// into the given map. @@ -759,6 +765,10 @@ } if (_sum_supply > 0) return INFEASIBLE; + // Check lower and upper bounds + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + // Initialize vectors for (int i = 0; i != _res_node_num; ++i) { @@ -769,7 +779,7 @@ // Remove infinite upper bounds and check negative arcs const Value MAX = std::numeric_limits::max(); int last_out; - if (_have_lower) { + if (_has_lower) { for (int i = 0; i != _root; ++i) { last_out = _first_out[i+1]; for (int j = _first_out[i]; j != last_out; ++j) { @@ -826,7 +836,7 @@ for (NodeIt n(_graph); n != INVALID; ++n) { sup[n] = _supply[_node_id[n]]; } - if (_have_lower) { + if (_has_lower) { for (ArcIt a(_graph); a != INVALID; ++a) { int j = _arc_idf[a]; Value c = _lower[j]; @@ -886,14 +896,6 @@ } } - 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); @@ -901,7 +903,22 @@ _bucket_prev.resize(_res_node_num + 1); _rank.resize(_res_node_num + 1); - // Execute the algorithm + return OPTIMAL; + } + + // Check if the upper bound is greater than or equal to the lower bound + // on each forward arc. + bool checkBoundMaps() { + for (int j = 0; j != _res_arc_num; ++j) { + if (_forward[j] && _upper[j] < _lower[j]) return false; + } + return true; + } + + // Execute the algorithm and transform the results + void start(Method method) { + const int MAX_PARTIAL_PATH_LENGTH = 4; + switch (method) { case PUSH: startPush(); @@ -910,32 +927,73 @@ startAugment(_res_node_num - 1); break; case PARTIAL_AUGMENT: - startAugment(MAX_PATH_LENGTH); + startAugment(MAX_PARTIAL_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]); + // Compute node potentials (dual solution) + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] = static_cast(_pi[i] / (_res_node_num * _alpha)); + } + bool optimal = true; + for (int i = 0; optimal && i != _res_node_num; ++i) { + LargeCost pi_i = _pi[i]; + int last_out = _first_out[i+1]; + for (int j = _first_out[i]; j != last_out; ++j) { + if (_res_cap[j] > 0 && _scost[j] + pi_i - _pi[_target[j]] < 0) { + optimal = false; + break; + } } } - _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(); + if (!optimal) { + // Compute node potentials for the original costs with BellmanFord + // (if it is necessary) + typedef std::pair IntPair; + StaticDigraph sgr; + std::vector arc_vec; + std::vector cost_vec; + LargeCostArcMap cost_map(cost_vec); + + arc_vec.clear(); + cost_vec.clear(); + for (int j = 0; j != _res_arc_num; ++j) { + if (_res_cap[j] > 0) { + int u = _source[j], v = _target[j]; + arc_vec.push_back(IntPair(u, v)); + cost_vec.push_back(_scost[j] + _pi[u] - _pi[v]); + } + } + sgr.build(_res_node_num, arc_vec.begin(), arc_vec.end()); + + typename BellmanFord::Create + bf(sgr, cost_map); + bf.init(0); + bf.start(); + + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] += bf.dist(sgr.node(i)); + } + } + + // Shift potentials to meet the requirements of the GEQ type + // optimality conditions + LargeCost max_pot = _pi[_root]; + for (int i = 0; i != _res_node_num; ++i) { + if (_pi[i] > max_pot) max_pot = _pi[i]; + } + if (max_pot != 0) { + for (int i = 0; i != _res_node_num; ++i) { + _pi[i] -= max_pot; + } + } // Handle non-zero lower bounds - if (_have_lower) { + if (_has_lower) { int limit = _first_out[_root]; for (int j = 0; j != limit; ++j) { - if (!_forward[j]) _res_cap[j] += _lower[j]; + if (_forward[j]) _res_cap[_reverse[j]] += _lower[j]; } } } @@ -947,13 +1005,15 @@ 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; + Value delta = _res_cap[a]; + if (delta > 0) { + int v = _target[a]; + if (_cost[a] + pi_u - _pi[v] < 0) { + _excess[u] -= delta; + _excess[v] += delta; + _res_cap[a] = 0; + _res_cap[_reverse[a]] += delta; + } } } } @@ -969,53 +1029,254 @@ } } - // Early termination heuristic - bool earlyTermination() { - const double EARLY_TERM_FACTOR = 3.0; + // Price (potential) refinement heuristic + bool priceRefinement() { - // 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); + // Stack for stroing the topological order + IntVector stack(_res_node_num); + int stack_top; + + // Perform phases + while (topologicalSort(stack, stack_top)) { + + // Compute node ranks in the acyclic admissible network and + // store the nodes in buckets + for (int i = 0; i != _res_node_num; ++i) { + _rank[i] = 0; } + const int bucket_end = _root + 1; + for (int r = 0; r != _max_rank; ++r) { + _buckets[r] = bucket_end; + } + int top_rank = 0; + for ( ; stack_top >= 0; --stack_top) { + int u = stack[stack_top], v; + int rank_u = _rank[u]; + + LargeCost rc, pi_u = _pi[u]; + int last_out = _first_out[u+1]; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] > 0) { + v = _target[a]; + rc = _cost[a] + pi_u - _pi[v]; + if (rc < 0) { + LargeCost nrc = static_cast((-rc - 0.5) / _epsilon); + if (nrc < LargeCost(_max_rank)) { + int new_rank_v = rank_u + static_cast(nrc); + if (new_rank_v > _rank[v]) { + _rank[v] = new_rank_v; + } + } + } + } + } + + if (rank_u > 0) { + top_rank = std::max(top_rank, rank_u); + int bfirst = _buckets[rank_u]; + _bucket_next[u] = bfirst; + _bucket_prev[bfirst] = u; + _buckets[rank_u] = u; + } + } + + // Check if the current flow is epsilon-optimal + if (top_rank == 0) { + return true; + } + + // Process buckets in top-down order + for (int rank = top_rank; rank > 0; --rank) { + while (_buckets[rank] != bucket_end) { + // Remove the first node from the current bucket + int u = _buckets[rank]; + _buckets[rank] = _bucket_next[u]; + + // Search the outgoing arcs of u + LargeCost rc, pi_u = _pi[u]; + int last_out = _first_out[u+1]; + int v, old_rank_v, new_rank_v; + for (int a = _first_out[u]; a != last_out; ++a) { + if (_res_cap[a] > 0) { + v = _target[a]; + old_rank_v = _rank[v]; + + if (old_rank_v < rank) { + + // Compute the new rank of node v + rc = _cost[a] + pi_u - _pi[v]; + if (rc < 0) { + new_rank_v = rank; + } else { + LargeCost nrc = rc / _epsilon; + new_rank_v = 0; + if (nrc < LargeCost(_max_rank)) { + new_rank_v = rank - 1 - static_cast(nrc); + } + } + + // Change the rank of node v + if (new_rank_v > old_rank_v) { + _rank[v] = new_rank_v; + + // Remove v from its old bucket + if (old_rank_v > 0) { + if (_buckets[old_rank_v] == v) { + _buckets[old_rank_v] = _bucket_next[v]; + } else { + int pv = _bucket_prev[v], nv = _bucket_next[v]; + _bucket_next[pv] = nv; + _bucket_prev[nv] = pv; + } + } + + // Insert v into its new bucket + int nv = _buckets[new_rank_v]; + _bucket_next[v] = nv; + _bucket_prev[nv] = v; + _buckets[new_rank_v] = v; + } + } + } + } + + // Refine potential of node u + _pi[u] -= rank * _epsilon; + } + } + } - _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 false; + } + + // Find and cancel cycles in the admissible network and + // determine topological order using DFS + bool topologicalSort(IntVector &stack, int &stack_top) { + const int MAX_CYCLE_CANCEL = 1; + + BoolVector reached(_res_node_num, false); + BoolVector processed(_res_node_num, false); + IntVector pred(_res_node_num); + for (int i = 0; i != _res_node_num; ++i) { + _next_out[i] = _first_out[i]; } - return done; + stack_top = -1; + + int cycle_cnt = 0; + for (int start = 0; start != _res_node_num; ++start) { + if (reached[start]) continue; + + // Start DFS search from this start node + pred[start] = -1; + int tip = start, v; + while (true) { + // Check the outgoing arcs of the current tip node + reached[tip] = true; + LargeCost pi_tip = _pi[tip]; + int a, last_out = _first_out[tip+1]; + for (a = _next_out[tip]; a != last_out; ++a) { + if (_res_cap[a] > 0) { + v = _target[a]; + if (_cost[a] + pi_tip - _pi[v] < 0) { + if (!reached[v]) { + // A new node is reached + reached[v] = true; + pred[v] = tip; + _next_out[tip] = a; + tip = v; + a = _next_out[tip]; + last_out = _first_out[tip+1]; + break; + } + else if (!processed[v]) { + // A cycle is found + ++cycle_cnt; + _next_out[tip] = a; + + // Find the minimum residual capacity along the cycle + Value d, delta = _res_cap[a]; + int u, delta_node = tip; + for (u = tip; u != v; ) { + u = pred[u]; + d = _res_cap[_next_out[u]]; + if (d <= delta) { + delta = d; + delta_node = u; + } + } + + // Augment along the cycle + _res_cap[a] -= delta; + _res_cap[_reverse[a]] += delta; + for (u = tip; u != v; ) { + u = pred[u]; + int ca = _next_out[u]; + _res_cap[ca] -= delta; + _res_cap[_reverse[ca]] += delta; + } + + // Check the maximum number of cycle canceling + if (cycle_cnt >= MAX_CYCLE_CANCEL) { + return false; + } + + // Roll back search to delta_node + if (delta_node != tip) { + for (u = tip; u != delta_node; u = pred[u]) { + reached[u] = false; + } + tip = delta_node; + a = _next_out[tip] + 1; + last_out = _first_out[tip+1]; + break; + } + } + } + } + } + + // Step back to the previous node + if (a == last_out) { + processed[tip] = true; + stack[++stack_top] = tip; + tip = pred[tip]; + if (tip < 0) { + // Finish DFS from the current start node + break; + } + ++_next_out[tip]; + } + } + + } + + return (cycle_cnt == 0); } // Global potential update heuristic void globalUpdate() { - int bucket_end = _root + 1; + const int bucket_end = _root + 1; // Initialize buckets for (int r = 0; r != _max_rank; ++r) { _buckets[r] = bucket_end; } Value total_excess = 0; + int b0 = bucket_end; 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; + _bucket_next[i] = b0; + _bucket_prev[b0] = i; + b0 = i; } else { total_excess += _excess[i]; _rank[i] = _max_rank; } } if (total_excess == 0) return; + _buckets[0] = b0; // Search the buckets int r = 0; @@ -1025,7 +1286,7 @@ int u = _buckets[r]; _buckets[r] = _bucket_next[u]; - // Search the incomming arcs of u + // Search the incoming 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) { @@ -1037,8 +1298,9 @@ // 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); + if (nrc < LargeCost(_max_rank)) { + new_rank_v = r + 1 + static_cast(nrc); + } // Change the rank of v if (new_rank_v < old_rank_v) { @@ -1050,14 +1312,16 @@ 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]; + int pv = _bucket_prev[v], nv = _bucket_next[v]; + _bucket_next[pv] = nv; + _bucket_prev[nv] = pv; } } - // Insert v to its new bucket - _bucket_next[v] = _buckets[new_rank_v]; - _bucket_prev[_buckets[new_rank_v]] = v; + // Insert v into its new bucket + int nv = _buckets[new_rank_v]; + _bucket_next[v] = nv; + _bucket_prev[nv] = v; _buckets[new_rank_v] = v; } } @@ -1086,23 +1350,25 @@ /// 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 * + const int PRICE_REFINEMENT_LIMIT = 2; + const double GLOBAL_UPDATE_FACTOR = 1.0; + const int global_update_skip = static_cast(GLOBAL_UPDATE_FACTOR * (_res_node_num + _sup_node_num * _sup_node_num)); - int next_update_limit = global_update_freq; - - int relabel_cnt = 0; + int next_global_update_limit = global_update_skip; // Perform cost scaling phases - std::vector path; + IntVector path; + BoolVector path_arc(_res_arc_num, false); + int relabel_cnt = 0; + int eps_phase_cnt = 0; for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? 1 : _epsilon / _alpha ) { - // Early termination heuristic - if (_epsilon <= EARLY_TERM_EPSILON_LIMIT) { - if (earlyTermination()) break; + ++eps_phase_cnt; + + // Price refinement heuristic + if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) { + if (priceRefinement()) continue; } // Initialize current phase @@ -1119,32 +1385,45 @@ 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) { + while (int(path.size()) < max_length && _excess[tip] >= 0) { int u; - LargeCost min_red_cost, rc, pi_tip = _pi[tip]; + LargeCost rc, min_red_cost = std::numeric_limits::max(); + LargeCost 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; + if (_res_cap[a] > 0) { + u = _target[a]; + rc = _cost[a] + pi_tip - _pi[u]; + if (rc < 0) { + path.push_back(a); + _next_out[tip] = a; + if (path_arc[a]) { + goto augment; // a cycle is found, stop path search + } + tip = u; + path_arc[a] = true; + goto next_step; + } + else if (rc < min_red_cost) { + min_red_cost = rc; + } } } // 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]]; + min_red_cost = + std::min(min_red_cost, _cost[ra] + pi_tip - _pi[_target[ra]]); } + last_out = _next_out[tip]; 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; + if (_res_cap[a] > 0) { + rc = _cost[a] + pi_tip - _pi[_target[a]]; + if (rc < min_red_cost) { + min_red_cost = rc; + } } } _pi[tip] -= min_red_cost + _epsilon; @@ -1153,7 +1432,9 @@ // Step back if (tip != start) { - tip = _source[path.back()]; + int pa = path.back(); + path_arc[pa] = false; + tip = _source[pa]; path.pop_back(); } @@ -1161,51 +1442,59 @@ } // Augment along the found path (as much flow as possible) + augment: Value delta; int pa, u, v = start; for (int i = 0; i != int(path.size()); ++i) { pa = path[i]; u = v; v = _target[pa]; + path_arc[pa] = false; 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) + if (_excess[v] > 0 && _excess[v] <= delta) { _active_nodes.push_back(v); + } } + path.clear(); // Global update heuristic - if (relabel_cnt >= next_update_limit) { + if (relabel_cnt >= next_global_update_limit) { globalUpdate(); - next_update_limit += global_update_freq; + next_global_update_limit += global_update_skip; } } + } + } /// Execute the algorithm performing push and relabel operations void startPush() { // Paramters for heuristics - const int EARLY_TERM_EPSILON_LIMIT = 1000; + const int PRICE_REFINEMENT_LIMIT = 2; const double GLOBAL_UPDATE_FACTOR = 2.0; - const int global_update_freq = int(GLOBAL_UPDATE_FACTOR * + const int global_update_skip = static_cast(GLOBAL_UPDATE_FACTOR * (_res_node_num + _sup_node_num * _sup_node_num)); - int next_update_limit = global_update_freq; - - int relabel_cnt = 0; + int next_global_update_limit = global_update_skip; // Perform cost scaling phases BoolVector hyper(_res_node_num, false); LargeCostVector hyper_cost(_res_node_num); + int relabel_cnt = 0; + int eps_phase_cnt = 0; for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? 1 : _epsilon / _alpha ) { - // Early termination heuristic - if (_epsilon <= EARLY_TERM_EPSILON_LIMIT) { - if (earlyTermination()) break; + ++eps_phase_cnt; + + // Price refinement heuristic + if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) { + if (priceRefinement()) continue; } // Initialize current phase @@ -1277,9 +1566,11 @@ 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; + if (_res_cap[a] > 0) { + rc = _cost[a] + pi_n - _pi[_target[a]]; + if (rc < min_red_cost) { + min_red_cost = rc; + } } } _pi[n] -= min_red_cost + _epsilon; @@ -1297,11 +1588,11 @@ } // Global update heuristic - if (relabel_cnt >= next_update_limit) { + if (relabel_cnt >= next_global_update_limit) { globalUpdate(); for (int u = 0; u != _res_node_num; ++u) hyper[u] = false; - next_update_limit += global_update_freq; + next_global_update_limit += global_update_skip; } } } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/counter.h --- a/lemon/counter.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/counter.h Wed Oct 17 19:14:07 2018 +0200 @@ -22,6 +22,8 @@ #include #include +#include + ///\ingroup timecount ///\file ///\brief Tools for counting steps and events diff -r cd72eae05bdf -r 3c00344f49c9 lemon/cplex.cc --- a/lemon/cplex.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/cplex.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -37,36 +37,54 @@ } } + void CplexEnv::incCnt() + { + _cnt_lock->lock(); + ++(*_cnt); + _cnt_lock->unlock(); + } + + void CplexEnv::decCnt() + { + _cnt_lock->lock(); + --(*_cnt); + if (*_cnt == 0) { + delete _cnt; + _cnt_lock->unlock(); + delete _cnt_lock; + CPXcloseCPLEX(&_env); + } + else _cnt_lock->unlock(); + } + CplexEnv::CplexEnv() { int status; + _env = CPXopenCPLEX(&status); + if (_env == 0) + throw LicenseError(status); _cnt = new int; - _env = CPXopenCPLEX(&status); - if (_env == 0) { - delete _cnt; - _cnt = 0; - throw LicenseError(status); - } + (*_cnt) = 1; + _cnt_lock = new bits::Lock; } CplexEnv::CplexEnv(const CplexEnv& other) { _env = other._env; _cnt = other._cnt; - ++(*_cnt); + _cnt_lock = other._cnt_lock; + incCnt(); } CplexEnv& CplexEnv::operator=(const CplexEnv& other) { + decCnt(); _env = other._env; _cnt = other._cnt; - ++(*_cnt); + _cnt_lock = other._cnt_lock; + incCnt(); return *this; } CplexEnv::~CplexEnv() { - --(*_cnt); - if (*_cnt == 0) { - delete _cnt; - CPXcloseCPLEX(&_env); - } + decCnt(); } CplexBase::CplexBase() : LpBase() { @@ -491,6 +509,17 @@ _message_enabled ? CPX_ON : CPX_OFF); } + void CplexBase::_write(std::string file, std::string format) const + { + if(format == "MPS" || format == "LP") + CPXwriteprob(cplexEnv(), cplexLp(), file.c_str(), format.c_str()); + else if(format == "SOL") + CPXsolwrite(cplexEnv(), cplexLp(), file.c_str()); + else throw UnsupportedFormatError(format); + } + + + // CplexLp members CplexLp::CplexLp() diff -r cd72eae05bdf -r 3c00344f49c9 lemon/cplex.h --- a/lemon/cplex.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/cplex.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -23,6 +23,7 @@ ///\brief Header of the LEMON-CPLEX lp solver interface. #include +#include struct cpxenv; struct cpxlp; @@ -40,7 +41,11 @@ private: cpxenv* _env; mutable int* _cnt; + mutable bits::Lock* _cnt_lock; + void incCnt(); + void decCnt(); + public: /// \brief This exception is thrown when the license check is not @@ -150,6 +155,8 @@ bool _message_enabled; + void _write(std::string file, std::string format) const; + public: /// Returns the used \c CplexEnv instance @@ -170,6 +177,19 @@ /// Returns the cplex problem object const cpxlp* cplexLp() const { return _prob; } +#ifdef DOXYGEN + /// Write the problem or the solution to a file in the given format + + /// This function writes the problem or the solution + /// to a file in the given format. + /// Trying to write in an unsupported format will trigger + /// \ref lemon::LpBase::UnsupportedFormatError "UnsupportedFormatError". + /// \param file The file path + /// \param format The output file format. + /// Supportted formats are "MPS", "LP" and "SOL". + void write(std::string file, std::string format = "MPS") const {} +#endif + }; /// \brief Interface for the CPLEX LP solver diff -r cd72eae05bdf -r 3c00344f49c9 lemon/cycle_canceling.h --- a/lemon/cycle_canceling.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/cycle_canceling.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -35,6 +35,7 @@ #include #include #include +#include namespace lemon { @@ -46,13 +47,14 @@ /// /// \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. + /// \cite amo93networkflows, \cite klein67primal, + /// \cite goldberg89cyclecanceling. + /// The most efficent one is the \ref CANCEL_AND_TIGHTEN + /// "Cancel-and-Tighten" algorithm, thus it is the default method. + /// It runs in strongly polynomial time \f$O(n^2 m^2 \log n)\f$, + /// but in practice, it is typically orders of magnitude slower than + /// the scaling algorithms and \ref NetworkSimplex. + /// (For more information, see \ref min_cost_flow_algs "the module page".) /// /// Most of the parameters of the problem (except for the digraph) /// can be given using separate functions, and the algorithm can be @@ -65,10 +67,11 @@ /// \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 + /// \warning Both \c V and \c C must be signed number types. + /// \warning All input data (capacities, supply values, and costs) must /// be integer. - /// \warning This algorithm does not support negative costs for such - /// arcs that have infinite upper bound. + /// \warning This algorithm does not support negative costs for + /// arcs having infinite upper bound. /// /// \note For more information about the three available methods, /// see \ref Method. @@ -115,27 +118,28 @@ /// 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. + /// methods. By default, \ref CANCEL_AND_TIGHTEN "Cancel-and-Tighten" + /// is used, which is by far the most efficient and the most robust. /// 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. + /// \ref BellmanFord "Bellman-Ford" algorithm for detecting negative + /// cycles in the residual network. + /// The number of Bellman-Ford iterations is bounded by a successively + /// increased limit. SIMPLE_CYCLE_CANCELING, /// The "Minimum Mean Cycle-Canceling" algorithm, which is a /// well-known strongly polynomial method - /// \ref goldberg89cyclecanceling. It improves along a + /// \cite goldberg89cyclecanceling. It improves along a /// \ref min_mean_cycle "minimum mean cycle" in each iteration. - /// Its running time complexity is O(n2m3log(n)). + /// Its running time complexity is \f$O(n^2 m^3 \log n)\f$. MINIMUM_MEAN_CYCLE_CANCELING, - /// The "Cancel And Tighten" algorithm, which can be viewed as an + /// The "Cancel-and-Tighten" algorithm, which can be viewed as an /// improved version of the previous method - /// \ref goldberg89cyclecanceling. + /// \cite goldberg89cyclecanceling. /// It is faster both in theory and in practice, its running time - /// complexity is O(n2m2log(n)). + /// complexity is \f$O(n^2 m^2 \log n)\f$. CANCEL_AND_TIGHTEN }; @@ -191,7 +195,7 @@ int _root; // Parameters of the problem - bool _have_lower; + bool _has_lower; Value _sum_supply; // Data structures for storing the digraph @@ -274,10 +278,9 @@ /// \return (*this) template CycleCanceling& lowerMap(const LowerMap& map) { - _have_lower = true; + _has_lower = true; for (ArcIt a(_graph); a != INVALID; ++a) { _lower[_arc_idf[a]] = map[a]; - _lower[_arc_idb[a]] = map[a]; } return *this; } @@ -349,7 +352,7 @@ /// 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 + /// with 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. @@ -467,7 +470,7 @@ _cost[j] = 0; _cost[_reverse[j]] = 0; } - _have_lower = false; + _has_lower = false; return *this; } @@ -572,7 +575,7 @@ /// \brief Return the total cost of the found flow. /// /// This function returns the total cost of the found flow. - /// Its complexity is O(e). + /// Its complexity is O(m). /// /// \note The return type of the function can be specified as a /// template parameter. For example, @@ -610,7 +613,8 @@ return _res_cap[_arc_idb[a]]; } - /// \brief Return the flow map (the primal solution). + /// \brief Copy the flow values (the primal solution) into the + /// given map. /// /// This function copies the flow value on each arc into the given /// map. The \c Value type of the algorithm must be convertible to @@ -634,7 +638,8 @@ return static_cast(_pi[_node_id[n]]); } - /// \brief Return the potential map (the dual solution). + /// \brief Copy the potential values (the dual solution) into the + /// given map. /// /// This function copies the potential (dual value) of each node /// into the given map. @@ -664,6 +669,10 @@ } if (_sum_supply > 0) return INFEASIBLE; + // Check lower and upper bounds + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + // Initialize vectors for (int i = 0; i != _res_node_num; ++i) { @@ -674,7 +683,7 @@ // Remove infinite upper bounds and check negative arcs const Value MAX = std::numeric_limits::max(); int last_out; - if (_have_lower) { + if (_has_lower) { for (int i = 0; i != _root; ++i) { last_out = _first_out[i+1]; for (int j = _first_out[i]; j != last_out; ++j) { @@ -717,7 +726,7 @@ for (NodeIt n(_graph); n != INVALID; ++n) { sup[n] = _supply[_node_id[n]]; } - if (_have_lower) { + if (_has_lower) { for (ArcIt a(_graph); a != INVALID; ++a) { int j = _arc_idf[a]; Value c = _lower[j]; @@ -774,6 +783,15 @@ return OPTIMAL; } + // Check if the upper bound is greater than or equal to the lower bound + // on each forward arc. + bool checkBoundMaps() { + for (int j = 0; j != _res_arc_num; ++j) { + if (_forward[j] && _upper[j] < _lower[j]) return false; + } + return true; + } + // Build a StaticDigraph structure containing the current // residual network void buildResidualNetwork() { @@ -816,10 +834,10 @@ } // Handle non-zero lower bounds - if (_have_lower) { + if (_has_lower) { int limit = _first_out[_root]; for (int j = 0; j != limit; ++j) { - if (!_forward[j]) _res_cap[j] += _lower[j]; + if (_forward[j]) _res_cap[_reverse[j]] += _lower[j]; } } } @@ -922,18 +940,41 @@ // Execute the "Minimum Mean Cycle Canceling" method void startMinMeanCycleCanceling() { - typedef SimplePath SPath; + typedef Path SPath; typedef typename SPath::ArcIt SPathArcIt; typedef typename HowardMmc - ::template SetPath::Create MMC; + ::template SetPath::Create HwMmc; + typedef typename HartmannOrlinMmc + ::template SetPath::Create HoMmc; + + const double HW_ITER_LIMIT_FACTOR = 1.0; + const int HW_ITER_LIMIT_MIN_VALUE = 5; + + const int hw_iter_limit = + std::max(static_cast(HW_ITER_LIMIT_FACTOR * _node_num), + HW_ITER_LIMIT_MIN_VALUE); SPath cycle; - MMC mmc(_sgr, _cost_map); - mmc.cycle(cycle); + HwMmc hw_mmc(_sgr, _cost_map); + hw_mmc.cycle(cycle); buildResidualNetwork(); - while (mmc.findCycleMean() && mmc.cycleCost() < 0) { - // Find the cycle - mmc.findCycle(); + while (true) { + + typename HwMmc::TerminationCause hw_tc = + hw_mmc.findCycleMean(hw_iter_limit); + if (hw_tc == HwMmc::ITERATION_LIMIT) { + // Howard's algorithm reached the iteration limit, start a + // strongly polynomial algorithm instead + HoMmc ho_mmc(_sgr, _cost_map); + ho_mmc.cycle(cycle); + // Find a minimum mean cycle (Hartmann-Orlin algorithm) + if (!(ho_mmc.findCycleMean() && ho_mmc.cycleCost() < 0)) break; + ho_mmc.findCycle(); + } else { + // Find a minimum mean cycle (Howard algorithm) + if (!(hw_tc == HwMmc::OPTIMAL && hw_mmc.cycleCost() < 0)) break; + hw_mmc.findCycle(); + } // Compute delta value Value delta = INF; @@ -954,11 +995,17 @@ } } - // Execute the "Cancel And Tighten" method + // 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; + const double HW_ITER_LIMIT_FACTOR = 1.0; + const int HW_ITER_LIMIT_MIN_VALUE = 5; + + const int hw_iter_limit = + std::max(static_cast(HW_ITER_LIMIT_FACTOR * _node_num), + HW_ITER_LIMIT_MIN_VALUE); // Contruct auxiliary data vectors DoubleVector pi(_res_node_num, 0.0); @@ -1132,17 +1179,30 @@ } } } else { - typedef HowardMmc MMC; + typedef HowardMmc HwMmc; + typedef HartmannOrlinMmc HoMmc; typedef typename BellmanFord ::template SetDistMap::Create BF; // Set epsilon to the minimum cycle mean + Cost cycle_cost = 0; + int cycle_size = 1; buildResidualNetwork(); - MMC mmc(_sgr, _cost_map); - mmc.findCycleMean(); - epsilon = -mmc.cycleMean(); - Cost cycle_cost = mmc.cycleCost(); - int cycle_size = mmc.cycleSize(); + HwMmc hw_mmc(_sgr, _cost_map); + if (hw_mmc.findCycleMean(hw_iter_limit) == HwMmc::ITERATION_LIMIT) { + // Howard's algorithm reached the iteration limit, start a + // strongly polynomial algorithm instead + HoMmc ho_mmc(_sgr, _cost_map); + ho_mmc.findCycleMean(); + epsilon = -ho_mmc.cycleMean(); + cycle_cost = ho_mmc.cycleCost(); + cycle_size = ho_mmc.cycleSize(); + } else { + // Set epsilon + epsilon = -hw_mmc.cycleMean(); + cycle_cost = hw_mmc.cycleCost(); + cycle_size = hw_mmc.cycleSize(); + } // Compute feasible potentials for the current epsilon for (int i = 0; i != int(_cost_vec.size()); ++i) { diff -r cd72eae05bdf -r 3c00344f49c9 lemon/dfs.h --- a/lemon/dfs.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/dfs.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -152,7 +152,7 @@ ///The type of the paths. typedef PredMapPath Path; - ///The \ref DfsDefaultTraits "traits class" of the algorithm. + ///The \ref lemon::DfsDefaultTraits "traits class" of the algorithm. typedef TR Traits; private: diff -r cd72eae05bdf -r 3c00344f49c9 lemon/dijkstra.h --- a/lemon/dijkstra.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/dijkstra.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -227,11 +227,11 @@ typedef typename TR::HeapCrossRef HeapCrossRef; ///The heap type used by the algorithm. typedef typename TR::Heap Heap; - ///\brief The \ref DijkstraDefaultOperationTraits "operation traits class" - ///of the algorithm. + /// \brief The \ref lemon::DijkstraDefaultOperationTraits + /// "operation traits class" of the algorithm. typedef typename TR::OperationTraits OperationTraits; - ///The \ref DijkstraDefaultTraits "traits class" of the algorithm. + ///The \ref lemon::DijkstraDefaultTraits "traits class" of the algorithm. typedef TR Traits; private: diff -r cd72eae05bdf -r 3c00344f49c9 lemon/dim2.h --- a/lemon/dim2.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/dim2.h Wed Oct 17 19:14:07 2018 +0200 @@ -20,6 +20,7 @@ #define LEMON_DIM2_H #include +#include ///\ingroup geomdat ///\file diff -r cd72eae05bdf -r 3c00344f49c9 lemon/dimacs.h --- a/lemon/dimacs.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/dimacs.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -25,6 +25,7 @@ #include #include #include + /// \ingroup dimacs_group /// \file /// \brief DIMACS file format reader. @@ -122,7 +123,7 @@ /// a non-zero value, that value will be used as "infinite". /// /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. + /// the descriptor struct should be given by the \c desc parameter. template @@ -276,7 +277,7 @@ /// a non-zero value, that value will be used as "infinite". /// /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. + /// the descriptor struct should be given by the \c desc parameter. template void readDimacsMax(std::istream& is, Digraph &g, @@ -303,7 +304,7 @@ /// source node. /// /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. + /// the descriptor struct should be given by the \c desc parameter. template void readDimacsSp(std::istream& is, Digraph &g, @@ -334,7 +335,7 @@ /// a non-zero value, that value will be used as "infinite". /// /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. + /// the descriptor struct should be given by the \c desc parameter. template void readDimacsCap(std::istream& is, Digraph &g, @@ -343,7 +344,7 @@ DimacsDescriptor desc=DimacsDescriptor()) { typename Digraph::Node u,v; if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); - if(desc.type!=DimacsDescriptor::MAX || desc.type!=DimacsDescriptor::SP) + if(desc.type!=DimacsDescriptor::MAX && desc.type!=DimacsDescriptor::SP) throw FormatError("Problem type mismatch"); _readDimacs(is, g, capacity, u, v, infty, desc); } @@ -374,7 +375,7 @@ /// At the beginning, \c g is cleared by \c g.clear(). /// /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. + /// the descriptor struct should be given by the \c desc parameter. template void readDimacsMat(std::istream& is, Graph &g, DimacsDescriptor desc=DimacsDescriptor()) diff -r cd72eae05bdf -r 3c00344f49c9 lemon/edge_set.h --- a/lemon/edge_set.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/edge_set.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/edmonds_karp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/edmonds_karp.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,556 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_EDMONDS_KARP_H +#define LEMON_EDMONDS_KARP_H + +/// \file +/// \ingroup max_flow +/// \brief Implementation of the Edmonds-Karp algorithm. + +#include +#include + +namespace lemon { + + /// \brief Default traits class of EdmondsKarp class. + /// + /// Default traits class of EdmondsKarp class. + /// \param GR Digraph type. + /// \param CAP Type of capacity map. + template + struct EdmondsKarpDefaultTraits { + + /// \brief The digraph type the algorithm runs on. + typedef GR Digraph; + + /// \brief The type of the map that stores the arc capacities. + /// + /// The type of the map that stores the arc capacities. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef CAP CapacityMap; + + /// \brief The type of the flow values. + typedef typename CapacityMap::Value Value; + + /// \brief The type of the map that stores the flow values. + /// + /// 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. + /// + /// This function instantiates a \ref FlowMap. + /// \param digraph The digraph for which we would like to define + /// the flow map. + static FlowMap* createFlowMap(const Digraph& digraph) { + return new FlowMap(digraph); + } + + /// \brief The tolerance used by the algorithm + /// + /// The tolerance used by the algorithm to handle inexact computation. + typedef lemon::Tolerance Tolerance; + + }; + + /// \ingroup max_flow + /// + /// \brief Edmonds-Karp algorithms class. + /// + /// This class provides an implementation of the \e Edmonds-Karp \e + /// algorithm producing a \ref max_flow "flow of maximum value" in a + /// digraph \cite clrs01algorithms, \cite amo93networkflows, + /// \cite edmondskarp72theoretical. + /// The Edmonds-Karp algorithm is slower than the Preflow + /// algorithm, but it has an advantage of the step-by-step execution + /// control with feasible flow solutions. The \e source node, the \e + /// target node, the \e capacity of the arcs and the \e starting \e + /// flow value of the arcs should be passed to the algorithm + /// through the constructor. + /// + /// The time complexity of the algorithm is \f$ O(nm^2) \f$ in + /// worst case. Always try the Preflow algorithm instead of this if + /// you just want to compute the optimal flow. + /// + /// \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 EdmondsKarpDefaultTraits + /// "EdmondsKarpDefaultTraits". + /// 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 = EdmondsKarpDefaultTraits > +#endif + class EdmondsKarp { + public: + + /// \brief The \ref lemon::EdmondsKarpDefaultTraits "traits class" + /// of the algorithm. + typedef TR Traits; + /// The type of the digraph the algorithm runs on. + typedef typename Traits::Digraph Digraph; + /// The type of the capacity map. + typedef typename Traits::CapacityMap CapacityMap; + /// The type of the flow values. + typedef typename Traits::Value Value; + + /// The type of the flow map. + typedef typename Traits::FlowMap FlowMap; + /// The type of the tolerance. + typedef typename Traits::Tolerance Tolerance; + + private: + + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); + typedef typename Digraph::template NodeMap PredMap; + + const Digraph& _graph; + const CapacityMap* _capacity; + + Node _source, _target; + + FlowMap* _flow; + bool _local_flow; + + PredMap* _pred; + std::vector _queue; + + Tolerance _tolerance; + Value _flow_value; + + void createStructures() { + if (!_flow) { + _flow = Traits::createFlowMap(_graph); + _local_flow = true; + } + if (!_pred) { + _pred = new PredMap(_graph); + } + _queue.resize(countNodes(_graph)); + } + + void destroyStructures() { + if (_local_flow) { + delete _flow; + } + if (_pred) { + delete _pred; + } + } + + public: + + typedef EdmondsKarp Create; + + ///\name Named template parameters + + ///@{ + + template + struct SetFlowMapTraits : public Traits { + typedef T FlowMap; + static FlowMap *createFlowMap(const Digraph&) { + LEMON_ASSERT(false, "FlowMap is not initialized"); + return 0; + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// FlowMap type + /// + /// \ref named-templ-param "Named parameter" for setting FlowMap + /// type + template + struct SetFlowMap + : public EdmondsKarp > { + typedef EdmondsKarp > Create; + }; + + /// @} + + protected: + + EdmondsKarp() {} + + public: + + /// \brief The constructor of the class. + /// + /// The constructor of the class. + /// \param digraph The digraph the algorithm runs on. + /// \param capacity The capacity of the arcs. + /// \param source The source node. + /// \param target The target node. + EdmondsKarp(const Digraph& digraph, const CapacityMap& capacity, + Node source, Node target) + : _graph(digraph), _capacity(&capacity), _source(source), _target(target), + _flow(0), _local_flow(false), _pred(0), _tolerance(), _flow_value() + { + LEMON_ASSERT(_source != _target, + "Flow source and target are the same nodes."); + } + + /// \brief Destructor. + /// + /// Destructor. + ~EdmondsKarp() { + destroyStructures(); + } + + /// \brief Sets the capacity map. + /// + /// Sets the capacity map. + /// \return (*this) + EdmondsKarp& capacityMap(const CapacityMap& map) { + _capacity = ↦ + return *this; + } + + /// \brief Sets the flow map. + /// + /// Sets the flow 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) + EdmondsKarp& flowMap(FlowMap& map) { + if (_local_flow) { + delete _flow; + _local_flow = false; + } + _flow = ↦ + return *this; + } + + /// \brief Sets the source node. + /// + /// Sets the source node. + /// \return (*this) + EdmondsKarp& source(const Node& node) { + _source = node; + return *this; + } + + /// \brief Sets the target node. + /// + /// Sets the target node. + /// \return (*this) + EdmondsKarp& target(const Node& node) { + _target = node; + return *this; + } + + /// \brief Sets the tolerance used by algorithm. + /// + /// Sets the tolerance used by algorithm. + /// \return (*this) + EdmondsKarp& tolerance(const Tolerance& tolerance) { + _tolerance = tolerance; + return *this; + } + + /// \brief 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; + } + + /// \name Execution control + /// The simplest way to execute the algorithm is to use \ref run().\n + /// 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 start() or multiple times the \ref augment() function. + + ///@{ + + /// \brief Initializes the algorithm. + /// + /// Initializes the internal data structures and sets the initial + /// flow to zero on each arc. + void init() { + createStructures(); + for (ArcIt it(_graph); it != INVALID; ++it) { + _flow->set(it, 0); + } + _flow_value = 0; + } + + /// \brief Initializes the algorithm using the given flow map. + /// + /// Initializes the internal data structures and sets the initial + /// flow to the given \c flowMap. The \c flowMap should + /// contain a feasible flow, i.e. at each node excluding the source + /// and the target, the incoming flow should be equal to the + /// outgoing flow. + template + void init(const FlowMap& flowMap) { + createStructures(); + for (ArcIt e(_graph); e != INVALID; ++e) { + _flow->set(e, flowMap[e]); + } + _flow_value = 0; + for (OutArcIt jt(_graph, _source); jt != INVALID; ++jt) { + _flow_value += (*_flow)[jt]; + } + for (InArcIt jt(_graph, _source); jt != INVALID; ++jt) { + _flow_value -= (*_flow)[jt]; + } + } + + /// \brief Initializes the algorithm using the given flow map. + /// + /// Initializes the internal data structures and sets the initial + /// flow to the given \c flowMap. The \c flowMap should + /// contain a feasible flow, i.e. at each node excluding the source + /// and the target, the incoming flow should be equal to the + /// outgoing flow. + /// \return \c false when the given \c flowMap does not contain a + /// feasible flow. + template + bool checkedInit(const FlowMap& flowMap) { + createStructures(); + for (ArcIt e(_graph); e != INVALID; ++e) { + _flow->set(e, flowMap[e]); + } + for (NodeIt it(_graph); it != INVALID; ++it) { + if (it == _source || it == _target) continue; + Value outFlow = 0; + for (OutArcIt jt(_graph, it); jt != INVALID; ++jt) { + outFlow += (*_flow)[jt]; + } + Value inFlow = 0; + for (InArcIt jt(_graph, it); jt != INVALID; ++jt) { + inFlow += (*_flow)[jt]; + } + if (_tolerance.different(outFlow, inFlow)) { + return false; + } + } + for (ArcIt it(_graph); it != INVALID; ++it) { + if (_tolerance.less((*_flow)[it], 0)) return false; + if (_tolerance.less((*_capacity)[it], (*_flow)[it])) return false; + } + _flow_value = 0; + for (OutArcIt jt(_graph, _source); jt != INVALID; ++jt) { + _flow_value += (*_flow)[jt]; + } + for (InArcIt jt(_graph, _source); jt != INVALID; ++jt) { + _flow_value -= (*_flow)[jt]; + } + return true; + } + + /// \brief Augments the solution along a shortest path. + /// + /// Augments the solution along a shortest path. This function searches a + /// shortest path between the source and the target + /// in the residual digraph by the Bfs algoritm. + /// Then it increases the flow on this path with the minimal residual + /// capacity on the path. If there is no such path, it gives back + /// false. + /// \return \c false when the augmenting did not success, i.e. the + /// current flow is a feasible and optimal solution. + bool augment() { + for (NodeIt n(_graph); n != INVALID; ++n) { + _pred->set(n, INVALID); + } + + int first = 0, last = 1; + + _queue[0] = _source; + _pred->set(_source, OutArcIt(_graph, _source)); + + while (first != last && (*_pred)[_target] == INVALID) { + Node n = _queue[first++]; + + for (OutArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_capacity)[e] - (*_flow)[e]; + Node t = _graph.target(e); + if (_tolerance.positive(rem) && (*_pred)[t] == INVALID) { + _pred->set(t, e); + _queue[last++] = t; + } + } + for (InArcIt e(_graph, n); e != INVALID; ++e) { + Value rem = (*_flow)[e]; + Node t = _graph.source(e); + if (_tolerance.positive(rem) && (*_pred)[t] == INVALID) { + _pred->set(t, e); + _queue[last++] = t; + } + } + } + + if ((*_pred)[_target] != INVALID) { + Node n = _target; + Arc e = (*_pred)[n]; + + Value prem = (*_capacity)[e] - (*_flow)[e]; + n = _graph.source(e); + while (n != _source) { + e = (*_pred)[n]; + if (_graph.target(e) == n) { + Value rem = (*_capacity)[e] - (*_flow)[e]; + if (rem < prem) prem = rem; + n = _graph.source(e); + } else { + Value rem = (*_flow)[e]; + if (rem < prem) prem = rem; + n = _graph.target(e); + } + } + + n = _target; + e = (*_pred)[n]; + + _flow->set(e, (*_flow)[e] + prem); + n = _graph.source(e); + while (n != _source) { + e = (*_pred)[n]; + if (_graph.target(e) == n) { + _flow->set(e, (*_flow)[e] + prem); + n = _graph.source(e); + } else { + _flow->set(e, (*_flow)[e] - prem); + n = _graph.target(e); + } + } + + _flow_value += prem; + return true; + } else { + return false; + } + } + + /// \brief Executes the algorithm + /// + /// Executes the algorithm by performing augmenting phases until the + /// optimal solution is reached. + /// \pre One of the \ref init() functions must be called before + /// using this function. + void start() { + while (augment()) {} + } + + /// \brief Runs the algorithm. + /// + /// Runs the Edmonds-Karp algorithm. + /// \note ek.run() is just a shortcut of the following code. + ///\code + /// ek.init(); + /// ek.start(); + ///\endcode + void run() { + init(); + start(); + } + + /// @} + + /// \name Query Functions + /// The result of the Edmonds-Karp algorithm can be obtained using these + /// functions.\n + /// Either \ref run() or \ref start() should be called before using them. + + ///@{ + + /// \brief Returns the value of the maximum flow. + /// + /// Returns the value of the maximum flow found by the algorithm. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Value flowValue() const { + return _flow_value; + } + + /// \brief Returns the flow value on the given arc. + /// + /// Returns the flow value on the given arc. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + Value flow(const Arc& arc) const { + return (*_flow)[arc]; + } + + /// \brief Returns a const reference to the flow map. + /// + /// Returns a const reference to the arc map storing the found flow. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + const FlowMap& flowMap() const { + return *_flow; + } + + /// \brief Returns \c true when the node is on the source side of the + /// minimum cut. + /// + /// Returns true when the node is on the source side of the found + /// minimum cut. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + bool minCut(const Node& node) const { + return ((*_pred)[node] != INVALID) || node == _source; + } + + /// \brief Gives back a minimum value cut. + /// + /// Sets \c cutMap to the characteristic vector of a minimum value + /// cut. \c cutMap should be a \ref concepts::WriteMap "writable" + /// node map with \c bool (or convertible) value type. + /// + /// \note This function calls \ref minCut() for each node, so it runs in + /// O(n) time. + /// + /// \pre Either \ref run() or \ref init() must be called before + /// using this function. + template + void minCutMap(CutMap& cutMap) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + cutMap.set(n, (*_pred)[n] != INVALID); + } + cutMap.set(_source, true); + } + + /// @} + + }; + +} + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/elevator.h --- a/lemon/elevator.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/elevator.h Wed Oct 17 19:14:07 2018 +0200 @@ -167,7 +167,7 @@ ///Return the number of items on level \c l. int onLevel(int l) const { - return _first[l+1]-_first[l]; + return static_cast(_first[l+1]-_first[l]); } ///Return true if level \c l is empty. bool emptyLevel(int l) const @@ -177,12 +177,12 @@ ///Return the number of items above level \c l. int aboveLevel(int l) const { - return _first[_max_level+1]-_first[l+1]; + return static_cast(_first[_max_level+1]-_first[l+1]); } ///Return the number of active items on level \c l. int activesOnLevel(int l) const { - return _last_active[l]-_first[l]+1; + return static_cast(_last_active[l]-_first[l]+1); } ///Return true if there is no active item on level \c l. bool activeFree(int l) const diff -r cd72eae05bdf -r 3c00344f49c9 lemon/euler.h --- a/lemon/euler.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/euler.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -36,7 +36,7 @@ ///Euler tour iterator for digraphs. - /// \ingroup graph_prop + /// \ingroup graph_properties ///This iterator provides an Euler tour (Eulerian circuit) of a \e directed ///graph (if there exists) and it converts to the \c Arc type of the digraph. /// diff -r cd72eae05bdf -r 3c00344f49c9 lemon/fractional_matching.h --- a/lemon/fractional_matching.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/fractional_matching.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -123,8 +123,8 @@ class MaxFractionalMatching { public: - /// \brief The \ref MaxFractionalMatchingDefaultTraits "traits - /// class" of the algorithm. + /// \brief The \ref lemon::MaxFractionalMatchingDefaultTraits + /// "traits class" of the algorithm. typedef TR Traits; /// The type of the graph the algorithm runs on. typedef typename TR::Graph Graph; diff -r cd72eae05bdf -r 3c00344f49c9 lemon/full_graph.h --- a/lemon/full_graph.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/full_graph.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -621,6 +621,460 @@ }; + class FullBpGraphBase { + + protected: + + int _red_num, _blue_num; + int _node_num, _edge_num; + + public: + + typedef FullBpGraphBase Graph; + + class Node; + class Arc; + class Edge; + + class Node { + friend class FullBpGraphBase; + protected: + + int _id; + explicit 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 RedNode : public Node { + friend class FullBpGraphBase; + protected: + + explicit RedNode(int pid) : Node(pid) {} + + public: + RedNode() {} + RedNode(const RedNode& node) : Node(node) {} + RedNode(Invalid) : Node(INVALID){} + }; + + class BlueNode : public Node { + friend class FullBpGraphBase; + protected: + + explicit BlueNode(int pid) : Node(pid) {} + + public: + BlueNode() {} + BlueNode(const BlueNode& node) : Node(node) {} + BlueNode(Invalid) : Node(INVALID){} + }; + + class Edge { + friend class FullBpGraphBase; + protected: + + int _id; + explicit Edge(int id) { _id = id;} + + public: + Edge() {} + Edge (Invalid) { _id = -1; } + bool operator==(const Edge& arc) const {return _id == arc._id;} + bool operator!=(const Edge& arc) const {return _id != arc._id;} + bool operator<(const Edge& arc) const {return _id < arc._id;} + }; + + class Arc { + friend class FullBpGraphBase; + protected: + + int _id; + explicit Arc(int id) { _id = id;} + + public: + operator Edge() const { + return _id != -1 ? edgeFromId(_id / 2) : INVALID; + } + + 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;} + }; + + + protected: + + FullBpGraphBase() + : _red_num(0), _blue_num(0), _node_num(0), _edge_num(0) {} + + void construct(int redNum, int blueNum) { + _red_num = redNum; _blue_num = blueNum; + _node_num = redNum + blueNum; _edge_num = redNum * blueNum; + } + + public: + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return _node_num; } + int redNum() const { return _red_num; } + int blueNum() const { return _blue_num; } + int edgeNum() const { return _edge_num; } + int arcNum() const { return 2 * _edge_num; } + + int maxNodeId() const { return _node_num - 1; } + int maxRedId() const { return _red_num - 1; } + int maxBlueId() const { return _blue_num - 1; } + int maxEdgeId() const { return _edge_num - 1; } + int maxArcId() const { return 2 * _edge_num - 1; } + + bool red(Node n) const { return n._id < _red_num; } + bool blue(Node n) const { return n._id >= _red_num; } + + static RedNode asRedNodeUnsafe(Node n) { return RedNode(n._id); } + static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n._id); } + + Node source(Arc a) const { + if (a._id & 1) { + return Node((a._id >> 1) % _red_num); + } else { + return Node((a._id >> 1) / _red_num + _red_num); + } + } + Node target(Arc a) const { + if (a._id & 1) { + return Node((a._id >> 1) / _red_num + _red_num); + } else { + return Node((a._id >> 1) % _red_num); + } + } + + RedNode redNode(Edge e) const { + return RedNode(e._id % _red_num); + } + BlueNode blueNode(Edge e) const { + return BlueNode(e._id / _red_num + _red_num); + } + + static bool direction(Arc a) { + return (a._id & 1) == 1; + } + + static Arc direct(Edge e, bool d) { + return Arc(e._id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node._id = _node_num - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(RedNode& node) const { + node._id = _red_num - 1; + } + + static void next(RedNode& node) { + --node._id; + } + + void first(BlueNode& node) const { + if (_red_num == _node_num) node._id = -1; + else node._id = _node_num - 1; + } + + void next(BlueNode& node) const { + if (node._id == _red_num) node._id = -1; + else --node._id; + } + + void first(Arc& arc) const { + arc._id = 2 * _edge_num - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void first(Edge& arc) const { + arc._id = _edge_num - 1; + } + + static void next(Edge& arc) { + --arc._id; + } + + void firstOut(Arc &a, const Node& v) const { + if (v._id < _red_num) { + a._id = 2 * (v._id + _red_num * (_blue_num - 1)) + 1; + } else { + a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num)); + } + } + void nextOut(Arc &a) const { + if (a._id & 1) { + a._id -= 2 * _red_num; + if (a._id < 0) a._id = -1; + } else { + if (a._id % (2 * _red_num) == 0) a._id = -1; + else a._id -= 2; + } + } + + void firstIn(Arc &a, const Node& v) const { + if (v._id < _red_num) { + a._id = 2 * (v._id + _red_num * (_blue_num - 1)); + } else { + a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num)) + 1; + } + } + void nextIn(Arc &a) const { + if (a._id & 1) { + if (a._id % (2 * _red_num) == 1) a._id = -1; + else a._id -= 2; + } else { + a._id -= 2 * _red_num; + if (a._id < 0) a._id = -1; + } + } + + void firstInc(Edge &e, bool& d, const Node& v) const { + if (v._id < _red_num) { + d = true; + e._id = v._id + _red_num * (_blue_num - 1); + } else { + d = false; + e._id = _red_num - 1 + _red_num * (v._id - _red_num); + } + } + void nextInc(Edge &e, bool& d) const { + if (d) { + e._id -= _red_num; + if (e._id < 0) e._id = -1; + } else { + if (e._id % _red_num == 0) e._id = -1; + else --e._id; + } + } + + static int id(const Node& v) { return v._id; } + int id(const RedNode& v) const { return v._id; } + int id(const BlueNode& v) const { return v._id - _red_num; } + static int id(Arc e) { return e._id; } + static int id(Edge e) { return e._id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + bool valid(Node n) const { + return n._id >= 0 && n._id < _node_num; + } + bool valid(Arc a) const { + return a._id >= 0 && a._id < 2 * _edge_num; + } + bool valid(Edge e) const { + return e._id >= 0 && e._id < _edge_num; + } + + RedNode redNode(int index) const { + return RedNode(index); + } + + int index(RedNode n) const { + return n._id; + } + + BlueNode blueNode(int index) const { + return BlueNode(index + _red_num); + } + + int index(BlueNode n) const { + return n._id - _red_num; + } + + void clear() { + _red_num = 0; _blue_num = 0; + _node_num = 0; _edge_num = 0; + } + + Edge edge(const Node& u, const Node& v) const { + if (u._id < _red_num) { + if (v._id < _red_num) { + return Edge(-1); + } else { + return Edge(u._id + _red_num * (v._id - _red_num)); + } + } else { + if (v._id < _red_num) { + return Edge(v._id + _red_num * (u._id - _red_num)); + } else { + return Edge(-1); + } + } + } + + Arc arc(const Node& u, const Node& v) const { + if (u._id < _red_num) { + if (v._id < _red_num) { + return Arc(-1); + } else { + return Arc(2 * (u._id + _red_num * (v._id - _red_num)) + 1); + } + } else { + if (v._id < _red_num) { + return Arc(2 * (v._id + _red_num * (u._id - _red_num))); + } else { + return Arc(-1); + } + } + } + + typedef True FindEdgeTag; + typedef True FindArcTag; + + Edge findEdge(Node u, Node v, Edge prev = INVALID) const { + return prev != INVALID ? INVALID : edge(u, v); + } + + Arc findArc(Node s, Node t, Arc prev = INVALID) const { + return prev != INVALID ? INVALID : arc(s, t); + } + + }; + + typedef BpGraphExtender ExtendedFullBpGraphBase; + + /// \ingroup graphs + /// + /// \brief An undirected full bipartite graph class. + /// + /// FullBpGraph is a simple and fast implmenetation of undirected + /// full bipartite graphs. It contains an edge between every + /// red-blue pairs of nodes, therefore the number of edges is + /// nr*nb. 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::BpGraph "BpGraph 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. + /// + /// \sa FullGraph + class FullBpGraph : public ExtendedFullBpGraphBase { + public: + + typedef ExtendedFullBpGraphBase Parent; + + /// \brief Default constructor. + /// + /// Default constructor. The number of nodes and edges will be zero. + FullBpGraph() { construct(0, 0); } + + /// \brief Constructor + /// + /// Constructor. + /// \param redNum The number of the red nodes. + /// \param blueNum The number of the blue nodes. + FullBpGraph(int redNum, int blueNum) { construct(redNum, blueNum); } + + /// \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 redNum, int blueNum) { + Parent::notifier(Arc()).clear(); + Parent::notifier(Edge()).clear(); + Parent::notifier(Node()).clear(); + Parent::notifier(BlueNode()).clear(); + Parent::notifier(RedNode()).clear(); + construct(redNum, blueNum); + Parent::notifier(RedNode()).build(); + Parent::notifier(BlueNode()).build(); + Parent::notifier(Node()).build(); + Parent::notifier(Edge()).build(); + Parent::notifier(Arc()).build(); + } + + using Parent::redNode; + using Parent::blueNode; + + /// \brief Returns the red node with the given index. + /// + /// Returns the red node with the given index. Since this + /// structure is completely static, the red nodes can be indexed + /// with integers from the range [0..redNum()-1]. + /// \sa redIndex() + RedNode redNode(int index) const { return Parent::redNode(index); } + + /// \brief Returns the index of the given red node. + /// + /// Returns the index of the given red node. Since this structure + /// is completely static, the red nodes can be indexed with + /// integers from the range [0..redNum()-1]. + /// + /// \sa operator()() + int index(RedNode node) const { return Parent::index(node); } + + /// \brief Returns the blue node with the given index. + /// + /// Returns the blue node with the given index. Since this + /// structure is completely static, the blue nodes can be indexed + /// with integers from the range [0..blueNum()-1]. + /// \sa blueIndex() + BlueNode blueNode(int index) const { return Parent::blueNode(index); } + + /// \brief Returns the index of the given blue node. + /// + /// Returns the index of the given blue node. Since this structure + /// is completely static, the blue nodes can be indexed with + /// integers from the range [0..blueNum()-1]. + /// + /// \sa operator()() + int index(BlueNode node) const { return Parent::index(node); } + + /// \brief Returns the edge which connects the given nodes. + /// + /// Returns the edge which connects the given nodes. + Edge edge(const Node& u, const Node& v) const { + return Parent::edge(u, v); + } + + /// \brief Returns the arc which connects the given nodes. + /// + /// Returns the arc which connects the given nodes. + Arc arc(const Node& u, const Node& v) const { + return Parent::arc(u, v); + } + + /// \brief Number of nodes. + int nodeNum() const { return Parent::nodeNum(); } + /// \brief Number of red nodes. + int redNum() const { return Parent::redNum(); } + /// \brief Number of blue nodes. + int blueNum() const { return Parent::blueNum(); } + /// \brief Number of arcs. + int arcNum() const { return Parent::arcNum(); } + /// \brief Number of edges. + int edgeNum() const { return Parent::edgeNum(); } + }; + } //namespace lemon diff -r cd72eae05bdf -r 3c00344f49c9 lemon/glpk.cc --- a/lemon/glpk.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/glpk.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -582,6 +582,15 @@ } } + void GlpkBase::_write(std::string file, std::string format) const + { + if(format == "MPS") + glp_write_mps(lp, GLP_MPS_FILE, 0, file.c_str()); + else if(format == "LP") + glp_write_lp(lp, 0, file.c_str()); + else throw UnsupportedFormatError(format); + } + GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper; // GlpkLp members @@ -998,4 +1007,6 @@ const char* GlpkMip::_solverName() const { return "GlpkMip"; } + + } //END OF NAMESPACE LEMON diff -r cd72eae05bdf -r 3c00344f49c9 lemon/glpk.h --- a/lemon/glpk.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/glpk.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -115,6 +115,8 @@ virtual void _messageLevel(MessageLevel level); + virtual void _write(std::string file, std::string format) const; + private: static void freeEnv(); @@ -144,6 +146,19 @@ ///Returns the variable identifier understood by GLPK. int lpxCol(Col c) const { return cols(id(c)); } +#ifdef DOXYGEN + /// Write the problem or the solution to a file in the given format + + /// This function writes the problem or the solution + /// to a file in the given format. + /// Trying to write in an unsupported format will trigger + /// \ref LpBase::UnsupportedFormatError. + /// \param file The file path + /// \param format The output file format. + /// Supportted formats are "MPS" and "LP". + void write(std::string file, std::string format = "MPS") const {} +#endif + }; /// \brief Interface for the GLPK LP solver diff -r cd72eae05bdf -r 3c00344f49c9 lemon/gomory_hu.h --- a/lemon/gomory_hu.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/gomory_hu.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -46,7 +46,7 @@ /// 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 + /// the \ref Preflow algorithm), thus it has \f$O(n^3\sqrt{m})\f$ overall /// time complexity. It calculates a rooted Gomory-Hu tree. /// The structure of the tree and the edge weights can be /// obtained using \c predNode(), \c predValue() and \c rootDist(). diff -r cd72eae05bdf -r 3c00344f49c9 lemon/graph_to_eps.h --- a/lemon/graph_to_eps.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/graph_to_eps.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -25,7 +25,7 @@ #include #include -#ifndef WIN32 +#ifndef LEMON_WIN32 #include #include #else @@ -222,7 +222,6 @@ using T::_title; using T::_copyright; - using typename T::NodeTextColorType; using T::CUST_COL; using T::DIST_COL; using T::DIST_BW; @@ -675,7 +674,7 @@ { os << "%%CreationDate: "; -#ifndef WIN32 +#ifndef LEMON_WIN32 timeval tv; gettimeofday(&tv, 0); diff -r cd72eae05bdf -r 3c00344f49c9 lemon/greedy_tsp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/greedy_tsp.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,251 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_GREEDY_TSP_H +#define LEMON_GREEDY_TSP_H + +/// \ingroup tsp +/// \file +/// \brief Greedy algorithm for symmetric TSP + +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief Greedy algorithm for symmetric TSP. + /// + /// GreedyTsp implements the greedy heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This algorithm is quite similar to the \ref NearestNeighborTsp + /// "nearest neighbor" heuristic, but it maintains a set of disjoint paths. + /// At each step, the shortest possible edge is added to these paths + /// as long as it does not create a cycle of less than n edges and it does + /// not increase the degree of any node above two. + /// + /// This method runs in O(n2) time. + /// It quickly finds a relatively short tour for most TSP instances, + /// but it could also yield a really bad (or even the worst) solution + /// in special cases. + /// + /// \tparam CM Type of the cost map. + template + class GreedyTsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + Cost _sum; + std::vector _path; + + private: + + // Functor class to compare edges by their costs + class EdgeComp { + private: + const CostMap &_cost; + + public: + EdgeComp(const CostMap &cost) : _cost(cost) {} + + bool operator()(const Edge &a, const Edge &b) const { + return _cost[a] < _cost[b]; + } + }; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + GreedyTsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. + /// + /// \return The total cost of the found tour. + Cost run() { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + + std::vector plist; + plist.resize(_gr.nodeNum()*2, -1); + + std::vector sorted_edges; + sorted_edges.reserve(_gr.edgeNum()); + for (EdgeIt e(_gr); e != INVALID; ++e) + sorted_edges.push_back(e); + std::sort(sorted_edges.begin(), sorted_edges.end(), EdgeComp(_cost)); + + FullGraph::NodeMap item_int_map(_gr); + UnionFind > union_find(item_int_map); + for (NodeIt n(_gr); n != INVALID; ++n) + union_find.insert(n); + + FullGraph::NodeMap degree(_gr, 0); + + int nodesNum = 0, i = 0; + while (nodesNum != _gr.nodeNum()-1) { + Edge e = sorted_edges[i++]; + Node u = _gr.u(e), + v = _gr.v(e); + + if (degree[u] <= 1 && degree[v] <= 1) { + if (union_find.join(u, v)) { + const int uid = _gr.id(u), + vid = _gr.id(v); + + plist[uid*2 + degree[u]] = vid; + plist[vid*2 + degree[v]] = uid; + + ++degree[u]; + ++degree[v]; + ++nodesNum; + } + } + } + + for (int i=0, n=-1; i<_gr.nodeNum()*2; ++i) { + if (plist[i] == -1) { + if (n==-1) { + n = i; + } else { + plist[n] = i/2; + plist[i] = n/2; + break; + } + } + } + + for (int i=0, next=0, last=-1; i!=_gr.nodeNum(); ++i) { + _path.push_back(_gr.nodeFromId(next)); + if (plist[2*next] != last) { + last = next; + next = plist[2*next]; + } else { + last = next; + next = plist[2*next+1]; + } + } + + _sum = _cost[_gr.edge(_path.back(), _path.front())]; + for (int i = 0; i < int(_path.size())-1; ++i) { + _sum += _cost[_gr.edge(_path[i], _path[i+1])]; + } + + return _sum; + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _path; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_path.begin(), _path.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_path.size()) - 1; ++i) { + path.addBack(_gr.arc(_path[i], _path[i+1])); + } + if (int(_path.size()) >= 2) { + path.addBack(_gr.arc(_path.back(), _path.front())); + } + } + + /// @} + + }; + +}; // namespace lemon + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/grosso_locatelli_pullan_mc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/grosso_locatelli_pullan_mc.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,840 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_GROSSO_LOCATELLI_PULLAN_MC_H +#define LEMON_GROSSO_LOCATELLI_PULLAN_MC_H + +/// \ingroup approx_algs +/// +/// \file +/// \brief The iterated local search algorithm of Grosso, Locatelli, and Pullan +/// for the maximum clique problem + +#include +#include +#include +#include + +namespace lemon { + + /// \addtogroup approx_algs + /// @{ + + /// \brief Implementation of the iterated local search algorithm of Grosso, + /// Locatelli, and Pullan for the maximum clique problem + /// + /// \ref GrossoLocatelliPullanMc implements the iterated local search + /// algorithm of Grosso, Locatelli, and Pullan for solving the \e maximum + /// \e clique \e problem \cite grosso08maxclique. + /// It is to find the largest complete subgraph (\e clique) in an + /// undirected graph, i.e., the largest set of nodes where each + /// pair of nodes is connected. + /// + /// This class provides a simple but highly efficient and robust heuristic + /// method that quickly finds a quite large clique, but not necessarily the + /// largest one. + /// The algorithm performs a certain number of iterations to find several + /// cliques and selects the largest one among them. Various limits can be + /// specified to control the running time and the effectiveness of the + /// search process. + /// + /// \tparam GR The undirected graph type the algorithm runs on. + /// + /// \note %GrossoLocatelliPullanMc provides three different node selection + /// rules, from which the most powerful one is used by default. + /// For more information, see \ref SelectionRule. + template + class GrossoLocatelliPullanMc + { + public: + + /// \brief Constants for specifying the node selection rule. + /// + /// Enum type containing constants for specifying the node selection rule + /// for the \ref run() function. + /// + /// During the algorithm, nodes are selected for addition to the current + /// clique according to the applied rule. + /// In general, the PENALTY_BASED rule turned out to be the most powerful + /// and the most robust, thus it is the default option. + /// However, another selection rule can be specified using the \ref run() + /// function with the proper parameter. + enum SelectionRule { + + /// A node is selected randomly without any evaluation at each step. + RANDOM, + + /// A node of maximum degree is selected randomly at each step. + DEGREE_BASED, + + /// A node of minimum penalty is selected randomly at each step. + /// The node penalties are updated adaptively after each stage of the + /// search process. + PENALTY_BASED + }; + + /// \brief Constants for the causes of search termination. + /// + /// Enum type containing constants for the different causes of search + /// termination. The \ref run() function returns one of these values. + enum TerminationCause { + + /// The iteration count limit is reached. + ITERATION_LIMIT, + + /// The step count limit is reached. + STEP_LIMIT, + + /// The clique size limit is reached. + SIZE_LIMIT + }; + + private: + + TEMPLATE_GRAPH_TYPEDEFS(GR); + + typedef std::vector IntVector; + typedef std::vector BoolVector; + typedef std::vector BoolMatrix; + // Note: vector is used instead of vector for efficiency reasons + + // The underlying graph + const GR &_graph; + IntNodeMap _id; + + // Internal matrix representation of the graph + BoolMatrix _gr; + int _n; + + // Search options + bool _delta_based_restart; + int _restart_delta_limit; + + // Search limits + int _iteration_limit; + int _step_limit; + int _size_limit; + + // The current clique + BoolVector _clique; + int _size; + + // The best clique found so far + BoolVector _best_clique; + int _best_size; + + // The "distances" of the nodes from the current clique. + // _delta[u] is the number of nodes in the clique that are + // not connected with u. + IntVector _delta; + + // The current tabu set + BoolVector _tabu; + + // Random number generator + Random _rnd; + + private: + + // Implementation of the RANDOM node selection rule. + class RandomSelectionRule + { + private: + + // References to the algorithm instance + const BoolVector &_clique; + const IntVector &_delta; + const BoolVector &_tabu; + Random &_rnd; + + // Pivot rule data + int _n; + + public: + + // Constructor + RandomSelectionRule(GrossoLocatelliPullanMc &mc) : + _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu), + _rnd(mc._rnd), _n(mc._n) + {} + + // Return a node index for a feasible add move or -1 if no one exists + int nextFeasibleAddNode() const { + int start_node = _rnd[_n]; + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && !_tabu[i]) return i; + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && !_tabu[i]) return i; + } + return -1; + } + + // Return a node index for a feasible swap move or -1 if no one exists + int nextFeasibleSwapNode() const { + int start_node = _rnd[_n]; + for (int i = start_node; i != _n; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i; + } + for (int i = 0; i != start_node; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i; + } + return -1; + } + + // Return a node index for an add move or -1 if no one exists + int nextAddNode() const { + int start_node = _rnd[_n]; + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0) return i; + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0) return i; + } + return -1; + } + + // Update internal data structures between stages (if necessary) + void update() {} + + }; //class RandomSelectionRule + + + // Implementation of the DEGREE_BASED node selection rule. + class DegreeBasedSelectionRule + { + private: + + // References to the algorithm instance + const BoolVector &_clique; + const IntVector &_delta; + const BoolVector &_tabu; + Random &_rnd; + + // Pivot rule data + int _n; + IntVector _deg; + + public: + + // Constructor + DegreeBasedSelectionRule(GrossoLocatelliPullanMc &mc) : + _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu), + _rnd(mc._rnd), _n(mc._n), _deg(_n) + { + for (int i = 0; i != _n; i++) { + int d = 0; + BoolVector &row = mc._gr[i]; + for (int j = 0; j != _n; j++) { + if (row[j]) d++; + } + _deg[i] = d; + } + } + + // Return a node index for a feasible add move or -1 if no one exists + int nextFeasibleAddNode() const { + int start_node = _rnd[_n]; + int node = -1, max_deg = -1; + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + return node; + } + + // Return a node index for a feasible swap move or -1 if no one exists + int nextFeasibleSwapNode() const { + int start_node = _rnd[_n]; + int node = -1, max_deg = -1; + for (int i = start_node; i != _n; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && + _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && + _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + return node; + } + + // Return a node index for an add move or -1 if no one exists + int nextAddNode() const { + int start_node = _rnd[_n]; + int node = -1, max_deg = -1; + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && _deg[i] > max_deg) { + node = i; + max_deg = _deg[i]; + } + } + return node; + } + + // Update internal data structures between stages (if necessary) + void update() {} + + }; //class DegreeBasedSelectionRule + + + // Implementation of the PENALTY_BASED node selection rule. + class PenaltyBasedSelectionRule + { + private: + + // References to the algorithm instance + const BoolVector &_clique; + const IntVector &_delta; + const BoolVector &_tabu; + Random &_rnd; + + // Pivot rule data + int _n; + IntVector _penalty; + + public: + + // Constructor + PenaltyBasedSelectionRule(GrossoLocatelliPullanMc &mc) : + _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu), + _rnd(mc._rnd), _n(mc._n), _penalty(_n, 0) + {} + + // Return a node index for a feasible add move or -1 if no one exists + int nextFeasibleAddNode() const { + int start_node = _rnd[_n]; + int node = -1, min_p = std::numeric_limits::max(); + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + return node; + } + + // Return a node index for a feasible swap move or -1 if no one exists + int nextFeasibleSwapNode() const { + int start_node = _rnd[_n]; + int node = -1, min_p = std::numeric_limits::max(); + for (int i = start_node; i != _n; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && + _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && + _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + return node; + } + + // Return a node index for an add move or -1 if no one exists + int nextAddNode() const { + int start_node = _rnd[_n]; + int node = -1, min_p = std::numeric_limits::max(); + for (int i = start_node; i != _n; i++) { + if (_delta[i] == 0 && _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + for (int i = 0; i != start_node; i++) { + if (_delta[i] == 0 && _penalty[i] < min_p) { + node = i; + min_p = _penalty[i]; + } + } + return node; + } + + // Update internal data structures between stages (if necessary) + void update() {} + + }; //class PenaltyBasedSelectionRule + + public: + + /// \brief Constructor. + /// + /// Constructor. + /// The global \ref rnd "random number generator instance" is used + /// during the algorithm. + /// + /// \param graph The undirected graph the algorithm runs on. + GrossoLocatelliPullanMc(const GR& graph) : + _graph(graph), _id(_graph), _rnd(rnd) + { + initOptions(); + } + + /// \brief Constructor with random seed. + /// + /// Constructor with random seed. + /// + /// \param graph The undirected graph the algorithm runs on. + /// \param seed Seed value for the internal random number generator + /// that is used during the algorithm. + GrossoLocatelliPullanMc(const GR& graph, int seed) : + _graph(graph), _id(_graph), _rnd(seed) + { + initOptions(); + } + + /// \brief Constructor with random number generator. + /// + /// Constructor with random number generator. + /// + /// \param graph The undirected graph the algorithm runs on. + /// \param random A random number generator that is used during the + /// algorithm. + GrossoLocatelliPullanMc(const GR& graph, const Random& random) : + _graph(graph), _id(_graph), _rnd(random) + { + initOptions(); + } + + /// \name Execution Control + /// The \ref run() function can be used to execute the algorithm.\n + /// The functions \ref iterationLimit(int), \ref stepLimit(int), and + /// \ref sizeLimit(int) can be used to specify various limits for the + /// search process. + + /// @{ + + /// \brief Sets the maximum number of iterations. + /// + /// This function sets the maximum number of iterations. + /// Each iteration of the algorithm finds a maximal clique (but not + /// necessarily the largest one) by performing several search steps + /// (node selections). + /// + /// This limit controls the running time and the success of the + /// algorithm. For larger values, the algorithm runs slower, but it more + /// likely finds larger cliques. For smaller values, the algorithm is + /// faster but probably gives worse results. + /// + /// The default value is \c 1000. + /// \c -1 means that number of iterations is not limited. + /// + /// \warning You should specify a reasonable limit for the number of + /// iterations and/or the number of search steps. + /// + /// \return (*this) + /// + /// \sa stepLimit(int) + /// \sa sizeLimit(int) + GrossoLocatelliPullanMc& iterationLimit(int limit) { + _iteration_limit = limit; + return *this; + } + + /// \brief Sets the maximum number of search steps. + /// + /// This function sets the maximum number of elementary search steps. + /// Each iteration of the algorithm finds a maximal clique (but not + /// necessarily the largest one) by performing several search steps + /// (node selections). + /// + /// This limit controls the running time and the success of the + /// algorithm. For larger values, the algorithm runs slower, but it more + /// likely finds larger cliques. For smaller values, the algorithm is + /// faster but probably gives worse results. + /// + /// The default value is \c -1, which means that number of steps + /// is not limited explicitly. However, the number of iterations is + /// limited and each iteration performs a finite number of search steps. + /// + /// \warning You should specify a reasonable limit for the number of + /// iterations and/or the number of search steps. + /// + /// \return (*this) + /// + /// \sa iterationLimit(int) + /// \sa sizeLimit(int) + GrossoLocatelliPullanMc& stepLimit(int limit) { + _step_limit = limit; + return *this; + } + + /// \brief Sets the desired clique size. + /// + /// This function sets the desired clique size that serves as a search + /// limit. If a clique of this size (or a larger one) is found, then the + /// algorithm terminates. + /// + /// This function is especially useful if you know an exact upper bound + /// for the size of the cliques in the graph or if any clique above + /// a certain size limit is sufficient for your application. + /// + /// The default value is \c -1, which means that the size limit is set to + /// the number of nodes in the graph. + /// + /// \return (*this) + /// + /// \sa iterationLimit(int) + /// \sa stepLimit(int) + GrossoLocatelliPullanMc& sizeLimit(int limit) { + _size_limit = limit; + return *this; + } + + /// \brief The maximum number of iterations. + /// + /// This function gives back the maximum number of iterations. + /// \c -1 means that no limit is specified. + /// + /// \sa iterationLimit(int) + int iterationLimit() const { + return _iteration_limit; + } + + /// \brief The maximum number of search steps. + /// + /// This function gives back the maximum number of search steps. + /// \c -1 means that no limit is specified. + /// + /// \sa stepLimit(int) + int stepLimit() const { + return _step_limit; + } + + /// \brief The desired clique size. + /// + /// This function gives back the desired clique size that serves as a + /// search limit. \c -1 means that this limit is set to the number of + /// nodes in the graph. + /// + /// \sa sizeLimit(int) + int sizeLimit() const { + return _size_limit; + } + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. If one of the specified limits + /// is reached, the search process terminates. + /// + /// \param rule The node selection rule. For more information, see + /// \ref SelectionRule. + /// + /// \return The termination cause of the search. For more information, + /// see \ref TerminationCause. + TerminationCause run(SelectionRule rule = PENALTY_BASED) + { + init(); + switch (rule) { + case RANDOM: + return start(); + case DEGREE_BASED: + return start(); + default: + return start(); + } + } + + /// @} + + /// \name Query Functions + /// The results of the algorithm can be obtained using these functions.\n + /// The run() function must be called before using them. + + /// @{ + + /// \brief The size of the found clique + /// + /// This function returns the size of the found clique. + /// + /// \pre run() must be called before using this function. + int cliqueSize() const { + return _best_size; + } + + /// \brief Gives back the found clique in a \c bool node map + /// + /// This function gives back the characteristic vector of the found + /// clique in the given node map. + /// It must be a \ref concepts::WriteMap "writable" node map with + /// \c bool (or convertible) value type. + /// + /// \pre run() must be called before using this function. + template + void cliqueMap(CliqueMap &map) const { + for (NodeIt n(_graph); n != INVALID; ++n) { + map[n] = static_cast(_best_clique[_id[n]]); + } + } + + /// \brief Iterator to list the nodes of the found clique + /// + /// This iterator class lists the nodes of the found clique. + /// Before using it, you must allocate a GrossoLocatelliPullanMc instance + /// and call its \ref GrossoLocatelliPullanMc::run() "run()" method. + /// + /// The following example prints out the IDs of the nodes in the found + /// clique. + /// \code + /// GrossoLocatelliPullanMc mc(g); + /// mc.run(); + /// for (GrossoLocatelliPullanMc::CliqueNodeIt n(mc); + /// n != INVALID; ++n) + /// { + /// std::cout << g.id(n) << std::endl; + /// } + /// \endcode + class CliqueNodeIt + { + private: + NodeIt _it; + BoolNodeMap _map; + + public: + + /// Constructor + + /// Constructor. + /// \param mc The algorithm instance. + CliqueNodeIt(const GrossoLocatelliPullanMc &mc) + : _map(mc._graph) + { + mc.cliqueMap(_map); + for (_it = NodeIt(mc._graph); _it != INVALID && !_map[_it]; ++_it) ; + } + + /// Conversion to \c Node + operator Node() const { return _it; } + + bool operator==(Invalid) const { return _it == INVALID; } + bool operator!=(Invalid) const { return _it != INVALID; } + + /// Next node + CliqueNodeIt &operator++() { + for (++_it; _it != INVALID && !_map[_it]; ++_it) ; + return *this; + } + + /// Postfix incrementation + + /// Postfix incrementation. + /// + /// \warning This incrementation returns a \c Node, not a + /// \c CliqueNodeIt as one may expect. + typename GR::Node operator++(int) { + Node n=*this; + ++(*this); + return n; + } + + }; + + /// @} + + private: + + // Initialize search options and limits + void initOptions() { + // Search options + _delta_based_restart = true; + _restart_delta_limit = 4; + + // Search limits + _iteration_limit = 1000; + _step_limit = -1; // this is disabled by default + _size_limit = -1; // this is disabled by default + } + + // Adds a node to the current clique + void addCliqueNode(int u) { + if (_clique[u]) return; + _clique[u] = true; + _size++; + BoolVector &row = _gr[u]; + for (int i = 0; i != _n; i++) { + if (!row[i]) _delta[i]++; + } + } + + // Removes a node from the current clique + void delCliqueNode(int u) { + if (!_clique[u]) return; + _clique[u] = false; + _size--; + BoolVector &row = _gr[u]; + for (int i = 0; i != _n; i++) { + if (!row[i]) _delta[i]--; + } + } + + // Initialize data structures + void init() { + _n = countNodes(_graph); + int ui = 0; + for (NodeIt u(_graph); u != INVALID; ++u) { + _id[u] = ui++; + } + _gr.clear(); + _gr.resize(_n, BoolVector(_n, false)); + ui = 0; + for (NodeIt u(_graph); u != INVALID; ++u) { + for (IncEdgeIt e(_graph, u); e != INVALID; ++e) { + int vi = _id[_graph.runningNode(e)]; + _gr[ui][vi] = true; + _gr[vi][ui] = true; + } + ++ui; + } + + _clique.clear(); + _clique.resize(_n, false); + _size = 0; + _best_clique.clear(); + _best_clique.resize(_n, false); + _best_size = 0; + _delta.clear(); + _delta.resize(_n, 0); + _tabu.clear(); + _tabu.resize(_n, false); + } + + // Executes the algorithm + template + TerminationCause start() { + if (_n == 0) return SIZE_LIMIT; + if (_n == 1) { + _best_clique[0] = true; + _best_size = 1; + return SIZE_LIMIT; + } + + // Iterated local search algorithm + const int max_size = _size_limit >= 0 ? _size_limit : _n; + const int max_restart = _iteration_limit >= 0 ? + _iteration_limit : std::numeric_limits::max(); + const int max_select = _step_limit >= 0 ? + _step_limit : std::numeric_limits::max(); + + SelectionRuleImpl sel_method(*this); + int select = 0, restart = 0; + IntVector restart_nodes; + while (select < max_select && restart < max_restart) { + + // Perturbation/restart + restart++; + if (_delta_based_restart) { + restart_nodes.clear(); + for (int i = 0; i != _n; i++) { + if (_delta[i] >= _restart_delta_limit) + restart_nodes.push_back(i); + } + } + int rs_node = -1; + if (restart_nodes.size() > 0) { + rs_node = restart_nodes[_rnd[restart_nodes.size()]]; + } else { + rs_node = _rnd[_n]; + } + BoolVector &row = _gr[rs_node]; + for (int i = 0; i != _n; i++) { + if (_clique[i] && !row[i]) delCliqueNode(i); + } + addCliqueNode(rs_node); + + // Local search + _tabu.clear(); + _tabu.resize(_n, false); + bool tabu_empty = true; + int max_swap = _size; + while (select < max_select) { + select++; + int u; + if ((u = sel_method.nextFeasibleAddNode()) != -1) { + // Feasible add move + addCliqueNode(u); + if (tabu_empty) max_swap = _size; + } + else if ((u = sel_method.nextFeasibleSwapNode()) != -1) { + // Feasible swap move + int v = -1; + BoolVector &row = _gr[u]; + for (int i = 0; i != _n; i++) { + if (_clique[i] && !row[i]) { + v = i; + break; + } + } + addCliqueNode(u); + delCliqueNode(v); + _tabu[v] = true; + tabu_empty = false; + if (--max_swap <= 0) break; + } + else if ((u = sel_method.nextAddNode()) != -1) { + // Non-feasible add move + addCliqueNode(u); + } + else break; + } + if (_size > _best_size) { + _best_clique = _clique; + _best_size = _size; + if (_best_size >= max_size) return SIZE_LIMIT; + } + sel_method.update(); + } + + return (restart >= max_restart ? ITERATION_LIMIT : STEP_LIMIT); + } + + }; //class GrossoLocatelliPullanMc + + ///@} + +} //namespace lemon + +#endif //LEMON_GROSSO_LOCATELLI_PULLAN_MC_H diff -r cd72eae05bdf -r 3c00344f49c9 lemon/hao_orlin.h --- a/lemon/hao_orlin.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/hao_orlin.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -53,8 +53,8 @@ /// minimum cut of \f$ D \f$. The algorithm is a modified /// preflow push-relabel algorithm. Our implementation calculates /// the minimum cut in \f$ O(n^2\sqrt{m}) \f$ time (we use the - /// highest-label rule), or in \f$O(nm)\f$ for unit capacities. The - /// purpose of such algorithm is e.g. testing network reliability. + /// highest-label rule), or in \f$O(nm)\f$ for unit capacities. A notable + /// use of this algorithm is testing network reliability. /// /// For an undirected graph you can run just the first phase of the /// algorithm or you can use the algorithm of Nagamochi and Ibaraki, @@ -912,6 +912,8 @@ /// This function calculates a minimum cut with \f$ source \f$ on the /// source-side (i.e. a set \f$ X\subsetneq V \f$ with /// \f$ source \in X \f$ and minimal outgoing capacity). + /// It updates the stored cut if (and only if) the newly found one + /// is better. /// /// \pre \ref init() must be called before using this function. void calculateOut() { @@ -924,6 +926,8 @@ /// This function calculates a minimum cut with \f$ source \f$ on the /// sink-side (i.e. a set \f$ X\subsetneq V \f$ with /// \f$ source \notin X \f$ and minimal outgoing capacity). + /// It updates the stored cut if (and only if) the newly found one + /// is better. /// /// \pre \ref init() must be called before using this function. void calculateIn() { @@ -933,8 +937,8 @@ /// \brief Run the algorithm. /// - /// This function runs the algorithm. It finds nodes \c source and - /// \c target arbitrarily and then calls \ref init(), \ref calculateOut() + /// This function runs the algorithm. It chooses source node, + /// then calls \ref init(), \ref calculateOut() /// and \ref calculateIn(). void run() { init(); @@ -944,9 +948,9 @@ /// \brief Run the algorithm. /// - /// 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(). + /// This function runs the algorithm. It calls \ref init(), + /// \ref calculateOut() and \ref calculateIn() with the given + /// source node. void run(const Node& s) { init(s); calculateOut(); @@ -965,7 +969,9 @@ /// \brief Return the value of the minimum cut. /// - /// This function returns the value of the minimum cut. + /// This function returns the value of the best cut found by the + /// previously called \ref run(), \ref calculateOut() or \ref + /// calculateIn(). /// /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() /// must be called before using this function. @@ -976,9 +982,13 @@ /// \brief Return a minimum cut. /// - /// This function sets \c cutMap to the characteristic vector of a - /// minimum value cut: it will give a non-empty set \f$ X\subsetneq V \f$ - /// with minimal outgoing capacity (i.e. \c cutMap will be \c true exactly + /// This function gives the best cut found by the + /// previously called \ref run(), \ref calculateOut() or \ref + /// calculateIn(). + /// + /// It sets \c cutMap to the characteristic vector of the found + /// minimum value cut - a non-empty set \f$ X\subsetneq V \f$ + /// of minimum outgoing capacity (i.e. \c cutMap will be \c true exactly /// for the nodes of \f$ X \f$). /// /// \param cutMap A \ref concepts::WriteMap "writable" node map with diff -r cd72eae05bdf -r 3c00344f49c9 lemon/hartmann_orlin_mmc.h --- a/lemon/hartmann_orlin_mmc.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/hartmann_orlin_mmc.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -98,10 +98,11 @@ /// /// 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 KarpMmc "Karp"'s original algorithm, - /// it applies an efficient early termination scheme. - /// It runs in time O(ne) and uses space O(n2+e). + /// \cite hartmann93finding, \cite dasdan98minmeancycle. + /// This method is based on \ref KarpMmc "Karp"'s original algorithm, but + /// applies an early termination scheme. It makes the algorithm + /// significantly faster for some problem instances, but slower for others. + /// The algorithm runs in time O(nm) and uses space O(n2+m). /// /// \tparam GR The type of the digraph the algorithm runs on. /// \tparam CM The type of the cost map. The default @@ -142,11 +143,14 @@ /// \brief The path type of the found cycles /// /// The path type of the found cycles. - /// Using the \ref HartmannOrlinMmcDefaultTraits "default traits class", + /// Using the \ref lemon::HartmannOrlinMmcDefaultTraits + /// "default traits class", /// it is \ref lemon::Path "Path". typedef typename TR::Path Path; - /// The \ref HartmannOrlinMmcDefaultTraits "traits class" of the algorithm + /// \brief The + /// \ref lemon::HartmannOrlinMmcDefaultTraits "traits class" + /// of the algorithm typedef TR Traits; private: @@ -274,8 +278,8 @@ /// 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 + /// \ref findCycleMean(), a local \ref Path "path" structure + /// will be allocated. The destuctor deallocates this automatically /// allocated object, of course. /// /// \note The algorithm calls only the \ref lemon::Path::addFront() diff -r cd72eae05bdf -r 3c00344f49c9 lemon/howard_mmc.h --- a/lemon/howard_mmc.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/howard_mmc.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -98,7 +98,7 @@ /// /// This class implements Howard's policy iteration algorithm for finding /// a directed cycle of minimum mean cost in a digraph - /// \ref amo93networkflows, \ref dasdan98minmeancycle. + /// \cite dasdan98minmeancycle, \cite dasdan04experimental. /// 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. @@ -142,13 +142,30 @@ /// \brief The path type of the found cycles /// /// The path type of the found cycles. - /// Using the \ref HowardMmcDefaultTraits "default traits class", + /// Using the \ref lemon::HowardMmcDefaultTraits "default traits class", /// it is \ref lemon::Path "Path". typedef typename TR::Path Path; - /// The \ref HowardMmcDefaultTraits "traits class" of the algorithm + /// The \ref lemon::HowardMmcDefaultTraits "traits class" of the algorithm typedef TR Traits; + /// \brief Constants for the causes of search termination. + /// + /// Enum type containing constants for the different causes of search + /// termination. The \ref findCycleMean() function returns one of + /// these values. + enum TerminationCause { + + /// No directed cycle can be found in the digraph. + NO_CYCLE = 0, + + /// Optimal solution (minimum cycle mean) is found. + OPTIMAL = 1, + + /// The iteration count limit is reached. + ITERATION_LIMIT + }; + private: TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); @@ -265,8 +282,8 @@ /// 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 + /// \ref findCycleMean(), a local \ref Path "path" structure + /// will be allocated. The destuctor deallocates this automatically /// allocated object, of course. /// /// \note The algorithm calls only the \ref lemon::Path::addBack() @@ -324,25 +341,47 @@ return findCycleMean() && findCycle(); } - /// \brief Find the minimum cycle mean. + /// \brief Find the minimum cycle mean (or an upper bound). /// /// This function finds the minimum mean cost of the directed - /// cycles in the digraph. + /// cycles in the digraph (or an upper bound for it). /// - /// \return \c true if a directed cycle exists in the digraph. - bool findCycleMean() { + /// By default, the function finds the exact minimum cycle mean, + /// but an optional limit can also be specified for the number of + /// iterations performed during the search process. + /// The return value indicates if the optimal solution is found + /// or the iteration limit is reached. In the latter case, an + /// approximate solution is provided, which corresponds to a directed + /// cycle whose mean cost is relatively small, but not necessarily + /// minimal. + /// + /// \param limit The maximum allowed number of iterations during + /// the search process. Its default value implies that the algorithm + /// runs until it finds the exact optimal solution. + /// + /// \return The termination cause of the search process. + /// For more information, see \ref TerminationCause. + TerminationCause findCycleMean(int limit = + std::numeric_limits::max()) { // Initialize and find strongly connected components init(); findComponents(); // Find the minimum cycle mean in the components + int iter_count = 0; + bool iter_limit_reached = false; for (int comp = 0; comp < _comp_num; ++comp) { // Find the minimum mean cycle in the current component if (!buildPolicyGraph(comp)) continue; while (true) { + if (++iter_count > limit) { + iter_limit_reached = true; + break; + } 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) ) { @@ -351,8 +390,15 @@ _best_size = _curr_size; _best_node = _curr_node; } + + if (iter_limit_reached) break; } - return _best_found; + + if (iter_limit_reached) { + return ITERATION_LIMIT; + } else { + return _best_found ? OPTIMAL : NO_CYCLE; + } } /// \brief Find a minimum mean directed cycle. diff -r cd72eae05bdf -r 3c00344f49c9 lemon/insertion_tsp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/insertion_tsp.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,533 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_INSERTION_TSP_H +#define LEMON_INSERTION_TSP_H + +/// \ingroup tsp +/// \file +/// \brief Insertion algorithm for symmetric TSP + +#include +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief Insertion algorithm for symmetric TSP. + /// + /// InsertionTsp implements the insertion heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This is a fast and effective tour construction method that has + /// many variants. + /// It starts with a subtour containing a few nodes of the graph and it + /// iteratively inserts the other nodes into this subtour according to a + /// certain node selection rule. + /// + /// This method is among the fastest TSP algorithms, and it typically + /// provides quite good solutions (usually much better than + /// \ref NearestNeighborTsp and \ref GreedyTsp). + /// + /// InsertionTsp implements four different node selection rules, + /// from which the most effective one (\e farthest \e node \e selection) + /// is used by default. + /// With this choice, the algorithm runs in O(n2) time. + /// For more information, see \ref SelectionRule. + /// + /// \tparam CM Type of the cost map. + template + class InsertionTsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + std::vector _notused; + std::vector _tour; + Cost _sum; + + public: + + /// \brief Constants for specifying the node selection rule. + /// + /// Enum type containing constants for specifying the node selection + /// rule for the \ref run() function. + /// + /// During the algorithm, nodes are selected for addition to the current + /// subtour according to the applied rule. + /// The FARTHEST method is one of the fastest selection rules, and + /// it is typically the most effective, thus it is the default + /// option. The RANDOM rule usually gives slightly worse results, + /// but it is more robust. + /// + /// The desired selection rule can be specified as a parameter of the + /// \ref run() function. + enum SelectionRule { + + /// An unvisited node having minimum distance from the current + /// subtour is selected at each step. + /// The algorithm runs in O(n2) time using this + /// selection rule. + NEAREST, + + /// An unvisited node having maximum distance from the current + /// subtour is selected at each step. + /// The algorithm runs in O(n2) time using this + /// selection rule. + FARTHEST, + + /// An unvisited node whose insertion results in the least + /// increase of the subtour's total cost is selected at each step. + /// The algorithm runs in O(n3) time using this + /// selection rule, but in most cases, it is almost as fast as + /// with other rules. + CHEAPEST, + + /// An unvisited node is selected randomly without any evaluation + /// at each step. + /// The global \ref rnd "random number generator instance" is used. + /// You can seed it before executing the algorithm, if you + /// would like to. + /// The algorithm runs in O(n2) time using this + /// selection rule. + RANDOM + }; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + InsertionTsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. + /// + /// \param rule The node selection rule. For more information, see + /// \ref SelectionRule. + /// + /// \return The total cost of the found tour. + Cost run(SelectionRule rule = FARTHEST) { + _tour.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _tour.push_back(_gr(0)); + return _sum = 0; + } + + switch (rule) { + case NEAREST: + init(true); + start >, + DefaultInsertion>(); + break; + case FARTHEST: + init(false); + start >, + DefaultInsertion>(); + break; + case CHEAPEST: + init(true); + start(); + break; + case RANDOM: + init(true); + start(); + break; + } + return _sum; + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _tour; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_tour.begin(), _tour.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_tour.size()) - 1; ++i) { + path.addBack(_gr.arc(_tour[i], _tour[i+1])); + } + if (int(_tour.size()) >= 2) { + path.addBack(_gr.arc(_tour.back(), _tour.front())); + } + } + + /// @} + + private: + + // Initializes the algorithm + void init(bool min) { + Edge min_edge = min ? mapMin(_gr, _cost) : mapMax(_gr, _cost); + + _tour.clear(); + _tour.push_back(_gr.u(min_edge)); + _tour.push_back(_gr.v(min_edge)); + + _notused.clear(); + for (NodeIt n(_gr); n!=INVALID; ++n) { + if (n != _gr.u(min_edge) && n != _gr.v(min_edge)) { + _notused.push_back(n); + } + } + + _sum = _cost[min_edge] * 2; + } + + // Executes the algorithm + template + void start() { + SelectionFunctor selectNode(_gr, _cost, _tour, _notused); + InsertionFunctor insertNode(_gr, _cost, _tour, _sum); + + for (int i=0; i<_gr.nodeNum()-2; ++i) { + insertNode.insert(selectNode.select()); + } + + _sum = _cost[_gr.edge(_tour.back(), _tour.front())]; + for (int i = 0; i < int(_tour.size())-1; ++i) { + _sum += _cost[_gr.edge(_tour[i], _tour[i+1])]; + } + } + + + // Implementation of the nearest and farthest selection rule + template + class ComparingSelection { + public: + ComparingSelection(const FullGraph &gr, const CostMap &cost, + std::vector &tour, std::vector ¬used) + : _gr(gr), _cost(cost), _tour(tour), _notused(notused), + _dist(gr, 0), _compare() + { + // Compute initial distances for the unused nodes + for (unsigned int i=0; i<_notused.size(); ++i) { + Node u = _notused[i]; + Cost min_dist = _cost[_gr.edge(u, _tour[0])]; + for (unsigned int j=1; j<_tour.size(); ++j) { + Cost curr = _cost[_gr.edge(u, _tour[j])]; + if (curr < min_dist) { + min_dist = curr; + } + } + _dist[u] = min_dist; + } + } + + Node select() { + + // Select an used node with minimum distance + Cost ins_dist = 0; + int ins_node = -1; + for (unsigned int i=0; i<_notused.size(); ++i) { + Cost curr = _dist[_notused[i]]; + if (_compare(curr, ins_dist) || ins_node == -1) { + ins_dist = curr; + ins_node = i; + } + } + + // Remove the selected node from the unused vector + Node sn = _notused[ins_node]; + _notused[ins_node] = _notused.back(); + _notused.pop_back(); + + // Update the distances of the remaining nodes + for (unsigned int i=0; i<_notused.size(); ++i) { + Node u = _notused[i]; + Cost nc = _cost[_gr.edge(sn, u)]; + if (nc < _dist[u]) { + _dist[u] = nc; + } + } + + return sn; + } + + private: + const FullGraph &_gr; + const CostMap &_cost; + std::vector &_tour; + std::vector &_notused; + FullGraph::NodeMap _dist; + Comparator _compare; + }; + + // Implementation of the cheapest selection rule + class CheapestSelection { + private: + Cost costDiff(Node u, Node v, Node w) const { + return + _cost[_gr.edge(u, w)] + + _cost[_gr.edge(v, w)] - + _cost[_gr.edge(u, v)]; + } + + public: + CheapestSelection(const FullGraph &gr, const CostMap &cost, + std::vector &tour, std::vector ¬used) + : _gr(gr), _cost(cost), _tour(tour), _notused(notused), + _ins_cost(gr, 0), _ins_pos(gr, -1) + { + // Compute insertion cost and position for the unused nodes + for (unsigned int i=0; i<_notused.size(); ++i) { + Node u = _notused[i]; + Cost min_cost = costDiff(_tour.back(), _tour.front(), u); + int min_pos = 0; + for (unsigned int j=1; j<_tour.size(); ++j) { + Cost curr_cost = costDiff(_tour[j-1], _tour[j], u); + if (curr_cost < min_cost) { + min_cost = curr_cost; + min_pos = j; + } + } + _ins_cost[u] = min_cost; + _ins_pos[u] = min_pos; + } + } + + Cost select() { + + // Select an used node with minimum insertion cost + Cost min_cost = 0; + int min_node = -1; + for (unsigned int i=0; i<_notused.size(); ++i) { + Cost curr_cost = _ins_cost[_notused[i]]; + if (curr_cost < min_cost || min_node == -1) { + min_cost = curr_cost; + min_node = i; + } + } + + // Remove the selected node from the unused vector + Node sn = _notused[min_node]; + _notused[min_node] = _notused.back(); + _notused.pop_back(); + + // Insert the selected node into the tour + const int ipos = _ins_pos[sn]; + _tour.insert(_tour.begin() + ipos, sn); + + // Update the insertion cost and position of the remaining nodes + for (unsigned int i=0; i<_notused.size(); ++i) { + Node u = _notused[i]; + Cost curr_cost = _ins_cost[u]; + int curr_pos = _ins_pos[u]; + + int ipos_prev = ipos == 0 ? _tour.size()-1 : ipos-1; + int ipos_next = ipos == int(_tour.size())-1 ? 0 : ipos+1; + Cost nc1 = costDiff(_tour[ipos_prev], _tour[ipos], u); + Cost nc2 = costDiff(_tour[ipos], _tour[ipos_next], u); + + if (nc1 <= curr_cost || nc2 <= curr_cost) { + // A new position is better than the old one + if (nc1 <= nc2) { + curr_cost = nc1; + curr_pos = ipos; + } else { + curr_cost = nc2; + curr_pos = ipos_next; + } + } + else { + if (curr_pos == ipos) { + // The minimum should be found again + curr_cost = costDiff(_tour.back(), _tour.front(), u); + curr_pos = 0; + for (unsigned int j=1; j<_tour.size(); ++j) { + Cost tmp_cost = costDiff(_tour[j-1], _tour[j], u); + if (tmp_cost < curr_cost) { + curr_cost = tmp_cost; + curr_pos = j; + } + } + } + else if (curr_pos > ipos) { + ++curr_pos; + } + } + + _ins_cost[u] = curr_cost; + _ins_pos[u] = curr_pos; + } + + return min_cost; + } + + private: + const FullGraph &_gr; + const CostMap &_cost; + std::vector &_tour; + std::vector &_notused; + FullGraph::NodeMap _ins_cost; + FullGraph::NodeMap _ins_pos; + }; + + // Implementation of the random selection rule + class RandomSelection { + public: + RandomSelection(const FullGraph &, const CostMap &, + std::vector &, std::vector ¬used) + : _notused(notused) {} + + Node select() const { + const int index = rnd[_notused.size()]; + Node n = _notused[index]; + _notused[index] = _notused.back(); + _notused.pop_back(); + return n; + } + + private: + std::vector &_notused; + }; + + + // Implementation of the default insertion method + class DefaultInsertion { + private: + Cost costDiff(Node u, Node v, Node w) const { + return + _cost[_gr.edge(u, w)] + + _cost[_gr.edge(v, w)] - + _cost[_gr.edge(u, v)]; + } + + public: + DefaultInsertion(const FullGraph &gr, const CostMap &cost, + std::vector &tour, Cost &total_cost) : + _gr(gr), _cost(cost), _tour(tour), _total(total_cost) {} + + void insert(Node n) const { + int min = 0; + Cost min_val = + costDiff(_tour.front(), _tour.back(), n); + + for (unsigned int i=1; i<_tour.size(); ++i) { + Cost tmp = costDiff(_tour[i-1], _tour[i], n); + if (tmp < min_val) { + min = i; + min_val = tmp; + } + } + + _tour.insert(_tour.begin()+min, n); + _total += min_val; + } + + private: + const FullGraph &_gr; + const CostMap &_cost; + std::vector &_tour; + Cost &_total; + }; + + // Implementation of a special insertion method for the cheapest + // selection rule + class CheapestInsertion { + TEMPLATE_GRAPH_TYPEDEFS(FullGraph); + public: + CheapestInsertion(const FullGraph &, const CostMap &, + std::vector &, Cost &total_cost) : + _total(total_cost) {} + + void insert(Cost diff) const { + _total += diff; + } + + private: + Cost &_total; + }; + + }; + +}; // namespace lemon + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/karp_mmc.h --- a/lemon/karp_mmc.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/karp_mmc.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -98,8 +98,8 @@ /// /// 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). + /// \cite karp78characterization, \cite dasdan98minmeancycle. + /// It runs in time O(nm) and uses space O(n2+m). /// /// \tparam GR The type of the digraph the algorithm runs on. /// \tparam CM The type of the cost map. The default @@ -140,11 +140,11 @@ /// \brief The path type of the found cycles /// /// The path type of the found cycles. - /// Using the \ref KarpMmcDefaultTraits "default traits class", + /// Using the \ref lemon::KarpMmcDefaultTraits "default traits class", /// it is \ref lemon::Path "Path". typedef typename TR::Path Path; - /// The \ref KarpMmcDefaultTraits "traits class" of the algorithm + /// The \ref lemon::KarpMmcDefaultTraits "traits class" of the algorithm typedef TR Traits; private: @@ -270,8 +270,8 @@ /// 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 + /// \ref findCycleMean(), a local \ref Path "path" structure + /// will be allocated. The destuctor deallocates this automatically /// allocated object, of course. /// /// \note The algorithm calls only the \ref lemon::Path::addFront() diff -r cd72eae05bdf -r 3c00344f49c9 lemon/kruskal.h --- a/lemon/kruskal.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/kruskal.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -30,9 +30,6 @@ ///\ingroup spantree ///\file ///\brief Kruskal's algorithm to compute a minimum cost spanning tree -/// -///Kruskal's algorithm to compute a minimum cost spanning tree. -/// namespace lemon { diff -r cd72eae05bdf -r 3c00344f49c9 lemon/lemon.pc.cmake --- a/lemon/lemon.pc.cmake Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=@CMAKE_INSTALL_PREFIX@/bin -libdir=@CMAKE_INSTALL_PREFIX@/lib -includedir=@CMAKE_INSTALL_PREFIX@/include - -Name: @PROJECT_NAME@ -Description: Library for Efficient Modeling and Optimization in Networks -Version: @PROJECT_VERSION@ -Libs: -L${libdir} -lemon @GLPK_LIBS@ @CPLEX_LIBS@ @SOPLEX_LIBS@ @CLP_LIBS@ @CBC_LIBS@ -Cflags: -I${includedir} diff -r cd72eae05bdf -r 3c00344f49c9 lemon/lemon.pc.in --- a/lemon/lemon.pc.in Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/lemon.pc.in Wed Oct 17 19:14:07 2018 +0200 @@ -1,10 +1,10 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@/bin +libdir=@CMAKE_INSTALL_PREFIX@/lib +includedir=@CMAKE_INSTALL_PREFIX@/include -Name: @PACKAGE_NAME@ +Name: @PROJECT_NAME@ Description: Library for Efficient Modeling and Optimization in Networks -Version: @PACKAGE_VERSION@ +Version: @PROJECT_VERSION@ Libs: -L${libdir} -lemon @GLPK_LIBS@ @CPLEX_LIBS@ @SOPLEX_LIBS@ @CLP_LIBS@ @CBC_LIBS@ Cflags: -I${includedir} diff -r cd72eae05bdf -r 3c00344f49c9 lemon/lgf_reader.h --- a/lemon/lgf_reader.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/lgf_reader.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2011 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -154,16 +154,16 @@ } }; - template + template > struct MapLookUpConverter { - const std::map& _map; - - MapLookUpConverter(const std::map& map) + const Map& _map; + + MapLookUpConverter(const Map& map) : _map(map) {} Value operator()(const std::string& str) { - typename std::map::const_iterator it = - _map.find(str); + typename Map::const_iterator it = _map.find(str); if (it == _map.end()) { std::ostringstream msg; msg << "Item not found: " << str; @@ -173,6 +173,39 @@ } }; + template , + typename Map2 = std::map > + struct DoubleMapLookUpConverter { + const Map1& _map1; + const Map2& _map2; + + DoubleMapLookUpConverter(const Map1& map1, const Map2& map2) + : _map1(map1), _map2(map2) {} + + Value operator()(const std::string& str) { + typename Map1::const_iterator it1 = _map1.find(str); + typename Map2::const_iterator it2 = _map2.find(str); + if (it1 == _map1.end()) { + if (it2 == _map2.end()) { + std::ostringstream msg; + msg << "Item not found: " << str; + throw FormatError(msg.str()); + } else { + return it2->second; + } + } else { + if (it2 == _map2.end()) { + return it1->second; + } else { + std::ostringstream msg; + msg << "Item is ambigous: " << str; + throw FormatError(msg.str()); + } + } + } + }; + template struct GraphArcLookUpConverter { const GR& _graph; @@ -1197,9 +1230,10 @@ /// \ingroup lemon_io /// - /// \brief Return a \ref DigraphReader class + /// \brief Return a \ref lemon::DigraphReader "DigraphReader" class /// - /// This function just returns a \ref DigraphReader class. + /// This function just returns a \ref lemon::DigraphReader + /// "DigraphReader" class. /// /// With this function a digraph can be read from an /// \ref lgf-format "LGF" file or input stream with several maps and @@ -1219,9 +1253,10 @@ /// run(); ///\endcode /// - /// For a complete documentation, please see the \ref DigraphReader + /// For a complete documentation, please see the + /// \ref lemon::DigraphReader "DigraphReader" /// class documentation. - /// \warning Don't forget to put the \ref DigraphReader::run() "run()" + /// \warning Don't forget to put the \ref lemon::DigraphReader::run() "run()" /// to the end of the parameter list. /// \relates DigraphReader /// \sa digraphReader(TDGR& digraph, const std::string& fn) @@ -2075,9 +2110,9 @@ /// \ingroup lemon_io /// - /// \brief Return a \ref GraphReader class + /// \brief Return a \ref lemon::GraphReader "GraphReader" class /// - /// This function just returns a \ref GraphReader class. + /// This function just returns a \ref lemon::GraphReader "GraphReader" class. /// /// With this function a graph can be read from an /// \ref lgf-format "LGF" file or input stream with several maps and @@ -2093,9 +2128,10 @@ /// run(); ///\endcode /// - /// For a complete documentation, please see the \ref GraphReader + /// For a complete documentation, please see the + /// \ref lemon::GraphReader "GraphReader" /// class documentation. - /// \warning Don't forget to put the \ref GraphReader::run() "run()" + /// \warning Don't forget to put the \ref lemon::GraphReader::run() "run()" /// to the end of the parameter list. /// \relates GraphReader /// \sa graphReader(TGR& graph, const std::string& fn) @@ -2128,6 +2164,1074 @@ return tmp; } + template + class BpGraphReader; + + template + BpGraphReader bpGraphReader(TBGR& graph, std::istream& is = std::cin); + template + BpGraphReader bpGraphReader(TBGR& graph, const std::string& fn); + template + BpGraphReader bpGraphReader(TBGR& graph, const char *fn); + + /// \ingroup lemon_io + /// + /// \brief \ref lgf-format "LGF" reader for bipartite graphs + /// + /// This utility reads an \ref lgf-format "LGF" file. + /// + /// It can be used almost the same way as \c GraphReader, but it + /// reads the red and blue nodes from separate sections, and these + /// sections can contain different set of maps. + /// + /// The red and blue node maps are read from the corresponding + /// sections. If a map is defined with the same name in both of + /// these sections, then it can be read as a node map. + template + class BpGraphReader { + public: + + typedef BGR Graph; + + private: + + TEMPLATE_BPGRAPH_TYPEDEFS(BGR); + + std::istream* _is; + bool local_is; + std::string _filename; + + BGR& _graph; + + std::string _nodes_caption; + std::string _edges_caption; + std::string _attributes_caption; + + typedef std::map RedNodeIndex; + RedNodeIndex _red_node_index; + typedef std::map BlueNodeIndex; + BlueNodeIndex _blue_node_index; + typedef std::map EdgeIndex; + EdgeIndex _edge_index; + + typedef std::vector*> > RedNodeMaps; + RedNodeMaps _red_node_maps; + typedef std::vector*> > BlueNodeMaps; + BlueNodeMaps _blue_node_maps; + + typedef std::vector*> > EdgeMaps; + EdgeMaps _edge_maps; + + typedef std::multimap + Attributes; + Attributes _attributes; + + bool _use_nodes; + bool _use_edges; + + bool _skip_nodes; + bool _skip_edges; + + int line_num; + std::istringstream line; + + public: + + /// \brief Constructor + /// + /// Construct an undirected graph reader, which reads from the given + /// input stream. + BpGraphReader(BGR& graph, std::istream& is = std::cin) + : _is(&is), local_is(false), _graph(graph), + _use_nodes(false), _use_edges(false), + _skip_nodes(false), _skip_edges(false) {} + + /// \brief Constructor + /// + /// Construct an undirected graph reader, which reads from the given + /// file. + BpGraphReader(BGR& graph, const std::string& fn) + : _is(new std::ifstream(fn.c_str())), local_is(true), + _filename(fn), _graph(graph), + _use_nodes(false), _use_edges(false), + _skip_nodes(false), _skip_edges(false) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Constructor + /// + /// Construct an undirected graph reader, which reads from the given + /// file. + BpGraphReader(BGR& graph, const char* fn) + : _is(new std::ifstream(fn)), local_is(true), + _filename(fn), _graph(graph), + _use_nodes(false), _use_edges(false), + _skip_nodes(false), _skip_edges(false) { + if (!(*_is)) { + delete _is; + throw IoError("Cannot open file", fn); + } + } + + /// \brief Destructor + ~BpGraphReader() { + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + delete it->second; + } + + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + delete it->second; + } + + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_is) { + delete _is; + } + + } + + private: + template + friend BpGraphReader bpGraphReader(TBGR& graph, std::istream& is); + template + friend BpGraphReader bpGraphReader(TBGR& graph, + const std::string& fn); + template + friend BpGraphReader bpGraphReader(TBGR& graph, const char *fn); + + BpGraphReader(BpGraphReader& other) + : _is(other._is), local_is(other.local_is), _graph(other._graph), + _use_nodes(other._use_nodes), _use_edges(other._use_edges), + _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { + + other._is = 0; + other.local_is = false; + + _red_node_index.swap(other._red_node_index); + _blue_node_index.swap(other._blue_node_index); + _edge_index.swap(other._edge_index); + + _red_node_maps.swap(other._red_node_maps); + _blue_node_maps.swap(other._blue_node_maps); + _edge_maps.swap(other._edge_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _edges_caption = other._edges_caption; + _attributes_caption = other._attributes_caption; + + } + + BpGraphReader& operator=(const BpGraphReader&); + + public: + + /// \name Reading Rules + /// @{ + + /// \brief Node map reading rule + /// + /// Add a node map reading rule to the reader. + template + BpGraphReader& nodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* red_storage = + new _reader_bits::MapStorage(map); + _red_node_maps.push_back(std::make_pair(caption, red_storage)); + _reader_bits::MapStorageBase* blue_storage = + new _reader_bits::MapStorage(map); + _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// \brief Node map reading rule + /// + /// Add a node map reading rule with specialized converter to the + /// reader. + template + BpGraphReader& nodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* red_storage = + new _reader_bits::MapStorage(map, converter); + _red_node_maps.push_back(std::make_pair(caption, red_storage)); + _reader_bits::MapStorageBase* blue_storage = + new _reader_bits::MapStorage(map, converter); + _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// Add a red node map reading rule to the reader. + template + BpGraphReader& redNodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _red_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Red node map reading rule + /// + /// Add a red node map node reading rule with specialized converter to + /// the reader. + template + BpGraphReader& redNodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _red_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// Add a blue node map reading rule to the reader. + template + BpGraphReader& blueNodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _blue_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node map reading rule + /// + /// Add a blue node map reading rule with specialized converter to + /// the reader. + template + BpGraphReader& blueNodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _blue_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map reading rule + /// + /// Add an edge map reading rule to the reader. + template + BpGraphReader& edgeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map reading rule + /// + /// Add an edge map reading rule with specialized converter to the + /// reader. + template + BpGraphReader& edgeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map reading rule + /// + /// Add an arc map reading rule to the reader. + template + BpGraphReader& arcMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* forward_storage = + new _reader_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _reader_bits::MapStorageBase* backward_storage = + new _reader_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Arc map reading rule + /// + /// Add an arc map reading rule with specialized converter to the + /// reader. + template + BpGraphReader& arcMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* forward_storage = + new _reader_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _reader_bits::MapStorageBase* backward_storage = + new _reader_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Attribute reading rule + /// + /// Add an attribute reading rule to the reader. + template + BpGraphReader& attribute(const std::string& caption, Value& value) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute reading rule + /// + /// Add an attribute reading rule with specialized converter to the + /// reader. + template + BpGraphReader& attribute(const std::string& caption, Value& value, + const Converter& converter = Converter()) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node reading rule + /// + /// Add a node reading rule to reader. + BpGraphReader& node(const std::string& caption, Node& node) { + typedef _reader_bits::DoubleMapLookUpConverter< + Node, RedNodeIndex, BlueNodeIndex> Converter; + Converter converter(_red_node_index, _blue_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Red node reading rule + /// + /// Add a red node reading rule to reader. + BpGraphReader& redNode(const std::string& caption, RedNode& node) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_red_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node reading rule + /// + /// Add a blue node reading rule to reader. + BpGraphReader& blueNode(const std::string& caption, BlueNode& node) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_blue_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge reading rule + /// + /// Add an edge reading rule to reader. + BpGraphReader& edge(const std::string& caption, Edge& edge) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_edge_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(edge, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc reading rule + /// + /// Add an arc reading rule to reader. + BpGraphReader& arc(const std::string& caption, Arc& arc) { + typedef _reader_bits::GraphArcLookUpConverter Converter; + Converter converter(_graph, _edge_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(arc, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// @} + + /// \name Select Section by Name + /// @{ + + /// \brief Set \c \@nodes section to be read + /// + /// Set \c \@nodes section to be read. + BpGraphReader& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \brief Set \c \@edges section to be read + /// + /// Set \c \@edges section to be read. + BpGraphReader& edges(const std::string& caption) { + _edges_caption = caption; + return *this; + } + + /// \brief Set \c \@attributes section to be read + /// + /// Set \c \@attributes section to be read. + BpGraphReader& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// @} + + /// \name Using Previously Constructed Node or Edge Set + /// @{ + + /// \brief Use previously constructed node set + /// + /// Use previously constructed node set, and specify the node + /// label map. + template + BpGraphReader& useNodes(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + _writer_bits::DefaultConverter converter; + for (RedNodeIt n(_graph); n != INVALID; ++n) { + _red_node_index.insert(std::make_pair(converter(map[n]), n)); + } + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + _blue_node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \brief Use previously constructed node set + /// + /// Use previously constructed node set, and specify the node + /// label map and a functor which converts the label map values to + /// \c std::string. + template + BpGraphReader& useNodes(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + for (RedNodeIt n(_graph); n != INVALID; ++n) { + _red_node_index.insert(std::make_pair(converter(map[n]), n)); + } + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + _blue_node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \brief Use previously constructed edge set + /// + /// Use previously constructed edge set, and specify the edge + /// label map. + template + BpGraphReader& useEdges(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); + _use_edges = true; + _writer_bits::DefaultConverter converter; + for (EdgeIt a(_graph); a != INVALID; ++a) { + _edge_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \brief Use previously constructed edge set + /// + /// Use previously constructed edge set, and specify the edge + /// label map and a functor which converts the label map values to + /// \c std::string. + template + BpGraphReader& useEdges(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); + _use_edges = true; + for (EdgeIt a(_graph); a != INVALID; ++a) { + _edge_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \brief Skip the reading of node section + /// + /// Omit the reading of the node section. This implies that each node + /// map reading rule will be abandoned, and the nodes of the graph + /// will not be constructed, which usually cause that the edge set + /// could not be read due to lack of node name + /// could not be read due to lack of node name resolving. + /// Therefore \c skipEdges() function should also be used, or + /// \c useNodes() should be used to specify the label of the nodes. + BpGraphReader& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Skip nodes already set"); + _skip_nodes = true; + return *this; + } + + /// \brief Skip the reading of edge section + /// + /// Omit the reading of the edge section. This implies that each edge + /// map reading rule will be abandoned, and the edges of the graph + /// will not be constructed. + BpGraphReader& skipEdges() { + LEMON_ASSERT(!_skip_edges, "Skip edges already set"); + _skip_edges = true; + return *this; + } + + /// @} + + private: + + bool readLine() { + std::string str; + while(++line_num, std::getline(*_is, str)) { + line.clear(); line.str(str); + char c; + if (line >> std::ws >> c && c != '#') { + line.putback(c); + return true; + } + } + return false; + } + + bool readSuccess() { + return static_cast(*_is); + } + + void skipSection() { + char c; + while (readSuccess() && line >> c && c != '@') { + readLine(); + } + if (readSuccess()) { + line.putback(c); + } + } + + void readRedNodes() { + + std::vector map_index(_red_node_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_red_node_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of red node map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_red_node_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_red_node_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _red_node_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + RedNode n; + if (!_use_nodes) { + n = _graph.addRedNode(); + if (label_index != -1) + _red_node_index.insert(std::make_pair(tokens[label_index], n)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _red_node_index.find(tokens[label_index]); + if (it == _red_node_index.end()) { + std::ostringstream msg; + msg << "Node with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + n = it->second; + } + + for (int i = 0; i < static_cast(_red_node_maps.size()); ++i) { + _red_node_maps[i].second->set(n, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readBlueNodes() { + + std::vector map_index(_blue_node_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_blue_node_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of blue node map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_blue_node_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_blue_node_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _blue_node_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + BlueNode n; + if (!_use_nodes) { + n = _graph.addBlueNode(); + if (label_index != -1) + _blue_node_index.insert(std::make_pair(tokens[label_index], n)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _blue_node_index.find(tokens[label_index]); + if (it == _blue_node_index.end()) { + std::ostringstream msg; + msg << "Node with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + n = it->second; + } + + for (int i = 0; i < static_cast(_blue_node_maps.size()); ++i) { + _blue_node_maps[i].second->set(n, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readEdges() { + + std::vector map_index(_edge_maps.size()); + int map_num, label_index; + + char c; + if (!readLine() || !(line >> c) || c == '@') { + if (readSuccess() && line) line.putback(c); + if (!_edge_maps.empty()) + throw FormatError("Cannot find map names"); + return; + } + line.putback(c); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readToken(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of edge map: " << map; + throw FormatError(msg.str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_edge_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found: " << _edge_maps[i].first; + throw FormatError(msg.str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt != maps.end()) { + label_index = jt->second; + } else { + label_index = -1; + } + } + map_num = maps.size(); + } + + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string source_token; + std::string target_token; + + if (!_reader_bits::readToken(line, source_token)) + throw FormatError("Red node not found"); + + if (!_reader_bits::readToken(line, target_token)) + throw FormatError("Blue node not found"); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw FormatError(msg.str()); + } + } + if (line >> std::ws >> c) + throw FormatError("Extra character at the end of line"); + + Edge e; + if (!_use_edges) { + typename RedNodeIndex::iterator rit = + _red_node_index.find(source_token); + if (rit == _red_node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << source_token; + throw FormatError(msg.str()); + } + RedNode source = rit->second; + typename BlueNodeIndex::iterator it = + _blue_node_index.find(target_token); + if (it == _blue_node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << target_token; + throw FormatError(msg.str()); + } + BlueNode target = it->second; + + // It is checked that source is red and + // target is blue, so this should be safe: + e = _graph.addEdge(source, target); + if (label_index != -1) + _edge_index.insert(std::make_pair(tokens[label_index], e)); + } else { + if (label_index == -1) + throw FormatError("Label map not found"); + typename std::map::iterator it = + _edge_index.find(tokens[label_index]); + if (it == _edge_index.end()) { + std::ostringstream msg; + msg << "Edge with label not found: " << tokens[label_index]; + throw FormatError(msg.str()); + } + e = it->second; + } + + for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { + _edge_maps[i].second->set(e, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readAttributes() { + + std::set read_attr; + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string attr, token; + if (!_reader_bits::readToken(line, attr)) + throw FormatError("Attribute name not found"); + if (!_reader_bits::readToken(line, token)) + throw FormatError("Attribute value not found"); + if (line >> c) + throw FormatError("Extra character at the end of line"); + + { + std::set::iterator it = read_attr.find(attr); + if (it != read_attr.end()) { + std::ostringstream msg; + msg << "Multiple occurence of attribute: " << attr; + throw FormatError(msg.str()); + } + read_attr.insert(attr); + } + + { + typename Attributes::iterator it = _attributes.lower_bound(attr); + while (it != _attributes.end() && it->first == attr) { + it->second->set(token); + ++it; + } + } + + } + if (readSuccess()) { + line.putback(c); + } + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + if (read_attr.find(it->first) == read_attr.end()) { + std::ostringstream msg; + msg << "Attribute not found: " << it->first; + throw FormatError(msg.str()); + } + } + } + + public: + + /// \name Execution of the Reader + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing + void run() { + + LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); + + bool red_nodes_done = _skip_nodes; + bool blue_nodes_done = _skip_nodes; + bool edges_done = _skip_edges; + bool attributes_done = false; + + line_num = 0; + readLine(); + skipSection(); + + while (readSuccess()) { + try { + char c; + std::string section, caption; + line >> c; + _reader_bits::readToken(line, section); + _reader_bits::readToken(line, caption); + + if (line >> c) + throw FormatError("Extra character at the end of line"); + + if (section == "red_nodes" && !red_nodes_done) { + if (_nodes_caption.empty() || _nodes_caption == caption) { + readRedNodes(); + red_nodes_done = true; + } + } else if (section == "blue_nodes" && !blue_nodes_done) { + if (_nodes_caption.empty() || _nodes_caption == caption) { + readBlueNodes(); + blue_nodes_done = true; + } + } else if ((section == "edges" || section == "arcs") && + !edges_done) { + if (_edges_caption.empty() || _edges_caption == caption) { + readEdges(); + edges_done = true; + } + } else if (section == "attributes" && !attributes_done) { + if (_attributes_caption.empty() || _attributes_caption == caption) { + readAttributes(); + attributes_done = true; + } + } else { + readLine(); + skipSection(); + } + } catch (FormatError& error) { + error.line(line_num); + error.file(_filename); + throw; + } + } + + if (!red_nodes_done) { + throw FormatError("Section @red_nodes not found"); + } + + if (!blue_nodes_done) { + throw FormatError("Section @blue_nodes not found"); + } + + if (!edges_done) { + throw FormatError("Section @edges not found"); + } + + if (!attributes_done && !_attributes.empty()) { + throw FormatError("Section @attributes not found"); + } + + } + + /// @} + + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref lemon::BpGraphReader "BpGraphReader" class + /// + /// This function just returns a \ref lemon::BpGraphReader + /// "BpGraphReader" class. + /// + /// 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 bipartite weighted matching problem + /// on a graph, i.e. a graph with a \e weight map on the edges. This + /// graph can be read with the following code: + /// + ///\code + ///ListBpGraph graph; + ///ListBpGraph::EdgeMap weight(graph); + ///bpGraphReader(graph, std::cin). + /// edgeMap("weight", weight). + /// run(); + ///\endcode + /// + /// For a complete documentation, please see the + /// \ref lemon::BpGraphReader "BpGraphReader" + /// class documentation. + /// \warning Don't forget to put the \ref lemon::BpGraphReader::run() "run()" + /// to the end of the parameter list. + /// \relates BpGraphReader + /// \sa bpGraphReader(TBGR& graph, const std::string& fn) + /// \sa bpGraphReader(TBGR& graph, const char* fn) + template + BpGraphReader bpGraphReader(TBGR& graph, std::istream& is) { + BpGraphReader tmp(graph, is); + return tmp; + } + + /// \brief Return a \ref BpGraphReader class + /// + /// This function just returns a \ref BpGraphReader class. + /// \relates BpGraphReader + /// \sa bpGraphReader(TBGR& graph, std::istream& is) + template + BpGraphReader bpGraphReader(TBGR& graph, const std::string& fn) { + BpGraphReader tmp(graph, fn); + return tmp; + } + + /// \brief Return a \ref BpGraphReader class + /// + /// This function just returns a \ref BpGraphReader class. + /// \relates BpGraphReader + /// \sa bpGraphReader(TBGR& graph, std::istream& is) + template + BpGraphReader bpGraphReader(TBGR& graph, const char* fn) { + BpGraphReader tmp(graph, fn); + return tmp; + } + class SectionReader; SectionReader sectionReader(std::istream& is); diff -r cd72eae05bdf -r 3c00344f49c9 lemon/lgf_writer.h --- a/lemon/lgf_writer.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/lgf_writer.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -191,16 +191,16 @@ } }; - template + template > struct MapLookUpConverter { - const std::map& _map; + const Map& _map; - MapLookUpConverter(const std::map& map) + MapLookUpConverter(const Map& map) : _map(map) {} - std::string operator()(const Value& str) { - typename std::map::const_iterator it = - _map.find(str); + std::string operator()(const Value& value) { + typename Map::const_iterator it = _map.find(value); if (it == _map.end()) { throw FormatError("Item not found"); } @@ -208,6 +208,35 @@ } }; + template , + typename Map2 = std::map > + struct DoubleMapLookUpConverter { + const Map1& _map1; + const Map2& _map2; + + DoubleMapLookUpConverter(const Map1& map1, const Map2& map2) + : _map1(map1), _map2(map2) {} + + std::string operator()(const Value& value) { + typename Map1::const_iterator it1 = _map1.find(value); + typename Map1::const_iterator it2 = _map2.find(value); + if (it1 == _map1.end()) { + if (it2 == _map2.end()) { + throw FormatError("Item not found"); + } else { + return it2->second; + } + } else { + if (it2 == _map2.end()) { + return it1->second; + } else { + throw FormatError("Item is ambigous"); + } + } + } + }; + template struct GraphArcLookUpConverter { const Graph& _graph; @@ -915,9 +944,10 @@ /// \ingroup lemon_io /// - /// \brief Return a \ref DigraphWriter class + /// \brief Return a \ref lemon::DigraphWriter "DigraphWriter" class /// - /// This function just returns a \ref DigraphWriter class. + /// This function just returns a \ref lemon::DigraphWriter + /// "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 @@ -938,9 +968,10 @@ /// run(); ///\endcode /// - /// For a complete documentation, please see the \ref DigraphWriter + /// For a complete documentation, please see the + /// \ref lemon::DigraphWriter "DigraphWriter" /// class documentation. - /// \warning Don't forget to put the \ref DigraphWriter::run() "run()" + /// \warning Don't forget to put the \ref lemon::DigraphWriter::run() "run()" /// to the end of the parameter list. /// \relates DigraphWriter /// \sa digraphWriter(const TDGR& digraph, const std::string& fn) @@ -986,7 +1017,7 @@ /// \ingroup lemon_io /// - /// \brief \ref lgf-format "LGF" writer for directed graphs + /// \brief \ref lgf-format "LGF" writer for undirected graphs /// /// This utility writes an \ref lgf-format "LGF" file. /// @@ -1042,15 +1073,15 @@ /// \brief Constructor /// - /// Construct a directed graph writer, which writes to the given - /// output stream. + /// Construct an undirected graph writer, which writes to the + /// given output stream. GraphWriter(const GR& graph, std::ostream& os = std::cout) : _os(&os), local_os(false), _graph(graph), _skip_nodes(false), _skip_edges(false) {} /// \brief Constructor /// - /// Construct a directed graph writer, which writes to the given + /// Construct a undirected graph writer, which writes to the given /// output file. GraphWriter(const GR& graph, const std::string& fn) : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph), @@ -1063,7 +1094,7 @@ /// \brief Constructor /// - /// Construct a directed graph writer, which writes to the given + /// Construct a undirected graph writer, which writes to the given /// output file. GraphWriter(const GR& graph, const char* fn) : _os(new std::ofstream(fn)), local_os(true), _graph(graph), @@ -1289,9 +1320,9 @@ return *this; } - /// \brief Add an additional caption to the \c \@arcs section + /// \brief Add an additional caption to the \c \@edges section /// - /// Add an additional caption to the \c \@arcs section. + /// Add an additional caption to the \c \@edges section. GraphWriter& edges(const std::string& caption) { _edges_caption = caption; return *this; @@ -1554,9 +1585,9 @@ /// \ingroup lemon_io /// - /// \brief Return a \ref GraphWriter class + /// \brief Return a \ref lemon::GraphWriter "GraphWriter" class /// - /// This function just returns a \ref GraphWriter class. + /// This function just returns a \ref lemon::GraphWriter "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 @@ -1573,9 +1604,10 @@ /// run(); ///\endcode /// - /// For a complete documentation, please see the \ref GraphWriter + /// For a complete documentation, please see the + /// \ref lemon::GraphWriter "GraphWriter" /// class documentation. - /// \warning Don't forget to put the \ref GraphWriter::run() "run()" + /// \warning Don't forget to put the \ref lemon::GraphWriter::run() "run()" /// to the end of the parameter list. /// \relates GraphWriter /// \sa graphWriter(const TGR& graph, const std::string& fn) @@ -1608,6 +1640,826 @@ return tmp; } + template + class BpGraphWriter; + + template + BpGraphWriter bpGraphWriter(const TBGR& graph, + std::ostream& os = std::cout); + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const std::string& fn); + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const char* fn); + + /// \ingroup lemon_io + /// + /// \brief \ref lgf-format "LGF" writer for undirected bipartite graphs + /// + /// This utility writes an \ref lgf-format "LGF" file. + /// + /// It can be used almost the same way as \c GraphWriter, but it + /// reads the red and blue nodes from separate sections, and these + /// sections can contain different set of maps. + /// + /// The red and blue node maps are written to the corresponding + /// sections. The node maps are written to both of these sections + /// with the same map name. + template + class BpGraphWriter { + public: + + typedef BGR BpGraph; + TEMPLATE_BPGRAPH_TYPEDEFS(BGR); + + private: + + + std::ostream* _os; + bool local_os; + + const BGR& _graph; + + std::string _nodes_caption; + std::string _edges_caption; + std::string _attributes_caption; + + typedef std::map RedNodeIndex; + RedNodeIndex _red_node_index; + typedef std::map BlueNodeIndex; + BlueNodeIndex _blue_node_index; + typedef std::map EdgeIndex; + EdgeIndex _edge_index; + + typedef std::vector* > > RedNodeMaps; + RedNodeMaps _red_node_maps; + typedef std::vector* > > BlueNodeMaps; + BlueNodeMaps _blue_node_maps; + + typedef std::vector* > >EdgeMaps; + EdgeMaps _edge_maps; + + typedef std::vector > Attributes; + Attributes _attributes; + + bool _skip_nodes; + bool _skip_edges; + + public: + + /// \brief Constructor + /// + /// Construct a bipartite graph writer, which writes to the given + /// output stream. + BpGraphWriter(const BGR& graph, std::ostream& os = std::cout) + : _os(&os), local_os(false), _graph(graph), + _skip_nodes(false), _skip_edges(false) {} + + /// \brief Constructor + /// + /// Construct a bipartite graph writer, which writes to the given + /// output file. + BpGraphWriter(const BGR& graph, const std::string& fn) + : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph), + _skip_nodes(false), _skip_edges(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Constructor + /// + /// Construct a bipartite graph writer, which writes to the given + /// output file. + BpGraphWriter(const BGR& graph, const char* fn) + : _os(new std::ofstream(fn)), local_os(true), _graph(graph), + _skip_nodes(false), _skip_edges(false) { + if (!(*_os)) { + delete _os; + throw IoError("Cannot write file", fn); + } + } + + /// \brief Destructor + ~BpGraphWriter() { + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + delete it->second; + } + + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + delete it->second; + } + + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_os) { + delete _os; + } + } + + private: + + template + friend BpGraphWriter bpGraphWriter(const TBGR& graph, + std::ostream& os); + template + friend BpGraphWriter bpGraphWriter(const TBGR& graph, + const std::string& fn); + template + friend BpGraphWriter bpGraphWriter(const TBGR& graph, const char *fn); + + BpGraphWriter(BpGraphWriter& other) + : _os(other._os), local_os(other.local_os), _graph(other._graph), + _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { + + other._os = 0; + other.local_os = false; + + _red_node_index.swap(other._red_node_index); + _blue_node_index.swap(other._blue_node_index); + _edge_index.swap(other._edge_index); + + _red_node_maps.swap(other._red_node_maps); + _blue_node_maps.swap(other._blue_node_maps); + _edge_maps.swap(other._edge_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _edges_caption = other._edges_caption; + _attributes_caption = other._attributes_caption; + } + + BpGraphWriter& operator=(const BpGraphWriter&); + + public: + + /// \name Writing Rules + /// @{ + + /// \brief Node map writing rule + /// + /// Add a node map writing rule to the writer. + template + BpGraphWriter& nodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* red_storage = + new _writer_bits::MapStorage(map); + _red_node_maps.push_back(std::make_pair(caption, red_storage)); + _writer_bits::MapStorageBase* blue_storage = + new _writer_bits::MapStorage(map); + _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// \brief Node map writing rule + /// + /// Add a node map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& nodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* red_storage = + new _writer_bits::MapStorage(map, converter); + _red_node_maps.push_back(std::make_pair(caption, red_storage)); + _writer_bits::MapStorageBase* blue_storage = + new _writer_bits::MapStorage(map, converter); + _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); + return *this; + } + + /// \brief Red node map writing rule + /// + /// Add a red node map writing rule to the writer. + template + BpGraphWriter& redNodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _red_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Red node map writing rule + /// + /// Add a red node map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& redNodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _red_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node map writing rule + /// + /// Add a blue node map writing rule to the writer. + template + BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _blue_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node map writing rule + /// + /// Add a blue node map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _blue_node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map writing rule + /// + /// Add an edge map writing rule to the writer. + template + BpGraphWriter& edgeMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge map writing rule + /// + /// Add an edge map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& edgeMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* storage = + new _writer_bits::MapStorage(map, converter); + _edge_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule to the writer. + template + BpGraphWriter& arcMap(const std::string& caption, const Map& map) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* forward_storage = + new _writer_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _writer_bits::MapStorageBase* backward_storage = + new _writer_bits::GraphArcMapStorage(_graph, map); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Arc map writing rule + /// + /// Add an arc map writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& arcMap(const std::string& caption, const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _writer_bits::MapStorageBase* forward_storage = + new _writer_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); + _writer_bits::MapStorageBase* backward_storage = + new _writer_bits::GraphArcMapStorage + (_graph, map, converter); + _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule to the writer. + template + BpGraphWriter& attribute(const std::string& caption, const Value& value) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Attribute writing rule + /// + /// Add an attribute writing rule with specialized converter to the + /// writer. + template + BpGraphWriter& attribute(const std::string& caption, const Value& value, + const Converter& converter = Converter()) { + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(value, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Node writing rule + /// + /// Add a node writing rule to the writer. + BpGraphWriter& node(const std::string& caption, const Node& node) { + typedef _writer_bits::DoubleMapLookUpConverter< + Node, RedNodeIndex, BlueNodeIndex> Converter; + Converter converter(_red_node_index, _blue_node_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(node, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Red node writing rule + /// + /// Add a red node writing rule to the writer. + BpGraphWriter& redNode(const std::string& caption, const RedNode& node) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_red_node_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(node, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Blue node writing rule + /// + /// Add a blue node writing rule to the writer. + BpGraphWriter& blueNode(const std::string& caption, const BlueNode& node) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_blue_node_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(node, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Edge writing rule + /// + /// Add an edge writing rule to writer. + BpGraphWriter& edge(const std::string& caption, const Edge& edge) { + typedef _writer_bits::MapLookUpConverter Converter; + Converter converter(_edge_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(edge, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \brief Arc writing rule + /// + /// Add an arc writing rule to writer. + BpGraphWriter& arc(const std::string& caption, const Arc& arc) { + typedef _writer_bits::GraphArcLookUpConverter Converter; + Converter converter(_graph, _edge_index); + _writer_bits::ValueStorageBase* storage = + new _writer_bits::ValueStorage(arc, converter); + _attributes.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \name Section Captions + /// @{ + + /// \brief Add an additional caption to the \c \@red_nodes and + /// \c \@blue_nodes section + /// + /// Add an additional caption to the \c \@red_nodes and \c + /// \@blue_nodes section. + BpGraphWriter& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@edges section + /// + /// Add an additional caption to the \c \@edges section. + BpGraphWriter& edges(const std::string& caption) { + _edges_caption = caption; + return *this; + } + + /// \brief Add an additional caption to the \c \@attributes section + /// + /// Add an additional caption to the \c \@attributes section. + BpGraphWriter& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// \name Skipping Section + /// @{ + + /// \brief Skip writing the node set + /// + /// The \c \@red_nodes and \c \@blue_nodes section will not be + /// written to the stream. + BpGraphWriter& skipNodes() { + LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); + _skip_nodes = true; + return *this; + } + + /// \brief Skip writing edge set + /// + /// The \c \@edges section will not be written to the stream. + BpGraphWriter& skipEdges() { + LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member"); + _skip_edges = true; + return *this; + } + + /// @} + + private: + + void writeRedNodes() { + _writer_bits::MapStorageBase* label = 0; + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@red_nodes"; + if (!_nodes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _nodes_caption); + } + *_os << std::endl; + + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector nodes; + for (RedNodeIt n(_graph); n != INVALID; ++n) { + nodes.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(nodes.begin(), nodes.end(), id_less); + } else { + label->sort(nodes); + } + + for (int i = 0; i < static_cast(nodes.size()); ++i) { + RedNode n = nodes[i]; + if (label == 0) { + std::ostringstream os; + os << _graph.id(static_cast(n)); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _red_node_index.insert(std::make_pair(n, os.str())); + } + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + std::string value = it->second->get(n); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _red_node_index.insert(std::make_pair(n, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void writeBlueNodes() { + _writer_bits::MapStorageBase* label = 0; + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@blue_nodes"; + if (!_nodes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _nodes_caption); + } + *_os << std::endl; + + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector nodes; + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + nodes.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(nodes.begin(), nodes.end(), id_less); + } else { + label->sort(nodes); + } + + for (int i = 0; i < static_cast(nodes.size()); ++i) { + BlueNode n = nodes[i]; + if (label == 0) { + std::ostringstream os; + os << _graph.id(static_cast(n)); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _blue_node_index.insert(std::make_pair(n, os.str())); + } + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + std::string value = it->second->get(n); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _blue_node_index.insert(std::make_pair(n, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createRedNodeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); + it != _red_node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (RedNodeIt n(_graph); n != INVALID; ++n) { + std::ostringstream os; + os << _graph.id(n); + _red_node_index.insert(std::make_pair(n, os.str())); + } + } else { + for (RedNodeIt n(_graph); n != INVALID; ++n) { + std::string value = label->get(n); + _red_node_index.insert(std::make_pair(n, value)); + } + } + } + + void createBlueNodeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); + it != _blue_node_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + std::ostringstream os; + os << _graph.id(n); + _blue_node_index.insert(std::make_pair(n, os.str())); + } + } else { + for (BlueNodeIt n(_graph); n != INVALID; ++n) { + std::string value = label->get(n); + _blue_node_index.insert(std::make_pair(n, value)); + } + } + } + + void writeEdges() { + _writer_bits::MapStorageBase* label = 0; + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + *_os << "@edges"; + if (!_edges_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _edges_caption); + } + *_os << std::endl; + + *_os << '\t' << '\t'; + if (label == 0) { + *_os << "label" << '\t'; + } + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << '\t'; + } + *_os << std::endl; + + std::vector edges; + for (EdgeIt n(_graph); n != INVALID; ++n) { + edges.push_back(n); + } + + if (label == 0) { + IdMap id_map(_graph); + _writer_bits::MapLess > id_less(id_map); + std::sort(edges.begin(), edges.end(), id_less); + } else { + label->sort(edges); + } + + for (int i = 0; i < static_cast(edges.size()); ++i) { + Edge e = edges[i]; + _writer_bits::writeToken(*_os, _red_node_index. + find(_graph.redNode(e))->second); + *_os << '\t'; + _writer_bits::writeToken(*_os, _blue_node_index. + find(_graph.blueNode(e))->second); + *_os << '\t'; + if (label == 0) { + std::ostringstream os; + os << _graph.id(e); + _writer_bits::writeToken(*_os, os.str()); + *_os << '\t'; + _edge_index.insert(std::make_pair(e, os.str())); + } + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + std::string value = it->second->get(e); + _writer_bits::writeToken(*_os, value); + if (it->first == "label") { + _edge_index.insert(std::make_pair(e, value)); + } + *_os << '\t'; + } + *_os << std::endl; + } + } + + void createEdgeIndex() { + _writer_bits::MapStorageBase* label = 0; + for (typename EdgeMaps::iterator it = _edge_maps.begin(); + it != _edge_maps.end(); ++it) { + if (it->first == "label") { + label = it->second; + break; + } + } + + if (label == 0) { + for (EdgeIt e(_graph); e != INVALID; ++e) { + std::ostringstream os; + os << _graph.id(e); + _edge_index.insert(std::make_pair(e, os.str())); + } + } else { + for (EdgeIt e(_graph); e != INVALID; ++e) { + std::string value = label->get(e); + _edge_index.insert(std::make_pair(e, value)); + } + } + } + + void writeAttributes() { + if (_attributes.empty()) return; + *_os << "@attributes"; + if (!_attributes_caption.empty()) { + _writer_bits::writeToken(*_os << ' ', _attributes_caption); + } + *_os << std::endl; + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + _writer_bits::writeToken(*_os, it->first) << ' '; + _writer_bits::writeToken(*_os, it->second->get()); + *_os << std::endl; + } + } + + public: + + /// \name Execution of the Writer + /// @{ + + /// \brief Start the batch processing + /// + /// This function starts the batch processing. + void run() { + if (!_skip_nodes) { + writeRedNodes(); + writeBlueNodes(); + } else { + createRedNodeIndex(); + createBlueNodeIndex(); + } + if (!_skip_edges) { + writeEdges(); + } else { + createEdgeIndex(); + } + writeAttributes(); + } + + /// \brief Give back the stream of the writer + /// + /// Give back the stream of the writer + std::ostream& ostream() { + return *_os; + } + + /// @} + }; + + /// \ingroup lemon_io + /// + /// \brief Return a \ref lemon::BpGraphWriter "BpGraphWriter" class + /// + /// This function just returns a \ref lemon::BpGraphWriter + /// "BpGraphWriter" class. + /// + /// With this function a bipartite graph can be write to a file or output + /// stream in \ref lgf-format "LGF" format with several maps and + /// attributes. For example, with the following code a bipartite + /// weighted matching problem can be written to the standard output, + /// i.e. a graph with a \e weight map on the edges: + /// + ///\code + ///ListBpGraph graph; + ///ListBpGraph::EdgeMap weight(graph); + /// // Setting the weight map + ///bpGraphWriter(graph, std::cout). + /// edgeMap("weight", weight). + /// run(); + ///\endcode + /// + /// For a complete documentation, please see the + /// \ref lemon::BpGraphWriter "BpGraphWriter" + /// class documentation. + /// \warning Don't forget to put the \ref lemon::BpGraphWriter::run() "run()" + /// to the end of the parameter list. + /// \relates BpGraphWriter + /// \sa bpGraphWriter(const TBGR& graph, const std::string& fn) + /// \sa bpGraphWriter(const TBGR& graph, const char* fn) + template + BpGraphWriter bpGraphWriter(const TBGR& graph, std::ostream& os) { + BpGraphWriter tmp(graph, os); + return tmp; + } + + /// \brief Return a \ref BpGraphWriter class + /// + /// This function just returns a \ref BpGraphWriter class. + /// \relates BpGraphWriter + /// \sa graphWriter(const TBGR& graph, std::ostream& os) + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const std::string& fn) { + BpGraphWriter tmp(graph, fn); + return tmp; + } + + /// \brief Return a \ref BpGraphWriter class + /// + /// This function just returns a \ref BpGraphWriter class. + /// \relates BpGraphWriter + /// \sa graphWriter(const TBGR& graph, std::ostream& os) + template + BpGraphWriter bpGraphWriter(const TBGR& graph, const char* fn) { + BpGraphWriter tmp(graph, fn); + return tmp; + } + class SectionWriter; SectionWriter sectionWriter(std::istream& is); diff -r cd72eae05bdf -r 3c00344f49c9 lemon/list_graph.h --- a/lemon/list_graph.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/list_graph.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -445,7 +445,7 @@ ///\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. + ///iterators are invalidated for the incoming arcs of \c v. ///Moreover all iterators referencing node \c v or the removed ///loops are also invalidated. Other iterators remain valid. /// @@ -582,7 +582,7 @@ snapshot.addNode(node); } virtual void add(const std::vector& nodes) { - for (int i = nodes.size() - 1; i >= 0; ++i) { + for (int i = nodes.size() - 1; i >= 0; --i) { snapshot.addNode(nodes[i]); } } @@ -632,7 +632,7 @@ snapshot.addArc(arc); } virtual void add(const std::vector& arcs) { - for (int i = arcs.size() - 1; i >= 0; ++i) { + for (int i = arcs.size() - 1; i >= 0; --i) { snapshot.addArc(arcs[i]); } } @@ -1394,7 +1394,7 @@ snapshot.addNode(node); } virtual void add(const std::vector& nodes) { - for (int i = nodes.size() - 1; i >= 0; ++i) { + for (int i = nodes.size() - 1; i >= 0; --i) { snapshot.addNode(nodes[i]); } } @@ -1444,7 +1444,7 @@ snapshot.addEdge(edge); } virtual void add(const std::vector& edges) { - for (int i = edges.size() - 1; i >= 0; ++i) { + for (int i = edges.size() - 1; i >= 0; --i) { snapshot.addEdge(edges[i]); } } @@ -1599,6 +1599,911 @@ }; /// @} + + class ListBpGraphBase { + + protected: + + struct NodeT { + int first_out; + int prev, next; + int partition_prev, partition_next; + int partition_index; + bool red; + }; + + struct ArcT { + int target; + int prev_out, next_out; + }; + + std::vector nodes; + + int first_node, first_red, first_blue; + int max_red, max_blue; + + int first_free_red, first_free_blue; + + std::vector arcs; + + int first_free_arc; + + public: + + typedef ListBpGraphBase BpGraph; + + class Node { + friend class ListBpGraphBase; + protected: + + int id; + explicit Node(int pid) { id = pid;} + + 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 RedNode : public Node { + friend class ListBpGraphBase; + protected: + + explicit RedNode(int pid) : Node(pid) {} + + public: + RedNode() {} + RedNode(const RedNode& node) : Node(node) {} + RedNode(Invalid) : Node(INVALID){} + }; + + class BlueNode : public Node { + friend class ListBpGraphBase; + protected: + + explicit BlueNode(int pid) : Node(pid) {} + + public: + BlueNode() {} + BlueNode(const BlueNode& node) : Node(node) {} + BlueNode(Invalid) : Node(INVALID){} + }; + + class Edge { + friend class ListBpGraphBase; + protected: + + int id; + explicit Edge(int pid) { id = pid;} + + public: + Edge() {} + Edge (Invalid) { id = -1; } + bool operator==(const Edge& edge) const {return id == edge.id;} + bool operator!=(const Edge& edge) const {return id != edge.id;} + bool operator<(const Edge& edge) const {return id < edge.id;} + }; + + class Arc { + friend class ListBpGraphBase; + protected: + + int id; + explicit Arc(int pid) { id = pid;} + + public: + operator Edge() const { + return id != -1 ? edgeFromId(id / 2) : INVALID; + } + + 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;} + }; + + ListBpGraphBase() + : nodes(), first_node(-1), + first_red(-1), first_blue(-1), + max_red(-1), max_blue(-1), + first_free_red(-1), first_free_blue(-1), + arcs(), first_free_arc(-1) {} + + + bool red(Node n) const { return nodes[n.id].red; } + bool blue(Node n) const { return !nodes[n.id].red; } + + static RedNode asRedNodeUnsafe(Node n) { return RedNode(n.id); } + static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n.id); } + + int maxNodeId() const { return nodes.size()-1; } + int maxRedId() const { return max_red; } + int maxBlueId() const { return max_blue; } + int maxEdgeId() const { return arcs.size() / 2 - 1; } + int maxArcId() const { return arcs.size()-1; } + + Node source(Arc e) const { return Node(arcs[e.id ^ 1].target); } + Node target(Arc e) const { return Node(arcs[e.id].target); } + + RedNode redNode(Edge e) const { + return RedNode(arcs[2 * e.id].target); + } + BlueNode blueNode(Edge e) const { + return BlueNode(arcs[2 * e.id + 1].target); + } + + static bool direction(Arc e) { + return (e.id & 1) == 1; + } + + static Arc direct(Edge e, bool d) { + return Arc(e.id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node.id = first_node; + } + + void next(Node& node) const { + node.id = nodes[node.id].next; + } + + void first(RedNode& node) const { + node.id = first_red; + } + + void next(RedNode& node) const { + node.id = nodes[node.id].partition_next; + } + + void first(BlueNode& node) const { + node.id = first_blue; + } + + void next(BlueNode& node) const { + node.id = nodes[node.id].partition_next; + } + + void first(Arc& e) const { + int n = first_node; + while (n != -1 && nodes[n].first_out == -1) { + n = nodes[n].next; + } + e.id = (n == -1) ? -1 : nodes[n].first_out; + } + + void next(Arc& e) const { + if (arcs[e.id].next_out != -1) { + e.id = arcs[e.id].next_out; + } else { + int n = nodes[arcs[e.id ^ 1].target].next; + while(n != -1 && nodes[n].first_out == -1) { + n = nodes[n].next; + } + e.id = (n == -1) ? -1 : nodes[n].first_out; + } + } + + void first(Edge& e) const { + int n = first_node; + while (n != -1) { + e.id = nodes[n].first_out; + while ((e.id & 1) != 1) { + e.id = arcs[e.id].next_out; + } + if (e.id != -1) { + e.id /= 2; + return; + } + n = nodes[n].next; + } + e.id = -1; + } + + void next(Edge& e) const { + int n = arcs[e.id * 2].target; + e.id = arcs[(e.id * 2) | 1].next_out; + while ((e.id & 1) != 1) { + e.id = arcs[e.id].next_out; + } + if (e.id != -1) { + e.id /= 2; + return; + } + n = nodes[n].next; + while (n != -1) { + e.id = nodes[n].first_out; + while ((e.id & 1) != 1) { + e.id = arcs[e.id].next_out; + } + if (e.id != -1) { + e.id /= 2; + return; + } + n = nodes[n].next; + } + e.id = -1; + } + + void firstOut(Arc &e, const Node& v) const { + e.id = nodes[v.id].first_out; + } + void nextOut(Arc &e) const { + e.id = arcs[e.id].next_out; + } + + void firstIn(Arc &e, const Node& v) const { + e.id = ((nodes[v.id].first_out) ^ 1); + if (e.id == -2) e.id = -1; + } + void nextIn(Arc &e) const { + e.id = ((arcs[e.id ^ 1].next_out) ^ 1); + if (e.id == -2) e.id = -1; + } + + void firstInc(Edge &e, bool& d, const Node& v) const { + int a = nodes[v.id].first_out; + if (a != -1 ) { + e.id = a / 2; + d = ((a & 1) == 1); + } else { + e.id = -1; + d = true; + } + } + void nextInc(Edge &e, bool& d) const { + int a = (arcs[(e.id * 2) | (d ? 1 : 0)].next_out); + if (a != -1 ) { + e.id = a / 2; + d = ((a & 1) == 1); + } else { + e.id = -1; + d = true; + } + } + + static int id(Node v) { return v.id; } + int id(RedNode v) const { return nodes[v.id].partition_index; } + int id(BlueNode v) const { return nodes[v.id].partition_index; } + static int id(Arc e) { return e.id; } + static int id(Edge e) { return e.id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + bool valid(Node n) const { + return n.id >= 0 && n.id < static_cast(nodes.size()) && + nodes[n.id].prev != -2; + } + + bool valid(Arc a) const { + return a.id >= 0 && a.id < static_cast(arcs.size()) && + arcs[a.id].prev_out != -2; + } + + bool valid(Edge e) const { + return e.id >= 0 && 2 * e.id < static_cast(arcs.size()) && + arcs[2 * e.id].prev_out != -2; + } + + RedNode addRedNode() { + int n; + + if(first_free_red==-1) { + n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].partition_index = ++max_red; + nodes[n].red = true; + } else { + n = first_free_red; + first_free_red = nodes[n].next; + } + + nodes[n].next = first_node; + if (first_node != -1) nodes[first_node].prev = n; + first_node = n; + nodes[n].prev = -1; + + nodes[n].partition_next = first_red; + if (first_red != -1) nodes[first_red].partition_prev = n; + first_red = n; + nodes[n].partition_prev = -1; + + nodes[n].first_out = -1; + + return RedNode(n); + } + + BlueNode addBlueNode() { + int n; + + if(first_free_blue==-1) { + n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].partition_index = ++max_blue; + nodes[n].red = false; + } else { + n = first_free_blue; + first_free_blue = nodes[n].next; + } + + nodes[n].next = first_node; + if (first_node != -1) nodes[first_node].prev = n; + first_node = n; + nodes[n].prev = -1; + + nodes[n].partition_next = first_blue; + if (first_blue != -1) nodes[first_blue].partition_prev = n; + first_blue = n; + nodes[n].partition_prev = -1; + + nodes[n].first_out = -1; + + return BlueNode(n); + } + + Edge addEdge(Node u, Node v) { + int n; + + if (first_free_arc == -1) { + n = arcs.size(); + arcs.push_back(ArcT()); + arcs.push_back(ArcT()); + } else { + n = first_free_arc; + first_free_arc = arcs[n].next_out; + } + + arcs[n].target = u.id; + arcs[n | 1].target = v.id; + + arcs[n].next_out = nodes[v.id].first_out; + if (nodes[v.id].first_out != -1) { + arcs[nodes[v.id].first_out].prev_out = n; + } + arcs[n].prev_out = -1; + nodes[v.id].first_out = n; + + arcs[n | 1].next_out = nodes[u.id].first_out; + if (nodes[u.id].first_out != -1) { + arcs[nodes[u.id].first_out].prev_out = (n | 1); + } + arcs[n | 1].prev_out = -1; + nodes[u.id].first_out = (n | 1); + + return Edge(n / 2); + } + + void erase(const Node& node) { + int n = node.id; + + if(nodes[n].next != -1) { + nodes[nodes[n].next].prev = nodes[n].prev; + } + + if(nodes[n].prev != -1) { + nodes[nodes[n].prev].next = nodes[n].next; + } else { + first_node = nodes[n].next; + } + + if (nodes[n].partition_next != -1) { + nodes[nodes[n].partition_next].partition_prev = nodes[n].partition_prev; + } + + if (nodes[n].partition_prev != -1) { + nodes[nodes[n].partition_prev].partition_next = nodes[n].partition_next; + } else { + if (nodes[n].red) { + first_red = nodes[n].partition_next; + } else { + first_blue = nodes[n].partition_next; + } + } + + if (nodes[n].red) { + nodes[n].next = first_free_red; + first_free_red = n; + } else { + nodes[n].next = first_free_blue; + first_free_blue = n; + } + nodes[n].prev = -2; + } + + void erase(const Edge& edge) { + int n = edge.id * 2; + + if (arcs[n].next_out != -1) { + arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; + } + + if (arcs[n].prev_out != -1) { + arcs[arcs[n].prev_out].next_out = arcs[n].next_out; + } else { + nodes[arcs[n | 1].target].first_out = arcs[n].next_out; + } + + if (arcs[n | 1].next_out != -1) { + arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out; + } + + if (arcs[n | 1].prev_out != -1) { + arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out; + } else { + nodes[arcs[n].target].first_out = arcs[n | 1].next_out; + } + + arcs[n].next_out = first_free_arc; + first_free_arc = n; + arcs[n].prev_out = -2; + arcs[n | 1].prev_out = -2; + + } + + void clear() { + arcs.clear(); + nodes.clear(); + first_node = first_free_arc = first_red = first_blue = + max_red = max_blue = first_free_red = first_free_blue = -1; + } + + protected: + + void changeRed(Edge e, RedNode n) { + if(arcs[(2 * e.id) | 1].next_out != -1) { + arcs[arcs[(2 * e.id) | 1].next_out].prev_out = + arcs[(2 * e.id) | 1].prev_out; + } + if(arcs[(2 * e.id) | 1].prev_out != -1) { + arcs[arcs[(2 * e.id) | 1].prev_out].next_out = + arcs[(2 * e.id) | 1].next_out; + } else { + nodes[arcs[2 * e.id].target].first_out = + arcs[(2 * e.id) | 1].next_out; + } + + if (nodes[n.id].first_out != -1) { + arcs[nodes[n.id].first_out].prev_out = ((2 * e.id) | 1); + } + arcs[2 * e.id].target = n.id; + arcs[(2 * e.id) | 1].prev_out = -1; + arcs[(2 * e.id) | 1].next_out = nodes[n.id].first_out; + nodes[n.id].first_out = ((2 * e.id) | 1); + } + + void changeBlue(Edge e, BlueNode n) { + if(arcs[2 * e.id].next_out != -1) { + arcs[arcs[2 * e.id].next_out].prev_out = arcs[2 * e.id].prev_out; + } + if(arcs[2 * e.id].prev_out != -1) { + arcs[arcs[2 * e.id].prev_out].next_out = + arcs[2 * e.id].next_out; + } else { + nodes[arcs[(2 * e.id) | 1].target].first_out = + arcs[2 * e.id].next_out; + } + + if (nodes[n.id].first_out != -1) { + arcs[nodes[n.id].first_out].prev_out = 2 * e.id; + } + arcs[(2 * e.id) | 1].target = n.id; + arcs[2 * e.id].prev_out = -1; + arcs[2 * e.id].next_out = nodes[n.id].first_out; + nodes[n.id].first_out = 2 * e.id; + } + + }; + + typedef BpGraphExtender ExtendedListBpGraphBase; + + + /// \addtogroup graphs + /// @{ + + ///A general undirected graph structure. + + ///\ref ListBpGraph is a versatile and fast undirected graph + ///implementation based on linked lists that are stored in + ///\c std::vector structures. + /// + ///This type fully conforms to the \ref concepts::BpGraph "BpGraph 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::BpGraph + ///\sa ListDigraph + class ListBpGraph : public ExtendedListBpGraphBase { + typedef ExtendedListBpGraphBase Parent; + + private: + /// BpGraphs are \e not copy constructible. Use BpGraphCopy instead. + ListBpGraph(const ListBpGraph &) :ExtendedListBpGraphBase() {}; + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use BpGraphCopy instead. + void operator=(const ListBpGraph &) {} + public: + /// Constructor + + /// Constructor. + /// + ListBpGraph() {} + + typedef Parent::OutArcIt IncEdgeIt; + + /// \brief Add a new red node to the graph. + /// + /// This function adds a red new node to the graph. + /// \return The new node. + RedNode addRedNode() { return Parent::addRedNode(); } + + /// \brief Add a new blue node to the graph. + /// + /// This function adds a blue new node to the graph. + /// \return The new node. + BlueNode addBlueNode() { return Parent::addBlueNode(); } + + /// \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(RedNode u, BlueNode v) { + return Parent::addEdge(u, v); + } + Edge addEdge(BlueNode v, RedNode u) { + return Parent::addEdge(u, v); + } + + ///\brief Erase a node from the graph. + /// + /// This function erases the given node along with its incident arcs + /// from the graph. + /// + /// \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. + /// + /// This function erases the given edge from the graph. + /// + /// \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 \c true if the given node is valid, + /// i.e. it is a real node of the graph. + /// + /// \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 \c true if the given arc is valid, + /// i.e. it is a real arc of the graph. + /// + /// \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); } + + /// \brief Change the red node of an edge. + /// + /// This function changes the red node of the given edge \c e to \c n. + /// + ///\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 changeRed(Edge e, RedNode n) { + Parent::changeRed(e, n); + } + /// \brief Change the blue node of an edge. + /// + /// This function changes the blue node of the given edge \c e to \c n. + /// + ///\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 changeBlue(Edge e, BlueNode n) { + Parent::changeBlue(e, n); + } + + ///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. + /// + /// Class to make a snapshot of the graph and restore it later. + /// + /// The newly added nodes and edges can be removed + /// using the restore() function. + /// + /// \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: + + typedef Parent::NodeNotifier NodeNotifier; + + class NodeObserverProxy : public NodeNotifier::ObserverBase { + public: + + NodeObserverProxy(Snapshot& _snapshot) + : snapshot(_snapshot) {} + + using NodeNotifier::ObserverBase::attach; + using NodeNotifier::ObserverBase::detach; + using NodeNotifier::ObserverBase::attached; + + protected: + + virtual void add(const Node& node) { + snapshot.addNode(node); + } + virtual void add(const std::vector& nodes) { + for (int i = nodes.size() - 1; i >= 0; --i) { + snapshot.addNode(nodes[i]); + } + } + virtual void erase(const Node& node) { + snapshot.eraseNode(node); + } + virtual void erase(const std::vector& nodes) { + for (int i = 0; i < int(nodes.size()); ++i) { + snapshot.eraseNode(nodes[i]); + } + } + virtual void build() { + Node node; + std::vector nodes; + for (notifier()->first(node); node != INVALID; + notifier()->next(node)) { + nodes.push_back(node); + } + for (int i = nodes.size() - 1; i >= 0; --i) { + snapshot.addNode(nodes[i]); + } + } + virtual void clear() { + Node node; + for (notifier()->first(node); node != INVALID; + notifier()->next(node)) { + snapshot.eraseNode(node); + } + } + + Snapshot& snapshot; + }; + + class EdgeObserverProxy : public EdgeNotifier::ObserverBase { + public: + + EdgeObserverProxy(Snapshot& _snapshot) + : snapshot(_snapshot) {} + + using EdgeNotifier::ObserverBase::attach; + using EdgeNotifier::ObserverBase::detach; + using EdgeNotifier::ObserverBase::attached; + + protected: + + virtual void add(const Edge& edge) { + snapshot.addEdge(edge); + } + virtual void add(const std::vector& edges) { + for (int i = edges.size() - 1; i >= 0; --i) { + snapshot.addEdge(edges[i]); + } + } + virtual void erase(const Edge& edge) { + snapshot.eraseEdge(edge); + } + virtual void erase(const std::vector& edges) { + for (int i = 0; i < int(edges.size()); ++i) { + snapshot.eraseEdge(edges[i]); + } + } + virtual void build() { + Edge edge; + std::vector edges; + for (notifier()->first(edge); edge != INVALID; + notifier()->next(edge)) { + edges.push_back(edge); + } + for (int i = edges.size() - 1; i >= 0; --i) { + snapshot.addEdge(edges[i]); + } + } + virtual void clear() { + Edge edge; + for (notifier()->first(edge); edge != INVALID; + notifier()->next(edge)) { + snapshot.eraseEdge(edge); + } + } + + Snapshot& snapshot; + }; + + ListBpGraph *graph; + + NodeObserverProxy node_observer_proxy; + EdgeObserverProxy edge_observer_proxy; + + std::list added_nodes; + std::list added_edges; + + + void addNode(const Node& node) { + added_nodes.push_front(node); + } + void eraseNode(const Node& node) { + std::list::iterator it = + std::find(added_nodes.begin(), added_nodes.end(), node); + if (it == added_nodes.end()) { + clear(); + edge_observer_proxy.detach(); + throw NodeNotifier::ImmediateDetach(); + } else { + added_nodes.erase(it); + } + } + + void addEdge(const Edge& edge) { + added_edges.push_front(edge); + } + void eraseEdge(const Edge& edge) { + std::list::iterator it = + std::find(added_edges.begin(), added_edges.end(), edge); + if (it == added_edges.end()) { + clear(); + node_observer_proxy.detach(); + throw EdgeNotifier::ImmediateDetach(); + } else { + added_edges.erase(it); + } + } + + void attach(ListBpGraph &_graph) { + graph = &_graph; + node_observer_proxy.attach(graph->notifier(Node())); + edge_observer_proxy.attach(graph->notifier(Edge())); + } + + void detach() { + node_observer_proxy.detach(); + edge_observer_proxy.detach(); + } + + bool attached() const { + return node_observer_proxy.attached(); + } + + void clear() { + added_nodes.clear(); + added_edges.clear(); + } + + public: + + /// \brief Default constructor. + /// + /// Default constructor. + /// 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 given graph. + Snapshot(ListBpGraph &gr) + : node_observer_proxy(*this), + edge_observer_proxy(*this) { + attach(gr); + } + + /// \brief Make a snapshot. + /// + /// 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. + void save(ListBpGraph &gr) { + if (attached()) { + detach(); + clear(); + } + attach(gr); + } + + /// \brief Undo the changes until the last snapshot. + /// + /// This function undos the changes until the last snapshot + /// created by save() or Snapshot(ListBpGraph&). + /// + /// \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(); + it != added_edges.end(); ++it) { + graph->erase(*it); + } + for(std::list::iterator it = added_nodes.begin(); + it != added_nodes.end(); ++it) { + graph->erase(*it); + } + clear(); + } + + /// \brief Returns \c true if the snapshot is valid. + /// + /// This function returns \c true if the snapshot is valid. + bool valid() const { + return attached(); + } + }; + }; + + /// @} } //namespace lemon diff -r cd72eae05bdf -r 3c00344f49c9 lemon/lp.h --- a/lemon/lp.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/lp.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -22,15 +22,21 @@ #include -#ifdef LEMON_HAVE_GLPK +#if LEMON_DEFAULT_LP == LEMON_GLPK_ || LEMON_DEFAULT_MIP == LEMON_GLPK_ #include -#elif LEMON_HAVE_CPLEX +#endif +#if LEMON_DEFAULT_LP == LEMON_CPLEX_ || LEMON_DEFAULT_MIP == LEMON_CPLEX_ #include -#elif LEMON_HAVE_SOPLEX +#endif +#if LEMON_DEFAULT_LP == LEMON_SOPLEX_ #include -#elif LEMON_HAVE_CLP +#endif +#if LEMON_DEFAULT_LP == LEMON_CLP_ #include #endif +#if LEMON_DEFAULT_MIP == LEMON_CBC_ +#include +#endif ///\file ///\brief Defines a default LP solver @@ -43,8 +49,8 @@ ///The default LP solver identifier. ///\ingroup lp_group /// - ///Currently, the possible values are \c GLPK, \c CPLEX, - ///\c SOPLEX or \c CLP + ///Currently, the possible values are \c LEMON_GLPK_, \c LEMON_CPLEX_, + ///\c LEMON_SOPLEX_ or \c LEMON_CLP_ #define LEMON_DEFAULT_LP SOLVER ///The default LP solver @@ -59,32 +65,32 @@ ///The default MIP solver identifier. ///\ingroup lp_group /// - ///Currently, the possible values are \c GLPK or \c CPLEX + ///Currently, the possible values are \c LEMON_GLPK_, \c LEMON_CPLEX_ + ///or \c LEMON_CBC_ #define LEMON_DEFAULT_MIP SOLVER ///The default MIP solver. ///The default MIP solver. ///\ingroup lp_group /// - ///Currently, it is either \c GlpkMip or \c CplexMip + ///Currently, it is either \c GlpkMip, \c CplexMip , \c CbcMip typedef GlpkMip Mip; #else -#ifdef LEMON_HAVE_GLPK -# define LEMON_DEFAULT_LP GLPK +#if LEMON_DEFAULT_LP == LEMON_GLPK_ typedef GlpkLp Lp; -# define LEMON_DEFAULT_MIP GLPK +#elif LEMON_DEFAULT_LP == LEMON_CPLEX_ + typedef CplexLp Lp; +#elif LEMON_DEFAULT_LP == LEMON_SOPLEX_ + typedef SoplexLp Lp; +#elif LEMON_DEFAULT_LP == LEMON_CLP_ + typedef ClpLp Lp; +#endif +#if LEMON_DEFAULT_MIP == LEMON_GLPK_ typedef GlpkMip Mip; -#elif LEMON_HAVE_CPLEX -# define LEMON_DEFAULT_LP CPLEX - typedef CplexLp Lp; -# define LEMON_DEFAULT_MIP CPLEX +#elif LEMON_DEFAULT_MIP == LEMON_CPLEX_ typedef CplexMip Mip; -#elif LEMON_HAVE_SOPLEX -# define DEFAULT_LP SOPLEX - typedef SoplexLp Lp; -#elif LEMON_HAVE_CLP -# define DEFAULT_LP CLP - typedef ClpLp Lp; +#elif LEMON_DEFAULT_MIP == LEMON_CBC_ + typedef CbcMip Mip; #endif #endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/lp_base.cc --- a/lemon/lp_base.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/lp_base.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/lp_base.h --- a/lemon/lp_base.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/lp_base.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -1007,6 +1007,36 @@ public: + ///Unsupported file format exception + class UnsupportedFormatError : public Exception + { + std::string _format; + mutable std::string _what; + public: + explicit UnsupportedFormatError(std::string format) throw() + : _format(format) { } + virtual ~UnsupportedFormatError() throw() {} + virtual const char* what() const throw() { + try { + _what.clear(); + std::ostringstream oss; + oss << "lemon::UnsupportedFormatError: " << _format; + _what = oss.str(); + } + catch (...) {} + if (!_what.empty()) return _what.c_str(); + else return "lemon::UnsupportedFormatError"; + } + }; + + protected: + virtual void _write(std::string, std::string format) const + { + throw UnsupportedFormatError(format); + } + + public: + /// Virtual destructor virtual ~LpBase() {} @@ -1555,12 +1585,27 @@ ///Set the sense to maximization void min() { _setSense(MIN); } - ///Clears the problem + ///Clear the problem void clear() { _clear(); rows.clear(); cols.clear(); } - /// Sets the message level of the solver + /// Set the message level of the solver void messageLevel(MessageLevel level) { _messageLevel(level); } + /// Write the problem to a file in the given format + + /// This function writes the problem to a file in the given format. + /// Different solver backends may support different formats. + /// Trying to write in an unsupported format will trigger + /// \ref UnsupportedFormatError. For the supported formats, + /// visit the documentation of the base class of the related backends + /// (\ref CplexBase, \ref GlpkBase etc.) + /// \param file The file path + /// \param format The output file format. + void write(std::string file, std::string format = "MPS") const + { + _write(file.c_str(),format.c_str()); + } + ///@} }; diff -r cd72eae05bdf -r 3c00344f49c9 lemon/lp_skeleton.cc --- a/lemon/lp_skeleton.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/lp_skeleton.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -91,6 +91,8 @@ void SkeletonSolverBase::_messageLevel(MessageLevel) {} + void SkeletonSolverBase::_write(std::string, std::string) const {} + LpSkeleton::SolveExitStatus LpSkeleton::_solve() { return SOLVED; } LpSkeleton::Value LpSkeleton::_getPrimal(int) const { return 0; } diff -r cd72eae05bdf -r 3c00344f49c9 lemon/lp_skeleton.h --- a/lemon/lp_skeleton.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/lp_skeleton.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -144,6 +144,10 @@ ///\e virtual void _messageLevel(MessageLevel); + + ///\e + virtual void _write(std::string file, std::string format) const; + }; /// \brief Skeleton class for an LP solver interface @@ -222,6 +226,7 @@ ///\e virtual const char* _solverName() const; + }; } //namespace lemon diff -r cd72eae05bdf -r 3c00344f49c9 lemon/maps.h --- a/lemon/maps.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/maps.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/matching.h --- a/lemon/matching.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/matching.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/math.h --- a/lemon/math.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/math.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -65,8 +65,13 @@ return v!=v; } + ///Round a value to its closest integer + inline double round(double r) { + return (r > 0.0) ? std::floor(r + 0.5) : std::ceil(r - 0.5); + } + /// @} } //namespace lemon -#endif //LEMON_TOLERANCE_H +#endif //LEMON_MATH_H diff -r cd72eae05bdf -r 3c00344f49c9 lemon/max_cardinality_search.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/max_cardinality_search.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,794 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_MAX_CARDINALITY_SEARCH_H +#define LEMON_MAX_CARDINALITY_SEARCH_H + + +/// \ingroup search +/// \file +/// \brief Maximum cardinality search in undirected digraphs. + +#include +#include + +#include +#include + +#include + +namespace lemon { + + /// \brief Default traits class of MaxCardinalitySearch class. + /// + /// Default traits class of MaxCardinalitySearch class. + /// \param Digraph Digraph type. + /// \param CapacityMap Type of capacity map. + template + struct MaxCardinalitySearchDefaultTraits { + /// The digraph type the algorithm runs on. + typedef GR Digraph; + + template + struct CapMapSelector { + + typedef CM CapacityMap; + + static CapacityMap *createCapacityMap(const Digraph& g) { + return new CapacityMap(g); + } + }; + + template + struct CapMapSelector > > { + + typedef ConstMap > CapacityMap; + + static CapacityMap *createCapacityMap(const Digraph&) { + return new CapacityMap; + } + }; + + /// \brief The type of the map that stores the arc capacities. + /// + /// The type of the map that stores the arc capacities. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef typename CapMapSelector::CapacityMap CapacityMap; + + /// \brief The type of the capacity of the arcs. + typedef typename CapacityMap::Value Value; + + /// \brief Instantiates a CapacityMap. + /// + /// This function instantiates a \ref CapacityMap. + /// \param digraph is the digraph, to which we would like to define + /// the CapacityMap. + static CapacityMap *createCapacityMap(const Digraph& digraph) { + return CapMapSelector::createCapacityMap(digraph); + } + + /// \brief The cross reference type used by heap. + /// + /// The cross reference type used by heap. + /// Usually it is \c Digraph::NodeMap. + typedef typename Digraph::template NodeMap HeapCrossRef; + + /// \brief Instantiates a HeapCrossRef. + /// + /// This function instantiates a \ref HeapCrossRef. + /// \param digraph is the digraph, to which we would like to define the + /// HeapCrossRef. + static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) { + return new HeapCrossRef(digraph); + } + + template + struct HeapSelector { + template + struct Selector { + typedef BinHeap > Heap; + }; + }; + + template + struct HeapSelector > > { + template + struct Selector { + typedef BucketHeap Heap; + }; + }; + + /// \brief The heap type used by MaxCardinalitySearch algorithm. + /// + /// The heap type used by MaxCardinalitySearch algorithm. It should + /// maximalize the priorities. The default heap type is + /// the \ref BinHeap, but it is specialized when the + /// CapacityMap is ConstMap > + /// to BucketHeap. + /// + /// \sa MaxCardinalitySearch + typedef typename HeapSelector + ::template Selector + ::Heap Heap; + + /// \brief Instantiates a Heap. + /// + /// This function instantiates a \ref Heap. + /// \param crossref The cross reference of the heap. + static Heap *createHeap(HeapCrossRef& crossref) { + return new Heap(crossref); + } + + /// \brief The type of the map that stores whether a node is processed. + /// + /// The type of the map that stores whether a node is processed. + /// It must meet the \ref concepts::WriteMap "WriteMap" concept. + /// By default it is a NullMap. + typedef NullMap ProcessedMap; + + /// \brief Instantiates a ProcessedMap. + /// + /// This function instantiates a \ref ProcessedMap. + /// \param digraph is the digraph, to which + /// we would like to define the \ref ProcessedMap +#ifdef DOXYGEN + static ProcessedMap *createProcessedMap(const Digraph &digraph) +#else + static ProcessedMap *createProcessedMap(const Digraph &) +#endif + { + return new ProcessedMap(); + } + + /// \brief The type of the map that stores the cardinalities of the nodes. + /// + /// The type of the map that stores the cardinalities of the nodes. + /// It must meet the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap CardinalityMap; + + /// \brief Instantiates a CardinalityMap. + /// + /// This function instantiates a \ref CardinalityMap. + /// \param digraph is the digraph, to which we would like to + /// define the \ref CardinalityMap + static CardinalityMap *createCardinalityMap(const Digraph &digraph) { + return new CardinalityMap(digraph); + } + + + }; + + /// \ingroup search + /// + /// \brief Maximum Cardinality Search algorithm class. + /// + /// This class provides an efficient implementation of Maximum Cardinality + /// Search algorithm. The maximum cardinality search first chooses any + /// node of the digraph. Then every time it chooses one unprocessed node + /// with maximum cardinality, i.e the sum of capacities on out arcs + /// to the nodes + /// which were previusly processed. + /// If there is a cut in the digraph the algorithm should choose + /// again any unprocessed node of the digraph. + + /// The arc capacities are passed to the algorithm using a + /// \ref concepts::ReadMap "ReadMap", so it is easy to change it to any + /// kind of capacity. + /// + /// The type of the capacity is determined by the \ref + /// concepts::ReadMap::Value "Value" of the capacity map. + /// + /// It is also possible to change the underlying priority heap. + /// + /// + /// \param GR The digraph type the algorithm runs on. The value of + /// Digraph is not used directly by the search algorithm, it + /// is only passed to \ref MaxCardinalitySearchDefaultTraits. + /// \param CAP This read-only ArcMap determines the capacities of + /// the arcs. It is read once for each arc, so the map may involve in + /// relatively time consuming process to compute the arc capacity if + /// it is necessary. The default map type is \ref + /// ConstMap "ConstMap >". The value + /// of CapacityMap is not used directly by search algorithm, it is only + /// passed to \ref MaxCardinalitySearchDefaultTraits. + /// \param TR Traits class to set various data types used by the + /// algorithm. The default traits class is + /// \ref MaxCardinalitySearchDefaultTraits + /// "MaxCardinalitySearchDefaultTraits". + /// See \ref MaxCardinalitySearchDefaultTraits + /// for the documentation of a MaxCardinalitySearch traits class. + +#ifdef DOXYGEN + template +#else + template >, + typename TR = + MaxCardinalitySearchDefaultTraits > +#endif + class MaxCardinalitySearch { + public: + + typedef TR Traits; + ///The type of the underlying digraph. + typedef typename Traits::Digraph Digraph; + + ///The type of the capacity of the arcs. + typedef typename Traits::CapacityMap::Value Value; + ///The type of the map that stores the arc capacities. + typedef typename Traits::CapacityMap CapacityMap; + ///The type of the map indicating if a node is processed. + typedef typename Traits::ProcessedMap ProcessedMap; + ///The type of the map that stores the cardinalities of the nodes. + typedef typename Traits::CardinalityMap CardinalityMap; + ///The cross reference type used for the current heap. + typedef typename Traits::HeapCrossRef HeapCrossRef; + ///The heap type used by the algorithm. It maximizes the priorities. + typedef typename Traits::Heap Heap; + private: + // Pointer to the underlying digraph. + const Digraph *_graph; + // Pointer to the capacity map + const CapacityMap *_capacity; + // Indicates if \ref _capacity is locally allocated (\c true) or not. + bool local_capacity; + // Pointer to the map of cardinality. + CardinalityMap *_cardinality; + // Indicates if \ref _cardinality is locally allocated (\c true) or not. + bool local_cardinality; + // Pointer to the map of processed status of the nodes. + ProcessedMap *_processed; + // Indicates if \ref _processed is locally allocated (\c true) or not. + bool local_processed; + // Pointer to the heap cross references. + HeapCrossRef *_heap_cross_ref; + // Indicates if \ref _heap_cross_ref is locally allocated (\c true) or not. + bool local_heap_cross_ref; + // Pointer to the heap. + Heap *_heap; + // Indicates if \ref _heap is locally allocated (\c true) or not. + bool local_heap; + + public : + + typedef MaxCardinalitySearch Create; + + ///\name Named template parameters + + ///@{ + + template + struct DefCapacityMapTraits : public Traits { + typedef T CapacityMap; + static CapacityMap *createCapacityMap(const Digraph &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// CapacityMap type + /// + /// \ref named-templ-param "Named parameter" for setting CapacityMap type + /// for the algorithm. + template + struct SetCapacityMap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > Create; + }; + + template + struct DefCardinalityMapTraits : public Traits { + typedef T CardinalityMap; + static CardinalityMap *createCardinalityMap(const Digraph &) + { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// CardinalityMap type + /// + /// \ref named-templ-param "Named parameter" for setting CardinalityMap + /// type for the algorithm. + template + struct SetCardinalityMap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > Create; + }; + + template + struct DefProcessedMapTraits : public Traits { + typedef T ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// ProcessedMap type + /// + /// \ref named-templ-param "Named parameter" for setting ProcessedMap type + /// for the algorithm. + template + struct SetProcessedMap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > Create; + }; + + template + struct DefHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(const Digraph &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + static Heap *createHeap(HeapCrossRef &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting heap + /// and cross reference type + /// + /// \ref named-templ-param "Named parameter" for setting heap and cross + /// reference type for the algorithm. + template > + struct SetHeap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch< Digraph, CapacityMap, + DefHeapTraits > Create; + }; + + template + struct DefStandardHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) { + return new HeapCrossRef(digraph); + } + static Heap *createHeap(HeapCrossRef &crossref) { + return new Heap(crossref); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting heap and + /// cross reference type with automatic allocation + /// + /// \ref named-templ-param "Named parameter" for setting heap and cross + /// reference type. It can allocate the heap and the cross reference + /// object if the cross reference's constructor waits for the digraph as + /// parameter and the heap's constructor waits for the cross reference. + template > + struct SetStandardHeap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > + Create; + }; + + ///@} + + + protected: + + MaxCardinalitySearch() {} + + public: + + /// \brief Constructor. + /// + ///\param digraph the digraph the algorithm will run on. + ///\param capacity the capacity map used by the algorithm. + MaxCardinalitySearch(const Digraph& digraph, + const CapacityMap& capacity) : + _graph(&digraph), + _capacity(&capacity), local_capacity(false), + _cardinality(0), local_cardinality(false), + _processed(0), local_processed(false), + _heap_cross_ref(0), local_heap_cross_ref(false), + _heap(0), local_heap(false) + { } + + /// \brief Constructor. + /// + ///\param digraph the digraph the algorithm will run on. + /// + ///A constant 1 capacity map will be allocated. + MaxCardinalitySearch(const Digraph& digraph) : + _graph(&digraph), + _capacity(0), local_capacity(false), + _cardinality(0), local_cardinality(false), + _processed(0), local_processed(false), + _heap_cross_ref(0), local_heap_cross_ref(false), + _heap(0), local_heap(false) + { } + + /// \brief Destructor. + ~MaxCardinalitySearch() { + if(local_capacity) delete _capacity; + if(local_cardinality) delete _cardinality; + if(local_processed) delete _processed; + if(local_heap_cross_ref) delete _heap_cross_ref; + if(local_heap) delete _heap; + } + + /// \brief Sets the capacity map. + /// + /// Sets the capacity map. + /// \return (*this) + MaxCardinalitySearch &capacityMap(const CapacityMap &m) { + if (local_capacity) { + delete _capacity; + local_capacity=false; + } + _capacity=&m; + return *this; + } + + /// \brief Returns a const reference to the capacity map. + /// + /// Returns a const reference to the capacity map used by + /// the algorithm. + const CapacityMap &capacityMap() const { + return *_capacity; + } + + /// \brief Sets the map storing the cardinalities calculated by the + /// algorithm. + /// + /// Sets the map storing the cardinalities calculated by the algorithm. + /// If you don't use this function before calling \ref run(), + /// it will allocate one. The destuctor deallocates this + /// automatically allocated map, of course. + /// \return (*this) + MaxCardinalitySearch &cardinalityMap(CardinalityMap &m) { + if(local_cardinality) { + delete _cardinality; + local_cardinality=false; + } + _cardinality = &m; + return *this; + } + + /// \brief Sets the map storing the processed nodes. + /// + /// Sets the map storing the processed nodes. + /// If you don't use this function before calling \ref run(), + /// it will allocate one. The destuctor deallocates this + /// automatically allocated map, of course. + /// \return (*this) + MaxCardinalitySearch &processedMap(ProcessedMap &m) + { + if(local_processed) { + delete _processed; + local_processed=false; + } + _processed = &m; + return *this; + } + + /// \brief Returns a const reference to the cardinality map. + /// + /// Returns a const reference to the cardinality map used by + /// the algorithm. + const ProcessedMap &processedMap() const { + return *_processed; + } + + /// \brief Sets the heap and the cross reference used by algorithm. + /// + /// Sets the heap and the cross reference used by algorithm. + /// If you don't use this function before calling \ref run(), + /// it will allocate one. The destuctor deallocates this + /// automatically allocated map, of course. + /// \return (*this) + MaxCardinalitySearch &heap(Heap& hp, HeapCrossRef &cr) { + if(local_heap_cross_ref) { + delete _heap_cross_ref; + local_heap_cross_ref = false; + } + _heap_cross_ref = &cr; + if(local_heap) { + delete _heap; + local_heap = false; + } + _heap = &hp; + return *this; + } + + /// \brief Returns a const reference to the heap. + /// + /// Returns a const reference to the heap used by + /// the algorithm. + const Heap &heap() const { + return *_heap; + } + + /// \brief Returns a const reference to the cross reference. + /// + /// Returns a const reference to the cross reference + /// of the heap. + const HeapCrossRef &heapCrossRef() const { + return *_heap_cross_ref; + } + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::InArcIt InArcIt; + + void create_maps() { + if(!_capacity) { + local_capacity = true; + _capacity = Traits::createCapacityMap(*_graph); + } + if(!_cardinality) { + local_cardinality = true; + _cardinality = Traits::createCardinalityMap(*_graph); + } + if(!_processed) { + local_processed = true; + _processed = Traits::createProcessedMap(*_graph); + } + if (!_heap_cross_ref) { + local_heap_cross_ref = true; + _heap_cross_ref = Traits::createHeapCrossRef(*_graph); + } + if (!_heap) { + local_heap = true; + _heap = Traits::createHeap(*_heap_cross_ref); + } + } + + void finalizeNodeData(Node node, Value capacity) { + _processed->set(node, true); + _cardinality->set(node, capacity); + } + + public: + /// \name Execution control + /// The simplest way to execute the algorithm is to use + /// one of the member functions called \ref run(). + /// \n + /// If you need more control on the execution, + /// first you must call \ref init(), then you can add several source nodes + /// with \ref addSource(). + /// Finally \ref start() will perform the computation. + + ///@{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures, and clears the heap. + void init() { + create_maps(); + _heap->clear(); + for (NodeIt it(*_graph) ; it != INVALID ; ++it) { + _processed->set(it, false); + _heap_cross_ref->set(it, Heap::PRE_HEAP); + } + } + + /// \brief Adds a new source node. + /// + /// Adds a new source node to the priority heap. + /// + /// It checks if the node has not yet been added to the heap. + void addSource(Node source, Value capacity = 0) { + if(_heap->state(source) == Heap::PRE_HEAP) { + _heap->push(source, capacity); + } + } + + /// \brief Processes the next node in the priority heap + /// + /// Processes the next node in the priority heap. + /// + /// \return The processed node. + /// + /// \warning The priority heap must not be empty! + Node processNextNode() { + Node node = _heap->top(); + finalizeNodeData(node, _heap->prio()); + _heap->pop(); + + for (InArcIt it(*_graph, node); it != INVALID; ++it) { + Node source = _graph->source(it); + switch (_heap->state(source)) { + case Heap::PRE_HEAP: + _heap->push(source, (*_capacity)[it]); + break; + case Heap::IN_HEAP: + _heap->decrease(source, (*_heap)[source] + (*_capacity)[it]); + break; + case Heap::POST_HEAP: + break; + } + } + return node; + } + + /// \brief Next node to be processed. + /// + /// Next node to be processed. + /// + /// \return The next node to be processed or INVALID if the + /// priority heap is empty. + Node nextNode() { + return !_heap->empty() ? _heap->top() : INVALID; + } + + /// \brief Returns \c false if there are nodes + /// to be processed in the priority heap + /// + /// Returns \c false if there are nodes + /// to be processed in the priority heap + bool emptyQueue() { return _heap->empty(); } + /// \brief Returns the number of the nodes to be processed + /// in the priority heap + /// + /// Returns the number of the nodes to be processed in the priority heap + int emptySize() { return _heap->size(); } + + /// \brief Executes the algorithm. + /// + /// Executes the algorithm. + /// + ///\pre init() must be called and at least one node should be added + /// with addSource() before using this function. + /// + /// This method runs the Maximum Cardinality Search algorithm from the + /// source node(s). + void start() { + while ( !_heap->empty() ) processNextNode(); + } + + /// \brief Executes the algorithm until \c dest is reached. + /// + /// Executes the algorithm until \c dest is reached. + /// + /// \pre init() must be called and at least one node should be added + /// with addSource() before using this function. + /// + /// This method runs the %MaxCardinalitySearch algorithm from the source + /// nodes. + void start(Node dest) { + while ( !_heap->empty() && _heap->top()!=dest ) processNextNode(); + if ( !_heap->empty() ) finalizeNodeData(_heap->top(), _heap->prio()); + } + + /// \brief Executes the algorithm until a condition is met. + /// + /// Executes the algorithm until a condition is met. + /// + /// \pre init() must be called and at least one node should be added + /// with addSource() before using this function. + /// + /// \param nm must be a bool (or convertible) node map. The algorithm + /// will stop when it reaches a node \c v with nm[v]==true. + template + void start(const NodeBoolMap &nm) { + while ( !_heap->empty() && !nm[_heap->top()] ) processNextNode(); + if ( !_heap->empty() ) finalizeNodeData(_heap->top(),_heap->prio()); + } + + /// \brief Runs the maximum cardinality search algorithm from node \c s. + /// + /// This method runs the %MaxCardinalitySearch algorithm from a root + /// node \c s. + /// + ///\note d.run(s) is just a shortcut of the following code. + ///\code + /// d.init(); + /// d.addSource(s); + /// d.start(); + ///\endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + /// \brief Runs the maximum cardinality search algorithm for the + /// whole digraph. + /// + /// This method runs the %MaxCardinalitySearch algorithm from all + /// unprocessed node of the digraph. + /// + ///\note d.run(s) is just a shortcut of the following code. + ///\code + /// d.init(); + /// for (NodeIt it(digraph); it != INVALID; ++it) { + /// if (!d.reached(it)) { + /// d.addSource(s); + /// d.start(); + /// } + /// } + ///\endcode + void run() { + init(); + for (NodeIt it(*_graph); it != INVALID; ++it) { + if (!reached(it)) { + addSource(it); + start(); + } + } + } + + ///@} + + /// \name Query Functions + /// The results of the maximum cardinality search algorithm can be + /// obtained using these functions. + /// \n + /// Before the use of these functions, either run() or start() must be + /// called. + + ///@{ + + /// \brief The cardinality of a node. + /// + /// Returns the cardinality of a node. + /// \pre \ref run() must be called before using this function. + /// \warning If node \c v in unreachable from the root the return value + /// of this funcion is undefined. + Value cardinality(Node node) const { return (*_cardinality)[node]; } + + /// \brief The current cardinality of a node. + /// + /// Returns the current cardinality of a node. + /// \pre the given node should be reached but not processed + Value currentCardinality(Node node) const { return (*_heap)[node]; } + + /// \brief Returns a reference to the NodeMap of cardinalities. + /// + /// Returns a reference to the NodeMap of cardinalities. \pre \ref run() + /// must be called before using this function. + const CardinalityMap &cardinalityMap() const { return *_cardinality;} + + /// \brief Checks if a node is reachable from the root. + /// + /// Returns \c true if \c v is reachable from the root. + /// \warning The source nodes are initated as unreached. + /// \pre \ref run() must be called before using this function. + bool reached(Node v) { return (*_heap_cross_ref)[v] != Heap::PRE_HEAP; } + + /// \brief Checks if a node is processed. + /// + /// Returns \c true if \c v is processed, i.e. the shortest + /// path to \c v has already found. + /// \pre \ref run() must be called before using this function. + bool processed(Node v) { return (*_heap_cross_ref)[v] == Heap::POST_HEAP; } + + ///@} + }; + +} + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/min_cost_arborescence.h --- a/lemon/min_cost_arborescence.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/min_cost_arborescence.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -101,7 +101,7 @@ /// more sources should be given to the algorithm and it will calculate /// the minimum cost subgraph that is the union of arborescences with the /// given sources and spans all the nodes which are reachable from the - /// sources. The time complexity of the algorithm is O(n2+e). + /// sources. The time complexity of the algorithm is O(n2+m). /// /// The algorithm also provides an optimal dual solution, therefore /// the optimality of the solution can be checked. @@ -128,7 +128,7 @@ class MinCostArborescence { public: - /// \brief The \ref MinCostArborescenceDefaultTraits "traits class" + /// \brief The \ref lemon::MinCostArborescenceDefaultTraits "traits class" /// of the algorithm. typedef TR Traits; /// The type of the underlying digraph. diff -r cd72eae05bdf -r 3c00344f49c9 lemon/nagamochi_ibaraki.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/nagamochi_ibaraki.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,702 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_NAGAMOCHI_IBARAKI_H +#define LEMON_NAGAMOCHI_IBARAKI_H + + +/// \ingroup min_cut +/// \file +/// \brief Implementation of the Nagamochi-Ibaraki algorithm. + +#include +#include +#include +#include +#include +#include + +#include + +namespace lemon { + + /// \brief Default traits class for NagamochiIbaraki class. + /// + /// Default traits class for NagamochiIbaraki class. + /// \param GR The undirected graph type. + /// \param CM Type of capacity map. + template + struct NagamochiIbarakiDefaultTraits { + /// The type of the capacity map. + typedef typename CM::Value Value; + + /// The undirected graph type the algorithm runs on. + typedef GR Graph; + + /// \brief The type of the map that stores the edge capacities. + /// + /// The type of the map that stores the edge capacities. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef CM CapacityMap; + + /// \brief Instantiates a CapacityMap. + /// + /// This function instantiates a \ref CapacityMap. +#ifdef DOXYGEN + static CapacityMap *createCapacityMap(const Graph& graph) +#else + static CapacityMap *createCapacityMap(const Graph&) +#endif + { + LEMON_ASSERT(false, "CapacityMap is not initialized"); + return 0; // ignore warnings + } + + /// \brief The cross reference type used by heap. + /// + /// The cross reference type used by heap. + /// Usually \c Graph::NodeMap. + typedef typename Graph::template NodeMap HeapCrossRef; + + /// \brief Instantiates a HeapCrossRef. + /// + /// This function instantiates a \ref HeapCrossRef. + /// \param g is the graph, to which we would like to define the + /// \ref HeapCrossRef. + static HeapCrossRef *createHeapCrossRef(const Graph& g) { + return new HeapCrossRef(g); + } + + /// \brief The heap type used by NagamochiIbaraki algorithm. + /// + /// The heap type used by NagamochiIbaraki algorithm. It has to + /// maximize the priorities. + /// + /// \sa BinHeap + /// \sa NagamochiIbaraki + typedef BinHeap > Heap; + + /// \brief Instantiates a Heap. + /// + /// This function instantiates a \ref Heap. + /// \param r is the cross reference of the heap. + static Heap *createHeap(HeapCrossRef& r) { + return new Heap(r); + } + }; + + /// \ingroup min_cut + /// + /// \brief Calculates the minimum cut in an undirected graph. + /// + /// Calculates the minimum cut in an undirected graph with the + /// Nagamochi-Ibaraki algorithm. The algorithm separates the graph's + /// nodes into two partitions with the minimum sum of edge capacities + /// between the two partitions. The algorithm can be used to test + /// the network reliability, especially to test how many links have + /// to be destroyed in the network to split it to at least two + /// distinict subnetworks. + /// + /// The complexity of the algorithm is \f$ O(nm\log(n)) \f$ but with + /// \ref FibHeap "Fibonacci heap" it can be decreased to + /// \f$ O(nm+n^2\log(n)) \f$. When the edges have unit capacities, + /// \c BucketHeap can be used which yields \f$ O(nm) \f$ time + /// complexity. + /// + /// \warning The value type of the capacity map should be able to + /// hold any cut value of the graph, otherwise the result can + /// overflow. + /// \note This capacity is supposed to be integer type. +#ifdef DOXYGEN + template +#else + template , + typename TR = NagamochiIbarakiDefaultTraits > +#endif + class NagamochiIbaraki { + public: + + typedef TR Traits; + /// The type of the underlying graph. + typedef typename Traits::Graph Graph; + + /// The type of the capacity map. + typedef typename Traits::CapacityMap CapacityMap; + /// The value type of the capacity map. + typedef typename Traits::CapacityMap::Value Value; + + /// The heap type used by the algorithm. + typedef typename Traits::Heap Heap; + /// The cross reference type used for the heap. + typedef typename Traits::HeapCrossRef HeapCrossRef; + + ///\name Named template parameters + + ///@{ + + struct SetUnitCapacityTraits : public Traits { + typedef ConstMap > CapacityMap; + static CapacityMap *createCapacityMap(const Graph&) { + return new CapacityMap(); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// the capacity map to a constMap() instance + /// + /// \ref named-templ-param "Named parameter" for setting + /// the capacity map to a constMap() instance + struct SetUnitCapacity + : public NagamochiIbaraki { + typedef NagamochiIbaraki Create; + }; + + + template + struct SetHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(int num) { + LEMON_ASSERT(false, "HeapCrossRef is not initialized"); + return 0; // ignore warnings + } + static Heap *createHeap(HeapCrossRef &) { + LEMON_ASSERT(false, "Heap is not initialized"); + return 0; // ignore warnings + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// heap and cross reference type + /// + /// \ref named-templ-param "Named parameter" for setting heap and + /// cross reference type. The heap has to maximize the priorities. + template > + struct SetHeap + : public NagamochiIbaraki > { + typedef NagamochiIbaraki< Graph, CapacityMap, SetHeapTraits > + Create; + }; + + template + struct SetStandardHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(int size) { + return new HeapCrossRef(size); + } + static Heap *createHeap(HeapCrossRef &crossref) { + return new Heap(crossref); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting + /// heap and cross reference type with automatic allocation + /// + /// \ref named-templ-param "Named parameter" for setting heap and + /// cross reference type with automatic allocation. They should + /// have standard constructor interfaces to be able to + /// automatically created by the algorithm (i.e. the graph 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 passed to the algorithm using the \ref heap() + /// function before calling \ref run() or \ref init(). The heap + /// has to maximize the priorities. + /// \sa SetHeap + template > + struct SetStandardHeap + : public NagamochiIbaraki > { + typedef NagamochiIbaraki > Create; + }; + + ///@} + + + private: + + const Graph &_graph; + const CapacityMap *_capacity; + bool _local_capacity; // unit capacity + + struct ArcData { + typename Graph::Node target; + int prev, next; + }; + struct EdgeData { + Value capacity; + Value cut; + }; + + struct NodeData { + int first_arc; + typename Graph::Node prev, next; + int curr_arc; + typename Graph::Node last_rep; + Value sum; + }; + + typename Graph::template NodeMap *_nodes; + std::vector _arcs; + std::vector _edges; + + typename Graph::Node _first_node; + int _node_num; + + Value _min_cut; + + HeapCrossRef *_heap_cross_ref; + bool _local_heap_cross_ref; + Heap *_heap; + bool _local_heap; + + typedef typename Graph::template NodeMap NodeList; + NodeList *_next_rep; + + typedef typename Graph::template NodeMap MinCutMap; + MinCutMap *_cut_map; + + void createStructures() { + if (!_nodes) { + _nodes = new (typename Graph::template NodeMap)(_graph); + } + if (!_capacity) { + _local_capacity = true; + _capacity = Traits::createCapacityMap(_graph); + } + if (!_heap_cross_ref) { + _local_heap_cross_ref = true; + _heap_cross_ref = Traits::createHeapCrossRef(_graph); + } + if (!_heap) { + _local_heap = true; + _heap = Traits::createHeap(*_heap_cross_ref); + } + if (!_next_rep) { + _next_rep = new NodeList(_graph); + } + if (!_cut_map) { + _cut_map = new MinCutMap(_graph); + } + } + + protected: + //This is here to avoid a gcc-3.3 compilation error. + //It should never be called. + NagamochiIbaraki() {} + + public: + + typedef NagamochiIbaraki Create; + + + /// \brief Constructor. + /// + /// \param graph The graph the algorithm runs on. + /// \param capacity The capacity map used by the algorithm. + NagamochiIbaraki(const Graph& graph, const CapacityMap& capacity) + : _graph(graph), _capacity(&capacity), _local_capacity(false), + _nodes(0), _arcs(), _edges(), _min_cut(), + _heap_cross_ref(0), _local_heap_cross_ref(false), + _heap(0), _local_heap(false), + _next_rep(0), _cut_map(0) {} + + /// \brief Constructor. + /// + /// This constructor can be used only when the Traits class + /// defines how can the local capacity map be instantiated. + /// If the SetUnitCapacity used the algorithm automatically + /// constructs the capacity map. + /// + ///\param graph The graph the algorithm runs on. + NagamochiIbaraki(const Graph& graph) + : _graph(graph), _capacity(0), _local_capacity(false), + _nodes(0), _arcs(), _edges(), _min_cut(), + _heap_cross_ref(0), _local_heap_cross_ref(false), + _heap(0), _local_heap(false), + _next_rep(0), _cut_map(0) {} + + /// \brief Destructor. + /// + /// Destructor. + ~NagamochiIbaraki() { + if (_local_capacity) delete _capacity; + if (_nodes) delete _nodes; + if (_local_heap) delete _heap; + if (_local_heap_cross_ref) delete _heap_cross_ref; + if (_next_rep) delete _next_rep; + if (_cut_map) delete _cut_map; + } + + /// \brief Sets the heap and the cross reference used by algorithm. + /// + /// Sets the heap and the cross reference used by algorithm. + /// If you don't use this function before calling \ref run(), + /// it will allocate one. The destuctor deallocates this + /// automatically allocated heap and cross reference, of course. + /// \return (*this) + NagamochiIbaraki &heap(Heap& hp, HeapCrossRef &cr) + { + if (_local_heap_cross_ref) { + delete _heap_cross_ref; + _local_heap_cross_ref = false; + } + _heap_cross_ref = &cr; + if (_local_heap) { + delete _heap; + _local_heap = false; + } + _heap = &hp; + return *this; + } + + /// \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 call the start() + /// or proper times the processNextPhase() member functions. + + ///@{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures. + void init() { + createStructures(); + + int edge_num = countEdges(_graph); + _edges.resize(edge_num); + _arcs.resize(2 * edge_num); + + typename Graph::Node prev = INVALID; + _node_num = 0; + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + (*_cut_map)[n] = false; + (*_next_rep)[n] = INVALID; + (*_nodes)[n].last_rep = n; + (*_nodes)[n].first_arc = -1; + (*_nodes)[n].curr_arc = -1; + (*_nodes)[n].prev = prev; + if (prev != INVALID) { + (*_nodes)[prev].next = n; + } + (*_nodes)[n].next = INVALID; + (*_nodes)[n].sum = 0; + prev = n; + ++_node_num; + } + + _first_node = typename Graph::NodeIt(_graph); + + int index = 0; + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + for (typename Graph::OutArcIt a(_graph, n); a != INVALID; ++a) { + typename Graph::Node m = _graph.target(a); + + if (!(n < m)) continue; + + (*_nodes)[n].sum += (*_capacity)[a]; + (*_nodes)[m].sum += (*_capacity)[a]; + + int c = (*_nodes)[m].curr_arc; + if (c != -1 && _arcs[c ^ 1].target == n) { + _edges[c >> 1].capacity += (*_capacity)[a]; + } else { + _edges[index].capacity = (*_capacity)[a]; + + _arcs[index << 1].prev = -1; + if ((*_nodes)[n].first_arc != -1) { + _arcs[(*_nodes)[n].first_arc].prev = (index << 1); + } + _arcs[index << 1].next = (*_nodes)[n].first_arc; + (*_nodes)[n].first_arc = (index << 1); + _arcs[index << 1].target = m; + + (*_nodes)[m].curr_arc = (index << 1); + + _arcs[(index << 1) | 1].prev = -1; + if ((*_nodes)[m].first_arc != -1) { + _arcs[(*_nodes)[m].first_arc].prev = ((index << 1) | 1); + } + _arcs[(index << 1) | 1].next = (*_nodes)[m].first_arc; + (*_nodes)[m].first_arc = ((index << 1) | 1); + _arcs[(index << 1) | 1].target = n; + + ++index; + } + } + } + + typename Graph::Node cut_node = INVALID; + _min_cut = std::numeric_limits::max(); + + for (typename Graph::Node n = _first_node; + n != INVALID; n = (*_nodes)[n].next) { + if ((*_nodes)[n].sum < _min_cut) { + cut_node = n; + _min_cut = (*_nodes)[n].sum; + } + } + (*_cut_map)[cut_node] = true; + if (_min_cut == 0) { + _first_node = INVALID; + } + } + + public: + + /// \brief Processes the next phase + /// + /// Processes the next phase in the algorithm. It must be called + /// at most one less the number of the nodes in the graph. + /// + ///\return %True when the algorithm finished. + bool processNextPhase() { + if (_first_node == INVALID) return true; + + _heap->clear(); + for (typename Graph::Node n = _first_node; + n != INVALID; n = (*_nodes)[n].next) { + (*_heap_cross_ref)[n] = Heap::PRE_HEAP; + } + + std::vector order; + order.reserve(_node_num); + int sep = 0; + + Value alpha = 0; + Value pmc = std::numeric_limits::max(); + + _heap->push(_first_node, static_cast(0)); + while (!_heap->empty()) { + typename Graph::Node n = _heap->top(); + Value v = _heap->prio(); + + _heap->pop(); + for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) { + switch (_heap->state(_arcs[a].target)) { + case Heap::PRE_HEAP: + { + Value nv = _edges[a >> 1].capacity; + _heap->push(_arcs[a].target, nv); + _edges[a >> 1].cut = nv; + } break; + case Heap::IN_HEAP: + { + Value nv = _edges[a >> 1].capacity + (*_heap)[_arcs[a].target]; + _heap->decrease(_arcs[a].target, nv); + _edges[a >> 1].cut = nv; + } break; + case Heap::POST_HEAP: + break; + } + } + + alpha += (*_nodes)[n].sum; + alpha -= 2 * v; + + order.push_back(n); + if (!_heap->empty()) { + if (alpha < pmc) { + pmc = alpha; + sep = order.size(); + } + } + } + + if (static_cast(order.size()) < _node_num) { + _first_node = INVALID; + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + (*_cut_map)[n] = false; + } + for (int i = 0; i < static_cast(order.size()); ++i) { + typename Graph::Node n = order[i]; + while (n != INVALID) { + (*_cut_map)[n] = true; + n = (*_next_rep)[n]; + } + } + _min_cut = 0; + return true; + } + + if (pmc < _min_cut) { + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + (*_cut_map)[n] = false; + } + for (int i = 0; i < sep; ++i) { + typename Graph::Node n = order[i]; + while (n != INVALID) { + (*_cut_map)[n] = true; + n = (*_next_rep)[n]; + } + } + _min_cut = pmc; + } + + for (typename Graph::Node n = _first_node; + n != INVALID; n = (*_nodes)[n].next) { + bool merged = false; + for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) { + if (!(_edges[a >> 1].cut < pmc)) { + if (!merged) { + for (int b = (*_nodes)[n].first_arc; b != -1; b = _arcs[b].next) { + (*_nodes)[_arcs[b].target].curr_arc = b; + } + merged = true; + } + typename Graph::Node m = _arcs[a].target; + int nb = 0; + for (int b = (*_nodes)[m].first_arc; b != -1; b = nb) { + nb = _arcs[b].next; + if ((b ^ a) == 1) continue; + typename Graph::Node o = _arcs[b].target; + int c = (*_nodes)[o].curr_arc; + if (c != -1 && _arcs[c ^ 1].target == n) { + _edges[c >> 1].capacity += _edges[b >> 1].capacity; + (*_nodes)[n].sum += _edges[b >> 1].capacity; + if (_edges[b >> 1].cut < _edges[c >> 1].cut) { + _edges[b >> 1].cut = _edges[c >> 1].cut; + } + if (_arcs[b ^ 1].prev != -1) { + _arcs[_arcs[b ^ 1].prev].next = _arcs[b ^ 1].next; + } else { + (*_nodes)[o].first_arc = _arcs[b ^ 1].next; + } + if (_arcs[b ^ 1].next != -1) { + _arcs[_arcs[b ^ 1].next].prev = _arcs[b ^ 1].prev; + } + } else { + if (_arcs[a].next != -1) { + _arcs[_arcs[a].next].prev = b; + } + _arcs[b].next = _arcs[a].next; + _arcs[b].prev = a; + _arcs[a].next = b; + _arcs[b ^ 1].target = n; + + (*_nodes)[n].sum += _edges[b >> 1].capacity; + (*_nodes)[o].curr_arc = b; + } + } + + if (_arcs[a].prev != -1) { + _arcs[_arcs[a].prev].next = _arcs[a].next; + } else { + (*_nodes)[n].first_arc = _arcs[a].next; + } + if (_arcs[a].next != -1) { + _arcs[_arcs[a].next].prev = _arcs[a].prev; + } + + (*_nodes)[n].sum -= _edges[a >> 1].capacity; + (*_next_rep)[(*_nodes)[n].last_rep] = m; + (*_nodes)[n].last_rep = (*_nodes)[m].last_rep; + + if ((*_nodes)[m].prev != INVALID) { + (*_nodes)[(*_nodes)[m].prev].next = (*_nodes)[m].next; + } else{ + _first_node = (*_nodes)[m].next; + } + if ((*_nodes)[m].next != INVALID) { + (*_nodes)[(*_nodes)[m].next].prev = (*_nodes)[m].prev; + } + --_node_num; + } + } + } + + if (_node_num == 1) { + _first_node = INVALID; + return true; + } + + return false; + } + + /// \brief Executes the algorithm. + /// + /// Executes the algorithm. + /// + /// \pre init() must be called + void start() { + while (!processNextPhase()) {} + } + + + /// \brief Runs %NagamochiIbaraki algorithm. + /// + /// This method runs the %Min cut algorithm + /// + /// \note mc.run(s) is just a shortcut of the following code. + ///\code + /// mc.init(); + /// mc.start(); + ///\endcode + void run() { + init(); + start(); + } + + ///@} + + /// \name Query Functions + /// + /// The result of the %NagamochiIbaraki + /// algorithm can be obtained using these functions.\n + /// Before the use of these functions, either run() or start() + /// must be called. + + ///@{ + + /// \brief Returns the min cut value. + /// + /// Returns the min cut value if the algorithm finished. + /// After the first processNextPhase() it is a value of a + /// valid cut in the graph. + Value minCutValue() const { + return _min_cut; + } + + /// \brief Returns a min cut in a NodeMap. + /// + /// It sets the nodes of one of the two partitions to true and + /// the other partition to false. + /// \param cutMap A \ref concepts::WriteMap "writable" node map with + /// \c bool (or convertible) value type. + template + Value minCutMap(CutMap& cutMap) const { + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + cutMap.set(n, (*_cut_map)[n]); + } + return minCutValue(); + } + + ///@} + + }; +} + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/nearest_neighbor_tsp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/nearest_neighbor_tsp.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,238 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_NEAREST_NEIGHBOUR_TSP_H +#define LEMON_NEAREST_NEIGHBOUR_TSP_H + +/// \ingroup tsp +/// \file +/// \brief Nearest neighbor algorithm for symmetric TSP + +#include +#include +#include +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief Nearest neighbor algorithm for symmetric TSP. + /// + /// NearestNeighborTsp implements the nearest neighbor heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This is probably the simplest TSP heuristic. + /// It starts with a minimum cost edge and at each step, it connects the + /// nearest unvisited node to the current path. + /// Finally, it connects the two end points of the path to form a tour. + /// + /// This method runs in O(n2) time. + /// It quickly finds a relatively short tour for most TSP instances, + /// but it could also yield a really bad (or even the worst) solution + /// in special cases. + /// + /// \tparam CM Type of the cost map. + template + class NearestNeighborTsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + Cost _sum; + std::vector _path; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + NearestNeighborTsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm. + /// + /// This function runs the algorithm. + /// + /// \return The total cost of the found tour. + Cost run() { + _path.clear(); + if (_gr.nodeNum() == 0) { + return _sum = 0; + } + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + + std::deque path_dq; + Edge min_edge1 = INVALID, + min_edge2 = INVALID; + + min_edge1 = mapMin(_gr, _cost); + Node n1 = _gr.u(min_edge1), + n2 = _gr.v(min_edge1); + path_dq.push_back(n1); + path_dq.push_back(n2); + + FullGraph::NodeMap used(_gr, false); + used[n1] = true; + used[n2] = true; + + min_edge1 = INVALID; + while (int(path_dq.size()) != _gr.nodeNum()) { + if (min_edge1 == INVALID) { + for (IncEdgeIt e(_gr, n1); e != INVALID; ++e) { + if (!used[_gr.runningNode(e)] && + (min_edge1 == INVALID || _cost[e] < _cost[min_edge1])) { + min_edge1 = e; + } + } + } + + if (min_edge2 == INVALID) { + for (IncEdgeIt e(_gr, n2); e != INVALID; ++e) { + if (!used[_gr.runningNode(e)] && + (min_edge2 == INVALID||_cost[e] < _cost[min_edge2])) { + min_edge2 = e; + } + } + } + + if (_cost[min_edge1] < _cost[min_edge2]) { + n1 = _gr.oppositeNode(n1, min_edge1); + path_dq.push_front(n1); + + used[n1] = true; + min_edge1 = INVALID; + + if (_gr.u(min_edge2) == n1 || _gr.v(min_edge2) == n1) + min_edge2 = INVALID; + } else { + n2 = _gr.oppositeNode(n2, min_edge2); + path_dq.push_back(n2); + + used[n2] = true; + min_edge2 = INVALID; + + if (_gr.u(min_edge1) == n2 || _gr.v(min_edge1) == n2) + min_edge1 = INVALID; + } + } + + n1 = path_dq.back(); + n2 = path_dq.front(); + _path.push_back(n2); + _sum = _cost[_gr.edge(n1, n2)]; + for (int i = 1; i < int(path_dq.size()); ++i) { + n1 = n2; + n2 = path_dq[i]; + _path.push_back(n2); + _sum += _cost[_gr.edge(n1, n2)]; + } + + return _sum; + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _path; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_path.begin(), _path.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_path.size()) - 1; ++i) { + path.addBack(_gr.arc(_path[i], _path[i+1])); + } + if (int(_path.size()) >= 2) { + path.addBack(_gr.arc(_path.back(), _path.front())); + } + } + + /// @} + + }; + +}; // namespace lemon + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/network_simplex.h --- a/lemon/network_simplex.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/network_simplex.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -41,16 +41,17 @@ /// /// \ref NetworkSimplex implements the primal Network Simplex algorithm /// for finding a \ref min_cost_flow "minimum cost flow" - /// \ref amo93networkflows, \ref dantzig63linearprog, - /// \ref kellyoneill91netsimplex. + /// \cite amo93networkflows, \cite dantzig63linearprog, + /// \cite kellyoneill91netsimplex. /// This algorithm is a highly efficient specialized version of the /// linear programming simplex method directly for the minimum cost /// flow problem. /// - /// 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. + /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest + /// implementations available in LEMON for solving this problem. + /// (For more information, see \ref min_cost_flow_algs "the module page".) + /// Furthermore, this class 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 @@ -63,7 +64,8 @@ /// \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 + /// \warning Both \c V and \c C must be signed number types. + /// \warning All input data (capacities, supply values, and costs) must /// be integer. /// /// \note %NetworkSimplex provides five different pivot rule @@ -121,14 +123,17 @@ /// Enum type containing constants for selecting the pivot rule for /// the \ref run() function. /// - /// \ref NetworkSimplex provides five different pivot rule - /// implementations that significantly affect the running time + /// \ref NetworkSimplex provides five different implementations for + /// the pivot strategy that significantly affects the running time /// of the algorithm. - /// By default, \ref BLOCK_SEARCH "Block Search" is used, which - /// proved to be the most efficient and the most robust on various - /// test inputs. - /// However, another pivot rule can be selected using the \ref run() - /// function with the proper parameter. + /// According to experimental tests conducted on various problem + /// instances, \ref BLOCK_SEARCH "Block Search" and + /// \ref ALTERING_LIST "Altering Candidate List" rules turned out + /// to be the most efficient. + /// Since \ref BLOCK_SEARCH "Block Search" is a simpler strategy that + /// seemed to be slightly more robust, it is used by default. + /// However, another pivot rule can easily be selected using the + /// \ref run() function with the proper parameter. enum PivotRule { /// The \e First \e Eligible pivot rule. @@ -154,7 +159,7 @@ /// 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 + /// It keeps only a few of the best eligible arcs from the former /// candidate list and extends this list in every iteration. ALTERING_LIST }; @@ -166,8 +171,9 @@ 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 + typedef std::vector CharVector; + // Note: vector is used instead of vector and + // vector for efficiency reasons // State constants for arcs enum ArcState { @@ -176,9 +182,11 @@ STATE_LOWER = 1 }; - typedef std::vector StateVector; - // Note: vector is used instead of vector for - // efficiency reasons + // Direction constants for tree arcs + enum ArcDirection { + DIR_DOWN = -1, + DIR_UP = 1 + }; private: @@ -190,7 +198,7 @@ int _search_arc_num; // Parameters of the problem - bool _have_lower; + bool _has_lower; SupplyType _stype; Value _sum_supply; @@ -217,15 +225,13 @@ IntVector _rev_thread; IntVector _succ_num; IntVector _last_succ; + CharVector _pred_dir; + CharVector _state; IntVector _dirty_revs; - BoolVector _forward; - StateVector _state; int _root; // Temporary data used in the current pivot iteration int in_arc, join, u_in, v_in, u_out, v_out; - int first, second, right, last; - int stem, par_stem, new_stem; Value delta; const Value MAX; @@ -250,7 +256,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const StateVector &_state; + const CharVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -302,7 +308,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const StateVector &_state; + const CharVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -341,7 +347,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const StateVector &_state; + const CharVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -414,7 +420,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const StateVector &_state; + const CharVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -517,7 +523,7 @@ const IntVector &_source; const IntVector &_target; const CostVector &_cost; - const StateVector &_state; + const CharVector &_state; const CostVector &_pi; int &_in_arc; int _search_arc_num; @@ -536,7 +542,7 @@ public: SortFunc(const CostVector &map) : _map(map) {} bool operator()(int left, int right) { - return _map[left] > _map[right]; + return _map[left] < _map[right]; } }; @@ -554,7 +560,7 @@ // The main parameters of the pivot rule const double BLOCK_SIZE_FACTOR = 1.0; const int MIN_BLOCK_SIZE = 10; - const double HEAD_LENGTH_FACTOR = 0.1; + const double HEAD_LENGTH_FACTOR = 0.01; const int MIN_HEAD_LENGTH = 3; _block_size = std::max( int(BLOCK_SIZE_FACTOR * @@ -570,11 +576,13 @@ bool findEnteringArc() { // Check the current candidate list int e; + Cost c; for (int i = 0; i != _curr_length; ++i) { e = _candidates[i]; - _cand_cost[e] = _state[e] * - (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (_cand_cost[e] >= 0) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _cand_cost[e] = c; + } else { _candidates[i--] = _candidates[--_curr_length]; } } @@ -584,9 +592,9 @@ int limit = _head_length; 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) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _cand_cost[e] = c; _candidates[_curr_length++] = e; } if (--cnt == 0) { @@ -596,9 +604,9 @@ } } 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) { + c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); + if (c < 0) { + _cand_cost[e] = c; _candidates[_curr_length++] = e; } if (--cnt == 0) { @@ -611,16 +619,16 @@ search_end: - // Make heap of the candidate list (approximating a partial sort) - make_heap( _candidates.begin(), _candidates.begin() + _curr_length, - _sort_func ); + // Perform partial sort operation on the candidate list + int new_length = std::min(_head_length + 1, _curr_length); + std::partial_sort(_candidates.begin(), _candidates.begin() + new_length, + _candidates.begin() + _curr_length, _sort_func); - // Pop the first element of the heap + // Select the entering arc and remove it from the list _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); + _candidates[0] = _candidates[new_length - 1]; + _curr_length = new_length - 1; return true; } @@ -633,11 +641,12 @@ /// The constructor of the class. /// /// \param graph The digraph the algorithm runs on. - /// \param arc_mixing Indicate if the arcs have to be stored in a + /// \param arc_mixing Indicate if the arcs will 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) : + /// In general, it leads to similar performance as using the original + /// arc order, but it makes the algorithm more robust and in special + /// cases, even significantly faster. Therefore, it is enabled by default. + NetworkSimplex(const GR& graph, bool arc_mixing = true) : _graph(graph), _node_id(graph), _arc_id(graph), _arc_mixing(arc_mixing), MAX(std::numeric_limits::max()), @@ -673,7 +682,7 @@ /// \return (*this) template NetworkSimplex& lowerMap(const LowerMap& map) { - _have_lower = true; + _has_lower = true; for (ArcIt a(_graph); a != INVALID; ++a) { _lower[_arc_id[a]] = map[a]; } @@ -730,6 +739,8 @@ /// of the algorithm. /// /// \return (*this) + /// + /// \sa supplyType() template NetworkSimplex& supplyMap(const SupplyMap& map) { for (NodeIt n(_graph); n != INVALID; ++n) { @@ -746,7 +757,7 @@ /// 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 + /// with 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. @@ -868,7 +879,7 @@ _upper[i] = INF; _cost[i] = 1; } - _have_lower = false; + _has_lower = false; _stype = GEQ; return *this; } @@ -913,7 +924,7 @@ _parent.resize(all_node_num); _pred.resize(all_node_num); - _forward.resize(all_node_num); + _pred_dir.resize(all_node_num); _thread.resize(all_node_num); _rev_thread.resize(all_node_num); _succ_num.resize(all_node_num); @@ -925,15 +936,15 @@ for (NodeIt n(_graph); n != INVALID; ++n, ++i) { _node_id[n] = i; } - if (_arc_mixing) { + if (_arc_mixing && _node_num > 1) { // Store the arcs in a mixed order - int k = std::max(int(std::sqrt(double(_arc_num))), 10); + const int skip = std::max(_arc_num / _node_num, 3); 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; + if ((i += skip) >= _arc_num) i = ++j; } } else { // Store the arcs in the original order @@ -962,7 +973,7 @@ /// \brief Return the total cost of the found flow. /// /// This function returns the total cost of the found flow. - /// Its complexity is O(e). + /// Its complexity is O(m). /// /// \note The return type of the function can be specified as a /// template parameter. For example, @@ -999,7 +1010,8 @@ return _flow[_arc_id[a]]; } - /// \brief Return the flow map (the primal solution). + /// \brief Copy the flow values (the primal solution) into the + /// given map. /// /// This function copies the flow value on each arc into the given /// map. The \c Value type of the algorithm must be convertible to @@ -1023,7 +1035,8 @@ return _pi[_node_id[n]]; } - /// \brief Return the potential map (the dual solution). + /// \brief Copy the potential values (the dual solution) into the + /// given map. /// /// This function copies the potential (dual value) of each node /// into the given map. @@ -1054,8 +1067,12 @@ if ( !((_stype == GEQ && _sum_supply <= 0) || (_stype == LEQ && _sum_supply >= 0)) ) return false; + // Check lower and upper bounds + LEMON_DEBUG(checkBoundMaps(), + "Upper bounds must be greater or equal to the lower bounds"); + // Remove non-zero lower bounds - if (_have_lower) { + if (_has_lower) { for (int i = 0; i != _arc_num; ++i) { Value c = _lower[i]; if (c >= 0) { @@ -1116,14 +1133,14 @@ _cap[e] = INF; _state[e] = STATE_TREE; if (_supply[u] >= 0) { - _forward[u] = true; + _pred_dir[u] = DIR_UP; _pi[u] = 0; _source[e] = u; _target[e] = _root; _flow[e] = _supply[u]; _cost[e] = 0; } else { - _forward[u] = false; + _pred_dir[u] = DIR_DOWN; _pi[u] = ART_COST; _source[e] = _root; _target[e] = u; @@ -1143,7 +1160,7 @@ _succ_num[u] = 1; _last_succ[u] = u; if (_supply[u] >= 0) { - _forward[u] = true; + _pred_dir[u] = DIR_UP; _pi[u] = 0; _pred[u] = e; _source[e] = u; @@ -1153,7 +1170,7 @@ _cost[e] = 0; _state[e] = STATE_TREE; } else { - _forward[u] = false; + _pred_dir[u] = DIR_DOWN; _pi[u] = ART_COST; _pred[u] = f; _source[f] = _root; @@ -1184,7 +1201,7 @@ _succ_num[u] = 1; _last_succ[u] = u; if (_supply[u] <= 0) { - _forward[u] = false; + _pred_dir[u] = DIR_DOWN; _pi[u] = 0; _pred[u] = e; _source[e] = _root; @@ -1194,7 +1211,7 @@ _cost[e] = 0; _state[e] = STATE_TREE; } else { - _forward[u] = true; + _pred_dir[u] = DIR_UP; _pi[u] = -ART_COST; _pred[u] = f; _source[f] = u; @@ -1218,6 +1235,15 @@ return true; } + // Check if the upper bound is greater than or equal to the lower bound + // on each arc. + bool checkBoundMaps() { + for (int j = 0; j != _arc_num; ++j) { + if (_upper[j] < _lower[j]) return false; + } + return true; + } + // Find the join node void findJoinNode() { int u = _source[in_arc]; @@ -1237,6 +1263,7 @@ bool findLeavingArc() { // Initialize first and second nodes according to the direction // of the cycle + int first, second; if (_state[in_arc] == STATE_LOWER) { first = _source[in_arc]; second = _target[in_arc]; @@ -1246,25 +1273,32 @@ } delta = _cap[in_arc]; int result = 0; - Value d; + Value c, d; int e; - // Search the cycle along the path form the first node to the root + // Search the cycle form the first node to the join node for (int u = first; u != join; u = _parent[u]) { e = _pred[u]; - d = _forward[u] ? - _flow[e] : (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]); + d = _flow[e]; + if (_pred_dir[u] == DIR_DOWN) { + c = _cap[e]; + d = c >= MAX ? INF : c - d; + } if (d < delta) { delta = d; u_out = u; result = 1; } } - // Search the cycle along the path form the second node to the root + + // Search the cycle form the second node to the join node for (int u = second; u != join; u = _parent[u]) { e = _pred[u]; - d = _forward[u] ? - (_cap[e] >= MAX ? INF : _cap[e] - _flow[e]) : _flow[e]; + d = _flow[e]; + if (_pred_dir[u] == DIR_UP) { + c = _cap[e]; + d = c >= MAX ? INF : c - d; + } if (d <= delta) { delta = d; u_out = u; @@ -1289,10 +1323,10 @@ Value val = _state[in_arc] * delta; _flow[in_arc] += val; for (int u = _source[in_arc]; u != join; u = _parent[u]) { - _flow[_pred[u]] += _forward[u] ? -val : val; + _flow[_pred[u]] -= _pred_dir[u] * val; } for (int u = _target[in_arc]; u != join; u = _parent[u]) { - _flow[_pred[u]] += _forward[u] ? val : -val; + _flow[_pred[u]] += _pred_dir[u] * val; } } // Update the state of the entering and leaving arcs @@ -1307,130 +1341,134 @@ // Update the tree structure void updateTreeStructure() { - int u, w; int old_rev_thread = _rev_thread[u_out]; int old_succ_num = _succ_num[u_out]; int old_last_succ = _last_succ[u_out]; v_out = _parent[u_out]; - u = _last_succ[u_in]; // the last successor of u_in - right = _thread[u]; // the node after it + // Check if u_in and u_out coincide + if (u_in == u_out) { + // Update _parent, _pred, _pred_dir + _parent[u_in] = v_in; + _pred[u_in] = in_arc; + _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; - // Handle the case when old_rev_thread equals to v_in - // (it also means that join and v_out coincide) - if (old_rev_thread == v_in) { - last = _thread[_last_succ[u_out]]; + // Update _thread and _rev_thread + if (_thread[v_in] != u_out) { + int after = _thread[old_last_succ]; + _thread[old_rev_thread] = after; + _rev_thread[after] = old_rev_thread; + after = _thread[v_in]; + _thread[v_in] = u_out; + _rev_thread[u_out] = v_in; + _thread[old_last_succ] = after; + _rev_thread[after] = old_last_succ; + } } else { - last = _thread[v_in]; - } + // Handle the case when old_rev_thread equals to v_in + // (it also means that join and v_out coincide) + int thread_continue = old_rev_thread == v_in ? + _thread[old_last_succ] : _thread[v_in]; - // Update _thread and _parent along the stem nodes (i.e. the nodes - // between u_in and u_out, whose parent have to be changed) - _thread[v_in] = stem = u_in; - _dirty_revs.clear(); - _dirty_revs.push_back(v_in); - par_stem = v_in; - while (stem != u_out) { - // Insert the next stem node into the thread list - new_stem = _parent[stem]; - _thread[u] = new_stem; - _dirty_revs.push_back(u); + // Update _thread and _parent along the stem nodes (i.e. the nodes + // between u_in and u_out, whose parent have to be changed) + int stem = u_in; // the current stem node + int par_stem = v_in; // the new parent of stem + int next_stem; // the next stem node + int last = _last_succ[u_in]; // the last successor of stem + int before, after = _thread[last]; + _thread[v_in] = u_in; + _dirty_revs.clear(); + _dirty_revs.push_back(v_in); + while (stem != u_out) { + // Insert the next stem node into the thread list + next_stem = _parent[stem]; + _thread[last] = next_stem; + _dirty_revs.push_back(last); - // Remove the subtree of stem from the thread list - w = _rev_thread[stem]; - _thread[w] = right; - _rev_thread[right] = w; + // Remove the subtree of stem from the thread list + before = _rev_thread[stem]; + _thread[before] = after; + _rev_thread[after] = before; - // Change the parent node and shift stem nodes - _parent[stem] = par_stem; - par_stem = stem; - stem = new_stem; + // Change the parent node and shift stem nodes + _parent[stem] = par_stem; + par_stem = stem; + stem = next_stem; - // Update u and right - u = _last_succ[stem] == _last_succ[par_stem] ? - _rev_thread[par_stem] : _last_succ[stem]; - right = _thread[u]; - } - _parent[u_out] = par_stem; - _thread[u] = last; - _rev_thread[last] = u; - _last_succ[u_out] = u; + // Update last and after + last = _last_succ[stem] == _last_succ[par_stem] ? + _rev_thread[par_stem] : _last_succ[stem]; + after = _thread[last]; + } + _parent[u_out] = par_stem; + _thread[last] = thread_continue; + _rev_thread[thread_continue] = last; + _last_succ[u_out] = last; - // Remove the subtree of u_out from the thread list except for - // the case when old_rev_thread equals to v_in - // (it also means that join and v_out coincide) - if (old_rev_thread != v_in) { - _thread[old_rev_thread] = right; - _rev_thread[right] = old_rev_thread; - } + // Remove the subtree of u_out from the thread list except for + // the case when old_rev_thread equals to v_in + if (old_rev_thread != v_in) { + _thread[old_rev_thread] = after; + _rev_thread[after] = old_rev_thread; + } - // Update _rev_thread using the new _thread values - for (int i = 0; i != int(_dirty_revs.size()); ++i) { - u = _dirty_revs[i]; - _rev_thread[_thread[u]] = u; - } + // Update _rev_thread using the new _thread values + for (int i = 0; i != int(_dirty_revs.size()); ++i) { + int u = _dirty_revs[i]; + _rev_thread[_thread[u]] = u; + } - // Update _pred, _forward, _last_succ and _succ_num for the - // stem nodes from u_out to u_in - int tmp_sc = 0, tmp_ls = _last_succ[u_out]; - u = u_out; - while (u != u_in) { - w = _parent[u]; - _pred[u] = _pred[w]; - _forward[u] = !_forward[w]; - tmp_sc += _succ_num[u] - _succ_num[w]; - _succ_num[u] = tmp_sc; - _last_succ[w] = tmp_ls; - u = w; - } - _pred[u_in] = in_arc; - _forward[u_in] = (u_in == _source[in_arc]); - _succ_num[u_in] = old_succ_num; - - // Set limits for updating _last_succ form v_in and v_out - // towards the root - int up_limit_in = -1; - int up_limit_out = -1; - if (_last_succ[join] == v_in) { - up_limit_out = join; - } else { - up_limit_in = join; + // Update _pred, _pred_dir, _last_succ and _succ_num for the + // stem nodes from u_out to u_in + int tmp_sc = 0, tmp_ls = _last_succ[u_out]; + for (int u = u_out, p = _parent[u]; u != u_in; u = p, p = _parent[u]) { + _pred[u] = _pred[p]; + _pred_dir[u] = -_pred_dir[p]; + tmp_sc += _succ_num[u] - _succ_num[p]; + _succ_num[u] = tmp_sc; + _last_succ[p] = tmp_ls; + } + _pred[u_in] = in_arc; + _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; + _succ_num[u_in] = old_succ_num; } // Update _last_succ from v_in towards the root - for (u = v_in; u != up_limit_in && _last_succ[u] == v_in; - u = _parent[u]) { - _last_succ[u] = _last_succ[u_out]; + int up_limit_out = _last_succ[join] == v_in ? join : -1; + int last_succ_out = _last_succ[u_out]; + for (int u = v_in; u != -1 && _last_succ[u] == v_in; u = _parent[u]) { + _last_succ[u] = last_succ_out; } + // Update _last_succ from v_out towards the root if (join != old_rev_thread && v_in != old_rev_thread) { - for (u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; + for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; u = _parent[u]) { _last_succ[u] = old_rev_thread; } - } else { - for (u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; + } + else if (last_succ_out != old_last_succ) { + for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; u = _parent[u]) { - _last_succ[u] = _last_succ[u_out]; + _last_succ[u] = last_succ_out; } } // Update _succ_num from v_in to join - for (u = v_in; u != join; u = _parent[u]) { + for (int u = v_in; u != join; u = _parent[u]) { _succ_num[u] += old_succ_num; } // Update _succ_num from v_out to join - for (u = v_out; u != join; u = _parent[u]) { + for (int u = v_out; u != join; u = _parent[u]) { _succ_num[u] -= old_succ_num; } } - // Update potentials + // Update potentials in the subtree that has been moved void updatePotential() { - Cost sigma = _forward[u_in] ? - _pi[v_in] - _pi[u_in] - _cost[_pred[u_in]] : - _pi[v_in] - _pi[u_in] + _cost[_pred[u_in]]; - // Update potentials in the subtree, which has been moved + Cost sigma = _pi[v_in] - _pi[u_in] - + _pred_dir[u_in] * _cost[in_arc]; int end = _thread[_last_succ[u_in]]; for (int u = u_in; u != end; u = _thread[u]) { _pi[u] += sigma; @@ -1478,7 +1516,7 @@ } } } else { - // Find the min. cost incomming arc for each demand node + // Find the min. cost incoming 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(); @@ -1574,7 +1612,7 @@ } // Transform the solution and the supply map to the original form - if (_have_lower) { + if (_has_lower) { for (int i = 0; i != _arc_num; ++i) { Value c = _lower[i]; if (c != 0) { diff -r cd72eae05bdf -r 3c00344f49c9 lemon/opt2_tsp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/opt2_tsp.h Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,367 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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_OPT2_TSP_H +#define LEMON_OPT2_TSP_H + +/// \ingroup tsp +/// \file +/// \brief 2-opt algorithm for symmetric TSP. + +#include +#include + +namespace lemon { + + /// \ingroup tsp + /// + /// \brief 2-opt algorithm for symmetric TSP. + /// + /// Opt2Tsp implements the 2-opt heuristic for solving + /// symmetric \ref tsp "TSP". + /// + /// This algorithm starts with an initial tour and iteratively improves it. + /// At each step, it removes two edges and the reconnects the created two + /// paths in the other way if the resulting tour is shorter. + /// The algorithm finishes when no such 2-opt move can be applied, and so + /// the tour is 2-optimal. + /// + /// If no starting tour is given to the \ref run() function, then the + /// algorithm uses the node sequence determined by the node IDs. + /// Oherwise, it starts with the given tour. + /// + /// This is a rather slow but effective method. + /// Its typical usage is the improvement of the result of a fast tour + /// construction heuristic (e.g. the InsertionTsp algorithm). + /// + /// \tparam CM Type of the cost map. + template + class Opt2Tsp + { + public: + + /// Type of the cost map + typedef CM CostMap; + /// Type of the edge costs + typedef typename CM::Value Cost; + + private: + + GRAPH_TYPEDEFS(FullGraph); + + const FullGraph &_gr; + const CostMap &_cost; + Cost _sum; + std::vector _plist; + std::vector _path; + + public: + + /// \brief Constructor + /// + /// Constructor. + /// \param gr The \ref FullGraph "full graph" the algorithm runs on. + /// \param cost The cost map. + Opt2Tsp(const FullGraph &gr, const CostMap &cost) + : _gr(gr), _cost(cost) {} + + /// \name Execution Control + /// @{ + + /// \brief Runs the algorithm from scratch. + /// + /// This function runs the algorithm starting from the tour that is + /// determined by the node ID sequence. + /// + /// \return The total cost of the found tour. + Cost run() { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + else if (_gr.nodeNum() == 2) { + _path.push_back(_gr(0)); + _path.push_back(_gr(1)); + return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; + } + + _plist.resize(2*_gr.nodeNum()); + for (int i = 1; i < _gr.nodeNum()-1; ++i) { + _plist[2*i] = i-1; + _plist[2*i+1] = i+1; + } + _plist[0] = _gr.nodeNum()-1; + _plist[1] = 1; + _plist[2*_gr.nodeNum()-2] = _gr.nodeNum()-2; + _plist[2*_gr.nodeNum()-1] = 0; + + return start(); + } + + /// \brief Runs the algorithm starting from the given tour. + /// + /// This function runs the algorithm starting from the given tour. + /// + /// \param tour The tour as a path structure. It must be a + /// \ref checkPath() "valid path" containing excactly n arcs. + /// + /// \return The total cost of the found tour. + template + Cost run(const Path& tour) { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + else if (_gr.nodeNum() == 2) { + _path.push_back(_gr(0)); + _path.push_back(_gr(1)); + return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; + } + + _plist.resize(2*_gr.nodeNum()); + typename Path::ArcIt it(tour); + int first = _gr.id(_gr.source(it)), + prev = first, + curr = _gr.id(_gr.target(it)), + next = -1; + _plist[2*first+1] = curr; + for (++it; it != INVALID; ++it) { + next = _gr.id(_gr.target(it)); + _plist[2*curr] = prev; + _plist[2*curr+1] = next; + prev = curr; + curr = next; + } + _plist[2*first] = prev; + + return start(); + } + + /// \brief Runs the algorithm starting from the given tour. + /// + /// This function runs the algorithm starting from the given tour + /// (node sequence). + /// + /// \param tour A vector that stores all Nodes of the graph + /// in the desired order. + /// + /// \return The total cost of the found tour. + Cost run(const std::vector& tour) { + _path.clear(); + + if (_gr.nodeNum() == 0) return _sum = 0; + else if (_gr.nodeNum() == 1) { + _path.push_back(_gr(0)); + return _sum = 0; + } + else if (_gr.nodeNum() == 2) { + _path.push_back(_gr(0)); + _path.push_back(_gr(1)); + return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; + } + + _plist.resize(2*_gr.nodeNum()); + typename std::vector::const_iterator it = tour.begin(); + int first = _gr.id(*it), + prev = first, + curr = _gr.id(*(++it)), + next = -1; + _plist[2*first+1] = curr; + for (++it; it != tour.end(); ++it) { + next = _gr.id(*it); + _plist[2*curr] = prev; + _plist[2*curr+1] = next; + prev = curr; + curr = next; + } + _plist[2*first] = curr; + _plist[2*curr] = prev; + _plist[2*curr+1] = first; + + return start(); + } + + /// @} + + /// \name Query Functions + /// @{ + + /// \brief The total cost of the found tour. + /// + /// This function returns the total cost of the found tour. + /// + /// \pre run() must be called before using this function. + Cost tourCost() const { + return _sum; + } + + /// \brief Returns a const reference to the node sequence of the + /// found tour. + /// + /// This function returns a const reference to a vector + /// that stores the node sequence of the found tour. + /// + /// \pre run() must be called before using this function. + const std::vector& tourNodes() const { + return _path; + } + + /// \brief Gives back the node sequence of the found tour. + /// + /// This function copies the node sequence of the found tour into + /// an STL container through the given output iterator. The + /// value_type of the container must be FullGraph::Node. + /// For example, + /// \code + /// std::vector nodes(countNodes(graph)); + /// tsp.tourNodes(nodes.begin()); + /// \endcode + /// or + /// \code + /// std::list nodes; + /// tsp.tourNodes(std::back_inserter(nodes)); + /// \endcode + /// + /// \pre run() must be called before using this function. + template + void tourNodes(Iterator out) const { + std::copy(_path.begin(), _path.end(), out); + } + + /// \brief Gives back the found tour as a path. + /// + /// This function copies the found tour as a list of arcs/edges into + /// the given \ref lemon::concepts::Path "path structure". + /// + /// \pre run() must be called before using this function. + template + void tour(Path &path) const { + path.clear(); + for (int i = 0; i < int(_path.size()) - 1; ++i) { + path.addBack(_gr.arc(_path[i], _path[i+1])); + } + if (int(_path.size()) >= 2) { + path.addBack(_gr.arc(_path.back(), _path.front())); + } + } + + /// @} + + private: + + // Iterator class for the linked list storage of the tour + class PathListIt { + public: + PathListIt(const std::vector &pl, int i=0) + : plist(&pl), act(i), last(pl[2*act]) {} + PathListIt(const std::vector &pl, int i, int l) + : plist(&pl), act(i), last(l) {} + + int nextIndex() const { + return (*plist)[2*act] == last ? 2*act+1 : 2*act; + } + + int prevIndex() const { + return (*plist)[2*act] == last ? 2*act : 2*act+1; + } + + int next() const { + int x = (*plist)[2*act]; + return x == last ? (*plist)[2*act+1] : x; + } + + int prev() const { + return last; + } + + PathListIt& operator++() { + int tmp = act; + act = next(); + last = tmp; + return *this; + } + + operator int() const { + return act; + } + + private: + const std::vector *plist; + int act; + int last; + }; + + // Checks and applies 2-opt move (if it improves the tour) + bool checkOpt2(const PathListIt& i, const PathListIt& j) { + Node u = _gr.nodeFromId(i), + un = _gr.nodeFromId(i.next()), + v = _gr.nodeFromId(j), + vn = _gr.nodeFromId(j.next()); + + if (_cost[_gr.edge(u, un)] + _cost[_gr.edge(v, vn)] > + _cost[_gr.edge(u, v)] + _cost[_gr.edge(un, vn)]) + { + _plist[PathListIt(_plist, i.next(), i).prevIndex()] = j.next(); + _plist[PathListIt(_plist, j.next(), j).prevIndex()] = i.next(); + + _plist[i.nextIndex()] = j; + _plist[j.nextIndex()] = i; + + return true; + } + + return false; + } + + // Executes the algorithm from the initial tour + Cost start() { + + restart_search: + for (PathListIt i(_plist); true; ++i) { + PathListIt j = i; + if (++j == 0 || ++j == 0) break; + for (; j != 0 && j != i.prev(); ++j) { + if (checkOpt2(i, j)) + goto restart_search; + } + } + + PathListIt i(_plist); + _path.push_back(_gr.nodeFromId(i)); + for (++i; i != 0; ++i) + _path.push_back(_gr.nodeFromId(i)); + + _sum = _cost[_gr.edge(_path.back(), _path.front())]; + for (int i = 0; i < int(_path.size())-1; ++i) { + _sum += _cost[_gr.edge(_path[i], _path[i+1])]; + } + + return _sum; + } + + }; + +}; // namespace lemon + +#endif diff -r cd72eae05bdf -r 3c00344f49c9 lemon/path.h --- a/lemon/path.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/path.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -43,7 +43,7 @@ /// \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 + /// LEMON path type stores just this list. As a consequence, it /// cannot enumerate the nodes of the path and the source node of /// a zero length path is undefined. /// @@ -148,7 +148,7 @@ /// \brief Reset the path to an empty one. void clear() { head.clear(); tail.clear(); } - /// \brief The nth arc. + /// \brief The n-th arc. /// /// \pre \c n is in the [0..length() - 1] range. const Arc& nth(int n) const { @@ -156,7 +156,7 @@ *(tail.begin() + (n - head.size())); } - /// \brief Initialize arc iterator to point to the nth arc + /// \brief Initialize arc iterator to point to the n-th arc /// /// \pre \c n is in the [0..length() - 1] range. ArcIt nthIt(int n) const { @@ -244,7 +244,7 @@ /// \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 + /// 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. /// @@ -317,7 +317,7 @@ /// Constructor with starting point ArcIt(const SimplePath &_path, int _idx) - : idx(_idx), path(&_path) {} + : path(&_path), idx(_idx) {} public: @@ -353,14 +353,14 @@ /// \brief Reset the path to an empty one. void clear() { data.clear(); } - /// \brief The nth arc. + /// \brief The n-th arc. /// /// \pre \c n is in the [0..length() - 1] range. const Arc& nth(int n) const { return data[n]; } - /// \brief Initializes arc iterator to point to the nth arc. + /// \brief Initializes arc iterator to point to the n-th arc. ArcIt nthIt(int n) const { return ArcIt(*this, n); } @@ -421,7 +421,7 @@ /// \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 + /// 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. /// @@ -543,9 +543,9 @@ Node *node; }; - /// \brief The nth arc. + /// \brief The n-th arc. /// - /// This function looks for the nth arc in O(n) time. + /// This function looks for the n-th arc in O(n) time. /// \pre \c n is in the [0..length() - 1] range. const Arc& nth(int n) const { Node *node = first; @@ -555,7 +555,7 @@ return node->arc; } - /// \brief Initializes arc iterator to point to the nth arc. + /// \brief Initializes arc iterator to point to the n-th arc. ArcIt nthIt(int n) const { Node *node = first; for (int i = 0; i < n; ++i) { @@ -774,7 +774,7 @@ /// \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 + /// LEMON path type stores just this list. As a consequence it /// cannot enumerate the nodes in the path and the source node of /// a zero length path is undefined. /// @@ -883,14 +883,14 @@ int idx; }; - /// \brief The nth arc. + /// \brief The n-th arc. /// /// \pre \c n is in the [0..length() - 1] range. const Arc& nth(int n) const { return arcs[n]; } - /// \brief The arc iterator pointing to the nth arc. + /// \brief The arc iterator pointing to the n-th arc. ArcIt nthIt(int n) const { return ArcIt(*this, n); } @@ -1094,7 +1094,7 @@ /// \brief Class which helps to iterate through the nodes of a path /// /// In a sense, the path can be treated as a list of arcs. The - /// lemon path type stores only this list. As a consequence, it + /// LEMON path type stores only this list. As a consequence, it /// cannot enumerate the nodes in the path and the zero length paths /// cannot have a source node. /// diff -r cd72eae05bdf -r 3c00344f49c9 lemon/planarity.h --- a/lemon/planarity.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/planarity.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -72,7 +72,6 @@ } void discover(const Arc& arc) { - Node source = _graph.source(arc); Node target = _graph.target(arc); _tree_map[arc] = true; @@ -2384,7 +2383,7 @@ PlanarEmbedding pe(_graph); if (!pe.run()) return false; - run(pe); + run(pe.embeddingMap()); return true; } @@ -2399,6 +2398,15 @@ void run(const EmbeddingMap& embedding) { typedef SmartEdgeSet AuxGraph; + if (countNodes(_graph) < 3) { + int y = 0; + for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { + _point_map[n].x = 0; + _point_map[n].y = y++; + } + return; + } + if (3 * countNodes(_graph) - 6 == countEdges(_graph)) { drawing(_graph, embedding, _point_map); return; diff -r cd72eae05bdf -r 3c00344f49c9 lemon/preflow.h --- a/lemon/preflow.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/preflow.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -102,12 +102,12 @@ /// /// 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 \ref clrs01algorithms, - /// \ref amo93networkflows, \ref goldberg88newapproach. + /// "flow of maximum value" in a digraph \cite clrs01algorithms, + /// \cite amo93networkflows, \cite goldberg88newapproach. /// The preflow algorithms are the fastest known maximum /// 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$. + /// The worst case time complexity of the algorithm is \f$O(n^2\sqrt{m})\f$. /// /// The algorithm consists of two phases. After the first phase /// the maximum flow value and the minimum cut is obtained. The @@ -134,7 +134,7 @@ class Preflow { public: - ///The \ref PreflowDefaultTraits "traits class" of the algorithm. + ///The \ref lemon::PreflowDefaultTraits "traits class" of the algorithm. typedef TR Traits; ///The type of the digraph the algorithm runs on. typedef typename Traits::Digraph Digraph; @@ -476,7 +476,7 @@ /// Initializes the internal data structures and sets the initial /// flow to the given \c flowMap. The \c flowMap should contain a /// flow or at least a preflow, i.e. at each node excluding the - /// source node the incoming flow should greater or equal to the + /// source node the incoming flow should be greater or equal to the /// outgoing flow. /// \return \c false if the given \c flowMap is not a preflow. template @@ -495,7 +495,7 @@ for (OutArcIt e(_graph, n); e != INVALID; ++e) { excess -= (*_flow)[e]; } - if (excess < 0 && n != _source) return false; + if (_tolerance.negative(excess) && n != _source) return false; (*_excess)[n] = excess; } @@ -554,10 +554,10 @@ (*_excess)[v] += rem; } } - for (NodeIt n(_graph); n != INVALID; ++n) + for (NodeIt n(_graph); n != INVALID; ++n) if(n!=_source && n!=_target && _tolerance.positive((*_excess)[n])) _level->activate(n); - + return true; } @@ -585,7 +585,7 @@ if (n == INVALID) goto first_phase_done; level = _level->highestActiveLevel(); --num; - + Value excess = (*_excess)[n]; int new_level = _level->maxLevel(); @@ -639,7 +639,7 @@ (*_excess)[n] = excess; - if (excess != 0) { + if (_tolerance.nonZero(excess)) { if (new_level + 1 < _level->maxLevel()) { _level->liftHighestActive(new_level + 1); } else { @@ -720,7 +720,7 @@ (*_excess)[n] = excess; - if (excess != 0) { + if (_tolerance.nonZero(excess)) { if (new_level + 1 < _level->maxLevel()) { _level->liftActiveOn(level, new_level + 1); } else { @@ -791,7 +791,7 @@ for (NodeIt n(_graph); n != INVALID; ++n) { if (!reached[n]) { _level->dirtyTopButOne(n); - } else if ((*_excess)[n] > 0 && _target != n) { + } else if (_tolerance.positive((*_excess)[n]) && _target != n) { _level->activate(n); } } @@ -852,7 +852,7 @@ (*_excess)[n] = excess; - if (excess != 0) { + if (_tolerance.nonZero(excess)) { if (new_level + 1 < _level->maxLevel()) { _level->liftHighestActive(new_level + 1); } else { diff -r cd72eae05bdf -r 3c00344f49c9 lemon/radix_sort.h --- a/lemon/radix_sort.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/radix_sort.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -34,6 +34,12 @@ namespace _radix_sort_bits { + template + bool unitRange(Iterator first, Iterator last) { + ++first; + return first == last; + } + template struct Identity { const Value& operator()(const Value& val) { @@ -60,9 +66,6 @@ } std::iter_swap(first, last); ++first; - if (!(first < last)) { - return first; - } while (true) { while (!(functor(*first) & mask)) { ++first; @@ -71,7 +74,7 @@ while (functor(*last) & mask) { --last; } - if (!(first < last)) { + if (unitRange(last, first)) { return first; } std::iter_swap(first, last); @@ -97,9 +100,6 @@ } std::iter_swap(first, last); ++first; - if (!(first < last)) { - return first; - } while (true) { while (functor(*first) < 0) { ++first; @@ -108,7 +108,7 @@ while (functor(*last) >= 0) { --last; } - if (!(first < last)) { + if (unitRange(last, first)) { return first; } std::iter_swap(first, last); @@ -119,7 +119,7 @@ template void radixIntroSort(Iterator first, Iterator last, Functor functor, Value mask) { - while (mask != 0 && last - first > 1) { + while (mask != 0 && first != last && !unitRange(first, last)) { Iterator cut = radixSortPartition(first, last, functor, mask); mask >>= 1; radixIntroSort(first, cut, functor, mask); @@ -328,7 +328,7 @@ typedef std::allocator Allocator; Allocator allocator; - int length = std::distance(first, last); + int length = static_cast(std::distance(first, last)); Key* buffer = allocator.allocate(2 * length); try { bool dir = true; diff -r cd72eae05bdf -r 3c00344f49c9 lemon/random.h --- a/lemon/random.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/random.h Wed Oct 17 19:14:07 2018 +0200 @@ -62,6 +62,8 @@ #ifndef LEMON_RANDOM_H #define LEMON_RANDOM_H +#include + #include #include #include @@ -71,7 +73,7 @@ #include #include -#ifndef WIN32 +#ifndef LEMON_WIN32 #include #include #include @@ -199,7 +201,7 @@ initState(init); - num = length > end - begin ? length : end - begin; + num = static_cast(length > end - begin ? length : end - begin); while (num--) { curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul1)) + *it + cnt; @@ -213,7 +215,7 @@ --curr; } - num = length - 1; cnt = length - (curr - state) - 1; + num = length - 1; cnt = static_cast(length - (curr - state) - 1); while (num--) { curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul2)) - cnt; @@ -340,7 +342,7 @@ do { num = rnd() & mask; } while (num > max); - return num; + return static_cast(num); } }; @@ -605,7 +607,7 @@ /// it uses the \c seedFromTime(). /// \return Currently always \c true. bool seed() { -#ifndef WIN32 +#ifndef LEMON_WIN32 if (seedFromFile("/dev/urandom", 0)) return true; #endif if (seedFromTime()) return true; @@ -625,7 +627,7 @@ /// \param file The source file /// \param offset The offset, from the file read. /// \return \c true when the seeding successes. -#ifndef WIN32 +#ifndef LEMON_WIN32 bool seedFromFile(const std::string& file = "/dev/urandom", int offset = 0) #else bool seedFromFile(const std::string& file = "", int offset = 0) @@ -647,7 +649,7 @@ /// random sequence. /// \return Currently always \c true. bool seedFromTime() { -#ifndef WIN32 +#ifndef LEMON_WIN32 timeval tv; gettimeofday(&tv, 0); seed(getpid() + tv.tv_sec + tv.tv_usec); diff -r cd72eae05bdf -r 3c00344f49c9 lemon/smart_graph.h --- a/lemon/smart_graph.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/smart_graph.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -405,8 +405,6 @@ std::vector nodes; std::vector arcs; - int first_free_arc; - public: typedef SmartGraphBase Graph; @@ -811,6 +809,535 @@ }; }; + class SmartBpGraphBase { + + protected: + + struct NodeT { + int first_out; + int partition_next; + int partition_index; + bool red; + }; + + struct ArcT { + int target; + int next_out; + }; + + std::vector nodes; + std::vector arcs; + + int first_red, first_blue; + int max_red, max_blue; + + public: + + typedef SmartBpGraphBase Graph; + + class Node; + class Arc; + class Edge; + + class Node { + friend class SmartBpGraphBase; + protected: + + int _id; + explicit 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 RedNode : public Node { + friend class SmartBpGraphBase; + protected: + + explicit RedNode(int pid) : Node(pid) {} + + public: + RedNode() {} + RedNode(const RedNode& node) : Node(node) {} + RedNode(Invalid) : Node(INVALID){} + }; + + class BlueNode : public Node { + friend class SmartBpGraphBase; + protected: + + explicit BlueNode(int pid) : Node(pid) {} + + public: + BlueNode() {} + BlueNode(const BlueNode& node) : Node(node) {} + BlueNode(Invalid) : Node(INVALID){} + }; + + class Edge { + friend class SmartBpGraphBase; + protected: + + int _id; + explicit Edge(int id) { _id = id;} + + public: + Edge() {} + Edge (Invalid) { _id = -1; } + bool operator==(const Edge& arc) const {return _id == arc._id;} + bool operator!=(const Edge& arc) const {return _id != arc._id;} + bool operator<(const Edge& arc) const {return _id < arc._id;} + }; + + class Arc { + friend class SmartBpGraphBase; + protected: + + int _id; + explicit Arc(int id) { _id = id;} + + public: + operator Edge() const { + return _id != -1 ? edgeFromId(_id / 2) : INVALID; + } + + 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;} + }; + + + + SmartBpGraphBase() + : nodes(), arcs(), first_red(-1), first_blue(-1), + max_red(-1), max_blue(-1) {} + + typedef True NodeNumTag; + typedef True EdgeNumTag; + typedef True ArcNumTag; + + int nodeNum() const { return nodes.size(); } + int redNum() const { return max_red + 1; } + int blueNum() const { return max_blue + 1; } + int edgeNum() const { return arcs.size() / 2; } + int arcNum() const { return arcs.size(); } + + int maxNodeId() const { return nodes.size()-1; } + int maxRedId() const { return max_red; } + int maxBlueId() const { return max_blue; } + int maxEdgeId() const { return arcs.size() / 2 - 1; } + int maxArcId() const { return arcs.size()-1; } + + bool red(Node n) const { return nodes[n._id].red; } + bool blue(Node n) const { return !nodes[n._id].red; } + + static RedNode asRedNodeUnsafe(Node n) { return RedNode(n._id); } + static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n._id); } + + Node source(Arc a) const { return Node(arcs[a._id ^ 1].target); } + Node target(Arc a) const { return Node(arcs[a._id].target); } + + RedNode redNode(Edge e) const { + return RedNode(arcs[2 * e._id].target); + } + BlueNode blueNode(Edge e) const { + return BlueNode(arcs[2 * e._id + 1].target); + } + + static bool direction(Arc a) { + return (a._id & 1) == 1; + } + + static Arc direct(Edge e, bool d) { + return Arc(e._id * 2 + (d ? 1 : 0)); + } + + void first(Node& node) const { + node._id = nodes.size() - 1; + } + + static void next(Node& node) { + --node._id; + } + + void first(RedNode& node) const { + node._id = first_red; + } + + void next(RedNode& node) const { + node._id = nodes[node._id].partition_next; + } + + void first(BlueNode& node) const { + node._id = first_blue; + } + + void next(BlueNode& node) const { + node._id = nodes[node._id].partition_next; + } + + void first(Arc& arc) const { + arc._id = arcs.size() - 1; + } + + static void next(Arc& arc) { + --arc._id; + } + + void first(Edge& arc) const { + arc._id = arcs.size() / 2 - 1; + } + + static void next(Edge& arc) { + --arc._id; + } + + void firstOut(Arc &arc, const Node& v) const { + arc._id = nodes[v._id].first_out; + } + void nextOut(Arc &arc) const { + arc._id = arcs[arc._id].next_out; + } + + void firstIn(Arc &arc, const Node& v) const { + arc._id = ((nodes[v._id].first_out) ^ 1); + if (arc._id == -2) arc._id = -1; + } + void nextIn(Arc &arc) const { + arc._id = ((arcs[arc._id ^ 1].next_out) ^ 1); + if (arc._id == -2) arc._id = -1; + } + + void firstInc(Edge &arc, bool& d, const Node& v) const { + int de = nodes[v._id].first_out; + if (de != -1) { + arc._id = de / 2; + d = ((de & 1) == 1); + } else { + arc._id = -1; + d = true; + } + } + void nextInc(Edge &arc, bool& d) const { + int de = (arcs[(arc._id * 2) | (d ? 1 : 0)].next_out); + if (de != -1) { + arc._id = de / 2; + d = ((de & 1) == 1); + } else { + arc._id = -1; + d = true; + } + } + + static int id(Node v) { return v._id; } + int id(RedNode v) const { return nodes[v._id].partition_index; } + int id(BlueNode v) const { return nodes[v._id].partition_index; } + static int id(Arc e) { return e._id; } + static int id(Edge e) { return e._id; } + + static Node nodeFromId(int id) { return Node(id);} + static Arc arcFromId(int id) { return Arc(id);} + static Edge edgeFromId(int id) { return Edge(id);} + + bool valid(Node n) const { + return n._id >= 0 && n._id < static_cast(nodes.size()); + } + bool valid(Arc a) const { + return a._id >= 0 && a._id < static_cast(arcs.size()); + } + bool valid(Edge e) const { + return e._id >= 0 && 2 * e._id < static_cast(arcs.size()); + } + + RedNode addRedNode() { + int n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].first_out = -1; + nodes[n].red = true; + nodes[n].partition_index = ++max_red; + nodes[n].partition_next = first_red; + first_red = n; + + return RedNode(n); + } + + BlueNode addBlueNode() { + int n = nodes.size(); + nodes.push_back(NodeT()); + nodes[n].first_out = -1; + nodes[n].red = false; + nodes[n].partition_index = ++max_blue; + nodes[n].partition_next = first_blue; + first_blue = n; + + return BlueNode(n); + } + + Edge addEdge(RedNode u, BlueNode v) { + int n = arcs.size(); + arcs.push_back(ArcT()); + arcs.push_back(ArcT()); + + arcs[n].target = u._id; + arcs[n | 1].target = v._id; + + arcs[n].next_out = nodes[v._id].first_out; + nodes[v._id].first_out = n; + + arcs[n | 1].next_out = nodes[u._id].first_out; + nodes[u._id].first_out = (n | 1); + + return Edge(n / 2); + } + + void clear() { + arcs.clear(); + nodes.clear(); + first_red = -1; + first_blue = -1; + max_blue = -1; + max_red = -1; + } + + }; + + typedef BpGraphExtender ExtendedSmartBpGraphBase; + + /// \ingroup graphs + /// + /// \brief A smart undirected bipartite graph class. + /// + /// \ref SmartBpGraph is a simple and fast bipartite 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). + /// + /// This type fully conforms to the \ref concepts::BpGraph "BpGraph 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::BpGraph + /// \sa SmartGraph + class SmartBpGraph : public ExtendedSmartBpGraphBase { + typedef ExtendedSmartBpGraphBase Parent; + + private: + /// Graphs are \e not copy constructible. Use GraphCopy instead. + SmartBpGraph(const SmartBpGraph &) : ExtendedSmartBpGraphBase() {}; + /// \brief Assignment of a graph to another one is \e not allowed. + /// Use GraphCopy instead. + void operator=(const SmartBpGraph &) {} + + public: + + /// Constructor + + /// Constructor. + /// + SmartBpGraph() {} + + /// \brief Add a new red node to the graph. + /// + /// This function adds a red new node to the graph. + /// \return The new node. + RedNode addRedNode() { return Parent::addRedNode(); } + + /// \brief Add a new blue node to the graph. + /// + /// This function adds a blue new node to the graph. + /// \return The new node. + BlueNode addBlueNode() { return Parent::addBlueNode(); } + + /// \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(RedNode u, BlueNode v) { + return Parent::addEdge(u, v); + } + Edge addEdge(BlueNode v, RedNode u) { + return Parent::addEdge(u, v); + } + + /// \brief Node validity check + /// + /// 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 + /// 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 \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 + /// if new edges are added to the graph. + bool valid(Arc a) const { return Parent::valid(a); } + + ///Clear 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; + + protected: + + void saveSnapshot(Snapshot &s) + { + s._graph = this; + s.node_num = nodes.size(); + s.arc_num = arcs.size(); + } + + void restoreSnapshot(const Snapshot &s) + { + while(s.arc_num dir; + dir.push_back(arcFromId(n)); + dir.push_back(arcFromId(n-1)); + Parent::notifier(Arc()).erase(dir); + nodes[arcs[n-1].target].first_out=arcs[n].next_out; + nodes[arcs[n].target].first_out=arcs[n-1].next_out; + arcs.pop_back(); + arcs.pop_back(); + } + while(s.node_numrestoreSnapshot(*this); + } + }; + }; + } //namespace lemon diff -r cd72eae05bdf -r 3c00344f49c9 lemon/soplex.cc --- a/lemon/soplex.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/soplex.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/soplex.h --- a/lemon/soplex.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/soplex.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 lemon/static_graph.h --- a/lemon/static_graph.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/static_graph.h Wed Oct 17 19:14:07 2018 +0200 @@ -203,7 +203,7 @@ built = true; node_num = n; - arc_num = std::distance(first, last); + arc_num = static_cast(std::distance(first, last)); node_first_out = new int[node_num + 1]; node_first_in = new int[node_num]; diff -r cd72eae05bdf -r 3c00344f49c9 lemon/suurballe.h --- a/lemon/suurballe.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/suurballe.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -137,7 +137,7 @@ /// The heap type used for internal Dijkstra computations. typedef typename TR::Heap Heap; - /// The \ref SuurballeDefaultTraits "traits class" of the algorithm. + /// The \ref lemon::SuurballeDefaultTraits "traits class" of the algorithm. typedef TR Traits; private: @@ -682,7 +682,7 @@ /// /// This function returns the total length of the found paths, i.e. /// the total cost of the found flow. - /// The complexity of the function is O(e). + /// The complexity of the function is O(m). /// /// \pre \ref run() or \ref findFlow() must be called before using /// this function. diff -r cd72eae05bdf -r 3c00344f49c9 lemon/time_measure.h --- a/lemon/time_measure.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/time_measure.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -23,7 +23,9 @@ ///\file ///\brief Tools for measuring cpu usage -#ifdef WIN32 +#include + +#ifdef LEMON_WIN32 #include #else #include @@ -34,6 +36,7 @@ #include #include #include +#include namespace lemon { @@ -63,16 +66,45 @@ double cstime; double rtime; + public: + ///Display format specifier + + ///\e + /// + enum Format { + /// Reports all measured values + NORMAL = 0, + /// Only real time and an error indicator is displayed + SHORT = 1 + }; + + private: + static Format _format; + void _reset() { utime = stime = cutime = cstime = rtime = 0; } public: + ///Set output format + + ///Set output format. + /// + ///The output format is global for all timestamp instances. + static void format(Format f) { _format = f; } + ///Retrieve the current output format + + ///Retrieve the current output format + /// + ///The output format is global for all timestamp instances. + static Format format() { return _format; } + + ///Read the current time values of the process void stamp() { -#ifndef WIN32 +#ifndef LEMON_WIN32 timeval tv; gettimeofday(&tv, 0); rtime=tv.tv_sec+double(tv.tv_usec)/1e6; @@ -224,11 +256,24 @@ /// calculated. inline std::ostream& operator<<(std::ostream& os,const TimeStamp &t) { - os << "u: " << t.userTime() << - "s, s: " << t.systemTime() << - "s, cu: " << t.cUserTime() << - "s, cs: " << t.cSystemTime() << - "s, real: " << t.realTime() << "s"; + switch(t._format) + { + case TimeStamp::NORMAL: + os << "u: " << t.userTime() << + "s, s: " << t.systemTime() << + "s, cu: " << t.cUserTime() << + "s, cs: " << t.cSystemTime() << + "s, real: " << t.realTime() << "s"; + break; + case TimeStamp::SHORT: + double total = t.userTime()+t.systemTime()+ + t.cUserTime()+t.cSystemTime(); + os << t.realTime() + << "s (err: " << round((t.realTime()-total)/ + t.realTime()*10000)/100 + << "%)"; + break; + } return os; } @@ -468,6 +513,7 @@ { std::string _title; std::ostream &_os; + bool _active; public: ///Constructor @@ -475,13 +521,27 @@ ///\param title This text will be printed before the ellapsed time. ///\param os The stream to print the report to. ///\param run Sets whether the timer should start immediately. - TimeReport(std::string title,std::ostream &os=std::cerr,bool run=true) - : Timer(run), _title(title), _os(os){} + ///\param active Sets whether the report should actually be printed + /// on destruction. + TimeReport(std::string title,std::ostream &os=std::cerr,bool run=true, + bool active=true) + : Timer(run), _title(title), _os(os), _active(active) {} ///Destructor that prints the ellapsed time ~TimeReport() { - _os << _title << *this << std::endl; + if(_active) _os << _title << *this << std::endl; } + + ///Retrieve the activity status + + ///\e + /// + bool active() const { return _active; } + ///Set the activity status + + /// This function set whether the time report should actually be printed + /// on destruction. + void active(bool a) { _active=a; } }; ///'Do nothing' version of TimeReport diff -r cd72eae05bdf -r 3c00344f49c9 lemon/unionfind.h --- a/lemon/unionfind.h Mon Jul 16 16:21:40 2018 +0200 +++ b/lemon/unionfind.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 m4/lx_check_coin.m4 --- a/m4/lx_check_coin.m4 Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -AC_DEFUN([LX_CHECK_COIN], -[ - AC_ARG_WITH([coin], -AS_HELP_STRING([--with-coin@<:@=PREFIX@:>@], [search for CLP under PREFIX or under the default search paths if PREFIX is not given @<:@default@:>@]) -AS_HELP_STRING([--without-coin], [disable checking for CLP]), - [], [with_coin=yes]) - - AC_ARG_WITH([coin-includedir], -AS_HELP_STRING([--with-coin-includedir=DIR], [search for CLP headers in DIR]), - [], [with_coin_includedir=no]) - - AC_ARG_WITH([coin-libdir], -AS_HELP_STRING([--with-coin-libdir=DIR], [search for CLP libraries in DIR]), - [], [with_coin_libdir=no]) - - lx_clp_found=no - if test x"$with_coin" != x"no"; then - AC_MSG_CHECKING([for CLP]) - - if test x"$with_coin_includedir" != x"no"; then - CLP_CXXFLAGS="-I$with_coin_includedir" - elif test x"$with_coin" != x"yes"; then - CLP_CXXFLAGS="-I$with_coin/include" - fi - - if test x"$with_coin_libdir" != x"no"; then - CLP_LDFLAGS="-L$with_coin_libdir" - elif test x"$with_coin" != x"yes"; then - CLP_LDFLAGS="-L$with_coin/lib" - fi - CLP_LIBS="-lClp -lCoinUtils -lm" - - lx_save_cxxflags="$CXXFLAGS" - lx_save_ldflags="$LDFLAGS" - lx_save_libs="$LIBS" - CXXFLAGS="$CLP_CXXFLAGS" - LDFLAGS="$CLP_LDFLAGS" - LIBS="$CLP_LIBS" - - lx_clp_test_prog=' - #include - - int main(int argc, char** argv) - { - ClpModel clp; - return 0; - }' - - AC_LANG_PUSH(C++) - AC_LINK_IFELSE([$lx_clp_test_prog], [lx_clp_found=yes], [lx_clp_found=no]) - AC_LANG_POP(C++) - - CXXFLAGS="$lx_save_cxxflags" - LDFLAGS="$lx_save_ldflags" - LIBS="$lx_save_libs" - - if test x"$lx_clp_found" = x"yes"; then - AC_DEFINE([LEMON_HAVE_CLP], [1], [Define to 1 if you have CLP.]) - lx_lp_found=yes - AC_DEFINE([LEMON_HAVE_LP], [1], [Define to 1 if you have any LP solver.]) - AC_MSG_RESULT([yes]) - else - CLP_CXXFLAGS="" - CLP_LDFLAGS="" - CLP_LIBS="" - AC_MSG_RESULT([no]) - fi - fi - CLP_LIBS="$CLP_LDFLAGS $CLP_LIBS" - AC_SUBST(CLP_CXXFLAGS) - AC_SUBST(CLP_LIBS) - AM_CONDITIONAL([HAVE_CLP], [test x"$lx_clp_found" = x"yes"]) - - - lx_cbc_found=no - if test x"$lx_clp_found" = x"yes"; then - if test x"$with_coin" != x"no"; then - AC_MSG_CHECKING([for CBC]) - - if test x"$with_coin_includedir" != x"no"; then - CBC_CXXFLAGS="-I$with_coin_includedir" - elif test x"$with_coin" != x"yes"; then - CBC_CXXFLAGS="-I$with_coin/include" - fi - - if test x"$with_coin_libdir" != x"no"; then - CBC_LDFLAGS="-L$with_coin_libdir" - elif test x"$with_coin" != x"yes"; then - CBC_LDFLAGS="-L$with_coin/lib" - fi - CBC_LIBS="-lOsi -lCbc -lCbcSolver -lClp -lOsiClp -lCoinUtils -lVol -lOsiVol -lCgl -lm -llapack -lblas" - - lx_save_cxxflags="$CXXFLAGS" - lx_save_ldflags="$LDFLAGS" - lx_save_libs="$LIBS" - CXXFLAGS="$CBC_CXXFLAGS" - LDFLAGS="$CBC_LDFLAGS" - LIBS="$CBC_LIBS" - - lx_cbc_test_prog=' - #include - - int main(int argc, char** argv) - { - CbcModel cbc; - return 0; - }' - - AC_LANG_PUSH(C++) - AC_LINK_IFELSE([$lx_cbc_test_prog], [lx_cbc_found=yes], [lx_cbc_found=no]) - AC_LANG_POP(C++) - - CXXFLAGS="$lx_save_cxxflags" - LDFLAGS="$lx_save_ldflags" - LIBS="$lx_save_libs" - - if test x"$lx_cbc_found" = x"yes"; then - AC_DEFINE([LEMON_HAVE_CBC], [1], [Define to 1 if you have CBC.]) - lx_lp_found=yes - AC_DEFINE([LEMON_HAVE_LP], [1], [Define to 1 if you have any LP solver.]) - lx_mip_found=yes - AC_DEFINE([LEMON_HAVE_MIP], [1], [Define to 1 if you have any MIP solver.]) - AC_MSG_RESULT([yes]) - else - CBC_CXXFLAGS="" - CBC_LDFLAGS="" - CBC_LIBS="" - AC_MSG_RESULT([no]) - fi - fi - fi - CBC_LIBS="$CBC_LDFLAGS $CBC_LIBS" - AC_SUBST(CBC_CXXFLAGS) - AC_SUBST(CBC_LIBS) - AM_CONDITIONAL([HAVE_CBC], [test x"$lx_cbc_found" = x"yes"]) -]) diff -r cd72eae05bdf -r 3c00344f49c9 m4/lx_check_cplex.m4 --- a/m4/lx_check_cplex.m4 Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -AC_DEFUN([LX_CHECK_CPLEX], -[ - AC_ARG_WITH([cplex], -AS_HELP_STRING([--with-cplex@<:@=PREFIX@:>@], [search for CPLEX under PREFIX or under the default search paths if PREFIX is not given @<:@default@:>@]) -AS_HELP_STRING([--without-cplex], [disable checking for CPLEX]), - [], [with_cplex=yes]) - - AC_ARG_WITH([cplex-includedir], -AS_HELP_STRING([--with-cplex-includedir=DIR], [search for CPLEX headers in DIR]), - [], [with_cplex_includedir=no]) - - AC_ARG_WITH([cplex-libdir], -AS_HELP_STRING([--with-cplex-libdir=DIR], [search for CPLEX libraries in DIR]), - [], [with_cplex_libdir=no]) - - lx_cplex_found=no - if test x"$with_cplex" != x"no"; then - AC_MSG_CHECKING([for CPLEX]) - - if test x"$with_cplex_includedir" != x"no"; then - CPLEX_CFLAGS="-I$with_cplex_includedir" - elif test x"$with_cplex" != x"yes"; then - CPLEX_CFLAGS="-I$with_cplex/include" - elif test x"$CPLEX_INCLUDEDIR" != x; then - CPLEX_CFLAGS="-I$CPLEX_INCLUDEDIR" - fi - - if test x"$with_cplex_libdir" != x"no"; then - CPLEX_LDFLAGS="-L$with_cplex_libdir" - elif test x"$with_cplex" != x"yes"; then - CPLEX_LDFLAGS="-L$with_cplex/lib" - elif test x"$CPLEX_LIBDIR" != x; then - CPLEX_LDFLAGS="-L$CPLEX_LIBDIR" - fi - CPLEX_LIBS="-lcplex -lm -lpthread" - - lx_save_cxxflags="$CXXFLAGS" - lx_save_ldflags="$LDFLAGS" - lx_save_libs="$LIBS" - CXXFLAGS="$CPLEX_CFLAGS" - LDFLAGS="$CPLEX_LDFLAGS" - LIBS="$CPLEX_LIBS" - - lx_cplex_test_prog=' - extern "C" { - #include - } - - int main(int argc, char** argv) - { - CPXENVptr env = NULL; - return 0; - }' - - AC_LANG_PUSH(C++) - AC_LINK_IFELSE([$lx_cplex_test_prog], [lx_cplex_found=yes], [lx_cplex_found=no]) - AC_LANG_POP(C++) - - CXXFLAGS="$lx_save_cxxflags" - LDFLAGS="$lx_save_ldflags" - LIBS="$lx_save_libs" - - if test x"$lx_cplex_found" = x"yes"; then - AC_DEFINE([LEMON_HAVE_CPLEX], [1], [Define to 1 if you have CPLEX.]) - lx_lp_found=yes - AC_DEFINE([LEMON_HAVE_LP], [1], [Define to 1 if you have any LP solver.]) - lx_mip_found=yes - AC_DEFINE([LEMON_HAVE_MIP], [1], [Define to 1 if you have any MIP solver.]) - AC_MSG_RESULT([yes]) - else - CPLEX_CFLAGS="" - CPLEX_LDFLAGS="" - CPLEX_LIBS="" - AC_MSG_RESULT([no]) - fi - fi - CPLEX_LIBS="$CPLEX_LDFLAGS $CPLEX_LIBS" - AC_SUBST(CPLEX_CFLAGS) - AC_SUBST(CPLEX_LIBS) - AM_CONDITIONAL([HAVE_CPLEX], [test x"$lx_cplex_found" = x"yes"]) -]) diff -r cd72eae05bdf -r 3c00344f49c9 m4/lx_check_glpk.m4 --- a/m4/lx_check_glpk.m4 Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -AC_DEFUN([LX_CHECK_GLPK], -[ - AC_ARG_WITH([glpk], -AS_HELP_STRING([--with-glpk@<:@=PREFIX@:>@], [search for GLPK under PREFIX or under the default search paths if PREFIX is not given @<:@default@:>@]) -AS_HELP_STRING([--without-glpk], [disable checking for GLPK]), - [], [with_glpk=yes]) - - AC_ARG_WITH([glpk-includedir], -AS_HELP_STRING([--with-glpk-includedir=DIR], [search for GLPK headers in DIR]), - [], [with_glpk_includedir=no]) - - AC_ARG_WITH([glpk-libdir], -AS_HELP_STRING([--with-glpk-libdir=DIR], [search for GLPK libraries in DIR]), - [], [with_glpk_libdir=no]) - - lx_glpk_found=no - if test x"$with_glpk" != x"no"; then - AC_MSG_CHECKING([for GLPK]) - - if test x"$with_glpk_includedir" != x"no"; then - GLPK_CFLAGS="-I$with_glpk_includedir" - elif test x"$with_glpk" != x"yes"; then - GLPK_CFLAGS="-I$with_glpk/include" - fi - - if test x"$with_glpk_libdir" != x"no"; then - GLPK_LDFLAGS="-L$with_glpk_libdir" - elif test x"$with_glpk" != x"yes"; then - GLPK_LDFLAGS="-L$with_glpk/lib" - fi - GLPK_LIBS="-lglpk" - - lx_save_cxxflags="$CXXFLAGS" - lx_save_ldflags="$LDFLAGS" - lx_save_libs="$LIBS" - CXXFLAGS="$GLPK_CFLAGS" - LDFLAGS="$GLPK_LDFLAGS" - LIBS="$GLPK_LIBS" - - lx_glpk_test_prog=' - extern "C" { - #include - } - - #if (GLP_MAJOR_VERSION < 4) \ - || (GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION < 33) - #error Supported GLPK versions: 4.33 or above - #endif - - int main(int argc, char** argv) - { - LPX *lp; - lp = lpx_create_prob(); - lpx_delete_prob(lp); - return 0; - }' - - AC_LANG_PUSH(C++) - AC_LINK_IFELSE([$lx_glpk_test_prog], [lx_glpk_found=yes], [lx_glpk_found=no]) - AC_LANG_POP(C++) - - CXXFLAGS="$lx_save_cxxflags" - LDFLAGS="$lx_save_ldflags" - LIBS="$lx_save_libs" - - if test x"$lx_glpk_found" = x"yes"; then - AC_DEFINE([LEMON_HAVE_GLPK], [1], [Define to 1 if you have GLPK.]) - lx_lp_found=yes - AC_DEFINE([LEMON_HAVE_LP], [1], [Define to 1 if you have any LP solver.]) - lx_mip_found=yes - AC_DEFINE([LEMON_HAVE_MIP], [1], [Define to 1 if you have any MIP solver.]) - AC_MSG_RESULT([yes]) - else - GLPK_CFLAGS="" - GLPK_LDFLAGS="" - GLPK_LIBS="" - AC_MSG_RESULT([no]) - fi - fi - GLPK_LIBS="$GLPK_LDFLAGS $GLPK_LIBS" - AC_SUBST(GLPK_CFLAGS) - AC_SUBST(GLPK_LIBS) - AM_CONDITIONAL([HAVE_GLPK], [test x"$lx_glpk_found" = x"yes"]) -]) diff -r cd72eae05bdf -r 3c00344f49c9 m4/lx_check_soplex.m4 --- a/m4/lx_check_soplex.m4 Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -AC_DEFUN([LX_CHECK_SOPLEX], -[ - AC_ARG_WITH([soplex], -AS_HELP_STRING([--with-soplex@<:@=PREFIX@:>@], [search for SOPLEX under PREFIX or under the default search paths if PREFIX is not given @<:@default@:>@]) -AS_HELP_STRING([--without-soplex], [disable checking for SOPLEX]), - [], [with_soplex=yes]) - - AC_ARG_WITH([soplex-includedir], -AS_HELP_STRING([--with-soplex-includedir=DIR], [search for SOPLEX headers in DIR]), - [], [with_soplex_includedir=no]) - - AC_ARG_WITH([soplex-libdir], -AS_HELP_STRING([--with-soplex-libdir=DIR], [search for SOPLEX libraries in DIR]), - [], [with_soplex_libdir=no]) - - lx_soplex_found=no - if test x"$with_soplex" != x"no"; then - AC_MSG_CHECKING([for SOPLEX]) - - if test x"$with_soplex_includedir" != x"no"; then - SOPLEX_CXXFLAGS="-I$with_soplex_includedir" - elif test x"$with_soplex" != x"yes"; then - SOPLEX_CXXFLAGS="-I$with_soplex/src" - fi - - if test x"$with_soplex_libdir" != x"no"; then - SOPLEX_LDFLAGS="-L$with_soplex_libdir" - elif test x"$with_soplex" != x"yes"; then - SOPLEX_LDFLAGS="-L$with_soplex/lib" - fi - SOPLEX_LIBS="-lsoplex -lz" - - lx_save_cxxflags="$CXXFLAGS" - lx_save_ldflags="$LDFLAGS" - lx_save_libs="$LIBS" - CXXFLAGS="$SOPLEX_CXXFLAGS" - LDFLAGS="$SOPLEX_LDFLAGS" - LIBS="$SOPLEX_LIBS" - - lx_soplex_test_prog=' - #include - - int main(int argc, char** argv) - { - soplex::SoPlex soplex; - return 0; - }' - - AC_LANG_PUSH(C++) - AC_LINK_IFELSE([$lx_soplex_test_prog], [lx_soplex_found=yes], [lx_soplex_found=no]) - AC_LANG_POP(C++) - - CXXFLAGS="$lx_save_cxxflags" - LDFLAGS="$lx_save_ldflags" - LIBS="$lx_save_libs" - - if test x"$lx_soplex_found" = x"yes"; then - AC_DEFINE([LEMON_HAVE_SOPLEX], [1], [Define to 1 if you have SOPLEX.]) - lx_lp_found=yes - AC_DEFINE([LEMON_HAVE_LP], [1], [Define to 1 if you have any LP solver.]) - AC_MSG_RESULT([yes]) - else - SOPLEX_CXXFLAGS="" - SOPLEX_LDFLAGS="" - SOPLEX_LIBS="" - AC_MSG_RESULT([no]) - fi - fi - SOPLEX_LIBS="$SOPLEX_LDFLAGS $SOPLEX_LIBS" - AC_SUBST(SOPLEX_CXXFLAGS) - AC_SUBST(SOPLEX_LIBS) - AM_CONDITIONAL([HAVE_SOPLEX], [test x"$lx_soplex_found" = x"yes"]) -]) diff -r cd72eae05bdf -r 3c00344f49c9 scripts/Makefile.am --- a/scripts/Makefile.am Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -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 -r cd72eae05bdf -r 3c00344f49c9 scripts/bib2dox.py --- a/scripts/bib2dox.py Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,816 +0,0 @@ -#! /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 -r cd72eae05bdf -r 3c00344f49c9 scripts/bootstrap.sh --- a/scripts/bootstrap.sh Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -#!/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 -r cd72eae05bdf -r 3c00344f49c9 scripts/chg-len.py --- a/scripts/chg-len.py Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -#! /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 - -from mercurial import ui, hg -from mercurial import util - -util.rcpath = lambda : [] - -if len(sys.argv)>1 and sys.argv[1] in ["-h","--help"]: - print """ -This utility just prints the length of the longest path -in the revision graph from revison 0 to the current one. -""" - exit(0) - -u = ui.ui() -r = hg.repository(u, ".") -N = r.changectx(".").rev() -lengths=[0]*(N+1) -for i in range(N+1): - p=r.changectx(i).parents() - if p[0]: - p0=lengths[p[0].rev()] - else: - p0=-1 - if len(p)>1 and p[1]: - p1=lengths[p[1].rev()] - else: - p1=-1 - lengths[i]=max(p0,p1)+1 -print lengths[N] diff -r cd72eae05bdf -r 3c00344f49c9 scripts/mk-release.sh --- a/scripts/mk-release.sh Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -#!/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 - -if [ $# = 0 ]; then - echo "Usage: $0 release-id" - exit 1 -else - export LEMON_VERSION=$1 -fi - -echo '*****************************************************************' -echo ' Start making release tarballs for version '${LEMON_VERSION} -echo '*****************************************************************' - -autoreconf -vif -./configure - -make -make html -make distcheck -tar xf lemon-${LEMON_VERSION}.tar.gz -zip -r lemon-${LEMON_VERSION}.zip lemon-${LEMON_VERSION} -mv lemon-${LEMON_VERSION}/doc/html lemon-doc-${LEMON_VERSION} -tar czf lemon-doc-${LEMON_VERSION}.tar.gz lemon-doc-${LEMON_VERSION} -zip -r lemon-doc-${LEMON_VERSION}.zip lemon-doc-${LEMON_VERSION} -tar czf lemon-nodoc-${LEMON_VERSION}.tar.gz lemon-${LEMON_VERSION} -zip -r lemon-nodoc-${LEMON_VERSION}.zip lemon-${LEMON_VERSION} -hg tag -m 'LEMON '${LEMON_VERSION}' released ('$(hg par --template="{node|short}")' tagged as r'${LEMON_VERSION}')' r${LEMON_VERSION} - -rm -rf lemon-${LEMON_VERSION} lemon-doc-${LEMON_VERSION} - -echo '*****************************************************************' -echo ' Release '${LEMON_VERSION}' has been created' -echo '*****************************************************************' diff -r cd72eae05bdf -r 3c00344f49c9 test/CMakeLists.txt --- a/test/CMakeLists.txt Mon Jul 16 16:21:40 2018 +0200 +++ b/test/CMakeLists.txt Wed Oct 17 19:14:07 2018 +0200 @@ -16,6 +16,7 @@ arc_look_up_test bellman_ford_test bfs_test + bpgraph_test circulation_test connectivity_test counter_test @@ -34,19 +35,24 @@ hao_orlin_test heap_test kruskal_test + lgf_reader_writer_test lgf_test maps_test matching_test + max_cardinality_search_test + max_clique_test + max_flow_test min_cost_arborescence_test min_cost_flow_test min_mean_cycle_test + nagamochi_ibaraki_test path_test planarity_test - preflow_test radix_sort_test random_test suurballe_test time_measure_test + tsp_test unionfind_test ) @@ -63,11 +69,14 @@ SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${GLPK_LIBRARIES}) ENDIF() IF(LEMON_HAVE_CPLEX) - SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${CPLEX_LIBRARIES}) + SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${ILOG_LIBRARIES}) ENDIF() IF(LEMON_HAVE_CLP) SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${COIN_CLP_LIBRARIES}) ENDIF() + IF(LEMON_HAVE_SOPLEX) + SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${SOPLEX_LIBRARIES}) + ENDIF() TARGET_LINK_LIBRARIES(lp_test ${LP_TEST_LIBS}) ADD_TEST(lp_test lp_test) @@ -87,7 +96,7 @@ GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION) GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CPLEX_BIN_DIR}/cplex.dll ${TARGET_PATH} + COMMAND ${CMAKE_COMMAND} -E copy ${ILOG_CPLEX_DLL} ${TARGET_PATH} ) ENDIF() ENDIF() @@ -105,7 +114,7 @@ SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${GLPK_LIBRARIES}) ENDIF() IF(LEMON_HAVE_CPLEX) - SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${CPLEX_LIBRARIES}) + SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${ILOG_LIBRARIES}) ENDIF() IF(LEMON_HAVE_CBC) SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${COIN_CBC_LIBRARIES}) @@ -129,7 +138,7 @@ GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION) GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CPLEX_BIN_DIR}/cplex.dll ${TARGET_PATH} + COMMAND ${CMAKE_COMMAND} -E copy ${ILOG_CPLEX_DLL} ${TARGET_PATH} ) ENDIF() ENDIF() diff -r cd72eae05bdf -r 3c00344f49c9 test/Makefile.am --- a/test/Makefile.am Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -if USE_VALGRIND -TESTS_ENVIRONMENT=$(top_srcdir)/scripts/valgrind-wrapper.sh -endif - -EXTRA_DIST += \ - test/CMakeLists.txt - -noinst_HEADERS += \ - test/graph_test.h \ - test/test_tools.h - -check_PROGRAMS += \ - test/adaptors_test \ - test/bellman_ford_test \ - test/bfs_test \ - test/circulation_test \ - test/connectivity_test \ - test/counter_test \ - test/dfs_test \ - test/digraph_test \ - test/dijkstra_test \ - test/dim_test \ - 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 \ - test/graph_utils_test \ - test/hao_orlin_test \ - test/heap_test \ - test/kruskal_test \ - test/lgf_test \ - test/maps_test \ - 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 \ - test/suurballe_test \ - test/test_tools_fail \ - test/test_tools_pass \ - test/time_measure_test \ - test/unionfind_test - -test_test_tools_pass_DEPENDENCIES = demo - -if HAVE_LP -check_PROGRAMS += test/lp_test -endif HAVE_LP -if HAVE_MIP -check_PROGRAMS += test/mip_test -endif HAVE_MIP - -TESTS += $(check_PROGRAMS) -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 -test_connectivity_test_SOURCES = test/connectivity_test.cc -test_dfs_test_SOURCES = test/dfs_test.cc -test_digraph_test_SOURCES = test/digraph_test.cc -test_dijkstra_test_SOURCES = test/dijkstra_test.cc -test_dim_test_SOURCES = test/dim_test.cc -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 -test_graph_utils_test_SOURCES = test/graph_utils_test.cc -test_heap_test_SOURCES = test/heap_test.cc -test_kruskal_test_SOURCES = test/kruskal_test.cc -test_hao_orlin_test_SOURCES = test/hao_orlin_test.cc -test_lgf_test_SOURCES = test/lgf_test.cc -test_lp_test_SOURCES = test/lp_test.cc -test_maps_test_SOURCES = test/maps_test.cc -test_mip_test_SOURCES = test/mip_test.cc -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 -test_random_test_SOURCES = test/random_test.cc -test_test_tools_fail_SOURCES = test/test_tools_fail.cc -test_test_tools_pass_SOURCES = test/test_tools_pass.cc -test_time_measure_test_SOURCES = test/time_measure_test.cc -test_unionfind_test_SOURCES = test/unionfind_test.cc diff -r cd72eae05bdf -r 3c00344f49c9 test/adaptors_test.cc --- a/test/adaptors_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/adaptors_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -65,7 +65,7 @@ Digraph::Arc a1 = digraph.addArc(n1, n2); Digraph::Arc a2 = digraph.addArc(n1, n3); Digraph::Arc a3 = digraph.addArc(n2, n3); - ignore_unused_variable_warning(a3); + ::lemon::ignore_unused_variable_warning(a3); // Check the adaptor checkGraphNodeList(adaptor, 3); @@ -100,7 +100,7 @@ Adaptor::Arc a6 = adaptor.addArc(n2, n4); Adaptor::Arc a7 = adaptor.addArc(n1, n4); Adaptor::Arc a8 = adaptor.addArc(n1, n2); - ignore_unused_variable_warning(a6,a7,a8); + ::lemon::ignore_unused_variable_warning(a6,a7,a8); adaptor.erase(a1); adaptor.erase(n3); @@ -760,7 +760,7 @@ Digraph::Arc a1 = digraph.addArc(n1, n2); Digraph::Arc a2 = digraph.addArc(n1, n3); Digraph::Arc a3 = digraph.addArc(n2, n3); - ignore_unused_variable_warning(a1,a2,a3); + ::lemon::ignore_unused_variable_warning(a1,a2,a3); checkGraphNodeList(adaptor, 6); checkGraphArcList(adaptor, 6); diff -r cd72eae05bdf -r 3c00344f49c9 test/arc_look_up_test.cc --- a/test/arc_look_up_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/arc_look_up_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -24,7 +24,6 @@ using namespace lemon; -const int lgfn = 4; const std::string lgf = "@nodes\n" "label\n" @@ -68,17 +67,17 @@ ListDigraph graph; std::istringstream lgfs(lgf); DigraphReader(graph, lgfs).run(); - + AllArcLookUp lookup(graph); - + int numArcs = countArcs(graph); - + int arcCnt = 0; for(ListDigraph::NodeIt n1(graph); n1 != INVALID; ++n1) for(ListDigraph::NodeIt n2(graph); n2 != INVALID; ++n2) for(ListDigraph::Arc a = lookup(n1, n2); a != INVALID; - a = lookup(n1, n2, a)) - ++arcCnt; + a = lookup(n1, n2, a)) + ++arcCnt; check(arcCnt==numArcs, "Wrong total number of arcs"); return 0; diff -r cd72eae05bdf -r 3c00344f49c9 test/bellman_ford_test.cc --- a/test/bellman_ford_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/bellman_ford_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -65,8 +65,10 @@ Node s, t, n; Arc e; Value l; + ::lemon::ignore_unused_variable_warning(l); int k=3; bool b; + ::lemon::ignore_unused_variable_warning(b); BF::DistMap d(gr); BF::PredMap p(gr); LengthMap length; @@ -147,6 +149,8 @@ Digraph g; bool b; + ::lemon::ignore_unused_variable_warning(b); + bellmanFord(g,LengthMap()).run(Node()); b = bellmanFord(g,LengthMap()).run(Node(),Node()); bellmanFord(g,LengthMap()) @@ -190,7 +194,7 @@ check(pathTarget(gr, p) == t, "path() found a wrong path."); ListPath path; - Value dist; + Value dist = 0; bool reached = bellmanFord(gr,length).path(path).dist(dist).run(s,t); check(reached && dist == -1, "Bellman-Ford found a wrong path."); diff -r cd72eae05bdf -r 3c00344f49c9 test/bfs_test.cc --- a/test/bfs_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/bfs_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -61,6 +61,7 @@ Node s, t, n; Arc e; int l, i; + ::lemon::ignore_unused_variable_warning(l,i); bool b; BType::DistMap d(G); BType::PredMap p(G); @@ -150,6 +151,8 @@ Digraph g; bool b; + ::lemon::ignore_unused_variable_warning(b); + bfs(g).run(Node()); b=bfs(g).run(Node(),Node()); bfs(g).run(); diff -r cd72eae05bdf -r 3c00344f49c9 test/bpgraph_test.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bpgraph_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,456 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 "test_tools.h" +#include "graph_test.h" + +using namespace lemon; +using namespace lemon::concepts; + +template +void checkBpGraphBuild() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G; + checkGraphNodeList(G, 0); + checkGraphRedNodeList(G, 0); + checkGraphBlueNodeList(G, 0); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + G.reserveNode(3); + G.reserveEdge(3); + + RedNode + rn1 = G.addRedNode(); + checkGraphNodeList(G, 1); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 0); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + BlueNode + bn1 = G.addBlueNode(), + bn2 = G.addBlueNode(); + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 0); + checkGraphArcList(G, 0); + + Edge e1 = G.addEdge(rn1, bn2); + check(G.redNode(e1) == rn1 && G.blueNode(e1) == bn2, "Wrong edge"); + check(G.u(e1) == rn1 && G.v(e1) == bn2, "Wrong edge"); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 1); + checkGraphArcList(G, 2); + + checkGraphIncEdgeArcLists(G, rn1, 1); + checkGraphIncEdgeArcLists(G, bn1, 0); + checkGraphIncEdgeArcLists(G, bn2, 1); + + checkGraphConEdgeList(G, 1); + checkGraphConArcList(G, 2); + + Edge + e2 = G.addEdge(bn1, rn1), + e3 = G.addEdge(rn1, bn2); + ::lemon::ignore_unused_variable_warning(e2,e3); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + checkGraphIncEdgeArcLists(G, rn1, 3); + checkGraphIncEdgeArcLists(G, bn1, 1); + checkGraphIncEdgeArcLists(G, bn2, 2); + + checkGraphConEdgeList(G, 3); + checkGraphConArcList(G, 6); + + checkArcDirections(G); + + checkNodeIds(G); + checkRedNodeIds(G); + checkBlueNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + + checkGraphNodeMap(G); + checkGraphRedNodeMap(G); + checkGraphBlueNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); +} + +template +void checkBpGraphErase() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G; + RedNode + n1 = G.addRedNode(), n4 = G.addRedNode(); + BlueNode + n2 = G.addBlueNode(), n3 = G.addBlueNode(); + Edge + e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3), + e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3); + ::lemon::ignore_unused_variable_warning(e1,e3,e4); + + // Check edge deletion + G.erase(e2); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 3); + checkGraphArcList(G, 6); + + checkGraphIncEdgeArcLists(G, n1, 1); + checkGraphIncEdgeArcLists(G, n2, 2); + checkGraphIncEdgeArcLists(G, n3, 1); + checkGraphIncEdgeArcLists(G, n4, 2); + + checkGraphConEdgeList(G, 3); + checkGraphConArcList(G, 6); + + // Check node deletion + G.erase(n3); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 1); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + checkGraphIncEdgeArcLists(G, n1, 1); + checkGraphIncEdgeArcLists(G, n2, 2); + checkGraphIncEdgeArcLists(G, n4, 1); + + checkGraphConEdgeList(G, 2); + checkGraphConArcList(G, 4); + +} + +template +void checkBpGraphAlter() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G; + RedNode + n1 = G.addRedNode(), n4 = G.addRedNode(); + BlueNode + n2 = G.addBlueNode(), n3 = G.addBlueNode(); + Edge + e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3), + e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3); + ::lemon::ignore_unused_variable_warning(e1,e3,e4); + + G.changeRed(e2, n4); + check(G.redNode(e2) == n4, "Wrong red node"); + check(G.blueNode(e2) == n3, "Wrong blue node"); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 4); + checkGraphArcList(G, 8); + + checkGraphIncEdgeArcLists(G, n1, 1); + checkGraphIncEdgeArcLists(G, n2, 2); + checkGraphIncEdgeArcLists(G, n3, 2); + checkGraphIncEdgeArcLists(G, n4, 3); + + checkGraphConEdgeList(G, 4); + checkGraphConArcList(G, 8); + + G.changeBlue(e2, n2); + check(G.redNode(e2) == n4, "Wrong red node"); + check(G.blueNode(e2) == n2, "Wrong blue node"); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 4); + checkGraphArcList(G, 8); + + checkGraphIncEdgeArcLists(G, n1, 1); + checkGraphIncEdgeArcLists(G, n2, 3); + checkGraphIncEdgeArcLists(G, n3, 1); + checkGraphIncEdgeArcLists(G, n4, 3); + + checkGraphConEdgeList(G, 4); + checkGraphConArcList(G, 8); +} + + +template +void checkBpGraphSnapshot() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G; + RedNode + n1 = G.addRedNode(); + BlueNode + n2 = G.addBlueNode(), + n3 = G.addBlueNode(); + Edge + e1 = G.addEdge(n1, n2), + e2 = G.addEdge(n1, n3); + ::lemon::ignore_unused_variable_warning(e1,e2); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + typename BpGraph::Snapshot snapshot(G); + + RedNode n4 = G.addRedNode(); + G.addEdge(n4, n2); + G.addEdge(n4, n3); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 4); + checkGraphArcList(G, 8); + + snapshot.restore(); + + checkGraphNodeList(G, 3); + checkGraphRedNodeList(G, 1); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + checkGraphIncEdgeArcLists(G, n1, 2); + checkGraphIncEdgeArcLists(G, n2, 1); + checkGraphIncEdgeArcLists(G, n3, 1); + + checkGraphConEdgeList(G, 2); + checkGraphConArcList(G, 4); + + checkNodeIds(G); + checkRedNodeIds(G); + checkBlueNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + + checkGraphNodeMap(G); + checkGraphRedNodeMap(G); + checkGraphBlueNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); + + G.addRedNode(); + snapshot.save(G); + + G.addEdge(G.addRedNode(), G.addBlueNode()); + + snapshot.restore(); + snapshot.save(G); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); + + G.addEdge(G.addRedNode(), G.addBlueNode()); + + snapshot.restore(); + + checkGraphNodeList(G, 4); + checkGraphRedNodeList(G, 2); + checkGraphBlueNodeList(G, 2); + checkGraphEdgeList(G, 2); + checkGraphArcList(G, 4); +} + +template +void checkBpGraphValidity() { + TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); + BpGraph g; + + RedNode + n1 = g.addRedNode(); + BlueNode + n2 = g.addBlueNode(), + n3 = g.addBlueNode(); + + Edge + e1 = g.addEdge(n1, n2), + e2 = g.addEdge(n1, n3); + ::lemon::ignore_unused_variable_warning(e2); + + check(g.valid(n1), "Wrong validity check"); + check(g.valid(e1), "Wrong validity check"); + check(g.valid(g.direct(e1, true)), "Wrong validity check"); + + check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.edgeFromId(-1)), "Wrong validity check"); + check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); +} + +void checkConcepts() { + { // Checking graph components + checkConcept(); + + checkConcept, + IDableBpGraphComponent<> >(); + + checkConcept, + IterableBpGraphComponent<> >(); + + checkConcept, + AlterableBpGraphComponent<> >(); + + checkConcept, + MappableBpGraphComponent<> >(); + + checkConcept, + ExtendableBpGraphComponent<> >(); + + checkConcept, + ErasableBpGraphComponent<> >(); + + checkConcept, + ClearableBpGraphComponent<> >(); + + } + { // Checking skeleton graph + checkConcept(); + } + { // Checking SmartBpGraph + checkConcept(); + checkConcept, SmartBpGraph>(); + checkConcept, SmartBpGraph>(); + checkConcept, SmartBpGraph>(); + } +} + +void checkFullBpGraph(int redNum, int blueNum) { + typedef FullBpGraph BpGraph; + BPGRAPH_TYPEDEFS(BpGraph); + + BpGraph G(redNum, blueNum); + checkGraphNodeList(G, redNum + blueNum); + checkGraphRedNodeList(G, redNum); + checkGraphBlueNodeList(G, blueNum); + checkGraphEdgeList(G, redNum * blueNum); + checkGraphArcList(G, 2 * redNum * blueNum); + + G.resize(redNum, blueNum); + checkGraphNodeList(G, redNum + blueNum); + checkGraphRedNodeList(G, redNum); + checkGraphBlueNodeList(G, blueNum); + checkGraphEdgeList(G, redNum * blueNum); + checkGraphArcList(G, 2 * redNum * blueNum); + + for (RedNodeIt n(G); n != INVALID; ++n) { + checkGraphOutArcList(G, n, blueNum); + checkGraphInArcList(G, n, blueNum); + checkGraphIncEdgeList(G, n, blueNum); + } + + for (BlueNodeIt n(G); n != INVALID; ++n) { + checkGraphOutArcList(G, n, redNum); + checkGraphInArcList(G, n, redNum); + checkGraphIncEdgeList(G, n, redNum); + } + + checkGraphConArcList(G, 2 * redNum * blueNum); + checkGraphConEdgeList(G, redNum * blueNum); + + checkArcDirections(G); + + checkNodeIds(G); + checkRedNodeIds(G); + checkBlueNodeIds(G); + checkArcIds(G); + checkEdgeIds(G); + + checkGraphNodeMap(G); + checkGraphRedNodeMap(G); + checkGraphBlueNodeMap(G); + checkGraphArcMap(G); + checkGraphEdgeMap(G); + + for (int i = 0; i < G.redNum(); ++i) { + check(G.red(G.redNode(i)), "Wrong node"); + check(G.index(G.redNode(i)) == i, "Wrong index"); + } + + for (int i = 0; i < G.blueNum(); ++i) { + check(G.blue(G.blueNode(i)), "Wrong node"); + check(G.index(G.blueNode(i)) == i, "Wrong index"); + } + + for (NodeIt u(G); u != INVALID; ++u) { + for (NodeIt v(G); v != INVALID; ++v) { + Edge e = G.edge(u, v); + Arc a = G.arc(u, v); + if (G.red(u) == G.red(v)) { + check(e == INVALID, "Wrong edge lookup"); + check(a == INVALID, "Wrong arc lookup"); + } else { + check((G.u(e) == u && G.v(e) == v) || + (G.u(e) == v && G.v(e) == u), "Wrong edge lookup"); + check(G.source(a) == u && G.target(a) == v, "Wrong arc lookup"); + } + } + } + +} + +void checkGraphs() { + { // Checking ListGraph + checkBpGraphBuild(); + checkBpGraphErase(); + checkBpGraphAlter(); + checkBpGraphSnapshot(); + checkBpGraphValidity(); + } + { // Checking SmartGraph + checkBpGraphBuild(); + checkBpGraphSnapshot(); + checkBpGraphValidity(); + } + { // Checking FullBpGraph + checkFullBpGraph(6, 8); + checkFullBpGraph(7, 4); + } +} + +int main() { + checkConcepts(); + checkGraphs(); + return 0; +} diff -r cd72eae05bdf -r 3c00344f49c9 test/circulation_test.cc --- a/test/circulation_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/circulation_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -73,6 +73,7 @@ BarrierMap bar; VType v; bool b; + ::lemon::ignore_unused_variable_warning(v,b); typedef Circulation ::SetFlowMap @@ -103,7 +104,7 @@ b = const_circ_test.barrier(n); const_circ_test.barrierMap(bar); - ignore_unused_variable_warning(fm); + ::lemon::ignore_unused_variable_warning(fm); } template diff -r cd72eae05bdf -r 3c00344f49c9 test/connectivity_test.cc --- a/test/connectivity_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/connectivity_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -68,7 +68,7 @@ Digraph::NodeMap order(d); Graph g(d); Digraph::Node n = d.addNode(); - ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(n); check(stronglyConnected(d), "This digraph is strongly connected"); check(countStronglyConnectedComponents(d) == 1, @@ -99,6 +99,23 @@ } { + ListGraph g; + ListGraph::NodeMap map(g); + + ListGraph::Node n1 = g.addNode(); + ListGraph::Node n2 = g.addNode(); + + ListGraph::Edge e1 = g.addEdge(n1, n2); + ::lemon::ignore_unused_variable_warning(e1); + check(biNodeConnected(g), "Graph is bi-node-connected"); + + ListGraph::Node n3 = g.addNode(); + ::lemon::ignore_unused_variable_warning(n3); + check(!biNodeConnected(g), "Graph is not bi-node-connected"); + } + + + { Digraph d; Digraph::NodeMap order(d); Graph g(d); @@ -246,7 +263,7 @@ Digraph::Node shoe = d.addNode(); Digraph::Node watch = d.addNode(); Digraph::Node pants = d.addNode(); - ignore_unused_variable_warning(watch); + ::lemon::ignore_unused_variable_warning(watch); d.addArc(socks, shoe); d.addArc(pants, shoe); diff -r cd72eae05bdf -r 3c00344f49c9 test/dfs_test.cc --- a/test/dfs_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/dfs_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -67,6 +67,8 @@ Arc e; int l, i; bool b; + ::lemon::ignore_unused_variable_warning(l,i,b); + DType::DistMap d(G); DType::PredMap p(G); Path pp; @@ -151,6 +153,8 @@ Digraph g; bool b; + ::lemon::ignore_unused_variable_warning(b); + dfs(g).run(Node()); b=dfs(g).run(Node(),Node()); dfs(g).run(); @@ -219,7 +223,7 @@ Dfs dfs(G); check(dfs.run(s1,t1) && dfs.reached(t1),"Node 3 is reachable from Node 6."); } - + { NullMap myPredMap; dfs(G).predMap(myPredMap).run(s); diff -r cd72eae05bdf -r 3c00344f49c9 test/digraph_test.cc --- a/test/digraph_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/digraph_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -64,7 +64,7 @@ Arc a2 = G.addArc(n2, n1), a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3); - ignore_unused_variable_warning(a2,a3,a4); + ::lemon::ignore_unused_variable_warning(a2,a3,a4); checkGraphNodeList(G, 3); checkGraphArcList(G, 4); @@ -93,7 +93,7 @@ Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode(); Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1), a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3); - ignore_unused_variable_warning(a1,a2,a3,a4); + ::lemon::ignore_unused_variable_warning(a1,a2,a3,a4); Node n4 = G.split(n2); @@ -127,7 +127,7 @@ Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1), a3 = G.addArc(n4, n3), a4 = G.addArc(n4, n3), a5 = G.addArc(n2, n4); - ignore_unused_variable_warning(a1,a2,a3,a5); + ::lemon::ignore_unused_variable_warning(a1,a2,a3,a5); checkGraphNodeList(G, 4); checkGraphArcList(G, 5); @@ -207,7 +207,7 @@ Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1), a3 = G.addArc(n4, n3), a4 = G.addArc(n3, n1), a5 = G.addArc(n2, n4); - ignore_unused_variable_warning(a2,a3,a4,a5); + ::lemon::ignore_unused_variable_warning(a2,a3,a4,a5); // Check arc deletion G.erase(a1); @@ -255,7 +255,7 @@ Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode(); Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1), a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3); - ignore_unused_variable_warning(a1,a2,a3,a4); + ::lemon::ignore_unused_variable_warning(a1,a2,a3,a4); typename Digraph::Snapshot snapshot(G); @@ -356,7 +356,7 @@ Arc e1 = g.addArc(n1, n2), e2 = g.addArc(n2, n3); - ignore_unused_variable_warning(e2); + ::lemon::ignore_unused_variable_warning(e2); check(g.valid(n1), "Wrong validity check"); check(g.valid(e1), "Wrong validity check"); @@ -442,6 +442,7 @@ a2 = g.addArc(n2, n1), a3 = g.addArc(n2, n3), a4 = g.addArc(n2, n3); + ::lemon::ignore_unused_variable_warning(a2,a3,a4); digraphCopy(g, G).nodeRef(nref).run(); diff -r cd72eae05bdf -r 3c00344f49c9 test/dijkstra_test.cc --- a/test/dijkstra_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/dijkstra_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -65,6 +65,8 @@ VType l; int i; bool b; + ::lemon::ignore_unused_variable_warning(l,i,b); + DType::DistMap d(G); DType::PredMap p(G); LengthMap length; @@ -162,6 +164,8 @@ Digraph g; bool b; + ::lemon::ignore_unused_variable_warning(b); + dijkstra(g,LengthMap()).run(Node()); b=dijkstra(g,LengthMap()).run(Node(),Node()); dijkstra(g,LengthMap()) diff -r cd72eae05bdf -r 3c00344f49c9 test/edge_set_test.cc --- a/test/edge_set_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/edge_set_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -44,12 +44,12 @@ n2 = digraph.addNode(); Digraph::Arc ga1 = digraph.addArc(n1, n2); - ignore_unused_variable_warning(ga1); + ::lemon::ignore_unused_variable_warning(ga1); ArcSet arc_set(digraph); Digraph::Arc ga2 = digraph.addArc(n2, n1); - ignore_unused_variable_warning(ga2); + ::lemon::ignore_unused_variable_warning(ga2); checkGraphNodeList(arc_set, 2); checkGraphArcList(arc_set, 0); @@ -77,7 +77,7 @@ ArcSet::Arc a2 = arc_set.addArc(n2, n1), a3 = arc_set.addArc(n2, n3), a4 = arc_set.addArc(n2, n3); - ignore_unused_variable_warning(a2,a3,a4); + ::lemon::ignore_unused_variable_warning(a2,a3,a4); checkGraphNodeList(arc_set, 3); checkGraphArcList(arc_set, 4); @@ -114,12 +114,12 @@ n2 = digraph.addNode(); Digraph::Arc ga1 = digraph.addArc(n1, n2); - ignore_unused_variable_warning(ga1); + ::lemon::ignore_unused_variable_warning(ga1); ArcSet arc_set(digraph); Digraph::Arc ga2 = digraph.addArc(n2, n1); - ignore_unused_variable_warning(ga2); + ::lemon::ignore_unused_variable_warning(ga2); checkGraphNodeList(arc_set, 2); checkGraphArcList(arc_set, 0); @@ -147,7 +147,7 @@ ArcSet::Arc a2 = arc_set.addArc(n2, n1), a3 = arc_set.addArc(n2, n3), a4 = arc_set.addArc(n2, n3); - ignore_unused_variable_warning(a2,a3,a4); + ::lemon::ignore_unused_variable_warning(a2,a3,a4); checkGraphNodeList(arc_set, 3); checkGraphArcList(arc_set, 4); @@ -198,12 +198,12 @@ n2 = digraph.addNode(); Digraph::Arc ga1 = digraph.addArc(n1, n2); - ignore_unused_variable_warning(ga1); + ::lemon::ignore_unused_variable_warning(ga1); EdgeSet edge_set(digraph); Digraph::Arc ga2 = digraph.addArc(n2, n1); - ignore_unused_variable_warning(ga2); + ::lemon::ignore_unused_variable_warning(ga2); checkGraphNodeList(edge_set, 2); checkGraphArcList(edge_set, 0); @@ -240,7 +240,7 @@ EdgeSet::Edge e2 = edge_set.addEdge(n2, n1), e3 = edge_set.addEdge(n2, n3), e4 = edge_set.addEdge(n2, n3); - ignore_unused_variable_warning(e2,e3,e4); + ::lemon::ignore_unused_variable_warning(e2,e3,e4); checkGraphNodeList(edge_set, 3); checkGraphEdgeList(edge_set, 4); @@ -286,12 +286,12 @@ n2 = digraph.addNode(); Digraph::Arc ga1 = digraph.addArc(n1, n2); - ignore_unused_variable_warning(ga1); + ::lemon::ignore_unused_variable_warning(ga1); EdgeSet edge_set(digraph); Digraph::Arc ga2 = digraph.addArc(n2, n1); - ignore_unused_variable_warning(ga2); + ::lemon::ignore_unused_variable_warning(ga2); checkGraphNodeList(edge_set, 2); checkGraphArcList(edge_set, 0); @@ -328,7 +328,7 @@ EdgeSet::Edge e2 = edge_set.addEdge(n2, n1), e3 = edge_set.addEdge(n2, n3), e4 = edge_set.addEdge(n2, n3); - ignore_unused_variable_warning(e2,e3,e4); + ::lemon::ignore_unused_variable_warning(e2,e3,e4); checkGraphNodeList(edge_set, 3); checkGraphEdgeList(edge_set, 4); diff -r cd72eae05bdf -r 3c00344f49c9 test/euler_test.cc --- a/test/euler_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/euler_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -101,8 +101,8 @@ Digraph d; Graph g(d); Digraph::Node n = d.addNode(); - ignore_unused_variable_warning(n); - + ::lemon::ignore_unused_variable_warning(n); + checkDiEulerIt(d); checkDiEulerIt(g); checkEulerIt(g); @@ -190,7 +190,7 @@ Digraph::Node n3 = d.addNode(); Digraph::Node n4 = d.addNode(); Digraph::Node n5 = d.addNode(); - ignore_unused_variable_warning(n0,n4,n5); + ::lemon::ignore_unused_variable_warning(n0,n4,n5); d.addArc(n1, n2); d.addArc(n2, n3); diff -r cd72eae05bdf -r 3c00344f49c9 test/fractional_matching_test.cc --- a/test/fractional_matching_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/fractional_matching_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -342,6 +342,7 @@ check(indeg == 1, "Invalid matching"); pv += weight[mwfm.matching(n)]; SmartGraph::Node o = graph.target(mwfm.matching(n)); + ::lemon::ignore_unused_variable_warning(o); } else { check(mwfm.nodeValue(n) == 0, "Invalid matching"); check(indeg == 0, "Invalid matching"); @@ -406,6 +407,7 @@ check(indeg == 1, "Invalid perfect matching"); pv += weight[mwpfm.matching(n)]; SmartGraph::Node o = graph.target(mwpfm.matching(n)); + ::lemon::ignore_unused_variable_warning(o); } for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { diff -r cd72eae05bdf -r 3c00344f49c9 test/gomory_hu_test.cc --- a/test/gomory_hu_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/gomory_hu_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -68,6 +68,7 @@ CutMap cut; Value v; int d; + ::lemon::ignore_unused_variable_warning(v,d); GomoryHu gh_test(g, cap); const GomoryHu& diff -r cd72eae05bdf -r 3c00344f49c9 test/graph_copy_test.cc --- a/test/graph_copy_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/graph_copy_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -26,6 +27,7 @@ using namespace std; using namespace lemon; +template void digraph_copy_test() { const int nn = 10; @@ -53,24 +55,24 @@ } // Test digraph copy - ListDigraph to; - ListDigraph::NodeMap tnm(to); - ListDigraph::ArcMap tam(to); - ListDigraph::Node tn; - ListDigraph::Arc ta; + GR to; + typename GR::template NodeMap tnm(to); + typename GR::template ArcMap tam(to); + typename GR::Node tn; + typename GR::Arc ta; - SmartDigraph::NodeMap nr(from); - SmartDigraph::ArcMap er(from); + SmartDigraph::NodeMap nr(from); + SmartDigraph::ArcMap er(from); - ListDigraph::NodeMap ncr(to); - ListDigraph::ArcMap ecr(to); + typename GR::template NodeMap ncr(to); + typename GR::template ArcMap ecr(to); digraphCopy(from, to). nodeMap(fnm, tnm).arcMap(fam, tam). nodeRef(nr).arcRef(er). nodeCrossRef(ncr).arcCrossRef(ecr). node(fn, tn).arc(fa, ta).run(); - + check(countNodes(from) == countNodes(to), "Wrong copy."); check(countArcs(from) == countArcs(to), "Wrong copy."); @@ -86,11 +88,11 @@ check(nr[from.target(it)] == to.target(er[it]), "Wrong copy."); } - for (ListDigraph::NodeIt it(to); it != INVALID; ++it) { + for (typename GR::NodeIt it(to); it != INVALID; ++it) { check(nr[ncr[it]] == it, "Wrong copy."); } - for (ListDigraph::ArcIt it(to); it != INVALID; ++it) { + for (typename GR::ArcIt it(to); it != INVALID; ++it) { check(er[ecr[it]] == it, "Wrong copy."); } check(tn == nr[fn], "Wrong copy."); @@ -98,11 +100,12 @@ // Test repeated copy digraphCopy(from, to).run(); - + check(countNodes(from) == countNodes(to), "Wrong copy."); check(countArcs(from) == countArcs(to), "Wrong copy."); } +template void graph_copy_test() { const int nn = 10; @@ -135,21 +138,21 @@ } // Test graph copy - ListGraph to; - ListGraph::NodeMap tnm(to); - ListGraph::ArcMap tam(to); - ListGraph::EdgeMap tem(to); - ListGraph::Node tn; - ListGraph::Arc ta; - ListGraph::Edge te; + GR to; + typename GR::template NodeMap tnm(to); + typename GR::template ArcMap tam(to); + typename GR::template EdgeMap tem(to); + typename GR::Node tn; + typename GR::Arc ta; + typename GR::Edge te; - SmartGraph::NodeMap nr(from); - SmartGraph::ArcMap ar(from); - SmartGraph::EdgeMap er(from); + SmartGraph::NodeMap nr(from); + SmartGraph::ArcMap ar(from); + SmartGraph::EdgeMap er(from); - ListGraph::NodeMap ncr(to); - ListGraph::ArcMap acr(to); - ListGraph::EdgeMap ecr(to); + typename GR::template NodeMap ncr(to); + typename GR::template ArcMap acr(to); + typename GR::template EdgeMap ecr(to); graphCopy(from, to). nodeMap(fnm, tnm).arcMap(fam, tam).edgeMap(fem, tem). @@ -184,14 +187,14 @@ "Wrong copy."); } - for (ListGraph::NodeIt it(to); it != INVALID; ++it) { + for (typename GR::NodeIt it(to); it != INVALID; ++it) { check(nr[ncr[it]] == it, "Wrong copy."); } - for (ListGraph::ArcIt it(to); it != INVALID; ++it) { + for (typename GR::ArcIt it(to); it != INVALID; ++it) { check(ar[acr[it]] == it, "Wrong copy."); } - for (ListGraph::EdgeIt it(to); it != INVALID; ++it) { + for (typename GR::EdgeIt it(to); it != INVALID; ++it) { check(er[ecr[it]] == it, "Wrong copy."); } check(tn == nr[fn], "Wrong copy."); @@ -200,16 +203,186 @@ // Test repeated copy graphCopy(from, to).run(); - + check(countNodes(from) == countNodes(to), "Wrong copy."); check(countEdges(from) == countEdges(to), "Wrong copy."); check(countArcs(from) == countArcs(to), "Wrong copy."); } +template +void bpgraph_copy_test() { + const int nn = 10; + + // Build a graph + SmartBpGraph from; + SmartBpGraph::NodeMap fnm(from); + SmartBpGraph::RedNodeMap frnm(from); + SmartBpGraph::BlueNodeMap fbnm(from); + SmartBpGraph::ArcMap fam(from); + SmartBpGraph::EdgeMap fem(from); + SmartBpGraph::Node fn = INVALID; + SmartBpGraph::RedNode frn = INVALID; + SmartBpGraph::BlueNode fbn = INVALID; + SmartBpGraph::Arc fa = INVALID; + SmartBpGraph::Edge fe = INVALID; + + std::vector frnv; + for (int i = 0; i < nn; ++i) { + SmartBpGraph::RedNode node = from.addRedNode(); + frnv.push_back(node); + fnm[node] = i * i; + frnm[node] = i + i; + if (i == 0) { + fn = node; + frn = node; + } + } + + std::vector fbnv; + for (int i = 0; i < nn; ++i) { + SmartBpGraph::BlueNode node = from.addBlueNode(); + fbnv.push_back(node); + fnm[node] = i * i; + fbnm[node] = i + i; + if (i == 0) fbn = node; + } + + for (int i = 0; i < nn; ++i) { + for (int j = 0; j < nn; ++j) { + SmartBpGraph::Edge edge = from.addEdge(frnv[i], fbnv[j]); + fem[edge] = i * i + j * j; + fam[from.direct(edge, true)] = i + j * j; + fam[from.direct(edge, false)] = i * i + j; + if (i == 0 && j == 0) fa = from.direct(edge, true); + if (i == 0 && j == 0) fe = edge; + } + } + + // Test graph copy + GR to; + typename GR::template NodeMap tnm(to); + typename GR::template RedNodeMap trnm(to); + typename GR::template BlueNodeMap tbnm(to); + typename GR::template ArcMap tam(to); + typename GR::template EdgeMap tem(to); + typename GR::Node tn; + typename GR::RedNode trn; + typename GR::BlueNode tbn; + typename GR::Arc ta; + typename GR::Edge te; + + SmartBpGraph::NodeMap nr(from); + SmartBpGraph::RedNodeMap rnr(from); + SmartBpGraph::BlueNodeMap bnr(from); + SmartBpGraph::ArcMap ar(from); + SmartBpGraph::EdgeMap er(from); + + typename GR::template NodeMap ncr(to); + typename GR::template RedNodeMap rncr(to); + typename GR::template BlueNodeMap bncr(to); + typename GR::template ArcMap acr(to); + typename GR::template EdgeMap ecr(to); + + bpGraphCopy(from, to). + nodeMap(fnm, tnm). + redNodeMap(frnm, trnm).blueNodeMap(fbnm, tbnm). + arcMap(fam, tam).edgeMap(fem, tem). + nodeRef(nr).redRef(rnr).blueRef(bnr). + arcRef(ar).edgeRef(er). + nodeCrossRef(ncr).redCrossRef(rncr).blueCrossRef(bncr). + arcCrossRef(acr).edgeCrossRef(ecr). + node(fn, tn).redNode(frn, trn).blueNode(fbn, tbn). + arc(fa, ta).edge(fe, te).run(); + + check(countNodes(from) == countNodes(to), "Wrong copy."); + check(countRedNodes(from) == countRedNodes(to), "Wrong copy."); + check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy."); + check(countEdges(from) == countEdges(to), "Wrong copy."); + check(countArcs(from) == countArcs(to), "Wrong copy."); + + for (SmartBpGraph::NodeIt it(from); it != INVALID; ++it) { + check(ncr[nr[it]] == it, "Wrong copy."); + check(fnm[it] == tnm[nr[it]], "Wrong copy."); + } + + for (SmartBpGraph::RedNodeIt it(from); it != INVALID; ++it) { + check(ncr[nr[it]] == it, "Wrong copy."); + check(fnm[it] == tnm[nr[it]], "Wrong copy."); + check(rnr[it] == nr[it], "Wrong copy."); + check(rncr[rnr[it]] == it, "Wrong copy."); + check(frnm[it] == trnm[rnr[it]], "Wrong copy."); + check(to.red(rnr[it]), "Wrong copy."); + } + + for (SmartBpGraph::BlueNodeIt it(from); it != INVALID; ++it) { + check(ncr[nr[it]] == it, "Wrong copy."); + check(fnm[it] == tnm[nr[it]], "Wrong copy."); + check(bnr[it] == nr[it], "Wrong copy."); + check(bncr[bnr[it]] == it, "Wrong copy."); + check(fbnm[it] == tbnm[bnr[it]], "Wrong copy."); + check(to.blue(bnr[it]), "Wrong copy."); + } + + for (SmartBpGraph::ArcIt it(from); it != INVALID; ++it) { + check(acr[ar[it]] == it, "Wrong copy."); + check(fam[it] == tam[ar[it]], "Wrong copy."); + check(nr[from.source(it)] == to.source(ar[it]), "Wrong copy."); + check(nr[from.target(it)] == to.target(ar[it]), "Wrong copy."); + } + + for (SmartBpGraph::EdgeIt it(from); it != INVALID; ++it) { + check(ecr[er[it]] == it, "Wrong copy."); + check(fem[it] == tem[er[it]], "Wrong copy."); + check(nr[from.u(it)] == to.u(er[it]) || nr[from.u(it)] == to.v(er[it]), + "Wrong copy."); + check(nr[from.v(it)] == to.u(er[it]) || nr[from.v(it)] == to.v(er[it]), + "Wrong copy."); + check((from.u(it) != from.v(it)) == (to.u(er[it]) != to.v(er[it])), + "Wrong copy."); + } + + for (typename GR::NodeIt it(to); it != INVALID; ++it) { + check(nr[ncr[it]] == it, "Wrong copy."); + } + for (typename GR::RedNodeIt it(to); it != INVALID; ++it) { + check(rncr[it] == ncr[it], "Wrong copy."); + check(rnr[rncr[it]] == it, "Wrong copy."); + } + for (typename GR::BlueNodeIt it(to); it != INVALID; ++it) { + check(bncr[it] == ncr[it], "Wrong copy."); + check(bnr[bncr[it]] == it, "Wrong copy."); + } + for (typename GR::ArcIt it(to); it != INVALID; ++it) { + check(ar[acr[it]] == it, "Wrong copy."); + } + for (typename GR::EdgeIt it(to); it != INVALID; ++it) { + check(er[ecr[it]] == it, "Wrong copy."); + } + check(tn == nr[fn], "Wrong copy."); + check(trn == rnr[frn], "Wrong copy."); + check(tbn == bnr[fbn], "Wrong copy."); + check(ta == ar[fa], "Wrong copy."); + check(te == er[fe], "Wrong copy."); + + // Test repeated copy + bpGraphCopy(from, to).run(); + + check(countNodes(from) == countNodes(to), "Wrong copy."); + check(countRedNodes(from) == countRedNodes(to), "Wrong copy."); + check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy."); + check(countEdges(from) == countEdges(to), "Wrong copy."); + check(countArcs(from) == countArcs(to), "Wrong copy."); +} + int main() { - digraph_copy_test(); - graph_copy_test(); + digraph_copy_test(); + digraph_copy_test(); + digraph_copy_test(); + graph_copy_test(); + graph_copy_test(); + bpgraph_copy_test(); + bpgraph_copy_test(); return 0; } diff -r cd72eae05bdf -r 3c00344f49c9 test/graph_test.cc --- a/test/graph_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/graph_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -66,7 +66,7 @@ Edge e2 = G.addEdge(n2, n1), e3 = G.addEdge(n2, n3); - ignore_unused_variable_warning(e2,e3); + ::lemon::ignore_unused_variable_warning(e2,e3); checkGraphNodeList(G, 3); checkGraphEdgeList(G, 3); @@ -99,7 +99,7 @@ Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1), e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4), e5 = G.addEdge(n4, n3); - ignore_unused_variable_warning(e1,e3,e4,e5); + ::lemon::ignore_unused_variable_warning(e1,e3,e4,e5); checkGraphNodeList(G, 4); checkGraphEdgeList(G, 5); @@ -179,7 +179,7 @@ Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1), e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4), e5 = G.addEdge(n4, n3); - ignore_unused_variable_warning(e1,e3,e4,e5); + ::lemon::ignore_unused_variable_warning(e1,e3,e4,e5); // Check edge deletion G.erase(e2); @@ -220,7 +220,7 @@ Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode(); Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1), e3 = G.addEdge(n2, n3); - ignore_unused_variable_warning(e1,e2,e3); + ::lemon::ignore_unused_variable_warning(e1,e2,e3); checkGraphNodeList(G, 3); checkGraphEdgeList(G, 3); @@ -385,7 +385,7 @@ Edge e1 = g.addEdge(n1, n2), e2 = g.addEdge(n2, n3); - ignore_unused_variable_warning(e2); + ::lemon::ignore_unused_variable_warning(e2); check(g.valid(n1), "Wrong validity check"); check(g.valid(e1), "Wrong validity check"); @@ -524,7 +524,7 @@ checkGraphArcList(G, dim * (1 << dim)); Node n = G.nodeFromId(dim); - ignore_unused_variable_warning(n); + ::lemon::ignore_unused_variable_warning(n); for (NodeIt n(G); n != INVALID; ++n) { checkGraphIncEdgeList(G, n, dim); diff -r cd72eae05bdf -r 3c00344f49c9 test/graph_test.h --- a/test/graph_test.h Mon Jul 16 16:21:40 2018 +0200 +++ b/test/graph_test.h Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -41,6 +41,42 @@ } template + void checkGraphRedNodeList(const Graph &G, int cnt) + { + typename Graph::RedNodeIt n(G); + for(int i=0;i + void checkGraphBlueNodeList(const Graph &G, int cnt) + { + typename Graph::BlueNodeIt n(G); + for(int i=0;i void checkGraphArcList(const Graph &G, int cnt) { typename Graph::ArcIt e(G); @@ -166,6 +202,7 @@ template void checkNodeIds(const Graph& G) { + typedef typename Graph::Node Node; std::set values; for (typename Graph::NodeIt n(G); n != INVALID; ++n) { check(G.nodeFromId(G.id(n)) == n, "Wrong id"); @@ -173,10 +210,38 @@ check(G.id(n) <= G.maxNodeId(), "Wrong maximum id"); values.insert(G.id(n)); } + check(G.maxId(Node()) <= G.maxNodeId(), "Wrong maximum id"); + } + + template + void checkRedNodeIds(const Graph& G) { + typedef typename Graph::RedNode RedNode; + std::set values; + for (typename Graph::RedNodeIt n(G); n != INVALID; ++n) { + check(G.red(n), "Wrong partition"); + check(values.find(G.id(n)) == values.end(), "Wrong id"); + check(G.id(n) <= G.maxRedId(), "Wrong maximum id"); + values.insert(G.id(n)); + } + check(G.maxId(RedNode()) == G.maxRedId(), "Wrong maximum id"); + } + + template + void checkBlueNodeIds(const Graph& G) { + typedef typename Graph::BlueNode BlueNode; + std::set values; + for (typename Graph::BlueNodeIt n(G); n != INVALID; ++n) { + check(G.blue(n), "Wrong partition"); + check(values.find(G.id(n)) == values.end(), "Wrong id"); + check(G.id(n) <= G.maxBlueId(), "Wrong maximum id"); + values.insert(G.id(n)); + } + check(G.maxId(BlueNode()) == G.maxBlueId(), "Wrong maximum id"); } template void checkArcIds(const Graph& G) { + typedef typename Graph::Arc Arc; std::set values; for (typename Graph::ArcIt a(G); a != INVALID; ++a) { check(G.arcFromId(G.id(a)) == a, "Wrong id"); @@ -184,10 +249,12 @@ check(G.id(a) <= G.maxArcId(), "Wrong maximum id"); values.insert(G.id(a)); } + check(G.maxId(Arc()) <= G.maxArcId(), "Wrong maximum id"); } template void checkEdgeIds(const Graph& G) { + typedef typename Graph::Edge Edge; std::set values; for (typename Graph::EdgeIt e(G); e != INVALID; ++e) { check(G.edgeFromId(G.id(e)) == e, "Wrong id"); @@ -195,6 +262,7 @@ check(G.id(e) <= G.maxEdgeId(), "Wrong maximum id"); values.insert(G.id(e)); } + check(G.maxId(Edge()) <= G.maxEdgeId(), "Wrong maximum id"); } template @@ -228,6 +296,66 @@ } template + void checkGraphRedNodeMap(const Graph& G) { + typedef typename Graph::Node Node; + typedef typename Graph::RedNodeIt RedNodeIt; + + typedef typename Graph::template RedNodeMap IntRedNodeMap; + IntRedNodeMap map(G, 42); + for (RedNodeIt it(G); it != INVALID; ++it) { + check(map[it] == 42, "Wrong map constructor."); + } + int s = 0; + for (RedNodeIt it(G); it != INVALID; ++it) { + map[it] = 0; + check(map[it] == 0, "Wrong operator[]."); + map.set(it, s); + check(map[it] == s, "Wrong set."); + ++s; + } + s = s * (s - 1) / 2; + for (RedNodeIt it(G); it != INVALID; ++it) { + s -= map[it]; + } + check(s == 0, "Wrong sum."); + + // map = constMap(12); + // for (NodeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template + void checkGraphBlueNodeMap(const Graph& G) { + typedef typename Graph::Node Node; + typedef typename Graph::BlueNodeIt BlueNodeIt; + + typedef typename Graph::template BlueNodeMap IntBlueNodeMap; + IntBlueNodeMap map(G, 42); + for (BlueNodeIt it(G); it != INVALID; ++it) { + check(map[it] == 42, "Wrong map constructor."); + } + int s = 0; + for (BlueNodeIt it(G); it != INVALID; ++it) { + map[it] = 0; + check(map[it] == 0, "Wrong operator[]."); + map.set(it, s); + check(map[it] == s, "Wrong set."); + ++s; + } + s = s * (s - 1) / 2; + for (BlueNodeIt it(G); it != INVALID; ++it) { + s -= map[it]; + } + check(s == 0, "Wrong sum."); + + // map = constMap(12); + // for (NodeIt it(G); it != INVALID; ++it) { + // check(map[it] == 12, "Wrong operator[]."); + // } + } + + template void checkGraphArcMap(const Graph& G) { typedef typename Graph::Arc Arc; typedef typename Graph::ArcIt ArcIt; diff -r cd72eae05bdf -r 3c00344f49c9 test/hao_orlin_test.cc --- a/test/hao_orlin_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/hao_orlin_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -66,6 +66,7 @@ CapMap cap; CutMap cut; Value v; + ::lemon::ignore_unused_variable_warning(v); HaoOrlin ho_test(g, cap); const HaoOrlin& diff -r cd72eae05bdf -r 3c00344f49c9 test/heap_test.cc --- a/test/heap_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/heap_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * diff -r cd72eae05bdf -r 3c00344f49c9 test/lgf_reader_writer_test.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/lgf_reader_writer_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,578 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 "test_tools.h" + +struct ReaderConverter { + int operator()(const std::string& str) const { + return str.length(); + } +}; + +struct WriterConverter { + std::string operator()(int value) const { + return std::string(value, '*'); + } +}; + +void checkDigraphReaderCompile() { + typedef lemon::concepts::ExtendableDigraphComponent< + lemon::concepts::Digraph> Digraph; + Digraph digraph; + Digraph::NodeMap node_map(digraph); + Digraph::ArcMap arc_map(digraph); + Digraph::Node node; + Digraph::Arc arc; + int attr; + + lemon::DigraphReader reader(digraph, "filename"); + reader.nodeMap("node_map", node_map); + reader.nodeMap("node_map", node_map, ReaderConverter()); + reader.arcMap("arc_map", arc_map); + reader.arcMap("arc_map", arc_map, ReaderConverter()); + reader.attribute("attr", attr); + reader.attribute("attr", attr, ReaderConverter()); + reader.node("node", node); + reader.arc("arc", arc); + + reader.nodes("alt_nodes_caption"); + reader.arcs("alt_arcs_caption"); + reader.attributes("alt_attrs_caption"); + + reader.useNodes(node_map); + reader.useNodes(node_map, WriterConverter()); + reader.useArcs(arc_map); + reader.useArcs(arc_map, WriterConverter()); + + reader.skipNodes(); + reader.skipArcs(); + + reader.run(); + + lemon::DigraphReader reader2(digraph, std::cin); +} + +void checkDigraphWriterCompile() { + typedef lemon::concepts::Digraph Digraph; + Digraph digraph; + Digraph::NodeMap node_map(digraph); + Digraph::ArcMap arc_map(digraph); + Digraph::Node node; + Digraph::Arc arc; + int attr; + + lemon::DigraphWriter writer(digraph, "filename"); + writer.nodeMap("node_map", node_map); + writer.nodeMap("node_map", node_map, WriterConverter()); + writer.arcMap("arc_map", arc_map); + writer.arcMap("arc_map", arc_map, WriterConverter()); + writer.attribute("attr", attr); + writer.attribute("attr", attr, WriterConverter()); + writer.node("node", node); + writer.arc("arc", arc); + + writer.nodes("alt_nodes_caption"); + writer.arcs("alt_arcs_caption"); + writer.attributes("alt_attrs_caption"); + + writer.skipNodes(); + writer.skipArcs(); + + writer.run(); +} + +void checkGraphReaderCompile() { + typedef lemon::concepts::ExtendableGraphComponent< + lemon::concepts::Graph> Graph; + Graph graph; + Graph::NodeMap node_map(graph); + Graph::ArcMap arc_map(graph); + Graph::EdgeMap edge_map(graph); + Graph::Node node; + Graph::Arc arc; + Graph::Edge edge; + int attr; + + lemon::GraphReader reader(graph, "filename"); + reader.nodeMap("node_map", node_map); + reader.nodeMap("node_map", node_map, ReaderConverter()); + reader.arcMap("arc_map", arc_map); + reader.arcMap("arc_map", arc_map, ReaderConverter()); + reader.edgeMap("edge_map", edge_map); + reader.edgeMap("edge_map", edge_map, ReaderConverter()); + reader.attribute("attr", attr); + reader.attribute("attr", attr, ReaderConverter()); + reader.node("node", node); + reader.arc("arc", arc); + + reader.nodes("alt_nodes_caption"); + reader.edges("alt_edges_caption"); + reader.attributes("alt_attrs_caption"); + + reader.useNodes(node_map); + reader.useNodes(node_map, WriterConverter()); + reader.useEdges(edge_map); + reader.useEdges(edge_map, WriterConverter()); + + reader.skipNodes(); + reader.skipEdges(); + + reader.run(); + + lemon::GraphReader reader2(graph, std::cin); +} + +void checkGraphWriterCompile() { + typedef lemon::concepts::Graph Graph; + Graph graph; + Graph::NodeMap node_map(graph); + Graph::ArcMap arc_map(graph); + Graph::EdgeMap edge_map(graph); + Graph::Node node; + Graph::Arc arc; + Graph::Edge edge; + int attr; + + lemon::GraphWriter writer(graph, "filename"); + writer.nodeMap("node_map", node_map); + writer.nodeMap("node_map", node_map, WriterConverter()); + writer.arcMap("arc_map", arc_map); + writer.arcMap("arc_map", arc_map, WriterConverter()); + writer.edgeMap("edge_map", edge_map); + writer.edgeMap("edge_map", edge_map, WriterConverter()); + writer.attribute("attr", attr); + writer.attribute("attr", attr, WriterConverter()); + writer.node("node", node); + writer.arc("arc", arc); + writer.edge("edge", edge); + + writer.nodes("alt_nodes_caption"); + writer.edges("alt_edges_caption"); + writer.attributes("alt_attrs_caption"); + + writer.skipNodes(); + writer.skipEdges(); + + writer.run(); + + lemon::GraphWriter writer2(graph, std::cout); +} + +void checkBpGraphReaderCompile() { + typedef lemon::concepts::ExtendableBpGraphComponent< + lemon::concepts::BpGraph> BpGraph; + BpGraph graph; + BpGraph::NodeMap node_map(graph); + BpGraph::RedNodeMap red_node_map(graph); + BpGraph::BlueNodeMap blue_node_map(graph); + BpGraph::ArcMap arc_map(graph); + BpGraph::EdgeMap edge_map(graph); + BpGraph::Node node; + BpGraph::RedNode red_node; + BpGraph::BlueNode blue_node; + BpGraph::Arc arc; + BpGraph::Edge edge; + int attr; + + lemon::BpGraphReader reader(graph, "filename"); + reader.nodeMap("node_map", node_map); + reader.nodeMap("node_map", node_map, ReaderConverter()); + reader.redNodeMap("red_node_map", red_node_map); + reader.redNodeMap("red_node_map", red_node_map, ReaderConverter()); + reader.blueNodeMap("blue_node_map", blue_node_map); + reader.blueNodeMap("blue_node_map", blue_node_map, ReaderConverter()); + reader.arcMap("arc_map", arc_map); + reader.arcMap("arc_map", arc_map, ReaderConverter()); + reader.edgeMap("edge_map", edge_map); + reader.edgeMap("edge_map", edge_map, ReaderConverter()); + reader.attribute("attr", attr); + reader.attribute("attr", attr, ReaderConverter()); + reader.node("node", node); + reader.redNode("red_node", red_node); + reader.blueNode("blue_node", blue_node); + reader.arc("arc", arc); + + reader.nodes("alt_nodes_caption"); + reader.edges("alt_edges_caption"); + reader.attributes("alt_attrs_caption"); + + reader.useNodes(node_map); + reader.useNodes(node_map, WriterConverter()); + reader.useEdges(edge_map); + reader.useEdges(edge_map, WriterConverter()); + + reader.skipNodes(); + reader.skipEdges(); + + reader.run(); + + lemon::BpGraphReader reader2(graph, std::cin); +} + +void checkBpGraphWriterCompile() { + typedef lemon::concepts::BpGraph BpGraph; + BpGraph graph; + BpGraph::NodeMap node_map(graph); + BpGraph::RedNodeMap red_node_map(graph); + BpGraph::BlueNodeMap blue_node_map(graph); + BpGraph::ArcMap arc_map(graph); + BpGraph::EdgeMap edge_map(graph); + BpGraph::Node node; + BpGraph::RedNode red_node; + BpGraph::BlueNode blue_node; + BpGraph::Arc arc; + BpGraph::Edge edge; + int attr; + + lemon::BpGraphWriter writer(graph, "filename"); + writer.nodeMap("node_map", node_map); + writer.nodeMap("node_map", node_map, WriterConverter()); + writer.redNodeMap("red_node_map", red_node_map); + writer.redNodeMap("red_node_map", red_node_map, WriterConverter()); + writer.blueNodeMap("blue_node_map", blue_node_map); + writer.blueNodeMap("blue_node_map", blue_node_map, WriterConverter()); + writer.arcMap("arc_map", arc_map); + writer.arcMap("arc_map", arc_map, WriterConverter()); + writer.edgeMap("edge_map", edge_map); + writer.edgeMap("edge_map", edge_map, WriterConverter()); + writer.attribute("attr", attr); + writer.attribute("attr", attr, WriterConverter()); + writer.node("node", node); + writer.redNode("red_node", red_node); + writer.blueNode("blue_node", blue_node); + writer.arc("arc", arc); + + writer.nodes("alt_nodes_caption"); + writer.edges("alt_edges_caption"); + writer.attributes("alt_attrs_caption"); + + writer.skipNodes(); + writer.skipEdges(); + + writer.run(); + + lemon::BpGraphWriter writer2(graph, std::cout); +} + +void checkDigraphReaderWriter() { + typedef lemon::SmartDigraph Digraph; + Digraph digraph; + Digraph::Node n1 = digraph.addNode(); + Digraph::Node n2 = digraph.addNode(); + Digraph::Node n3 = digraph.addNode(); + + Digraph::Arc a1 = digraph.addArc(n1, n2); + Digraph::Arc a2 = digraph.addArc(n2, n3); + + Digraph::NodeMap node_map(digraph); + node_map[n1] = 11; + node_map[n2] = 12; + node_map[n3] = 13; + + Digraph::ArcMap arc_map(digraph); + arc_map[a1] = 21; + arc_map[a2] = 22; + + int attr = 100; + + std::ostringstream os; + lemon::DigraphWriter writer(digraph, os); + + writer.nodeMap("node_map1", node_map); + writer.nodeMap("node_map2", node_map, WriterConverter()); + writer.arcMap("arc_map1", arc_map); + writer.arcMap("arc_map2", arc_map, WriterConverter()); + writer.node("node", n2); + writer.arc("arc", a1); + writer.attribute("attr1", attr); + writer.attribute("attr2", attr, WriterConverter()); + + writer.run(); + + typedef lemon::ListDigraph ExpDigraph; + ExpDigraph exp_digraph; + ExpDigraph::NodeMap exp_node_map1(exp_digraph); + ExpDigraph::NodeMap exp_node_map2(exp_digraph); + ExpDigraph::ArcMap exp_arc_map1(exp_digraph); + ExpDigraph::ArcMap exp_arc_map2(exp_digraph); + ExpDigraph::Node exp_n2; + ExpDigraph::Arc exp_a1; + int exp_attr1; + int exp_attr2; + + std::istringstream is(os.str()); + lemon::DigraphReader reader(exp_digraph, is); + + reader.nodeMap("node_map1", exp_node_map1); + reader.nodeMap("node_map2", exp_node_map2, ReaderConverter()); + reader.arcMap("arc_map1", exp_arc_map1); + reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter()); + reader.node("node", exp_n2); + reader.arc("arc", exp_a1); + reader.attribute("attr1", exp_attr1); + reader.attribute("attr2", exp_attr2, ReaderConverter()); + + reader.run(); + + check(lemon::countNodes(exp_digraph) == 3, "Wrong number of nodes"); + check(lemon::countArcs(exp_digraph) == 2, "Wrong number of arcs"); + check(exp_node_map1[exp_n2] == 12, "Wrong map value"); + check(exp_node_map2[exp_n2] == 12, "Wrong map value"); + check(exp_arc_map1[exp_a1] == 21, "Wrong map value"); + check(exp_arc_map2[exp_a1] == 21, "Wrong map value"); + check(exp_attr1 == 100, "Wrong attr value"); + check(exp_attr2 == 100, "Wrong attr value"); +} + +void checkGraphReaderWriter() { + typedef lemon::SmartGraph Graph; + Graph graph; + Graph::Node n1 = graph.addNode(); + Graph::Node n2 = graph.addNode(); + Graph::Node n3 = graph.addNode(); + + Graph::Edge e1 = graph.addEdge(n1, n2); + Graph::Edge e2 = graph.addEdge(n2, n3); + + Graph::NodeMap node_map(graph); + node_map[n1] = 11; + node_map[n2] = 12; + node_map[n3] = 13; + + Graph::EdgeMap edge_map(graph); + edge_map[e1] = 21; + edge_map[e2] = 22; + + Graph::ArcMap arc_map(graph); + arc_map[graph.direct(e1, true)] = 211; + arc_map[graph.direct(e1, false)] = 212; + arc_map[graph.direct(e2, true)] = 221; + arc_map[graph.direct(e2, false)] = 222; + + int attr = 100; + + std::ostringstream os; + lemon::GraphWriter writer(graph, os); + + writer.nodeMap("node_map1", node_map); + writer.nodeMap("node_map2", node_map, WriterConverter()); + writer.edgeMap("edge_map1", edge_map); + writer.edgeMap("edge_map2", edge_map, WriterConverter()); + writer.arcMap("arc_map1", arc_map); + writer.arcMap("arc_map2", arc_map, WriterConverter()); + writer.node("node", n2); + writer.edge("edge", e1); + writer.arc("arc", graph.direct(e1, false)); + writer.attribute("attr1", attr); + writer.attribute("attr2", attr, WriterConverter()); + + writer.run(); + + typedef lemon::ListGraph ExpGraph; + ExpGraph exp_graph; + ExpGraph::NodeMap exp_node_map1(exp_graph); + ExpGraph::NodeMap exp_node_map2(exp_graph); + ExpGraph::EdgeMap exp_edge_map1(exp_graph); + ExpGraph::EdgeMap exp_edge_map2(exp_graph); + ExpGraph::ArcMap exp_arc_map1(exp_graph); + ExpGraph::ArcMap exp_arc_map2(exp_graph); + ExpGraph::Node exp_n2; + ExpGraph::Edge exp_e1; + ExpGraph::Arc exp_a1; + int exp_attr1; + int exp_attr2; + + std::istringstream is(os.str()); + lemon::GraphReader reader(exp_graph, is); + + reader.nodeMap("node_map1", exp_node_map1); + reader.nodeMap("node_map2", exp_node_map2, ReaderConverter()); + reader.edgeMap("edge_map1", exp_edge_map1); + reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter()); + reader.arcMap("arc_map1", exp_arc_map1); + reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter()); + reader.node("node", exp_n2); + reader.edge("edge", exp_e1); + reader.arc("arc", exp_a1); + reader.attribute("attr1", exp_attr1); + reader.attribute("attr2", exp_attr2, ReaderConverter()); + + reader.run(); + + check(lemon::countNodes(exp_graph) == 3, "Wrong number of nodes"); + check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges"); + check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs"); + check(exp_node_map1[exp_n2] == 12, "Wrong map value"); + check(exp_node_map2[exp_n2] == 12, "Wrong map value"); + check(exp_edge_map1[exp_e1] == 21, "Wrong map value"); + check(exp_edge_map2[exp_e1] == 21, "Wrong map value"); + check(exp_arc_map1[exp_a1] == 212, "Wrong map value"); + check(exp_arc_map2[exp_a1] == 212, "Wrong map value"); + check(exp_attr1 == 100, "Wrong attr value"); + check(exp_attr2 == 100, "Wrong attr value"); +} + +void checkBpGraphReaderWriter() { + typedef lemon::SmartBpGraph Graph; + Graph graph; + Graph::RedNode rn1 = graph.addRedNode(); + Graph::RedNode rn2 = graph.addRedNode(); + Graph::RedNode rn3 = graph.addRedNode(); + Graph::BlueNode bn1 = graph.addBlueNode(); + Graph::BlueNode bn2 = graph.addBlueNode(); + Graph::Node n = bn1; + + Graph::Edge e1 = graph.addEdge(rn1, bn1); + Graph::Edge e2 = graph.addEdge(rn2, bn1); + + Graph::NodeMap node_map(graph); + node_map[rn1] = 11; + node_map[rn2] = 12; + node_map[rn3] = 13; + node_map[bn1] = 14; + node_map[bn2] = 15; + + Graph::NodeMap red_node_map(graph); + red_node_map[rn1] = 411; + red_node_map[rn2] = 412; + red_node_map[rn3] = 413; + + Graph::NodeMap blue_node_map(graph); + blue_node_map[bn1] = 414; + blue_node_map[bn2] = 415; + + Graph::EdgeMap edge_map(graph); + edge_map[e1] = 21; + edge_map[e2] = 22; + + Graph::ArcMap arc_map(graph); + arc_map[graph.direct(e1, true)] = 211; + arc_map[graph.direct(e1, false)] = 212; + arc_map[graph.direct(e2, true)] = 221; + arc_map[graph.direct(e2, false)] = 222; + + int attr = 100; + + std::ostringstream os; + lemon::BpGraphWriter writer(graph, os); + + writer.nodeMap("node_map1", node_map); + writer.nodeMap("node_map2", node_map, WriterConverter()); + writer.nodeMap("red_node_map1", red_node_map); + writer.nodeMap("red_node_map2", red_node_map, WriterConverter()); + writer.nodeMap("blue_node_map1", blue_node_map); + writer.nodeMap("blue_node_map2", blue_node_map, WriterConverter()); + writer.edgeMap("edge_map1", edge_map); + writer.edgeMap("edge_map2", edge_map, WriterConverter()); + writer.arcMap("arc_map1", arc_map); + writer.arcMap("arc_map2", arc_map, WriterConverter()); + writer.node("node", n); + writer.redNode("red_node", rn1); + writer.blueNode("blue_node", bn2); + writer.edge("edge", e1); + writer.arc("arc", graph.direct(e1, false)); + writer.attribute("attr1", attr); + writer.attribute("attr2", attr, WriterConverter()); + + writer.run(); + + typedef lemon::ListBpGraph ExpGraph; + ExpGraph exp_graph; + ExpGraph::NodeMap exp_node_map1(exp_graph); + ExpGraph::NodeMap exp_node_map2(exp_graph); + ExpGraph::RedNodeMap exp_red_node_map1(exp_graph); + ExpGraph::RedNodeMap exp_red_node_map2(exp_graph); + ExpGraph::BlueNodeMap exp_blue_node_map1(exp_graph); + ExpGraph::BlueNodeMap exp_blue_node_map2(exp_graph); + ExpGraph::EdgeMap exp_edge_map1(exp_graph); + ExpGraph::EdgeMap exp_edge_map2(exp_graph); + ExpGraph::ArcMap exp_arc_map1(exp_graph); + ExpGraph::ArcMap exp_arc_map2(exp_graph); + ExpGraph::Node exp_n; + ExpGraph::RedNode exp_rn1; + ExpGraph::BlueNode exp_bn2; + ExpGraph::Edge exp_e1; + ExpGraph::Arc exp_a1; + int exp_attr1; + int exp_attr2; + + std::istringstream is(os.str()); + lemon::BpGraphReader reader(exp_graph, is); + + reader.nodeMap("node_map1", exp_node_map1); + reader.nodeMap("node_map2", exp_node_map2, ReaderConverter()); + reader.redNodeMap("red_node_map1", exp_red_node_map1); + reader.redNodeMap("red_node_map2", exp_red_node_map2, ReaderConverter()); + reader.blueNodeMap("blue_node_map1", exp_blue_node_map1); + reader.blueNodeMap("blue_node_map2", exp_blue_node_map2, ReaderConverter()); + reader.edgeMap("edge_map1", exp_edge_map1); + reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter()); + reader.arcMap("arc_map1", exp_arc_map1); + reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter()); + reader.node("node", exp_n); + reader.redNode("red_node", exp_rn1); + reader.blueNode("blue_node", exp_bn2); + reader.edge("edge", exp_e1); + reader.arc("arc", exp_a1); + reader.attribute("attr1", exp_attr1); + reader.attribute("attr2", exp_attr2, ReaderConverter()); + + reader.run(); + + check(lemon::countNodes(exp_graph) == 5, "Wrong number of nodes"); + check(lemon::countRedNodes(exp_graph) == 3, "Wrong number of red nodes"); + check(lemon::countBlueNodes(exp_graph) == 2, "Wrong number of blue nodes"); + check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges"); + check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs"); + check(exp_node_map1[exp_n] == 14, "Wrong map value"); + check(exp_node_map2[exp_n] == 14, "Wrong map value"); + check(exp_red_node_map1[exp_rn1] == 411, "Wrong map value"); + check(exp_red_node_map2[exp_rn1] == 411, "Wrong map value"); + check(exp_blue_node_map1[exp_bn2] == 415, "Wrong map value"); + check(exp_blue_node_map2[exp_bn2] == 415, "Wrong map value"); + check(exp_edge_map1[exp_e1] == 21, "Wrong map value"); + check(exp_edge_map2[exp_e1] == 21, "Wrong map value"); + check(exp_arc_map1[exp_a1] == 212, "Wrong map value"); + check(exp_arc_map2[exp_a1] == 212, "Wrong map value"); + check(exp_attr1 == 100, "Wrong attr value"); + check(exp_attr2 == 100, "Wrong attr value"); +} + + +int main() { + { // Check digrpah + checkDigraphReaderWriter(); + } + { // Check graph + checkGraphReaderWriter(); + } + { // Check bipartite graph + checkBpGraphReaderWriter(); + } + return 0; +} diff -r cd72eae05bdf -r 3c00344f49c9 test/lgf_test.cc --- a/test/lgf_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/lgf_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2011 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -63,10 +63,10 @@ "0 1\n"; -int main() +int main() { { - ListDigraph d; + ListDigraph d; ListDigraph::Node s,t; ListDigraph::ArcMap label(d); std::istringstream input(test_lgf); @@ -93,7 +93,7 @@ } { - ListDigraph d; + ListDigraph d; std::istringstream input(test_lgf_nomap); digraphReader(d, input). run(); @@ -110,14 +110,14 @@ } { - ListDigraph d; + ListDigraph d; std::istringstream input(test_lgf_bad1); bool ok=false; try { digraphReader(d, input). run(); } - catch (FormatError&) + catch (FormatError&) { ok = true; } @@ -139,7 +139,7 @@ } { - ListDigraph d; + ListDigraph d; std::istringstream input(test_lgf_bad2); bool ok=false; try { diff -r cd72eae05bdf -r 3c00344f49c9 test/lp_test.cc --- a/test/lp_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/lp_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -39,6 +39,9 @@ #include #endif +#ifdef LEMON_HAVE_LP +#include +#endif using namespace lemon; int countCols(LpBase & lp) { @@ -198,7 +201,12 @@ LP::Constr c = v >= -3; c = c <= 4; LP::Constr c2; +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 3 ) + c2 = ( -3 <= v ) <= 4; +#else c2 = -3 <= v <= 4; +#endif + } e[x[3]]=2; @@ -240,8 +248,7 @@ { LP::DualExpr e,f,g; - LP::Row p1 = INVALID, p2 = INVALID, p3 = INVALID, - p4 = INVALID, p5 = INVALID; + LP::Row p1 = INVALID, p2 = INVALID; e[p1]=2; e[p1]+=2; @@ -412,6 +419,15 @@ LpSkeleton lp_skel; lpTest(lp_skel); +#ifdef LEMON_HAVE_LP + { + Lp lp,lp2; + lpTest(lp); + aTest(lp2); + cloneTest(); + } +#endif + #ifdef LEMON_HAVE_GLPK { GlpkLp lp_glpk1,lp_glpk2; diff -r cd72eae05bdf -r 3c00344f49c9 test/maps_test.cc --- a/test/maps_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/maps_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -103,7 +103,7 @@ checkConcept, NullMap >(); NullMap map1; NullMap map2 = map1; - ignore_unused_variable_warning(map2); + ::lemon::ignore_unused_variable_warning(map2); map1 = nullMap(); } @@ -114,14 +114,14 @@ ConstMap map1; ConstMap map2 = B(); ConstMap map3 = map1; - ignore_unused_variable_warning(map2,map3); + ::lemon::ignore_unused_variable_warning(map2,map3); map1 = constMap(B()); map1 = constMap(); map1.setAll(B()); ConstMap map4(C(1)); ConstMap map5 = map4; - ignore_unused_variable_warning(map5); + ::lemon::ignore_unused_variable_warning(map5); map4 = constMap(C(2)); map4.setAll(C(3)); @@ -143,7 +143,7 @@ checkConcept, IdentityMap >(); IdentityMap map1; IdentityMap map2 = map1; - ignore_unused_variable_warning(map2); + ::lemon::ignore_unused_variable_warning(map2); map1 = identityMap(); @@ -204,9 +204,9 @@ typedef ComposeMap > CompMap; checkConcept, CompMap>(); CompMap map1 = CompMap(DoubleMap(),ReadMap()); - ignore_unused_variable_warning(map1); + ::lemon::ignore_unused_variable_warning(map1); CompMap map2 = composeMap(DoubleMap(), ReadMap()); - ignore_unused_variable_warning(map2); + ::lemon::ignore_unused_variable_warning(map2); SparseMap m1(false); m1[3.14] = true; RangeMap m2(2); m2[0] = 3.0; m2[1] = 3.14; @@ -219,9 +219,9 @@ typedef CombineMap > CombMap; checkConcept, CombMap>(); CombMap map1 = CombMap(DoubleMap(), DoubleMap()); - ignore_unused_variable_warning(map1); + ::lemon::ignore_unused_variable_warning(map1); CombMap map2 = combineMap(DoubleMap(), DoubleMap(), std::plus()); - ignore_unused_variable_warning(map2); + ::lemon::ignore_unused_variable_warning(map2); check(combineMap(constMap(), identityMap(), &binc)[B()] == 3, "Something is wrong with CombineMap"); @@ -233,15 +233,15 @@ checkConcept, FunctorToMap >(); FunctorToMap map1; FunctorToMap map2 = FunctorToMap(F()); - ignore_unused_variable_warning(map2); + ::lemon::ignore_unused_variable_warning(map2); B b = functorToMap(F())[A()]; - ignore_unused_variable_warning(b); + ::lemon::ignore_unused_variable_warning(b); checkConcept, MapToFunctor > >(); MapToFunctor > map = MapToFunctor >(ReadMap()); - ignore_unused_variable_warning(map); + ::lemon::ignore_unused_variable_warning(map); check(functorToMap(&func)[A()] == 3, "Something is wrong with FunctorToMap"); @@ -259,9 +259,9 @@ checkConcept, ConvertMap, double> >(); ConvertMap, int> map1(rangeMap(1, true)); - ignore_unused_variable_warning(map1); + ::lemon::ignore_unused_variable_warning(map1); ConvertMap, int> map2 = convertMap(rangeMap(2, false)); - ignore_unused_variable_warning(map2); + ::lemon::ignore_unused_variable_warning(map2); } @@ -535,7 +535,8 @@ "Wrong SourceMap or TargetMap"); typedef Orienter > Digraph; - Digraph dgr(gr, constMap(true)); + ConstMap true_edge_map(true); + Digraph dgr(gr, true_edge_map); OutDegMap odm(dgr); InDegMap idm(dgr); diff -r cd72eae05bdf -r 3c00344f49c9 test/matching_test.cc --- a/test/matching_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/matching_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -145,6 +145,7 @@ MaxMatching::Status stat = const_mat_test.status(n); + ::lemon::ignore_unused_variable_warning(stat); const MaxMatching::StatusMap& smap = const_mat_test.statusMap(); stat = smap[n]; diff -r cd72eae05bdf -r 3c00344f49c9 test/max_cardinality_search_test.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/max_cardinality_search_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,162 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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" +#include +#include +#include +#include +#include +#include + +using namespace lemon; +using namespace std; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "@arcs\n" + " label capacity\n" + "0 1 0 2\n" + "1 0 1 2\n" + "2 1 2 1\n" + "2 3 3 3\n" + "3 2 4 3\n" + "3 1 5 5\n" + "@attributes\n" + "s 0\n" + "x 1\n" + "y 2\n" + "z 3\n"; + +void checkMaxCardSearchCompile() { + + typedef concepts::Digraph Digraph; + typedef int Value; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef concepts::ReadMap CapMap; + typedef concepts::ReadWriteMap CardMap; + typedef concepts::ReadWriteMap ProcMap; + typedef Digraph::NodeMap HeapCrossRef; + + Digraph g; + Node n,s; + CapMap cap; + CardMap card; + ProcMap proc; + HeapCrossRef crossref(g); + + typedef MaxCardinalitySearch + ::SetCapacityMap + ::SetCardinalityMap + ::SetProcessedMap + ::SetStandardHeap > + ::Create MaxCardType; + + MaxCardType maxcard(g,cap); + const MaxCardType& const_maxcard = maxcard; + + const MaxCardType::Heap& heap_const = const_maxcard.heap(); + MaxCardType::Heap& heap = const_cast(heap_const); + maxcard.heap(heap,crossref); + + maxcard.capacityMap(cap).cardinalityMap(card).processedMap(proc); + + maxcard.init(); + maxcard.addSource(s); + n = maxcard.nextNode(); + maxcard.processNextNode(); + maxcard.start(); + maxcard.run(s); + maxcard.run(); + } + + void checkWithIntMap( std::istringstream& input) + { + typedef SmartDigraph Digraph; + typedef Digraph::Node Node; + typedef Digraph::ArcMap CapMap; + + Digraph g; + Node s,x,y,z,a; + CapMap cap(g); + + DigraphReader(g,input). + arcMap("capacity", cap). + node("s",s). + node("x",x). + node("y",y). + node("z",z). + run(); + + MaxCardinalitySearch maxcard(g,cap); + + maxcard.init(); + maxcard.addSource(s); + maxcard.start(x); + + check(maxcard.processed(s) && !maxcard.processed(x) && + !maxcard.processed(y), "Wrong processed()!"); + + a=maxcard.nextNode(); + check(maxcard.processNextNode()==a, + "Wrong nextNode() or processNextNode() return value!"); + + check(maxcard.processed(a), "Wrong processNextNode()!"); + + maxcard.start(); + check(maxcard.cardinality(x)==2 && maxcard.cardinality(y)>=4, + "Wrong cardinalities!"); + } + + void checkWithConst1Map(std::istringstream &input) { + typedef SmartDigraph Digraph; + typedef Digraph::Node Node; + + Digraph g; + Node s,x,y,z; + + DigraphReader(g,input). + node("s",s). + node("x",x). + node("y",y). + node("z",z). + run(); + + MaxCardinalitySearch maxcard(g); + maxcard.run(s); + check(maxcard.cardinality(x)==1 && + maxcard.cardinality(y)+maxcard.cardinality(z)==3, + "Wrong cardinalities!"); +} + +int main() { + + std::istringstream input1(test_lgf); + checkWithIntMap(input1); + + std::istringstream input2(test_lgf); + checkWithConst1Map(input2); +} diff -r cd72eae05bdf -r 3c00344f49c9 test/max_clique_test.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/max_clique_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,188 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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; + +char test_lgf[] = + "@nodes\n" + "label max_clique\n" + "1 0\n" + "2 0\n" + "3 0\n" + "4 1\n" + "5 1\n" + "6 1\n" + "7 1\n" + "@edges\n" + " label\n" + "1 2 1\n" + "1 3 2\n" + "1 4 3\n" + "1 6 4\n" + "2 3 5\n" + "2 5 6\n" + "2 7 7\n" + "3 4 8\n" + "3 5 9\n" + "4 5 10\n" + "4 6 11\n" + "4 7 12\n" + "5 6 13\n" + "5 7 14\n" + "6 7 15\n"; + + +// Check with general graphs +template +void checkMaxCliqueGeneral(Param rule) { + typedef ListGraph GR; + typedef GrossoLocatelliPullanMc McAlg; + typedef McAlg::CliqueNodeIt CliqueIt; + + // Basic tests + { + GR g; + GR::NodeMap map(g); + McAlg mc(g); + mc.iterationLimit(50); + check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 0, "Wrong clique size"); + check(CliqueIt(mc) == INVALID, "Wrong CliqueNodeIt"); + + GR::Node u = g.addNode(); + check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 1, "Wrong clique size"); + mc.cliqueMap(map); + check(map[u], "Wrong clique map"); + CliqueIt it1(mc); + check(static_cast(it1) == u && ++it1 == INVALID, + "Wrong CliqueNodeIt"); + + GR::Node v = g.addNode(); + check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 1, "Wrong clique size"); + mc.cliqueMap(map); + check((map[u] && !map[v]) || (map[v] && !map[u]), "Wrong clique map"); + CliqueIt it2(mc); + check(it2 != INVALID && ++it2 == INVALID, "Wrong CliqueNodeIt"); + + g.addEdge(u, v); + check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 2, "Wrong clique size"); + mc.cliqueMap(map); + check(map[u] && map[v], "Wrong clique map"); + CliqueIt it3(mc); + check(it3 != INVALID && ++it3 != INVALID && ++it3 == INVALID, + "Wrong CliqueNodeIt"); + } + + // Test graph + { + GR g; + GR::NodeMap max_clique(g); + GR::NodeMap map(g); + std::istringstream input(test_lgf); + graphReader(g, input) + .nodeMap("max_clique", max_clique) + .run(); + + McAlg mc(g); + mc.iterationLimit(50); + check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 4, "Wrong clique size"); + mc.cliqueMap(map); + for (GR::NodeIt n(g); n != INVALID; ++n) { + check(map[n] == max_clique[n], "Wrong clique map"); + } + int cnt = 0; + for (CliqueIt n(mc); n != INVALID; ++n) { + cnt++; + check(map[n] && max_clique[n], "Wrong CliqueNodeIt"); + } + check(cnt == 4, "Wrong CliqueNodeIt"); + } +} + +// Check with full graphs +template +void checkMaxCliqueFullGraph(Param rule) { + typedef FullGraph GR; + typedef GrossoLocatelliPullanMc McAlg; + typedef McAlg::CliqueNodeIt CliqueIt; + + for (int size = 0; size <= 40; size = size * 3 + 1) { + GR g(size); + GR::NodeMap map(g); + McAlg mc(g); + check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == size, "Wrong clique size"); + mc.cliqueMap(map); + for (GR::NodeIt n(g); n != INVALID; ++n) { + check(map[n], "Wrong clique map"); + } + int cnt = 0; + for (CliqueIt n(mc); n != INVALID; ++n) cnt++; + check(cnt == size, "Wrong CliqueNodeIt"); + } +} + +// Check with grid graphs +template +void checkMaxCliqueGridGraph(Param rule) { + GridGraph g(5, 7); + GridGraph::NodeMap map(g); + GrossoLocatelliPullanMc mc(g); + + mc.iterationLimit(100); + check(mc.run(rule) == mc.ITERATION_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 2, "Wrong clique size"); + + mc.stepLimit(100); + check(mc.run(rule) == mc.STEP_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 2, "Wrong clique size"); + + mc.sizeLimit(2); + check(mc.run(rule) == mc.SIZE_LIMIT, "Wrong termination cause"); + check(mc.cliqueSize() == 2, "Wrong clique size"); +} + + +int main() { + checkMaxCliqueGeneral(GrossoLocatelliPullanMc::RANDOM); + checkMaxCliqueGeneral(GrossoLocatelliPullanMc::DEGREE_BASED); + checkMaxCliqueGeneral(GrossoLocatelliPullanMc::PENALTY_BASED); + + checkMaxCliqueFullGraph(GrossoLocatelliPullanMc::RANDOM); + checkMaxCliqueFullGraph(GrossoLocatelliPullanMc::DEGREE_BASED); + checkMaxCliqueFullGraph(GrossoLocatelliPullanMc::PENALTY_BASED); + + checkMaxCliqueGridGraph(GrossoLocatelliPullanMc::RANDOM); + checkMaxCliqueGridGraph(GrossoLocatelliPullanMc::DEGREE_BASED); + checkMaxCliqueGridGraph(GrossoLocatelliPullanMc::PENALTY_BASED); + + return 0; +} diff -r cd72eae05bdf -r 3c00344f49c9 test/max_flow_test.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/max_flow_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,440 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace lemon; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "8\n" + "9\n" + "@arcs\n" + " label capacity\n" + "0 1 0 20\n" + "0 2 1 0\n" + "1 1 2 3\n" + "1 2 3 8\n" + "1 3 4 8\n" + "2 5 5 5\n" + "3 2 6 5\n" + "3 5 7 5\n" + "3 6 8 5\n" + "4 3 9 3\n" + "5 7 10 3\n" + "5 6 11 10\n" + "5 8 12 10\n" + "6 8 13 8\n" + "8 9 14 20\n" + "8 1 15 5\n" + "9 5 16 5\n" + "@attributes\n" + "source 1\n" + "target 8\n"; + +char test_lgf_float[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "6\n" + "7\n" + "8\n" + "9\n" + "@arcs\n" + " capacity\n" + "0 1 0.1\n" + "0 2 0.1\n" + "0 3 0.1\n" + "1 4 0.1\n" + "2 4 0.1\n" + "3 4 0.1\n" + "4 5 0.3\n" + "5 6 0.1\n" + "5 7 0.1\n" + "5 8 0.1\n" + "6 9 0.1\n" + "7 9 0.1\n" + "8 9 0.1\n" + "@attributes\n" + "source 0\n" + "target 9\n"; + +// Checks the general interface of a max flow algorithm +template +struct MaxFlowClassConcept +{ + + template + struct Constraints { + + typedef typename GR::Node Node; + typedef typename GR::Arc Arc; + typedef typename CAP::Value Value; + typedef concepts::ReadWriteMap FlowMap; + typedef concepts::WriteMap CutMap; + + GR g; + Node n; + Arc e; + CAP cap; + FlowMap flow; + CutMap cut; + Value v; + bool b; + + void constraints() { + checkConcept(); + + const Constraints& me = *this; + + typedef typename MF + ::template SetFlowMap + ::Create MaxFlowType; + typedef typename MF::Create MaxFlowType2; + MaxFlowType max_flow(me.g, me.cap, me.n, me.n); + const MaxFlowType& const_max_flow = max_flow; + + max_flow + .capacityMap(cap) + .flowMap(flow) + .source(n) + .target(n); + + typename MaxFlowType::Tolerance tol = const_max_flow.tolerance(); + max_flow.tolerance(tol); + + max_flow.init(); + max_flow.init(cap); + max_flow.run(); + + v = const_max_flow.flowValue(); + v = const_max_flow.flow(e); + const FlowMap& fm = const_max_flow.flowMap(); + + b = const_max_flow.minCut(n); + const_max_flow.minCutMap(cut); + + ::lemon::ignore_unused_variable_warning(fm); + } + + }; + +}; + +// Checks the specific parts of Preflow's interface +void checkPreflowCompile() +{ + typedef int Value; + typedef concepts::Digraph Digraph; + typedef concepts::ReadMap CapMap; + typedef Elevator Elev; + typedef LinkedElevator LinkedElev; + + Digraph g; + Digraph::Node n; + CapMap cap; + + typedef Preflow + ::SetElevator + ::SetStandardElevator + ::Create PreflowType; + 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)); + + bool b = preflow_test.init(cap); + preflow_test.startFirstPhase(); + preflow_test.startSecondPhase(); + preflow_test.runMinCut(); + + ::lemon::ignore_unused_variable_warning(b); +} + +// Checks the specific parts of EdmondsKarp's interface +void checkEdmondsKarpCompile() +{ + typedef int Value; + typedef concepts::Digraph Digraph; + typedef concepts::ReadMap CapMap; + + Digraph g; + Digraph::Node n; + CapMap cap; + + EdmondsKarp ek_test(g, cap, n, n); + + ek_test.init(cap); + bool b = ek_test.checkedInit(cap); + b = ek_test.augment(); + ek_test.start(); + + ::lemon::ignore_unused_variable_warning(b); +} + + +template +T cutValue(const SmartDigraph& g, + const SmartDigraph::NodeMap& cut, + const SmartDigraph::ArcMap& cap) { + + T c = 0; + for (SmartDigraph::ArcIt e(g); e != INVALID; ++e) { + if (cut[g.source(e)] && !cut[g.target(e)]) c += cap[e]; + } + return c; +} + +template +bool checkFlow(const SmartDigraph& g, + const SmartDigraph::ArcMap& flow, + const SmartDigraph::ArcMap& cap, + SmartDigraph::Node s, SmartDigraph::Node t, + const Tolerance& tol) { + + for (SmartDigraph::ArcIt e(g); e != INVALID; ++e) { + if (tol.negative(flow[e]) || tol.less(cap[e], flow[e])) return false; + } + + for (SmartDigraph::NodeIt n(g); n != INVALID; ++n) { + if (n == s || n == t) continue; + T sum = 0; + for (SmartDigraph::OutArcIt e(g, n); e != INVALID; ++e) { + sum += flow[e]; + } + for (SmartDigraph::InArcIt e(g, n); e != INVALID; ++e) { + sum -= flow[e]; + } + if (tol.nonZero(sum)) return false; + } + return true; +} + +void checkInitPreflow() +{ + DIGRAPH_TYPEDEFS(SmartDigraph); + + SmartDigraph g; + SmartDigraph::ArcMap cap(g), iflow(g); + Node s = g.addNode(); Node t = g.addNode(); + Node n1 = g.addNode(); Node n2 = g.addNode(); + Arc a; + a = g.addArc(s, n1); cap[a] = 20; iflow[a] = 20; + a = g.addArc(n1, n2); cap[a] = 10; iflow[a] = 0; + a = g.addArc(n2, t); cap[a] = 20; iflow[a] = 0; + + Preflow pre(g, cap, s, t); + pre.init(iflow); + pre.startFirstPhase(); + + check(pre.flowValue() == 10, "Incorrect max flow value."); + check(pre.minCut(s), "Wrong min cut (Node s)."); + check(pre.minCut(n1), "Wrong min cut (Node n1)."); + check(!pre.minCut(n2), "Wrong min cut (Node n2)."); + check(!pre.minCut(t), "Wrong min cut (Node t)."); +} + +template +void checkMaxFlowAlg(const char *input_lgf, typename MF::Value expected) { + typedef SmartDigraph Digraph; + DIGRAPH_TYPEDEFS(Digraph); + + typedef typename MF::Value Value; + typedef Digraph::ArcMap CapMap; + typedef CapMap FlowMap; + typedef BoolNodeMap CutMap; + + Tolerance tol; + + Digraph g; + Node s, t; + CapMap cap(g); + std::istringstream input(input_lgf); + DigraphReader(g, input) + .arcMap("capacity", cap) + .node("source", s) + .node("target", t) + .run(); + + MF max_flow(g, cap, s, t); + max_flow.run(); + + check(!tol.different(expected, max_flow.flowValue()), + "Incorrect max flow value."); + check(checkFlow(g, max_flow.flowMap(), cap, s, t, tol), + "The flow is not feasible."); + + CutMap min_cut(g); + max_flow.minCutMap(min_cut); + Value min_cut_value = cutValue(g, min_cut, cap); + + check(!tol.different(expected, min_cut_value), + "Incorrect min cut value."); + + FlowMap flow(g); + for (ArcIt e(g); e != INVALID; ++e) flow[e] = 13 * max_flow.flowMap()[e]; + for (ArcIt e(g); e != INVALID; ++e) cap[e] = 17 * cap[e]; + max_flow.init(flow); + + SF::startFirstPhase(max_flow); // start first phase of the algorithm + + CutMap min_cut1(g); + max_flow.minCutMap(min_cut1); + min_cut_value = cutValue(g, min_cut1, cap); + + check(!tol.different(17 * expected, max_flow.flowValue()), + "Incorrect max flow value."); + check(!tol.different(17 * expected, min_cut_value), + "Incorrect min cut value."); + + SF::startSecondPhase(max_flow); // start second phase of the algorithm + + check(checkFlow(g, max_flow.flowMap(), cap, s, t, tol), + "The flow is not feasible."); + + CutMap min_cut2(g); + max_flow.minCutMap(min_cut2); + min_cut_value = cutValue(g, min_cut2, cap); + + check(!tol.different(17 * expected, max_flow.flowValue()), + "Incorrect max flow value."); + check(!tol.different(17 * expected, min_cut_value), + "Incorrect min cut value."); + + max_flow.flowMap(flow); + + NodeIt tmp1(g, s); + ++tmp1; + if (tmp1 != INVALID) s = tmp1; + + NodeIt tmp2(g, t); + ++tmp2; + if (tmp2 != INVALID) t = tmp2; + + max_flow.source(s); + max_flow.target(t); + + max_flow.run(); + + CutMap min_cut3(g); + max_flow.minCutMap(min_cut3); + min_cut_value = cutValue(g, min_cut3, cap); + + check(!tol.different(max_flow.flowValue(), min_cut_value), + "The max flow value or the min cut value is wrong."); +} + +// Struct for calling start functions of a general max flow algorithm +template +struct GeneralStartFunctions { + + static void startFirstPhase(MF& mf) { + mf.start(); + } + + static void startSecondPhase(MF& mf) { + ::lemon::ignore_unused_variable_warning(mf); + } + +}; + +// Struct for calling start functions of Preflow +template +struct PreflowStartFunctions { + + static void startFirstPhase(MF& mf) { + mf.startFirstPhase(); + } + + static void startSecondPhase(MF& mf) { + mf.startSecondPhase(); + } + +}; + +int main() { + + typedef concepts::Digraph GR; + typedef concepts::ReadMap CM1; + typedef concepts::ReadMap CM2; + + // Check the interface of Preflow + checkConcept< MaxFlowClassConcept, + Preflow >(); + checkConcept< MaxFlowClassConcept, + Preflow >(); + + // Check the interface of EdmondsKarp + checkConcept< MaxFlowClassConcept, + EdmondsKarp >(); + checkConcept< MaxFlowClassConcept, + EdmondsKarp >(); + + // Check Preflow + typedef Preflow > PType1; + typedef Preflow > PType2; + typedef Preflow > PType3; + + checkMaxFlowAlg >(test_lgf, 13); + checkMaxFlowAlg >(test_lgf, 13); + checkMaxFlowAlg >(test_lgf, 13); + + checkMaxFlowAlg >(test_lgf_float, 0.3f); + checkMaxFlowAlg >(test_lgf_float, 0.3); + + checkInitPreflow(); + + // Check EdmondsKarp + typedef EdmondsKarp > EKType1; + typedef EdmondsKarp > EKType2; + typedef EdmondsKarp > EKType3; + + checkMaxFlowAlg >(test_lgf, 13); + checkMaxFlowAlg >(test_lgf, 13); + checkMaxFlowAlg >(test_lgf, 13); + + checkMaxFlowAlg >(test_lgf_float, 0.3f); + checkMaxFlowAlg >(test_lgf_float, 0.3); + + return 0; +} diff -r cd72eae05bdf -r 3c00344f49c9 test/min_cost_arborescence_test.cc --- a/test/min_cost_arborescence_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/min_cost_arborescence_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -91,6 +91,7 @@ Arc e; VType c; bool b; + ::lemon::ignore_unused_variable_warning(c,b); int i; CostMap cost; ArbMap arb; @@ -126,8 +127,8 @@ i = const_mcarb_test.dualSize(i); c = const_mcarb_test.dualValue(i); - ignore_unused_variable_warning(am); - ignore_unused_variable_warning(pm); + ::lemon::ignore_unused_variable_warning(am); + ::lemon::ignore_unused_variable_warning(pm); } int main() { diff -r cd72eae05bdf -r 3c00344f49c9 test/min_cost_flow_test.cc --- a/test/min_cost_flow_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/min_cost_flow_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -395,6 +395,12 @@ 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); + + // Tests for empty graph + Digraph gr0; + MCF mcf0(gr0); + mcf0.run(param); + check(mcf0.totalCost() == 0, "Wrong total cost"); } template < typename MCF, typename Param > diff -r cd72eae05bdf -r 3c00344f49c9 test/min_mean_cycle_test.cc --- a/test/min_mean_cycle_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/min_mean_cycle_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -110,7 +110,7 @@ const SmartDigraph::ArcMap& cm, int cost, int size) { MMC alg(gr, lm); - alg.findCycleMean(); + check(alg.findCycleMean(), "Wrong result"); check(alg.cycleMean() == static_cast(cost) / size, "Wrong cycle mean"); alg.findCycle(); @@ -210,6 +210,13 @@ checkMmcAlg >(gr, l2, c2, 5, 2); checkMmcAlg >(gr, l3, c3, 0, 1); checkMmcAlg >(gr, l4, c4, -1, 1); + + // Howard with iteration limit + HowardMmc mmc(gr, l1); + check((mmc.findCycleMean(2) == HowardMmc::ITERATION_LIMIT), + "Wrong termination cause"); + check((mmc.findCycleMean(4) == HowardMmc::OPTIMAL), + "Wrong termination cause"); } return 0; diff -r cd72eae05bdf -r 3c00344f49c9 test/mip_test.cc --- a/test/mip_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/mip_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -32,6 +32,10 @@ #include #endif +#ifdef LEMON_HAVE_MIP +#include +#endif + using namespace lemon; @@ -128,6 +132,14 @@ int main() { +#ifdef LEMON_HAVE_MIP + { + Mip mip1; + aTest(mip1); + cloneTest(); + } +#endif + #ifdef LEMON_HAVE_GLPK { GlpkMip mip1; diff -r cd72eae05bdf -r 3c00344f49c9 test/nagamochi_ibaraki_test.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/nagamochi_ibaraki_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,142 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 "test_tools.h" + +using namespace lemon; +using namespace std; + +const std::string lgf = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "4\n" + "5\n" + "@edges\n" + " cap1 cap2 cap3\n" + "0 1 1 1 1 \n" + "0 2 2 2 4 \n" + "1 2 4 4 4 \n" + "3 4 1 1 1 \n" + "3 5 2 2 4 \n" + "4 5 4 4 4 \n" + "2 3 1 6 6 \n"; + +void checkNagamochiIbarakiCompile() +{ + typedef int Value; + typedef concepts::Graph Graph; + + typedef Graph::Node Node; + typedef Graph::Edge Edge; + typedef concepts::ReadMap CapMap; + typedef concepts::WriteMap CutMap; + + Graph g; + Node n; + CapMap cap; + CutMap cut; + Value v; + bool b; + ::lemon::ignore_unused_variable_warning(v,b); + + NagamochiIbaraki ni_test(g, cap); + const NagamochiIbaraki& const_ni_test = ni_test; + + ni_test.init(); + ni_test.start(); + b = ni_test.processNextPhase(); + ni_test.run(); + + v = const_ni_test.minCutValue(); + v = const_ni_test.minCutMap(cut); +} + +template +typename CapMap::Value + cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut) +{ + typename CapMap::Value sum = 0; + for (typename Graph::EdgeIt e(graph); e != INVALID; ++e) { + if (cut[graph.u(e)] != cut[graph.v(e)]) { + sum += cap[e]; + } + } + return sum; +} + +int main() { + SmartGraph graph; + SmartGraph::EdgeMap cap1(graph), cap2(graph), cap3(graph); + SmartGraph::NodeMap cut(graph); + + istringstream input(lgf); + graphReader(graph, input) + .edgeMap("cap1", cap1) + .edgeMap("cap2", cap2) + .edgeMap("cap3", cap3) + .run(); + + { + NagamochiIbaraki ni(graph, cap1); + ni.run(); + ni.minCutMap(cut); + + check(ni.minCutValue() == 1, "Wrong cut value"); + check(ni.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value"); + } + { + NagamochiIbaraki ni(graph, cap2); + ni.run(); + ni.minCutMap(cut); + + check(ni.minCutValue() == 3, "Wrong cut value"); + check(ni.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value"); + } + { + NagamochiIbaraki ni(graph, cap3); + ni.run(); + ni.minCutMap(cut); + + check(ni.minCutValue() == 5, "Wrong cut value"); + check(ni.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value"); + } + { + NagamochiIbaraki::SetUnitCapacity::Create ni(graph); + ni.run(); + ni.minCutMap(cut); + + ConstMap cap4(1); + check(ni.minCutValue() == 1, "Wrong cut value"); + check(ni.minCutValue() == cutValue(graph, cap4, cut), "Wrong cut value"); + } + + return 0; +} diff -r cd72eae05bdf -r 3c00344f49c9 test/path_test.cc --- a/test/path_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/path_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -30,44 +31,309 @@ using namespace std; using namespace lemon; -void check_concepts() { - checkConcept, concepts::Path >(); - checkConcept, Path >(); - checkConcept, SimplePath >(); - checkConcept, StaticPath >(); - checkConcept, ListPath >(); +template +void checkConcepts() { + checkConcept, concepts::Path >(); + checkConcept, Path >(); + checkConcept, SimplePath >(); + checkConcept, StaticPath >(); + checkConcept, ListPath >(); +} + +// Conecpt checking for path structures +void checkPathConcepts() { + checkConcepts(); + checkConcepts(); } // Check if proper copy consructor is called (use valgrind for testing) -template -void checkCopy() -{ +template +void checkCopy(typename GR::Arc a) { + P1 p; + p.addBack(a); + P1 q; + q = p; + P1 r(p); + P2 q2; + q2 = p; + P2 r2(p); +} + +// Tests for copy constructors and assignment operators of paths +void checkPathCopy() { ListDigraph g; - ListDigraph::Arc a = g.addArc(g.addNode(), g.addNode()); - - _Path p,q; - p.addBack(a); - q=p; - _Path r(p); - StaticPath s(r); + ListDigraph::Arc a = g.addArc(g.addNode(), g.addNode()); + + typedef Path Path1; + typedef SimplePath Path2; + typedef ListPath Path3; + typedef StaticPath Path4; + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); + checkCopy(a); } - + +// Class for testing path functions +class CheckPathFunctions { + typedef ListDigraph GR; + DIGRAPH_TYPEDEFS(GR); + GR gr; + const GR& cgr; + Node n1, n2, n3, n4; + Node tmp_n; + Arc a1, a2, a3, a4; + Arc tmp_a; + +public: + + CheckPathFunctions() : cgr(gr) { + n1 = gr.addNode(); + n2 = gr.addNode(); + n3 = gr.addNode(); + n4 = gr.addNode(); + a1 = gr.addArc(n1, n2); + a2 = gr.addArc(n2, n3); + a3 = gr.addArc(n3, n4); + a4 = gr.addArc(n4, n1); + } + + void run() { + checkBackAndFrontInsertablePath >(); + checkBackAndFrontInsertablePath >(); + checkBackInsertablePath >(); + + checkListPathSplitAndSplice(); + } + +private: + + template + void checkBackInsertablePath() { + + // Create and check empty path + P p; + const P& cp = p; + check(cp.empty(), "The path is not empty"); + check(cp.length() == 0, "The path is not empty"); +// check(cp.front() == INVALID, "Wrong front()"); +// check(cp.back() == INVALID, "Wrong back()"); + typename P::ArcIt ai(cp); + check(ai == INVALID, "Wrong ArcIt"); + check(pathSource(cgr, cp) == INVALID, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == INVALID, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + PathNodeIt

ni(cgr, cp); + check(ni == INVALID, "Wrong PathNodeIt"); + + // Check single-arc path + p.addBack(a1); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 1, "Wrong length"); + check(cp.front() == a1, "Wrong front()"); + check(cp.back() == a1, "Wrong back()"); + check(cp.nth(0) == a1, "Wrong nth()"); + ai = cp.nthIt(0); + check((tmp_a = ai) == a1, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + typename P::ArcIt ai2(cp); + check((tmp_a = ai2) == a1, "Wrong ArcIt"); + check(++ai2 == INVALID, "Wrong ArcIt"); + check(pathSource(cgr, cp) == n1, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + PathNodeIt

ni2(cgr, cp); + check((tmp_n = ni2) == n1, "Wrong PathNodeIt"); + check((tmp_n = ++ni2) == n2, "Wrong PathNodeIt"); + check(++ni2 == INVALID, "Wrong PathNodeIt"); + + // Check adding more arcs + p.addBack(a2); + p.addBack(a3); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 3, "Wrong length"); + check(cp.front() == a1, "Wrong front()"); + check(cp.back() == a3, "Wrong back()"); + check(cp.nth(0) == a1, "Wrong nth()"); + check(cp.nth(1) == a2, "Wrong nth()"); + check(cp.nth(2) == a3, "Wrong nth()"); + typename P::ArcIt ai3(cp); + check((tmp_a = ai3) == a1, "Wrong ArcIt"); + check((tmp_a = ++ai3) == a2, "Wrong nthIt()"); + check((tmp_a = ++ai3) == a3, "Wrong nthIt()"); + check(++ai3 == INVALID, "Wrong nthIt()"); + ai = cp.nthIt(0); + check((tmp_a = ai) == a1, "Wrong nthIt()"); + check((tmp_a = ++ai) == a2, "Wrong nthIt()"); + ai = cp.nthIt(2); + check((tmp_a = ai) == a3, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(pathSource(cgr, cp) == n1, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n4, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + PathNodeIt

ni3(cgr, cp); + check((tmp_n = ni3) == n1, "Wrong PathNodeIt"); + check((tmp_n = ++ni3) == n2, "Wrong PathNodeIt"); + check((tmp_n = ++ni3) == n3, "Wrong PathNodeIt"); + check((tmp_n = ++ni3) == n4, "Wrong PathNodeIt"); + check(++ni3 == INVALID, "Wrong PathNodeIt"); + + // Check arc removal and addition + p.eraseBack(); + p.eraseBack(); + p.addBack(a2); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 2, "Wrong length"); + check(cp.front() == a1, "Wrong front()"); + check(cp.back() == a2, "Wrong back()"); + check(pathSource(cgr, cp) == n1, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + + // Check clear() + p.clear(); + check(cp.empty(), "The path is not empty"); + check(cp.length() == 0, "The path is not empty"); + + // Check inconsistent path + p.addBack(a4); + p.addBack(a2); + p.addBack(a1); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 3, "Wrong length"); + check(cp.front() == a4, "Wrong front()"); + check(cp.back() == a1, "Wrong back()"); + check(pathSource(cgr, cp) == n4, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()"); + check(!checkPath(cgr, cp), "Wrong checkPath()"); + } + + template + void checkBackAndFrontInsertablePath() { + + // Include back insertable test cases + checkBackInsertablePath

(); + + // Check front and back insertion + P p; + const P& cp = p; + p.addFront(a4); + p.addBack(a1); + p.addFront(a3); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 3, "Wrong length"); + check(cp.front() == a3, "Wrong front()"); + check(cp.back() == a1, "Wrong back()"); + check(cp.nth(0) == a3, "Wrong nth()"); + check(cp.nth(1) == a4, "Wrong nth()"); + check(cp.nth(2) == a1, "Wrong nth()"); + typename P::ArcIt ai(cp); + check((tmp_a = ai) == a3, "Wrong ArcIt"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + check((tmp_a = ++ai) == a1, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + ai = cp.nthIt(0); + check((tmp_a = ai) == a3, "Wrong nthIt()"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + ai = cp.nthIt(2); + check((tmp_a = ai) == a1, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(pathSource(cgr, cp) == n3, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + + // Check eraseFront() + p.eraseFront(); + p.addBack(a2); + check(!cp.empty(), "Wrong empty()"); + check(cp.length() == 3, "Wrong length"); + check(cp.front() == a4, "Wrong front()"); + check(cp.back() == a2, "Wrong back()"); + check(cp.nth(0) == a4, "Wrong nth()"); + check(cp.nth(1) == a1, "Wrong nth()"); + check(cp.nth(2) == a2, "Wrong nth()"); + typename P::ArcIt ai2(cp); + check((tmp_a = ai2) == a4, "Wrong ArcIt"); + check((tmp_a = ++ai2) == a1, "Wrong nthIt()"); + check((tmp_a = ++ai2) == a2, "Wrong nthIt()"); + check(++ai2 == INVALID, "Wrong nthIt()"); + ai = cp.nthIt(0); + check((tmp_a = ai) == a4, "Wrong nthIt()"); + check((tmp_a = ++ai) == a1, "Wrong nthIt()"); + ai = cp.nthIt(2); + check((tmp_a = ai) == a2, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(pathSource(cgr, cp) == n4, "Wrong pathSource()"); + check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()"); + check(checkPath(cgr, cp), "Wrong checkPath()"); + } + + void checkListPathSplitAndSplice() { + + // Build a path with spliceFront() and spliceBack() + ListPath p1, p2, p3, p4; + p1.addBack(a3); + p1.addFront(a2); + p2.addBack(a1); + p1.spliceFront(p2); + p3.addFront(a4); + p1.spliceBack(p3); + check(p1.length() == 4, "Wrong length"); + check(p1.front() == a1, "Wrong front()"); + check(p1.back() == a4, "Wrong back()"); + ListPath::ArcIt ai(p1); + check((tmp_a = ai) == a1, "Wrong ArcIt"); + check((tmp_a = ++ai) == a2, "Wrong nthIt()"); + check((tmp_a = ++ai) == a3, "Wrong nthIt()"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(checkPath(cgr, p1), "Wrong checkPath()"); + + // Check split() + p1.split(p1.nthIt(2), p2); + check(p1.length() == 2, "Wrong length"); + ai = p1.nthIt(0); + check((tmp_a = ai) == a1, "Wrong ArcIt"); + check((tmp_a = ++ai) == a2, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(checkPath(cgr, p1), "Wrong checkPath()"); + check(p2.length() == 2, "Wrong length"); + ai = p2.nthIt(0); + check((tmp_a = ai) == a3, "Wrong ArcIt"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(checkPath(cgr, p2), "Wrong checkPath()"); + + // Check split() and splice() + p1.spliceFront(p2); + p1.split(p1.nthIt(2), p2); + p2.split(p2.nthIt(1), p3); + p2.spliceBack(p1); + p2.splice(p2.nthIt(1), p3); + check(p2.length() == 4, "Wrong length"); + check(p2.front() == a1, "Wrong front()"); + check(p2.back() == a4, "Wrong back()"); + ai = p2.nthIt(0); + check((tmp_a = ai) == a1, "Wrong ArcIt"); + check((tmp_a = ++ai) == a2, "Wrong nthIt()"); + check((tmp_a = ++ai) == a3, "Wrong nthIt()"); + check((tmp_a = ++ai) == a4, "Wrong nthIt()"); + check(++ai == INVALID, "Wrong nthIt()"); + check(checkPath(cgr, p2), "Wrong checkPath()"); + } + +}; + int main() { - check_concepts(); - - checkCopy >(); - checkCopy >(); - checkCopy >(); - - ListDigraph g; - ListDigraph::Arc a = g.addArc(g.addNode(), g.addNode()); - - Path p; - StaticPath q,r; - p.addBack(a); - q=p; - r=q; - StaticPath s(q); + checkPathConcepts(); + checkPathCopy(); + CheckPathFunctions cpf; + cpf.run(); return 0; } diff -r cd72eae05bdf -r 3c00344f49c9 test/planarity_test.cc --- a/test/planarity_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/planarity_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -30,10 +30,40 @@ using namespace lemon; using namespace lemon::dim2; -const int lgfn = 4; +const int lgfn = 8; const std::string lgf[lgfn] = { "@nodes\n" "label\n" + "@edges\n" + " label\n", + + "@nodes\n" + "label\n" + "0\n" + "@edges\n" + " label\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "@edges\n" + " label\n" + "0 1 0\n", + + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "@edges\n" + " label\n" + "0 1 0\n" + "1 2 1\n" + "2 0 2\n", + + "@nodes\n" + "label\n" "0\n" "1\n" "2\n" @@ -136,8 +166,11 @@ ++face_num; } } - check(face_num + countNodes(graph) - countConnectedComponents(graph) == - countEdges(graph) + 1, "Euler test does not passed"); + + if (face_num != 0) { + check(face_num + countNodes(graph) - countConnectedComponents(graph) == + countEdges(graph) + 1, "Euler test does not passed"); + } } void checkKuratowski(const Graph& graph, PE& pe) { @@ -245,13 +278,29 @@ if (planar) { checkEmbedding(graph, pe); - PlanarDrawing pd(graph); - pd.run(pe.embeddingMap()); - checkDrawing(graph, pd); + { + PlanarDrawing pd(graph); + pd.run(pe.embeddingMap()); + checkDrawing(graph, pd); + } - PlanarColoring pc(graph); - pc.runFiveColoring(pe.embeddingMap()); - checkColoring(graph, pc, 5); + { + PlanarDrawing pd(graph); + pd.run(); + checkDrawing(graph, pd); + } + + { + PlanarColoring pc(graph); + pc.runFiveColoring(pe.embeddingMap()); + checkColoring(graph, pc, 5); + } + + { + PlanarColoring pc(graph); + pc.runFiveColoring(); + checkColoring(graph, pc, 5); + } } else { checkKuratowski(graph, pe); diff -r cd72eae05bdf -r 3c00344f49c9 test/preflow_test.cc --- a/test/preflow_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +0,0 @@ -/* -*- 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" -#include -#include -#include -#include -#include -#include - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "8\n" - "9\n" - "@arcs\n" - " label capacity\n" - "0 1 0 20\n" - "0 2 1 0\n" - "1 1 2 3\n" - "1 2 3 8\n" - "1 3 4 8\n" - "2 5 5 5\n" - "3 2 6 5\n" - "3 5 7 5\n" - "3 6 8 5\n" - "4 3 9 3\n" - "5 7 10 3\n" - "5 6 11 10\n" - "5 8 12 10\n" - "6 8 13 8\n" - "8 9 14 20\n" - "8 1 15 5\n" - "9 5 16 5\n" - "@attributes\n" - "source 1\n" - "target 8\n"; - -void checkPreflowCompile() -{ - typedef int VType; - typedef concepts::Digraph Digraph; - - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - typedef concepts::ReadMap CapMap; - typedef concepts::ReadWriteMap FlowMap; - typedef concepts::WriteMap CutMap; - - typedef Elevator Elev; - typedef LinkedElevator LinkedElev; - - Digraph g; - Node n; - Arc e; - CapMap cap; - FlowMap flow; - CutMap cut; - VType v; - bool b; - - typedef Preflow - ::SetFlowMap - ::SetElevator - ::SetStandardElevator - ::Create PreflowType; - 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) - .source(n) - .target(n); - - preflow_test.init(); - preflow_test.init(cap); - preflow_test.startFirstPhase(); - preflow_test.startSecondPhase(); - preflow_test.run(); - preflow_test.runMinCut(); - - v = const_preflow_test.flowValue(); - v = const_preflow_test.flow(e); - const FlowMap& fm = const_preflow_test.flowMap(); - b = const_preflow_test.minCut(n); - const_preflow_test.minCutMap(cut); - - ignore_unused_variable_warning(fm); -} - -int cutValue (const SmartDigraph& g, - const SmartDigraph::NodeMap& cut, - const SmartDigraph::ArcMap& cap) { - - int c=0; - for(SmartDigraph::ArcIt e(g); e!=INVALID; ++e) { - if (cut[g.source(e)] && !cut[g.target(e)]) c+=cap[e]; - } - return c; -} - -bool checkFlow(const SmartDigraph& g, - const SmartDigraph::ArcMap& flow, - const SmartDigraph::ArcMap& cap, - SmartDigraph::Node s, SmartDigraph::Node t) { - - for (SmartDigraph::ArcIt e(g); e != INVALID; ++e) { - if (flow[e] < 0 || flow[e] > cap[e]) return false; - } - - for (SmartDigraph::NodeIt n(g); n != INVALID; ++n) { - if (n == s || n == t) continue; - int sum = 0; - for (SmartDigraph::OutArcIt e(g, n); e != INVALID; ++e) { - sum += flow[e]; - } - for (SmartDigraph::InArcIt e(g, n); e != INVALID; ++e) { - sum -= flow[e]; - } - if (sum != 0) return false; - } - return true; -} - -void initFlowTest() -{ - DIGRAPH_TYPEDEFS(SmartDigraph); - - SmartDigraph g; - SmartDigraph::ArcMap cap(g),iflow(g); - Node s=g.addNode(); Node t=g.addNode(); - Node n1=g.addNode(); Node n2=g.addNode(); - Arc a; - a=g.addArc(s,n1); cap[a]=20; iflow[a]=20; - a=g.addArc(n1,n2); cap[a]=10; iflow[a]=0; - a=g.addArc(n2,t); cap[a]=20; iflow[a]=0; - - Preflow pre(g,cap,s,t); - pre.init(iflow); - pre.startFirstPhase(); - check(pre.flowValue() == 10, "The incorrect max flow value."); - check(pre.minCut(s), "Wrong min cut (Node s)."); - check(pre.minCut(n1), "Wrong min cut (Node n1)."); - check(!pre.minCut(n2), "Wrong min cut (Node n2)."); - check(!pre.minCut(t), "Wrong min cut (Node t)."); -} - - -int main() { - - typedef SmartDigraph Digraph; - - typedef Digraph::Node Node; - typedef Digraph::NodeIt NodeIt; - typedef Digraph::ArcIt ArcIt; - typedef Digraph::ArcMap CapMap; - typedef Digraph::ArcMap FlowMap; - typedef Digraph::NodeMap CutMap; - - typedef Preflow PType; - - Digraph g; - Node s, t; - CapMap cap(g); - std::istringstream input(test_lgf); - DigraphReader(g,input). - arcMap("capacity", cap). - node("source",s). - node("target",t). - run(); - - PType preflow_test(g, cap, s, t); - preflow_test.run(); - - check(checkFlow(g, preflow_test.flowMap(), cap, s, t), - "The flow is not feasible."); - - CutMap min_cut(g); - preflow_test.minCutMap(min_cut); - int min_cut_value=cutValue(g,min_cut,cap); - - check(preflow_test.flowValue() == min_cut_value, - "The max flow value is not equal to the three min cut values."); - - FlowMap flow(g); - for(ArcIt e(g); e!=INVALID; ++e) flow[e] = preflow_test.flowMap()[e]; - - int flow_value=preflow_test.flowValue(); - - for(ArcIt e(g); e!=INVALID; ++e) cap[e]=2*cap[e]; - preflow_test.init(flow); - preflow_test.startFirstPhase(); - - CutMap min_cut1(g); - preflow_test.minCutMap(min_cut1); - min_cut_value=cutValue(g,min_cut1,cap); - - check(preflow_test.flowValue() == min_cut_value && - min_cut_value == 2*flow_value, - "The max flow value or the min cut value is wrong."); - - preflow_test.startSecondPhase(); - - check(checkFlow(g, preflow_test.flowMap(), cap, s, t), - "The flow is not feasible."); - - CutMap min_cut2(g); - preflow_test.minCutMap(min_cut2); - min_cut_value=cutValue(g,min_cut2,cap); - - check(preflow_test.flowValue() == min_cut_value && - min_cut_value == 2*flow_value, - "The max flow value or the three min cut values were not doubled"); - - - preflow_test.flowMap(flow); - - NodeIt tmp1(g,s); - ++tmp1; - if ( tmp1 != INVALID ) s=tmp1; - - NodeIt tmp2(g,t); - ++tmp2; - if ( tmp2 != INVALID ) t=tmp2; - - preflow_test.source(s); - preflow_test.target(t); - - preflow_test.run(); - - CutMap min_cut3(g); - preflow_test.minCutMap(min_cut3); - min_cut_value=cutValue(g,min_cut3,cap); - - - check(preflow_test.flowValue() == min_cut_value, - "The max flow value or the three min cut values are incorrect."); - - initFlowTest(); - - return 0; -} diff -r cd72eae05bdf -r 3c00344f49c9 test/radix_sort_test.cc --- a/test/radix_sort_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/radix_sort_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -16,6 +16,8 @@ * */ +#include + #include #include #include @@ -25,6 +27,7 @@ #include "test_tools.h" #include +#include #include using namespace lemon; @@ -39,8 +42,58 @@ int negate(int a) { return - a; } +template +bool isTheSame(T &a, T&b) +{ + typename T::iterator ai=a.begin(); + typename T::iterator bi=b.begin(); + for(;ai!=a.end()||bi!=b.end();++ai,++bi) + if(*ai!=*bi) return false; + return ai==a.end()&&bi==b.end(); +} -void generateIntSequence(int n, std::vector& data) { +template +T listsort(typename T::iterator b, typename T::iterator e) +{ + if(b==e) return T(); + typename T::iterator bn=b; + if(++bn==e) { + T l; + l.push_back(*b); + return l; + } + typename T::iterator m=b; + bool x=false; + for(typename T::iterator i=b;i!=e;++i,x=!x) + if(x) ++m; + T l1(listsort(b,m)); + T l2(listsort(m,e)); + T l; + while((!l1.empty())&&(!l2.empty())) + if(l1.front()<=l2.front()) + { + l.push_back(l1.front()); + l1.pop_front(); + } + else { + l.push_back(l2.front()); + l2.pop_front(); + } + while(!l1.empty()) + { + l.push_back(l1.front()); + l1.pop_front(); + } + while(!l2.empty()) + { + l.push_back(l2.front()); + l2.pop_front(); + } + return l; +} + +template +void generateIntSequence(int n, T & data) { int prime = 9973; int root = 136, value = 1; for (int i = 0; i < n; ++i) { @@ -49,7 +102,8 @@ } } -void generateCharSequence(int n, std::vector& data) { +template +void generateCharSequence(int n, T & data) { int prime = 251; int root = 3, value = root; for (int i = 0; i < n; ++i) { @@ -71,15 +125,15 @@ check(data1[i] == data2[i], "Test failed"); } - radixSort(data2.begin(), data2.end(), Negate()); - for (int i = 0; i < n; ++i) { - check(data1[i] == data2[n - 1 - i], "Test failed"); - } + // radixSort(data2.begin(), data2.end(), Negate()); + // for (int i = 0; i < n; ++i) { + // check(data1[i] == data2[n - 1 - i], "Test failed"); + // } - radixSort(data2.begin(), data2.end(), negate); - for (int i = 0; i < n; ++i) { - check(data1[i] == data2[n - 1 - i], "Test failed"); - } + // radixSort(data2.begin(), data2.end(), negate); + // for (int i = 0; i < n; ++i) { + // check(data1[i] == data2[n - 1 - i], "Test failed"); + // } } @@ -96,6 +150,42 @@ } } + { + std::list data1; + generateIntSequence(n, data1); + + std::list data2(listsort >(data1.begin(), data1.end())); + + radixSort(data1.begin(), data1.end()); + + check(isTheSame(data1,data2), "Test failed"); + + + // radixSort(data2.begin(), data2.end(), Negate()); + // check(isTheSame(data1,data2), "Test failed"); + // for (int i = 0; i < n; ++i) { + // check(data1[i] == data2[n - 1 - i], "Test failed"); + // } + + // radixSort(data2.begin(), data2.end(), negate); + // for (int i = 0; i < n; ++i) { + // check(data1[i] == data2[n - 1 - i], "Test failed"); + // } + + } + + { + std::list data1(n); + generateCharSequence(n, data1); + + std::list data2(listsort > + (data1.begin(), + data1.end())); + + radixSort(data1.begin(), data1.end()); + check(isTheSame(data1,data2), "Test failed"); + + } } @@ -136,6 +226,37 @@ } } + { + std::list data1; + generateIntSequence(n, data1); + + std::list data2(listsort >(data1.begin(), + data1.end())); + stableRadixSort(data1.begin(), data1.end()); + check(isTheSame(data1,data2), "Test failed"); + + // stableRadixSort(data2.begin(), data2.end(), Negate()); + // for (int i = 0; i < n; ++i) { + // check(data1[i] == data2[n - 1 - i], "Test failed"); + // } + + // stableRadixSort(data2.begin(), data2.end(), negate); + // for (int i = 0; i < n; ++i) { + // check(data1[i] == data2[n - 1 - i], "Test failed"); + // } + } + + { + std::list data1(n); + generateCharSequence(n, data1); + + std::list data2(listsort > + (data1.begin(), + data1.end())); + radixSort(data1.begin(), data1.end()); + check(isTheSame(data1,data2), "Test failed"); + + } } int main() { diff -r cd72eae05bdf -r 3c00344f49c9 test/suurballe_test.cc --- a/test/suurballe_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/suurballe_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -117,6 +117,8 @@ int f; VType c; + ::lemon::ignore_unused_variable_warning(f,c); + c = const_suurb_test.totalLength(); f = const_suurb_test.flow(e); const SuurballeType::FlowMap& fm = @@ -127,8 +129,8 @@ k = const_suurb_test.pathNum(); Path p = const_suurb_test.path(k); - ignore_unused_variable_warning(fm); - ignore_unused_variable_warning(pm); + ::lemon::ignore_unused_variable_warning(fm); + ::lemon::ignore_unused_variable_warning(pm); } // Check the feasibility of the flow diff -r cd72eae05bdf -r 3c00344f49c9 test/time_measure_test.cc --- a/test/time_measure_test.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/test/time_measure_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2009 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -35,7 +35,7 @@ for(int i=0;i<1000;i++) { TimeStamp x(T); - ignore_unused_variable_warning(x); + ::lemon::ignore_unused_variable_warning(x); } } diff -r cd72eae05bdf -r 3c00344f49c9 test/tsp_test.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tsp_test.cc Wed Oct 17 19:14:07 2018 +0200 @@ -0,0 +1,287 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2013 + * 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 lemon; + +// // Tests checkMetricCost() function +// void metricCostTest() { +// GRAPH_TYPEDEFS(FullGraph); +// FullGraph g(10); +// check(checkMetricCost(g, constMap(0)), "Wrong checkMetricCost()"); +// check(checkMetricCost(g, constMap(1)), "Wrong checkMetricCost()"); +// check(!checkMetricCost(g, constMap(-1)), "Wrong checkMetricCost()"); +// +// FullGraph::EdgeMap cost(g); +// for (NodeIt u(g); u != INVALID; ++u) { +// for (NodeIt v(g); v != INVALID; ++v) { +// if (u == v) continue; +// float x1 = g.id(u), x2 = g.id(v); +// float y1 = x1 * x1, y2 = x2 * x2; +// cost[g.edge(u, v)] = std::sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); +// } +// } +// check(checkMetricCost(g, cost), "Wrong checkMetricCost()"); +// float eps = Tolerance::defaultEpsilon(); +// cost[g.edge(g(0), g(9))] = +// cost[g.edge(g(0), g(8))] + cost[g.edge(g(8), g(9))] + eps * 2; +// check(!checkMetricCost(g, cost), "Wrong checkMetricCost()"); +// check(checkMetricCost(g, cost, Tolerance(eps * 4)), +// "Wrong checkMetricCost()"); +// } + +// Checks tour validity +template +bool checkTour(const FullGraph &gr, const Container &p) { + FullGraph::NodeMap used(gr, false); + + int node_cnt = 0; + for (typename Container::const_iterator it = p.begin(); it != p.end(); ++it) + { + FullGraph::Node node = *it; + if (used[node]) return false; + used[node] = true; + ++node_cnt; + } + + return (node_cnt == gr.nodeNum()); +} + +// Checks tour validity +bool checkTourPath(const FullGraph &gr, const Path &p) { + FullGraph::NodeMap used(gr, false); + + if (!checkPath(gr, p)) return false; + if (gr.nodeNum() <= 1 && p.length() != 0) return false; + if (gr.nodeNum() > 1 && p.length() != gr.nodeNum()) return false; + + for (int i = 0; i < p.length(); ++i) { + if (used[gr.target(p.nth(i))]) return false; + used[gr.target(p.nth(i))] = true; + } + return true; +} + +// Checks tour cost +template +bool checkCost(const FullGraph &gr, const std::vector &p, + const CostMap &cost, typename CostMap::Value total) +{ + typedef typename CostMap::Value Cost; + + Cost s = 0; + for (int i = 0; i < int(p.size()) - 1; ++i) + s += cost[gr.edge(p[i], p[i+1])]; + if (int(p.size()) >= 2) + s += cost[gr.edge(p.back(), p.front())]; + + return !Tolerance().different(s, total); +} + +// Checks tour cost +template +bool checkCost(const FullGraph &, const Path &p, + const CostMap &cost, typename CostMap::Value total) +{ + typedef typename CostMap::Value Cost; + + Cost s = 0; + for (int i = 0; i < p.length(); ++i) + s += cost[p.nth(i)]; + + return !Tolerance().different(s, total); +} + +// Tests a TSP algorithm on small graphs +template +void tspTestSmall(const std::string &alg_name) { + GRAPH_TYPEDEFS(FullGraph); + + for (int n = 0; n <= 5; ++n) { + FullGraph g(n); + unsigned nsize = n; + int esize = n <= 1 ? 0 : n; + + ConstMap cost_map(1); + TSP alg(g, cost_map); + + check(alg.run() == esize, alg_name + ": Wrong total cost"); + check(alg.tourCost() == esize, alg_name + ": Wrong total cost"); + + std::list list1(nsize), list2; + std::vector vec1(nsize), vec2; + alg.tourNodes(list1.begin()); + alg.tourNodes(vec1.begin()); + alg.tourNodes(std::front_inserter(list2)); + alg.tourNodes(std::back_inserter(vec2)); + check(checkTour(g, alg.tourNodes()), alg_name + ": Wrong node sequence"); + check(checkTour(g, list1), alg_name + ": Wrong node sequence"); + check(checkTour(g, vec1), alg_name + ": Wrong node sequence"); + check(checkTour(g, list2), alg_name + ": Wrong node sequence"); + check(checkTour(g, vec2), alg_name + ": Wrong node sequence"); + check(checkCost(g, vec1, constMap(1), esize), + alg_name + ": Wrong tour cost"); + + SimplePath path; + alg.tour(path); + check(path.length() == esize, alg_name + ": Wrong tour"); + check(checkTourPath(g, path), alg_name + ": Wrong tour"); + check(checkCost(g, path, constMap(1), esize), + alg_name + ": Wrong tour cost"); + } +} + +// Tests a TSP algorithm on random graphs +template +void tspTestRandom(const std::string &alg_name) { + GRAPH_TYPEDEFS(FullGraph); + + FullGraph g(20); + FullGraph::NodeMap > pos(g); + DoubleEdgeMap cost(g); + + TSP alg(g, cost); + Opt2Tsp opt2(g, cost); + + for (int i = 1; i <= 3; i++) { + for (NodeIt u(g); u != INVALID; ++u) { + pos[u] = dim2::Point(rnd(), rnd()); + } + for (NodeIt u(g); u != INVALID; ++u) { + for (NodeIt v(g); v != INVALID; ++v) { + if (u == v) continue; + cost[g.edge(u, v)] = (pos[u] - pos[v]).normSquare(); + } + } + + check(alg.run() > 0, alg_name + ": Wrong total cost"); + + std::vector vec; + alg.tourNodes(std::back_inserter(vec)); + check(checkTour(g, vec), alg_name + ": Wrong node sequence"); + check(checkCost(g, vec, cost, alg.tourCost()), + alg_name + ": Wrong tour cost"); + + SimplePath path; + alg.tour(path); + check(checkTourPath(g, path), alg_name + ": Wrong tour"); + check(checkCost(g, path, cost, alg.tourCost()), + alg_name + ": Wrong tour cost"); + + check(!Tolerance().less(alg.tourCost(), opt2.run(alg.tourNodes())), + "2-opt improvement: Wrong total cost"); + check(checkTour(g, opt2.tourNodes()), + "2-opt improvement: Wrong node sequence"); + check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()), + "2-opt improvement: Wrong tour cost"); + + check(!Tolerance().less(alg.tourCost(), opt2.run(path)), + "2-opt improvement: Wrong total cost"); + check(checkTour(g, opt2.tourNodes()), + "2-opt improvement: Wrong node sequence"); + check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()), + "2-opt improvement: Wrong tour cost"); + } +} + +// Algorithm class for Nearest Insertion +template +class NearestInsertionTsp : public InsertionTsp { +public: + NearestInsertionTsp(const FullGraph &gr, const CM &cost) + : InsertionTsp(gr, cost) {} + typename CM::Value run() { + return InsertionTsp::run(InsertionTsp::NEAREST); + } +}; + +// Algorithm class for Farthest Insertion +template +class FarthestInsertionTsp : public InsertionTsp { +public: + FarthestInsertionTsp(const FullGraph &gr, const CM &cost) + : InsertionTsp(gr, cost) {} + typename CM::Value run() { + return InsertionTsp::run(InsertionTsp::FARTHEST); + } +}; + +// Algorithm class for Cheapest Insertion +template +class CheapestInsertionTsp : public InsertionTsp { +public: + CheapestInsertionTsp(const FullGraph &gr, const CM &cost) + : InsertionTsp(gr, cost) {} + typename CM::Value run() { + return InsertionTsp::run(InsertionTsp::CHEAPEST); + } +}; + +// Algorithm class for Random Insertion +template +class RandomInsertionTsp : public InsertionTsp { +public: + RandomInsertionTsp(const FullGraph &gr, const CM &cost) + : InsertionTsp(gr, cost) {} + typename CM::Value run() { + return InsertionTsp::run(InsertionTsp::RANDOM); + } +}; + +int main() { + GRAPH_TYPEDEFS(FullGraph); + + // metricCostTest(); + + tspTestSmall > >("Nearest Neighbor"); + tspTestSmall > >("Greedy"); + tspTestSmall > >("Nearest Insertion"); + tspTestSmall > > + ("Farthest Insertion"); + tspTestSmall > > + ("Cheapest Insertion"); + tspTestSmall > >("Random Insertion"); + tspTestSmall > >("Christofides"); + tspTestSmall > >("2-opt"); + + tspTestRandom >("Nearest Neighbor"); + tspTestRandom >("Greedy"); + tspTestRandom >("Nearest Insertion"); + tspTestRandom >("Farthest Insertion"); + tspTestRandom >("Cheapest Insertion"); + tspTestRandom >("Random Insertion"); + tspTestRandom >("Christofides"); + tspTestRandom >("2-opt"); + + return 0; +} diff -r cd72eae05bdf -r 3c00344f49c9 tools/Makefile.am --- a/tools/Makefile.am Mon Jul 16 16:21:40 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -EXTRA_DIST += \ - tools/CMakeLists.txt - -if WANT_TOOLS - -bin_PROGRAMS += \ - tools/dimacs-solver \ - tools/dimacs-to-lgf \ - tools/lgf-gen - -dist_bin_SCRIPTS += tools/lemon-0.x-to-1.x.sh - -endif WANT_TOOLS - -tools_dimacs_solver_SOURCES = tools/dimacs-solver.cc -tools_dimacs_to_lgf_SOURCES = tools/dimacs-to-lgf.cc -tools_lgf_gen_SOURCES = tools/lgf-gen.cc diff -r cd72eae05bdf -r 3c00344f49c9 tools/dimacs-solver.cc --- a/tools/dimacs-solver.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/tools/dimacs-solver.cc Wed Oct 17 19:14:07 2018 +0200 @@ -2,7 +2,7 @@ * * This file is a part of LEMON, a generic C++ optimization library. * - * Copyright (C) 2003-2010 + * Copyright (C) 2003-2013 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * @@ -117,16 +117,18 @@ } if (report) std::cerr << "Read the file: " << ti << '\n'; + typedef NetworkSimplex MCF; ti.restart(); - NetworkSimplex ns(g); + MCF ns(g); ns.lowerMap(lower).upperMap(cap).costMap(cost).supplyMap(sup); if (sum_sup > 0) ns.supplyType(ns.LEQ); if (report) std::cerr << "Setup NetworkSimplex class: " << ti << '\n'; ti.restart(); - bool res = ns.run(); + typename MCF::ProblemType res = ns.run(); if (report) { std::cerr << "Run NetworkSimplex: " << ti << "\n\n"; - std::cerr << "Feasible flow: " << (res ? "found" : "not found") << '\n'; + std::cerr << "Feasible flow: " << (res == MCF::OPTIMAL ? "found" : + "not found") << '\n'; if (res) std::cerr << "Min flow cost: " << ns.template totalCost() << '\n'; } @@ -187,9 +189,6 @@ } int main(int argc, const char *argv[]) { - typedef SmartDigraph Digraph; - - typedef Digraph::Arc Arc; std::string inputName; std::string outputName; @@ -223,11 +222,13 @@ if (!output) { throw IoError("Cannot open the file for writing", ap.files()[1]); } + // fall through case 1: input.open(ap.files()[0].c_str()); if (!input) { throw IoError("File cannot be found", ap.files()[0]); } + // fall through case 0: break; default: @@ -252,6 +253,7 @@ break; case DimacsDescriptor::SP: std::cout << "sp"; + break; case DimacsDescriptor::MAT: std::cout << "mat"; break; diff -r cd72eae05bdf -r 3c00344f49c9 tools/dimacs-to-lgf.cc --- a/tools/dimacs-to-lgf.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/tools/dimacs-to-lgf.cc Wed Oct 17 19:14:07 2018 +0200 @@ -73,11 +73,13 @@ if (!output) { throw IoError("Cannot open the file for writing", ap.files()[1]); } + // fall through case 1: input.open(ap.files()[0].c_str()); if (!input) { throw IoError("File cannot be found", ap.files()[0]); } + // fall through case 0: break; default: diff -r cd72eae05bdf -r 3c00344f49c9 tools/lgf-gen.cc --- a/tools/lgf-gen.cc Mon Jul 16 16:21:40 2018 +0200 +++ b/tools/lgf-gen.cc Wed Oct 17 19:14:07 2018 +0200 @@ -246,7 +246,7 @@ struct BeachIt; - typedef std::multimap SpikeHeap; + typedef std::multimap SpikeHeap; typedef std::multimap Beach; @@ -329,6 +329,7 @@ Beach::iterator bit = beach.upper_bound(Part(site, site, site)); if (bit->second != spikeheap.end()) { + delete bit->second->second; spikeheap.erase(bit->second); } @@ -342,8 +343,8 @@ if (prev != -1 && circle_form(points[prev], points[curr], points[site])) { double x = circle_point(points[prev], points[curr], points[site]); - pit = spikeheap.insert(std::make_pair(x, BeachIt(beach.end()))); - pit->second.it = + pit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); + pit->second->it = beach.insert(std::make_pair(Part(prev, curr, site), pit)); } else { beach.insert(std::make_pair(Part(prev, curr, site), pit)); @@ -355,8 +356,8 @@ if (next != -1 && circle_form(points[site], points[curr],points[next])) { double x = circle_point(points[site], points[curr], points[next]); - nit = spikeheap.insert(std::make_pair(x, BeachIt(beach.end()))); - nit->second.it = + nit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); + nit->second->it = beach.insert(std::make_pair(Part(site, curr, next), nit)); } else { beach.insert(std::make_pair(Part(site, curr, next), nit)); @@ -366,7 +367,7 @@ } else { sweep = spit->first; - Beach::iterator bit = spit->second.it; + Beach::iterator bit = spit->second->it; int prev = bit->first.prev; int curr = bit->first.curr; @@ -399,10 +400,22 @@ Beach::iterator nbit = bit; ++nbit; int nnt = nbit->first.next; - if (bit->second != spikeheap.end()) spikeheap.erase(bit->second); - if (pbit->second != spikeheap.end()) spikeheap.erase(pbit->second); - if (nbit->second != spikeheap.end()) spikeheap.erase(nbit->second); - + if (bit->second != spikeheap.end()) + { + delete bit->second->second; + spikeheap.erase(bit->second); + } + if (pbit->second != spikeheap.end()) + { + delete pbit->second->second; + spikeheap.erase(pbit->second); + } + if (nbit->second != spikeheap.end()) + { + delete nbit->second->second; + spikeheap.erase(nbit->second); + } + beach.erase(nbit); beach.erase(bit); beach.erase(pbit); @@ -412,8 +425,8 @@ circle_form(points[ppv], points[prev], points[next])) { double x = circle_point(points[ppv], points[prev], points[next]); if (x < sweep) x = sweep; - pit = spikeheap.insert(std::make_pair(x, BeachIt(beach.end()))); - pit->second.it = + pit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); + pit->second->it = beach.insert(std::make_pair(Part(ppv, prev, next), pit)); } else { beach.insert(std::make_pair(Part(ppv, prev, next), pit)); @@ -424,8 +437,8 @@ circle_form(points[prev], points[next], points[nnt])) { double x = circle_point(points[prev], points[next], points[nnt]); if (x < sweep) x = sweep; - nit = spikeheap.insert(std::make_pair(x, BeachIt(beach.end()))); - nit->second.it = + nit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); + nit->second->it = beach.insert(std::make_pair(Part(prev, next, nnt), nit)); } else { beach.insert(std::make_pair(Part(prev, next, nnt), nit));