import pandas as pd
import json
from itables import init_notebook_mode, show
=False)
init_notebook_mode(all_interactiveimport math
import numpy as np
import plotly.graph_objects as go
2024-06-06
OBP:
Afspraken:
# Read the JSON data from the file
with open('methods.json', 'r') as file:
= json.load(file)
data
# Sort the data by the "Year" field
= sorted(data, key=lambda x: x["Year"])
sorted_data
# Extracting the data for the table
= ["BibTex ID", "Time Slots", "Schedule Format", "Overbooking Allowed", "Service Time", "No-Shows Assumed", "Emergency Patients Assumed", "Punctuality Assumed", "Waiting Time", "Idle Time", "Overtime", "Solution Method"]
headers = []
rows
for article in sorted_data:
= [
row "BibTex ID"],
article["Modeling Approach"]["time slot length"],
article["Modeling Approach"]["schedule format"],
article["Modeling Approach"]["overbooking allowed"],
article["Modeling Approach"]["service time"],
article["Modeling Approach"]["no-shows assumed"],
article["Modeling Approach"]["emergency patients assumed"],
article["Modeling Approach"]["punctuality assumed"],
article["Modeling Approach"]["objective function elements"]["waiting time"],
article["Modeling Approach"]["objective function elements"]["idle time"],
article["Modeling Approach"]["objective function elements"]["overtime"],
article["Solution method summary"]
article[
]
rows.append(row)
# Create a DataFrame
= pd.DataFrame(rows, columns=headers)
df
# Use Styler to format the DataFrame
= df.style.set_properties(**{'text-align': 'left', 'white-space': 'pre-wrap'}) \
styled_table dict(selector='th', props=[('text-align', 'left'), ('vertical-align', 'top')])])
.set_table_styles([
show(styled_table,=False,
paging='display compact cell-border',
classes=['copyHtml5', 'csvHtml5', 'excelHtml5'],
buttons={'top1': 'searchPanes'},
layout={"cascadePanes": True, 'initCollapsed': True},) searchPanes
BibTex ID | Time Slots | Schedule Format | Overbooking Allowed | Service Time | No-Shows Assumed | Emergency Patients Assumed | Punctuality Assumed | Waiting Time | Idle Time | Overtime | Solution Method |
---|---|---|---|---|---|---|---|---|---|---|---|
kaandorp_optimal_2007 | fixed | number of patients per time slot | yes | exponential distribution | yes | no | yes | yes | yes | yes | A local search procedure ensures globally optimal schedules by evaluating and improving performance iteratively. |
klassen_improving_2009 | variable, results from schedule | appointment time, discrete | yes | lognormal distribution | yes | no | yes | yes | yes | yes | A simulation optimization approach integrates metaheuristics to iteratively search for optimal scheduling solutions. |
koeleman_optimal_2012 | fixed | number of patients per time slot | yes | general distribution | yes | yes | yes | yes | yes | yes | A generalized local search method evaluates and iteratively improves schedules to find the optimal solution. |
cayirli_universal_2012 | variable | ['number of patients per time slot', 'appointment time, integer'] | yes | lognormal distribution | yes | yes | yes | yes | yes | yes | The 'Dome' rule is parameterized using simulation and nonlinear regression to accommodate no-shows and walk-ins. |
qingxia_kong_scheduling_2013 | variable, results from schedule | time interval, continuous | yes | general distribution | no | no | yes | yes | no | yes | A convex conic programming approach uses a two-stage stochastic optimization problem to minimize maximum expected cost. |
klassen_strategies_2014 | variable, results from schedule | appointment time, integer | no | lognormal distribution | yes | no | no | yes | yes | yes | A simulation optimization framework explores various scheduling rules to design effective schedules under patient unpunctuality. |
kuiper_computational_2015 | variable, results from schedule | appointment time, continuous | no | general distribution | no | no | yes | yes | yes | yes | A computational approach uses phase-type distributions to approximate service times for sequential and simultaneous optimization. |
jiang_integer_2017 | variable, results from schedule | time interval, continuous | yes | general distribution | yes | no | yes | yes | yes | yes | Distributionally robust optimization models use integer programming to manage random no-shows and service durations. |
deceuninck_outpatient_2018 | fixed | appointment time, integer | yes | lognormal distribution | yes | no | no | yes | yes | yes | A numerical methodology using a modified Lindley recursion evaluates schedules accounting for no-shows and unpunctuality. |
wang_managing_2020 | fixed | number of patients per time slot | yes | general distribution | yes | yes | yes | yes | yes | yes | A two-stage stochastic linear programming model incorporates walk-in processes and heterogeneous no-show behaviors. |
zacharias_multimodularity_2020 | fixed | number of patients per time slot | yes | general distribution | yes | yes | no | yes | yes | yes | A novel method uses nonlinear integer programming and multimodularity to ensure globally optimal schedules. |
homem-de-mello_simulation_2022 | variable, results from schedule | time interval, continuous | no | general distribution | yes | no | yes | yes | yes | yes | A simulation optimization approach uses Monte Carlo simulations and a projected gradient path algorithm. |
kuiper_flexible_2023 | variable | time interval, continuous | no | phase-type distribution | yes | yes | no | yes | yes | yes | A method using phase-type distribution approximations minimizes idle time and waiting time with penalties for overtime. |
Solution landscape
The scheduling problem can be illustrated as a landscape that contains all possible solutions (points) and the task is to find a path that leads to the solution that has the lowest value. Each solution \(x\) can be defined as an array of \(T\) coordinates with values between \(0\) and \(N\), such that the sum of all coordinates equals \(N\):
\[ x = (x_1, x_2, \ldots, x_T) \quad \text{where} \quad x_t \in \{0, 1, \ldots, N\} \quad \text{and} \quad \sum_{t=1}^{T} x_t = N \]
def binomial_coefficient(N, T):
return math.comb(N + T - 1, N)
def create_square_matrix(i):
if i < 1:
raise ValueError("The input must be an integer greater than 1.")
# Find n and m such that n * m = i and |n - m| is minimized
= int(np.sqrt(i))
n while i % n != 0:
-= 1
n = i // n
m
# Generate the n x m matrix with random values
= np.random.rand(n, m)
matrix
return matrix
def find_positions(matrix, values):
= []
positions for value in values:
= np.where(matrix == value)
result 0][0], result[1][0]))
positions.append((result[return positions
def plot_matrix_with_arrows(N, T, l):
= binomial_coefficient(N, T)
i = create_square_matrix(i)
matrix = matrix.shape
n, m = [], [], []
x, y, values
for i in range(n):
for j in range(m):
x.append(j)- i - 1) # Invert y-axis to have the origin at the top-left corner
y.append(n
values.append(matrix[i, j])
# Find the four lowest values and their positions
= np.sort(matrix, axis=None)
sorted_values = sorted_values[:l]
lowest_values
= find_positions(matrix, lowest_values)
positions
= go.Figure(data=go.Scatter(
fig =x,
x=y,
y='markers',
mode=dict(
marker=20,
size=values,
color='deep',
colorscale
),= 'Value: %{marker.color:.5f}<extra></extra>'
hovertemplate
))
fig.update_layout(=f'Landscape with all {n * m} possible solutions for N = {N} and T = {T}',
title=dict(
xaxis='linear',
tickmode=1,
dtickrange=[-0.5, m - 0.5],
=False # numbers below
visible
),=dict(
yaxis='linear',
tickmode=1,
dtickrange=[-0.5, n - 0.5],
='reversed',
autorange=False # numbers below
visible
),# xaxis_title='Column',
# yaxis_title='Row',
=800,
width=800,
height= False
showlegend
)
# Add arrows from the fourth lowest to the lowest value
for i in range(l-1):
= positions[i + 1]
(start_i, start_j) = positions[i]
(end_i, end_j)
fig.add_annotation(=end_j,
x=n - end_i - 1,
y=start_j,
ax=n - start_i - 1,
ay="x",
xref="y",
yref="x",
axref="y",
ayref=True,
showarrow=2,
arrowhead=3,
arrowsize=2,
arrowwidth="red"
arrowcolor
)
fig.show()"images/landscape-with-arrows.png", scale=4)
fig.write_image(
# Example usage
= 7
N = 5
T
# Plot the matrix with arrows
6) plot_matrix_with_arrows(N, T,
What we know is:
-
A scheduling problem with fixed and equal time slots defined as:
\[ \min \left\{ \alpha_W W(x) + \alpha_I I(x) + \alpha_L L(x) \ \middle| \ \begin{array}{c} \sum_{t}^{T} x_t = N \\ x_t \in \mathbb{N}_0 \end{array} \right\} \]
has a multimodular objective (Kaandorp and Koole 2007). This means that any local optimum is also the global optimum. -
In the case where appointment times are continuous and variable the optimal schedule is dome-shaped, meaning the time allotted for each appointment initially increases sharply, then climbs slowly to a peak, and decreases slowly after the peak. This allows for some buffer time to absorb increasing service time variability as the day progresses due to accumulated delays, while keeping slots tight at the start and end (Klassen and Yoogalingam 2009).
Would that mean that schedules with overbooking at the start and towards the finish and more zeroes in the middle show optimal performance?