Skip to content

Production Assignment API Reference

The Production Assignment and Scheduling (PAS) use case optimizes job-to-machine assignments while balancing value maximization, setup time minimization, and load balancing.

Data

Data model for PAS (Production Assignment and Scheduling).

PasData

Bases: UcData

Data for the Production Assignment and Scheduling (PAS) use case.

The PAS problem assigns jobs to machines and orders them to maximize job value while minimizing setup and balancing machine busy times. The formulation in the provided QCHALLenge documents uses machine-dependent values v[j, m], machine-dependent processing times p[j, m] (or machine-independent if each column is identical), machine-independent setup times s[i, j], and eligibility sets E_j.

Attributes:

Name Type Description
name Literal['production_assignment_and_scheduling']

Identifier for this data type.

job_names list[str]

Identifiers for jobs (size n_jobs).

machine_names list[str]

Identifiers for machines (size n_machines).

processing_times NumPyArray

2D array [n_jobs, n_machines] with processing time of job j on machine m. If times are machine-independent, each row can repeat the same value across machines.

setup_times NumPyArray

2D array [n_jobs, n_jobs] with machine-independent setup time from job i to job j (s[i, j]). Diagonal is typically 0.

values NumPyArray

2D array [n_jobs, n_machines] with job value v[j, m] when job j runs on machine m.

eligibility NumPyArray

Boolean mask [n_jobs, n_machines]; True if machine m can process job j (i.e., m ∈ E_j). Ineligible pairs can be masked in the formulation.

value_weight float

Weight alpha for the value objective term.

setup_weight float

Weight for penalizing setup time.

balance_weight float

Weight for penalizing machine busy-time imbalance.

plot(*, ax: Axes | None = None) -> Axes

Plot a heatmap of job values by machine.

Ineligible job-machine pairs are greyed out. The colour intensity of each cell reflects the value v[j, m].

Parameters:

Name Type Description Default
ax Axes | None

Matplotlib axes to draw on. Creates a new figure if None.

None

Returns:

Type Description
Axes

The axes with the plot.

to_string() -> str

Print detailed human-readable representation of all data.

from_random(n_jobs: int = 12, n_machines: int = 4, seed: int | None = None) -> PasData staticmethod

Generate a random PAS instance consistent with the PDFs.

Parameters:

Name Type Description Default
n_jobs int

Number of jobs to generate.

12
n_machines int

Number of machines to generate.

4
seed int | None

Random seed for reproducibility.

None

Returns:

Type Description
PasData

A randomly generated PAS data instance.

Random generation heuristics
  • processing_times: positive times, mildly machine-dependent
  • setup_times: machine-independent, diagonal set to zero
  • values: positive values, machine-dependent
  • eligibility: each job eligible on ~70% of machines, with fallback to ensure at least one eligible machine per job

Formulation

Formulation for PAS (Production Assignment and Scheduling) use case.

PasFormulation

Bases: UcFormulation[PasData, PasSolution]

Constraint-based formulation for Production Assignment and Scheduling.

Mathematical Formulation (from QCHALLenge PDF)
Decision Variables:
    x[j, m, n] ∈ {0,1}:  1 if job j is the n-th job on machine m, 0 otherwise
        - j ∈ Jobs
        - m ∈ Machines (only if m is eligible for j)
        - n ∈ Positions (sequence slots on each machine)

Objectives (multi-objective minimization):
    1. Maximize job values:  α · Σ_j,m,n v[j,m] · x[j,m,n]
    2. Minimize setup times: β · Σ_j,j',m,n s[j,j'] · x[j,m,n] · x[j',m,n+1]
    3. Balance machines:     γ · Σ_m (Σ_j,n p[j] · x[j,m,n])²
Where:
    α = value_weight (weight for job values)
    β = setup_weight (weight for setup times)
    γ = balance_weight (weight for load balancing)

Constraints:
    1. Eligibility: x[j,m,n] = 0 if machine m cannot process job j
    2. Each job assigned once: Σ_m,n x[j,m,n] = 1 ∀j
    3. At most one job per slot: Σ_j x[j,m,n] ≤ 1 ∀m,n
    4. No gaps in schedule: Σ_j x[j,m,n+1] ≤ Σ_j x[j,m,n] ∀m,n

to_string(data: PasData) -> str staticmethod

Print the formulation summary.

formulate(data: PasData) -> Model staticmethod

Formulate PAS as a constraint-based quantum optimization model.

Parameters:

Name Type Description Default
data PasData

The problem data.

required

Returns:

Type Description
Model

A LunaModel ready to be solved.

interpret(solution: Solution, data: PasData) -> PasSolution staticmethod

Extract solution from quantum result.

Parameters:

Name Type Description Default
solution Solution

The quantum solution.

required
data PasData

The problem data.

required

Returns:

Type Description
PasSolution

Structured solution with metrics.

Solution

Solution model for PAS use case.

PasSolution

Bases: UcSolution

Solution for the Production Assignment and Scheduling use case.

Attributes:

Name Type Description
name Literal['production_assignment_and_scheduling']

Use case identifier (always "production_assignment_and_scheduling").

schedule list[tuple[int, int, int]]

List of (job_id, machine_id, position) assignments.

total_value float

Sum of job values from all assignments.

total_setup float

Sum of setup times between consecutive jobs on each machine.

machine_loads list[float]

Total processing time for each machine.

balance_metric float

Sum of squared machine loads (imbalance measure).

objective_value float

Combined weighted objective value.

plot(data: PasData | None = None, *, ax: Axes | None = None) -> Axes

Plot the schedule as a Gantt-style chart.

Each coloured block represents a job placed on a machine at a given position. When data is supplied, block widths are proportional to processing_times[job_id, machine_id]; otherwise every block has uniform width 1.

Parameters:

Name Type Description Default
data PasData | None

Problem data. When provided, block widths reflect processing times and job labels use data.job_names.

None
ax Axes | None

Matplotlib axes to draw on. Creates a new figure if None.

None

Returns:

Type Description
Axes

The axes with the plot.

to_string() -> str

Print the solution in human-readable format.

Returns:

Type Description
str

Formatted string representation of the solution.

Instance

Instance model for Pas use case.

PasInstance

Bases: UcInstance[PasData, UcFormulation[PasData, PasSolution], PasSolution]

Instance combining data and formulation for Pas.

formulate() -> Model

Formulate the instance as AqModel, applying weight overrides.

interpret(solution: Solution) -> PasSolution

Interpret the solution to the AqModel, applying weight overrides.

to_string() -> str

Return the data and formulation summaries with overrides applied.

Collection

Collection of Pas instances.

PasCollection

Bases: UcInstanceCollection[PasInstance]

Collection of Pas instances.

This collection provides methods to generate benchmark instances with various characteristics for testing and evaluation.

from_random(min_size: int | None = None, max_size: int | None = None, num_instances: int = 1, *, sizes: Sequence[int] | None = None, seed: int | None = None, formulation_class: type[UcFormulation[PasData, PasSolution]] = PasFormulation) -> PasCollection classmethod

Generate random instances.

Parameters:

Name Type Description Default
min_size int | None

Minimum problem size.

None
max_size int | None

Maximum problem size.

None
num_instances int

Number of instances per size, by default 1.

1
seed int | None

Random seed for reproducibility, by default None.

None
formulation_class type[UcFormulation[PasData,

PasSolution]], optional Formulation class to instantiate for each generated instance, by default PasFormulation.

PasFormulation
sizes Sequence[int] | None

Explicit sizes to generate, e.g. [10, 50, 100], instead of a range. Mutually exclusive with min_size/max_size, by default None.

None

Returns:

Type Description
PasCollection

Collection containing generated instances.

Examples:

>>> collection = PasCollection.from_random(
...     min_size=5,
...     max_size=10,
...     num_instances=3,
...     seed=42,
... )
>>> from luna_usecases.production_assignment_and_scheduling import (
...     PasConvexFormulation,
... )
>>> convex_collection = PasCollection.from_random(
...     min_size=5,
...     max_size=10,
...     num_instances=3,
...     seed=42,
...     formulation_class=PasConvexFormulation,
... )

filter_infeasible(max_runtime: float = 3600, *, quiet: bool = True) -> list[bool]

Drop the instances of this collection that have no feasible solution.

Every instance is formulated and handed to SCIP, which stops as soon as it finds the first feasible solution. An instance is removed from the collection when SCIP proves the model infeasible, when no solution turns up within max_runtime, or when formulating it fails altogether. This keeps randomly generated instances from breaking a downstream pipeline.

Parameters:

Name Type Description Default
max_runtime float

SCIP time limit per instance in seconds. Must be positive. Defaults to 3600 seconds.

3600
quiet bool

Suppress the SCIP solver output.

True

Returns:

Type Description
list[bool]

Feasibility mask over the instances as they were before filtering, in that order: True where the instance was kept, False where it was removed.

Raises:

Type Description
ValueError

If max_runtime is not positive.