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
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.")
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