Original Message:
Sent: Fri April 22, 2022 06:03 AM
From: Renaud Dumeur
Subject: Additional setup time due to secondary resource
Dear Sebastian,
Here is a model that no longer relies on the distance matrix in the no overlap constrainst but explicitely creates job and pod setups.
It relies on the sequence type_of_prev for pods or jobs to determine if a setup interval is present.
It then use the distance matrix to configure the length of the setup intervals.
I hope it helps.
Cheers,
Edit: simplified the pod setup presence status propagation
from docplex.cp import model as cpfrom random import randint, seedjobs = [0, 1, 2, 3]pod_capacity = 3seed(1)model = cp.CpoModel()# Intervals: the jobs to be executedits = [cp.interval_var(length=1, name=f'J{j}') for j in jobs]# Ensure intervals do not overlap and add setup time between each intervaldistance_matrix = [[randint(1, 5) for _ in range(len(jobs))] for _ in range(len(jobs))]seq = cp.sequence_var(vars=its, types=jobs, name='Seq')#model.add(cp.no_overlap(sequence=seq, distance_matrix=distance_matrix))model.add(cp.no_overlap(sequence=seq))# Alternative intervals, one per available containerpod1_its = [cp.interval_var(optional=True, name=f'Pod1_J{j}') for j in jobs]pod2_its = [cp.interval_var(optional=True, name=f'Pod2_J{j}') for j in jobs]# Ensure one of the helper intervals is executedfor j in jobs: model.add(cp.alternative(its[j], [pod1_its[j], pod2_its[j]]))# create a sequence var for the containerspods = [0, 1]pod_its = pod1_its + pod2_itspod_types = [0]*len(pod1_its) + [1]*len(pod2_its)pod_seq = cp.sequence_var(vars=pod_its, types=pod_types, name='PodSeq')# transition time between different podspod_change_delay = 1pod_distance_matrix = [ [0 if i == j else pod_change_delay for i in pods ] for j in pods ]#model.add(cp.no_overlap(sequence=pod_seq, distance_matrix=pod_distance_matrix))model.add(cp.no_overlap(sequence=pod_seq))# materialize the job setup as intervalsjob_setups = [cp.interval_var(name=f'JobSetup_{j}', optional=True) for j in jobs]for js, itv, j in zip(job_setups, its, jobs): distance_to_j = [distance_matrix[i][j] for i in jobs] # if the job type changes, then instantiate the job setup model.add((cp.type_of_prev(seq, itv, -1, -1) != -1) == cp.presence_of(js)) model.add(cp.if_then(cp.presence_of(js), (cp.length_of(js) == cp.element(distance_to_j, cp.type_of_prev(seq, itv))) & (cp.end_of(js) == cp.start_of(itv))))# materialize the pod setups as intervalspod_setups = [cp.interval_var(name=f'PodSetup_{j}', optional=True) for j in jobs]for pod_type, pod_itv, j in zip(pod_types, pod_its, jobs + jobs): ps = pod_setups[j] js = job_setups[j] # if the used pod type changes, then a pod setup must be present model.add(cp.if_then(cp.presence_of(pod_itv), (cp.type_of_prev(pod_seq, pod_itv, pod_type, pod_type) != pod_type) == cp.presence_of(ps))) # if present a pod setup duration is taken from the matrix and must end before the start. model.add(cp.if_then(cp.presence_of(ps), (cp.length_of(ps) == pod_change_delay) & (cp.end_of(ps) == cp.min(cp.start_of(its[j]), cp.start_of(js, cp.INT_MAX)))))# put setup and job itvs in a sequenceglobal_seq = cp.sequence_var(vars = job_setups + pod_setups + its, name="global")# ensure they don't overlapmodel.add(cp.no_overlap(sequence=global_seq))# Ensure pods do not overlap# user constraintspod1_it = cp.interval_var(name='It_Pod1')pod2_it = cp.interval_var(name='It_Pod2')model.add(cp.span(pod1_it, pod1_its))model.add(cp.span(pod2_it, pod2_its))model.add(cp.no_overlap([pod1_it, pod2_it]))solution = model.solve(LogPeriod=1000000)if not solution: res=model.refine_conflict() print(res)model.export_model()solution.write()
------------------------------
Renaud Dumeur
------------------------------
Original Message:
Sent: Fri April 22, 2022 03:43 AM
From: Sebastian Bayer
Subject: Additional setup time due to secondary resource
Dear Renaud,
yes exactly, this is a setup change that needs to run after the primary setups are performed, i.e. sequentially.
Best
Sebastian
------------------------------
Sebastian Bayer
Original Message:
Sent: Fri April 22, 2022 03:16 AM
From: Renaud Dumeur
Subject: Additional setup time due to secondary resource
Dear Sebastian,
So do you actually want both setups to be performed in sequence rather than in parallel?
Cheers,
------------------------------
Renaud Dumeur
Original Message:
Sent: Thu April 21, 2022 09:32 AM
From: Sebastian Bayer
Subject: Additional setup time due to secondary resource
Dear Renaud,
it works perfectly the the distance between jobs is 0:
Pod1_J0 = IntervalVarValue(start=1, end=2, size=1)Pod1_J1 = IntervalVarValue(start=2, end=3, size=1)Pod1_J2 = IntervalVarValue(start=0, end=1, size=1)Pod1_J3 = ()Pod2_J0 = ()Pod2_J1 = ()Pod2_J2 = ()Pod2_J3 = IntervalVarValue(start=4, end=5, size=1)PodSeq = ['Pod1_J2', 'Pod1_J0', 'Pod1_J1', 'Pod2_J3']Seq = ['J2', 'J0', 'J1', 'J3']
In reality, however, the distance between jobs is unfortunately larger than the distance between secondary resources.
------------------------------
Sebastian Bayer
Original Message:
Sent: Thu April 21, 2022 09:27 AM
From: Renaud Dumeur
Subject: Additional setup time due to secondary resource
Dear Sebastian,
To check if this actually work, I suggest you try set the distance matrix for jobs to 0 and see the effect of the pods distance matrix.
Cheers,
------------------------------
Renaud Dumeur
Original Message:
Sent: Thu April 21, 2022 07:19 AM
From: Sebastian Bayer
Subject: Additional setup time due to secondary resource
Dear Renaud,
many thanks for taking time to reply!
Your suggestion does not work, unfortunately. The solution is still
Pod1_J0 = ()Pod1_J1 = ()Pod1_J2 = ()Pod1_J3 = IntervalVarValue(start=11, end=12, size=1)Pod2_J0 = IntervalVarValue(start=0, end=1, size=1)Pod2_J1 = IntervalVarValue(start=6, end=7, size=1)Pod2_J2 = IntervalVarValue(start=2, end=3, size=1)Pod2_J3 = ()PodSeq = ['Pod2_J0', 'Pod2_J2', 'Pod2_J1', 'Pod1_J3']Seq = ['J0', 'J2', 'J1', 'J3']
i.e., the start of Pod1_J3 is 11 and not 12.
I think the reason for this is that the setup time between the jobs is greater than the setup time between the pods. Thus, the additional constraint is always fulfilled.
Regards
Sebastian
------------------------------
Sebastian Bayer
Original Message:
Sent: Thu April 21, 2022 04:06 AM
From: Renaud Dumeur
Subject: Additional setup time due to secondary resource
Dear Sebastian,
Maybe the solution would be to create a secondary sequence containing each pod interval from pod1_its and pod2_its and impose a transition time when type pod type changes:
# create a sequence var for the containers
pods = [0, 1]
pod_seq = cp.sequence_var(vars=pod1_its + pod2_its, types=[0]*len(pod1_its) + [1]*len(pod2_its), name='PodSeq')
# transition time between different pods
pod_change_delay = 1
pod_distance_matrix = [ [0 if i == j else pod_change_delay for i in pods ] for j in pods ]
model.add(cp.no_overlap(sequence=pod_seq, distance_matrix=pod_distance_matrix))
This way, the alternative constraints select appropriate intervals in the pod_seq sequence which obeys the transition times specified by the matrix (1 if pod changes else 0).
I hope this helps.
Cheers,
------------------------------
Renaud Dumeur
Original Message:
Sent: Thu April 21, 2022 01:49 AM
From: Sebastian Bayer
Subject: Additional setup time due to secondary resource
Hello,
unfortunately I could not get anywhere with this topic. Does anyone in the community have any ideas on how to proceed here?
Thanks
Sebastian
------------------------------
Sebastian Bayer