Mathematical Formulation

This page documents the mixed-integer linear programming (MILP) model implemented in Scheduler._build_model. For usage-oriented movement configuration examples, see Building Movement and Staggered Starts.

Code-Aligned Notation

This table maps the mathematical symbols to the exact Pyomo components in the code.

Math symbol

Code component

Meaning

\(\mathcal{S}\)

m.visitors

Visitor set

\(\mathcal{F}\)

m.faculty

Faculty set with non-empty availability

\(\mathcal{T}\)

m.time

Time-slot index set

\(\mathcal{K}\)

m.buildings

Building set

\(\mathcal{F}_k\)

m.faculty_by_building[k]

Faculty assigned to building \(k\)

\(\mathcal{B}\)

m.break_options

Candidate break slots

\(w_{sf}\)

m.weights[s, f]

Utility weight for visitor-faculty match

\(p\)

m.penalty

Group penalty coefficient

\(y_{sft}\)

m.y[s, f, t]

Meeting assignment decision variable

\(z_{ft}\)

m.beyond_one_visitor[f, t]

Visitors beyond one in a meeting

\(q_f\)

m.faculty_too_many_meetings[f]

Overload indicator

\(\beta_{skt}\)

m.in_building[s, k, t]

Visitor in building \(k\) at slot \(t\) (travel policies)

\(r_{ft}\)

m.faculty_breaks[f, t]

Faculty break indicator

\(\underline{L}_s,\overline{U}_s\)

set_visitor_meeting_bounds(...) + min_faculty

Effective visitor min/max meetings

\(\underline{L}_f,\overline{U}_f\)

set_faculty_meeting_bounds(...) + min_visitors/max_visitors

Effective faculty min/max meetings

Worked Example Dataset

The repository includes a formulation-focused dataset:

  • examples/faculty_formulation.yaml

  • examples/config_formulation.yaml

  • examples/data_formulation_visitors.csv

Dataset size:

  • 6 faculty (Prof. A through Prof. F)

  • 4 time slots

  • 10 visitors

  • buildings: ABC and XYZ

  • topic areas: Energy, Bio, Theory

  • break window: slots 2 and 3

Runner script:

  • scripts/run_formulation_example.py

Faculty availability conflicts in this example:

Faculty

Available slots

Unavailable slots

Prof. A

1, 2, 3, 4

None

Prof. B

1, 2, 4

3

Prof. C

1, 3, 4

2

Prof. D

2, 3, 4

1

Prof. E

1, 2, 3

4

Prof. F

1, 3, 4

2

Student Preference Summary

Visitor

Prof1

Prof2

Prof3

Prof4

Area1

Area2

Visitor 01

Prof. A

Prof. C

Prof. E

Prof. F

Energy

Theory

Visitor 02

Prof. B

Prof. D

Prof. F

Prof. C

Bio

Energy

Visitor 03

Prof. C

Prof. A

Prof. E

Prof. B

Theory

Energy

Visitor 04

Prof. D

Prof. F

Prof. B

Prof. A

Energy

Bio

Visitor 05

Prof. E

Prof. C

Prof. A

Prof. D

Bio

Theory

Visitor 06

Prof. F

Prof. B

Prof. D

Prof. E

Theory

Bio

Visitor 07

Prof. A

Prof. E

Prof. C

Prof. D

Energy

Bio

Visitor 08

Prof. B

Prof. F

Prof. D

Prof. A

Bio

Theory

Visitor 09

Prof. C

Prof. E

Prof. A

Prof. B

Theory

Energy

Visitor 10

Prof. D

Prof. B

Prof. F

Prof. C

Energy

Theory

Sets and Indices

  • \(s \in \mathcal{S}\): visitors

  • \(f \in \mathcal{F}\): faculty with at least one available time slot

  • \(t \in \mathcal{T} = \{1, \dots, T\}\): time slots

  • \(k \in \mathcal{K}\): buildings

  • \(\mathcal{F}_k \subseteq \mathcal{F}\): faculty located in building \(k\)

  • \(\mathcal{B} \subseteq \mathcal{T}\): configured break slot options

Parameters

  • \(w_{sf}\): utility weight for assigning visitor \(s\) to faculty \(f\)

  • \(p \ge 0\): group meeting penalty (group_penalty)

  • \(L_f\): minimum visitors per faculty (min_visitors)

  • \(U_f\): maximum visitors per faculty (max_visitors)

  • \(L_s\): minimum faculty meetings per visitor (min_faculty)

  • \(\underline{L}_s,\overline{U}_s\): effective visitor bounds after optional per-visitor overrides

  • \(\underline{L}_f,\overline{U}_f\): effective faculty bounds after optional per-faculty overrides

  • \(G\): maximum group size in a faculty-time meeting (max_group)

  • \(a_{ft} \in \{0,1\}\): 1 if faculty \(f\) is available at slot \(t\)

Decision Variables

  • \(y_{sft} \in \{0,1\}\): 1 if visitor \(s\) meets faculty \(f\) at time \(t\)

  • \(z_{ft} \ge 0\): number of visitors beyond one in faculty-time meeting \((f,t)\)

  • \(q_f \in \{0,1\}\): overload indicator for faculty \(f\)

  • \(\beta_{skt} \in \{0,1\}\): visitor \(s\) is in building \(k\) at slot \(t\) (when movement.policy is travel_time or nonoverlap_time)

  • \(r_{ft} \in \{0,1\}\): faculty \(f\) is on break at candidate break slot \(t \in \mathcal{B}\)

Objective

Maximize preference satisfaction minus group/overload penalties:

\[ \max \sum_{s \in \mathcal{S}} \sum_{f \in \mathcal{F}} \sum_{t \in \mathcal{T}} w_{sf} y_{sft} - p \sum_{f \in \mathcal{F}} \sum_{t \in \mathcal{T}} z_{ft} - 3p \sum_{f \in \mathcal{F}} q_f \]

Interpretation:

  • First term rewards satisfying visitor preferences.

  • Second term discourages group meetings larger than one visitor.

  • Third term discourages faculty loads beyond the soft threshold used in the implementation.

Constraints

1. Faculty availability

\[ y_{sft} \le a_{ft} \quad \forall s,f,t \]

Meetings can only occur when faculty are available.

2. Faculty minimum and maximum total meetings (with optional overrides)

\[ \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} y_{sft} \ge \underline{L}_f \quad \forall f \]
\[ \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} y_{sft} \le \overline{U}_f \quad \forall f \]

3. Visitor cannot attend simultaneous meetings

\[ \sum_{f \in \mathcal{F}} y_{sft} \le 1 \quad \forall s,t \]

4. Visitor minimum and optional maximum total meetings

\[ \sum_{f \in \mathcal{F}} \sum_{t \in \mathcal{T}} y_{sft} \ge \underline{L}_s \quad \forall s \]

The default lower bound is \(\underline{L}_s=\min\left(L_s,\left|\mathcal{T}_s^{\text{avail}}\right|\right)\), then overridden by set_visitor_meeting_bounds when provided.

When a visitor-specific maximum is configured:

\[ \sum_{f \in \mathcal{F}} \sum_{t \in \mathcal{T}} y_{sft} \le \overline{U}_s \quad \forall s \text{ with override} \]

5. Visitor meets same faculty at most once

\[ \sum_{t \in \mathcal{T}} y_{sft} \le 1 \quad \forall s,f \]

6. Excess visitors per faculty-time slot

\[ z_{ft} \ge \sum_{s \in \mathcal{S}} y_{sft} - 1 \quad \forall f,t \]

This linearizes the “beyond one visitor” quantity used in the objective penalty.

7. Faculty overload indicator

\[ 2q_f \ge \sum_{s \in \mathcal{S}} \sum_{t \in \mathcal{T}} y_{sft} - U_f + 2 \quad \forall f \]

This activates \(q_f\) when total meetings exceed the soft threshold \(U_f - 2\).

8. Maximum group size per meeting

\[ \sum_{s \in \mathcal{S}} y_{sft} \le G \quad \forall f,t \]

9. Building phase constraints (movement.phase_slot)

Each building \(k\) has an earliest allowed meeting slot \(\phi_k\):

\[ y_{sft} \le \mathbf{1}\!\left[t \ge \phi_{\text{building}(f)}\right] \quad \forall s,f,t \]

This supports staggered schedules such as “Building A first” or “Building B first” without requiring a dedicated mode.

10. Travel-time occupancy and lag constraints (movement.policy = travel_time or nonoverlap_time)

When travel-time constraints are enabled, occupancy indicators are linked by:

\[ \sum_{f \in \mathcal{F}_k} y_{sft} \le \beta_{skt} \quad \forall s,k,t \]

For each building pair \((k,\ell)\) with lag \(\tau_{k\ell} > 0\), transitions within the lag window are forbidden:

\[ \beta_{sk t_1} + \beta_{s\ell t_2} \le 1, \quad \forall s,\; k \ne \ell,\; 0 < t_2-t_1 \le \tau_{k\ell} \]

When travel_slots: auto or policy: nonoverlap_time is used, \(\tau_{k\ell}\) is derived from absolute slot timestamps so overlapping real-time transitions are disallowed (optionally with additional min_buffer_minutes).

11. Visitor break requirement

Applied when automatic student break constraints are enabled (movement legacy NO_OFFSET compatibility, student_breaks > 0, or legacy enforce_breaks=True):

\[ \sum_{f \in \mathcal{F}} \sum_{t \in \mathcal{B}} y_{sft} \le |\mathcal{B}| - b_s \quad \forall s \]

Here \(b_s\) is the configured student_breaks count. Each visitor must have at least that many breaks during the configured break window.

12. Faculty break variables and requirement

Applied when automatic faculty break constraints are enabled (faculty_breaks > 0, movement legacy NO_OFFSET compatibility, or legacy enforce_breaks=True):

\[ \sum_{s \in \mathcal{S}} y_{sft} \le G(1-r_{ft}) \quad \forall f,\; t \in \mathcal{B} \]

If \(r_{ft}=1\), faculty \(f\) has no meeting at break slot \(t\).

\[ u_f + \sum_{t \in \mathcal{B}} r_{ft} \ge b \quad \forall f \]

Here \(b\) is the configured faculty_breaks count after applying legacy alias resolution, and \(u_f\) counts faculty-unavailable slots outside the configured break window that already count as breaks. Unavailable slots inside the break window are fixed to \(r_{ft}=1\) in the implementation. Legacy enforce_breaks=True maps to faculty_breaks=1 and student_breaks=1.

13. Fixed unavailability for visitors

For visitor-specific availability restrictions, decision variables are fixed to zero:

\[ y_{sft} = 0 \quad \forall (s,t) \text{ not available to visitor } s,\; \forall f \]

14. User-specified visitor/faculty hard constraints (optional)

The APIs forbid_meeting, require_meeting, and require_break add explicit hard constraints:

All-slot forbid (forbid_meeting(s,f)):

\[ y_{sft}=0 \quad \forall t \in \mathcal{T} \]

Slot-specific forbid (forbid_meeting(s,f,t^\*)):

\[ y_{sf t^\*}=0 \]

All-slot require (require_meeting(s,f)):

\[ \sum_{t \in \mathcal{T}} y_{sft}=1 \]

Slot-specific require (require_meeting(s,f,t^\*)):

\[ y_{sf t^\*}=1 \]

Required breaks (require_break(s,\mathcal{T}',b)):

\[ \sum_{f \in \mathcal{F}}\sum_{t\in\mathcal{T}'} y_{sft}\le |\mathcal{T}'|-b \]

where \(b\) is min_breaks.

Top-N No-Good Cuts (Optional Multi-Solution Extension)

When generating ranked alternatives, the model adds one no-good cut after each feasible solution to exclude the exact same binary assignment vector in later iterations.

Let \(\mathcal{I}\) be all assignment indices \((s,f,t)\) and let \(\mathcal{A}^{(k)} \subseteq \mathcal{I}\) be the active assignment set in rank-\(k\) solution. The no-good cut for solution \(k\) is:

\[ \sum_{i \in \mathcal{A}^{(k)}} \left(1 - y_i\right) + \sum_{i \in \mathcal{I}\setminus \mathcal{A}^{(k)}} y_i \ge 1 \]

This enforces that at least one binary variable differs from solution \(k\).

Notes on Implementation

  • The model is assembled in Scheduler._build_model and solved in Scheduler._solve_model.

  • Feasibility checks and diagnostics are available through has_feasible_solution and infeasibility_report.

  • Constraint activation depends on movement policy plus the resolved faculty_breaks / student_breaks values exactly as documented above.

  • Legacy mode-specific movement constraints are superseded by the movement.phase_slot and movement.travel_slots formulation above.

  • When advanced user hard constraints or per-entity bounds are configured, pre-solve consistency checks run via _run_presolve_hard_constraint_checks. These checks catch obvious contradictions before solver execution and raise clear ValueError messages.

  • debug_infeasible=False (default): fail fast before model build.

  • debug_infeasible=True: build model first, then raise pre-solve errors so advanced users can inspect s.model (for example before IIS workflows).

Example Solutions

The table below was generated by solving the worked dataset with:

  • solver=Solver.HIGHS

  • group_penalty=0.2

  • min_visitors=2

  • max_visitors=8

  • min_faculty=1

  • max_group=2

  • faculty_breaks=1

  • student_breaks=1

Solver metrics:

  • total utility: 113.5

  • total excess-visitors penalty term: 0.2 * 13 = 2.6

  • faculty overload indicators: 0

  • objective value: 110.9

Solver-Generated Visitor Schedule

Visitor

Slot 1

Slot 2

Slot 3

Slot 4

Visitor 01

Prof. E

Prof. A

Break

Prof. C

Visitor 02

Prof. B

Break

Prof. D

Prof. F

Visitor 03

Prof. E

Prof. A

Break

Prof. C

Visitor 04

Prof. F

Prof. B

Break

Prof. D

Visitor 05

Prof. C

Prof. E

Break

Prof. A

Visitor 06

Prof. F

Prof. D

Break

Prof. B

Visitor 07

Prof. A

Prof. E

Break

Prof. D

Visitor 08

Prof. A

Break

Prof. F

Prof. B

Visitor 09

Prof. C

Break

Prof. E

Prof. A

Visitor 10

Prof. B

Prof. D

Break

Prof. F

Solver-Generated Faculty Load Summary

Faculty

Total meetings

Slot 1

Slot 2

Slot 3

Slot 4

Prof. A

6

2

2

0

2

Prof. B

5

2

1

0

2

Prof. C

4

2

0

0

2

Prof. D

5

0

2

1

2

Prof. E

5

2

2

1

0

Prof. F

5

2

0

1

2