Same shift every day #1543
-
|
Following the example of shift_scheduling_sat.py, how could I create a soft constraint that always defines the same shift every day for the same agent. |
Beta Was this translation helpful? Give feedback.
Replies: 18 comments
-
|
For each shift and each sequence of two days, create a boolean if both are
true.
create a boolean equivalent to the same shift being used every day of this
week using BoolAnd and BoolOr with implications
Then create a boolean equivalent to one of these above all week day
booleans being true.
Laurent Perron | Operations Research | [email protected] | (33) 1 42 68 53
00
Le mar. 3 sept. 2019 à 21:19, sergioterzella <[email protected]> a
écrit :
… Following the example of shift_scheduling_sat.py, how could I create a
soft constraint that always defines the same shift every day for the same
agent.
Remembering that the shift cannot be fixed, it must be done in conjunction
with the other constraints defined in the code.
thanks
Sergio Terzella
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<https://github.com/google/or-tools/issues/1543?email_source=notifications&email_token=ACUPL3NIIXLHEAPMFW3OF4LQH22E5A5CNFSM4ITJ52QKYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HJCFESA>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACUPL3KC4BPGBQARSJVEBKLQH22E5ANCNFSM4ITJ52QA>
.
|
Beta Was this translation helpful? Give feedback.
-
|
Thanks for your response! worker 00: O M M M M M M O A A A A A A O M M M M M M thanks |
Beta Was this translation helpful? Give feedback.
-
|
I am facing the same issue with rtools and I saw you reply to Sergio Terzella.
|
Beta Was this translation helpful? Give feedback.
-
|
Yes, half reified Boolean constraints.
Le mer. 4 sept. 2019 à 18:20, YagoRegis <[email protected]> a écrit :
… I am facing the same issue with rtools and I saw you reply to Sergio
Terzella.
are you saying to use reified constraint? thats the idea?
For each shift and each sequence of two days, create a boolean if both are
true. create a boolean equivalent to the same shift being used every day of
this week using BoolAnd and BoolOr with implications Then create a boolean
equivalent to one of these above all week day booleans being true. Laurent
Perron | Operations Research | ***@***.*** | (33) 1 42 68 53 00 Le
mar. 3 sept. 2019 à 21:19, sergioterzella ***@***.*** a
écrit :
… <#m_-5233035533147993232_>
Following the example of shift_scheduling_sat.py, how could I create a
soft constraint that always defines the same shift every day for the same
agent. Remembering that the shift cannot be fixed, it must be done in
conjunction with the other constraints defined in the code. thanks Sergio
Terzella — You are receiving this because you are subscribed to this
thread. Reply to this email directly, view it on GitHub <#1543
<https://github.com/google/or-tools/issues/1543>?email_source=notifications&email_token=ACUPL3NIIXLHEAPMFW3OF4LQH22E5A5CNFSM4ITJ52QKYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HJCFESA>,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACUPL3KC4BPGBQARSJVEBKLQH22E5ANCNFSM4ITJ52QA
.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<https://github.com/google/or-tools/issues/1543?email_source=notifications&email_token=ACUPL3OVLO6DRJHOVXGBJJTQH7N57A5CNFSM4ITJ52QKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD54EUZI#issuecomment-527977061>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACUPL3K2WD4OFBSMKC3MJWLQH7N57ANCNFSM4ITJ52QA>
.
|
Beta Was this translation helpful? Give feedback.
-
|
Iperron good afternoon, I tried to use the example of "Reified constraints", available at the link below, but I can't apply it to the scale model, certainly for lack of experience in Ortools. |
Beta Was this translation helpful? Give feedback.
-
|
what do you mean 'to the scale model' ? |
Beta Was this translation helpful? Give feedback.
-
|
a model for working scale generation as we have in the example shift_scheduling_sat.py. |
Beta Was this translation helpful? Give feedback.
-
|
ok, make it short 2 shifts, 3 days s0d0, s0d1, s0d2 create 2 x 2 extra var s0t0, s0t1, s1t0, s1t1 s0t0 is true iff s0d0 and s0d1 are true: repeat for the remaining 3 transitions. create 2 extra vars s0, s1 that are true if both transitions on the same shift are true exactly same code: repeat for s1. now s0 is true iif all s0dX are true, same thing for s1. One of them must be true: |
Beta Was this translation helpful? Give feedback.
-
|
Actually, this is over-complicated just do and keep |
Beta Was this translation helpful? Give feedback.
-
|
Any news ? |
Beta Was this translation helpful? Give feedback.
-
|
Sorry for the delay in answering, I was sick these days, I returned to work today. |
Beta Was this translation helpful? Give feedback.
-
|
Good afternoon @lperron , I had include the code as explained, however, the result generated were "INFEASIBLE". es = {} I believe this way we will also have problems with the day off shifts, which are not entering the calculation. |
Beta Was this translation helpful? Give feedback.
-
|
I include code in shift_scheduling_sat.py for testing: from __future__ import print_function
import argparse
from ortools.sat.python import cp_model
from google.protobuf import text_format
PARSER = argparse.ArgumentParser()
PARSER.add_argument(
'--output_proto',
default="",
help='Output file to write the cp_model'
'proto to.')
PARSER.add_argument('--params', default="", help='Sat solver parameters.')
def negated_bounded_span(works, start, length):
sequence = []
# Left border (start of works, or works[start - 1])
if start > 0:
sequence.append(works[start - 1])
for i in range(length):
sequence.append(works[start + i].Not())
# Right border (end of works or works[start + length])
if start + length < len(works):
sequence.append(works[start + length])
return sequence
def add_soft_sequence_constraint(model, works, hard_min, soft_min, min_cost,soft_max, hard_max, max_cost, prefix):
cost_literals = []
cost_coefficients = []
# Forbid sequences that are too short.
for length in range(1, hard_min):
for start in range(len(works) - length + 1):
model.AddBoolOr(negated_bounded_span(works, start, length))
# Penalize sequences that are below the soft limit.
if min_cost > 0:
for length in range(hard_min, soft_min):
for start in range(len(works) - length + 1):
span = negated_bounded_span(works, start, length)
name = ': under_span(start=%i, length=%i)' % (start, length)
lit = model.NewBoolVar(prefix + name)
span.append(lit)
model.AddBoolOr(span)
cost_literals.append(lit)
# We filter exactly the sequence with a short length.
# The penalty is proportional to the delta with soft_min.
cost_coefficients.append(min_cost * (soft_min - length))
# Penalize sequences that are above the soft limit.
if max_cost > 0:
for length in range(soft_max + 1, hard_max + 1):
for start in range(len(works) - length + 1):
span = negated_bounded_span(works, start, length)
name = ': over_span(start=%i, length=%i)' % (start, length)
lit = model.NewBoolVar(prefix + name)
span.append(lit)
model.AddBoolOr(span)
cost_literals.append(lit)
# Cost paid is max_cost * excess length.
cost_coefficients.append(max_cost * (length - soft_max))
# Just forbid any sequence of true variables with length hard_max + 1
for start in range(len(works) - hard_max):
model.AddBoolOr(
[works[i].Not() for i in range(start, start + hard_max + 1)])
return cost_literals, cost_coefficients
def add_soft_sum_constraint(model, works, hard_min, soft_min, min_cost,soft_max, hard_max, max_cost, prefix):
cost_variables = []
cost_coefficients = []
sum_var = model.NewIntVar(hard_min, hard_max, '')
# This adds the hard constraints on the sum.
model.Add(sum_var == sum(works))
# Penalize sums below the soft_min target.
if soft_min > hard_min and min_cost > 0:
delta = model.NewIntVar(-len(works), len(works), '')
model.Add(delta == soft_min - sum_var)
# TODO(user): Compare efficiency with only excess >= soft_min - sum_var.
excess = model.NewIntVar(0, 7, prefix + ': under_sum')
model.AddMaxEquality(excess, [delta, 0])
cost_variables.append(excess)
cost_coefficients.append(min_cost)
# Penalize sums above the soft_max target.
if soft_max < hard_max and max_cost > 0:
delta = model.NewIntVar(-7, 7, '')
model.Add(delta == sum_var - soft_max)
excess = model.NewIntVar(0, 7, prefix + ': over_sum')
model.AddMaxEquality(excess, [delta, 0])
cost_variables.append(excess)
cost_coefficients.append(max_cost)
return cost_variables, cost_coefficients
def solve_shift_scheduling(params, output_proto):
# Data
num_employees = 8
num_weeks = 3
shifts = ['O', 'M', 'A', 'N']
# daily demands for work shifts (morning, afternon, night) for each day
# of the week starting on Monday.
weekly_cover_demands = [
(2, 3, 1), # Monday
(2, 3, 1), # Tuesday
(2, 2, 2), # Wednesday
(2, 3, 1), # Thursday
(2, 2, 2), # Friday
(1, 2, 3), # Saturday
(1, 3, 1), # Sunday
]
# Penalty for exceeding the cover constraint per shift type.
excess_cover_penalties = (2, 2, 5)
num_days = num_weeks * 7
num_shifts = len(shifts)
model = cp_model.CpModel()
work = {}
for e in range(num_employees):
for s in range(num_shifts):
for d in range(num_days):
work[e, s, d] = model.NewBoolVar('work%i_%i_%i' % (e, s, d))
# Linear terms of the objective in a minimization context.
obj_int_vars = []
obj_int_coeffs = []
obj_bool_vars = []
obj_bool_coeffs = []
# Exactly one shift per day.
for e in range(num_employees):
for d in range(num_days):
model.Add(sum(work[e, s, d] for s in range(num_shifts)) == 1)
# Cover constraints
for s in range(1, num_shifts):
for w in range(num_weeks):
for d in range(7):
works = [work[e, s, w * 7 + d] for e in range(num_employees)]
# Ignore Off shift.
min_demand = weekly_cover_demands[d][s - 1]
worked = model.NewIntVar(min_demand, num_employees, '')
model.Add(worked == sum(works))
over_penalty = excess_cover_penalties[s - 1]
if over_penalty > 0:
name = 'excess_demand(shift=%i, week=%i, day=%i)' % (s, w,d)
excess = model.NewIntVar(0, num_employees - min_demand,name)
model.Add(excess == worked - min_demand)
obj_int_vars.append(excess)
obj_int_coeffs.append(over_penalty)
# Controla dias trabalhados por semana
for e in range(num_employees):
for w in range(num_weeks):
works = [work[e, s, d + w * 7] for d in [0,1,2,3,4,5,6] for s in range(1,num_shifts)] # Folgar qualquer dia da semana
#works = [work[e, s, d + w * 7] for d in [0,1,2,3,4] for s in range(3,num_shifts)] # Folgar em dias da semana
#print(works)
# soft_min > hard_min and min_cost > 0 AND soft_max < hard_max and max_cost > 0 para penalizar
# (hard_min, soft_min, min_penalty, soft_max, hard_max, max_penalty)
lista_limites = (0 , 5, 100, 5, 6, 100)
#lista_limites = (0 , 6, 100, 6, 7, 100)
hard_min = lista_limites[0]
soft_min = lista_limites[1]
min_cost = lista_limites[2]
soft_max = lista_limites[3]
hard_max = lista_limites[4]
max_cost = lista_limites[5]
variables, coeffs = add_soft_sum_constraint(model, works, hard_min, soft_min, min_cost, soft_max,hard_max, max_cost,'Trabalhar %i dias(agente %i, week %i)' % (soft_max,e, w))
obj_int_vars.extend(variables)
obj_int_coeffs.extend(coeffs)
es = {}
for e in range(num_employees):
for s in range(1,num_shifts):
es[e, s] = model.NewBoolVar('es%i_%i' % (e, s))
for d in range(num_days):
if d+1 <= num_shifts:
model.AddBoolAnd([work[e, s, d],work[e, s, d+1]]).OnlyEnforceIf(es[e, s])
model.AddBoolOr([work[e, s, d].Not(), work[e, s, d+1].Not(), es[e, s]])
model.AddBoolOr([es[e,s] for s in range(1,num_shifts)])
"""es = {}
for e in range(num_employees):
for s in range(3,num_shifts):
es[e, s] = model.NewBoolVar('es%i_%i' % (e, s))
model.AddBoolAnd([work[e, s, d] for d in range(num_days)]).OnlyEnforceIf(es[e,s])
lista = [work[e, s, d].Not() for d in range(num_days)]
lista.append(es[e, s])
model.AddBoolOr(lista)
model.AddBoolOr([es[e, s] for s in range(3,num_shifts)])"""
# Objective
model.Minimize(
sum(obj_bool_vars[i] * obj_bool_coeffs[i]
for i in range(len(obj_bool_vars)))
+ sum(obj_int_vars[i] * obj_int_coeffs[i]
for i in range(len(obj_int_vars))))
if output_proto:
print('Writing proto to %s' % output_proto)
with open(output_proto, 'w') as text_file:
text_file.write(str(model))
# Solve the model.
solver = cp_model.CpSolver()
solver.parameters.num_search_workers = 8
if params:
text_format.Merge(params, solver.parameters)
solution_printer = cp_model.ObjectiveSolutionPrinter()
status = solver.SolveWithSolutionCallback(model, solution_printer)
# Print solution.
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print()
header = ' '
for w in range(num_weeks):
header += 'SEG TER QUA QUI SEX SAB DOM '
print(header)
for e in range(num_employees):
schedule = ''
for d in range(num_days):
for s in range(num_shifts):
if solver.BooleanValue(work[e, s, d]):
schedule += ' '+ shifts[s] + ' '
print('worker %i: %s' % (e, schedule))
print()
print('Penalties:')
for i, var in enumerate(obj_bool_vars):
if solver.BooleanValue(var):
penalty = obj_bool_coeffs[i]
if penalty > 0:
print(' %s violated, penalty=%i' % (var.Name(), penalty))
else:
print(' %s fulfilled, gain=%i' % (var.Name(), -penalty))
for i, var in enumerate(obj_int_vars):
if solver.Value(var) > 0:
print(' %s violated by %i, linear penalty=%i' %
(var.Name(), solver.Value(var), obj_int_coeffs[i]))
print()
print(solver.ResponseStats())
def main(args):
solve_shift_scheduling(args.params, args.output_proto)
if __name__ == '__main__':
main(PARSER.parse_args())` |
Beta Was this translation helpful? Give feedback.
-
|
I do not have the time to debug your code.
Reduce your model, add 1 constraint at a time, and make sure you verify
your code at each step.
Laurent Perron | Operations Research | [email protected] | (33) 1 42 68 53
00
Le mar. 10 sept. 2019 à 21:39, sergioterzella <[email protected]> a
écrit :
… I include code in shift_scheduling_sat.py for testing:
`from *future* import print_function
import argparse
from ortools.sat.python import cp_model
from google.protobuf import text_format
PARSER = argparse.ArgumentParser()
PARSER.add_argument(
'--output_proto',
default="",
help='Output file to write the cp_model'
'proto to.')
PARSER.add_argument('--params', default="", help='Sat solver parameters.')
def negated_bounded_span(works, start, length):
sequence = []
# Left border (start of works, or works[start - 1])
if start > 0:
sequence.append(works[start - 1])
for i in range(length):
sequence.append(works[start + i].Not())
# Right border (end of works or works[start + length])
if start + length < len(works):
sequence.append(works[start + length])
return sequence
def add_soft_sequence_constraint(model, works, hard_min, soft_min,
min_cost,soft_max, hard_max, max_cost, prefix):
cost_literals = []
cost_coefficients = []
# Forbid sequences that are too short.
for length in range(1, hard_min):
for start in range(len(works) - length + 1):
model.AddBoolOr(negated_bounded_span(works, start, length))
# Penalize sequences that are below the soft limit.
if min_cost > 0:
for length in range(hard_min, soft_min):
for start in range(len(works) - length + 1):
span = negated_bounded_span(works, start, length)
name = ': under_span(start=%i, length=%i)' % (start, length)
lit = model.NewBoolVar(prefix + name)
span.append(lit)
model.AddBoolOr(span)
cost_literals.append(lit)
# We filter exactly the sequence with a short length.
# The penalty is proportional to the delta with soft_min.
cost_coefficients.append(min_cost * (soft_min - length))
# Penalize sequences that are above the soft limit.
if max_cost > 0:
for length in range(soft_max + 1, hard_max + 1):
for start in range(len(works) - length + 1):
span = negated_bounded_span(works, start, length)
name = ': over_span(start=%i, length=%i)' % (start, length)
lit = model.NewBoolVar(prefix + name)
span.append(lit)
model.AddBoolOr(span)
cost_literals.append(lit)
# Cost paid is max_cost * excess length.
cost_coefficients.append(max_cost * (length - soft_max))
# Just forbid any sequence of true variables with length hard_max + 1
for start in range(len(works) - hard_max):
model.AddBoolOr(
[works[i].Not() for i in range(start, start + hard_max + 1)])
return cost_literals, cost_coefficients
def add_soft_sum_constraint(model, works, hard_min, soft_min,
min_cost,soft_max, hard_max, max_cost, prefix):
cost_variables = []
cost_coefficients = []
sum_var = model.NewIntVar(hard_min, hard_max, '')
# This adds the hard constraints on the sum.
model.Add(sum_var == sum(works))
# Penalize sums below the soft_min target.
if soft_min > hard_min and min_cost > 0:
delta = model.NewIntVar(-len(works), len(works), '')
model.Add(delta == soft_min - sum_var)
# TODO(user): Compare efficiency with only excess >= soft_min - sum_var.
excess = model.NewIntVar(0, 7, prefix + ': under_sum')
model.AddMaxEquality(excess, [delta, 0])
cost_variables.append(excess)
cost_coefficients.append(min_cost)
# Penalize sums above the soft_max target.
if soft_max < hard_max and max_cost > 0:
delta = model.NewIntVar(-7, 7, '')
model.Add(delta == sum_var - soft_max)
excess = model.NewIntVar(0, 7, prefix + ': over_sum')
model.AddMaxEquality(excess, [delta, 0])
cost_variables.append(excess)
cost_coefficients.append(max_cost)
return cost_variables, cost_coefficients
def solve_shift_scheduling(params, output_proto):
# Data
num_employees = 8
num_weeks = 3
shifts = ['O', 'M', 'A', 'N']
# daily demands for work shifts (morning, afternon, night) for each day
# of the week starting on Monday.
weekly_cover_demands = [
(2, 3, 1), # Monday
(2, 3, 1), # Tuesday
(2, 2, 2), # Wednesday
(2, 3, 1), # Thursday
(2, 2, 2), # Friday
(1, 2, 3), # Saturday
(1, 3, 1), # Sunday
]
# Penalty for exceeding the cover constraint per shift type.
excess_cover_penalties = (2, 2, 5)
num_days = num_weeks * 7
num_shifts = len(shifts)
model = cp_model.CpModel()
work = {}
for e in range(num_employees):
for s in range(num_shifts):
for d in range(num_days):
work[e, s, d] = model.NewBoolVar('work%i_%i_%i' % (e, s, d))
# Linear terms of the objective in a minimization context.
obj_int_vars = []
obj_int_coeffs = []
obj_bool_vars = []
obj_bool_coeffs = []
# Exactly one shift per day.
for e in range(num_employees):
for d in range(num_days):
model.Add(sum(work[e, s, d] for s in range(num_shifts)) == 1)
# Cover constraints
for s in range(1, num_shifts):
for w in range(num_weeks):
for d in range(7):
works = [work[e, s, w * 7 + d] for e in range(num_employees)]
# Ignore Off shift.
min_demand = weekly_cover_demands[d][s - 1]
worked = model.NewIntVar(min_demand, num_employees, '')
model.Add(worked == sum(works))
over_penalty = excess_cover_penalties[s - 1]
if over_penalty > 0:
name = 'excess_demand(shift=%i, week=%i, day=%i)' % (s, w,d)
excess = model.NewIntVar(0, num_employees - min_demand,name)
model.Add(excess == worked - min_demand)
obj_int_vars.append(excess)
obj_int_coeffs.append(over_penalty)
# Controla dias trabalhados por semana
for e in range(num_employees):
for w in range(num_weeks):
works = [work[e, s, d + w * 7] for d in [0,1,2,3,4,5,6] for s in range(1,num_shifts)] # Folgar qualquer dia da semana
#works = [work[e, s, d + w * 7] for d in [0,1,2,3,4] for s in range(3,num_shifts)] # Folgar em dias da semana
#print(works)
# soft_min > hard_min and min_cost > 0 AND soft_max < hard_max and max_cost > 0 para penalizar
# (hard_min, soft_min, min_penalty, soft_max, hard_max, max_penalty)
lista_limites = (0 , 5, 100, 5, 6, 100)
#lista_limites = (0 , 6, 100, 6, 7, 100)
hard_min = lista_limites[0]
soft_min = lista_limites[1]
min_cost = lista_limites[2]
soft_max = lista_limites[3]
hard_max = lista_limites[4]
max_cost = lista_limites[5]
variables, coeffs = add_soft_sum_constraint(model, works, hard_min, soft_min, min_cost, soft_max,hard_max, max_cost,'Trabalhar %i dias(agente %i, week %i)' % (soft_max,e, w))
obj_int_vars.extend(variables)
obj_int_coeffs.extend(coeffs)
es = {}
for e in range(num_employees):
for s in range(1,num_shifts):
es[e, s] = model.NewBoolVar('es%i_%i' % (e, s))
for d in range(num_days):
if d+1 <= num_shifts:
model.AddBoolAnd([work[e, s, d],work[e, s, d+1]]).OnlyEnforceIf(es[e, s])
model.AddBoolOr([work[e, s, d].Not(), work[e, s, d+1].Not(), es[e, s]])
model.AddBoolOr([es[e,s] for s in range(1,num_shifts)])
"""es = {}
for e in range(num_employees):
for s in range(3,num_shifts):
es[e, s] = model.NewBoolVar('es%i_%i' % (e, s))
model.AddBoolAnd([work[e, s, d] for d in range(num_days)]).OnlyEnforceIf(es[e,s])
lista = [work[e, s, d].Not() for d in range(num_days)]
lista.append(es[e, s])
model.AddBoolOr(lista)
model.AddBoolOr([es[e, s] for s in range(3,num_shifts)])"""
# Objective
model.Minimize(
sum(obj_bool_vars[i] * obj_bool_coeffs[i]
for i in range(len(obj_bool_vars)))
+ sum(obj_int_vars[i] * obj_int_coeffs[i]
for i in range(len(obj_int_vars))))
if output_proto:
print('Writing proto to %s' % output_proto)
with open(output_proto, 'w') as text_file:
text_file.write(str(model))
# Solve the model.
solver = cp_model.CpSolver()
solver.parameters.num_search_workers = 8
if params:
text_format.Merge(params, solver.parameters)
solution_printer = cp_model.ObjectiveSolutionPrinter()
status = solver.SolveWithSolutionCallback(model, solution_printer)
# Print solution.
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print()
header = ' '
for w in range(num_weeks):
header += 'SEG TER QUA QUI SEX SAB DOM '
print(header)
for e in range(num_employees):
schedule = ''
for d in range(num_days):
for s in range(num_shifts):
if solver.BooleanValue(work[e, s, d]):
schedule += ' '+ shifts[s] + ' '
print('worker %i: %s' % (e, schedule))
print()
print('Penalties:')
for i, var in enumerate(obj_bool_vars):
if solver.BooleanValue(var):
penalty = obj_bool_coeffs[i]
if penalty > 0:
print(' %s violated, penalty=%i' % (var.Name(), penalty))
else:
print(' %s fulfilled, gain=%i' % (var.Name(), -penalty))
for i, var in enumerate(obj_int_vars):
if solver.Value(var) > 0:
print(' %s violated by %i, linear penalty=%i' %
(var.Name(), solver.Value(var), obj_int_coeffs[i]))
print()
print(solver.ResponseStats())
def main(args):
solve_shift_scheduling(args.params, args.output_proto)
if *name* == '*main*':
main(PARSER.parse_args())`
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<https://github.com/google/or-tools/issues/1543?email_source=notifications&email_token=ACUPL3ITZHHDDJJNHAZ46NDQI7ZXTA5CNFSM4ITJ52QKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6MIFSA#issuecomment-530088648>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACUPL3KZ3YKYDR3CETIM5JDQI7ZXTANCNFSM4ITJ52QA>
.
|
Beta Was this translation helpful? Give feedback.
-
|
Sorry but my intention was not to ask you to debug my code, but to show where I am trying to apply the code. Sorry again and thanks for the help. |
Beta Was this translation helpful? Give feedback.
-
|
I am also creatin a workin scale using or-tools as example. I understood that a I need to include the agent at the same shift level, is that right? es_extra = {}
for e in range(num_employees):
for s in range(num_shifts):
es_extra[e, s] = model.NewBoolVar('work_extra%i_%i' % (e, s))
lt = []
for e in range(num_employees):
for s in range(num_shifts):
works = [work[e, s, d] for d in range(num_days)]
model.AddBoolAnd(works).OnlyEnforceIf(es_extra[e,s])
works1 = [work[e, s, d].Not() for d in range(num_days)]
works1.append(es_extra[e,s])
model.AddBoolOr(works1)
lt.append(es_extra[e,s])
model.AddBoolOr(lt)Should i include all days or just 3 days in the constraint. like the example? works = [work[e, s, d] for d in range(num_days)] The above code did not create a same day shift sequence as I expected. And, would we get the constraint using the first day shift? thanks in advice. |
Beta Was this translation helpful? Give feedback.
-
|
I believe you need to forbid the same pattern for each consecutive starts of the pattern. |
Beta Was this translation helpful? Give feedback.
-
|
Seems dead. Moving to the discussions part. |
Beta Was this translation helpful? Give feedback.
Seems dead. Moving to the discussions part.