├── .gitignore ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── cmake └── FindGUROBI.cmake ├── include ├── callback │ └── callback_sec.hpp ├── config_parameters.hpp ├── ext │ ├── cvrpsep │ │ ├── basegrph.h │ │ ├── capsep.h │ │ ├── cnstrmgr.h │ │ ├── compcuts.h │ │ ├── compress.h │ │ ├── cutbase.h │ │ ├── fcapfix.h │ │ ├── grsearch.h │ │ ├── memmod.h │ │ ├── mxf.h │ │ ├── sort.h │ │ └── strngcmp.h │ └── loguru │ │ └── loguru.hpp ├── init_grb_model.hpp ├── instance.hpp ├── irp_lp.hpp └── utils │ └── constants.hpp ├── input ├── .gitignore ├── example.cfg └── instances │ ├── abs1n5.dat │ └── abs2n5.dat └── src ├── callback ├── callback_sec.cpp └── cuts │ └── cvrpsep.cpp ├── config_parameters.cpp ├── ext ├── cvrpsep │ ├── basegrph.cpp │ ├── capsep.cpp │ ├── cnstrmgr.cpp │ ├── compcuts.cpp │ ├── compress.cpp │ ├── cutbase.cpp │ ├── fcapfix.cpp │ ├── grsearch.cpp │ ├── memmod.cpp │ ├── mxf.cpp │ ├── sort.cpp │ └── strngcmp.cpp └── loguru │ └── loguru.cpp ├── init_grb_model.cpp ├── instance.cpp ├── irp_lp.cpp └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore vscode dir 2 | Makefile 3 | .vscode/ 4 | *.o 5 | *.a 6 | *.sh 7 | *.lp 8 | *.bas 9 | *.out 10 | *.zip 11 | *.log 12 | /build/ 13 | /bin/ 14 | /output/ 15 | .VSCodeCounter/ 16 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # To build on Linux/macOS: 2 | # cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release [Debug] 3 | # cmake --build build 4 | 5 | cmake_minimum_required(VERSION 3.08) 6 | 7 | # set the project name and version 8 | project(bc_irp VERSION 0.5.1) 9 | 10 | option(CXX "enable C++ compilation" ON) 11 | 12 | if(NOT CMAKE_BUILD_TYPE) 13 | set(CMAKE_BUILD_TYPE "Release") 14 | endif(NOT CMAKE_BUILD_TYPE) 15 | 16 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 17 | 18 | include_directories(${PROJECT_SOURCE_DIR}/headers) 19 | 20 | # specify the C++ standard 21 | set(CMAKE_CXX_STANDARD 17) 22 | set(CMAKE_CXX_STANDARD_REQUIRED True) 23 | 24 | # compiler flags 25 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -Wno-deprecated-copy -pedantic-errors") 26 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g") 27 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG") 28 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fopenmp") 29 | 30 | # determine the Gurobi's necessary include and linker commands 31 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 32 | find_package(GUROBI REQUIRED) 33 | include_directories(${GUROBI_INCLUDE_DIRS}) 34 | 35 | # list all source files here 36 | set(SOURCES 37 | src/main.cpp 38 | src/config_parameters.cpp 39 | src/init_grb_model.cpp 40 | src/instance.cpp 41 | src/irp_lp.cpp 42 | src/callback/callback_sec.cpp 43 | src/callback/cuts/cvrpsep.cpp 44 | src/ext/loguru/loguru.cpp 45 | src/ext/cvrpsep/basegrph.cpp 46 | src/ext/cvrpsep/capsep.cpp 47 | src/ext/cvrpsep/cnstrmgr.cpp 48 | src/ext/cvrpsep/compcuts.cpp 49 | src/ext/cvrpsep/compress.cpp 50 | src/ext/cvrpsep/cutbase.cpp 51 | src/ext/cvrpsep/fcapfix.cpp 52 | src/ext/cvrpsep/grsearch.cpp 53 | src/ext/cvrpsep/memmod.cpp 54 | src/ext/cvrpsep/mxf.cpp 55 | src/ext/cvrpsep/sort.cpp 56 | src/ext/cvrpsep/strngcmp.cpp) 57 | 58 | # list all header files here 59 | set(HEADERS 60 | include/config_parameters.hpp 61 | include/init_grb_model.hpp 62 | include/instance.hpp 63 | include/irp_lp.hpp 64 | include/callback/callback_sec.hpp 65 | include/utils/constants.hpp 66 | include/ext/loguru/loguru.hpp 67 | include/ext/cvrpsep/basegrph.h 68 | include/ext/cvrpsep/capsep.h 69 | include/ext/cvrpsep/cnstrmgr.h 70 | include/ext/cvrpsep/compcuts.h 71 | include/ext/cvrpsep/compress.h 72 | include/ext/cvrpsep/cutbase.h 73 | include/ext/cvrpsep/fcapfix.h 74 | include/ext/cvrpsep/grsearch.h 75 | include/ext/cvrpsep/memmod.h 76 | include/ext/cvrpsep/mxf.h 77 | include/ext/cvrpsep/sort.h 78 | include/ext/cvrpsep/strngcmp.h) 79 | 80 | # add the executable 81 | add_executable(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS}) 82 | 83 | target_link_libraries(${CMAKE_PROJECT_NAME} optimized ${GUROBI_CXX_LIBRARY} debug ${GUROBI_CXX_DEBUG_LIBRARY}) 84 | target_link_libraries(${CMAKE_PROJECT_NAME} ${GUROBI_LIBRARY}) 85 | target_link_libraries(${CMAKE_PROJECT_NAME} dl) # for fix -ldl linker error -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inventory-routing problem (IRP) branch-and-cut algorithm using CVRPSEP package 2 | 3 | A C++ implementation of an IRP [[1](#references)] branch-and-cut algorithm using Gurobi's API and CVRPSEP package [[2](#references)]. 4 | 5 | ## Prerequisites 6 | 7 | * CMake. 8 | 9 | * C++17 compiler or an early version. 10 | 11 | * GUROBI solver (9 or an early version). Academics can obtain it via this [link](https://www.gurobi.com/downloads/gurobi-optimizer-eula/#Reg "Gurobi's register page"). 12 | 13 | ## Compile and run instructions 14 | 15 | Go to the source code folder and to compile type: 16 | 17 | ```sh 18 | cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug 19 | cmake --build build 20 | ``` 21 | 22 | for the debug version or simply 23 | 24 | ```sh 25 | cmake -H. -Bbuild 26 | cmake --build build 27 | ``` 28 | 29 | for the release version. 30 | 31 | To run with a configuration file: 32 | 33 | ```sh 34 | $ ./build/irp_solver -f [configuration file path] 35 | ``` 36 | 37 | See the "example.cfg" file at the "input" folder for an example of the input configuration file. 38 | 39 | ## References 40 | 41 | **[\[1\] C. Archetti, L. Bertazzi, G. Laporte and M. G. Speranza. A Branch-and-Cut Algorithm for a Vendor-Managed Inventory-Routing Problem Transportation Science, 41(3), 2007, pp. 382-391.](https://pubsonline.informs.org/doi/10.1287/trsc.1060.0188)** 42 | 43 | **[\[2\] J. Lysgaard, A.N. Letchford and R.W. Eglese. A New Branch-and-Cut Algorithm for the Capacitated Vehicle Routing Problem, Mathematical Programming, vol. 100 (2), pp. 423-445](https://pubsonline.informs.org/doi/10.1287/trsc.1060.0188)** -------------------------------------------------------------------------------- /cmake/FindGUROBI.cmake: -------------------------------------------------------------------------------- 1 | # from https://bit.ly/3gFm0Ms 2 | 3 | find_path(GUROBI_INCLUDE_DIRS 4 | NAMES gurobi_c.h 5 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 6 | PATH_SUFFIXES include) 7 | 8 | find_library(GUROBI_LIBRARY 9 | NAMES gurobi gurobi81 gurobi90 gurobi91 10 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 11 | PATH_SUFFIXES lib) 12 | 13 | if(CXX) 14 | if(MSVC) 15 | # determine Visual Studio year 16 | if(MSVC_TOOLSET_VERSION EQUAL 142) 17 | set(MSVC_YEAR "2019") 18 | elseif(MSVC_TOOLSET_VERSION EQUAL 141) 19 | set(MSVC_YEAR "2017") 20 | elseif(MSVC_TOOLSET_VERSION EQUAL 140) 21 | set(MSVC_YEAR "2015") 22 | endif() 23 | 24 | if(MT) 25 | set(M_FLAG "mt") 26 | else() 27 | set(M_FLAG "md") 28 | endif() 29 | 30 | find_library(GUROBI_CXX_LIBRARY 31 | NAMES gurobi_c++${M_FLAG}${MSVC_YEAR} 32 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 33 | PATH_SUFFIXES lib) 34 | find_library(GUROBI_CXX_DEBUG_LIBRARY 35 | NAMES gurobi_c++${M_FLAG}d${MSVC_YEAR} 36 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 37 | PATH_SUFFIXES lib) 38 | else() 39 | find_library(GUROBI_CXX_LIBRARY 40 | NAMES gurobi_c++ 41 | HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} 42 | PATH_SUFFIXES lib) 43 | set(GUROBI_CXX_DEBUG_LIBRARY ${GUROBI_CXX_LIBRARY}) 44 | endif() 45 | endif() 46 | 47 | include(FindPackageHandleStandardArgs) 48 | find_package_handle_standard_args(GUROBI DEFAULT_MSG GUROBI_LIBRARY) 49 | -------------------------------------------------------------------------------- /include/callback/callback_sec.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: callback_sec.hpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Callback class declaration for lazy/cut subtour separation 7 | * constraints. 8 | * 9 | * (I'm sorry for my bad english xD) 10 | * 11 | * Created on November 15, 2020, 11:59 PM 12 | * 13 | * References: 14 | */ 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef CALLBACK_SEC_HPP 18 | #define CALLBACK_SEC_HPP 19 | 20 | #include 21 | 22 | #include "gurobi_c++.h" 23 | 24 | #include "../instance.hpp" 25 | 26 | class CallbackSEC : public GRBCallback 27 | { 28 | public: 29 | 30 | enum class constrsType {lazy, cut}; 31 | 32 | CallbackSEC(const CallbackSEC& other) = default; 33 | CallbackSEC(CallbackSEC&& other) = default; 34 | ~CallbackSEC() = default; 35 | 36 | CallbackSEC() = delete; 37 | CallbackSEC& operator=(const CallbackSEC& other) = delete; 38 | CallbackSEC& operator=(CallbackSEC&& other) = delete; 39 | 40 | CallbackSEC( 41 | const std::vector>>& q, 42 | const std::vector>>>& x, 43 | const std::vector>>& y, 44 | const std::shared_ptr& pInst); 45 | 46 | private: 47 | 48 | // quantities delivered to i by vehicle k at time t 49 | const std::vector>>& m_q; 50 | // equal to one if j immediately follows i in the route traveled at time t 51 | const std::vector>>>& m_x; 52 | // retailer i is served at time t 53 | const std::vector>>& m_y; 54 | 55 | std::shared_ptr mpInst; 56 | 57 | void callback() override; 58 | 59 | int addCVRPSEPCAP(const constrsType cstType); 60 | 61 | /** 62 | * @brief Retrieve the q variables values from the relaxation solution at 63 | * the current node. 64 | * @param: constraint type. 65 | * @return: q variables values at the current node. 66 | */ 67 | std::vector>> getqVarsValues( 68 | const constrsType cstType); 69 | 70 | /** 71 | * @brief Retrieve the x variables values from the relaxation solution at 72 | * the current node. 73 | * @param: constraint type. 74 | * @return: x variables values at the current node. 75 | */ 76 | std::vector>>> getxVarsValues( 77 | const constrsType cstType); 78 | 79 | /** 80 | * @brief Retrieve the y variables values from the relaxation solution at 81 | * the current node. 82 | * @param: constraint type. 83 | * @return: y variables values at the current node. 84 | */ 85 | std::vector>> getyVarsValues( 86 | const constrsType cstType); 87 | }; 88 | 89 | #endif // CALLBACK_SEC_HPP -------------------------------------------------------------------------------- /include/config_parameters.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: config_parameters.hpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Configuration input parameters class declartion 7 | * (see ./input/example.cfg). 8 | * 9 | * (I'm sorry for my bad english xD) 10 | * 11 | * Created on January 9, 2020, 11:58 PM 12 | * 13 | * References: 14 | */ 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef CONFIG_PARAMETERS_HPP 18 | #define CONFIG_PARAMETERS_HPP 19 | 20 | #include 21 | #include 22 | 23 | class ConfigParameters 24 | { 25 | public: 26 | 27 | /** 28 | * @brief Solver parameters. 29 | */ 30 | struct solver 31 | { 32 | bool show_log; // print output parameters 33 | std::size_t time_limit; // time limit of the solver 34 | std::size_t nb_threads; // # of threads used by solver 35 | std::string logFile_; 36 | }; 37 | 38 | struct model 39 | { 40 | enum policy_opt {ML, OU}; 41 | enum sec_opt {STD, CVRPSEP}; 42 | 43 | int K_; 44 | policy_opt policy; 45 | sec_opt sec_strategy; 46 | }; 47 | 48 | /** 49 | * @brief Default constructor, copy constructor, move constructor, 50 | * destructor, copy assingment operator and move assingment operator. 51 | */ 52 | ConfigParameters() = default; 53 | ConfigParameters(const ConfigParameters& other) = default; 54 | ConfigParameters(ConfigParameters&& other) = default; 55 | ~ConfigParameters() = default; 56 | ConfigParameters& operator=(const ConfigParameters& other) = default; 57 | ConfigParameters& operator=(ConfigParameters&& other) = default; 58 | 59 | /** 60 | * @brief Constructor from file. 61 | * @param const std::string&: configuration file path with values of all 62 | * parameters. 63 | */ 64 | ConfigParameters(const std::string config_path); 65 | 66 | /** 67 | * @brief Get the instance path. 68 | * @return {std::string}:. 69 | */ 70 | std::string getInstancePath() const; 71 | 72 | /** 73 | * @brief Get the default output folder path. 74 | * @return {std::string}:. 75 | */ 76 | std::string getOutputDir() const; 77 | 78 | /** 79 | * @brief. 80 | */ 81 | model getModelParams() const; 82 | 83 | /** 84 | * @brief. 85 | */ 86 | solver getSolverParams() const; 87 | 88 | /** 89 | * @brief. 90 | */ 91 | void setLogFilePath(const std::string& path); 92 | 93 | /** 94 | * @brief Prints instance value. 95 | */ 96 | void show() const; 97 | 98 | private: 99 | 100 | // Instance path (or instaces directory path) 101 | std::string mInstancePath; 102 | 103 | // Output folder path. 104 | std::string mOutputDir; 105 | 106 | // Model parameters 107 | ConfigParameters::model mModelParam; 108 | 109 | // Solver parameters 110 | ConfigParameters::solver mSolverParam; 111 | 112 | // Config_parameters values (from input file) mapping. 113 | std::map mData; 114 | 115 | /** 116 | * @brief Initializes the parameters. 117 | */ 118 | void setupParameters(); 119 | }; 120 | 121 | #endif // CONFIG_PARAMETERS_HPPs -------------------------------------------------------------------------------- /include/ext/cvrpsep/basegrph.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_BASEGRPH 6 | #define _H_BASEGRPH 7 | 8 | typedef struct 9 | { 10 | int CFN; /* Cardinality (number) of Forward Nodes */ 11 | int CBN; /* Cardinality (number) of Backward Nodes */ 12 | int FLD; /* Forward List Dimension (memory is allocated for records */ 13 | int BLD; /* Backward List Dimension (memory is allocated for records */ 14 | int *FAL; /* Forward Arc List */ 15 | int *BAL; /* Backward Arc List */ 16 | } ReachNodeRec; 17 | 18 | typedef struct 19 | { 20 | int n; 21 | ReachNodeRec *LP; /* List Pointer */ 22 | } ReachTopRec; 23 | 24 | typedef ReachTopRec *ReachPtr; 25 | 26 | typedef struct 27 | { 28 | int Row; 29 | int CFN; 30 | int *FAL; 31 | } CompFReachNodeRec; 32 | 33 | typedef struct 34 | { 35 | int NoOfRows; 36 | CompFReachNodeRec *FLP; 37 | } CompFReachRec; 38 | 39 | typedef CompFReachRec *CompFReachPtr; 40 | 41 | void WriteReachPtr(ReachPtr P); 42 | void ReachInitMem(ReachPtr *P, int n); 43 | void ReachPtrExpandDim(ReachPtr P, int NewN); 44 | void ReachClearLists(ReachPtr P); 45 | void ReachClearForwLists(ReachPtr P); 46 | void ReachSetForwList(ReachPtr P, int *ArcList, int Row, int Arcs); 47 | void ReachSetBackwList(ReachPtr P, int *ArcList, int Col, int Arcs); 48 | void ReachCreateInLists(ReachPtr P); 49 | void ReachAddArc(ReachPtr P, int Row, int Col); 50 | void ReachAddForwArc(ReachPtr P, int Row, int Col); 51 | void CopyReachPtr(ReachPtr SourcePtr, ReachPtr *SinkPtr); 52 | void ReachFreeMem(ReachPtr *P); 53 | void WriteCompPtr(CompFReachPtr P); 54 | void CopyReachPtrToCompPtr(ReachPtr SourcePtr, CompFReachPtr *SinkPtr); 55 | void CompFPtrFreeMem(CompFReachPtr *P); 56 | 57 | #endif 58 | 59 | -------------------------------------------------------------------------------- /include/ext/cvrpsep/capsep.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include "cnstrmgr.h" //Cleder (CnstrMgrPointer) 6 | #include "basegrph.h" //Cleder (ReachPtr) 7 | 8 | #ifndef _H_CAPSEP 9 | #define _H_CAPSEP 10 | 11 | void CAPSEP_GetOneVehicleCapCuts(CnstrMgrPointer CutsCMP, 12 | ReachPtr *RPtr, 13 | int *NoOfCuts); 14 | 15 | void CAPSEP_SeparateCapCuts(int NoOfCustomers, 16 | int *Demand, 17 | int CAP, 18 | int NoOfEdges, 19 | int *EdgeTail, 20 | int *EdgeHead, 21 | double *EdgeX, 22 | CnstrMgrPointer CMPExistingCuts, 23 | int MaxNoOfCuts, 24 | double EpsForIntegrality, 25 | char *IntegerAndFeasible, 26 | double *MaxViolation, 27 | CnstrMgrPointer CutsCMP); 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /include/ext/cvrpsep/cnstrmgr.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include //Cleder (FILE) 6 | 7 | #ifndef _H_CNSTRMGR 8 | #define _H_CNSTRMGR 9 | 10 | /* Definition of constants for identification of constraint types. */ 11 | 12 | #define CMGR_CT_MIN_ROUTES 101 13 | #define CMGR_CT_NODE_DEGREE 102 /* Degree = 2 for each customer. */ 14 | #define CMGR_CT_CAP 103 /* Capacity constraint. */ 15 | #define CMGR_CT_GENCAP 104 /* Generalized capacity constraint. */ 16 | #define CMGR_CT_FCI 104 /* For public version. */ 17 | #define CMGR_CT_TWOMATCHING 105 18 | #define CMGR_CT_COMB 106 19 | #define CMGR_CT_STR_COMB 107 /* Strengthened comb. */ 20 | #define CMGR_CT_HYPOTOUR 108 21 | #define CMGR_CT_EXT_HYPOTOUR 109 22 | #define CMGR_CT_MSTAR 110 /* Homogeneous multistar. */ 23 | #define CMGR_CT_WMSTAR 111 /* Weak multistar. */ 24 | #define CMGR_CT_DJCUT 112 /* Disjunctive cut. */ 25 | #define CMGR_CT_GOMORY 113 /* By variable numbers */ 26 | #define CMGR_CT_TWOEDGES_HYPOTOUR 114 /* 2EH inequality */ 27 | #define CMGR_BT_CLIQUE_DOWN 201 /* x(S:S) <= RHS */ 28 | #define CMGR_BT_CLIQUE_UP 202 /* x(S:S) >= RHS */ 29 | #define CMGR_BT_STAR_DOWN 301 /* x(i:F) <=RHS */ 30 | #define CMGR_BT_STAR_UP 302 /* x(i:F) >=RHS */ 31 | 32 | #define CMGR_CT_SLB 401 /* x(F) >= RHS. Simple lower bound */ 33 | 34 | typedef struct 35 | { 36 | int CType; /* Constraint Type. */ 37 | int Key; 38 | int IntListSize; 39 | int *IntList; 40 | int ExtListSize; 41 | int *ExtList; 42 | int CListSize; 43 | int *CList; 44 | double *CoeffList; 45 | int A,B,L; /* For MSTARs: Lambda=L/B, Sigma=A/B. */ 46 | double RHS; 47 | int BranchLevel; 48 | int GlobalNr; 49 | } CnstrRecord; 50 | typedef CnstrRecord *CnstrPointer; 51 | 52 | typedef CnstrPointer *CnstrPointerList; 53 | 54 | typedef struct 55 | { 56 | CnstrPointerList CPL; 57 | int Dim; /* Vector is zero-based (0..Dim-1). */ 58 | int Size; 59 | } CnstrMgrRecord; 60 | typedef CnstrMgrRecord *CnstrMgrPointer; 61 | 62 | 63 | void CMGR_CreateCMgr(CnstrMgrPointer *CMP, int Dim); 64 | void CMGR_FreeMemCMgr(CnstrMgrPointer *CMP); 65 | void CMGR_AddCnstr(CnstrMgrPointer CMP, 66 | int CType, int Key, int IntListSize, int *IntList, 67 | double RHS); 68 | void CMGR_AddBranchCnstr(CnstrMgrPointer CMP, 69 | int CType, int Key, int IntListSize, int *IntList, 70 | double RHS, 71 | int BranchLevel); 72 | void CMGR_AddExtCnstr(CnstrMgrPointer CMP, 73 | int CType, int Key, int IntListSize, int *IntList, 74 | int ExtListSize, int *ExtList, 75 | double RHS); 76 | void CMGR_AddExplicitCnstr(CnstrMgrPointer CMP, 77 | int CType, int Key, 78 | int ListSize, 79 | int *IntList, 80 | int *ExtList, 81 | double *CoeffList, 82 | double RHS); 83 | void CMGR_AddGomoryCnstr(CnstrMgrPointer CMP, 84 | int CType, int Key, 85 | int ListSize, 86 | int *IntList, /* Variable numbers */ 87 | double *CoeffList, 88 | double RHS); /* >= RHS */ 89 | void CMGR_AppendCMP(CnstrMgrPointer Sink, 90 | CnstrMgrPointer Source); 91 | void CMGR_SearchCap(CnstrMgrPointer CMP, 92 | int IntListSize, int *IntList, 93 | char *CapExists); 94 | void CMGR_AddMStar(CnstrMgrPointer CMP, 95 | int CType, int Key, int IntListSize, int *IntList, 96 | int ExtListSize, int *ExtList, 97 | int A, int B, int L); 98 | void CMGR_AddPartialMStar(CnstrMgrPointer CMP, 99 | int CType, int Key, 100 | int IntListSize, int *IntList, 101 | int ExtListSize, int *ExtList, 102 | int CListSize, int *CList, 103 | int A, int B, int L); 104 | void CMGR_MoveCnstr(CnstrMgrPointer SourcePtr, 105 | CnstrMgrPointer SinkPtr, 106 | int SourceIndex, 107 | int SinkIndex); 108 | void CMGR_ClearCnstr(CnstrMgrPointer SourcePtr, 109 | int Index); 110 | void CMGR_CompressCMP(CnstrMgrPointer CMP); 111 | void CMGR_ChgRHS(CnstrMgrPointer CMP, int CnstrNr, double NewRHS); 112 | void CMGR_SaveCMP(FILE *f, CnstrMgrPointer CMP, 113 | char MatchType, 114 | int CnstrType, 115 | char WriteLabel, 116 | int Label); 117 | void CMGR_WriteCMP(CnstrMgrPointer CMP, int MinCNr); 118 | 119 | #endif -------------------------------------------------------------------------------- /include/ext/cvrpsep/compcuts.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_COMPCUTS 6 | #define _H_COMPCUTS 7 | 8 | void COMPCUTS_ComputeCompCuts(ReachPtr SupportPtr, 9 | int NoOfCustomers, 10 | int *Demand, 11 | int CAP, 12 | double **XMatrix, 13 | CnstrMgrPointer CutsCMP, 14 | int *GeneratedCuts); 15 | 16 | #endif 17 | 18 | -------------------------------------------------------------------------------- /include/ext/cvrpsep/compress.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_COMPRESS 6 | #define _H_COMPRESS 7 | 8 | void COMPRESS_ShrinkGraph(ReachPtr SupportPtr, 9 | int NoOfCustomers, 10 | double **XMatrix, 11 | double **SMatrix, 12 | int NoOfV1Cuts, 13 | ReachPtr V1CutsPtr, 14 | ReachPtr SAdjRPtr, /* Shrunk support graph */ 15 | ReachPtr SuperNodesRPtr, /* Nodes in supernodes */ 16 | int *ShrunkGraphCustNodes); /* Excl. depot */ 17 | 18 | #endif 19 | 20 | -------------------------------------------------------------------------------- /include/ext/cvrpsep/cutbase.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_CUTBASE 6 | #define _H_CUTBASE 7 | 8 | void CUTBASE_CompXSumInSet(ReachPtr SupportPtr, 9 | int NoOfCustomers, 10 | char *InNodeSet, 11 | int *NodeList, int NodeListSize, 12 | double **XMatrix, 13 | double *XSumInSet); 14 | 15 | void CUTBASE_CompVehiclesForSet(int NoOfCustomers, 16 | char *NodeInSet, 17 | int *NodeList, 18 | int NodeListSize, 19 | int *Demand, 20 | int CAP, 21 | int *MinV); 22 | 23 | void CUTBASE_CompCapViolation(ReachPtr SupportPtr, 24 | int NoOfCustomers, 25 | char *NodeInSet, 26 | int *NodeList, int NodeListSize, 27 | int *Demand, int CAP, 28 | double **XMatrix, 29 | double *Violation); 30 | 31 | #endif 32 | 33 | -------------------------------------------------------------------------------- /include/ext/cvrpsep/fcapfix.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_FCAPFIX 6 | #define _H_FCAPFIX 7 | 8 | void FCAPFIX_ComputeCuts(ReachPtr SupportPtr, 9 | int NoOfCustomers, 10 | int *Demand, int CAP, 11 | int *SuperNodeSize, 12 | double **XMatrix, 13 | int MaxCuts, 14 | int MaxRounds, 15 | int *NoOfGeneratedCuts, 16 | ReachPtr ResultRPtr); 17 | 18 | #endif 19 | 20 | -------------------------------------------------------------------------------- /include/ext/cvrpsep/grsearch.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_GRSEARCH 6 | #define _H_GRSEARCH 7 | 8 | void GRSEARCH_SetUnitDemand(char UnitDemand); 9 | 10 | void GRSEARCH_SwapNodesInPos(int *Node, int *Pos, int s, int t); 11 | 12 | void GRSEARCH_GetInfeasExt(int *Pos, 13 | int MinCandidateIdx, int MaxCandidateIdx, 14 | int NoOfCustomers, 15 | int NodeSum, /* Sum of node numbers. */ 16 | ReachPtr RPtr, 17 | int RPtrSize, 18 | int *NodeLabel, 19 | int Label, 20 | char *CallBack); 21 | 22 | void GRSEARCH_AddSet(ReachPtr RPtr, 23 | int Index, 24 | int SetSize, 25 | int *List, 26 | char AddFullSumList); 27 | 28 | void GRSEARCH_CapCuts(ReachPtr SupportPtr, 29 | int NoOfCustomers, 30 | int *Demand, int CAP, 31 | int *SuperNodeSize, 32 | double *XInSuperNode, 33 | double **XMatrix, 34 | int *GeneratedSets, 35 | int *GeneratedAntiSets, 36 | ReachPtr SetsRPtr, /* Identified cuts. */ 37 | ReachPtr AntiSetsRPtr, 38 | int MaxTotalGeneratedSets); 39 | 40 | void GRSEARCH_CheckForExistingSet(ReachPtr RPtr, 41 | int RPtrSize, 42 | int *NodeLabel, 43 | int Label, 44 | int NodeSum, /* Sum of node numbers. */ 45 | int NodeSetSize, 46 | char *ListFound); 47 | 48 | void GRSEARCH_AddDropCapsOnGS(ReachPtr SupportPtr, /* On GS */ 49 | int NoOfCustomers, 50 | int ShrunkGraphCustNodes, 51 | int *SuperDemand, int CAP, 52 | int *SuperNodeSize, 53 | double *XInSuperNode, 54 | ReachPtr SuperNodesRPtr, 55 | double **SMatrix, /* Shrunk graph */ 56 | double Eps, 57 | CnstrMgrPointer CMPSourceCutList, 58 | int *NoOfGeneratedSets, 59 | int MaxTotalGeneratedSets, 60 | ReachPtr SetsRPtr); /* Identified cuts. */ 61 | 62 | #endif 63 | 64 | -------------------------------------------------------------------------------- /include/ext/cvrpsep/memmod.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_MEMMOD 6 | #define _H_MEMMOD 7 | 8 | #include 9 | 10 | void* MemGet(int NoOfBytes); 11 | void* MemReGet(void *p, int NewNoOfBytes); 12 | void MemFree(void *p); 13 | char* MemGetCV(int n); 14 | char** MemGetCM(int Rows, int Cols); 15 | void MemFreeCM(char **p, int Rows); 16 | int* MemGetIV(int n); 17 | int** MemGetIM(int Rows, int Cols); 18 | void MemFreeIM(int **p, int Rows); 19 | double* MemGetDV(int n); 20 | double** MemGetDM(int Rows, int Cols); 21 | void MemFreeDM(double **p, int Rows); 22 | 23 | #endif -------------------------------------------------------------------------------- /include/ext/cvrpsep/mxf.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_MXF 6 | #define _H_MXF 7 | 8 | typedef void *MaxFlowPtr; 9 | 10 | void MXF_WriteArcList(MaxFlowPtr Ptr); 11 | void MXF_WriteNodeList(MaxFlowPtr Ptr); 12 | void MXF_InitMem(MaxFlowPtr *Ptr, 13 | int TotalNodes, 14 | int TotalArcs); 15 | void MXF_FreeMem(MaxFlowPtr Ptr); 16 | void MXF_ClearNodeList(MaxFlowPtr Ptr); 17 | void MXF_ClearArcList(MaxFlowPtr Ptr); 18 | void MXF_SetNodeListSize(MaxFlowPtr Ptr, 19 | int TotalNodes); 20 | void MXF_AddArc(MaxFlowPtr Ptr, 21 | int Tail, 22 | int Head, 23 | int Capacity); 24 | void MXF_ChgArcCap(MaxFlowPtr Ptr, 25 | int Tail, 26 | int Head, 27 | int Capacity); 28 | void MXF_CreateMates(MaxFlowPtr Ptr); 29 | 30 | void MXF_CreateArcMap(MaxFlowPtr Ptr); 31 | 32 | void MXF_SolveMaxFlow(MaxFlowPtr Ptr, 33 | char InitByZeroFlow, 34 | int Source, 35 | int Sink, 36 | int *CutValue, 37 | char GetSinkSide, 38 | int *NodeListSize, 39 | int *NodeList); 40 | 41 | void MXF_GetNetworkSize(MaxFlowPtr Ptr, 42 | int *Nodes, 43 | int *Arcs); 44 | 45 | void MXF_GetCurrentFlow(MaxFlowPtr Ptr, 46 | int *ArcResidualCapacity, 47 | int *NodeExcess); 48 | 49 | void MXF_SetFlow(MaxFlowPtr Ptr, 50 | int *ArcResidualCapacity, 51 | int *NodeExcess); 52 | 53 | void MXF_ComputeGHCutTree(MaxFlowPtr Ptr, 54 | int CenterNode, 55 | int *CutValue, 56 | int *NextOnPath); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/ext/cvrpsep/sort.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_SORT 6 | #define _H_SORT 7 | 8 | void SortIVInc(int *Value, int n); 9 | void SortIVDec(int *Value, int n); 10 | void SortDVInc(double *Value, int n); 11 | void SortDVDec(double *Value, int n); 12 | void SortIndexIVInc(int *Index, int *Value, int n); 13 | void SortIndexIVDec(int *Index, int *Value, int n); 14 | void SortIndexDVDec(int *Index, double *Value, int n); 15 | void SortIndexDVInc(int *Index, double *Value, int n); 16 | 17 | #endif -------------------------------------------------------------------------------- /include/ext/cvrpsep/strngcmp.h: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #ifndef _H_STRNGCMP 6 | #define _H_STRNGCMP 7 | 8 | #include "basegrph.h" 9 | 10 | void ComputeStrongComponents(ReachPtr RPtr, ReachPtr ResultPtr, 11 | int *NoOfComponents, int n, 12 | char *CVWrk1, 13 | int *IVWrk1, int *IVWrk2, int *IVWrk3, 14 | int *IVWrk4); 15 | 16 | #endif -------------------------------------------------------------------------------- /include/init_grb_model.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: init_grb_model.hpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Gurobi's model initialization helper functions declartions. 7 | * 8 | * (I'm sorry for my bad english xD) 9 | * 10 | * Created on October 22, 2020, 10:44 PM. 11 | * 12 | * References: 13 | */ 14 | //////////////////////////////////////////////////////////////////////////////// 15 | 16 | #ifndef INIT_GRB_MODE_HPP 17 | #define INIT_GRB_MODE_HPP 18 | 19 | #include 20 | 21 | #include "gurobi_c++.h" 22 | 23 | #include "instance.hpp" 24 | 25 | namespace init 26 | { 27 | 28 | /** 29 | * @brief:. 30 | * @param:. 31 | * @param:. 32 | * @param:. 33 | */ 34 | void inventoryLevelVariables(GRBModel& model, 35 | std::vector>& I, 36 | const std::shared_ptr& pInst); 37 | 38 | /** 39 | * @brief:. 40 | * @param:. 41 | * @param:. 42 | * @param:. 43 | */ 44 | void quantityVariables(GRBModel& model, 45 | std::vector>>& q, 46 | const std::shared_ptr& pInst); 47 | 48 | 49 | /** 50 | * @brief:. 51 | * @param:. 52 | * @param:. 53 | * @param:. 54 | */ 55 | void visitationVariables(GRBModel& model, 56 | std::vector>>& y, 57 | const std::shared_ptr& pInst); 58 | 59 | /** 60 | * @brief:. 61 | * @param:. 62 | * @param:. 63 | * @param:. 64 | */ 65 | void routingVariables( 66 | GRBModel& model, 67 | std::vector>>>& x, 68 | const std::shared_ptr& pInst); 69 | 70 | /** 71 | * @brief:. 72 | * @param:. 73 | * @param:. 74 | * @param:. 75 | * @param:. 76 | * @param:. 77 | */ 78 | void inventoryDefDepotConstrs( 79 | GRBModel& model, 80 | std::vector& constrs, 81 | const std::vector>& I, 82 | const std::vector>>& q, 83 | const std::shared_ptr& pInst); 84 | 85 | /** 86 | * @brief:. 87 | * @param:. 88 | * @param:. 89 | * @param:. 90 | * @param:. 91 | * @param:. 92 | */ 93 | void stockOutDepotConstrs( 94 | GRBModel& model, 95 | std::vector& constrs, 96 | const std::vector>& I, 97 | const std::vector>>& q, 98 | const std::shared_ptr& pInst); 99 | 100 | /** 101 | * @brief:. 102 | * @param:. 103 | * @param:. 104 | * @param:. 105 | * @param:. 106 | * @param:. 107 | */ 108 | void inventoryDefCustomersConstrs( 109 | GRBModel& model, 110 | std::vector& constrs, 111 | const std::vector>& I, 112 | const std::vector>>& q, 113 | const std::shared_ptr& pInst); 114 | 115 | /** 116 | * @brief:. 117 | * @param:. 118 | * @param:. 119 | * @param:. 120 | * @param:. 121 | * @param:. 122 | */ 123 | void capacityConstrs(GRBModel& model, 124 | std::vector& constrs, 125 | const std::vector>>& q, 126 | const std::shared_ptr& pInst); 127 | 128 | /** 129 | * @brief:. 130 | * @param:. 131 | * @param:. 132 | * @param:. 133 | * @param:. 134 | * @param:. 135 | */ 136 | void inventoryLevelConstrs( 137 | GRBModel& model, 138 | std::vector& constrs, 139 | const std::vector>& I, 140 | const std::vector>>& q, 141 | const std::shared_ptr& pInst); 142 | 143 | /** 144 | * @brief:. 145 | * @param:. 146 | * @param:. 147 | * @param:. 148 | * @param:. 149 | * @param:. 150 | */ 151 | void mlQuantityCapacityConstrs( 152 | GRBModel& model, 153 | std::vector& constrs, 154 | const std::vector>& I, 155 | const std::vector>>& q, 156 | const std::shared_ptr& pInst); 157 | 158 | /** 159 | * @brief:. 160 | * @param:. 161 | * @param:. 162 | * @param:. 163 | * @param:. 164 | * @param:. 165 | */ 166 | void ouQuantityCapacityConstrs( 167 | GRBModel& model, 168 | std::vector& constrs, 169 | const std::vector>& I, 170 | const std::vector>>& y, 171 | const std::vector>>& q, 172 | const std::shared_ptr& pInst); 173 | 174 | /** 175 | * @brief:. 176 | * @param:. 177 | * @param:. 178 | * @param:. 179 | * @param:. 180 | * @param:. 181 | */ 182 | void quantitiesRoutingConstraint( 183 | GRBModel& model, 184 | std::vector& constrs, 185 | const std::vector>>& y, 186 | const std::vector>>& q, 187 | const std::shared_ptr& pInst); 188 | 189 | /** 190 | * @brief:. 191 | * @param:. 192 | * @param:. 193 | * @param:. 194 | * @param:. 195 | * @param:. 196 | */ 197 | void capacityVehicleConstraint( 198 | GRBModel& model, 199 | std::vector& constrs, 200 | const std::vector>>& y, 201 | const std::vector>>& q, 202 | const std::shared_ptr& pInst); 203 | 204 | /** 205 | * @brief:. 206 | * @param:. 207 | * @param:. 208 | * @param:. 209 | * @param:. 210 | * @param:. 211 | */ 212 | void degreeConstrs( 213 | GRBModel& model, 214 | std::vector& constrs, 215 | const std::vector>>& y, 216 | const std::vector>>>& x, 217 | const std::shared_ptr& pInst); 218 | 219 | 220 | /** 221 | * @brief:. 222 | * @param:. 223 | * @param:. 224 | * @param:. 225 | * @param:. 226 | * @param:. 227 | */ 228 | void subtourEliminationConstrs( 229 | GRBModel& model, 230 | std::vector& constrs, 231 | const std::vector>>& y, 232 | const std::vector>>>& x, 233 | const std::shared_ptr& pInst); 234 | 235 | /** 236 | * @brief:. 237 | * @param:. 238 | * @param:. 239 | * @param:. 240 | */ 241 | void noSplitDelivery(GRBModel& model, 242 | const std::vector>>& y, 243 | const std::shared_ptr& pInst); 244 | 245 | } // init namespace 246 | 247 | #endif // INIT_IRP_MODE_HPP -------------------------------------------------------------------------------- /include/instance.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: instance.hpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief IRP instance class declaration. 7 | * 8 | * (I'm sorry for my bad english xD) 9 | * 10 | * Created on October 22, 2020, 06:44 PM. 11 | * 12 | * References: 13 | * https://bit.ly/3dQu0Kc 14 | */ 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef INSTANCE_HPP 18 | #define INSTANCE_HPP 19 | 20 | #include 21 | #include 22 | 23 | class ConfigParameters; 24 | 25 | class Instance 26 | { 27 | public: 28 | 29 | /** 30 | * @brief Default constructor, copy constructor, move constructor, 31 | * destructor, copy assingment operator and move assingment operator. 32 | */ 33 | Instance() = default; 34 | Instance(const Instance& other) = default; 35 | Instance(Instance&& other) = default; 36 | ~Instance() = default; 37 | Instance& operator=(const Instance& other) = default; 38 | Instance& operator=(Instance&& other) = default; 39 | 40 | /** 41 | * @brief Constructs from a instance file. 42 | * @param : const std::string&: instance file path. 43 | */ 44 | Instance(const std::string& filePath, const int K); 45 | 46 | double getC() const; 47 | 48 | double getCk(const int k) const; 49 | 50 | double get_cij(const int i, const int j) const; 51 | 52 | double get_hi(const int i) const; 53 | 54 | double getIi0(const int i) const; 55 | 56 | int getK() const; // number of vehicles 57 | 58 | double getLi(const int i) const; 59 | 60 | std::string getName() const; 61 | 62 | int getNbVertices() const; 63 | 64 | double get_rit(const int i, const int t) const; 65 | 66 | int getT() const; 67 | 68 | double getUi(const int i) const; 69 | 70 | void setK(const int K); 71 | 72 | /** 73 | * @brief: Print instance on console. 74 | */ 75 | void show() const; 76 | 77 | private: 78 | 79 | // instance full path 80 | std::string mPath; 81 | 82 | // number of vertices (depot and customers) 83 | int mNbVertices; 84 | 85 | // number of vehicles 86 | int mK; 87 | 88 | // number of discrete time instants of the planning time horizon 89 | int mT; 90 | 91 | // transportation capacity 92 | double mC; 93 | 94 | // transportation capacity of vehicle k 95 | std::vector mCk; 96 | 97 | // unit inventory cost 98 | std::vector m_hi; 99 | 100 | // starting level of the inventory 101 | std::vector mIi0; 102 | 103 | // minimum level of the inventory at the retailer i 104 | std::vector mLi; 105 | 106 | // maximum level of the inventory at the retailer i 107 | std::vector mUi; 108 | 109 | // quantity absorved by the retailer i at each dicrete time instante 110 | std::vector> m_rit; 111 | 112 | // (x, y) coordinates of the supply and the retailers 113 | std::vector> mCoord; 114 | 115 | // distance matrix 116 | std::vector> m_cij; 117 | 118 | /** 119 | * @brief Initializes the instance object from the instance file path. 120 | * @param:. 121 | */ 122 | void init(const std::string& filePath); 123 | }; 124 | 125 | #endif // INSTANCE_HPP -------------------------------------------------------------------------------- /include/irp_lp.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: irp_lp.hpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Classic Inventory-Routing Problem (IRP) linear program [1] class 7 | * declaration. 8 | * 9 | * (I'm sorry for my bad english xD) 10 | * 11 | * Created on October 22, 2020, 06:47 PM. 12 | * 13 | * References: 14 | * [1] C. Archetti, L. Bertazzi, G. Laporte and M. G. Speranza. A Branch-and-Cut 15 | * Algorithm for a Vendor-Managed Inventory-Routing Problem. Transportation 16 | * Science, 41(3), 2007, pp. 382-391. 17 | */ 18 | //////////////////////////////////////////////////////////////////////////////// 19 | 20 | #ifndef IRP_LP_HPP 21 | #define IRP_LP_HPP 22 | 23 | #include 24 | #include 25 | 26 | #include "gurobi_c++.h" 27 | 28 | #include "config_parameters.hpp" 29 | #include "instance.hpp" 30 | #include "callback/callback_sec.hpp" 31 | 32 | class Irp_lp 33 | { 34 | public: 35 | 36 | Irp_lp(const Irp_lp& other) = default; 37 | Irp_lp(Irp_lp&& other) = default; 38 | ~Irp_lp() = default; 39 | 40 | Irp_lp() = delete; 41 | Irp_lp& operator=(const Irp_lp& other) = delete; 42 | Irp_lp& operator=(Irp_lp&& other) = delete; 43 | 44 | Irp_lp(const std::shared_ptr& p_inst, 45 | const ConfigParameters::model& params); 46 | 47 | bool solve(const ConfigParameters::solver& params); 48 | 49 | void writeIis(std::string path); 50 | 51 | void writeModel(std::string path); 52 | 53 | void writeResultsJSON(std::string path); 54 | 55 | void writeSolution(std::string path); 56 | 57 | private: 58 | 59 | // pointer to instance 60 | std::shared_ptr mpInst; 61 | 62 | GRBEnv mEnv; 63 | GRBModel mModel; 64 | std::vector mConstrs; 65 | 66 | // inventory level variables 67 | std::vector> mI; 68 | // product quantity shipped to the retailer by vehicle k 69 | std::vector>> m_q; 70 | /* equal to one if j immediately follows i in the route traveled at time t 71 | by vehicle k */ 72 | std::vector>>> m_x; 73 | // retailer i is served at time t by vehicle k 74 | std::vector>> m_y; 75 | 76 | CallbackSEC mCbSEC; 77 | }; 78 | 79 | #endif // IRP_LP_HPP -------------------------------------------------------------------------------- /include/utils/constants.hpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: constants.hpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Constants file. 7 | * 8 | * (I'm sorry for my bad english xD) 9 | * 10 | * Created on January 7, 2021, 5:56 PM 11 | * 12 | * References: 13 | * [1] https://bit.ly/2RHRnfm. 14 | */ 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef UTILS_CONSTANTS_HPP 18 | #define UTILS_CONSTANTS_HPP 19 | 20 | namespace utils 21 | { 22 | 23 | /** 24 | * @brief GUROBI's epsilon [1]. 25 | */ 26 | const static double GRB_EPSILON = 1e-6; 27 | 28 | } // utils namespace 29 | 30 | #endif // UTILS_CONSTANTS_HPP -------------------------------------------------------------------------------- /input/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file and cfg file example 4 | !.gitignore 5 | !example.cfg 6 | !instances/ -------------------------------------------------------------------------------- /input/example.cfg: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # Classic IRP solver: example of the input configuration file. 4 | # 5 | ################################################################################ 6 | # 7 | # --- Execution configuration options --- 8 | # 9 | # ============================= General parameters ============================= 10 | # 11 | # (std::string): single instance path or instances directory (all instances from 12 | # this directory are executed in batch). 13 | # (single instance execution) 14 | instance_path = ./input/instances/abs1n10.dat 15 | # (batch execution) 16 | # instance_path = ./input/instances/ 17 | # 18 | # (std::string): directory path where all methods output (results, statistics, 19 | # etc) will be stored. A folder is created if it does not exist. 20 | output_dir = ./output/ 21 | # 22 | # ============================= Solver parameters ============================== 23 | # 24 | # (bool): silences (or not) the solver output. 25 | solver_show_log = true 26 | # 27 | # (unsigned int): solver maximum execution time (in seconds) in every solver 28 | # execution. Set 'unlimited' to don't limit it. 29 | solver_time_limit = 7200 30 | # 31 | # (unsigned int): number of threads used by the solver. Set 'max' to use all the 32 | # machine threads. 33 | solver_nb_threads = max 34 | # 35 | # ============================== Model parameters ============================== 36 | # 37 | # (unsigned int): number of vehicles (K). 38 | nb_vehicles = 3 39 | # 40 | # (unsigned int): execution model invetory policy: 41 | # 0: maximum level inventory policy (ML). 42 | # 1: order-up to level inventory policy (OU). 43 | model_policy = 0 44 | # 45 | # (unsigned int): subtour elimination strategy : 46 | # 0: adds the standard subtour elimination constraints to the model. 47 | # 1: adds lazy and cut constraints from CVRPSEP package. 48 | sec_strategy = 1 -------------------------------------------------------------------------------- /input/instances/abs1n5.dat: -------------------------------------------------------------------------------- 1 | 6 3 289 2 | 1 154.0 417.0 510 193 .30 3 | 2 172.0 334.0 130 195 0 65 .23 4 | 3 267.0 87.0 70 105 0 35 .32 5 | 4 148.0 433.0 58 116 0 58 .33 6 | 5 355.0 444.0 48 72 0 24 .23 7 | 6 38.0 152.0 11 22 0 11 .18 -------------------------------------------------------------------------------- /input/instances/abs2n5.dat: -------------------------------------------------------------------------------- 1 | 6 3 237 2 | 1 309.0 334.0 462 158 .30 3 | 2 345.0 168.0 62 93 0 31 .35 4 | 3 34.0 174.0 120 180 0 60 .14 5 | 4 297.0 367.0 34 51 0 17 .17 6 | 5 211.0 389.0 76 114 0 38 .36 7 | 6 76.0 304.0 12 24 0 12 .25 8 | -------------------------------------------------------------------------------- /src/callback/callback_sec.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: callback_sec.cpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Callback class definition for lazy/cut subtour separation 7 | * constraints. 8 | * 9 | * @acknowledgment Special thanks to Ph.D. Cleder Marcos Schenekemberg. 10 | * 11 | * (I'm sorry for my bad english xD) 12 | * 13 | * Created on November 16, 2020, 00:15 AM 14 | * 15 | * References: 16 | */ 17 | //////////////////////////////////////////////////////////////////////////////// 18 | 19 | #include "../../include/ext/loguru/loguru.hpp" 20 | 21 | #include "../../include/callback/callback_sec.hpp" 22 | #include "../../include/ext/cvrpsep/capsep.h" 23 | #include "../../include/ext/cvrpsep/cnstrmgr.h" 24 | 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | namespace 28 | { 29 | 30 | static const int C_EPS = 1e-5; 31 | 32 | } // anonymous namespace 33 | 34 | //////////////////////////////////////////////////////////////////////////////// 35 | 36 | CallbackSEC::CallbackSEC( 37 | const std::vector>>& q, 38 | const std::vector>>>& x, 39 | const std::vector>>& y, 40 | const std::shared_ptr& p_inst) : 41 | m_q(q), 42 | m_x(x), 43 | m_y(y), 44 | mpInst(p_inst) 45 | {} 46 | 47 | 48 | void CallbackSEC::callback() 49 | { 50 | try 51 | { 52 | if (where == GRB_CB_MIPSOL) 53 | { 54 | addCVRPSEPCAP(constrsType::lazy); 55 | } 56 | else if (where == GRB_CB_MIPNODE && 57 | getIntInfo(GRB_CB_MIPNODE_STATUS) == GRB_OPTIMAL) 58 | { 59 | addCVRPSEPCAP(constrsType::cut); 60 | } 61 | } 62 | catch (GRBException& e) 63 | { 64 | RAW_LOG_F(ERROR, "callback() exp: %s", e.getMessage().c_str()); 65 | } 66 | catch (...) 67 | { 68 | RAW_LOG_F(ERROR, "callback(): Unknown Exception"); 69 | } 70 | } 71 | 72 | /* -------------------------------------------------------------------------- */ 73 | 74 | std::vector>> CallbackSEC::getqVarsValues( 75 | const constrsType cstType) 76 | { 77 | std::vector>> qVal( 78 | mpInst->getNbVertices(), std::vector>( 79 | mpInst->getK(), std::vector(mpInst->getT(), 0) 80 | ) 81 | ); 82 | 83 | for (int i = 1; i < mpInst->getNbVertices(); ++i) 84 | { 85 | for (int k = 0; k < mpInst->getK(); ++k) 86 | { 87 | for (int t = 0; t < mpInst->getT(); ++t) 88 | { 89 | DCHECK_F(i < static_cast(m_q.size())); 90 | DCHECK_F(k < static_cast(m_q[i].size())); 91 | DCHECK_F(t < static_cast(m_q[i][k].size())); 92 | if (cstType == constrsType::lazy) 93 | { 94 | qVal[i][k][t] = getSolution(m_q[i][k][t]); 95 | } 96 | else 97 | { 98 | qVal[i][k][t] = getNodeRel(m_q[i][k][t]); 99 | } 100 | } 101 | } 102 | } 103 | 104 | return qVal; 105 | } 106 | 107 | 108 | std::vector>>> 109 | CallbackSEC::getxVarsValues(const constrsType cstType) 110 | { 111 | std::vector>>> xVal( 112 | mpInst->getNbVertices(), std::vector>>( 113 | mpInst->getNbVertices(), std::vector>( 114 | mpInst->getK(), std::vector(mpInst->getT(), 0) 115 | ) 116 | ) 117 | ); 118 | 119 | for (int i = 0; i < mpInst->getNbVertices(); ++i) 120 | { 121 | for (int j = i + 1; j < mpInst->getNbVertices(); ++j) 122 | { 123 | for (int k = 0; k < mpInst->getK(); ++k) 124 | { 125 | for (int t = 0; t < mpInst->getT(); ++t) 126 | { 127 | DCHECK_F(i < static_cast(m_x.size())); 128 | DCHECK_F(j < static_cast(m_x[i].size())); 129 | DCHECK_F(k < static_cast(m_x[i][j].size())); 130 | DCHECK_F(t < static_cast(m_x[i][j][k].size())); 131 | if (cstType == constrsType::lazy) 132 | { 133 | xVal[i][j][k][t] = getSolution(m_x[i][j][k][t]); 134 | } 135 | else 136 | { 137 | xVal[i][j][k][t] = getNodeRel(m_x[i][j][k][t]); 138 | } 139 | } 140 | } 141 | } 142 | } 143 | 144 | return xVal; 145 | } 146 | 147 | 148 | std::vector>> CallbackSEC::getyVarsValues( 149 | const constrsType cstType) 150 | { 151 | std::vector>> yVal( 152 | mpInst->getNbVertices(), std::vector>( 153 | mpInst->getK(), std::vector(mpInst->getT(), 0) 154 | ) 155 | ); 156 | 157 | for (int i = 0; i < mpInst->getNbVertices(); ++i) 158 | { 159 | for (int k = 0; k < mpInst->getK(); ++k) 160 | { 161 | for (int t = 0; t < mpInst->getT(); ++t) 162 | { 163 | DCHECK_F(i < static_cast(m_y.size())); 164 | DCHECK_F(k < static_cast(m_y[i].size())); 165 | DCHECK_F(t < static_cast(m_y[i][k].size())); 166 | if (cstType == constrsType::lazy) 167 | { 168 | yVal[i][k][t] = getSolution(m_y[i][k][t]); 169 | } 170 | else 171 | { 172 | yVal[i][k][t] = getNodeRel(m_y[i][k][t]); 173 | } 174 | } 175 | } 176 | } 177 | 178 | return yVal; 179 | } -------------------------------------------------------------------------------- /src/callback/cuts/cvrpsep.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: cvrpsep.cpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Lazy and cut CVRPSEP functions. 7 | * 8 | * (I'm sorry for my bad english xD) 9 | * 10 | * Created on January 20, 2020, 06:51 PM 11 | * 12 | * References: 13 | */ 14 | //////////////////////////////////////////////////////////////////////////////// 15 | 16 | #include 17 | 18 | #include "../../../include/ext/cvrpsep/capsep.h" 19 | #include "../../../include/ext/cvrpsep/cnstrmgr.h" 20 | #include "../../../include/ext/loguru/loguru.hpp" 21 | 22 | #include "../../../include/callback/callback_sec.hpp" 23 | #include "../../../include/utils/constants.hpp" 24 | 25 | ////////////////////////////// Helper functions /////////////////////////////// 26 | 27 | namespace 28 | { 29 | 30 | static const int cDim = 100; // ? 31 | static const int cMaxNbCapCuts = 8; // ? 32 | 33 | /** 34 | * @brief 35 | */ 36 | int checkForDepot(const int i, const int n) 37 | { 38 | return i == n ? 0 : i; 39 | } 40 | 41 | /* 42 | * @brief 43 | */ 44 | std::vector getDemand( 45 | const std::vector>>& qVal, 46 | const int k, 47 | const int t) 48 | { 49 | std::vector demand(qVal.size(), 0); 50 | 51 | for (std::size_t i = 1; i < demand.size(); ++i) 52 | { 53 | demand[i] = static_cast(std::ceil(qVal[i][k][t])); 54 | } 55 | 56 | return demand; 57 | } 58 | 59 | /** 60 | * @brief 61 | */ 62 | std::tuple, std::vector, std::vector> 63 | getEdges( 64 | const std::vector>>>& xVal, 65 | const int n, 66 | const int k, 67 | const int t) 68 | { 69 | int nbEdges = 0; 70 | for (int i = 0; i < n; ++i) 71 | { 72 | for (int j = i + 1; j < n; ++j) 73 | { 74 | if (xVal[i][j][k][t] > utils::GRB_EPSILON) 75 | { 76 | ++nbEdges; 77 | } 78 | } 79 | } 80 | 81 | std::vector edgeTail; 82 | std::vector edgeHead; 83 | std::vector edgeX; 84 | 85 | if (nbEdges > 0) 86 | { 87 | edgeTail.reserve(nbEdges + 1); 88 | edgeHead.reserve(nbEdges + 1); 89 | edgeX.reserve(nbEdges + 1); 90 | /* skip first element */ 91 | edgeTail.push_back(0); 92 | edgeHead.push_back(0); 93 | edgeX.push_back(0); 94 | 95 | for (int i = 0; i < n; ++i) 96 | { 97 | for (int j = i + 1; j < n; ++j) 98 | { 99 | if (xVal[i][j][k][t] > utils::GRB_EPSILON) 100 | { 101 | edgeTail.push_back(i == 0 ? n : i); 102 | edgeHead.push_back(j); 103 | edgeX.push_back(xVal[i][j][k][t]); 104 | } 105 | } 106 | } 107 | } 108 | 109 | return std::make_tuple(nbEdges, edgeTail, edgeHead, edgeX); 110 | } 111 | 112 | } 113 | 114 | //////////////////////////////////////////////////////////////////////////////// 115 | 116 | 117 | int CallbackSEC::addCVRPSEPCAP(const constrsType cstType) 118 | { 119 | int nbAdded = 0; // # of lazy/cuts added in this call 120 | 121 | /* get solution: delivery quantities */ 122 | auto qVal = getqVarsValues(cstType); 123 | /* get solution: routing */ 124 | auto xVal = getxVarsValues(cstType); 125 | /* get solution: visitation */ 126 | auto yVal = getyVarsValues(cstType); 127 | 128 | const int n = mpInst->getNbVertices(); 129 | for (int k = 0; k < mpInst->getK(); ++k) 130 | { 131 | for (int t = 0; t < mpInst->getT(); ++t) 132 | { 133 | auto [nbEdges, edgeTail, edgeHead, edgeX] = getEdges(xVal, n, k, t); 134 | 135 | if (nbEdges == 0) continue; 136 | 137 | /* Parameters of the CVRPSEP */ 138 | char integerAndFeasible; 139 | double maxViolation = 0; 140 | auto demand = getDemand(qVal, k, t); 141 | CnstrMgrPointer cutsCMP, myOldCutsCMP; 142 | CMGR_CreateCMgr(&cutsCMP, cDim); 143 | CMGR_CreateCMgr(&myOldCutsCMP, cDim); 144 | 145 | CAPSEP_SeparateCapCuts(n - 1, 146 | demand.data(), 147 | mpInst->getCk(k), 148 | nbEdges, 149 | edgeTail.data(), 150 | edgeHead.data(), 151 | edgeX.data(), 152 | myOldCutsCMP, 153 | cMaxNbCapCuts, 154 | utils::GRB_EPSILON, 155 | &integerAndFeasible, 156 | &maxViolation, 157 | cutsCMP); 158 | 159 | for (int c = 0; c < cutsCMP->Size; ++c) 160 | { 161 | if (cutsCMP->CPL[c]->CType == CMGR_CT_CAP) 162 | { 163 | std::vector list; 164 | list.reserve(cutsCMP->CPL[c]->IntListSize); 165 | for (int j = 1; j <= cutsCMP->CPL[c]->IntListSize; ++j) 166 | { 167 | list.push_back( 168 | checkForDepot(cutsCMP->CPL[c]->IntList[j], n)); 169 | } 170 | 171 | GRBLinExpr xExpr = 0, yExpr = 0; 172 | double xSum = 0, ySum = 0; 173 | for (std::size_t i = 0; i < list.size(); ++i) 174 | { 175 | for (std::size_t j = 0; j < list.size(); ++j) 176 | { 177 | if (list[i] < list[j]) 178 | { 179 | xExpr += m_x[list[i]][list[j]][k][t]; 180 | xSum += xVal[list[i]][list[j]][k][t]; 181 | } 182 | } 183 | yExpr += m_y[list[i]][k][t]; 184 | ySum += yVal[list[i]][k][t]; 185 | } 186 | 187 | for (std::size_t i = 0; i < list.size(); ++i) 188 | { 189 | if (cstType == constrsType::lazy) 190 | { 191 | addLazy(xExpr <= yExpr - m_y[list[i]][k][t]); 192 | ++nbAdded; 193 | } 194 | else if (xSum - ySum + yVal[list[i]][k][t] > 195 | utils::GRB_EPSILON) 196 | { 197 | addCut(xExpr <= yExpr - m_y[list[i]][k][t]); 198 | ++nbAdded; 199 | } 200 | } 201 | } 202 | } 203 | 204 | CMGR_FreeMemCMgr(&cutsCMP); 205 | CMGR_FreeMemCMgr(&myOldCutsCMP); 206 | } 207 | } 208 | 209 | return nbAdded; 210 | } -------------------------------------------------------------------------------- /src/config_parameters.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: ConfigParameters.cpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Configuration input parameters class definition 7 | * (see ./input/example.cfg). 8 | * 9 | * (I'm sorry for my bad english xD) 10 | * 11 | * Created on January 9, 2020, 11:58 PM 12 | * 13 | * References: 14 | */ 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "../include/ext/loguru/loguru.hpp" 22 | 23 | #include "../include/config_parameters.hpp" 24 | 25 | //////////////////////////////// Helper methods //////////////////////////////// 26 | 27 | namespace 28 | { 29 | 30 | /** 31 | * @brief Strings labels of each parameter. 32 | */ 33 | const std::string c_instance_path = "instance_path"; 34 | const std::string c_output_dir = "output_dir"; 35 | const std::string c_solver_show_log = "solver_show_log"; 36 | const std::string c_solver_time_limit = "solver_time_limit"; 37 | const std::string c_solver_nb_threads = "solver_nb_threads"; 38 | const std::string c_nb_vehicles = "nb_vehicles"; 39 | const std::string c_model_policy = "model_policy"; 40 | const std::string c_sec_strategy = "sec_strategy"; 41 | 42 | /** 43 | * @brief Parse string to boolean. 44 | * @param: const std::string &: string to be parsed. 45 | * @return: bool: parsed value. 46 | */ 47 | bool parseBool(const std::string& str) 48 | { 49 | return str.compare("true") == 0; 50 | } 51 | 52 | /** 53 | * @brief:. 54 | * @param:. 55 | * @return:. 56 | */ 57 | std::size_t parseUint(const std::string& str) 58 | { 59 | int val = std::stoi(str); 60 | CHECK_F(val >= 0, "Input parameter: Invalid value"); 61 | return static_cast(val); 62 | } 63 | 64 | /** 65 | * @brief Parse string to unsigned int. It also checks if the input string is 66 | * set to max. If so, then parse to max value. 67 | * @param: const std::string &: string to be parsed. 68 | * @return: std::size_t: parsed value. 69 | */ 70 | std::size_t parseNbThreads(const std::string& str) 71 | { 72 | if (str == "max") 73 | { 74 | return std::thread::hardware_concurrency(); 75 | } 76 | 77 | int val = std::stoi(str); 78 | CHECK_F(val >= 0, "Input parameter: Invalid value"); 79 | 80 | return static_cast(val); 81 | } 82 | 83 | /** 84 | * @brief. 85 | */ 86 | ConfigParameters::model::policy_opt parsePolicyOpt(const std::string &str) 87 | { 88 | if (std::stoi(str) == 0) 89 | { 90 | return ConfigParameters::model::policy_opt::ML; 91 | } 92 | else 93 | { 94 | CHECK_F(std::stoi(str) == 1); 95 | return ConfigParameters::model::policy_opt::OU; 96 | } 97 | } 98 | 99 | /** 100 | * @brief. 101 | */ 102 | ConfigParameters::model::sec_opt parseSECOpt(const std::string &str) 103 | { 104 | if (std::stoi(str) == 0) 105 | { 106 | return ConfigParameters::model::sec_opt::STD; 107 | } 108 | else 109 | { 110 | CHECK_F(std::stoi(str) == 1); 111 | return ConfigParameters::model::sec_opt::CVRPSEP; 112 | } 113 | } 114 | 115 | /** 116 | * @brief. 117 | * @param:. 118 | * @return:. 119 | */ 120 | std::map readCfgFile(const std::string &config_path) 121 | { 122 | std::ifstream file(config_path); 123 | std::string line; 124 | 125 | std::map data; 126 | 127 | while (std::getline(file, line)) 128 | { 129 | std::size_t begin = line.find_first_not_of( " \f\t\v" ); 130 | 131 | if (begin == std::string::npos) 132 | { 133 | continue; // skip blank lines 134 | } 135 | 136 | if (std::string("#").find(line[begin]) != std::string::npos) 137 | { 138 | continue; // skip commentary 139 | } 140 | 141 | std::size_t end = line.find('=', begin); 142 | std::string key = line.substr(begin, end - begin); 143 | 144 | // (no leading or trailing whitespace allowed) 145 | key.erase(key.find_last_not_of( " \f\t\v" ) + 1); 146 | 147 | if (key.empty()) 148 | { 149 | continue; // no blank keys allowed 150 | } 151 | 152 | // extract the value (no leading or trailing whitespace allowed) 153 | begin = line.find_first_not_of(" \f\n\r\t\v", end + 1); 154 | end = line.find_last_not_of(" \f\n\r\t\v") + 1; 155 | 156 | std::string value = line.substr(begin, end - begin); 157 | 158 | data[key] = value; 159 | } 160 | 161 | return data; 162 | } 163 | 164 | } // anonymous namespace 165 | 166 | //////////////////////////////////////////////////////////////////////////////// 167 | 168 | ConfigParameters::ConfigParameters(const std::string config_path) 169 | { 170 | CHECK_F(std::filesystem::exists(config_path)); 171 | mData = readCfgFile(config_path); 172 | setupParameters(); 173 | } 174 | 175 | 176 | std::string ConfigParameters::getInstancePath() const 177 | { 178 | return mInstancePath; 179 | } 180 | 181 | 182 | std::string ConfigParameters::getOutputDir() const 183 | { 184 | return mOutputDir; 185 | } 186 | 187 | 188 | ConfigParameters::model ConfigParameters::getModelParams() const 189 | { 190 | return mModelParam; 191 | } 192 | 193 | 194 | ConfigParameters::solver ConfigParameters::getSolverParams() const 195 | { 196 | return mSolverParam; 197 | } 198 | 199 | 200 | void ConfigParameters::setLogFilePath(const std::string& path) 201 | { 202 | mSolverParam.logFile_ = path; 203 | } 204 | 205 | 206 | void ConfigParameters::show() const 207 | { 208 | RAW_LOG_F(INFO, std::string(80, '-').c_str()); 209 | RAW_LOG_F(INFO, "Parameters"); 210 | for (auto &e : mData) 211 | { 212 | std::ostringstream oss; 213 | oss << std::setw(40) << e.first << std::setw(40) << e.second; 214 | RAW_LOG_F(INFO, oss.str().c_str()); 215 | } 216 | RAW_LOG_F(INFO, std::string(80, '-').c_str()); 217 | } 218 | 219 | /////////////////////////////// private methods //////////////////////////////// 220 | 221 | void ConfigParameters::setupParameters() 222 | { 223 | // ---- General parameters ---- 224 | mInstancePath = mData[c_instance_path]; 225 | mOutputDir = mData[c_output_dir]; 226 | // ---- Solver parameters ---- 227 | mSolverParam.show_log = parseBool(mData[c_solver_show_log]); 228 | mSolverParam.time_limit = parseUint(mData[c_solver_time_limit]); 229 | mSolverParam.nb_threads = parseNbThreads(mData[c_solver_nb_threads]); 230 | // ---- Model parameters ---- 231 | mModelParam.K_ = parseUint(mData[c_nb_vehicles]); 232 | mModelParam.policy = parsePolicyOpt(mData[c_model_policy]); 233 | mModelParam.sec_strategy = parseSECOpt(mData[c_sec_strategy]); 234 | } -------------------------------------------------------------------------------- /src/ext/cvrpsep/basegrph.cpp: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include 6 | #include 7 | 8 | #include "../../../include/ext/cvrpsep/memmod.h" 9 | #include "../../../include/ext/cvrpsep/basegrph.h" 10 | 11 | void WriteReachPtr(ReachPtr P) 12 | { 13 | int i,j; 14 | 15 | if (P==NULL) 16 | { 17 | printf("ReachPtr==NULL\n"); 18 | return; 19 | } 20 | 21 | printf("ReachPtr (P->n = %d):\n",P->n); 22 | for (i=1; i<=P->n; i++) 23 | { 24 | if (P->LP[i].CFN > 0) 25 | { 26 | printf("%2d (%2d) ->",i,P->LP[i].CFN); 27 | for (j=1; j<=P->LP[i].CFN; j++) 28 | printf(" %d",P->LP[i].FAL[j]); 29 | printf("\n"); 30 | } 31 | 32 | if (P->LP[i].CBN > 0) 33 | { 34 | printf("%2d <-",i); 35 | for (j=1; j<=P->LP[i].CBN; j++) 36 | printf(" %d",P->LP[i].BAL[j]); 37 | printf("\n"); 38 | } 39 | } 40 | 41 | } 42 | 43 | void ReachInitMem(ReachPtr *P, int n) 44 | { 45 | int i; 46 | 47 | (*P) = (ReachTopRec *) MemGet(sizeof(ReachTopRec)); 48 | (*(*P)).n = n; 49 | (*(*P)).LP = (ReachNodeRec *) MemGet(sizeof(ReachNodeRec)*(n+1)); 50 | 51 | for (i=0; i<=n; i++) 52 | { 53 | (*(*P)).LP[i].CFN = 0; 54 | (*(*P)).LP[i].CBN = 0; 55 | (*(*P)).LP[i].FLD = 0; 56 | (*(*P)).LP[i].BLD = 0; 57 | (*(*P)).LP[i].FAL = NULL; 58 | (*(*P)).LP[i].BAL = NULL; 59 | } 60 | } 61 | 62 | void ReachPtrExpandDim(ReachPtr P, int NewN) 63 | { 64 | int i; 65 | 66 | P->LP = (ReachNodeRec *) MemReGet(P->LP,sizeof(ReachNodeRec)*(NewN+1)); 67 | 68 | for (i=P->n+1; i<=NewN; i++) 69 | { 70 | P->LP[i].CFN = 0; 71 | P->LP[i].CBN = 0; 72 | P->LP[i].FLD = 0; 73 | P->LP[i].BLD = 0; 74 | P->LP[i].FAL = NULL; 75 | P->LP[i].BAL = NULL; 76 | } 77 | 78 | P->n = NewN; 79 | } 80 | 81 | void ReachClearLists(ReachPtr P) 82 | { 83 | int i; 84 | 85 | for (i=1; i<=P->n; i++) 86 | { 87 | P->LP[i].CFN=0; 88 | P->LP[i].CBN=0; 89 | } 90 | } 91 | 92 | void ReachClearForwLists(ReachPtr P) 93 | { 94 | int i; 95 | 96 | for (i=1; i<=P->n; i++) 97 | P->LP[i].CFN=0; 98 | } 99 | 100 | void ReachSetForwList(ReachPtr P, int *ArcList, int Row, int Arcs) 101 | { 102 | int j; 103 | 104 | if (((*P).LP)[Row].FLD < Arcs) 105 | { 106 | ((*P).LP)[Row].FAL = (int *) 107 | MemReGet(((*P).LP)[Row].FAL, 108 | sizeof(int)*(Arcs+1)); 109 | ((*P).LP)[Row].FLD = Arcs; 110 | } 111 | 112 | for (j=1; j<=Arcs; j++) 113 | { 114 | ((*P).LP)[Row].FAL[j]=ArcList[j]; 115 | } 116 | 117 | ((*P).LP)[Row].CFN = Arcs; 118 | } 119 | 120 | 121 | void ReachSetBackwList(ReachPtr P, int *ArcList, int Col, int Arcs) 122 | { 123 | int j; 124 | 125 | if (((*P).LP)[Col].BLD < Arcs) 126 | { 127 | ((*P).LP)[Col].BAL = (int *) 128 | MemReGet(((*P).LP)[Col].BAL, 129 | sizeof(int)*(Arcs+1)); 130 | ((*P).LP)[Col].BLD = Arcs; 131 | } 132 | 133 | for (j=1; j<=Arcs; j++) 134 | { 135 | ((*P).LP)[Col].BAL[j]=ArcList[j]; 136 | } 137 | 138 | ((*P).LP)[Col].CBN = Arcs; 139 | } 140 | 141 | 142 | 143 | void ReachCreateInLists(ReachPtr P) 144 | { 145 | int i,j,k,n; 146 | int *InDegree; 147 | 148 | n = P->n; 149 | 150 | InDegree = MemGetIV(P->n+1); 151 | 152 | for (i=1; i<=n; i++) InDegree[i]=0; 153 | 154 | for (i=1; i<=n; i++) 155 | { 156 | for (j=1; j<=P->LP[i].CFN; j++) 157 | InDegree[P->LP[i].FAL[j]]++; 158 | } 159 | 160 | for (i=1; i<=n; i++) 161 | { 162 | if (P->LP[i].BLD < InDegree[i]) 163 | P->LP[i].BAL = (int *) MemReGet(P->LP[i].BAL,sizeof(int)*(InDegree[i]+1)); 164 | 165 | /* P->LP[i].BAL = MemGetIV(InDegree[i]+1); */ 166 | P->LP[i].BLD = InDegree[i]; 167 | P->LP[i].CBN = 0; 168 | } 169 | 170 | for (i=1; i<=n; i++) 171 | { 172 | for (j=1; j<=P->LP[i].CFN; j++) 173 | { 174 | k = P->LP[i].FAL[j]; 175 | P->LP[k].CBN++; 176 | P->LP[k].BAL[P->LP[k].CBN]=i; 177 | } 178 | } 179 | 180 | MemFree(InDegree); 181 | } 182 | 183 | void ReachAddArc(ReachPtr P, int Row, int Col) 184 | { 185 | int ArcsOut, ArcsIn; 186 | 187 | ArcsOut = ++(P->LP[Row].CFN); 188 | 189 | if (P->LP[Row].FLD < ArcsOut) 190 | { 191 | ((*P).LP)[Row].FAL = (int *) 192 | MemReGet(((*P).LP)[Row].FAL, 193 | sizeof(int)*(ArcsOut+1)); 194 | ((*P).LP)[Row].FLD = ArcsOut; 195 | } 196 | 197 | ((*P).LP)[Row].FAL[ArcsOut]=Col; 198 | 199 | ArcsIn = ++(P->LP[Col].CBN); 200 | 201 | if (P->LP[Col].BLD < ArcsIn) 202 | { 203 | P->LP[Col].BAL = (int *) MemReGet(P->LP[Col].BAL, 204 | sizeof(int)*(ArcsIn+1)); 205 | P->LP[Col].BLD = ArcsIn; 206 | } 207 | 208 | P->LP[Col].BAL[ArcsIn]=Row; 209 | } 210 | 211 | void ReachAddForwArc(ReachPtr P, int Row, int Col) 212 | { 213 | int ArcsOut, NewDim; 214 | 215 | ArcsOut = ++(P->LP[Row].CFN); 216 | 217 | if (P->LP[Row].FLD < ArcsOut) 218 | { 219 | NewDim=((*P).LP)[Row].FLD*2; 220 | if (NewDim < 4) NewDim=4; 221 | ((*P).LP)[Row].FAL = (int *) 222 | MemReGet(((*P).LP)[Row].FAL, 223 | sizeof(int)*(NewDim+1)); 224 | ((*P).LP)[Row].FLD = NewDim; 225 | } 226 | 227 | ((*P).LP)[Row].FAL[ArcsOut]=Col; 228 | } 229 | 230 | void CopyReachPtr(ReachPtr SourcePtr, ReachPtr *SinkPtr) 231 | { 232 | int i,j; 233 | 234 | if (SourcePtr == NULL) 235 | { 236 | *SinkPtr = NULL; 237 | return; 238 | } 239 | 240 | ReachInitMem(SinkPtr,SourcePtr->n); 241 | 242 | for (i=1; i<=SourcePtr->n; i++) 243 | { 244 | if (SourcePtr->LP[i].CFN>0) 245 | { 246 | (*SinkPtr)->LP[i].FAL = MemGetIV(SourcePtr->LP[i].CFN+1); 247 | for (j=1; j<=SourcePtr->LP[i].CFN; j++) 248 | (*SinkPtr)->LP[i].FAL[j]=SourcePtr->LP[i].FAL[j]; 249 | 250 | (*SinkPtr)->LP[i].CFN=SourcePtr->LP[i].CFN; 251 | (*SinkPtr)->LP[i].FLD=SourcePtr->LP[i].CFN; 252 | } 253 | 254 | if (SourcePtr->LP[i].CBN>0) 255 | { 256 | (*SinkPtr)->LP[i].BAL = MemGetIV(SourcePtr->LP[i].CBN+1); 257 | for (j=1; j<=SourcePtr->LP[i].CBN; j++) 258 | (*SinkPtr)->LP[i].BAL[j]=SourcePtr->LP[i].BAL[j]; 259 | 260 | (*SinkPtr)->LP[i].CBN=SourcePtr->LP[i].CBN; 261 | (*SinkPtr)->LP[i].BLD=SourcePtr->LP[i].CBN; 262 | } 263 | } 264 | } 265 | 266 | void ReachFreeMem(ReachPtr *P) 267 | { 268 | int i; 269 | 270 | if (*P == NULL) return; 271 | 272 | for (i=1; i<=(*P)->n; i++) 273 | { 274 | MemFree((*(*P)).LP[i].FAL); 275 | MemFree((*(*P)).LP[i].BAL); 276 | } 277 | 278 | MemFree((*(*P)).LP); 279 | MemFree(*P); 280 | *P=NULL; 281 | } 282 | 283 | void WriteCompPtr(CompFReachPtr P) 284 | { 285 | int i,j; 286 | 287 | if (P==NULL) 288 | { 289 | printf("\nCompFPtr == NULL\n"); 290 | return; 291 | } 292 | 293 | printf("\nCompFPtr:\n"); 294 | printf("NoOfRows = %d\n",P->NoOfRows); 295 | for (i=1; i<=P->NoOfRows; i++) 296 | { 297 | printf("Idx=%d, Row=%d, CFN=%d, FAL: ",i,P->FLP[i].Row,P->FLP[i].CFN); 298 | for (j=1; j<=P->FLP[i].CFN; j++) 299 | printf("%d ",P->FLP[i].FAL[j]); 300 | printf("\n"); 301 | } 302 | } 303 | 304 | void CopyReachPtrToCompPtr(ReachPtr SourcePtr, CompFReachPtr *SinkPtr) 305 | { 306 | int i,j,RowIdx,SourceRows; 307 | 308 | if (SourcePtr == NULL) 309 | { 310 | (*SinkPtr = NULL); 311 | return; 312 | } 313 | 314 | (*SinkPtr) = (CompFReachPtr) MemGet(sizeof(CompFReachRec)); 315 | 316 | for (SourceRows=0, i=1; i<=SourcePtr->n; i++) 317 | if (SourcePtr->LP[i].CFN>0) 318 | SourceRows++; 319 | 320 | (*SinkPtr)->NoOfRows=SourceRows; 321 | (*SinkPtr)->FLP = (CompFReachNodeRec *) 322 | MemGet(sizeof(CompFReachNodeRec)*(SourceRows+1)); 323 | 324 | for (RowIdx=0, i=1; i<=SourcePtr->n; i++) 325 | { 326 | if (SourcePtr->LP[i].CFN>0) 327 | { 328 | RowIdx++; 329 | (*SinkPtr)->FLP[RowIdx].Row=i; 330 | (*SinkPtr)->FLP[RowIdx].CFN=SourcePtr->LP[i].CFN; 331 | (*SinkPtr)->FLP[RowIdx].FAL = 332 | (int *) MemGet(sizeof(int)*(SourcePtr->LP[i].CFN+1)); 333 | 334 | for (j=1; j<=SourcePtr->LP[i].CFN; j++) 335 | (*SinkPtr)->FLP[RowIdx].FAL[j]=SourcePtr->LP[i].FAL[j]; 336 | } 337 | } 338 | } 339 | 340 | void CompFPtrFreeMem(CompFReachPtr *P) 341 | { 342 | int i; 343 | 344 | if ((*P)==NULL) return; 345 | 346 | for (i=1; i<=(*P)->NoOfRows; i++) 347 | MemFree((*P)->FLP[i].FAL); 348 | 349 | MemFree((*P)->FLP); 350 | MemFree((*P)); 351 | (*P)=NULL; 352 | } 353 | 354 | -------------------------------------------------------------------------------- /src/ext/cvrpsep/capsep.cpp: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include 6 | #include 7 | 8 | #include "../../../include/ext/cvrpsep/memmod.h" 9 | #include "../../../include/ext/cvrpsep/basegrph.h" 10 | #include "../../../include/ext/cvrpsep/sort.h" 11 | #include "../../../include/ext/cvrpsep/cnstrmgr.h" 12 | #include "../../../include/ext/cvrpsep/cutbase.h" 13 | #include "../../../include/ext/cvrpsep/compcuts.h" 14 | #include "../../../include/ext/cvrpsep/compress.h" 15 | #include "../../../include/ext/cvrpsep/fcapfix.h" 16 | #include "../../../include/ext/cvrpsep/grsearch.h" 17 | 18 | void CAPSEP_GetOneVehicleCapCuts(CnstrMgrPointer CutsCMP, 19 | ReachPtr *RPtr, 20 | int *NoOfCuts) 21 | { 22 | int i,Dim,Size; 23 | double SetSize,RHS; 24 | 25 | CnstrMgrPointer CMP; 26 | 27 | Size = 0; 28 | Dim = 50; 29 | ReachInitMem(RPtr,Dim); 30 | 31 | CMP = CutsCMP; 32 | 33 | for (i=0; iSize; i++) 34 | { 35 | if (CMP->CPL[i]->CType == CMGR_CT_CAP) 36 | { 37 | SetSize = 1.0 * CMP->CPL[i]->IntListSize; 38 | RHS = CMP->CPL[i]->RHS; 39 | 40 | /* RHS must be equal to SetSize - 1. */ 41 | if ((RHS >= (SetSize - 1.01)) && (RHS <= (SetSize - 0.99))) 42 | { 43 | Size++; 44 | if (Size > Dim) 45 | { 46 | Dim *= 2; 47 | ReachPtrExpandDim((*RPtr),Dim); 48 | } 49 | 50 | ReachSetForwList((*RPtr), 51 | CMP->CPL[i]->IntList, 52 | Size, 53 | CMP->CPL[i]->IntListSize); 54 | } 55 | } 56 | } 57 | 58 | *NoOfCuts = Size; 59 | } 60 | 61 | void CAPSEP_SeparateCapCuts(int NoOfCustomers, 62 | int *Demand, 63 | int CAP, 64 | int NoOfEdges, 65 | int *EdgeTail, 66 | int *EdgeHead, 67 | double *EdgeX, 68 | CnstrMgrPointer CMPExistingCuts, 69 | int MaxNoOfCuts, 70 | double EpsForIntegrality, 71 | char *IntegerAndFeasible, 72 | double *MaxViolation, 73 | CnstrMgrPointer CutsCMP) 74 | { 75 | int i,j,k,Idx; 76 | int GeneratedCuts; 77 | int NoOfV1Cuts; 78 | int ShrunkGraphCustNodes; 79 | int MaxCuts; 80 | int FCapFixRounds; 81 | int GeneratedAntiSets; 82 | int CutsBeforeLastProc; 83 | int CutNr,NodeListSize,NodeSum; 84 | int MinV; 85 | double XSumInSet,LHS,RHS,Violation,EpsViolation,EpsInt; 86 | int *SuperDemand; 87 | int *SuperNodeSize; 88 | int *NodeList; 89 | double *XInSuperNode; 90 | double **XMatrix; 91 | double **SMatrix; 92 | ReachPtr SupportPtr; 93 | ReachPtr V1CutsPtr; 94 | ReachPtr SAdjRPtr; 95 | ReachPtr SuperNodesRPtr; 96 | ReachPtr CapCutsRPtr; 97 | ReachPtr AntiSetsRPtr; 98 | ReachPtr OrigCapCutsRPtr; 99 | 100 | EpsViolation = 0.01; 101 | *IntegerAndFeasible = 0; 102 | 103 | ReachInitMem(&SupportPtr,NoOfCustomers+1); 104 | ReachInitMem(&SAdjRPtr,NoOfCustomers+1); 105 | ReachInitMem(&SuperNodesRPtr,NoOfCustomers+1); 106 | ReachInitMem(&CapCutsRPtr,MaxNoOfCuts); 107 | ReachInitMem(&OrigCapCutsRPtr,MaxNoOfCuts); 108 | AntiSetsRPtr = NULL; 109 | 110 | SuperDemand = MemGetIV(NoOfCustomers+1); 111 | SuperNodeSize = MemGetIV(NoOfCustomers+1); 112 | NodeList = MemGetIV(NoOfCustomers+1); 113 | XInSuperNode = MemGetDV(NoOfCustomers+1); 114 | 115 | SMatrix = MemGetDM(NoOfCustomers+2,NoOfCustomers+2); 116 | XMatrix = MemGetDM(NoOfCustomers+2,NoOfCustomers+2); 117 | for (i=1; i<=NoOfCustomers+1; i++) 118 | for (j=1; j<=NoOfCustomers+1; j++) 119 | XMatrix[i][j] = 0.0; 120 | 121 | 122 | for (i=1; i<=NoOfEdges; i++) 123 | { 124 | ReachAddForwArc(SupportPtr,EdgeTail[i],EdgeHead[i]); 125 | ReachAddForwArc(SupportPtr,EdgeHead[i],EdgeTail[i]); 126 | 127 | XMatrix[EdgeTail[i]][EdgeHead[i]] = EdgeX[i]; 128 | XMatrix[EdgeHead[i]][EdgeTail[i]] = EdgeX[i]; 129 | } 130 | 131 | *MaxViolation = 0.0; 132 | GeneratedCuts = 0; 133 | 134 | COMPCUTS_ComputeCompCuts(SupportPtr, 135 | NoOfCustomers, 136 | Demand, 137 | CAP, 138 | XMatrix, 139 | CutsCMP, 140 | &GeneratedCuts); 141 | 142 | if (GeneratedCuts > 0) 143 | { 144 | for (i=0; iCPL[i]->IntList, 147 | CutsCMP->CPL[i]->IntListSize); 148 | 149 | CUTBASE_CompCapViolation(SupportPtr, 150 | NoOfCustomers, 151 | NULL, 152 | CutsCMP->CPL[i]->IntList, 153 | CutsCMP->CPL[i]->IntListSize, 154 | Demand, 155 | CAP, 156 | XMatrix, 157 | &Violation); 158 | 159 | if (Violation > *MaxViolation) *MaxViolation = Violation; 160 | } 161 | 162 | goto EndOfCapSep; 163 | } 164 | 165 | *IntegerAndFeasible = 1; 166 | 167 | EpsInt = EpsForIntegrality; 168 | for (i=1; i<=NoOfCustomers; i++) 169 | { 170 | for (k=1; k<=SupportPtr->LP[i].CFN; k++) 171 | { 172 | j = SupportPtr->LP[i].FAL[k]; 173 | if (j < i) continue; 174 | 175 | if (((XMatrix[i][j] >= EpsInt) && (XMatrix[i][j] <= (1.0-EpsInt))) || 176 | ((XMatrix[i][j] >= (1.0+EpsInt)) && (XMatrix[i][j] <= (2.0-EpsInt)))) 177 | { 178 | *IntegerAndFeasible = 0; 179 | goto NotIntegerAndFeasible; 180 | } 181 | } 182 | } 183 | 184 | NotIntegerAndFeasible: 185 | 186 | V1CutsPtr = NULL; 187 | CAPSEP_GetOneVehicleCapCuts(CMPExistingCuts, 188 | &V1CutsPtr, 189 | &NoOfV1Cuts); 190 | 191 | COMPRESS_ShrinkGraph(SupportPtr, 192 | NoOfCustomers, 193 | XMatrix, 194 | SMatrix, 195 | NoOfV1Cuts, 196 | V1CutsPtr, 197 | SAdjRPtr, 198 | SuperNodesRPtr, 199 | &ShrunkGraphCustNodes); 200 | 201 | ReachFreeMem(&V1CutsPtr); 202 | 203 | /* Compute data of supernodes */ 204 | for (i=1; i<=ShrunkGraphCustNodes; i++) 205 | { 206 | SuperNodeSize[i] = SuperNodesRPtr->LP[i].CFN; 207 | XInSuperNode[i] = SMatrix[i][i]; 208 | 209 | SuperDemand[i] = 0; 210 | for (j=1; j<=SuperNodesRPtr->LP[i].CFN; j++) 211 | { 212 | k = SuperNodesRPtr->LP[i].FAL[j]; 213 | SuperDemand[i] += Demand[k]; 214 | } 215 | } 216 | 217 | FCapFixRounds = 3; 218 | MaxCuts = MaxNoOfCuts / 2; 219 | 220 | FCAPFIX_ComputeCuts(SAdjRPtr, 221 | ShrunkGraphCustNodes, 222 | SuperDemand, 223 | CAP, 224 | SuperNodeSize, 225 | SMatrix, 226 | MaxCuts, 227 | FCapFixRounds, 228 | &GeneratedCuts, 229 | CapCutsRPtr); 230 | 231 | /* Add information to CapCutsRPtr so that the labels will be 232 | set up correctly for the greedy search. */ 233 | 234 | for (i=1; i<=GeneratedCuts; i++) 235 | { 236 | /* Compute sum (k) of node numbers. */ 237 | k = 0; 238 | for (Idx=1; Idx<=CapCutsRPtr->LP[i].CFN; Idx++) 239 | { 240 | j = CapCutsRPtr->LP[i].FAL[Idx]; 241 | k += j; 242 | } 243 | 244 | NodeList[1] = k; 245 | ReachSetBackwList(CapCutsRPtr,NodeList,i,1); 246 | /* Backward arc list length equals one means that only the entire set 247 | is prohibited. */ 248 | } 249 | 250 | /* Copy contents of CapCutsRPtr to AntiSetsRPtr for greedy search */ 251 | CopyReachPtr(CapCutsRPtr,&AntiSetsRPtr); 252 | GeneratedAntiSets = GeneratedCuts; 253 | 254 | ReachPtrExpandDim(AntiSetsRPtr,CapCutsRPtr->n + ShrunkGraphCustNodes); 255 | 256 | MaxCuts = MaxNoOfCuts; /* Now allow up to the total maximum */ 257 | GRSEARCH_CapCuts(SAdjRPtr, 258 | ShrunkGraphCustNodes, 259 | SuperDemand, 260 | CAP, 261 | SuperNodeSize, 262 | XInSuperNode, 263 | SMatrix, 264 | &GeneratedCuts, 265 | &GeneratedAntiSets, 266 | CapCutsRPtr, 267 | AntiSetsRPtr, 268 | MaxCuts); 269 | 270 | CutsBeforeLastProc = GeneratedCuts; 271 | /* Expand cuts to original nodes. */ 272 | for (CutNr=1; CutNr<=GeneratedCuts; CutNr++) 273 | { 274 | /* Expand supernodes. */ 275 | NodeListSize=0; 276 | NodeSum=0; 277 | for (Idx=1; Idx<=CapCutsRPtr->LP[CutNr].CFN; Idx++) 278 | { 279 | i = CapCutsRPtr->LP[CutNr].FAL[Idx]; /* Supernode nr. i. */ 280 | for (j=1; j<=SuperNodesRPtr->LP[i].CFN; j++) 281 | { 282 | k = SuperNodesRPtr->LP[i].FAL[j]; /* Original node nr. k. */ 283 | NodeList[++NodeListSize] = k; 284 | NodeSum += k; 285 | } 286 | } 287 | 288 | CUTBASE_CompVehiclesForSet(NoOfCustomers,NULL, 289 | NodeList,NodeListSize, 290 | Demand,CAP, 291 | &MinV); 292 | RHS = NodeListSize - MinV; 293 | 294 | CUTBASE_CompXSumInSet(SupportPtr,NoOfCustomers,NULL, 295 | NodeList,NodeListSize, 296 | XMatrix, 297 | &XSumInSet); 298 | 299 | LHS = XSumInSet; 300 | Violation = LHS - RHS; 301 | 302 | if (Violation > *MaxViolation) *MaxViolation = Violation; 303 | 304 | if (Violation >= EpsViolation) 305 | { 306 | SortIVInc(NodeList,NodeListSize); 307 | CMGR_AddCnstr(CutsCMP, 308 | CMGR_CT_CAP,0, 309 | NodeListSize, 310 | NodeList, 311 | RHS); 312 | } 313 | 314 | ReachSetForwList(OrigCapCutsRPtr,NodeList,CutNr,NodeListSize); 315 | 316 | NodeList[1] = NodeSum; 317 | ReachSetBackwList(OrigCapCutsRPtr,NodeList,CutNr,1); 318 | /* Backward arc list equals one means that only the entire set 319 | is prohibited. */ 320 | } 321 | 322 | 323 | if (GeneratedCuts < MaxNoOfCuts) 324 | { 325 | GRSEARCH_AddDropCapsOnGS(SAdjRPtr, 326 | NoOfCustomers, 327 | ShrunkGraphCustNodes, 328 | SuperDemand,CAP, 329 | SuperNodeSize, 330 | XInSuperNode, 331 | SuperNodesRPtr, 332 | SMatrix, 333 | EpsViolation, 334 | CMPExistingCuts, 335 | &GeneratedCuts, 336 | MaxNoOfCuts, 337 | OrigCapCutsRPtr); 338 | 339 | for (CutNr=CutsBeforeLastProc+1; CutNr<=GeneratedCuts; CutNr++) 340 | { 341 | NodeListSize = OrigCapCutsRPtr->LP[CutNr].CFN; 342 | 343 | for (i=1; i<=NodeListSize; i++) 344 | { 345 | NodeList[i] = OrigCapCutsRPtr->LP[CutNr].FAL[i]; 346 | } 347 | 348 | CUTBASE_CompVehiclesForSet(NoOfCustomers,NULL, 349 | NodeList,NodeListSize, 350 | Demand,CAP, 351 | &MinV); 352 | RHS = NodeListSize - MinV; 353 | 354 | CUTBASE_CompXSumInSet(SupportPtr,NoOfCustomers,NULL, 355 | NodeList,NodeListSize, 356 | XMatrix, 357 | &XSumInSet); 358 | 359 | LHS = XSumInSet; 360 | Violation = LHS - RHS; 361 | 362 | if (Violation > *MaxViolation) *MaxViolation = Violation; 363 | 364 | if (Violation >= EpsViolation) 365 | { 366 | SortIVInc(NodeList,NodeListSize); 367 | CMGR_AddCnstr(CutsCMP, 368 | CMGR_CT_CAP,0, 369 | NodeListSize, 370 | NodeList, 371 | RHS); 372 | } 373 | } 374 | } 375 | 376 | /* GeneratedCuts = CutsCMP->Size. */ 377 | 378 | EndOfCapSep: 379 | 380 | MemFree(SuperDemand); 381 | MemFree(SuperNodeSize); 382 | MemFree(NodeList); 383 | MemFree(XInSuperNode); 384 | 385 | MemFreeDM(SMatrix,NoOfCustomers+2); 386 | MemFreeDM(XMatrix,NoOfCustomers+2); 387 | 388 | ReachFreeMem(&SupportPtr); 389 | ReachFreeMem(&SAdjRPtr); 390 | ReachFreeMem(&SuperNodesRPtr); 391 | ReachFreeMem(&CapCutsRPtr); 392 | ReachFreeMem(&AntiSetsRPtr); 393 | ReachFreeMem(&OrigCapCutsRPtr); 394 | } 395 | 396 | -------------------------------------------------------------------------------- /src/ext/cvrpsep/cnstrmgr.cpp: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include 6 | #include 7 | 8 | #include "../../../include/ext/cvrpsep/sort.h" 9 | #include "../../../include/ext/cvrpsep/cnstrmgr.h" 10 | #include "../../../include/ext/cvrpsep/memmod.h" 11 | 12 | void CMGR_CreateCMgr(CnstrMgrPointer *CMP, int Dim) 13 | { 14 | int i; 15 | 16 | (*CMP) = (CnstrMgrPointer) MemGet(sizeof(CnstrMgrRecord)); 17 | (*CMP)->Dim = Dim; 18 | (*CMP)->Size = 0; 19 | (*CMP)->CPL = (CnstrPointerList) MemGet(sizeof(CnstrPointer)*Dim); 20 | 21 | for (i=0; iCPL[i] = NULL; 23 | 24 | /* (*CMP)->CPL[i] = (CnstrPointer) MemGet(sizeof(CnstrRecord)); */ 25 | 26 | /* 27 | for (i=0; iCPL[i]->CType = 0; 30 | (*CMP)->CPL[i]->Key = 0; 31 | (*CMP)->CPL[i]->IntListSize = 0; 32 | (*CMP)->CPL[i]->IntList = NULL; 33 | (*CMP)->CPL[i]->RHS = 0.0; 34 | } 35 | */ 36 | 37 | } 38 | 39 | void CMGR_ExpandCMgr(CnstrMgrPointer CMP, int NewDim) 40 | { 41 | int i; 42 | 43 | if (NewDim <= CMP->Dim) return; 44 | 45 | CMP->CPL = (CnstrPointerList) MemReGet(CMP->CPL,sizeof(CnstrPointer)*NewDim); 46 | 47 | for (i=CMP->Dim; iCPL[i] = NULL; 50 | /* CMP->CPL[i] = (CnstrPointer) MemGet(sizeof(CnstrRecord)); */ 51 | 52 | /* 53 | for (i=CMP->Dim; iCPL[i]->CType = 0; 56 | CMP->CPL[i]->Key = 0; 57 | CMP->CPL[i]->IntListSize = 0; 58 | CMP->CPL[i]->IntList = NULL; 59 | CMP->CPL[i]->RHS = 0.0; 60 | } 61 | */ 62 | 63 | CMP->Dim = NewDim; 64 | } 65 | 66 | void CMGR_FreeMemCMgr(CnstrMgrPointer *CMP) 67 | { 68 | int i; 69 | 70 | if (*CMP == NULL) return; 71 | 72 | for (i=0; i<(*CMP)->Dim; i++) 73 | { 74 | if ((*CMP)->CPL[i] == NULL) continue; 75 | if ((*CMP)->CPL[i]->IntList != NULL) MemFree((*CMP)->CPL[i]->IntList); 76 | if ((*CMP)->CPL[i]->ExtList != NULL) MemFree((*CMP)->CPL[i]->ExtList); 77 | if ((*CMP)->CPL[i]->CList != NULL) MemFree((*CMP)->CPL[i]->CList); 78 | MemFree((*CMP)->CPL[i]); 79 | } 80 | 81 | MemFree((*CMP)->CPL); 82 | MemFree(*CMP); 83 | *CMP = NULL; 84 | } 85 | 86 | void CMGR_AddCnstr(CnstrMgrPointer CMP, 87 | int CType, int Key, int IntListSize, int *IntList, 88 | double RHS) 89 | { 90 | int i,j; 91 | 92 | if (CMP->Dim <= CMP->Size) 93 | { 94 | i = CMP->Size + 100; 95 | CMGR_ExpandCMgr(CMP,i); 96 | } 97 | 98 | (CMP->Size)++; 99 | i = CMP->Size - 1; /* Index k-1 is used for the k'th constraint. */ 100 | 101 | CMP->CPL[i] = (CnstrPointer) MemGet(sizeof(CnstrRecord)); 102 | 103 | CMP->CPL[i]->CType = CType; 104 | CMP->CPL[i]->Key = Key; 105 | CMP->CPL[i]->IntListSize = IntListSize; 106 | CMP->CPL[i]->RHS = RHS; 107 | CMP->CPL[i]->IntList = NULL; 108 | CMP->CPL[i]->GlobalNr = 0; 109 | 110 | if (IntListSize > 0) 111 | { 112 | CMP->CPL[i]->IntList = MemGetIV(IntListSize+1); 113 | /* Index from 1 to IntListSize. */ 114 | for (j=1; j<=IntListSize; j++) 115 | CMP->CPL[i]->IntList[j] = IntList[j]; 116 | } 117 | 118 | CMP->CPL[i]->ExtListSize = 0; 119 | CMP->CPL[i]->ExtList = NULL; 120 | 121 | CMP->CPL[i]->CListSize = 0; 122 | CMP->CPL[i]->CList = NULL; 123 | 124 | CMP->CPL[i]->CoeffList = NULL; 125 | 126 | CMP->CPL[i]->BranchLevel = 0; 127 | } 128 | 129 | void CMGR_AddBranchCnstr(CnstrMgrPointer CMP, 130 | int CType, int Key, int IntListSize, int *IntList, 131 | double RHS, 132 | int BranchLevel) 133 | { 134 | int i; 135 | 136 | CMGR_AddCnstr(CMP,CType,Key,IntListSize,IntList,RHS); 137 | 138 | i = CMP->Size - 1; 139 | CMP->CPL[i]->BranchLevel = BranchLevel; 140 | } 141 | 142 | 143 | void CMGR_AddExtCnstr(CnstrMgrPointer CMP, 144 | int CType, int Key, int IntListSize, int *IntList, 145 | int ExtListSize, int *ExtList, 146 | double RHS) 147 | { 148 | int i,j; 149 | 150 | CMGR_AddCnstr(CMP,CType,Key,IntListSize,IntList,RHS); 151 | if (ExtListSize > 0) 152 | { 153 | i = CMP->Size - 1; 154 | 155 | CMP->CPL[i]->ExtListSize = ExtListSize; 156 | 157 | CMP->CPL[i]->ExtList = MemGetIV(ExtListSize+1); 158 | 159 | for (j=1; j<=ExtListSize; j++) 160 | CMP->CPL[i]->ExtList[j] = ExtList[j]; 161 | } 162 | } 163 | 164 | void CMGR_AddExplicitCnstr(CnstrMgrPointer CMP, 165 | int CType, int Key, 166 | int ListSize, 167 | int *IntList, 168 | int *ExtList, 169 | double *CoeffList, 170 | double RHS) 171 | { 172 | int i,j; 173 | 174 | CMGR_AddCnstr(CMP,CType,Key,ListSize,IntList,RHS); 175 | 176 | i = CMP->Size - 1; 177 | 178 | CMP->CPL[i]->ExtListSize = ListSize; 179 | 180 | CMP->CPL[i]->ExtList = MemGetIV(ListSize+1); 181 | 182 | for (j=1; j<=ListSize; j++) 183 | CMP->CPL[i]->ExtList[j] = ExtList[j]; 184 | 185 | CMP->CPL[i]->CoeffList = MemGetDV(ListSize+1); 186 | 187 | for (j=1; j<=ListSize; j++) 188 | CMP->CPL[i]->CoeffList[j] = CoeffList[j]; 189 | } 190 | 191 | void CMGR_AddGomoryCnstr(CnstrMgrPointer CMP, 192 | int CType, int Key, 193 | int ListSize, 194 | int *IntList, /* Variable numbers */ 195 | double *CoeffList, 196 | double RHS) /* >= RHS */ 197 | { 198 | int i,j; 199 | 200 | CMGR_AddCnstr(CMP,CType,Key,ListSize,IntList,RHS); 201 | 202 | i = CMP->Size - 1; 203 | 204 | CMP->CPL[i]->CoeffList = MemGetDV(ListSize+1); 205 | 206 | for (j=1; j<=ListSize; j++) 207 | CMP->CPL[i]->CoeffList[j] = CoeffList[j]; 208 | } 209 | 210 | 211 | void CMGR_AppendCMP(CnstrMgrPointer Sink, 212 | CnstrMgrPointer Source) 213 | { 214 | /* Append a copy of each record in Source to Sink */ 215 | int i,j; 216 | 217 | for (i=0; iSize; i++) 218 | { 219 | CMGR_AddExtCnstr(Sink, 220 | Source->CPL[i]->CType,Source->CPL[i]->Key, 221 | Source->CPL[i]->IntListSize,Source->CPL[i]->IntList, 222 | Source->CPL[i]->ExtListSize,Source->CPL[i]->ExtList, 223 | Source->CPL[i]->RHS); 224 | 225 | j = Sink->Size - 1; 226 | 227 | Sink->CPL[j]->A = Source->CPL[i]->A; 228 | Sink->CPL[j]->B = Source->CPL[i]->B; 229 | Sink->CPL[j]->L = Source->CPL[i]->L; 230 | 231 | Sink->CPL[j]->BranchLevel = Source->CPL[i]->BranchLevel; 232 | } 233 | } 234 | 235 | void CMGR_CompareLists(int ListSizeA, int *ListA, 236 | int ListSizeB, int *ListB, 237 | char *Equal) 238 | { 239 | int i; 240 | 241 | *Equal = 0; 242 | if (ListSizeA == ListSizeB) 243 | { 244 | *Equal = 1; 245 | for (i=1; i<=ListSizeA; i++) 246 | { 247 | if (ListA[i] != ListB[i]) 248 | { 249 | *Equal = 0; 250 | return; 251 | } 252 | } 253 | } 254 | } 255 | 256 | 257 | void CMGR_CheckDomPartialMStar(CnstrMgrPointer CMP, 258 | int IntListSize, int *IntList, 259 | int ExtListSize, int *ExtList, 260 | int CListSize, int *CList, 261 | int A, int B, int L, 262 | char *Dominated) 263 | { 264 | char Equal; 265 | char NotDomByThis; 266 | int i,j,Idx,MaxIntVal; 267 | char *InList; 268 | 269 | MaxIntVal = 0; 270 | for (i=1; i<=IntListSize; i++) 271 | if (IntList[i] > MaxIntVal) 272 | MaxIntVal = IntList[i]; 273 | 274 | for (i=1; i<=ExtListSize; i++) 275 | if (ExtList[i] > MaxIntVal) 276 | MaxIntVal = ExtList[i]; 277 | 278 | for (i=1; i<=CListSize; i++) 279 | if (CList[i] > MaxIntVal) 280 | MaxIntVal = CList[i]; 281 | 282 | InList = MemGetCV(MaxIntVal+1); 283 | 284 | *Dominated = 0; 285 | 286 | for (Idx=0; IdxSize; Idx++) 287 | { 288 | if (CMP->CPL[Idx]->CType != CMGR_CT_MSTAR) continue; 289 | 290 | if ((CMP->CPL[Idx]->L * B) < (L * CMP->CPL[Idx]->B)) 291 | { 292 | NotDomByThis = 1; 293 | continue; 294 | } 295 | 296 | if ((CMP->CPL[Idx]->A * B) < (A * CMP->CPL[Idx]->B)) 297 | { 298 | NotDomByThis = 1; 299 | continue; 300 | } 301 | 302 | CMGR_CompareLists(CMP->CPL[Idx]->IntListSize, 303 | CMP->CPL[Idx]->IntList, 304 | IntListSize,IntList,&Equal); 305 | if (Equal == 0) continue; 306 | 307 | for (i=1; i<=MaxIntVal; i++) InList[i] = 0; 308 | 309 | for (i=1; i<=CMP->CPL[Idx]->ExtListSize; i++) 310 | { 311 | j = CMP->CPL[Idx]->ExtList[i]; 312 | if (j <= MaxIntVal) 313 | InList[j] = 1; 314 | } 315 | 316 | NotDomByThis = 0; 317 | for (i=1; i<=ExtListSize; i++) 318 | { 319 | j = ExtList[i]; 320 | if (InList[j] == 0) 321 | { 322 | NotDomByThis = 1; 323 | break; 324 | } 325 | } 326 | 327 | if (NotDomByThis) continue; 328 | 329 | for (i=1; i<=MaxIntVal; i++) InList[i] = 0; 330 | 331 | for (i=1; i<=CMP->CPL[Idx]->CListSize; i++) 332 | { 333 | j = CMP->CPL[Idx]->CList[i]; 334 | if (j <= MaxIntVal) 335 | InList[j] = 1; 336 | } 337 | 338 | NotDomByThis = 0; 339 | for (i=1; i<=CListSize; i++) 340 | { 341 | j = CList[i]; 342 | if (InList[j] == 0) 343 | { 344 | NotDomByThis = 1; 345 | break; 346 | } 347 | } 348 | 349 | if (NotDomByThis) continue; 350 | 351 | *Dominated = 1; 352 | break; 353 | } 354 | 355 | MemFree(InList); 356 | 357 | } 358 | 359 | 360 | void CMGR_SearchPartialMStar(CnstrMgrPointer CMP, 361 | int IntListSize, int *IntList, 362 | int ExtListSize, int *ExtList, 363 | int CListSize, int *CList, 364 | int A, int B, int L, 365 | char *MStarExists) 366 | { 367 | char Equal; 368 | int Idx; 369 | 370 | *MStarExists = 0; 371 | 372 | for (Idx=0; IdxSize; Idx++) 373 | { 374 | if (CMP->CPL[Idx]->CType != CMGR_CT_MSTAR) continue; 375 | 376 | CMGR_CompareLists(CMP->CPL[Idx]->IntListSize, 377 | CMP->CPL[Idx]->IntList, 378 | IntListSize,IntList,&Equal); 379 | if (Equal == 0) continue; 380 | 381 | CMGR_CompareLists(CMP->CPL[Idx]->ExtListSize, 382 | CMP->CPL[Idx]->ExtList, 383 | ExtListSize,ExtList,&Equal); 384 | if (Equal == 0) continue; 385 | 386 | CMGR_CompareLists(CMP->CPL[Idx]->CListSize, 387 | CMP->CPL[Idx]->CList, 388 | CListSize,CList,&Equal); 389 | if (Equal == 0) continue; 390 | 391 | if ((CMP->CPL[Idx]->A == A) && 392 | (CMP->CPL[Idx]->B == B) && 393 | (CMP->CPL[Idx]->L == L)) 394 | { 395 | Equal = 1; 396 | } 397 | 398 | if (Equal == 1) 399 | { 400 | *MStarExists = 1; 401 | break; 402 | } 403 | } 404 | } 405 | 406 | 407 | void CMGR_SearchMStar(CnstrMgrPointer CMP, 408 | int IntListSize, int *IntList, 409 | int ExtListSize, int *ExtList, 410 | int A, int B, int L, 411 | char *MStarExists) 412 | { 413 | char Diff; 414 | int i,j,k,Idx; 415 | 416 | *MStarExists = 0; 417 | 418 | for (Idx=0; IdxSize; Idx++) 419 | { 420 | if (CMP->CPL[Idx]->CType != CMGR_CT_MSTAR) continue; 421 | 422 | if (IntListSize != CMP->CPL[Idx]->IntListSize) continue; 423 | if (ExtListSize != CMP->CPL[Idx]->ExtListSize) continue; 424 | 425 | Diff = 0; 426 | for (i=1; i<=IntListSize; i++) 427 | { 428 | j = IntList[i]; 429 | k = CMP->CPL[Idx]->IntList[i]; 430 | 431 | if (j != k) 432 | { 433 | Diff = 1; 434 | break; 435 | } 436 | } 437 | 438 | if (Diff == 1) continue; 439 | 440 | for (i=1; i<=ExtListSize; i++) 441 | { 442 | j = ExtList[i]; 443 | k = CMP->CPL[Idx]->ExtList[i]; 444 | 445 | if (j != k) 446 | { 447 | Diff = 1; 448 | break; 449 | } 450 | } 451 | 452 | if (Diff == 1) continue; 453 | 454 | if ((CMP->CPL[Idx]->A != A) || 455 | (CMP->CPL[Idx]->B != B) || 456 | (CMP->CPL[Idx]->L != L)) 457 | { 458 | Diff = 1; 459 | } 460 | 461 | if (Diff == 0) 462 | { 463 | *MStarExists = 1; 464 | break; 465 | } 466 | } 467 | } 468 | 469 | void CMGR_SearchCap(CnstrMgrPointer CMP, 470 | int IntListSize, int *IntList, 471 | char *CapExists) 472 | { 473 | char Diff; 474 | int i,j,k,Idx; 475 | 476 | *CapExists = 0; 477 | 478 | for (Idx=0; IdxSize; Idx++) 479 | { 480 | if (CMP->CPL[Idx]->CType != CMGR_CT_CAP) continue; 481 | 482 | if (IntListSize != CMP->CPL[Idx]->IntListSize) continue; 483 | 484 | Diff = 0; 485 | for (i=1; i<=IntListSize; i++) 486 | { 487 | j = IntList[i]; 488 | k = CMP->CPL[Idx]->IntList[i]; 489 | 490 | if (j != k) 491 | { 492 | Diff = 1; 493 | break; 494 | } 495 | } 496 | 497 | if (Diff == 0) 498 | { 499 | *CapExists = 1; 500 | break; 501 | } 502 | } 503 | } 504 | 505 | 506 | void CMGR_AddMStar(CnstrMgrPointer CMP, 507 | int CType, int Key, int IntListSize, int *IntList, 508 | int ExtListSize, int *ExtList, 509 | int A, int B, int L) 510 | { 511 | int i; 512 | 513 | SortIVInc(IntList,IntListSize); 514 | SortIVInc(ExtList,ExtListSize); 515 | 516 | CMGR_AddExtCnstr(CMP,CType,Key, 517 | IntListSize,IntList, 518 | ExtListSize,ExtList, 519 | 0.0); 520 | 521 | i = CMP->Size - 1; 522 | CMP->CPL[i]->A = A; 523 | CMP->CPL[i]->B = B; 524 | CMP->CPL[i]->L = L; 525 | } 526 | 527 | void CMGR_AddPartialMStar(CnstrMgrPointer CMP, 528 | int CType, int Key, 529 | int IntListSize, int *IntList, 530 | int ExtListSize, int *ExtList, 531 | int CListSize, int *CList, 532 | int A, int B, int L) 533 | { 534 | char Dominated; 535 | int i,j; 536 | 537 | if (CListSize > 0) SortIVInc(CList,CListSize); 538 | 539 | CMGR_CheckDomPartialMStar(CMP, 540 | IntListSize,IntList, 541 | ExtListSize,ExtList, 542 | CListSize,CList, 543 | A,B,L, 544 | &Dominated); 545 | 546 | if (Dominated) 547 | { 548 | return; 549 | } 550 | 551 | CMGR_AddMStar(CMP, 552 | CType,Key, 553 | IntListSize,IntList, 554 | ExtListSize,ExtList, 555 | A,B,L); 556 | 557 | i = CMP->Size - 1; 558 | CMP->CPL[i]->CListSize = CListSize; 559 | CMP->CPL[i]->CList = NULL; 560 | 561 | if (CListSize > 0) 562 | { 563 | CMP->CPL[i]->CList = MemGetIV(CListSize+1); 564 | 565 | for (j=1; j<=CListSize; j++) 566 | CMP->CPL[i]->CList[j] = CList[j]; 567 | } 568 | 569 | } 570 | 571 | void CMGR_MoveCnstr(CnstrMgrPointer SourcePtr, 572 | CnstrMgrPointer SinkPtr, 573 | int SourceIndex, 574 | int SinkIndex) 575 | { 576 | int i; 577 | 578 | if (SinkIndex == 0) 579 | { 580 | /* Add constraint to SinkPtr. */ 581 | if (SinkPtr->Dim <= SinkPtr->Size) 582 | { 583 | i = SinkPtr->Size + 100; 584 | CMGR_ExpandCMgr(SinkPtr,i); 585 | } 586 | 587 | (SinkPtr->Size)++; 588 | SinkIndex = SinkPtr->Size - 1; 589 | } 590 | 591 | SinkPtr->CPL[SinkIndex] = SourcePtr->CPL[SourceIndex]; 592 | SourcePtr->CPL[SourceIndex] = NULL; 593 | } 594 | 595 | void CMGR_ClearCnstr(CnstrMgrPointer SourcePtr, 596 | int Index) 597 | { 598 | if (SourcePtr->CPL[Index]->IntListSize > 0) 599 | MemFree(SourcePtr->CPL[Index]->IntList); 600 | 601 | if (SourcePtr->CPL[Index]->ExtListSize > 0) 602 | MemFree(SourcePtr->CPL[Index]->ExtList); 603 | 604 | if (SourcePtr->CPL[Index]->CoeffList != NULL) 605 | MemFree(SourcePtr->CPL[Index]->CoeffList); 606 | 607 | MemFree(SourcePtr->CPL[Index]); 608 | SourcePtr->CPL[Index] = NULL; 609 | } 610 | 611 | void CMGR_CompressCMP(CnstrMgrPointer CMP) 612 | { 613 | int SourceIdx, Delta, MaxIdx; 614 | 615 | MaxIdx = CMP->Size - 1; 616 | Delta = 0; 617 | 618 | for (SourceIdx=0; SourceIdx<=MaxIdx; SourceIdx++) 619 | { 620 | if (CMP->CPL[SourceIdx] == NULL) 621 | { 622 | Delta++; 623 | } 624 | else 625 | if (Delta > 0) 626 | { 627 | CMP->CPL[SourceIdx-Delta] = CMP->CPL[SourceIdx]; 628 | CMP->CPL[SourceIdx] = NULL; 629 | } 630 | } 631 | 632 | (CMP->Size) -= Delta; 633 | } 634 | 635 | void CMGR_ChgRHS(CnstrMgrPointer CMP, int CnstrNr, double NewRHS) 636 | { 637 | CMP->CPL[CnstrNr]->RHS = NewRHS; 638 | } 639 | 640 | void CMGR_SaveCMP(FILE *f, CnstrMgrPointer CMP, 641 | char MatchType, 642 | int CnstrType, 643 | char WriteLabel, 644 | int Label) 645 | { 646 | int CoeffListActive; 647 | int i,j; 648 | 649 | for (i=0; iSize; i++) 650 | { 651 | if (CMP->CPL[i] == NULL) 652 | { 653 | continue; 654 | } 655 | 656 | if (CMP->CPL[i]->CType == CMGR_CT_MIN_ROUTES) continue; 657 | if (CMP->CPL[i]->CType == CMGR_CT_NODE_DEGREE) continue; 658 | 659 | if (MatchType) 660 | { 661 | if (CMP->CPL[i]->CType != CnstrType) 662 | continue; 663 | } 664 | 665 | if (CMP->CPL[i]->CoeffList != NULL) 666 | CoeffListActive = 1; 667 | else 668 | CoeffListActive = 0; 669 | 670 | if (WriteLabel) 671 | fprintf(f,"\n%d\n",Label); 672 | else 673 | fprintf(f,"\n"); 674 | 675 | fprintf(f,"%d %d %lf %d %d %d\n", 676 | CMP->CPL[i]->CType, 677 | CMP->CPL[i]->Key, 678 | CMP->CPL[i]->RHS, 679 | CMP->CPL[i]->IntListSize, 680 | CMP->CPL[i]->ExtListSize, 681 | CoeffListActive); 682 | 683 | if (CMP->CPL[i]->IntListSize > 0) 684 | { 685 | for (j=1; j<=CMP->CPL[i]->IntListSize; j++) 686 | { 687 | fprintf(f," %d",CMP->CPL[i]->IntList[j]); 688 | if (((j % 10) == 0) && (CMP->CPL[i]->IntListSize > j)) 689 | fprintf(f,"\n"); 690 | } 691 | } 692 | fprintf(f,"\n"); 693 | 694 | if (CMP->CPL[i]->ExtListSize > 0) 695 | { 696 | for (j=1; j<=CMP->CPL[i]->ExtListSize; j++) 697 | { 698 | fprintf(f," %d",CMP->CPL[i]->ExtList[j]); 699 | if (((j % 10) == 0) && (CMP->CPL[i]->ExtListSize > j)) 700 | fprintf(f,"\n"); 701 | } 702 | } 703 | fprintf(f,"\n"); 704 | 705 | if (CMP->CPL[i]->CoeffList != NULL) 706 | { 707 | for (j=1; j<=CMP->CPL[i]->ExtListSize; j++) 708 | { 709 | fprintf(f," %lf",CMP->CPL[i]->CoeffList[j]); 710 | if (((j % 10) == 0) && (CMP->CPL[i]->ExtListSize > j)) 711 | fprintf(f,"\n"); 712 | } 713 | } 714 | fprintf(f,"\n"); 715 | 716 | if (CMP->CPL[i]->CType == CMGR_CT_MSTAR) 717 | { 718 | fprintf(f," %d %d %d\n", 719 | CMP->CPL[i]->A, 720 | CMP->CPL[i]->B, 721 | CMP->CPL[i]->L); 722 | } 723 | } 724 | } 725 | 726 | void CMGR_WriteCMP(CnstrMgrPointer CMP, int MinCNr) 727 | { 728 | int i,j,k; 729 | 730 | printf("CnstrMgrPointer:\n"); 731 | printf("----------------\n"); 732 | 733 | printf("Dim=%d, Size=%d\n",CMP->Dim,CMP->Size); 734 | for (i=MinCNr; iSize; i++) 735 | { 736 | if (CMP->CPL[i] == NULL) 737 | { 738 | printf("Cnstr[%d] = NULL\n",i); 739 | continue; 740 | } 741 | 742 | printf("Cnstr[%d]: Nr=%d, CType=%d, Key=%d, ILSize=%d, RHS=%lf, ELSize=%d, CLSize=%d, BL=%d\n", 743 | i, 744 | CMP->CPL[i]->GlobalNr, 745 | CMP->CPL[i]->CType, 746 | CMP->CPL[i]->Key, 747 | CMP->CPL[i]->IntListSize, 748 | CMP->CPL[i]->RHS, 749 | CMP->CPL[i]->ExtListSize, 750 | CMP->CPL[i]->CListSize, 751 | CMP->CPL[i]->BranchLevel); 752 | if (CMP->CPL[i]->IntListSize > 0) 753 | { 754 | if (CMP->CPL[i]->IntList == NULL) printf("IntList=NULL!!\n"); 755 | printf(" IntList ="); 756 | k=0; 757 | for (j=1; j<=CMP->CPL[i]->IntListSize; j++) 758 | { 759 | printf(" %2d",CMP->CPL[i]->IntList[j]); 760 | k++; 761 | if ((k == 10) && (j != CMP->CPL[i]->IntListSize)) 762 | { 763 | printf("\n "); 764 | k=0; 765 | } 766 | } 767 | printf("\n"); 768 | } 769 | if (CMP->CPL[i]->ExtListSize > 0) 770 | { 771 | if (CMP->CPL[i]->ExtList == NULL) printf("ExtList=NULL!!\n"); 772 | printf(" ExtList(Size=%d) =",CMP->CPL[i]->ExtListSize); 773 | for (j=1; j<=CMP->CPL[i]->ExtListSize; j++) 774 | printf(" %d",CMP->CPL[i]->ExtList[j]); 775 | printf("\n"); 776 | } 777 | if (CMP->CPL[i]->CListSize > 0) 778 | { 779 | if (CMP->CPL[i]->CList == NULL) printf("CList=NULL!!\n"); 780 | printf(" CList(Size=%d) =",CMP->CPL[i]->CListSize); 781 | for (j=1; j<=CMP->CPL[i]->CListSize; j++) 782 | printf(" %d",CMP->CPL[i]->CList[j]); 783 | printf("\n"); 784 | } 785 | if (CMP->CPL[i]->CoeffList != NULL) 786 | { 787 | printf(" CoeffList(Size=%d) =",CMP->CPL[i]->IntListSize); 788 | for (j=1; j<=CMP->CPL[i]->IntListSize; j++) 789 | printf(" %.2lf",CMP->CPL[i]->CoeffList[j]); 790 | printf("\n"); 791 | } 792 | if (CMP->CPL[i]->CType == CMGR_CT_MSTAR) 793 | printf(" A=%d, B=%d, L=%d (Sigma=A/B, Lambda=L/B)\n", 794 | CMP->CPL[i]->A, 795 | CMP->CPL[i]->B, 796 | CMP->CPL[i]->L); 797 | } 798 | 799 | printf("----------------\n"); 800 | } 801 | 802 | 803 | -------------------------------------------------------------------------------- /src/ext/cvrpsep/compcuts.cpp: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../../../include/ext/cvrpsep/memmod.h" 10 | #include "../../../include/ext/cvrpsep/basegrph.h" 11 | #include "../../../include/ext/cvrpsep/strngcmp.h" 12 | #include "../../../include/ext/cvrpsep/cnstrmgr.h" 13 | #include "../../../include/ext/cvrpsep/compcuts.h" 14 | 15 | void COMPCUTS_ComputeCompCuts(ReachPtr SupportPtr, 16 | int NoOfCustomers, 17 | int *Demand, 18 | int CAP, 19 | double **XMatrix, 20 | CnstrMgrPointer CutsCMP, 21 | int *GeneratedCuts) 22 | { 23 | int i,j,k; 24 | int TotalNodes,NoOfComponents,DepotCompNr,DepotDegree,NodeListSize,CutNr; 25 | int CAPSum,MinV,TotalDemand,ComplementDemand; 26 | int DemandSum; 27 | double EpsViolation; 28 | double SumOfCompXSums,ComplementXSum; 29 | double LHS,RHS; 30 | 31 | char *CVWrk1; 32 | int *IVWrk1, *IVWrk2, *IVWrk3, *IVWrk4; 33 | 34 | char *ConnectedToDepot; 35 | int *NodeList; 36 | int *CompNr; /* Node j is in component nr. CompNr[j]. */ 37 | int *CompDemandSum; 38 | double *CompXSum; 39 | 40 | ReachPtr CompsRPtr; 41 | 42 | CutNr = 0; 43 | EpsViolation = 0.01; 44 | 45 | TotalNodes = NoOfCustomers + 1; 46 | 47 | CVWrk1 = MemGetCV(TotalNodes+1); 48 | 49 | IVWrk1 = MemGetIV(TotalNodes+1); 50 | IVWrk2 = MemGetIV(TotalNodes+1); 51 | IVWrk3 = MemGetIV(TotalNodes+1); 52 | IVWrk4 = MemGetIV(TotalNodes+1); 53 | 54 | NodeList = MemGetIV(TotalNodes+1); 55 | CompNr = MemGetIV(TotalNodes+1); 56 | 57 | ReachInitMem(&CompsRPtr,TotalNodes); 58 | 59 | DepotDegree = SupportPtr->LP[TotalNodes].CFN; 60 | SupportPtr->LP[TotalNodes].CFN = 0; 61 | ComputeStrongComponents(SupportPtr,CompsRPtr, 62 | &NoOfComponents,TotalNodes, 63 | CVWrk1, 64 | IVWrk1,IVWrk2,IVWrk3,IVWrk4); 65 | SupportPtr->LP[TotalNodes].CFN = DepotDegree; 66 | 67 | /* The number of components excl. the depot is NoOfComponents-1 */ 68 | 69 | CompDemandSum = MemGetIV(NoOfComponents+1); 70 | CompXSum = MemGetDV(NoOfComponents+1); 71 | 72 | if (NoOfComponents == 2) goto EndOfCompCuts; /* The depot is one comp. */ 73 | 74 | for (i=1; i<=NoOfComponents; i++) 75 | { 76 | for (j=1; j<=CompsRPtr->LP[i].CFN; j++) 77 | { 78 | k = CompsRPtr->LP[i].FAL[j]; 79 | CompNr[k] = i; 80 | } 81 | } 82 | 83 | DepotCompNr = CompNr[TotalNodes]; 84 | 85 | for (i=1; i<=NoOfComponents; i++) CompDemandSum[i] = 0; 86 | for (i=1; i<=NoOfComponents; i++) CompXSum[i] = 0.0; 87 | 88 | for (i=1; i<=NoOfCustomers; i++) 89 | CompDemandSum[CompNr[i]] += Demand[i]; 90 | 91 | for (i=1; iLP[i].CFN; j++) 94 | { 95 | k = SupportPtr->LP[i].FAL[j]; 96 | if ((k > i) && (k <= NoOfCustomers)) /* Only one of (i,k) and (k,i). */ 97 | CompXSum[CompNr[i]] += XMatrix[i][k]; 98 | } 99 | } 100 | 101 | SumOfCompXSums = 0.0; 102 | for (i=1; i<=NoOfComponents; i++) SumOfCompXSums += CompXSum[i]; 103 | 104 | TotalDemand = 0; 105 | for (i=1; i<=NoOfComponents; i++) TotalDemand += CompDemandSum[i]; 106 | 107 | for (i=1; i<=NoOfComponents; i++) 108 | { 109 | if (i == DepotCompNr) continue; 110 | 111 | CAPSum = CAP; 112 | MinV = 1; 113 | 114 | while (CAPSum < CompDemandSum[i]) 115 | { 116 | CAPSum += CAP; 117 | MinV++; 118 | } 119 | 120 | LHS = CompXSum[i]; 121 | RHS = CompsRPtr->LP[i].CFN - MinV; 122 | 123 | if ((LHS - RHS) >= EpsViolation) 124 | { 125 | CutNr++; 126 | 127 | CMGR_AddCnstr(CutsCMP, 128 | CMGR_CT_CAP,0, 129 | CompsRPtr->LP[i].CFN, 130 | CompsRPtr->LP[i].FAL, 131 | RHS); 132 | } 133 | 134 | if (NoOfComponents >= 4) 135 | { 136 | /* Minimum 4 components. The depot is one component, so 137 | 3 customer components are required if the complement customers 138 | are not all in one component. */ 139 | 140 | ComplementDemand = TotalDemand - CompDemandSum[i]; 141 | ComplementXSum = SumOfCompXSums - CompXSum[i]; 142 | 143 | CAPSum = CAP; 144 | MinV = 1; 145 | 146 | while (CAPSum < ComplementDemand) 147 | { 148 | CAPSum += CAP; 149 | MinV++; 150 | } 151 | 152 | LHS = ComplementXSum; 153 | RHS = (NoOfCustomers - CompsRPtr->LP[i].CFN) - MinV; 154 | 155 | if ((LHS - RHS) >= EpsViolation) 156 | { 157 | CutNr++; 158 | 159 | NodeListSize = 0; 160 | for (j=1; j<=NoOfCustomers; j++) 161 | if (CompNr[j] != i) 162 | NodeList[++NodeListSize] = j; 163 | 164 | CMGR_AddCnstr(CutsCMP, 165 | CMGR_CT_CAP,0, 166 | NodeListSize, 167 | NodeList, 168 | RHS); 169 | } 170 | } 171 | } 172 | 173 | if (NoOfComponents >= 5) 174 | { 175 | /* Generate a cut for the union of those components 176 | that are not connected to the depot. */ 177 | 178 | ConnectedToDepot = MemGetCV(NoOfComponents+1); 179 | for (i=1; i<=NoOfComponents; i++) ConnectedToDepot[i] = 0; 180 | 181 | /* DepotIndex = TotalNodes. */ 182 | for (i=1; i<=SupportPtr->LP[TotalNodes].CFN; i++) 183 | { 184 | j = SupportPtr->LP[TotalNodes].FAL[i]; 185 | k = CompNr[j]; 186 | ConnectedToDepot[k] = 1; 187 | } 188 | 189 | j = 0; 190 | k = 0; 191 | for (i=1; i<=NoOfComponents; i++) 192 | { 193 | if (i == DepotCompNr) continue; 194 | 195 | if (ConnectedToDepot[i]) 196 | j++; 197 | else 198 | k++; 199 | } 200 | 201 | /* j components are connected to the depot */ 202 | /* k components are not connected to the depot */ 203 | 204 | if ((j >= 2) && (k >= 2)) 205 | { 206 | /* Generate a cut for the union of the components that are 207 | not adjacent to the depot. */ 208 | 209 | NodeListSize = 0; 210 | LHS = 0.0; 211 | 212 | DemandSum = 0; 213 | for (i=1; i<=NoOfComponents; i++) 214 | { 215 | if (i == DepotCompNr) continue; 216 | 217 | if (ConnectedToDepot[i] == 0) 218 | { 219 | DemandSum += CompDemandSum[i]; 220 | LHS += CompXSum[i]; 221 | 222 | for (j=1; j<=CompsRPtr->LP[i].CFN; j++) 223 | { 224 | k = CompsRPtr->LP[i].FAL[j]; 225 | NodeList[++NodeListSize] = k; 226 | } 227 | } 228 | } 229 | 230 | CAPSum = CAP; 231 | MinV = 1; 232 | 233 | while (CAPSum < DemandSum) 234 | { 235 | CAPSum += CAP; 236 | MinV++; 237 | } 238 | 239 | RHS = NodeListSize - MinV; 240 | 241 | if ((LHS - RHS) >= EpsViolation) 242 | { 243 | CutNr++; 244 | CMGR_AddCnstr(CutsCMP, 245 | CMGR_CT_CAP,0, 246 | NodeListSize, 247 | NodeList, 248 | RHS); 249 | } 250 | } 251 | 252 | MemFree(ConnectedToDepot); 253 | } 254 | 255 | EndOfCompCuts: 256 | 257 | *GeneratedCuts = CutNr; 258 | 259 | MemFree(CVWrk1); 260 | 261 | MemFree(IVWrk1); 262 | MemFree(IVWrk2); 263 | MemFree(IVWrk3); 264 | MemFree(IVWrk4); 265 | 266 | MemFree(NodeList); 267 | MemFree(CompNr); 268 | MemFree(CompDemandSum); 269 | MemFree(CompXSum); 270 | 271 | ReachFreeMem(&CompsRPtr); 272 | } 273 | 274 | -------------------------------------------------------------------------------- /src/ext/cvrpsep/compress.cpp: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include 6 | #include 7 | 8 | #include "../../../include/ext/cvrpsep/memmod.h" 9 | #include "../../../include/ext/cvrpsep/basegrph.h" 10 | #include "../../../include/ext/cvrpsep/strngcmp.h" 11 | #include "../../../include/ext/cvrpsep/cutbase.h" 12 | #include "../../../include/ext/cvrpsep/compress.h" 13 | 14 | void COMPRESS_CheckV1Set(ReachPtr SupportPtr, 15 | int NoOfCustomers, 16 | int *CompNr, 17 | double **XMatrix, 18 | double *Slack, 19 | int *CompListSize, 20 | int *CompList, 21 | int CutNr, 22 | ReachPtr V1CutsPtr) 23 | { 24 | int j,k; 25 | double XSumInSet; 26 | char *InNodeSet; 27 | char *CompInSet; 28 | 29 | InNodeSet = MemGetCV(NoOfCustomers+1); 30 | CompInSet = MemGetCV(NoOfCustomers+1); 31 | 32 | for (j=1; j<=NoOfCustomers; j++) InNodeSet[j] = 0; 33 | for (j=1; j<=NoOfCustomers; j++) CompInSet[j] = 0; 34 | 35 | *CompListSize = 0; 36 | 37 | for (k=1; k<=V1CutsPtr->LP[CutNr].CFN; k++) 38 | { 39 | j = V1CutsPtr->LP[CutNr].FAL[k]; 40 | InNodeSet[j] = 1; 41 | 42 | if (CompInSet[CompNr[j]] == 0) 43 | { 44 | CompList[++(*CompListSize)] = CompNr[j]; 45 | CompInSet[CompNr[j]] = 1; 46 | } 47 | } 48 | 49 | CUTBASE_CompXSumInSet(SupportPtr,NoOfCustomers,InNodeSet,NULL,0, 50 | XMatrix,&XSumInSet); 51 | 52 | *Slack = (1.0 * V1CutsPtr->LP[CutNr].CFN) - XSumInSet - 1.0; 53 | 54 | MemFree(InNodeSet); 55 | MemFree(CompInSet); 56 | } 57 | 58 | void COMPRESS_ShrinkGraph(ReachPtr SupportPtr, 59 | int NoOfCustomers, 60 | double **XMatrix, 61 | double **SMatrix, 62 | int NoOfV1Cuts, 63 | ReachPtr V1CutsPtr, 64 | ReachPtr SAdjRPtr, /* Shrunk support graph */ 65 | ReachPtr SuperNodesRPtr, /* Nodes in supernodes */ 66 | int *ShrunkGraphCustNodes) /* Excl. depot */ 67 | { 68 | char NewLinks,TolerantShrinking,ShrinkableSet; 69 | int i,j,k,Tail,Head; 70 | int NoOfComponents,NodeListSize; 71 | int CompListSize; 72 | double EdgeEps,TripleEps,XVal; 73 | double MaxEdge; 74 | double Slack; 75 | double MaxShrinkTolerance,UsedTolerance; 76 | 77 | char *CVWrk1; 78 | int *IVWrk1, *IVWrk2, *IVWrk3, *IVWrk4; 79 | 80 | char *Shrinkable; 81 | int *CompNr; /* Node j is in component nr. CompNr[j]. */ 82 | int *NodeList; 83 | int *CompList; 84 | 85 | ReachPtr CmprsEdgesRPtr; 86 | ReachPtr CompsRPtr; 87 | 88 | EdgeEps = 0.999; /* Shrink any edge >= Eps. */ 89 | TripleEps = 1.999; 90 | 91 | TolerantShrinking = 0; 92 | MaxShrinkTolerance = 0.01; 93 | UsedTolerance = 0.0; 94 | 95 | CVWrk1 = MemGetCV(NoOfCustomers+1); 96 | 97 | IVWrk1 = MemGetIV(NoOfCustomers+1); 98 | IVWrk2 = MemGetIV(NoOfCustomers+1); 99 | IVWrk3 = MemGetIV(NoOfCustomers+1); 100 | IVWrk4 = MemGetIV(NoOfCustomers+1); 101 | 102 | Shrinkable = MemGetCV(NoOfCustomers+1); 103 | 104 | CompNr = MemGetIV(NoOfCustomers+2); 105 | NodeList = MemGetIV(NoOfCustomers+1); 106 | CompList = MemGetIV(NoOfCustomers+1); 107 | 108 | ReachInitMem(&CmprsEdgesRPtr,NoOfCustomers+1); 109 | ReachInitMem(&CompsRPtr,NoOfCustomers+1); 110 | 111 | for (i=1; iLP[i].CFN; k++) 114 | { 115 | j = SupportPtr->LP[i].FAL[k]; 116 | if ((j <= NoOfCustomers) && (j > i)) 117 | if (XMatrix[i][j] >= EdgeEps) 118 | { 119 | ReachAddForwArc(CmprsEdgesRPtr,i,j); 120 | ReachAddForwArc(CmprsEdgesRPtr,j,i); 121 | } 122 | } 123 | } 124 | 125 | do 126 | { 127 | ReachClearForwLists(CompsRPtr); 128 | 129 | ComputeStrongComponents(CmprsEdgesRPtr,CompsRPtr, 130 | &NoOfComponents,NoOfCustomers, 131 | CVWrk1, 132 | IVWrk1,IVWrk2,IVWrk3,IVWrk4); 133 | 134 | for (i=1; i<=NoOfComponents; i++) 135 | { 136 | for (k=1; k<=CompsRPtr->LP[i].CFN; k++) 137 | { 138 | j = CompsRPtr->LP[i].FAL[k]; 139 | CompNr[j] = i; 140 | } 141 | } 142 | 143 | CompNr[NoOfCustomers+1] = NoOfComponents+1; /* Depot in last comp. */ 144 | 145 | for (i=1; i<=NoOfComponents+1; i++) 146 | for (j=1; j<=NoOfComponents+1; j++) 147 | SMatrix[i][j] = 0.0; 148 | 149 | for (i=1; i<=NoOfCustomers; i++) /* i = NoOfCustomers is ok, */ 150 | { /* j may be the depot. */ 151 | for (k=1; k<=SupportPtr->LP[i].CFN; k++) 152 | { 153 | j = SupportPtr->LP[i].FAL[k]; 154 | if (j > i) 155 | { 156 | XVal = XMatrix[i][j]; 157 | SMatrix[CompNr[i]][CompNr[j]] += XVal; 158 | 159 | if (CompNr[i] != CompNr[j]) 160 | SMatrix[CompNr[j]][CompNr[i]] += XVal; 161 | } 162 | } 163 | } 164 | 165 | for (i=1; i<=NoOfComponents; i++) 166 | { 167 | if (SMatrix[i][i] < (CompsRPtr->LP[i].CFN - 1 + 0.01)) 168 | Shrinkable[i] = 1; 169 | else 170 | Shrinkable[i] = 0; 171 | } 172 | 173 | /* Check for new possible compressions. */ 174 | 175 | NewLinks = 0; 176 | 177 | for (i=1; i= EdgeEps) 186 | { 187 | Tail = CompsRPtr->LP[i].FAL[1]; 188 | Head = CompsRPtr->LP[j].FAL[1]; 189 | 190 | ReachAddForwArc(CmprsEdgesRPtr,Tail,Head); 191 | ReachAddForwArc(CmprsEdgesRPtr,Head,Tail); 192 | NewLinks = 1; 193 | } 194 | } 195 | } 196 | 197 | if (NewLinks == 0) 198 | { 199 | /* (check triplets) */ 200 | for (i=1; i= TripleEps) 218 | { 219 | Tail = CompsRPtr->LP[i].FAL[1]; 220 | Head = CompsRPtr->LP[j].FAL[1]; 221 | 222 | ReachAddForwArc(CmprsEdgesRPtr,Tail,Head); 223 | ReachAddForwArc(CmprsEdgesRPtr,Head,Tail); 224 | 225 | Head = CompsRPtr->LP[k].FAL[1]; 226 | 227 | ReachAddForwArc(CmprsEdgesRPtr,Tail,Head); 228 | ReachAddForwArc(CmprsEdgesRPtr,Head,Tail); 229 | 230 | NewLinks = 1; 231 | goto EndOfTriplets; 232 | } 233 | } 234 | } 235 | } 236 | 237 | EndOfTriplets: 238 | 239 | i = 0; 240 | 241 | } 242 | 243 | if ((NewLinks == 0) && 244 | (TolerantShrinking) && 245 | (UsedTolerance < MaxShrinkTolerance)) 246 | { 247 | Tail = 0; 248 | Head = 0; 249 | MaxEdge = 0.0; 250 | for (i=1; i MaxEdge) 254 | { 255 | MaxEdge = SMatrix[i][j]; 256 | Tail = i; 257 | Head = j; 258 | } 259 | } 260 | 261 | if (Tail > 0) 262 | if ((1.0 - MaxEdge) <= (MaxShrinkTolerance - UsedTolerance)) 263 | { 264 | NewLinks = 1; 265 | 266 | i = Tail; 267 | j = Head; 268 | 269 | Tail = CompsRPtr->LP[i].FAL[1]; 270 | Head = CompsRPtr->LP[j].FAL[1]; 271 | 272 | ReachAddForwArc(CmprsEdgesRPtr,Tail,Head); 273 | ReachAddForwArc(CmprsEdgesRPtr,Head,Tail); 274 | UsedTolerance += (1.0 - MaxEdge); 275 | } 276 | } 277 | 278 | if (NewLinks == 0) 279 | { 280 | for (i=1; i<=NoOfV1Cuts; i++) 281 | { 282 | COMPRESS_CheckV1Set(SupportPtr,NoOfCustomers,CompNr, 283 | XMatrix, 284 | &Slack, 285 | &CompListSize, 286 | CompList, 287 | i, 288 | V1CutsPtr); 289 | 290 | ShrinkableSet = 1; 291 | for (j=1; j<=CompListSize; j++) 292 | { 293 | if (Shrinkable[CompList[j]] == 0) 294 | { 295 | ShrinkableSet = 0; 296 | break; 297 | } 298 | } 299 | 300 | if ((Slack <= 0.01) && (CompListSize > 1) && (ShrinkableSet)) 301 | { 302 | Tail = CompsRPtr->LP[CompList[1]].FAL[1]; 303 | 304 | for (j=2; j<=CompListSize; j++) 305 | { 306 | Head = CompsRPtr->LP[CompList[j]].FAL[1]; 307 | 308 | ReachAddForwArc(CmprsEdgesRPtr,Tail,Head); 309 | ReachAddForwArc(CmprsEdgesRPtr,Head,Tail); 310 | } 311 | 312 | NewLinks = 1; 313 | goto EndOfSetShrinking; 314 | } 315 | } 316 | 317 | EndOfSetShrinking: 318 | 319 | i = 0; 320 | } 321 | 322 | } while (NewLinks); 323 | 324 | /* SuperNode number NoOfComponents+1 is the depot. */ 325 | 326 | for (i=1; i<=NoOfComponents+1; i++) 327 | { 328 | NodeListSize = 0; 329 | for (j=1; j<=NoOfComponents+1; j++) 330 | { 331 | if (j != i) 332 | if (SMatrix[i][j] >= 0.0001) 333 | { 334 | NodeList[++NodeListSize] = j; 335 | } 336 | } 337 | 338 | ReachSetForwList(SAdjRPtr,NodeList,i,NodeListSize); 339 | } 340 | 341 | for (i=1; i<=NoOfComponents; i++) 342 | { 343 | ReachSetForwList(SuperNodesRPtr, 344 | CompsRPtr->LP[i].FAL, 345 | i, 346 | CompsRPtr->LP[i].CFN); 347 | } 348 | 349 | /* Depot: */ 350 | NodeList[1] = NoOfCustomers+1; 351 | ReachSetForwList(SuperNodesRPtr,NodeList,NoOfComponents+1,1); 352 | 353 | *ShrunkGraphCustNodes = NoOfComponents; 354 | 355 | MemFree(CVWrk1); 356 | 357 | MemFree(IVWrk1); 358 | MemFree(IVWrk2); 359 | MemFree(IVWrk3); 360 | MemFree(IVWrk4); 361 | 362 | MemFree(CompNr); 363 | MemFree(NodeList); 364 | 365 | MemFree(Shrinkable); 366 | MemFree(CompList); 367 | 368 | ReachFreeMem(&CmprsEdgesRPtr); 369 | ReachFreeMem(&CompsRPtr); 370 | } 371 | 372 | -------------------------------------------------------------------------------- /src/ext/cvrpsep/cutbase.cpp: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include 6 | #include 7 | 8 | #include "../../../include/ext/cvrpsep/memmod.h" 9 | #include "../../../include/ext/cvrpsep/basegrph.h" 10 | #include "../../../include/ext/cvrpsep/cutbase.h" 11 | 12 | void CUTBASE_CompXSumInSet(ReachPtr SupportPtr, 13 | int NoOfCustomers, 14 | char *InNodeSet, 15 | int *NodeList, int NodeListSize, 16 | double **XMatrix, 17 | double *XSumInSet) 18 | { 19 | char *InSet; 20 | char Allocated; 21 | int i,j,k; 22 | double XSum; 23 | 24 | if (InNodeSet == NULL) 25 | { 26 | Allocated = 1; 27 | InSet = MemGetCV(NoOfCustomers+1); 28 | for (i=1; i<=NoOfCustomers; i++) InSet[i] = 0; 29 | for (i=1; i<=NodeListSize; i++) InSet[NodeList[i]] = 1; 30 | } 31 | else 32 | { 33 | Allocated = 0; 34 | InSet = InNodeSet; 35 | } 36 | 37 | XSum = 0.0; 38 | for (i=1; iLP[i].CFN; k++) 43 | { 44 | j = SupportPtr->LP[i].FAL[k]; 45 | if ((j > i) && (j <= NoOfCustomers)) /* Only one of (i,j) and (j,i) */ 46 | if (InSet[j]) 47 | XSum += XMatrix[i][j]; 48 | } 49 | } 50 | 51 | 52 | if (Allocated == 1) 53 | { 54 | MemFree(InSet); 55 | } 56 | 57 | *XSumInSet = XSum; 58 | } 59 | 60 | void CUTBASE_CompVehiclesForSet(int NoOfCustomers, 61 | char *NodeInSet, 62 | int *NodeList, 63 | int NodeListSize, 64 | int *Demand, 65 | int CAP, 66 | int *MinV) 67 | { 68 | int i; 69 | int DemandSum,CAPSum; 70 | 71 | DemandSum = 0; 72 | if (NodeInSet == NULL) 73 | { 74 | for (i=1; i<=NodeListSize; i++) DemandSum += Demand[NodeList[i]]; 75 | } 76 | else 77 | { 78 | for (i=1; i<=NoOfCustomers; i++) 79 | if (NodeInSet[i]) 80 | DemandSum += Demand[i]; 81 | } 82 | 83 | *MinV = 1; 84 | CAPSum = CAP; 85 | 86 | while (CAPSum < DemandSum) 87 | { 88 | (*MinV)++; 89 | CAPSum += CAP; 90 | } 91 | } 92 | 93 | void CUTBASE_CompCapViolation(ReachPtr SupportPtr, 94 | int NoOfCustomers, 95 | char *NodeInSet, 96 | int *NodeList, int NodeListSize, 97 | int *Demand, int CAP, 98 | double **XMatrix, 99 | double *Violation) 100 | { 101 | int i,MinV,SetSize; 102 | double XSum,RHS; 103 | 104 | CUTBASE_CompXSumInSet(SupportPtr,NoOfCustomers, 105 | NodeInSet, 106 | NodeList,NodeListSize, 107 | XMatrix, 108 | &XSum); 109 | 110 | CUTBASE_CompVehiclesForSet(NoOfCustomers, 111 | NodeInSet, 112 | NodeList,NodeListSize, 113 | Demand,CAP,&MinV); 114 | 115 | if (NodeInSet != NULL) 116 | { 117 | SetSize=0; 118 | for (i=1; i<=NoOfCustomers; i++) 119 | if (NodeInSet[i]) 120 | SetSize++; 121 | } 122 | else 123 | { 124 | SetSize = NodeListSize; 125 | } 126 | 127 | RHS = SetSize - MinV; 128 | *Violation = XSum - RHS; 129 | } 130 | 131 | -------------------------------------------------------------------------------- /src/ext/cvrpsep/fcapfix.cpp: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include 6 | #include 7 | 8 | #include "../../../include/ext/cvrpsep/memmod.h" 9 | #include "../../../include/ext/cvrpsep/basegrph.h" 10 | #include "../../../include/ext/cvrpsep/cutbase.h" 11 | #include "../../../include/ext/cvrpsep/mxf.h" 12 | 13 | void FCAPFIX_CompSourceFixNodes(ReachPtr HistoryPtr, 14 | int HistoryListSize, 15 | int SeedNode, 16 | int NoOfCustomers, 17 | int *List, 18 | int *ListSize) 19 | { 20 | char SeedInSet; 21 | char CoveredSet; 22 | char *FixedOutNode; 23 | int i,j,SetNr; 24 | 25 | FixedOutNode = MemGetCV(NoOfCustomers+1); 26 | for (i=1; i<=NoOfCustomers; i++) FixedOutNode[i] = 0; 27 | 28 | for (SetNr=HistoryListSize; SetNr>=1; SetNr--) 29 | { 30 | if (HistoryPtr->LP[SetNr].CFN == 1) 31 | { 32 | continue; 33 | } 34 | 35 | /* Check if SeedNode is in this set */ 36 | SeedInSet=0; 37 | for (i=1; i<=HistoryPtr->LP[SetNr].CFN; i++) 38 | { 39 | j = HistoryPtr->LP[SetNr].FAL[i]; 40 | if (j == SeedNode) 41 | { 42 | SeedInSet=1; 43 | break; 44 | } 45 | } 46 | 47 | if (SeedInSet == 1) 48 | { 49 | CoveredSet=0; 50 | for (i=1; i<=HistoryPtr->LP[SetNr].CFN; i++) 51 | { 52 | j = HistoryPtr->LP[SetNr].FAL[i]; 53 | if (FixedOutNode[j] == 1) 54 | { 55 | CoveredSet=1; 56 | /* The set is already covered by node j */ 57 | break; 58 | } 59 | } 60 | } 61 | else 62 | { 63 | CoveredSet = 1; 64 | } 65 | 66 | if (CoveredSet == 0) 67 | { 68 | j = HistoryPtr->LP[SetNr].BAL[1]; 69 | if (j != SeedNode) 70 | { 71 | FixedOutNode[j] = 1; 72 | } 73 | else 74 | { 75 | for (i=1; i<=HistoryPtr->LP[SetNr].CFN; i++) 76 | { 77 | j = HistoryPtr->LP[SetNr].FAL[i]; 78 | if (j != SeedNode) 79 | { 80 | break; 81 | } 82 | } 83 | 84 | FixedOutNode[j] = 1; 85 | } 86 | } 87 | } 88 | 89 | *ListSize = 0; 90 | for (i=1; i<=NoOfCustomers; i++) 91 | { 92 | if (FixedOutNode[i] == 1) 93 | { 94 | List[++(*ListSize)] = i; 95 | } 96 | } 97 | 98 | MemFree(FixedOutNode); 99 | } 100 | 101 | void FCAPFIX_CompAddSinkNode(ReachPtr SupportPtr, 102 | int NoOfCustomers, 103 | double **XMatrix, 104 | int SeedNode, 105 | int *AddNodeToSinkSide, 106 | int *SourceList, 107 | int SourceListSize) 108 | { 109 | int i,j; 110 | double XScore,BestXScore; 111 | char *OnSourceSide; 112 | 113 | OnSourceSide = MemGetCV(NoOfCustomers+1); 114 | for (i=1; i<=NoOfCustomers; i++) OnSourceSide[i] = 0; 115 | 116 | for (i=1; i<=SourceListSize; i++) 117 | { 118 | j = SourceList[i]; 119 | OnSourceSide[j] = 1; 120 | } 121 | 122 | *AddNodeToSinkSide = 0; 123 | BestXScore = 0.0; 124 | 125 | for (i=1; i<=SupportPtr->LP[SeedNode].CFN; i++) 126 | { 127 | j = SupportPtr->LP[SeedNode].FAL[i]; 128 | if (j > NoOfCustomers) continue; 129 | 130 | if (OnSourceSide[j] == 0) 131 | { 132 | XScore = XMatrix[SeedNode][j]; 133 | if ((*AddNodeToSinkSide == 0) || (XScore > BestXScore)) 134 | { 135 | *AddNodeToSinkSide = j; 136 | BestXScore = XScore; 137 | } 138 | } 139 | } 140 | 141 | MemFree(OnSourceSide); 142 | } 143 | 144 | void FCAPFIX_SolveMaxFlow(MaxFlowPtr MXFPtr, 145 | int NoOfCustomers, 146 | int InfCap, 147 | int *ResidualCap, 148 | int *NodeExcess, 149 | int *ArcCapFromSource, 150 | int *ArcCapToSink, 151 | int *FixOnSourceSide, 152 | int SourceFixedListSize, 153 | int *FixOnSinkSide, 154 | int SinkFixedListSize, 155 | int *SinkNodeList, /* Resulting set */ 156 | int *SinkNodeListSize) /* Size of resulting set */ 157 | { 158 | int i,k,MaxFlowValue; 159 | 160 | /* Source is NoOfCustomers+1, Sink is NoOfCustomers+2 */ 161 | 162 | MXF_SetFlow(MXFPtr,ResidualCap,NodeExcess); 163 | 164 | for (i=1; i<=SourceFixedListSize; i++) 165 | { 166 | k = FixOnSourceSide[i]; 167 | MXF_ChgArcCap(MXFPtr,NoOfCustomers+1,k,InfCap); 168 | } 169 | 170 | for (i=1; i<=SinkFixedListSize; i++) 171 | { 172 | k = FixOnSinkSide[i]; 173 | MXF_ChgArcCap(MXFPtr,k,NoOfCustomers+2,InfCap); 174 | } 175 | 176 | MXF_SolveMaxFlow(MXFPtr,0,NoOfCustomers+1,NoOfCustomers+2,&MaxFlowValue,1, 177 | SinkNodeListSize,SinkNodeList); 178 | 179 | (*SinkNodeListSize)--; /* Excl. sink node. */ 180 | 181 | /* Restore arc capacities */ 182 | 183 | for (i=1; i<=SourceFixedListSize; i++) 184 | { 185 | k = FixOnSourceSide[i]; 186 | MXF_ChgArcCap(MXFPtr,NoOfCustomers+1,k,ArcCapFromSource[k]); 187 | } 188 | 189 | for (i=1; i<=SinkFixedListSize; i++) 190 | { 191 | k = FixOnSinkSide[i]; 192 | MXF_ChgArcCap(MXFPtr,k,NoOfCustomers+2,ArcCapToSink[k]); 193 | } 194 | } 195 | 196 | void FCAPFIX_CheckExpandSet(ReachPtr SupportPtr, 197 | int NoOfCustomers, 198 | int *Demand, int CAP, 199 | double **XMatrix, 200 | char *NodeInSet, 201 | char *FixedOut, 202 | int *AddNode, 203 | int *AddSecondNode) 204 | { 205 | int i,j,k; 206 | int DemandSum,CAPSum,MinV,BestAddNode,BestSecondNode; 207 | double XVal,XSumInSet,BestXScore; 208 | double *XNodeSum; 209 | 210 | XNodeSum = MemGetDV(NoOfCustomers+1); 211 | for (i=1; i<=NoOfCustomers; i++) XNodeSum[i] = 0.0; 212 | 213 | XSumInSet = 0.0; 214 | for (i=1; i<=NoOfCustomers; i++) 215 | { 216 | for (k=1; k<=SupportPtr->LP[i].CFN; k++) 217 | { 218 | j = SupportPtr->LP[i].FAL[k]; 219 | if ((j <= NoOfCustomers) && (j > i)) 220 | { 221 | XVal = XMatrix[i][j]; 222 | if (NodeInSet[i]) XNodeSum[j] += XVal; 223 | if (NodeInSet[j]) XNodeSum[i] += XVal; 224 | if ((NodeInSet[i]) && (NodeInSet[j])) XSumInSet += XVal; 225 | } 226 | } 227 | } 228 | 229 | DemandSum = 0; 230 | for (j=1; j<=NoOfCustomers; j++) 231 | if (NodeInSet[j] == 1) 232 | DemandSum += Demand[j]; 233 | 234 | CAPSum = CAP; 235 | MinV = 1; 236 | 237 | while (CAPSum < DemandSum) 238 | { 239 | CAPSum += CAP; 240 | MinV++; 241 | } 242 | 243 | BestXScore = 0.0; 244 | BestAddNode = 0; 245 | 246 | for (i=1; i<=NoOfCustomers; i++) 247 | { 248 | if (NodeInSet[i] == 0) continue; 249 | 250 | for (k=1; k<=SupportPtr->LP[i].CFN; k++) 251 | { 252 | j = SupportPtr->LP[i].FAL[k]; 253 | if ((j <= NoOfCustomers) && 254 | (NodeInSet[j] == 0) && 255 | (FixedOut[j] == 0) && 256 | ((Demand[j] + DemandSum) > CAPSum)) 257 | { 258 | if ((BestAddNode == 0) || (XNodeSum[j] > BestXScore)) 259 | { 260 | BestAddNode = j; 261 | BestXScore = XNodeSum[j]; 262 | } 263 | } 264 | } 265 | } 266 | 267 | BestSecondNode = 0; 268 | 269 | *AddNode = BestAddNode; 270 | *AddSecondNode = BestSecondNode; 271 | 272 | MemFree(XNodeSum); 273 | } 274 | 275 | 276 | void FCAPFIX_ComputeCuts(ReachPtr SupportPtr, 277 | int NoOfCustomers, 278 | int *Demand, int CAP, 279 | int *SuperNodeSize, 280 | double **XMatrix, 281 | int MaxCuts, 282 | int MaxRounds, 283 | int *NoOfGeneratedCuts, 284 | ReachPtr ResultRPtr) 285 | { 286 | const double EpsViolation = 0.01; 287 | int i,j,k,DepotIdx,RoundNr,AddNode,AddSecondNode; 288 | int GraphNodes,ArcCap,InfCap,VCAP,MaxFlowValue; 289 | int OrigNodes,MinV,DemandSum,CAPSum,MaxDemand; 290 | int FlowScale; 291 | double XVal,XInSet; 292 | double Violation,LHS,RHS; 293 | int SinkNodeListSize; 294 | int HistoryListSize,MaxHistoryListSize; 295 | int FixedToSourceListSize, FixedToSinkListSize; 296 | int SeedNode,AddSeedNode; 297 | int NodeListSize; 298 | int ExpandNr; 299 | char *UseSeed; 300 | char *OneNodeCut; 301 | 302 | char *NodeInSet; 303 | char *FixedOut; 304 | 305 | int *ResidualCap, *NodeExcess; 306 | int NetworkNodes, NetworkArcs; 307 | 308 | int *NodeList; 309 | int *FixedToSourceList, *FixedToSinkList; 310 | int *ArcCapToSink, *ArcCapFromSource; 311 | double *DepotEdgeXVal; 312 | ReachPtr HistoryRPtr; 313 | MaxFlowPtr MXFPtr; 314 | 315 | *NoOfGeneratedCuts = 0; 316 | 317 | MaxHistoryListSize = MaxRounds * NoOfCustomers; 318 | ReachInitMem(&HistoryRPtr,MaxHistoryListSize); 319 | 320 | /* The graph for max. flow contains NoOfCustomers+2 nodes. 321 | Nodes 1..NoOfCustomers represent customers, 322 | node NoOfCustomers+1 is the source, 323 | and node NoOfCustomers+2 is the sink. */ 324 | 325 | GraphNodes = (NoOfCustomers + 2); 326 | MXF_InitMem(&MXFPtr,GraphNodes,GraphNodes*5); 327 | MXF_ClearNodeList(MXFPtr); 328 | MXF_SetNodeListSize(MXFPtr,GraphNodes); 329 | MXF_ClearArcList(MXFPtr); 330 | 331 | UseSeed = MemGetCV(NoOfCustomers+1); 332 | OneNodeCut = MemGetCV(NoOfCustomers+1); 333 | 334 | NodeInSet = MemGetCV(NoOfCustomers+1); 335 | FixedOut = MemGetCV(NoOfCustomers+1); 336 | 337 | ArcCapToSink = MemGetIV(NoOfCustomers+1); 338 | ArcCapFromSource = MemGetIV(NoOfCustomers+1); 339 | FixedToSourceList = MemGetIV(NoOfCustomers+1); 340 | FixedToSinkList = MemGetIV(NoOfCustomers+1); 341 | NodeList = MemGetIV(NoOfCustomers+2); /* (space for sink in flow network) */ 342 | 343 | DepotEdgeXVal = MemGetDV(NoOfCustomers+1); 344 | 345 | VCAP = CAP; 346 | FlowScale = 1; 347 | 348 | while (VCAP < 1000) 349 | { 350 | VCAP *= 10; 351 | FlowScale *= 10; 352 | } 353 | 354 | /* All demands and capacity are multiplied by FlowScale. */ 355 | 356 | for (i=1; i<=NoOfCustomers; i++) 357 | { 358 | for (j=1; j<=SupportPtr->LP[i].CFN; j++) 359 | { 360 | k = SupportPtr->LP[i].FAL[j]; 361 | if ((k <= NoOfCustomers) && (k > i)) 362 | { 363 | XVal = XMatrix[i][k]; 364 | XVal *= VCAP; 365 | ArcCap = XVal + 1; /* => Round up. */ 366 | 367 | MXF_AddArc(MXFPtr,i,k,ArcCap); 368 | MXF_AddArc(MXFPtr,k,i,ArcCap); 369 | } 370 | } 371 | } 372 | 373 | DepotIdx = NoOfCustomers + 1; 374 | 375 | for (k=1; k<=NoOfCustomers; k++) DepotEdgeXVal[k] = 0.0; 376 | 377 | for (j=1; j<=SupportPtr->LP[DepotIdx].CFN; j++) 378 | { 379 | k = SupportPtr->LP[DepotIdx].FAL[j]; 380 | DepotEdgeXVal[k] = XMatrix[DepotIdx][k]; 381 | } 382 | 383 | InfCap = 0; 384 | 385 | for (k=1; k<=NoOfCustomers; k++) 386 | { 387 | XVal = DepotEdgeXVal[k]; 388 | XVal *= VCAP; 389 | 390 | XVal = XVal + 1 - 2 * FlowScale * Demand[k]; 391 | 392 | /* Arcs (Source,k) and (k,Sink) are added in any case. */ 393 | 394 | if (XVal > 0) 395 | { 396 | ArcCap = XVal; 397 | 398 | InfCap += ArcCap; 399 | 400 | MXF_AddArc(MXFPtr,NoOfCustomers+1,k,ArcCap); 401 | MXF_AddArc(MXFPtr,k,NoOfCustomers+2,0); /* Zero capacity to sink. */ 402 | ArcCapToSink[k] = 0; 403 | ArcCapFromSource[k] = ArcCap; 404 | } 405 | else 406 | if (XVal <= 0) 407 | { 408 | ArcCap = -XVal; 409 | 410 | MXF_AddArc(MXFPtr,k,NoOfCustomers+2,ArcCap); 411 | MXF_AddArc(MXFPtr,NoOfCustomers+1,k,0); /* Zero capacity from source. */ 412 | ArcCapToSink[k] = ArcCap; 413 | ArcCapFromSource[k] = 0; 414 | } 415 | } 416 | 417 | InfCap += (2 * VCAP); 418 | 419 | MXF_CreateMates(MXFPtr); 420 | 421 | MXF_SolveMaxFlow(MXFPtr,1,NoOfCustomers+1,NoOfCustomers+2,&MaxFlowValue,1, 422 | &SinkNodeListSize,NodeList); 423 | 424 | MXF_CreateArcMap(MXFPtr); 425 | 426 | MXF_GetNetworkSize(MXFPtr,&NetworkNodes,&NetworkArcs); 427 | 428 | ResidualCap = MemGetIV(NetworkArcs+1); 429 | NodeExcess = MemGetIV(NetworkNodes+1); 430 | 431 | MXF_GetCurrentFlow(MXFPtr,ResidualCap,NodeExcess); 432 | 433 | HistoryListSize = 0; 434 | for (i=1; i<=NoOfCustomers; i++) UseSeed[i] = 1; 435 | for (i=1; i<=NoOfCustomers; i++) OneNodeCut[i] = 0; 436 | 437 | for (RoundNr=1; RoundNr<=MaxRounds; RoundNr++) 438 | { 439 | if ((*NoOfGeneratedCuts >= MaxCuts) && (RoundNr > 1)) 440 | { 441 | goto EndOfCutGeneration; 442 | } 443 | 444 | for (SeedNode=1; SeedNode<=NoOfCustomers; SeedNode++) 445 | { 446 | if (UseSeed[SeedNode] == 0) continue; 447 | 448 | FCAPFIX_CompSourceFixNodes(HistoryRPtr, 449 | HistoryListSize, 450 | SeedNode, 451 | NoOfCustomers, 452 | FixedToSourceList, 453 | &FixedToSourceListSize); 454 | 455 | FixedToSinkList[1] = SeedNode; 456 | FixedToSinkListSize = 1; 457 | 458 | if (OneNodeCut[SeedNode]) 459 | { 460 | 461 | FCAPFIX_CompAddSinkNode(SupportPtr, 462 | NoOfCustomers, 463 | XMatrix, 464 | SeedNode, 465 | &AddSeedNode, 466 | FixedToSourceList, 467 | FixedToSourceListSize); 468 | 469 | if (AddSeedNode > 0) 470 | { 471 | FixedToSinkList[2] = AddSeedNode; 472 | FixedToSinkListSize = 2; 473 | } 474 | else 475 | { 476 | UseSeed[SeedNode] = 0; 477 | } 478 | } 479 | 480 | if (UseSeed[SeedNode] == 0) 481 | { 482 | continue; 483 | } 484 | 485 | FCAPFIX_SolveMaxFlow(MXFPtr, 486 | NoOfCustomers, 487 | InfCap, 488 | ResidualCap, 489 | NodeExcess, 490 | ArcCapFromSource, 491 | ArcCapToSink, 492 | FixedToSourceList, 493 | FixedToSourceListSize, 494 | FixedToSinkList, 495 | FixedToSinkListSize, 496 | NodeList, 497 | &NodeListSize); 498 | 499 | for (i=1; i<=NoOfCustomers; i++) NodeInSet[i] = 0; 500 | for (i=1; i<=NodeListSize; i++) NodeInSet[NodeList[i]] = 1; 501 | 502 | for (i=1; i<=NoOfCustomers; i++) FixedOut[i] = 0; 503 | for (i=1; i<=FixedToSourceListSize; i++) 504 | FixedOut[FixedToSourceList[i]] = 1; 505 | 506 | DemandSum = 0; 507 | 508 | for (i=1; i<=NodeListSize; i++) 509 | { 510 | j = NodeList[i]; 511 | DemandSum += Demand[j]; 512 | } 513 | 514 | CAPSum = CAP; 515 | MinV = 1; 516 | 517 | while (CAPSum < DemandSum) 518 | { 519 | CAPSum += CAP; 520 | MinV++; 521 | } 522 | 523 | MaxDemand = 0; 524 | 525 | for (i=1; i<=NoOfCustomers; i++) 526 | { 527 | if (NodeInSet[i] == 0) 528 | { 529 | if (Demand[i] > MaxDemand) 530 | MaxDemand = Demand[i]; 531 | } 532 | } 533 | 534 | ExpandNr = 0; 535 | 536 | if ((MaxDemand + DemandSum) > CAPSum) 537 | do 538 | { 539 | FCAPFIX_CheckExpandSet(SupportPtr, 540 | NoOfCustomers, 541 | Demand,CAP, 542 | XMatrix, 543 | NodeInSet, 544 | FixedOut, 545 | &AddNode, 546 | &AddSecondNode); 547 | 548 | if (AddNode > 0) 549 | { 550 | ExpandNr++; 551 | 552 | NodeList[++NodeListSize] = AddNode; 553 | NodeInSet[AddNode] = 1; 554 | 555 | if (AddSecondNode > 0) 556 | { 557 | NodeList[++NodeListSize] = AddSecondNode; 558 | NodeInSet[AddSecondNode] = 1; 559 | } 560 | } 561 | } while (AddNode > 0); 562 | 563 | 564 | if (NodeListSize == 1) 565 | { 566 | OneNodeCut[SeedNode] = 1; 567 | } 568 | 569 | HistoryListSize++; 570 | 571 | ReachSetForwList(HistoryRPtr,NodeList,HistoryListSize,NodeListSize); 572 | ReachSetBackwList(HistoryRPtr,FixedToSinkList,HistoryListSize,1); 573 | 574 | /* Check for violation. */ 575 | 576 | CUTBASE_CompXSumInSet(SupportPtr,NoOfCustomers, 577 | NULL, 578 | NodeList,NodeListSize, 579 | XMatrix, 580 | &XInSet); 581 | 582 | OrigNodes = 0; 583 | DemandSum = 0; 584 | for (i=1; i<=NodeListSize; i++) 585 | { 586 | j = NodeList[i]; 587 | OrigNodes += SuperNodeSize[j]; 588 | DemandSum += Demand[j]; 589 | 590 | if (SuperNodeSize[j] > 1) 591 | XInSet += XMatrix[j][j]; 592 | } 593 | 594 | CAPSum = CAP; 595 | MinV = 1; 596 | 597 | while (CAPSum < DemandSum) 598 | { 599 | CAPSum += CAP; 600 | MinV++; 601 | } 602 | 603 | LHS = XInSet; 604 | RHS = OrigNodes - MinV; 605 | 606 | Violation = LHS - RHS; 607 | 608 | if (Violation >= EpsViolation) 609 | { 610 | (*NoOfGeneratedCuts)++; 611 | 612 | ReachSetForwList(ResultRPtr, 613 | NodeList, 614 | (*NoOfGeneratedCuts), 615 | NodeListSize); 616 | 617 | if (*NoOfGeneratedCuts >= MaxCuts) 618 | { 619 | goto EndOfCutGeneration; 620 | } 621 | 622 | } 623 | 624 | } 625 | } 626 | 627 | EndOfCutGeneration: 628 | 629 | MemFree(UseSeed); 630 | 631 | MemFree(ArcCapToSink); 632 | MemFree(ArcCapFromSource); 633 | MemFree(FixedToSourceList); 634 | MemFree(FixedToSinkList); 635 | MemFree(NodeList); 636 | 637 | MemFree(DepotEdgeXVal); 638 | 639 | ReachFreeMem(&HistoryRPtr); 640 | 641 | MXF_FreeMem(MXFPtr); 642 | 643 | MemFree(ResidualCap); 644 | MemFree(NodeExcess); 645 | 646 | MemFree(OneNodeCut); 647 | MemFree(NodeInSet); 648 | MemFree(FixedOut); 649 | } 650 | 651 | -------------------------------------------------------------------------------- /src/ext/cvrpsep/memmod.cpp: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include 6 | #include 7 | 8 | #include "../../../include/ext/cvrpsep/memmod.h" 9 | 10 | void* MemGet(int NoOfBytes) 11 | { 12 | void *p; 13 | if ((p = malloc(NoOfBytes)) != NULL) 14 | { 15 | return p; 16 | } 17 | else 18 | { 19 | printf("*** MemGet(%d bytes)\n",NoOfBytes); 20 | printf("*** Error in memory allocation\n"); 21 | exit(0); /* Program stop. */ 22 | return NULL; /* Never called, but avoids compiler warning. */ 23 | } 24 | } 25 | 26 | void* MemReGet(void *p, int NewNoOfBytes) 27 | { 28 | if (p==NULL) return MemGet(NewNoOfBytes); 29 | 30 | if ((p = realloc(p,NewNoOfBytes)) != NULL) 31 | { 32 | return p; 33 | } 34 | else 35 | { 36 | printf("*** MemReGet(%d bytes)\n",NewNoOfBytes); 37 | printf("*** Error in memory allocation\n"); 38 | exit(0); /* Program stop. */ 39 | return NULL; /* Never called, but avoids compiler warning. */ 40 | } 41 | } 42 | 43 | void MemFree(void *p) 44 | { 45 | if (p!=NULL) 46 | { 47 | free(p); 48 | } 49 | } 50 | 51 | char* MemGetCV(int n) 52 | { 53 | return (char *) MemGet(sizeof(char)*n); 54 | } 55 | 56 | char** MemGetCM(int Rows, int Cols) 57 | { 58 | char **p; 59 | int i; 60 | p = (char **) MemGet(sizeof(char *)*Rows); 61 | if (p!=NULL) 62 | for (i=0; i 6 | #include 7 | 8 | #include "../../../include/ext/cvrpsep/memmod.h" 9 | 10 | int *StackLeft, *StackRight; 11 | char StacksAllocated = 0; 12 | 13 | void SortCheckStacks() 14 | { 15 | if (StacksAllocated) return; 16 | 17 | StackLeft = MemGetIV(50); /* Sufficient for sorting 2^50 numbers!! */ 18 | StackRight = MemGetIV(50); 19 | StacksAllocated = 1; 20 | } 21 | 22 | void SortIVInc(int *Value, int n) 23 | { 24 | int i,j,StackSize,Left,Right,Tmp,KeyValue; 25 | 26 | SortCheckStacks(); 27 | 28 | StackLeft[1]=1; 29 | StackRight[1]=n; 30 | StackSize=1; 31 | 32 | do 33 | { 34 | Left=StackLeft[StackSize]; 35 | Right=StackRight[StackSize]; 36 | StackSize--; 37 | 38 | do 39 | { 40 | i=Left; 41 | j=Right; 42 | 43 | KeyValue=Value[Left]; 44 | 45 | do 46 | { 47 | while ((j>i) && (Value[j] >= KeyValue)) 48 | j--; 49 | 50 | if (j>i) 51 | { 52 | Tmp=Value[j]; 53 | Value[j]=Value[i]; 54 | Value[i]=Tmp; 55 | i++; 56 | } 57 | 58 | while ((j>i) && (Value[i] <= KeyValue)) 59 | i++; 60 | 61 | if (j>i) 62 | { 63 | Tmp=Value[j]; 64 | Value[j]=Value[i]; 65 | Value[i]=Tmp; 66 | j--; 67 | } 68 | 69 | } while (i!=j); 70 | 71 | /* Find partition: */ 72 | 73 | if (i>Left) i--; 74 | if (j (Right-j)) 77 | { 78 | if (Left0); 100 | 101 | } 102 | 103 | void SortIVDec(int *Value, int n) 104 | { 105 | int i,j,StackSize,Left,Right,Tmp,KeyValue; 106 | 107 | SortCheckStacks(); 108 | 109 | StackLeft[1]=1; 110 | StackRight[1]=n; 111 | StackSize=1; 112 | 113 | do 114 | { 115 | Left=StackLeft[StackSize]; 116 | Right=StackRight[StackSize]; 117 | StackSize--; 118 | 119 | do 120 | { 121 | i=Left; 122 | j=Right; 123 | 124 | KeyValue=Value[Left]; 125 | /* Key=C[R[Left]]; */ 126 | 127 | do 128 | { 129 | while ((j>i) && (Value[j] <= KeyValue)) 130 | j--; 131 | 132 | if (j>i) 133 | { 134 | Tmp=Value[j]; 135 | Value[j]=Value[i]; 136 | Value[i]=Tmp; 137 | i++; 138 | } 139 | 140 | while ((j>i) && (Value[i] >= KeyValue)) 141 | i++; 142 | 143 | if (j>i) 144 | { 145 | Tmp=Value[j]; 146 | Value[j]=Value[i]; 147 | Value[i]=Tmp; 148 | j--; 149 | } 150 | 151 | } while (i!=j); 152 | 153 | /* Find partition: */ 154 | 155 | if (i>Left) i--; 156 | if (j (Right-j)) 159 | { 160 | if (Left0); 182 | 183 | } 184 | 185 | void SortDVInc(double *Value, int n) 186 | { 187 | int i,j,StackSize,Left,Right; 188 | double Tmp,KeyValue; 189 | 190 | SortCheckStacks(); 191 | 192 | StackLeft[1]=1; 193 | StackRight[1]=n; 194 | StackSize=1; 195 | 196 | do 197 | { 198 | Left=StackLeft[StackSize]; 199 | Right=StackRight[StackSize]; 200 | StackSize--; 201 | 202 | do 203 | { 204 | i=Left; 205 | j=Right; 206 | 207 | KeyValue=Value[Left]; 208 | 209 | do 210 | { 211 | while ((j>i) && (Value[j] >= KeyValue)) 212 | j--; 213 | 214 | if (j>i) 215 | { 216 | Tmp=Value[j]; 217 | Value[j]=Value[i]; 218 | Value[i]=Tmp; 219 | i++; 220 | } 221 | 222 | while ((j>i) && (Value[i] <= KeyValue)) 223 | i++; 224 | 225 | if (j>i) 226 | { 227 | Tmp=Value[j]; 228 | Value[j]=Value[i]; 229 | Value[i]=Tmp; 230 | j--; 231 | } 232 | 233 | } while (i!=j); 234 | 235 | /* Find partition: */ 236 | 237 | if (i>Left) i--; 238 | if (j (Right-j)) 241 | { 242 | if (Left0); 264 | 265 | } 266 | 267 | 268 | void SortDVDec(double *Value, int n) 269 | { 270 | int i,j,StackSize,Left,Right; 271 | double Tmp,KeyValue; 272 | 273 | SortCheckStacks(); 274 | 275 | StackLeft[1]=1; 276 | StackRight[1]=n; 277 | StackSize=1; 278 | 279 | do 280 | { 281 | Left=StackLeft[StackSize]; 282 | Right=StackRight[StackSize]; 283 | StackSize--; 284 | 285 | do 286 | { 287 | i=Left; 288 | j=Right; 289 | 290 | KeyValue=Value[Left]; 291 | 292 | do 293 | { 294 | while ((j>i) && (Value[j] <= KeyValue)) 295 | j--; 296 | 297 | if (j>i) 298 | { 299 | Tmp=Value[j]; 300 | Value[j]=Value[i]; 301 | Value[i]=Tmp; 302 | i++; 303 | } 304 | 305 | while ((j>i) && (Value[i] >= KeyValue)) 306 | i++; 307 | 308 | if (j>i) 309 | { 310 | Tmp=Value[j]; 311 | Value[j]=Value[i]; 312 | Value[i]=Tmp; 313 | j--; 314 | } 315 | 316 | } while (i!=j); 317 | 318 | /* Find partition: */ 319 | 320 | if (i>Left) i--; 321 | if (j (Right-j)) 324 | { 325 | if (Left0); 347 | 348 | } 349 | 350 | void SortIndexIVInc(int *Index, int *Value, int n) 351 | { 352 | /* Sorts the indices in the Index vector so that the 353 | k'th smallest value in the Value vector is Value[Index[k]]. */ 354 | 355 | int i,j,StackSize,Left,Right,Tmp; 356 | int KeyValue; 357 | 358 | SortCheckStacks(); 359 | 360 | StackLeft[1]=1; 361 | StackRight[1]=n; 362 | StackSize=1; 363 | 364 | do 365 | { 366 | Left=StackLeft[StackSize]; 367 | Right=StackRight[StackSize]; 368 | StackSize--; 369 | 370 | do 371 | { 372 | i=Left; 373 | j=Right; 374 | 375 | KeyValue=Value[Index[Left]]; 376 | 377 | do 378 | { 379 | while ((j>i) && (Value[Index[j]] >= KeyValue)) 380 | j--; 381 | 382 | if (j>i) 383 | { 384 | Tmp=Index[j]; 385 | Index[j]=Index[i]; 386 | Index[i]=Tmp; 387 | i++; 388 | } 389 | 390 | while ((j>i) && (Value[Index[i]] <= KeyValue)) 391 | i++; 392 | 393 | if (j>i) 394 | { 395 | Tmp=Index[j]; 396 | Index[j]=Index[i]; 397 | Index[i]=Tmp; 398 | j--; 399 | } 400 | 401 | } while (i!=j); 402 | 403 | /* Find partition: */ 404 | 405 | if (i>Left) i--; 406 | if (j (Right-j)) 409 | { 410 | if (Left0); 432 | } 433 | 434 | void SortIndexIVDec(int *Index, int *Value, int n) 435 | { 436 | int i,j,StackSize,Left,Right,Tmp; 437 | int KeyValue; 438 | 439 | SortCheckStacks(); 440 | 441 | StackLeft[1]=1; 442 | StackRight[1]=n; 443 | StackSize=1; 444 | 445 | do 446 | { 447 | Left=StackLeft[StackSize]; 448 | Right=StackRight[StackSize]; 449 | StackSize--; 450 | 451 | do 452 | { 453 | i=Left; 454 | j=Right; 455 | 456 | KeyValue=Value[Index[Left]]; 457 | 458 | do 459 | { 460 | while ((j>i) && (Value[Index[j]] <= KeyValue)) 461 | j--; 462 | 463 | if (j>i) 464 | { 465 | Tmp=Index[j]; 466 | Index[j]=Index[i]; 467 | Index[i]=Tmp; 468 | i++; 469 | } 470 | 471 | while ((j>i) && (Value[Index[i]] >= KeyValue)) 472 | i++; 473 | 474 | if (j>i) 475 | { 476 | Tmp=Index[j]; 477 | Index[j]=Index[i]; 478 | Index[i]=Tmp; 479 | j--; 480 | } 481 | 482 | } while (i!=j); 483 | 484 | /* Find partition: */ 485 | 486 | if (i>Left) i--; 487 | if (j (Right-j)) 490 | { 491 | if (Left0); 513 | } 514 | 515 | void SortIndexDVInc(int *Index, double *Value, int n) 516 | { 517 | /* Sorts the indices in the Index vector so that the 518 | k'th smallest value in the Value vector is Value[Index[k]]. */ 519 | 520 | int i,j,StackSize,Left,Right,Tmp; 521 | double KeyValue; 522 | 523 | SortCheckStacks(); 524 | 525 | StackLeft[1]=1; 526 | StackRight[1]=n; 527 | StackSize=1; 528 | 529 | do 530 | { 531 | Left=StackLeft[StackSize]; 532 | Right=StackRight[StackSize]; 533 | StackSize--; 534 | 535 | do 536 | { 537 | i=Left; 538 | j=Right; 539 | 540 | KeyValue=Value[Index[Left]]; 541 | 542 | do 543 | { 544 | while ((j>i) && (Value[Index[j]] >= KeyValue)) 545 | j--; 546 | 547 | if (j>i) 548 | { 549 | Tmp=Index[j]; 550 | Index[j]=Index[i]; 551 | Index[i]=Tmp; 552 | i++; 553 | } 554 | 555 | while ((j>i) && (Value[Index[i]] <= KeyValue)) 556 | i++; 557 | 558 | if (j>i) 559 | { 560 | Tmp=Index[j]; 561 | Index[j]=Index[i]; 562 | Index[i]=Tmp; 563 | j--; 564 | } 565 | 566 | } while (i!=j); 567 | 568 | /* Find partition: */ 569 | 570 | if (i>Left) i--; 571 | if (j (Right-j)) 574 | { 575 | if (Left0); 597 | } 598 | 599 | void SortIndexDVDec(int *Index, double *Value, int n) 600 | { 601 | /* Sorts the indices in the Index vector so that the 602 | k'th largest value in the Value vector is Value[Index[k]]. */ 603 | 604 | int i,j,StackSize,Left,Right,Tmp; 605 | double KeyValue; 606 | 607 | SortCheckStacks(); 608 | 609 | StackLeft[1]=1; 610 | StackRight[1]=n; 611 | StackSize=1; 612 | 613 | do 614 | { 615 | Left=StackLeft[StackSize]; 616 | Right=StackRight[StackSize]; 617 | StackSize--; 618 | 619 | do 620 | { 621 | i=Left; 622 | j=Right; 623 | 624 | KeyValue=Value[Index[Left]]; 625 | 626 | do 627 | { 628 | while ((j>i) && (Value[Index[j]] <= KeyValue)) 629 | j--; 630 | 631 | if (j>i) 632 | { 633 | Tmp=Index[j]; 634 | Index[j]=Index[i]; 635 | Index[i]=Tmp; 636 | i++; 637 | } 638 | 639 | while ((j>i) && (Value[Index[i]] >= KeyValue)) 640 | i++; 641 | 642 | if (j>i) 643 | { 644 | Tmp=Index[j]; 645 | Index[j]=Index[i]; 646 | Index[i]=Tmp; 647 | j--; 648 | } 649 | 650 | } while (i!=j); 651 | 652 | /* Find partition: */ 653 | 654 | if (i>Left) i--; 655 | if (j (Right-j)) 658 | { 659 | if (Left0); 681 | } 682 | 683 | 684 | -------------------------------------------------------------------------------- /src/ext/cvrpsep/strngcmp.cpp: -------------------------------------------------------------------------------- 1 | /* (C) Copyright 2003 Jens Lysgaard. All rights reserved. */ 2 | /* OSI Certified Open Source Software */ 3 | /* This software is licensed under the Common Public License Version 1.0 */ 4 | 5 | #include 6 | #include 7 | 8 | #include "../../../include/ext/cvrpsep/basegrph.h" 9 | #include "../../../include/ext/cvrpsep/strngcmp.h" 10 | 11 | int ConnectCallNr; 12 | int StackSize, ComponentSize; 13 | int ComponentNr; 14 | char *OnStack; 15 | int *NUMBER, *LOWLINK, *Stack, *Component; 16 | ReachPtr AdjPtr, ResCompPtr; 17 | 18 | void StrongConnect(int v) 19 | { 20 | int a,w; 21 | 22 | ConnectCallNr++; 23 | 24 | LOWLINK[v]=ConnectCallNr; 25 | NUMBER[v]=ConnectCallNr; 26 | 27 | Stack[++StackSize]=v; 28 | OnStack[v]=1; 29 | 30 | for (a=1; a<=AdjPtr->LP[v].CFN; a++) 31 | { 32 | w=AdjPtr->LP[v].FAL[a]; 33 | if (NUMBER[w]==0) 34 | { 35 | StrongConnect(w); 36 | if (LOWLINK[w] < LOWLINK[v]) LOWLINK[v] = LOWLINK[w]; 37 | } 38 | else 39 | if (NUMBER[w] < NUMBER[v]) 40 | { 41 | if (OnStack[w]) 42 | { 43 | if (NUMBER[w] < LOWLINK[v]) LOWLINK[v] = NUMBER[w]; 44 | } 45 | } 46 | } 47 | 48 | 49 | if (LOWLINK[v]==NUMBER[v]) 50 | { 51 | ComponentNr++; 52 | ComponentSize=0; 53 | 54 | while ((StackSize > 0) && (NUMBER[Stack[StackSize]] >= NUMBER[v])) 55 | { 56 | OnStack[Stack[StackSize]]=0; 57 | Component[++ComponentSize]=Stack[StackSize--]; 58 | } 59 | 60 | ReachSetForwList(ResCompPtr,Component,ComponentNr,ComponentSize); 61 | } 62 | 63 | } 64 | 65 | 66 | void ComputeStrongComponents(ReachPtr RPtr, ReachPtr ResultPtr, 67 | int *NoOfComponents, int n, 68 | char *CVWrk1, 69 | int *IVWrk1, int *IVWrk2, int *IVWrk3, 70 | int *IVWrk4) 71 | { 72 | int i; 73 | 74 | OnStack = CVWrk1; 75 | 76 | NUMBER = IVWrk1; 77 | LOWLINK = IVWrk2; 78 | Stack = IVWrk3; 79 | Component = IVWrk4; 80 | 81 | for (i=1; i<=n; i++) 82 | { 83 | NUMBER[i]=0; 84 | OnStack[i]=0; 85 | } 86 | 87 | ConnectCallNr = 0; 88 | StackSize = 0; 89 | ComponentNr = 0; 90 | 91 | AdjPtr = RPtr; 92 | ResCompPtr = ResultPtr; 93 | 94 | for (i=1; i<=n; i++) 95 | { 96 | if (NUMBER[i]==0) 97 | StrongConnect(i); 98 | } 99 | 100 | *NoOfComponents = ComponentNr; 101 | } 102 | -------------------------------------------------------------------------------- /src/init_grb_model.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: init_grb_model.cpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Gurobi's model initialization helper functions definitions. 7 | * 8 | * @acknowledgment Special thanks to Ph.D. Cleder Marcos Schenekemberg. 9 | * 10 | * (I'm sorry for my bad english xD) 11 | * 12 | * Created on October 22, 2020, 10:44 PM. 13 | * 14 | * References: 15 | */ 16 | //////////////////////////////////////////////////////////////////////////////// 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "../include/ext/loguru/loguru.hpp" 23 | 24 | #include "../include/init_grb_model.hpp" 25 | 26 | /////////////////////////////// Helper functions /////////////////////////////// 27 | 28 | namespace 29 | { 30 | 31 | std::vector findSetS(const int idx, const int nbVertices) 32 | { 33 | const int MAX_N = 30; 34 | CHECK_F(nbVertices < MAX_N, "You shouldn't use SEC with |V| > 30"); 35 | 36 | std::vector inS; 37 | inS.reserve(nbVertices); 38 | 39 | std::bitset myBitset(idx); 40 | for (int i = 1; i < nbVertices; ++i) 41 | { 42 | if (myBitset[i - 1]) 43 | { 44 | inS.push_back(i); 45 | } 46 | } 47 | 48 | return inS; 49 | } 50 | 51 | } // anonymous namespace 52 | 53 | 54 | void init::inventoryLevelVariables( 55 | GRBModel& model, 56 | std::vector>& I, 57 | const std::shared_ptr& pInst) 58 | { 59 | DRAW_LOG_F(INFO, "\tinitializing inventory level variables (I_it)"); 60 | 61 | I.reserve(pInst->getNbVertices()); 62 | for (auto i = 0; i < pInst->getNbVertices(); ++i) 63 | { 64 | I.push_back(std::vector()); 65 | I[i].reserve(pInst->getT() + 1); 66 | for (auto t = 0; t <= pInst->getT(); ++t) 67 | { 68 | std::ostringstream oss; 69 | oss << "I_" << i << "_" << t; 70 | I[i].push_back(model.addVar(0, 71 | i == 0 ? GRB_INFINITY : pInst->getUi(i), 72 | pInst->get_hi(i), 73 | GRB_CONTINUOUS, 74 | oss.str())); 75 | } 76 | } 77 | } 78 | 79 | void init::quantityVariables(GRBModel& model, 80 | std::vector>>& q, 81 | const std::shared_ptr& pInst) 82 | { 83 | DRAW_LOG_F(INFO, "\tinitializing quantity delivered variables (q_it)"); 84 | 85 | q.reserve(pInst->getNbVertices()); 86 | for (auto i = 0; i < pInst->getNbVertices(); ++i) 87 | { 88 | q.push_back(std::vector>()); 89 | q[i].reserve(pInst->getK()); 90 | 91 | for (auto k = 0; k < pInst->getK(); ++k) 92 | { 93 | q[i].push_back(std::vector(pInst->getT() + 1)); 94 | 95 | if (i == 0) continue; 96 | 97 | for (auto t = 0; t < pInst->getT(); ++t) 98 | { 99 | std::ostringstream oss; 100 | oss << "q_" << i << "_" << k << "_" << t; 101 | q[i][k][t] = model.addVar(0, 102 | GRB_INFINITY, 103 | 0, 104 | GRB_CONTINUOUS, 105 | oss.str()); 106 | } 107 | } 108 | } 109 | } 110 | 111 | 112 | void init::visitationVariables(GRBModel& model, 113 | std::vector>>& y, 114 | const std::shared_ptr& pInst) 115 | { 116 | DRAW_LOG_F(INFO, "\tinitializing visitation variables (y_it)"); 117 | 118 | y.reserve(pInst->getNbVertices()); 119 | for (auto i = 0; i < pInst->getNbVertices(); ++i) 120 | { 121 | y.push_back(std::vector>()); 122 | y[i].reserve(pInst->getK()); 123 | for (auto k = 0; k < pInst->getK(); ++k) 124 | { 125 | y[i].push_back(std::vector(pInst->getT() + 1)); 126 | for (auto t = 0; t < pInst->getT(); ++t) 127 | { 128 | std::ostringstream oss; 129 | oss << "y_" << i << "_" << k << "_" << t; 130 | y[i][k][t] = model.addVar(0, 1, 0, GRB_BINARY, oss.str()); 131 | } 132 | } 133 | } 134 | } 135 | 136 | 137 | void init::routingVariables( 138 | GRBModel& model, 139 | std::vector>>>& x, 140 | const std::shared_ptr& pInst) 141 | { 142 | DRAW_LOG_F(INFO, "\tinitializing routing variables (x_ijt)"); 143 | 144 | x.reserve(pInst->getNbVertices()); 145 | for (auto i = 0; i < pInst->getNbVertices(); ++i) 146 | { 147 | x.push_back(std::vector>>()); 148 | x[i].reserve(pInst->getNbVertices()); 149 | for (auto j = 0; j < pInst->getNbVertices(); ++j) 150 | { 151 | x[i].push_back(std::vector>()); 152 | x[i][j].reserve(pInst->getK()); 153 | 154 | for (auto k = 0; k < pInst->getK(); ++k) 155 | { 156 | x[i][j].push_back(std::vector(pInst->getT() + 1)); 157 | if (j <= i) continue; 158 | 159 | for (auto t = 0; t < pInst->getT(); ++t) 160 | { 161 | std::ostringstream oss; 162 | oss << "x_" << i << "_" << j << "_" << k << "_" << t; 163 | x[i][j][k][t] = model.addVar(0, 164 | (i == 0 ? 2 : 1), 165 | pInst->get_cij(i, j), 166 | GRB_INTEGER, 167 | oss.str()); 168 | } 169 | } 170 | } 171 | } 172 | } 173 | 174 | 175 | // ok 176 | void init::inventoryDefDepotConstrs( 177 | GRBModel& model, 178 | std::vector& constrs, 179 | const std::vector>& I, 180 | const std::vector>>& q, 181 | const std::shared_ptr& pInst) 182 | { 183 | DRAW_LOG_F(INFO, "\tinitializing inventory definition depot constraints"); 184 | 185 | constrs.push_back(model.addConstr(I[0][0] == pInst->getIi0(0), "1C_0")); 186 | for (auto t = 1; t <= pInst->getT(); ++t) 187 | { 188 | GRBLinExpr e = I[0][t - 1] + pInst->get_rit(0, t - 1); 189 | for (auto i = 1; i < pInst->getNbVertices(); ++i) // skip depot 190 | { 191 | for (auto k = 0; k < pInst->getK(); ++k) 192 | { 193 | e -= q[i][k][t - 1]; 194 | } 195 | } 196 | 197 | std::ostringstream oss; 198 | oss << "1C_" << t; 199 | constrs.push_back(model.addConstr(I[0][t] == e, oss.str())); 200 | } 201 | } 202 | 203 | 204 | // ok 205 | void init::stockOutDepotConstrs( 206 | GRBModel& model, 207 | std::vector& constrs, 208 | const std::vector>& I, 209 | const std::vector>>& q, 210 | const std::shared_ptr& pInst) 211 | { 212 | DRAW_LOG_F(INFO, "\tinitializing stockout depot contraints"); 213 | 214 | for (auto t = 0; t < pInst->getT(); ++t) 215 | { 216 | GRBLinExpr e = 0; 217 | for (int i = 1; i < pInst->getNbVertices(); i++) 218 | { 219 | for (auto k = 0; k < pInst->getK(); ++k) 220 | { 221 | e += q[i][k][t]; 222 | } 223 | } 224 | 225 | std::ostringstream oss; 226 | oss << "2C_" << t; 227 | constrs.push_back(model.addConstr(I[0][t] >= e, oss.str())); 228 | } 229 | } 230 | 231 | 232 | // ok 233 | void init::inventoryDefCustomersConstrs( 234 | GRBModel& model, 235 | std::vector& constrs, 236 | const std::vector>& I, 237 | const std::vector>>& q, 238 | const std::shared_ptr& pInst) 239 | { 240 | DRAW_LOG_F(INFO, "\tinitializing inventory definition customers contraints"); 241 | 242 | for (auto i = 1; i < pInst->getNbVertices(); ++i) 243 | { 244 | std::ostringstream oss; 245 | oss << "3C_" << i; 246 | constrs.push_back( 247 | model.addConstr(I[i][0] == pInst->getIi0(i), oss.str())); 248 | 249 | for (auto t = 1; t <= pInst->getT(); ++t) 250 | { 251 | GRBLinExpr e = 0; 252 | for (auto k = 0; k < pInst->getK(); ++k) 253 | { 254 | e += q[i][k][t - 1]; 255 | } 256 | 257 | e += I[i][t - 1] - pInst->get_rit(i, t - 1); 258 | 259 | oss.clear(); 260 | oss.str(""); 261 | oss << "3C_" << i << "_" << t; 262 | constrs.push_back(model.addConstr(I[i][t] == e, oss.str())); 263 | } 264 | } 265 | } 266 | 267 | 268 | // ok 269 | void init::inventoryLevelConstrs( 270 | GRBModel& model, 271 | std::vector& constrs, 272 | const std::vector>& I, 273 | const std::vector>>& q, 274 | const std::shared_ptr& pInst) 275 | { 276 | DRAW_LOG_F(INFO, "\tinitializing inventory level constraints"); 277 | 278 | for (int t = 0; t < pInst->getT(); ++t) 279 | { 280 | GRBLinExpr e = 0; 281 | for (int i = 1; i < pInst->getNbVertices(); ++i) 282 | { 283 | for (auto k = 0; k < pInst->getK(); ++k) 284 | { 285 | e += q[i][k][t]; 286 | } 287 | } 288 | 289 | std::ostringstream oss; 290 | oss << "5C_" << t; 291 | constrs.push_back(model.addConstr(I[0][t] >= e, oss.str())); 292 | } 293 | } 294 | 295 | 296 | // ok 297 | void init::mlQuantityCapacityConstrs( 298 | GRBModel& model, 299 | std::vector& constrs, 300 | const std::vector>& I, 301 | const std::vector>>& q, 302 | const std::shared_ptr& pInst) 303 | { 304 | DRAW_LOG_F(INFO, "\tML quantity capacity constraints"); 305 | 306 | for (auto i = 1; i < pInst->getNbVertices(); ++i) 307 | { 308 | for (auto t = 0; t < pInst->getT(); ++t) 309 | { 310 | GRBLinExpr e = 0; 311 | for (auto k = 0; k < pInst->getK(); ++k) 312 | { 313 | e += q[i][k][t]; 314 | } 315 | 316 | std::ostringstream oss; 317 | oss << "6C_ML" << i << "_" << t; 318 | constrs.push_back( 319 | model.addConstr(e <= pInst->getUi(i) - I[i][t], oss.str())); 320 | } 321 | } 322 | } 323 | 324 | 325 | // ok 326 | void init::ouQuantityCapacityConstrs( 327 | GRBModel& model, 328 | std::vector& constrs, 329 | const std::vector>& I, 330 | const std::vector>>& y, 331 | const std::vector>>& q, 332 | const std::shared_ptr& pInst) 333 | { 334 | DRAW_LOG_F(INFO, "\tOU quantity capacity constraints"); 335 | 336 | for (auto i = 1; i < pInst->getNbVertices(); ++i) 337 | { 338 | for (auto t = 0; t < pInst->getT(); ++t) 339 | { 340 | GRBLinExpr e1 = 0; 341 | GRBLinExpr e2 = 0; 342 | for (int k = 0; k < pInst->getK(); ++k) 343 | { 344 | e1 += q[i][k][t]; 345 | e2 += y[i][k][t]; 346 | } 347 | 348 | std::ostringstream oss; 349 | oss << "6C_OU" << i << "_" << t; 350 | constrs.push_back(model.addConstr(e1 >= 351 | pInst->getUi(i) * e2 - I[i][t], oss.str())); 352 | } 353 | } 354 | } 355 | 356 | 357 | // ok 358 | void init::quantitiesRoutingConstraint( 359 | GRBModel& model, 360 | std::vector& constrs, 361 | const std::vector>>& y, 362 | const std::vector>>& q, 363 | const std::shared_ptr& pInst) 364 | { 365 | DRAW_LOG_F(INFO, "\tinitializing quantities routing constraints"); 366 | 367 | for (auto i = 1; i < pInst->getNbVertices(); ++i) 368 | { 369 | for (int k = 0; k < pInst->getK(); ++k) 370 | { 371 | for (auto t = 0; t < pInst->getT(); ++t) 372 | { 373 | std::ostringstream oss; 374 | oss << "7C" << i << "_" << k << "_" << t; 375 | constrs.push_back(model.addConstr(q[i][k][t] <= 376 | pInst->getUi(i) * y[i][k][t], oss.str())); 377 | } 378 | } 379 | } 380 | } 381 | 382 | 383 | // ok 384 | void init::capacityVehicleConstraint( 385 | GRBModel& model, 386 | std::vector& constrs, 387 | const std::vector>>& y, 388 | const std::vector>>& q, 389 | const std::shared_ptr& pInst) 390 | { 391 | DRAW_LOG_F(INFO, "\tinitializing capacity vehicles constraints"); 392 | 393 | for (int k = 0; k < pInst->getK(); ++k) 394 | { 395 | for (auto t = 0; t < pInst->getT(); ++t) 396 | { 397 | GRBLinExpr e = 0; 398 | for (auto i = 1; i < pInst->getNbVertices(); ++i) 399 | { 400 | e += q[i][k][t]; 401 | } 402 | 403 | std::ostringstream oss; 404 | oss << "8C_" << k << "_" << t; 405 | constrs.push_back( 406 | model.addConstr(e <= pInst->getCk(k) * y[0][k][t], oss.str())); 407 | } 408 | } 409 | } 410 | 411 | 412 | // ok 413 | void init::degreeConstrs( 414 | GRBModel& model, 415 | std::vector& constrs, 416 | const std::vector>>& y, 417 | const std::vector>>>& x, 418 | const std::shared_ptr& pInst) 419 | { 420 | DRAW_LOG_F(INFO, "\tinitializing degree constraints"); 421 | 422 | for (auto k = 0; k < pInst->getK(); ++k) 423 | { 424 | for (auto t = 0; t < pInst->getT(); ++t) 425 | { 426 | for (auto i = 0; i < pInst->getNbVertices(); ++i) 427 | { 428 | GRBLinExpr e1 = 0; 429 | for (auto j = i + 1; j < pInst->getNbVertices(); ++j) 430 | { 431 | e1 += x[i][j][k][t]; 432 | } 433 | 434 | GRBLinExpr e2 = 0; 435 | for (auto j = 0; j < i; ++j) 436 | { 437 | e2 += x[j][i][k][t]; 438 | } 439 | 440 | std::ostringstream oss; 441 | oss << "9C_" << i << "_" << k << "_" << t; 442 | constrs.push_back( 443 | model.addConstr(e1 + e2 == 2 * y[i][k][t], oss.str())); 444 | } 445 | } 446 | } 447 | } 448 | 449 | 450 | void init::subtourEliminationConstrs( 451 | GRBModel& model, 452 | std::vector& constrs, 453 | const std::vector>>& y, 454 | const std::vector>>>& x, 455 | const std::shared_ptr& pInst) 456 | { 457 | DRAW_LOG_F(INFO, "\tinitializing subtour elimination constraints"); 458 | 459 | const auto nbSets = std::pow(2, pInst->getNbVertices() - 1); 460 | for (int c = 1; c < nbSets; ++c) 461 | { 462 | auto S = findSetS(c, pInst->getNbVertices()); 463 | if (S.size() > 1) 464 | { 465 | for (int k = 0; k < pInst->getK(); ++k) 466 | { 467 | for (auto t = 0; t < pInst->getT(); ++t) 468 | { 469 | for (auto m : S) 470 | { 471 | GRBLinExpr lhs = 0; 472 | GRBLinExpr rhs = 0; 473 | for (auto i : S) 474 | { 475 | for (auto j : S) 476 | { 477 | if (i < j) 478 | { 479 | lhs += x[i][j][k][t]; 480 | } 481 | } 482 | rhs += y[i][k][t]; 483 | } 484 | 485 | rhs -= y[m][k][t]; 486 | 487 | std::ostringstream oss; 488 | oss << "5CB_" << c << "_" << k << "_" << t << "_" << m; 489 | constrs.push_back(model.addConstr(lhs <= rhs, 490 | oss.str())); 491 | } 492 | } 493 | } 494 | } 495 | } 496 | } 497 | 498 | 499 | void init::noSplitDelivery( 500 | GRBModel& model, 501 | const std::vector>>& y, 502 | const std::shared_ptr& pInst) 503 | { 504 | DRAW_LOG_F(INFO, "\tinitializing no split delivery constraints"); 505 | 506 | for (int t = 0; t < pInst->getT(); ++t) 507 | { 508 | for (int i = 1; i < pInst->getNbVertices(); ++i) 509 | { 510 | GRBLinExpr e = 0; 511 | for (int k = 0; k < pInst->getK(); ++k) 512 | { 513 | e += y[i][k][t]; 514 | } 515 | 516 | std::ostringstream oss; 517 | oss << "10C_" << t << "_" << i; 518 | model.addConstr(e <= 1, oss.str()); 519 | } 520 | } 521 | } -------------------------------------------------------------------------------- /src/instance.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: instance.cpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief IRP instance class declaration. 7 | * 8 | * (I'm sorry for my bad english xD) 9 | * 10 | * Created on October 22, 2020, 07:02 PM. 11 | * 12 | * References: 13 | * https://bit.ly/3dQu0Kc 14 | */ 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "../include/ext/loguru/loguru.hpp" 24 | 25 | #include "../include/config_parameters.hpp" 26 | #include "../include/instance.hpp" 27 | 28 | /////////////////////////////// Helper methods //////////////////////////////// 29 | 30 | namespace 31 | { 32 | 33 | /** 34 | * @brief:. 35 | * @param:. 36 | * @return:. 37 | */ 38 | std::vector> compute_distance_mtx( 39 | const std::vector>& coord) 40 | { 41 | std::vector> cij(coord.size(), 42 | std::vector(coord.size(), 0)); 43 | 44 | for (std::size_t i = 0; i < coord.size(); ++i) 45 | { 46 | for (std::size_t j = i + 1; j < coord.size(); ++j) 47 | { 48 | auto tmp = std::sqrt(std::pow(coord[i].first - coord[j].first, 2) + 49 | std::pow(coord[i].second - coord[j].second,2)); 50 | cij[i][j] = static_cast(std::round(tmp)); 51 | cij[j][i] = cij[i][j]; 52 | } 53 | } 54 | 55 | return cij; 56 | } 57 | 58 | 59 | template 60 | std::ostream& operator<<(std::ostream& out, const std::vector& v) 61 | { 62 | if (!v.empty()) 63 | { 64 | out << '['; 65 | std::copy(v.begin(), v.end(), std::ostream_iterator(out, ", ")); 66 | out << "\b\b]"; 67 | } 68 | return out; 69 | } 70 | 71 | 72 | } // anonymous namespace 73 | 74 | //////////////////////////////////////////////////////////////////////////////// 75 | 76 | Instance::Instance(const std::string& filePath, const int K) : 77 | mPath(filePath), 78 | mK(K) 79 | { 80 | CHECK_F(std::filesystem::exists(filePath)); 81 | init(filePath); 82 | } 83 | 84 | 85 | double Instance::getC() const 86 | { 87 | return mC; 88 | } 89 | 90 | 91 | double Instance::getCk(const int k) const 92 | { 93 | DCHECK_F(k < static_cast(mCk.size())); 94 | return mCk[k]; 95 | } 96 | 97 | 98 | double Instance::get_cij(const int i, const int j) const 99 | { 100 | DCHECK_F(i < static_cast(m_cij.size())); 101 | DCHECK_F(j < static_cast(m_cij[i].size())); 102 | return m_cij[i][j]; 103 | } 104 | 105 | 106 | double Instance::get_hi(const int i) const 107 | { 108 | DCHECK_F(i < static_cast(m_hi.size())); 109 | return m_hi[i]; 110 | } 111 | 112 | 113 | double Instance::getIi0(const int i) const 114 | { 115 | DCHECK_F(i < static_cast(mIi0.size())); 116 | return mIi0[i]; 117 | } 118 | 119 | 120 | double Instance::getLi(const int i) const 121 | { 122 | DCHECK_F(i < static_cast(mLi.size())); 123 | return mLi[i]; 124 | } 125 | 126 | 127 | int Instance::getK() const 128 | { 129 | return mK; 130 | } 131 | 132 | 133 | std::string Instance::getName() const 134 | { 135 | return std::filesystem::path(mPath).stem().string(); 136 | } 137 | 138 | 139 | int Instance::getNbVertices() const 140 | { 141 | return mNbVertices; 142 | } 143 | 144 | 145 | double Instance::get_rit(const int i, const int t) const 146 | { 147 | DCHECK_F(i < static_cast(m_rit.size())); 148 | DCHECK_F(t < static_cast(m_rit[i].size())); 149 | return m_rit[i][t]; 150 | } 151 | 152 | 153 | int Instance::getT() const 154 | { 155 | return mT; 156 | } 157 | 158 | 159 | double Instance::getUi(const int i) const 160 | { 161 | DCHECK_F(i < static_cast(mUi.size())); 162 | return mUi[i]; 163 | } 164 | 165 | 166 | void Instance::setK(const int K) 167 | { 168 | mK = K; 169 | } 170 | 171 | 172 | void Instance::show() const 173 | { 174 | RAW_LOG_F(INFO, std::string(80, '-').c_str()); 175 | 176 | std::ostringstream oss; 177 | 178 | oss << "Instance details\n"; 179 | oss << "n\t" << mNbVertices << "\n"; 180 | oss << "H\t" << mT << "\n"; 181 | oss << "C\t" << mC; 182 | 183 | RAW_LOG_F(INFO, oss.str().c_str()); 184 | 185 | oss.clear(); 186 | oss.str(""); 187 | oss << "Li:\n"; 188 | oss << mLi << "\n"; 189 | oss << "Ui:\n"; 190 | oss << mUi << "\n"; 191 | 192 | oss << "Distance matrix:\n"; 193 | for (auto &r : m_cij) 194 | { 195 | oss << "|"; 196 | std::string sep = ""; 197 | for (auto e : r) 198 | { 199 | oss << sep << e; 200 | sep = "\t"; 201 | } 202 | oss << sep << "|\n"; 203 | } 204 | 205 | RAW_LOG_F(INFO, oss.str().c_str()); 206 | RAW_LOG_F(INFO, std::string(80, '-').c_str()); 207 | } 208 | 209 | 210 | /////////////////////////////// private methods //////////////////////////////// 211 | 212 | void Instance::init(const std::string& filePath) 213 | { 214 | std::ifstream file(filePath); 215 | 216 | file >> mNbVertices; 217 | file >> mT; 218 | file >> mC; 219 | 220 | m_hi.reserve(mNbVertices); 221 | mIi0.reserve(mNbVertices); 222 | m_rit.reserve(mNbVertices); 223 | mLi.reserve(mNbVertices); 224 | mLi.push_back(0); 225 | mUi.reserve(mNbVertices); 226 | mUi.push_back(0); 227 | mCoord.reserve(mNbVertices); 228 | 229 | mCk.reserve(mK); 230 | for (int i = 0; i < mK; ++i) 231 | { 232 | mCk.push_back(std::round(mC / mK)); 233 | } 234 | 235 | /* first line: depot */ 236 | { 237 | double x, y; 238 | file >> x >> x >> y; // skip index 239 | mCoord.push_back(std::make_pair(x, y)); 240 | } 241 | 242 | double tmp = 0; 243 | file >> tmp; 244 | mIi0.push_back(tmp); 245 | 246 | file >> tmp; 247 | m_rit = std::vector>(mNbVertices, 248 | std::vector(mT + 1, 0)); 249 | for (auto t = 0; t < mT; ++t) 250 | { 251 | DCHECK_F(t < static_cast(m_rit[0].size())); 252 | m_rit[0][t] = tmp; 253 | } 254 | 255 | file >> tmp; 256 | m_hi.push_back(tmp); 257 | 258 | /* retailers */ 259 | std::string line; 260 | int count = 1; 261 | while (count < mNbVertices) 262 | { 263 | int index = 0; 264 | file >> index; 265 | 266 | { 267 | double x, y; 268 | file >> x >> y; 269 | mCoord.push_back(std::make_pair(x, y)); 270 | } 271 | 272 | file >> tmp; 273 | mIi0.push_back(tmp); 274 | file >> tmp; 275 | mUi.push_back(tmp); 276 | file >> tmp; 277 | mLi.push_back(tmp); 278 | 279 | file >> tmp; 280 | for (auto t = 0; t < mT; ++t) 281 | { 282 | DCHECK_F(index - 1 < static_cast(m_rit.size())); 283 | DCHECK_F(t < static_cast(m_rit[index - 1].size())); 284 | m_rit[index - 1][t] = tmp; 285 | } 286 | 287 | file >> tmp; 288 | m_hi.push_back(tmp); 289 | ++count; 290 | } 291 | 292 | m_cij = compute_distance_mtx(mCoord); 293 | } -------------------------------------------------------------------------------- /src/irp_lp.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: irp_lp.cpp 4 | * Author: Guilherme O. Chagas 5 | * 6 | * @brief Classic Inventory-Routing Problem (IRP) linear program [1] class 7 | * definition. 8 | * 9 | * (I'm sorry for my bad english xD) 10 | * 11 | * Created on October 22, 2020, 06:49 PM. 12 | * 13 | * References: 14 | * [1] C. Archetti, L. Bertazzi, G. Laporte and M. G. Speranza. A Branch-and-Cut 15 | * Algorithm for a Vendor-Managed Inventory-Routing Problem. Transportation 16 | * Science, 41(3), 2007, pp. 382-391. 17 | */ 18 | //////////////////////////////////////////////////////////////////////////////// 19 | 20 | #include 21 | #include 22 | 23 | #include "../include/ext/loguru/loguru.hpp" 24 | 25 | #include "../include/irp_lp.hpp" 26 | #include "../include/init_grb_model.hpp" 27 | 28 | //////////////////////////////// Helper methods //////////////////////////////// 29 | 30 | namespace 31 | { 32 | 33 | 34 | void initModel(GRBModel& model, 35 | std::vector>& I, 36 | std::vector>>& q, 37 | std::vector>>>& x, 38 | std::vector>>& y, 39 | std::vector& constrs, 40 | CallbackSEC &CbSEC, 41 | const std::shared_ptr& pInst, 42 | const ConfigParameters::model& params) 43 | { 44 | RAW_LOG_F(INFO, "Building model..."); 45 | 46 | try 47 | { 48 | /* Initialize variables */ 49 | init::inventoryLevelVariables(model, I, pInst); 50 | init::quantityVariables(model, q, pInst); 51 | init::visitationVariables(model, y, pInst); 52 | init::routingVariables(model, x, pInst); 53 | 54 | /* Iniialize constraints */ 55 | init::inventoryDefDepotConstrs(model, constrs, I, q, pInst); 56 | init::inventoryDefCustomersConstrs(model, constrs, I, q, pInst); 57 | init::inventoryLevelConstrs(model, constrs, I, q, pInst); 58 | init::quantitiesRoutingConstraint(model, constrs, y, q, pInst); 59 | init::capacityVehicleConstraint(model, constrs, y, q, pInst); 60 | init::degreeConstrs(model, constrs, y, x, pInst); 61 | init::noSplitDelivery(model, y, pInst); 62 | 63 | /* define which policy should be use */ 64 | switch (params.policy) 65 | { 66 | case ConfigParameters::model::policy_opt::ML : 67 | { 68 | init::mlQuantityCapacityConstrs(model, constrs, I, q, pInst); 69 | break; 70 | } 71 | case ConfigParameters::model::policy_opt::OU : 72 | { 73 | init::mlQuantityCapacityConstrs(model, constrs, I, q, pInst); 74 | init::ouQuantityCapacityConstrs(model, constrs, I, y, q, pInst); 75 | break; 76 | } 77 | default: 78 | { 79 | RAW_LOG_F(FATAL, "IRP::initModel(): invalid policy option"); 80 | break; 81 | } 82 | } 83 | 84 | switch (params.sec_strategy) 85 | { 86 | case ConfigParameters::model::sec_opt::STD : 87 | { 88 | init::subtourEliminationConstrs(model, constrs, y, x, pInst); 89 | break; 90 | } 91 | case ConfigParameters::model::sec_opt::CVRPSEP : 92 | { 93 | RAW_LOG_F(INFO, "\tusing lazy and cut (CVRPSEP package)"); 94 | model.set(GRB_IntParam_LazyConstraints, 1); 95 | model.setCallback(&CbSEC); 96 | break; 97 | } 98 | } 99 | } 100 | catch (GRBException e) 101 | { 102 | RAW_LOG_F(FATAL, "IRP::initModel(): error code: %d", e.getErrorCode()); 103 | RAW_LOG_F(FATAL, "IRP::initModel(): C-Exp: %s", e.getMessage().c_str()); 104 | } 105 | catch (...) 106 | { 107 | RAW_LOG_F(FATAL, "IRP::initModel(): unknown Exception"); 108 | } 109 | } 110 | 111 | } // anonymous namespace 112 | 113 | //////////////////////////////////////////////////////////////////////////////// 114 | 115 | Irp_lp::Irp_lp(const std::shared_ptr& pInst, 116 | const ConfigParameters::model& params) : 117 | mpInst(pInst), 118 | mModel(mEnv), 119 | mCbSEC(m_q, m_x, m_y, pInst) 120 | { 121 | initModel(mModel, mI, m_q, m_x, m_y, mConstrs, mCbSEC, mpInst, params); 122 | } 123 | 124 | 125 | bool Irp_lp::solve(const ConfigParameters::solver& params) 126 | { 127 | RAW_LOG_F(INFO, "Solving IRP LP...\n%s", std::string(80, '-').c_str()); 128 | bool solved = true; 129 | 130 | try 131 | { 132 | // set solver parameters 133 | mModel.set(GRB_IntParam_OutputFlag, params.show_log); 134 | mModel.set(GRB_DoubleParam_TimeLimit, params.time_limit); 135 | mModel.set(GRB_IntParam_Threads, params.nb_threads); 136 | mModel.set(GRB_StringParam_LogFile, params.logFile_); 137 | 138 | mModel.optimize(); 139 | 140 | if (mModel.get(GRB_IntAttr_Status) == GRB_INFEASIBLE) 141 | { 142 | solved = false; 143 | } 144 | } 145 | catch (GRBException& e) 146 | { 147 | RAW_LOG_F(FATAL, "IRP::solve(): error code: %d", e.getErrorCode()); 148 | RAW_LOG_F(FATAL, "IRP::solve(): C-Exp: %s", e.getMessage().c_str()); 149 | } 150 | catch (...) 151 | { 152 | RAW_LOG_F(FATAL, "IRP::solve(): unknown Exception"); 153 | } 154 | 155 | return solved; 156 | } 157 | 158 | 159 | void Irp_lp::writeIis(std::string path) 160 | { 161 | DCHECK_F(std::filesystem::is_directory(path), "dir does not exists"); 162 | path += mpInst->getName() + "_irp.ilp"; 163 | 164 | try 165 | { 166 | mModel.computeIIS(); 167 | mModel.write(path); 168 | } 169 | catch (GRBException& e) 170 | { 171 | RAW_LOG_F(ERROR, "writeIis() exp: %s", e.getMessage().c_str()); 172 | } 173 | catch (...) 174 | { 175 | RAW_LOG_F(ERROR, "writeIis(): Unknown Exception"); 176 | } 177 | } 178 | 179 | 180 | void Irp_lp::writeModel(std::string path) 181 | { 182 | DCHECK_F(std::filesystem::is_directory(path), "dir does not exists"); 183 | path += mpInst->getName() + "_irp.lp"; 184 | 185 | try 186 | { 187 | mModel.write(path); 188 | } 189 | catch (GRBException& e) 190 | { 191 | RAW_LOG_F(ERROR, "writeModel() exp: %s", e.getMessage().c_str()); 192 | } 193 | catch (...) 194 | { 195 | RAW_LOG_F(ERROR, "writeModel(): Unknown Exception"); 196 | } 197 | } 198 | 199 | 200 | void Irp_lp::writeResultsJSON(std::string path) 201 | { 202 | DCHECK_F(std::filesystem::is_directory(path), "dir does not exists"); 203 | path += mpInst->getName() + ".json"; 204 | 205 | try 206 | { 207 | mModel.set(GRB_IntParam_JSONSolDetail, 1); 208 | mModel.write(path); 209 | } 210 | catch (GRBException& e) 211 | { 212 | RAW_LOG_F(ERROR, "writeSolution() exp: %s", e.getMessage().c_str()); 213 | } 214 | catch (...) 215 | { 216 | RAW_LOG_F(ERROR, "writeSolution(): Unknown Exception"); 217 | } 218 | } 219 | 220 | 221 | void Irp_lp::writeSolution(std::string path) 222 | { 223 | DCHECK_F(std::filesystem::is_directory(path), "dir does not exists"); 224 | path += mpInst->getName() + ".sol"; 225 | 226 | try 227 | { 228 | mModel.write(path); 229 | } 230 | catch (GRBException& e) 231 | { 232 | RAW_LOG_F(ERROR, "writeSolution() exp: %s", e.getMessage().c_str()); 233 | } 234 | catch (...) 235 | { 236 | RAW_LOG_F(ERROR, "writeSolution(): Unknown Exception"); 237 | } 238 | } -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /* 3 | * File: main.cpp 4 | * 5 | * @brief Classic Inventory-Routing Problem (IRP) linear program [1]. 6 | * @author Guilherme O. Chagas (guilherme.o.chagas[a]gmail.com) 7 | * @date This file was created on October 22, 2020, 05:52 PM 8 | * @warning I'm sorry for my bad English xD. 9 | * @acknowledgment Special thanks to Ph.D. Leandro C. Coelho and Ph.D. Cleder 10 | * Marcos Schenekemberg. 11 | * @copyright GNU General Public License. 12 | * 13 | * References: 14 | * [1] C. Archetti, L. Bertazzi, G. Laporte and M. G. Speranza. A Branch-and-Cut 15 | * Algorithm for a Vendor-Managed Inventory-Routing Problem. Transportation 16 | * Science, 41(3), 2007, pp. 382-391. 17 | */ 18 | //////////////////////////////////////////////////////////////////////////////// 19 | 20 | #include 21 | 22 | #include "../include/ext/loguru/loguru.hpp" 23 | 24 | #include "../include/config_parameters.hpp" 25 | #include "../include/instance.hpp" 26 | #include "../include/irp_lp.hpp" 27 | 28 | 29 | void buildNsolve(const std::shared_ptr& pInst, 30 | const ConfigParameters& params) 31 | { 32 | pInst->show(); 33 | 34 | Irp_lp irpSolver(pInst, params.getModelParams()); 35 | // irpSolver.writeModel(params.getOutputDir()); 36 | bool solved = irpSolver.solve(params.getSolverParams()); 37 | 38 | if (solved) 39 | { 40 | irpSolver.writeResultsJSON(params.getOutputDir()); 41 | irpSolver.writeSolution(params.getOutputDir()); 42 | } 43 | else 44 | { 45 | irpSolver.writeIis(params.getOutputDir()); 46 | } 47 | } 48 | 49 | 50 | int main(int argc, char **argv) 51 | { 52 | loguru::init(argc, argv); 53 | CHECK_F(argc == 3, "Invalid number of parameters! Please see usage..."); 54 | CHECK_F(std::string(argv[1]) == "-f", "Unknown flag! Please see usage..."); 55 | 56 | ConfigParameters params(argv[2]); 57 | std::filesystem::create_directories(params.getOutputDir()); 58 | 59 | /* Put every log message in "execution.log": */ 60 | { 61 | using namespace loguru; 62 | auto t = std::time(nullptr); 63 | auto tm = *std::localtime(&t); 64 | std::ostringstream oss; 65 | oss << params.getOutputDir() << "execution_" << 66 | std::put_time(&tm, "%d_%m_%Y_%H_%M_%S") << ".log"; 67 | loguru::add_file(oss.str().c_str(), Append, Verbosity_MAX); 68 | params.setLogFilePath(oss.str()); 69 | } 70 | 71 | params.show(); 72 | 73 | const std::string path = params.getInstancePath(); 74 | if (std::filesystem::is_directory(path)) 75 | { 76 | /* execute in batch */ 77 | for (const auto &f : std::filesystem::directory_iterator(path)) 78 | { 79 | RAW_LOG_F(INFO, "executing instance: %s", f.path().c_str()); 80 | auto pInst = std::make_shared(f.path(), 81 | params.getModelParams().K_); 82 | buildNsolve(pInst, params); 83 | RAW_LOG_F(INFO, std::string(80, '=').c_str()); 84 | } 85 | } 86 | else 87 | { 88 | /* single instance execution */ 89 | RAW_LOG_F(INFO, "executing instance: %s", path.c_str()); 90 | auto pInst = std::make_shared(path, 91 | params.getModelParams().K_); 92 | buildNsolve(pInst, params); 93 | } 94 | 95 | return EXIT_SUCCESS; 96 | } --------------------------------------------------------------------------------