Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added scip_cmd, added uv #804

Merged
merged 7 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 22 additions & 35 deletions .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,27 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install uv and set the python version
uses: astral-sh/setup-uv@v5
with:
python-version: ${{ matrix.python-version }}
- name: Update pip, install dev deps
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
run: uv pip install -r requirements-dev.txt
- name: Code Quality
run: |
python -m pip install black
black pulp/ --check
run: black pulp/ --check
- name: Type Check
run: |
mypy ./
- name: Install dependencies
run: |
python -m pip install .
- name: install glpk
run: mypy ./
- name: install ubuntu-only solvers
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update -qq
sudo apt-get install -qq glpk-utils
sudo apt update -qq
sudo apt install -qq glpk-utils
- name: install xpress
if: matrix.os != 'macOS-latest' && matrix.python-version != '3.12'
run: python -m pip install xpress
- name: Install gurobipy
run: |
python -m pip install gurobipy
- name: Install highspy
if: matrix.python-version != '3.12'
# alternatively if: contains(fromJSON("['3.8', '3.9', '3.10', '3.11']"), matrix.python-version)
run: uv pip install xpress
- name: Install other solvers, gurobi, highspy, coptpy, saspy, swat, SCIP_PY
run: |
python -m pip install highspy "numpy<2"
uv pip install gurobipy highspy "numpy<2" coptpy saspy swat pyscipopt .
- name: Install highspy cmd
if: matrix.os == 'ubuntu-latest'
uses: supplypike/setup-bin@v4
Expand All @@ -58,17 +49,13 @@ jobs:
subPath: 'bin'
name: 'highs'
version: '1.7.1'
- name: Install coptpy
run: |
python -m pip install coptpy
- name: Install saspy
run: |
python -m pip install saspy
- name: Install swat
run: |
python -m pip install swat
- name: Install SCIP_PY
run: |
python -m pip install pyscipopt
- name: Install SCIP_CMD
if: matrix.os == 'ubuntu-latest'
uses: supplypike/setup-bin@v4
with:
uri: 'https://www.scipopt.org/download/release/SCIPOptSuite-9.2.1-Linux-ubuntu24.deb'
name: 'SCIPOptSuite-9.2.1-Linux-ubuntu24.deb'
version: '9.2.1'
command: "sudo apt install -qq ./SCIPOptSuite-9.2.1-Linux-ubuntu24.deb"
- name: Test with pulptest
run: pulptest
run: uv run --no-project pulp/tests/run_tests.py
9 changes: 5 additions & 4 deletions pulp/apis/scip_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,6 @@ def readsol(filename):
)
values = {}

if status in SCIP_CMD.NO_SOLUTION_STATUSES:
return status, values

# Look for an objective value. If we can't find one, stop.
try:
line = f.readline()
Expand All @@ -211,7 +208,8 @@ def readsol(filename):
assert len(comps) == 2
float(comps[1].strip())
except Exception:
raise PulpSolverError(f"Can't get SCIP solver objective: {line!r}")
# we assume there was not solution found
return status, values

# Parse the variable values.
for line in f:
Expand All @@ -221,6 +219,9 @@ def readsol(filename):
except:
raise PulpSolverError(f"Can't read SCIP solver output: {line!r}")

# if we have a solution, we should change status to Optimal by conventio
status = constants.LpStatusOptimal

return status, values


Expand Down
13 changes: 9 additions & 4 deletions pulp/tests/test_pulp.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,13 @@ def test_unbounded(self):
elif self.solver.__class__ is GLPK_CMD:
# GLPK_CMD Does not report unbounded problems, correctly
pulpTestCheck(prob, self.solver, [const.LpStatusUndefined])
elif self.solver.__class__ in [GUROBI_CMD, SCIP_CMD, FSCIP_CMD, SCIP_PY]:
elif self.solver.__class__ in [GUROBI_CMD, SCIP_CMD, SCIP_PY]:
# GUROBI_CMD has a very simple interface
pulpTestCheck(prob, self.solver, [const.LpStatusNotSolved])
elif self.solver.__class__ in [CHOCO_CMD, HiGHS_CMD]:
elif self.solver.__class__ in [CHOCO_CMD, HiGHS_CMD, FSCIP_CMD]:
# choco bounds all variables. Would not return unbounded status
# highs_cmd is inconsistent
# FSCIP_CMD is inconsistent
pass
else:
pulpTestCheck(prob, self.solver, [const.LpStatusUnbounded])
Expand Down Expand Up @@ -850,10 +851,11 @@ def test_elastic_constraints_penalty_unbounded(self):
elif self.solver.__class__ is GLPK_CMD:
# GLPK_CMD Does not report unbounded problems, correctly
pulpTestCheck(prob, self.solver, [const.LpStatusUndefined])
elif self.solver.__class__ in [GUROBI_CMD, FSCIP_CMD]:
elif self.solver.__class__ in [GUROBI_CMD, SCIP_CMD]:
pulpTestCheck(prob, self.solver, [const.LpStatusNotSolved])
elif self.solver.__class__ in [CHOCO_CMD]:
elif self.solver.__class__ in [CHOCO_CMD, FSCIP_CMD]:
# choco bounds all variables. Would not return unbounded status
# FSCIP_CMD returns optimal
pass
else:
pulpTestCheck(prob, self.solver, [const.LpStatusUnbounded])
Expand Down Expand Up @@ -1292,6 +1294,7 @@ def test_measuring_solving_time(self):
solver_settings = dict(
PULP_CBC_CMD=30,
COIN_CMD=30,
SCIP_PY=30,
SCIP_CMD=30,
GUROBI_CMD=50,
CPLEX_CMD=50,
Expand Down Expand Up @@ -1352,6 +1355,8 @@ def test_invalid_var_names(self):
prob += w >= 0, "c4"
if self.solver.name not in [
"GUROBI_CMD", # end is a key-word for LP files
"SCIP_CMD", # not sure why it returns a wrong result
"FSCIP_CMD", # not sure why it returns a wrong result
]:
pulpTestCheck(
prob,
Expand Down
Loading