I'm working on an app which aims to give an optimized weekly planning considering multiple constraints ( Hours per week, availabilities of each person, etc... ). My app is built entirely with node js, and i'm using glpk.js. It is working quite well, and i'm able to generate my planning, but i'm struggling while adding a new constraint to my LP problem.
Basically, i want each employee's shift to last at least 3 hours.
Here are my types, employeer's availabilities is an array of 14 (number of shift per week) number (0, or 1) where each value represent an employee availability for the shift 'x' :
export interface LPEmployeeInput {
id: number;
name: string;
availability: number[];
hoursPerWeek: number;
formations: string[];
}
export interface LPDailyNeed {
hour: number;
kitchen: number;
service: number;
manager: number;
}
Here is an example of a daily need :
[
{ hour: 11, kitchen: 1, service: 1, manager: 1 },
{ hour: 12, kitchen: 1, service: 2, manager: 1 },
{ hour: 13, kitchen: 1, service: 2, manager: 1 },
{ hour: 14, kitchen: 1, service: 2, manager: 1 },
{ hour: 18, kitchen: 2, service: 1, manager: 1 },
{ hour: 19, kitchen: 2, service: 2, manager: 1 },
{ hour: 20, kitchen: 2, service: 2, manager: 1 },
{ hour: 21, kitchen: 2, service: 1, manager: 1 }
]
Here is the LP solve code :
const lp: LP = {
name: 'Employee Scheduling',
objective: {
direction: glpk.GLP_MAX,
name: 'total_hours',
vars: []
},
subjectTo: []
};
// Add daily hours constraints
for (let i = 0; i < numEmployees; i++) {
for (let j = 0; j < numDays; j++) {
const noonVars: any[] = [];
const eveningVars: any[] = [];
for (let k = 0; k < dailyNeeds[j].length; k++) {
if(dailyNeeds[j][k].hour < shiftBreakpoint && employees[i].availability[j * 2] == 1){
//NOON
noonVars.push({ name: `x_${i}_${j}_${k}`, coef: 1 });
} else if(dailyNeeds[j][k].hour >= shiftBreakpoint && employees[i].availability[j * 2 + 1] == 1){
//EVENING
eveningVars.push({ name: `x_${i}_${j}_${k}`, coef: 1 });
}
}
if(employees[i].availability[j * 2] == 1){
lp.subjectTo.push({
name: `daily_hours_${i}_${j}_noon`,
vars: noonVars,
bnds: { type: glpk.GLP_LO, ub: Infinity, lb: 2 }
});
}
if(employees[i].availability[j * 2 + 1] == 1){
lp.subjectTo.push({
name: `daily_hours_${i}_${j}_evening`,
vars: eveningVars,
bnds: { type: glpk.GLP_LO, ub: Infinity, lb: 2 }
});
}
}
}
// Than there is Others constraints
// Solve the problem
const result = glpk.solve(lp, glpk.GLP_MSG_ALL);
EDIT : In the following code, i'm adding a constraint that ensure an employee that come to work for a shift will work at least two hours. Now how can I keep this constraint while still accepting an employee to work 0 hours on a day.
I've been reading the glpk docs since a moment now, but i'm struggling findin a solution. The 'glpk.GLP_DP' seems to not work in my case, cause i need the number of hours to be <= 0 and >= 3 which does not work together.