Skip to content

Commit 2fec9f9

Browse files
authored
Fix #511: [Model] TimetableDesign (#719)
* Add plan for #511: [Model] TimetableDesign * Add TimetableDesign model and CLI support * Implement #511: [Model] TimetableDesign * chore: remove plan file after implementation * Fix formatting after merge with main * Fix display-name alphabetical ordering for TimetableDesign
1 parent 4f83030 commit 2fec9f9

9 files changed

Lines changed: 1008 additions & 5 deletions

File tree

docs/paper/reductions.typ

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@
153153
"StrongConnectivityAugmentation": [Strong Connectivity Augmentation],
154154
"SubgraphIsomorphism": [Subgraph Isomorphism],
155155
"SumOfSquaresPartition": [Sum of Squares Partition],
156+
"TimetableDesign": [Timetable Design],
156157
"TwoDimensionalConsecutiveSets": [2-Dimensional Consecutive Sets],
157158
)
158159

@@ -3582,6 +3583,53 @@ A classical NP-complete problem from Garey and Johnson @garey1979[Ch.~3, p.~76],
35823583
) <fig:staff-scheduling>
35833584
]
35843585

3586+
#{
3587+
let x = load-model-example("TimetableDesign")
3588+
let assignments = x.optimal_config.enumerate().filter(((idx, value)) => value == 1).map(((idx, value)) => (
3589+
calc.floor(idx / (x.instance.num_tasks * x.instance.num_periods)),
3590+
calc.floor(calc.rem(idx, x.instance.num_tasks * x.instance.num_periods) / x.instance.num_periods),
3591+
calc.rem(idx, x.instance.num_periods),
3592+
))
3593+
let fmt-assignment(entry) = $(c_#(entry.at(0) + 1), t_#(entry.at(1) + 1))$
3594+
let period-0 = assignments.filter(entry => entry.at(2) == 0)
3595+
let period-1 = assignments.filter(entry => entry.at(2) == 1)
3596+
let period-2 = assignments.filter(entry => entry.at(2) == 2)
3597+
[
3598+
#problem-def("TimetableDesign")[
3599+
Given a set $H$ of work periods, a set $C$ of craftsmen, a set $T$ of tasks, availability sets $A_C(c) subset.eq H$ for each craftsman $c in C$, availability sets $A_T(t) subset.eq H$ for each task $t in T$, and exact workload requirements $R: C times T -> ZZ_(>= 0)$, determine whether there exists a function $f: C times T times H -> {0, 1}$ such that:
3600+
$
3601+
f(c, t, h) = 1 => h in A_C(c) inter A_T(t),
3602+
$
3603+
$
3604+
forall c in C, h in H: sum_(t in T) f(c, t, h) <= 1,
3605+
$
3606+
$
3607+
forall t in T, h in H: sum_(c in C) f(c, t, h) <= 1,
3608+
$
3609+
and
3610+
$
3611+
forall c in C, t in T: sum_(h in H) f(c, t, h) = R(c, t).
3612+
$
3613+
][
3614+
Timetable Design is the classical timetabling feasibility problem catalogued as SS19 in Garey & Johnson @garey1979. Even, Itai, and Shamir showed that it is NP-complete even when there are only three work periods, every task is available in every period, and every requirement is binary @evenItaiShamir1976. The same paper also identifies polynomial-time islands, including cases where each craftsman is available in at most two periods or where all craftsmen and tasks are available in every period @evenItaiShamir1976. The implementation in this repository uses one binary variable for each triple $(c, t, h)$, so the registered baseline explores a configuration space of size $2^(|C| |T| |H|)$.
3615+
3616+
*Example.* The canonical instance has three periods $H = {h_1, h_2, h_3}$, five craftsmen, five tasks, and seven nonzero workload requirements. The satisfying timetable stored in the example database assigns #period-0.map(fmt-assignment).join(", ") during $h_1$, #period-1.map(fmt-assignment).join(", ") during $h_2$, and #period-2.map(fmt-assignment).join(", ") during $h_3$. Every listed assignment lies in the corresponding availability intersection $A_C(c) inter A_T(t)$, no craftsman or task appears twice in the same period, and each required pair is scheduled exactly once, so the verifier returns YES.
3617+
3618+
#figure(
3619+
align(center, table(
3620+
columns: 2,
3621+
align: center,
3622+
table.header([Period], [Assignments]),
3623+
[$h_1$], [#period-0.map(fmt-assignment).join(", ")],
3624+
[$h_2$], [#period-1.map(fmt-assignment).join(", ")],
3625+
[$h_3$], [#period-2.map(fmt-assignment).join(", ")],
3626+
)),
3627+
caption: [Worked Timetable Design instance derived from the canonical example DB. Each row lists the craftsman-task pairs assigned in one work period.],
3628+
) <fig:timetable-design>
3629+
]
3630+
]
3631+
}
3632+
35853633
#{
35863634
let x = load-model-example("MultiprocessorScheduling")
35873635
let lengths = x.instance.lengths

problemreductions-cli/src/cli.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ Flags by problem type:
278278
StrongConnectivityAugmentation --arcs, --candidate-arcs, --bound [--num-vertices]
279279
FlowShopScheduling --task-lengths, --deadline [--num-processors]
280280
StaffScheduling --schedules, --requirements, --num-workers, --k
281+
TimetableDesign --num-periods, --num-craftsmen, --num-tasks, --craftsman-avail, --task-avail, --requirements
281282
MinimumTardinessSequencing --n, --deadlines [--precedence-pairs]
282283
RectilinearPictureCompression --matrix (0/1), --k
283284
SchedulingWithIndividualDeadlines --n, --num-processors/--m, --deadlines [--precedence-pairs]
@@ -570,12 +571,27 @@ pub struct CreateArgs {
570571
/// Binary schedule patterns for StaffScheduling (semicolon-separated rows, e.g., "1,1,0;0,1,1")
571572
#[arg(long)]
572573
pub schedules: Option<String>,
573-
/// Minimum staffing requirements per period for StaffScheduling
574+
/// Requirements for StaffScheduling (comma-separated) or TimetableDesign (semicolon-separated rows)
574575
#[arg(long)]
575576
pub requirements: Option<String>,
576577
/// Number of available workers for StaffScheduling
577578
#[arg(long)]
578579
pub num_workers: Option<u64>,
580+
/// Number of work periods for TimetableDesign
581+
#[arg(long)]
582+
pub num_periods: Option<usize>,
583+
/// Number of craftsmen for TimetableDesign
584+
#[arg(long)]
585+
pub num_craftsmen: Option<usize>,
586+
/// Number of tasks for TimetableDesign
587+
#[arg(long)]
588+
pub num_tasks: Option<usize>,
589+
/// Craftsman availability rows for TimetableDesign (semicolon-separated 0/1 rows)
590+
#[arg(long)]
591+
pub craftsman_avail: Option<String>,
592+
/// Task availability rows for TimetableDesign (semicolon-separated 0/1 rows)
593+
#[arg(long)]
594+
pub task_avail: Option<String>,
579595
/// Alphabet size for LCS, SCS, StringToStringCorrection, or TwoDimensionalConsecutiveSets (optional; inferred from the input strings if omitted)
580596
#[arg(long)]
581597
pub alphabet_size: Option<usize>,

0 commit comments

Comments
 (0)