def cplex_makespan_model(n: int, m: int, durations, machines) -> CpoModel: # n number of jobs, m machines # 1 line for un job with tasks on m machines naive = np.sum(durations) mdl = CpoModel() #Une variable est l'intervalle de durée pour une tache x = [[ mdl.interval_var(size=durations[i, j], name="O{}-{}".format(i, j)) for j in range(m) ] for i in range(n)] #contrainte end max d'une tache calculée avant for i in range(n): for j in range(m): mdl.add(mdl.end_of(x[i][j]) <= naive) #precedence for i in range(n): #for each job for j in range(m - 1): #taches ordonnées mdl.add(mdl.end_before_start(x[i][j], x[i][j + 1])) # une machine ne peut faire qu'une tache à la fois listtaches = [[] for k in range(m)] for i in range(n): for j in range(m): listtaches[machines[i, j]].append(x[i][j]) for k in range(m): mdl.add(mdl.no_overlap(listtaches[k])) makespan = mdl.integer_var(0, naive, name="makespan") # le makespan est le max des tps pour chaque job mdl.add(makespan == mdl.max([mdl.end_of(x[i][m - 1]) for i in range(n)])) mdl.add(mdl.minimize(makespan)) return mdl, x
def recherche_exact(instance, temps): ''' :param temps: int, temps de recherche :param instance: nom de l'instance str :return: None ''' problem_data, optimum = loader(instance) nb_machine = problem_data["nb_machine"] nb_jobs = problem_data["nb_jobs"] problem = problem_data["problem"] machine, durations = separate(problem) model = CpoModel(name='Scheduling') # Variable job_operations = [[model.interval_var(size=durations[j][m], name="O{}-{}".format(j, m)) for m in range(nb_machine)] for j in range(nb_jobs)] # chaque opération doit commencer aprés la fin de la précedente for j in range(nb_jobs): for s in range(1, nb_machine): model.add(model.end_before_start(job_operations[j][s - 1], job_operations[j][s])) # Pas d'overlap pour les operations executées sur une même machine machine_operations = [[] for m in range(nb_machine)] for j in range(nb_jobs): for s in range(0, nb_machine): machine_operations[machine[j][s]].append(job_operations[j][s]) for lops in machine_operations: model.add(model.no_overlap(lops)) # Minimiser la date de fin model.add(model.minimize(model.max([model.end_of(job_operations[i][nb_machine - 1]) for i in range(nb_jobs)]))) # Solve model print("Solving model....") msol = model.solve(TimeLimit=temps)
dem_non_renewables = m[3 + NB_RENEWABLE:3 + NB_RENEWABLE + NB_NON_RENEWABLE] mode = Mode("T{}-M{}".format(taskid, modeid), tasks_data[taskid], dur, dem_renewables, dem_non_renewables) tasks_data[taskid].modes.append(mode) modes_data.append(mode) #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create one interval variable per task 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]))
os.path.abspath(__file__)) + "/data/flowshop_default.data" with open(filename, "r") as file: NB_JOBS, NB_MACHINES = [int(v) for v in file.readline().split()] JOB_DURATIONS = [[int(v) for v in file.readline().split()] for i in range(NB_JOBS)] #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create one interval variable per job operation job_operations = [[ mdl.interval_var(size=JOB_DURATIONS[j][m], name="J{}-M{}".format(j, m)) for m in range(NB_MACHINES) ] for j in range(NB_JOBS)] # Force each operation to start after the end of the previous for j in range(NB_JOBS): for m in range(1, NB_MACHINES): mdl.add( mdl.end_before_start(job_operations[j][m - 1], job_operations[j][m])) # Force no overlap for operations executed on a same machine for m in range(NB_MACHINES): mdl.add(mdl.no_overlap([job_operations[j][m] for j in range(NB_JOBS)])) # Minimize termination date
# Assign an index to tasks ALL_TASKS = (MASONRY, CARPENTRY, PLUMBING, CEILING, ROOFING, PAINTING, WINDOWS, FACADE, GARDEN, MOVING) for i in range(len(ALL_TASKS)): ALL_TASKS[i].id = i #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create interval variable for each building task tasks = [mdl.interval_var(size=t.duration, name=t.name) for t in ALL_TASKS] # Add precedence constraints for p, s in PRECEDENCES: mdl.add(mdl.end_before_start(tasks[p.id], tasks[s.id])) # Cost function cost = [] # List of individual costs fearliness = dict() # Task earliness cost function (for display) ftardiness = dict() # Task tardiness cost function (for display) for t in ALL_TASKS: task = tasks[t.id] if t.release_date is not None: f = CpoSegmentedFunction((-t.earliness_cost, 0), [(t.release_date, 0, 0)])
def main(): filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data_in/test_1.txt") inst = instance.Instance(filename) # input from master problem, now random id_profile = 0 random.seed(42) rewards = [random.randint(0, 30000) for i in range(inst.J)] #rewards = [random.uniform(0.0, 30000.0) for i in range(inst.J)] equivalences = [[0, 1], [2, 3]] mutexes = [[2, 1], [4, 3]] # input from master problem, now random types = inst.profiles[id_profile] types.insert(0, inst.INIT) types.append(inst.TERM) trans_cost = [[0 for i in range(inst.V)] for j in range(inst.V)] trans_time = [[0 for i in range(inst.V)] for j in range(inst.V)] for i in range(len(inst.edges)): for j in range(len(inst.edges[i])): trans_cost[i][inst.edges[i][j][ 'to']] = inst.edges[i][j]['C'] * inst.edges[i][j]['t'] trans_time[i][inst.edges[i][j]['to']] = inst.edges[i][j]['t'] changeover_cost = 0 for i in range(1, len(types)): changeover_cost += trans_cost[types[i - 1]][types[i]] cp = CpoModel() primitives = [[] for i in range(inst.J)] all_primitives = [] init = cp.interval_var(start=0) init.set_end_max(inst.L) total_cost = changeover_cost + inst.vertices[ inst.INIT]['C'] * cp.length_of(init, 0) modes_of_mach = [init ] # serves only for retrieving starts and ends of modes last_shift = init for i in range(1, len(types) - 1): v = types[i] shift = cp.interval_var() shift.set_size_min(inst.vertices[v]['t_min']) shift.set_size_max(inst.vertices[v]['t_max']) shift.set_end_max(inst.L) total_cost += inst.vertices[v]['C'] * cp.length_of(shift, 0) cp.add( cp.start_at_end(shift, last_shift, -trans_time[types[i - 1]][types[i]])) last_shift = shift modes_of_mach.append(shift) for t in range(inst.J): if inst.tasks[t]['p'][v] <= inst.L: prim = cp.interval_var(size=inst.tasks[t]['p'][v]) total_cost -= rewards[t] * cp.presence_of(prim) prim.set_optional() prim.set_start_min(inst.tasks[t]['r']) prim.set_end_max(inst.tasks[t]['d']) primitives[t].append(prim) all_primitives.append(prim) cp.add(cp.start_before_start(shift, prim)) cp.add(cp.end_before_end(prim, shift)) term = cp.interval_var(end=inst.L) total_cost += inst.vertices[inst.TERM]['C'] * cp.length_of(term, 0) cp.add( cp.start_at_end(term, last_shift, -trans_time[types[len(types) - 2]][inst.TERM])) modes_of_mach.append(term) cp.add(cp.no_overlap(cp.sequence_var(all_primitives))) for t in range(inst.J): cp.add(sum([cp.presence_of(p) for p in primitives[t]]) <= 1) for eq in equivalences: cp.add( sum([cp.presence_of(p) for p in primitives[eq[0]]]) == sum( [cp.presence_of(p) for p in primitives[eq[1]]])) for mut in mutexes: cp.add( sum([cp.presence_of(p) for p in primitives[mut[0]]]) + sum([cp.presence_of(p) for p in primitives[mut[1]]]) <= 1) cp.add(cp.minimize(total_cost)) # set TimeLimit in seconds or delete it for no limit # parameters DefaultInferenceLevel and Workers may be beneficial to add sol = cp.solve( TimeLimit=30, LogVerbosity="Quiet") #, DefaultInferenceLevel='Extended', Workers=1) if sol: tasks = [] for t in range(inst.J): for pr in primitives[t]: p = sol.get_var_solution(pr) if p.is_present(): tasks.append({ "task": t, "start": p.get_start(), "end": p.get_end() }) break modes = [] sched_cost = 0 for t in range(len(modes_of_mach)): m = sol.get_var_solution(modes_of_mach[t]) modes.append({ "mode": types[t], "start": m.get_start(), "end": m.get_end() }) sched_cost += inst.vertices[types[t]]['C'] * m.get_length() print("Solution status: " + sol.get_solve_status()) print("Solve time: " + str(sol.get_solve_time())) print("Objective: " + str(sol.get_objective_values()[0])) print("Schedule cost: " + str(sched_cost)) print(tasks) print(modes) else: print("No solution found.")
#----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Variables of the model tasks = {} # dict of interval variable for each house and task wtasks = {} # dict of interval variable for each house and skill for house in HOUSES: for task in TASKS: v = (0, MAX_SCHEDULE) tasks[(house, task)] = mdl.interval_var(v, v, size=task.duration, name="house {} task {}".format( house, task)) for task in SKILLS: wtasks[(house, task)] = mdl.interval_var( optional=True, name="house {} skill {}".format(house, task)) # Maximization objective of the model obj2 = mdl.sum([ 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
# Построим модель mdl = CpoModel() tasks = [] # заведём задачи по монтажникам for i in range(WORKERS_COUNT): worker_tasks = [] for j in range(ORDERS_COUNT): if all([(a >= b) for a, b in zip(INSTALLERS[i][1:], WAIT_ORDERS[j][2:])]): worker_tasks.append( mdl.interval_var(size=WAIT_ORDERS[j][0], name=TASK_TEMPLATE_NAME.format(num=str(j), name=WAIT_ORDERS[j][1]), start=(0, MAX_SCHEDULE), end=(0, MAX_SCHEDULE), optional=True) ) tasks.append(worker_tasks) # посмотрим, что создали # 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)] # одна задача - один монтажник
# Size of the englobing square SIZE_SQUARE = 112 # Sizes of the sub-squares SIZE_SUBSQUARE = [50, 42, 37, 35, 33, 29, 27, 25, 24, 19, 18, 17, 16, 15, 11, 9, 8, 7, 6, 4, 2] NB_SUBSQUARE = len(SIZE_SUBSQUARE) #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create array of variables for subsquares vx = [mdl.interval_var(size=SIZE_SUBSQUARE[i], name="X" + str(i), end=(0, SIZE_SQUARE)) for i in range(NB_SUBSQUARE)] vy = [mdl.interval_var(size=SIZE_SUBSQUARE[i], name="Y" + str(i), end=(0, SIZE_SQUARE)) for i in range(NB_SUBSQUARE)] # Create dependencies between variables for i in range(len(SIZE_SUBSQUARE)): for j in range(i): mdl.add( (mdl.end_of(vx[i]) <= mdl.start_of(vx[j])) | (mdl.end_of(vx[j]) <= mdl.start_of(vx[i])) | (mdl.end_of(vy[i]) <= mdl.start_of(vy[j])) | (mdl.end_of(vy[j]) <= mdl.start_of(vy[i]))) # To speed-up the search, create cumulative expressions on each dimension rx = mdl.sum([mdl.pulse(vx[i], SIZE_SUBSQUARE[i]) for i in range(NB_SUBSQUARE)]) mdl.add(mdl.always_in(rx, (0, SIZE_SQUARE), SIZE_SQUARE, SIZE_SQUARE)) ry = mdl.sum([mdl.pulse(vy[i], SIZE_SUBSQUARE[i]) for i in range(NB_SUBSQUARE)]) mdl.add(mdl.always_in(ry, (0, SIZE_SQUARE), SIZE_SQUARE, SIZE_SQUARE))
def floorPlanner(CONFIG, SCHEDULER, RATE, printFlag=0, figFlag=0): HEIGHT_REC = 4 WIDTH_REC = 4 NUM_RESOURCES = 16 # Sizes of the hardware resources SIZE_HARDWARE = [1 for _ in range(NUM_RESOURCES)] RESOUCE_dict = { 0: 'A72', 1: 'A53-0', 2: 'A53-1', 3: 'FFT', 4: 'DAP-0', 5: 'DAP-1', 6: 'Memory', 7: 'Cache-1', 8: 'Cache-2', 9: 'Cache-3', 10: 'Cache-4' } # read from rpt file df = pd.read_fwf("inputs/" + CONFIG + "/trace_" + SCHEDULER + "_" + RATE + "/matrix_traffic_" + SCHEDULER + "_" + RATE + ".rpt") # read file --- MODIFY HERE df = df.drop(df.columns[df.columns.str.contains('unnamed', case=False)], axis=1) # drop unnamed df = df.drop(range(10)) # drop the first 10 lines vol = df.values.tolist() vol_commu = [list(map(int, i)) for i in vol] extend_factor = NUM_RESOURCES - len(vol_commu) for i in range(extend_factor): RESOUCE_dict[len(vol_commu) + i] = 'empty' for _ in range(extend_factor): for row in range(len(vol_commu)): vol_commu[row].extend([0]) for _ in range(extend_factor): vol_commu.append([0 for _ in range(len(vol_commu[0]))]) #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create array of variables for subsquares vx = [ mdl.interval_var(size=SIZE_HARDWARE[i], name="X" + str(i), end=(0, WIDTH_REC)) for i in range(NUM_RESOURCES) ] vy = [ mdl.interval_var(size=SIZE_HARDWARE[i], name="Y" + str(i), end=(0, HEIGHT_REC)) for i in range(NUM_RESOURCES) ] # Create dependencies between variables for i in range(len(SIZE_HARDWARE)): for j in range(i): mdl.add((mdl.end_of(vx[i]) <= mdl.start_of(vx[j])) | (mdl.end_of(vx[j]) <= mdl.start_of(vx[i])) | (mdl.end_of(vy[i]) <= mdl.start_of(vy[j])) | (mdl.end_of(vy[j]) <= mdl.start_of(vy[i]))) # Set up the objective """ obj = mdl.minimize( mdl.sum( vol_commu[i][j] * ( mdl.max( [mdl.end_of(vx[i]) - mdl.end_of(vx[j]), mdl.end_of(vx[j]) - mdl.end_of(vx[i])] )\ + mdl.max( [mdl.start_of(vy[i]) - mdl.end_of(vy[j]), mdl.start_of(vy[j]) - mdl.end_of(vy[i])] ) ) \ for i in range(NUM_RESOURCES) for j in range(NUM_RESOURCES) if vol_commu[i][j]) ) """ obj = mdl.minimize( mdl.sum( vol_commu[i][j] * ( mdl.max( [mdl.end_of(vx[i]) - mdl.end_of(vx[j]), mdl.end_of(vx[j]) - mdl.end_of(vx[i])] )\ + mdl.min([mdl.min([mdl.max( [mdl.start_of(vy[i]) - mdl.end_of(vy[j]), 0] ), mdl.max( [mdl.start_of(vy[j]) - mdl.end_of(vy[i]), 0] )]), 1]) ) \ for i in range(NUM_RESOURCES) for j in range(NUM_RESOURCES) if vol_commu[i][j]) ) mdl.add(obj) # To speed-up the search, create cumulative expressions on each dimension rx = mdl.sum( [mdl.pulse(vx[i], SIZE_HARDWARE[i]) for i in range(NUM_RESOURCES)]) mdl.add(mdl.always_in(rx, (0, WIDTH_REC), WIDTH_REC, WIDTH_REC)) ry = mdl.sum( [mdl.pulse(vy[i], SIZE_HARDWARE[i]) for i in range(NUM_RESOURCES)]) mdl.add(mdl.always_in(ry, (0, HEIGHT_REC), HEIGHT_REC, HEIGHT_REC)) # Define search phases, also to speed-up the search mdl.set_search_phases([mdl.search_phase(vx), mdl.search_phase(vy)]) #----------------------------------------------------------------------------- # Solve the model and display the result #----------------------------------------------------------------------------- # Solve model print("Solving model....") msol = mdl.solve(TimeLimit=20, LogPeriod=50000) if printFlag: print("Solution: ") msol.print_solution() if msol and visu.is_visu_enabled(): import matplotlib.pyplot as plt import matplotlib.cm as cm from matplotlib.patches import Polygon import matplotlib.ticker as ticker # Plot external square if figFlag: plt.show() print("Plotting squares....") fig, ax = plt.subplots() plt.plot((0, 0), (0, HEIGHT_REC), (WIDTH_REC, HEIGHT_REC), (WIDTH_REC, 0)) plt.xlim((0, WIDTH_REC)) plt.ylim((0, HEIGHT_REC // 2)) for i in range(len(SIZE_HARDWARE)): # Display square i sx, sy = msol.get_var_solution(vx[i]), msol.get_var_solution(vy[i]) (sx_st, sx_ed, sy_st, sy_ed) = (sx.get_start(), sx.get_end(), sy.get_start(), sy.get_end()) # transform #sx1, sx2, sy1, sy2 = sx_st, sx_ed, sy_st, sy_ed sx1 = sx_st + 0.5 if sy_st % 2 else sx_st sy1 = sy_st / 2 sx2, sy2 = sx1 + 0.5, sy1 + 0.5 poly = Polygon([(sx1, sy1), (sx1, sy2), (sx2, sy2), (sx2, sy1)], fc=cm.Set2(float(i) / len(SIZE_HARDWARE))) ax.add_patch(poly) # Display identifier of square i at its center ax.text(float(sx1 + sx2) / 2, float(sy1 + sy2) / 2, RESOUCE_dict[i], ha='center', va='center') ax.xaxis.set_major_locator(ticker.MultipleLocator(0.5)) ax.yaxis.set_major_locator(ticker.MultipleLocator(0.5)) plt.margins(0) fig.savefig("outputs/MESH/" + CONFIG + "_" + SCHEDULER + "_" + RATE + ".png") if figFlag: plt.show()
# Extract demand of each task DEMANDS = [TASKS[t][1:NB_RESOURCES + 1] for t in range(NB_TASKS)] # Extract successors of each task SUCCESSORS = [TASKS[t][NB_RESOURCES + 2:] for t in range(NB_TASKS)] #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create task interval variables tasks = [mdl.interval_var(name="T{}".format(i + 1), size=DURATIONS[i]) for i in range(NB_TASKS)] # Add precedence constraints for t in range(NB_TASKS): for s in SUCCESSORS[t]: mdl.add(mdl.end_before_start(tasks[t], tasks[s - 1])) # Constrain capacity of resources for r in range(NB_RESOURCES): resources = [mdl.pulse(tasks[t], DEMANDS[t][r]) for t in range(NB_TASKS) if DEMANDS[t][r] > 0] mdl.add(mdl.sum(resources) <= CAPACITIES[r]) # Minimize end of all tasks mdl.add(mdl.minimize(mdl.max([mdl.end_of(t) for t in tasks])))
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
def init_model(self): # INPUTS -------------------------------------------------- inst = self.instance id_profile = self.profile_idx rewards = self.l_j equivalences = self.on_same mutexes = self.on_diff # END INPUTS ---------------------------------------------- # MODEL -------------------------------------------------- types = list(inst.profiles[id_profile]) types.insert(0, inst.INIT) types.append(inst.TERM) trans_time = [[0 for i in range(inst.V)] for j in range(inst.V)] for i in range(len(inst.edges)): for j in range(len(inst.edges[i])): trans_time[i][inst.edges[i][j]['to']] = inst.edges[i][j]['t'] changeover_cost = inst.get_trans_cost(id_profile) cp = CpoModel() """ primitives = [[] for i in range(inst.J)] all_primitives = [] init = cp.interval_var(start=0) init.set_end_max(inst.L) total_cost = changeover_cost + inst.vertices[inst.INIT]['C'] * cp.length_of(init, 0) - self.l_0 # subtract l_0 modes_of_mach = [init] # serves only for retrieving starts and ends of modes last_shift = init for i in range(1, len(types) - 1): v = types[i] shift = cp.interval_var() shift.set_size_min(inst.vertices[v]['t_min']) shift.set_size_max(inst.vertices[v]['t_max']) shift.set_end_max(inst.L) total_cost += inst.vertices[v]['C'] * cp.length_of(shift, 0) cp.add(cp.start_at_end(shift, last_shift, -trans_time[types[i - 1]][types[i]])) last_shift = shift modes_of_mach.append(shift) for t in range(inst.J): if inst.tasks[t]['p'][v] <= inst.L: prim = cp.interval_var(size=inst.tasks[t]['p'][v]) total_cost -= rewards[t] * cp.presence_of(prim) prim.set_optional() prim.set_start_min(inst.tasks[t]['r']) prim.set_end_max(inst.tasks[t]['d']) primitives[t].append(prim) all_primitives.append(prim) cp.add(cp.start_before_start(shift, prim)) cp.add(cp.end_before_end(prim, shift)) term = cp.interval_var(end=inst.L) total_cost += inst.vertices[inst.TERM]['C'] * cp.length_of(term, 0) cp.add(cp.start_at_end(term, last_shift, -trans_time[types[len(types) - 2]][inst.TERM])) modes_of_mach.append(term) cp.add(cp.no_overlap(cp.sequence_var(all_primitives))) for t in range(inst.J): cp.add(sum([cp.presence_of(p) for p in primitives[t]]) <= 1) for eq in equivalences: cp.add(sum([cp.presence_of(p) for p in primitives[eq[0]]]) == sum( [cp.presence_of(p) for p in primitives[eq[1]]])) for mut in mutexes: cp.add(sum([cp.presence_of(p) for p in primitives[mut[0]]]) + sum( [cp.presence_of(p) for p in primitives[mut[1]]]) <= 1) """ #""" # MODEL 2 primitives = [[] for i in range(inst.J)] all_primitives = [] init = cp.interval_var(start=0) init.set_end_max(inst.L) total_cost = changeover_cost + inst.vertices[ inst.INIT]['C'] * cp.length_of(init, 0) - self.l_0 modes_of_mach = [ init ] # serves only for retrieving starts and ends of modes last_shift = init for i in range(1, len(types) - 1): v = types[i] shift = cp.interval_var() shift.set_size_min(inst.vertices[v]['t_min']) shift.set_size_max(inst.vertices[v]['t_max']) shift.set_end_max(inst.L) total_cost += inst.vertices[v]['C'] * cp.length_of(shift, 0) cp.add( cp.start_at_end(shift, last_shift, -trans_time[types[i - 1]][types[i]])) last_shift = shift modes_of_mach.append(shift) sub_tasks = [] for t in range(inst.J): if inst.tasks[t]['p'][v] <= inst.L: prim = cp.interval_var(size=inst.tasks[t]['p'][v]) total_cost -= rewards[t] * cp.presence_of(prim) prim.set_optional() prim.set_start_min(inst.tasks[t]['r']) prim.set_end_max(inst.tasks[t]['d']) primitives[t].append(prim) sub_tasks.append(prim) cp.add(cp.start_before_start(shift, prim)) cp.add(cp.end_before_end(prim, shift)) if len(sub_tasks) > 1: cp.add(cp.no_overlap(cp.sequence_var(sub_tasks))) term = cp.interval_var(end=inst.L) total_cost += inst.vertices[inst.TERM]['C'] * cp.length_of(term, 0) cp.add( cp.start_at_end(term, last_shift, -trans_time[types[len(types) - 2]][inst.TERM])) modes_of_mach.append(term) for t in range(inst.J): cp.add(sum([cp.presence_of(p) for p in primitives[t]]) <= 1) for eq in equivalences: cp.add( sum([cp.presence_of(p) for p in primitives[eq[0]]]) == sum( [cp.presence_of(p) for p in primitives[eq[1]]])) for mut in mutexes: cp.add( sum([cp.presence_of(p) for p in primitives[mut[0]]]) + sum([cp.presence_of(p) for p in primitives[mut[1]]]) <= 1) #""" """ # MOdel 3 primitives = [[] for i in range(inst.J)] init = cp.interval_var(start=0) init.set_end_max(inst.L) total_cost = changeover_cost + inst.vertices[inst.INIT]['C'] * cp.length_of(init, 0) - self.l_0 modes_of_mach = [init] # serves only for retrieving starts and ends of modes last_shift = init for i in range(1, len(types) - 1): v = types[i] shift = cp.interval_var() shift.set_size_min(inst.vertices[v]['t_min']) shift.set_size_max(inst.vertices[v]['t_max']) shift.set_end_max(inst.L) total_cost += inst.vertices[v]['C'] * cp.length_of(shift, 0) cp.add(cp.start_at_end(shift, last_shift, -trans_time[types[i - 1]][types[i]])) last_shift = shift modes_of_mach.append(shift) for t in range(inst.J): if inst.tasks[t]['p'][v] <= inst.L: prim = cp.interval_var(size=inst.tasks[t]['p'][v]) prim.set_optional() prim.set_start_min(inst.tasks[t]['r']) prim.set_end_max(inst.tasks[t]['d']) primitives[t].append(prim) cp.add(cp.start_before_start(shift, prim)) cp.add(cp.end_before_end(prim, shift)) term = cp.interval_var(end=inst.L) total_cost += inst.vertices[inst.TERM]['C'] * cp.length_of(term, 0) cp.add(cp.start_at_end(term, last_shift, -trans_time[types[len(types) - 2]][inst.TERM])) modes_of_mach.append(term) masters = [] for t in range(inst.J): new_master = cp.interval_var() new_master.set_optional() masters.append(new_master) total_cost -= rewards[t] * cp.presence_of(new_master) cp.add(cp.alternative(new_master, primitives[t])) cp.add(cp.no_overlap(cp.sequence_var(masters))) for eq in equivalences: cp.add(cp.presence_of(masters[eq[0]]) == cp.presence_of(masters[eq[1]])) for mut in mutexes: cp.add(cp.presence_of(masters[mut[0]]) + cp.presence_of(masters[mut[1]]) <= 1) """ cp.add(cp.minimize(total_cost)) # Set self.model self.model = cp self.primitives = primitives self.modes_of_mach = modes_of_mach self.types = types
for j in range(NB_JOBS)] # Build list of durations. DURATION[j][s] = duration of the operation s of the job j DURATION = [[JOBS[j][2 * s + 1] for s in range(NB_MACHINES)] for j in range(NB_JOBS)] # ----------------------------------------------------------------------------- # Build the model # ----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create one interval variable per job operation job_operations = [[ mdl.interval_var(size=DURATION[j][m], name="O{}-{}".format(j, m)) for m in range(NB_MACHINES) ] for j in range(NB_JOBS)] # Each operation must start after the end of the previous for j in range(NB_JOBS): for s in range(1, NB_MACHINES): mdl.add( mdl.end_before_start(job_operations[j][s - 1], job_operations[j][s])) # Force no overlap for operations executed on a same machine machine_operations = [[] for m in range(NB_MACHINES)] for j in range(NB_JOBS): for s in range(0, NB_MACHINES): machine_operations[MACHINES[j][s]].append(job_operations[j][s])
model.end_before_start(on_intervals[m_id][i - 1], on_intervals[m_id][i], 1)) # Bind with task intervals for on_i in on_intervals[m_id]: machine_on_off[m_id] += model.pulse(on_i, 1) model.add( model.always_constant(tasks_running_on_machines[m_id], on_i, True, True)) for task in data['tasks']: # Master task interval task_interval = model.interval_var( size=task['duration'], start=(task['earliest_start_time'], task['latest_end_time'] - task['duration']), end=(task['earliest_start_time'] + task['duration'], task['latest_end_time']), name='task_{}'.format(task['id'])) # Optional task intervals that belong to each machine task_machine_intervals = model.interval_var_list(NUM_MACHINES, name='task_{}_on_'.format( task['id']), optional=True) for i in range(NUM_MACHINES): m_id = data['machines'][i]['id'] # Bind with machine switched on intervals model.add( model.always_equal(tasks_running_on_machines[m_id],
def tw_schedule(time_slot, tasks): start_time = time_slot[0] end_time = time_slot[1] mdl = CpoModel(name="generate_tw") # Create model for CP and solve for the first time to obtain initial time windows # Decision variables: time interval of each task task_vars = {} early = lambda x: "task_" + str(x) + "_early" late = lambda x: "task_" + str(x) + "_late" for id in tasks: if tasks[id].exact_time != None: # print("exact time: {}".format(tasks[id].exact_time)) task_vars[early(id)] = mdl.interval_var(start=tasks[id].exact_time, size=tasks[id].duration, name=early(id)) task_vars[late(id)] = mdl.interval_var(start=tasks[id].exact_time, size=tasks[id].duration, name=late(id)) else: task_vars[early(id)] = mdl.interval_var(size=tasks[id].duration, name=early(id)) task_vars[late(id)] = mdl.interval_var(size=tasks[id].duration, name=late(id)) slot = mdl.interval_var(start=start_time, end=end_time) # Time interval of entire time slot # Add Constraints: for id in tasks: # 1st constraint: all intervals are within start and end time mdl.add(mdl.start_before_start(slot, task_vars[early(id)])) mdl.add(mdl.end_before_end(task_vars[early(id)], slot)) mdl.add(mdl.start_before_start(slot, task_vars[late(id)])) mdl.add(mdl.end_before_end(task_vars[late(id)], slot)) # mdl.add(mdl.span(slot, task_vars.values())) if tasks[id].precedence_before != []: # Tasks that have precedence_before constraints # 2nd Constraints: end of precedence_before_task is before start of current task for id_before in tasks[id].precedence_before: mdl.add( mdl.end_before_start(task_vars[early(id_before)], task_vars[early(id)])) mdl.add( mdl.end_before_start(task_vars[late(id_before)], task_vars[late(id)])) # Add objective: obj = mdl.maximize( sum([ mdl.start_of(task_vars[late(id)]) - mdl.start_of(task_vars[early(id)]) for id in tasks ])) mdl.add(obj) # Solve model # sol = mdl.solve(TimeLimit = 10, LogVerbosity = "Verbose") sol = mdl.solve( TimeLimit=10, LogVerbosity="Quiet", agent='local', execfile= '/Applications/CPLEX_Studio201/cpoptimizer/bin/x86-64_osx/cpoptimizer') # sol = mdl.solve() if sol: # sol.write() time_window = { id: (sol.get_var_solution(task_vars[early(id)]).get_start(), sol.get_var_solution(task_vars[late(id)]).get_start()) for id in tasks } else: print("Instance not feasible - earliest start time") return {} return time_window
numdetails = 12 WorkerNames = ["worker1", "worker2", "worker3"] TaskNames = ["obtain_parts", "repair", "delivery"] # minutes_on_repair - число минут, которые тратит работник на починку девайса minutes_on_repair = [140, 80, 160, 120, 160, 120, 130, 100, 40, 140, 160, 60] # minutes_on_obtain_parts - число минут, которые тратит работник на поиск запчастей minutes_on_obtain_parts = [20, 30, 40, 50, 100, 10, 20, 40, 100, 10, 50, 20] # minutes_on_delivery - число минут, которое уходит на доставку can be done in parallel minutes_on_delivery = [ 120, 150, 170, 100, 140, 100, 150, 230, 100, 90, 180, 280 ] # euro_penalty - число евро, составляющие штраф за откладку на день euro_penalty = [100, 80, 120, 100, 80, 120, 120, 90, 100, 80, 150, 13] mdl = CpoModel() details = [ mdl.interval_var(name="Detail{}".format(i + 1)) for i in range(numdetails) ] TaskNames_ids = {} itvs_1 = {} itvs_2 = {} itvs_3 = {} itvs = {} #zadadim treh for d in range(numdetails): _name = "obtain_parts1_{}".format(d + 1) itvs_1[(d, 0)] = mdl.interval_var(size=minutes_on_obtain_parts[d], name=_name, optional=True) for d in range(numdetails): _name = "repair1_{}".format(d + 1) itvs_1[(d, 1)] = mdl.interval_var(size=minutes_on_repair[d],
if (task_data["skill"] in skills_of_this_worker) ] for worker_id, skills_of_this_worker in workers_skills.items() } deadline = 1000 # in hours # Create model mdl = CpoModel(name="scheduling") # tasks tasks = { task_id: mdl.interval_var( name=f"{task_id}, {task_data['skill']}", size=task_data["duration"], end=(INTERVAL_MIN, deadline), ) for task_id, task_data in tasks_data.items() } allocs = {} # key: task id, value: list of worker-task assignment variables worker_tasks = {} # key: worker id, value: list of worker-task assignment variables for worker_id, task_ids in workers_tasks_eligibility.items(): for task_id in task_ids: wt = mdl.interval_var(name=f"{worker_id}, {task_id}", optional=True) worker_tasks[worker_id] = worker_tasks.get(worker_id, []) worker_tasks[worker_id].append(wt) allocs[task_id] = allocs.get(task_id, [])
def CP_model_subsequence_restricted(params): ## NUM_COLORS, NUM_ITEMS, BIN_SIZE, DISCREPANCY, ITEM_SIZES, COLORS, NUM_BINS, Timelimit, SEED = params print("*** Running CP Subseq Restricted with instance NUM_COLORS{} NUM_ITEMS{} BIN_SIZE {} DISCREPANCY {} SEED {}".format( NUM_COLORS, NUM_ITEMS, BIN_SIZE, DISCREPANCY, SEED)) mdl = CpoModel() ITEMS = [mdl.interval_var(start=[0, sum(ITEM_SIZES)], size=ITEM_SIZES[item], optional=False, name="item_"+str(item)) for item in range(NUM_ITEMS)] ITEMS_TO_BINS = [[mdl.interval_var(start=(0, BIN_SIZE-min(ITEM_SIZES)), end=(min(ITEM_SIZES), BIN_SIZE), size=ITEM_SIZES[item], optional=True, name="item{}InBin{}".format(item, bin)) for bin in range(NUM_BINS)] for item in range(NUM_ITEMS)] ITEMS_S = mdl.sequence_var(ITEMS, types=COLORS, name="itemSequence") BIN_S = [mdl.sequence_var([ITEMS_TO_BINS[item][bin] for item in range(NUM_ITEMS)], types=[COLORS[item] for item in range(NUM_ITEMS)], name="bin{}Sequence".format(bin)) for bin in range(NUM_BINS)] # COLORS_S = [[mdl.sequence_var(ITEMS[item][bin] for item in range(NUM_ITEMS) if COLORS[item] == color)] for color in range(NUM_COLORS)] BINS_USED = [mdl.binary_var() for bin in range(NUM_BINS)] for item in range(NUM_ITEMS): # for bin in range(NUM_BINS): # mdl.add_kpi( # mdl.presence_of(ITEMS_TO_BINS[item][bin]), # "item_"+str(item)+" "+str(bin) # ) mdl.add( mdl.sum( [mdl.presence_of( ITEMS_TO_BINS[item][bin]) for bin in range(NUM_BINS)] ) == 1 ) # for item in range(NUM_ITEMS): # mdl.add( # mdl.alternative(ITEMS[item], [ITEMS_TO_BINS[item][bin] for bin in range(NUM_BINS)]) # ) for bin in range(NUM_BINS): mdl.add(mdl.no_overlap(BIN_S[bin])) for item in range(NUM_ITEMS-1): mdl.add( mdl.end_before_start(ITEMS[item], ITEMS[item+1]) ) mdl.add(mdl.no_overlap(ITEMS_S)) for bin in range(NUM_BINS): mdl.add( mdl.same_common_subsequence( ITEMS_S, BIN_S[bin], ) ) for item in range(NUM_ITEMS): for bin in range(NUM_BINS): # if (item, bin) in [(17,5), (20, 5), (29, 5)]: # mdl.add_kpi(mdl.type_of_next(BIN_S[bin], ITEMS_TO_BINS[item][bin], lastValue=-1, absentValue=-1), name="typeofnext{}_{}".format(item, bin)) # # mdl.add_kpi(mdl.type_of_prev(BIN_S[bin], ITEMS_TO_BINS[item][bin], firstValue=-1, absentValue=-1), name="typeofprev{}_{}".format(item, bin)) mdl.add( COLORS[item] != mdl.type_of_next(BIN_S[bin], ITEMS_TO_BINS[item][bin], lastValue=-1, absentValue=-1) ) mdl.add( COLORS[item] != mdl.type_of_prev(BIN_S[bin], ITEMS_TO_BINS[item][bin], firstValue=-1, absentValue=-1) ) for bin in range(NUM_BINS): mdl.add( BINS_USED[bin] == mdl.any([ mdl.presence_of(ITEMS_TO_BINS[item][bin]) for item in range(NUM_ITEMS) ]) ) for bin in range(NUM_BINS-1): mdl.add( BINS_USED[bin] >= BINS_USED[bin+1] ) mdl.add( mdl.minimize( mdl.sum( BINS_USED ) ) ) # mdl.add( # mdl.sum( # BINS_USED # ) < 48 # ) try: msol = mdl.solve(TimeLimit = Timelimit) mdl._myInstance = (NUM_COLORS, NUM_ITEMS, BIN_SIZE, DISCREPANCY, SEED) if msol: ITEMS_TO_BINS_S = [] for bin in range(NUM_BINS): b_ = [] for item in range(NUM_ITEMS): s = msol[ITEMS_TO_BINS[item][bin]] if s: b_.append(s) ITEMS_TO_BINS_S.append(b_) # return mdl seq = msol.get_var_solution(BIN_S[0]) print(ITEM_SIZES) print("CL: ",COLORS) Xs = [] for item in range(NUM_ITEMS): for bin in range(NUM_BINS): s = msol[ITEMS_TO_BINS[item][bin]] if s: # print(s) Xs.append(bin) print("Xs: ", Xs) Xs = np.array(Xs) if solution_checker(Xs, params, "restricted_cp_subsequence"): write_to_global_cp(msol, mdl, 'restricted_subsequence') except Exception as err: print(err) write_to_global_failed(params, 'restricted_cp_subsequence', is_bad_solution=False)
if ind != -1: checked_cur = [ind_col[ind],i] checked.append(checked_cur) sum_col.pop(ind) ind_col.pop(ind) else: sum_col.append(pr) ind_col.append(i) print('found symmetries: ') print(checked) print('without symmetry: ') print(ind_col) return checked #list of intervals compositions=[mdl.interval_var(size=waittimes[i], end = [0,33], start=[0,33], name="song_"+str(i+1)) for i in range(numcompositions)] domain=mdl.sequence_var([compositions[i] for i in range(numcompositions)], types=[t for t in range(numcompositions)], name="domain") mdl.add(mdl.no_overlap(domain)) checked = checksymmetries(players_compositions, 9) for i,c in enumerate(checked): if i ==2: mdl.add(mdl.start_before_start(compositions[c[1]],compositions[c[0]])) else: mdl.add(mdl.start_before_start(compositions[c[0]],compositions[c[1]])) ENDS = [] STARTS = [] WAITNESS=[] for k in range(numplayers): for j in range(numcompositions): print(players_compositions[k][j])
print("find interval from {} to {}".format( cnst_pr[0], cnst_pr[1])) cnst_pr[0] = cnst_pr[1] = fdays * HOURS_IN_DAY + fhours elif fval == 0 and last_val == 1: cnst_pr[0] = cnst_pr[1] = fdays * HOURS_IN_DAY + fhours last_val = fval RND_CALENDAR.append(fs) # ----------------------------------------------------------------------------- # Описание модели # ----------------------------------------------------------------------------- mdl = CpoModel() # задача в interval variables tasks = [ mdl.interval_var(name="T{}".format(i + 1), size=DURATIONS[i]) for i in range(NB_TASKS) ] # ОГРАНИЧЕНИЯ # # Учтём приоритеты for i in range(NB_RESOURCES): successors_tasks = [] high_priority = [] for k, j in enumerate(TASKS): if j["rnd"] == i and j["rank"] == 1: successors_tasks.append(k) if j["rnd"] == i and j["rank"] == 0: high_priority.append(k) for s in high_priority:
for j in range(NB_TYPES): if SETUP_M1[i][j] < 0: SETUP_M1[i][j] = INTERVAL_MAX; if SETUP_M2[i][j] < 0: SETUP_M2[i][j] = INTERVAL_MAX; #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Build tasks for machine M1 and M2 tasks_m1 = [mdl.interval_var(name="A{}_M1_TP{}".format(i, TASK_TYPE[i]), optional=True, size=TASK_DUR_M1[i]) for i in range(NB_TASKS)] tasks_m2 = [mdl.interval_var(name="A{}_M2_TP{}".format(i, TASK_TYPE[i]), optional=True, size=TASK_DUR_M1[i]) 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])) 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')
def _create_cp_model(all_jobs, job_ids, job_num, all_machines, r_times, d_times, p_intervals, assign): """ Prepare the index for decision variables """ # typle of jobs, form (job_0, job_1, ...) jobs = tuple(job_ids) """ Parameters model (dictionary) """ # 1. release time release_time = dict(zip(jobs, tuple(r_times))) # 2. due time due_time = dict(zip(jobs, tuple(d_times))) # 3. processing time process_time = dict(zip(jobs, tuple(p_intervals))) """ Creation of the CP model container """ cp_model = CpoModel(name="CP-Model") """ Creation of variables """ # for j_id in all_jobs: # for m_id in all_machines: # if assign[(j_id, m_id)].x == 1: # print(assign[(j_id, m_id)]) # 1. Variable subscript z_i represents machine selected to process job i z = { j_id: m_id for j_id in all_jobs for m_id in all_machines if assign[(j_id, m_id)].x == 1 } # print("z: ", z) """ DOCPLEX """ # 1. list of interval variable, is a list of start time of jobs (i.start in CP model) start_time_cp = [ cp_model.interval_var(size=process_time[j_id][z[j_id]], name="start-time-J{}".format(j_id)) for j_id in all_jobs ] # if assign[(j_id, z[j_id])].x == 1] """ Create constraints """ # 1. job release time constraint cp_model.add(start_of(start_time_cp[i]) >= release_time[i] for i in jobs) # 2. job due time constraint cp_model.add( start_of(start_time_cp[i]) <= due_time[i] - process_time[i][z[i]] for i in jobs) # 3. duration of processing one job constraint cp_model.add( size_of(start_time_cp[i]) == process_time[i][z[i]] for i in jobs) # 4. assignment of a job to a specific machine as well as sequence of jobs assigned to same machine # "requires" in OPL construct # job i requires unary resource corresponding to machine which was assigned from MILP # force no overlap for jobs # Constrain jobs to no overlap on each machine # Force no overlap for jobs executed on a same machine # disjunctive resource (unary resource): end(J1) <= start(J2) ||end(J2) <= start(J1) for job_id1 in range(job_num - 1): for job_id2 in range(job_id1 + 1, job_num): # print("job id1 & job id2", job_id1, job_id2) if z[job_id1] == z[job_id2]: cp_model.add( cp_model.logical_or( end_of(start_time_cp[job_id1]) <= start_of( start_time_cp[job_id2]), end_of(start_time_cp[job_id2]) <= start_of( start_time_cp[job_id1]))) return cp_model, start_time_cp
def initialize(self): model = CpoModel() self.model = model instance = self.instance T = len(instance.intervals) first_on = instance.earliest_on_interval_idx last_on = instance.latest_on_interval_idx init_start_times = self.get_init_start_times(sort_starts=True) ub = min(instance.get_ub(), self.get_upper_bound(init_start_times)) total_proc = sum(j.processing_time for j in instance.jobs) # -------------------------------------- Construct the model. job_vars = dict() # Dict[Job, CpoIntervalVar] self.job_vars = job_vars gap_vars = dict() # Dict[Tuple[int, int], CpoIntervalVar] obj = 0 # objective value seq_vars = [] # variables for no-overlap constraint stp = model.create_empty_solution( ) # starting point of the solving procedure step_fns = CpGeneral.get_step_functions( instance, first_on, last_on) # Generate seqment function for each processing time. first_job_var = model.interval_var(length=0, optional=False, name="first_job_var", start=1) seq_vars.append( first_job_var) # dummy job with 0 length, first in the sequence last_job_var = model.interval_var(length=0, optional=False, name="last_job_var", end=T - 1) seq_vars.append( last_job_var) # dummy job with 0 length, last in the sequence # variables for jobs ------------------------------------------------------------------------------------------- for job in instance.jobs: var = model.interval_var(length=job.processing_time, optional=False, name="j[{:d}]".format(job.id)) model.add(cpmod.start_of(var) >= first_on) # earliest possible start time is first_on model.add(cpmod.end_of(var) <= last_on + 1) # latest possible end time is last_on job_vars[job] = var seq_vars.append(var) if self.specialized_solver_config[ "JobInObjectiveModelling"] == 0: # Optional : alternatives = [] for t in range(first_on, T): if t <= last_on - ( job.processing_time - 1 ): # (-1) because unit job can be processed in last_on var = model.interval_var(start=t, length=job.processing_time, optional=True, name="j[{:d},{:d}]".format( t, job.id)) alternatives.append(var) obj += cpmod.presence_of( var) * instance.cumulative_energy_cost[t][ t + job.processing_time - 1] * instance.on_power_consumption # add a present variable for the job model.add(cpmod.alternative(job_vars[job], alternatives)) elif self.specialized_solver_config[ "JobInObjectiveModelling"] == 1: # Logical : for t in range(T): if first_on <= t <= last_on - (job.processing_time - 1): obj += (cpmod.start_of(var, absentValue=-1) == t) * instance.cumulative_energy_cost[t][ t + job.processing_time - 1] * instance.on_power_consumption elif self.specialized_solver_config[ "JobInObjectiveModelling"] == 2: # Element : energy = [ instance.cumulative_energy_cost[t][t + job.processing_time - 1] * instance.on_power_consumption if (first_on <= t <= last_on - (job.processing_time - 1)) else 0 for t in range(T) ] obj += cpmod.element(energy, cpmod.start_of(var)) elif self.specialized_solver_config[ "JobInObjectiveModelling"] == 3: # Overlap : for t in range(T): # add overlaps to objective if first_on <= t <= last_on: obj += cpmod.overlap_length( var, (t, t + 1)) * instance.intervals[ t].energy_cost * instance.on_power_consumption elif self.specialized_solver_config[ "JobInObjectiveModelling"] == 4: # Step function : obj += cpmod.start_eval(var, step_fns[job.processing_time]) else: raise Exception( "Given JobInObjectiveModelling method {0} is not supported." .format( self. specialized_solver_config["JobInObjectiveModelling"])) # add variables for gaps --------------------------------------------------------------------------------------- if self.specialized_solver_config[ "GapsInObjectiveModelling"] == 0: # Fixed : for t_s in range(1, T): for t_e in range(t_s + 1, T): if instance.has_switching_cost(t_s, t_e): if instance.get_gap_lower_bound( t_s, t_e) > ub: # skip gaps that are too costly continue sw_cost = instance.optimal_switching_costs[t_s][t_e] var = model.interval_var(start=t_s, end=t_e, optional=True, name="gap[{:d},{:d}]".format( t_s, t_e)) gap_vars[t_s, t_e] = var seq_vars.append(var) obj += cpmod.presence_of( var ) * sw_cost # if the gap is present, add cost to objective elif self.specialized_solver_config[ "GapsInObjectiveModelling"] == 1: # Free : gaps_by_lengths = {i: [] for i in range(1, T - 1)} for gap_len in range(1, T - total_proc - 1): costs = [ instance.optimal_switching_costs[t][t + gap_len] if instance.optimal_switching_costs[t][t + gap_len] is not None else len(instance.intervals) * instance.on_power_consumption + 1 # TODO : max value for t in range(T) if t + gap_len < T ] costs[0] = 0 # TODO: for absent value for i in range(int(T / gap_len)): var = model.interval_var(optional=True, length=gap_len, name="gap[{:d},{:d}]".format( gap_len, i)) model.add(cpmod.start_of(var, absentValue=1) >= 1) model.add(cpmod.end_of(var) <= T - 1) obj += cpmod.element(costs, cpmod.start_of(var)) gaps_by_lengths[gap_len].append(var) seq_vars.append(var) # force order on the gaps for cur, nxt in zip(gaps_by_lengths[gap_len], gaps_by_lengths[gap_len][1:]): model.add(cpmod.presence_of(cur) >= cpmod.presence_of(nxt)) model.add(cpmod.end_before_start(cur, nxt)) elif self.specialized_solver_config[ "GapsInObjectiveModelling"] == 2: # No : # Gaps will be added to the objective after introducing the sequence variable pass else: raise Exception( "Given GapsInObjectiveModelling method {0} is not supported.". format(self. specialized_solver_config["GapsInObjectiveModelling"])) # add no overlap constraint ------------------------------------------------------------------------------------ seq = model.sequence_var(seq_vars, name="seq") model.add(cpmod.no_overlap(seq)) model.add(cpmod.first(seq, first_job_var)) model.add(cpmod.last(seq, last_job_var)) if self.specialized_solver_config[ "GapsInObjectiveModelling"] == 2: # No : gap_costs = ( [0 for _ in range(T)] + # gap_len == 0 [ instance.optimal_switching_costs[gap_s][gap_s + gap_len] if gap_s + gap_len <= T - 1 and instance.optimal_switching_costs[gap_s][gap_s + gap_len] is not None else INT_MAX for gap_len in range(1, T) for gap_s in range(T) ]) for job in instance.jobs: job_var = self.job_vars[job] obj += cpmod.element( gap_costs, (cpmod.start_of_next(seq, job_var, T - 1) - cpmod.end_of(job_var)) * T + cpmod.end_of(job_var)) obj += cpmod.element(gap_costs, cpmod.start_of_next(seq, first_job_var) * T) # constrain lengths to fill the whole horizon ------------------------------------------------------------------ if self.specialized_solver_config[ "GapsInObjectiveModelling"] != 2: # gaps are modelled if self.specialized_solver_config[ "FillAllModelling"] == 0: # SumLengths : model.add( sum([cpmod.length_of(var) for var in seq_vars]) == T - 2) elif self.specialized_solver_config[ "FillAllModelling"] == 1: # Pulse : cumul_func = 0 for var in seq_vars: if var is not first_job_var and var is not last_job_var: cumul_func += cpmod.pulse(var, 1) model.add(cpmod.always_in(cumul_func, (1, T - 1), 1, 1)) elif self.specialized_solver_config[ "FillAllModelling"] == 2: # StartOfNext : for var in seq_vars: if var is not last_job_var: model.add( cpmod.start_of_next( seq, var, lastValue=T, absentValue=0) == cpmod.end_of(var, absentValue=0)) else: raise Exception( "Given FillAllModelling method {0} is not supported.". format(self.specialized_solver_config["FillAllModelling"])) # set objective model.minimize(obj) # - init start times. # if init_start_times is not None: # for job in instance.jobs: # stp.add_interval_var_solution(job_vars[job], presence=True, start=init_start_times[job]) # # # gaps in the schedule # gaps = self.get_gaps_in_schedule(init_start_times) # # for g_s, g_e in gaps: # stp.add_interval_var_solution(gap_vars[g_s, g_e], presence=True, start=g_s) # # # set starting point # model.set_starting_point(stp) # force ordering of the jobs jobs_by_lengths = self.get_job_by_lengths() for lst in jobs_by_lengths.values(): for j_cur, j_nxt in zip(lst, lst[1:]): model.add( cpmod.end_before_start(job_vars[j_cur], job_vars[j_nxt]))
Skills = [[("M"+str(JOBS[j][2 * s]),s) for s in range(NB_MACHINES)] for j in range(NB_JOBS) ] #append abilities of additional 5 machines for j in range(NB_JOBS): for i in range(len(Skills[j])): if int(Skills[j][i][0][-1:]) < IDENTICAL_MACHINES_NUM+1: for f in range(flag-1): add_s = ('M' + str(int(Skills[j][i][0][-1:]))+'e'+str(f+1), Skills[j][i][1]) Skills[j].append(add_s) Precedences = [(i, i+1) for i in range(NB_MACHINES-1)] tasks = {} mtasks = {} for j in range(NB_JOBS): for i,t in enumerate(Tasks[j]): # print((j,JOBS[j][2 * t],t),JOBS[j][2 * Tasks[j][-1] ]) tasks[(j,JOBS[j][2 * t],t)] = mdl.interval_var(size = Durations[j][i], name="J{}-M{}".format(j, JOBS[j][2 * t])) # print("SKILLS") for s in Skills[j]: # print((j,s),"J{}-{}".format(j, s)) mtasks[(j,s)] = mdl.interval_var(optional=True, name=str(j))#"J{}-{}".format(j, s) 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):
expressed through precedence constraints. Please refer to documentation for appropriate setup of solving configuration. """ from docplex.cp.model import CpoModel import docplex.cp.utils_visu as visu #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() masonry = mdl.interval_var(name='masonry', size=35) carpentry = mdl.interval_var(name='carpentry', size=15) plumbing = mdl.interval_var(name='plumbing', size=40) ceiling = mdl.interval_var(name='ceiling', size=15) roofing = mdl.interval_var(name='roofing', size=5) painting = mdl.interval_var(name='painting', size=10) windows = mdl.interval_var(name='windows', size=5) facade = mdl.interval_var(name='facade', size=10) garden = mdl.interval_var(name='garden', size=5) moving = mdl.interval_var(name='moving', size=5) # Add precedence constraints mdl.add(mdl.end_before_start(masonry, carpentry)) mdl.add(mdl.end_before_start(masonry, plumbing)) mdl.add(mdl.end_before_start(masonry, ceiling)) mdl.add(mdl.end_before_start(carpentry, roofing))
# Task type TASK_TYPE = [ 8, 1, 6, 3, 4, 8, 8, 4, 3, 5, 9, 4, 1, 5, 8, 8, 4, 1, 9, 2, 6, 0, 8, 9, 1, 0, 1, 7, 5, 9, 3, 1, 9, 3, 0, 7, 0, 7, 1, 4, 5, 7, 4, 0, 9, 1, 5, 4, 5, 1 ] #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Build tasks for machine M1 and M2 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]]))
MODES = [] for t in TASKS: for i, m in enumerate(t['modes']): m['id'] = "T{}-M{}".format(t['id'], i + 1) MODES.append(m) #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # 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
for i in range(len(PRODUCT_WEIGHT)): p = [] for j in range(SIZE_SHELF["x"] * SHELF_COUNT): p.append(E[int(j / SIZE_SHELF["x"])] * PRODUCT_WEIGHT[i]) SHELVES_PRODUCT_MATRIX.append(p) # ----------------------------------------------------------------------------- # Описание модели # ----------------------------------------------------------------------------- mdl = CpoModel() # Создадим массивы продуктов по сторонам vx = [ mdl.interval_var(size=WEIGHT_SIZE_A[i], name="X" + str(i), end=(0, SIZE_SHELF["x"] * SHELF_COUNT)) for i in range(NB_WEIGHTS) ] vy = [ mdl.interval_var(size=WEIGHT_SIZE_B[i], name="Y" + str(i), end=(0, SIZE_SHELF["y"] * 1)) for i in range(NB_WEIGHTS) ] # Запретим пересекать границы полок и учтём температуры for i in range(NB_WEIGHTS): mdl.add( mdl.forbid_extent(vx[i], get_allowable_area(SHELVES, 'x', PRODUCT_T[i])))