s.level * mdl.presence_of(wtasks[(h, s)]) for s in SKILLS for h in HOUSES ]) mdl.add(mdl.maximize(obj2)) # Constraints of the model for h in HOUSES: # Temporal constraints for p in TASK_PRECEDENCES: mdl.add( mdl.end_before_start(tasks[(h, find_tasks(p.beforeTask))], tasks[(h, find_tasks(p.afterTask))])) # Alternative workers for t in TASKS: mdl.add( mdl.alternative( tasks[(h, t)], [wtasks[(h, s)] for s in SKILLS if (s.task == t.name)], 1)) # Continuity constraints for c in CONTINUITIES: mdl.add( mdl.presence_of(wtasks[(h, find_skills(c.worker, c.task1))]) == mdl.presence_of(wtasks[(h, find_skills(c.worker, c.task2))])) # No overlap constraint for w in WORKERS: mdl.add( mdl.no_overlap( [wtasks[(h, s)] for h in HOUSES for s in SKILLS if s.worker == w])) #----------------------------------------------------------------------------- # Solve the model and display the result
# Create model mdl = CpoModel() # Create one interval variable per task tasks = {t['id']: mdl.interval_var(name="T{}".format(t['id'])) for t in TASKS} # Add precedence constraints for t in TASKS: for s in t['successors']: mdl.add(mdl.end_before_start(tasks[t['id']], tasks[s])) # Create one optional interval variable per task mode and add alternatives for tasks modes = {} # Map of all modes for t in TASKS: tmds = [mdl.interval_var(name=m['id'], optional=True, size=m['duration']) for m in t['modes']] mdl.add(mdl.alternative(tasks[t['id']], tmds)) for m in tmds: modes[m.name] = m # Initialize pulse functions for renewable and non renewable resources renewables = [mdl.pulse((0, 0), 0) for j in range(NB_RENEWABLE)] non_renewables = [0 for j in range(NB_NON_RENEWABLE)] for m in MODES: dren = m['demandRenewable'] dnren = m['demandNonRenewable'] for j in range(NB_RENEWABLE): dem = m['demandRenewable'][j] if dem > 0: renewables[j] += mdl.pulse(modes[m['id']], dem) for j in range(NB_NON_RENEWABLE): dem = m['demandNonRenewable'][j]
task_machine_intervals[i], 1)) model.add( model.always_in(machine_on_off[m_id], task_machine_intervals[i], 1, 1)) # Add resource usage by task for j in range(NUM_RESOURCES): machine_resources[m_id][j] += model.pulse( task_machine_intervals[i], task['resource_usage'][j]) # For visualization task_intervals_on_machines[m_id].append( (task, task_machine_intervals[i])) # Only one interval will be effective model.add(model.alternative(task_interval, task_machine_intervals)) task_intervals.append((task, task_interval)) # Add power consumption by tasks cost_tasks = model.sum([ model.start_eval(task_int, energy_intervals_array[task['duration'] - 1]) * task['power_consumption'] for task, task_int in task_intervals ]) # Add resource capacity constraints for machine in data['machines']: m_id = machine['id'] for j in range(NUM_RESOURCES): model.add( machine_resources[m_id][j] <= machine['resource_capacities'][j])
# посмотрим, что создали # print_tasks(tasks) # Реально выполняемые задачи tasks_act = [mdl.interval_var(name="T{}_{}".format(str(i), WAIT_ORDERS[i][1]), size=WAIT_ORDERS[i][0], start=(0, MAX_SCHEDULE), end=(0, MAX_SCHEDULE)) for i in range(ORDERS_COUNT)] # одна задача - один монтажник for i in range(ORDERS_COUNT): a_t = WAIT_ORDERS[i][1] kk = [tasks[p][k] for p in range(WORKERS_COUNT) for k in range(len(tasks[p])) if (tasks[p][k].get_name() == a_t)] if len(kk) != 0: mdl.add(mdl.alternative(tasks_act[i], kk, 1)) # в один момент времени - одна задача for i in range(WORKERS_COUNT): mdl.add(mdl.no_overlap(tasks[i])) # все задачи должны быть выполнены for i in range(ORDERS_COUNT): a_t = TASK_TEMPLATE_NAME.format(num=str(i), name=WAIT_ORDERS[i][1]) mdl.add(mdl.sum([mdl.presence_of(t) for k in tasks for t in k if t.get_name() == a_t]) > 0) # OF mdl.add( mdl.minimize(mdl.max([mdl.end_of(t) * mdl.presence_of(t) for i, tp in enumerate(tasks) for j, t in enumerate(tp)])) )
tasks_m1 = [ mdl.interval_var(name="A{}_M1_TP{}".format(i, TASK_TYPE[i]), optional=True) for i in range(NB_TASKS) ] tasks_m2 = [ mdl.interval_var(name="A{}_M2_TP{}".format(i, TASK_TYPE[i]), optional=True) for i in range(NB_TASKS) ] # Build actual tasks as an alternative between machines tasks = [ mdl.interval_var(name="A{}_TP{}".format(i, TASK_TYPE[i]), size=TASK_DURATION[i]) for i in range(NB_TASKS) ] for i in range(NB_TASKS): mdl.add(mdl.alternative(tasks[i], [tasks_m1[i], tasks_m2[i]])) # Build a map to retrieve task id from variable name (for display purpose) task_id = dict() for i in range(NB_TASKS): task_id[tasks_m1[i].get_name()] = i task_id[tasks_m2[i].get_name()] = i # Constrain tasks to no overlap on each machine s1 = mdl.sequence_var(tasks_m1, types=TASK_TYPE, name='M1') s2 = mdl.sequence_var(tasks_m2, types=TASK_TYPE, name='M2') mdl.add(mdl.no_overlap(s1, SETUP_M1, 1)) mdl.add(mdl.no_overlap(s2, SETUP_M2, 1)) # Minimize the number of "long" setup times on machines. nbLongSetups = 0
for j in range(NB_JOBS): # print(j) for p in Precedences: # print((j,JOBS[j][2 * p[0]]),(j,JOBS[j][2 * p[1]])) mdl.add( mdl.end_before_start(tasks[j,JOBS[j][2 * p[0]],p[0]], tasks[j,JOBS[j][2 * p[1]],p[1]]) ) #for j in range(NB_JOBS): # for t in Tasks[j]: # print( (j,JOBS[j][2 * t]), [(j,s) for s in Skills[j] if s[0][:len('M'+str(JOBS[j][2 * t])) ] == 'M'+str(JOBS[j][2 * t]) and s[0][len('M'+str(JOBS[j][2 * t])): len('M'+str(JOBS[j][2 * t]))+1] in 'e'] ) for j in range(NB_JOBS): for t in Tasks[j]: mdl.add( mdl.alternative( tasks[j,JOBS[j][2 * t],t], [mtasks[j,s] for s in Skills[j] if s[0][:len('M'+str(JOBS[j][2 * t]))] == 'M'+str(JOBS[j][2 * t]) and s[0][len('M'+str(JOBS[j][2 * t])): len('M'+str(JOBS[j][2 * t]))+1] in 'e' ] ) ) for m in Maschines: # print([(j,s) for j in range(NB_JOBS) for s in Skills[j] if s[0]==m]) mdl.add( mdl.no_overlap([mtasks[j,s] for j in range(NB_JOBS) for s in Skills[j] if s[0]==m]) ) # Minimize termination date mdl.add(mdl.minimize(mdl.max([mdl.end_of(tasks[i,JOBS[i][2 * Tasks[i][-1] ],NB_MACHINES - 1]) for i in range(NB_JOBS)]))) #----------------------------------------------------------------------------- # Solve the model and display the result #----------------------------------------------------------------------------- # Solve model #print("Solving model....")
#zadadim obshie for d in range(numdetails): _name = "obtain_parts{}".format(d + 1) itvs[(d, 0)] = mdl.interval_var(size=minutes_on_obtain_parts[d], name=_name) for d in range(numdetails): _name = "repair{}".format(d + 1) itvs[(d, 1)] = mdl.interval_var(size=minutes_on_repair[d], name=_name) for d in range(numdetails): _name = "delivery{}".format(d + 1) itvs[(d, 2)] = mdl.interval_var(size=minutes_on_delivery[d], name=_name) #альтернатива между работниками for i in range(numdetails): for j in range(2): mdl.add( mdl.alternative(itvs[(i, j)], [itvs_3[(i, j)], itvs_2[(i, j)], itvs_1[(i, j)]])) #навесим последовательность TO DO для 1,2,3 #for h in range(numdetails): # mdl.add(mdl.end_before_start(itvs[(h, 1)], itvs[(h, 2)])) #for h in range(numdetails): # mdl.add(mdl.end_before_start(itvs[(h, 0)], itvs[(h, 1)])) #навесим последовательность жестко for h in range(numdetails): mdl.add(mdl.end_before_start(itvs[(h, 1)], itvs[(h, 2)])) for h in range(numdetails): mdl.add(mdl.end_before_start(itvs[(h, 0)], itvs[(h, 1)])) for h in range(numdetails): mdl.add(mdl.start_at_end(itvs[(h, 1)], itvs[(h, 0)])) #навесим принадлежность for h in range(numdetails): mdl.add(mdl.span(details[h], [itvs[(h, t)] for t in range(3)]))
def create_model(self): mdl = CpoModel(name = "TAS Scheduling") ##################################################### # Creating interval variables for WEST module ##################################################### i = 0 MS1_vars = [] MS4_vars = [] GTW_vars = [] WEST_vars = [] table_occupied_WEST = [] kits_pulse_for_choice = [] for i in range(len(self.timeOUEST)): min_start_time = int(date_converter.convert_to_work_time(datetime.timestamp(pd.to_datetime(self.req_matOUEST.iloc[i,2])))) #print(min_start_time, self.req_matOUEST.iloc[i,2]) meca_length = int(self.timeOUEST.iloc[i, 2] / 10) qc_length = int(self.timeOUEST.iloc[i, 3] / 10) kit_interval = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), name = "kitting " + self.timeOUEST.index[i]) kit_interval1mec = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = self.kitting_time_max, name = "kitting 1 op " + self.timeOUEST.index[i], optional = True) kit_interval2mec = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = self.kitting_time_mid, name = "kitting 2 op " + self.timeOUEST.index[i], optional = True) kit_interval3mec = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = self.kitting_time_min, name = "kitting 3 op " + self.timeOUEST.index[i], optional = True) mdl.add(mdl.alternative(interval = kit_interval, array = [kit_interval1mec, kit_interval2mec, kit_interval3mec])) kits_pulse_for_choice += [kit_interval1mec, kit_interval2mec, kit_interval3mec] meca_interval = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = meca_length, name = "meca " + self.timeOUEST.index[i]) qc_interval = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = qc_length, name = "qc " + self.timeOUEST.index[i]) table_slot_occupied_interval = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = (0, 9999999999999), name = "Table occupied " + self.timeOUEST.index[i]) table_occupied_WEST += [table_slot_occupied_interval] mdl.add(mdl.end_before_start(kit_interval, meca_interval)) mdl.add(mdl.end_before_start(meca_interval, qc_interval)) mdl.add(mdl.start_at_end(table_slot_occupied_interval, kit_interval)) mdl.add(mdl.start_at_end(meca_interval, table_slot_occupied_interval)) WEST_vars += [kit_interval] WEST_vars += [meca_interval] WEST_vars += [qc_interval] if i < 19: MS1_vars += [kit_interval] MS1_vars += [meca_interval] MS1_vars += [qc_interval] elif i >= 45: GTW_vars += [kit_interval] GTW_vars += [meca_interval] GTW_vars += [qc_interval] else: MS4_vars += [kit_interval] MS4_vars += [meca_interval] MS4_vars += [qc_interval] ###################################################### # Creating interval variables for EAST module ###################################################### FOV_vars = [] MS2_vars = [] MS3_vars = [] EAST_vars = [] table_occupied_EAST = [] for i in range(len(self.timeEST)): min_start_time = int(date_converter.convert_to_work_time(datetime.timestamp(pd.to_datetime(self.req_matOUEST.iloc[i,2])))) meca_length = int(self.timeOUEST.iloc[i, 2] / 10) qc_length = int(self.timeOUEST.iloc[i, 3] / 10) kit_interval = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), name = "kitting " + self.timeEST.index[i]) kit_interval1mec = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = self.kitting_time_max, name = "kitting 1 op " + self.timeEST.index[i], optional = True) kit_interval2mec = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = self.kitting_time_mid, name = "kitting 2 op " + self.timeEST.index[i], optional = True) kit_interval3mec = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = self.kitting_time_min, name = "kitting 3 op " + self.timeEST.index[i], optional = True) mdl.add(mdl.alternative(interval = kit_interval, array = [kit_interval1mec, kit_interval2mec, kit_interval3mec])) kits_pulse_for_choice += [kit_interval1mec, kit_interval2mec, kit_interval3mec] meca_interval = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = meca_length, name = "meca " + self.timeEST.index[i]) qc_interval = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = qc_length, name = "qc " + self.timeEST.index[i]) table_slot_occupied_interval = mdl.interval_var(start = (min_start_time, self.max_end_timestamp), length = (0, 9999999999999), name = "Table occupied " + self.timeEST.index[i]) table_occupied_EAST += [table_slot_occupied_interval] mdl.add(mdl.end_before_start(kit_interval, meca_interval)) mdl.add(mdl.end_before_start(meca_interval, qc_interval)) mdl.add(mdl.start_at_end(table_slot_occupied_interval, kit_interval)) mdl.add(mdl.start_at_end(meca_interval, table_slot_occupied_interval)) EAST_vars += [kit_interval] EAST_vars += [meca_interval] EAST_vars += [qc_interval] if i < 11: FOV_vars += [kit_interval] FOV_vars += [meca_interval] FOV_vars += [qc_interval] elif i >= 25: MS3_vars += [kit_interval] MS3_vars += [meca_interval] MS3_vars += [qc_interval] else: MS2_vars += [kit_interval] MS2_vars += [meca_interval] MS2_vars += [qc_interval] ################################################## # Setting requirement relations between interval variables ################################################## for task in MS1_vars: for i in range(len(self.req_taskOUEST)): if (self.req_taskOUEST.index[i] in task.name) and "meca" in task.name: for j in range(len(self.req_taskOUEST.iloc[i, 0])): for other_task in WEST_vars: if self.req_taskOUEST.iloc[i, 0][j] in other_task.name and "qc" in other_task.name: mdl.add(mdl.end_before_start(other_task, task)) #print("##############################################") for task in MS4_vars: for i in range(len(self.req_taskOUEST)): if (self.req_taskOUEST.index[i] in task.name) and "meca" in task.name: for j in range(len(self.req_taskOUEST.iloc[i, 0])): for other_task in WEST_vars: if self.req_taskOUEST.iloc[i, 0][j] in other_task.name and "qc" in other_task.name: mdl.add(mdl.end_before_start(other_task, task)) #print("##############################################") for task in GTW_vars: for i in range(len(self.req_taskOUEST)): if (self.req_taskOUEST.index[i] in task.name) and "meca" in task.name: for j in range(len(self.req_taskOUEST.iloc[i, 0])): for other_task in WEST_vars: if self.req_taskOUEST.iloc[i, 0][j] in other_task.name and "qc" in other_task.name: mdl.add(mdl.end_before_start(other_task, task)) #print("##############################################") for task in MS2_vars: for i in range(len(self.req_taskEST)): if (self.req_taskEST.index[i] in task.name) and "meca" in task.name: for j in range(len(self.req_taskEST.iloc[i, 0])): for other_task in EAST_vars: if self.req_taskEST.iloc[i, 0][j] in other_task.name and "qc" in other_task.name: mdl.add(mdl.end_before_start(other_task, task)) #print("##############################################") for task in MS3_vars: for i in range(len(self.req_taskEST)): if (self.req_taskEST.index[i] in task.name) and "meca" in task.name: for j in range(len(self.req_taskEST.iloc[i, 0])): for other_task in EAST_vars: if self.req_taskEST.iloc[i, 0][j] in other_task.name and "qc" in other_task.name: mdl.add(mdl.end_before_start(other_task, task)) #print("##############################################") for task in FOV_vars: for i in range(len(self.req_taskEST)): if (self.req_taskEST.index[i] in task.name) and "meca" in task.name: for j in range(len(self.req_taskEST.iloc[i, 0])): for other_task in EAST_vars: if self.req_taskEST.iloc[i, 0][j] in other_task.name and "qc" in other_task.name: mdl.add(mdl.end_before_start(other_task, task)) ############################################## # Adding resources constraints ############################################## all_tasks = EAST_vars + WEST_vars meca_resources = [mdl.pulse(task, 1) for task in EAST_vars if "meca" in task.name] meca_resources += [mdl.pulse(task, 1) for task in WEST_vars if "meca" in task.name] meca_resources += [mdl.pulse(task, 1) for task in kits_pulse_for_choice if "kitting 1 op" in task.name] meca_resources += [mdl.pulse(task, 2) for task in kits_pulse_for_choice if "kitting 2 op" in task.name] meca_resources += [mdl.pulse(task, 3) for task in kits_pulse_for_choice if "kitting 3 op" in task.name] qc_resources = [mdl.pulse(task, 1) for task in EAST_vars if "qc" in task.name] qc_resources += [mdl.pulse(task, 1) for task in WEST_vars if "qc" in task.name] work_slots_EAST = [mdl.pulse(task, 1) for task in EAST_vars if "qc" in task.name or "meca" in task.name] work_slots_WEST = [mdl.pulse(task, 1) for task in WEST_vars if "qc" in task.name or "meca" in task.name] kitting_slots_EAST = [mdl.pulse(task, 1) for task in table_occupied_EAST] kitting_slots_EAST += [mdl.pulse(task, 1) for task in EAST_vars if "kitting" in task.name] kitting_slots_WEST = [mdl.pulse(task, 1) for task in table_occupied_WEST] kitting_slots_WEST += [mdl.pulse(task, 1) for task in WEST_vars if "kitting" in task.name] mdl.add(mdl.sum(meca_resources) <= 3) mdl.add(mdl.sum(qc_resources) <= 1) mdl.add(mdl.sum(work_slots_EAST) <= 2) mdl.add(mdl.sum(work_slots_WEST) <= 2) mdl.add(mdl.sum(kitting_slots_EAST) <= 3) mdl.add(mdl.sum(kitting_slots_WEST) <= 3) [mdl.add(mdl.start_of(task) % (14*6) < 11*6) for task in all_tasks if "meca" in task.name] MS1_meca_qc = [task for task in MS1_vars if (("meca" in task.name) or ("qc" in task.name))] mdl.add(mdl.no_overlap(MS1_meca_qc)) MS2_meca_qc = [task for task in MS2_vars if (("meca" in task.name) or ("qc" in task.name))] mdl.add(mdl.no_overlap(MS2_meca_qc)) MS3_meca_qc = [task for task in MS3_vars if (("meca" in task.name) or ("qc" in task.name))] mdl.add(mdl.no_overlap(MS3_meca_qc)) MS4_meca_qc = [task for task in MS4_vars if (("meca" in task.name) or ("qc" in task.name))] mdl.add(mdl.no_overlap(MS4_meca_qc)) FOV_meca_qc = [task for task in FOV_vars if (("meca" in task.name) or ("qc" in task.name))] mdl.add(mdl.no_overlap(FOV_meca_qc)) GTW_meca_qc = [task for task in GTW_vars if (("meca" in task.name) or ("qc" in task.name))] mdl.add(mdl.no_overlap(GTW_meca_qc)) mdl.add(mdl.minimize(mdl.max([mdl.end_of(t) for t in all_tasks]) - mdl.min([mdl.start_of(t) for t in all_tasks]))) return mdl
tasks = {t: mdl.interval_var(name=t.name) for t in tasks_data} # Add precedence constraints for t in tasks_data: for s in t.successors: mdl.add(mdl.end_before_start(tasks[t], tasks[tasks_data[s]])) # Create one optional interval variable per mode modes = { m: mdl.interval_var(name=m.name, optional=True, size=m.duration) for m in modes_data } # Add mode alternative for each task for t in tasks_data: mdl.add(mdl.alternative(tasks[t], [modes[m] for m in t.modes])) # Initialize pulse functions for renewable and non renewable resources renewables = [mdl.pulse((0, 0), 0) for j in range(NB_RENEWABLE)] non_renewables = [0 for j in range(NB_NON_RENEWABLE)] for m in modes_data: for j in range(NB_RENEWABLE): if m.demand_renewable[j] > 0: renewables[j] += mdl.pulse(modes[m], m.demand_renewable[j]) for j in range(NB_NON_RENEWABLE): if m.demand_non_renewable[j] > 0: non_renewables[j] += m.demand_non_renewable[j] * mdl.presence_of( modes[m]) # Constrain renewable resources capacity for j in range(NB_RENEWABLE):