Skip to content

Commit

Permalink
Test python 3.12
Browse files Browse the repository at this point in the history
- Enforce cffi>=1.17 (updated for python 3.12, avoid weird errors for
  dependencies relying on C code)
- Update time limits to avoid errors with ubuntu + python 12:
  It seems ortools gets slower in its latest release 9.11 on ubuntu...
- Fix LP_MRCPSP_GUROBI for python 3.12:
  we have a crash when using gurobi.Model.addConstrs with a
  quicksum on a list rather than on a generator.
  In other words, we need to get rid of [].
  See https://support.gurobi.com/hc/en-us/community/posts/28192464443281-model-addConstrs-breaking-sometimes-after-Python-version-change
  for more details.
- Add a test dedicated to LP_MRCPSP_GUROBI.
  • Loading branch information
nhuet committed Sep 19, 2024
1 parent e78275b commit f87ece9
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 17 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ jobs:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-12", "macos-latest", "windows-latest"]
python-version: ["3.8", "3.11"]
python-version: ["3.8", "3.12"]
wo_gurobi: ["", "without gurobi"]
include:
- os: "ubuntu-latest"
Expand Down Expand Up @@ -124,7 +124,7 @@ jobs:
- coverage: false # generally no coverage to avoid multiple reports
- coverage: true # coverage only for one entry of the matrix
os: "ubuntu-latest"
python-version: "3.11"
python-version: "3.12"
wo_gurobi: ""
exclude:
- os: "windows-latest"
Expand All @@ -139,7 +139,7 @@ jobs:
- os: "macos-latest"
python-version: "3.8"
- os: "macos-12"
python-version: "3.11"
python-version: "3.12"
runs-on: ${{ matrix.os }}
defaults:
run:
Expand All @@ -162,7 +162,7 @@ jobs:
run: |
python -m pip install -U pip
wheelfile=$(ls ./dist/discrete_optimization*.whl)
pip install ${wheelfile}
pip install ${wheelfile} "cffi>=1.17"
- name: Check import work without minizinc if DO_SKIP_MZN_CHECK set
run: |
export DO_SKIP_MZN_CHECK=1
Expand Down
14 changes: 5 additions & 9 deletions discrete_optimization/rcpsp/solver/rcpsp_lp_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,10 +728,8 @@ def init_model(self, **args):
for j in variable_per_task
)
self.model.addConstrs(
gurobi.quicksum(
[key[2] * self.x[key] for key in variable_per_task[s]]
+ [-key[2] * self.x[key] for key in variable_per_task[j]]
)
gurobi.quicksum(key[2] * self.x[key] for key in variable_per_task[s])
- gurobi.quicksum(key[2] * self.x[key] for key in variable_per_task[j])
>= durations[j]
for (j, s) in S
)
Expand Down Expand Up @@ -781,11 +779,9 @@ def init_model(self, **args):
if p_s.start_times is not None:
constraints = self.model.addConstrs(
gurobi.quicksum(
[
self.x[k]
for k in self.variable_per_task[task]
if k[2] == p_s.start_times[task]
]
self.x[k]
for k in self.variable_per_task[task]
if k[2] == p_s.start_times[task]
)
== 1
for task in p_s.start_times
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development",
"Topic :: Scientific/Engineering",
]
Expand Down
8 changes: 4 additions & 4 deletions tests/pickup_vrp/solvers/test_ortools_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def test_ortools_with_cb(random_seed):
parameters_cost=[ParametersCost(dimension_name="Distance", global_span=True)],
local_search_metaheuristic=LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH,
first_solution_strategy=first_solution_strategy,
time_limit=5,
time_limit=10,
use_cp=use_cp,
use_lns=use_lns,
use_cp_sat=use_cp_sat,
Expand All @@ -105,7 +105,7 @@ def test_ortools_with_cb(random_seed):
assert isinstance(fit, float)
assert isinstance(sol, GPDPSolution)
assert nb_iteration_tracker.nb_iteration > 0
assert (end_time - start_time).total_seconds() < 5
assert (end_time - start_time).total_seconds() < 10


def test_ortools_with_warm_start(random_seed):
Expand Down Expand Up @@ -142,7 +142,7 @@ def test_ortools_with_warm_start(random_seed):
parameters_cost=[ParametersCost(dimension_name="Distance", global_span=True)],
local_search_metaheuristic=LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH,
first_solution_strategy=first_solution_strategy,
time_limit=5,
time_limit=10,
use_cp=use_cp,
use_lns=use_lns,
use_cp_sat=use_cp_sat,
Expand Down Expand Up @@ -173,7 +173,7 @@ def test_ortools_with_warm_start(random_seed):
parameters_cost=[ParametersCost(dimension_name="Distance", global_span=True)],
local_search_metaheuristic=LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH,
first_solution_strategy=first_solution_strategy,
time_limit=5,
time_limit=10,
use_cp=use_cp,
use_lns=use_lns,
use_cp_sat=use_cp_sat,
Expand Down
51 changes: 51 additions & 0 deletions tests/rcpsp/solver/test_rcpsp_gurobi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright (c) 2022 AIRBUS and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

import pytest

from discrete_optimization.generic_tools.cp_tools import ParametersCP
from discrete_optimization.rcpsp.rcpsp_parser import get_data_available, parse_file
from discrete_optimization.rcpsp.solver.cpsat_solver import CPSatRCPSPSolver
from discrete_optimization.rcpsp.solver.rcpsp_lp_solver import LP_MRCPSP_GUROBI

try:
import gurobipy
except ImportError:
gurobi_available = False
else:
gurobi_available = True


@pytest.mark.skipif(not gurobi_available, reason="You need Gurobi to test this solver.")
@pytest.mark.parametrize(
"model",
["j301_1.sm", "j1010_1.mm"],
)
def test_gurobi(model):
files_available = get_data_available()
file = [f for f in files_available if model in f][0]
rcpsp_problem = parse_file(file)
solver = LP_MRCPSP_GUROBI(problem=rcpsp_problem)

result_storage = solver.solve()

# test warm start
parameters_cp = ParametersCP.default()
parameters_cp.time_limit = 20
start_solution = (
CPSatRCPSPSolver(problem=rcpsp_problem)
.solve(parameters_cp=parameters_cp)
.get_best_solution_fit()[0]
)

# first solution is not start_solution
assert result_storage[0][0].rcpsp_schedule != start_solution.rcpsp_schedule

# warm start at first solution
solver = LP_MRCPSP_GUROBI(problem=rcpsp_problem)
solver.init_model()
solver.set_warm_start(start_solution)
# force first solution to be the hinted one
result_storage = solver.solve()
assert result_storage[0][0].rcpsp_schedule == start_solution.rcpsp_schedule
File renamed without changes.

0 comments on commit f87ece9

Please sign in to comment.