Skip to content

Commit 81c61b0

Browse files
committed
Special-case NW-PFSP for CP Optimizer (permutation constraints)
1 parent dc06b33 commit 81c61b0

3 files changed

Lines changed: 24 additions & 11 deletions

File tree

benchmark.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from functools import partial
44
from multiprocessing import cpu_count
55
from pathlib import Path
6-
from typing import Optional
76

87
import numpy as np
98
import tomli
@@ -115,10 +114,10 @@ def _solve(
115114
time_limit: float,
116115
display: bool,
117116
num_workers_per_instance: int,
118-
config_loc: Optional[Path],
119-
sol_dir: Optional[Path],
117+
config_loc: Path | None,
118+
sol_dir: Path | None,
120119
permutation_max_jobs: int,
121-
) -> Optional[tuple[str, str, float, float, float]]:
120+
) -> tuple[str, str, float, float, float] | None:
122121
"""
123122
Solves a single problem instance.
124123
"""
@@ -128,11 +127,12 @@ def _solve(
128127
else:
129128
params = {}
130129

131-
data = read(instance_loc, problem_variant)
132-
if data.constraints.same_sequence:
130+
data = read(instance_loc, problem_variant, solver)
131+
if data.constraints.same_sequence and problem_variant != ProblemVariant.NW_PFSP:
133132
# For permutation problems we skip instances that are too large.
134133
# We have to recompute the number of jobs because we no longer
135134
# create jobs if they are not relevant to the problem.
135+
# NW-PFSP is exempt: it is solved at all sizes regardless of solver.
136136
num_factories = data.num_modes // data.num_tasks
137137
num_stages = data.num_machines // num_factories
138138
num_jobs = data.num_tasks // num_stages
@@ -161,7 +161,7 @@ def _solve(
161161

162162

163163
def _check_cpu_usage(
164-
num_parallel_instances: int, num_workers_per_instance: Optional[int]
164+
num_parallel_instances: int, num_workers_per_instance: int | None
165165
):
166166
"""
167167
Warns if the number of workers per instance times the number of parallel

read/machine.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,16 @@ def parse_osp(cls, loc: Path):
211211
return instance
212212

213213
@classmethod
214-
def parse_nw_pfsp(cls, loc: Path):
214+
def parse_nw_pfsp(cls, loc: Path, solver: str | None = None):
215215
instance = cls.parse_npfsp(loc)
216216
instance.no_wait = True
217-
# TODO might add permutation here for CP Optimizer?
217+
218+
if solver == "cpoptimizer":
219+
# For NW-PFSP, only CP Optimizer benefits from explicit permutation
220+
# constraints. For OR-Tools the no-wait constraints already pin the
221+
# sequence, so adding them only slows it down.
222+
instance.permutation = list(pairwise(range(instance.num_machines)))
223+
218224
return instance
219225

220226
@classmethod

read/read.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,23 @@
66
from pyjobshop import ProblemData, read as _read
77

88

9-
def read(loc: Path, problem: ProblemVariant) -> ProblemData:
9+
def read(
10+
loc: Path, problem: ProblemVariant, solver: str | None = None
11+
) -> ProblemData:
1012
"""
1113
Reads a problem instance from file and returns a ProblemData instance.
14+
15+
The ``solver`` argument is passed to the parsers to apply solver-specific
16+
modeling choices (e.g. the NW-PFSP permutation constraints).
1217
"""
1318
machine_variants = {
1419
ProblemVariant.JSP: MachineInstance.parse_jsp,
1520
ProblemVariant.FJSP: MachineInstance.parse_fjsp,
1621
ProblemVariant.HFSP: MachineInstance.parse_hfsp,
1722
ProblemVariant.NPFSP: MachineInstance.parse_npfsp,
18-
ProblemVariant.NW_PFSP: MachineInstance.parse_nw_pfsp,
23+
ProblemVariant.NW_PFSP: partial(
24+
MachineInstance.parse_nw_pfsp, solver=solver
25+
),
1926
ProblemVariant.PMP: MachineInstance.parse_pmp,
2027
ProblemVariant.OSP: MachineInstance.parse_osp,
2128
# Permutation machine scheduling

0 commit comments

Comments
 (0)