def solve(self, **kwargs): res_storage = solve(method=self.method, rcpsp_model=self.model_rcpsp, **self.args_solve) list_solution_fits = [] for s, fit in res_storage.list_solution_fits: sol: RCPSPSolution = s mode = sol.rcpsp_modes modes = {i + 2: mode[i] for i in range(len(mode))} modes[self.model.source_task] = 1 modes[self.model.sink_task] = 1 # print(fit, " found by ", self.method.__name__) ms_rcpsp_solution = MS_RCPSPSolution_Variant( problem=self.model, priority_list_task=sol.rcpsp_permutation, modes_vector=sol.rcpsp_modes, priority_worker_per_task=[[ w for w in self.model.employees ] for i in range(self.model.n_jobs_non_dummy)], ) list_solution_fits += [(ms_rcpsp_solution, self.aggreg_from_sol(ms_rcpsp_solution))] return ResultStorage( list_solution_fits=list_solution_fits, mode_optim=self.params_objective_function.sense_function, )
def generate_super_pareto(self): sols = [] for rs in self.list_result_storage: for s in rs.list_solution_fits: sols.append(s) rs = ResultStorage(list_solution_fits=sols, best_solution=None) pareto_store = result_storage_to_pareto_front(result_storage=rs, problem=None) return pareto_store
def adding_constraint_from_results_store( self, milp_solver: LP_Solver_MRSCPSP, result_storage: ResultStorage ) -> Iterable[Any]: current_solution: MS_RCPSPSolution = result_storage.get_best_solution() # st = milp_solver.start_solution # if self.problem.evaluate(st)["makespan"] < self.problem.evaluate(current_solution)["makespan"]: # current_solution = st start = [] for j in current_solution.schedule: start_time_j = current_solution.schedule[j]["start_time"] mode = current_solution.modes[j] start += [(milp_solver.start_times_task[j], start_time_j)] start += [(milp_solver.modes[j][mode], 1)] for m in milp_solver.modes[j]: start += [(milp_solver.modes[j][m], 1 if mode == m else 0)] milp_solver.model.start = start constraints_dict = {} constraints_dict["range_start_time"] = [] max_time = max( [ current_solution.schedule[x]["end_time"] for x in current_solution.schedule ] ) last_jobs = [ x for x in current_solution.schedule if current_solution.schedule[x]["end_time"] >= max_time - 5 ] nb_jobs = self.problem.nb_tasks jobs_to_fix = set( random.sample( current_solution.schedule.keys(), int(self.fraction_to_fix * nb_jobs) ) ) for lj in last_jobs: if lj in jobs_to_fix: jobs_to_fix.remove(lj) for job in jobs_to_fix: start_time_j = current_solution.schedule[job]["start_time"] min_st = max(start_time_j - self.minus_delta, 0) max_st = min(start_time_j + self.plus_delta, max_time) constraints_dict["range_start_time"].append( milp_solver.model.add_constr( milp_solver.start_times_task[job] <= max_st ) ) constraints_dict["range_start_time"].append( milp_solver.model.add_constr( milp_solver.start_times_task[job] >= min_st ) ) if milp_solver.lp_solver == MilpSolverName.GRB: milp_solver.model.solver.update() return constraints_dict
def adding_constraint_from_results_store( self, cp_solver: Union[CP_RCPSP_MZN, CP_MRCPSP_MZN], child_instance, result_storage: ResultStorage, ) -> Iterable[Any]: constraints_dict = {} current_solution, fit = result_storage.get_best_solution_fit() max_time = max([ current_solution.rcpsp_schedule[x]["end_time"] for x in current_solution.rcpsp_schedule ]) last_jobs = [ x for x in current_solution.rcpsp_schedule if current_solution.rcpsp_schedule[x]["end_time"] >= max_time - self.delta_time_from_makepan_to_not_fix ] nb_jobs = self.problem.n_jobs + 2 jobs_to_fix = set( random.sample( current_solution.rcpsp_schedule.keys(), int(self.fraction_to_fix * nb_jobs), )) for lj in last_jobs: if lj in jobs_to_fix: jobs_to_fix.remove(lj) list_strings = [] for job in jobs_to_fix: start_time_j = current_solution.rcpsp_schedule[job]["start_time"] min_st = max(start_time_j - self.minus_delta, 0) max_st = min(start_time_j + self.plus_delta, max_time) if isinstance(cp_solver, CP_RCPSP_MZN): string1 = "constraint s[" + str(job) + "] <= " + str( max_st) + ";\n" string2 = "constraint s[" + str(job) + "] >= " + str( min_st) + ";\n" elif isinstance(cp_solver, CP_MRCPSP_MZN): string1 = "constraint start[" + str(job) + "] <= " + str( max_st) + ";\n" string2 = "constraint start[" + str(job) + "] >= " + str( min_st) + ";\n" list_strings += [string1] list_strings += [string2] child_instance.add_string(string1) child_instance.add_string(string2) for job in current_solution.rcpsp_schedule: if isinstance(cp_solver, CP_RCPSP_MZN): string = ("constraint s[" + str(job) + "] <= " + str(max_time + 50) + ";\n") if isinstance(cp_solver, CP_MRCPSP_MZN): string = ("constraint start[" + str(job) + "] <= " + str(max_time + 50) + ";\n") child_instance.add_string(string) return list_strings
def retrieve_solutions( self, result, parameters_cp: ParametersCP = ParametersCP.default() ): intermediate_solutions = parameters_cp.intermediate_solution best_solution = None best_makespan = -float("inf") list_solutions_fit = [] starts = [] mruns = [] object_result: List[MRCPSP_Result] = [] if intermediate_solutions: for i in range(len(result)): object_result += [result[i]] else: object_result += [result] for res in object_result: modes = [] for j in range(len(res.mode_chosen)): if (self.modeindex_map[j + 1]["task"] != 1) and ( self.modeindex_map[j + 1]["task"] != self.rcpsp_model.n_jobs + 2 ): modes.append( self.modeindex_map[res.mode_chosen[j]]["original_mode_index"] ) elif (self.modeindex_map[j + 1]["task"] == 1) or ( self.modeindex_map[j + 1]["task"] == self.rcpsp_model.n_jobs + 2 ): modes.append(1) rcpsp_schedule = {} start_times = res.dict["start"] for i in range(len(start_times)): rcpsp_schedule[i + 1] = { "start_time": start_times[i], "end_time": start_times[i] + self.rcpsp_model.mode_details[i + 1][modes[i]]["duration"], } sol = RCPSPSolution( problem=self.rcpsp_model, rcpsp_schedule=rcpsp_schedule, rcpsp_modes=modes[1:-1], rcpsp_schedule_feasible=True, ) objective = self.aggreg_from_dict_values(self.rcpsp_model.evaluate(sol)) if objective > best_makespan: best_makespan = objective best_solution = sol.copy() list_solutions_fit += [(sol, objective)] result_storage = ResultStorage( list_solution_fits=list_solutions_fit, best_solution=best_solution, mode_optim=self.params_objective_function.sense_function, limit_store=False, ) return result_storage
def get_starting_solution(self) -> ResultStorage: if self.initial_method == InitialMethodRCPSP.PILE: greedy_solver = PileSolverRCPSP(self.problem) store_solution = greedy_solver.solve( greedy_choice=GreedyChoice.MOST_SUCCESSORS ) if self.initial_method == InitialMethodRCPSP.PILE_CALENDAR: greedy_solver = PileSolverRCPSP_Calendar(self.problem) store_solution = greedy_solver.solve( greedy_choice=GreedyChoice.MOST_SUCCESSORS ) elif self.initial_method == InitialMethodRCPSP.DUMMY: solution = self.problem.get_dummy_solution() fit = self.aggreg(solution) store_solution = ResultStorage( list_solution_fits=[(solution, fit)], best_solution=solution, mode_optim=self.params_objective_function.sense_function, ) elif self.initial_method == InitialMethodRCPSP.CP: solver = CP_MRCPSP_MZN( rcpsp_model=self.problem, params_objective_function=self.params_objective_function, ) store_solution = solver.solve(parameters_cp=ParametersCP.default()) elif self.initial_method == InitialMethodRCPSP.LS: dummy = self.problem.get_dummy_solution() _, mutations = get_available_mutations(self.problem, dummy) list_mutation = [ mutate[0].build(self.problem, dummy, **mutate[1]) for mutate in mutations if mutate[0] == PermutationMutationRCPSP ] # and mutate[1]["other_mutation"] == TwoOptMutation] mixed_mutation = BasicPortfolioMutation( list_mutation, np.ones((len(list_mutation))) ) res = RestartHandlerLimit( 500, cur_solution=dummy, cur_objective=self.problem.evaluate(dummy) ) sa = SimulatedAnnealing( evaluator=self.problem, mutator=mixed_mutation, restart_handler=res, temperature_handler=TemperatureSchedulingFactor(2, res, 0.9999), mode_mutation=ModeMutation.MUTATE, params_objective_function=self.params_objective_function, store_solution=True, nb_solutions=10000, ) store_solution = sa.solve( dummy, nb_iteration_max=10000, pickle_result=False ) return store_solution
def adding_constraint_from_results_store( self, milp_solver: Union[LP_RCPSP, LP_MRCPSP], result_storage: ResultStorage ) -> Iterable[Any]: constraints_dict = {} current_solution, fit = result_storage.get_best_solution_fit() # milp_solver.init_model(greedy_start=False, start_solution=current_solution) # Starting point : start = [] for j in milp_solver.J: start_time_j = current_solution.rcpsp_schedule[j + 1]["start_time"] for t in milp_solver.T: if start_time_j == t: start += [(milp_solver.x[j][t], 1)] else: start += [(milp_solver.x[j][t], 0)] milp_solver.model.start = start constraints_dict["range_start_time"] = [] max_time = max( [ current_solution.rcpsp_schedule[x]["end_time"] for x in current_solution.rcpsp_schedule ] ) last_jobs = [ x for x in current_solution.rcpsp_schedule if current_solution.rcpsp_schedule[x]["end_time"] >= max_time - 5 ] nb_jobs = self.problem.n_jobs + 2 jobs_to_fix = set( random.sample( current_solution.rcpsp_schedule.keys(), int(self.fraction_to_fix * nb_jobs), ) ) for lj in last_jobs: if lj in jobs_to_fix: jobs_to_fix.remove(lj) for job in jobs_to_fix: start_time_j = current_solution.rcpsp_schedule[job]["start_time"] min_st = max(start_time_j - self.minus_delta, 0) max_st = min(start_time_j + self.plus_delta, max_time) for t in milp_solver.T: if t < min_st or t > max_st: constraints_dict["range_start_time"].append( milp_solver.model.add_constr(milp_solver.x[job - 1][t] == 0) ) if milp_solver.lp_solver == LP_RCPSP_Solver.GRB: milp_solver.model.solver.update() return constraints_dict
def adding_constraint_from_results_store( self, cp_solver: CP_MS_MRCPSP_MZN, child_instance, result_storage: ResultStorage ) -> Iterable[Any]: new_fitness = result_storage.get_best_solution_fit()[1] if self.last_index_param is not None: if new_fitness != self.last_fitness: self.status[self.last_index_param]["nb_improvement"] += 1 self.last_fitness = new_fitness self.list_proba[self.last_index_param] *= 1.05 self.list_proba = self.list_proba / np.sum(self.list_proba) else: self.list_proba[self.last_index_param] *= 0.95 self.list_proba = self.list_proba / np.sum(self.list_proba) else: self.last_fitness = new_fitness if random.random() <= 0.95: choice = np.random.choice(self.index_np, size=1, p=self.list_proba)[0] else: max_improvement = max( [ self.status[x]["nb_improvement"] / max(self.status[x]["nb_usage"], 1) for x in self.status ] ) choice = random.choice( [ x for x in self.status if self.status[x]["nb_improvement"] / max(self.status[x]["nb_usage"], 1) == max_improvement ] ) d_params = { key: getattr(self.list_params[int(choice)], key) for key in self.list_params[0].__dict__.keys() } print("Params : ", d_params) ch = ConstraintHandlerStartTimeInterval_CP(problem=self.problem, **d_params) self.current_iteration += 1 self.last_index_param = choice self.status[self.last_index_param]["nb_usage"] += 1 print("Status ", self.status) return ch.adding_constraint_from_results_store( cp_solver, child_instance, result_storage )
def retrieve_solutions( self, result, parameters_cp: ParametersCP = ParametersCP.default() ) -> ResultStorage: intermediate_solutions = parameters_cp.intermediate_solution best_solution = None best_makespan = -float("inf") list_solutions_fit = [] starts = [] if intermediate_solutions: for i in range(len(result)): if isinstance(result[i], RCPSPSolCP): starts += [result[i].dict["s"]] else: starts += [result[i, "s"]] else: if isinstance(result, RCPSPSolCP): starts += [result.dict["s"]] else: starts = [result["s"]] for start_times in starts: rcpsp_schedule = {} for k in range(len(start_times)): rcpsp_schedule[k + 1] = { "start_time": start_times[k], "end_time": start_times[k] + self.rcpsp_model.mode_details[k + 1][1]["duration"], } sol = RCPSPSolution( problem=self.rcpsp_model, rcpsp_schedule=rcpsp_schedule, rcpsp_schedule_feasible=True, ) objective = self.aggreg_from_dict_values(self.rcpsp_model.evaluate(sol)) if objective > best_makespan: best_makespan = objective best_solution = sol.copy() list_solutions_fit += [(sol, objective)] result_storage = ResultStorage( list_solution_fits=list_solutions_fit, best_solution=best_solution, mode_optim=self.params_objective_function.sense_function, limit_store=False, ) return result_storage
def solve(self, **kwargs): # Initialise the population (here at random) population = self._toolbox.population() fits = self._toolbox.map(self._toolbox.evaluate, population) for fit, ind in zip(fits, population): ind.fitness.values = fit # Define the statistics to collect at each generation hof = tools.HallOfFame(1) stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("avg", np.mean) stats.register("std", np.std) stats.register("min", np.min) stats.register("max", np.max) # Run the GA: final population and statistics logbook are created pop_vector, logbook = algorithms.eaSimple( population=population, toolbox=self._toolbox, cxpb=self._crossover_rate, mutpb=self._mut_rate, ngen=int(self._max_evals / self._pop_size), stats=stats, halloffame=hof, verbose=self._deap_verbose, ) best_vector = hof[0] s_pure_int = [i for i in best_vector] kwargs = { self._encoding_variable_name: s_pure_int, "problem": self.problem } problem_sol = self.problem.get_solution_type()(**kwargs) result_storage = ResultStorage( list_solution_fits=[(problem_sol, self.aggreg_from_sol(problem_sol))], best_solution=problem_sol, mode_optim=self.params_objective_function.sense_function, ) return result_storage
def adding_constraint_from_results_store( self, milp_solver: LP_RCPSP_Solver, result_storage: ResultStorage ) -> Iterable[Any]: nb_jobs = self.problem.n_jobs + 2 constraints_dict = {} current_solution, fit = result_storage.get_best_solution_fit() # Starting point : start = [] for j in milp_solver.J: start_time_j = current_solution.rcpsp_schedule[j + 1]["start_time"] for t in milp_solver.T: if start_time_j == t: start += [(milp_solver.x[j][t], 1)] else: start += [(milp_solver.x[j][t], 0)] milp_solver.model.start = start # Fix start time for a subset of task. jobs_to_fix = set( random.sample( current_solution.rcpsp_schedule.keys(), int(self.fraction_fix_start_time * nb_jobs), ) ) constraints_dict["fix_start_time"] = [] for job_to_fix in jobs_to_fix: for t in milp_solver.T: if current_solution.rcpsp_schedule[job_to_fix]["start_time"] == t: constraints_dict["fix_start_time"].append( milp_solver.model.add_constr( milp_solver.x[job_to_fix - 1][t] == 1 ) ) else: constraints_dict["fix_start_time"].append( milp_solver.model.add_constr( milp_solver.x[job_to_fix - 1][t] == 0 ) ) if milp_solver.lp_solver == LP_RCPSP_Solver.GRB: milp_solver.model.solver.update() return constraints_dict
def retrieve_solutions(self, parameters_milp: ParametersMilp) -> ResultStorage: retrieve_all_solution = parameters_milp.retrieve_all_solution nb_solutions_max = parameters_milp.n_solutions_max nb_solution = min(nb_solutions_max, self.model.SolCount) if not retrieve_all_solution: nb_solution = 1 list_solution_fits = [] for s in range(nb_solution): self.model.params.SolutionNumber = s rcpsp_schedule = {} modes = {} objective = self.model.getAttr("ObjVal") for (task, mode, t) in self.x: value = self.x[(task, mode, t)].getAttr("Xn") if value >= 0.5: rcpsp_schedule[task] = { "start_time": t, "end_time": t + self.rcpsp_model.mode_details[task][mode]["duration"], } modes[task] = mode print("Size schedule : ", len(rcpsp_schedule.keys())) try: modes.pop(1) modes.pop(self.rcpsp_model.n_jobs + 2) modes_vec = [modes[k] for k in sorted(modes)] solution = RCPSPSolution( problem=self.rcpsp_model, rcpsp_schedule=rcpsp_schedule, rcpsp_modes=modes_vec, rcpsp_schedule_feasible=True, ) fit = self.aggreg_from_sol(solution) list_solution_fits += [(solution, fit)] except: pass return ResultStorage( list_solution_fits=list_solution_fits, best_solution=min(list_solution_fits, key=lambda x: x[1])[0], mode_optim=self.params_objective_function.sense_function, )
def get_starting_solution(self) -> ResultStorage: multi_skill_rcpsp = self.problem.build_multimode_rcpsp_calendar_representative() from skdecide.discrete_optimization.rcpsp.solver.rcpsp_lp_lns_solver import ( InitialSolutionRCPSP, ) init_solution = InitialSolutionRCPSP( problem=multi_skill_rcpsp, params_objective_function=self.params_objective_function, initial_method=self.initial_method, ) s = init_solution.get_starting_solution() list_solution_fits = [] for s, fit in s.list_solution_fits: sol: RCPSPSolution = s mode = sol.rcpsp_modes modes = {i + 2: mode[i] for i in range(len(mode))} modes[self.problem.source_task] = 1 modes[self.problem.sink_task] = 1 # ms_rcpsp_solution = MS_RCPSPSolution(problem=self.problem, # modes=modes, # schedule=sol.rcpsp_schedule, # employee_usage=None) ms_rcpsp_solution = MS_RCPSPSolution_Variant( problem=self.problem, priority_list_task=sol.rcpsp_permutation, modes_vector=sol.rcpsp_modes, priority_worker_per_task=[ [w for w in self.problem.employees] for i in range(self.problem.n_jobs_non_dummy) ], ) list_solution_fits += [(ms_rcpsp_solution, self.aggreg(ms_rcpsp_solution))] return ResultStorage( list_solution_fits=list_solution_fits, mode_optim=self.params_objective_function.sense_function, )
def solve(self, **kwargs): # Initialise the population (here at random) count_evals = 0 current_encoding_index = 0 for i in range(len(self.encodings)): self.problem.set_fixed_attributes( self.encodings[i], self.problem.get_dummy_solution()) while count_evals < self.max_evals: ga_solver = Ga( problem=self.problem, encoding=self.encodings[current_encoding_index], objective_handling=self.objective_handling, objectives=self.objectives, objective_weights=self.objective_weights, mutation=self.mutations[current_encoding_index], max_evals=self.sub_evals[current_encoding_index], ) tmp_sol = ga_solver.solve().get_best_solution() count_evals += self.sub_evals[current_encoding_index] # TODO: implement function below (1 in rcpsp domains, 1 in rcpsp solutions) self.problem.set_fixed_attributes( self.encodings[current_encoding_index], tmp_sol) problem_sol = tmp_sol result_storage = ResultStorage( list_solution_fits=[(problem_sol, self.aggreg_from_sol(problem_sol))], best_solution=problem_sol, mode_optim=self.params_objective_function.sense_function, ) return result_storage
def adding_constraint_from_results_store( self, milp_solver: LP_Solver_MRSCPSP, result_storage: ResultStorage ) -> Iterable[Any]: nb_jobs = self.problem.nb_tasks constraints_dict = {} current_solution, fit = result_storage.get_best_solution_fit() start = [] for j in current_solution.schedule: start_time_j = current_solution.schedule[j]["start_time"] mode = current_solution.modes[j] start += [(milp_solver.start_times_task[j], start_time_j)] start += [(milp_solver.modes[j][mode], 1)] for m in milp_solver.modes[j]: start += [(milp_solver.modes[j][m], 1 if mode == m else 0)] milp_solver.model.start = start # Fix start time for a subset of task. jobs_to_fix = set( random.sample( current_solution.rcpsp_schedule.keys(), int(self.fraction_fix_start_time * nb_jobs), ) ) constraints_dict["fix_start_time"] = [] for job_to_fix in jobs_to_fix: constraints_dict["fix_start_time"].append( milp_solver.model.add_constr( milp_solver.start_times_task[job_to_fix] - current_solution.schedule[job_to_fix]["start_time"] == 0 ) ) if milp_solver.lp_solver == MilpSolverName.GRB: milp_solver.model.solver.update() return constraints_dict
def retrieve_solutions(self, parameters_milp: ParametersMilp) -> ResultStorage: retrieve_all_solution = parameters_milp.retrieve_all_solution nb_solutions_max = parameters_milp.n_solutions_max nb_solution = min(nb_solutions_max, self.model.num_solutions) if not retrieve_all_solution: nb_solution = 1 list_solution_fits = [] print(nb_solution, " solutions found") for s in range(nb_solution): rcpsp_schedule = {} objective = self.model.objective_values[s] for (j, t) in product(self.J, self.T): value = self.x[j][t].xi(s) if value >= 0.5: rcpsp_schedule[j + 1] = { "start_time": t, "end_time": t + self.rcpsp_model.mode_details[j + 1][1]["duration"], } print("Size schedule : ", len(rcpsp_schedule.keys())) try: solution = RCPSPSolution( problem=self.rcpsp_model, rcpsp_schedule=rcpsp_schedule, rcpsp_schedule_feasible=True, ) fit = self.aggreg_from_sol(solution) list_solution_fits += [(solution, fit)] except: print("Problem =", rcpsp_schedule, len(rcpsp_schedule)) pass return ResultStorage( list_solution_fits=list_solution_fits, best_solution=min(list_solution_fits, key=lambda x: x[1])[0], mode_optim=self.params_objective_function.sense_function, )
def retrieve_solutions(self, parameters_milp: ParametersMilp) -> ResultStorage: retrieve_all_solution = parameters_milp.retrieve_all_solution nb_solutions_max = parameters_milp.n_solutions_max nb_solution = min(nb_solutions_max, self.model.num_solutions) if not retrieve_all_solution: nb_solution = 1 list_solution_fits = [] print(nb_solution, " solutions found") for s in range(nb_solution): rcpsp_schedule = {} modes = {} objective = self.model.objective_values[s] results = {} employee_usage = {} employee_usage_solution = {} for task in self.start_times: for mode in self.start_times[task]: for t in self.start_times[task][mode]: value = self.start_times[task][mode][t].xi(s) results[(task, mode, t)] = value if value >= 0.5: rcpsp_schedule[task] = { "start_time": int(t), "end_time": int(t + self.rcpsp_model.mode_details[task] [mode]["duration"]), } modes[task] = mode for t in self.employee_usage: employee_usage[t] = self.employee_usage[t].xi(s) if employee_usage[t] >= 0.5: if t[1] not in employee_usage_solution: employee_usage_solution[t[1]] = {} if t[0] not in employee_usage_solution[t[1]]: employee_usage_solution[t[1]][t[0]] = set() employee_usage_solution[t[1]][t[0]].add(t[4]) # (employee, task, mode, time, skill) modes = {} modes_task = {} for t in self.modes: for m in self.modes[t]: modes[(t, m)] = self.modes[t][m].xi(s) if modes[(t, m)] >= 0.5: modes_task[t] = m durations = {} for t in self.durations: durations[t] = self.durations[t].xi(s) start_time = {} for t in self.start_times_task: start_time[t] = self.start_times_task[t].xi(s) end_time = {} for t in self.start_times_task: end_time[t] = self.end_times_task[t].xi(s) print("Size schedule : ", len(rcpsp_schedule.keys())) print( "results", "(task, mode, time)", {x: results[x] for x in results if results[x] == 1.0}, ) print( "Employee usage : ", "(employee, task, mode, time, skill)", { x: employee_usage[x] for x in employee_usage if employee_usage[x] == 1.0 }, ) print( "task mode : ", "(task, mode)", {t: modes[t] for t in modes if modes[t] == 1.0}, ) print("durations : ", durations) print("Start time ", start_time) print("End time ", end_time) solution = MS_RCPSPSolution( problem=self.rcpsp_model, modes=modes_task, schedule=rcpsp_schedule, employee_usage=employee_usage_solution, ) fit = self.aggreg_from_sol(solution) list_solution_fits += [(solution, fit)] return ResultStorage( list_solution_fits=list_solution_fits, mode_optim=self.params_objective_function.sense_function, )
def adding_constraint_from_results_store( self, milp_solver: LP_MRCPSP_GUROBI, result_storage: ResultStorage ) -> Iterable[Any]: current_solution, fit = result_storage.get_best_solution_fit() st = milp_solver.start_solution if ( self.problem.evaluate(st)["makespan"] < self.problem.evaluate(current_solution)["makespan"] ): current_solution = st start = [] for j in current_solution.rcpsp_schedule: start_time_j = current_solution.rcpsp_schedule[j]["start_time"] mode_j = ( 1 if j == 1 or j == self.problem.n_jobs + 2 else current_solution.rcpsp_modes[j - 2] ) start += [ ( milp_solver.durations[j], self.problem.mode_details[j][mode_j]["duration"], ) ] for k in milp_solver.variable_per_task[j]: task, mode, time = k if start_time_j == time and mode == mode_j: milp_solver.x[k].start = 1 milp_solver.starts[j].start = start_time_j else: milp_solver.x[k].start = 0 # milp_solver.model.start = start constraints_dict = {} constraints_dict["range_start_time"] = [] max_time = max( [ current_solution.rcpsp_schedule[x]["end_time"] for x in current_solution.rcpsp_schedule ] ) last_jobs = [ x for x in current_solution.rcpsp_schedule if current_solution.rcpsp_schedule[x]["end_time"] >= max_time - 5 ] nb_jobs = self.problem.n_jobs + 2 jobs_to_fix = set( random.sample( current_solution.rcpsp_schedule.keys(), int(self.fraction_to_fix * nb_jobs), ) ) for lj in last_jobs: if lj in jobs_to_fix: jobs_to_fix.remove(lj) for job in jobs_to_fix: start_time_j = current_solution.rcpsp_schedule[job]["start_time"] min_st = max(start_time_j - self.minus_delta, 0) max_st = min(start_time_j + self.plus_delta, max_time) for key in milp_solver.variable_per_task[job]: t = key[2] if t < min_st or t > max_st: constraints_dict["range_start_time"].append( milp_solver.model.addConstr(milp_solver.x[key] == 0) ) milp_solver.model.update() return constraints_dict
def adding_constraint_from_results_store( self, cp_solver: CP_MS_MRCPSP_MZN, child_instance, result_storage: ResultStorage ) -> Iterable[Any]: constraints_dict = {} r = random.random() if r <= 0.2: current_solution, fit = result_storage.get_last_best_solution() elif r <= 0.4: current_solution, fit = result_storage.get_best_solution_fit() elif r <= 0.99: current_solution, fit = result_storage.get_random_best_solution() else: current_solution, fit = result_storage.get_random_solution() print("Fit", fit) current_solution: MS_RCPSPSolution = current_solution max_time = max( [ current_solution.schedule[x]["end_time"] for x in current_solution.schedule ] ) last_jobs = [ x for x in current_solution.schedule if current_solution.schedule[x]["end_time"] >= max_time - 20 ] # last_jobs = [] nb_jobs = self.problem.n_jobs_non_dummy + 2 jobs_to_fix = set( random.sample( current_solution.schedule.keys(), int(self.fraction_to_fix * nb_jobs) ) ) for lj in last_jobs: if lj in jobs_to_fix: jobs_to_fix.remove(lj) list_strings = [] self.employees_position = sorted(self.problem.employees) task_to_fix = set( random.sample( current_solution.schedule.keys(), int(self.fraction_task_to_fix_employee * nb_jobs), ) ) employee_to_not_fix = set( random.sample( range(1, len(self.employees_position) + 1), min(5, int(1.0 * len(self.employees_position))), ) ) employee_usage = { emp: [ task for task in current_solution.employee_usage if emp in current_solution.employee_usage[task] ] for emp in self.problem.employees } employee_usage_max_time = { emp: max( [current_solution.schedule[t]["end_time"] for t in employee_usage[emp]] ) if len(employee_usage[emp]) > 0 else 0 for emp in employee_usage } # employee_usage_time = {emp: sum([current_solution.schedule[t]["end_time"] - # current_solution.schedule[t]["start_time"] # for t in employee_usage[emp]]) # for emp in employee_usage} if False: sorted_employee = list( sorted(employee_usage, key=lambda x: employee_usage_max_time[x]) ) for i in range(int(len(employee_usage) / 4)): index = self.employees_position.index(sorted_employee[i]) + 1 string1 = ( "constraint sum(task in Act)(unit_used[" + str(index) + ", task] >= " + str(int(len(employee_usage[sorted_employee[i]]))) + ";\n" ) for i in range(int(len(employee_usage) / 4)): index = ( self.employees_position.index( sorted_employee[len(sorted_employee) - 1 - i] ) + 1 ) string1 = ( "constraint sum(task in Act)(unit_used[" + str(index) + ", task] <= " + str( int( len( employee_usage[ sorted_employee[len(sorted_employee) - 1 - i] ] ) ) ) + ";\n" ) for i in range(1, len(self.employees_position) + 1): # if i in employee_to_not_fix: # continue for task in task_to_fix: emp = self.employees_position[i - 1] if ( task in current_solution.employee_usage and emp in current_solution.employee_usage[task] and len(current_solution.employee_usage[task][emp]) > 0 ): string1 = ( "constraint unit_used[" + str(i) + "," + str(task) + "] = 1;\n" ) else: string1 = ( "constraint unit_used[" + str(i) + "," + str(task) + "] = 0;\n" ) child_instance.add_string(string1) list_strings += [string1] for job in [self.problem.sink_task]: start_time_j = current_solution.schedule[job]["start_time"] string1 = ( "constraint start[" + str(job) + "] <= " + str(start_time_j) + ";\n" ) list_strings += [string1] child_instance.add_string(string1) for job in jobs_to_fix: start_time_j = current_solution.schedule[job]["start_time"] min_st = max(start_time_j - self.minus_delta, 0) max_st = min(start_time_j + self.plus_delta, max_time) string1 = "constraint start[" + str(job) + "] <= " + str(max_st) + ";\n" string2 = "constraint start[" + str(job) + "] >= " + str(min_st) + ";\n" list_strings += [string1] list_strings += [string2] child_instance.add_string(string1) child_instance.add_string(string2) for job in current_solution.schedule.keys(): if job in jobs_to_fix: continue # start_time_j = current_solution.schedule[job]["start_time"] # min_st = max(start_time_j-100, 0) # max_st = min(start_time_j+100, max_time) # string1 = "constraint start[" + str(job) + "] <= " + str(max_time) + ";\n" # string2 = "constraint start[" + str(job) + "] >= " + str(min_st) + ";\n" # list_strings += [string1] # list_strings += [string2] # child_instance.add_string(string1) # child_instance.add_string(string2) return list_strings
def adding_constraint_from_results_store( self, cp_solver: Union[CP_RCPSP_MZN, CP_MRCPSP_MZN], child_instance, result_storage: ResultStorage, ) -> Iterable[Any]: solution, fit = result_storage.get_best_solution_fit() if "satisfy" in solution.__dict__.keys() and solution.satisfy: return self.other_constraint.adding_constraint_from_results_store( cp_solver, child_instance, result_storage ) ressource_breaks, constraints = get_ressource_breaks( self.problem_calendar, self.problem_no_calendar, solution ) list_strings = [] max_time = max( [solution.rcpsp_schedule[x]["end_time"] for x in solution.rcpsp_schedule] ) tasks = sorted(self.problem_calendar.mode_details.keys()) for r in constraints: for t in constraints[r]: index = tasks.index(t) s = None if isinstance(cp_solver, CP_MRCPSP_MZN): if ( constraints[r][t][0] is not None and constraints[r][t][1] is not None ): s = ( """constraint start[""" + str(index + 1) + """]<=""" + str(constraints[r][t][0]) + " \/ " "start[" "" + str(index + 1) + """]>=""" + str(constraints[r][t][1]) + """;\n""" ) elif ( constraints[r][t][0] is None and constraints[r][t][1] is not None ): s = ( """constraint start[""" + str(index + 1) + """]>=""" + str(constraints[r][t][1]) + """;\n""" ) elif ( constraints[r][t][0] is not None and constraints[r][t][1] is None ): s = ( """constraint start[""" + str(index + 1) + """]<=""" + str(constraints[r][t][0]) + """;\n""" ) elif isinstance(cp_solver, CP_RCPSP_MZN): if ( constraints[r][t][0] is not None and constraints[r][t][1] is not None ): s = ( """constraint s[""" + str(index + 1) + """]<=""" + str(constraints[r][t][0]) + " \/ " "s[" "" + str(index + 1) + """]>=""" + str(constraints[r][t][1]) + """;\n""" ) elif ( constraints[r][t][0] is None and constraints[r][t][1] is not None ): s = ( """constraint s[""" + str(index + 1) + """]>=""" + str(constraints[r][t][1]) + """;\n""" ) elif ( constraints[r][t][0] is not None and constraints[r][t][1] is None ): s = ( """constraint s[""" + str(index + 1) + """]<=""" + str(constraints[r][t][0]) + """;\n""" ) if s is not None: child_instance.add_string(s) list_strings += [s] for r in ressource_breaks: index_ressource = cp_solver.resources_index.index(r) for index in ressource_breaks[r]: if random.random() < 0.1: continue ind = index[0] rq = self.problem_calendar.resources[r][ind] if isinstance(cp_solver, CP_MRCPSP_MZN): s = ( """constraint """ + str(rq) + """>=sum( i in Act ) ( bool2int(start[i] <=""" + str(ind) + """ /\ """ + str(ind) + """< start[i] + adur[i]) * arreq[""" + str(index_ressource + 1) + """,i]);\n""" ) elif isinstance(cp_solver, CP_RCPSP_MZN): s = ( """constraint """ + str(rq) + """>=sum( i in Tasks ) ( bool2int(s[i] <=""" + str(ind) + """ /\ """ + str(ind) + """< s[i] + d[i]) * rr[""" + str(index_ressource + 1) + """,i]);\n""" ) child_instance.add_string(s) list_strings += [s] satisfiable = [ (s, f) for s, f in result_storage.list_solution_fits if "satisfy" in s.__dict__.keys() and s.satisfy ] if len(satisfiable) > 0: res = ResultStorage( list_solution_fits=satisfiable, mode_optim=result_storage.mode_optim ) self.other_constraint.adding_constraint_from_results_store( cp_solver, child_instance, res ) return ["req"] + list_strings
def solve( self, initial_variable: Solution, nb_iteration_max: int, pickle_result=False, pickle_name="tsp", ) -> ResultLS: objective = self.aggreg_from_dict_values( self.evaluator.evaluate(initial_variable)) cur_variable = initial_variable.copy() cur_best_variable = initial_variable.copy() cur_objective = objective cur_best_objective = objective if self.store_solution: store = ResultStorage( list_solution_fits=[(initial_variable, objective)], best_solution=initial_variable.copy(), limit_store=True, nb_best_store=1000, ) else: store = ResultStorage( list_solution_fits=[(initial_variable, objective)], best_solution=initial_variable.copy(), limit_store=True, nb_best_store=1, ) self.restart_handler.best_fitness = objective iteration = 0 while iteration < nb_iteration_max: local_improvement = False global_improvement = False local_move_accepted = False if self.mode_mutation == ModeMutation.MUTATE: nv, move = self.mutator.mutate(cur_variable) objective = self.aggreg_from_dict_values( self.evaluator.evaluate(nv)) elif self.mode_mutation == ModeMutation.MUTATE_AND_EVALUATE: nv, move, objective = self.mutator.mutate_and_compute_obj( cur_variable) objective = self.aggreg_from_dict_values(objective) if self.mode_optim == ModeOptim.MINIMIZATION and objective < cur_objective: accept = True local_improvement = True global_improvement = objective < cur_best_objective elif (self.mode_optim == ModeOptim.MAXIMIZATION and objective > cur_objective): accept = True local_improvement = True global_improvement = objective > cur_best_objective else: r = random.random() fac = 1 if self.mode_optim == ModeOptim.MAXIMIZATION else -1 p = math.exp(fac * (objective - cur_objective) / self.temperature_handler.temperature) accept = p > r local_move_accepted = accept if accept: cur_objective = objective cur_variable = nv # print("iter ", iteration) # print("acceptance ", objective) else: cur_variable = move.backtrack_local_move(nv) # print(move) # print("cur_variable", cur_variable) if self.store_solution: store.add_solution(nv.copy(), objective) if global_improvement: print("iter ", iteration) # print(cur_variable) print("new obj ", objective, " better than ", cur_best_objective) cur_best_objective = objective cur_best_variable = cur_variable.copy() if not self.store_solution: store.add_solution(cur_variable.copy(), objective) self.temperature_handler.next_temperature() # Update the temperature self.restart_handler.update(nv, objective, global_improvement, local_improvement) # Update info in restart handler cur_variable, cur_objective = self.restart_handler.restart( cur_variable, cur_objective) # possibly restart somewhere iteration += 1 if pickle_result and iteration % 20000 == 0: pickle.dump(cur_best_variable, open(pickle_name + ".pk", "wb")) store.finalize() return store
def solve(self, **kwargs) -> ResultStorage: greedy_choice = kwargs.get("greedy_choice", GreedyChoice.MOST_SUCCESSORS) verbose = kwargs.get("verbose", False) current_succ = { k: { "succs": set(self.successors_map[k]["succs"]), "nb": self.successors_map[k]["nb"], } for k in self.successors_map } current_pred = { k: { "succs": set(self.predecessors_map[k]["succs"]), "nb": self.predecessors_map[k]["nb"], } for k in self.predecessors_map } schedule = {} current_ressource_available = self.resources.copy() current_ressource_non_renewable = { nr: self.resources[nr] for nr in self.non_renewable } schedule[1] = {"start_time": 0, "end_time": 0} available_activities = { n for n in current_pred if n not in schedule and current_pred[n]["nb"] == 0 } available_activities.update( {n for n in self.all_activities if n not in current_pred}) for neighbor in current_pred: if 1 in current_pred[neighbor]["succs"]: current_pred[neighbor]["succs"].remove(1) current_pred[neighbor]["nb"] -= 1 if current_pred[neighbor]["nb"] == 0: available_activities.add(neighbor) if verbose: print(current_pred) queue = [] current_time = 0 perm = [] while len(schedule) < self.n_jobs + 2: if verbose: print(len(schedule)) print("available activities : ", available_activities) possible_activities = [ n for n in available_activities if all(self.mode_details[n][self.modes_dict[n]][r] <= current_ressource_available[r] for r in current_ressource_available) ] if verbose: print("Ressources : ", current_ressource_available) while len(possible_activities) > 0: if greedy_choice == GreedyChoice.MOST_SUCCESSORS: next_activity = max(possible_activities, key=lambda x: current_succ[x]["nb"]) if greedy_choice == GreedyChoice.SAMPLE_MOST_SUCCESSORS: prob = np.array([ current_succ[possible_activities[i]]["nb"] for i in range(len(possible_activities)) ]) s = np.sum(prob) if s != 0: prob = prob / s else: prob = (1.0 / len(possible_activities) * np.ones( (len(possible_activities)))) next_activity = np.random.choice(np.arange( 0, len(possible_activities)), size=1, p=prob)[0] next_activity = possible_activities[next_activity] if greedy_choice == GreedyChoice.FASTEST: next_activity = min( possible_activities, key=lambda x: self.mode_details[x][self.modes_dict[x]][ "duration"], ) if greedy_choice == GreedyChoice.TOTALLY_RANDOM: next_activity = random.choice(possible_activities) available_activities.remove(next_activity) perm += [next_activity - 2] schedule[next_activity] = {} schedule[next_activity]["start_time"] = current_time schedule[next_activity]["end_time"] = ( current_time + self.mode_details[next_activity][ self.modes_dict[next_activity]]["duration"]) push(queue, (schedule[next_activity]["end_time"], next_activity, "end_")) for r in self.resources: current_ressource_available[r] -= self.mode_details[ next_activity][self.modes_dict[next_activity]][r] if r in current_ressource_non_renewable: current_ressource_non_renewable[ r] -= self.mode_details[next_activity][ self.modes_dict[next_activity]][r] if verbose: print( current_time, "Current ressource available : ", current_ressource_available, ) possible_activities = [ n for n in available_activities if all(self.mode_details[n][self.modes_dict[n]][r] <= current_ressource_available[r] for r in current_ressource_available) ] current_time, activity, descr = pop(queue) for neighbor in current_pred: if activity in current_pred[neighbor]["succs"]: current_pred[neighbor]["succs"].remove(activity) current_pred[neighbor]["nb"] -= 1 if current_pred[neighbor]["nb"] == 0: available_activities.add(neighbor) for r in self.resources: if r not in current_ressource_non_renewable: current_ressource_available[r] += self.mode_details[ activity][self.modes_dict[activity]][r] if verbose: print("Final Time ", current_time) sol = RCPSPSolution( problem=self.rcpsp_model, rcpsp_permutation=perm[:-1], rcpsp_schedule=schedule, rcpsp_modes=[self.modes_dict[i + 2] for i in range(self.n_jobs)], rcpsp_schedule_feasible=True, ) result_storage = ResultStorage( list_solution_fits=[(sol, self.aggreg_from_sol(sol))], best_solution=sol, mode_optim=self.params_objective_function.sense_function, ) return result_storage
def solve(self, **kwargs) -> ResultStorage: greedy_choice = kwargs.get("greedy_choice", GreedyChoice.MOST_SUCCESSORS) verbose = kwargs.get("verbose", False) current_succ = { k: { "succs": set(self.successors_map[k]["succs"]), "nb": self.successors_map[k]["nb"], } for k in self.successors_map } current_pred = { k: { "succs": set(self.predecessors_map[k]["succs"]), "nb": self.predecessors_map[k]["nb"], } for k in self.predecessors_map } schedule = {} partial_solution: PartialSolution = kwargs.get("partial_solution", None) # TODO continue on this... the mode partial solution will probaby override the self.modes_dict at some point. if partial_solution is not None: if partial_solution.start_times is not None: starting_time = 0 for task in partial_solution.start_times: schedule[task] = { "start_time": partial_solution.start_times[task] } starting_time = max(starting_time, partial_solution.start_times[task]) if partial_solution.end_times is not None: for task in partial_solution.end_times: if task in schedule: schedule[task][ "end_time"] = partial_solution.end_times[task] current_ressource_available = { r: list(self.resources[r]) + [self.resources[r][-1]] * 100 for r in self.resources } current_ressource_non_renewable = { nr: list(self.resources[nr]) + [self.resources[nr][-1]] * 100 for nr in self.non_renewable } if 1 not in schedule: schedule[1] = {"start_time": 0, "end_time": 0} available_activities = { n for n in current_pred if n not in schedule and current_pred[n]["nb"] == 0 } available_activities.update( {n for n in self.all_activities if n not in current_pred}) for neighbor in current_pred: if 1 in current_pred[neighbor]["succs"]: current_pred[neighbor]["succs"].remove(1) current_pred[neighbor]["nb"] -= 1 if current_pred[neighbor]["nb"] == 0: available_activities.add(neighbor) if verbose: print(current_pred) queue = [] current_time = 0 perm = [] while len(schedule) < self.n_jobs + 2: if True: print(len(schedule), current_time) print("available activities : ", available_activities) possible_activities = [ n for n in available_activities if all( self.mode_details[n][self.modes_dict[n]][r] <= current_ressource_available[r][min( time, len(current_ressource_available[r]) - 1)] for r in current_ressource_available for time in range( current_time, current_time + self.mode_details[n][self.modes_dict[n]]["duration"], )) ] if verbose: print("Ressources : ", current_ressource_available) while len(possible_activities) > 0: if greedy_choice == GreedyChoice.MOST_SUCCESSORS: next_activity = max(possible_activities, key=lambda x: current_succ[x]["nb"]) if greedy_choice == GreedyChoice.SAMPLE_MOST_SUCCESSORS: prob = np.array([ current_succ[possible_activities[i]]["nb"] for i in range(len(possible_activities)) ]) s = np.sum(prob) if s != 0: prob = prob / s else: prob = (1.0 / len(possible_activities) * np.ones( (len(possible_activities)))) next_activity = np.random.choice(np.arange( 0, len(possible_activities)), size=1, p=prob)[0] next_activity = possible_activities[next_activity] if greedy_choice == GreedyChoice.FASTEST: next_activity = min( possible_activities, key=lambda x: self.mode_details[x][self.modes_dict[x]][ "duration"], ) if greedy_choice == GreedyChoice.TOTALLY_RANDOM: next_activity = random.choice(possible_activities) available_activities.remove(next_activity) perm += [next_activity - 2] schedule[next_activity] = {} schedule[next_activity]["start_time"] = current_time schedule[next_activity]["end_time"] = ( current_time + self.mode_details[next_activity][ self.modes_dict[next_activity]]["duration"]) push(queue, (schedule[next_activity]["end_time"], next_activity, "end_")) mode = self.modes_dict[next_activity] duration = self.mode_details[next_activity][mode]["duration"] for r in self.resources: for t in range(current_time, current_time + duration): current_ressource_available[r][t] -= self.mode_details[ next_activity][mode][r] if r in current_ressource_non_renewable: current_ressource_non_renewable[r][ t] -= self.mode_details[next_activity][mode][r] possible_activities = [ n for n in available_activities if all(self.mode_details[n][self.modes_dict[n]][r] <= current_ressource_available[r][time] for r in current_ressource_available for time in range( current_time, current_time + self.mode_details[n][ self.modes_dict[n]]["duration"] + 1, )) ] if len(queue) > 0: current_time, activity, descr = pop(queue) for neighbor in current_pred: if activity in current_pred[neighbor]["succs"]: current_pred[neighbor]["succs"].remove(activity) current_pred[neighbor]["nb"] -= 1 if current_pred[neighbor]["nb"] == 0: available_activities.add(neighbor) else: current_time += 1 if verbose: print("Final Time ", current_time) sol = RCPSPSolution( problem=self.rcpsp_model, rcpsp_permutation=perm[:-1], rcpsp_schedule=schedule, rcpsp_modes=[self.modes_dict[i + 2] for i in range(self.n_jobs)], rcpsp_schedule_feasible=True, ) result_storage = ResultStorage( list_solution_fits=[(sol, self.aggreg_from_sol(sol))], best_solution=sol, mode_optim=self.params_objective_function.sense_function, ) return result_storage
def solve(self, parameters_cp: ParametersCP, nb_iteration_lns: int, nb_iteration_no_improvement: Optional[int] = None, max_time_seconds: Optional[int] = None, skip_first_iteration: bool = False, **args) -> ResultStorage: sense = self.params_objective_function.sense_function if max_time_seconds is None: max_time_seconds = 3600 * 24 # One day if nb_iteration_no_improvement is None: nb_iteration_no_improvement = 2 * nb_iteration_lns current_nb_iteration_no_improvement = 0 deb_time = time.time() if not skip_first_iteration: store_lns = self.initial_solution_provider.get_starting_solution() store_lns = self.post_process_solution.build_other_solution( store_lns) store_with_all = ResultStorage(list(store_lns.list_solution_fits), mode_optim=store_lns.mode_optim) init_solution, objective = store_lns.get_best_solution_fit() best_solution = init_solution.copy() satisfy = self.problem_calendar.satisfy(init_solution) best_objective = objective else: best_objective = (float("inf") if sense == ModeOptim.MINIMIZATION else -float("inf")) best_solution = None constraint_iterable = {"empty": []} store_lns = None store_with_all = None constraint_to_keep = set() for iteration in range(nb_iteration_lns): try: print( "Best feasible solution ", max([ f for s, f in store_with_all.list_solution_fits if "satisfy" in s.__dict__.keys() and s.satisfy ]), ) except: print("No Feasible solution yet") with self.cp_solver.instance.branch() as child: if iteration == 0 and not skip_first_iteration or iteration >= 1: for c in constraint_to_keep: child.add_string(c) constraint_iterable = ( self.constraint_handler. adding_constraint_from_results_store( cp_solver=self.cp_solver, child_instance=child, result_storage=store_lns, )) if constraint_iterable[0] == "req": constraint_to_keep.update( set([c for c in constraint_iterable[1:]])) if True: if iteration == 0: result = child.solve( timeout=timedelta( seconds=parameters_cp.TimeLimit_iter0), intermediate_solutions=parameters_cp. intermediate_solution, ) else: result = child.solve( timeout=timedelta(seconds=parameters_cp.TimeLimit), intermediate_solutions=parameters_cp. intermediate_solution, ) result_store = self.cp_solver.retrieve_solutions( result, parameters_cp=parameters_cp) if len(result_store.list_solution_fits) > 0: bsol, fit = result_store.get_best_solution_fit() result_store = self.post_process_solution.build_other_solution( result_store) bsol, fit = result_store.get_best_solution_fit() if sense == ModeOptim.MAXIMIZATION and fit >= best_objective: if fit > best_objective: current_nb_iteration_no_improvement = 0 else: current_nb_iteration_no_improvement += 1 best_solution = bsol best_objective = fit elif sense == ModeOptim.MAXIMIZATION: current_nb_iteration_no_improvement += 1 elif sense == ModeOptim.MINIMIZATION and fit <= best_objective: if fit < best_objective: current_nb_iteration_no_improvement = 0 else: current_nb_iteration_no_improvement += 1 best_solution = bsol best_objective = fit elif sense == ModeOptim.MINIMIZATION: current_nb_iteration_no_improvement += 1 if skip_first_iteration and iteration == 0: store_lns = result_store store_with_all = ResultStorage( list_solution_fits=list( store_lns.list_solution_fits), mode_optim=store_lns.mode_optim, ) store_lns = result_store for s, f in store_lns.list_solution_fits: store_with_all.list_solution_fits += [(s, f)] for s, f in store_with_all.list_solution_fits: if s.satisfy: store_lns.list_solution_fits += [(s, f)] else: current_nb_iteration_no_improvement += 1 if (skip_first_iteration and result.status == Status.OPTIMAL_SOLUTION and iteration == 0 and best_solution.satisfy): break else: current_nb_iteration_no_improvement += 1 if time.time() - deb_time > max_time_seconds: break if current_nb_iteration_no_improvement > nb_iteration_no_improvement: break return store_with_all
def adding_constraint_from_results_store( self, cp_solver: Union[CP_MS_MRCPSP_MZN], child_instance, result_storage: ResultStorage, ) -> Iterable[Any]: solution, fit = result_storage.get_best_solution_fit() solution: MS_RCPSPSolution = solution if "satisfy" in solution.__dict__.keys() and solution.satisfy: return self.other_constraint.adding_constraint_from_results_store( cp_solver, child_instance, ResultStorage( list_solution_fits=[(solution, fit)], mode_optim=result_storage.mode_optim, ), ) ressource_breaks, constraints, constraints_employee = get_ressource_breaks( self.problem_calendar, solution) list_strings = [] max_time = max( [solution.schedule[x]["end_time"] for x in solution.schedule]) tasks = sorted(self.problem_calendar.mode_details.keys()) for r in constraints: for t in constraints[r]: index = tasks.index(t) s = None if isinstance(cp_solver, CP_MS_MRCPSP_MZN): if (constraints[r][t][0] is not None and constraints[r][t][1] is not None): s = ("""constraint start[""" + str(index + 1) + """]<=""" + str(constraints[r][t][0]) + " \/ " "start[" "" + str(index + 1) + """]>=""" + str(constraints[r][t][1]) + """;\n""") elif (constraints[r][t][0] is None and constraints[r][t][1] is not None): s = ("""constraint start[""" + str(index + 1) + """]>=""" + str(constraints[r][t][1]) + """;\n""") elif (constraints[r][t][0] is not None and constraints[r][t][1] is None): s = ("""constraint start[""" + str(index + 1) + """]<=""" + str(constraints[r][t][0]) + """;\n""") if s is not None: child_instance.add_string(s) list_strings += [s] # for r in ressource_breaks: # index_ressource = cp_solver.resources_index.index(r) # for t in range(len(self.problem_calendar.resources[r])): # rq = self.problem_calendar.resources[r][t] # if t<max_time: # if isinstance(cp_solver, CP_MRCPSP_MZN): # s = """constraint """ + str(rq) + """>=sum( i in Act ) ( # bool2int(start[i] <=""" + str(t) + """ /\ """ + str(t) \ # + """< start[i] + adur[i]) * arreq[""" + str(index_ressource + 1) + """,i]);\n""" # elif isinstance(cp_solver, CP_RCPSP_MZN): # s = """constraint """ + str(rq) + """>=sum( i in Tasks ) ( # bool2int(s[i] <=""" + str(t) + """ /\ """ + str(t) \ # + """< s[i] + d[i]) * rr[""" + str(index_ressource + 1) + """,i]);\n""" # child_instance.add_string(s) # list_strings += [s] for r in ressource_breaks: for index in ressource_breaks[r]: if random.random() < 0.6: continue ind = index[0] if r in self.problem_calendar.resources_availability: index_ressource = cp_solver.resources_index.index(r) rq = self.problem_calendar.resources_availability[r][ind] # if random.random() <= 0.3: # continue s = ("""constraint """ + str(rq) + """>=sum( i in Act ) ( bool2int(start[i] <=""" + str(ind) + """ /\ """ + str(ind) + """< start[i] + adur[i]) * arreq[""" + str(index_ressource + 1) + """,i]);\n""") child_instance.add_string(s) list_strings += [s] if r in self.problem_calendar.employees: index_ressource = cp_solver.employees_position.index(r) rq = int(self.problem_calendar.employees[r]. calendar_employee[ind]) # if random.random() <= 0.3: # continue s = ("""constraint """ + str(rq) + """>=sum( i in Act ) ( bool2int(start[i] <=""" + str(ind) + """ /\ """ + str(ind) + """< start[i] + adur[i]) * unit_used[""" + str(index_ressource + 1) + """,i]);\n""") child_instance.add_string(s) list_strings += [s] satisfiable = [(s, f) for s, f in result_storage.list_solution_fits if "satisfy" in s.__dict__.keys() and s.satisfy] if len(satisfiable) > 0: res = ResultStorage(list_solution_fits=satisfiable, mode_optim=result_storage.mode_optim) self.other_constraint.adding_constraint_from_results_store( cp_solver, child_instance, res) return ["req"] + list_strings
def compute_schedule_from_priority_list(self, permutation_jobs: List[int], modes_dict: Dict[int, int]): current_pred = { k: { "succs": set(self.immediate_predecessors[k]), "nb": len(self.immediate_predecessors[k]), } for k in self.immediate_predecessors } schedule = {} current_ressource_available = self.resources.copy() current_ressource_non_renewable = { nr: self.resources[nr] for nr in self.non_renewable } schedule[1] = {"start_time": 0, "end_time": 0} available_activities = { n for n in current_pred if n not in schedule and current_pred[n]["nb"] == 0 } available_activities.update( {n for n in self.all_activities if n not in current_pred}) for neighbor in self.immediate_successors[1]: if 1 in current_pred[neighbor]["succs"]: current_pred[neighbor]["succs"].remove(1) current_pred[neighbor]["nb"] -= 1 if current_pred[neighbor]["nb"] == 0: available_activities.add(neighbor) permutation_jobs.remove(1) queue = [] current_time = 0 perm = [] while len(schedule) < self.n_jobs + 2: possible_activities = [ n for n in available_activities if all(self.mode_details[n][modes_dict[n]][r] <= current_ressource_available[r] for r in current_ressource_available) ] while len(possible_activities) > 0: next_activity = min(possible_activities, key=lambda x: permutation_jobs.index(x)) available_activities.remove(next_activity) perm += [next_activity - 2] schedule[next_activity] = {} schedule[next_activity]["start_time"] = current_time schedule[next_activity]["end_time"] = ( current_time + self.mode_details[next_activity][ modes_dict[next_activity]]["duration"]) permutation_jobs.remove(next_activity) push(queue, (schedule[next_activity]["end_time"], next_activity, "end_")) for r in self.resources: current_ressource_available[r] -= self.mode_details[ next_activity][modes_dict[next_activity]][r] if r in current_ressource_non_renewable: current_ressource_non_renewable[ r] -= self.mode_details[next_activity][ modes_dict[next_activity]][r] possible_activities = [ n for n in available_activities if all(self.mode_details[n][modes_dict[n]][r] <= current_ressource_available[r] for r in current_ressource_available) ] current_time, activity, descr = pop(queue) for neighbor in self.immediate_successors[activity]: if activity in current_pred[neighbor]["succs"]: current_pred[neighbor]["succs"].remove(activity) current_pred[neighbor]["nb"] -= 1 if current_pred[neighbor]["nb"] == 0: available_activities.add(neighbor) for r in self.resources: if r not in current_ressource_non_renewable: current_ressource_available[r] += self.mode_details[ activity][modes_dict[activity]][r] sol = RCPSPSolution( problem=self.rcpsp_model, rcpsp_permutation=perm[:-1], rcpsp_schedule=schedule, rcpsp_modes=[modes_dict[i + 1] for i in range(self.n_jobs)], rcpsp_schedule_feasible=True, ) result_storage = ResultStorage( list_solution_fits=[(sol, self.aggreg_from_sol(sol))], best_solution=sol, mode_optim=self.params_objective_function.sense_function, ) return result_storage
def retrieve_solutions( self, result, parameters_cp: ParametersCP = ParametersCP.default()): intermediate_solutions = parameters_cp.intermediate_solution best_solution = None best_makespan = -float("inf") list_solutions_fit = [] starts = [] mruns = [] units_used = [] if intermediate_solutions: for i in range(len(result)): if isinstance(result[i], MS_RCPSPSolCP): starts += [result[i].dict["start"]] mruns += [result[i].dict["mrun"]] units_used += [result[i].dict["unit_used"]] else: starts += [result[i, "start"]] mruns += [result[i, "mrun"]] units_used += [result[i, "unit_used"]] else: if isinstance(result, MS_RCPSPSolCP): starts += [result.dict["start"]] mruns += [result.dict["mrun"]] units_used += [result.dict["unit_used"]] else: starts += [result["start"]] mruns += [result["mrun"]] units_used += [result["unit_used"]] # array_skill = result["array_skills_required"] for start_times, mrun, unit_used in zip(starts, mruns, units_used): modes = [] usage = {} for i in range(len(mrun)): if (mrun[i] and (self.modeindex_map[i + 1]["task"] != 1) and (self.modeindex_map[i + 1]["task"] != self.rcpsp_model.n_jobs_non_dummy + 2)): modes.append(self.modeindex_map[i + 1]["original_mode_index"]) elif (self.modeindex_map[i + 1]["task"] == 1) or (self.modeindex_map[i + 1]["task"] == self.rcpsp_model.n_jobs_non_dummy + 2): modes.append(1) for w in range(len(unit_used)): for task in range(len(unit_used[w])): if unit_used[w][task] == 1: task_id = task + 1 mode = modes[task_id - 1] skills_needed = set([ s # , self.rcpsp_model.mode_details[task_id][mode][s]) for s in self.rcpsp_model.skills_set if s in self.rcpsp_model.mode_details[task_id][mode] and self.rcpsp_model.mode_details[task_id][mode][s] > 0 ]) skills_worker = set([ s # self.rcpsp_model.employees[self.employees_position[w]].dict_skill[s].skill_value) for s in self.rcpsp_model.employees[ self.employees_position[w]].dict_skill if self.rcpsp_model.employees[ self.employees_position[w]].dict_skill[s]. skill_value > 0 ]) intersection = skills_needed.intersection( skills_worker) if len(intersection) > 0: if task_id not in usage: usage[task_id] = {} usage[task_id][ self.employees_position[w]] = intersection rcpsp_schedule = {} for i in range(len(start_times)): rcpsp_schedule[i + 1] = { "start_time": start_times[i], "end_time": start_times[i] + self.rcpsp_model.mode_details[i + 1][modes[i]]["duration"], } sol = MS_RCPSPSolution( problem=self.rcpsp_model, modes={i + 1: modes[i] for i in range(len(modes))}, schedule=rcpsp_schedule, employee_usage=usage, ) objective = self.aggreg_from_dict_values( self.rcpsp_model.evaluate(sol)) if objective > best_makespan: best_makespan = objective best_solution = sol.copy() list_solutions_fit += [(sol, objective)] result_storage = ResultStorage( list_solution_fits=list_solutions_fit, best_solution=best_solution, mode_optim=self.params_objective_function.sense_function, limit_store=False, ) return result_storage
def solve(self, **kwargs): # Define the statistics to collect at each generation stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("avg", np.mean, axis=0) stats.register("std", np.std, axis=0) stats.register("min", np.min, axis=0) stats.register("max", np.max, axis=0) logbook = tools.Logbook() logbook.header = "gen", "evals", "std", "min", "avg", "max" # Initialise the population (here at random) pop = self._toolbox.population() invalid_ind = [ind for ind in pop if not ind.fitness.valid] fitnesses = self._toolbox.map(self._toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit # Compile statistics about the population record = stats.compile(pop) logbook.record(gen=0, evals=len(invalid_ind), **record) print(logbook.stream) # Begin the generational process ngen = int(self._max_evals / self._pop_size) print("ngen:", ngen) for gen in range(1, ngen): offspring = algorithms.varAnd( pop, self._toolbox, self._crossover_rate, self._mut_rate ) # Evaluate the individuals with an invalid fitness invalid_ind = [ind for ind in offspring if not ind.fitness.valid] fitnesses = self._toolbox.map(self._toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit # Select the next generation population from parents and offspring pop = self._toolbox.select(pop + offspring, self._pop_size) # Compile statistics about the new population record = stats.compile(pop) logbook.record(gen=gen, evals=len(invalid_ind), **record) print(logbook.stream) sols = [] for s in pop: s_pure_int = [i for i in s] kwargs = {self._encoding_variable_name: s_pure_int, "problem": self.problem} problem_sol = self.problem.get_solution_type()(**kwargs) fits = self.evaluate_sol(problem_sol) # fits = TupleFitness(np.array(s.fitness.values), len(s.fitness.values)) sols.append((problem_sol, fits)) rs = ResultStorage( list_solution_fits=sols, best_solution=None, mode_optim=self.params_objective_function.sense_function, ) return rs