Model introduction
Higher-education teaching teams often need to allocate multiple types of work across the same pool of staff or graduate students. A common setting involves three roles:
- Teaching-assistant work (TA), such as tutorials, laboratory sessions, and other forms of direct teaching support.
- Grading work (GR), such as marking assignments, tests, and examinations.
- A third role, E, which captures lighter or more intermittent duties such as exam invigilation, consultation support, and routine administrative tasks.
This model is useful when a department must satisfy exact demand for each role while also accounting for role-specific preferences, priority rules for lighter duties, and protections for selected cohorts. It can also incorporate previous workload and balance total workload over a longer planning horizon.
Let there be individuals indexed by and courses or tasks indexed by . For each task-role pair, where , the required demand must be fully assigned.
For each individual-task pair, and denote the user-supplied TA and grading preference scores. Higher values indicate stronger preferences. Year of study is denoted by (capped within 1-4), and is a user-configurable score that guides E allocation. The model also tracks past semester TA and GR workload, denoted by and .
TA and GR may protect different cohorts. Let denote the protected years for the two roles. Each role’s fairness spread excludes its own protected cohort. The model supports one protected cohort per role, but the two roles may protect the same or different cohorts.
The generalized model balances:
- annual TA and GR workload fairness,
- role-specific TA and grading preferences,
- score-guided allocation of lighter E duties, and
- separate TA and GR workload protection for selected cohorts.
Model formulation
Objective function
All objective weights are non-negative and user-specified. and control the importance of annual workload balance for the two main roles. and reward role-specific preference satisfaction. The E term rewards allocation to individuals with larger when . Finally, and penalize violations of the protected cohorts’ soft workload limits.
Role-specific workload spread
Annual TA spread is measured outside the TA-protected cohort:
Annual GR spread is measured outside the GR-protected cohort:
The two protected years may be the same or different. If a role’s protection penalty is disabled, no cohort is protected for that role and all individuals enter its fairness spread.
Annual workload equality
Let denote semester workload capacity per individual. The model fixes each individual’s annual workload total at :
Protected-cohort soft upper bounds
Current-semester TA workload is softly capped for the TA-protected cohort:
Current-semester grading workload is separately capped for the GR-protected cohort:
The slack variables preserve feasibility while making excess workload costly through the corresponding terms.
Package interface
The multi-role workflow consists of:
-
extract_multirole_info()orextract_info(assignment = "multirole"), -
prepare_multirole_model()orprepare_model(assignment = "multirole"), -
solve_assignment(assignment = "multirole")or the lower-levelompr::solve_model()andassign_job()functions.
The bundled multi-role example data demonstrate the generalized interface. Here the same matrix is supplied for TA and GR preferences only to keep the example compact. In practice, the matrices can contain different user-defined scores.
Semester history and capacity
By default, extract_multirole_info() expects
student_id, year, past_ta, and
past_gr as the first four columns of
student_df and uses the supplied prior workload. Semester
capacity C is also supplied at extraction and stored in the
returned input list. prepare_multirole_model() reads this
stored value when enforcing annual workload of 2 * C; it
does not take a separate capacity argument.
For an allocation with no prior-semester workload data, use
single_semester = TRUE. In this mode, only
student_id and year are required as the first
two columns, and any supplied past-workload columns are ignored.
Extraction generates t1 = 0 and g1 = C for
every individual:
single_semester_students <- grouper::multirole_students_ex001[
, c("student_id", "year", "Name")
]
single_semester_inputs <- grouper::extract_multirole_info(
student_df = single_semester_students,
d_mat = grouper::multirole_demand_ex001,
p_ta_mat = grouper::multirole_prefmat_ex001,
e_mode = "rr",
C = 4,
single_semester = TRUE
)
cbind(t1 = single_semester_inputs$t1, g1 = single_semester_inputs$g1)
#> t1 g1
#> [1,] 0 4
#> [2,] 0 4
#> [3,] 0 4
#> [4,] 0 4The uniform synthetic g1 = C workload adds the same
constant to every individual’s annual GR workload, so it does not change
the GR spread. It fills the prior-semester half of the annual equality
and leaves C units per individual for current TA, GR, and E
allocation.
E-allocation scoring
extract_multirole_info() accepts a four-value
s vector ordered by Years 1 to 4. The default is set to
c(-1, 0, 1, 2), which encourages E allocation to more
senior students.
default_inputs <- grouper::extract_multirole_info(
student_df = grouper::multirole_students_ex001,
d_mat = grouper::multirole_demand_ex001,
p_ta_mat = grouper::multirole_prefmat_ex001,
p_gr_mat = grouper::multirole_prefmat_ex001,
e_mode = "none"
)
default_inputs$s
#> [1] -1 0 1 2Users can provide a different encoding to control the E-allocation objective:
custom_inputs <- grouper::extract_multirole_info(
student_df = grouper::multirole_students_ex001,
d_mat = grouper::multirole_demand_ex001,
p_ta_mat = grouper::multirole_prefmat_ex001,
p_gr_mat = grouper::multirole_prefmat_ex001,
e_mode = "none",
s = c(0, 1, 3, 6)
)
custom_inputs$s
#> [1] 0 1 3 6The score vector affects only the E objective. Protection and TA
fairness use student_df$year. Both preference matrices are
used exactly as supplied, so users can choose their own numeric scoring
schemes during preprocessing rather than using the example
3/2/1/-99 encoding.
Role-specific terms
The new GR terms are disabled by default. Set their weights to positive values to enable GR workload spread, grading preferences, and GR cohort protection:
multi_role_model <- grouper::prepare_model(
default_inputs,
assignment = "multirole",
alpha_ta = 2,
alpha_gr = 2,
beta_ta = 1,
beta_gr = 1,
phi = 1,
rho_ta = 10,
rho_gr = 10,
protected_year_ta = 1,
protected_year_gr = 3,
ta_protected_max = 1,
gr_protected_max = 1
)The TA and GR protected years must each be one value from 1 to 4. The selected cohort receives that role’s soft upper bound and slack penalty, and is excluded from that role’s fairness spread.
Keeping the model small
An objective weight set to NULL or zero is disabled
during model construction. The corresponding objective expression is not
added. For spread and protection terms, their supporting variables and
constraints are also omitted. For example:
ta_only_model <- grouper::prepare_multirole_model(
default_inputs,
alpha_gr = NULL,
beta_gr = NULL,
rho_gr = NULL
)This conditional construction is useful for larger allocation
problems because the solver receives only the variables and constraints
needed for the selected formulation. When rho_ta or
rho_gr is disabled, that role has no protected cohort and
its fairness spread, if active, includes every individual.