use grb::prelude::*;
pub fn make_model(env: &Env) -> grb::Result<Model> {
let workers = vec!["Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu"];
let pays = vec![10.0, 12.0, 10.0, 8.0, 8.0, 9.0, 11.0];
let shifts = vec![
"Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11",
"Fri12", "Sat13", "Sun14",
];
let shift_requirements = vec![
3.0, 2.0, 4.0, 4.0, 5.0, 6.0, 5.0, 2.0, 2.0, 3.0, 4.0, 6.0, 7.0, 5.0,
];
let availability = vec![
vec![0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1],
vec![1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0],
vec![0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1],
vec![0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1],
vec![1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1],
vec![1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1],
vec![1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];
let mut model = Model::with_env("assignment", env)?;
let mut x = Vec::with_capacity(workers.len());
for ((worker, &pay), worker_avail) in workers.iter().zip(&pays).zip(&availability) {
let mut xshift = Vec::new();
for (shift, &is_avail) in shifts.iter().zip(worker_avail) {
let vname = format!("{}.{}", worker, shift);
xshift.push(add_binvar!(model, name: &vname, bounds: 0..is_avail, obj: pay)?);
}
x.push(xshift);
}
model.update()?;
model.set_attr(attr::ModelSense, Minimize)?;
for (s, (shift, &requirement)) in shifts.iter().zip(shift_requirements.iter()).enumerate() {
model.add_constr(
format!("shift-{}", shift).as_str(),
c!(x.iter().map(|x_workers| x_workers[s]).grb_sum() == requirement),
)?;
}
Ok(model)
}