Job Shop Scheduling Problem (JSSP) Example
Job Shop Scheduling assigns operations of jobs to time slots on machines so that the overall makespan is minimised. It is NP-hard and central to manufacturing and production planning.
import getpass
import os
from dotenv import load_dotenv
from luna_quantum.algorithms import SCIP
from luna_usecases.job_shop_scheduling import (
JsspCollection,
JsspData,
JsspFormulation,
JsspInstance,
)
load_dotenv()
if "LUNA_API_KEY" not in os.environ:
os.environ["LUNA_API_KEY"] = getpass.getpass("Enter your Luna API key: ")
Create Data
Define 3 jobs on 2 machines using the from_jobs() factory method. Each job has an ordered sequence of operations specified as (machine, duration) pairs.
jobs = [
[(0, 3), (1, 2)], # Job 0: machine 0 for 3, then machine 1 for 2
[(1, 4), (0, 1)], # Job 1: machine 1 for 4, then machine 0 for 1
[(0, 2), (1, 3)], # Job 2: machine 0 for 2, then machine 1 for 3
]
data = JsspData.from_jobs(jobs=jobs, n_machines=2, deadline=10)
print(data.to_string())
Plot Data
Visualize job operation sequences.
Create Formulation
Schedule operations to minimize makespan, respecting machine capacity and job ordering.
Job Shop Scheduling Formulation:
Jobs: 3
Machines: 2
Operations: 6
Deadline (horizon): 10
Decision Variables:
s[o] integer for o = 0, ..., 5 (start time of operation o)
y[o1,o2] in {0,1} for each pair on the same machine (ordering indicator)
C_max integer (makespan)
Total: 6 integer + 6 binary + 1 integer = 13 variables
Objective:
minimize C_max
Constraints:
1. Makespan bound (6 constraints):
s[o] + dur[o] <= C_max for all o = 0, ..., 5
2. Precedence within each job (3 constraints):
s[o_next] >= s[o_prev] + dur[o_prev] for consecutive operations in each job
Variable bounds (on s[o]):
ES[o] <= s[o] <= LS[o] (from job precedence time windows)
4. Disjunctive (per-pair Big-M) for same-machine operations (12 constraints):
s[o1] - s[o2] + M_a * y[o1,o2] <= M_a - dur[o1]
s[o2] - s[o1] - M_b * y[o1,o2] <= -dur[o2]
where M_a = LS[o1]+dur[o1]-ES[o2], M_b = LS[o2]+dur[o2]-ES[o1]
Create Instance
Combine data and formulation into a solvable instance.
Data:Job Shop Scheduling Data:
Jobs: 3
Machines: 2
Total operations: 6
Deadline: 10
Formulation:Job Shop Scheduling Formulation:
Jobs: 3
Machines: 2
Operations: 6
Deadline (horizon): 10
Decision Variables:
s[o] integer for o = 0, ..., 5 (start time of operation o)
y[o1,o2] in {0,1} for each pair on the same machine (ordering indicator)
C_max integer (makespan)
Total: 6 integer + 6 binary + 1 integer = 13 variables
Objective:
minimize C_max
Constraints:
1. Makespan bound (6 constraints):
s[o] + dur[o] <= C_max for all o = 0, ..., 5
2. Precedence within each job (3 constraints):
s[o_next] >= s[o_prev] + dur[o_prev] for consecutive operations in each job
Variable bounds (on s[o]):
ES[o] <= s[o] <= LS[o] (from job precedence time windows)
4. Disjunctive (per-pair Big-M) for same-machine operations (12 constraints):
s[o1] - s[o2] + M_a * y[o1,o2] <= M_a - dur[o1]
s[o2] - s[o1] - M_b * y[o1,o2] <= -dur[o2]
where M_a = LS[o1]+dur[o1]-ES[o2], M_b = LS[o2]+dur[o2]-ES[o1]
Formulate Model
Translate the instance into a mathematical optimization model.
Solve and Interpret
Solve the model with SCIP and interpret the raw result into a use-case-specific solution.
scip = SCIP()
job = scip.run(model)
sol = job.result()
uc_solution = instance.interpret(sol)
print(uc_solution.to_string())
/Users/maximilianjanetschek/PycharmProjects/luna-usecases/.venv/lib/python3.13/site-packages/rich/live.py:260:
UserWarning: install "ipywidgets" for Jupyter support
warnings.warn('install "ipywidgets" for Jupyter support')
Job Shop Scheduling Solution:
Makespan: 9
Valid: True
machine_0: [(0, 0, 3), (2, 3, 2), (1, 7, 1)]
machine_1: [(1, 0, 4), (0, 4, 2), (2, 6, 3)]
Plot Solution
Visualize the optimal solution.
Collections
Generate a benchmark collection of random instances for batch processing.
collection = JsspCollection.from_random(min_jobs=2, max_jobs=3, n_machines=2, seed=42)
model = collection.instances[0].formulate()
print(model)
Model: job_shop_scheduling<job_shop_scheduling>
Minimize
C_max
Subject To
makespan_bound_0: s_0 - C_max <= -2
makespan_bound_1: s_1 - C_max <= -2
makespan_bound_2: s_2 - C_max <= -1
makespan_bound_3: s_3 - C_max <= -1
prec_j0_p0: -s_0 + s_1 >= 2
prec_j1_p0: -s_2 + s_3 >= 1
disj_a_0_3: s_0 - s_3 + y_0_3 <= -1
disj_b_0_3: -s_0 + s_3 - 4 * y_0_3 <= -1
disj_a_1_2: s_1 - s_2 + 4 * y_1_2 <= 2
disj_b_1_2: -s_1 + s_2 - y_1_2 <= -1
Bounds
0 <= s_0 <= 0
2 <= s_1 <= 2
0 <= s_2 <= 2
1 <= s_3 <= 3
0 <= C_max
Binary
y_0_3 y_1_2
Integer
s_0 s_1 s_2 s_3 C_max