PyJobShop

class Model

A simple modeling interface for building a scheduling problem step-by-step.

Methods

add_job

Adds a job to the model.

add_machine

Adds a machine to the model.

add_renewable

Adds a renewable resource to the model.

add_consumable

Adds a consumable resource to the model.

add_task

Adds a task to the model.

add_mode

Adds a processing mode to the model.

add_start_before_start

Adds a constraint that task 1 must start before task 2 starts, with an optional delay.

add_start_before_end

Adds a constraint that task 1 must start before task 2 ends, with an optional delay.

add_end_before_start

Adds a constraint that task 1 must end before task 2 starts, with an optional delay.

add_end_before_end

Adds a constraint that task 1 must end before task 2 ends, with an optional delay.

add_start_at_start

Adds a constraint that task 2 must start exactly at the start of task 1 plus the delay.

add_start_at_end

Adds a constraint that task 2 must end exactly at the start of task 1 plus the delay.

add_end_at_start

Adds a constraint that task 2 must start exactly at the end of task 1 plus the delay.

add_end_at_end

Adds a constraint that task 2 must end exactly at the end of task 1 plus the delay.

add_identical_resources

Adds a constraint that two tasks must be scheduled with modes that require identical resources.

add_different_resources

Adds a constraint that the two tasks must be scheduled with modes that require different resources.

add_consecutive

Adds a constraint that the first task must be scheduled right before the second task, meaning that no task is allowed to be scheduled between, on machines that they are both scheduled on.

add_same_sequence

Adds a constraint that requires the two machines to schedule its tasks in the same sequence.

add_setup_time

Adds a setup time between two tasks on a machine.

add_mode_dependency

Adds a mode dependency between one mode and a list of modes, meaning that if the first mode has been selected, one out of the list of modes must be selected.

add_select_all_or_none

Adds a constraint that all tasks from the given list are selected, or none are.

add_select_at_least_one

Adds a constraint that at least one task from the given list is selected.

add_select_exactly_one

Adds a constraint that exactly one task from the given list is selected.

set_objective

Sets the objective function in this model.

summary

Returns a summary of the model, which is the string representation of the ProblemData instance created by the model.

from_data

Creates a Model instance from a ProblemData instance.

data

Returns a ProblemData object containing the problem instance.

solve

Solves the problem data instance created by the model.

property jobs : list[Job]

Returns the list of jobs in the model.

property resources : list[Machine | Renewable | Consumable]

Returns the list of resources in the model.

property tasks : list[Task]

Returns the list of tasks in the model.

property modes : list[Mode]

Returns the list of modes in the model.

property constraints : Constraints

Returns the constraints in this model.

property objective : Objective

Returns the objective function in this model.

add_job(weight: int = 1, release_date: int = 0, deadline: int = MAX_VALUE, due_date: int | None = None, *, name: str = '') Job

Adds a job to the model.

add_machine(breaks: list[tuple[int, int]] | None = None, no_idle: bool = False, *, name: str = '') Machine

Adds a machine to the model.

add_renewable(capacity: int, breaks: list[tuple[int, int]] | None = None, *, name: str = '') Renewable

Adds a renewable resource to the model.

add_consumable(capacity: int, breaks: list[tuple[int, int]] | None = None, *, name: str = '') Consumable

Adds a consumable resource to the model.

add_task(job: Job | None = None, earliest_start: int = 0, latest_start: int = MAX_VALUE, earliest_end: int = 0, latest_end: int = MAX_VALUE, allow_idle: bool = False, allow_breaks: bool = False, optional: bool = False, *, name: str = '') Task

Adds a task to the model.

add_mode(task: Task, resources: Machine | Renewable | Consumable | list[Machine | Renewable | Consumable], duration: int, demands: int | list[int] | None = None, *, name: str = '') Mode

Adds a processing mode to the model.

add_start_before_start(task1: Task, task2: Task, delay: int = 0) StartBeforeStart

Adds a constraint that task 1 must start before task 2 starts, with an optional delay.

add_start_before_end(task1: Task, task2: Task, delay: int = 0) StartBeforeEnd

Adds a constraint that task 1 must start before task 2 ends, with an optional delay.

add_end_before_start(task1: Task, task2: Task, delay: int = 0) EndBeforeStart

Adds a constraint that task 1 must end before task 2 starts, with an optional delay.

add_end_before_end(task1: Task, task2: Task, delay: int = 0) EndBeforeEnd

Adds a constraint that task 1 must end before task 2 ends, with an optional delay.

add_start_at_start(task1: Task, task2: Task, delay: int = 0) StartAtStart

Adds a constraint that task 2 must start exactly at the start of task 1 plus the delay.

add_start_at_end(task1: Task, task2: Task, delay: int = 0) StartAtEnd

Adds a constraint that task 2 must end exactly at the start of task 1 plus the delay.

add_end_at_start(task1: Task, task2: Task, delay: int = 0) EndAtStart

Adds a constraint that task 2 must start exactly at the end of task 1 plus the delay.

add_end_at_end(task1: Task, task2: Task, delay: int = 0) EndAtEnd

Adds a constraint that task 2 must end exactly at the end of task 1 plus the delay.

add_identical_resources(task1: Task, task2: Task) IdenticalResources

Adds a constraint that two tasks must be scheduled with modes that require identical resources.

add_different_resources(task1: Task, task2: Task) DifferentResources

Adds a constraint that the two tasks must be scheduled with modes that require different resources.

add_consecutive(task1: Task, task2: Task) Consecutive

Adds a constraint that the first task must be scheduled right before the second task, meaning that no task is allowed to be scheduled between, on machines that they are both scheduled on.

add_same_sequence(machine1: Machine, machine2: Machine, tasks1: list[Task] | None = None, tasks2: list[Task] | None = None) SameSequence

Adds a constraint that requires the two machines to schedule its tasks in the same sequence.

add_setup_time(machine: Machine, task1: Task, task2: Task, duration: int) SetupTime

Adds a setup time between two tasks on a machine.

add_mode_dependency(mode1: Mode, modes2: list[Mode]) ModeDependency

Adds a mode dependency between one mode and a list of modes, meaning that if the first mode has been selected, one out of the list of modes must be selected.

add_select_all_or_none(tasks: list[Task], condition_task: Task | None = None) SelectAllOrNone

Adds a constraint that all tasks from the given list are selected, or none are. If condition_task is provided, this rule only applies when that task is selected.

add_select_at_least_one(tasks: list[Task], condition_task: Task | None = None) SelectAtLeastOne

Adds a constraint that at least one task from the given list is selected. If condition_task is provided, this rule only applies when that task is selected.

add_select_exactly_one(tasks: list[Task], condition_task: Task | None = None) SelectExactlyOne

Adds a constraint that exactly one task from the given list is selected. If condition_task is provided, this rule only applies when that task is selected.

set_objective(weight_makespan: int = 0, weight_tardy_jobs: int = 0, weight_total_tardiness: int = 0, weight_total_flow_time: int = 0, weight_total_earliness: int = 0, weight_max_tardiness: int = 0, weight_total_setup_time: int = 0) Objective

Sets the objective function in this model.

summary() str

Returns a summary of the model, which is the string representation of the ProblemData instance created by the model.

classmethod from_data(data: ProblemData)

Creates a Model instance from a ProblemData instance.

data() ProblemData

Returns a ProblemData object containing the problem instance.

solve(solver: 'ortools' | 'cpoptimizer' = 'ortools', time_limit: float = float('inf'), display: bool = True, num_workers: int | None = None, initial_solution: Solution | None = None, **kwargs) Result

Solves the problem data instance created by the model.

Parameters:
solver: 'ortools' | 'cpoptimizer' = 'ortools'

The solver to use. Either 'ortools' (default) or 'cpoptimizer'.

time_limit: float = float('inf')

The time limit for the solver in seconds. Default float('inf').

display: bool = True

Whether to display the solver output. Default True.

num_workers: int | None = None

The number of workers to use for parallel solving. If not specified, the default of the selected solver is used, which is typically the number of available CPU cores.

initial_solution: Solution | None = None

An initial solution to start the solver from. Default is no solution.

**kwargs

Additional parameters passed to the solver.

Returns:

A Result object containing the best found solution and additional information about the solver run.

Return type:

Result

class ProblemData(jobs: list[Job], resources: list[Machine | Renewable | Consumable], tasks: list[Task], modes: list[Mode], constraints: Constraints = Constraints(), objective: Objective = Objective(weight_makespan=1))

Class that contains all data needed to solve the scheduling problem.

Parameters:
jobs: list[Job]

List of jobs.

resources: list[Machine | Renewable | Consumable]

List of resources.

tasks: list[Task]

List of tasks.

modes: list[Mode]

List of processing modes of tasks.

constraints: Constraints = Constraints()

The constraints of this problem data instance.

objective: Objective = Objective(weight_makespan=1)

The objective function. Default is minimizing the makespan.

jobs

List of jobs.

resources

List of resources.

tasks

List of tasks.

modes

List of processing modes of tasks.

constraints

The constraints of this problem data instance.

objective

The objective function. Default is minimizing the makespan.

replace(jobs: list[Job] | None = None, resources: list[Machine | Renewable | Consumable] | None = None, tasks: list[Task] | None = None, modes: list[Mode] | None = None, constraints: Constraints | None = None, objective: Objective | None = None) ProblemData

Returns a new ProblemData instance with possibly replaced data. If a parameter is not provided, the original data is deepcopied instead.

Parameters:
jobs: list[Job] | None = None

Optional list of jobs.

resources: list[Machine | Renewable | Consumable] | None = None

Optional list of resources.

tasks: list[Task] | None = None

Optional list of tasks.

modes: list[Mode] | None = None

Optional processing modes of tasks.

constraints: Constraints | None = None

Optional constraints.

objective: Objective | None = None

Optional objective function.

Returns:

A new ProblemData instance with possibly replaced data.

Return type:

ProblemData

property num_jobs : int

Returns the number of jobs in this instance.

property num_resources : int

Returns the number of resources in this instance.

property num_machines : int

Returns the number of machines in this instance.

property num_renewables : int

Returns the number of renewable resources in this instance.

property num_consumables : int

Returns the number of consumable resources in this instance.

property num_tasks : int

Returns the number of tasks in this instance.

property num_modes : int

Returns the number of modes in this instance.

property num_constraints : int

Returns the number of constraints in this instance.

property machine_idcs : list[int]

Returns the list of resource indices corresponding to machines.

property renewable_idcs : list[int]

Returns the list of resource indices corresponding to renewable resources.

property consumable_idcs : list[int]

Returns the list of resource indices corresponding to consumable resources.

task2modes(task: int) list[int]

Returns the list of mode indices corresponding to the given task.

Parameters:
task: int

The task index.

Returns:

The list of mode indices for the given task.

Return type:

list[int]

resource2modes(resource: int) list[int]

Returns the list of mode indices corresponding to the given resource.

Parameters:
resource: int

The resource index.

Returns:

The list of mode indices for the given resource.

Return type:

list[int]

task2resources(task: int) list[int]

Returns the resource indices that the given task can use.

Parameters:
task: int

The task index.

Returns:

The list of resource indices for the given task.

Return type:

list[int]

to_json(indent: int | str | None = 2, **kwargs) str

Serializes this ProblemData instance to a JSON string.

Parameters:
indent: int | str | None = 2

If indent is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines. None is the most compact representation. Default is 2.

**kwargs

Additional keyword arguments passed to json.dumps().

Returns:

JSON representation of this problem data instance.

Return type:

str

classmethod from_json(json_str: str, **kwargs) ProblemData

Deserializes a ProblemData instance from a JSON string.

Parameters:
json_str: str

The JSON string to deserialize.

**kwargs

Additional keyword arguments passed to json.loads().

Returns:

The deserialized ProblemData instance.

Return type:

ProblemData

class Job(weight: int = 1, release_date: int = 0, deadline: int = 4398046511104, due_date: int | None = None, tasks: list[int] = [], *, name: str = '')

Simple dataclass for storing job-related data.

Parameters:
weight: int = 1

The weight of the job, used as multiplicative factor in the objective function. Must be non-negative.

release_date: int = 0

The earliest time that the job may start. Must be non-negative.

deadline: int = 4398046511104

The latest time by which the job must be completed. Note that a deadline is different from a due date; the latter does not restrict the latest completion time.

due_date: int | None = None

The latest time that the job should be completed before incurring penalties. Can be negative to represent past due dates. Default is None, meaning there is no due date.

tasks: list[int] = []

List of task indices that belong to this job. Default is an empty list.

name: str = ''

Name of the job.

Raises:

ValueError – If the release date is greater than the deadline.

weight

The weight of the job, used as multiplicative factor in the objective function. Must be non-negative.

release_date

The earliest time that the job may start. Must be non-negative.

deadline

The latest time by which the job must be completed. Note that a deadline is different from a due date; the latter does not restrict the latest completion time.

due_date

The latest time that the job should be completed before incurring penalties. Can be negative to represent past due dates. Default is None, meaning there is no due date.

tasks

List of task indices that belong to this job. Default is an empty list.

name

Name of the job.

add_task(idx: int)

Adds a task index to the job.

Parameters:
idx: int

Task index to add.

class Machine(breaks: list[tuple[int, int]] = [], no_idle: bool = False, *, name: str = '')

A resource that processes tasks only one at a time and can enforce sequencing constraints.

Parameters:
breaks: list[tuple[int, int]] = []

List of time intervals during which tasks cannot be processed. Each break is represented as a tuple (start, end), where start must be non-negative and start must be smaller than end. Default is no breaks.

no_idle: bool = False

Whether the machine must operate continuously without idle time between tasks. When True, tasks are scheduled back-to-back with no gaps, except for required setup times. When False (default), the machine can remain idle between tasks. Cannot be combined with breaks.

name: str = ''

Name of the machine.

Raises:

ValueError – When breaks are specified and no_idle=True.

breaks

List of time intervals during which tasks cannot be processed. Each break is represented as a tuple (start, end), where start must be non-negative and start must be smaller than end. Default is no breaks.

no_idle

Whether the machine must operate continuously without idle time between tasks. When True, tasks are scheduled back-to-back with no gaps, except for required setup times. When False (default), the machine can remain idle between tasks. Cannot be combined with breaks.

name

Name of the machine.

class Renewable(capacity: int, breaks: list[tuple[int, int]] = [], *, name: str = '')

A resource that replenishes its capacity after each task completion.

Parameters:
capacity: int

Capacity of the resource. Must be non-negative.

breaks: list[tuple[int, int]] = []

List of time intervals during which tasks cannot be processed. Each break is represented as a tuple (start, end), where start must be non-negative and start must be smaller than end. Default is no breaks.

name: str = ''

Name of the resource.

capacity

Capacity of the resource. Must be non-negative.

breaks

List of time intervals during which tasks cannot be processed. Each break is represented as a tuple (start, end), where start must be non-negative and start must be smaller than end. Default is no breaks.

name

Name of the resource.

class Consumable(capacity: int, breaks: list[tuple[int, int]] = [], *, name: str = '')

A resource with finite capacity that is permanently consumed by tasks. Unlike renewable resources, consumed capacity is never replenished during the scheduling horizon.

Parameters:
capacity: int

Capacity of the resource. Must be non-negative.

breaks: list[tuple[int, int]] = []

List of time intervals during which tasks cannot be processed. Each break is represented as a tuple (start, end), where start must be non-negative and start must be smaller than end. Default is no breaks.

name: str = ''

Name of the resource.

capacity

Capacity of the resource. Must be non-negative.

breaks

List of time intervals during which tasks cannot be processed. Each break is represented as a tuple (start, end), where start must be non-negative and start must be smaller than end. Default is no breaks.

name

Name of the resource.

class Task(job: int | None = None, earliest_start: int = 0, latest_start: int = 4398046511104, earliest_end: int = 0, latest_end: int = 4398046511104, allow_idle: bool = False, allow_breaks: bool = False, optional: bool = False, *, name: str = '')

Simple dataclass for storing task-related data.

Parameters:
job: int | None = None

The index of the job that this task belongs to, None if the task does not belong to any job.

earliest_start: int = 0

Earliest start time of the task.

latest_start: int = 4398046511104

Latest start time of the task.

earliest_end: int = 0

Earliest end time of the task.

latest_end: int = 4398046511104

Latest end time of the task.

allow_idle: bool = False

Whether the task can remain idle after completing its processing. If True, the task can continue occupying resources after finishing (e.g., blocking in flow shops).

allow_breaks: bool = False

Whether the task can be interrupted by resource breaks. If True, the task stops processing during breaks and resumes afterwards.

optional: bool = False

Whether the task is optional.

name: str = ''

Name of the task.

job

The index of the job that this task belongs to, None if the task does not belong to any job.

earliest_start

Earliest start time of the task.

latest_start

Latest start time of the task.

earliest_end

Earliest end time of the task.

latest_end

Latest end time of the task.

allow_idle

Whether the task can remain idle after completing its processing. If True, the task can continue occupying resources after finishing (e.g., blocking in flow shops).

allow_breaks

Whether the task can be interrupted by resource breaks. If True, the task stops processing during breaks and resumes afterwards.

optional

Whether the task is optional.

name

Name of the task.

class Mode(task: int, resources: list[int], duration: int, demands: list[int] = [], *, name: str = '')

Simple dataclass for storing processing mode data.

Parameters:
task: int

Task index that this mode belongs to.

resources: list[int]

List of unique resources that are required for this mode.

duration: int

Processing duration of this mode. Must be non-negative.

demands: list[int] = []

List of demands for each resource for this mode. Demands must be non-negative. By default, the demands are initialized as a list of zeros with the same length as the resources.

name: str = ''

Name of the mode.

Raises:

ValueError – If the length of resources and demands do not match.

task

Task index that this mode belongs to.

resources

List of unique resources that are required for this mode.

duration

Processing duration of this mode. Must be non-negative.

demands

List of demands for each resource for this mode. Demands must be non-negative. By default, the demands are initialized as a list of zeros with the same length as the resources.

name

Name of the mode.

class StartBeforeStart(task1: int, task2: int, delay: int = 0)

Start task 1 (\(s_1\)) before task 2 starts (\(s_2\)), with an optional delay \(d\). That is,

\[s_1 + d \leq s_2.\]
class StartBeforeEnd(task1: int, task2: int, delay: int = 0)

Start task 1 (\(s_1\)) before task 2 ends (\(e_2\)), with an optional delay \(d\). That is,

\[s_1 + d \leq e_2.\]
class EndBeforeStart(task1: int, task2: int, delay: int = 0)

End task 1 (\(e_1\)) before task 2 starts (\(s_2\)), with an optional delay \(d\). That is,

\[e_1 + d \leq s_2.\]
class EndBeforeEnd(task1: int, task2: int, delay: int = 0)

End task 1 (\(e_1\)) before task 2 ends (\(e_2\)), with an optional delay \(d\). That is,

\[e_1 + d \leq e_2.\]
class StartAtStart(task1: int, task2: int, delay: int = 0)

Start task 1 (\(s_1\)) at the start of task 2 (\(s_2\)), with an optional delay \(d\). That is,

\[s_1 + d = s_2.\]
class StartAtEnd(task1: int, task2: int, delay: int = 0)

Start task 1 (\(s_1\)) at the end of task 2 (\(e_2\)), with an optional delay \(d\). That is,

\[s_1 + d = e_2.\]
class EndAtStart(task1: int, task2: int, delay: int = 0)

End task 1 (\(e_1\)) at the start of task 2 (\(s_2\)), with an optional delay \(d\). That is,

\[e_1 + d = s_2.\]
class EndAtEnd(task1: int, task2: int, delay: int = 0)

End task 1 (\(e_1\)) at the end of task 2 (\(e_2\)), with an optional delay \(d\). That is,

\[e_1 + d = e_2.\]
class IdenticalResources(task1: int, task2: int)

Select modes for task 1 and task 2 that use the same resources.

Let \(m_1, m_2\) be the selected modes of task 1 and task 2, and let \(R_m\) denote the resources required by mode \(m\). This constraint ensures that

\[R_{m_1} = R_{m_2}.\]
class DifferentResources(task1: int, task2: int)

Select modes for task 1 and task 2 that use different resources.

Let \(m_1, m_2\) be the selected modes of task 1 and task 2, and let \(R_m\) denote the resources required by mode \(m\). This constraint ensures that

\[R_{m_1} \cap R_{m_2} = \emptyset.\]
class Consecutive(task1: int, task2: int)

Sequence task 1 and task 2 consecutively on the machines they are both assigned to, meaning that no other task is allowed to be scheduled between them.

Hand-waving some details, let \(m_1, m_2\) be the selected modes of task 1 and task 2, and let \(R\) denote the machines that both modes require. This constraint ensures that

\[m_1 \to m_2 \quad \forall r \in R,\]

where \(\to\) means that \(m_1\) is directly followed by \(m_2\) and no other interval is scheduled between them.

class SameSequence(machine1: int, machine2: int, tasks1: list[int] | None = None, tasks2: list[int] | None = None)

Ensures that two machines process their assigned tasks in the same relative order. Both machines must have the same number of assigned tasks for this constraint to be valid.

When tasks1 and tasks2 are not specified, the constraint applies to all tasks assigned to each machine, with ordering determined by their task indices in ascending order. For explicit control over the task sequence, use the tasks1 and tasks2 parameters.

Example

Assume that machine 1 can process tasks [1, 3] and machine 2 can process tasks [2, 4]. The default (by task indices) allows the following valid sequences:

  • (1→3, 2→4) or (3→1, 4→2)

If passing arguments tasks1=[1, 3] and tasks2=[4, 2], then the following sequences are valid:

  • (1→3, 4→2) or (3→1, 2→4)

class SetupTime(machine: int, task1: int, task2: int, duration: int)

Sequence-dependent setup time between task 1 and task 2 on the given machine.

Let \(e_1\) be the end time of task 1 and let \(s_2\) be the start time of task 2. If the selected modes of task 1 and task 2 both require the given machine, then this constraint ensures that

\[e_1 + d \leq s_2,\]

where \(d\) is the setup time duration. Note that this also implies an end-before-start relationship between task 1 and task 2.

When using Machine.breaks, setup times are allowed to take place during the breaks.

class ModeDependency(mode1: int, modes2: list[int])

Represents a dependency between task modes: if mode 1 is selected, then at least one of the modes in modes2 must also be selected.

Let \(m_1\) be the Boolean variable indicating whether mode 1 is selected. Let \(M_2\) be the set of Boolean variables corresponding to the modes in modes2.

The constraint is then expressed as:

\[m_1 \leq \sum_{m \in M_2} m\]
class SelectAllOrNone(tasks: list[int], condition_task: int | None = None)

Enforces that all tasks from the given list are selected, or none are.

If condition_task is provided, this rule only applies when that task is selected; otherwise, it has no effect.

class SelectAtLeastOne(tasks: list[int], condition_task: int | None = None)

Enforces that at least one task from the given list is selected.

If condition_task is provided, this rule only applies when that task is selected; otherwise, it has no effect.

class SelectExactlyOne(tasks: list[int], condition_task: int | None = None)

Enforces that exactly one task from the given list is selected.

If condition_task is provided, this rule only applies when that task is selected; otherwise, it has no effect.

class Constraints(start_before_start: list[StartBeforeStart] = [], start_before_end: list[StartBeforeEnd] = [], end_before_start: list[EndBeforeStart] = [], end_before_end: list[EndBeforeEnd] = [], start_at_start: list[StartAtStart] = [], start_at_end: list[StartAtEnd] = [], end_at_start: list[EndAtStart] = [], end_at_end: list[EndAtEnd] = [], identical_resources: list[IdenticalResources] = [], different_resources: list[DifferentResources] = [], consecutive: list[Consecutive] = [], same_sequence: list[SameSequence] = [], setup_times: list[SetupTime] = [], mode_dependencies: list[ModeDependency] = [], select_all_or_none: list[SelectAllOrNone] = [], select_at_least_one: list[SelectAtLeastOne] = [], select_exactly_one: list[SelectExactlyOne] = [])

Simple container class for storing all constraints.

class Objective(weight_makespan: int = 0, weight_tardy_jobs: int = 0, weight_total_flow_time: int = 0, weight_total_tardiness: int = 0, weight_total_earliness: int = 0, weight_max_tardiness: int = 0, weight_total_setup_time: int = 0)

The objective class represents a weighted sum of objective functions \(f\), calculated as: \(\sum_f \text{weight}_f \cdot \text{value}_f\) with \(\text{weight}_f \ge 0\). The objective functions \(f\) are defined below.

In the following, let \(J\) denote the set of jobs, \(T\) denote the set of tasks, \(C_j\) denote the completion time of job \(j\), and \(C_t\) denote the completion time of task \(t\).

Makespan (\(C_{\max}\)): The finish time of the latest task.
\[C_{\max} = \max_{t \in T} C_t\]
Number of tardy jobs (\(NTJ\)): The weighted sum of all tardy jobs, where a job is tardy when it does not meet its due date \(d_j\).
\[NTJ = \sum_{j \in J} w_j \mathbb{1}_{\{C_j - d_j > 0\}}\]

where \(\mathbb{1}_{\{x\}}\) is the indicator function.

Total flow time (\(TFT\)): The weighted sum of the length of stay in the system of each job, from their release date to their completion.
\[TFT = \sum_{j \in J} w_j ( C_j - r_j )\]
Total tardiness (\(TT\)): The weighted sum of the tardiness of each job, where the tardiness is the difference between completion time and due date \(d_j\) (0 if completed before due date).
\[TT = \sum_{j \in J} w_j \max(C_j - d_j, 0)\]
Total earliness (\(TE\)): The weighted sum of the earliness of each job, where earliness is the difference between due date \(d_j\) and completion time (0 if completed after due date).
\[TE = \sum_{j \in J} w_j (\max(d_j - C_j, 0))\]
Maximum tardiness (\(U_{\max}\)): The weighted maximum tardiness of all jobs.
\[U_{\max} = \max_{j \in J} w_j (\max(C_j - d_j, 0))\]
Total setup time (\(TST\)): The sum of all sequence-dependent setup times between consecutive tasks on each machine, where \(R\) denotes the set of machines, \(M^R_r\) denotes the set of modes requiring \(r \in R\), \(s_{t_u, t_v, r}\) denotes the setup time between tasks \(t_u\) and \(t_v\) on machine \(r\) and \(b_{ruv}\) is the binary variable indicating whether task \(t_u\) is followed by task \(t_v\) on machine \(r\).
\[TST = \sum_{r \in R} \sum_{u, v \in M^R_r} s_{t_u, t_v, r} b_{ruv}\]

Note

Use Job.weight to set a specific job’s weight (\(w_j\)) in the objective function.

class Solution(data: ProblemData, tasks: list[ScheduledTask])

Solution to the scheduling problem.

Parameters:
data: ProblemData

The problem data instance.

tasks: list[ScheduledTask]

The list of ScheduledTask objects, one for each task in the problem, or an empty list if a dummy solution is to be created.

Note

This class does not validate whether the solution is feasible. When instantiated directly, it assumes that the provided task data represent a feasible solution, or an empty solution if no tasks are provided.

property tasks : list[ScheduledTask]

Returns the list of task data.

property jobs : list[ScheduledJob]

Returns the list of job data.

property objective : int

Returns the objective value of this solution.

property makespan : int

Returns the makespan of the solution.

property tardy_jobs : int

Returns the weighted number of tardy jobs.

property total_flow_time : int

Returns the total weighted flow time of all jobs.

property total_tardiness : int

Returns the total weighted tardiness of all jobs.

property total_earliness : int

Returns the total weighted earliness of all jobs.

property max_tardiness : int

Returns the maximum tardiness of all jobs.

property total_setup_time : int

Returns the total setup time of all machines.

class ScheduledTask(mode: int, resources: list[int], start: int, end: int, idle: int = 0, breaks: int = 0, present: bool = True)

Stores scheduling data related to a task.

Parameters:
mode: int

The selected mode.

resources: list[int]

The selected resources.

start: int

The start time.

end: int

The end time.

idle: int = 0

The time that this task is not processing, excluding breaks.

breaks: int = 0

The total time that this task is interrupted by resource breaks.

present: bool = True

Whether the task is present in the solution.

mode

The selected mode.

resources

The selected resources.

start

The start time.

end

The end time.

idle

The time that this task is not processing, excluding breaks.

breaks

The total time that this task is interrupted by resource breaks.

present

Whether the task is present in the solution.

property duration : int

Returns the total duration of the task.

property processing : int

Returns the processing time of the task.

class ScheduledJob(start: int, end: int, release_date: int = 0, due_date: int | None = None, present: bool = True)

Stores scheduling data related to a job.

Parameters:
start: int

The start time of the job.

end: int

The end time of the job.

release_date: int = 0

The release date of the job. Default 0.

due_date: int | None = None

The due date of the job. Default None.

present: bool = True

Whether at least one of the job’s tasks is present in the solution. If False, all job attributes are zero or False. Default True.

start

The start time of the job.

end

The end time of the job.

release_date

The release date of the job. Default 0.

due_date

The due date of the job. Default None.

present

Whether at least one of the job’s tasks is present in the solution. If False, all job attributes are zero or False. Default True.

property duration : int

Returns the total duration of the job.

property flow_time : int

Returns the flow time of the job.

property is_tardy : bool

Returns whether the job is tardy. If the job has no due date, returns False.

property tardiness : int

Returns the tardiness of the job. If the job has no due date, returns 0.

property earliness : int

Returns the earliness of the job. If the job has no due date, returns 0.

class Result(objective: float, lower_bound: float, status: SolveStatus, runtime: float, best: Solution)

Result class that stores information about the solver run.

Parameters:
objective: float

The objective value of the solution. If no feasible solution was found, this is set to float('inf').

lower_bound: float

The lower bound of the objective function. If no feasible solution was found, this is set to 0.

status: SolveStatus

The termination status of the solver run.

runtime: float

The runtime of the solver.

best: Solution

The best found solution. If no feasible solution was found, this is an empty solution.

objective

The objective value of the solution. If no feasible solution was found, this is set to float('inf').

lower_bound

The lower bound of the objective function. If no feasible solution was found, this is set to 0.

status

The termination status of the solver run.

runtime

The runtime of the solver.

best

The best found solution. If no feasible solution was found, this is an empty solution.

class SolveStatus

Enum representing the termination status of the solver run.

OPTIMAL = "Optimal"

Solution is proven optimal.

FEASIBLE = "Feasible"

A feasible solution was found.

INFEASIBLE = "Infeasible"

Problem is proven infeasible.

TIME_LIMIT = "Time-limit"

Solver terminated due to time limit.

UNKNOWN = "Unknown"

Solver terminated with unknown status.

solve(data: ProblemData, solver: 'ortools' | 'cpoptimizer' = 'ortools', time_limit: float = float('inf'), display: bool = False, num_workers: int | None = None, initial_solution: Solution | None = None, **kwargs) Result

Solves the given problem data instance.

Parameters:
data: ProblemData

The problem data instance.

solver: 'ortools' | 'cpoptimizer' = 'ortools'

The solver to use. Either 'ortools' (default) or 'cpoptimizer'.

time_limit: float = float('inf')

The time limit for the solver in seconds. Default float('inf').

display: bool = False

Whether to display the solver output. Default False.

num_workers: int | None = None

The number of workers to use for parallel solving. If not specified, the default of the selected solver is used, which is typically the number of available CPU cores.

initial_solution: Solution | None = None

An initial solution to start the solver from. Default is no solution.

**kwargs

Additional parameters passed to the solver.

Returns:

A Result object containing the best found solution and additional information about the solver run.

Return type:

Result

Raises:

ModuleNotFoundError – If CP Optimizer is chosen but its dependencies are not installed.

MAX_VALUE = 4398046511104

Maximum allowed value, equal to 2^42.

Type:

int