# Staff Scheduling Optimization

**URL:** <https://discourse.julialang.org/t/staff-scheduling-optimization/123230>\
**Category:** Optimization (Mathematical)\
**Tags:** jump\
**Created:** [November 28, 2024, 11:13pm UTC](https://discourse.julialang.org/t/staff-scheduling-optimization/123230 "2024-11-28T23:13:38Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Honcho868](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/honcho868/32/213792_2.png) [@Honcho868](https://discourse.julialang.org/u/Honcho868)\
**Post date:** [November 28, 2024, 11:13pm UTC](https://discourse.julialang.org/t/staff-scheduling-optimization/123230/1 "2024-11-28T23:13:38Z")

</div>

So im trying to code the following model from the paper in JuMP to determine optimal number of staff for 3 shifts daily for 7 days a week where staff must work atleast 1 shift per day

This is the code:

```julia
using JuMP
using HiGHS
Wjk = [
    19 16 22 22 22 22 22
    19 16 22 22 22 22 22
    14 11 16 16 16 16 16
]
J, K = size(Wjk)
Ajk = 8
N = 100 #Upper limit
model = Model(HiGHS.Optimizer)
@variable(model, x[1:N, 1:J, 1:K], Bin)
@variable(model, y[1:N], Bin)
@objective(model, Min, sum(x))
@constraint(model, [i in 1:N], sum(x[i, :, :]) <= J * K * y[i]) # y[i] is 1 if employee i is used
@constraint(model, [i in 2:N], y[i-1] >= y[i]) # Ordering on y[i]. If we don't use y[i-1], then we can't use y[i]
@constraint(model, [i in 1:N, k in 1:K], x[i,1,k] + x[i,2,k] + x[i,3,k] <= 2) # Constraint (8)
@constraint(model, [i in 1:N, k in 1:K], x[i,2,k] + x[i,3,k] + x[i,1,k%7+1] <= 2) # Constraint (9)
@constraint(model, [i in 1:N, k in 1:K], x[i,3,k] + x[i,1,k%7+1] + x[i,2,k%7+1] <= 2) # Constraint (10)
@constraint(model, [j in 1:J, k in 1:K], sum(x[:,j,k]) >= Wjk[j,k]) # Constraint (11)
@constraint(model, [j in 1:J, k in 1:K], sum(x[:,j,k]) <= Wjk[j,k] + Ajk) # Constraint (12)
@constraint(model, [i in 1:N], sum(x[i,j,(i-1)%7+1] + x[i,j,i%7+1] for j in 1:J) == 0) # Constraint (13)
@constraint(model, [i in 1:N, k in 1:5], sum(x[i,j,(i+k)%7+1] for j in 1:J) >= y[i]) # Constraint (14)

optimize!(model)
status = termination_status(m)
println("Solution status: ", status)
println("Number of Employees: ", N)
println("Optimal Shift Allocation:")
for i in 1:N, j in 1:J, k in 1:K
    if value(x[i, j, k]) > 0.5
        println("Employee $i, Shift $j on Day $k")
    end
end

```

Although its producing results, the model is infeasible and the number of employees is always the upper limit of 100

---

<div class="post-metadata">

**Author:** ![Honcho868](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/honcho868/32/213792_2.png) [@Honcho868](https://discourse.julialang.org/u/Honcho868)\
**Post date:** [November 28, 2024, 11:15pm UTC](https://discourse.julialang.org/t/staff-scheduling-optimization/123230/2 "2024-11-28T23:15:07Z")

</div>

![Screenshot 2023-12-06 153815](https://global.discourse-cdn.com/julialang/original/3X/7/3/73188e5fce47ef9dcc82ed3084ad70c47b9bb592.png)

This is from the paper

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [November 28, 2024, 11:34pm UTC](https://discourse.julialang.org/t/staff-scheduling-optimization/123230/3 "2024-11-28T23:34:49Z")

</div>

Note that you have

> `status = termination_status(m)`

but your model is called `model`. You’re looking up the termination status of some other JuMP model.

Also note that you’ve asked to minimise the number shifts worked. The objective does not have a component to minimise the distinct number of employees.

Also note that:

> `println("Number of Employees: ", N)`

you’re just printing out the constant `N`. If you do:

> `println("Number of Employees: ", sum(value.(y)))`

You’ll find that you’re using 48 employees.

---

<div class="post-metadata">

**Author:** ![Honcho868](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/honcho868/32/213792_2.png) [@Honcho868](https://discourse.julialang.org/u/Honcho868)\
**Post date:** [November 29, 2024, 12:21am UTC](https://discourse.julialang.org/t/staff-scheduling-optimization/123230/4 "2024-11-29T00:21:03Z")

</div>

ahhhhh such a silly error, ok i understand now. Thank you

I just noticed the the status error as well as you mentioned it so thank you for that too.

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [November 29, 2024, 12:34am UTC](https://discourse.julialang.org/t/staff-scheduling-optimization/123230/5 "2024-11-29T00:34:18Z")

</div>

No problem 😄

---

<div class="post-metadata">

**Author:** ![Honcho868](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/honcho868/32/213792_2.png) [@Honcho868](https://discourse.julialang.org/u/Honcho868)\
**Post date:** [November 29, 2024, 12:40am UTC](https://discourse.julialang.org/t/staff-scheduling-optimization/123230/6 "2024-11-29T00:40:16Z")

</div>

I know the variable y is for whether an employee worked a shift or not. What do the constraints below determine, mainly the second of the 2

```julia
@constraint(model, [i in 1:N], sum(x[i, :, :]) <= J * K * y[i]) # y[i] is 1 if employee i is used
@constraint(model, [i in 2:N], y[i-1] >= y[i]) # Ordering on y[i]. If we don't use y[i-1], then we can't use y[i]

```

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [November 29, 2024, 12:50am UTC](https://discourse.julialang.org/t/staff-scheduling-optimization/123230/7 "2024-11-29T00:50:36Z")

</div>

Where did you get the code from? Did you not write the comments?

The first constraints say that if `y[i] == 0` then all of the `x[i` variables must be zero.

The second is a symmetry breaking constraint that does not change the optimal objective value, but ensures that the `y` are used in order. Otherwise there would be many more equivalent solutions with different permutations of `y`.

---

<div class="post-metadata">

**Author:** ![Honcho868](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/honcho868/32/213792_2.png) [@Honcho868](https://discourse.julialang.org/u/Honcho868)\
**Post date:** [November 29, 2024, 1:12am UTC](https://discourse.julialang.org/t/staff-scheduling-optimization/123230/8 "2024-11-29T01:12:57Z")

</div>

Yeah i adapted the code from the previous thread because i didnt have a y variable originally in mine. I understood the first constraint wrt to the variable created for y, was just a little hazy on the second one but i understand it now. It simply ensures that the model doesnt skip any of the employees when determining an optimal solution so y[i-1] must be equal to 1 (have worked a shift) before y[i] can work a shift.
