def minimum_resources(task: ElasticTask, allocation_priority: NonElasticResourcePriority) -> Tuple[int, int, int]: """ Find the optimal non_elastic speeds of the task :param task: The task to use :param allocation_priority: The non-elastic value function to value the speeds :return: non_elastic speeds """ model = CpoModel('non_elasticSpeedsPrioritisation') loading_speed = model.integer_var(min=1, name='loading speed') compute_speed = model.integer_var(min=1, name='compute speed') sending_speed = model.integer_var(min=1, name='sending speed') model.add(task.required_storage / loading_speed + task.required_computation / compute_speed + task.required_results_data / sending_speed <= task.deadline) model.minimize(allocation_priority.evaluate(loading_speed, compute_speed, sending_speed)) model_solution = model.solve(log_output=None) assert model_solution.get_solve_status() == SOLVE_STATUS_FEASIBLE or \ model_solution.get_solve_status() == SOLVE_STATUS_OPTIMAL, \ (model_solution.get_solve_status(), task.__str__()) assert 0 < model_solution.get_value(loading_speed) and \ 0 < model_solution.get_value(compute_speed) and \ 0 < model_solution.get_value(sending_speed), \ (model_solution.get(loading_speed), model_solution.get(compute_speed), model_solution.get(sending_speed)) return model_solution.get_value(loading_speed), \ model_solution.get_value(compute_speed), \ model_solution.get_value(sending_speed)
def allocate(self, task: ElasticTask, server: Server) -> Tuple[int, int, int]: """ Determines the resource speed for the task on the server but finding the smallest :param task: The task :param server: The server :return: A tuple of resource speeds """ """ Initial version that attempts brute force however too computationally expensive when the discretisation of the server resources is too high return min(((s, w, r) for s in range(1, server.available_bandwidth + 1) for w in range(1, server.available_computation + 1) for r in range(1, server.available_bandwidth - s + 1) if task.required_storage * w * r + s * task.required_computation * r + s * w * task.required_results_data <= task.deadline * s * w * r), key=lambda bid: self.resource_evaluator(task, server, bid[0], bid[1], bid[2]))""" # TODO possible to use KKT model = CpoModel('resource allocation') loading = model.integer_var(min=1, max=server.available_bandwidth - 1) compute = model.integer_var(min=1, max=server.available_computation) sending = model.integer_var(min=1, max=server.available_bandwidth - 1) model.add( task.required_storage * compute * sending + loading * task.required_computation * sending + loading * compute * task.required_results_data <= task.deadline * loading * compute * sending) model.add(loading + sending <= server.available_bandwidth) model.minimize( self.resource_evaluator(task, server, loading, compute, sending)) model_solution = model.solve(log_output=None) if model_solution.get_solve_status() != SOLVE_STATUS_FEASIBLE and \ model_solution.get_solve_status() != SOLVE_STATUS_OPTIMAL: print( f'Resource allocation fail - status: {model_solution.get_solve_status()} ' f'for {str(task)} and {str(server)}') raise Exception( f'Resource allocation for a task is infeasible, ' f'model solution is {model_solution.get_solve_status()}. ' f'The task setting is {task.save()} and ' f'the server setting has available bandwidth of {server.available_bandwidth} and ' f'available computation of {server.available_computation} ' f'(storage: {server.available_storage})') return model_solution.get_value(loading), model_solution.get_value( compute), model_solution.get_value(sending)
def BRAttackerP(gameModel): source = gameModel.source_list[0] edges = list(gameModel.G.edges()) nodes = list(gameModel.G.nodes()) defender_coverage = gameModel.defender_strategy_set defender_prob = gameModel.defender_prob assert(len(defender_coverage) == len(defender_prob)) resource_list = gameModel.resource_list edge2index = gameModel.edge2index solution_list = [] # =================== attacker CP ================== for j in range(len(gameModel.terminal_list)): # ---------------- tarminal j ------------------ target = gameModel.terminal_list[j] cpo = CpoModel() # cpo.add_parameters(LogVerbosity="Quiet") edge_variables = cpo.binary_var_list(gameModel.m, "gamma") cpo.add(sum([edge_variables[edge2index[source_out]] for source_out in gameModel.G.out_edges(source)]) - sum([edge_variables[edge2index[source_in]] for source_in in gameModel.G.in_edges(source)]) == 1) cpo.add(sum([edge_variables[edge2index[target_out]] for target_out in gameModel.G.out_edges(target)]) - sum([edge_variables[edge2index[target_in]] for target_in in gameModel.G.in_edges(target)]) == -1) for node in nodes: if node == source or node == target: continue else: cpo.add(sum([edge_variables[edge2index[in_edge]] for in_edge in gameModel.G.in_edges(node)]) == sum([edge_variables[edge2index[out_edge]] for out_edge in gameModel.G.out_edges(node)])) # incoming flow == outgoing flow # -------------- computing the objective value ------------- objective_value = 0 for i in range(len(defender_coverage)): success_prob = 1 for r in range(gameModel.R): covering_prob = gameModel.resource_list[r].prob # covering prob # print defender_coverage[i].resource_usage for e_i in range(len(defender_coverage[i].resource_usage[r])): e = defender_coverage[i].resource_usage[r][e_i] success_prob *= (1 - edge_variables[edge2index[e]] * covering_prob) objective_value += success_prob * defender_prob[i] * gameModel.terminal_payoff[j] cpo.add(cpo.maximize(objective_value)) cpo_solution = cpo.solve() if cpo_solution: edge_usage = [edges[i] for i in range(gameModel.m) if cpo_solution[edge_variables[i]] == 1] obj = cpo_solution.get_objective_values() solution_list.append((obj, edge_usage, target, cpo)) else: print("no solution") best_solution = max(solution_list, key=lambda x: x[0]) best_target = best_solution[2] best_cpo = best_solution[3] best_cpo.export_model("attacker.cpo") new_obj = best_solution[0] new_G = nx.DiGraph(best_solution[1]) print("edges:", new_G.edges) new_path = nx.shortest_path(new_G, source, best_target) return new_obj, new_path
def elastic_feasible_allocation( task_server_allocations: Dict[Server, List[ElasticTask]], time_limit: int = 60 ) -> Optional[Dict[ElasticTask, Tuple[int, int, int]]]: """ Checks whether a task to server allocation is a feasible solution to the problem :param task_server_allocations: The current task allocation :param time_limit: The time limit to solve the problem within :return: An optional dictionary of the task to the tuple of resource speeds """ model = CpoModel("Allocation Feasibility") loading_speeds: Dict[ElasticTask, CpoVariable] = {} compute_speeds: Dict[ElasticTask, CpoVariable] = {} sending_speeds: Dict[ElasticTask, CpoVariable] = {} for server, tasks in task_server_allocations.items(): for task in tasks: loading_speeds[task] = model.integer_var( min=1, max=server.bandwidth_capacity, name=f'Task {task.name} loading speed') compute_speeds[task] = model.integer_var( min=1, max=server.computation_capacity, name=f'Task {task.name} compute speed') sending_speeds[task] = model.integer_var( min=1, max=server.bandwidth_capacity, name=f'Task {task.name} sending speed') model.add((task.required_storage / loading_speeds[task]) + (task.required_computation / compute_speeds[task]) + (task.required_results_data / sending_speeds[task]) <= task.deadline) model.add( sum(task.required_storage for task in tasks) <= server.storage_capacity) model.add( sum(compute_speeds[task] for task in tasks) <= server.computation_capacity) model.add( sum((loading_speeds[task] + sending_speeds[task]) for task in tasks) <= server.bandwidth_capacity) model_solution = model.solve(log_output=None, TimeLimit=time_limit) if model_solution.get_solve_status() == SOLVE_STATUS_FEASIBLE: return { task: (model_solution.get_value(loading_speeds[task]), model_solution.get_value(compute_speeds[task]), model_solution.get_value(sending_speeds[task])) for tasks in task_server_allocations.values() for task in tasks } else: return None
def convert_fixed_task(tasks: List[Task]): """ Converts tasks to fixed tasks Args: tasks: List of tasks Returns: List of fixed tasks """ fixed_tasks = [] for task in tasks: model = CpoModel('FixedTask') loading_speed = model.integer_var(min=1, name='loading speed') compute_speed = model.integer_var(min=1, name='compute speed') sending_speed = model.integer_var(min=1, name='sending speed') model.add((task.required_storage / loading_speed) + (task.required_computation / compute_speed) + (task.required_results_data / sending_speed) <= ( task.deadline - task.auction_time)) model.minimize(1.2**loading_speed + 1.2**compute_speed + 1.2**sending_speed) model_solution = model.solve(log_output=None, TimeLimit=3) if model_solution.get_solve_status( ) != SOLVE_STATUS_FEASIBLE or model_solution.get_solve_status( ) != SOLVE_STATUS_OPTIMAL: fixed_tasks.append( FixedTask(name=task.name, auction_time=task.auction_time, deadline=task.deadline, required_storage=task.required_storage, required_computation=task.required_computation, required_results_data=task.required_results_data, fixed_loading_speed=model_solution.get_value( loading_speed), fixed_compute_speed=model_solution.get_value( compute_speed), fixed_sending_speed=model_solution.get_value( sending_speed))) else: print(f'Error: {model_solution.get_solve_status()}') return fixed_tasks
def cplex_makespan_model(n: int, m: int, durations, machines) -> CpoModel: # n number of jobs, m machines # 1 line for un job with tasks on m machines naive = np.sum(durations) mdl = CpoModel() #Une variable est l'intervalle de durée pour une tache x = [[ mdl.interval_var(size=durations[i, j], name="O{}-{}".format(i, j)) for j in range(m) ] for i in range(n)] #contrainte end max d'une tache calculée avant for i in range(n): for j in range(m): mdl.add(mdl.end_of(x[i][j]) <= naive) #precedence for i in range(n): #for each job for j in range(m - 1): #taches ordonnées mdl.add(mdl.end_before_start(x[i][j], x[i][j + 1])) # une machine ne peut faire qu'une tache à la fois listtaches = [[] for k in range(m)] for i in range(n): for j in range(m): listtaches[machines[i, j]].append(x[i][j]) for k in range(m): mdl.add(mdl.no_overlap(listtaches[k])) makespan = mdl.integer_var(0, naive, name="makespan") # le makespan est le max des tps pour chaque job mdl.add(makespan == mdl.max([mdl.end_of(x[i][m - 1]) for i in range(n)])) mdl.add(mdl.minimize(makespan)) return mdl, x
def ALBP(TaskTime, nbStations, PrecedenceTasks): """ Prepare the data for modeling """ # tasks set TASKS = range(len(TaskTime)) # workstations set WORKSTATIONS = range(nbStations) """ Build the model """ # Create CPO model myModel = CpoModel() # Assign tasks to workstation WhichWorkstation = myModel.integer_var_list(len(TaskTime), 0, nbStations - 1) # Cycle time CycleTime = myModel.integer_var(max(TaskTime), sum(TaskTime)) # Add station load constraints for k in WORKSTATIONS: myModel.add(sum(TaskTime[i] * (WhichWorkstation[i] == k) for i in TASKS) <= CycleTime) # Add precedence constraints for i in TASKS: for j in PrecedenceTasks[i]: myModel.add(WhichWorkstation[j] <= WhichWorkstation[i]) # Create model objective myModel.add(myModel.minimize(CycleTime)) """ Solve model """ solution = myModel.solve(FailLimit=100000, TimeLimit=10) """ Print solution """ return solution
def solve(self): mdl = CpoModel() power = [2**i for i in range(0, self.U + 1)] M = mdl.integer_var_list(self.n + 1, 0, self.U, "M") T = mdl.integer_var_list(self.n + 1, 0, power[self.U], "T") mdl.add(mdl.element(power, M[i]) == T[i] for i in range(0, self.n + 1)) mdl.add(T[i] >= T[0] for i in range(0, self.n + 1)) mdl.minimize( mdl.sum(self.H[i] * T[i] / self.beta + self.K[i] / (T[i] / self.beta) for i in range(0, self.n + 1))) # Solve model print("Solving model....") msol = mdl.solve( TimeLimit=10, agent='local', execfile= '/Applications/CPLEX_Studio1210/cpoptimizer/bin/x86-64_osx/cpoptimizer' ) # Print solution if msol: stdout.write("Total cost : " + str(msol.get_objective_values()[0]) + "\n") stdout.write("T: [") for t in T: stdout.write(" {}".format(msol[t])) stdout.write("]\n") stdout.write("M: [") for m in M: stdout.write(" {}".format(msol[m])) stdout.write("]\n") return msol.get_objective_values()[0] else: stdout.write("Solve status: {}\n".format(msol.get_solve_status())) return None
def solve(self, factors, observed, config, all_bits): rvs = list(sorted(factors.keys())) # https://cdn.rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/cp/creating_model.html model = CpoModel() # model.context.cplex_parameters.threads = cpu_count() rv2var = {rv: model.binary_var(str(rv)) for rv in rvs} for rv, val in observed.items(): model.add(rv2var[rv] == bool(val)) for rv, factor in factors.items(): ftype = factor.factor_type if ftype == 'INV': inp = factor.input_rvs[0] model.add(rv2var[inp] == 1 - rv2var[rv]) elif ftype == 'SAME': inp = factor.input_rvs[0] model.add(rv2var[inp] == rv2var[rv]) elif ftype == 'AND': inp1, inp2 = factor.input_rvs[:2] # Linearization of out = inp1 * inp2 for binary variables model.add(rv2var[rv] <= rv2var[inp1]) model.add(rv2var[rv] <= rv2var[inp2]) model.add(rv2var[rv] >= rv2var[inp1] + rv2var[inp2] - 1) # https://cdn.rawgit.com/IBMDecisionOptimization/docplex-doc/master/docs/cp/docplex.cp.parameters.py.html#docplex.cp.parameters.CpoParameters params = CpoParameters(Workers=cpu_count()) model.print_information() sol = model.solve( agent='local', params=params, execfile= '/Applications/CPLEX_Studio1210/cpoptimizer/bin/x86-64_osx/cpoptimizer' ) solution = {rv: sol.get_value(rv2var[rv]) for rv in rvs} return solution
def solveSchedulingSubproblem(numJobs, totalTime, availResources, jobLength): ''' Input data numJobs: Number of jobs (int) totalTime: Total time blocks (int) availResources: Total amount of resource available for this machine. Assume each job uses one resource. (int) jobLength: The length (in time blocks) of each job (list, by job number) ''' # Create a CPO model model = CpoModel() # Create variables TIME = model.integer_var_list(numJobs, 0, totalTime - 1, "TIME") # For each job, indicate start time RESOURCE = model.integer_var_list( numJobs, 0, availResources - 1, "RESOURCE") # For each job, indicate resource used # Add general constraints for i in range(numJobs): # Jobs must end before the end of the totalTime available model.add(TIME[i] + jobLength[i] <= totalTime) # Jobs can't be scheduled on a machine at the same time for j in range(numJobs): if i != j: model.add((RESOURCE[i] != RESOURCE[j]) | (TIME[i] + jobLength[i] <= TIME[j]) | (TIME[j] + jobLength[j] <= TIME[i])) # If there's only one job, then above constraints will never reference RESOURCE variable. # In that case, RESOURCE won't show up in the problem, and won't get a value. # To prevent this, we add dummy constraints on RESOURCE as follows: if numJobs == 1: model.add(RESOURCE[0] >= 0) # Solve model print("Solving model....") msol = model.solve(TimeLimit=10) if msol: # If the model ran successfully, it returns True print("Solution:") for j in range(numJobs): print("Job " + str(j) + " starts at time " + str(msol[TIME[j]]) + " and uses resource " + str(msol[RESOURCE[j]])) print("Last job time ends at " + str(max(msol[TIME[j]] + jobLength[j] for j in range(numJobs)))) return True else: # Problem is infeasible; print the infeasibility # theConflictsResult = model.refine_conflict() # print(theConflictsResult) return False
def solve(storage_budget: List[float], query_size: List[float], query_latency: List[List[float]]): """ Solve result placement with ILP. :param storage_budget: (1 x n_storage) array of storage budgets. :param query_size: (1 x n_query) array of sizes of query. :param query_latency: (n_query x n_storage) array of latencies for each query when placed on each storage. """ n_storage = len(storage_budget) n_query = len(query_size) # Init variables mdl = CpoModel() X = [[ mdl.integer_var(min=0, max=1, name="C" + str(i) + str(j)) for j in range(n_storage) ] for i in range(n_query)] # Objective: minimize delay obj = mdl.sum([ X[i][j] * query_latency[i][j] for j in range(n_storage) for i in range(n_query) ]) mdl.add(mdl.minimize(obj)) # Constraint 1: cannot exceed mem size for j in range(n_storage): mdl.add( mdl.sum([X[i][j] * query_size[i] for i in range(n_query)]) <= storage_budget[j]) # Constraint 2: each query at least placed somewhere for i in range(n_query): mdl.add(mdl.sum([X[i][j] for j in range(n_storage)]) == 1) print('Solving model....') msol = mdl.solve(TimeLimit=10) if msol: sol = [[msol[X[i][j]] for j in range(n_storage)] for i in range(n_query)] print('Solution found:') print_grid(sol) else: print('No solution found')
def recherche_exact(instance, temps): ''' :param temps: int, temps de recherche :param instance: nom de l'instance str :return: None ''' problem_data, optimum = loader(instance) nb_machine = problem_data["nb_machine"] nb_jobs = problem_data["nb_jobs"] problem = problem_data["problem"] machine, durations = separate(problem) model = CpoModel(name='Scheduling') # Variable job_operations = [[model.interval_var(size=durations[j][m], name="O{}-{}".format(j, m)) for m in range(nb_machine)] for j in range(nb_jobs)] # chaque opération doit commencer aprés la fin de la précedente for j in range(nb_jobs): for s in range(1, nb_machine): model.add(model.end_before_start(job_operations[j][s - 1], job_operations[j][s])) # Pas d'overlap pour les operations executées sur une même machine machine_operations = [[] for m in range(nb_machine)] for j in range(nb_jobs): for s in range(0, nb_machine): machine_operations[machine[j][s]].append(job_operations[j][s]) for lops in machine_operations: model.add(model.no_overlap(lops)) # Minimiser la date de fin model.add(model.minimize(model.max([model.end_of(job_operations[i][nb_machine - 1]) for i in range(nb_jobs)]))) # Solve model print("Solving model....") msol = model.solve(TimeLimit=temps)
# Create model mdl = CpoModel() masonry = mdl.interval_var(name='masonry', size=35) carpentry = mdl.interval_var(name='carpentry', size=15) plumbing = mdl.interval_var(name='plumbing', size=40) ceiling = mdl.interval_var(name='ceiling', size=15) roofing = mdl.interval_var(name='roofing', size=5) painting = mdl.interval_var(name='painting', size=10) windows = mdl.interval_var(name='windows', size=5) facade = mdl.interval_var(name='facade', size=10) garden = mdl.interval_var(name='garden', size=5) moving = mdl.interval_var(name='moving', size=5) # Add precedence constraints mdl.add(mdl.end_before_start(masonry, carpentry)) mdl.add(mdl.end_before_start(masonry, plumbing)) mdl.add(mdl.end_before_start(masonry, ceiling)) mdl.add(mdl.end_before_start(carpentry, roofing)) mdl.add(mdl.end_before_start(ceiling, painting)) mdl.add(mdl.end_before_start(roofing, windows)) mdl.add(mdl.end_before_start(roofing, facade)) mdl.add(mdl.end_before_start(plumbing, facade)) mdl.add(mdl.end_before_start(roofing, garden)) mdl.add(mdl.end_before_start(plumbing, garden)) mdl.add(mdl.end_before_start(windows, moving)) mdl.add(mdl.end_before_start(facade, moving)) mdl.add(mdl.end_before_start(garden, moving)) mdl.add(mdl.end_before_start(painting, moving)) #-----------------------------------------------------------------------------
return res # Create model mdl = CpoModel() # Create one binary variable for each colored cell color = [[ mdl.integer_var(min=0, max=1, name="C" + str(l) + "_" + str(c)) for c in range(SIZE) ] for l in range(SIZE)] # Forbid adjacent colored cells for l in range(SIZE): for c in range(SIZE - 1): mdl.add((color[l][c] + color[l][c + 1]) < 2) for c in range(SIZE): for l in range(SIZE - 1): mdl.add((color[l][c] + color[l + 1][c]) < 2) # Color cells for digits occurring more than once for l in range(SIZE): lvals = [] # List of values already processed for c in range(SIZE): v = PUZZLE[l][c] if v not in lvals: lvals.append(v) lvars = [color[l][c]] for c2 in range(c + 1, SIZE): if PUZZLE[l][c2] == v: lvars.append(color[l][c2])
# Create variables identifying which location serves each customer cust = mdl.integer_var_list(nbCustomer, 0, nbLocation - 1, "CustomerLocation") # Create variables indicating which plant location is open open = mdl.integer_var_list(nbLocation, 0, 1, "OpenLocation") # Create variables indicating load of each plant load = [ mdl.integer_var(0, capacity[p], "PlantLoad_" + str(p)) for p in range(nbLocation) ] # Associate plant openness to its load for p in range(nbLocation): mdl.add(open[p] == (load[p] > 0)) # Add constraints mdl.add(mdl.pack(load, cust, demand)) # Add objective obj = mdl.scal_prod(fixedCost, open) for c in range(nbCustomer): obj += mdl.element(cust[c], cost[c]) mdl.add(mdl.minimize(obj)) #----------------------------------------------------------------------------- # Solve the model, tracking objective with a callback #-----------------------------------------------------------------------------
# Estimate an upper bound to the ruler length MAX_LENGTH = (ORDER - 1)**2 #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create array of variables corresponding to position rule marks marks = mdl.integer_var_list(ORDER, 0, MAX_LENGTH, "M") # Create marks distances that should be all different dist = [marks[i] - marks[j] for i in range(1, ORDER) for j in range(0, i)] mdl.add(mdl.all_diff(dist)) # Avoid symmetric solutions by ordering marks mdl.add(marks[0] == 0) for i in range(1, ORDER): mdl.add(marks[i] > marks[i - 1]) # Avoid mirror solution mdl.add((marks[1] - marks[0]) < (marks[ORDER - 1] - marks[ORDER - 2])) # Minimize ruler size (position of the last mark) mdl.add(mdl.minimize(marks[ORDER - 1])) #----------------------------------------------------------------------------- # Solve the model and display the result #-----------------------------------------------------------------------------
nbKids = 300 # Indexes busSize = 0 busCost = 1 for b in Buses: print("buses with ", b[busSize], " seats cost ", b[busCost]) mdl = CpoModel(name='buses') #decision variables mdl.nbBus = { b: mdl.integer_var(0, 1000, name="nbBus" + str(b[busSize])) for b in Buses } # Constraint mdl.add(sum(mdl.nbBus[b] * b[busSize] for b in Buses) >= nbKids) # Objective mdl.minimize(sum(mdl.nbBus[b] * b[busCost] for b in Buses)) msol = mdl.solve() # Dislay solution for b in Buses: print(msol[mdl.nbBus[b]], " buses with ", b[busSize], " seats")
for i in range(len(ALL_TASKS)): ALL_TASKS[i].id = i #----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create interval variable for each building task tasks = [mdl.interval_var(size=t.duration, name=t.name) for t in ALL_TASKS] # Add precedence constraints for p, s in PRECEDENCES: mdl.add(mdl.end_before_start(tasks[p.id], tasks[s.id])) # Cost function cost = [] # List of individual costs fearliness = dict() # Task earliness cost function (for display) ftardiness = dict() # Task tardiness cost function (for display) for t in ALL_TASKS: task = tasks[t.id] if t.release_date is not None: f = CpoSegmentedFunction((-t.earliness_cost, 0), [(t.release_date, 0, 0)]) cost.append(mdl.start_eval(task, f)) fearliness[t] = f if t.due_date is not None: f = CpoSegmentedFunction((0, 0), [(t.due_date, 0, t.tardiness_cost)])
global cash # Allocate tasks to workers for t in ALL_TASKS: desc[tasks[t.id]] = t house[tasks[t.id]] = loc workers_usage += mdl.pulse(tasks[t.id], 1) cash -= mdl.step_at_start(tasks[t.id], 200 * t.duration) # Make houses for i, sd in enumerate(HOUSES): make_house(i, sd) # Number of workers should not be greater than the limit mdl.add(workers_usage <= NB_WORKERS) # Cash should not be negative mdl.add(cash >= 0) # Minimize overall completion date mdl.add(mdl.minimize(mdl.max([mdl.end_of(task) for task in all_tasks]))) #----------------------------------------------------------------------------- # Solve the model and display the result #----------------------------------------------------------------------------- def compact(name): # Example: H3-garden -> G3 # ^ ^
def initialize(self): model = CpoModel() self.model = model instance = self.instance T = len(instance.intervals) first_on = instance.earliest_on_interval_idx last_on = instance.latest_on_interval_idx init_start_times = self.get_init_start_times(sort_starts=True) ub = min(instance.get_ub(), self.get_upper_bound(init_start_times)) total_proc = sum(j.processing_time for j in instance.jobs) # -------------------------------------- Construct the model. job_vars = dict() # Dict[Job, CpoIntervalVar] self.job_vars = job_vars gap_vars = dict() # Dict[Tuple[int, int], CpoIntervalVar] obj = 0 # objective value seq_vars = [] # variables for no-overlap constraint stp = model.create_empty_solution( ) # starting point of the solving procedure step_fns = CpGeneral.get_step_functions( instance, first_on, last_on) # Generate seqment function for each processing time. first_job_var = model.interval_var(length=0, optional=False, name="first_job_var", start=1) seq_vars.append( first_job_var) # dummy job with 0 length, first in the sequence last_job_var = model.interval_var(length=0, optional=False, name="last_job_var", end=T - 1) seq_vars.append( last_job_var) # dummy job with 0 length, last in the sequence # variables for jobs ------------------------------------------------------------------------------------------- for job in instance.jobs: var = model.interval_var(length=job.processing_time, optional=False, name="j[{:d}]".format(job.id)) model.add(cpmod.start_of(var) >= first_on) # earliest possible start time is first_on model.add(cpmod.end_of(var) <= last_on + 1) # latest possible end time is last_on job_vars[job] = var seq_vars.append(var) if self.specialized_solver_config[ "JobInObjectiveModelling"] == 0: # Optional : alternatives = [] for t in range(first_on, T): if t <= last_on - ( job.processing_time - 1 ): # (-1) because unit job can be processed in last_on var = model.interval_var(start=t, length=job.processing_time, optional=True, name="j[{:d},{:d}]".format( t, job.id)) alternatives.append(var) obj += cpmod.presence_of( var) * instance.cumulative_energy_cost[t][ t + job.processing_time - 1] * instance.on_power_consumption # add a present variable for the job model.add(cpmod.alternative(job_vars[job], alternatives)) elif self.specialized_solver_config[ "JobInObjectiveModelling"] == 1: # Logical : for t in range(T): if first_on <= t <= last_on - (job.processing_time - 1): obj += (cpmod.start_of(var, absentValue=-1) == t) * instance.cumulative_energy_cost[t][ t + job.processing_time - 1] * instance.on_power_consumption elif self.specialized_solver_config[ "JobInObjectiveModelling"] == 2: # Element : energy = [ instance.cumulative_energy_cost[t][t + job.processing_time - 1] * instance.on_power_consumption if (first_on <= t <= last_on - (job.processing_time - 1)) else 0 for t in range(T) ] obj += cpmod.element(energy, cpmod.start_of(var)) elif self.specialized_solver_config[ "JobInObjectiveModelling"] == 3: # Overlap : for t in range(T): # add overlaps to objective if first_on <= t <= last_on: obj += cpmod.overlap_length( var, (t, t + 1)) * instance.intervals[ t].energy_cost * instance.on_power_consumption elif self.specialized_solver_config[ "JobInObjectiveModelling"] == 4: # Step function : obj += cpmod.start_eval(var, step_fns[job.processing_time]) else: raise Exception( "Given JobInObjectiveModelling method {0} is not supported." .format( self. specialized_solver_config["JobInObjectiveModelling"])) # add variables for gaps --------------------------------------------------------------------------------------- if self.specialized_solver_config[ "GapsInObjectiveModelling"] == 0: # Fixed : for t_s in range(1, T): for t_e in range(t_s + 1, T): if instance.has_switching_cost(t_s, t_e): if instance.get_gap_lower_bound( t_s, t_e) > ub: # skip gaps that are too costly continue sw_cost = instance.optimal_switching_costs[t_s][t_e] var = model.interval_var(start=t_s, end=t_e, optional=True, name="gap[{:d},{:d}]".format( t_s, t_e)) gap_vars[t_s, t_e] = var seq_vars.append(var) obj += cpmod.presence_of( var ) * sw_cost # if the gap is present, add cost to objective elif self.specialized_solver_config[ "GapsInObjectiveModelling"] == 1: # Free : gaps_by_lengths = {i: [] for i in range(1, T - 1)} for gap_len in range(1, T - total_proc - 1): costs = [ instance.optimal_switching_costs[t][t + gap_len] if instance.optimal_switching_costs[t][t + gap_len] is not None else len(instance.intervals) * instance.on_power_consumption + 1 # TODO : max value for t in range(T) if t + gap_len < T ] costs[0] = 0 # TODO: for absent value for i in range(int(T / gap_len)): var = model.interval_var(optional=True, length=gap_len, name="gap[{:d},{:d}]".format( gap_len, i)) model.add(cpmod.start_of(var, absentValue=1) >= 1) model.add(cpmod.end_of(var) <= T - 1) obj += cpmod.element(costs, cpmod.start_of(var)) gaps_by_lengths[gap_len].append(var) seq_vars.append(var) # force order on the gaps for cur, nxt in zip(gaps_by_lengths[gap_len], gaps_by_lengths[gap_len][1:]): model.add(cpmod.presence_of(cur) >= cpmod.presence_of(nxt)) model.add(cpmod.end_before_start(cur, nxt)) elif self.specialized_solver_config[ "GapsInObjectiveModelling"] == 2: # No : # Gaps will be added to the objective after introducing the sequence variable pass else: raise Exception( "Given GapsInObjectiveModelling method {0} is not supported.". format(self. specialized_solver_config["GapsInObjectiveModelling"])) # add no overlap constraint ------------------------------------------------------------------------------------ seq = model.sequence_var(seq_vars, name="seq") model.add(cpmod.no_overlap(seq)) model.add(cpmod.first(seq, first_job_var)) model.add(cpmod.last(seq, last_job_var)) if self.specialized_solver_config[ "GapsInObjectiveModelling"] == 2: # No : gap_costs = ( [0 for _ in range(T)] + # gap_len == 0 [ instance.optimal_switching_costs[gap_s][gap_s + gap_len] if gap_s + gap_len <= T - 1 and instance.optimal_switching_costs[gap_s][gap_s + gap_len] is not None else INT_MAX for gap_len in range(1, T) for gap_s in range(T) ]) for job in instance.jobs: job_var = self.job_vars[job] obj += cpmod.element( gap_costs, (cpmod.start_of_next(seq, job_var, T - 1) - cpmod.end_of(job_var)) * T + cpmod.end_of(job_var)) obj += cpmod.element(gap_costs, cpmod.start_of_next(seq, first_job_var) * T) # constrain lengths to fill the whole horizon ------------------------------------------------------------------ if self.specialized_solver_config[ "GapsInObjectiveModelling"] != 2: # gaps are modelled if self.specialized_solver_config[ "FillAllModelling"] == 0: # SumLengths : model.add( sum([cpmod.length_of(var) for var in seq_vars]) == T - 2) elif self.specialized_solver_config[ "FillAllModelling"] == 1: # Pulse : cumul_func = 0 for var in seq_vars: if var is not first_job_var and var is not last_job_var: cumul_func += cpmod.pulse(var, 1) model.add(cpmod.always_in(cumul_func, (1, T - 1), 1, 1)) elif self.specialized_solver_config[ "FillAllModelling"] == 2: # StartOfNext : for var in seq_vars: if var is not last_job_var: model.add( cpmod.start_of_next( seq, var, lastValue=T, absentValue=0) == cpmod.end_of(var, absentValue=0)) else: raise Exception( "Given FillAllModelling method {0} is not supported.". format(self.specialized_solver_config["FillAllModelling"])) # set objective model.minimize(obj) # - init start times. # if init_start_times is not None: # for job in instance.jobs: # stp.add_interval_var_solution(job_vars[job], presence=True, start=init_start_times[job]) # # # gaps in the schedule # gaps = self.get_gaps_in_schedule(init_start_times) # # for g_s, g_e in gaps: # stp.add_interval_var_solution(gap_vars[g_s, g_e], presence=True, start=g_s) # # # set starting point # model.set_starting_point(stp) # force ordering of the jobs jobs_by_lengths = self.get_job_by_lengths() for lst in jobs_by_lengths.values(): for j_cur, j_nxt in zip(lst, lst[1:]): model.add( cpmod.end_before_start(job_vars[j_cur], job_vars[j_nxt]))
def solve_seer_ilp(companies, facilities, customers, facilityDemands, costs, alpha=1, log_verbose='Quiet'): assert alpha >= 0 # ensure trace-off factor is >= 0, which show the contribution of representative cost assert log_verbose in ['Quiet', 'Terse', 'Normal', 'Verbose'] n_company = len(companies) n_facility = len(facilities) n_customer = len(customers) n_type = len(facilityDemands) mdl = CpoModel() customerSupplier = mdl.integer_var_list(n_customer, 0, n_facility - 1, 'customerSupplier') openFacility = mdl.integer_var_list(n_facility, 0, 1, 'openFacility') facilityType = mdl.integer_var_list(n_facility, 0, n_type, 'facilityType') customerType = mdl.integer_var_list(n_customer, 0, n_type - 1, 'customerType') openCompany = mdl.integer_var_list(n_company, 0, 1, 'openCompany') company2id = {companies[i].name: i for i in range(n_company)} type2id = {facilityDemands[i].type: i for i in range(n_type)} facilityCompany = [ company2id[facilities[i].company] for i in range(n_facility) ] validFacilityType = np.zeros((n_facility, n_type + 1)) validFacilityType[:, n_type] = 1 for i in range(n_facility): validFacilityType[i, type2id[facilities[i].type]] = 1 for i in range(n_customer): mdl.add(mdl.element(openFacility, customerSupplier[i]) == 1) mdl.add( mdl.element(customerType, i) == mdl.element( facilityType, customerSupplier[i])) mdl.add( mdl.element(mdl.element(customerType, i), validFacilityType[i]) == 1) for i in range(n_facility): mdl.add( mdl.element(mdl.element(facilityType, i), validFacilityType[i]) == 1) mdl.add( mdl.element(openFacility, i) <= mdl.element( openCompany, facilityCompany[i])) mdl.add((mdl.element(openFacility, i) == 1) == ( mdl.element(facilityType, i) < n_type)) for i in range(n_type): mdl.add(mdl.count(facilityType, i) == facilityDemands[i].demand) # Objective total_cost = mdl.scal_prod(openCompany, [c.cost for c in companies]) for i in range(n_customer): total_cost += mdl.element(customerSupplier[i], alpha * costs[i]) mdl.add(mdl.minimize(total_cost)) # ----------------------------------------------------------------------------- # Solve the model and display the result # ----------------------------------------------------------------------------- # Solve model msol = mdl.solve(TimeLimit=TIME_LIMIT, LogVerbosity=log_verbose) selectedFacilities = [] selectedCompanies = [] if msol: for i in range(n_facility): if msol[facilityType[i]] < n_type: selectedFacilities.append(i) if facilityCompany[i] not in selectedCompanies: selectedCompanies.append(facilityCompany[i]) return msol, selectedFacilities, selectedCompanies
#----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create one interval variable per job operation job_operations = [[ mdl.interval_var(size=JOB_DURATIONS[j][m], name="J{}-M{}".format(j, m)) for m in range(NB_MACHINES) ] for j in range(NB_JOBS)] # Force each operation to start after the end of the previous for j in range(NB_JOBS): for m in range(1, NB_MACHINES): mdl.add( mdl.end_before_start(job_operations[j][m - 1], job_operations[j][m])) # Force no overlap for operations executed on a same machine for m in range(NB_MACHINES): mdl.add(mdl.no_overlap([job_operations[j][m] for j in range(NB_JOBS)])) # Minimize termination date mdl.add( mdl.minimize( mdl.max([ mdl.end_of(job_operations[i][NB_MACHINES - 1]) for i in range(NB_JOBS) ]))) #-----------------------------------------------------------------------------
for task in TASKS: v = (0, MAX_SCHEDULE) tasks[(house, task)] = mdl.interval_var(v, v, size=task.duration, name="house {} task {}".format( house, task)) for task in SKILLS: wtasks[(house, task)] = mdl.interval_var( optional=True, name="house {} skill {}".format(house, task)) # Maximization objective of the model obj2 = mdl.sum([ s.level * mdl.presence_of(wtasks[(h, s)]) for s in SKILLS for h in HOUSES ]) mdl.add(mdl.maximize(obj2)) # Constraints of the model for h in HOUSES: # Temporal constraints for p in TASK_PRECEDENCES: mdl.add( mdl.end_before_start(tasks[(h, find_tasks(p.beforeTask))], tasks[(h, find_tasks(p.afterTask))])) # Alternative workers for t in TASKS: mdl.add( mdl.alternative( tasks[(h, t)], [wtasks[(h, s)] for s in SKILLS if (s.task == t.name)], 1)) # Continuity constraints
all_pins_list = [] for macro in macros: for term in macro.terms: all_pins_list.append(term) for i in list(range(0, len(all_pins_list))): for j in list(range(i + 1, len(all_pins_list))): cpo_pinPitch = cplex_helpers.t2tDistance(mdl, all_pins_list[i], all_pins_list[j]) mdl.add(cpo_pinPitch >= minPinPitch) ''' new_index_list = [] for key, value in new_index_map.items(): new_index_list.append(value) for i in range(0, len(new_index_list)): for j in range(i + 1, len(new_index_list)): mdl.add(new_index_list[i] != new_index_list[j]) #mdl.add(new_index_list[i] - new_index_list[j] > minPinPitch/pinMovement) # maxPinPitch Constraints - save cpo_perturbation_list for objectives modeling cpo_perturbation_list = [] for macro in macros: for term in macro.terms: cpo_perturbation = cplex_helpers.termPerturbation(mdl, term) cpo_perturbation_list.append(cpo_perturbation) if maxPerturbation != -1: mdl.add(cpo_perturbation < maxPerturbation) # ---------------- # Add Objective # ---------------- # Update terms info in all nets - because no initialization
#----------------------------------------------------------------------------- # Build the model #----------------------------------------------------------------------------- # Create model mdl = CpoModel() # Create one interval variable per task tasks = {t['id']: mdl.interval_var(name="T{}".format(t['id'])) for t in TASKS} # Add precedence constraints for t in TASKS: for s in t['successors']: mdl.add(mdl.end_before_start(tasks[t['id']], tasks[s])) # Create one optional interval variable per task mode and add alternatives for tasks modes = {} # Map of all modes for t in TASKS: tmds = [mdl.interval_var(name=m['id'], optional=True, size=m['duration']) for m in t['modes']] mdl.add(mdl.alternative(tasks[t['id']], tmds)) for m in tmds: modes[m.name] = m # Initialize pulse functions for renewable and non renewable resources renewables = [mdl.pulse((0, 0), 0) for j in range(NB_RENEWABLE)] non_renewables = [0 for j in range(NB_NON_RENEWABLE)] for m in MODES: dren = m['demandRenewable'] dnren = m['demandNonRenewable']
def main(): filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data_in/test_1.txt") inst = instance.Instance(filename) # input from master problem, now random id_profile = 0 random.seed(42) rewards = [random.randint(0, 30000) for i in range(inst.J)] #rewards = [random.uniform(0.0, 30000.0) for i in range(inst.J)] equivalences = [[0, 1], [2, 3]] mutexes = [[2, 1], [4, 3]] # input from master problem, now random types = inst.profiles[id_profile] types.insert(0, inst.INIT) types.append(inst.TERM) trans_cost = [[0 for i in range(inst.V)] for j in range(inst.V)] trans_time = [[0 for i in range(inst.V)] for j in range(inst.V)] for i in range(len(inst.edges)): for j in range(len(inst.edges[i])): trans_cost[i][inst.edges[i][j][ 'to']] = inst.edges[i][j]['C'] * inst.edges[i][j]['t'] trans_time[i][inst.edges[i][j]['to']] = inst.edges[i][j]['t'] changeover_cost = 0 for i in range(1, len(types)): changeover_cost += trans_cost[types[i - 1]][types[i]] cp = CpoModel() primitives = [[] for i in range(inst.J)] all_primitives = [] init = cp.interval_var(start=0) init.set_end_max(inst.L) total_cost = changeover_cost + inst.vertices[ inst.INIT]['C'] * cp.length_of(init, 0) modes_of_mach = [init ] # serves only for retrieving starts and ends of modes last_shift = init for i in range(1, len(types) - 1): v = types[i] shift = cp.interval_var() shift.set_size_min(inst.vertices[v]['t_min']) shift.set_size_max(inst.vertices[v]['t_max']) shift.set_end_max(inst.L) total_cost += inst.vertices[v]['C'] * cp.length_of(shift, 0) cp.add( cp.start_at_end(shift, last_shift, -trans_time[types[i - 1]][types[i]])) last_shift = shift modes_of_mach.append(shift) for t in range(inst.J): if inst.tasks[t]['p'][v] <= inst.L: prim = cp.interval_var(size=inst.tasks[t]['p'][v]) total_cost -= rewards[t] * cp.presence_of(prim) prim.set_optional() prim.set_start_min(inst.tasks[t]['r']) prim.set_end_max(inst.tasks[t]['d']) primitives[t].append(prim) all_primitives.append(prim) cp.add(cp.start_before_start(shift, prim)) cp.add(cp.end_before_end(prim, shift)) term = cp.interval_var(end=inst.L) total_cost += inst.vertices[inst.TERM]['C'] * cp.length_of(term, 0) cp.add( cp.start_at_end(term, last_shift, -trans_time[types[len(types) - 2]][inst.TERM])) modes_of_mach.append(term) cp.add(cp.no_overlap(cp.sequence_var(all_primitives))) for t in range(inst.J): cp.add(sum([cp.presence_of(p) for p in primitives[t]]) <= 1) for eq in equivalences: cp.add( sum([cp.presence_of(p) for p in primitives[eq[0]]]) == sum( [cp.presence_of(p) for p in primitives[eq[1]]])) for mut in mutexes: cp.add( sum([cp.presence_of(p) for p in primitives[mut[0]]]) + sum([cp.presence_of(p) for p in primitives[mut[1]]]) <= 1) cp.add(cp.minimize(total_cost)) # set TimeLimit in seconds or delete it for no limit # parameters DefaultInferenceLevel and Workers may be beneficial to add sol = cp.solve( TimeLimit=30, LogVerbosity="Quiet") #, DefaultInferenceLevel='Extended', Workers=1) if sol: tasks = [] for t in range(inst.J): for pr in primitives[t]: p = sol.get_var_solution(pr) if p.is_present(): tasks.append({ "task": t, "start": p.get_start(), "end": p.get_end() }) break modes = [] sched_cost = 0 for t in range(len(modes_of_mach)): m = sol.get_var_solution(modes_of_mach[t]) modes.append({ "mode": types[t], "start": m.get_start(), "end": m.get_end() }) sched_cost += inst.vertices[types[t]]['C'] * m.get_length() print("Solution status: " + sol.get_solve_status()) print("Solve time: " + str(sol.get_solve_time())) print("Objective: " + str(sol.get_objective_values()[0])) print("Schedule cost: " + str(sched_cost)) print(tasks) print(modes) else: print("No solution found.")
def fixed_resource_allocation_model(env: OnlineFlexibleResourceAllocationEnv, state: EnvState): """ Generate the fixed resource allocation model and then solve it Args: env: Online Flexible Resource Allocation Env state: Environment state Returns: Cplex model """ tasks = env._unallocated_tasks if state.auction_task: tasks.append(state.auction_task) fixed_tasks = convert_fixed_task(tasks) servers = list(state.server_tasks.keys()) model = CpoModel('FixedEnv') server_task_allocation = { (server, task): model.binary_var(name=f'{server.name} server - {task.name} task') for server in servers for task in fixed_tasks } for task in fixed_tasks: model.add( sum(server_task_allocation[(server, task)] for server in servers) <= 1) for server in servers: for time in range(env._total_time_steps): time_tasks = [ task for task in fixed_tasks if task.auction_time <= time <= task.deadline ] model.add( sum( min( task.required_storage, task.fixed_loading_speed * (time + 1 - task.auction_time)) * server_task_allocation[(server, task)] for task in time_tasks) <= server.storage_cap) model.add( sum(task.fixed_compute_speed * server_task_allocation[(server, task)] for task in time_tasks) <= server.computational_cap) model.add( sum((task.fixed_loading_speed + task.fixed_sending_speed) * server_task_allocation[(server, task)] for task in time_tasks) <= server.bandwidth_cap) model.maximize( sum(server_task_allocation[(server, task)] for server in servers for task in fixed_tasks)) model_solution = model.solve(log_output=None, TimeLimit=150) total_tasks_completed = sum( model_solution.get_value(server_task_allocation[(server, task)]) for server in servers for task in fixed_tasks) return total_tasks_completed
from docplex.cp.model import CpoModel from docplex.cp.model import CpoParameters mdl = CpoModel(name='buses') nbbus40 = mdl.integer_var(0, 1000, name='nbBus40') nbbus30 = mdl.integer_var(0, 1000, name='nbBus30') mdl.add(nbbus40 * 40 + nbbus30 * 30 >= 300) mdl.minimize(nbbus40 * 500 + nbbus30 * 400) param = CpoParameters() param.set_TimeLimit(20) param.TimeLimit = 20 #use parameters param for model mdl mdl.set_parameters(param) msol = mdl.solve() print(msol[nbbus40], " buses 40 seats") print(msol[nbbus30], " buses 30 seats") #read params from model mdl param2 = mdl.get_parameters() print("time limit = ", param2["TimeLimit"]) print("time limit = ", param2.get_attribute("TimeLimit")) for i in param2: print(i, " = ", param2[i]) """ which gives
from docplex.cp.model import CpoModel mdl = CpoModel(name='buses') nbbus40 = mdl.integer_var(0, 6, name='nbBus40') nbbus30 = mdl.integer_var(0, 6, name='nbBus30') cost = mdl.integer_var(0, 1000000, name='cost') mdl.add(cost == nbbus40 * 500 + nbbus30 * 400) mdl.add(cost <= 4000) mdl.add(nbbus40 * 40 + nbbus30 * 30 >= 300) siter = mdl.start_search(SearchType='DepthFirst', Workers=1, TimeLimit=100) # Parameters needed to avoid duplicate solutions from pandas import * dfsol = pandas.DataFrame() for msol in siter: print(msol[nbbus40], " buses 40 seats") print(msol[nbbus30], " buses 30 seats") print("cost = ", msol[cost]) dfsol = concat( [dfsol, DataFrame([msol[nbbus40], msol[nbbus30], msol[cost]])], axis=1) print("\n") dfsol.columns = ["sol1", "sol2", "sol3"] print(dfsol) """ which gives
for b in Buses: print("buses with ", b[busSize], " seats cost ", b[busCost]) print() for b in Buses: print("buses with ", b[busSize], " seats cost ", b[busCost]) mdl = CpoModel(name='buses') #decision variables mdl.nbBus = mdl.integer_var_dict(Buses, 0, maxquantity, name="nbBus") # Constraint mdl.add(sum(mdl.nbBus[b] * b[busSize] for b in Buses) >= nbKids) # Objective mdl.minimize(sum(mdl.nbBus[b] * b[busCost] for b in Buses)) msol = mdl.solve() # Dislay solution for b in Buses: print(msol[mdl.nbBus[b]], " buses with ", b[busSize], " seats") #Add a constraint # Number of different quantity should be less than 1 mdl.add( mdl.sum(((mdl.count(mdl.nbBus.values(), q) >= 1)