Skip to content

Flight Gate Assignment Example

Download Notebook


The Flight Gate Assignment problem assigns flights to airport gates so that total passenger transit time is minimised while respecting time-overlap constraints. It is a key problem in airport operations research.

import getpass
import os

import numpy as np
from dotenv import load_dotenv
from luna_quantum.algorithms import SCIP

from luna_usecases.flight_gate_assignment import (
    FlightGateAssignmentCollection,
    FlightGateAssignmentData,
    FlightGateAssignmentFormulation,
    FlightGateAssignmentInstance,
)

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 4 flights with passenger counts and time windows, and 3 gates with positions.

data = FlightGateAssignmentData.from_schedule(
    arrival_passengers=[120, 80, 150, 90],
    departure_passengers=[100, 110, 70, 130],
    flight_times=[(0.0, 2.0), (1.0, 3.0), (2.5, 4.5), (3.0, 5.0)],
    gate_to_terminal=np.array([[0.0, 0.0], [1.0, 0.0], [0.5, 1.0]]),
    buffer_time=0.5,
)
print(data.to_string())
Flight Gate Assignment Data:
  Flights: 4
  Gates: 3
  Buffer time: 0.5

Plot Data

Visualize flight time windows and gate layout.

data.plot()

<Axes: title={'center': 'FGA - Flight Schedule'}, xlabel='Time'>
png

Create Formulation

Assign flights to gates minimizing passenger walking distance, respecting time overlaps.

formulation = FlightGateAssignmentFormulation()
print(formulation.to_string(data))
Flight Gate Assignment Formulation:
  Flights: 4
  Gates: 3
  Buffer time: 0.5

Decision Variables:
  x[f,g] in {0,1} for f = 0, ..., 3, g = 0, ..., 2
  x[f,g] = 1 if flight f is assigned to gate g
  Total: 12 binary variables

Objective:
  minimize sum_(Undefined, Undefined) (arr_pax[f]*dist[g,0] + dep_pax[f]*dist[g,1]) * x[f,g]

Constraints:
  1. Each flight assigned to exactly one gate (4 constraints):
     sum_g x[f,g] == 1  for all f = 0, ..., 3
  2. Non-overlapping flights at same gate (12 constraints):
     x[f1,g] + x[f2,g] <= 1  for all overlapping pairs (f1,f2), g = 0, ..., 2

Create Instance

Combine data and formulation into a solvable instance.

instance = FlightGateAssignmentInstance(data=data, formulation=formulation)
print(instance.to_string())
Data:Flight Gate Assignment Data:
  Flights: 4
  Gates: 3
  Buffer time: 0.5
Formulation:Flight Gate Assignment Formulation:
  Flights: 4
  Gates: 3
  Buffer time: 0.5

Decision Variables:
  x[f,g] in {0,1} for f = 0, ..., 3, g = 0, ..., 2
  x[f,g] = 1 if flight f is assigned to gate g
  Total: 12 binary variables

Objective:
  minimize sum_(Undefined, Undefined) (arr_pax[f]*dist[g,0] + dep_pax[f]*dist[g,1]) * x[f,g]

Constraints:
  1. Each flight assigned to exactly one gate (4 constraints):
     sum_g x[f,g] == 1  for all f = 0, ..., 3
  2. Non-overlapping flights at same gate (12 constraints):
     x[f1,g] + x[f2,g] <= 1  for all overlapping pairs (f1,f2), g = 0, ..., 2

Formulate Model

Translate the instance into a mathematical optimization model.

model = instance.formulate()

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')






2026-05-29 11:33:33 INFO     Sleeping for 5.0 seconds. Waiting and checking a function in a loop.


2026-05-29 11:33:39 INFO     Sleeping for 10.0 seconds. Waiting and checking a function in a loop.


2026-05-29 11:33:50 INFO     Sleeping for 15.0 seconds. Waiting and checking a function in a loop.


2026-05-29 11:34:07 INFO     Sleeping for 20.0 seconds. Waiting and checking a function in a loop.




Flight Gate Assignment Solution:
  Total transit time: 225.00
  Valid: True
  Assignments: {0: 0, 1: 1, 2: 2, 3: 0}

Plot Solution

Visualize the optimal solution.

uc_solution.plot(data)

<Axes: title={'center': 'FGA Solution - transit 225.0'}, xlabel='Time    (bc = baggage claim dist., ci = check-in dist.)'>
png

Collections

Generate a benchmark collection of random instances for batch processing.

collection = FlightGateAssignmentCollection.from_random(
    min_flights=3,
    max_flights=5,
    n_gates=3,
    seed=42,
)
model = collection.instances[0].formulate()
print(model)
Model: flight_gate_assignment<flight_gate_assignment>
Minimize
  759.2076155731002 * x_0_0 + 1502.554563337249 * x_0_1
  + 1468.877425136867 * x_0_2 + 300.375532664159 * x_1_0
  + 593.1773484883886 * x_1_1 + 641.9422753541782 * x_1_2
  + 426.5532537392471 * x_2_0 + 844.0948044103003 * x_2_1
  + 829.9810983990487 * x_2_2
Subject To
  one_gate_0: x_0_0 + x_0_1 + x_0_2 == 1
  one_gate_1: x_1_0 + x_1_1 + x_1_2 == 1
  one_gate_2: x_2_0 + x_2_1 + x_2_2 == 1
  no_overlap_0_2_g0: x_0_0 + x_2_0 <= 1
  no_overlap_0_2_g1: x_0_1 + x_2_1 <= 1
  no_overlap_0_2_g2: x_0_2 + x_2_2 <= 1
Binary
  x_0_0 x_0_1 x_0_2 x_1_0 x_1_1 x_1_2 x_2_0 x_2_1 x_2_2