r"""
SCIP (Solving Constraint Integer Programs)
"""
# Copyright (c) 2024 Thinklab@SJTU
# ML4CO-Kit is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
import os
import sys
import shutil
from ml4co_kit.utils.file_utils import download
from ml4co_kit.optimizer.base import OptimizerBase
from ml4co_kit.task.base import TaskBase, TASK_TYPE
from ml4co_kit.solver.base import SolverBase, SOLVER_TYPE
from .lib.scip.lp_scip import lp_scip
from .lib.scip.milp_scip import milp_scip
from .lib.scip.mopo_scip import mopo_scip
from .lib.scip.maxretpo_scip import maxretpo_scip
from .lib.scip.minvarpo_scip import minvarpo_scip
[docs]class SCIPSolver(SolverBase):
"""
SCIP: https://github.com/scipopt/scip
PySCIPOpt: https://github.com/scipopt/PySCIPOpt
Current Version: 10.0.2
Last Update: 2026-05-26
@incollection{
MaherMiltenbergerPedrosoRehfeldtSchwarzSerrano2016,
author = {Stephen Maher and Matthias Miltenberger and Jo{\~{a}}o Pedro Pedroso
and Daniel Rehfeldt and Robert Schwarz and Felipe Serrano},
title = {{PySCIPOpt}: Mathematical Programming in Python with the {SCIP} Optimization Suite},
booktitle = {Mathematical Software {\textendash} {ICMS} 2016},
publisher = {Springer International Publishing},
pages = {301--307},
year = {2016},
doi = {10.1007/978-3-319-42432-3_37},
}
"""
def __init__(
self,
scip_time_limit: float = 10.0,
soplex_version: str = "8.0.2",
scip_version: str = "10.0.2",
optimizer: OptimizerBase = None
):
# Super Initialization
super(SCIPSolver, self).__init__(
solver_type=SOLVER_TYPE.SCIP, optimizer=optimizer
)
# Set Attributes
self.scip_time_limit = scip_time_limit
self.soplex_version = soplex_version
self.scip_version = scip_version
# SOPLEX Path Check
self.soplex_store_path = sys.prefix
self.soplex_bin_path = os.path.join(self.soplex_store_path, "bin", "soplex")
if not os.path.exists(self.soplex_bin_path):
self.install_soplex()
# SCIP Path Check
self.scip_store_path = sys.prefix
self.scip_bin_path = os.path.join(self.scip_store_path, "bin", "scip")
if not os.path.exists(self.scip_bin_path):
self.install()
def _solve(self, task_data: TaskBase):
"""Solve the task data using SCIP Solver."""
if task_data.task_type == TASK_TYPE.MAXRETPO:
return maxretpo_scip(
task_data=task_data,
scip_time_limit=self.scip_time_limit
)
elif task_data.task_type == TASK_TYPE.MINVARPO:
return minvarpo_scip(
task_data=task_data,
scip_time_limit=self.scip_time_limit
)
elif task_data.task_type == TASK_TYPE.MOPO:
return mopo_scip(
task_data=task_data,
scip_time_limit=self.scip_time_limit
)
elif task_data.task_type == TASK_TYPE.LP:
return lp_scip(
task_data=task_data,
scip_time_limit=self.scip_time_limit
)
elif task_data.task_type == TASK_TYPE.MILP:
return milp_scip(
task_data=task_data,
scip_time_limit=self.scip_time_limit
)
else:
raise ValueError(
f"SCIP Solver does not support task type: {task_data.task_type}. "
f"Supported types: LP, MILP, MaxRetPO, MinVarPO, MOPO"
)
[docs] def install_soplex(self):
"""
Install SOPLEX.
SoPlex: https://github.com/soplexopt/soplex
"""
# Step1: Download SCIP
soplex_url = (
f"https://codeload.github.com/scipopt/soplex/"
f"tar.gz/refs/tags/v{self.soplex_version}"
)
download(file_path=f"soplex-{self.soplex_version}.tgz", url=soplex_url)
# Step2: tar .tgz file
os.system(f"tar xvfz soplex-{self.soplex_version}.tgz")
os.makedirs(f"soplex-{self.soplex_version}/build", exist_ok=True)
# Step3: build SCIP
ori_dir = os.getcwd()
os.chdir(f"soplex-{self.soplex_version}/build")
cmake_cmd = (
f"cmake .. "
f"-DCMAKE_BUILD_TYPE=Release "
f"-DCMAKE_INSTALL_PREFIX={self.soplex_store_path}"
)
os.system(cmake_cmd)
os.system("make")
os.system("make install")
os.chdir(ori_dir)
# Step4: clean up
os.remove(f"soplex-{self.soplex_version}.tgz")
shutil.rmtree(f"soplex-{self.soplex_version}")
[docs] def install(self):
"""Install SCIP Solver."""
# Step1: Download SCIP
scip_url = (
f"https://codeload.github.com/scipopt/scip/"
f"tar.gz/refs/tags/v{self.scip_version}"
)
download(file_path=f"SCIP-{self.scip_version}.tgz", url=scip_url)
# Step2: tar .tgz file
os.system(f"tar xvfz SCIP-{self.scip_version}.tgz")
os.makedirs(f"scip-{self.scip_version}/build", exist_ok=True)
# Step3: build SCIP
ori_dir = os.getcwd()
os.chdir(f"scip-{self.scip_version}/build")
cmake_cmd = (
f"cmake .. "
f"-DAUTOBUILD=on "
f"-DCMAKE_INSTALL_PREFIX={self.scip_store_path}"
)
os.system(cmake_cmd)
os.system("make")
os.system("make install")
os.chdir(ori_dir)
# Step4: clean up
os.remove(f"SCIP-{self.scip_version}.tgz")
shutil.rmtree(f"scip-{self.scip_version}")
msg = (
f"SCIP Solver installed successfully at {self.scip_store_path}. "
f"The executable is at {self.scip_bin_path}.\n"
f"Note: AUTOBUILD=on may skip optional features. For full functionality, "
f"see https://github.com/scipopt/scip/blob/master/INSTALL.md"
)
print(msg)