├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CMakeLists.txt ├── Dockerfile ├── FindGUROBI.cmake ├── LICENSE ├── MANIFEST.in ├── README.md ├── azure-pipelines.yml ├── docs ├── VPSolver3.pdf ├── arcflow.bib ├── html │ ├── CHANGELOG.html │ ├── Docker.html │ ├── Home.html │ ├── PyMPL.html │ ├── Python-API.html │ └── README.html ├── reports │ ├── Report1_GeneralArcFlow.pdf │ ├── Report2_BinaryCSP.pdf │ ├── Report3_MultipleChoiceVBP.pdf │ └── ThesisBrandaoF.pdf ├── vpsolver_manual.pdf └── vpsolver_poster.pdf ├── examples ├── .vscode │ └── settings.json ├── notebooks │ ├── example_mvp.ipynb │ ├── example_vbp.ipynb │ ├── graph_mvp.svg │ ├── graph_mvp_lpaths.svg │ ├── graph_vbp.svg │ └── graph_vbp_lpaths.svg ├── pympl │ ├── data │ │ ├── instance.mvp │ │ ├── instance.vbp │ │ ├── tsp_20_1.txt │ │ ├── tsp_30_1.txt │ │ ├── tsp_51_1.txt │ │ ├── tsp_5_1.txt │ │ └── twostage_A2.txt │ ├── instance_mvp.mod │ ├── instance_mvp.py │ ├── instance_vbp.mod │ ├── instance_vbp.py │ ├── test_pympl.py │ ├── tmp │ │ └── .gitignore │ ├── twostage.mod │ ├── twostage.py │ ├── wolsey.py │ ├── wolseyR1gamma.mod │ └── wolseyR2network.mod └── vpsolver │ ├── example.py │ ├── example.sh │ ├── example_ampl.sh │ ├── example_coinor.sh │ ├── example_glpk.sh │ ├── example_mvp.py │ ├── example_vbp.py │ ├── example_vsbpp.py │ ├── instance.mvp │ ├── instance.vbp │ ├── test_examples.py │ ├── test_vpsolver.py │ └── tmp │ ├── .gitignore │ ├── graph1.svg │ ├── graph2.svg │ ├── graphA_mvbp.svg │ ├── graphB_mvbp.svg │ ├── graph_vbp.svg │ └── graph_vsbpp.svg ├── pyvpsolver ├── .vscode │ └── settings.json ├── __init__.py ├── afgraph.py ├── solvers │ ├── __init__.py │ ├── mvpsolver2013.py │ ├── mvpsolver2016.py │ └── vbpsolver.py ├── utils.py ├── vpsolver.py └── webapp │ ├── __init__.py │ ├── app.py │ ├── data │ └── examples │ │ ├── mvp │ │ ├── mvp.mvp │ │ └── vsbpp.mvp │ │ └── vbp │ │ ├── bpp.vbp │ │ ├── csp.vbp │ │ └── vbp.vbp │ ├── static │ ├── bootstrap │ │ ├── css │ │ │ ├── bootstrap-theme-readable.css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ └── bootstrap.min.css │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ └── npm.js │ ├── css │ │ ├── app.css │ │ └── bootstrap.min.css │ ├── favicon.ico │ └── js │ │ ├── app.js │ │ ├── jquery-1.11.2.js │ │ └── jquery-1.11.2.min.map │ └── templates │ └── input.html ├── requirements.txt ├── scripts ├── .vscode │ └── settings.json ├── afg2ampl ├── afg2lp ├── afg2mps ├── afg2svg ├── vbp2afg ├── vbpsol ├── vpsolver_ampl.sh ├── vpsolver_base.sh ├── vpsolver_coinor.sh ├── vpsolver_cplex.sh ├── vpsolver_glpk.sh ├── vpsolver_gurobi.sh ├── vpsolver_lpsolve.sh └── vpsolver_scip.sh ├── setup.py ├── src ├── afg2ampl.cpp ├── afg2lp.cpp ├── afg2mps.cpp ├── arcflow.cpp ├── arcflow.hpp ├── arcflowsol.cpp ├── arcflowsol.hpp ├── common.cpp ├── common.hpp ├── config.hpp ├── config.hpp.in ├── graph.cpp ├── graph.hpp ├── instance.cpp ├── instance.hpp ├── vbp2afg.cpp ├── vbpsol.cpp └── vpsolver.cpp ├── swig ├── afg2ampl.i ├── afg2ampl.py ├── afg2ampl_wrap.cxx ├── afg2lp.i ├── afg2lp.py ├── afg2lp_wrap.cxx ├── afg2mps.i ├── afg2mps.py ├── afg2mps_wrap.cxx ├── vbp2afg.i ├── vbp2afg.py ├── vbp2afg_wrap.cxx ├── vbpsol.i ├── vbpsol.py └── vbpsol_wrap.cxx ├── virtualenv.sh └── webapp.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.log 3 | *.out 4 | *.pyc 5 | *.pyo 6 | *.o 7 | *.egg-info 8 | .ipynb_checkpoints 9 | .coverage 10 | .vscode 11 | .idea 12 | docker.sh 13 | coverage_html 14 | /bin/ 15 | /build/ 16 | /dist/ 17 | /.cache/ 18 | /venv* 19 | /swig.sh 20 | /clear.sh 21 | /register.sh 22 | /git_push.sh 23 | /git_fetch.sh 24 | /update_submodules.sh 25 | /workspace_private 26 | /Makefile 27 | /MANIFEST 28 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodules/PyMPL-git"] 2 | path = submodules/PyMPL-git 3 | url = https://github.com/fdabrandao/pympl.git 4 | ignore = dirty 5 | [submodule "submodules/docker-ubuntu-git"] 6 | path = submodules/docker-ubuntu-git 7 | url = https://github.com/fdabrandao/docker-ubuntu.git 8 | ignore = dirty 9 | [submodule "docs/wiki"] 10 | path = docs/wiki 11 | url = https://github.com/fdabrandao/vpsolver.wiki.git 12 | ignore = dirty 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [3.1.4] - 2023-05-03 6 | 7 | ### Added 8 | - Wheels for Python up to 3.11. 9 | 10 | ### Fixed 11 | - Fixed compilation error on Linux. 12 | 13 | ## [3.1.3] - 2021-10-02 14 | 15 | ### Added 16 | - Basic CMake support. 17 | - Binary wheels for all platforms. 18 | 19 | ## [3.1.2] - 2016-06-28 20 | 21 | ### Changed 22 | - Simplified the .afg format. 23 | 24 | ### Fixed 25 | - Fixed crash on Windows x64. 26 | 27 | 28 | ## [3.1.1] - 2016-05-12 29 | 30 | ### Changed 31 | - Simplified the Python API. 32 | 33 | ### Fixed 34 | - Fixed `afg2svg`. 35 | 36 | 37 | ## [3.1.0] - 2016-05-05 38 | 39 | ### Added 40 | - Jupyter Notebooks. 41 | 42 | ### Changed 43 | - The syntax used in the .vbp and .afg files for additional parameters. 44 | 45 | 46 | ## [3.0.1] - 2016-02-23 47 | 48 | ### Fixed 49 | - Fixed a minor compatibility issue with Python 2.7. 50 | 51 | 52 | ## [3.0.0] - 2016-02-23 53 | 54 | ### Added 55 | - New graph construction and compression algorithm for multiple-choice vector packing. 56 | 57 | ### Changed 58 | - Replaced the GPLv3+ license by AGPLv3+. 59 | 60 | ### Removed 61 | - Dropped backwards support for all previous graph construction and compression algorithms. 62 | 63 | ### Fixed 64 | - Various bugfixes. 65 | 66 | 67 | ## [2.0.0] - 2015-10-16 68 | 69 | ### Added 70 | - Documentation. 71 | - Full compatibility with both python 2 and 3. 72 | 73 | ### Removed 74 | - Dropped backwards support for `bin/gg_afg`, `bin/solve_glpk`, and `bin/solve_gurobi` from v1.0.0. 75 | 76 | ### Fixed 77 | - Various bugfixes. 78 | 79 | ## [1.3.0] - 2015-07-27 80 | 81 | ### Added 82 | - Initial version of PyMPL. 83 | 84 | 85 | ## [1.2.0] - 2015-07-21 86 | 87 | ### Added 88 | - Flask web app. 89 | 90 | 91 | ## [1.1.0] - 2015-05-20 92 | 93 | ### Added 94 | - Python API (pyvpsolver). 95 | 96 | 97 | ## 1.0.0 - 2013-11-06 98 | 99 | ### Added 100 | - First official release of the C++ implementation of VPSolver. 101 | 102 | [Unreleased]: https://github.com/fdabrandao/vpsolver/compare/v3.1.2...H 103 | [3.1.2]: https://github.com/fdabrandao/vpsolver/compare/v3.1.1...v3.1.2 104 | [3.1.1]: https://github.com/fdabrandao/vpsolver/compare/v3.1.0...v3.1.1 105 | [3.1.0]: https://github.com/fdabrandao/vpsolver/compare/v3.0.1...v3.1.0 106 | [3.0.1]: https://github.com/fdabrandao/vpsolver/compare/v3.0.0...v3.0.1 107 | [3.0.0]: https://github.com/fdabrandao/vpsolver/compare/v2.0.0...v3.0.0 108 | [2.0.0]: https://github.com/fdabrandao/vpsolver/compare/v1.3.0...v2.0.0 109 | [1.3.0]: https://github.com/fdabrandao/vpsolver/compare/v1.2.0...v1.3.0 110 | [1.2.0]: https://github.com/fdabrandao/vpsolver/compare/v1.1.0...v1.2.0 111 | [1.1.0]: https://github.com/fdabrandao/vpsolver/compare/v1.0.0...v1.1.0 112 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3...3.19) 2 | 3 | project( 4 | VPSolver 5 | VERSION 3.0 6 | LANGUAGES CXX) 7 | 8 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}) 9 | set(CMAKE_CXX_STANDARD 11) 10 | 11 | # Visual Studio compiler with static runtime libraries 12 | if(MSVC AND MT) 13 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 14 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") 15 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") 16 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") 17 | endif() 18 | 19 | add_library(vpsolver-lib OBJECT 20 | src/instance.cpp src/instance.hpp 21 | src/graph.cpp src/graph.hpp 22 | src/arcflow.cpp src/arcflow.hpp 23 | src/arcflowsol.cpp src/arcflowsol.hpp 24 | src/common.cpp src/common.hpp) 25 | 26 | # VPSolver executable 27 | find_package(GUROBI) 28 | if(GUROBI_CXX_LIBRARY AND GUROBI_LIBRARY AND GUROBI_INCLUDE_DIRS) 29 | add_executable(vpsolver src/vpsolver.cpp $) 30 | target_include_directories(vpsolver PRIVATE ${GUROBI_INCLUDE_DIRS}) 31 | target_link_libraries(vpsolver ${GUROBI_CXX_LIBRARY} ${GUROBI_LIBRARY}) 32 | install(TARGETS vpsolver DESTINATION bin) 33 | endif() 34 | 35 | # Auxiliary executables 36 | add_executable(vbp2afg src/vbp2afg.cpp $) 37 | add_executable(afg2ampl src/afg2ampl.cpp $) 38 | add_executable(afg2mps src/afg2mps.cpp $) 39 | add_executable(afg2lp src/afg2lp.cpp $) 40 | add_executable(vbpsol src/vbpsol.cpp $) 41 | install(TARGETS vbp2afg afg2mps afg2lp vbpsol DESTINATION bin) 42 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scripts/ DESTINATION scripts) 43 | 44 | # CPack 45 | set(CPACK_GENERATOR ZIP) 46 | set(CPACK_PACKAGE_FILE_NAME vpsolver) 47 | include(CPack) 48 | 49 | # CTest 50 | include(CTest) 51 | enable_testing() -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fdabrandao/docker-ubuntu 2 | 3 | MAINTAINER Filipe Brandão 4 | 5 | USER root 6 | RUN mkdir -p /vpsolver 7 | ADD . /vpsolver 8 | ENV HOME=/vpsolver 9 | WORKDIR /vpsolver 10 | 11 | # python2.7 virtualenv 12 | RUN rm -rf venv2.7 13 | RUN bash virtualenv.sh -p python2.7 --venv venv2.7 14 | 15 | # python3.5 virtualenv 16 | RUN rm -rf venv3.5 17 | RUN bash virtualenv.sh -p python3.5 --venv venv3.5 18 | 19 | # c++ 20 | RUN ./configure 21 | RUN make 22 | RUN make install 23 | 24 | EXPOSE 5555 25 | CMD bash webapp.sh --venv venv2.7 --port 5555 26 | -------------------------------------------------------------------------------- /FindGUROBI.cmake: -------------------------------------------------------------------------------- 1 | find_path( 2 | GUROBI_INCLUDE_DIRS 3 | NAMES gurobi_c.h 4 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 5 | PATH_SUFFIXES include) 6 | 7 | find_library( 8 | GUROBI_LIBRARY 9 | NAMES gurobi gurobi81 gurobi90 gurobi95 10 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 11 | PATH_SUFFIXES lib) 12 | 13 | get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) 14 | if("CXX" IN_LIST languages) 15 | if(MSVC) 16 | # determine Visual Studio year 17 | if(MSVC_TOOLSET_VERSION EQUAL 142) 18 | set(MSVC_YEAR "2019") 19 | elseif(MSVC_TOOLSET_VERSION EQUAL 141) 20 | set(MSVC_YEAR "2017") 21 | elseif(MSVC_TOOLSET_VERSION EQUAL 140) 22 | set(MSVC_YEAR "2015") 23 | endif() 24 | 25 | if(MT) 26 | set(M_FLAG "mt") 27 | else() 28 | set(M_FLAG "md") 29 | endif() 30 | 31 | find_library( 32 | GUROBI_CXX_LIBRARY 33 | NAMES gurobi_c++${M_FLAG}${MSVC_YEAR} 34 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 35 | PATH_SUFFIXES lib) 36 | find_library( 37 | GUROBI_CXX_DEBUG_LIBRARY 38 | NAMES gurobi_c++${M_FLAG}d${MSVC_YEAR} 39 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 40 | PATH_SUFFIXES lib) 41 | else() 42 | find_library( 43 | GUROBI_CXX_LIBRARY 44 | NAMES gurobi_c++ 45 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 46 | PATH_SUFFIXES lib) 47 | set(GUROBI_CXX_DEBUG_LIBRARY ${GUROBI_CXX_LIBRARY}) 48 | endif() 49 | endif() 50 | 51 | include(FindPackageHandleStandardArgs) 52 | find_package_handle_standard_args(GUROBI DEFAULT_MSG GUROBI_LIBRARY 53 | GUROBI_INCLUDE_DIRS) 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (C) 2013-2022, Filipe Brandão 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md CHANGELOG.md COPYING LICENSE requirements.txt 2 | recursive-include pyvpsolver * 3 | recursive-include src *.cpp 4 | recursive-include src *.cxx 5 | recursive-include src *.hpp 6 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | CIBW_SKIP: pp* cp27-* *_i686 *-win32 *musllinux* *-manylinux*_i686 3 | 4 | jobs: 5 | - job: sdist 6 | pool: {vmImage: 'Ubuntu-20.04'} 7 | steps: 8 | - task: UsePythonVersion@0 9 | - bash: | 10 | set -ex 11 | python -m pip install --upgrade pip 12 | python setup.py sdist -d upload 13 | displayName: Build documentation 14 | - task: PublishBuildArtifacts@1 15 | inputs: 16 | pathtoPublish: 'upload' 17 | artifactName: 'wheels' 18 | - job: manylinux 19 | pool: {vmImage: 'Ubuntu-20.04'} 20 | steps: 21 | - task: UsePythonVersion@0 22 | - bash: | 23 | set -ex 24 | mkdir -p build/{,upload} && cd build 25 | cmake .. && cmake --build . 26 | cpack && cp vpsolver.zip upload/vpsolver-linux64.zip 27 | displayName: Build binaries 28 | - task: PublishBuildArtifacts@1 29 | inputs: 30 | pathtoPublish: 'build/upload' 31 | artifactName: 'binaries' 32 | - bash: | 33 | set -ex 34 | python -m pip install --upgrade cibuildwheel==1.12.0 35 | CIBW_BUILD="cp35-*" cibuildwheel --platform linux --output-dir wheelhouse . 36 | python -m pip install --upgrade cibuildwheel==2.12.0 37 | cibuildwheel --platform linux --output-dir wheelhouse . 38 | displayName: Build wheels 39 | - task: PublishBuildArtifacts@1 40 | inputs: 41 | pathtoPublish: 'wheelhouse' 42 | artifactName: 'wheels' 43 | - job: macos 44 | pool: {vmImage: 'macos-latest'} 45 | steps: 46 | - task: UsePythonVersion@0 47 | - bash: | 48 | set -ex 49 | mkdir -p build/{,upload} && cd build 50 | cmake .. -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 && cmake --build . 51 | cpack && cp vpsolver.zip upload/vpsolver-macos64.zip 52 | displayName: Build binaries 53 | - task: PublishBuildArtifacts@1 54 | inputs: 55 | pathtoPublish: 'build/upload' 56 | artifactName: 'binaries' 57 | - bash: | 58 | set -ex 59 | python -m pip install --upgrade cibuildwheel==2.12.0 60 | cibuildwheel --platform macos --output-dir wheelhouse . 61 | displayName: Build wheels 62 | - task: PublishBuildArtifacts@1 63 | inputs: 64 | pathtoPublish: 'wheelhouse' 65 | artifactName: 'wheels' 66 | - job: windows 67 | pool: {vmImage: 'windows-2019'} 68 | steps: 69 | - task: UsePythonVersion@0 70 | - bash: | 71 | set -ex 72 | mkdir -p build/{,upload} && cd build 73 | cmake .. && cmake --build . --config Release 74 | cpack && cp vpsolver.zip upload/vpsolver-mswin64.zip 75 | displayName: Build binaries 76 | - task: PublishBuildArtifacts@1 77 | inputs: 78 | pathtoPublish: 'build/upload' 79 | artifactName: 'binaries' 80 | - bash: | 81 | set -ex 82 | python -m pip install --upgrade cibuildwheel==1.12.0 83 | CIBW_BUILD="cp35-*" cibuildwheel --platform windows --output-dir wheelhouse . 84 | python -m pip install --upgrade cibuildwheel==2.12.0 85 | cibuildwheel --platform windows --output-dir wheelhouse . 86 | displayName: Build wheels 87 | - task: PublishBuildArtifacts@1 88 | inputs: 89 | pathtoPublish: 'wheelhouse' 90 | artifactName: 'wheels' 91 | -------------------------------------------------------------------------------- /docs/VPSolver3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/docs/VPSolver3.pdf -------------------------------------------------------------------------------- /docs/arcflow.bib: -------------------------------------------------------------------------------- 1 | % http://vpsolver.dcc.fc.up.pt/ 2 | % http://www.dcc.fc.up.pt/~fdabrandao/ 3 | % https://github.com/fdabrandao/vpsolver 4 | % https://bitbucket.org/fdabrandao/vpsolver 5 | 6 | % http://arxiv.org/abs/1602.04876 7 | @misc{VPSolver3, 8 | author = {Brand\~ao, Filipe}, 9 | title = {{VPSolver 3}: {M}ultiple-choice {V}ector {P}acking {S}olver}, 10 | year = {2016}, 11 | note = {arXiv:1602.04876}, 12 | eprint = {arXiv:1602.04876}, 13 | url = {http://arxiv.org/abs/1602.04876}, 14 | } 15 | 16 | % http://dx.doi.org/10.1016/j.cor.2015.11.009 17 | @article{GeneralArcFlowPaper, 18 | title = "Bin packing and related problems: General arc-flow formulation with graph compression", 19 | journal = "Computers \& Operations Research", 20 | volume = "69", 21 | number = "", 22 | pages = "56 - 67", 23 | year = "2016", 24 | note = "", 25 | issn = "0305-0548", 26 | doi = "http://dx.doi.org/10.1016/j.cor.2015.11.009", 27 | url = "http://www.sciencedirect.com/science/article/pii/S0305054815002762", 28 | author = "Brand\~ao, Filipe and Pedroso, J. P.", 29 | keywords = "Bin packing", 30 | keywords = "Cutting stock", 31 | keywords = "Vector packing", 32 | keywords = "Arc-flow formulation" 33 | } 34 | 35 | % http://arxiv.org/abs/1310.6887 36 | @TechReport{GeneralArcFlowReport, 37 | author = {Brand\~ao, Filipe and Pedroso, J. P.}, 38 | title = {{Bin Packing and Related Problems: General Arc-flow Formulation with Graph Compression}}, 39 | type = {Technical Report}, 40 | number = {DCC-2013-08}, 41 | institution = {Faculdade de Ci\^encias da Universidade do Porto}, 42 | address = {Portugal}, 43 | year = {2013}, 44 | } 45 | 46 | % http://arxiv.org/abs/1502.02899 47 | @TechReport{BinaryCSP, 48 | author = {Brand\~ao, Filipe and Pedroso, J. P.}, 49 | title = {{Cutting Stock with Binary Patterns: Arc-flow Formulation with Graph Compression}}, 50 | type = {Technical Report}, 51 | number = {DCC-2013-09}, 52 | institution = {Faculdade de Ci\^encias da Universidade do Porto}, 53 | address = {Portugal}, 54 | year = {2013}, 55 | } 56 | 57 | % http://arxiv.org/abs/1312.3836 58 | @TechReport{MultipleChoiceVBP, 59 | author = {Brand\~ao, Filipe and Pedroso, J. P.}, 60 | title = {{Multiple-choice Vector Bin Packing: Arc-flow Formulation with Graph Compression}}, 61 | type = {Technical Report}, 62 | number = {DCC-2013-13}, 63 | institution = {Faculdade de Ci\^encias da Universidade do Porto}, 64 | address = {Portugal}, 65 | year = {2013}, 66 | } 67 | 68 | @MastersThesis{ThesisBrandaoF, 69 | author = {Brand\~ao, Filipe}, 70 | title = {{Bin Packing and Related Problems: Pattern-Based Approaches}}, 71 | school = {Faculdade de Ci\^encias da Universidade do Porto}, 72 | address = {Portugal}, 73 | year = {2012}, 74 | } 75 | -------------------------------------------------------------------------------- /docs/reports/Report1_GeneralArcFlow.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/docs/reports/Report1_GeneralArcFlow.pdf -------------------------------------------------------------------------------- /docs/reports/Report2_BinaryCSP.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/docs/reports/Report2_BinaryCSP.pdf -------------------------------------------------------------------------------- /docs/reports/Report3_MultipleChoiceVBP.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/docs/reports/Report3_MultipleChoiceVBP.pdf -------------------------------------------------------------------------------- /docs/reports/ThesisBrandaoF.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/docs/reports/ThesisBrandaoF.pdf -------------------------------------------------------------------------------- /docs/vpsolver_manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/docs/vpsolver_manual.pdf -------------------------------------------------------------------------------- /docs/vpsolver_poster.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/docs/vpsolver_poster.pdf -------------------------------------------------------------------------------- /examples/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#4e5a84", 4 | "activityBar.background": "#4e5a84", 5 | "activityBar.foreground": "#e7e7e7", 6 | "activityBar.inactiveForeground": "#e7e7e799", 7 | "activityBarBadge.background": "#3c2429", 8 | "activityBarBadge.foreground": "#e7e7e7", 9 | "commandCenter.border": "#e7e7e799", 10 | "sash.hoverBorder": "#4e5a84", 11 | "statusBar.background": "#3b4464", 12 | "statusBar.foreground": "#e7e7e7", 13 | "statusBarItem.hoverBackground": "#4e5a84", 14 | "statusBarItem.remoteBackground": "#3b4464", 15 | "statusBarItem.remoteForeground": "#e7e7e7", 16 | "tab.activeBorder": "#4e5a84", 17 | "titleBar.activeBackground": "#3b4464", 18 | "titleBar.activeForeground": "#e7e7e7", 19 | "titleBar.inactiveBackground": "#3b446499", 20 | "titleBar.inactiveForeground": "#e7e7e799" 21 | }, 22 | "peacock.color": "#3b4464" 23 | } -------------------------------------------------------------------------------- /examples/notebooks/graph_mvp.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %3 11 | 12 | 13 | 1 14 | 15 | 1 16 | 17 | 18 | 2 19 | 20 | 2 21 | 22 | 23 | 1->2 24 | 25 | 26 | 27 | 28 | T2 29 | 30 | T2 31 | 32 | 33 | 1->T2 34 | 35 | 36 | 37 | 38 | 2->T2 39 | 40 | 41 | 42 | 43 | 3 44 | 45 | 3 46 | 47 | 48 | 2->3 49 | 50 | 51 | 52 | 53 | T1 54 | 55 | T1 56 | 57 | 58 | T2->T1 59 | 60 | 61 | 62 | 63 | 3->T1 64 | 65 | 66 | 67 | 68 | S 69 | 70 | S 71 | 72 | 73 | S->1 74 | 75 | 76 | 77 | 78 | S->1 79 | 80 | 81 | 82 | 83 | S->2 84 | 85 | 86 | 87 | 88 | S->T2 89 | 90 | 91 | 92 | 93 | S->T1 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /examples/pympl/data/instance.mvp: -------------------------------------------------------------------------------- 1 | 2 2 | 3 | 5 4 | 100 100 100 -1 5 | 50 120 700 -1 6 | 150 25 2 1 7 | 150 25 3 -1 8 | 25 50 10 -1 9 | 10 | 3 11 | 12 | 3 1 13 | 50 25 14 | 25 50 15 | 0 75 16 | 17 | 3 1 18 | 40 40 19 | 60 25 20 | 25 60 21 | 22 | 3 1 23 | 30 10 24 | 20 40 25 | 10 50 26 | -------------------------------------------------------------------------------- /examples/pympl/data/instance.vbp: -------------------------------------------------------------------------------- 1 | 2 2 | 100 100 3 | 97 4 | 9 13 1 5 | 11 11 1 6 | 17 10 1 7 | 17 16 1 8 | 18 29 1 9 | 21 10 1 10 | 21 20 1 11 | 21 32 1 12 | 22 32 1 13 | 22 40 1 14 | 22 41 1 15 | 23 27 1 16 | 24 7 1 17 | 24 17 1 18 | 25 7 1 19 | 25 26 1 20 | 25 27 1 21 | 26 27 1 22 | 26 40 1 23 | 26 42 1 24 | 26 43 1 25 | 27 28 1 26 | 27 39 1 27 | 28 33 1 28 | 28 39 1 29 | 28 44 1 30 | 28 45 1 31 | 28 46 1 32 | 29 26 1 33 | 29 37 1 34 | 30 28 1 35 | 30 30 1 36 | 30 34 1 37 | 30 36 1 38 | 30 37 1 39 | 30 40 1 40 | 30 43 1 41 | 31 17 1 42 | 31 21 1 43 | 31 31 1 44 | 31 34 1 45 | 32 19 1 46 | 32 34 1 47 | 32 36 1 48 | 33 22 1 49 | 33 26 1 50 | 33 28 1 51 | 33 36 1 52 | 33 37 1 53 | 34 12 1 54 | 34 30 1 55 | 34 36 2 56 | 34 39 1 57 | 34 46 1 58 | 35 33 1 59 | 35 43 1 60 | 35 50 1 61 | 36 25 1 62 | 36 36 1 63 | 36 40 1 64 | 36 46 1 65 | 37 31 1 66 | 37 42 1 67 | 37 44 2 68 | 38 37 1 69 | 38 44 1 70 | 38 49 1 71 | 39 19 1 72 | 39 26 1 73 | 39 30 1 74 | 39 34 1 75 | 39 47 1 76 | 39 49 1 77 | 40 12 1 78 | 40 42 1 79 | 40 44 1 80 | 40 46 1 81 | 40 48 1 82 | 42 18 1 83 | 42 28 1 84 | 42 36 1 85 | 42 40 1 86 | 43 26 1 87 | 43 32 1 88 | 43 41 1 89 | 43 46 1 90 | 44 40 1 91 | 44 47 1 92 | 45 28 1 93 | 45 48 1 94 | 46 39 1 95 | 47 44 1 96 | 48 28 1 97 | 48 30 1 98 | 48 46 1 99 | 49 33 1 100 | 49 47 1 101 | -------------------------------------------------------------------------------- /examples/pympl/data/tsp_20_1.txt: -------------------------------------------------------------------------------- 1 | 20 2 | 27 68 3 | 30 48 4 | 43 67 5 | 58 48 6 | 58 27 7 | 37 69 8 | 38 46 9 | 46 10 10 | 61 33 11 | 62 63 12 | 63 69 13 | 32 22 14 | 45 35 15 | 59 15 16 | 5 6 17 | 10 17 18 | 21 10 19 | 5 64 20 | 30 15 21 | 39 10 22 | -------------------------------------------------------------------------------- /examples/pympl/data/tsp_30_1.txt: -------------------------------------------------------------------------------- 1 | 30 2 | 27 68 3 | 30 48 4 | 43 67 5 | 58 48 6 | 58 27 7 | 37 69 8 | 38 46 9 | 46 10 10 | 61 33 11 | 62 63 12 | 63 69 13 | 32 22 14 | 45 35 15 | 59 15 16 | 5 6 17 | 10 17 18 | 21 10 19 | 5 64 20 | 30 15 21 | 39 10 22 | 32 39 23 | 25 32 24 | 25 55 25 | 48 28 26 | 56 37 27 | 30 40 28 | 37 52 29 | 49 49 30 | 52 64 31 | 20 26 32 | -------------------------------------------------------------------------------- /examples/pympl/data/tsp_51_1.txt: -------------------------------------------------------------------------------- 1 | 51 2 | 27 68 3 | 30 48 4 | 43 67 5 | 58 48 6 | 58 27 7 | 37 69 8 | 38 46 9 | 46 10 10 | 61 33 11 | 62 63 12 | 63 69 13 | 32 22 14 | 45 35 15 | 59 15 16 | 5 6 17 | 10 17 18 | 21 10 19 | 5 64 20 | 30 15 21 | 39 10 22 | 32 39 23 | 25 32 24 | 25 55 25 | 48 28 26 | 56 37 27 | 30 40 28 | 37 52 29 | 49 49 30 | 52 64 31 | 20 26 32 | 40 30 33 | 21 47 34 | 17 63 35 | 31 62 36 | 52 33 37 | 51 21 38 | 42 41 39 | 31 32 40 | 5 25 41 | 12 42 42 | 36 16 43 | 52 41 44 | 27 23 45 | 17 33 46 | 13 13 47 | 57 58 48 | 62 42 49 | 42 57 50 | 16 57 51 | 8 52 52 | 7 38 53 | -------------------------------------------------------------------------------- /examples/pympl/data/tsp_5_1.txt: -------------------------------------------------------------------------------- 1 | 5 2 | 0 0 3 | 0 0.5 4 | 0 1 5 | 1 1 6 | 1 0 7 | -------------------------------------------------------------------------------- /examples/pympl/data/twostage_A2.txt: -------------------------------------------------------------------------------- 1 | 60 60 2 | 20 3 | 32 40 1 4 | 29 42 2 5 | 31 39 1 6 | 27 38 1 7 | 27 37 3 8 | 24 36 4 9 | 25 35 2 10 | 28 34 2 11 | 33 25 4 12 | 23 31 4 13 | 31 24 3 14 | 26 18 3 15 | 18 29 4 16 | 15 24 2 17 | 16 25 4 18 | 17 26 3 19 | 23 14 4 20 | 21 15 3 21 | 19 16 2 22 | 12 17 1 23 | -------------------------------------------------------------------------------- /examples/pympl/instance_mvp.mod: -------------------------------------------------------------------------------- 1 | $EXEC{ 2 | from pyvpsolver import MVP 3 | inst = MVP.from_file("data/instance.mvp") 4 | }; 5 | $PARAM[nbtypes]{len(inst.Ws)}; 6 | $PARAM[Cs]{inst.Cs, i0=1}; 7 | $PARAM[Qs]{inst.Qs, i0=1}; 8 | $PARAM[m]{inst.m}; 9 | $PARAM[b]{inst.b, i0=1}; 10 | 11 | set I := 1..m; 12 | set T := 1..nbtypes; 13 | var Z{T}, integer, >= 0; 14 | var x{I}, >= 0; 15 | var cost; 16 | 17 | $MVP_FLOW[^Z{T}]{inst.Ws, inst.ws, ["x[{0}]".format(i+1) for i in range(inst.m)], i0=1}; 18 | 19 | /* 20 | # MVP_FLOW is equivalent to: 21 | $MVP_GRAPH[V, A]{ 22 | inst.Ws, 23 | inst.ws, 24 | {(i, j): (i+1, j+1) for i in range(inst.m) for j in range(len(inst.ws[i]))}, 25 | inst.b, 26 | S="S", Ts=["T{}".format(i+1) for i in range(len(inst.Ws))], LOSS=("LOSS", "ARC") 27 | }; 28 | var f{(u, v, i, o) in A}, >= 0, <= (if i != 'LOSS' then b[i] else Infinity); 29 | s.t. flow_con{k in V}: 30 | sum{(u, v, i, o) in A: v==k} f[u, v, i, o] - sum{(u, v, i, o) in A: u==k} f[u, v, i, o] = 0; 31 | s.t. assocs{it in I}: x[it] = sum{(u, v, i, o) in A: i == it} f[u, v, i, o]; 32 | s.t. zvalues{t in T}: Z[t] = f['T'&t, 'S', 'LOSS', 'ARC']; 33 | */ 34 | 35 | minimize obj: cost; 36 | s.t. demand{i in 1..m}: x[i] >= b[i]; 37 | s.t. zub{t in T: Qs[t] != -1}: Z[t] <= Qs[t]; 38 | s.t. total_cost: cost = sum{t in T} Z[t]*Cs[t]; 39 | end; 40 | -------------------------------------------------------------------------------- /examples/pympl/instance_mvp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | import os 4 | 5 | 6 | def main(): 7 | """Parses 'instance_mvp.mod'""" 8 | from pympl import PyMPL, Tools, glpkutils 9 | 10 | os.chdir(os.path.dirname(__file__) or os.curdir) 11 | 12 | mod_in = "instance_mvp.mod" 13 | mod_out = "tmp/instance_mvp.out.mod" 14 | parser = PyMPL(locals_=locals(), globals_=globals()) 15 | parser.parse(mod_in, mod_out) 16 | 17 | lp_out = "tmp/instance_mvp.lp" 18 | glpkutils.mod2lp(mod_out, lp_out, True) 19 | out, varvalues = Tools.script("glpk_wrapper.sh", lp_out, verbose=True) 20 | sol = parser["MVP_FLOW"].extract( 21 | lambda varname: varvalues.get(varname, 0), verbose=True 22 | ) 23 | 24 | print("") 25 | print("sol:", sol) 26 | print("varvalues:", [(k, v) for k, v in sorted(varvalues.items())]) 27 | print("") 28 | assert varvalues["cost"] == 8 # check the solution objective value 29 | 30 | # exit_code = os.system("glpsol --math {0}".format(mod_out)) 31 | # assert exit_code == 0 32 | 33 | 34 | if __name__ == "__main__": 35 | main() 36 | -------------------------------------------------------------------------------- /examples/pympl/instance_vbp.mod: -------------------------------------------------------------------------------- 1 | $EXEC{ 2 | from pyvpsolver import VBP 3 | instance = VBP.from_file("data/instance.vbp") 4 | }; 5 | $SET[I]{range(instance.m)}; 6 | $PARAM[b{^I}]{instance.b}; 7 | var x{I}, >= 0; 8 | var Z, >= 0; 9 | 10 | minimize obj: Z; 11 | s.t. demand{i in I}: x[i] >= b[i]; 12 | 13 | $VBP_FLOW[^Z]{instance.W, instance.w, ["x[%d]"%i for i in range(instance.m)]}; 14 | 15 | /* 16 | # VBP_FLOW is equivalent to: 17 | $VBP_GRAPH[V,A]{instance.W, instance.w, range(instance.m), instance.b, S="S", T="T", LOSS="LOSS"}; 18 | var f{(u, v, i) in A}, >= 0, <= (if i != 'LOSS' then b[i] else Infinity); 19 | s.t. flow_con{k in V}: 20 | sum{(u, v, i) in A: v==k} f[u, v, i] - sum{(u, v, i) in A: u==k} f[u, v, i] = 0; 21 | s.t. assocs{it in I}: x[it] = sum{(u, v, i) in A: i == it} f[u, v, i]; 22 | s.t. zvalue: Z = f['T', 'S', 'LOSS']; 23 | */ 24 | end; 25 | -------------------------------------------------------------------------------- /examples/pympl/instance_vbp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | import os 4 | 5 | 6 | def main(): 7 | """Parses 'instance_vbp.mod'""" 8 | from pympl import PyMPL, Tools, glpkutils 9 | 10 | os.chdir(os.path.dirname(__file__) or os.curdir) 11 | 12 | mod_in = "instance_vbp.mod" 13 | mod_out = "tmp/instance_vbp.out.mod" 14 | parser = PyMPL(locals_=locals(), globals_=globals()) 15 | parser.parse(mod_in, mod_out) 16 | 17 | lp_out = "tmp/instance_vbp.lp" 18 | glpkutils.mod2lp(mod_out, lp_out, True) 19 | out, varvalues = Tools.script("glpk_wrapper.sh", lp_out, verbose=True) 20 | sol = parser["VBP_FLOW"].extract( 21 | lambda varname: varvalues.get(varname, 0), verbose=True 22 | ) 23 | 24 | print("") 25 | print("sol:", sol) 26 | print("varvalues:", [(k, v) for k, v in sorted(varvalues.items())]) 27 | print("") 28 | assert varvalues["Z"] == 33 # check the solution objective value 29 | 30 | # exit_code = os.system("glpsol --math {0}".format(mod_out)) 31 | # assert exit_code == 0 32 | 33 | 34 | if __name__ == "__main__": 35 | main() 36 | -------------------------------------------------------------------------------- /examples/pympl/test_pympl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | 5 | def test_instance_vbp(): 6 | """Test instance_vbp.""" 7 | import instance_vbp 8 | 9 | instance_vbp.main() 10 | 11 | 12 | def test_instance_mvp(): 13 | """Test instance_mvp.""" 14 | import instance_mvp 15 | 16 | instance_mvp.main() 17 | 18 | 19 | def test_wolsey(): 20 | """Test wolsey.""" 21 | import wolsey 22 | 23 | wolsey.main() 24 | 25 | 26 | def test_twostage(): 27 | """Test twostage.""" 28 | import twostage 29 | 30 | twostage.main() 31 | 32 | 33 | if __name__ == "__main__": 34 | test_instance_vbp() 35 | test_instance_mvp() 36 | test_wolsey() 37 | test_twostage() 38 | -------------------------------------------------------------------------------- /examples/pympl/tmp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /examples/pympl/twostage.mod: -------------------------------------------------------------------------------- 1 | /* 2 | Models the two-stage two-dimensional guillotine cutting stock problem 3 | based on a simplified version of Macedo et al. (2010) arc-flow model 4 | */ 5 | 6 | $EXEC{ 7 | W, H, w, h, b = read_twostage("data/twostage_A2.txt") 8 | hcuts = sorted(set(h)|set(w)) 9 | }; 10 | 11 | $SET[HS]{hcuts}; 12 | $SET[I]{range(len(b))}; 13 | $PARAM[b{^I}]{b}; 14 | 15 | $EXEC{ 16 | HS = _sets["HS"] 17 | I = _sets["I"] 18 | }; 19 | 20 | # Stage 1 (horizontal cuts): 21 | # Z is the number of sheets used 22 | # hbars[h] is the number of horizontal strips of height h cut 23 | var hbars{HS}, >= 0, integer; 24 | $VBP_FLOW[Z]{ 25 | [H], 26 | [[hc] for hc in hcuts], 27 | ["hbars[%d]"%height for height in HS] 28 | }; 29 | 30 | # Stage 2 (vertical cuts): 31 | # x[h, i] is the number of items of type i cut from strips of height h 32 | var x{HS, I, {0, 1}}, >= 0, integer; 33 | $EXEC{ 34 | for height in HS: 35 | ws, xvars, labels = [], [], [] 36 | 37 | ws += [[w[it]] if h[it] <= height else [W+1] for it in I] 38 | xvars += ["x[%d,%d,0]"%(height, it) for it in I] 39 | labels += ["({}x{})".format(w[it], h[it]) for it in I] 40 | 41 | ws += [[h[it]] if w[it] <= height else [W+1] for it in I] 42 | xvars += ["x[%d,%d,1]"%(height, it) for it in I] 43 | labels += ["({}x{})^r".format(w[it], h[it]) for it in I] 44 | 45 | VBP_FLOW["^hbars[%d]"%height]([W], ws, xvars, labels=labels) 46 | }; 47 | 48 | # Demand constraints: 49 | s.t. demand{it in I}: sum{h in HS} (x[h, it, 0] + x[h, it, 1]) >= b[it]; 50 | 51 | minimize obj: Z; 52 | end; 53 | -------------------------------------------------------------------------------- /examples/pympl/twostage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | from builtins import range 4 | from builtins import map 5 | import os 6 | 7 | 8 | def read_twostage(fname): 9 | """Loads two-stage instances.""" 10 | with open(fname) as f: 11 | lst = list(map(int, f.read().split())) 12 | W = lst.pop(0) 13 | H = lst.pop(0) 14 | m = lst.pop(0) 15 | w, h, b = [], [], [] 16 | for i in range(m): 17 | w.append(lst.pop(0)) 18 | h.append(lst.pop(0)) 19 | b.append(lst.pop(0)) 20 | return W, H, w, h, b 21 | 22 | 23 | def main(): 24 | """Parses 'twostage.mod'.""" 25 | from pympl import PyMPL, Tools, glpkutils 26 | 27 | os.chdir(os.path.dirname(__file__) or os.curdir) 28 | 29 | mod_in = "twostage.mod" 30 | mod_out = "tmp/twostage.out.mod" 31 | parser = PyMPL(locals_=locals(), globals_=globals()) 32 | parser.parse(mod_in, mod_out) 33 | 34 | lp_out = "tmp/twostage.lp" 35 | glpkutils.mod2lp(mod_out, lp_out, True) 36 | 37 | out, varvalues = Tools.script("glpk_wrapper.sh", lp_out, verbose=True) 38 | 39 | print("") 40 | print( 41 | "varvalues:", 42 | [(k, v) for k, v in sorted(varvalues.items()) if not k.startswith("_")], 43 | ) 44 | print("") 45 | assert varvalues["Z"] == 11 # check the solution objective value 46 | 47 | exctacted_solution = parser["VBP_FLOW"].extract( 48 | lambda name: varvalues.get(name, 0), verbose=True 49 | ) 50 | 51 | solution = {} 52 | for zvar, value, sol in exctacted_solution: 53 | solution[zvar] = [] 54 | for r, pattern in sol: 55 | solution[zvar] += [pattern] * r 56 | assert value == len(solution[zvar]) 57 | 58 | def pop_pattern(zvar): 59 | pattern = [] 60 | for it in solution[zvar].pop(): 61 | if it not in solution: 62 | pattern.append(it) 63 | else: 64 | pattern.append((it, pop_pattern(it))) 65 | return pattern 66 | 67 | print("\n\nSolution:") 68 | for i in range(varvalues["Z"]): 69 | pattern = pop_pattern("Z") 70 | print("Sheet {}: {}".format(i + 1, pattern)) 71 | 72 | 73 | if __name__ == "__main__": 74 | main() 75 | -------------------------------------------------------------------------------- /examples/pympl/wolsey.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | from __future__ import division 4 | from builtins import range 5 | import os 6 | 7 | 8 | def main(): 9 | """Parses 'graph.mod'""" 10 | from pympl import PyMPL, Tools, glpkutils 11 | 12 | os.chdir(os.path.dirname(__file__) or os.curdir) 13 | 14 | a, a0 = [65, 64, 41, 22, 13, 12, 8, 2], 80 15 | aS = abs(2 * a0 + 1 - sum(a)) 16 | if a0 < (sum(a) - 1) // 2: 17 | a0 += aS 18 | a.append(aS) 19 | 20 | print("self-dual:", a, a0) 21 | 22 | m = len(a) 23 | W = [a0] + [1] * len(a) 24 | w = [[a[i]] + [1 if j == i else 0 for j in range(m)] for i in range(m)] 25 | labels = [i + 1 for i in range(m)] 26 | bounds = [1 if w[i] <= W else 0 for i in range(m)] 27 | 28 | # wolseyR2network: 29 | 30 | print("-" * 10) 31 | print("Primal:") 32 | 33 | mod_in = "wolseyR2network.mod" 34 | mod_out = "tmp/wolseyR2network.out.mod" 35 | parser = PyMPL(locals_=locals(), globals_=globals()) 36 | parser.parse(mod_in, mod_out) 37 | lp_out = "tmp/wolseyR2network.lp" 38 | glpkutils.mod2lp(mod_out, lp_out, verbose=False) 39 | out, varvalues = Tools.script("glpk_wrapper.sh", lp_out, verbose=False) 40 | print("") 41 | print("varvalues:", [(k, v) for k, v in sorted(varvalues.items())]) 42 | print("") 43 | 44 | # Check the solution objective value: 45 | assert abs(varvalues["Z0"] - 9) < 1e-5 46 | 47 | # exit_code = os.system("glpsol --math {0}".format(mod_out)) 48 | # assert exit_code == 0 49 | 50 | # wolseyR1gamma: 51 | 52 | print("-" * 10) 53 | print("wolseyR1gamma:") 54 | 55 | mod_in = "wolseyR1gamma.mod" 56 | mod_out = "tmp/wolseyR1gamma.mod.out.mod" 57 | parser = PyMPL(locals_=locals(), globals_=globals()) 58 | parser.parse(mod_in, mod_out) 59 | lp_out = "tmp/wolseyR1gamma.mod.lp" 60 | glpkutils.mod2lp(mod_out, lp_out, verbose=False) 61 | out, varvalues = Tools.script("glpk_wrapper.sh", lp_out, verbose=False) 62 | print("") 63 | print("varvalues:", [(k, v) for k, v in sorted(varvalues.items())]) 64 | print("") 65 | 66 | # Check the solution objective value: 67 | assert abs(varvalues["theta(T)"] - 9) < 1e-5 68 | 69 | # exit_code = os.system("glpsol --math {0}".format(mod_out)) 70 | # assert exit_code == 0 71 | 72 | 73 | if __name__ == "__main__": 74 | main() 75 | -------------------------------------------------------------------------------- /examples/pympl/wolseyR1gamma.mod: -------------------------------------------------------------------------------- 1 | /* 2 | Wolsey, L. A. (1977). Valid inequalities, covering problems and discrete 3 | dynamic programs. 4 | */ 5 | $VBP_GRAPH[V,A]{W, w, labels, bounds}; 6 | 7 | $PARAM[m]{m}; 8 | 9 | set I := 1..m; 10 | var pi{I} >= 0; 11 | var theta{V} >= 0; 12 | 13 | minimize obj: theta['T']; 14 | s.t. gamma{(u,v,i) in A: v != 'S'}: 15 | theta[v] >= theta[u]+(if i != 'LOSS' then pi[i] else 0); 16 | s.t. pisum: sum{i in I} pi[i] = 1+2*theta['T']; 17 | end; 18 | -------------------------------------------------------------------------------- /examples/pympl/wolseyR2network.mod: -------------------------------------------------------------------------------- 1 | /* 2 | Wolsey, L. A. (1977). Valid inequalities, covering problems and discrete 3 | dynamic programs. 4 | */ 5 | $VBP_GRAPH[V,A]{W, w, labels, bounds}; 6 | 7 | $PARAM[m]{m}; 8 | 9 | set I := 1..m; 10 | var f{A} >= 0; 11 | var Z; 12 | var Z0; 13 | 14 | maximize obj: Z0; 15 | s.t. flowcon{k in V}: 16 | sum{(u,v,i) in A: v == k} f[u,v,i] - sum{(u,v,i) in A: u == k} f[u, v, i] = 0; 17 | s.t. feedback: f['T', 'S', 'LOSS'] = 1+2*Z0; 18 | s.t. demand{k in I}: sum{(u,v,i) in A: i == k} -f[u,v,i]+Z0 <= 0; 19 | end; 20 | -------------------------------------------------------------------------------- /examples/vpsolver/example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | import os 4 | 5 | 6 | def main(): 7 | """Examples: how to use VBP, MVP, AFG, MPS, LP and VPSolver""" 8 | from pyvpsolver import VPSolver, VBP, MVP, AFG, MPS, LP 9 | from pyvpsolver.solvers import vbpsolver, mvpsolver 10 | 11 | os.chdir(os.path.dirname(__file__) or os.curdir) 12 | 13 | # Create instanceA: 14 | instanceA = VBP( 15 | (5180,), 16 | [(1120,), (1250,), (520,), (1066,), (1000,), (1150,)], 17 | [9, 5, 91, 18, 11, 64], 18 | ) 19 | 20 | # Create instanceB from a .vbp file 21 | instanceB = VBP.from_file("instance.vbp") 22 | 23 | # Create an arc-flow graph for instanceA 24 | afg = AFG(instanceA, verbose=False) 25 | 26 | # Create .mps and .lp models for instanceA 27 | mps_model = MPS(afg, verbose=False) 28 | lp_model = LP(afg, verbose=False) 29 | 30 | # Draw the arc-flow graph for instanceA (requires pygraphviz) 31 | try: 32 | afg.draw("tmp/graph1.svg") 33 | except ImportError as e: 34 | print(repr(e)) 35 | 36 | # Solve instanceA using bin/vpsolver (requires Gurobi) 37 | try: 38 | out, sol = VPSolver.vpsolver(instanceA, verbose=True) 39 | except Exception as e: 40 | print("Failed to call vpsolver") 41 | print(repr(e)) 42 | 43 | # Solve instanceA using any vpsolver script (i.e., any MIP solver): 44 | # The scripts accept models with and without the underlying graphs. 45 | # However, the graphs are required to extract the solution. 46 | out, sol = VPSolver.script("vpsolver_glpk.sh", lp_model, afg, verbose=True) 47 | try: 48 | out, sol = VPSolver.script("vpsolver_gurobi.sh", mps_model, verbose=True) 49 | except Exception as e: 50 | print(repr(e)) 51 | 52 | # Solve an instance directly without creating AFG, MPS or LP objects: 53 | out, solution = VPSolver.script("vpsolver_glpk.sh", instanceB, verbose=True) 54 | 55 | # Print the solution: 56 | obj, patterns = solution 57 | print("Objective:", obj) 58 | print("Solution:", patterns) 59 | 60 | # Pretty-print the solution: 61 | vbpsolver.print_solution(solution) 62 | 63 | # check the solution objective value 64 | obj, patterns = solution 65 | assert obj == 21 66 | 67 | # Create instanceC: 68 | W1 = (100, 100) 69 | W2 = (50, 120) 70 | W3 = (150, 25) 71 | ws1, b1 = [(50, 25), (25, 50), (0, 75)], 1 72 | ws2, b2 = [(40, 40), (60, 25), (25, 60)], 1 73 | ws3, b3 = [(30, 10), (20, 40), (10, 50)], 1 74 | Ws = [W1, W2, W3] # capacities 75 | Cs = [3, 7, 2] # costs 76 | Qs = [-1, -1, -1] # number of bins available 77 | ws = [ws1, ws2, ws3] # items 78 | b = [b1, b2, b3] # demands 79 | instanceC = MVP(Ws, Cs, Qs, ws, b) 80 | 81 | # Solve an instance directly without creating AFG, MPS or LP objects: 82 | out, solution = VPSolver.script("vpsolver_glpk.sh", instanceC, verbose=True) 83 | mvpsolver.print_solution(solution) 84 | 85 | # check the solution objective value 86 | obj, patterns = solution 87 | assert obj == 3 88 | 89 | # Create instanceD from a .mvp file 90 | instanceD = MVP.from_file("instance.mvp") 91 | 92 | # Draw the arc-flow graph for instanceD (requires pygraphviz) 93 | try: 94 | AFG(instanceD).draw("tmp/graph2.svg") 95 | except ImportError as e: 96 | print(repr(e)) 97 | 98 | # Solve an instance directly without creating AFG, MPS or LP objects: 99 | out, solution = VPSolver.script("vpsolver_glpk.sh", instanceD, verbose=True) 100 | mvpsolver.print_solution(solution) 101 | 102 | # check the solution objective value 103 | obj, patterns = solution 104 | assert obj == 8 105 | 106 | 107 | if __name__ == "__main__": 108 | main() 109 | -------------------------------------------------------------------------------- /examples/vpsolver/example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BASEDIR=`dirname "$0"` 3 | cd $BASEDIR 4 | 5 | TMP_DIR=`mktemp -d -t XXXXXXXXXX` 6 | trap "rm -rf $TMP_DIR" EXIT 7 | 8 | PATH="../bin/:../scripts/:$PATH" 9 | 10 | echo "**********************************************************" 11 | echo "* Example 1: *" 12 | echo "* > vpsolver instance.vbp *" 13 | echo "**********************************************************" 14 | vpsolver instance.vbp 15 | 16 | echo -e "\n\n" 17 | 18 | echo "**********************************************************" 19 | echo "* Example 2: *" 20 | echo "* > vbp2afg instance.vbp graph.afg *" 21 | echo "* > afg2mps graph.afg model.mps *" 22 | echo "* > vpsolver_gurobi.sh --mps model.mps --wsol vars.sol *" 23 | echo "* > vbpsol graph.afg vars.sol *" 24 | echo "**********************************************************" 25 | vbp2afg instance.vbp $TMP_DIR/graph.afg 26 | afg2mps $TMP_DIR/graph.afg $TMP_DIR/model.mps 27 | vpsolver_gurobi.sh --mps $TMP_DIR/model.mps --wsol $TMP_DIR/vars.sol 28 | vbpsol $TMP_DIR/graph.afg $TMP_DIR/vars.sol 29 | 30 | echo -e "\n\n" 31 | 32 | echo "**********************************************************" 33 | echo "* Example 3: *" 34 | echo "* > vbp2afg instance.vbp graph.afg *" 35 | echo "* > afg2lp graph.afg model.lp *" 36 | echo "* > vpsolver_glpk.sh --lp model.lp --wsol vars.sol *" 37 | echo "* > vbpsol graph.afg vars.sol *" 38 | echo "**********************************************************" 39 | vbp2afg instance.vbp $TMP_DIR/graph.afg 40 | afg2lp $TMP_DIR/graph.afg $TMP_DIR/model.lp 41 | vpsolver_glpk.sh --lp $TMP_DIR/model.lp --wsol $TMP_DIR/vars.sol 42 | vbpsol $TMP_DIR/graph.afg $TMP_DIR/vars.sol 43 | 44 | echo -e "\n\n" 45 | 46 | echo "**********************************************************" 47 | echo "* Example 4: *" 48 | echo "* > vbp2afg instance.vbp graph.afg *" 49 | echo "* > afg2lp graph.afg model.lp *" 50 | echo "* > vpsolver_glpk.sh --lp model.lp --afg graph.afg *" 51 | echo "**********************************************************" 52 | vbp2afg instance.vbp $TMP_DIR/graph.afg 53 | afg2lp $TMP_DIR/graph.afg $TMP_DIR/model.lp 54 | vpsolver_glpk.sh --lp $TMP_DIR/model.lp --afg $TMP_DIR/graph.afg 55 | 56 | echo -e "\n\n" 57 | 58 | echo "**********************************************************" 59 | echo "* Example 5: *" 60 | echo "* > vbp2afg instance.vbp graph.afg *" 61 | echo "* > afg2mps graph.afg model.mps *" 62 | echo "* > vpsolver_gurobi.sh --mps model.mps --afg graph.afg *" 63 | echo "**********************************************************" 64 | vbp2afg instance.vbp $TMP_DIR/graph.afg 65 | afg2mps $TMP_DIR/graph.afg $TMP_DIR/model.mps 66 | vpsolver_gurobi.sh --mps $TMP_DIR/model.mps --afg $TMP_DIR/graph.afg 67 | 68 | echo -e "\n\n" 69 | 70 | echo "**********************************************************" 71 | echo "* Example 6: *" 72 | echo "* > ./vpsolver_gurobi.sh --vbp instance.vbp *" 73 | echo "**********************************************************" 74 | vpsolver_gurobi.sh --vbp instance.vbp 75 | -------------------------------------------------------------------------------- /examples/vpsolver/example_ampl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BASEDIR=`dirname "$0"` 3 | cd $BASEDIR 4 | 5 | TMP_DIR=`mktemp -d -t XXXXXXXXXX` 6 | trap "rm -rf $TMP_DIR" EXIT 7 | 8 | PATH="../bin/:../scripts/:$PATH" 9 | 10 | echo "**********************************************************" 11 | echo "* Example 6: *" 12 | echo "* > ./vpsolver_ampl.sh --vbp instance.vbp *" 13 | echo "**********************************************************" 14 | vpsolver_ampl.sh --vbp instance.vbp --solver gurobi --options "outlev=1" 15 | -------------------------------------------------------------------------------- /examples/vpsolver/example_coinor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BASEDIR=`dirname "$0"` 3 | cd $BASEDIR 4 | 5 | TMP_DIR=`mktemp -d -t XXXXXXXXXX` 6 | trap "rm -rf $TMP_DIR" EXIT 7 | 8 | PATH="../bin/:../scripts/:$PATH" 9 | 10 | echo "**********************************************************" 11 | echo "* Example 1: *" 12 | echo "* > vpsolver instance.vbp *" 13 | echo "**********************************************************" 14 | vpsolver instance.vbp 15 | 16 | echo -e "\n\n" 17 | 18 | echo "**********************************************************" 19 | echo "* Example 2: *" 20 | echo "* > vbp2afg instance.vbp graph.afg *" 21 | echo "* > afg2mps graph.afg model.mps *" 22 | echo "* > vpsolver_coinor.sh --mps model.mps --wsol vars.sol *" 23 | echo "* > vbpsol graph.afg vars.sol *" 24 | echo "**********************************************************" 25 | vbp2afg instance.vbp $TMP_DIR/graph.afg 26 | afg2mps $TMP_DIR/graph.afg $TMP_DIR/model.mps 27 | vpsolver_coinor.sh --mps $TMP_DIR/model.mps --wsol $TMP_DIR/vars.sol 28 | vbpsol $TMP_DIR/graph.afg $TMP_DIR/vars.sol 29 | 30 | echo -e "\n\n" 31 | 32 | echo "**********************************************************" 33 | echo "* Example 3: *" 34 | echo "* > vbp2afg instance.vbp graph.afg *" 35 | echo "* > afg2lp graph.afg model.lp *" 36 | echo "* > vpsolver_coinor.sh --lp model.lp --wsol vars.sol *" 37 | echo "* > vbpsol graph.afg vars.sol *" 38 | echo "**********************************************************" 39 | vbp2afg instance.vbp $TMP_DIR/graph.afg 40 | afg2lp $TMP_DIR/graph.afg $TMP_DIR/model.lp 41 | vpsolver_coinor.sh --lp $TMP_DIR/model.lp --wsol $TMP_DIR/vars.sol 42 | vbpsol $TMP_DIR/graph.afg $TMP_DIR/vars.sol 43 | 44 | echo -e "\n\n" 45 | 46 | echo "**********************************************************" 47 | echo "* Example 4: *" 48 | echo "* > vbp2afg instance.vbp graph.afg *" 49 | echo "* > afg2lp graph.afg model.lp *" 50 | echo "* > vpsolver_coinor.sh --lp model.lp --afg graph.afg *" 51 | echo "**********************************************************" 52 | vbp2afg instance.vbp $TMP_DIR/graph.afg 53 | afg2lp $TMP_DIR/graph.afg $TMP_DIR/model.lp 54 | vpsolver_coinor.sh --lp $TMP_DIR/model.lp --afg $TMP_DIR/graph.afg 55 | 56 | echo -e "\n\n" 57 | 58 | echo "**********************************************************" 59 | echo "* Example 5: *" 60 | echo "* > vbp2afg instance.vbp graph.afg *" 61 | echo "* > afg2mps graph.afg model.mps *" 62 | echo "* > vpsolver_coinor.sh --mps model.mps --afg graph.afg *" 63 | echo "**********************************************************" 64 | vbp2afg instance.vbp $TMP_DIR/graph.afg 65 | afg2mps $TMP_DIR/graph.afg $TMP_DIR/model.mps 66 | vpsolver_coinor.sh --mps $TMP_DIR/model.mps --afg $TMP_DIR/graph.afg 67 | 68 | echo -e "\n\n" 69 | 70 | echo "**********************************************************" 71 | echo "* Example 6: *" 72 | echo "* > ./vpsolver_coinor.sh --vbp instance.vbp *" 73 | echo "**********************************************************" 74 | vpsolver_coinor.sh --vbp instance.vbp 75 | -------------------------------------------------------------------------------- /examples/vpsolver/example_glpk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BASEDIR=`dirname "$0"` 3 | cd $BASEDIR 4 | 5 | TMP_DIR=`mktemp -d -t XXXXXXXXXX` 6 | trap "rm -rf $TMP_DIR" EXIT 7 | 8 | PATH="../bin/:../scripts/:$PATH" 9 | 10 | echo "**********************************************************" 11 | echo "* Example 1: *" 12 | echo "* > vpsolver instance.vbp *" 13 | echo "**********************************************************" 14 | vpsolver instance.vbp 15 | 16 | echo -e "\n\n" 17 | 18 | echo "**********************************************************" 19 | echo "* Example 2: *" 20 | echo "* > vbp2afg instance.vbp graph.afg *" 21 | echo "* > afg2mps graph.afg model.mps *" 22 | echo "* > vpsolver_glpk.sh --mps model.mps --wsol vars.sol *" 23 | echo "* > vbpsol graph.afg vars.sol *" 24 | echo "**********************************************************" 25 | vbp2afg instance.vbp $TMP_DIR/graph.afg 26 | afg2mps $TMP_DIR/graph.afg $TMP_DIR/model.mps 27 | vpsolver_glpk.sh --mps $TMP_DIR/model.mps --wsol $TMP_DIR/vars.sol 28 | vbpsol $TMP_DIR/graph.afg $TMP_DIR/vars.sol 29 | 30 | echo -e "\n\n" 31 | 32 | echo "**********************************************************" 33 | echo "* Example 3: *" 34 | echo "* > vbp2afg instance.vbp graph.afg *" 35 | echo "* > afg2lp graph.afg model.lp *" 36 | echo "* > vpsolver_glpk.sh --lp model.lp --wsol vars.sol *" 37 | echo "* > vbpsol graph.afg vars.sol *" 38 | echo "**********************************************************" 39 | vbp2afg instance.vbp $TMP_DIR/graph.afg 40 | afg2lp $TMP_DIR/graph.afg $TMP_DIR/model.lp 41 | vpsolver_glpk.sh --lp $TMP_DIR/model.lp --wsol $TMP_DIR/vars.sol 42 | vbpsol $TMP_DIR/graph.afg $TMP_DIR/vars.sol 43 | 44 | echo -e "\n\n" 45 | 46 | echo "**********************************************************" 47 | echo "* Example 4: *" 48 | echo "* > vbp2afg instance.vbp graph.afg *" 49 | echo "* > afg2lp graph.afg model.lp *" 50 | echo "* > vpsolver_glpk.sh --lp model.lp --afg graph.afg *" 51 | echo "**********************************************************" 52 | vbp2afg instance.vbp $TMP_DIR/graph.afg 53 | afg2lp $TMP_DIR/graph.afg $TMP_DIR/model.lp 54 | vpsolver_glpk.sh --lp $TMP_DIR/model.lp --afg $TMP_DIR/graph.afg 55 | 56 | echo -e "\n\n" 57 | 58 | echo "**********************************************************" 59 | echo "* Example 5: *" 60 | echo "* > vbp2afg instance.vbp graph.afg *" 61 | echo "* > afg2mps graph.afg model.mps *" 62 | echo "* > vpsolver_glpk.sh --mps model.mps --afg graph.afg *" 63 | echo "**********************************************************" 64 | vbp2afg instance.vbp $TMP_DIR/graph.afg 65 | afg2mps $TMP_DIR/graph.afg $TMP_DIR/model.mps 66 | vpsolver_glpk.sh --mps $TMP_DIR/model.mps --afg $TMP_DIR/graph.afg 67 | 68 | echo -e "\n\n" 69 | 70 | echo "**********************************************************" 71 | echo "* Example 6: *" 72 | echo "* > ./vpsolver_glpk.sh --vbp instance.vbp *" 73 | echo "**********************************************************" 74 | vpsolver_glpk.sh --vbp instance.vbp 75 | -------------------------------------------------------------------------------- /examples/vpsolver/example_mvp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | import os 4 | 5 | 6 | def main(): 7 | """Examples: Multiple-choice Vector Bin Packing""" 8 | from pyvpsolver.solvers import mvpsolver 9 | 10 | os.chdir(os.path.dirname(__file__) or os.curdir) 11 | 12 | # Example 1: 13 | # Bins: 14 | W1 = (100, 100) 15 | W2 = (50, 120) 16 | W3 = (150, 25) 17 | Ws = [W1, W2, W3] # Capacities 18 | Cs = [3, 7, 2] # Costs 19 | Qs = [-1, -1, -1] # Number of available bins 20 | # Items: 21 | ws1, b1 = [(50, 25), (25, 50), (0, 75)], 1 22 | ws2, b2 = [(40, 40), (60, 25), (25, 60)], 1 23 | ws3, b3 = [(30, 10), (20, 40), (10, 50)], 1 24 | b = [b1, b2, b3] 25 | ws = [ws1, ws2, ws3] 26 | 27 | # Solve Example 1: 28 | solution = mvpsolver.solve( 29 | Ws, 30 | Cs, 31 | Qs, 32 | ws, 33 | b, 34 | svg_file="tmp/graphA_mvbp.svg", 35 | script="vpsolver_glpk.sh", 36 | verbose=True, 37 | ) 38 | mvpsolver.print_solution(solution) 39 | 40 | # check the solution objective value 41 | obj, patterns = solution 42 | assert obj == 3 43 | 44 | # Example 2 45 | # Bins: 46 | W1 = (100, 75) 47 | W2 = (75, 50) 48 | Ws = [W1, W2] 49 | Cs = [3, 2] 50 | Qs = [-1, -1] 51 | # Items 52 | ws1, b1 = [(75, 50)], 2 53 | ws2, b2 = [(40, 15), (25, 25)], 1 54 | b = [b1, b2] 55 | ws = [ws1, ws2] 56 | 57 | # Solve Example 2: 58 | solution = mvpsolver.solve( 59 | Ws, 60 | Cs, 61 | Qs, 62 | ws, 63 | b, 64 | svg_file="tmp/graphB_mvbp.svg", 65 | script="vpsolver_glpk.sh", 66 | verbose=True, 67 | ) 68 | mvpsolver.print_solution(solution) 69 | 70 | # check the solution objective value 71 | obj, patterns = solution 72 | assert obj == 5 73 | 74 | 75 | if __name__ == "__main__": 76 | main() 77 | -------------------------------------------------------------------------------- /examples/vpsolver/example_vbp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | import os 4 | 5 | 6 | def main(): 7 | """Example: solve a vector packing instance using 'solvers.vbpsolver'""" 8 | from pyvpsolver.solvers import vbpsolver 9 | 10 | os.chdir(os.path.dirname(__file__) or os.curdir) 11 | 12 | W = (5180, 9) 13 | w = [(1120, 1), (1250, 1), (520, 1), (1066, 1), (1000, 1), (1150, 1)] 14 | b = [9, 5, 91, 18, 11, 64] 15 | 16 | # Solve: 17 | solution = vbpsolver.solve( 18 | W, w, b, svg_file="tmp/graph_vbp.svg", script="vpsolver_glpk.sh", verbose=True 19 | ) 20 | vbpsolver.print_solution(solution) 21 | 22 | # check the solution objective value 23 | obj, patterns = solution 24 | assert obj == 33 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /examples/vpsolver/example_vsbpp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | import os 4 | 5 | 6 | def main(): 7 | """Variable-sized Bin Packing Example""" 8 | from pyvpsolver.solvers import mvpsolver 9 | 10 | os.chdir(os.path.dirname(__file__) or os.curdir) 11 | 12 | # Capacities: 13 | Ws = [[100], [120], [150]] 14 | 15 | # Cots: 16 | Cs = [100, 120, 150] 17 | 18 | # Number of bins available of each type: 19 | Qs = [-1, -1, -1] 20 | 21 | # Item weights: 22 | ws = [ 23 | [[10]], 24 | [[14]], 25 | [[17]], 26 | [[19]], 27 | [[24]], 28 | [[29]], 29 | [[32]], 30 | [[33]], 31 | [[36]], 32 | [[38]], 33 | [[40]], 34 | [[50]], 35 | [[54]], 36 | [[55]], 37 | [[63]], 38 | [[66]], 39 | [[71]], 40 | [[77]], 41 | [[79]], 42 | [[83]], 43 | [[92]], 44 | [[95]], 45 | [[99]], 46 | ] 47 | 48 | # Item demands: 49 | b = [1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1] 50 | 51 | # Solve the variable-sized bin packing instance: 52 | solution = mvpsolver.solve( 53 | Ws, 54 | Cs, 55 | Qs, 56 | ws, 57 | b, 58 | svg_file="tmp/graph_vsbpp.svg", 59 | script="vpsolver_glpk.sh", 60 | verbose=True, 61 | ) 62 | mvpsolver.print_solution(solution) 63 | 64 | # check the solution objective value 65 | obj, patterns = solution 66 | assert obj == 1280 67 | 68 | 69 | if __name__ == "__main__": 70 | main() 71 | -------------------------------------------------------------------------------- /examples/vpsolver/instance.mvp: -------------------------------------------------------------------------------- 1 | 2 2 | 3 | 5 4 | 100 100 100 -1 5 | 50 120 700 -1 6 | 150 25 2 1 7 | 150 25 3 -1 8 | 25 50 10 -1 9 | 10 | 3 11 | 12 | 3 1 13 | 50 25 14 | 25 50 15 | 0 75 16 | 17 | 3 1 18 | 40 40 19 | 60 25 20 | 25 60 21 | 22 | 3 1 23 | 30 10 24 | 20 40 25 | 10 50 26 | -------------------------------------------------------------------------------- /examples/vpsolver/instance.vbp: -------------------------------------------------------------------------------- 1 | 20 2 | 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 3 | 51 4 | 35 50 35 50 50 26 50 26 35 50 35 50 50 26 50 26 35 50 35 50 1 5 | 49 47 49 47 26 49 26 49 49 47 49 47 26 49 26 49 49 47 49 47 1 6 | 33 48 48 46 48 28 19 48 33 48 38 49 38 49 49 43 49 43 38 49 1 7 | 47 34 48 28 47 43 33 48 47 34 48 46 48 28 19 48 33 48 48 46 1 8 | 39 47 44 47 44 47 47 43 39 47 48 28 47 43 33 48 47 34 48 28 1 9 | 27 46 27 46 47 37 47 34 21 46 44 47 44 47 47 43 39 47 44 47 1 10 | 21 46 28 46 46 43 46 43 46 40 28 46 47 37 47 34 21 46 28 46 1 11 | 46 40 28 45 28 46 46 40 28 45 28 45 28 46 46 40 46 40 28 45 1 12 | 28 45 45 28 46 5 46 21 45 28 45 28 46 5 46 21 28 45 45 28 1 13 | 45 28 28 44 45 25 45 25 30 44 28 44 45 25 45 25 45 28 28 44 1 14 | 30 44 44 40 27 45 27 45 44 30 44 40 27 45 27 45 30 44 44 40 1 15 | 44 30 43 26 26 44 30 44 44 22 43 32 26 44 30 44 44 30 43 41 1 16 | 44 22 43 32 30 44 44 39 28 44 43 41 30 44 44 39 44 22 35 43 1 17 | 28 44 43 41 44 40 28 44 19 44 35 43 44 40 28 44 28 44 43 26 1 18 | 19 44 35 43 44 37 43 31 43 32 43 26 44 37 43 31 19 44 26 43 1 19 | 30 43 43 26 43 26 36 43 43 41 26 43 43 31 36 43 43 41 43 32 1 20 | 43 11 26 43 43 31 43 28 35 43 42 40 43 26 43 28 35 43 42 40 1 21 | 43 32 42 40 43 26 29 42 36 43 40 42 42 40 29 42 36 43 40 42 1 22 | 43 41 40 42 42 40 42 39 29 42 42 28 40 42 42 39 29 42 42 28 1 23 | 35 43 42 28 40 42 26 42 42 39 37 42 42 28 26 42 42 39 37 42 1 24 | 36 43 37 42 42 28 42 42 26 42 42 36 37 42 42 42 26 42 42 36 1 25 | 29 42 42 36 37 42 41 32 42 42 30 40 42 36 41 32 42 42 30 40 1 26 | 42 39 30 40 42 36 40 28 41 28 29 39 41 32 40 28 41 28 39 26 1 27 | 26 42 29 39 41 32 40 37 31 40 39 26 12 41 40 37 40 28 39 30 1 28 | 42 42 39 26 12 41 40 31 40 28 39 30 40 36 40 31 40 37 39 19 1 29 | 31 40 39 30 40 36 39 23 40 37 39 19 40 31 39 23 30 40 27 39 1 30 | 40 28 39 19 40 31 33 39 30 40 27 39 33 39 33 39 39 26 37 31 1 31 | 40 37 27 39 33 39 39 22 39 26 37 31 39 30 39 22 38 20 33 37 1 32 | 30 40 37 31 39 30 28 38 38 20 33 37 22 39 28 38 28 38 32 36 1 33 | 39 26 33 37 22 39 10 37 28 38 32 36 20 38 10 37 37 6 34 36 1 34 | 38 20 32 36 20 38 37 27 37 6 34 36 36 35 37 27 37 12 33 36 1 35 | 37 6 34 36 36 35 36 35 37 12 33 36 34 36 36 35 36 25 36 36 1 36 | 37 12 33 36 34 36 36 27 36 25 35 33 33 36 36 27 32 36 35 33 1 37 | 36 25 35 33 33 36 36 28 32 36 31 34 36 33 36 28 36 27 31 34 1 38 | 32 36 33 28 36 33 32 35 36 27 33 28 34 36 34 36 34 36 33 28 1 39 | 36 27 28 33 32 35 26 35 34 36 28 33 32 35 32 35 36 28 28 33 1 40 | 34 36 22 32 26 35 27 33 36 28 22 32 26 35 26 35 36 36 22 32 1 41 | 36 28 31 21 6 34 28 33 35 33 31 21 6 34 27 33 35 33 21 32 1 42 | 35 33 31 31 23 33 31 33 31 34 31 31 23 33 28 33 31 34 31 21 1 43 | 33 26 30 28 28 33 32 31 33 26 31 17 28 33 31 33 33 26 31 31 1 44 | 28 33 30 28 11 31 17 31 28 33 30 28 31 30 32 31 28 33 31 17 1 45 | 33 31 28 29 31 30 31 30 33 31 28 29 31 19 17 31 33 31 30 28 1 46 | 31 31 18 29 31 19 28 30 31 31 18 29 28 30 31 30 31 31 18 29 1 47 | 30 28 27 28 28 30 28 29 30 28 27 28 28 29 28 30 30 28 27 28 1 48 | 26 28 23 27 28 29 29 24 26 28 23 27 28 28 29 24 26 27 23 27 1 49 | 26 27 26 27 28 28 26 28 26 27 26 27 27 28 28 11 25 27 26 27 1 50 | 25 27 25 27 27 28 28 11 25 27 25 27 28 15 28 28 25 26 25 27 1 51 | 25 26 25 26 27 25 28 28 25 26 25 26 27 25 27 25 18 23 25 26 1 52 | 18 23 24 17 25 21 27 25 18 23 24 17 25 21 21 26 15 21 24 17 1 53 | 15 20 21 10 20 18 21 26 15 20 21 10 20 18 17 21 15 20 21 10 1 54 | 5 13 11 11 13 15 11 18 5 13 11 11 13 15 11 18 5 13 11 11 1 55 | -------------------------------------------------------------------------------- /examples/vpsolver/test_examples.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | 5 | def test_example(): 6 | """Test example.""" 7 | import example 8 | 9 | example.main() 10 | 11 | 12 | def test_example_vbp(): 13 | """Test example_vbp.""" 14 | import example_vbp 15 | 16 | example_vbp.main() 17 | 18 | 19 | def test_example_mvp(): 20 | """Test example_mvp.""" 21 | import example_mvp 22 | 23 | example_mvp.main() 24 | 25 | 26 | def test_example_vsbpp(): 27 | """Test example_vsbpp.""" 28 | import example_vsbpp 29 | 30 | example_vsbpp.main() 31 | 32 | 33 | if __name__ == "__main__": 34 | test_example() 35 | test_example_vbp() 36 | test_example_mvp() 37 | test_example_vsbpp() 38 | -------------------------------------------------------------------------------- /examples/vpsolver/test_vpsolver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | inf = float("inf") 5 | 6 | 7 | def test_vbpsolver(): 8 | """Test vbpsolver.""" 9 | from pyvpsolver import VPSolver 10 | from pyvpsolver.solvers import vbpsolver 11 | 12 | W, w, b = (1,), [(1,)], [1] 13 | lp_file = VPSolver.new_tmp_file(".lp") 14 | mps_file = VPSolver.new_tmp_file(".mps") 15 | svg_file = VPSolver.new_tmp_file(".svg") 16 | 17 | solution = vbpsolver.solve(W, w, b, script="vpsolver_glpk.sh") 18 | vbpsolver.print_solution(solution) 19 | obj, patterns = solution 20 | assert obj == 1 21 | 22 | solution = vbpsolver.solve( 23 | W, 24 | w, 25 | b, 26 | lp_file=lp_file, 27 | mps_file=mps_file, 28 | svg_file=svg_file, 29 | script="vpsolver_glpk.sh", 30 | ) 31 | vbpsolver.print_solution(solution) 32 | obj, patterns = solution 33 | assert obj == 1 34 | vbpsolver.print_solution(obj, patterns) 35 | 36 | 37 | def test_mvpsolvers(): 38 | """Test mvpsolvers.""" 39 | from pyvpsolver import VPSolver 40 | from pyvpsolver.solvers import mvpsolver2013, mvpsolver2016 41 | 42 | Ws = [(100, 75), (75, 50), (75, 50), (100, 100)] 43 | Cs = [3, 2, 3, 100] 44 | Qs = [inf, -1, -1, -1] 45 | ws = [[(75, 50)], [(40, 75), (25, 25)]] 46 | b = [2, 1] 47 | for mvpsolver in [mvpsolver2013, mvpsolver2016]: 48 | solution = mvpsolver.solve(Ws, Cs, Qs, ws, b, script="vpsolver_glpk.sh") 49 | mvpsolver.print_solution(solution) 50 | obj, patterns = solution 51 | assert obj == 5 52 | 53 | lp_file = VPSolver.new_tmp_file(".lp") 54 | mps_file = VPSolver.new_tmp_file(".mps") 55 | svg_file = VPSolver.new_tmp_file(".svg") 56 | 57 | solution = mvpsolver.solve( 58 | Ws, 59 | Cs, 60 | Qs, 61 | ws, 62 | b, 63 | lp_file=lp_file, 64 | mps_file=mps_file, 65 | svg_file=svg_file, 66 | script="vpsolver_glpk.sh", 67 | verbose=True, 68 | ) 69 | mvpsolver.print_solution(solution) 70 | obj, patterns = solution 71 | assert obj == 5 72 | mvpsolver.print_solution(obj, patterns) 73 | 74 | 75 | def test_scripts(): 76 | """Test scripts.""" 77 | from pyvpsolver import VPSolver, VBP, MVP, AFG, LP, MPS 78 | 79 | VPSolver.clear() 80 | vbp = VBP(W=(1,), w=[(1,)], b=[1], verbose=True) 81 | mvp = MVP(Ws=[(1,)], Cs=[1], Qs=[inf], ws=[[(1,)]], b=[1], verbose=True) 82 | for instance in [vbp, mvp]: 83 | afg = AFG(instance, verbose=True) 84 | lp = LP(afg, verbose=True) 85 | mps = MPS(afg, verbose=True) 86 | VPSolver.set_verbose(False) 87 | output, solution = VPSolver.script( 88 | "vpsolver_glpk.sh", instance, options="--seed 1234" 89 | ) 90 | assert solution[0] == 1 91 | if isinstance(instance, (VBP, MVP)): 92 | instance_file = instance.filename 93 | output, solution = VPSolver.script("vpsolver_glpk.sh", instance_file) 94 | assert solution[0] == 1 95 | output, solution = VPSolver.script("vpsolver_glpk.sh", afg) 96 | assert solution[0] == 1 97 | output, solution = VPSolver.script("vpsolver_glpk.sh", afg, lp) 98 | assert solution[0] == 1 99 | output, solution = VPSolver.script("vpsolver_glpk.sh", afg, mps) 100 | assert solution[0] == 1 101 | output, solution = VPSolver.script("vpsolver_glpk.sh", lp) 102 | assert solution is None 103 | output, solution = VPSolver.script("vpsolver_glpk.sh", mps) 104 | assert solution is None 105 | output, solution = VPSolver.script("vpsolver_glpk.sh", afg.filename) 106 | assert solution[0] == 1 107 | output, solution = VPSolver.script("vpsolver_glpk.sh", lp.filename) 108 | assert solution is None 109 | output, solution = VPSolver.script("vpsolver_glpk.sh", mps.filename) 110 | assert solution is None 111 | 112 | 113 | def test_vbpsol(): 114 | """Test vbpsol.""" 115 | from pyvpsolver import VPSolver, VBP, MVP, AFG, LP, MPS 116 | 117 | vbp = VBP(W=(1,), w=[(1,)], b=[1], verbose=True) 118 | afg = AFG(vbp, verbose=True) 119 | lp = LP(afg, verbose=True) 120 | sol_file = VPSolver.new_tmp_file(".sol") 121 | output, solution = VPSolver.script_wsol("vpsolver_glpk.sh", lp) 122 | assert isinstance(solution, dict) 123 | with open(sol_file, "w") as f: 124 | lst = [] 125 | for var, value in solution.items(): 126 | lst.append(str(var)) 127 | lst.append(str(value)) 128 | print(" ".join(lst), file=f) 129 | obj, patterns = VPSolver.vbpsol(afg, sol_file) 130 | assert obj == 1 131 | 132 | 133 | def test_draw(): 134 | """Test scripts.""" 135 | from pyvpsolver import VPSolver, VBP, MVP, AFG 136 | 137 | vbp = VBP(W=(1,), w=[(1,)], b=[1]) 138 | mvp = MVP(Ws=[(1,)], Cs=[1], Qs=[inf], ws=[[(1,)]], b=[1]) 139 | svg_file = VPSolver.new_tmp_file(".svg") 140 | for instance in [vbp, mvp]: 141 | afg = AFG(instance) 142 | try: 143 | afg.draw(svg_file, lpaths=True, graph_attrs={"size": "8,8"}) 144 | except Exception as e: 145 | print(repr(e)) 146 | try: 147 | VPSolver.afg2svg(afg, svg_file) 148 | except Exception as e: 149 | print(repr(e)) 150 | try: 151 | VPSolver.afg2svg(afg.filename, svg_file) 152 | except Exception as e: 153 | print(repr(e)) 154 | 155 | 156 | def test_lowlevel(): 157 | """Test low-level API.""" 158 | from pyvpsolver import VPSolver, VBP, MVP, AFG 159 | 160 | vbp = VBP(W=(1,), w=[(1,)], b=[1]) 161 | mvp = MVP(Ws=[(1,)], Cs=[1], Qs=[inf], ws=[[(1,)]], b=[1]) 162 | afg_file = VPSolver.new_tmp_file(".afg") 163 | lp_file = VPSolver.new_tmp_file(".lp") 164 | mps_file = VPSolver.new_tmp_file(".mps") 165 | svg_file = VPSolver.new_tmp_file(".svg") 166 | VPSolver.vbp2afg(vbp, afg_file) 167 | VPSolver.vbp2afg(mvp, afg_file) 168 | VPSolver.vbp2afg(vbp.filename, afg_file) 169 | VPSolver.vbp2afg(mvp.filename, afg_file) 170 | VPSolver.afg2lp(afg_file, lp_file) 171 | VPSolver.afg2mps(afg_file, mps_file) 172 | VPSolver.afg2lp(AFG(vbp), lp_file) 173 | VPSolver.afg2mps(AFG(mvp), mps_file) 174 | 175 | 176 | if __name__ == "__main__": 177 | test_vbpsolver() 178 | test_mvpsolvers() 179 | test_scripts() 180 | test_vbpsol() 181 | test_draw() 182 | test_lowlevel() 183 | -------------------------------------------------------------------------------- /examples/vpsolver/tmp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*.svg 3 | !.gitignore 4 | 5 | -------------------------------------------------------------------------------- /examples/vpsolver/tmp/graphB_mvbp.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %3 11 | 12 | 13 | 1 14 | 15 | 1 16 | 17 | 18 | 2 19 | 20 | 2 21 | 22 | 23 | 1->2 24 | 25 | 26 | 27 | 28 | T2 29 | 30 | T2 31 | 32 | 33 | 1->T2 34 | 35 | 36 | 37 | 38 | 2->T2 39 | 40 | 41 | 42 | 43 | 3 44 | 45 | 3 46 | 47 | 48 | 2->3 49 | 50 | 51 | 52 | 53 | T1 54 | 55 | T1 56 | 57 | 58 | T2->T1 59 | 60 | 61 | 62 | 63 | 3->T1 64 | 65 | 66 | 67 | 68 | S 69 | 70 | S 71 | 72 | 73 | S->1 74 | 75 | 76 | 77 | 78 | S->1 79 | 80 | 81 | 82 | 83 | S->2 84 | 85 | 86 | 87 | 88 | S->T2 89 | 90 | 91 | 92 | 93 | S->T1 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /pyvpsolver/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#ec9463", 4 | "activityBar.background": "#ec9463", 5 | "activityBar.foreground": "#15202b", 6 | "activityBar.inactiveForeground": "#15202b99", 7 | "activityBarBadge.background": "#e3fcec", 8 | "activityBarBadge.foreground": "#15202b", 9 | "commandCenter.border": "#15202b99", 10 | "sash.hoverBorder": "#ec9463", 11 | "statusBar.background": "#e77535", 12 | "statusBar.foreground": "#15202b", 13 | "statusBarItem.hoverBackground": "#d05b19", 14 | "statusBarItem.remoteBackground": "#e77535", 15 | "statusBarItem.remoteForeground": "#15202b", 16 | "tab.activeBorder": "#ec9463", 17 | "titleBar.activeBackground": "#e77535", 18 | "titleBar.activeForeground": "#15202b", 19 | "titleBar.inactiveBackground": "#e7753599", 20 | "titleBar.inactiveForeground": "#15202b99" 21 | }, 22 | "peacock.color": "#e77535" 23 | } -------------------------------------------------------------------------------- /pyvpsolver/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | """ 4 | 5 | __version__ = "3.1.4" 6 | 7 | from .afgraph import AFGraph 8 | from .vpsolver import VPSolver, VBP, MVP, AFG, MPS, LP 9 | from . import solvers 10 | -------------------------------------------------------------------------------- /pyvpsolver/afgraph.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | """ 4 | from builtins import zip 5 | from builtins import map 6 | from builtins import range 7 | from builtins import sorted 8 | from builtins import object 9 | 10 | from .utils import inf, relabel_graph, sort_vertices, sort_arcs, draw_graph 11 | 12 | 13 | class AFGraph(object): 14 | """Manipulable graph objects.""" 15 | 16 | def __init__(self, V, A, S, Ts, LOSS=None): 17 | self.V, self.A = list(set(V)), list(set(A)) 18 | self.S, self.Ts, self.LOSS = S, Ts, LOSS 19 | self.names = {} 20 | self.flow = None 21 | self.labels = None 22 | 23 | def relabel(self, fv, fa=lambda x: x): 24 | """Relabel the graph.""" 25 | assert self.flow is None 26 | assert self.labels is None 27 | self.V, self.A = relabel_graph(self.V, self.A, fv, fa) 28 | if self.LOSS is not None: 29 | self.LOSS = fa(self.LOSS) 30 | if self.S is not None: 31 | self.S = fv(self.S) 32 | if self.Ts is not None: 33 | self.Ts = [fv(t) for t in self.Ts] 34 | 35 | def draw( 36 | self, 37 | svg_file, 38 | show_labels=False, 39 | ignore=None, 40 | back=None, 41 | loss=None, 42 | weights=None, 43 | capacities=None, 44 | lpaths=False, 45 | graph_attrs=None, 46 | verbose=False, 47 | ): 48 | """Draw the arc-flow graph in .svg format.""" 49 | V, A = self.V, self.A 50 | if loss is None: 51 | loss = self.LOSS 52 | if back is None: 53 | back = set((u, v) for (u, v, i) in self.A if v == self.S) 54 | 55 | if lpaths: 56 | assert weights is not None 57 | assert capacities is not None 58 | lp_source = self.lpaths_source(weights, capacities) 59 | lp_targets = self.lpaths_targets(weights, capacities) 60 | newlabels = { 61 | v: "{}:\nL({})\nU({})".format( 62 | str(v), 63 | ",".join(map(str, lp_source[v])), 64 | ",".join(map(str, lp_targets[v])), 65 | ) 66 | for v in V 67 | } 68 | if ignore is not None: 69 | ignore = [ 70 | (newlabels.get(u, u), newlabels.get(v, v)) for (u, v) in ignore 71 | ] 72 | if back is not None: 73 | back = [(newlabels.get(u, u), newlabels.get(v, v)) for (u, v) in back] 74 | V, A = relabel_graph(V, A, lambda v: newlabels.get(v, v)) 75 | 76 | draw_graph( 77 | svg_file, 78 | sort_vertices(V), 79 | sort_arcs(A), 80 | show_labels=show_labels, 81 | ignore=ignore, 82 | back=back, 83 | loss=loss, 84 | graph_attrs=graph_attrs, 85 | verbose=verbose, 86 | ) 87 | 88 | def vname(self, u, v, i, vnames=None): 89 | """Return the variable name attributed to the arc.""" 90 | if vnames is None: 91 | vnames = self.names 92 | if (u, v, i) in vnames: 93 | return vnames[u, v, i] 94 | vnames[u, v, i] = "F{0:x}".format(len(vnames)) 95 | # vnames[u, v, i] = "F_{0}_{1}_{2}".format(u, v, i) 96 | return vnames[u, v, i] 97 | 98 | def lpaths_source(self, weights, capacities): 99 | """Compute longest paths to the source.""" 100 | ndims = len(capacities[0]) 101 | radj = {u: [] for u in self.V} 102 | for u, v, lbl in self.A: 103 | if v != self.S: 104 | radj[v].append((u, lbl)) 105 | 106 | zero = tuple([0] * ndims) 107 | minlabel = tuple([0] * ndims) 108 | 109 | def lp_source(u, labels): 110 | if u in labels: 111 | return labels[u] 112 | lbl = minlabel 113 | for v, it in radj[u]: 114 | wi = weights.get(it, zero) 115 | vlbl = lp_source(v, labels) 116 | lbl = tuple(max(lbl[d], vlbl[d] + wi[d]) for d in range(ndims)) 117 | labels[u] = lbl 118 | return lbl 119 | 120 | labels = {} 121 | for t in self.Ts: 122 | lp_source(t, labels) 123 | return labels 124 | 125 | def lpaths_targets(self, weights, capacities): 126 | """Compute longest paths to the targets.""" 127 | ndims = len(capacities[0]) 128 | adj = {u: [] for u in self.V} 129 | for u, v, lbl in self.A: 130 | if v != self.S: 131 | adj[u].append((v, lbl)) 132 | 133 | zero = tuple([0] * ndims) 134 | maxlabel = tuple([inf] * ndims) 135 | 136 | def lp_targets(u, labels): 137 | if u in labels: 138 | return labels[u] 139 | lbl = maxlabel 140 | for v, it in adj[u]: 141 | wi = weights.get(it, zero) 142 | vlbl = lp_targets(v, labels) 143 | lbl = tuple(min(lbl[d], vlbl[d] - wi[d]) for d in range(ndims)) 144 | labels[u] = lbl 145 | return lbl 146 | 147 | labels = {t: Wt for t, Wt in zip(self.Ts, capacities)} 148 | lp_targets(self.S, labels) 149 | return labels 150 | 151 | def get_vertices_sorted(self, reverse=False): 152 | """Return the list of vertices sorted.""" 153 | return sort_vertices(self.V, reverse) 154 | 155 | def get_arcs_sorted(self, reverse=False): 156 | """Return the list of arcs sorted.""" 157 | return sort_arcs(self.A, reverse) 158 | 159 | def get_flow_cons(self, vnames=None): 160 | """Return the list of flow conservation constraints.""" 161 | Ain = {u: [] for u in self.V} 162 | Aout = {u: [] for u in self.V} 163 | varl = [] 164 | for (u, v, i) in self.get_arcs_sorted(): 165 | name = self.vname(u, v, i, vnames) 166 | Aout[u].append(name) 167 | Ain[v].append(name) 168 | varl.append(name) 169 | cons = [] 170 | for u in self.get_vertices_sorted(): 171 | if Ain[u] != [] and Aout[u] != []: 172 | lincomb = [] 173 | if u in Ain: 174 | lincomb += [(var, 1) for var in Ain[u]] 175 | if u in Aout: 176 | lincomb += [(var, -1) for var in Aout[u]] 177 | if lincomb != []: 178 | cons.append((lincomb, "=", 0)) 179 | return varl, cons 180 | 181 | def get_assocs(self, vnames=None): 182 | """Return the arc variables grouped by label.""" 183 | assocs = {} 184 | for (u, v, i) in self.get_arcs_sorted(): 185 | if i not in assocs: 186 | assocs[i] = [] 187 | name = self.vname(u, v, i, vnames) 188 | assocs[i].append(name) 189 | return assocs 190 | 191 | def set_flow(self, varvalues, vnames=None): 192 | """Set flows.""" 193 | flow = {} 194 | for (u, v, i) in self.A: 195 | name = self.vname(u, v, i, vnames) 196 | f = varvalues.get(name, 0) 197 | if f != 0: 198 | flow[u, v, i] = f 199 | self.flow = flow 200 | 201 | def set_labels(self, labels): 202 | """Set labels.""" 203 | self.labels = labels 204 | 205 | def extract_solution(self, source, direction, target, flow_limit=inf): 206 | """Extract a vector packing solution form an arc-flow solution.""" 207 | assert direction in ("<-", "->") 208 | assert self.flow is not None 209 | assert self.labels is not None 210 | flow = self.flow 211 | labels = self.labels 212 | adj = {u: [] for u in self.V} 213 | 214 | if direction == "<-": 215 | node_a, node_b = target, source 216 | for (u, v, i) in flow: 217 | adj[v].append((u, (u, v, i))) 218 | else: 219 | node_a, node_b = source, target 220 | for (u, v, i) in flow: 221 | adj[u].append((v, (u, v, i))) 222 | 223 | if node_a not in adj or node_b not in adj: 224 | return [] 225 | 226 | solution = [] 227 | 228 | def go(u, f, path): 229 | """Recursive function for flow extraction.""" 230 | if f == 0: 231 | return 232 | if u == node_b: 233 | patt = [] 234 | for arc in path: 235 | flow[arc] -= f 236 | patt += labels.get(arc, []) 237 | solution.append((f, patt)) 238 | else: 239 | for v, arc in adj[u]: 240 | # v != node_a to avoid cycles 241 | if v != node_a and flow[arc] > 0: 242 | ff = min(f, flow[arc]) 243 | go(v, ff, path + [arc]) 244 | f -= ff 245 | 246 | go(node_a, flow_limit, []) 247 | 248 | # group identical patterns 249 | rep = {} 250 | for (r, p) in solution: 251 | p = tuple(sorted(p, key=repr)) 252 | if p not in rep: 253 | rep[p] = r 254 | else: 255 | rep[p] += r 256 | 257 | solution = [] 258 | for p in rep: 259 | solution.append((rep[p], list(p))) 260 | 261 | return solution 262 | -------------------------------------------------------------------------------- /pyvpsolver/solvers/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | """ 4 | 5 | from . import vbpsolver 6 | from . import mvpsolver2013 7 | from . import mvpsolver2016 8 | from . import mvpsolver2016 as mvpsolver 9 | -------------------------------------------------------------------------------- /pyvpsolver/solvers/mvpsolver2016.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | """ 4 | from __future__ import print_function 5 | 6 | import sys 7 | from .. import VPSolver, MVP, AFG, MPS 8 | 9 | 10 | def solve(Ws, Cs, Qs, ws, b, 11 | svg_file="", lp_file="", mps_file="", 12 | script=None, script_options=None, stats=None, verbose=None): 13 | """ 14 | Solve multiple-choice vector bin packing instances 15 | using the method proposed in: 16 | Brandao, F. (2016). VPSolver 3: Multiple-choice Vector Packing Solver. 17 | arXiv:1602.04876. http://arxiv.org/abs/1602.04876 18 | """ 19 | assert script is not None 20 | assert svg_file == "" or svg_file.endswith(".svg") 21 | if stats is None and verbose is not None: 22 | stats = verbose 23 | instance = MVP(Ws, Cs, Qs, ws, b, verbose=False) 24 | if (stats == verbose and svg_file == "" and 25 | lp_file == "" and mps_file == ""): 26 | out, (obj, sol) = VPSolver.script(script, instance, verbose=verbose) 27 | else: 28 | afg = AFG(instance, verbose=stats) 29 | if svg_file.endswith(".svg"): 30 | VPSolver.log("Generating .SVG file...", verbose) 31 | try: 32 | graph = afg.graph() 33 | graph.draw(svg_file, verbose=verbose) 34 | except Exception as e: 35 | VPSolver.log(e, verbose) 36 | if lp_file.endswith(".lp"): 37 | VPSolver.afg2lp(afg.afg_file, lp_file, verbose=False) 38 | VPSolver.log(".LP model successfully generated!", verbose) 39 | if mps_file.endswith(".mps"): 40 | VPSolver.afg2mps(afg.afg_file, mps_file, verbose=False) 41 | VPSolver.log(".MPS model successfully generated!", verbose) 42 | mps_model = MPS(afg, verbose=verbose) 43 | out, (obj, sol) = VPSolver.script( 44 | script, mps_model, afg, options=script_options, verbose=verbose 45 | ) 46 | return obj, sol 47 | 48 | 49 | def print_solution(solution, arg2=None, i0=1, fout=sys.stdout): 50 | """Pretty-print a multiple-choice vector packing solution.""" 51 | if arg2 is None: 52 | obj, lst_sol = solution 53 | else: 54 | obj, lst_sol = solution, arg2 55 | if obj is not None: 56 | print("Objective:", obj, file=fout) 57 | print("Solution:", file=fout) 58 | for i, sol in enumerate(lst_sol): 59 | cnt = sum(m for m, p in sol) 60 | print("Bins of type {0}: {1} {2}".format( 61 | i+i0, cnt, ["bins", "bin"][cnt == 1] 62 | ), file=fout) 63 | for mult, patt in sol: 64 | print("{0} x [{1}]".format( 65 | mult, ", ".join( 66 | ["i={0} opt={1}".format(it+i0, opt+i0) for it, opt in patt] 67 | ) 68 | ), file=fout) 69 | -------------------------------------------------------------------------------- /pyvpsolver/solvers/vbpsolver.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | """ 4 | from __future__ import print_function 5 | 6 | import sys 7 | from .. import VPSolver, VBP, AFG, MPS 8 | 9 | 10 | def solve( 11 | W, 12 | w, 13 | b, 14 | svg_file="", 15 | lp_file="", 16 | mps_file="", 17 | script=None, 18 | script_options=None, 19 | stats=None, 20 | verbose=None, 21 | ): 22 | """ 23 | Solve vector packing instances using the method proposed in: 24 | Brandao, F. and Pedroso, J. P. (2013). Bin Packing and Related 25 | Problems: General Arc-flow Formulation with Graph Compression. Technical 26 | Report DCC-2013-08, Faculdade de Ciencias da Universidade do Porto, 27 | Universidade do Porto, Portugal. 28 | """ 29 | assert script is not None 30 | assert svg_file == "" or svg_file.endswith(".svg") 31 | if stats is None and verbose is not None: 32 | stats = verbose 33 | instance = VBP(W, w, b, verbose=False) 34 | if stats == verbose and svg_file == "" and lp_file == "" and mps_file == "": 35 | out, (obj, sol) = VPSolver.script(script, instance, verbose=verbose) 36 | else: 37 | afg = AFG(instance, verbose=stats) 38 | if svg_file.endswith(".svg"): 39 | VPSolver.log("Generating .SVG file...", verbose) 40 | try: 41 | afg.graph().draw(svg_file, verbose=verbose) 42 | except Exception as e: 43 | VPSolver.log(e, verbose) 44 | if lp_file.endswith(".lp"): 45 | VPSolver.afg2lp(afg.afg_file, lp_file, verbose=False) 46 | VPSolver.log(".LP model successfully generated!", verbose) 47 | if mps_file.endswith(".mps"): 48 | VPSolver.afg2mps(afg.afg_file, mps_file, verbose=False) 49 | VPSolver.log(".MPS model successfully generated!", verbose) 50 | mps_model = MPS(afg, verbose=verbose) 51 | out, (obj, sol) = VPSolver.script( 52 | script, mps_model, afg, options=script_options, verbose=verbose 53 | ) 54 | return obj, sol 55 | 56 | 57 | def print_solution(solution, arg2=None, i0=1, fout=sys.stdout): 58 | """Pretty-print a vector packing solution.""" 59 | if arg2 is None: 60 | obj, lst_sol = solution 61 | else: 62 | obj, lst_sol = solution, arg2 63 | assert len(lst_sol) == 1 64 | sol = lst_sol[0] 65 | if obj is not None: 66 | print("Objective:", obj, file=fout) 67 | print("Solution:", file=fout) 68 | for mult, patt in sol: 69 | assert all(opt == 0 for it, opt in patt) 70 | print( 71 | "{0} x [{1}]".format( 72 | mult, ", ".join(["i={0}".format(it + i0) for it, opt in patt]) 73 | ), 74 | file=fout, 75 | ) 76 | -------------------------------------------------------------------------------- /pyvpsolver/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | """ 4 | from __future__ import print_function 5 | from __future__ import division 6 | from builtins import zip 7 | from builtins import str 8 | from builtins import map 9 | from builtins import range 10 | from builtins import object 11 | from builtins import sorted 12 | import re 13 | 14 | inf = float("inf") 15 | 16 | 17 | def get_content(fname): 18 | """Read the content of a file.""" 19 | with open(fname, "r") as f: 20 | return f.read() 21 | 22 | 23 | def get_opt(key, content, default=None): 24 | """Extract an option from the content of a .vbp/.afg file.""" 25 | matches = re.findall("\${0}\s*{{([^}}]+)}}".format(key), content) 26 | if matches == []: 27 | return default 28 | else: 29 | return matches[0] 30 | 31 | 32 | def get_instance_data(content): 33 | """Extract the instance data from the content of a .vbp/.afg file.""" 34 | if "$INSTANCE" in content: 35 | lst = list(map(int, get_opt("INSTANCE", content).split())) 36 | else: 37 | lst = [] 38 | for value in content.split(): 39 | if int(value) != float(value): 40 | break 41 | lst.append(int(value)) 42 | return lst 43 | 44 | 45 | def relabel_graph(V, A, fv, fa=lambda x: x): 46 | """Relabel an arc-flow graph.""" 47 | V = set(map(fv, V)) 48 | A = set((fv(u), fv(v), fa(i)) for (u, v, i) in A if fv(u) != fv(v)) 49 | return list(V), list(A) 50 | 51 | 52 | def sort_vertices(V, reverse=False): 53 | """Return the list of vertices sorted.""" 54 | return sorted(V, key=lambda k: (repr(type(k)), k), reverse=reverse) 55 | 56 | 57 | def sort_arcs(A, reverse=False): 58 | """Return the list of arcs sorted.""" 59 | return sorted( 60 | A, key=lambda a: tuple((repr(type(k)), k) for k in a), reverse=reverse 61 | ) 62 | 63 | 64 | def draw_graph( 65 | svg_file, 66 | V, 67 | A, 68 | show_labels=False, 69 | ignore=None, 70 | back=None, 71 | loss=None, 72 | graph_attrs=None, 73 | verbose=False, 74 | ): 75 | """Draw an arc-flow graph in .svg format.""" 76 | from pygraphviz.agraph import AGraph 77 | 78 | if ignore is None: 79 | ignore = [] 80 | if back is None: 81 | back = [] 82 | if loss is None: 83 | loss = [] 84 | elif not isinstance(loss, (tuple, list)): 85 | loss = [loss] 86 | g = AGraph( 87 | rankdir="LR", 88 | directed=True, 89 | bgcolor="white", 90 | ranksep="1.0", 91 | nodesep="0.10", 92 | strict=False, 93 | ) 94 | if graph_attrs is not None: 95 | for attr, value in graph_attrs.items(): 96 | g.graph_attr[attr] = value 97 | g.node_attr["shape"] = "ellipse" 98 | g.node_attr["color"] = "black" 99 | g.node_attr["fontcolor"] = "black" 100 | g.node_attr["penwidth"] = "2.0" 101 | 102 | lbls = sorted( 103 | set(i for (u, v, i) in A if i not in loss), 104 | key=lambda lbl: (repr(type(lbl)), lbl), 105 | ) 106 | 107 | colors = Colors.uniquecolors(len(lbls) + 1, v=0.5, p=0.0) 108 | 109 | used = set() 110 | for (u, v, i) in A: 111 | if (u, v) in ignore: 112 | continue 113 | used.add(u) 114 | used.add(v) 115 | if (u, v) in back: 116 | u, v = v, u 117 | d = "back" 118 | else: 119 | d = "front" 120 | if i in loss: 121 | g.add_edge(u, v, color="black", style="dashed", penwidth=2, dir=d) 122 | else: 123 | lbl = str(i) if show_labels else "" 124 | color = colors[lbls.index(i) % len(colors)] 125 | g.add_edge(u, v, color=color, penwidth=2, label=lbl, dir=d) 126 | 127 | for v in V: 128 | if v not in used: 129 | g.add_node(v) 130 | 131 | g.draw(svg_file, format="svg", prog="dot") 132 | if verbose: 133 | print("SVG file '{0}' generated!".format(svg_file)) 134 | 135 | 136 | class Colors(object): 137 | """ 138 | Finding N Distinct RGB Colors 139 | Based on code from StackOverflow: http://stackoverflow.com/a/2142206 140 | """ 141 | 142 | @staticmethod 143 | def rgbcode(t): 144 | """Convert (r, g, b) tuples to hexadecimal.""" 145 | r, g, b = t 146 | r = int(r * 255) 147 | g = int(g * 255) 148 | b = int(b * 255) 149 | return "#{0:0>2x}{1:0>2x}{2:0>2x}".format(r, g, b) 150 | 151 | @staticmethod 152 | def rgbcolor(h, f, v, p): 153 | """Convert colors specified by h-value and f-value to RGB three-tuples.""" 154 | # q = 1 - f 155 | # t = f 156 | if h == 0: 157 | return v, f, p 158 | elif h == 1: 159 | return 1 - f, v, p 160 | elif h == 2: 161 | return p, v, f 162 | elif h == 3: 163 | return p, 1 - f, v 164 | elif h == 4: 165 | return f, p, v 166 | elif h == 5: 167 | return v, p, 1 - f 168 | 169 | @staticmethod 170 | def uniquecolors(n, v=0.5, p=0.0): 171 | """Generate a list of distinct colors, each of which is 172 | represented as an RGB three-tuple.""" 173 | import math 174 | 175 | hues = list(360.0 / n * i for i in range(n)) 176 | hs = list(math.floor(hue / 60) % 6 for hue in hues) 177 | fs = list((hue / 60) % 1 for hue in hues) 178 | return [Colors.rgbcode(Colors.rgbcolor(h, f, v, p)) for h, f in zip(hs, fs)] 179 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | """ 4 | 5 | from . import app 6 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 4 | """ 5 | from __future__ import print_function 6 | from builtins import str 7 | from builtins import object 8 | 9 | import os 10 | import sys 11 | import flask 12 | import signal 13 | from flask import Flask, Response 14 | from flask import render_template, json, request, redirect, url_for 15 | from multiprocessing import Process 16 | from pyvpsolver import VPSolver, VBP, MVP, AFG, LP 17 | from pympl import PyMPL 18 | 19 | DEBUG = False 20 | PORT = 5555 21 | 22 | if __name__ == "__main__": 23 | if len(sys.argv) >= 2 and sys.argv[1].isdigit(): 24 | PORT = int(sys.argv[1]) 25 | 26 | app = Flask(__name__) 27 | app.debug = True 28 | 29 | 30 | @app.context_processor 31 | def inject_globals(): 32 | """Send global data to templates.""" 33 | data = dict( 34 | app_name="VPSolver App", 35 | pages=[ 36 | ("/vbp", "Vector Packing"), 37 | ("/mvp", "Multiple-choice"), 38 | ], 39 | ) 40 | return data 41 | 42 | 43 | @app.route("/favicon.ico") 44 | def favicon(): 45 | """Favicon route.""" 46 | return flask.send_from_directory( 47 | os.path.join(app.root_path, "static"), 48 | "favicon.ico", 49 | mimetype="image/vnd.microsoft.icon", 50 | ) 51 | 52 | 53 | @app.route("/") 54 | def index(): 55 | """Render the index page.""" 56 | return redirect(url_for("vbp")) 57 | 58 | 59 | def load(fname): 60 | """Load a text file as a string.""" 61 | with open(fname, "r") as f: 62 | return f.read().strip("\n") 63 | 64 | 65 | @app.route("/vbp/", defaults={"example": None}) 66 | @app.route("/vbp/") 67 | def vbp(example): 68 | """Render the input page for VBP.""" 69 | title = "Vector Packing" 70 | 71 | example_folder = os.path.join(os.path.dirname(__file__), "data", "examples", "vbp") 72 | examples = [ 73 | ("/vbp/", "", None), 74 | ("/vbp/bpp", "BPP", "bpp.vbp"), 75 | ("/vbp/csp", "CSP", "csp.vbp"), 76 | ("/vbp/vbp", "VBP", "vbp.vbp"), 77 | ] 78 | 79 | input_data = "" 80 | for url, description, fname in examples: 81 | if request.path == url: 82 | if fname is not None: 83 | input_data = load(os.path.join(example_folder, fname)) 84 | break 85 | 86 | scripts = [ 87 | ("vpsolver_glpk.sh", "GLPK"), 88 | ("vpsolver_gurobi.sh", "GUROBI"), 89 | ("vpsolver_cplex.sh", "CPLEX"), 90 | ("vpsolver_coinor.sh", "COIN-OR"), 91 | ("vpsolver_lpsolve.sh", "LPSOLVE"), 92 | ("vpsolver_scip.sh", "SCIP"), 93 | ] 94 | 95 | return render_template( 96 | "input.html", 97 | title=title, 98 | examples=examples, 99 | scripts=scripts, 100 | input_data=input_data, 101 | solver_url="/solve/vbp", 102 | ) 103 | 104 | 105 | @app.route("/mvp/", defaults={"example": None}) 106 | @app.route("/mvp/") 107 | def mvp(example): 108 | """Render the input page for MVP.""" 109 | title = "Multiple-choice Vector Packing" 110 | 111 | example_folder = os.path.join(os.path.dirname(__file__), "data", "examples", "mvp") 112 | examples = [ 113 | ("/mvp/", "", None), 114 | ("/mvp/vsbpp", "VSBPP", "vsbpp.mvp"), 115 | ("/mvp/mvp", "MVP", "mvp.mvp"), 116 | ] 117 | 118 | input_data = "" 119 | for url, description, fname in examples: 120 | if request.path == url: 121 | if fname is not None: 122 | input_data = load(os.path.join(example_folder, fname)) 123 | break 124 | 125 | scripts = [ 126 | ("vpsolver_glpk.sh", "GLPK"), 127 | ("vpsolver_gurobi.sh", "GUROBI"), 128 | ("vpsolver_cplex.sh", "CPLEX"), 129 | ("vpsolver_coinor.sh", "COIN-OR"), 130 | ("vpsolver_lpsolve.sh", "LPSOLVE"), 131 | ("vpsolver_scip.sh", "SCIP"), 132 | ] 133 | 134 | return render_template( 135 | "input.html", 136 | title=title, 137 | examples=examples, 138 | scripts=scripts, 139 | input_data=input_data, 140 | solver_url="/solve/mvp", 141 | ) 142 | 143 | 144 | def solve_worker(app_name, method, form, args, output=sys.stdout): 145 | """Worker for solving the problem in a separate process.""" 146 | VPSolver.PLIST = [] 147 | 148 | def signal_handler(sig, frame): 149 | """Signal handler for cleaner exit.""" 150 | for p in VPSolver.PLIST: 151 | try: 152 | os.killpg(p.pid, signal.SIGTERM) 153 | except Exception as e: 154 | pass 155 | sys.exit(0) 156 | 157 | signal.signal(signal.SIGTERM, signal_handler) 158 | 159 | sys.stdout = output 160 | sys.stderr = output 161 | input_ = form["input"].strip("\n") 162 | if DEBUG: 163 | print("Input:\n{0}\n\nOutput:".format(input_)) 164 | output.flush() 165 | 166 | if app_name == "vbp": 167 | tmpfile = VPSolver.new_tmp_file(ext=".vbp") 168 | with open(tmpfile, "w") as f: 169 | f.write(input_) 170 | instance = VBP.from_file(tmpfile, verbose=False) 171 | afg = AFG(instance, verbose=True) 172 | lp_model = LP(afg, verbose=False) 173 | out, sol = VPSolver.script( 174 | form["script"], lp_model, afg, pyout=False, verbose=True 175 | ) 176 | elif app_name == "mvp": 177 | tmpfile = VPSolver.new_tmp_file(ext=".mvp") 178 | with open(tmpfile, "w") as f: 179 | f.write(input_) 180 | instance = MVP.from_file(tmpfile, verbose=False) 181 | afg = AFG(instance, verbose=True) 182 | lp_model = LP(afg, verbose=False) 183 | out, sol = VPSolver.script( 184 | form["script"], lp_model, afg, pyout=False, verbose=True 185 | ) 186 | 187 | print("EOF\n") 188 | output.flush() 189 | 190 | 191 | class IterativeOutput(object): 192 | """Iterable class for retrieving workers output""" 193 | 194 | def __init__(self, target, args): 195 | rfd, wfd = os.pipe() 196 | args += (os.fdopen(wfd, "w"),) 197 | self.proc = Process(target=target, args=args) 198 | self.proc.start() 199 | self.output = os.fdopen(rfd, "r") 200 | 201 | def __iter__(self): 202 | """Retrieve the output iteratively.""" 203 | for line in iter(self.output.readline, "EOF\n"): 204 | yield line.rstrip() + "\n" 205 | if not self.proc.is_alive(): 206 | print("DONE {0}!".format(self.proc.pid)) 207 | 208 | def __del__(self): 209 | try: 210 | print("TERMINATE {0}!".format(self.proc.pid)) 211 | os.kill(self.proc.pid, signal.SIGTERM) 212 | # self.proc.terminate() 213 | except: 214 | pass 215 | 216 | 217 | @app.route("/solve/", methods=["POST"]) 218 | def solve(app_name): 219 | """Render the solver page.""" 220 | try: 221 | args = (app_name, request.method, request.form, request.args) 222 | return Response(IterativeOutput(solve_worker, args), mimetype="text/plain") 223 | except Exception as e: 224 | return json.dumps({"error": str(e)}) 225 | finally: 226 | pass 227 | 228 | 229 | def get_ip_address(): 230 | """Return the ip address of 'eth0'.""" 231 | import socket 232 | 233 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 234 | s.connect(("8.8.8.8", 80)) 235 | return s.getsockname()[0] 236 | 237 | 238 | if __name__ == "__main__": 239 | print("URL: http://{0}:{1}/".format(get_ip_address(), PORT)) 240 | app.run(host="0.0.0.0", port=PORT, threaded=True) 241 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/data/examples/mvp/mvp.mvp: -------------------------------------------------------------------------------- 1 | 2 2 | 5 3 | 100 100 100 -1 4 | 50 120 700 -1 5 | 150 25 2 1 6 | 150 25 3 -1 7 | 25 50 10 -1 8 | 3 9 | 3 1 10 | 50 25 11 | 25 50 12 | 0 75 13 | 3 1 14 | 40 40 15 | 60 25 16 | 25 60 17 | 3 1 18 | 30 10 19 | 20 40 20 | 10 50 21 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/data/examples/mvp/vsbpp.mvp: -------------------------------------------------------------------------------- 1 | 1 2 | 3 3 | 100 100 -1 4 | 120 120 -1 5 | 150 150 -1 6 | 23 7 | 1 1 8 | 10 9 | 1 1 10 | 14 11 | 1 1 12 | 17 13 | 1 2 14 | 19 15 | 1 1 16 | 24 17 | 1 1 18 | 29 19 | 1 1 20 | 32 21 | 1 1 22 | 33 23 | 1 1 24 | 36 25 | 1 1 26 | 38 27 | 1 1 28 | 40 29 | 1 1 30 | 50 31 | 1 1 32 | 54 33 | 1 1 34 | 55 35 | 1 1 36 | 63 37 | 1 1 38 | 66 39 | 1 1 40 | 71 41 | 1 2 42 | 77 43 | 1 1 44 | 79 45 | 1 1 46 | 83 47 | 1 1 48 | 92 49 | 1 1 50 | 95 51 | 1 1 52 | 99 53 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/data/examples/vbp/bpp.vbp: -------------------------------------------------------------------------------- 1 | 1 2 | 1000 3 | 45 4 | 150 1 5 | 151 4 6 | 152 1 7 | 155 1 8 | 156 3 9 | 157 2 10 | 158 2 11 | 159 2 12 | 161 3 13 | 162 2 14 | 163 4 15 | 164 1 16 | 165 1 17 | 166 3 18 | 167 4 19 | 168 4 20 | 169 2 21 | 170 2 22 | 171 1 23 | 172 1 24 | 173 1 25 | 174 3 26 | 175 4 27 | 176 1 28 | 178 3 29 | 179 2 30 | 180 3 31 | 181 2 32 | 182 3 33 | 183 1 34 | 184 2 35 | 185 2 36 | 186 1 37 | 187 3 38 | 188 1 39 | 189 3 40 | 190 1 41 | 191 1 42 | 192 2 43 | 193 1 44 | 194 2 45 | 195 7 46 | 197 4 47 | 198 2 48 | 200 1 49 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/data/examples/vbp/csp.vbp: -------------------------------------------------------------------------------- 1 | 1 2 | 5180 3 | 6 4 | 1120 9 5 | 1250 5 6 | 520 91 7 | 1066 18 8 | 1000 11 9 | 1150 64 10 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/data/examples/vbp/vbp.vbp: -------------------------------------------------------------------------------- 1 | 20 2 | 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 3 | 51 4 | 35 50 35 50 50 26 50 26 35 50 35 50 50 26 50 26 35 50 35 50 1 5 | 49 47 49 47 26 49 26 49 49 47 49 47 26 49 26 49 49 47 49 47 1 6 | 33 48 48 46 48 28 19 48 33 48 38 49 38 49 49 43 49 43 38 49 1 7 | 47 34 48 28 47 43 33 48 47 34 48 46 48 28 19 48 33 48 48 46 1 8 | 39 47 44 47 44 47 47 43 39 47 48 28 47 43 33 48 47 34 48 28 1 9 | 27 46 27 46 47 37 47 34 21 46 44 47 44 47 47 43 39 47 44 47 1 10 | 21 46 28 46 46 43 46 43 46 40 28 46 47 37 47 34 21 46 28 46 1 11 | 46 40 28 45 28 46 46 40 28 45 28 45 28 46 46 40 46 40 28 45 1 12 | 28 45 45 28 46 5 46 21 45 28 45 28 46 5 46 21 28 45 45 28 1 13 | 45 28 28 44 45 25 45 25 30 44 28 44 45 25 45 25 45 28 28 44 1 14 | 30 44 44 40 27 45 27 45 44 30 44 40 27 45 27 45 30 44 44 40 1 15 | 44 30 43 26 26 44 30 44 44 22 43 32 26 44 30 44 44 30 43 41 1 16 | 44 22 43 32 30 44 44 39 28 44 43 41 30 44 44 39 44 22 35 43 1 17 | 28 44 43 41 44 40 28 44 19 44 35 43 44 40 28 44 28 44 43 26 1 18 | 19 44 35 43 44 37 43 31 43 32 43 26 44 37 43 31 19 44 26 43 1 19 | 30 43 43 26 43 26 36 43 43 41 26 43 43 31 36 43 43 41 43 32 1 20 | 43 11 26 43 43 31 43 28 35 43 42 40 43 26 43 28 35 43 42 40 1 21 | 43 32 42 40 43 26 29 42 36 43 40 42 42 40 29 42 36 43 40 42 1 22 | 43 41 40 42 42 40 42 39 29 42 42 28 40 42 42 39 29 42 42 28 1 23 | 35 43 42 28 40 42 26 42 42 39 37 42 42 28 26 42 42 39 37 42 1 24 | 36 43 37 42 42 28 42 42 26 42 42 36 37 42 42 42 26 42 42 36 1 25 | 29 42 42 36 37 42 41 32 42 42 30 40 42 36 41 32 42 42 30 40 1 26 | 42 39 30 40 42 36 40 28 41 28 29 39 41 32 40 28 41 28 39 26 1 27 | 26 42 29 39 41 32 40 37 31 40 39 26 12 41 40 37 40 28 39 30 1 28 | 42 42 39 26 12 41 40 31 40 28 39 30 40 36 40 31 40 37 39 19 1 29 | 31 40 39 30 40 36 39 23 40 37 39 19 40 31 39 23 30 40 27 39 1 30 | 40 28 39 19 40 31 33 39 30 40 27 39 33 39 33 39 39 26 37 31 1 31 | 40 37 27 39 33 39 39 22 39 26 37 31 39 30 39 22 38 20 33 37 1 32 | 30 40 37 31 39 30 28 38 38 20 33 37 22 39 28 38 28 38 32 36 1 33 | 39 26 33 37 22 39 10 37 28 38 32 36 20 38 10 37 37 6 34 36 1 34 | 38 20 32 36 20 38 37 27 37 6 34 36 36 35 37 27 37 12 33 36 1 35 | 37 6 34 36 36 35 36 35 37 12 33 36 34 36 36 35 36 25 36 36 1 36 | 37 12 33 36 34 36 36 27 36 25 35 33 33 36 36 27 32 36 35 33 1 37 | 36 25 35 33 33 36 36 28 32 36 31 34 36 33 36 28 36 27 31 34 1 38 | 32 36 33 28 36 33 32 35 36 27 33 28 34 36 34 36 34 36 33 28 1 39 | 36 27 28 33 32 35 26 35 34 36 28 33 32 35 32 35 36 28 28 33 1 40 | 34 36 22 32 26 35 27 33 36 28 22 32 26 35 26 35 36 36 22 32 1 41 | 36 28 31 21 6 34 28 33 35 33 31 21 6 34 27 33 35 33 21 32 1 42 | 35 33 31 31 23 33 31 33 31 34 31 31 23 33 28 33 31 34 31 21 1 43 | 33 26 30 28 28 33 32 31 33 26 31 17 28 33 31 33 33 26 31 31 1 44 | 28 33 30 28 11 31 17 31 28 33 30 28 31 30 32 31 28 33 31 17 1 45 | 33 31 28 29 31 30 31 30 33 31 28 29 31 19 17 31 33 31 30 28 1 46 | 31 31 18 29 31 19 28 30 31 31 18 29 28 30 31 30 31 31 18 29 1 47 | 30 28 27 28 28 30 28 29 30 28 27 28 28 29 28 30 30 28 27 28 1 48 | 26 28 23 27 28 29 29 24 26 28 23 27 28 28 29 24 26 27 23 27 1 49 | 26 27 26 27 28 28 26 28 26 27 26 27 27 28 28 11 25 27 26 27 1 50 | 25 27 25 27 27 28 28 11 25 27 25 27 28 15 28 28 25 26 25 27 1 51 | 25 26 25 26 27 25 28 28 25 26 25 26 27 25 27 25 18 23 25 26 1 52 | 18 23 24 17 25 21 27 25 18 23 24 17 25 21 21 26 15 21 24 17 1 53 | 15 20 21 10 20 18 21 26 15 20 21 10 20 18 17 21 15 20 21 10 1 54 | 5 13 11 11 13 15 11 18 5 13 11 11 13 15 11 18 5 13 11 11 1 55 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/static/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/pyvpsolver/webapp/static/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /pyvpsolver/webapp/static/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/pyvpsolver/webapp/static/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /pyvpsolver/webapp/static/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/pyvpsolver/webapp/static/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /pyvpsolver/webapp/static/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/pyvpsolver/webapp/static/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /pyvpsolver/webapp/static/bootstrap/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /pyvpsolver/webapp/static/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-bottom: 100px; 3 | padding-top: 75px; 4 | } 5 | 6 | #input { 7 | font-family: "Courier New", Courier, monospace; 8 | font-size: 14px; 9 | } 10 | 11 | form { 12 | padding-left: 25px; 13 | padding-right: 25px; 14 | } 15 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdabrandao/vpsolver/c01e1d38a12ec25a6398aa36c7629bb2ceca8404/pyvpsolver/webapp/static/favicon.ico -------------------------------------------------------------------------------- /pyvpsolver/webapp/static/js/app.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | $("#examples").change(function() { 3 | document.location.href = $(this).val(); 4 | }); 5 | 6 | $("#input").keydown(function(e) { 7 | if (e.keyCode === 9) { // tab was pressed 8 | // get caret position/selection 9 | var val = this.value, 10 | start = this.selectionStart, 11 | end = this.selectionEnd; 12 | 13 | // set textarea value to: text before caret + tab + text after caret 14 | this.value = val.substring(0, start) + " " + val.substring(end); 15 | 16 | // put caret at right position again 17 | this.selectionStart = this.selectionEnd = start + 4; 18 | 19 | // prevent the focus lose 20 | return false; 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /pyvpsolver/webapp/templates/input.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ app_name }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 48 | 49 |
50 | 51 |
52 |
53 | {% if examples is defined %} 54 |
55 | 56 | 61 |
62 | {% endif %} 63 | 64 | 65 | 66 | 67 | {% if scripts is defined %} 68 |
69 | 70 | 75 |
76 | {% endif %} 77 | 78 | 79 |
80 | 81 |
82 | 83 | 90 | 91 |
92 | 93 | 94 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | future >= 0.15.0 2 | six >= 1.5.2 3 | flask >= 0.10.1 4 | pympl >= 1.1.2 5 | pytest >= 2.9.1 6 | pytest-cov >= 2.2.1 7 | coveralls >= 1.1 8 | -------------------------------------------------------------------------------- /scripts/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#7c5389", 4 | "activityBar.background": "#7c5389", 5 | "activityBar.foreground": "#e7e7e7", 6 | "activityBar.inactiveForeground": "#e7e7e799", 7 | "activityBarBadge.background": "#ab9e74", 8 | "activityBarBadge.foreground": "#15202b", 9 | "commandCenter.border": "#e7e7e799", 10 | "sash.hoverBorder": "#7c5389", 11 | "statusBar.background": "#5f4069", 12 | "statusBar.foreground": "#e7e7e7", 13 | "statusBarItem.hoverBackground": "#7c5389", 14 | "statusBarItem.remoteBackground": "#5f4069", 15 | "statusBarItem.remoteForeground": "#e7e7e7", 16 | "tab.activeBorder": "#7c5389", 17 | "titleBar.activeBackground": "#5f4069", 18 | "titleBar.activeForeground": "#e7e7e7", 19 | "titleBar.inactiveBackground": "#5f406999", 20 | "titleBar.inactiveForeground": "#e7e7e799" 21 | }, 22 | "peacock.color": "#5f4069" 23 | } -------------------------------------------------------------------------------- /scripts/afg2ampl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | from _afg2ampl import swig_main 4 | 5 | sys.exit(swig_main(len(sys.argv), [x.encode("ascii") for x in sys.argv])) 6 | -------------------------------------------------------------------------------- /scripts/afg2lp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | from _afg2lp import swig_main 4 | 5 | sys.exit(swig_main(len(sys.argv), [x.encode("ascii") for x in sys.argv])) 6 | -------------------------------------------------------------------------------- /scripts/afg2mps: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | from _afg2mps import swig_main 4 | 5 | sys.exit(swig_main(len(sys.argv), [x.encode("ascii") for x in sys.argv])) 6 | -------------------------------------------------------------------------------- /scripts/afg2svg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | 4 | if __name__ == "__main__": 5 | from pyvpsolver import VPSolver 6 | 7 | assert len(sys.argv) in (2, 3) 8 | afg_fname = sys.argv[1] 9 | assert afg_fname.endswith(".afg") 10 | if len(sys.argv) == 3: 11 | svg_fname = sys.argv[2] 12 | assert svg_fname.endswith(".svg") 13 | else: 14 | svg_fname = afg_fname.rstrip(".afg") + ".svg" 15 | VPSolver.afg2svg(afg_fname, svg_fname) 16 | -------------------------------------------------------------------------------- /scripts/vbp2afg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | from _vbp2afg import swig_main 4 | 5 | sys.exit(swig_main(len(sys.argv), [x.encode("ascii") for x in sys.argv])) 6 | -------------------------------------------------------------------------------- /scripts/vbpsol: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | from _vbpsol import swig_main 4 | 5 | sys.exit(swig_main(len(sys.argv), [x.encode("ascii") for x in sys.argv])) 6 | -------------------------------------------------------------------------------- /scripts/vpsolver_ampl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | set -e 4 | echo "Copyright (C) 2013-2022, Filipe Brandao" 5 | 6 | solve_model(){ 7 | if [[ -z "$solver" ]]; then 8 | error 9 | fi 10 | echo -e "\n>>> solving the MIP model using AMPL..." 11 | echo -e "Note: different parameter settings may improve the performance substantially!" 12 | rm -rf $TMP_DIR/vars.sol; 13 | ( 14 | echo "model $model_file;" 15 | echo "data $data_file;" 16 | echo "option solver $solver;" 17 | echo "option ${solver}_options '$options';" 18 | echo "solve;" 19 | echo "for {i in 1.._nvars: _var[i] > 0} {printf '%d %g\n', i-1, _var[i] > $TMP_DIR/vars.sol;}" 20 | ) | ampl & 21 | local pid=$! 22 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 23 | wait $pid 24 | echo "" 25 | } 26 | 27 | BASEDIR="`dirname "$0"`" 28 | source $BASEDIR/vpsolver_base.sh 29 | usage(){ 30 | basename=`basename $0` 31 | echo -e "Usage:" 32 | echo -e " $basename --vbp instance.vbp --solver --options " 33 | echo -e " $basename --mvp instance.mvp --solver --options " 34 | echo -e " $basename --afg graph.afg --solver --options " 35 | } 36 | init_vars 37 | parse_args $* 38 | generate_ampl_model 39 | solve_model 40 | extract_solution 41 | -------------------------------------------------------------------------------- /scripts/vpsolver_base.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/false 2 | 3 | init_vars() { 4 | CMD="$0 $*" 5 | BIN_DIR=$BASEDIR/../bin/ 6 | PATH=$BIN_DIR:$PATH 7 | TMP_DIR=`mktemp -d -t XXXXXXXXXX` 8 | trap "rm -rf $TMP_DIR;" SIGHUP SIGINT SIGTERM EXIT 9 | instance_file="" 10 | model_file="" 11 | data_file="" 12 | afg_file="" 13 | sol_file="" 14 | vbpsol_opts="" 15 | solver="" 16 | options="" 17 | } 18 | 19 | usage(){ 20 | basename=`basename $0` 21 | echo -e "Usage:" 22 | echo -e " $basename --vbp/--mvp instance.vbp/.mvp" 23 | echo -e " $basename --afg graph.afg" 24 | echo -e " $basename --mps/--lp model.mps/.lp" 25 | echo -e " $basename --mps/--lp model.mps/.lp --afg graph.afg" 26 | } 27 | 28 | error(){ 29 | echo "Command line: "$CMD 30 | echo "Error: invalid arguments." 31 | usage 32 | exit 1 33 | } 34 | 35 | parse_args(){ 36 | while true; 37 | do 38 | case "$1" in 39 | --mps) 40 | if [[ -z "$model_file" && -n "$2" && -e "$2" && "$2" =~ \.mps$ ]]; then 41 | model_file=$2 42 | else 43 | error 44 | fi 45 | shift 2;; 46 | 47 | --lp) 48 | if [[ -z "$model_file" && -n "$2" && -e "$2" && "$2" =~ \.lp$ ]]; then 49 | model_file=$2 50 | else 51 | error 52 | fi 53 | shift 2;; 54 | 55 | --afg) 56 | if [[ -z "$afg_file" && -n "$2" && -e "$2" && "$2" =~ \.afg$ ]]; then 57 | afg_file=$2 58 | else 59 | error 60 | fi 61 | shift 2;; 62 | 63 | --vbp) 64 | if [[ -z "$instance_file" && -n "$2" && -e "$2" && "$2" =~ \.vbp$ ]]; then 65 | instance_file=$2 66 | else 67 | error 68 | fi 69 | shift 2;; 70 | 71 | --mvp) 72 | if [[ -z "$instance_file" && -n "$2" && -e "$2" && "$2" =~ \.mvp$ ]]; then 73 | instance_file=$2 74 | else 75 | error 76 | fi 77 | shift 2;; 78 | 79 | --wsol) 80 | if [[ -z "$sol_file" && -n "$2" ]]; then 81 | sol_file=$2 82 | else 83 | error 84 | fi 85 | shift 2;; 86 | 87 | --pyout) 88 | if [[ -z "$vbpsol_opts" ]]; then 89 | vbpsol_opts="0 1" 90 | else 91 | error 92 | fi 93 | shift 1;; 94 | 95 | --solver) 96 | if [[ -n "$2" ]]; then 97 | solver=$2 98 | else 99 | error 100 | fi 101 | shift 2;; 102 | 103 | --options) 104 | if [[ -n "$2" ]]; then 105 | options=$2 106 | else 107 | error 108 | fi 109 | shift 2;; 110 | 111 | *) 112 | if [[ -n "$1" ]]; then 113 | error 114 | else 115 | break 116 | fi 117 | esac 118 | done 119 | } 120 | 121 | generate_model(){ 122 | if [[ -z "$instance_file" && -z "$model_file" && -z "$afg_file" ]]; then 123 | error 124 | fi 125 | 126 | if [[ -n "$instance_file" ]]; then 127 | if [[ -n "$afg_file" || -n "$model_file" ]]; then 128 | error 129 | fi 130 | 131 | afg_file=$TMP_DIR/graph.afg 132 | model_file=$TMP_DIR/model.mps 133 | 134 | echo -e "\n>>> vbp2afg..." 135 | vbp2afg $instance_file $afg_file & 136 | pid=$! 137 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 138 | wait $pid 139 | 140 | echo -e "\n>>> afg2mps..." 141 | afg2mps $afg_file $model_file 142 | elif [[ -n "$afg_file" ]]; then 143 | if [[ -n "$instance_file" ]]; then 144 | error 145 | fi 146 | 147 | if [[ -z $model_file ]]; then 148 | model_file=$TMP_DIR/model.mps 149 | 150 | echo -e "\n>>> afg2mps..." 151 | afg2mps $afg_file $model_file 152 | fi 153 | fi 154 | } 155 | 156 | generate_ampl_model(){ 157 | if [[ -z "$instance_file" && -z "$model_file" && -z "$afg_file" ]]; then 158 | error 159 | fi 160 | 161 | if [[ -n "$instance_file" ]]; then 162 | if [[ -n "$afg_file" || -n "$model_file" ]]; then 163 | error 164 | fi 165 | 166 | afg_file=$TMP_DIR/graph.afg 167 | model_file=$TMP_DIR/arcflow.mod 168 | data_file=$TMP_DIR/arcflow.dat 169 | 170 | echo -e "\n>>> vbp2afg..." 171 | vbp2afg $instance_file $afg_file & 172 | pid=$! 173 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 174 | wait $pid 175 | 176 | echo -e "\n>>> afg2ampl..." 177 | afg2ampl $afg_file $model_file $data_file 178 | elif [[ -n "$afg_file" ]]; then 179 | if [[ -n "$instance_file" ]]; then 180 | error 181 | fi 182 | 183 | if [[ -z $model_file ]]; then 184 | model_file=$TMP_DIR/arcflow.mod 185 | data_file=$TMP_DIR/arcflow.dat 186 | 187 | echo -e "\n>>> afg2mps..." 188 | afg2ampl $afg_file $model_file $data_file 189 | fi 190 | fi 191 | } 192 | 193 | extract_solution() { 194 | if [[ -n "$afg_file" && -z "$sol_file" ]]; then 195 | echo -e "\n>>> vbpsol..." 196 | vbpsol $afg_file $TMP_DIR/vars.sol $vbpsol_opts 197 | fi 198 | 199 | if [[ -n "$sol_file" ]]; then 200 | cp $TMP_DIR/vars.sol $sol_file 201 | fi 202 | } -------------------------------------------------------------------------------- /scripts/vpsolver_coinor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | set -e 4 | echo "Copyright (C) 2013-2022, Filipe Brandao" 5 | 6 | solve_model(){ 7 | echo -e "\n>>> solving the MIP model using COIN-OR CBC..." 8 | echo -e "Note: different parameter settings may improve the performance substantially!" 9 | if ! [ -x "$(command -v stdbuf)" ]; then 10 | cbc $model_file $options -solve -solu $TMP_DIR/sol.out & 11 | else 12 | stdbuf -i0 -o0 -e0 cbc $model_file $options -solve -solu $TMP_DIR/sol.out & 13 | fi 14 | local pid=$! 15 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 16 | wait $pid 17 | tail -n +2 $TMP_DIR/sol.out | awk '{ print $2, $3 }' > $TMP_DIR/vars.sol 18 | } 19 | 20 | BASEDIR="`dirname "$0"`" 21 | source $BASEDIR/vpsolver_base.sh 22 | init_vars 23 | options="-cuts off -randomSeed 1234 -randomCbcSeed 1234" 24 | parse_args $* 25 | generate_model 26 | solve_model 27 | extract_solution 28 | -------------------------------------------------------------------------------- /scripts/vpsolver_cplex.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | set -e 4 | echo "Copyright (C) 2013-2022, Filipe Brandao" 5 | 6 | solve_model(){ 7 | echo -e "\n>>> solving the MIP model using CPLEX..." 8 | echo -e "Note: different parameter settings may improve the performance substantially!" 9 | rm -rf $TMP_DIR/vars.sol; 10 | ( 11 | echo "read $model_file" 12 | echo -e "$options" 13 | echo "optimize" 14 | echo "write $TMP_DIR/vars.sol" 15 | ) | cplex & 16 | local pid=$! 17 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 18 | wait $pid 19 | echo "" 20 | awk -F\" '/variable name/ {print $2, $6}' OFS=" " $TMP_DIR/vars.sol > $TMP_DIR/vars.sol2 21 | mv $TMP_DIR/vars.sol2 $TMP_DIR/vars.sol 22 | } 23 | 24 | BASEDIR="`dirname "$0"`" 25 | source $BASEDIR/vpsolver_base.sh 26 | init_vars 27 | options="set randomseed 1234\n" 28 | parse_args $* 29 | generate_model 30 | solve_model 31 | extract_solution 32 | -------------------------------------------------------------------------------- /scripts/vpsolver_glpk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | set -e 4 | echo "Copyright (C) 2013-2022, Filipe Brandao" 5 | 6 | solve_model(){ 7 | echo -e "\n>>> solving the MIP model using GLPK..." 8 | echo -e "Note: different parameter settings may improve the performance substantially!" 9 | if [[ $model_file =~ \.mps$ ]]; then 10 | glpsol --mps $model_file $options -o $TMP_DIR/sol.out & 11 | local pid=$! 12 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 13 | wait $pid 14 | else 15 | glpsol --lp $model_file $options -o $TMP_DIR/sol.out & 16 | local pid=$! 17 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 18 | wait $pid 19 | fi 20 | sed -n '/Column name/,/^$/p' $TMP_DIR/sol.out > $TMP_DIR/sol.out2 21 | mv $TMP_DIR/sol.out2 $TMP_DIR/sol.out 22 | sed '1,2d' $TMP_DIR/sol.out > $TMP_DIR/sol.out2 23 | mv $TMP_DIR/sol.out2 $TMP_DIR/sol.out 24 | sed ':a;N;$!ba;s/\n\s\{20\}/ /g' $TMP_DIR/sol.out > $TMP_DIR/sol.out2 25 | mv $TMP_DIR/sol.out2 $TMP_DIR/sol.out 26 | sed 's/\*/ /g' $TMP_DIR/sol.out > $TMP_DIR/sol.out2 27 | mv $TMP_DIR/sol.out2 $TMP_DIR/sol.out 28 | tr '\n' '$' < $TMP_DIR/sol.out | sed 's/$ //g' | tr '$' '\n' > $TMP_DIR/sol.out2 29 | mv $TMP_DIR/sol.out2 $TMP_DIR/sol.out 30 | awk '{ if ( $3 ~ /^[0-9][^\s]*$/ ){ print $2, $3 }else{ print $2, $4 } }' $TMP_DIR/sol.out > $TMP_DIR/vars.sol 31 | } 32 | 33 | BASEDIR="`dirname "$0"`" 34 | source $BASEDIR/vpsolver_base.sh 35 | init_vars 36 | options="--seed 1234" 37 | parse_args $* 38 | generate_model 39 | solve_model 40 | extract_solution 41 | -------------------------------------------------------------------------------- /scripts/vpsolver_gurobi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | set -e 4 | echo "Copyright (C) 2013-2022, Filipe Brandao" 5 | 6 | solve_model(){ 7 | echo -e "\n>>> solving the MIP model using Gurobi..." 8 | echo -e "Note: different parameter settings may improve the performance substantially!" 9 | gurobi_cl $options ResultFile=$TMP_DIR/vars.sol $model_file & 10 | local pid=$! 11 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 12 | wait $pid 13 | sed '/#/d' $TMP_DIR/vars.sol > $TMP_DIR/vars.sol2 14 | mv $TMP_DIR/vars.sol2 $TMP_DIR/vars.sol 15 | } 16 | 17 | BASEDIR="`dirname "$0"`" 18 | source $BASEDIR/vpsolver_base.sh 19 | init_vars 20 | options="Threads=1 Presolve=1 Method=2 MIPFocus=1 Heuristics=1 MIPGap=0 MIPGapAbs=0.99999 Seed=1234" 21 | parse_args $* 22 | generate_model 23 | solve_model 24 | extract_solution 25 | -------------------------------------------------------------------------------- /scripts/vpsolver_lpsolve.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | set -e 4 | echo "Copyright (C) 2013-2022, Filipe Brandao" 5 | 6 | solve_model(){ 7 | echo -e "\n>>> solving the MIP model using lp_solve..." 8 | echo -e "Note: different parameter settings may improve the performance substantially!" 9 | if [[ $model_file =~ \.mps$ ]]; then 10 | lp_solve -mps $model_file $options > $TMP_DIR/sol.out & 11 | local pid=$! 12 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 13 | wait $pid 14 | else 15 | echo -e "Note: lp_solve requires xli_CPLEX to read CPLEX lp models" 16 | lp_solve -rxli xli_CPLEX $model_file $options > $TMP_DIR/sol.out & 17 | local pid=$! 18 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 19 | wait $pid 20 | fi 21 | sed -e '1,/variables:/d' $TMP_DIR/sol.out > $TMP_DIR/vars.sol 22 | } 23 | 24 | BASEDIR="`dirname "$0"`" 25 | source $BASEDIR/vpsolver_base.sh 26 | init_vars 27 | options="" 28 | parse_args $* 29 | generate_model 30 | solve_model 31 | extract_solution 32 | -------------------------------------------------------------------------------- /scripts/vpsolver_scip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | set -e 4 | echo "Copyright (C) 2013-2022, Filipe Brandao" 5 | 6 | solve_model(){ 7 | echo -e "\n>>> solving the MIP model using SCIP..." 8 | echo -e "Note: different parameter settings may improve the performance substantially!" 9 | rm -rf $TMP_DIR/vars.sol; 10 | ( 11 | echo "read $model_file" 12 | echo -e "$options" 13 | echo "optimize" 14 | echo "write solution $TMP_DIR/vars.sol" 15 | ) | scip & 16 | local pid=$! 17 | trap "kill $pid &> /dev/null" SIGHUP SIGINT SIGTERM 18 | wait $pid 19 | echo "" 20 | tail -n+3 $TMP_DIR/vars.sol | awk '{ print $1, $2 }' > $TMP_DIR/vars.sol2 21 | mv $TMP_DIR/vars.sol2 $TMP_DIR/vars.sol 22 | } 23 | 24 | BASEDIR="`dirname "$0"`" 25 | source $BASEDIR/vpsolver_base.sh 26 | init_vars 27 | options="" 28 | parse_args $* 29 | generate_model 30 | solve_model 31 | extract_solution 32 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | VPSolver 4 | -------- 5 | VPSolver is a vector packing solver based on an arc-flow formulation 6 | with graph compression. VPSolver generates very strong models that can 7 | be solved using general-purpose mixed-integer programming solvers such 8 | as Gurobi and GLPK. For modelling other problems easily, VPSolver 9 | includes a Python API and a modelling toolbox (PyMPL). 10 | 11 | Setup 12 | ````` 13 | 14 | .. code:: bash 15 | 16 | $ pip install pyvpsolver 17 | 18 | System requirements 19 | ``````````````````` 20 | 21 | * UNIX-like operating system or a UNIX-like environment such as Cygwin 22 | * g++ >= 4.8; bash >= 3.0 23 | 24 | Links 25 | ````` 26 | 27 | * `VPSolver wiki `_ 28 | * `GiHub repository `_ 29 | * `BitBucket repository `_ 30 | """ 31 | import os 32 | import re 33 | import ast 34 | import platform 35 | from distutils.core import setup, Extension 36 | 37 | 38 | OSTYPE = platform.system() 39 | ARCH = platform.processor() 40 | x64 = platform.architecture()[0] == '64bit' 41 | 42 | 43 | def ls_dir(base_dir): 44 | """List files recursively.""" 45 | base_dir = os.path.join(base_dir, "") 46 | return [ 47 | os.path.join(dirpath.replace(base_dir, "", 1), f) 48 | for (dirpath, dirnames, files) in os.walk(base_dir) 49 | for f in files 50 | if ( 51 | not f.endswith(("~", ".pyc", ".pyo", ".log")) and 52 | not f.startswith(".") 53 | ) 54 | ] 55 | 56 | 57 | def compile_args(): 58 | if OSTYPE == 'Windows': 59 | return ['/TP', '/EHsc', '/O2'] 60 | elif OSTYPE == 'Linux': 61 | ignore_warnings = [ 62 | '-Wno-stringop-truncation', 63 | '-Wno-catch-value', 64 | '-Wno-unused-variable', 65 | ] 66 | return ['-std=c++11', '-O2'] + ignore_warnings 67 | elif OSTYPE == 'Darwin': 68 | ignore_warnings = [ 69 | '-Wno-unused-variable', 70 | ] 71 | return ['-std=c++11', '-O2', '-mmacosx-version-min=10.9'] + ignore_warnings 72 | else: 73 | return [] 74 | 75 | 76 | _vbp2afg = Extension( 77 | "_vbp2afg", 78 | sources=[ 79 | "swig/vbp2afg_wrap.cxx", "src/vbp2afg.cpp", 80 | "src/instance.cpp", "src/graph.cpp", 81 | "src/arcflow.cpp", "src/common.cpp" 82 | ], 83 | extra_compile_args=compile_args(), 84 | undef_macros=['NDEBUG'], 85 | ) 86 | 87 | _afg2ampl = Extension( 88 | "_afg2ampl", 89 | sources=[ 90 | "swig/afg2ampl_wrap.cxx", "src/afg2ampl.cpp", 91 | "src/instance.cpp", "src/graph.cpp", 92 | "src/arcflow.cpp", "src/common.cpp" 93 | ], 94 | extra_compile_args=compile_args(), 95 | undef_macros=['NDEBUG'], 96 | ) 97 | 98 | _afg2lp = Extension( 99 | "_afg2lp", 100 | sources=[ 101 | "swig/afg2lp_wrap.cxx", "src/afg2lp.cpp", 102 | "src/instance.cpp", "src/graph.cpp", 103 | "src/arcflow.cpp", "src/common.cpp" 104 | ], 105 | extra_compile_args=compile_args(), 106 | undef_macros=['NDEBUG'], 107 | ) 108 | 109 | _afg2mps = Extension( 110 | "_afg2mps", 111 | sources=[ 112 | "swig/afg2mps_wrap.cxx", "src/afg2mps.cpp", 113 | "src/instance.cpp", "src/graph.cpp", 114 | "src/arcflow.cpp", "src/common.cpp" 115 | ], 116 | extra_compile_args=compile_args(), 117 | undef_macros=['NDEBUG'], 118 | ) 119 | 120 | _vbpsol = Extension( 121 | "_vbpsol", 122 | sources=[ 123 | "swig/vbpsol_wrap.cxx", "src/vbpsol.cpp", 124 | "src/instance.cpp", "src/graph.cpp", 125 | "src/arcflow.cpp", "src/arcflowsol.cpp", 126 | "src/common.cpp" 127 | ], 128 | extra_compile_args=compile_args(), 129 | undef_macros=['NDEBUG'], 130 | ) 131 | 132 | _version_re = re.compile(r'__version__\s+=\s+(.*)') 133 | with open("pyvpsolver/__init__.py", "rb") as f: 134 | version = str(ast.literal_eval(_version_re.search( 135 | f.read().decode("utf-8")).group(1))) 136 | 137 | setup( 138 | name="pyvpsolver", 139 | version=version, 140 | license="BSD-3", 141 | author="Filipe Brandao", 142 | author_email="fdabrandao@gmail.com", 143 | maintainer='Filipe Brandao', 144 | maintainer_email='fdabrandao@gmail.com', 145 | url="https://github.com/fdabrandao/vpsolver", 146 | description="Arc-flow Vector Packing Solver (VPSolver)", 147 | long_description=__doc__, 148 | packages=["pyvpsolver"], 149 | package_data={"": ls_dir("pyvpsolver/")}, 150 | platforms=["unix", "linux", "osx"], 151 | scripts=[os.path.join("scripts", f) for f in ls_dir("scripts/")], 152 | install_requires=open("requirements.txt").read().split("\n"), 153 | classifiers=[ 154 | "Development Status :: 5 - Production/Stable", 155 | "Intended Audience :: Science/Research", 156 | "Programming Language :: Python", 157 | "Programming Language :: Python :: 3", 158 | "License :: OSI Approved :: BSD License", 159 | "Topic :: Scientific/Engineering" 160 | ], 161 | ext_modules=[_vbp2afg, _afg2ampl, _afg2lp, _afg2mps, _vbpsol], 162 | ) 163 | -------------------------------------------------------------------------------- /src/afg2ampl.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include "config.hpp" 6 | #include "common.hpp" 7 | #include "arcflow.hpp" 8 | #include "instance.hpp" 9 | 10 | int swig_main(int argc, char **argv) { 11 | printf(PACKAGE_STRING", Copyright (C) 2013-2022, Filipe Brandao\n"); 12 | setvbuf(stdout, NULL, _IONBF, 0); 13 | if (argc != 4) { 14 | printf("Usage: afg2ampl graph.afg model.mod data.dat\n"); 15 | return 1; 16 | } 17 | try { 18 | throw_assert(check_ext(argv[1], ".afg")); 19 | Arcflow afg(argv[1]); 20 | Instance &inst = afg.inst; 21 | 22 | FILE *fmod = fopen(argv[2], "w"); 23 | if (fmod == NULL) { 24 | perror("fopen"); 25 | } 26 | throw_assert(fmod != NULL); 27 | 28 | FILE *fdat = fopen(argv[3], "w"); 29 | if (fmod == NULL) { 30 | perror("fopen"); 31 | } 32 | throw_assert(fdat != NULL); 33 | 34 | /* model file */ 35 | printf("Generating the .mod file..."); 36 | const char *model = \ 37 | "set Items;\n" 38 | "param Demand{Items};\n" 39 | "set Labels;\n" 40 | "param ItemId{Labels};\n" 41 | "param ItemOpt{Labels};\n" 42 | "\n" 43 | "set V;\n" 44 | "set A dimen 3;\n" 45 | "param S;\n" 46 | "param LOSS;\n" 47 | "param ArcId{A};\n" 48 | "param ArcBounds{Labels union {LOSS}} default +Infinity;\n" 49 | "var Flow{(u,v,l) in A} integer >= 0 <= ArcBounds[l];\n" 50 | "set Targets;\n" 51 | "param Cost{Targets};\n" 52 | "param Quantity{Targets};\n" 53 | "\n" 54 | "minimize TotalCost:\n" 55 | " sum{t in Targets} Cost[t] * Flow[t,S,LOSS];\n" 56 | "s.t. BinQuantity{t in Targets: Quantity[t] >= 0}:\n" 57 | " Flow[t,S,LOSS] <= Quantity[t];\n" 58 | "param RelaxDomains default 1;\n" 59 | "s.t. SatisfyDemandStrict{i in Items: RelaxDomains != 1}:\n" 60 | " sum{l in Labels : ItemId[l]==i} sum{(u,v,l) in A} Flow[u,v,l] == Demand[i];\n" 61 | "s.t. SatisfyDemandRelaxed{i in Items: RelaxDomains == 1}:\n" 62 | " sum{l in Labels : ItemId[l]==i} sum{(u,v,l) in A} Flow[u,v,l] >= Demand[i];\n" 63 | "s.t. FlowConservation{k in V}:\n" 64 | " (sum{(u,v,l) in A: v == k} Flow[u,v,l]) - (sum{(u,v,l) in A: u == k} Flow[u,v,l]) == 0;"; 65 | fprintf(fmod, "%s", model); 66 | fclose(fmod); 67 | 68 | /* data file */ 69 | printf("Generating the .dat file..."); 70 | fprintf(fdat, "data;\n"); 71 | fprintf(fdat, "set Targets :="); 72 | for (const int t : afg.Ts) { 73 | fprintf(fdat, " %d", t); 74 | } 75 | fprintf(fdat, ";\n"); 76 | 77 | fprintf(fdat, "param Cost :="); 78 | for (size_t i = 0; i < afg.Ts.size(); i++) { 79 | fprintf(fdat, " %d %d", afg.Ts[i], inst.Cs[i]); 80 | } 81 | fprintf(fdat, ";\n"); 82 | 83 | fprintf(fdat, "param Quantity :="); 84 | for (size_t i = 0; i < afg.Ts.size(); i++) { 85 | fprintf(fdat, " %d %d", afg.Ts[i], inst.Qs[i]); 86 | } 87 | fprintf(fdat, ";\n"); 88 | 89 | fprintf(fdat, "set Items :="); 90 | for (int i = 0; i < inst.m; i++) { 91 | fprintf(fdat, " %d", i+1); 92 | } 93 | fprintf(fdat, ";\n"); 94 | 95 | fprintf(fdat, "param Demand :="); 96 | for (int i = 0; i < inst.m; i++) { 97 | fprintf(fdat, " %d %d", i+1, inst.demands[i]); 98 | } 99 | fprintf(fdat, ";\n"); 100 | 101 | fprintf(fdat, "param RelaxDomains := %d;\n", inst.relax_domains); 102 | 103 | if (!inst.relax_domains) { 104 | fprintf(fdat, "param ArcBounds :="); 105 | for (const Item &item : inst.items) { 106 | fprintf(fdat, " %d %d", item.id, item.demand); 107 | } 108 | fprintf(fdat, ";\n"); 109 | } 110 | 111 | fprintf(fdat, "set Labels :="); 112 | for (const Item &item : inst.items) { 113 | fprintf(fdat, " %d", item.id); 114 | } 115 | fprintf(fdat, ";\n"); 116 | 117 | fprintf(fdat, "param ItemId :="); 118 | for (const Item &item : inst.items) { 119 | fprintf(fdat, " %d %d", item.id, item.type+1); 120 | } 121 | fprintf(fdat, ";\n"); 122 | 123 | fprintf(fdat, "param ItemOpt :="); 124 | for (const Item &item : inst.items) { 125 | fprintf(fdat, " %d %d", item.id, item.opt+1); 126 | } 127 | fprintf(fdat, ";\n"); 128 | 129 | fprintf(fdat, "param S := %d;\n", afg.S); 130 | fprintf(fdat, "param LOSS := %d;\n", afg.LOSS); 131 | 132 | fprintf(fdat, "set V :="); 133 | for (int i = 0 ; i < afg.NV; i++) { 134 | fprintf(fdat, " %d", i); 135 | } 136 | fprintf(fdat, ";\n"); 137 | 138 | fprintf(fdat, "set A :="); 139 | for (const Arc &a : afg.A) { 140 | fprintf(fdat, " (%d, %d, %d)", a.u, a.v, a.label); 141 | } 142 | fprintf(fdat, ";\n"); 143 | fclose(fdat); 144 | 145 | printf("DONE!\n"); 146 | return 0; 147 | } catch (const std::runtime_error &e) { 148 | printf("%s\n", e.what()); 149 | return 1; 150 | } catch (...) { 151 | printf("UnknownError\n"); 152 | return 1; 153 | } 154 | } 155 | 156 | int main(int argc, char *argv[]) { 157 | return swig_main(argc, argv); 158 | } 159 | -------------------------------------------------------------------------------- /src/afg2lp.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "config.hpp" 9 | #include "common.hpp" 10 | #include "arcflow.hpp" 11 | #include "instance.hpp" 12 | 13 | /* 14 | LP format example: 15 | 16 | Maximize 17 | obj: x1 + 2 x2 + 3 x3 + x4 18 | Subject To 19 | c1: - x1 + x2 + x3 + 10 x4 <= 20 20 | c2: x1 - 3 x2 + x3 <= 30 21 | c3: x2 - 3.5 x4 = 0 22 | Bounds 23 | 0 <= x1 <= 40 24 | 2 <= x4 <= 3 25 | General 26 | x4 27 | End 28 | */ 29 | 30 | int swig_main(int argc, char **argv) { 31 | printf(PACKAGE_STRING", Copyright (C) 2013-2022, Filipe Brandao\n"); 32 | setvbuf(stdout, NULL, _IONBF, 0); 33 | if (argc != 3) { 34 | printf("Usage: afg2mps graph.afg model.lp\n"); 35 | return 1; 36 | } 37 | try { 38 | throw_assert(check_ext(argv[1], ".afg")); 39 | Arcflow afg(argv[1]); 40 | Instance &inst = afg.inst; 41 | 42 | FILE *fout = fopen(argv[2], "w"); 43 | if (fout == NULL) { 44 | perror("fopen"); 45 | } 46 | throw_assert(fout != NULL); 47 | 48 | printf("Generating the .LP model..."); 49 | 50 | std::map> Ai; 51 | std::map> in; 52 | std::map> out; 53 | 54 | /* objective */ 55 | 56 | fprintf(fout, "Minimize"); 57 | std::vector ub(afg.NA); 58 | for (int i = 0; i < afg.NA; i++) { 59 | const Arc &a = afg.A[i]; 60 | Ai[a.label].push_back(i); 61 | in[a.v].push_back(i); 62 | out[a.u].push_back(i); 63 | if (a.v == afg.S) { 64 | for (int j = 0; j < static_cast(afg.Ts.size()); j++) { 65 | if (afg.Ts[j] == a.u) { 66 | ub[i] = (inst.Qs[j] >= 0) ? inst.Qs[j] : inst.n; 67 | if (inst.Cs[j] >= 0) { 68 | fprintf(fout, " +%d X%x", inst.Cs[j], i); 69 | } else { 70 | fprintf(fout, " -%d X%x", abs(inst.Cs[j]), i); 71 | } 72 | break; 73 | } 74 | } 75 | } else { 76 | if (a.label != afg.LOSS && !inst.relax_domains) { 77 | ub[i] = inst.items[a.label].demand; 78 | } else { 79 | ub[i] = inst.n; 80 | } 81 | } 82 | } 83 | fprintf(fout, "\n"); 84 | 85 | /* constraints */ 86 | 87 | fprintf(fout, "Subject To\n"); 88 | 89 | // demand constraints 90 | 91 | for (int i = 0; i < inst.m; i++) { 92 | if (inst.items[i].demand == 0) { 93 | continue; 94 | } 95 | fprintf(fout, "\tB%d:", i); 96 | for (int j = 0; j < inst.nsizes; j++) { 97 | if (inst.items[j].type == i) { 98 | for (const int &ai : Ai[j]) { 99 | fprintf(fout, " + X%x", ai); 100 | } 101 | } 102 | } 103 | if (inst.ctypes[i] == '=' && !inst.relax_domains) { 104 | fprintf(fout, " = %d", inst.demands[i]); 105 | } else { 106 | fprintf(fout, " >= %d", inst.demands[i]); 107 | } 108 | fprintf(fout, "\n"); 109 | } 110 | 111 | // flow conservation constraints 112 | 113 | for (int i = 0; i < afg.NV; i++) { 114 | fprintf(fout, "\tF%x:", i); 115 | for (const int &ai : in[i]) { 116 | fprintf(fout, " + X%x", ai); 117 | } 118 | for (const int &ai : out[i]) { 119 | fprintf(fout, " - X%x", ai); 120 | } 121 | fprintf(fout, " = 0\n"); 122 | } 123 | 124 | /* bounds */ 125 | 126 | fprintf(fout, "Bounds\n"); 127 | 128 | for (int i = 0; i < afg.NA; i++) { 129 | fprintf(fout, "0 <= X%x <= %d\n", i, ub[i]); 130 | } 131 | 132 | /* integer variables */ 133 | 134 | if (inst.vtype == 'I') { 135 | fprintf(fout, "General\n"); 136 | 137 | fprintf(fout, "\t"); 138 | for (int i = 0; i < afg.NA; i++) { 139 | if (!i) { 140 | fprintf(fout, "X%x", i); 141 | } else { 142 | fprintf(fout, " X%x", i); 143 | } 144 | } 145 | } 146 | 147 | fprintf(fout, "\nEnd\n"); 148 | fclose(fout); 149 | printf("DONE!\n"); 150 | return 0; 151 | } catch (const std::runtime_error &e) { 152 | printf("%s\n", e.what()); 153 | return 1; 154 | } catch (...) { 155 | printf("UnknownError\n"); 156 | return 1; 157 | } 158 | } 159 | 160 | int main(int argc, char *argv[]) { 161 | return swig_main(argc, argv); 162 | } 163 | -------------------------------------------------------------------------------- /src/afg2mps.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "config.hpp" 9 | #include "arcflow.hpp" 10 | #include "instance.hpp" 11 | 12 | /* 13 | MPS format 14 | 15 | Field: 1 2 3 4 5 6 16 | Columns: 2-3 5-12 15-22 25-36 40-47 50-61 17 | */ 18 | 19 | #define BUF_LEN 80 20 | #define NFIELDS 7 21 | 22 | const int field_start[NFIELDS] = {0, 1, 4, 14, 24, 39, 49}; 23 | 24 | class MPS { 25 | private: 26 | FILE *fout; 27 | int p; 28 | int cur_field; 29 | char buf[BUF_LEN]; 30 | 31 | void clear() { 32 | p = 0; 33 | cur_field = 0; 34 | memset(buf, ' ', sizeof(buf)); 35 | } 36 | 37 | void add_field(const char *str) { 38 | throw_assert(cur_field < NFIELDS); 39 | p = field_start[cur_field]; 40 | for (int i = 0; str[i]; i++) { 41 | buf[p++] = str[i]; 42 | } 43 | cur_field++; 44 | } 45 | 46 | public: 47 | MPS(FILE *_fout = stdout) : fout(_fout) {} 48 | 49 | void write(int count, ...) { 50 | clear(); 51 | 52 | va_list v; 53 | va_start(v, count); 54 | for (int i = 0; i < count; i++) { 55 | add_field(va_arg(v, const char *)); 56 | } 57 | va_end(v); 58 | 59 | throw_assert(p < BUF_LEN); 60 | buf[p] = 0; 61 | fprintf(fout, "%s\n", buf); 62 | clear(); 63 | } 64 | }; 65 | 66 | int swig_main(int argc, char **argv) { 67 | printf(PACKAGE_STRING", Copyright (C) 2013-2022, Filipe Brandao\n"); 68 | setvbuf(stdout, NULL, _IONBF, 0); 69 | if (argc != 3) { 70 | printf("Usage: afg2mps graph.afg model.mps\n"); 71 | return 1; 72 | } 73 | try { 74 | throw_assert(check_ext(argv[1], ".afg")); 75 | Arcflow afg(argv[1]); 76 | Instance &inst = afg.inst; 77 | 78 | FILE *fout = fopen(argv[2], "w"); 79 | if (fout == NULL) { 80 | perror("fopen"); 81 | } 82 | throw_assert(fout != NULL); 83 | 84 | printf("Generating the .MPS model..."); 85 | 86 | MPS mps(fout); 87 | mps.write(4, "NAME", "", "", "ARCFLOW"); 88 | mps.write(1, "ROWS"); 89 | mps.write(3, "", "N", "OBJ"); 90 | 91 | char buf[BUF_LEN]; 92 | char buf1[BUF_LEN]; 93 | char buf2[BUF_LEN]; 94 | 95 | /* demand constraints */ 96 | 97 | for (int i = 0; i < inst.m; i++) { 98 | char ctype = inst.ctypes[i]; 99 | throw_assert(ctype == '>' || ctype == '='); 100 | snprintf(buf, sizeof(buf), "B%d", i); 101 | if (ctype == '=' && !inst.relax_domains) { 102 | mps.write(3, "", "E", buf); 103 | } else { 104 | mps.write(3, "", "G", buf); 105 | } 106 | } 107 | 108 | /* flow conservation constraints */ 109 | 110 | for (int i = 0; i < afg.NV; i++) { 111 | snprintf(buf, sizeof(buf), "F%x", i); 112 | mps.write(3, "", "E", buf); 113 | } 114 | 115 | /* A-matrix */ 116 | 117 | mps.write(1, "COLUMNS"); 118 | 119 | if (inst.vtype == 'I') { 120 | mps.write(6, "", "", "MARKER", "'MARKER'", "", "'INTORG'"); 121 | } 122 | 123 | std::vector labels; 124 | std::vector ub(afg.NA); 125 | for (int i = 0; i < afg.NA; i++) { 126 | const Arc &a = afg.A[i]; 127 | labels.push_back(a.label); 128 | snprintf(buf, sizeof(buf), "X%x", i); 129 | snprintf(buf1, sizeof(buf1), "F%x", a.u); 130 | snprintf(buf2, sizeof(buf2), "F%x", a.v); 131 | mps.write(7, "", "", buf, buf1, "-1", buf2, "1"); 132 | if (a.label != afg.LOSS) { 133 | snprintf(buf1, sizeof(buf1), "B%d", inst.items[a.label].type); 134 | mps.write(5, "", "", buf, buf1, "1"); 135 | } 136 | if (a.v == afg.S) { 137 | for (int j = 0; j < static_cast(afg.Ts.size()); j++) { 138 | if (afg.Ts[j] == a.u) { 139 | ub[i] = (inst.Qs[j] >= 0) ? inst.Qs[j] : inst.n; 140 | snprintf(buf1, sizeof(buf1), "%d", inst.Cs[j]); 141 | mps.write(5, "", "", buf, "OBJ", buf1); 142 | break; 143 | } 144 | } 145 | } else { 146 | if (a.label != afg.LOSS && !inst.relax_domains) { 147 | ub[i] = inst.items[a.label].demand; 148 | } else { 149 | ub[i] = inst.n; 150 | } 151 | } 152 | } 153 | 154 | if (inst.vtype == 'I') { 155 | mps.write(6, "", "", "MARKER", "'MARKER'", "", "'INTEND'"); 156 | } 157 | 158 | /* right-hand-side vector */ 159 | 160 | mps.write(1, "RHS"); 161 | 162 | for (int i = 0; i < inst.m; i++) { 163 | snprintf(buf, sizeof(buf), "B%d", i); 164 | snprintf(buf1, sizeof(buf1), "%d", inst.demands[i]); 165 | mps.write(5, "", "", "RHS1", buf, buf1); 166 | } 167 | 168 | /* bounds */ 169 | 170 | mps.write(1, "BOUNDS"); 171 | 172 | for (int i = 0; i < afg.NA; i++) { 173 | snprintf(buf, sizeof(buf), "X%x", i); 174 | mps.write(5, "", "LO", "BND1", buf, "0"); 175 | snprintf(buf1, sizeof(buf1), "%d", ub[i]); 176 | mps.write(5, "", "UP", "BND1", buf, buf1); 177 | } 178 | 179 | mps.write(1, "ENDATA"); 180 | fclose(fout); 181 | printf("DONE!\n"); 182 | return 0; 183 | } catch (const std::runtime_error &e) { 184 | printf("%s\n", e.what()); 185 | return 1; 186 | } catch (...) { 187 | printf("UnknownError\n"); 188 | return 1; 189 | } 190 | } 191 | 192 | int main(int argc, char *argv[]) { 193 | return swig_main(argc, argv); 194 | } 195 | -------------------------------------------------------------------------------- /src/arcflow.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #ifndef SRC_ARCFLOW_HPP_ 5 | #define SRC_ARCFLOW_HPP_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "graph.hpp" 12 | #include "common.hpp" 13 | #include "instance.hpp" 14 | 15 | class Arcflow { 16 | private: 17 | bool ready; 18 | std::set AS; 19 | NodeSet NS; 20 | std::vector maxW; 21 | std::map, int> dp; 22 | 23 | int go(std::vector su); 24 | 25 | inline std::vector hash(const std::vector &su); 26 | 27 | std::vector max_label; 28 | std::vector hash_bits; 29 | std::vector max_rep; 30 | std::vector sitems; 31 | std::vector> weights; 32 | int label_size; 33 | 34 | std::vector count_max_rep(const std::vector &space, int i0, 35 | int sub_i0) const; 36 | 37 | void lift_state(const std::vector &valid_opts, std::vector &u, int it, 38 | int ic) const; 39 | 40 | int min_slack(const std::vector &b, int i0, int d, 41 | const std::vector &caps) const; 42 | 43 | bool is_valid(const std::vector &u, const std::vector &W) const; 44 | 45 | bool is_full(const std::vector &u, const std::vector &W) const; 46 | 47 | void relabel_graph(const std::vector &labels); 48 | 49 | void init(const Instance &_inst); 50 | 51 | void init(const char *fname); 52 | 53 | void read(const char *fname); 54 | 55 | void read(FILE *fin); 56 | 57 | void build(); 58 | 59 | void final_compression_step(); 60 | 61 | void reduce_redundancy(); 62 | 63 | void finalize(); 64 | 65 | public: 66 | clock_t tstart; 67 | Instance inst; 68 | int NV; 69 | int NA; 70 | int S; 71 | std::vector Ts; 72 | std::vector A; 73 | int LOSS; 74 | 75 | explicit Arcflow(const Instance &_inst); 76 | 77 | explicit Arcflow(const char *fname); 78 | 79 | void write(const char *fname); 80 | 81 | void write(FILE *fout); 82 | }; 83 | 84 | #endif // SRC_ARCFLOW_HPP_ 85 | -------------------------------------------------------------------------------- /src/arcflowsol.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "graph.hpp" 9 | #include "common.hpp" 10 | #include "instance.hpp" 11 | #include "arcflowsol.hpp" 12 | 13 | /* Class ArcflowSol */ 14 | 15 | ArcflowSol::ArcflowSol(const Instance &_inst, const std::map &_flow, 16 | int _S, const std::vector &_Ts, int _LOSS) : 17 | inst(_inst), flow(_flow), S(_S), Ts(_Ts), LOSS(_LOSS) { 18 | std::vector dem(inst.m); 19 | for (int i = 0; i < inst.m; i++) { 20 | dem[i] = inst.demands[i]; 21 | } 22 | 23 | objvalue = 0; 24 | sols.resize(inst.nbtypes); 25 | nbins.resize(inst.nbtypes); 26 | for (int t = 0; t < inst.nbtypes; t++) { 27 | sols[t] = extract_solution(&dem, Ts[t]); 28 | if (!is_valid(sols[t], t)) { 29 | throw_error("Invalid solution! (capacity)"); 30 | } 31 | 32 | for (const pattern_pair &pat : sols[t]) { 33 | objvalue += pat.first * inst.Cs[t]; 34 | nbins[t] += pat.first; 35 | } 36 | } 37 | 38 | for (int i = 0; i < inst.m; i++) { 39 | if (dem[i] > 0) { 40 | throw_error("Invalid solution! (demand)"); 41 | } 42 | } 43 | 44 | int fs = 0; 45 | for (const auto &kvpair : flow) { 46 | fs += kvpair.second; 47 | } 48 | if (fs != 0) { 49 | throw_error("Invalid solution! (flow)"); 50 | } 51 | } 52 | 53 | std::vector ArcflowSol::remove_excess(const std::vector &sol, 54 | std::vector *_dem) const { 55 | std::vector &dem = *_dem; 56 | std::vector tmp; 57 | for (const pattern_int &pat : sol) { 58 | std::map count; 59 | for (const int &it : pat.second) { 60 | count[it] += 1; 61 | } 62 | std::vector rm; 63 | int rep = pat.first; 64 | while (rep > 0) { 65 | rm.clear(); 66 | for (auto &kvpair : count) { 67 | int type = inst.items[kvpair.first].type; 68 | kvpair.second = std::min(kvpair.second, dem[type]); 69 | if (kvpair.second == 0) { 70 | rm.push_back(kvpair.first); 71 | } 72 | } 73 | for (const int &ind : rm) { 74 | count.erase(ind); 75 | } 76 | 77 | int f = rep; 78 | for (const auto &kvpair : count) { 79 | int type = inst.items[kvpair.first].type; 80 | f = std::min(f, dem[type] / kvpair.second); 81 | } 82 | rep -= f; 83 | 84 | tmp.push_back(MP(f, std::vector(all(count)))); 85 | for (const auto &kvpair : count) { 86 | int type = inst.items[kvpair.first].type; 87 | dem[type] -= f * kvpair.second; 88 | } 89 | } 90 | } 91 | 92 | std::map, int> mp; 93 | for (pattern_pair &pp : tmp) { 94 | sort(all(pp.second)); 95 | mp[pp.second] += pp.first; 96 | } 97 | 98 | std::vector finalsol; 99 | for (const auto &kvpair : mp) { 100 | finalsol.push_back(MP(kvpair.second, kvpair.first)); 101 | } 102 | return finalsol; 103 | } 104 | 105 | std::vector ArcflowSol::extract_solution(std::vector *_dem, int T) { 106 | std::vector &dem = *_dem; 107 | std::set nodes; 108 | std::map> adj; 109 | for (const auto &kvpair : flow) { 110 | int u = kvpair.first.u; 111 | int v = kvpair.first.v; 112 | nodes.insert(u); 113 | nodes.insert(v); 114 | if (v != S) { 115 | adj[v].push_back(kvpair.first); 116 | } 117 | } 118 | 119 | int &zflow = flow[Arc(T, S, LOSS)]; 120 | 121 | std::vector lst(all(nodes)); 122 | 123 | std::vector sol; 124 | while (true) { 125 | std::map pred; 126 | std::map dp; 127 | dp[S] = zflow; 128 | for (const int &v : lst) { 129 | int &val = dp[v]; 130 | Arc &p = pred[v]; 131 | for (const Arc &a : adj[v]) { 132 | throw_assert(dp.count(a.u) != 0); 133 | int mf = std::min(dp[a.u], flow[a]); 134 | if (mf > val) { 135 | p = a; 136 | val = mf; 137 | } 138 | } 139 | } 140 | int f = dp[T]; 141 | zflow -= f; 142 | if (f == 0) { 143 | break; 144 | } 145 | int v = T; 146 | sol.push_back(pattern_int()); 147 | pattern_int &patt = sol.back(); 148 | patt.first = f; 149 | while (v != S) { 150 | Arc a = pred[v]; 151 | int u = a.u; 152 | int lbl = a.label; 153 | if (lbl != LOSS) { 154 | patt.second.push_back(lbl); 155 | } 156 | flow[a] -= f; 157 | v = u; 158 | } 159 | } 160 | return remove_excess(sol, &dem); 161 | } 162 | 163 | bool ArcflowSol::is_valid(const std::vector &sol, int btype) const { 164 | for (const pattern_pair &pat : sol) { 165 | std::vector w(inst.ndims); 166 | for (const auto &itpair : pat.second) { 167 | if (inst.binary && itpair.second > 1) { 168 | return false; 169 | } 170 | const Item &it = inst.items[itpair.first]; 171 | for (int i = 0; i < inst.ndims; i++) { 172 | w[i] += it[i] * itpair.second; 173 | } 174 | } 175 | for (int i = 0; i < inst.ndims; i++) { 176 | if (w[i] > inst.Ws[btype][i]) { 177 | return false; 178 | } 179 | } 180 | } 181 | return true; 182 | } 183 | 184 | void ArcflowSol::print_solution(bool print_inst = true, bool pyout = false) { 185 | printf("Objective: %d\n", objvalue); 186 | printf("Solution:\n"); 187 | for (int t = 0; t < inst.nbtypes; t++) { 188 | if (inst.nbtypes > 1) { 189 | printf("Bins of type %d: %d\n", t + 1, nbins[t]); 190 | } 191 | std::vector &sol = sols[t]; 192 | for (const pattern_pair &pat : sol) { 193 | std::vector tmp; 194 | for (const int_pair &itpair : pat.second) { 195 | int t = inst.items[itpair.first].type; 196 | int opt = inst.items[itpair.first].opt; 197 | for (int i = 0; i < itpair.second; i++) { 198 | tmp.push_back(MP(t, opt)); 199 | } 200 | } 201 | sort(all(tmp)); 202 | printf("%d x [", pat.first); 203 | bool first = true; 204 | for (const int_pair &p : tmp) { 205 | if (first) { 206 | first = false; 207 | } else { 208 | printf(", "); 209 | } 210 | if (p.second == -1) { 211 | printf("i=%d", p.first + 1); 212 | } else { 213 | printf("i=%d opt=%d", p.first + 1, p.second + 1); 214 | } 215 | } 216 | printf("]\n"); 217 | } 218 | } 219 | 220 | if (print_inst) { 221 | inst.print(); 222 | } 223 | 224 | if (pyout) { 225 | printf("PYSOL=(%d,[", objvalue); 226 | for (int t = 0; t < inst.nbtypes; t++) { 227 | printf("["); 228 | std::vector &sol = sols[t]; 229 | for (const pattern_pair &pat : sol) { 230 | std::vector tmp; 231 | for (const int_pair &itpair : pat.second) { 232 | int t = inst.items[itpair.first].type; 233 | int opt = inst.items[itpair.first].opt; 234 | for (int i = 0; i < itpair.second; i++) { 235 | tmp.push_back(MP(t, opt)); 236 | } 237 | } 238 | sort(all(tmp)); 239 | 240 | printf("(%d,[", pat.first); 241 | for (const int_pair &p : tmp) { 242 | if (p.second == -1) { 243 | printf("(%d, 0),", p.first); 244 | } else { 245 | printf("(%d, %d),", p.first, p.second); 246 | } 247 | } 248 | printf("]),"); 249 | } 250 | printf("],"); 251 | } 252 | printf("])\n"); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/arcflowsol.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #ifndef SRC_ARCFLOWSOL_HPP_ 5 | #define SRC_ARCFLOWSOL_HPP_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "graph.hpp" 13 | #include "common.hpp" 14 | #include "instance.hpp" 15 | 16 | typedef std::pair> pattern_int; 17 | typedef std::pair> pattern_pair; 18 | 19 | class ArcflowSol { 20 | private: 21 | Instance inst; 22 | std::map flow; 23 | int S; 24 | std::vector Ts; 25 | int LOSS; 26 | int objvalue; 27 | std::vector nbins; 28 | std::vector> sols; 29 | 30 | std::vector extract_solution(std::vector *_dem, int T); 31 | 32 | std::vector remove_excess(const std::vector &sol, 33 | std::vector *_dem) const; 34 | 35 | bool is_valid(const std::vector &sol, int btype) const; 36 | 37 | public: 38 | ArcflowSol(const Instance &_inst, const std::map &_flow, int _S, 39 | const std::vector &_Ts, int _LOSS); 40 | 41 | void print_solution(bool print_inst, bool pyout); 42 | }; 43 | 44 | #endif // SRC_ARCFLOWSOL_HPP_ 45 | -------------------------------------------------------------------------------- /src/common.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include "common.hpp" 6 | 7 | bool check_ext(const char *name, const char *extension) { 8 | const char *end = strrchr(name, '.'); 9 | return strcmp(end, extension) == 0; 10 | } 11 | 12 | bool prefix(const char *pre, const char *str) { 13 | return strncmp(pre, str, strlen(pre)) == 0; 14 | } 15 | -------------------------------------------------------------------------------- /src/common.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #ifndef SRC_COMMON_HPP_ 5 | #define SRC_COMMON_HPP_ 6 | 7 | #define EPS 1e-5 8 | #define MAX_LEN 256 9 | #define TRANSPOSE (1) 10 | #define all(x) (x).begin(),(x).end() 11 | #define MP(x, y) std::make_pair(x,y) 12 | 13 | #define MIN_METHOD -3 14 | #define MAX_METHOD -3 15 | 16 | #define CURTIME clock() 17 | #define TIMEDIF(t0) (static_cast(clock()-t0)/CLOCKS_PER_SEC) 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | typedef std::pair int_pair; 25 | 26 | bool check_ext(const char *name, const char *extension); 27 | 28 | bool prefix(const char *pre, const char *str); 29 | 30 | #define throw_error(error) \ 31 | { \ 32 | char _error_msg_[MAX_LEN]; \ 33 | snprintf(_error_msg_, MAX_LEN, \ 34 | "Error: `%s` in \"%s\" line %d", \ 35 | error, __FILE__, __LINE__); \ 36 | throw std::runtime_error(_error_msg_); \ 37 | } 38 | 39 | #define throw_assert(condition) \ 40 | { if (!(condition)) { \ 41 | char _error_msg_[MAX_LEN]; \ 42 | snprintf(_error_msg_, MAX_LEN, \ 43 | "AssertionError: assertion `%s` failed in \"%s\" line %d", \ 44 | #condition, __FILE__, __LINE__); \ 45 | throw std::runtime_error(_error_msg_); \ 46 | } } 47 | 48 | #endif // SRC_COMMON_HPP_ 49 | -------------------------------------------------------------------------------- /src/config.hpp: -------------------------------------------------------------------------------- 1 | /* src/config.hpp. Generated from config.hpp.in by configure. */ 2 | /* src/config.hpp.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* Name of package */ 5 | #define PACKAGE "vpsolver" 6 | 7 | /* Define to the address where bug reports for this package should be sent. */ 8 | #define PACKAGE_BUGREPORT "fdabrandao@dcc.fc.up.pt" 9 | 10 | /* Define to the full name of this package. */ 11 | #define PACKAGE_NAME "VPSolver" 12 | 13 | /* Define to the full name and version of this package. */ 14 | #define PACKAGE_STRING "VPSolver 3.1.3" 15 | 16 | /* Define to the one symbol short name of this package. */ 17 | #define PACKAGE_TARNAME "vpsolver" 18 | 19 | /* Define to the home page for this package. */ 20 | #define PACKAGE_URL "http://vpsolver.dcc.fc.up.pt/" 21 | 22 | /* Define to the version of this package. */ 23 | #define PACKAGE_VERSION "3.1.3" 24 | 25 | /* Version number of package */ 26 | #define VERSION "3.1.3" 27 | -------------------------------------------------------------------------------- /src/config.hpp.in: -------------------------------------------------------------------------------- 1 | /* src/config.hpp.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Name of package */ 4 | #undef PACKAGE 5 | 6 | /* Define to the address where bug reports for this package should be sent. */ 7 | #undef PACKAGE_BUGREPORT 8 | 9 | /* Define to the full name of this package. */ 10 | #undef PACKAGE_NAME 11 | 12 | /* Define to the full name and version of this package. */ 13 | #undef PACKAGE_STRING 14 | 15 | /* Define to the one symbol short name of this package. */ 16 | #undef PACKAGE_TARNAME 17 | 18 | /* Define to the home page for this package. */ 19 | #undef PACKAGE_URL 20 | 21 | /* Define to the version of this package. */ 22 | #undef PACKAGE_VERSION 23 | 24 | /* Version number of package */ 25 | #undef VERSION 26 | -------------------------------------------------------------------------------- /src/graph.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include 6 | #include "graph.hpp" 7 | #include "common.hpp" 8 | 9 | /* Class NodeSet */ 10 | 11 | int NodeSet::get_index(const std::vector &lbl) { 12 | if (index.count(lbl)) { 13 | return index[lbl]; 14 | } else { 15 | int ind = labels.size(); 16 | labels.push_back(lbl); 17 | index[lbl] = ind; 18 | return ind; 19 | } 20 | } 21 | 22 | std::vector NodeSet::get_label(int ind) const { 23 | throw_assert(ind < static_cast(labels.size())); 24 | return labels[ind]; 25 | } 26 | 27 | int NodeSet::size() const { 28 | return labels.size(); 29 | } 30 | 31 | void NodeSet::clear() { 32 | index.clear(); 33 | labels.clear(); 34 | } 35 | 36 | void NodeSet::sort() { 37 | index.clear(); 38 | std::sort(all(labels)); 39 | int pos = 0; 40 | for (const std::vector &lbl : labels) { 41 | index[lbl] = pos++; 42 | } 43 | } 44 | 45 | std::vector NodeSet::topological_order() const { 46 | std::vector ord(index.size()); 47 | int pos = 0; 48 | for (const auto &kvpair : index) { 49 | ord[kvpair.second] = pos++; 50 | } 51 | return ord; 52 | } 53 | 54 | 55 | /* Class Arc */ 56 | 57 | bool Arc::operator<(const Arc &o) const { 58 | return (u < o.u) || 59 | (u == o.u && v < o.v) || 60 | (u == o.u && v == o.v && label < o.label); 61 | } 62 | 63 | bool Arc::operator==(const Arc &o) const { 64 | return u == o.u && v == o.v && label == o.label; 65 | } 66 | 67 | 68 | /* Additional Functions */ 69 | 70 | adj_list get_adj(int nv, const std::vector &arcs, bool transpose) { 71 | adj_list adj(nv); 72 | for (const Arc &a : arcs) { 73 | throw_assert(a.u < nv && a.v < nv); 74 | if (!transpose) { 75 | adj[a.u].push_back(MP(a.v, a.label)); 76 | } else { 77 | adj[a.v].push_back(MP(a.u, a.label)); 78 | } 79 | } 80 | return adj; 81 | } 82 | -------------------------------------------------------------------------------- /src/graph.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | 4 | Copyright (C) 2013-2021, Filipe Brandao 5 | **/ 6 | #ifndef SRC_GRAPH_HPP_ 7 | #define SRC_GRAPH_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "common.hpp" 14 | 15 | typedef std::vector> adj_list; 16 | 17 | class NodeSet { 18 | private: 19 | std::map, int> index; 20 | std::vector> labels; 21 | public: 22 | int get_index(const std::vector &lbl); 23 | 24 | std::vector get_label(int ind) const; 25 | 26 | int size() const; 27 | 28 | void clear(); 29 | 30 | void sort(); 31 | 32 | std::vector topological_order() const; 33 | }; 34 | 35 | class Arc { 36 | public: 37 | int u; 38 | int v; 39 | int label; 40 | 41 | explicit Arc(const int &_u = -1, const int &_v = -1, int _label = -1) : 42 | u(_u), v(_v), label(_label) {} 43 | 44 | bool operator<(const Arc &o) const; 45 | 46 | bool operator==(const Arc &o) const; 47 | }; 48 | 49 | adj_list get_adj(int nv, const std::vector &arcs, bool transpose = false); 50 | 51 | #endif // SRC_GRAPH_HPP_ 52 | -------------------------------------------------------------------------------- /src/instance.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "common.hpp" 10 | #include "instance.hpp" 11 | 12 | #define NORM_PRECISION 10000 13 | 14 | /* Class Item */ 15 | 16 | bool Item::operator<(const Item &o) const { 17 | throw_assert(ndims == o.ndims); 18 | if (abs(key - o.key) >= 1e-5) { 19 | return key < o.key; 20 | } 21 | for (int i = 0; i < ndims; i++) { 22 | if (w[i] != o.w[i]) { 23 | return w[i] < o.w[i]; 24 | } 25 | } 26 | return demand < o.demand; 27 | } 28 | 29 | int Item::operator[](int i) const { 30 | throw_assert(i < ndims); 31 | return w[i]; 32 | } 33 | 34 | int &Item::operator[](int i) { 35 | throw_assert(i < ndims); 36 | return w[i]; 37 | } 38 | 39 | /* Class Instance */ 40 | 41 | void Instance::init() { 42 | relax_domains = false; 43 | binary = false; 44 | method = -3; 45 | vtype = 'I'; 46 | ndims = 0; 47 | m = 0; 48 | } 49 | 50 | Instance::Instance() { 51 | init(); 52 | } 53 | 54 | Instance::Instance(FILE *fin, ftype type) { 55 | init(); 56 | read(fin, type); 57 | } 58 | 59 | Instance::Instance(const char *fname) { 60 | init(); 61 | read(fname); 62 | } 63 | 64 | std::vector Instance::sorted_items() { 65 | std::vector sitems(items); 66 | std::stable_sort(all(sitems)); 67 | std::reverse(all(sitems)); 68 | return sitems; 69 | } 70 | 71 | void Instance::print() const { 72 | printf("Instance:\n"); 73 | int p = 0; 74 | for (int i = 0; i < m; i++) { 75 | printf("i=%d (nopts: %d, demand: %d)\n", i + 1, nopts[i], demands[i]); 76 | for (int q = 0; q < nopts[i]; q++) { 77 | printf(" opt=%d: (", q + 1); 78 | for (int j = 0; j < ndims; j++) { 79 | if (j) { 80 | printf(", "); 81 | } 82 | printf("%d", items[p][j]); 83 | } 84 | printf(")\n"); 85 | p++; 86 | } 87 | } 88 | } 89 | 90 | void Instance::read(const char *fname) { 91 | FILE *fin = fopen(fname, "r"); 92 | if (fin == NULL) { 93 | perror("fopen"); 94 | } 95 | throw_assert(fin != NULL); 96 | if (check_ext(fname, ".vbp")) { 97 | read(fin, VBP); 98 | } else if (check_ext(fname, ".mvp")) { 99 | read(fin, MVP); 100 | } else { 101 | throw_error("Invalid file extension"); 102 | } 103 | fclose(fin); 104 | } 105 | 106 | void Instance::read(FILE *fin, ftype type) { 107 | throw_assert(fscanf(fin, " #INSTANCE_BEGIN#") == 0); 108 | throw_assert(fscanf(fin, " $INSTANCE {") == 0); 109 | throw_assert(fscanf(fin, "%d", &ndims) == 1); 110 | throw_assert(ndims >= 1); 111 | 112 | if (type == MVP) { 113 | throw_assert(fscanf(fin, "%d", &nbtypes) == 1); 114 | throw_assert(nbtypes >= 1); 115 | } else { 116 | nbtypes = 1; 117 | } 118 | 119 | Ws.resize(nbtypes); 120 | Cs.resize(nbtypes); 121 | Qs.resize(nbtypes); 122 | for (int t = 0; t < nbtypes; t++) { 123 | Ws[t].resize(ndims); 124 | for (int d = 0; d < ndims; d++) { 125 | throw_assert(fscanf(fin, "%d", &Ws[t][d]) == 1); 126 | throw_assert(Ws[t][d] >= 0); 127 | } 128 | if (type == MVP) { 129 | throw_assert(fscanf(fin, "%d", &Cs[t]) == 1); 130 | throw_assert(fscanf(fin, "%d", &Qs[t]) == 1); 131 | } else { 132 | Cs[t] = 1; 133 | Qs[t] = -1; 134 | } 135 | } 136 | 137 | items.clear(); 138 | nopts.clear(); 139 | ctypes.clear(); 140 | demands.clear(); 141 | int it_count = 0; 142 | throw_assert(fscanf(fin, "%d", &m) == 1); 143 | for (int it_type = 0; it_type < m; it_type++) { 144 | int ti, bi; 145 | if (type == MVP) { 146 | throw_assert(fscanf(fin, "%d", &ti) == 1); 147 | throw_assert(ti >= 0); 148 | throw_assert(fscanf(fin, "%d", &bi) == 1); 149 | throw_assert(bi >= 0); 150 | demands.push_back(bi); 151 | } else { 152 | ti = 1; 153 | bi = -1; 154 | } 155 | nopts.push_back(ti); 156 | ctypes.push_back('*'); 157 | 158 | int nfits = 0; 159 | for (int opt = 0; opt < ti; opt++) { 160 | items.push_back(Item(ndims)); 161 | Item &item = items.back(); 162 | if (ti > 1) { 163 | item.opt = opt; 164 | } else { 165 | item.opt = -1; 166 | } 167 | 168 | for (int d = 0; d < ndims; d++) { 169 | throw_assert(fscanf(fin, "%d", &item[d]) == 1); 170 | throw_assert(item[d] >= 0); 171 | if (item[d] != 0) { 172 | item.nonzero.push_back(d); 173 | } 174 | } 175 | throw_assert(!item.nonzero.empty()); 176 | 177 | if (type == VBP) { 178 | throw_assert(fscanf(fin, "%d", &bi) == 1); 179 | throw_assert(bi >= 0); 180 | demands.push_back(bi); 181 | } 182 | item.demand = bi; 183 | 184 | int S = 0; 185 | std::vector maxW(ndims, 0); 186 | for (int d = 0; d < ndims; d++) { 187 | for (int t = 0; t < nbtypes; t++) { 188 | maxW[d] = std::max(maxW[d], Ws[t][d]); 189 | } 190 | } 191 | for (int d = 0; d < ndims; d++) { 192 | if (maxW[d] > 0) { 193 | S += round( 194 | item[d] / static_cast(maxW[d]) * NORM_PRECISION); 195 | } 196 | } 197 | if (item.demand > 0) { 198 | bool fits = false; 199 | for (int t = 0; t < nbtypes; t++) { 200 | fits = true; 201 | for (int d = 0; d < ndims; d++) { 202 | if (item[d] > Ws[t][d]) { 203 | fits = false; 204 | break; 205 | } 206 | } 207 | if (fits) { 208 | break; 209 | } 210 | } 211 | nfits += fits; 212 | } 213 | item.key = S; 214 | item.type = it_type; 215 | item.id = it_count++; 216 | } 217 | if (bi > 0) { 218 | throw_assert(nfits >= 1); 219 | } 220 | } 221 | throw_assert(fscanf(fin, " } ;") <= 0); 222 | 223 | char buf[MAX_LEN]; 224 | while (fscanf(fin, " $%[^{ \n]", buf) == 1) { 225 | if (!strcmp(buf, "VTYPE")) { 226 | throw_assert(fscanf(fin, " { %[^}, \n] } ;", buf) == 1); 227 | vtype = buf[0]; 228 | throw_assert(vtype == 'C' || vtype == 'I'); 229 | } else if (!strcmp(buf, "CTYPE")) { 230 | throw_assert(fscanf(fin, " {") == 0); 231 | ctypes.clear(); 232 | for (int i = 0; i < m; i++) { 233 | if (i) throw_assert(fscanf(fin, " ,") == 0); 234 | throw_assert(fscanf(fin, " %[^}, \n]", buf) == 1); 235 | if (!strcmp(buf, ">")) { 236 | ctypes.push_back('>'); 237 | } else if (!strcmp(buf, "=")) { 238 | ctypes.push_back('='); 239 | } else { 240 | throw_assert(!strcmp(buf, "*")); 241 | ctypes.push_back('*'); 242 | } 243 | } 244 | throw_assert(fscanf(fin, " } ;") == 0); 245 | } else if (!strcmp(buf, "METHOD")) { 246 | throw_assert(fscanf(fin, " { %d } ;", &method) == 1); 247 | throw_assert(method >= MIN_METHOD && method <= MAX_METHOD); 248 | } else if (!strcmp(buf, "RELAX")) { 249 | int trelax = 0; 250 | throw_assert(fscanf(fin, " { %d } ;", &trelax) == 1); 251 | throw_assert(trelax == 0 || trelax == 1); 252 | relax_domains = trelax; 253 | } else if (!strcmp(buf, "BINARY")) { 254 | int tbinary = 0; 255 | throw_assert(fscanf(fin, " { %d } ;", &tbinary) == 1); 256 | throw_assert(tbinary == 0 || tbinary == 1); 257 | binary = tbinary; 258 | } else { 259 | printf("Invalid option '%s'!\n", buf); 260 | exit(1); 261 | } 262 | } 263 | throw_assert(fscanf(fin, " #INSTANCE_END#") <= 0); 264 | 265 | for (int i = 0; i < m; i++) { 266 | if (ctypes[i] == '*') { 267 | ctypes[i] = (demands[i] <= 1) ? '=' : '>'; 268 | } 269 | } 270 | 271 | n = 0; 272 | for (int i = 0; i < m; i++) { 273 | n += demands[i]; 274 | } 275 | 276 | nsizes = items.size(); 277 | } 278 | 279 | void Instance::write(FILE *fout) const { 280 | fprintf(fout, "#INSTANCE_BEGIN#\n"); 281 | fprintf(fout, "$INSTANCE{\n"); 282 | fprintf(fout, "%d\n", ndims); 283 | 284 | fprintf(fout, "%d\n", nbtypes); 285 | 286 | for (int t = 0; t < nbtypes; t++) { 287 | for (int i = 0; i < ndims; i++) { 288 | fprintf(fout, " %d", Ws[t][i]); 289 | } 290 | fprintf(fout, " %d", Cs[t]); 291 | fprintf(fout, " %d\n", Qs[t]); 292 | } 293 | 294 | fprintf(fout, "%d\n", m); 295 | int p = 0; 296 | std::vector rid(items.size()); 297 | for (int it = 0; it < static_cast(items.size()); it++) { 298 | rid[items[it].id] = it; 299 | } 300 | for (int i = 0; i < m; i++) { 301 | fprintf(fout, "%d %d\n", nopts[i], demands[i]); 302 | for (int q = 0; q < nopts[i]; q++) { 303 | for (int j = 0; j < ndims; j++) { 304 | fprintf(fout, " %d", items[rid[p]][j]); 305 | } 306 | fprintf(fout, "\n"); 307 | p++; 308 | } 309 | } 310 | fprintf(fout, "};\n"); 311 | 312 | fprintf(fout, "$VTYPE{%c};\n", vtype); 313 | 314 | fprintf(fout, "$CTYPE{"); 315 | for (int i = 0; i < m; i++) { 316 | if (i) fprintf(fout, ","); 317 | fprintf(fout, "%c", ctypes[i]); 318 | } 319 | fprintf(fout, "};\n"); 320 | 321 | fprintf(fout, "$METHOD{%d};\n", method); 322 | 323 | fprintf(fout, "$RELAX{%d};\n", relax_domains); 324 | 325 | fprintf(fout, "$BINARY{%d};\n", binary); 326 | 327 | fprintf(fout, "#INSTANCE_END#\n"); 328 | } 329 | -------------------------------------------------------------------------------- /src/instance.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #ifndef SRC_INSTANCE_HPP_ 5 | #define SRC_INSTANCE_HPP_ 6 | 7 | #include 8 | #include 9 | 10 | enum ftype { 11 | VBP, MVP 12 | }; 13 | 14 | class Item { 15 | public: 16 | std::vector w; 17 | std::vector nonzero; 18 | int id; 19 | int type; 20 | int opt; 21 | int ndims; 22 | int demand; 23 | int key; 24 | 25 | explicit Item(int _ndims) : ndims(_ndims) { 26 | w = std::vector(_ndims); 27 | } 28 | 29 | void add_dim(int dw) { 30 | ndims++; 31 | w.push_back(dw); 32 | } 33 | 34 | bool operator<(const Item &o) const; 35 | 36 | int operator[](int i) const; 37 | 38 | int &operator[](int i); 39 | }; 40 | 41 | class Instance { 42 | private: 43 | void init(); 44 | 45 | public: 46 | int ndims; 47 | int nbtypes; 48 | int nsizes; 49 | int m, n; 50 | std::vector> Ws; // bin types 51 | std::vector Cs; // costs 52 | std::vector Qs; // quantities 53 | std::vector items; 54 | int method; 55 | bool binary; 56 | bool relax_domains; 57 | 58 | char vtype; 59 | std::vector ctypes; 60 | std::vector nopts; 61 | std::vector demands; 62 | 63 | Instance(); 64 | 65 | explicit Instance(const char *fname); 66 | 67 | explicit Instance(FILE *fin, ftype type = MVP); 68 | 69 | std::vector sorted_items(); 70 | 71 | void print() const; 72 | 73 | void read(const char *fname); 74 | 75 | void read(FILE *fin, ftype type = MVP); 76 | 77 | void write(FILE *fout) const; 78 | }; 79 | 80 | #endif // SRC_INSTANCE_HPP_ 81 | -------------------------------------------------------------------------------- /src/vbp2afg.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include 6 | #include "config.hpp" 7 | #include "arcflow.hpp" 8 | #include "instance.hpp" 9 | 10 | int swig_main(int argc, char **argv) { 11 | printf(PACKAGE_STRING", Copyright (C) 2013-2022, Filipe Brandao\n"); 12 | setvbuf(stdout, NULL, _IONBF, 0); 13 | if (argc < 3 || argc > 6) { 14 | printf("Usage: vbp2afg instance.vbp/instance.mvp graph.afg " 15 | "[method:-3] [binary:0] [vtype:I]\n"); 16 | return 1; 17 | } 18 | FILE *fout = NULL; 19 | try { 20 | fout = fopen(argv[2], "w"); 21 | if (fout == NULL) { 22 | perror("fopen"); 23 | } 24 | throw_assert(fout != NULL); 25 | 26 | Instance inst(argv[1]); 27 | if (argc >= 4) { 28 | inst.method = atoi(argv[3]); 29 | throw_assert(inst.method >= MIN_METHOD && 30 | inst.method <= MAX_METHOD); 31 | } 32 | if (argc >= 5) { 33 | int value = atoi(argv[4]); 34 | if (value >= 0) { 35 | inst.binary = value; 36 | } 37 | } 38 | if (argc >= 6) { 39 | inst.vtype = argv[5][0]; 40 | throw_assert(inst.vtype == 'I' || inst.vtype == 'C'); 41 | } 42 | 43 | Arcflow graph(inst); 44 | inst.write(fout); 45 | graph.write(fout); 46 | 47 | fclose(fout); 48 | return 0; 49 | } catch (const std::runtime_error &e) { 50 | if (fout != NULL) { 51 | fclose(fout); 52 | } 53 | printf("%s\n", e.what()); 54 | return 1; 55 | } catch (...) { 56 | if (fout != NULL) { 57 | fclose(fout); 58 | } 59 | printf("UnknownError\n"); 60 | return 1; 61 | } 62 | } 63 | 64 | int main(int argc, char *argv[]) { 65 | return swig_main(argc, argv); 66 | } 67 | -------------------------------------------------------------------------------- /src/vbpsol.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "config.hpp" 10 | #include "common.hpp" 11 | #include "arcflow.hpp" 12 | #include "instance.hpp" 13 | #include "arcflowsol.hpp" 14 | 15 | int swig_main(int argc, char **argv) { 16 | printf(PACKAGE_STRING", Copyright (C) 2013-2022, Filipe Brandao\n"); 17 | setvbuf(stdout, NULL, _IONBF, 0); 18 | if (argc < 3 || argc > 5) { 19 | printf("Usage: vbpsol graph.afg vars.sol " 20 | "[print_instance:0] [pyout:0]\n"); 21 | return 1; 22 | } 23 | FILE *fsol = NULL; 24 | try { 25 | throw_assert(check_ext(argv[1], ".afg")); 26 | Arcflow afg(argv[1]); 27 | Instance &inst = afg.inst; 28 | 29 | fsol = fopen(argv[2], "r"); 30 | if (fsol == NULL) { 31 | perror("fopen"); 32 | } 33 | throw_assert(fsol != NULL); 34 | 35 | bool print_inst = false; 36 | if (argc >= 4) { 37 | print_inst = atoi(argv[3]) != 0; 38 | } 39 | bool pyout = false; 40 | if (argc >= 5) { 41 | pyout = atoi(argv[4]) != 0; 42 | } 43 | 44 | int ind; 45 | double x; 46 | char buf[MAX_LEN]; 47 | std::map flow; 48 | while (fscanf(fsol, "%s %lf", buf, &x) != EOF) { 49 | if (strlen(buf) <= 1) { 50 | continue; 51 | } 52 | if (buf[0] == 'X') { 53 | sscanf(&buf[1], "%x", &ind); 54 | } else { 55 | sscanf(&buf[0], "%d", &ind); 56 | } 57 | throw_assert(ind < afg.NA); 58 | int rx = static_cast(round(x)); 59 | throw_assert(x - rx <= EPS); 60 | if (rx > 0) { 61 | flow[afg.A[ind]] = rx; 62 | } 63 | } 64 | fclose(fsol); 65 | 66 | ArcflowSol sol(inst, flow, afg.S, afg.Ts, afg.LOSS); 67 | sol.print_solution(print_inst, pyout); 68 | return 0; 69 | } catch (const std::runtime_error &e) { 70 | if (fsol != NULL) { 71 | fclose(fsol); 72 | } 73 | printf("%s\n", e.what()); 74 | return 1; 75 | } catch (...) { 76 | if (fsol != NULL) { 77 | fclose(fsol); 78 | } 79 | printf("UnknownError\n"); 80 | return 1; 81 | } 82 | } 83 | 84 | int main(int argc, char *argv[]) { 85 | return swig_main(argc, argv); 86 | } 87 | -------------------------------------------------------------------------------- /src/vpsolver.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | This code is part of the Arc-flow Vector Packing Solver (VPSolver). 3 | **/ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "gurobi_c++.h" 11 | #include "config.hpp" 12 | #include "common.hpp" 13 | #include "instance.hpp" 14 | #include "arcflow.hpp" 15 | #include "arcflowsol.hpp" 16 | 17 | void solve(const Instance &inst, bool print_inst = false, bool pyout = false) { 18 | Arcflow afg(inst); 19 | char vtype = inst.vtype; 20 | GRBEnv env = GRBEnv(); 21 | GRBModel model = GRBModel(env); 22 | model.set(GRB_StringAttr_ModelName, "flow"); 23 | 24 | model.getEnv().set(GRB_IntParam_OutputFlag, 1); 25 | model.getEnv().set(GRB_IntParam_Threads, 1); 26 | model.getEnv().set(GRB_IntParam_Presolve, 1); 27 | // model.getEnv().set(GRB_IntParam_Method, 0); 28 | model.getEnv().set(GRB_IntParam_Method, 2); 29 | model.getEnv().set(GRB_IntParam_MIPFocus, 1); 30 | // model.getEnv().set(GRB_IntParam_RINS, 1); 31 | model.getEnv().set(GRB_DoubleParam_Heuristics, 1); 32 | model.getEnv().set(GRB_DoubleParam_MIPGap, 0); 33 | model.getEnv().set(GRB_DoubleParam_MIPGapAbs, 1 - 1e-5); 34 | // model.getEnv().set(GRB_DoubleParam_ImproveStartTime, 60); 35 | // model.getEnv().set(GRB_DoubleParam_ImproveStartGap, 1); 36 | 37 | std::vector As(afg.A); 38 | std::sort(all(As)); 39 | std::map va; 40 | int lastv = afg.Ts[0] - 1; 41 | for (int i = 0; i < inst.nbtypes; i++) { 42 | lastv = std::min(lastv, afg.Ts[i] - 1); 43 | } 44 | for (int i = 0; i < 3; i++) { 45 | for (const Arc &a : As) { 46 | if (i == 1 && a.u != afg.S) { 47 | continue; 48 | } else if (i == 2 && a.v <= lastv) { 49 | continue; 50 | } else if (i == 0 && (a.u == afg.S || a.v > lastv)) { 51 | continue; 52 | } 53 | 54 | if (a.label == afg.LOSS || inst.relax_domains) { 55 | va[a] = model.addVar( 56 | 0.0, inst.n, 0, vtype); 57 | } else { 58 | va[a] = model.addVar( 59 | 0.0, inst.items[a.label].demand, 0, vtype); 60 | } 61 | } 62 | } 63 | model.update(); 64 | 65 | for (int i = 0; i < inst.nbtypes; i++) { 66 | GRBVar &feedback = va[Arc(afg.Ts[i], afg.S, afg.LOSS)]; 67 | feedback.set(GRB_DoubleAttr_Obj, inst.Cs[i]); 68 | if (inst.Qs[i] >= 0) { 69 | feedback.set(GRB_DoubleAttr_UB, inst.Qs[i]); 70 | } 71 | } 72 | 73 | std::vector > Al(inst.nsizes); 74 | std::vector > in(afg.NV); 75 | std::vector > out(afg.NV); 76 | 77 | for (const Arc &a : As) { 78 | if (a.label != afg.LOSS) { 79 | Al[a.label].push_back(a); 80 | } 81 | out[a.u].push_back(a); 82 | in[a.v].push_back(a); 83 | } 84 | 85 | for (int i = 0; i < inst.m; i++) { 86 | GRBLinExpr lin = 0; 87 | for (int it = 0; it < inst.nsizes; it++) { 88 | if (inst.items[it].type == i) { 89 | for (const Arc &a : Al[it]) { 90 | lin += va[a]; 91 | } 92 | } 93 | } 94 | if (inst.ctypes[i] == '>' || inst.relax_domains) { 95 | model.addConstr(lin >= inst.demands[i]); 96 | } else { 97 | model.addConstr(lin == inst.demands[i]); 98 | } 99 | } 100 | 101 | for (int u = 0; u < afg.NV; u++) { 102 | GRBLinExpr lin = 0; 103 | for (const Arc &a : in[u]) { 104 | lin += va[a]; 105 | } 106 | for (const Arc &a : out[u]) { 107 | lin -= va[a]; 108 | } 109 | model.addConstr(lin == 0); 110 | } 111 | 112 | Al.clear(); 113 | in.clear(); 114 | out.clear(); 115 | 116 | double pre = TIMEDIF(afg.tstart); 117 | model.optimize(); 118 | printf("Preprocessing time: %.2f seconds\n", pre); 119 | double tg = model.get(GRB_DoubleAttr_Runtime); 120 | printf("Gurobi run time: %.2f seconds\n", tg); 121 | printf("Total run time: %.2f seconds\n", tg + pre); 122 | 123 | if (inst.vtype == 'I') { 124 | std::map flow; 125 | for (const auto &a : va) { 126 | double x = a.second.get(GRB_DoubleAttr_X); 127 | int rx = static_cast(round(x)); 128 | assert(x - rx <= EPS); 129 | if (rx > 0) { 130 | int u = a.first.u; 131 | int v = a.first.v; 132 | int lbl = a.first.label; 133 | Arc a(u, v, lbl); 134 | flow[a] = rx; 135 | } 136 | } 137 | ArcflowSol solution(inst, flow, afg.S, afg.Ts, afg.LOSS); 138 | solution.print_solution(print_inst, pyout); 139 | } 140 | } 141 | 142 | int main(int argc, char *argv[]) { 143 | printf(PACKAGE_STRING", Copyright (C) 2013-2022, Filipe Brandao\n"); 144 | setvbuf(stdout, NULL, _IONBF, 0); 145 | if (argc < 2 || argc > 7) { 146 | printf("Usage: vpsolver instance.vbp/instance.mvp " 147 | "[method:-3] [binary:0] [vtype:I] " 148 | "[print_instance:0] [pyout:0]\n"); 149 | return 1; 150 | } 151 | try { 152 | Instance inst(argv[1]); 153 | if (argc >= 3) { 154 | inst.method = atoi(argv[2]); 155 | throw_assert(inst.method >= MIN_METHOD && 156 | inst.method <= MAX_METHOD); 157 | } 158 | if (argc >= 4) { 159 | int value = atoi(argv[3]); 160 | if (value >= 0) { 161 | inst.binary = value; 162 | } 163 | } 164 | if (argc >= 5) { 165 | inst.vtype = argv[4][0]; 166 | throw_assert(inst.vtype == 'I' || inst.vtype == 'C'); 167 | } 168 | bool print_inst = false; 169 | if (argc >= 6) { 170 | print_inst = atoi(argv[5]) != 0; 171 | } 172 | bool pyout = false; 173 | if (argc >= 7) { 174 | pyout = atoi(argv[6]) != 0; 175 | } 176 | solve(inst, print_inst, pyout); 177 | return 0; 178 | } catch (GRBException e) { 179 | printf("Error code = %d\n", e.getErrorCode()); 180 | printf("GurobiError: %s\n", e.getMessage().c_str()); 181 | return 1; 182 | } catch (const std::runtime_error &e) { 183 | printf("%s\n", e.what()); 184 | return 1; 185 | } catch (...) { 186 | printf("UnknownError\n"); 187 | return 1; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /swig/afg2ampl.i: -------------------------------------------------------------------------------- 1 | %module afg2ampl 2 | 3 | // http://www.swig.org/Doc1.3/Python.html#Python_nn59 4 | // This tells SWIG to treat char ** as a special case 5 | %typemap(in) char ** { 6 | /* Check if is a list */ 7 | if (PyList_Check($input)) { 8 | int size = PyList_Size($input); 9 | int i = 0; 10 | $1 = (char **) malloc((size+1)*sizeof(char *)); 11 | for (i = 0; i < size; i++) { 12 | PyObject *o = PyList_GetItem($input, i); 13 | if (PyString_Check(o)) 14 | $1[i] = PyString_AsString(PyList_GetItem($input, i)); 15 | else { 16 | PyErr_SetString(PyExc_TypeError, "list must contain strings"); 17 | free($1); 18 | return NULL; 19 | } 20 | } 21 | $1[i] = 0; 22 | } else { 23 | PyErr_SetString(PyExc_TypeError, "not a list"); 24 | return NULL; 25 | } 26 | } 27 | 28 | // This cleans up the char ** array we malloc'd before the function call 29 | %typemap(freearg) char ** { 30 | free((char *) $1); 31 | } 32 | 33 | %{ 34 | /* Put header files here or function declarations like below */ 35 | extern int swig_main(int argc, char **argv); 36 | %} 37 | 38 | extern int swig_main(int argc, char **argv); 39 | -------------------------------------------------------------------------------- /swig/afg2ampl.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 4.0.2 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info < (2, 7, 0): 9 | raise RuntimeError("Python 2.7 or later required") 10 | 11 | # Pull in all the attributes from the low-level C/C++ module 12 | if __package__ or "." in __name__: 13 | from ._afg2ampl import * 14 | else: 15 | from _afg2ampl import * 16 | 17 | try: 18 | import builtins as __builtin__ 19 | except ImportError: 20 | import __builtin__ 21 | 22 | def _swig_repr(self): 23 | try: 24 | strthis = "proxy of " + self.this.__repr__() 25 | except __builtin__.Exception: 26 | strthis = "" 27 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 28 | 29 | 30 | def _swig_setattr_nondynamic_instance_variable(set): 31 | def set_instance_attr(self, name, value): 32 | if name == "thisown": 33 | self.this.own(value) 34 | elif name == "this": 35 | set(self, name, value) 36 | elif hasattr(self, name) and isinstance(getattr(type(self), name), property): 37 | set(self, name, value) 38 | else: 39 | raise AttributeError("You cannot add instance attributes to %s" % self) 40 | return set_instance_attr 41 | 42 | 43 | def _swig_setattr_nondynamic_class_variable(set): 44 | def set_class_attr(cls, name, value): 45 | if hasattr(cls, name) and not isinstance(getattr(cls, name), property): 46 | set(cls, name, value) 47 | else: 48 | raise AttributeError("You cannot add class attributes to %s" % cls) 49 | return set_class_attr 50 | 51 | 52 | def _swig_add_metaclass(metaclass): 53 | """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass""" 54 | def wrapper(cls): 55 | return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy()) 56 | return wrapper 57 | 58 | 59 | class _SwigNonDynamicMeta(type): 60 | """Meta class to enforce nondynamic attributes (no new attributes) for a class""" 61 | __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__) 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /swig/afg2lp.i: -------------------------------------------------------------------------------- 1 | %module afg2lp 2 | 3 | // http://www.swig.org/Doc1.3/Python.html#Python_nn59 4 | // This tells SWIG to treat char ** as a special case 5 | %typemap(in) char ** { 6 | /* Check if is a list */ 7 | if (PyList_Check($input)) { 8 | int size = PyList_Size($input); 9 | int i = 0; 10 | $1 = (char **) malloc((size+1)*sizeof(char *)); 11 | for (i = 0; i < size; i++) { 12 | PyObject *o = PyList_GetItem($input, i); 13 | if (PyString_Check(o)) 14 | $1[i] = PyString_AsString(PyList_GetItem($input, i)); 15 | else { 16 | PyErr_SetString(PyExc_TypeError, "list must contain strings"); 17 | free($1); 18 | return NULL; 19 | } 20 | } 21 | $1[i] = 0; 22 | } else { 23 | PyErr_SetString(PyExc_TypeError, "not a list"); 24 | return NULL; 25 | } 26 | } 27 | 28 | // This cleans up the char ** array we malloc'd before the function call 29 | %typemap(freearg) char ** { 30 | free((char *) $1); 31 | } 32 | 33 | %{ 34 | /* Put header files here or function declarations like below */ 35 | extern int swig_main(int argc, char **argv); 36 | %} 37 | 38 | extern int swig_main(int argc, char **argv); 39 | -------------------------------------------------------------------------------- /swig/afg2lp.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 4.0.2 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info < (2, 7, 0): 9 | raise RuntimeError("Python 2.7 or later required") 10 | 11 | # Pull in all the attributes from the low-level C/C++ module 12 | if __package__ or "." in __name__: 13 | from ._afg2lp import * 14 | else: 15 | from _afg2lp import * 16 | 17 | try: 18 | import builtins as __builtin__ 19 | except ImportError: 20 | import __builtin__ 21 | 22 | def _swig_repr(self): 23 | try: 24 | strthis = "proxy of " + self.this.__repr__() 25 | except __builtin__.Exception: 26 | strthis = "" 27 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 28 | 29 | 30 | def _swig_setattr_nondynamic_instance_variable(set): 31 | def set_instance_attr(self, name, value): 32 | if name == "thisown": 33 | self.this.own(value) 34 | elif name == "this": 35 | set(self, name, value) 36 | elif hasattr(self, name) and isinstance(getattr(type(self), name), property): 37 | set(self, name, value) 38 | else: 39 | raise AttributeError("You cannot add instance attributes to %s" % self) 40 | return set_instance_attr 41 | 42 | 43 | def _swig_setattr_nondynamic_class_variable(set): 44 | def set_class_attr(cls, name, value): 45 | if hasattr(cls, name) and not isinstance(getattr(cls, name), property): 46 | set(cls, name, value) 47 | else: 48 | raise AttributeError("You cannot add class attributes to %s" % cls) 49 | return set_class_attr 50 | 51 | 52 | def _swig_add_metaclass(metaclass): 53 | """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass""" 54 | def wrapper(cls): 55 | return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy()) 56 | return wrapper 57 | 58 | 59 | class _SwigNonDynamicMeta(type): 60 | """Meta class to enforce nondynamic attributes (no new attributes) for a class""" 61 | __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__) 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /swig/afg2mps.i: -------------------------------------------------------------------------------- 1 | %module afg2mps 2 | 3 | // http://www.swig.org/Doc1.3/Python.html#Python_nn59 4 | // This tells SWIG to treat char ** as a special case 5 | %typemap(in) char ** { 6 | /* Check if is a list */ 7 | if (PyList_Check($input)) { 8 | int size = PyList_Size($input); 9 | int i = 0; 10 | $1 = (char **) malloc((size+1)*sizeof(char *)); 11 | for (i = 0; i < size; i++) { 12 | PyObject *o = PyList_GetItem($input, i); 13 | if (PyString_Check(o)) 14 | $1[i] = PyString_AsString(PyList_GetItem($input, i)); 15 | else { 16 | PyErr_SetString(PyExc_TypeError, "list must contain strings"); 17 | free($1); 18 | return NULL; 19 | } 20 | } 21 | $1[i] = 0; 22 | } else { 23 | PyErr_SetString(PyExc_TypeError, "not a list"); 24 | return NULL; 25 | } 26 | } 27 | 28 | // This cleans up the char ** array we malloc'd before the function call 29 | %typemap(freearg) char ** { 30 | free((char *) $1); 31 | } 32 | 33 | %{ 34 | /* Put header files here or function declarations like below */ 35 | extern int swig_main(int argc, char **argv); 36 | %} 37 | 38 | extern int swig_main(int argc, char **argv); 39 | -------------------------------------------------------------------------------- /swig/afg2mps.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 4.0.2 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info < (2, 7, 0): 9 | raise RuntimeError("Python 2.7 or later required") 10 | 11 | # Pull in all the attributes from the low-level C/C++ module 12 | if __package__ or "." in __name__: 13 | from ._afg2mps import * 14 | else: 15 | from _afg2mps import * 16 | 17 | try: 18 | import builtins as __builtin__ 19 | except ImportError: 20 | import __builtin__ 21 | 22 | def _swig_repr(self): 23 | try: 24 | strthis = "proxy of " + self.this.__repr__() 25 | except __builtin__.Exception: 26 | strthis = "" 27 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 28 | 29 | 30 | def _swig_setattr_nondynamic_instance_variable(set): 31 | def set_instance_attr(self, name, value): 32 | if name == "thisown": 33 | self.this.own(value) 34 | elif name == "this": 35 | set(self, name, value) 36 | elif hasattr(self, name) and isinstance(getattr(type(self), name), property): 37 | set(self, name, value) 38 | else: 39 | raise AttributeError("You cannot add instance attributes to %s" % self) 40 | return set_instance_attr 41 | 42 | 43 | def _swig_setattr_nondynamic_class_variable(set): 44 | def set_class_attr(cls, name, value): 45 | if hasattr(cls, name) and not isinstance(getattr(cls, name), property): 46 | set(cls, name, value) 47 | else: 48 | raise AttributeError("You cannot add class attributes to %s" % cls) 49 | return set_class_attr 50 | 51 | 52 | def _swig_add_metaclass(metaclass): 53 | """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass""" 54 | def wrapper(cls): 55 | return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy()) 56 | return wrapper 57 | 58 | 59 | class _SwigNonDynamicMeta(type): 60 | """Meta class to enforce nondynamic attributes (no new attributes) for a class""" 61 | __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__) 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /swig/vbp2afg.i: -------------------------------------------------------------------------------- 1 | %module vbp2afg 2 | 3 | // http://www.swig.org/Doc1.3/Python.html#Python_nn59 4 | // This tells SWIG to treat char ** as a special case 5 | %typemap(in) char ** { 6 | /* Check if is a list */ 7 | if (PyList_Check($input)) { 8 | int size = PyList_Size($input); 9 | int i = 0; 10 | $1 = (char **) malloc((size+1)*sizeof(char *)); 11 | for (i = 0; i < size; i++) { 12 | PyObject *o = PyList_GetItem($input, i); 13 | if (PyString_Check(o)) 14 | $1[i] = PyString_AsString(PyList_GetItem($input, i)); 15 | else { 16 | PyErr_SetString(PyExc_TypeError, "list must contain strings"); 17 | free($1); 18 | return NULL; 19 | } 20 | } 21 | $1[i] = 0; 22 | } else { 23 | PyErr_SetString(PyExc_TypeError, "not a list"); 24 | return NULL; 25 | } 26 | } 27 | 28 | // This cleans up the char ** array we malloc'd before the function call 29 | %typemap(freearg) char ** { 30 | free((char *) $1); 31 | } 32 | 33 | %{ 34 | /* Put header files here or function declarations like below */ 35 | extern int swig_main(int argc, char **argv); 36 | %} 37 | 38 | extern int swig_main(int argc, char **argv); 39 | -------------------------------------------------------------------------------- /swig/vbp2afg.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 4.0.2 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info < (2, 7, 0): 9 | raise RuntimeError("Python 2.7 or later required") 10 | 11 | # Pull in all the attributes from the low-level C/C++ module 12 | if __package__ or "." in __name__: 13 | from ._vbp2afg import * 14 | else: 15 | from _vbp2afg import * 16 | 17 | try: 18 | import builtins as __builtin__ 19 | except ImportError: 20 | import __builtin__ 21 | 22 | def _swig_repr(self): 23 | try: 24 | strthis = "proxy of " + self.this.__repr__() 25 | except __builtin__.Exception: 26 | strthis = "" 27 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 28 | 29 | 30 | def _swig_setattr_nondynamic_instance_variable(set): 31 | def set_instance_attr(self, name, value): 32 | if name == "thisown": 33 | self.this.own(value) 34 | elif name == "this": 35 | set(self, name, value) 36 | elif hasattr(self, name) and isinstance(getattr(type(self), name), property): 37 | set(self, name, value) 38 | else: 39 | raise AttributeError("You cannot add instance attributes to %s" % self) 40 | return set_instance_attr 41 | 42 | 43 | def _swig_setattr_nondynamic_class_variable(set): 44 | def set_class_attr(cls, name, value): 45 | if hasattr(cls, name) and not isinstance(getattr(cls, name), property): 46 | set(cls, name, value) 47 | else: 48 | raise AttributeError("You cannot add class attributes to %s" % cls) 49 | return set_class_attr 50 | 51 | 52 | def _swig_add_metaclass(metaclass): 53 | """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass""" 54 | def wrapper(cls): 55 | return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy()) 56 | return wrapper 57 | 58 | 59 | class _SwigNonDynamicMeta(type): 60 | """Meta class to enforce nondynamic attributes (no new attributes) for a class""" 61 | __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__) 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /swig/vbpsol.i: -------------------------------------------------------------------------------- 1 | %module vbpsol 2 | 3 | // http://www.swig.org/Doc1.3/Python.html#Python_nn59 4 | // This tells SWIG to treat char ** as a special case 5 | %typemap(in) char ** { 6 | /* Check if is a list */ 7 | if (PyList_Check($input)) { 8 | int size = PyList_Size($input); 9 | int i = 0; 10 | $1 = (char **) malloc((size+1)*sizeof(char *)); 11 | for (i = 0; i < size; i++) { 12 | PyObject *o = PyList_GetItem($input, i); 13 | if (PyString_Check(o)) 14 | $1[i] = PyString_AsString(PyList_GetItem($input, i)); 15 | else { 16 | PyErr_SetString(PyExc_TypeError, "list must contain strings"); 17 | free($1); 18 | return NULL; 19 | } 20 | } 21 | $1[i] = 0; 22 | } else { 23 | PyErr_SetString(PyExc_TypeError, "not a list"); 24 | return NULL; 25 | } 26 | } 27 | 28 | // This cleans up the char ** array we malloc'd before the function call 29 | %typemap(freearg) char ** { 30 | free((char *) $1); 31 | } 32 | 33 | %{ 34 | /* Put header files here or function declarations like below */ 35 | extern int swig_main(int argc, char **argv); 36 | %} 37 | 38 | extern int swig_main(int argc, char **argv); 39 | -------------------------------------------------------------------------------- /swig/vbpsol.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 4.0.2 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info < (2, 7, 0): 9 | raise RuntimeError("Python 2.7 or later required") 10 | 11 | # Pull in all the attributes from the low-level C/C++ module 12 | if __package__ or "." in __name__: 13 | from ._vbpsol import * 14 | else: 15 | from _vbpsol import * 16 | 17 | try: 18 | import builtins as __builtin__ 19 | except ImportError: 20 | import __builtin__ 21 | 22 | def _swig_repr(self): 23 | try: 24 | strthis = "proxy of " + self.this.__repr__() 25 | except __builtin__.Exception: 26 | strthis = "" 27 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 28 | 29 | 30 | def _swig_setattr_nondynamic_instance_variable(set): 31 | def set_instance_attr(self, name, value): 32 | if name == "thisown": 33 | self.this.own(value) 34 | elif name == "this": 35 | set(self, name, value) 36 | elif hasattr(self, name) and isinstance(getattr(type(self), name), property): 37 | set(self, name, value) 38 | else: 39 | raise AttributeError("You cannot add instance attributes to %s" % self) 40 | return set_instance_attr 41 | 42 | 43 | def _swig_setattr_nondynamic_class_variable(set): 44 | def set_class_attr(cls, name, value): 45 | if hasattr(cls, name) and not isinstance(getattr(cls, name), property): 46 | set(cls, name, value) 47 | else: 48 | raise AttributeError("You cannot add class attributes to %s" % cls) 49 | return set_class_attr 50 | 51 | 52 | def _swig_add_metaclass(metaclass): 53 | """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass""" 54 | def wrapper(cls): 55 | return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy()) 56 | return wrapper 57 | 58 | 59 | class _SwigNonDynamicMeta(type): 60 | """Meta class to enforce nondynamic attributes (no new attributes) for a class""" 61 | __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__) 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /virtualenv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BASEDIR=`dirname "$0"` 3 | cd $BASEDIR 4 | CMD="$0 $*" 5 | 6 | usage(){ 7 | echo -e "Usage:" 8 | echo -e " $0 --venv venv_dir [-p python_exe]" 9 | } 10 | 11 | error(){ 12 | echo "Command line: "$CMD 13 | echo "Error: invalid arguments." 14 | usage 15 | exit 1 16 | } 17 | 18 | pyexec=""; 19 | venv="venv"; 20 | 21 | while true; 22 | do 23 | case "$1" in 24 | -p) 25 | if [[ -n "$2" ]]; then pyexec=$2; else error; fi 26 | shift 2;; 27 | --venv) 28 | if [[ -n "$2" ]]; then venv=$2; else error; fi 29 | shift 2;; 30 | *) 31 | if [[ -n "$1" ]]; then error; else break; fi 32 | esac 33 | done 34 | 35 | if [[ -z "$venv" ]]; then 36 | error 37 | fi 38 | 39 | if [[ -n "$pyexec" ]]; then 40 | virtualenv --system-site-packages -p $pyexec $venv || exit 1; 41 | else 42 | virtualenv --system-site-packages $venv || exit 1; 43 | fi 44 | 45 | rm -rf build *.egg-info 46 | source $venv/bin/activate || exit 1 47 | python --version || exit 1 48 | pip install --upgrade --ignore-installed -r requirements.txt || exit 1 49 | pip install --upgrade --ignore-installed --pre pympl || exit 1 50 | pip install --upgrade --ignore-installed --no-deps . || exit 1 51 | cd examples || exit 1 52 | py.test -v --cov pyvpsolver || exit 1 53 | deactivate || exit 1 54 | -------------------------------------------------------------------------------- /webapp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BASEDIR=`dirname "$0"` 3 | cd $BASEDIR 4 | CMD="$0 $*" 5 | 6 | usage(){ 7 | echo -e "Usage:" 8 | echo -e " $0 [--venv venv_dir] [--port app_port]" 9 | } 10 | 11 | error(){ 12 | echo "Command line: "$CMD 13 | echo "Error: invalid arguments." 14 | usage 15 | exit 1 16 | } 17 | 18 | venv="" 19 | port=5555 20 | 21 | while true; 22 | do 23 | case "$1" in 24 | --venv) 25 | if [[ -n "$2" ]]; then venv=$2; else error; fi 26 | shift 2;; 27 | --port) 28 | if [[ -n "$2" ]]; then port=$2; else error; fi 29 | shift 2;; 30 | *) 31 | if [[ -n "$1" ]]; then error; else break; fi 32 | esac 33 | done 34 | 35 | if [[ -n "$venv" ]]; then 36 | source $venv/bin/activate; 37 | fi; 38 | 39 | ifconfig eth0 || exit 1 40 | python --version || exit 1 41 | python -m pyvpsolver.webapp.app $port || exit 1 42 | --------------------------------------------------------------------------------