Quick examples

Open In Colab

If you’re using this notebook in Google Colab, be sure to install PyJobShop first by executing pip install pyjobshop in a cell.

This notebook contains a number of quick examples to demonstrate PyJobShop features not contained in the other notebooks.

[1]:
from pyjobshop import Model
from pyjobshop.plot import plot_machine_gantt

Sequence-dependent setup times

Machines may require different configuration settings for processing different types of tasks. This results in sequence-dependent setup times, which is the time that is required to reconfigure machines between processing two tasks. Let’s showcase a small example here.

[2]:
model = Model()
tasks = [model.add_task() for _ in range(6)]
machines = [model.add_machine() for _ in range(2)]

for task in tasks:
    # The first machine is faster than the second machine.
    model.add_mode(task, machines[0], duration=1)
    model.add_mode(task, machines[1], duration=3)

for task1 in tasks:
    for task2 in tasks:
        model.add_setup_time(machines[0], task1, task2, duration=1)
        model.add_setup_time(machines[1], task1, task2, duration=2)
[3]:
result = model.solve(display=False)
print(result)
Solution results
================
  objective: 8.00
lower bound: 8.00
     status: Optimal
    runtime: 0.10 seconds
[4]:
data = model.data()
plot_machine_gantt(result.best, data, plot_labels=True)
../_images/examples_quick_examples_5_0.png

Some notes:

  • Instances with sequence-dependent setup times are generally hard to solve, and it’s even harder to solve to optimality. Consider using a time limit when solving such instances.

  • Unlike CP Optimizer, OR-Tools does not have specialized constraints to deal with sequence-dependent setup times. This makes the implementation of OR-Tools substantially slower.

Finding feasible solutions

In some situations, it may be only needed to find a feasible solution. You can achieve this by passing an additional parameter to the solve function, depending on the solver used:

  • OR-Tools: stop_after_first_solution=True.

  • CP Optimizer: SolutionLimit=1.

Below we demonstrate it with OR-Tools (used by default).

[5]:
model = Model()
tasks = [model.add_task(name=idx) for idx in range(6)]
machines = [model.add_machine(name=idx) for idx in range(2)]

for task in tasks:
    model.add_mode(task, machines[0], duration=1)
    model.add_mode(task, machines[1], duration=3)
[6]:
result = model.solve(display=False, stop_after_first_solution=True)
print(result)
Solution results
================
  objective: 6.00
lower bound: 5.00
     status: Feasible
    runtime: 0.01 seconds

Let’s double-check that the optimal solution is better:

[7]:
result = model.solve(display=False)
print(result)
Solution results
================
  objective: 5.00
lower bound: 5.00
     status: Optimal
    runtime: 0.00 seconds

No-idle machines

Sometimes machines must operate continuously without idle time between tasks. This constraint can be added to machines using the no_idle=True parameter. When enabled, tasks are scheduled back-to-back with no gaps (except for required setup times).

[8]:
model = Model()
machine = model.add_machine(no_idle=True)

task1 = model.add_task(earliest_start=5, name="Task1")
task2 = model.add_task(name="Task2")

model.add_mode(task1, machine, duration=1)
model.add_mode(task2, machine, duration=2)

result = model.solve(display=False)
[9]:
data = model.data()
plot_machine_gantt(result.best, data, plot_labels=True)
../_images/examples_quick_examples_15_0.png

Since task 1 cannot start before time 5, the solver places task 2 at time 3-5 so the machine operates continuously without gaps.

Some notes:

  • No-idle machines cannot have breaks defined (breaks parameter cannot be used with no_idle=True)

  • This constraint is particularly useful for modeling continuous production processes where stopping and restarting the machine is costly

  • The no-idle constraint works with setup times - tasks are still scheduled back-to-back, but setup times are accounted for between tasks.