remove support for sulum; bump scip_interface code to support 4.0; change the way we interact with scip at compile time
This commit is contained in:
@@ -2274,7 +2274,6 @@ LP_LIB_OBJS = \
|
||||
$(OBJ_DIR)/linear_solver/model_exporter.$O \
|
||||
$(OBJ_DIR)/linear_solver/model_validator.$O \
|
||||
$(OBJ_DIR)/linear_solver/scip_interface.$O \
|
||||
$(OBJ_DIR)/linear_solver/sulum_interface.$O \
|
||||
$(OBJ_DIR)/linear_solver/linear_solver.pb.$O
|
||||
|
||||
$(SRC_DIR)/linear_solver/glop_utils.h: \
|
||||
@@ -2460,17 +2459,6 @@ $(OBJ_DIR)/linear_solver/scip_interface.$O: \
|
||||
$(SRC_DIR)/base/timer.h
|
||||
$(CCC) $(CFLAGS) -c $(SRC_DIR)/linear_solver/scip_interface.cc $(OBJ_OUT)$(OBJ_DIR)$Slinear_solver$Sscip_interface.$O
|
||||
|
||||
$(OBJ_DIR)/linear_solver/sulum_interface.$O: \
|
||||
$(SRC_DIR)/linear_solver/sulum_interface.cc \
|
||||
$(SRC_DIR)/linear_solver/linear_solver.h \
|
||||
$(SRC_DIR)/base/commandlineflags.h \
|
||||
$(SRC_DIR)/base/hash.h \
|
||||
$(SRC_DIR)/base/integral_types.h \
|
||||
$(SRC_DIR)/base/logging.h \
|
||||
$(SRC_DIR)/base/stringprintf.h \
|
||||
$(SRC_DIR)/base/timer.h
|
||||
$(CCC) $(CFLAGS) -c $(SRC_DIR)/linear_solver/sulum_interface.cc $(OBJ_OUT)$(OBJ_DIR)$Slinear_solver$Ssulum_interface.$O
|
||||
|
||||
$(GEN_DIR)/linear_solver/linear_solver.pb.cc: $(SRC_DIR)/linear_solver/linear_solver.proto
|
||||
$(PROTOBUF_DIR)/bin/protoc --proto_path=$(INC_DIR) --cpp_out=$(GEN_DIR) $(SRC_DIR)/linear_solver/linear_solver.proto
|
||||
|
||||
|
||||
@@ -142,7 +142,6 @@ ifeq ("$(SYSTEM)","win")
|
||||
|
||||
# Third party specific
|
||||
CBC_PLATFORM = $(CBC_PLATFORM_PREFIX)-$(VS_RELEASE)-Release
|
||||
SCIP_MAKEFILE = \# SCIP not compiled
|
||||
|
||||
# Java specific
|
||||
ifeq ($(JAVA_HOME),)
|
||||
@@ -203,4 +202,3 @@ ifeq ("$(SYSTEM)","unix")
|
||||
else
|
||||
@echo CMAKE_PLATFORM = $(CMAKE_PLATFORM)
|
||||
endif
|
||||
|
||||
|
||||
@@ -12,40 +12,6 @@ AUTOCONF_TAG = 2.69
|
||||
AUTOMAKE_TAG = 1.15
|
||||
LIBTOOL_TAG = 2.4.6
|
||||
|
||||
# Build extra dependencies (GLPK, SCIP) from archive only if the
|
||||
# archive is present.
|
||||
#
|
||||
# The GLPK archive should be glpk-4.57.tar.gz
|
||||
GLPK_TAG = 4.57
|
||||
# The SCIP archive should be scipoptsuite-3.2.1.tgz
|
||||
SCIP_TAG = 3.2.1
|
||||
# Version of Sulum
|
||||
SULUM_TAG = 43
|
||||
|
||||
# Detect if SCIP archive is there.
|
||||
ifeq ($(wildcard dependencies/archives/scipoptsuite-$(SCIP_TAG).tgz),)
|
||||
SCIP_TARGET =
|
||||
SCIP_MAKEFILE = "\# Download and put scipoptsuite-$(SCIP_TAG).tgz in the dependencies/archives directory to add support for SCIP."
|
||||
else
|
||||
SCIP_TARGET = dependencies/install/scipoptsuite-$(SCIP_TAG)/scip-$(SCIP_TAG)/bin/scip
|
||||
SCIP_MAKEFILE = UNIX_SCIP_DIR = $(OR_ROOT_FULL)/dependencies/install/scipoptsuite-$(SCIP_TAG)/scip-$(SCIP_TAG)
|
||||
ifeq ($(PLATFORM), LINUX)
|
||||
BUILD_SCIP = make ZIMPL=false READLINE=false USRCXXFLAGS=-fPIC CFLAGS=-fPIC GMP=false
|
||||
endif
|
||||
ifeq ($(PLATFORM), MACOSX)
|
||||
BUILD_SCIP = make ZIMPL=false READLINE=false GMP=false
|
||||
endif
|
||||
endif
|
||||
|
||||
# Detect if GLPK archive is there.
|
||||
ifeq ($(wildcard dependencies/archives/glpk-$(GLPK_TAG).tar.gz),)
|
||||
GLPK_TARGET =
|
||||
GLPK_MAKEFILE = "\# Download and put glpk-$(GLPK_TAG).tar.gz under dependencies/archives to add support for GLPK."
|
||||
else
|
||||
GLPK_TARGET = dependencies/install/bin/glpsol
|
||||
GLPK_MAKEFILE = UNIX_GLPK_DIR = $(OR_ROOT_FULL)/dependencies/install
|
||||
endif
|
||||
|
||||
# Detect if patchelf is needed
|
||||
ifeq ($(PLATFORM), LINUX)
|
||||
PATCHELF=dependencies/install/bin/patchelf
|
||||
@@ -110,8 +76,6 @@ install_third_party: \
|
||||
install_protobuf \
|
||||
install_swig \
|
||||
install_cbc \
|
||||
install_glpk \
|
||||
install_scip \
|
||||
$(CSHARP_THIRD_PARTY)
|
||||
|
||||
bin:
|
||||
@@ -297,24 +261,6 @@ dependencies/sources/swig-$(SWIG_TAG)/configure: dependencies/sources/swig-$(SWI
|
||||
dependencies/sources/swig-$(SWIG_TAG)/autogen.sh:
|
||||
git clone -b rel-$(SWIG_TAG) https://github.com/swig/swig dependencies/sources/swig-$(SWIG_TAG)
|
||||
|
||||
# Install glpk if needed.
|
||||
install_glpk: $(GLPK_TARGET)
|
||||
|
||||
dependencies/install/bin/glpsol: dependencies/sources/glpk-$(GLPK_TAG)/Makefile
|
||||
cd dependencies/sources/glpk-$(GLPK_TAG) && make install
|
||||
|
||||
dependencies/sources/glpk-$(GLPK_TAG)/Makefile: dependencies/sources/glpk-$(GLPK_TAG)/configure $(ACLOCAL_TARGET)
|
||||
cd dependencies/sources/glpk-$(GLPK_TAG) && $(SET_PATH) ./configure --prefix=$(OR_ROOT_FULL)/dependencies/install --with-pic
|
||||
|
||||
dependencies/sources/glpk-$(GLPK_TAG)/configure: dependencies/archives/glpk-$(GLPK_TAG).tar.gz
|
||||
cd dependencies/sources && tar xvzmf ../archives/glpk-$(GLPK_TAG).tar.gz
|
||||
|
||||
# Install scip if needed.
|
||||
install_scip: $(SCIP_TARGET)
|
||||
|
||||
dependencies/install/scipoptsuite-$(SCIP_TAG)/scip-$(SCIP_TAG)/bin/scip: dependencies/archives/scipoptsuite-$(SCIP_TAG).tgz
|
||||
cd dependencies/install && tar xvzmf ../archives/scipoptsuite-$(SCIP_TAG).tgz && cd scipoptsuite-$(SCIP_TAG) && $(BUILD_SCIP)
|
||||
|
||||
# Install patchelf on linux platforms.
|
||||
dependencies/install/bin/patchelf: dependencies/sources/patchelf-0.8/Makefile
|
||||
cd dependencies/sources/patchelf-0.8 && make && make install
|
||||
@@ -428,16 +374,15 @@ Makefile.local: makefiles/Makefile.third_party.unix.mk
|
||||
@echo PATH_TO_CSHARP_COMPILER = $(DETECTED_MCS_BINARY)>> Makefile.local
|
||||
@echo CLR_KEYFILE = bin/or-tools.snk>> Makefile.local
|
||||
@echo >> Makefile.local
|
||||
@echo $(GLPK_MAKEFILE)>> Makefile.local
|
||||
@echo $(SCIP_MAKEFILE)>> Makefile.local
|
||||
@echo \# Define UNIX_SLM_DIR to use Sulum Optimization.>> Makefile.local
|
||||
@echo \# Define UNIX_GUROBI_DIR and GUROBI_LIB_VERSION to use Gurobi.>> Makefile.local
|
||||
@echo \# Define UNIX_CPLEX_DIR to use CPLEX.>> Makefile.local
|
||||
@echo "# Define UNIX_GLPK_DIR to point to a compiled version of GLPK to use it" >> Makefile.local
|
||||
@echo "# Define UNIX_SCIP_DIR to point to a compiled version of SCIP to use it ">> Makefile.local
|
||||
@echo "# i.e.: <path>/scipoptsuite-4.0.0/scip-4.0.0" >> Makefile.local
|
||||
@echo "# compile scip with GMP=false READLINE=false" >> Makefile.local
|
||||
@echo "# Define UNIX_GUROBI_DIR and GUROBI_LIB_VERSION to use Gurobi" >> Makefile.local
|
||||
@echo "# Define UNIX_CPLEX_DIR to use CPLEX" >> Makefile.local
|
||||
@echo >> Makefile.local
|
||||
@echo UNIX_GFLAGS_DIR = $(OR_ROOT_FULL)/dependencies/install>> Makefile.local
|
||||
@echo UNIX_PROTOBUF_DIR = $(OR_ROOT_FULL)/dependencies/install>> Makefile.local
|
||||
@echo UNIX_SWIG_BINARY = $(OR_ROOT_FULL)/dependencies/install/bin/swig>> Makefile.local
|
||||
@echo UNIX_CLP_DIR = $(OR_ROOT_FULL)/dependencies/install>> Makefile.local
|
||||
@echo UNIX_CBC_DIR = $(OR_ROOT_FULL)/dependencies/install>> Makefile.local
|
||||
@echo UNIX_SCIP_TAG = $(SCIP_TAG)>> Makefile.local
|
||||
@echo UNIX_SULUM_VERSION = $(SULUM_TAG) >> Makefile.local
|
||||
|
||||
@@ -6,35 +6,9 @@ ZLIB_TAG = 1.2.11
|
||||
ZLIB_ARCHIVE_TAG = 1211
|
||||
SWIG_TAG = 3.0.12
|
||||
|
||||
# Build extra dependencies (GLPK, SCIP) from archive only if the archive is present.
|
||||
# The archive should be glpk-4.57.tar.gz
|
||||
GLPK_TAG = 4.57
|
||||
# The archive should be scipoptsuite-3.2.0.tgz
|
||||
SCIP_TAG = 3.2.0
|
||||
SOPLEX_TAG = 2.2.0
|
||||
# Version of Sulum
|
||||
SULUM_TAG = 43
|
||||
|
||||
# Added in support of clean third party targets
|
||||
TSVNCACHE_EXE = TSVNCache.exe
|
||||
|
||||
# Detect if scip archive is there.
|
||||
ifeq ($(wildcard dependencies/archives/scipoptsuite-$(SCIP_TAG).tgz),)
|
||||
SCIP_TARGET =
|
||||
SCIP_MAKEFILE = \# WINDOWS_SCIP_DIR support not included.
|
||||
else
|
||||
SCIP_TARGET = dependencies/install/lib/scip.lib
|
||||
SCIP_MAKEFILE = WINDOWS_SCIP_DIR = $(OR_ROOT_FULL)\\dependencies\\install
|
||||
endif
|
||||
|
||||
# Detect if GLPK archive is there.
|
||||
ifeq ($(wildcard dependencies/archives/glpk-$(GLPK_TAG).tar.gz),)
|
||||
GLPK_TARGET =
|
||||
GLPK_MAKEFILE = \# GLPK support not included.
|
||||
else
|
||||
GLPK_TARGET = dependencies\install\bin\glpsol.exe
|
||||
GLPK_MAKEFILE = WINDOWS_GLPK_DIR = $(OR_ROOT_FULL)\\dependencies\\install
|
||||
endif
|
||||
# Main target.
|
||||
.PHONY: third_party build_third_party makefile_third_party
|
||||
third_party: build_third_party makefile_third_party
|
||||
@@ -85,9 +59,7 @@ build_third_party: \
|
||||
install_gflags \
|
||||
install_protobuf \
|
||||
install_swig \
|
||||
install_coin_cbc \
|
||||
install_glpk \
|
||||
install_scip
|
||||
install_coin_cbc
|
||||
|
||||
bin:
|
||||
$(MKDIR_P) bin
|
||||
@@ -333,49 +305,6 @@ dependencies\install\swigwin-$(SWIG_TAG)\swig.exe: dependencies\archives\swigwin
|
||||
dependencies\archives\swigwin-$(SWIG_TAG).zip:
|
||||
tools\wget -P dependencies\archives --no-check-certificate http://prdownloads.sourceforge.net/swig/swigwin-$(SWIG_TAG).zip || (@echo wget failed to dowload http://prdownloads.sourceforge.net/swig/swigwin-$(SWIG_TAG).zip, try running 'tools\wget -P dependencies\archives --no-check-certificate http://prdownloads.sourceforge.net/swig/swigwin-$(SWIG_TAG).zip' then rerun 'make third_party' && exit 1)
|
||||
|
||||
# Install glpk if needed.
|
||||
install_glpk: $(GLPK_TARGET)
|
||||
|
||||
dependencies\install\bin\glpsol.exe: dependencies\sources\glpk-$(GLPK_TAG)\$(GLPK_PLATFORM)\glpsol.exe
|
||||
copy dependencies\sources\glpk-$(GLPK_TAG)\$(GLPK_PLATFORM)\glpk.lib dependencies\install\lib
|
||||
copy dependencies\sources\glpk-$(GLPK_TAG)\src\glpk.h dependencies\install\include
|
||||
copy dependencies\sources\glpk-$(GLPK_TAG)\$(GLPK_PLATFORM)\glpsol.exe dependencies\install\bin
|
||||
|
||||
dependencies\sources\glpk-$(GLPK_TAG)\$(GLPK_PLATFORM)\glpsol.exe: dependencies\sources\glpk-$(GLPK_TAG)\configure
|
||||
copy dependencies\sources\glpk-$(GLPK_TAG)\$(GLPK_PLATFORM)\config_VC dependencies\sources\glpk-$(GLPK_TAG)\$(GLPK_PLATFORM)\config.h
|
||||
cd dependencies\sources\glpk-$(GLPK_TAG)\$(GLPK_PLATFORM) && nmake -f makefile_VC
|
||||
|
||||
dependencies\sources\glpk-$(GLPK_TAG)\configure: dependencies\archives\glpk-$(GLPK_TAG).tar.gz
|
||||
cd dependencies\sources && ..\..\tools\gzip -dc ..\archives\glpk-$(GLPK_TAG).tar.gz | ..\..\tools\tar.exe xvmf -
|
||||
$(SED) -i -e 's/nologo/nologo \/MD/g' dependencies\sources\glpk-$(GLPK_TAG)\$(GLPK_PLATFORM)/Makefile_VC
|
||||
|
||||
# Install scip if needed.
|
||||
install_scip: $(SCIP_TARGET)
|
||||
|
||||
dependencies/install/lib/scip.lib: dependencies/archives/scipoptsuite-$(SCIP_TAG).tgz
|
||||
# cd dependencies\install && ..\..\tools\gzip -dc ..\archives\scipoptsuite-$(SCIP_TAG).tgz | ..\..\tools\tar.exe xvmf -
|
||||
cd dependencies\install && ..\..\tools\tar.exe xvmf ..\archives\scipoptsuite-$(SCIP_TAG).tgz
|
||||
cd dependencies\install\scipoptsuite-$(SCIP_TAG) && ..\..\..\tools\gzip -dc soplex-$(SOPLEX_TAG).tgz | ..\..\..\tools\tar.exe xvmf -
|
||||
# cd dependencies\install\scipoptsuite-$(SCIP_TAG) && ..\..\..\tools\gzip -dc scip-$(SCIP_TAG).tgz | ..\..\..\tools\tar.exe xvmf -
|
||||
cd dependencies\install\scipoptsuite-$(SCIP_TAG) && ..\..\..\tools\gzip -d scip-$(SCIP_TAG).tgz
|
||||
- cd dependencies\install\scipoptsuite-$(SCIP_TAG) && ..\..\..\tools\tar.exe xvmf scip-$(SCIP_TAG).tar
|
||||
tools\upgrade_vs_project.cmd dependencies\\solutions\\Scip\\soplex\\soplex.vcxproj $(VS_RELEASE)
|
||||
tools\upgrade_vs_project.cmd dependencies\\solutions\\Scip\\scip\\scip.vcxproj $(VS_RELEASE)
|
||||
cd dependencies\solutions\Scip && msbuild /t:soplex
|
||||
cd dependencies\solutions\Scip && msbuild /t:scip
|
||||
-mkdir dependencies\install\include
|
||||
-mkdir dependencies\install\include\scip
|
||||
-mkdir dependencies\install\include\scip\scip
|
||||
-mkdir dependencies\install\include\scip\blockmemshell
|
||||
-mkdir dependencies\install\include\scip\lpi
|
||||
-mkdir dependencies\install\include\scip\nlpi
|
||||
copy dependencies\install\scipoptsuite-$(SCIP_TAG)\scip-$(SCIP_TAG)\src\scip\*.h dependencies\install\include\scip\scip
|
||||
copy dependencies\install\scipoptsuite-$(SCIP_TAG)\scip-$(SCIP_TAG)\src\lpi\*.h dependencies\install\include\scip\lpi
|
||||
copy dependencies\install\scipoptsuite-$(SCIP_TAG)\scip-$(SCIP_TAG)\src\nlpi\*.h dependencies\install\include\scip\nlpi
|
||||
copy dependencies\install\scipoptsuite-$(SCIP_TAG)\scip-$(SCIP_TAG)\src\blockmemshell\*.h dependencies\install\include\scip\blockmemshell
|
||||
git checkout dependencies/solutions/Scip/soplex/soplex.vcxproj
|
||||
git checkout dependencies/solutions/Scip/scip/scip.vcxproj
|
||||
|
||||
# Install Java protobuf
|
||||
|
||||
install_java_protobuf: dependencies/install/lib/protobuf.jar
|
||||
@@ -422,12 +351,10 @@ Makefile.local: makefiles/Makefile.third_party.$(SYSTEM).mk
|
||||
@echo $(SELECTED_JDK_DEF)>> Makefile.local
|
||||
@echo $(SELECTED_PATH_TO_PYTHON)>> Makefile.local
|
||||
@echo $(SELECTED_CSC_BINARY)>> Makefile.local
|
||||
@echo #>> Makefile.local
|
||||
@echo $(GLPK_MAKEFILE)>> Makefile.local
|
||||
@echo $(SCIP_MAKEFILE)>> Makefile.local
|
||||
@echo # >> Makefile.local
|
||||
@echo # Define WINDOWS_SCIP_DIR to point to a compiled version of SCIP to use it >> Makefile.local
|
||||
@echo # i.e.: <path>\\scipoptsuite-4.0.0\\scip-4.0.0
|
||||
@echo CLR_KEYFILE = bin\\or-tools.snk>> Makefile.local
|
||||
@echo WINDOWS_SULUM_VERSION = $(SULUM_TAG)>> Makefile.local
|
||||
@echo # Define WINDOWS_SLM_DIR to use Sulum Optimization.>> Makefile.local
|
||||
@echo # Define WINDOWS_GUROBI_DIR and GUROBI_LIB_VERSION to use Gurobi.>> Makefile.local
|
||||
@echo #>> Makefile.local
|
||||
@echo WINDOWS_ZLIB_DIR = $(OR_ROOT_FULL)\\dependencies\\install>> Makefile.local
|
||||
|
||||
@@ -89,11 +89,6 @@ ifdef UNIX_SCIP_DIR
|
||||
SCIP_INC = -I$(UNIX_SCIP_DIR)/src -DUSE_SCIP
|
||||
SCIP_SWIG = $(SCIP_INC)
|
||||
endif
|
||||
# This is needed to find SULUM include files.
|
||||
ifdef UNIX_SLM_DIR
|
||||
SLM_INC = -I$(UNIX_SLM_DIR)/header -DUSE_SLM
|
||||
SLM_SWIG = $(SLM_INC)
|
||||
endif
|
||||
ifdef UNIX_GUROBI_DIR
|
||||
GUROBI_INC = -I$(UNIX_GUROBI_DIR)/$(GUROBI_PLATFORM)/include -DUSE_GUROBI
|
||||
GUROBI_SWIG = $(GUROBI_INC)
|
||||
@@ -103,7 +98,7 @@ ifdef UNIX_CPLEX_DIR
|
||||
CPLEX_SWIG = $(CPLEX_INC)
|
||||
endif
|
||||
|
||||
SWIG_INC = $(GLPK_SWIG) $(CLP_SWIG) $(CBC_SWIG) $(SCIP_SWIG) $(SLM_SWIG) $(GUROBI_SWIG) $(CPLEX_SWIG) -DUSE_GLOP -DUSE_BOP
|
||||
SWIG_INC = $(GLPK_SWIG) $(CLP_SWIG) $(CBC_SWIG) $(SCIP_SWIG) $(GUROBI_SWIG) $(CPLEX_SWIG) -DUSE_GLOP -DUSE_BOP
|
||||
|
||||
# Compilation flags
|
||||
DEBUG = -O4 -DNDEBUG
|
||||
@@ -154,14 +149,7 @@ ifeq ($(PLATFORM),LINUX)
|
||||
else
|
||||
SCIP_ARCH = linux.x86.gnu.opt
|
||||
endif
|
||||
SCIP_LNK = $(UNIX_SCIP_DIR)/lib/libscip.$(SCIP_ARCH).a $(UNIX_SCIP_DIR)/lib/libnlpi.cppad.$(SCIP_ARCH).a $(UNIX_SCIP_DIR)/lib/liblpispx.$(SCIP_ARCH).a $(UNIX_SCIP_DIR)/lib/libsoplex.$(SCIP_ARCH).a
|
||||
endif
|
||||
ifdef UNIX_SLM_DIR
|
||||
ifeq ($(PTRLENGTH),64)
|
||||
SLM_LNK = -Wl,-rpath $(UNIX_SLM_DIR)/linux64/bin/ -L$(UNIX_SLM_DIR)/linux64/bin/ -m64 -lc -ldl -lm -lpthread -lsulum$(UNIX_SULUM_VERSION)
|
||||
else
|
||||
SLM_LNK = -Wl,-rpath $(UNIX_SLM_DIR)/linux32/bin/ -L$(UNIX_SLM_DIR)/linux32/bin/ -m32 -lc -ldl -lm -lpthread -lsulum$(UNIX_SULUM_VERSION)
|
||||
endif
|
||||
SCIP_LNK = $(UNIX_SCIP_DIR)/lib/static/libscip.$(SCIP_ARCH).a $(UNIX_SCIP_DIR)/lib/static/libnlpi.cppad.$(SCIP_ARCH).a $(UNIX_SCIP_DIR)/lib/static/liblpispx.$(SCIP_ARCH).a $(UNIX_SCIP_DIR)/lib/static/libsoplex.$(SCIP_ARCH).a
|
||||
endif
|
||||
ifdef UNIX_GUROBI_DIR
|
||||
ifeq ($(PTRLENGTH),64)
|
||||
@@ -235,7 +223,7 @@ ifeq ($(PLATFORM),MACOSX)
|
||||
endif
|
||||
ifdef UNIX_SCIP_DIR
|
||||
SCIP_ARCH = darwin.x86_64.gnu.opt
|
||||
SCIP_LNK = -force_load $(UNIX_SCIP_DIR)/lib/libscip.$(SCIP_ARCH).a $(UNIX_SCIP_DIR)/lib/libnlpi.cppad.$(SCIP_ARCH).a -force_load $(UNIX_SCIP_DIR)/lib/liblpispx.$(SCIP_ARCH).a -force_load $(UNIX_SCIP_DIR)/lib/libsoplex.$(SCIP_ARCH).a
|
||||
SCIP_LNK = -force_load $(UNIX_SCIP_DIR)/lib/static/libscip.$(SCIP_ARCH).a $(UNIX_SCIP_DIR)/lib/static/libnlpi.cppad.$(SCIP_ARCH).a -force_load $(UNIX_SCIP_DIR)/lib/static/liblpispx2.$(SCIP_ARCH).a -force_load $(UNIX_SCIP_DIR)/lib/static/libsoplex.$(SCIP_ARCH).a
|
||||
endif
|
||||
ifdef UNIX_GUROBI_DIR
|
||||
GUROBI_LNK = -L$(UNIX_GUROBI_DIR)/mac64/bin/ -m64 -lc -ldl -lm -lpthread -lgurobi$(GUROBI_LIB_VERSION)
|
||||
@@ -243,16 +231,13 @@ ifeq ($(PLATFORM),MACOSX)
|
||||
ifdef UNIX_CPLEX_DIR
|
||||
CPLEX_LNK = -force_load $(UNIX_CPLEX_DIR)/cplex/lib/x86-64_osx/static_pic/libcplex.a -lm -lpthread -framework CoreFoundation -framework IOKit
|
||||
endif
|
||||
ifdef UNIX_SLM_DIR
|
||||
SLM_LNK = -rpath $(UNIX_SLM_DIR)/mac64/bin/ -L$(UNIX_SLM_DIR)/mac64/bin/ -lc -ldl -lm -lpthread -lsulum$(UNIX_SULUM_VERSION)
|
||||
endif
|
||||
endif # MAC OS X
|
||||
|
||||
CFLAGS = $(DEBUG) -I$(INC_DIR) -I$(EX_DIR) -I$(GEN_DIR) $(GFLAGS_INC) $(ARCH) \
|
||||
-Wno-deprecated $(PROTOBUF_INC) $(CBC_INC) $(CLP_INC) $(GLPK_INC) \
|
||||
$(SCIP_INC) $(SLM_INC) $(GUROBI_INC) $(CPLEX_INC) -DUSE_GLOP -DUSE_BOP $(SPARSEHASH_INC)
|
||||
$(SCIP_INC) $(GUROBI_INC) $(CPLEX_INC) -DUSE_GLOP -DUSE_BOP $(SPARSEHASH_INC)
|
||||
|
||||
JNIFLAGS = $(JNIDEBUG) -I$(INC_DIR) -I$(EX_DIR) -I$(GEN_DIR) $(GFLAGS_INC) $(ARCH) \
|
||||
-Wno-deprecated $(PROTOBUF_INC) $(CBC_INC) $(CLP_INC) $(GLPK_INC) $(SCIP_INC) $(SLM_INC) $(GUROBI_INC) $(CPLEX_INC) -DUSE_GLOP -DUSE_BOP
|
||||
-Wno-deprecated $(PROTOBUF_INC) $(CBC_INC) $(CLP_INC) $(GLPK_INC) $(SCIP_INC) $(GUROBI_INC) $(CPLEX_INC) -DUSE_GLOP -DUSE_BOP
|
||||
DEPENDENCIES_LNK = $(GLPK_LNK) $(CBC_LNK) $(CLP_LNK) $(SCIP_LNK) $(LM_LNK) $(GUROBI_LNK) $(CPLEX_LNK) $(GFLAGS_LNK) $(PROTOBUF_LNK)
|
||||
OR_TOOLS_LD_FLAGS = $(ZLIB_LNK) $(SYS_LNK)
|
||||
|
||||
@@ -106,13 +106,6 @@ ifdef WINDOWS_SCIP_DIR
|
||||
STATIC_SCIP_LNK = $(SCIP_LNK_DIR)\\lib\\scip.lib $(SCIP_LNK_DIR)\\lib\\soplex.lib
|
||||
DYNAMIC_SCIP_LNK = $(SCIP_LNK_DIR)\\lib\\scip.lib $(SCIP_LNK_DIR)\\lib\\soplex.lib
|
||||
endif
|
||||
# This is needed to find SULUM include files and libraries.
|
||||
ifdef WINDOWS_SLM_DIR
|
||||
SLM_INC = /I$(WINDOWS_SLM_DIR)\\header /DUSE_SLM
|
||||
SLM_SWIG = -DUSE_SLM
|
||||
DYNAMIC_SLM_LNK = $(WINDOWS_SLM_DIR)\\win$(PTRLENGTH)\\bin\\sulum$(WINDOWS_SULUM_VERSION).lib
|
||||
STATIC_SLM_LNK = $(WINDOWS_SLM_DIR)\\win$(PTRLENGTH)\\bin\\sulum$(WINDOWS_SULUM_VERSION).lib
|
||||
endif
|
||||
ifdef WINDOWS_GUROBI_DIR
|
||||
ifeq ($(PTRLENGTH),64)
|
||||
GUROBI_INC = /I$(WINDOWS_GUROBI_DIR)\win64\include /DUSE_GUROBI
|
||||
@@ -127,7 +120,7 @@ ifdef WINDOWS_GUROBI_DIR
|
||||
endif
|
||||
endif
|
||||
|
||||
SWIG_INC = $(GLPK_SWIG) $(CLP_SWIG) $(CBC_SWIG) $(SCIP_SWIG) $(SLM_SWIG) $(GUROBI_SWIG) -DUSE_GLOP -DUSE_BOP
|
||||
SWIG_INC = $(GLPK_SWIG) $(CLP_SWIG) $(CBC_SWIG) $(SCIP_SWIG) $(GUROBI_SWIG) -DUSE_GLOP -DUSE_BOP
|
||||
|
||||
JAVA_INC=/I"$(JDK_DIRECTORY)\\include" /I"$(JDK_DIRECTORY)\\include\\win32"
|
||||
JAVAC_BIN="$(JDK_DIRECTORY)/bin/javac"
|
||||
@@ -136,7 +129,7 @@ JAR_BIN="$(JDK_DIRECTORY)/bin/jar"
|
||||
|
||||
CFLAGS= -nologo $(SYSCFLAGS) $(DEBUG) /I$(INC_DIR) /I$(EX_DIR) /I$(GEN_DIR) \
|
||||
$(GFLAGS_INC) $(ZLIB_INC) $(MINISAT_INC) $(PROTOBUF_INC) $(CBC_INC) \
|
||||
$(CLP_INC) $(GLPK_INC) $(SCIP_INC) $(SLM_INC) $(GUROBI_INC) /DUSE_GLOP /DUSE_BOP \
|
||||
$(CLP_INC) $(GLPK_INC) $(SCIP_INC) $(GUROBI_INC) /DUSE_GLOP /DUSE_BOP \
|
||||
/D__WIN32__ $(SPARSEHASH_INC) /DPSAPI_VERSION=1 $(ARCH)
|
||||
JNIFLAGS=$(CFLAGS) $(JAVA_INC)
|
||||
DYNAMIC_GFLAGS_LNK = $(WINDOWS_GFLAGS_DIR)\\lib\\gflags_static.lib
|
||||
@@ -145,7 +138,7 @@ ZLIB_LNK = $(WINDOWS_ZLIB_DIR)\\lib\\$(WINDOWS_ZLIB_NAME)
|
||||
DYNAMIC_PROTOBUF_LNK = $(PROTOBUF_DIR)\\lib\\libprotobuf.lib
|
||||
STATIC_PROTOBUF_LNK = $(PROTOBUF_DIR)\\lib\\libprotobuf.lib
|
||||
SYS_LNK=psapi.lib ws2_32.lib shlwapi.lib
|
||||
DEPENDENCIES_LNK = $(STATIC_CBC_LNK) $(STATIC_CLP_LNK) $(STATIC_GLPK_LNK) $(STATIC_SCIP_LNK) $(STATIC_SLM_LNK) $(STATIC_GUROBI_LNK) $(STATIC_GFLAGS_LNK) $(STATIC_PROTOBUF_LNK)
|
||||
DEPENDENCIES_LNK = $(STATIC_CBC_LNK) $(STATIC_CLP_LNK) $(STATIC_GLPK_LNK) $(STATIC_SCIP_LNK) $(STATIC_GUROBI_LNK) $(STATIC_GFLAGS_LNK) $(STATIC_PROTOBUF_LNK)
|
||||
OR_TOOLS_LD_FLAGS = $(ZLIB_LNK) $(SYS_LNK)
|
||||
|
||||
COMMA := ,
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
%{
|
||||
#include "linear_solver/linear_solver.h"
|
||||
#include "linear_solver/linear_solver.pb.h"
|
||||
#include "linear_solver/linear_solver_ext.h"
|
||||
%}
|
||||
|
||||
// We need to forward-declare the proto here, so that the PROTO_* macros
|
||||
@@ -217,6 +216,5 @@ class MPSolutionResponse;
|
||||
%warnfilter(401) CoeffMap;
|
||||
|
||||
%include "linear_solver/linear_solver.h"
|
||||
%include "linear_solver/linear_solver_ext.h"
|
||||
|
||||
%unignoreall
|
||||
|
||||
@@ -45,7 +45,6 @@ class MPSolutionResponse;
|
||||
|
||||
%{
|
||||
#include "linear_solver/linear_solver.h"
|
||||
#include "linear_solver/linear_solver_ext.h"
|
||||
%}
|
||||
|
||||
%typemap(javaimports) SWIGTYPE %{
|
||||
|
||||
@@ -392,12 +392,6 @@ MPSolverInterface* BuildSolverInterface(MPSolver* const solver) {
|
||||
case MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING:
|
||||
return BuildSCIPInterface(solver);
|
||||
#endif
|
||||
#if defined(USE_SLM)
|
||||
case MPSolver::SULUM_LINEAR_PROGRAMMING:
|
||||
return BuildSLMInterface(solver, false);
|
||||
case MPSolver::SULUM_MIXED_INTEGER_PROGRAMMING:
|
||||
return BuildSLMInterface(solver, true);
|
||||
#endif
|
||||
#if defined(USE_GUROBI)
|
||||
case MPSolver::GUROBI_LINEAR_PROGRAMMING:
|
||||
return BuildGurobiInterface(false, solver);
|
||||
@@ -463,10 +457,6 @@ bool MPSolver::SupportsProblemType(OptimizationProblemType problem_type) {
|
||||
#ifdef USE_GLOP
|
||||
if (problem_type == GLOP_LINEAR_PROGRAMMING) return true;
|
||||
#endif
|
||||
#if defined(USE_SLM)
|
||||
if (problem_type == SULUM_LINEAR_PROGRAMMING) return true;
|
||||
if (problem_type == SULUM_MIXED_INTEGER_PROGRAMMING) return true;
|
||||
#endif
|
||||
#ifdef USE_GUROBI
|
||||
if (problem_type == GUROBI_LINEAR_PROGRAMMING) return true;
|
||||
if (problem_type == GUROBI_MIXED_INTEGER_PROGRAMMING) return true;
|
||||
@@ -1619,4 +1609,3 @@ int MPSolverParameters::GetIntegerParam(MPSolverParameters::IntegerParam param)
|
||||
|
||||
|
||||
} // namespace operations_research
|
||||
|
||||
|
||||
@@ -181,9 +181,6 @@ class MPSolver {
|
||||
#ifdef USE_GLOP
|
||||
GLOP_LINEAR_PROGRAMMING = 2,
|
||||
#endif
|
||||
#if defined(USE_SLM)
|
||||
SULUM_LINEAR_PROGRAMMING = 8,
|
||||
#endif
|
||||
#ifdef USE_GUROBI
|
||||
GUROBI_LINEAR_PROGRAMMING = 6,
|
||||
#endif
|
||||
@@ -201,9 +198,6 @@ class MPSolver {
|
||||
#ifdef USE_CBC
|
||||
CBC_MIXED_INTEGER_PROGRAMMING = 5,
|
||||
#endif
|
||||
#if defined(USE_SLM)
|
||||
SULUM_MIXED_INTEGER_PROGRAMMING = 9,
|
||||
#endif
|
||||
#if defined(USE_GUROBI)
|
||||
GUROBI_MIXED_INTEGER_PROGRAMMING = 7,
|
||||
#endif
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
// Copyright 2010-2014 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_EXT_H_
|
||||
#define OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_EXT_H_
|
||||
|
||||
#include "base/hash.h"
|
||||
#include "base/hash.h"
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/integral_types.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/strutil.h"
|
||||
#include "base/sparsetable.h"
|
||||
#include "base/hash.h"
|
||||
#include "linear_solver/linear_solver.h"
|
||||
|
||||
#if defined(USE_SLM)
|
||||
|
||||
extern "C" {
|
||||
#include "sulumc.h"
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace operations_research {
|
||||
// Special API
|
||||
#if defined(USE_SLM)
|
||||
|
||||
// Helper functions specific to using Google OR Tools with Sulum Optimizer
|
||||
// The advantage is these functions does directly to the outer API
|
||||
|
||||
// Set a integer parameter in sulum as underlying solver
|
||||
// Return : 'true' if set 'false' if out of range
|
||||
bool SulumSetIntParam(MPSolver &solver,
|
||||
int iprm,
|
||||
int ival)
|
||||
{
|
||||
return ( SlmRetOk == SlmSetIntParam(solver.underlying_solver(), static_cast<SlmParamInt>(iprm), ival ) );
|
||||
}
|
||||
|
||||
// Get a integer parameter from sulum as underlying solver
|
||||
// Return : 'true' if get 'false' if out of range
|
||||
bool SulumGetIntParam(MPSolver &solver,
|
||||
int iprm,
|
||||
int &ival)
|
||||
{
|
||||
return ( SlmRetOk == SlmGetIntParam(solver.underlying_solver(), static_cast<SlmParamInt>(iprm), &ival ) );
|
||||
}
|
||||
|
||||
// Set a double parameter in sulum as underlying solver
|
||||
// Return : 'true' if set 'false' if out of range
|
||||
bool SulumSetDbParam(MPSolver &solver,
|
||||
int dprm,
|
||||
double dval)
|
||||
{
|
||||
return ( SlmRetOk == SlmSetDbParam(solver.underlying_solver(), static_cast<SlmParamDb>(dprm), dval ) );
|
||||
}
|
||||
|
||||
// Get a double parameter from sulum as underlying solver
|
||||
// Return : 'true' if get 'false' if out of range
|
||||
bool SulumGetDbParam(MPSolver &solver,
|
||||
int dprm,
|
||||
double &dval)
|
||||
{
|
||||
return ( SlmRetOk == SlmGetDbParam(solver.underlying_solver(), static_cast<SlmParamDb>(dprm), &dval ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
} // namespace operations_research
|
||||
|
||||
#endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_EXT_H_
|
||||
@@ -525,7 +525,7 @@ MPSolver::ResultStatus SCIPInterface::Solve(const MPSolverParameters& param) {
|
||||
|
||||
SCIP_Bool is_feasible;
|
||||
ORTOOLS_SCIP_CALL(SCIPcheckSol(
|
||||
scip_, solution, /*printreason=*/FALSE, /*checkbounds=*/TRUE,
|
||||
scip_, solution, /*printreason=*/FALSE, /*completely=*/FALSE, /*checkbounds=*/TRUE,
|
||||
/*checkintegrality=*/TRUE, /*checklprows=*/TRUE, &is_feasible));
|
||||
VLOG(1) << "Solution hint is " << (is_feasible ? "FEASIBLE" : "INFEASIBLE");
|
||||
|
||||
@@ -536,7 +536,7 @@ MPSolver::ResultStatus SCIPInterface::Solve(const MPSolverParameters& param) {
|
||||
SCIP_Bool is_stored;
|
||||
if (SCIPisTransformed(scip_)) {
|
||||
ORTOOLS_SCIP_CALL(SCIPtrySolFree(
|
||||
scip_, &solution, /*printreason=*/FALSE, /*checkbounds=*/TRUE,
|
||||
scip_, &solution, /*printreason=*/FALSE, /*completely=*/FALSE, /*checkbounds=*/TRUE,
|
||||
/*checkintegrality=*/TRUE, /*checklprows=*/TRUE, &is_stored));
|
||||
} else {
|
||||
ORTOOLS_SCIP_CALL(SCIPaddSolFree(scip_, &solution, &is_stored));
|
||||
|
||||
@@ -1,999 +0,0 @@
|
||||
// Copyright 2010-2014 Google
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
#include "base/hash.h"
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <float.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/integral_types.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/stringprintf.h"
|
||||
#include "base/timer.h"
|
||||
#include "base/hash.h"
|
||||
#include "linear_solver/linear_solver.h"
|
||||
|
||||
#if defined(USE_SLM)
|
||||
|
||||
extern "C" {
|
||||
#include "sulumc.h"
|
||||
}
|
||||
|
||||
void ExLogCallbackFunction(enum SlmStream str, const char *strprint, void *handle )
|
||||
{
|
||||
/* Print with printf */
|
||||
std::cout <<strprint;
|
||||
}
|
||||
|
||||
#define CheckReturnKey(__ret__)\
|
||||
{\
|
||||
if( (__ret__) != SlmRetOk ) {\
|
||||
VLOG(0) <<"Writing problem to : sulum_error.mps";\
|
||||
int wret = SlmWriteProblem(model_,"sulum_error.mps");\
|
||||
if( (wret) != SlmRetOk )\
|
||||
{\
|
||||
VLOG(0) <<"Error writing problem to : sulum_error.mps : "<<(wret);\
|
||||
}\
|
||||
VLOG(0) <<"Writing solution to : sulum_error.sol";\
|
||||
wret = SlmWriteSolution(model_,"sulum_error.sol");\
|
||||
if( (wret) != SlmRetOk )\
|
||||
{\
|
||||
VLOG(0) <<"Error writing solution to : sulum_error.sol : "<<(wret);\
|
||||
}\
|
||||
LOG(FATAL) <<"Error Sulum API call failed : at line "<<__LINE__<<" ret : "<<(__ret__);\
|
||||
}\
|
||||
}
|
||||
|
||||
DECLARE_double(solver_timeout_in_seconds);
|
||||
DECLARE_string(solver_write_model);
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
// ----- SLM Solver -----
|
||||
|
||||
class SLMInterface : public MPSolverInterface {
|
||||
public:
|
||||
// Constructor that takes a name for the underlying slm solver.
|
||||
SLMInterface(MPSolver* const solver, bool mip);
|
||||
~SLMInterface();
|
||||
|
||||
// Sets the optimization direction (min/max).
|
||||
virtual void SetOptimizationDirection(bool maximize);
|
||||
|
||||
// ----- Solve -----
|
||||
// Solve the problem using the parameter values specified.
|
||||
virtual MPSolver::ResultStatus Solve(const MPSolverParameters& param);
|
||||
|
||||
// ----- Model modifications and extraction -----
|
||||
// Resets extracted model
|
||||
virtual void Reset();
|
||||
|
||||
// Modify bounds.
|
||||
virtual void SetVariableBounds(int var_index, double lb, double ub);
|
||||
virtual void SetVariableInteger(int var_index, bool integer);
|
||||
virtual void SetConstraintBounds(int row_index, double lb, double ub);
|
||||
|
||||
// Add Constraint incrementally.
|
||||
void AddRowConstraint(MPConstraint* const ct);
|
||||
// Add variable incrementally.
|
||||
void AddVariable(MPVariable* const var);
|
||||
// Change a coefficient in a constraint.
|
||||
virtual void SetCoefficient(MPConstraint* const constraint,
|
||||
const MPVariable* const variable,
|
||||
double new_value,
|
||||
double old_value);
|
||||
// Clear a constraint from all its terms.
|
||||
virtual void ClearConstraint(MPConstraint* const constraint);
|
||||
// Change a coefficient in the linear objective
|
||||
virtual void SetObjectiveCoefficient(const MPVariable* const variable,
|
||||
double coefficient);
|
||||
// Change the constant term in the linear objective.
|
||||
virtual void SetObjectiveOffset(double value);
|
||||
// Clear the objective from all its terms.
|
||||
virtual void ClearObjective();
|
||||
|
||||
// ------ Query statistics on the solution and the solve ------
|
||||
// Number of simplex iterations
|
||||
virtual int64 iterations() const;
|
||||
// Number of branch-and-bound nodes. Only available for discrete problems.
|
||||
virtual int64 nodes() const;
|
||||
// Best objective bound. Only available for discrete problems.
|
||||
virtual double best_objective_bound() const;
|
||||
|
||||
// Returns the basis status of a row.
|
||||
virtual MPSolver::BasisStatus row_status(int constraint_index) const;
|
||||
// Returns the basis status of a column.
|
||||
virtual MPSolver::BasisStatus column_status(int variable_index) const;
|
||||
|
||||
// Checks whether a feasible solution exists.
|
||||
virtual bool CheckSolutionExists() const;
|
||||
// Checks whether information on the best objective bound exists.
|
||||
virtual bool CheckBestObjectiveBoundExists() const;
|
||||
|
||||
// ----- Misc -----
|
||||
// Write model
|
||||
virtual void WriteModel(const std::string& filename);
|
||||
|
||||
// Query problem type.
|
||||
virtual bool IsContinuous() const { return IsLP(); }
|
||||
virtual bool IsLP() const { return !mip_; }
|
||||
virtual bool IsMIP() const { return mip_; }
|
||||
|
||||
virtual void ExtractNewVariables();
|
||||
virtual void ExtractNewConstraints();
|
||||
virtual void ExtractObjective();
|
||||
|
||||
virtual std::string SolverVersion() const {
|
||||
int major,minor,interim;
|
||||
|
||||
SlmGetSulumVersion(&major,&minor,&interim);
|
||||
|
||||
return StringPrintf("SLM major : %d minor : %d interim : %d",major,minor,interim);
|
||||
}
|
||||
|
||||
virtual void* underlying_solver() {
|
||||
return reinterpret_cast<void*>(model_);
|
||||
}
|
||||
|
||||
virtual double ComputeExactConditionNumber() const;
|
||||
|
||||
private:
|
||||
// Configure the solver's parameters.
|
||||
void ConfigureSLMParameters(const MPSolverParameters& param);
|
||||
|
||||
// Set all parameters in the underlying solver.
|
||||
virtual void SetParameters(const MPSolverParameters& param);
|
||||
// Set each parameter in the underlying solver.
|
||||
virtual void SetRelativeMipGap(double value);
|
||||
virtual void SetPrimalTolerance(double value);
|
||||
virtual void SetDualTolerance(double value);
|
||||
virtual void SetPresolveMode(int value);
|
||||
virtual void SetScalingMode(int value);
|
||||
virtual void SetLpAlgorithm(int value);
|
||||
|
||||
void ExtractOldConstraints();
|
||||
void ExtractOneConstraint(MPConstraint* const constraint,
|
||||
int* const indices,
|
||||
double* const coefs);
|
||||
// Transforms basis status from SLM integer code to MPSolver::BasisStatus.
|
||||
MPSolver::BasisStatus TransformSLMBasisStatus(SlmStatusKey slm_basis_status) const;
|
||||
|
||||
// Computes the L1-norm of the current scaled basis.
|
||||
// The L1-norm |A| is defined as max_j sum_i |a_ij|
|
||||
// This method is available only for continuous problems.
|
||||
double ComputeScaledBasisL1Norm(
|
||||
int num_rows, int num_cols,
|
||||
double* row_scaling_factor, double* column_scaling_factor) const;
|
||||
|
||||
// Computes the L1-norm of the inverse of the current scaled
|
||||
// basis.
|
||||
// This method is available only for continuous problems.
|
||||
double ComputeInverseScaledBasisL1Norm(
|
||||
int num_rows, int num_cols,
|
||||
double* row_scaling_factor, double* column_scaling_factor) const;
|
||||
|
||||
SlmEnv_t env_;
|
||||
SlmModel_t model_;
|
||||
bool mip_;
|
||||
};
|
||||
|
||||
// Creates a LP/MIP instance with the specified name and minimization objective.
|
||||
SLMInterface::SLMInterface(MPSolver* const solver, bool mip)
|
||||
: MPSolverInterface(solver), env_(NULL), model_(NULL), mip_(mip) {
|
||||
CheckReturnKey(SlmMakeEnv(&env_));
|
||||
CheckReturnKey(SlmMakeModel(env_,&model_));
|
||||
|
||||
/* Add logging callback function */
|
||||
CheckReturnKey(SlmSetLoggingCallback(model_,&ExLogCallbackFunction,NULL));
|
||||
|
||||
if(solver_->name_.empty() == false) {
|
||||
CheckReturnKey(SlmSetObjName(model_, solver_->name_.c_str()));
|
||||
}
|
||||
|
||||
SetOptimizationDirection(maximize_);
|
||||
}
|
||||
|
||||
// Frees the LP memory allocations.
|
||||
SLMInterface::~SLMInterface() {
|
||||
CHECK_NOTNULL(env_);
|
||||
CHECK_NOTNULL(model_);
|
||||
CheckReturnKey(SlmFreeModel(env_,&model_));
|
||||
CheckReturnKey(SlmFreeEnv(&env_));
|
||||
|
||||
env_ = NULL;
|
||||
model_ = NULL;
|
||||
}
|
||||
|
||||
void SLMInterface::Reset() {
|
||||
CHECK_NOTNULL(model_);
|
||||
CheckReturnKey(SlmClear(model_));
|
||||
CheckReturnKey(SlmSetObjName(model_, solver_->name_.c_str()));
|
||||
CheckReturnKey(SlmSetParamDefault(model_));
|
||||
SetOptimizationDirection(maximize_);
|
||||
ResetExtractionInformation();
|
||||
}
|
||||
|
||||
void SLMInterface::WriteModel(const std::string& filename) {
|
||||
CheckReturnKey(SlmWriteProblem(model_, filename.c_str()));
|
||||
}
|
||||
|
||||
// ------ Model modifications and extraction -----
|
||||
|
||||
// Not cached
|
||||
void SLMInterface::SetOptimizationDirection(bool maximize) {
|
||||
maximize_ = maximize;
|
||||
InvalidateSolutionSynchronization();
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntObjSense,maximize_ == true ? SlmObjSenseMax : SlmObjSenseMin ));
|
||||
}
|
||||
|
||||
void SLMInterface::SetVariableBounds(int var_index, double lb, double ub) {
|
||||
InvalidateSolutionSynchronization();
|
||||
if (variable_is_extracted(var_index)) {
|
||||
// Not cached if the variable has been extracted.
|
||||
DCHECK(model_ != NULL);
|
||||
const double infinity = solver_->infinity();
|
||||
|
||||
SlmBoundKey bk;
|
||||
double lo = lb;
|
||||
double up = ub;
|
||||
|
||||
if (lb != -infinity) {
|
||||
if (ub != infinity) {
|
||||
if (lb == ub) {
|
||||
bk = SlmBndFx;
|
||||
} else {
|
||||
bk = SlmBndRa;
|
||||
}
|
||||
} else {
|
||||
up = SlmInfinity;
|
||||
bk = SlmBndLo;
|
||||
}
|
||||
} else if (ub != infinity) {
|
||||
lo = -SlmInfinity;
|
||||
bk = SlmBndUp;
|
||||
} else {
|
||||
lo = -SlmInfinity;
|
||||
up = SlmInfinity;
|
||||
bk = SlmBndFr;
|
||||
}
|
||||
|
||||
CheckReturnKey(SlmSetKeyVarsI(model_,var_index,bk));
|
||||
CheckReturnKey(SlmSetLoVarsI(model_,var_index,lo));
|
||||
CheckReturnKey(SlmSetUpVarsI(model_,var_index,up));
|
||||
} else {
|
||||
sync_status_ = MUST_RELOAD;
|
||||
}
|
||||
}
|
||||
|
||||
void SLMInterface::SetVariableInteger(int var_index, bool integer) {
|
||||
InvalidateSolutionSynchronization();
|
||||
if (mip_) {
|
||||
if (variable_is_extracted(var_index)) {
|
||||
// Not cached if the variable has been extracted.
|
||||
SlmVarType type;
|
||||
CheckReturnKey(SlmGetTypeVarsI(model_,var_index,&type));
|
||||
|
||||
if(type ==SlmVarTypeCont) {
|
||||
integer = false;
|
||||
}
|
||||
else {
|
||||
integer = true;
|
||||
}
|
||||
} else {
|
||||
sync_status_ = MUST_RELOAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SLMInterface::SetConstraintBounds(int index, double lb, double ub) {
|
||||
InvalidateSolutionSynchronization();
|
||||
if (constraint_is_extracted(index)) {
|
||||
// Not cached if the row has been extracted
|
||||
DCHECK(model_ != NULL);
|
||||
const double infinity = solver_->infinity();
|
||||
SlmBoundKey bk;
|
||||
double lo = lb;
|
||||
double up = ub;
|
||||
|
||||
if (lb != -infinity) {
|
||||
if (ub != infinity) {
|
||||
if (lb == ub) {
|
||||
bk = SlmBndFx;
|
||||
} else {
|
||||
bk = SlmBndRa;
|
||||
}
|
||||
} else {
|
||||
up = SlmInfinity;
|
||||
bk = SlmBndLo;
|
||||
}
|
||||
} else if (ub != infinity) {
|
||||
lo = -SlmInfinity;
|
||||
bk = SlmBndUp;
|
||||
} else {
|
||||
lo = -SlmInfinity;
|
||||
up = SlmInfinity;
|
||||
bk = SlmBndFr;
|
||||
}
|
||||
|
||||
CheckReturnKey(SlmSetKeyConsI(model_,index,bk));
|
||||
CheckReturnKey(SlmSetLoConsI(model_,index,lo));
|
||||
CheckReturnKey(SlmSetUpConsI(model_,index,up));
|
||||
} else {
|
||||
sync_status_ = MUST_RELOAD;
|
||||
}
|
||||
}
|
||||
|
||||
void SLMInterface::SetCoefficient(MPConstraint* const constraint,
|
||||
const MPVariable* const variable,
|
||||
double new_value,
|
||||
double old_value) {
|
||||
InvalidateSolutionSynchronization();
|
||||
const int constraint_index = constraint->index();
|
||||
const int variable_index = variable->index();
|
||||
if (constraint_is_extracted(constraint_index) &&
|
||||
variable_is_extracted(variable_index)) {
|
||||
// The modification of the coefficient for an extracted row and
|
||||
// variable is not cached.
|
||||
DCHECK_LE(constraint_index, last_constraint_index_);
|
||||
DCHECK_LE(variable_index, last_variable_index_);
|
||||
CheckReturnKey(SlmSetAIJ(model_,constraint_index, variable_index, new_value));
|
||||
} else {
|
||||
// The modification of an unextracted row or variable is cached
|
||||
// and handled in ExtractModel.
|
||||
sync_status_ = MUST_RELOAD;
|
||||
}
|
||||
}
|
||||
|
||||
// Not cached
|
||||
void SLMInterface::ClearConstraint(MPConstraint* const constraint) {
|
||||
InvalidateSolutionSynchronization();
|
||||
const int constraint_index = constraint->index();
|
||||
// Constraint may not have been extracted yet.
|
||||
if (constraint_is_extracted(constraint_index)) {
|
||||
CheckReturnKey(SlmSetAConsI(model_, constraint_index, 0, NULL, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
// Cached
|
||||
void SLMInterface::SetObjectiveCoefficient(const MPVariable* const variable,
|
||||
double coefficient) {
|
||||
sync_status_ = MUST_RELOAD;
|
||||
}
|
||||
|
||||
// Cached
|
||||
void SLMInterface::SetObjectiveOffset(double value) {
|
||||
sync_status_ = MUST_RELOAD;
|
||||
}
|
||||
|
||||
// Clear objective of all its terms (linear)
|
||||
void SLMInterface::ClearObjective() {
|
||||
InvalidateSolutionSynchronization();
|
||||
for (const auto& it : solver_->objective_->coefficients_) {
|
||||
const int var_index = it.first->index();
|
||||
// Variable may have not been extracted yet.
|
||||
if (!variable_is_extracted(var_index)) {
|
||||
DCHECK_NE(MODEL_SYNCHRONIZED, sync_status_);
|
||||
} else {
|
||||
CheckReturnKey(SlmSetObjVarsI(model_,var_index, 0.0));
|
||||
}
|
||||
}
|
||||
// Constant term.
|
||||
CheckReturnKey(SlmSetObjFix(model_, 0.0));
|
||||
}
|
||||
|
||||
void SLMInterface::AddRowConstraint(MPConstraint* const ct) {
|
||||
sync_status_ = MUST_RELOAD;
|
||||
}
|
||||
|
||||
void SLMInterface::AddVariable(MPVariable* const var) {
|
||||
sync_status_ = MUST_RELOAD;
|
||||
}
|
||||
|
||||
// Define new variables and add them to existing constraints.
|
||||
void SLMInterface::ExtractNewVariables() {
|
||||
int total_num_vars = solver_->variables_.size();
|
||||
if (total_num_vars > last_variable_index_) {
|
||||
CheckReturnKey(SlmAddEmptyVars(model_,total_num_vars - last_variable_index_));
|
||||
for (int j = last_variable_index_; j < solver_->variables_.size(); ++j) {
|
||||
MPVariable* const var = solver_->variables_[j];
|
||||
set_variable_as_extracted(var->index(), true);
|
||||
if (!var->name().empty()) {
|
||||
CheckReturnKey(SlmSetNameVarsI(model_,j, var->name().c_str()));
|
||||
}
|
||||
|
||||
SetVariableBounds(j, var->lb(), var->ub());
|
||||
SetVariableInteger(j, var->integer());
|
||||
|
||||
// The true objective coefficient will be set later in ExtractObjective.
|
||||
double tmp_obj_coef = 0.0;
|
||||
CheckReturnKey(SlmSetObjVarsI(model_,j, tmp_obj_coef));
|
||||
}
|
||||
// Add new variables to the existing constraints.
|
||||
ExtractOldConstraints();
|
||||
}
|
||||
}
|
||||
|
||||
// Extract again existing constraints if they contain new variables.
|
||||
void SLMInterface::ExtractOldConstraints() {
|
||||
int max_constraint_size = solver_->ComputeMaxConstraintSize(
|
||||
0, last_constraint_index_);
|
||||
|
||||
std::unique_ptr<int[]> indices(new int[max_constraint_size ]);
|
||||
std::unique_ptr<double[]> coefs(new double[max_constraint_size ]);
|
||||
|
||||
for (int i = 0; i < last_constraint_index_; ++i) {
|
||||
MPConstraint* const ct = solver_->constraints_[i];
|
||||
CHECK(constraint_is_extracted(i));
|
||||
const int size = ct->coefficients_.size();
|
||||
if (size == 0) {
|
||||
continue;
|
||||
}
|
||||
// Update the constraint's coefficients if it contains new variables.
|
||||
if (ct->ContainsNewVariables()) {
|
||||
ExtractOneConstraint(ct, indices.get(), coefs.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract one constraint. Arrays indices and coefs must be
|
||||
// preallocated to have enough space to contain the constraint's
|
||||
// coefficients.
|
||||
void SLMInterface::ExtractOneConstraint(MPConstraint* const constraint,
|
||||
int* const indices,
|
||||
double* const coefs) {
|
||||
int k = 0;
|
||||
for (const auto& it : constraint->coefficients_) {
|
||||
const int var_index = it.first->index();
|
||||
CHECK(variable_is_extracted(var_index));
|
||||
indices[k] = var_index;
|
||||
coefs[k] = it.second;
|
||||
++k;
|
||||
}
|
||||
|
||||
CheckReturnKey(SlmSetAConsI(model_,constraint->index(), k, indices, coefs));
|
||||
}
|
||||
|
||||
// Define new constraints on old and new variables.
|
||||
void SLMInterface::ExtractNewConstraints() {
|
||||
int total_num_rows = solver_->constraints_.size();
|
||||
if (last_constraint_index_ < total_num_rows) {
|
||||
// Find the length of the longest row.
|
||||
int64 newanz = 0;
|
||||
int64 oldanz = 0;
|
||||
|
||||
int max_row_length = 0;
|
||||
for (int i = last_constraint_index_; i < total_num_rows; ++i) {
|
||||
MPConstraint* const ct = solver_->constraints_[i];
|
||||
CHECK(!constraint_is_extracted(i));
|
||||
set_constraint_as_extracted(i, true);
|
||||
if (ct->coefficients_.size() > max_row_length) {
|
||||
max_row_length = ct->coefficients_.size();
|
||||
}
|
||||
|
||||
newanz += ct->coefficients_.size();
|
||||
}
|
||||
|
||||
int addrows = total_num_rows - last_constraint_index_;
|
||||
|
||||
// Add sizes for efficiens
|
||||
CheckReturnKey(SlmGetANz64(model_,&oldanz));
|
||||
CheckReturnKey(SlmHintAMaxNz64(model_,newanz+oldanz));
|
||||
CheckReturnKey(SlmAddEmptyCons(model_,addrows));
|
||||
|
||||
// Make space for dummy variable.
|
||||
max_row_length = std::max(1, max_row_length);
|
||||
std::unique_ptr<int[]> indices(new int[max_row_length]);
|
||||
std::unique_ptr<double[]> coefs(new double[max_row_length]);
|
||||
|
||||
// Add each new constraint.
|
||||
for (int i = last_constraint_index_; i < total_num_rows; ++i) {
|
||||
MPConstraint* const ct = solver_->constraints_[i];
|
||||
CHECK(constraint_is_extracted(i));
|
||||
int size = ct->coefficients_.size();
|
||||
int j = 0;
|
||||
for (const auto& it : ct->coefficients_) {
|
||||
const int var_index = it.first->index();
|
||||
CHECK(variable_is_extracted(var_index));
|
||||
indices[j] = var_index;
|
||||
coefs[j] = it.second;
|
||||
j++;
|
||||
}
|
||||
|
||||
if( size > 0 ) {
|
||||
CheckReturnKey(SlmSetAConsI(model_,i,size,indices.get(),coefs.get()));
|
||||
}
|
||||
|
||||
SetConstraintBounds(i, ct->lb(),ct->ub());
|
||||
|
||||
if (!ct->name().empty()) {
|
||||
std::string std_name = ct->name();
|
||||
CheckReturnKey(SlmSetNameConsI(model_,ct->index(), std_name.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SLMInterface::ExtractObjective() {
|
||||
// Linear objective: set objective coefficients for all variables
|
||||
// (some might have been modified).
|
||||
for (hash_map<const MPVariable*, double>::const_iterator it =
|
||||
solver_->objective_->coefficients_.begin();
|
||||
it != solver_->objective_->coefficients_.end();
|
||||
++it) {
|
||||
CheckReturnKey(SlmSetObjVarsI(model_,it->first->index(), it->second));
|
||||
}
|
||||
// Constant term.
|
||||
CheckReturnKey(SlmSetObjFix(model_, solver_->Objective().offset()));
|
||||
}
|
||||
|
||||
// Solve the problem using the parameter values specified.
|
||||
MPSolver::ResultStatus SLMInterface::Solve(const MPSolverParameters& param) {
|
||||
WallTimer timer;
|
||||
timer.Start();
|
||||
|
||||
// Note that SLM provides incrementality for LP but not for MIP.
|
||||
if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) ==
|
||||
MPSolverParameters::INCREMENTALITY_OFF) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
// Set log level.
|
||||
if (quiet_) {
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntLogLevel,0));
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntSimLogLevel,0));
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntLogNoModuleMessage,SlmOff));
|
||||
} else {
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntLogLevel,5));
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntSimLogLevel,5));
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntLogNoModuleMessage,SlmOn));
|
||||
}
|
||||
|
||||
ExtractModel();
|
||||
VLOG(1) << StringPrintf("Model built in %.3f seconds.", timer.Get());
|
||||
|
||||
// Configure parameters at every solve, even when the model has not
|
||||
// been changed, in case some of the parameters such as the time
|
||||
// limit have been changed since the last solve.
|
||||
ConfigureSLMParameters(param);
|
||||
|
||||
// Solve
|
||||
timer.Restart();
|
||||
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntUpdateSolQuality,SlmOn));
|
||||
|
||||
CheckReturnKey(SlmOptimize(model_));
|
||||
|
||||
VLOG(1) << StringPrintf("Solved in %.3f seconds.", timer.Get());
|
||||
|
||||
// Get the results.
|
||||
CheckReturnKey(SlmGetDbInfo(model_,SlmInfoDbPrimObj,&objective_value_));
|
||||
|
||||
VLOG(1) << "objective=" << objective_value_;
|
||||
for (int i = 0; i < solver_->variables_.size(); ++i) {
|
||||
MPVariable* const var = solver_->variables_[i];
|
||||
double val;
|
||||
CheckReturnKey(SlmGetSolPrimVarsI(model_,var->index(),&val));
|
||||
var->set_solution_value(val);
|
||||
VLOG(3) << var->name() << ": value =" << val;
|
||||
if (!mip_) {
|
||||
double reduced_cost;
|
||||
CheckReturnKey(SlmGetSolDualVarsI(model_,var->index(),&reduced_cost));
|
||||
var->set_reduced_cost(reduced_cost);
|
||||
VLOG(4) << var->name() << ": reduced cost = " << reduced_cost;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < solver_->constraints_.size(); ++i) {
|
||||
MPConstraint* const ct = solver_->constraints_[i];
|
||||
if (!mip_) {
|
||||
double dual_value;
|
||||
CheckReturnKey(SlmGetSolDualConsI(model_,ct->index(),&dual_value));
|
||||
ct->set_dual_value(dual_value);
|
||||
VLOG(4) << "row " << ct->index()
|
||||
<< ": dual value = " << dual_value;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the status: optimal, infeasible, etc.
|
||||
SlmSolStatus tmp_status;
|
||||
CheckReturnKey(SlmGetSolStatus(model_,&tmp_status));
|
||||
|
||||
switch(tmp_status)
|
||||
{
|
||||
case SlmSolStatUnk :
|
||||
VLOG(1) << "slm result status: SlmSolStatUnk";
|
||||
result_status_ = MPSolver::INFEASIBLE; /* What ever that means.. */
|
||||
break;
|
||||
case SlmSolStatOpt :
|
||||
VLOG(1) << "slm result status: SlmSolStatOpt";
|
||||
result_status_ = MPSolver::OPTIMAL;
|
||||
break;
|
||||
case SlmSolStatPrimFeas :
|
||||
VLOG(1) << "slm result status: SlmSolStatPrimFeas";
|
||||
result_status_ = MPSolver::FEASIBLE; /* What ever that means.. */
|
||||
break;
|
||||
case SlmSolStatDualFeas :
|
||||
VLOG(1) << "slm result status: SlmSolStatDualFeas";
|
||||
result_status_ = MPSolver::FEASIBLE; /* What ever that means.. */
|
||||
break;
|
||||
case SlmSolStatPrimInf :
|
||||
VLOG(1) << "slm result status: SlmSolStatPrimInf";
|
||||
result_status_ = MPSolver::INFEASIBLE;
|
||||
break;
|
||||
case SlmSolStatDualInf :
|
||||
VLOG(1) << "slm result status: SlmSolStatDualInf";
|
||||
result_status_ = MPSolver::UNBOUNDED; /* Theoretically not correct, you need a primal feasible point in LP */
|
||||
break;
|
||||
case SlmSolStatIntFeas :
|
||||
VLOG(1) << "slm result status: SlmSolStatIntFeas";
|
||||
result_status_ = MPSolver::FEASIBLE;
|
||||
break;
|
||||
case SlmSolStatIntInf :
|
||||
VLOG(1) << "slm result status: SlmSolStatIntInf";
|
||||
result_status_ = MPSolver::INFEASIBLE;
|
||||
break;
|
||||
}
|
||||
|
||||
sync_status_ = SOLUTION_SYNCHRONIZED;
|
||||
|
||||
return result_status_;
|
||||
}
|
||||
|
||||
MPSolver::BasisStatus
|
||||
SLMInterface::TransformSLMBasisStatus(SlmStatusKey slm_basis_status) const {
|
||||
switch (slm_basis_status) {
|
||||
case SlmStaBa:
|
||||
return MPSolver::BASIC;
|
||||
case SlmStaLo:
|
||||
return MPSolver::AT_LOWER_BOUND;
|
||||
case SlmStaUp:
|
||||
return MPSolver::AT_UPPER_BOUND;
|
||||
case SlmStaSb:
|
||||
return MPSolver::FREE;
|
||||
case SlmStaFx:
|
||||
return MPSolver::FIXED_VALUE;
|
||||
default:
|
||||
LOG(FATAL) << "Unknown SLM basis status";
|
||||
return MPSolver::FREE;
|
||||
}
|
||||
}
|
||||
|
||||
MPSolverInterface* BuildSLMInterface(MPSolver* const solver, bool mip) {
|
||||
return new SLMInterface(solver, mip);
|
||||
}
|
||||
|
||||
// ------ Query statistics on the solution and the solve ------
|
||||
|
||||
int64 SLMInterface::iterations() const {
|
||||
int iter;
|
||||
CheckSolutionIsSynchronized();
|
||||
if(mip_) {
|
||||
LOG(WARNING) << "Total number of iterations is not available";
|
||||
return kUnknownNumberOfIterations;
|
||||
}
|
||||
else {
|
||||
CheckReturnKey(SlmGetIntInfo(model_,SlmInfoIntSimIter,&iter));
|
||||
}
|
||||
|
||||
return static_cast<int64>(iter);
|
||||
}
|
||||
|
||||
int64 SLMInterface::nodes() const {
|
||||
if (mip_) {
|
||||
CheckSolutionIsSynchronized();
|
||||
int nodes;
|
||||
CheckReturnKey(SlmGetIntInfo(model_,SlmInfoIntMipNodes,&nodes));
|
||||
return static_cast<int64>(nodes);
|
||||
} else {
|
||||
LOG(FATAL) << "Number of nodes only available for discrete problems";
|
||||
return kUnknownNumberOfNodes;
|
||||
}
|
||||
}
|
||||
|
||||
double SLMInterface::best_objective_bound() const {
|
||||
if (mip_) {
|
||||
CheckSolutionIsSynchronized();
|
||||
CheckBestObjectiveBoundExists();
|
||||
if (solver_->variables_.size() == 0 && solver_->constraints_.size() == 0) {
|
||||
// Special case for empty model.
|
||||
return solver_->Objective().offset();
|
||||
} else {
|
||||
double best_objective_bound;
|
||||
CheckReturnKey(SlmGetDbInfo(model_,SlmInfoDbMipBoundLP,&best_objective_bound));
|
||||
return best_objective_bound;
|
||||
}
|
||||
} else {
|
||||
LOG(FATAL) << "Best objective bound only available for discrete problems";
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
MPSolver::BasisStatus SLMInterface::row_status(int constraint_index) const {
|
||||
// + 1 because of SLM indexing convention.
|
||||
DCHECK_LE(1, constraint_index);
|
||||
DCHECK_GT(last_constraint_index_ + 1, constraint_index);
|
||||
SlmStatusKey slm_basis_status;
|
||||
CheckReturnKey(SlmGetSolKeyPrimConsI(model_,constraint_index,&slm_basis_status));
|
||||
return TransformSLMBasisStatus(slm_basis_status);
|
||||
}
|
||||
|
||||
MPSolver::BasisStatus SLMInterface::column_status(int variable_index) const {
|
||||
// + 1 because of SLM indexing convention.
|
||||
DCHECK_LE(1, variable_index);
|
||||
DCHECK_GT(last_variable_index_ + 1, variable_index);
|
||||
SlmStatusKey slm_basis_status;
|
||||
CheckReturnKey(SlmGetSolKeyPrimVarsI(model_,variable_index,&slm_basis_status));
|
||||
return TransformSLMBasisStatus(slm_basis_status);
|
||||
}
|
||||
|
||||
bool SLMInterface::CheckSolutionExists() const {
|
||||
if (result_status_ == MPSolver::ABNORMAL) {
|
||||
LOG(WARNING) << "Ignoring ABNORMAL status from SLM: This status may or may"
|
||||
<< " not indicate that a solution exists.";
|
||||
return false;
|
||||
} else {
|
||||
// Call default implementation
|
||||
return MPSolverInterface::CheckSolutionExists();
|
||||
}
|
||||
}
|
||||
|
||||
bool SLMInterface::CheckBestObjectiveBoundExists() const {
|
||||
if (result_status_ == MPSolver::ABNORMAL) {
|
||||
LOG(WARNING) << "Ignoring ABNORMAL status from SLM: This status may or may"
|
||||
<< " not indicate that information is available on the best"
|
||||
<< " objective bound.";
|
||||
return false;
|
||||
} else {
|
||||
// Call default implementation
|
||||
return MPSolverInterface::CheckBestObjectiveBoundExists();
|
||||
}
|
||||
}
|
||||
|
||||
double SLMInterface::ComputeExactConditionNumber() const {
|
||||
CHECK(IsContinuous()) <<
|
||||
"Condition number only available for continuous problems";
|
||||
CheckSolutionIsSynchronized();
|
||||
// Simplex is the only LP algorithm supported in the wrapper for
|
||||
// SLM, so when a solution exists, a basis exists.
|
||||
CheckSolutionExists();
|
||||
int num_rows;
|
||||
int num_cols;
|
||||
|
||||
CheckReturnKey(SlmGetCons(model_,&num_rows));
|
||||
CheckReturnKey(SlmGetVars(model_,&num_cols));
|
||||
|
||||
std::unique_ptr<double[]> row_scaling_factor(new double[num_rows]);
|
||||
std::unique_ptr<double[]> column_scaling_factor(new double[num_cols]);
|
||||
|
||||
for (int row = 0; row < num_rows; ++row) {
|
||||
row_scaling_factor[row] = 1.0;
|
||||
}
|
||||
for (int col = 0; col < num_cols; ++col) {
|
||||
column_scaling_factor[col] = 1.0;
|
||||
}
|
||||
|
||||
return
|
||||
ComputeInverseScaledBasisL1Norm(
|
||||
num_rows, num_cols,
|
||||
row_scaling_factor.get(), column_scaling_factor.get()) *
|
||||
ComputeScaledBasisL1Norm(
|
||||
num_rows, num_cols,
|
||||
row_scaling_factor.get(), column_scaling_factor.get());
|
||||
}
|
||||
|
||||
double SLMInterface::ComputeScaledBasisL1Norm(
|
||||
int num_rows, int num_cols,
|
||||
double* row_scaling_factor, double* column_scaling_factor) const {
|
||||
double norm = 0.0;
|
||||
|
||||
std::unique_ptr<double[]> values(new double[num_rows]);
|
||||
std::unique_ptr<int[]> indices(new int[num_rows]);
|
||||
for (int col = 0; col < num_cols; ++col) {
|
||||
SlmStatusKey slm_basis_status;
|
||||
|
||||
CheckReturnKey(SlmGetSolKeyPrimVarsI(model_,col,&slm_basis_status));
|
||||
|
||||
// Take into account only basic columns.
|
||||
if (slm_basis_status == SlmStaBa) {
|
||||
// Compute L1-norm of column 'col': sum_row |a_row,col|.
|
||||
int num_nz;
|
||||
|
||||
CheckReturnKey(SlmGetAVarsI(model_, col,&num_nz,indices.get(), values.get()));
|
||||
|
||||
double column_norm = 0.0;
|
||||
for (int k = 0; k < num_nz; k++) {
|
||||
column_norm += fabs(values[k] * row_scaling_factor[indices[k]]);
|
||||
}
|
||||
column_norm *= fabs(column_scaling_factor[col]);
|
||||
// Compute max_col column_norm
|
||||
norm = std::max(norm, column_norm);
|
||||
}
|
||||
}
|
||||
// Slack variables.
|
||||
for (int row = 0; row < num_rows; ++row) {
|
||||
SlmStatusKey slm_basis_status;
|
||||
|
||||
CheckReturnKey(SlmGetSolKeyPrimConsI(model_,row,&slm_basis_status));
|
||||
|
||||
// Take into account only basic slack variables.
|
||||
if (slm_basis_status == SlmStaBa) {
|
||||
// Only one non-zero coefficient: +/- 1.0 in the corresponding
|
||||
// row. The row has a scaling coefficient but the slack variable
|
||||
// is never scaled on top of that.
|
||||
const double column_norm = fabs(row_scaling_factor[row]);
|
||||
// Compute max_col column_norm
|
||||
norm = std::max(norm, column_norm);
|
||||
}
|
||||
}
|
||||
|
||||
return norm;
|
||||
}
|
||||
|
||||
double SLMInterface::ComputeInverseScaledBasisL1Norm(
|
||||
int num_rows, int num_cols,
|
||||
double* row_scaling_factor, double* column_scaling_factor) const {
|
||||
|
||||
// Currently we just refactor each time
|
||||
int ret = SlmInitBasisSolves(model_);
|
||||
|
||||
// Compute the LU factorization if it doesn't exist yet.
|
||||
if ( ret != SlmRetOk ) {
|
||||
switch (ret) {
|
||||
case SlmRetBasisSingular: {
|
||||
LOG(WARNING)
|
||||
<< "Not able to factorize: "
|
||||
<< "the basis matrix is singular within the working precision.";
|
||||
return MPSolver::infinity();
|
||||
}
|
||||
default:
|
||||
CheckReturnKey(ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<double[]> right_hand_side(new double[num_rows]);
|
||||
std::unique_ptr<int[]> basidx(new int[num_rows]);
|
||||
|
||||
CheckReturnKey(SlmGetBasisHead(model_,basidx.get()));
|
||||
|
||||
double norm = 0.0;
|
||||
|
||||
// Iteratively solve B x = e_k, where e_k is the kth unit vector.
|
||||
// The result of this computation is the kth column of B^-1.
|
||||
|
||||
for (int k = 0; k < num_rows; ++k) {
|
||||
for (int row = 0; row < num_rows; ++row) {
|
||||
right_hand_side[row] = 0.0;
|
||||
}
|
||||
right_hand_side[k] = 1.0;
|
||||
// Multiply input by inv(R).
|
||||
for (int row = 0; row < num_rows; ++row) {
|
||||
right_hand_side[row] /= row_scaling_factor[row];
|
||||
}
|
||||
|
||||
CheckReturnKey(SlmSolveFtranDense(model_, right_hand_side.get()));
|
||||
|
||||
// stores the result in the same vector where the right
|
||||
// hand side was provided.
|
||||
// Multiply result by inv(SB).
|
||||
for (int row = 0; row < num_rows; ++row) {
|
||||
const int k = basidx[row];
|
||||
if (k <= num_rows) {
|
||||
// Auxiliary variable.
|
||||
right_hand_side[row] *= row_scaling_factor[k];
|
||||
} else {
|
||||
// Structural variable.
|
||||
right_hand_side[row] /= column_scaling_factor[k - num_rows];
|
||||
}
|
||||
}
|
||||
|
||||
// Compute sum_row |vector_row|.
|
||||
double column_norm = 0.0;
|
||||
for (int row = 0; row < num_rows; ++row) {
|
||||
column_norm += fabs(right_hand_side[row]);
|
||||
}
|
||||
|
||||
// Compute max_col column_norm
|
||||
norm = std::max(norm, column_norm);
|
||||
}
|
||||
|
||||
return norm;
|
||||
}
|
||||
|
||||
// ------ Parameters ------
|
||||
|
||||
void SLMInterface::ConfigureSLMParameters(const MPSolverParameters& param) {
|
||||
// Time limit
|
||||
if (solver_->time_limit()) {
|
||||
VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
|
||||
CheckReturnKey(SlmSetDbParam(model_,SlmPrmDbOptTimeLimit,solver_->time_limit()));
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckReturnKey(SlmSetDbParam(model_,SlmPrmDbOptTimeLimit,DBL_MAX));
|
||||
}
|
||||
|
||||
// Set parameters specified by the user.
|
||||
SetParameters(param);
|
||||
}
|
||||
|
||||
void SLMInterface::SetParameters(const MPSolverParameters& param) {
|
||||
SetCommonParameters(param);
|
||||
if (mip_) {
|
||||
SetMIPParameters(param);
|
||||
}
|
||||
}
|
||||
|
||||
void SLMInterface::SetRelativeMipGap(double value) {
|
||||
if (mip_) {
|
||||
CheckReturnKey(SlmSetDbParam(model_,SlmPrmDbMipTolRelGap, value));
|
||||
} else {
|
||||
LOG(WARNING) << "The relative MIP gap is only available "
|
||||
<< "for discrete problems.";
|
||||
}
|
||||
}
|
||||
|
||||
void SLMInterface::SetPrimalTolerance(double value) {
|
||||
CheckReturnKey(SlmSetDbParam(model_,SlmPrmDbSimTolPrim, value));
|
||||
}
|
||||
|
||||
void SLMInterface::SetDualTolerance(double value) {
|
||||
CheckReturnKey(SlmSetDbParam(model_,SlmPrmDbSimTolDual, value));
|
||||
}
|
||||
|
||||
void SLMInterface::SetPresolveMode(int value) {
|
||||
switch (value) {
|
||||
case MPSolverParameters::PRESOLVE_OFF: {
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntPresolve,SlmPreOff));
|
||||
break;
|
||||
}
|
||||
case MPSolverParameters::PRESOLVE_ON: {
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntPresolve,SlmPreFree));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SLMInterface::SetLpAlgorithm(int value) {
|
||||
switch (value) {
|
||||
case MPSolverParameters::DUAL: {
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntOptimizer,SlmOptDual));
|
||||
break;
|
||||
}
|
||||
case MPSolverParameters::PRIMAL: {
|
||||
CheckReturnKey(SlmSetIntParam(model_,SlmPrmIntOptimizer,SlmOptPrim));
|
||||
break;
|
||||
}
|
||||
case MPSolverParameters::BARRIER:
|
||||
default: {
|
||||
SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
|
||||
value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SLMInterface::SetScalingMode(int value) {
|
||||
SetUnsupportedIntegerParam(MPSolverParameters::SCALING);
|
||||
}
|
||||
} // namespace operations_research
|
||||
#endif // #if defined(USE_SLM)
|
||||
Reference in New Issue
Block a user