def __init__(self, problem): # Problem self.problem = problem # Utilities self.num_weeks = len(problem.weeks) self.num_days = len(problem.working_days) self.num_doctors = len(problem.doctors) self.num_areas = len(problem.areas) self.num_schedules = len(problem.schedules) self.num_versions = len(problem.versions) self.schedule_versions = [ x * self.num_schedules + y for x in problem.schedules for y in problem.versions ] self.num_schedule_versions = self.num_schedules * self.num_versions all_schedule_versions = range(self.num_schedule_versions) all_doctors = range(self.num_doctors) all_weeks = range(self.num_weeks) all_days = range(self.num_days) all_versions = range(self.num_versions) all_areas = range(self.num_areas) all_schedules = range(self.num_schedules) self.model = cp_model.CpModel() # build all the possible permutations including the specialties self.assignment = {} for sv in all_schedule_versions: for w in all_weeks: for a in all_areas: for d in all_doctors: for day in all_days: if d in self.problem.specialties[a]: name = 'C:{%i} W:{%i} S:{%i} T:{%i} Slot:{%i}' % ( sv, w, a, d, day) # print(name) self.assignment[sv, w, a, d, day] = self.model.NewBoolVar( name) else: name = 'NO DISP C:{%i} W:{%i} S:{%i} T:{%i} Slot:{%i}' % ( sv, w, a, d, day) # print(name) self.assignment[sv, w, a, d, day] = self.model.NewIntVar( 0, 0, name) # Constraints # Each schedule/version must have the quantity of areas specified in the curriculum # 8/15: All areas are required 5 days of the week for sch in all_schedules: for ver in all_versions: sch_ver = sch * self.num_versions + ver for week in all_weeks: for area in all_areas: required_days = self.problem.curriculum[ self.problem.schedules[sch], self.problem.areas[area]] self.model.Add( sum(self.assignment[sch_ver, week, area, doctor, day] for day in all_days for doctor in all_doctors) == required_days) # Doctor can work at only one area at a time (per day) for doctor in all_doctors: for week in all_weeks: for day in all_days: self.model.Add( sum([ self.assignment[sv, week, a, doctor, day] for sv in all_schedule_versions for a in all_areas ]) <= 1) # Ensure that each day of the week is accounted for and no duplicate days for week in all_weeks: for day in all_days: for a in all_areas: self.model.Add( sum([ self.assignment[sv, week, a, d, day] for sv in all_schedule_versions for d in all_doctors ]) == 1) # Maximum work days for each doctor for week in all_weeks: for doctor in all_doctors: self.model.Add( sum([ self.assignment[sv, week, a, doctor, day] for sv in all_schedule_versions for a in all_areas for day in all_days ]) <= self.problem.doctor_work_days[doctor]) # Doctor makes all the classes of a area's course # So if Ian can teach math and history, he can only teach it in his course # If Donald also teaches history, students in his course would never be taught by Ian # doctor_schedule_versions = {} # for level in all_schedules: # for section in all_versions: # course = level * self.num_versions + section # for area in all_areas: # for t in all_doctors: # name = 'C:{%i} S:{%i} T:{%i}' % (course, area, doctor) # doctor_schedule_versions[course, area, t] = self.model.NewBoolVar(name) # temp_array = [ # self.assignment[course, area, t, slot] for slot in all_slots # ] # self.model.AddMaxEquality(doctor_schedule_versions[course, area, t], # temp_array) # self.model.Add( # sum(doctor_schedule_versions[course, area, t] # for t in all_doctors) == 1) # Solution collector self.collector = None
def SolveRcpsp(problem, proto_file): # Determine problem type. problem_type = ('Resource investment' if problem.is_resource_investment else 'RCPSP') if problem.is_rcpsp_max: problem_type += '/Max delay' if problem.is_consumer_producer: print('Solving %s with %i reservoir resources and %i tasks' % (problem_type, len(problem.resources), len(problem.tasks))) else: print('Solving %s with %i resources and %i tasks' % (problem_type, len(problem.resources), len(problem.tasks))) # Create the model. model = cp_model.CpModel() num_tasks = len(problem.tasks) num_resources = len(problem.resources) all_tasks = range(num_tasks) all_active_tasks = range(1, num_tasks - 1) all_resources = range(num_resources) horizon = problem.deadline if problem.deadline != -1 else problem.horizon if horizon == -1: # Naive computation. horizon = sum( max(r.duration for r in t.recipes) for t in problem.tasks) if problem.is_rcpsp_max: for t in problem.tasks: for sd in t.successor_delays: for rd in sd.recipe_delays: for d in rd.min_delays: horizon += abs(d) print(' - horizon = %i' % horizon) # Containers used to build resources. intervals_per_resource = defaultdict(list) demands_per_resource = defaultdict(list) presences_per_resource = defaultdict(list) starts_per_resource = defaultdict(list) # Starts and ends for master interval variables. task_starts = {} task_ends = {} # Containers for per-recipe per task variables. alternatives_per_task = defaultdict(list) presences_per_task = defaultdict(list) starts_per_task = defaultdict(list) ends_per_task = defaultdict(list) # Create tasks. for t in all_active_tasks: task = problem.tasks[t] if len(task.recipes) == 1: # Create interval. recipe = task.recipes[0] task_starts[t] = model.NewIntVar(0, horizon, 'start_of_task_%i' % t) task_ends[t] = model.NewIntVar(0, horizon, 'end_of_task_%i' % t) interval = model.NewIntervalVar(task_starts[t], recipe.duration, task_ends[t], 'interval_%i' % t) # Store for later. alternatives_per_task[t].append(interval) starts_per_task[t].append(task_starts[t]) ends_per_task[t].append(task_ends[t]) presences_per_task[t].append(1) # Register for resources. for i in range(len(recipe.demands)): demand = recipe.demands[i] res = recipe.resources[i] demands_per_resource[res].append(demand) if problem.resources[res].renewable: intervals_per_resource[res].append(interval) else: starts_per_resource[res].append(task_starts[t]) presences_per_resource[res].append(1) else: all_recipes = range(len(task.recipes)) # Compute duration range. min_size = min(recipe.duration for recipe in task.recipes) max_size = max(recipe.duration for recipe in task.recipes) # Create one optional interval per recipe. for r in all_recipes: recipe = task.recipes[r] is_present = model.NewBoolVar('is_present_%i_r%i' % (t, r)) start = model.NewOptionalIntVar(0, horizon, is_present, 'start_%i_r%i' % (t, r)) end = model.NewOptionalIntVar(0, horizon, is_present, 'end_%i_r%i' % (t, r)) interval = model.NewOptionalIntervalVar( start, recipe.duration, end, is_present, 'interval_%i_r%i' % (t, r)) # Store variables. alternatives_per_task[t].append(interval) starts_per_task[t].append(start) ends_per_task[t].append(end) presences_per_task[t].append(is_present) # Register intervals in resources. for i in range(len(recipe.demands)): demand = recipe.demands[i] res = recipe.resources[i] demands_per_resource[res].append(demand) if problem.resources[res].renewable: intervals_per_resource[res].append(interval) else: starts_per_resource[res].append(start) presences_per_resource[res].append(is_present) # Create the master interval for the task. task_starts[t] = model.NewIntVar(0, horizon, 'start_of_task_%i' % t) task_ends[t] = model.NewIntVar(0, horizon, 'end_of_task_%i' % t) duration = model.NewIntVar(min_size, max_size, 'duration_of_task_%i' % t) interval = model.NewIntervalVar(task_starts[t], duration, task_ends[t], 'interval_%i' % t) # Link with optional per-recipe copies. for r in all_recipes: p = presences_per_task[t][r] model.Add( task_starts[t] == starts_per_task[t][r]).OnlyEnforceIf(p) model.Add(task_ends[t] == ends_per_task[t][r]).OnlyEnforceIf(p) model.Add( duration == task.recipes[r].duration).OnlyEnforceIf(p) model.Add(sum(presences_per_task[t]) == 1) # Create makespan variable makespan = model.NewIntVar(0, horizon, 'makespan') # Add precedences. if problem.is_rcpsp_max: for t in all_active_tasks: task = problem.tasks[t] num_modes = len(task.recipes) num_successors = len(task.successors) for s in range(num_successors): n = task.successors[s] delay_matrix = task.successor_delays[s] num_other_modes = len(problem.tasks[n].recipes) for m1 in range(num_modes): s1 = starts_per_task[t][m1] if n == num_tasks - 1: delay = delay_matrix.recipe_delays[m1].min_delays[0] model.Add(s1 + delay <= makespan) else: for m2 in range(num_other_modes): delay = delay_matrix.recipe_delays[m1].min_delays[ m2] s2 = starts_per_task[n][m2] model.Add(s1 + delay <= s2) else: # Normal dependencies (task ends before the start of successors). for t in all_active_tasks: for n in problem.tasks[t].successors: if n == num_tasks - 1: model.Add(task_ends[t] <= makespan) else: model.Add(task_ends[t] <= task_starts[n]) # Containers for resource investment problems. capacities = [] max_cost = 0 # Create resources. for r in all_resources: resource = problem.resources[r] c = resource.max_capacity if c == -1: c = sum(demands_per_resource[r]) if problem.is_resource_investment: capacity = model.NewIntVar(0, c, 'capacity_of_%i' % r) model.AddCumulative(intervals_per_resource[r], demands_per_resource[r], capacity) capacities.append(capacity) max_cost += c * resource.unit_cost elif resource.renewable: if intervals_per_resource[r]: model.AddCumulative(intervals_per_resource[r], demands_per_resource[r], c) elif presences_per_resource[r]: # Non empty non renewable resource. if problem.is_consumer_producer: model.AddReservoirConstraint(starts_per_resource[r], demands_per_resource[r], resource.min_capacity, resource.max_capacity) else: model.Add( sum(presences_per_resource[r][i] * demands_per_resource[r][i] for i in range(len(presences_per_resource[r]))) <= c) # Objective. if problem.is_resource_investment: objective = model.NewIntVar(0, max_cost, 'capacity_costs') model.Add(objective == sum(problem.resources[i].unit_cost * capacities[i] for i in range(len(capacities)))) else: objective = makespan model.Minimize(objective) if proto_file: print('Writing proto to %s' % proto_file) text_file = open(proto_file, 'w') text_file.write(str(model)) text_file.close() # Solve model. solver = cp_model.CpSolver() solution_printer = SolutionPrinter() status = solver.SolveWithSolutionObserver(model, solution_printer) print('Solve status: %s' % solver.StatusName(status)) print('Optimal objective value: %i' % solver.ObjectiveValue()) print('Statistics') print(' - conflicts : %i' % solver.NumConflicts()) print(' - branches : %i' % solver.NumBranches()) print(' - wall time : %f s' % solver.WallTime())
def LiteralSample(): model = cp_model.CpModel() x = model.NewBoolVar('x') not_x = x.Not() print(x) print(not_x)
def jobshop_with_maintenance(): """Solves a jobshop with maintenance on one machine.""" # Create the model. model = cp_model.CpModel() jobs_data = [ # task = (machine_id, processing_time). [(0, 3), (1, 2), (2, 2)], # Job0 [(0, 2), (2, 1), (1, 4)], # Job1 [(1, 4), (2, 3)] # Job2 ] machines_count = 1 + max(task[0] for job in jobs_data for task in job) all_machines = range(machines_count) # Computes horizon dynamically as the sum of all durations. horizon = sum(task[1] for job in jobs_data for task in job) # Named tuple to store information about created variables. task_type = collections.namedtuple('Task', 'start end interval') # Named tuple to manipulate solution information. assigned_task_type = collections.namedtuple('assigned_task_type', 'start job index duration') # Creates job intervals and add to the corresponding machine lists. all_tasks = {} machine_to_intervals = collections.defaultdict(list) for job_id, job in enumerate(jobs_data): for task_id, task in enumerate(job): machine = task[0] duration = task[1] suffix = '_%i_%i' % (job_id, task_id) start_var = model.NewIntVar(0, horizon, 'start' + suffix) end_var = model.NewIntVar(0, horizon, 'end' + suffix) interval_var = model.NewIntervalVar(start_var, duration, end_var, 'interval' + suffix) all_tasks[job_id, task_id] = task_type(start=start_var, end=end_var, interval=interval_var) machine_to_intervals[machine].append(interval_var) # Add maintenance interval (machine 0 is not available on time {4, 5, 6, 7}). machine_to_intervals[0].append(model.NewIntervalVar(4, 4, 8, 'weekend_0')) # Create and add disjunctive constraints. for machine in all_machines: model.AddNoOverlap(machine_to_intervals[machine]) # Precedences inside a job. for job_id, job in enumerate(jobs_data): for task_id in range(len(job) - 1): model.Add(all_tasks[job_id, task_id + 1].start >= all_tasks[job_id, task_id].end) # Makespan objective. obj_var = model.NewIntVar(0, horizon, 'makespan') model.AddMaxEquality(obj_var, [ all_tasks[job_id, len(job) - 1].end for job_id, job in enumerate(jobs_data) ]) model.Minimize(obj_var) # Solve model. solver = cp_model.CpSolver() status = solver.Solve(model) # Output solution. if status == cp_model.OPTIMAL: # Create one list of assigned tasks per machine. assigned_jobs = collections.defaultdict(list) for job_id, job in enumerate(jobs_data): for task_id, task in enumerate(job): machine = task[0] assigned_jobs[machine].append( assigned_task_type(start=solver.Value( all_tasks[job_id, task_id].start), job=job_id, index=task_id, duration=task[1])) # Create per machine output lines. output = '' for machine in all_machines: # Sort by starting time. assigned_jobs[machine].sort() sol_line_tasks = 'Machine ' + str(machine) + ': ' sol_line = ' ' for assigned_task in assigned_jobs[machine]: name = 'job_%i_%i' % (assigned_task.job, assigned_task.index) # Add spaces to output to align columns. sol_line_tasks += '%-10s' % name start = assigned_task.start duration = assigned_task.duration sol_tmp = '[%i,%i]' % (start, start + duration) # Add spaces to output to align columns. sol_line += '%-10s' % sol_tmp sol_line += '\n' sol_line_tasks += '\n' output += sol_line_tasks output += sol_line # Finally print the solution found. print('Optimal Schedule Length: %i' % solver.ObjectiveValue()) print(output)
def solve_correction_term(self): if len(self.a) == 0: raise Exception( 'First array of community/group numbers is empty! Please set it as' ) if len(self.b) == 0: raise Exception( 'Second array of community/group numbers is empty! Please set it as' ) if sum(self.a) is not sum(self.b): raise Exception( 'The two arrays represent networks with different amount of nodes. Their sums is not equal.' ) #Constant declaration self.inform('Problem constants:') n = sum(self.a) R = len(self.a) S = len(self.b) self.inform(f'n = {n}, R = {R}, S = {S}') for i in range(R): exec(f'a{i+1} = self.a[i]') for i in range(S): exec(f'b{i+1} = self.b[i]') model = cp_model.CpModel() #Variable declaration self.inform('Declaring variables:') for i in range(R): exp = '' for j in range(S): exec(f'c{i+1}{j+1} = model.NewIntVar(0, n, \'c{i+1}{j+1}\')') exp += f'c{i+1}{j+1} ' self.inform(exp) #Overlooping for code clarity self.inform('First set of constraints:') for i in range(R): exp = '' for j in range(S): exp += f'+ c{i+1}{j+1} ' if j > 0 else f'c{i+1}1 ' exp += f'== a{i+1}' self.inform(exp) model.Add(eval(exp)) #Overlooping for code clarity self.inform('Second set of constraints:') for j in range(S): exp = '' for i in range(R): exp += f'+ c{i+1}{j+1} ' if i > 0 else f'c1{j+1} ' exp += f'== b{j+1}' self.inform(exp) model.Add(eval(exp)) solver = cp_model.CpSolver() self.inform('Starting to solve...') status = solver.SearchForAllSolutions(model, self.solution_callback) self.inform('Found %i solutions' % self.solution_count()) self.inform('All solutions found: ', status == cp_model.OPTIMAL) self.inform('-' * 50) return self.solution_count()
def solve_with_discrete_model(num_tables, table_capacity, min_known_neighbors, C, names): num_guests = len(C) all_tables = range(num_tables) all_guests = range(num_guests) maxSolutions = 1 # Create the cp model. model = cp_model.CpModel() # # Decision variables # seats = {} for t in all_tables: for g in all_guests: seats[(t, g)] = model.NewBoolVar("guest %i seats on table %i" % (g, t)) colocated = {} for g1 in range(num_guests - 1): for g2 in range(g1 + 1, num_guests): colocated[(g1, g2)] = model.NewBoolVar( "guest %i seats with guest %i" % (g1, g2)) same_table = {} for g1 in range(num_guests - 1): for g2 in range(g1 + 1, num_guests): for t in all_tables: same_table[(g1, g2, t)] = model.NewBoolVar( "guest %i seats with guest %i on table %i" % (g1, g2, t)) # Objective model.Maximize( sum(C[g1][g2] * colocated[g1, g2] for g1 in range(num_guests - 1) for g2 in range(g1 + 1, num_guests) if C[g1][g2] > 0)) # # Constraints # # Everybody seats at one table. for g in all_guests: model.Add(sum(seats[(t, g)] for t in all_tables) == 1) # Tables have a max capacity. for t in all_tables: model.Add(sum(seats[(t, g)] for g in all_guests) <= table_capacity) # Link colocated with seats for g1 in range(num_guests - 1): for g2 in range(g1 + 1, num_guests): for t in all_tables: # Link same_table and seats. model.AddBoolOr([ seats[(t, g1)].Not(), seats[(t, g2)].Not(), same_table[(g1, g2, t)] ]) model.AddImplication(same_table[(g1, g2, t)], seats[(t, g1)]) model.AddImplication(same_table[(g1, g2, t)], seats[(t, g2)]) # Link colocated and same_table. model.Add( sum(same_table[(g1, g2, t)] for t in all_tables) == colocated[(g1, g2)]) # Min known neighbors rule. for t in all_tables: model.Add( sum(same_table[(g1, g2, t)] for g1 in range(num_guests - 1) for g2 in range(g1 + 1, num_guests) for t in all_tables if C[g1][g2] > 0) >= min_known_neighbors) # Symmetry breaking. First guest seats on the first table. model.Add(seats[(0, 0)] == 1) ### Solve model solver = cp_model.CpSolver() solution_printer = WeddingChartPrinter(seats, names, num_tables, num_guests, maxSolutions) solver.SolveWithSolutionCallback(model, solution_printer) return solution_printer.getSolution()
def scheduling(body): # data = { # 'cantJobs': "3", # 'cantTasks': "4", # 'tiempoTasks': # lo que se demora cada tarea # [3, 3, 2, 1], # 'precedencia': # restricciones de precedencia, son del tipo endBeforeStart(tarea1, tarea2) # [[4, 3], # [3, 2], # [2, 1]], # 'cantRecursos': "2", # 'cantUnidades': # cantidad de cada recurso # [1, 2], # 'demandaTasks': # [[1, 0], # [1, 1], # [0, 1], # [1, 0]] # } json_data = body print("llego") print(json_data) cant_jobs = int(json_data['cantJobs']) cant_tasks = int(json_data['cantTasks']) tiempo_tasks = json_data['tiempoTasks'] precedencia = (json_data['precedencia']) cant_recursos = int(json_data['cantRecursos']) cant_unidades = json_data['cantUnidades'] demanda_tasks = json_data['demandaTasks'] # crear modelo model = cp_model.CpModel() # crear las variables de decision: intervalos para cada task task_type = namedtuple('task_type', 'jobId taskId start end interval demand') jobs = [] all_tasks = [] limite = sum( tiempo_tasks) * cant_jobs # limite de tiempo para las variables for j in range(cant_jobs): tasks = [] for t in range(cant_tasks): id = '_' + str(j) + '_' + str(t) start = model.NewIntVar(0, limite, 'start' + id) duration = tiempo_tasks[t] end = model.NewIntVar(0, limite, 'end' + id) interval = model.NewIntervalVar(start, duration, end, 'interval' + id) demand = demanda_tasks[t] task = task_type(j, t, start, end, interval, demand) tasks.append(task) all_tasks.append(task) jobs.append(tasks) print(jobs) # Restricciones # Precedencia for p in precedencia: end_task = p[0] - 1 before_start_task = p[1] - 1 for job in jobs: model.Add(job[end_task].end <= job[before_start_task].start) # Recursos: va a ser siempre con reposición, que el acumulado de la demanda de cada recurso no supere la capacidad # en un momento dado for r in range(cant_recursos): model.AddCumulative( [task.interval for task in all_tasks], # los intervalos de los tasks [task.demand[r] for task in all_tasks], # la demanda por cada task de ese recurso cant_unidades[r]) # la capacidad de cada recurso # Objetivo: crear un timeSpan que termine lo antes posible la ultima tarea del ultimo job obj_var = model.NewIntVar(0, limite, 'makespan') model.AddMaxEquality(obj_var, [task.end for task in job for job in jobs]) model.Minimize(obj_var) # Resolver el modelo solver = cp_model.CpSolver() status = solver.Solve(model) if status == cp_model.OPTIMAL: solution = [] for task in all_tasks: solution.append({ 'job': task.jobId + 1, 'task': task.taskId + 1, 'start': solver.Value(task.start), 'end': solver.Value(task.end) }) answer = {'error': False, 'solution': solution} else: answer = {'error': True, 'message': 'No existe una solución'} print(solution) print(answer) return answer
def main(): # Creates the solver. model = cp_model.CpModel() machines_count = 6 jobs_count = 6 all_machines = range(0, machines_count) all_jobs = range(0, jobs_count) durations = [[1, 3, 6, 7, 3, 6], [8, 5, 10, 10, 10, 4], [5, 4, 8, 9, 1, 7], [5, 5, 5, 3, 8, 9], [9, 3, 5, 4, 3, 1], [3, 3, 9, 10, 4, 1]] machines = [[2, 0, 1, 3, 5, 4], [1, 2, 4, 5, 0, 3], [2, 3, 5, 0, 1, 4], [1, 0, 2, 3, 4, 5], [2, 1, 4, 5, 0, 3], [1, 3, 5, 0, 4, 2]] # Computes horizon dynamically. horizon = sum([sum(durations[i]) for i in all_jobs]) Task = collections.namedtuple('Task', 'start end interval') # Creates jobs. all_tasks = {} for i in all_jobs: for j in all_machines: start_var = model.NewIntVar(0, horizon, 'start_%i_%i' % (i, j)) duration = durations[i][j] end_var = model.NewIntVar(0, horizon, 'end_%i_%i' % (i, j)) interval_var = model.NewIntervalVar(start_var, duration, end_var, 'interval_%i_%i' % (i, j)) all_tasks[(i, j)] = Task( start=start_var, end=end_var, interval=interval_var) # Create disjuctive constraints. machine_to_jobs = {} for i in all_machines: machines_jobs = [] for j in all_jobs: for k in all_machines: if machines[j][k] == i: machines_jobs.append(all_tasks[(j, k)].interval) machine_to_jobs[i] = machines_jobs model.AddNoOverlap(machines_jobs) # Precedences inside a job. for i in all_jobs: for j in range(0, machines_count - 1): model.Add(all_tasks[(i, j + 1)].start >= all_tasks[(i, j)].end) # Makespan objective. obj_var = model.NewIntVar(0, horizon, 'makespan') model.AddMaxEquality( obj_var, [all_tasks[(i, machines_count - 1)].end for i in all_jobs]) model.Minimize(obj_var) # Solve model. solver = cp_model.CpSolver() response = solver.Solve(model) # Output solution. if visualization.RunFromIPython(): starts = [[solver.Value(all_tasks[(i, j)][0]) for j in all_machines] for i in all_jobs] visualization.DisplayJobshop(starts, durations, machines, 'FT06') else: print('Optimal makespan: %i' % solver.ObjectiveValue())
def steel_mill_slab(problem, break_symmetries, output_proto): """Solves the Steel Mill Slab Problem.""" ### Load problem. (num_slabs, capacities, num_colors, orders) = build_problem(problem) num_orders = len(orders) num_capacities = len(capacities) all_slabs = range(num_slabs) all_colors = range(num_colors) all_orders = range(len(orders)) print('Solving steel mill with %i orders, %i slabs, and %i capacities' % (num_orders, num_slabs, num_capacities - 1)) # Compute auxilliary data. widths = [x[0] for x in orders] colors = [x[1] for x in orders] max_capacity = max(capacities) loss_array = [ min(x for x in capacities if x >= c) - c for c in range(max_capacity + 1) ] max_loss = max(loss_array) orders_per_color = [[o for o in all_orders if colors[o] == c + 1] for c in all_colors] unique_color_orders = [ o for o in all_orders if len(orders_per_color[colors[o] - 1]) == 1 ] ### Model problem. # Create the model and the decision variables. model = cp_model.CpModel() assign = [[ model.NewBoolVar('assign_%i_to_slab_%i' % (o, s)) for s in all_slabs ] for o in all_orders] loads = [ model.NewIntVar(0, max_capacity, 'load_of_slab_%i' % s) for s in all_slabs ] color_is_in_slab = [[ model.NewBoolVar('color_%i_in_slab_%i' % (c + 1, s)) for c in all_colors ] for s in all_slabs] # Compute load of all slabs. for s in all_slabs: model.Add( sum(assign[o][s] * widths[o] for o in all_orders) == loads[s]) # Orders are assigned to one slab. for o in all_orders: model.Add(sum(assign[o]) == 1) # Redundant constraint (sum of loads == sum of widths). model.Add(sum(loads) == sum(widths)) # Link present_colors and assign. for c in all_colors: for s in all_slabs: for o in orders_per_color[c]: model.AddImplication(assign[o][s], color_is_in_slab[s][c]) model.AddImplication(color_is_in_slab[s][c].Not(), assign[o][s].Not()) # At most two colors per slab. for s in all_slabs: model.Add(sum(color_is_in_slab[s]) <= 2) # Project previous constraint on unique_color_orders for s in all_slabs: model.Add(sum(assign[o][s] for o in unique_color_orders) <= 2) # Symmetry breaking. for s in range(num_slabs - 1): model.Add(loads[s] >= loads[s + 1]) # Collect equivalent orders. width_to_unique_color_order = {} ordered_equivalent_orders = [] for c in all_colors: colored_orders = orders_per_color[c] if not colored_orders: continue if len(colored_orders) == 1: o = colored_orders[0] w = widths[o] if w not in width_to_unique_color_order: width_to_unique_color_order[w] = [o] else: width_to_unique_color_order[w].append(o) else: local_width_to_order = {} for o in colored_orders: w = widths[o] if w not in local_width_to_order: local_width_to_order[w] = [] local_width_to_order[w].append(o) for w, os in local_width_to_order.items(): if len(os) > 1: for p in range(len(os) - 1): ordered_equivalent_orders.append((os[p], os[p + 1])) for w, os in width_to_unique_color_order.items(): if len(os) > 1: for p in range(len(os) - 1): ordered_equivalent_orders.append((os[p], os[p + 1])) # Create position variables if there are symmetries to be broken. if break_symmetries and ordered_equivalent_orders: print(' - creating %i symmetry breaking constraints' % len(ordered_equivalent_orders)) positions = {} for p in ordered_equivalent_orders: if p[0] not in positions: positions[p[0]] = model.NewIntVar(0, num_slabs - 1, 'position_of_slab_%i' % p[0]) model.AddMapDomain(positions[p[0]], assign[p[0]]) if p[1] not in positions: positions[p[1]] = model.NewIntVar(0, num_slabs - 1, 'position_of_slab_%i' % p[1]) model.AddMapDomain(positions[p[1]], assign[p[1]]) # Finally add the symmetry breaking constraint. model.Add(positions[p[0]] <= positions[p[1]]) # Objective. obj = model.NewIntVar(0, num_slabs * max_loss, 'obj') losses = [model.NewIntVar(0, max_loss, 'loss_%i' % s) for s in all_slabs] for s in all_slabs: model.AddElement(loads[s], loss_array, losses[s]) model.Add(obj == sum(losses)) model.Minimize(obj) ### Solve model. solver = cp_model.CpSolver() solver.parameters.num_search_workers = 8 objective_printer = cp_model.ObjectiveSolutionPrinter() status = solver.SolveWithSolutionCallback(model, objective_printer) ### Output the solution. if status in (cp_model.OPTIMAL, cp_model.FEASIBLE): print('Loss = %i, time = %f s, %i conflicts' % (solver.ObjectiveValue(), solver.WallTime(), solver.NumConflicts())) else: print('No solution')
def MinimalJobshopSat(): """Minimal jobshop problem.""" # Create the model. model = cp_model.CpModel()
def MinimalJobshopToy(): #define the model model = cp_model.CpModel() '''Import Data''' #set data directory data_dir = 'Toy Job Shop problem.xlsx' imported_data_df = pd.read_excel(data_dir, sheet_name='Data') #print (imported_data_df) #check column format imported_data_df.dtypes #Organisation object #Task 1 completion date datetime64[ns] #Task 2 Completion date datetime64[ns] #Task 3 length int64 #Task 4 length int64 #dtype: object #Create initialisation date 2019-10-01 imported_data_df = imported_data_df.assign( Initialisation_Date=pd.to_datetime('2019-10-01')) #create Task_1_length column (int) imported_data_df = imported_data_df.assign( Task_1_length=((imported_data_df['Task 1 completion date'] - imported_data_df['Initialisation_Date']) / np.timedelta64(1, 'D')).astype(int)) #creating Task_2_lenght on the assumption that task two can start only after task 1 is completed. is that the case? imported_data_df = imported_data_df.assign( Task_2_length=((imported_data_df['Task 2 Completion date'] - imported_data_df['Task 1 completion date']) / np.timedelta64(1, 'D')).astype(int)) #df['diff_days'] = df['End_date'] - df['Start_date'] #df['diff_days']=df['diff_days']/np.timedelta64(1,'D') #find max(Task 2 Completion date) and define Transition_Date_Start as max(Task 2 Completion date) +5 imported_data_df = imported_data_df.assign(Max_Preparation_Task_2_dt=max( imported_data_df['Task 2 Completion date'])) #imported_data_df=imported_data_df.assign(Transition_Date_Start = imported_data_df['Max_Preparation_Task_2_dt'] + 5 ) imported_data_df["Transition_Date_Start"] = imported_data_df[ "Max_Preparation_Task_2_dt"] + timedelta(days=5) #compute waiting days between task2 end date and transition start date wait_days = imported_data_df['Transition_Date_Start'] - imported_data_df[ 'Task 2 Completion date'] #convert the days into integer format Pause_length = [] for i in wait_days: j = i.days Pause_length.append(j) #Add this column to the dataframe imported_data_df['Pause_length'] = Pause_length '''Define the data''' df = imported_data_df[[ 'Organisation', 'Task_1_length', 'Task_2_length', 'Pause_length', 'Task 3 length', 'Task 4 length' ]] jobs_data = [] for j in range(1, len(df.columns)): ls = [] for i in range(0, len(df.index)): task = (i + 1, df.iloc[i, j]) ls.append(task) jobs_data.append(ls) org_count = 1 + max(task[0] for job in jobs_data for task in job) all_organisations = range(org_count) '''Define Variables''' # Named tuple to store information about created variables. task_type = collections.namedtuple('task_type', 'start end interval') # Named tuple to manipulate solution information. assigned_task_type = collections.namedtuple('assigned_task_type', 'start job index duration') # Create job intervals and add to the corresponding machine lists. all_tasks = {} org_to_intervals = collections.defaultdict(list) # Computes horizon dynamically as the sum of all durations. horizon = sum(task[1] for job in jobs_data for task in job) for job_id, job in enumerate(jobs_data): for task_id, task in enumerate(job): organisation = task[0] duration = task[1] suffix = '_%i_%i' % (job_id, task_id) start_var = model.NewIntVar(0, int(horizon), 'start' + suffix) end_var = model.NewIntVar(0, int(horizon), 'end' + suffix) interval_var = model.NewIntervalVar(start_var, duration, end_var, 'interval' + suffix) all_tasks[job_id, task_id] = task_type(start=start_var, end=end_var, interval=interval_var) org_to_intervals[organisation].append(interval_var) '''Define Constraints''' # Create and add disjunctive constraints. for organisation in all_organisations: model.AddNoOverlap(org_to_intervals[organisation]) '''Define the Objective''' # Makespan objective. obj_var = model.NewIntVar(0, int(horizon), 'makespan') model.AddMaxEquality(obj_var, [ all_tasks[job_id, len(job) - 1].end for job_id, job in enumerate(jobs_data) ]) model.Minimize(obj_var) '''Declare the Solver''' # Solve model. solver = cp_model.CpSolver() status = solver.Solve(model) '''Display the results''' # Create one list of assigned tasks per machine. assigned_jobs = collections.defaultdict(list) for job_id, job in enumerate(jobs_data): for task_id, task in enumerate(job): organisation = task[0] assigned_jobs[organisation].append( assigned_task_type(start=solver.Value( all_tasks[job_id, task_id].start), job=job_id, index=task_id, duration=task[1])) # Create per organisation output lines. output = '' for organisation in all_organisations: # Sort by starting time. assigned_jobs[organisation].sort() sol_line_tasks = 'Organisation ' + str(organisation) + ': ' sol_line = ' ' for assigned_task in assigned_jobs[organisation]: name = 'job_%i_%i' % (assigned_task.job, assigned_task.index) # Add spaces to output to align columns. sol_line_tasks += '%-10s' % name start = assigned_task.start duration = assigned_task.duration sol_tmp = '[%i,%i]' % (start, start + duration) # Add spaces to output to align columns. sol_line += '%-10s' % sol_tmp sol_line += '\n' sol_line_tasks += '\n' output += sol_line_tasks output += sol_line # Finally print the solution found. print('Optimal Schedule Length: %i' % solver.ObjectiveValue()) print(output)
def model_powereco_plant(): t = 'model_powereco_plant' ### onde usar isto ....???? ## creating a model the_model = cp_model.CpModel() # DATA --- C1 = 35 ### Capacity of a supplier ... 1 up to 3 C2 = 50 C3 = 40 suppliers = 3 ### index 0 up to 2 cities = 4 ### 0 .. 3 ''' custo = 8*x11 + 6*x12 + 10*x13 + 9*x14 + 9*x21 + 12*x22 + 13*x23 + 7*x24+ 14*x31 + 9*x32 + 16*x33 + 5*x34; ''' ## transmission cost between suppliers (i -- rows) and cities (j--cols) cost = [ [8, 6, 10, 9], [9, 12, 13, 7], [14, 9, 16, 5] ] ### Should be come from a file NINE_NINE = 999999 ### a constant #### VARIABLES ## ANOTHER IDEA AROUND THIS --- how much is going from i to j? ### Example x=[[s.NumVar(0,C[i][j],'')for j in range(n)]for i in range(n) x = [ [the_model.NewIntVar(0, C1, 'x[0][%i]' % INDEX_1) for INDEX_1 in range(cities)] , [the_model.NewIntVar(0, C2, 'x[1][%i]' % INDEX_2) for INDEX_2 in range(cities)] , [the_model.NewIntVar(0, C3, 'x[2][%i]' % INDEX_3) for INDEX_3 in range(cities)] ] ### range(start, range ) --- start in specific index # f_objective = the_model.NewIntVar (0, NINE_NINE, 'cost function') # CONSTRAINTS ADDED ####x11 + x12 + x13 + x14 <= C1; %(Plant 1 supply constraint) ## C capacity of each Suppliers the_model.Add(sum(x[0][j] for j in range(cities)) <= C1) the_model.Add(sum(x[1][j] for j in range(cities)) <= C2) the_model.Add(sum(x[2][j] for j in range(cities)) <= C3) ''' x11 + x21 + x31 >= 45 /\ x12 + x22 + x32 >= 20 /\ x13 + x23 + x33 >= 30 /\ x14 + x24 + x34 >= 30 ; >>> for i in range(1,4): print(i) ## learning Python ... 1 2 3 ''' ### Demand of each City 1..4 .... from these suppliers the_model.Add(sum(x[i][0] for i in range(suppliers)) >= 45) the_model.Add(sum(x[i][1] for i in range(suppliers)) >= 20) the_model.Add(sum(x[i][2] for i in range(suppliers)) >= 30) the_model.Add(sum(x[i][3] for i in range(suppliers)) >= 30) ### Objective Function the_model.Add( f_objective == sum( (cost[i][j] * x[i][j]) \ for i in range(suppliers) \ for j in range(cities) )### of sum )## of Add ### optmization function or objective function # OR: the_model.Maximize(-less_DIF) the_model.Minimize(f_objective) ### data_from_model = call the solver for model s # code calls the solver solver_OUT = cp_model.CpSolver() solver_OUT.parameters.max_time_in_seconds = 10 status = solver_OUT.Solve(the_model) if status not in (cp_model.OPTIMAL, cp_model.FEASIBLE): raise ValueError("No solution was found for the given input values") else : my_print_VARS( x , suppliers, cities, f_objective, solver_OUT ) print("\n END SOLVER and Model ") print_t(40) return ###### end function
def __init__(self, N, A): self.N = N self.A = A self.model = cp_model.CpModel()
def solve_cutting_stock_with_arc_flow_and_sat(output_proto_file): """Solve the cutting stock with arc-flow and the CP-SAT solver.""" items = regroup_and_count(DESIRED_LENGTHS) print('Items:', items) num_items = len(DESIRED_LENGTHS) max_capacity = max(POSSIBLE_CAPACITIES) states, transitions = create_state_graph(items, max_capacity) print('Dynamic programming has generated', len(states), 'states and', len(transitions), 'transitions') incoming_vars = collections.defaultdict(list) outgoing_vars = collections.defaultdict(list) incoming_sink_vars = [] item_vars = collections.defaultdict(list) item_coeffs = collections.defaultdict(list) transition_vars = [] model = cp_model.CpModel() objective_vars = [] objective_coeffs = [] for outgoing, incoming, item_index, card in transitions: count = items[item_index][1] max_count = count // card count_var = model.NewIntVar( 0, max_count, 'i%i_f%i_t%i_C%s' % (item_index, incoming, outgoing, card)) incoming_vars[incoming].append(count_var) outgoing_vars[outgoing].append(count_var) item_vars[item_index].append(count_var) item_coeffs[item_index].append(card) transition_vars.append(count_var) for state_index, state in enumerate(states): if state_index == 0: continue exit_var = model.NewIntVar(0, num_items, 'e%i' % state_index) outgoing_vars[state_index].append(exit_var) incoming_sink_vars.append(exit_var) price = price_usage(state, POSSIBLE_CAPACITIES) objective_vars.append(exit_var) objective_coeffs.append(price) # Flow conservation for state_index in range(1, len(states)): model.Add( sum(incoming_vars[state_index]) == sum(outgoing_vars[state_index])) # Flow going out of the source must go in the sink model.Add(sum(outgoing_vars[0]) == sum(incoming_sink_vars)) # Items must be placed for item_index, size_and_count in enumerate(items): num_arcs = len(item_vars[item_index]) model.Add( sum(item_vars[item_index][i] * item_coeffs[item_index][i] for i in range(num_arcs)) == size_and_count[1]) # Objective is the sum of waste model.Minimize( sum(objective_vars[i] * objective_coeffs[i] for i in range(len(objective_vars)))) # Output model proto to file. if output_proto_file: output_file = open(output_proto_file, 'w') output_file.write(str(model.Proto())) output_file.close() # Solve model. solver = cp_model.CpSolver() solver.parameters.log_search_progress = True solver.parameters.num_search_workers = 8 status = solver.Solve(model) print(solver.ResponseStats())
def SimpleSatProgram(): """Minimal CP-SAT example to showcase calling the solver.""" # Creates the model. model = cp_model.CpModel() # Creates the variables. num_vals = 4 A1 = model.NewIntVar(1, num_vals, 'a1') A2 = model.NewIntVar(1, num_vals, 'a2') A3 = model.NewIntVar(1, num_vals, 'a3') A4 = model.NewIntVar(1, num_vals, 'a4') B1 = model.NewIntVar(1, num_vals, 'b1') B2 = model.NewIntVar(1, num_vals, 'b2') B3 = model.NewIntVar(1, num_vals, 'b3') B4 = model.NewIntVar(1, num_vals, 'b4') C1 = model.NewIntVar(1, num_vals, 'c1') C2 = model.NewIntVar(1, num_vals, 'c2') C3 = model.NewIntVar(1, num_vals, 'c3') C4 = model.NewIntVar(1, num_vals, 'c4') D1 = model.NewIntVar(1, num_vals, 'd1') D2 = model.NewIntVar(1, num_vals, 'd2') D3 = model.NewIntVar(1, num_vals, 'd3') D4 = model.NewIntVar(1, num_vals, 'd4') # Creates the constraints. model.Add(A1 != A2) model.Add(A1 != A3) model.Add(A1 != A4) model.Add(A1 != B1) model.Add(A1 != C1) model.Add(A1 != D1) model.Add(A2 != A3) model.Add(A2 != A4) model.Add(A2 != B2) model.Add(A2 != C2) model.Add(A2 != D2) model.Add(A3 != A4) model.Add(A3 != B3) model.Add(A3 != C3) model.Add(A3 != D3) model.Add(A4 != B4) model.Add(A4 != C4) model.Add(A4 != D4) model.Add(B1 != B2) model.Add(B1 != B3) model.Add(B1 != B4) model.Add(B1 != C1) model.Add(B1 != D1) model.Add(B2 != B3) model.Add(B2 != B4) model.Add(B2 != C2) model.Add(B2 != D2) model.Add(B3 != B4) model.Add(B3 != C3) model.Add(B3 != D3) model.Add(B4 != C4) model.Add(B4 != D4) model.Add(C1 != C2) model.Add(C1 != C3) model.Add(C1 != C4) model.Add(C1 != D1) model.Add(C2 != C3) model.Add(C2 != C4) model.Add(C2 != D2) model.Add(C3 != C4) model.Add(C3 != D3) model.Add(C4 != D4) model.Add(D1 != D2) model.Add(D1 != D3) model.Add(D1 != D4) if line1[1].isdigit(): if line1[0] == "A1": model.Add(A1 == int(line1[1])) if line1[0] == "A2": model.Add(A2 == int(line1[1])) if line1[0] == "A3": model.Add(A3 == int(line1[1])) if line1[0] == "A4": model.Add(A4 == int(line1[1])) if line1[0] == "B1": model.Add(B1 == int(line1[1])) if line1[0] == "B2": model.Add(B2 == int(line1[1])) if line1[0] == "B3": model.Add(B3 == int(line1[1])) if line1[0] == "B4": model.Add(B4 == int(line1[1])) if line1[0] == "C1": model.Add(C1 == int(line1[1])) if line1[0] == "C2": model.Add(C2 == int(line1[1])) if line1[0] == "C3": model.Add(C3 == int(line1[1])) if line1[0] == "C4": model.Add(C4 == int(line1[1])) if line1[0] == "D1": model.Add(D1 == int(line1[1])) if line1[0] == "D2": model.Add(D2 == int(line1[1])) if line1[0] == "D3": model.Add(D3 == int(line1[1])) if line1[0] == "D4": model.Add(D4 == int(line1[1])) else: if line1[0] == "A1": if line1[1] == "A2": model.Add(A1 > A2) if line1[1] == "B1": model.Add(A1 > B1) if line1[0] == "A2": if line1[1] == "A1": model.Add(A2 > A1) if line1[1] == "A3": model.Add(A2 > A3) if line1[1] == "B2": model.Add(A2 > B2) if line1[0] == "A3": if line1[1] == "A2": model.Add(A3 > A2) if line1[1] == "A4": model.Add(A3 > A4) if line1[1] == "B3": model.Add(A3 > B3) if line1[0] == "A4": if line1[1] == "B4": model.Add(A4 > B4) if line1[1] == "A3": model.Add(A4 > A3) if line1[0] == "B1": if line1[1] == "A1": model.Add(B1 > A1) if line1[1] == "C1": model.Add(B1 > C1) if line1[1] == "B2": model.Add(B1 > B2) if line1[0] == "B2": if line1[1] == "A2": model.Add(B2 > A2) if line1[1] == "B1": model.Add(B2 > B1) if line1[1] == "B3": model.Add(B2 > B3) if line1[1] == "C2": model.Add(B2 > C2) if line1[0] == "B3": if line1[1] == "A3": model.Add(B3 > A3) if line1[1] == "B2": model.Add(B3 > B2) if line1[1] == "B4": model.Add(B3 > B4) if line1[1] == "C3": model.Add(B3 > C3) if line1[0] == "B4": if line1[1] == "A4": model.Add(B4 > A4) if line1[1] == "B3": model.Add(B4 > B3) if line1[1] == "C4": model.Add(B4 > C4) if line1[0] == "C1": if line1[1] == "B1": model.Add(C1 > B1) if line1[1] == "C2": model.Add(C1 > C2) if line1[1] == "D1": model.Add(C1 > D1) if line1[0] == "C2": if line1[1] == "B2": model.Add(C2 > B2) if line1[1] == "C1": model.Add(C2 > C1) if line1[1] == "C3": model.Add(C2 > C3) if line1[1] == "D2": model.Add(C2 > D2) if line1[0] == "C3": if line1[1] == "B3": model.Add(C3 > B3) if line1[1] == "C2": model.Add(C3 > C2) if line1[1] == "C4": model.Add(C3 > C4) if line1[1] == "D3": model.Add(C3 > D3) if line1[0] == "C4": if line1[1] == "B4": model.Add(C4 > B4) if line1[1] == "D2": model.Add(C4 > D4) if line1[1] == "C3": model.Add(C4 > C3) if line1[0] == "D1": if line1[1] == "C1": model.Add(D1 > C1) if line1[1] == "D2": model.Add(D1 > D2) if line1[0] == "D2": if line1[1] == "D1": model.Add(D2 > D1) if line1[1] == "C2": model.Add(D2 > C2) if line1[1] == "D3": model.Add(D2 > D3) if line1[0] == "D3": if line1[1] == "C3": model.Add(D3 > C3) if line1[1] == "D2": model.Add(D3 > D2) if line1[1] == "D4": model.Add(D3 > D4) if line1[0] == "D4": if line1[1] == "D3": model.Add(D4 > D3) if line1[1] == "C4": model.Add(D4 > C4) #line if line2[1].isdigit(): if line2[0] == "A1": model.Add(A1 == int(line2[1])) if line2[0] == "A2": model.Add(A2 == int(line2[1])) if line2[0] == "A3": model.Add(A3 == int(line2[1])) if line2[0] == "A4": model.Add(A4 == int(line2[1])) if line2[0] == "B1": model.Add(B1 == int(line2[1])) if line2[0] == "B2": model.Add(B2 == int(line2[1])) if line2[0] == "B3": model.Add(B3 == int(line2[1])) if line2[0] == "B4": model.Add(B4 == int(line2[1])) if line2[0] == "C1": model.Add(C1 == int(line2[1])) if line2[0] == "C2": model.Add(C2 == int(line2[1])) if line2[0] == "C3": model.Add(C3 == int(line2[1])) if line2[0] == "C4": model.Add(C4 == int(line2[1])) if line2[0] == "D1": model.Add(D1 == int(line2[1])) if line2[0] == "D2": model.Add(D2 == int(line2[1])) if line2[0] == "D3": model.Add(D3 == int(line2[1])) if line2[0] == "D4": model.Add(D4 == int(line2[1])) else: if line2[0] == "A1": if line2[1] == "A2": model.Add(A1 > A2) if line2[1] == "B1": model.Add(A1 > B1) if line2[0] == "A2": if line2[1] == "A1": model.Add(A2 > A1) if line2[1] == "A3": model.Add(A2 > A3) if line2[1] == "B2": model.Add(A2 > B2) if line2[0] == "A3": if line2[1] == "A2": model.Add(A3 > A2) if line2[1] == "A4": model.Add(A3 > A4) if line2[1] == "B3": model.Add(A3 > B3) if line2[0] == "A4": if line2[1] == "B4": model.Add(A4 > B4) if line2[1] == "A3": model.Add(A4 > A3) if line2[0] == "B1": if line2[1] == "A1": model.Add(B1 > A1) if line2[1] == "C1": model.Add(B1 > C1) if line2[1] == "B2": model.Add(B1 > B2) if line2[0] == "B2": if line2[1] == "A2": model.Add(B2 > A2) if line2[1] == "B1": model.Add(B2 > B1) if line2[1] == "B3": model.Add(B2 > B3) if line2[1] == "C2": model.Add(B2 > C2) if line2[0] == "B3": if line2[1] == "A3": model.Add(B3 > A3) if line2[1] == "B2": model.Add(B3 > B2) if line2[1] == "B4": model.Add(B3 > B4) if line2[1] == "C3": model.Add(B3 > C3) if line2[0] == "B4": if line2[1] == "A4": model.Add(B4 > A4) if line2[1] == "B3": model.Add(B4 > B3) if line2[1] == "C4": model.Add(B4 > C4) if line2[0] == "C1": if line2[1] == "B1": model.Add(C1 > B1) if line2[1] == "C2": model.Add(C1 > C2) if line2[1] == "D1": model.Add(C1 > D1) if line2[0] == "C2": if line2[1] == "B2": model.Add(C2 > B2) if line2[1] == "C1": model.Add(C2 > C1) if line2[1] == "C3": model.Add(C2 > C3) if line2[1] == "D2": model.Add(C2 > D2) if line2[0] == "C3": if line2[1] == "B3": model.Add(C3 > B3) if line2[1] == "C2": model.Add(C3 > C2) if line2[1] == "C4": model.Add(C3 > C4) if line2[1] == "D3": model.Add(C3 > D3) if line2[0] == "C4": if line2[1] == "B4": model.Add(C4 > B4) if line2[1] == "D2": model.Add(C4 > D4) if line2[1] == "C3": model.Add(C4 > C3) if line2[0] == "D1": if line2[1] == "C1": model.Add(D1 > C1) if line2[1] == "D2": model.Add(D1 > D2) if line2[0] == "D2": if line2[1] == "D1": model.Add(D2 > D1) if line2[1] == "C2": model.Add(D2 > C2) if line2[1] == "D3": model.Add(D2 > D3) if line2[0] == "D3": if line2[1] == "C3": model.Add(D3 > C3) if line2[1] == "D2": model.Add(D3 > D2) if line2[1] == "D4": model.Add(D3 > D4) if line2[0] == "D4": if line2[1] == "D3": model.Add(D4 > D3) if line2[1] == "C4": model.Add(D4 > C4) #line3 if line3[1].isdigit(): if line3[0] == "A1": model.Add(A1 == int(line3[1])) if line3[0] == "A2": model.Add(A2 == int(line3[1])) if line3[0] == "A3": model.Add(A3 == int(line3[1])) if line3[0] == "A4": model.Add(A4 == int(line3[1])) if line3[0] == "B1": model.Add(B1 == int(line3[1])) if line3[0] == "B2": model.Add(B2 == int(line3[1])) if line3[0] == "B3": model.Add(B3 == int(line3[1])) if line3[0] == "B4": model.Add(B4 == int(line3[1])) if line3[0] == "C1": model.Add(C1 == int(line3[1])) if line3[0] == "C2": model.Add(C2 == int(line3[1])) if line3[0] == "C3": model.Add(C3 == int(line3[1])) if line3[0] == "C4": model.Add(C4 == int(line3[1])) if line3[0] == "D1": model.Add(D1 == int(line3[1])) if line3[0] == "D2": model.Add(D2 == int(line3[1])) if line3[0] == "D3": model.Add(D3 == int(line3[1])) if line3[0] == "D4": model.Add(D4 == int(line3[1])) else: if line3[0] == "A1": if line3[1] == "A2": model.Add(A1 > A2) if line3[1] == "B1": model.Add(A1 > B1) if line3[0] == "A2": if line3[1] == "A1": model.Add(A2 > A1) if line3[1] == "A3": model.Add(A2 > A3) if line3[1] == "B2": model.Add(A2 > B2) if line3[0] == "A3": if line3[1] == "A2": model.Add(A3 > A2) if line3[1] == "A4": model.Add(A3 > A4) if line3[1] == "B3": model.Add(A3 > B3) if line3[0] == "A4": if line3[1] == "B4": model.Add(A4 > B4) if line3[1] == "A3": model.Add(A4 > A3) if line3[0] == "B1": if line3[1] == "A1": model.Add(B1 > A1) if line3[1] == "C1": model.Add(B1 > C1) if line3[1] == "B2": model.Add(B1 > B2) if line3[0] == "B2": if line3[1] == "A2": model.Add(B2 > A2) if line3[1] == "B1": model.Add(B2 > B1) if line3[1] == "B3": model.Add(B2 > B3) if line3[1] == "C2": model.Add(B2 > C2) if line3[0] == "B3": if line3[1] == "A3": model.Add(B3 > A3) if line3[1] == "B2": model.Add(B3 > B2) if line3[1] == "B4": model.Add(B3 > B4) if line3[1] == "C3": model.Add(B3 > C3) if line3[0] == "B4": if line3[1] == "A4": model.Add(B4 > A4) if line3[1] == "B3": model.Add(B4 > B3) if line3[1] == "C4": model.Add(B4 > C4) if line3[0] == "C1": if line3[1] == "B1": model.Add(C1 > B1) if line3[1] == "C2": model.Add(C1 > C2) if line3[1] == "D1": model.Add(C1 > D1) if line3[0] == "C2": if line3[1] == "B2": model.Add(C2 > B2) if line3[1] == "C1": model.Add(C2 > C1) if line3[1] == "C3": model.Add(C2 > C3) if line3[1] == "D2": model.Add(C2 > D2) if line3[0] == "C3": if line3[1] == "B3": model.Add(C3 > B3) if line3[1] == "C2": model.Add(C3 > C2) if line3[1] == "C4": model.Add(C3 > C4) if line3[1] == "D3": model.Add(C3 > D3) if line3[0] == "C4": if line3[1] == "B4": model.Add(C4 > B4) if line3[1] == "D2": model.Add(C4 > D4) if line3[1] == "C3": model.Add(C4 > C3) if line3[0] == "D1": if line3[1] == "C1": model.Add(D1 > C1) if line3[1] == "D2": model.Add(D1 > D2) if line3[0] == "D2": if line3[1] == "D1": model.Add(D2 > D1) if line3[1] == "C2": model.Add(D2 > C2) if line3[1] == "D3": model.Add(D2 > D3) if line3[0] == "D3": if line3[1] == "C3": model.Add(D3 > C3) if line3[1] == "D2": model.Add(D3 > D2) if line3[1] == "D4": model.Add(D3 > D4) if line3[0] == "D4": if line3[1] == "D3": model.Add(D4 > D3) if line3[1] == "C4": model.Add(D4 > C4) #line4 if line4[1].isdigit(): if line4[0] == "A1": model.Add(A1 == int(line4[1])) if line4[0] == "A2": model.Add(A2 == int(line4[1])) if line4[0] == "A3": model.Add(A3 == int(line4[1])) if line4[0] == "A4": model.Add(A4 == int(line4[1])) if line4[0] == "B1": model.Add(B1 == int(line4[1])) if line4[0] == "B2": model.Add(B2 == int(line4[1])) if line4[0] == "B3": model.Add(B3 == int(line4[1])) if line4[0] == "B4": model.Add(B4 == int(line4[1])) if line4[0] == "C1": model.Add(C1 == int(line4[1])) if line4[0] == "C2": model.Add(C2 == int(line4[1])) if line4[0] == "C3": model.Add(C3 == int(line4[1])) if line4[0] == "C4": model.Add(C4 == int(line4[1])) if line4[0] == "D1": model.Add(D1 == int(line4[1])) if line4[0] == "D2": model.Add(D2 == int(line4[1])) if line4[0] == "D3": model.Add(D3 == int(line4[1])) if line4[0] == "D4": model.Add(D4 == int(line4[1])) else: if line4[0] == "A1": if line4[1] == "A2": model.Add(A1 > A2) if line4[1] == "B1": model.Add(A1 > B1) if line4[0] == "A2": if line4[1] == "A1": model.Add(A2 > A1) if line4[1] == "A3": model.Add(A2 > A3) if line4[1] == "B2": model.Add(A2 > B2) if line4[0] == "A3": if line4[1] == "A2": model.Add(A3 > A2) if line4[1] == "A4": model.Add(A3 > A4) if line4[1] == "B3": model.Add(A3 > B3) if line4[0] == "A4": if line4[1] == "B4": model.Add(A4 > B4) if line4[1] == "A3": model.Add(A4 > A3) if line4[0] == "B1": if line4[1] == "A1": model.Add(B1 > A1) if line4[1] == "C1": model.Add(B1 > C1) if line4[1] == "B2": model.Add(B1 > B2) if line4[0] == "B2": if line4[1] == "A2": model.Add(B2 > A2) if line4[1] == "B1": model.Add(B2 > B1) if line4[1] == "B3": model.Add(B2 > B3) if line4[1] == "C2": model.Add(B2 > C2) if line4[0] == "B3": if line4[1] == "A3": model.Add(B3 > A3) if line4[1] == "B2": model.Add(B3 > B2) if line4[1] == "B4": model.Add(B3 > B4) if line4[1] == "C3": model.Add(B3 > C3) if line4[0] == "B4": if line4[1] == "A4": model.Add(B4 > A4) if line4[1] == "B3": model.Add(B4 > B3) if line4[1] == "C4": model.Add(B4 > C4) if line4[0] == "C1": if line4[1] == "B1": model.Add(C1 > B1) if line4[1] == "C2": model.Add(C1 > C2) if line4[1] == "D1": model.Add(C1 > D1) if line4[0] == "C2": if line4[1] == "B2": model.Add(C2 > B2) if line4[1] == "C1": model.Add(C2 > C1) if line4[1] == "C3": model.Add(C2 > C3) if line4[1] == "D2": model.Add(C2 > D2) if line4[0] == "C3": if line4[1] == "B3": model.Add(C3 > B3) if line4[1] == "C2": model.Add(C3 > C2) if line4[1] == "C4": model.Add(C3 > C4) if line4[1] == "D3": model.Add(C3 > D3) if line4[0] == "C4": if line4[1] == "B4": model.Add(C4 > B4) if line4[1] == "D2": model.Add(C4 > D4) if line4[1] == "C3": model.Add(C4 > C3) if line4[0] == "D1": if line4[1] == "C1": model.Add(D1 > C1) if line4[1] == "D2": model.Add(D1 > D2) if line4[0] == "D2": if line4[1] == "D1": model.Add(D2 > D1) if line4[1] == "C2": model.Add(D2 > C2) if line4[1] == "D3": model.Add(D2 > D3) if line4[0] == "D3": if line4[1] == "C3": model.Add(D3 > C3) if line4[1] == "D2": model.Add(D3 > D2) if line4[1] == "D4": model.Add(D3 > D4) if line4[0] == "D4": if line4[1] == "D3": model.Add(D4 > D3) if line4[1] == "C4": model.Add(D4 > C4) #line5 if line5[1].isdigit(): if line5[0] == "A1": model.Add(A1 == int(line5[1])) if line5[0] == "A2": model.Add(A2 == int(line5[1])) if line5[0] == "A3": model.Add(A3 == int(line5[1])) if line5[0] == "A4": model.Add(A4 == int(line5[1])) if line5[0] == "B1": model.Add(B1 == int(line5[1])) if line5[0] == "B2": model.Add(B2 == int(line5[1])) if line5[0] == "B3": model.Add(B3 == int(line5[1])) if line5[0] == "B4": model.Add(B4 == int(line5[1])) if line5[0] == "C1": model.Add(C1 == int(line5[1])) if line5[0] == "C2": model.Add(C2 == int(line5[1])) if line5[0] == "C3": model.Add(C3 == int(line5[1])) if line5[0] == "C4": model.Add(C4 == int(line5[1])) if line5[0] == "D1": model.Add(D1 == int(line5[1])) if line5[0] == "D2": model.Add(D2 == int(line5[1])) if line5[0] == "D3": model.Add(D3 == int(line5[1])) if line5[0] == "D4": model.Add(D4 == int(line5[1])) else: if line5[0] == "A1": if line5[1] == "A2": model.Add(A1 > A2) if line5[1] == "B1": model.Add(A1 > B1) if line5[0] == "A2": if line5[1] == "A1": model.Add(A2 > A1) if line5[1] == "A3": model.Add(A2 > A3) if line5[1] == "B2": model.Add(A2 > B2) if line5[0] == "A3": if line5[1] == "A2": model.Add(A3 > A2) if line5[1] == "A4": model.Add(A3 > A4) if line5[1] == "B3": model.Add(A3 > B3) if line5[0] == "A4": if line5[1] == "B4": model.Add(A4 > B4) if line5[1] == "A3": model.Add(A4 > A3) if line5[0] == "B1": if line5[1] == "A1": model.Add(B1 > A1) if line5[1] == "C1": model.Add(B1 > C1) if line5[1] == "B2": model.Add(B1 > B2) if line5[0] == "B2": if line5[1] == "A2": model.Add(B2 > A2) if line5[1] == "B1": model.Add(B2 > B1) if line5[1] == "B3": model.Add(B2 > B3) if line5[1] == "C2": model.Add(B2 > C2) if line5[0] == "B3": if line5[1] == "A3": model.Add(B3 > A3) if line5[1] == "B2": model.Add(B3 > B2) if line5[1] == "B4": model.Add(B3 > B4) if line5[1] == "C3": model.Add(B3 > C3) if line5[0] == "B4": if line5[1] == "A4": model.Add(B4 > A4) if line5[1] == "B3": model.Add(B4 > B3) if line5[1] == "C4": model.Add(B4 > C4) if line5[0] == "C1": if line5[1] == "B1": model.Add(C1 > B1) if line5[1] == "C2": model.Add(C1 > C2) if line5[1] == "D1": model.Add(C1 > D1) if line5[0] == "C2": if line5[1] == "B2": model.Add(C2 > B2) if line5[1] == "C1": model.Add(C2 > C1) if line5[1] == "C3": model.Add(C2 > C3) if line5[1] == "D2": model.Add(C2 > D2) if line5[0] == "C3": if line5[1] == "B3": model.Add(C3 > B3) if line5[1] == "C2": model.Add(C3 > C2) if line5[1] == "C4": model.Add(C3 > C4) if line5[1] == "D3": model.Add(C3 > D3) if line5[0] == "C4": if line5[1] == "B4": model.Add(C4 > B4) if line5[1] == "D2": model.Add(C4 > D4) if line5[1] == "C3": model.Add(C4 > C3) if line5[0] == "D1": if line5[1] == "C1": model.Add(D1 > C1) if line5[1] == "D2": model.Add(D1 > D2) if line5[0] == "D2": if line5[1] == "D1": model.Add(D2 > D1) if line5[1] == "C2": model.Add(D2 > C2) if line5[1] == "D3": model.Add(D2 > D3) if line5[0] == "D3": if line5[1] == "C3": model.Add(D3 > C3) if line5[1] == "D2": model.Add(D3 > D2) if line5[1] == "D4": model.Add(D3 > D4) if line5[0] == "D4": if line5[1] == "D3": model.Add(D4 > D3) if line5[1] == "C4": model.Add(D4 > C4) #line6 if line6[1].isdigit(): if line6[0] == "A1": model.Add(A1 == int(line6[1])) if line6[0] == "A2": model.Add(A2 == int(line6[1])) if line6[0] == "A3": model.Add(A3 == int(line6[1])) if line6[0] == "A4": model.Add(A4 == int(line6[1])) if line6[0] == "B1": model.Add(B1 == int(line6[1])) if line6[0] == "B2": model.Add(B2 == int(line6[1])) if line6[0] == "B3": model.Add(B3 == int(line6[1])) if line6[0] == "B4": model.Add(B4 == int(line6[1])) if line6[0] == "C1": model.Add(C1 == int(line6[1])) if line6[0] == "C2": model.Add(C2 == int(line6[1])) if line6[0] == "C3": model.Add(C3 == int(line6[1])) if line6[0] == "C4": model.Add(C4 == int(line6[1])) if line6[0] == "D1": model.Add(D1 == int(line6[1])) if line6[0] == "D2": model.Add(D2 == int(line6[1])) if line6[0] == "D3": model.Add(D3 == int(line6[1])) if line6[0] == "D4": model.Add(D4 == int(line6[1])) else: if line6[0] == "A1": if line6[1] == "A2": model.Add(A1 > A2) if line6[1] == "B1": model.Add(A1 > B1) if line6[0] == "A2": if line6[1] == "A1": model.Add(A2 > A1) if line6[1] == "A3": model.Add(A2 > A3) if line6[1] == "B2": model.Add(A2 > B2) if line6[0] == "A3": if line6[1] == "A2": model.Add(A3 > A2) if line6[1] == "A4": model.Add(A3 > A4) if line6[1] == "B3": model.Add(A3 > B3) if line6[0] == "A4": if line6[1] == "B4": model.Add(A4 > B4) if line6[1] == "A3": model.Add(A4 > A3) if line6[0] == "B1": if line6[1] == "A1": model.Add(B1 > A1) if line6[1] == "C1": model.Add(B1 > C1) if line6[1] == "B2": model.Add(B1 > B2) if line6[0] == "B2": if line6[1] == "A2": model.Add(B2 > A2) if line6[1] == "B1": model.Add(B2 > B1) if line6[1] == "B3": model.Add(B2 > B3) if line6[1] == "C2": model.Add(B2 > C2) if line6[0] == "B3": if line6[1] == "A3": model.Add(B3 > A3) if line6[1] == "B2": model.Add(B3 > B2) if line6[1] == "B4": model.Add(B3 > B4) if line6[1] == "C3": model.Add(B3 > C3) if line6[0] == "B4": if line6[1] == "A4": model.Add(B4 > A4) if line6[1] == "B3": model.Add(B4 > B3) if line6[1] == "C4": model.Add(B4 > C4) if line6[0] == "C1": if line6[1] == "B1": model.Add(C1 > B1) if line6[1] == "C2": model.Add(C1 > C2) if line6[1] == "D1": model.Add(C1 > D1) if line6[0] == "C2": if line6[1] == "B2": model.Add(C2 > B2) if line6[1] == "C1": model.Add(C2 > C1) if line6[1] == "C3": model.Add(C2 > C3) if line6[1] == "D2": model.Add(C2 > D2) if line6[0] == "C3": if line6[1] == "B3": model.Add(C3 > B3) if line6[1] == "C2": model.Add(C3 > C2) if line6[1] == "C4": model.Add(C3 > C4) if line6[1] == "D3": model.Add(C3 > D3) if line6[0] == "C4": if line6[1] == "B4": model.Add(C4 > B4) if line6[1] == "D2": model.Add(C4 > D4) if line6[1] == "C3": model.Add(C4 > C3) if line6[0] == "D1": if line6[1] == "C1": model.Add(D1 > C1) if line6[1] == "D2": model.Add(D1 > D2) if line6[0] == "D2": if line6[1] == "D1": model.Add(D2 > D1) if line6[1] == "C2": model.Add(D2 > C2) if line6[1] == "D3": model.Add(D2 > D3) if line6[0] == "D3": if line6[1] == "C3": model.Add(D3 > C3) if line6[1] == "D2": model.Add(D3 > D2) if line6[1] == "D4": model.Add(D3 > D4) if line6[0] == "D4": if line6[1] == "D3": model.Add(D4 > D3) if line6[1] == "C4": model.Add(D4 > C4) # Creates a solver and solves the model. solver = cp_model.CpSolver() status = solver.Solve(model) if status == cp_model.FEASIBLE: A1 = solver.Value(A1) A2 = solver.Value(A2) A3 = solver.Value(A3) A4 = solver.Value(A4) B1 = solver.Value(B1) B2 = solver.Value(B2) B3 = solver.Value(B3) B4 = solver.Value(B4) C1 = solver.Value(C1) C2 = solver.Value(C2) C3 = solver.Value(C3) C4 = solver.Value(C4) D1 = solver.Value(D1) D2 = solver.Value(D2) D3 = solver.Value(D3) D4 = solver.Value(D4) #print(A1,",",A2,",",A3,",",A4) #print(B1,",",B2,",",B3,",",B4) #print(C1,",",C2,",",C3,",",C4) #print(D1,",",D2,",",D3,",",D4) list = [A1, A2, A3, A4] list2 = [B1, B2, B3, B4] list3 = [C1, C2, C3, C4] list4 = [D1, D2, D3, D4] for i in list: output.write(str(i)) if i == list[3]: break else: output.write(",") output.write("\n") for i in list2: output.write(str(i)) if i == list2[3]: break else: output.write(",") output.write("\n") for i in list3: output.write(str(i)) if i == list3[3]: break else: output.write(",") output.write("\n") for i in list4: output.write(str(i)) if i == list4[3]: break else: output.write(",")
def steel_mill_slab_with_valid_slabs(problem, break_symmetries, output_proto): """Solves the Steel Mill Slab Problem.""" ### Load problem. (num_slabs, capacities, num_colors, orders) = build_problem(problem) num_orders = len(orders) num_capacities = len(capacities) all_slabs = range(num_slabs) all_colors = range(num_colors) all_orders = range(len(orders)) print('Solving steel mill with %i orders, %i slabs, and %i capacities' % (num_orders, num_slabs, num_capacities - 1)) # Compute auxilliary data. widths = [x[0] for x in orders] colors = [x[1] for x in orders] max_capacity = max(capacities) loss_array = [ min(x for x in capacities if x >= c) - c for c in range(max_capacity + 1) ] max_loss = max(loss_array) ### Model problem. # Create the model and the decision variables. model = cp_model.CpModel() assign = [[ model.NewBoolVar('assign_%i_to_slab_%i' % (o, s)) for s in all_slabs ] for o in all_orders] loads = [ model.NewIntVar(0, max_capacity, 'load_%i' % s) for s in all_slabs ] losses = [model.NewIntVar(0, max_loss, 'loss_%i' % s) for s in all_slabs] unsorted_valid_slabs = collect_valid_slabs_dp(capacities, colors, widths, loss_array) # Sort slab by descending load/loss. Remove duplicates. valid_slabs = sorted(unsorted_valid_slabs, key=lambda c: 1000 * c[-1] + c[-2]) for s in all_slabs: model.AddAllowedAssignments([assign[o][s] for o in all_orders] + [losses[s], loads[s]], valid_slabs) # Orders are assigned to one slab. for o in all_orders: model.Add(sum(assign[o]) == 1) # Redundant constraint (sum of loads == sum of widths). model.Add(sum(loads) == sum(widths)) # Symmetry breaking. for s in range(num_slabs - 1): model.Add(loads[s] >= loads[s + 1]) # Collect equivalent orders. if break_symmetries: print('Breaking symmetries') width_to_unique_color_order = {} ordered_equivalent_orders = [] orders_per_color = [[o for o in all_orders if colors[o] == c + 1] for c in all_colors] for c in all_colors: colored_orders = orders_per_color[c] if not colored_orders: continue if len(colored_orders) == 1: o = colored_orders[0] w = widths[o] if w not in width_to_unique_color_order: width_to_unique_color_order[w] = [o] else: width_to_unique_color_order[w].append(o) else: local_width_to_order = {} for o in colored_orders: w = widths[o] if w not in local_width_to_order: local_width_to_order[w] = [] local_width_to_order[w].append(o) for w, os in local_width_to_order.items(): if len(os) > 1: for p in range(len(os) - 1): ordered_equivalent_orders.append( (os[p], os[p + 1])) for w, os in width_to_unique_color_order.items(): if len(os) > 1: for p in range(len(os) - 1): ordered_equivalent_orders.append((os[p], os[p + 1])) # Create position variables if there are symmetries to be broken. if ordered_equivalent_orders: print(' - creating %i symmetry breaking constraints' % len(ordered_equivalent_orders)) positions = {} for p in ordered_equivalent_orders: if p[0] not in positions: positions[p[0]] = model.NewIntVar( 0, num_slabs - 1, 'position_of_slab_%i' % p[0]) model.AddMapDomain(positions[p[0]], assign[p[0]]) if p[1] not in positions: positions[p[1]] = model.NewIntVar( 0, num_slabs - 1, 'position_of_slab_%i' % p[1]) model.AddMapDomain(positions[p[1]], assign[p[1]]) # Finally add the symmetry breaking constraint. model.Add(positions[p[0]] <= positions[p[1]]) # Objective. model.Minimize(sum(losses)) print('Model created') # Output model proto to file. if output_proto: output_file = open(output_proto, 'w') output_file.write(str(model.Proto())) output_file.close() ### Solve model. solver = cp_model.CpSolver() solver.num_search_workers = 8 solution_printer = SteelMillSlabSolutionPrinter(orders, assign, loads, losses) status = solver.SolveWithSolutionCallback(model, solution_printer) ### Output the solution. if status == cp_model.OPTIMAL: print('Loss = %i, time = %.2f s, %i conflicts' % (solver.ObjectiveValue(), solver.WallTime(), solver.NumConflicts())) else: print('No solution')
def MinimalJobShop(): """Minimal jobshop problem.""" # Create the model. model = cp_model.CpModel() machines_count = 3 jobs_count = 3 all_machines = range(0, machines_count) all_jobs = range(0, jobs_count) # Define data. machines = [[0, 1, 2], [0, 2, 1], [1, 2]] processing_times = [[3, 2, 2], [2, 1, 4], [4, 3]] # Computes horizon. horizon = 0 for job in all_jobs: horizon += sum(processing_times[job]) task_type = collections.namedtuple('task_type', 'start end interval') assigned_task_type = collections.namedtuple('assigned_task_type', 'start job index') # Creates jobs. all_tasks = {} for job in all_jobs: for index in range(0, len(machines[job])): start_var = model.NewIntVar(0, horizon, 'start_%i_%i' % (job, index)) duration = processing_times[job][index] end_var = model.NewIntVar(0, horizon, 'end_%i_%i' % (job, index)) interval_var = model.NewIntervalVar( start_var, duration, end_var, 'interval_%i_%i' % (job, index)) all_tasks[(job, index)] = task_type(start=start_var, end=end_var, interval=interval_var) # Creates sequence variables and add disjunctive constraints. for machine in all_machines: intervals = [] for job in all_jobs: for index in range(0, len(machines[job])): if machines[job][index] == machine: intervals.append(all_tasks[(job, index)].interval) model.AddNoOverlap(intervals) # Add precedence contraints. for job in all_jobs: for index in range(0, len(machines[job]) - 1): model.Add(all_tasks[(job, index + 1)].start >= all_tasks[(job, index)].end) # Makespan objective. obj_var = model.NewIntVar(0, horizon, 'makespan') model.AddMaxEquality( obj_var, [all_tasks[(job, len(machines[job]) - 1)].end for job in all_jobs]) model.Minimize(obj_var) # Solve model. solver = cp_model.CpSolver() status = solver.Solve(model) if status == cp_model.OPTIMAL: # Print out makespan. print('Optimal Schedule Length: %i' % solver.ObjectiveValue()) print() # Create one list of assigned tasks per machine. assigned_jobs = [[] for _ in range(machines_count)] for job in all_jobs: for index in range(len(machines[job])): machine = machines[job][index] assigned_jobs[machine].append( assigned_task_type(start=solver.Value( all_tasks[(job, index)].start), job=job, index=index)) disp_col_width = 10 sol_line = '' sol_line_tasks = '' print('Optimal Schedule', '\n') for machine in all_machines: # Sort by starting time. assigned_jobs[machine].sort() sol_line += 'Machine ' + str(machine) + ': ' sol_line_tasks += 'Machine ' + str(machine) + ': ' for assigned_task in assigned_jobs[machine]: name = 'job_%i_%i' % (assigned_task.job, assigned_task.index) # Add spaces to output to align columns. sol_line_tasks += name + ' ' * (disp_col_width - len(name)) start = assigned_task.start duration = processing_times[assigned_task.job][ assigned_task.index] sol_tmp = '[%i,%i]' % (start, start + duration) # Add spaces to output to align columns. sol_line += sol_tmp + ' ' * (disp_col_width - len(sol_tmp)) sol_line += '\n' sol_line_tasks += '\n' print(sol_line_tasks) print('Time Intervals for task_types\n') print(sol_line)
def steel_mill_slab_with_column_generation(problem, output_proto): """Solves the Steel Mill Slab Problem.""" ### Load problem. (num_slabs, capacities, _, orders) = build_problem(problem) num_orders = len(orders) num_capacities = len(capacities) all_orders = range(len(orders)) print('Solving steel mill with %i orders, %i slabs, and %i capacities' % (num_orders, num_slabs, num_capacities - 1)) # Compute auxilliary data. widths = [x[0] for x in orders] colors = [x[1] for x in orders] max_capacity = max(capacities) loss_array = [ min(x for x in capacities if x >= c) - c for c in range(max_capacity + 1) ] ### Model problem. # Generate all valid slabs (columns) unsorted_valid_slabs = collect_valid_slabs_dp(capacities, colors, widths, loss_array) # Sort slab by descending load/loss. Remove duplicates. valid_slabs = sorted(unsorted_valid_slabs, key=lambda c: 1000 * c[-1] + c[-2]) all_valid_slabs = range(len(valid_slabs)) # create model and decision variables. model = cp_model.CpModel() selected = [model.NewBoolVar('selected_%i' % i) for i in all_valid_slabs] for order_id in all_orders: model.Add( sum(selected[i] for i, slab in enumerate(valid_slabs) if slab[order_id]) == 1) # Redundant constraint (sum of loads == sum of widths). model.Add( sum(selected[i] * valid_slabs[i][-1] for i in all_valid_slabs) == sum(widths)) # Objective. model.Minimize( sum(selected[i] * valid_slabs[i][-2] for i in all_valid_slabs)) print('Model created') # Output model proto to file. if output_proto: output_file = open(output_proto, 'w') output_file.write(str(model.Proto())) output_file.close() ### Solve model. solver = cp_model.CpSolver() solver.parameters.num_search_workers = 8 solution_printer = cp_model.ObjectiveSolutionPrinter() status = solver.SolveWithSolutionCallback(model, solution_printer) ### Output the solution. if status in (cp_model.OPTIMAL, cp_model.FEASIBLE): print('Loss = %i, time = %.2f s, %i conflicts' % (solver.ObjectiveValue(), solver.WallTime(), solver.NumConflicts())) else: print('No solution')
def cover_rectangle(num_squares): """Try to fill the rectangle with a given number of squares.""" size_x = 72 size_y = 37 model = cp_model.CpModel() areas = [] sizes = [] x_intervals = [] y_intervals = [] x_starts = [] y_starts = [] # Creates intervals for the NoOverlap2D and size variables. for i in range(num_squares): size = model.NewIntVar(1, size_y, 'size_%i' % i) startx = model.NewIntVar(0, size_x, 'sx_%i' % i) endx = model.NewIntVar(0, size_x, 'ex_%i' % i) starty = model.NewIntVar(0, size_y, 'sy_%i' % i) endy = model.NewIntVar(0, size_y, 'ey_%i' % i) interval_x = model.NewIntervalVar(startx, size, endx, 'ix_%i' % i) interval_y = model.NewIntervalVar(starty, size, endy, 'iy_%i' % i) area = model.NewIntVar(1, size_y * size_y, 'area_%i' % i) model.AddProdEquality(area, [size, size]) areas.append(area) x_intervals.append(interval_x) y_intervals.append(interval_y) sizes.append(size) x_starts.append(startx) y_starts.append(starty) # Main constraint. model.AddNoOverlap2D(x_intervals, y_intervals) # Redundant constraints. model.AddCumulative(x_intervals, sizes, size_y) model.AddCumulative(y_intervals, sizes, size_x) # Forces the rectangle to be exactly covered. model.Add(sum(areas) == size_x * size_y) # Symmetry breaking 1: sizes are ordered. for i in range(num_squares - 1): model.Add(sizes[i] <= sizes[i + 1]) # Symmetry breaking 2: first square in one quadrant. model.Add(x_starts[0] < 36) model.Add(y_starts[0] < 19) # Creates a solver and solves. solver = cp_model.CpSolver() status = solver.Solve(model) print('%s found in %0.2fs' % (solver.StatusName(status), solver.WallTime())) # Prints solution. if status == cp_model.FEASIBLE: display = [[' ' for _ in range(size_x)] for _ in range(size_y)] for i in range(num_squares): sol_x = solver.Value(x_starts[i]) sol_y = solver.Value(y_starts[i]) sol_s = solver.Value(sizes[i]) char = format(i, '01x') for j in range(sol_s): for k in range(sol_s): if display[sol_y + j][sol_x + k] != ' ': print('ERROR between %s and %s' % (display[sol_y + j][sol_x + k], char)) display[sol_y + j][sol_x + k] = char for line in range(size_y): print(' '.join(display[line])) return status == cp_model.FEASIBLE
def main(): """Create the shift scheduling model and solve it.""" # Create the model. model = cp_model.CpModel() # # data # num_vendors = 9 num_hours = 10 num_work_types = 1 traffic = [100, 500, 100, 200, 320, 300, 200, 220, 300, 120] max_traffic_per_vendor = 100 # Last columns are : # index_of_the_schedule, sum of worked hours (per work type). # The index is useful for branching. possible_schedules = [[1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 8], [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 4], [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 2, 5], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 4], [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0]] num_possible_schedules = len(possible_schedules) selected_schedules = [] vendors_stat = [] hours_stat = [] # Auxiliary data min_vendors = [t // max_traffic_per_vendor for t in traffic] all_vendors = range(num_vendors) all_hours = range(num_hours) # # declare variables # x = {} for v in all_vendors: tmp = [] for h in all_hours: x[v, h] = model.NewIntVar(0, num_work_types, 'x[%i,%i]' % (v, h)) tmp.append(x[v, h]) selected_schedule = model.NewIntVar(0, num_possible_schedules - 1, 's[%i]' % v) hours = model.NewIntVar(0, num_hours, 'h[%i]' % v) selected_schedules.append(selected_schedule) vendors_stat.append(hours) tmp.append(selected_schedule) tmp.append(hours) model.AddAllowedAssignments(tmp, possible_schedules) # # Statistics and constraints for each hour # for h in all_hours: workers = model.NewIntVar(0, 1000, 'workers[%i]' % h) model.Add(workers == sum(x[v, h] for v in all_vendors)) hours_stat.append(workers) model.Add(workers * max_traffic_per_vendor >= traffic[h]) # # Redundant constraint: sort selected_schedules # for v in range(num_vendors - 1): model.Add(selected_schedules[v] <= selected_schedules[v + 1]) # Solve model. solver = cp_model.CpSolver() solver.parameters.enumerate_all_solutions = True solution_printer = SolutionPrinter(num_vendors, num_hours, possible_schedules, selected_schedules, hours_stat, min_vendors) status = solver.Solve(model, solution_printer) print('Status = %s' % solver.StatusName(status)) print('Statistics') print(' - conflicts : %i' % solver.NumConflicts()) print(' - branches : %i' % solver.NumBranches()) print(' - wall time : %f s' % solver.WallTime()) print( ' - number of solutions found: %i' % solution_printer.solution_count())
def main(): # Data # [START data] costs = [ [90, 76, 75, 70, 50, 74, 12, 68], [35, 85, 55, 65, 48, 101, 70, 83], [125, 95, 90, 105, 59, 120, 36, 73], [45, 110, 95, 115, 104, 83, 37, 71], [60, 105, 80, 75, 59, 62, 93, 88], [45, 65, 110, 95, 47, 31, 81, 34], [38, 51, 107, 41, 69, 99, 115, 48], [47, 85, 57, 71, 92, 77, 109, 36], [39, 63, 97, 49, 118, 56, 92, 61], [47, 101, 71, 60, 88, 109, 52, 90], ] num_workers = len(costs) num_tasks = len(costs[0]) task_sizes = [10, 7, 3, 12, 15, 4, 11, 5] # Maximum total of task sizes for any worker total_size_max = 15 # [END data] # Model # [START model] model = cp_model.CpModel() # [END model] # Variables # [START variables] x = {} for worker in range(num_workers): for task in range(num_tasks): x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]') # [END variables] # Constraints # [START constraints] # Each worker is assigned to at most one task. for worker in range(num_workers): model.Add( sum(task_sizes[task] * x[worker, task] for task in range(num_tasks)) <= total_size_max) # Each task is assigned to exactly one worker. for task in range(num_tasks): model.AddExactlyOne([x[worker, task] for worker in range(num_workers)]) # [END constraints] # Objective # [START objective] objective_terms = [] for worker in range(num_workers): for task in range(num_tasks): objective_terms.append(costs[worker][task] * x[worker, task]) model.Minimize(sum(objective_terms)) # [END objective] # Solve # [START solve] solver = cp_model.CpSolver() status = solver.Solve(model) # [END solve] # Print solution. # [START print_solution] if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE: print(f'Total cost = {solver.ObjectiveValue()}\n') for worker in range(num_workers): for task in range(num_tasks): if solver.BooleanValue(x[worker, task]): print(f'Worker {worker} assigned to task {task}.' + f' Cost = {costs[worker][task]}') else: print('No solution found.')
def poma_scheduler(self): # Database model creation schedule = skynet_models.Schedule.objects.create(celery_id=self.request.id) # We run the dispatcher, to update previous tasks status tareas.octoprint_task_dispatcher() # Data type definition used for scheduling task_data_type = collections.namedtuple( 'task_data', 'piece_id processing_time deadline copy processing_on') tasks_data = [] # Pending pieces for p in skynet_models.Piece.objects.all(): if p.quote_ready() and not p.cancelled: for copy in range(0, p.queued_pieces): tasks_data.append( task_data_type( p.id, int(p.get_build_time()), max(int(p.get_deadline_from_now()), int(p.get_build_time())), copy, None)) # Machines available_machines = [ p for p in skynet_models.Printer.objects.all() if p.printer_connection_enabled ] machines_count = len(available_machines) # Create the model. model = cp_model.CpModel() # Machines queue definition machines_queue = {} machines_corresp_to_db = {} for id, m in enumerate(available_machines): machines_queue[id] = [] machines_corresp_to_db[id] = m.id # Pieces in progress for m in available_machines: if m.connection.active_task is not None: at = m.connection.active_task if not at.finished: tasks_data.append( task_data_type('OT{}'.format(at.id), int(at.time_left), int(at.time_left), 0, [ x for x in machines_corresp_to_db.keys() if machines_corresp_to_db[x] == m.id ][0])) # Horizon definition horizon = max(sum([t.processing_time for t in tasks_data]), 3600 * 24) tasks_count = len(tasks_data) # Forbidden zones definition bounds = get_formatted_forbidden_bounds(horizon) print(tasks_data) # Tasks creation task_type = collections.namedtuple('task', 'id data start end interval machine') task_optional_type = collections.namedtuple( 'task_optional', 'id start end interval machine flag') all_tasks = [] task_queue = {} for id, task in enumerate(tasks_data): start_var = model.NewIntVar(0, horizon, 'start_{id}'.format(id=id)) end_var = model.NewIntVar(0, horizon, 'end_{id}'.format(id=id)) interval = model.NewIntervalVar(start_var, task.processing_time, end_var, 'interval_{id}'.format(id=id)) machine_var = model.NewIntVar(0, machines_count, 'machine_{id}'.format(id=id)) all_tasks.append( task_type(id=id, data=task, start=start_var, end=end_var, interval=interval, machine=machine_var)) # We create a copy of each interval, on each machine, as an OptionalIntervalVar, if we can print it on it task_queue[id] = [] for m in machines_queue.keys(): # Consider possible tasks and present tasks ## Possible tasks if task.processing_on is None: # Printer compatibility check if print_piece_on_printer_check( skynet_models.Piece.objects.get(id=task.piece_id), skynet_models.Printer.objects.get( id=machines_corresp_to_db[m])): start_var_o = model.NewIntVar( 0, horizon, 'start_{id}_on_{machine}'.format(id=id, machine=m)) end_var_o = model.NewIntVar( 0, horizon, 'end_{id}_on_{machine}'.format(id=id, machine=m)) flag = model.NewBoolVar('perform_{id}_on_{machine}'.format( id=id, machine=m)) task_queue[id].append(flag) interval_o = model.NewOptionalIntervalVar( start_var_o, task.processing_time, end_var_o, flag, 'interval_{id}_on_{machine}'.format(id=id, machine=m)) machines_queue[m].append( task_optional_type(id=id, start=start_var_o, end=end_var_o, interval=interval_o, machine=m, flag=flag)) ## We only propagate the constraint if the task is performed on the machine model.Add(start_var == start_var_o).OnlyEnforceIf(flag) model.Add(machine_var == m).OnlyEnforceIf(flag) ## Present tasks else: if m == task.processing_on: start_var_o = model.NewIntVar( 0, horizon, 'start_{id}_on_{machine}'.format(id=id, machine=m)) end_var_o = model.NewIntVar( 0, horizon, 'end_{id}_on_{machine}'.format(id=id, machine=m)) flag = model.NewBoolVar('perform_{id}_on_{machine}'.format( id=id, machine=m)) task_queue[id].append(flag) interval_o = model.NewOptionalIntervalVar( start_var_o, task.processing_time, end_var_o, flag, 'interval_{id}_on_{machine}'.format(id=id, machine=m)) machines_queue[m].append( task_optional_type(id=id, start=start_var_o, end=end_var_o, interval=interval_o, machine=m, flag=flag)) ## We only propagate the constraint if the task is performed on the machine model.Add(start_var == start_var_o) model.Add(machine_var == m) model.Add(start_var_o == 0) model.Add(flag == True) # Constrains ## Task_i is performed somewhere (and only on one machine) for t in task_queue.keys(): model.AddBoolXOr(task_queue[t]) ## Disjunctive constrains for m in range(machines_count): model.AddNoOverlap([t.interval for t in machines_queue[m]]) ## Jobs should be ended by deadline for task_i in all_tasks: model.Add(task_i.end <= task_i.data.deadline) ## Forbidden zones constrains for task in all_tasks: model.AddLinearConstraintWithBounds([(task.start, 1)], bounds) # Makespan objective. obj_var = model.NewIntVar(0, horizon, 'makespan') model.AddMaxEquality(obj_var, [task.end for task in all_tasks]) model.Minimize(obj_var) # Solve model. solver = cp_model.CpSolver() solver.parameters.num_search_workers = os.cpu_count() # Solver solution limit solver.parameters.max_time_in_seconds = 3600 * 2 status = solver.SolveWithSolutionCallback(model, CpModelSolutionCallback(10**5)) print('Model validated: {}'.format(status == cp_model.OPTIMAL)) # We are ready! Finally, we save the results schedule.status = status schedule.finished = timezone.now() schedule.save() if not status == cp_model.OPTIMAL or not status == cp_model.FEASIBLE: if status == cp_model.MODEL_INVALID: print(model.Validate()) print(model.ModelStats()) if status == cp_model.INFEASIBLE: print("Infeasible schedule") print( "Available printers: {machines_count}\nTasks: {tasks_count}\nHorizon: {horizon}" .format(machines_count=machines_count, tasks_count=tasks_count, horizon=horizon)) # TODO : Handlear mejor el caso de que la optimizacion no tenga solucion, alivinanando constrains a cambio de una penalizacion return False for m in range(machines_count): # We sort task by start time order = lambda x: solver.Value(x.start) queue = [task for task in all_tasks if solver.Value(task.machine) == m] queue.sort(key=order) print("Machine {} schedule:".format(m)) for t in queue: print( "Task {id} - copy {copy}: start {start} ends {end} with {deadline} deadline" .format(id=t.data.piece_id, copy=t.data.copy, start=round(float(solver.Value(t.start)) / 3600, 2), end=round(float(solver.Value(t.end)) / 3600, 2), deadline=round(float(t.data.deadline) / 3600, 2))) for task in all_tasks: o = skynet_models.ScheduleEntry.objects.create( schedule=schedule, printer=skynet_models.Printer.objects.get( id=machines_corresp_to_db[solver.Value(task.machine)]), start=relative_to_absolute_date(solver.Value(task.start)), end=relative_to_absolute_date(solver.Value(task.end)), deadline=relative_to_absolute_date(task.data.deadline)) if 'OT' in str(task.data.piece_id): o.task = skynet_models.OctoprintTask.objects.get( id=task.data.piece_id[2:]) else: o.piece = skynet_models.Piece.objects.get(id=task.data.piece_id) o.save() return schedule.id
def solve_flow_shop_with_ortools(filename): data, tasks, machines = readData(filename) model = cp_model.CpModel() max_variable_cmax = sum(task for job in data for task in job) # Named tuple to store information about created variables. task_type = collections.namedtuple('task_type', 'start end interval') assigned_task_type = collections.namedtuple('assigned_task_type', 'start job index') # Creates job intervals and add to the corresponding machine lists. all_tasks = {} machine_to_intervals = collections.defaultdict(list) for job_id, job in enumerate(data): for task_id, task in enumerate(job): duration = task start_var = model.NewIntVar( 0, max_variable_cmax, 'start task: ' + str(job_id) + ' machine: ' + str(task_id)) end_var = model.NewIntVar( 0, max_variable_cmax, 'end task: ' + str(job_id) + ' machine: ' + str(task_id)) interval_var = model.NewIntervalVar( start_var, duration, end_var, 'interval' + str(job_id) + ' machine: ' + str(task_id)) all_tasks[job_id, task_id] = task_type(start=start_var, end=end_var, interval=interval_var) machine_to_intervals[task_id].append(interval_var) for machine in range(0, machines): model.AddNoOverlap(machine_to_intervals[machine]) for job_id, job in enumerate(data): for task_id in range(0, machines - 1): model.Add(all_tasks[job_id, task_id + 1].start >= all_tasks[job_id, task_id].end) c_max = model.NewIntVar(0, max_variable_cmax, 'cmax-makespan') model.AddMaxEquality( c_max, [all_tasks[job_id, machines - 1].end for job_id in range(0, tasks)]) model.Minimize(c_max) # Inicjalizujemy solver, który spróbuje znaleźć rozwiązanie w ramach naszego modelu: solver = cp_model.CpSolver() solver.parameters.max_time_in_seconds = 300.0 # dodatkowo ograniczmy czas wykonywania obliczeń do maksymalnie 5 min # Wszystkie ograniczenia dodane! pora odpalić solver! status = solver.Solve( model ) # solver zwróci status, ale jako typ wyliczeniowy, więc troche nieczytelnie dla nas if ( status is not cp_model.OPTIMAL ): # sprawdzamy status, aby określić czy solver znalazł rozwiązanie optymalne status_readable = "not optimal solution :(" else: status_readable = "optimum found!" pi_order = [] for task_number in range(0, tasks): pi_order.append( (task_number + 1, solver.Value(all_tasks[task_number, 0].start))) pi_order.sort(key=lambda x: x[1]) pi_order = [ x[0] for x in pi_order ] # modyfikujemy naszą listę, aby przechowywać tylko numer zadań, bez czasów rozpocz print('C_Max: %i' % solver.ObjectiveValue()) print("Kolejność: " + str(pi_order)) print(status_readable) return solver.ObjectiveValue(), pi_order, status_readable
def SolveRosteringWithTravel(): model = cp_model.CpModel() # [duration, start, end, location] jobs = [[3, 0, 6, 1], [5, 0, 6, 0], [1, 3, 7, 1], [1, 3, 5, 0], [3, 0, 3, 0], [3, 0, 8, 0]] max_length = 20 num_machines = 3 all_machines = range(num_machines) horizon = 20 travel_time = 1 num_jobs = len(jobs) all_jobs = range(num_jobs) intervals = [] optional_intervals = [] performed = [] starts = [] ends = [] travels = [] for m in all_machines: optional_intervals.append([]) for i in all_jobs: # Create main interval. start = model.NewIntVar(jobs[i][1], horizon, 'start_%i' % i) duration = jobs[i][0] end = model.NewIntVar(0, jobs[i][2], 'end_%i' % i) interval = model.NewIntervalVar(start, duration, end, 'interval_%i' % i) starts.append(start) intervals.append(interval) ends.append(end) job_performed = [] job_travels = [] for m in all_machines: performed_on_m = model.NewBoolVar('perform_%i_on_m%i' % (i, m)) job_performed.append(performed_on_m) # Create an optional copy of interval to be executed on a machine location0 = model.NewOptionalIntVar(jobs[i][3], jobs[i][3], performed_on_m, 'location_%i_on_m%i' % (i, m)) start0 = model.NewOptionalIntVar(jobs[i][1], horizon, performed_on_m, 'start_%i_on_m%i' % (i, m)) end0 = model.NewOptionalIntVar(0, jobs[i][2], performed_on_m, 'end_%i_on_m%i' % (i, m)) interval0 = model.NewOptionalIntervalVar( start0, duration, end0, performed_on_m, 'interval_%i_on_m%i' % (i, m)) optional_intervals[m].append(interval0) # We only propagate the constraint if the tasks is performed on the machine. model.Add(start0 == start).OnlyEnforceIf(performed_on_m) # Adding travel constraint travel = model.NewBoolVar('is_travel_%i_on_m%i' % (i, m)) startT = model.NewOptionalIntVar(0, horizon, travel, 'start_%i_on_m%i' % (i, m)) endT = model.NewOptionalIntVar(0, horizon, travel, 'end_%i_on_m%i' % (i, m)) intervalT = model.NewOptionalIntervalVar( startT, travel_time, endT, travel, 'travel_interval_%i_on_m%i' % (i, m)) optional_intervals[m].append(intervalT) job_travels.append(travel) model.Add(end0 == startT).OnlyEnforceIf(travel) performed.append(job_performed) travels.append(job_travels) model.Add(sum(job_performed) == 1) for m in all_machines: if m == 1: for i in all_jobs: if i == 2: for c in all_jobs: if (i != c) and (jobs[i][3] != jobs[c][3]): is_job_earlier = model.NewBoolVar( 'is_j%i_earlier_j%i' % (i, c)) model.Add(starts[i] < starts[c]).OnlyEnforceIf( is_job_earlier) model.Add(starts[i] >= starts[c]).OnlyEnforceIf( is_job_earlier.Not()) # Max Length constraint (modeled as a cumulative) # model.AddCumulative(intervals, demands, max_length) # Choose which machine to perform the jobs on. for m in all_machines: model.AddNoOverlap(optional_intervals[m]) # Objective variable. total_cost = model.NewIntVar(0, 1000, 'cost') model.Add(total_cost == sum(performed[j][m] * (10 * (m + 1)) for j in all_jobs for m in all_machines)) model.Minimize(total_cost) # Solve model. solver = cp_model.CpSolver() result = solver.Solve(model) print() print(result) print('Statistics') print(' - conflicts : %i' % solver.NumConflicts()) print(' - branches : %i' % solver.NumBranches()) print(' - wall time : %f ms' % solver.WallTime())
def main(): # Data. num_nurses = 4 num_shifts = 4 # Nurse assigned to shift 0 means not working that day. num_days = 7 all_nurses = range(num_nurses) all_shifts = range(num_shifts) all_working_shifts = range(1, num_shifts) all_days = range(num_days) # Creates the model. model = cp_model.CpModel() # Creates shift variables. # shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'. shifts = {} for n in all_nurses: for d in all_days: for s in all_shifts: shifts[(n, d, s)] = model.NewBoolVar('shift_n%id%is%i' % (n, d, s)) # Makes assignments different on each day, that is each shift is assigned at # most one nurse. As we have the same number of nurses and shifts, then each # day, each shift is assigned to exactly one nurse. for d in all_days: for s in all_shifts: model.Add(sum(shifts[(n, d, s)] for n in all_nurses) == 1) # Nurses do 1 shift per day. for n in all_nurses: for d in all_days: model.Add(sum(shifts[(n, d, s)] for s in all_shifts) == 1) # Each nurse works 5 or 6 days in a week. # That is each nurse works shift 0 at most 2 times. for n in all_nurses: model.AddSumConstraint([shifts[(n, d, 0)] for d in all_days], 1, 2) # works_shift[(n, s)] is 1 if nurse n works shift s at least one day in # the week. works_shift = {} for n in all_nurses: for s in all_shifts: works_shift[(n, s)] = model.NewBoolVar('works_shift_n%is%i' % (n, s)) model.AddMaxEquality(works_shift[(n, s)], [shifts[(n, d, s)] for d in all_days]) # For each shift, at most 2 nurses are assigned to that shift during the week. for s in all_working_shifts: model.Add(sum(works_shift[(n, s)] for n in all_nurses) <= 2) # If a nurse works shifts 2 or 3 on, she must also work that shift the # previous day or the following day. # This means that on a given day and shift, either she does not work that # shift on that day, or she works that shift on the day before, or the day # after. for n in all_nurses: for s in [2, 3]: for d in all_days: yesterday = (d - 1) % num_days tomorrow = (d + 1) % num_days model.AddBoolOr([shifts[(n, yesterday, s)], shifts[(n, d, s)].Not(), shifts[(n, tomorrow, s)]]) # Creates the solver and solve. solver = cp_model.CpSolver() # Display a few solutions picked at random. a_few_solutions = [859, 2034, 5091, 7003] solution_printer = NursesPartialSolutionPrinter(shifts, num_nurses, num_days, num_shifts, a_few_solutions) status = solver.SearchForAllSolutions(model, solution_printer) # Statistics. print() print('Statistics') print(' - conflicts : %i' % solver.NumConflicts()) print(' - branches : %i' % solver.NumBranches()) print(' - wall time : %f ms' % solver.WallTime()) print(' - solutions found : %i' % solution_printer.SolutionCount())
def main(): # Data # [START data_model] costs = [ [90, 80, 75, 70], [35, 85, 55, 65], [125, 95, 90, 95], [45, 110, 95, 115], [50, 100, 90, 100], ] num_workers = len(costs) num_tasks = len(costs[0]) # [END data_model] # Model # [START model] model = cp_model.CpModel() # [END model] # Variables # [START variables] x = [] for i in range(num_workers): t = [] for j in range(num_tasks): t.append(model.NewBoolVar(f'x[{i},{j}]')) x.append(t) # [END variables] # Constraints # [START constraints] # Each worker is assigned to at most one task. for i in range(num_workers): model.Add(sum(x[i][j] for j in range(num_tasks)) <= 1) # Each task is assigned to exactly one worker. for j in range(num_tasks): model.Add(sum(x[i][j] for i in range(num_workers)) == 1) # [END constraints] # Objective # [START objective] objective_terms = [] for i in range(num_workers): for j in range(num_tasks): objective_terms.append(costs[i][j] * x[i][j]) model.Minimize(sum(objective_terms)) # [END objective] # Solve # [START solve] solver = cp_model.CpSolver() status = solver.Solve(model) # [END solve] # Print solution. # [START print_solution] if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE: print(f'Total cost = {solver.ObjectiveValue()}') print() for i in range(num_workers): for j in range(num_tasks): if solver.BooleanValue(x[i][j]): print( f'Worker {i} assigned to task {j} Cost = {costs[i][j]}') else: print('No solution found.')
def main(): """Minimal jobshop problem.""" # Data. # [START data] jobs_data = [ # task = (machine_id, processing_time). [(0, 3), (1, 2), (2, 2)], # Job0 [(0, 2), (2, 1), (1, 4)], # Job1 [(1, 4), (2, 3)] # Job2 ] machines_count = 1 + max(task[0] for job in jobs_data for task in job) all_machines = range(machines_count) # Computes horizon dynamically as the sum of all durations. horizon = sum(task[1] for job in jobs_data for task in job) # [END data] # Create the model. # [START model] model = cp_model.CpModel() # [END model] # [START variables] # Named tuple to store information about created variables. task_type = collections.namedtuple('task_type', 'start end interval') # Named tuple to manipulate solution information. assigned_task_type = collections.namedtuple('assigned_task_type', 'start job index duration') # Creates job intervals and add to the corresponding machine lists. all_tasks = {} machine_to_intervals = collections.defaultdict(list) for job_id, job in enumerate(jobs_data): for task_id, task in enumerate(job): machine = task[0] duration = task[1] suffix = '_%i_%i' % (job_id, task_id) start_var = model.NewIntVar(0, horizon, 'start' + suffix) end_var = model.NewIntVar(0, horizon, 'end' + suffix) interval_var = model.NewIntervalVar(start_var, duration, end_var, 'interval' + suffix) all_tasks[job_id, task_id] = task_type(start=start_var, end=end_var, interval=interval_var) machine_to_intervals[machine].append(interval_var) # [END variables] # [START constraints] # Create and add disjunctive constraints. for machine in all_machines: model.AddNoOverlap(machine_to_intervals[machine]) # Precedences inside a job. for job_id, job in enumerate(jobs_data): for task_id in range(len(job) - 1): model.Add(all_tasks[job_id, task_id + 1].start >= all_tasks[job_id, task_id].end) # [END constraints] # [START objective] # Makespan objective. obj_var = model.NewIntVar(0, horizon, 'makespan') model.AddMaxEquality(obj_var, [ all_tasks[job_id, len(job) - 1].end for job_id, job in enumerate(jobs_data) ]) model.Minimize(obj_var) # [END objective] # Creates the solver and solve. # [START solve] solver = cp_model.CpSolver() status = solver.Solve(model) # [END solve] # [START print_solution] if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE: print('Solution:') # Create one list of assigned tasks per machine. assigned_jobs = collections.defaultdict(list) for job_id, job in enumerate(jobs_data): for task_id, task in enumerate(job): machine = task[0] assigned_jobs[machine].append( assigned_task_type(start=solver.Value( all_tasks[job_id, task_id].start), job=job_id, index=task_id, duration=task[1])) # Create per machine output lines. output = '' for machine in all_machines: # Sort by starting time. assigned_jobs[machine].sort() sol_line_tasks = 'Machine ' + str(machine) + ': ' sol_line = ' ' for assigned_task in assigned_jobs[machine]: name = 'job_%i_task_%i' % (assigned_task.job, assigned_task.index) # Add spaces to output to align columns. sol_line_tasks += '%-15s' % name start = assigned_task.start duration = assigned_task.duration sol_tmp = '[%i,%i]' % (start, start + duration) # Add spaces to output to align columns. sol_line += '%-15s' % sol_tmp sol_line += '\n' sol_line_tasks += '\n' output += sol_line_tasks output += sol_line # Finally print the solution found. print(f'Optimal Schedule Length: {solver.ObjectiveValue()}') print(output) else: print('No solution found.') # [END print_solution] # Statistics. # [START statistics] print('\nStatistics') print(' - conflicts: %i' % solver.NumConflicts()) print(' - branches : %i' % solver.NumBranches()) print(' - wall time: %f s' % solver.WallTime())
def _optimize_rule_ortools(set_opt_model_func, profile, committeesize, resolute): """Compute ABC rules, which are given in the form of an integer optimization problem, using the OR-Tools CP-SAT Solver. Parameters ---------- set_opt_model_func : callable sets constraints and objective and adds additional variables, see examples below for its signature profile : abcvoting.preferences.Profile approval sets of voters committeesize : int number of chosen alternatives resolute : bool Returns ------- committees : list of sets a list of winning committees, each of them represented as set of integers """ maxscore = None committees = [] # TODO add a max iterations parameter with fancy default value which works in almost all # cases to avoid endless hanging computations, e.g. when CI runs the tests while True: model = cp_model.CpModel() # `in_committee` is a binary variable indicating whether `cand` is in the committee in_committee = [ model.NewBoolVar(f"cand{cand}_in_committee") for cand in profile.candidates ] set_opt_model_func( model, profile, in_committee, committeesize, committees, ) solver = cp_model.CpSolver() status = solver.Solve(model) if status not in [cp_model.OPTIMAL, cp_model.INFEASIBLE]: raise RuntimeError( f"OR-Tools returned an unexpected status code: {status}" "Warning: solutions may be incomplete or not optimal.") elif status == cp_model.INFEASIBLE: if len(committees) == 0: # we are in the first round of searching for committees # and Gurobi didn't find any raise RuntimeError("OR-Tools found no solution (INFEASIBLE)") break objective_value = solver.ObjectiveValue() if maxscore is None: maxscore = objective_value elif objective_value > maxscore: raise RuntimeError( "OR-Tools found a solution better than a previous optimum. This " f"should not happen (previous optimal score: {maxscore}, " f"new optimal score: {objective_value}).") elif objective_value < maxscore: # no longer optimal break committee = set(cand for cand in profile.candidates if solver.Value(in_committee[cand]) >= 1) if len(committee) != committeesize: raise RuntimeError( "_optimize_rule_ortools produced a committee with " "fewer than `committeesize` members.") committees.append(committee) if resolute: break return committees
from ortools.sat.python import cp_model if __name__ == '__main__': model = cp_model.CpModel() solver = cp_model.CpSolver() # # decision variables # S = model.NewIntVar(0, 9, 'S') E = model.NewIntVar(0, 9, 'E') N = model.NewIntVar(0, 9, 'N') D = model.NewIntVar(0, 9, 'D') M = model.NewIntVar(0, 9, 'M') O = model.NewIntVar(0, 9, 'O') R = model.NewIntVar(0, 9, 'R') Y = model.NewIntVar(0, 9, 'Y') # # constraints # send = ((S * 10 + E) * 10 + N) * 10 + D more = ((M * 10 + O) * 10 + R) * 10 + E money = (((M * 10 + O) * 10 + N) * 10 + E) * 10 + Y model.Add(send + more == money) model.Add(S != 0) model.Add(M != 0) total = [S, E, N, D, M, O, R, Y] for i in range(len(total)): for j in range(i):
def createGrille(niveau): #Creates the model model= cp_model.CpModel() numVals=9 nbrCases=0; if niveau=="très difficile": nbrCases=17 if niveau=="difficile": nbrCases=26 if niveau=="moyen": nbrCases=33 if niveau=="facile": nbrCases=40 if niveau=="débutant": nbrCases=50 G= [[0] * 9 for i in range(9)] A= [[0] * 9 for i in range(9)] compteur=0 #on cherche aléatoirement la position des n chiffres que l'on souhaite placés #leur position est modélisé par un 1 while compteur<nbrCases : ligne=randint(0,8) colonne=randint(0,8) if G[ligne][colonne]==0: G[ligne][colonne]=1 compteur+=1 cellSize=3 cell=range(cellSize) for ligne in range(9): for colonne in range(9): A[ligne][colonne]=model.NewIntVar(0,numVals,'A[%i][%a]' %(ligne,colonne)) #contraintes #les éléments mis sur une ligne de peuvent pas être identiques for ligne in range(9): diff=[] for colonne in range(9): if G[ligne][colonne]==1: diff.append(A[ligne][colonne]) else: model.Add(A[ligne][colonne]==0) #on ne veut pas appliquer les contraintes aux 0 qui représentent des cases vides model.AddAllDifferent(diff) #aucune même valeur sur une colonne for colonne in range(9): diff=[] for ligne in range(9): if G[ligne][colonne]==1: diff.append(A[ligne][colonne]) model.AddAllDifferent(diff) #aucune même valeur dans les sous-carrées de 3*3 for i in cell: for j in cell: oneCell=[] for di in cell: for dj in cell: if G[i*cellSize+di][j*cellSize+dj]==1: oneCell.append(A[i*cellSize+di][j*cellSize+dj]) model.AddAllDifferent(oneCell) #solveur solver = cp_model.CpSolver() status = solver.Solve(model) if status == cp_model.FEASIBLE: R=[] for ligne in range(9): R.append([solver.Value(A[ligne][j]) for j in range(9)]) print([solver.Value(A[ligne][j]) for j in range(9)]) return R