def __init__( self, problem: Problem, cp_solver: CPSolver, initial_solution_provider: InitialSolution, constraint_handler: ConstraintHandler, post_process_solution: PostProcessSolution = None, params_objective_function: ParamsObjectiveFunction = None, ): self.problem = problem self.cp_solver = cp_solver self.initial_solution_provider = initial_solution_provider self.constraint_handler = constraint_handler self.post_process_solution = post_process_solution if self.post_process_solution is None: self.post_process_solution = TrivialPostProcessSolution() self.params_objective_function = params_objective_function ( self.aggreg_from_sol, self.aggreg_dict, self.params_objective_function, ) = build_aggreg_function_and_params_objective( problem=self.problem, params_objective_function=self.params_objective_function, )
def __init__( self, rcpsp_model: MultiModeRCPSPModel, lp_solver=LP_RCPSP_Solver.CBC, params_objective_function: ParamsObjectiveFunction = None, **kwargs ): self.rcpsp_model = rcpsp_model self.model: gurobi.Model = None self.lp_solver = CBC if lp_solver == LP_RCPSP_Solver.GRB: self.lp_solver = GRB elif lp_solver == LP_RCPSP_Solver.CBC: self.lp_solver = CBC self.variable_decision = {} self.constraints_dict = {} self.constraints_dict["lns"] = [] ( self.aggreg_from_sol, self.aggreg_dict, self.params_objective_function, ) = build_aggreg_function_and_params_objective( problem=self.rcpsp_model, params_objective_function=params_objective_function, )
def __init__(self, rcpsp_model: RCPSPModel, params_objective_function: ParamsObjectiveFunction = None, **kwargs): self.rcpsp_model = rcpsp_model self.resources = rcpsp_model.resources self.non_renewable = rcpsp_model.non_renewable_resources self.n_jobs = rcpsp_model.n_jobs self.mode_details = rcpsp_model.mode_details self.graph = rcpsp_model.compute_graph() self.nx_graph: nx.DiGraph = self.graph.to_networkx() self.successors_map = {} self.predecessors_map = {} # successors = nx.dfs_successors(self.nx_graph, 1, self.n_jobs+2) successors = { n: nx.algorithms.descendants(self.nx_graph, n) for n in self.nx_graph.nodes() } self.source = 1 self.sink = self.n_jobs + 2 self.all_activities = set(range(1, self.n_jobs + 3)) for k in successors: self.successors_map[k] = { "succs": successors[k], "nb": len(successors[k]) } predecessors = { n: nx.algorithms.ancestors(self.nx_graph, n) for n in self.nx_graph.nodes() } for k in predecessors: self.predecessors_map[k] = { "succs": predecessors[k], "nb": len(predecessors[k]), } ( self.aggreg_from_sol, self.aggreg_from_dict, self.params_objective_function, ) = build_aggreg_function_and_params_objective( problem=self.rcpsp_model, params_objective_function=params_objective_function, ) if isinstance(self.rcpsp_model, (MultiModeRCPSPModel, RCPSPModelCalendar)): solver = CP_MRCPSP_MZN_MODES(self.rcpsp_model, cp_solver_name=CPSolverName.CHUFFED) params_cp = ParametersCP.default() params_cp.time_limit = 1 params_cp.pool_solutions = 10000 params_cp.nr_solutions = 1 # params_cp.nr_solutions = float("inf") params_cp.all_solutions = False result_storage = solver.solve(parameters_cp=params_cp) one_mode_setting = result_storage[0] self.modes_dict = {} for i in range(len(one_mode_setting)): self.modes_dict[i + 1] = one_mode_setting[i] else: self.modes_dict = {t: 1 for t in self.mode_details}
def __init__(self, rcpsp_model: MS_RCPSPModel, cp_solver_name: CPSolverName = CPSolverName.CHUFFED, params_objective_function: ParamsObjectiveFunction = None, **kwargs): self.rcpsp_model = rcpsp_model self.instance: Instance = None self.cp_solver_name = cp_solver_name self.key_decision_variable = [ "start", "mrun", ] # For now, I've put the var names of the CP model (not the rcpsp_model) ( self.aggreg_sol, self.aggreg_from_dict_values, self.params_objective_function, ) = build_aggreg_function_and_params_objective( self.rcpsp_model, params_objective_function=params_objective_function) self.calendar = True if isinstance(self.rcpsp_model, RCPSPModelCalendar): self.calendar = True self.one_ressource_per_task = kwargs.get("one_ressource_per_task", False) self.resources_index = None
def __init__(self, rcpsp_model: MultiModeRCPSPModel, params_objective_function: ParamsObjectiveFunction = None, **kwargs): self.rcpsp_model = rcpsp_model ( self.aggreg_sol, self.aggreg_from_dict_values, self.params_objective_function, ) = build_aggreg_function_and_params_objective( self.rcpsp_model, params_objective_function=params_objective_function)
def __init__(self, model: Union[RCPSPModel, MS_RCPSPModel], params_objective_function: ParamsObjectiveFunction = None, ls_solver: LS_SOLVER = LS_SOLVER.SA, **args): self.model = model ( self.aggreg_from_sol, self.aggreg_dict, self.params_objective_function, ) = build_aggreg_function_and_params_objective( problem=self.model, params_objective_function=params_objective_function) self.ls_solver = ls_solver
def __init__(self, model: Union[MS_RCPSPModel, MS_RCPSPModel_Variant], method, params_objective_function: ParamsObjectiveFunction = None, **args): self.model = model self.model_rcpsp = model.build_multimode_rcpsp_calendar_representative( ) self.method = method self.args_solve = args ( self.aggreg_from_sol, self.aggreg_dict, self.params_objective_function, ) = build_aggreg_function_and_params_objective( problem=self.model, params_objective_function=params_objective_function) self.args_solve[ "params_objective_function"] = self.params_objective_function
def __init__(self, rcpsp_model: MS_RCPSPModel, lp_solver: MilpSolverName = MilpSolverName.CBC, params_objective_function: ParamsObjectiveFunction = None, **kwargs): self.rcpsp_model = rcpsp_model self.model: Model = None self.lp_solver = lp_solver self.variable_decision = {} self.constraints_dict = {} self.constraints_dict["lns"] = [] ( self.aggreg_from_sol, self.aggreg_dict, self.params_objective_function, ) = build_aggreg_function_and_params_objective( problem=self.rcpsp_model, params_objective_function=params_objective_function, )
def __init__( self, rcpsp_model: RCPSPModel, cp_solver_name: CPSolverName = CPSolverName.CHUFFED, params_objective_function: ParamsObjectiveFunction = None, ): self.rcpsp_model = rcpsp_model self.instance: Instance = None self.cp_solver_name = cp_solver_name self.key_decision_variable = [ "start", "mrun", ] # For now, I've put the var names of the CP model (not the rcpsp_model) ( self.aggreg_sol, self.aggreg_from_dict_values, self.params_objective_function, ) = build_aggreg_function_and_params_objective( self.rcpsp_model, params_objective_function=params_objective_function )
def __init__( self, problem: Problem, encodings: Union[List[str], List[Dict[str, Any]]] = None, mutations: Optional[Union[List[Mutation], List[DeapMutation]]] = None, crossovers: Optional[List[DeapCrossover]] = None, selections: Optional[List[DeapSelection]] = None, objective_handling: Optional[ObjectiveHandling] = None, objectives: Optional[Union[str, List[str]]] = None, objective_weights: Optional[List[float]] = None, pop_size: int = None, max_evals: int = None, sub_evals: List[int] = None, mut_rate: float = None, crossover_rate: float = None, tournament_size: float = None, deap_verbose: bool = None, ): self.problem = problem self.encodings = encodings self.mutations = mutations self.crossovers = crossovers self.selections = selections self.objective_handling = objective_handling self.objectives = objectives self.objective_weights = objective_weights self.pop_size = pop_size self.max_evals = max_evals self.sub_evals = sub_evals self.mut_rate = mut_rate self.crossover_rate = crossover_rate self.tournament_size = tournament_size self.deap_verbose = deap_verbose ( self.aggreg_from_sol, self.aggreg_dict, self.params_objective_function, ) = build_aggreg_function_and_params_objective( problem=self.problem, params_objective_function=None)
def __init__( self, problem: Problem, mutation: Union[Mutation, DeapMutation] = None, crossover: DeapCrossover = None, selection: DeapSelection = None, encoding: Optional[Union[str, Dict[str, Any]]] = None, objective_handling: Optional[ObjectiveHandling] = None, objectives: Optional[Union[str, List[str]]] = None, objective_weights: Optional[List[float]] = None, pop_size: int = None, max_evals: int = None, mut_rate: float = None, crossover_rate: float = None, tournament_size: float = None, deap_verbose: bool = None, ): self._default_crossovers = { TypeAttribute.LIST_BOOLEAN: DeapCrossover.CX_UNIFORM, TypeAttribute.LIST_INTEGER: DeapCrossover.CX_ONE_POINT, TypeAttribute.LIST_INTEGER_SPECIFIC_ARRITY: DeapCrossover.CX_ONE_POINT, TypeAttribute.PERMUTATION: DeapCrossover.CX_UNIFORM_PARTIALY_MATCHED, } self._default_mutations = { TypeAttribute.LIST_BOOLEAN: DeapMutation.MUT_FLIP_BIT, TypeAttribute.LIST_INTEGER: DeapMutation.MUT_UNIFORM_INT, TypeAttribute.LIST_INTEGER_SPECIFIC_ARRITY: DeapMutation.MUT_UNIFORM_INT, TypeAttribute.PERMUTATION: DeapMutation.MUT_SHUFFLE_INDEXES, } self._default_selection = DeapSelection.SEL_TOURNAMENT self.problem = problem if pop_size is not None: self._pop_size = pop_size else: self._pop_size = 100 if max_evals is not None: self._max_evals = max_evals else: self._max_evals = 100 * self._pop_size print( "No value specified for max_evals. Using the default 10*pop_size - This should really be set carefully" ) if mut_rate is not None: self._mut_rate = mut_rate else: self._mut_rate = 0.1 if crossover_rate is not None: self._crossover_rate = crossover_rate else: self._crossover_rate = 0.9 self.problem = problem if tournament_size is not None: self._tournament_size = tournament_size else: self._tournament_size = 0.2 # as a percentage of the population if deap_verbose is not None: self._deap_verbose = deap_verbose else: self._deap_verbose = True # set encoding register_solution: EncodingRegister = problem.get_attribute_register() self._encoding_name = None self._encoding_variable_name = None if encoding is not None and isinstance(encoding, str): # check name specified is in problem register print(encoding) if encoding in register_solution.dict_attribute_to_type.keys(): self._encoding_name = encoding self._encoding_variable_name = register_solution.dict_attribute_to_type[ self._encoding_name]["name"] self._encoding_type = register_solution.dict_attribute_to_type[ self._encoding_name]["type"][0] self.n = register_solution.dict_attribute_to_type[ self._encoding_name]["n"] if self._encoding_type == TypeAttribute.LIST_INTEGER: self.arrity = register_solution.dict_attribute_to_type[ self._encoding_name]["arrity"] self.arrities = [self.arrity for i in range(self.n)] else: self.arrity = None if self._encoding_type == TypeAttribute.LIST_INTEGER_SPECIFIC_ARRITY: self.arrities = register_solution.dict_attribute_to_type[ self._encoding_name]["arrities"] # else: # self.arrities = None if encoding is not None and isinstance(encoding, Dict): # check there is a type key and a n key if ("name" in encoding.keys() and "type" in encoding.keys() and "n" in encoding.keys()): self._encoding_name = "custom" self._encoding_variable_name = encoding["name"] self._encoding_type = encoding["type"][0] self.n = encoding["n"] if "arrity" in encoding.keys(): self.arrity = encoding["arrity"] self.arrities = [self.arrity for i in range(self.n)] if "arrities" in encoding.keys(): self.arrities = register_solution.dict_attribute_to_type[ self._encoding_name]["arrities"] else: print( "Erroneous encoding provided as input (encoding name not matching encoding of problem or custom " "definition not respecting encoding dict entry format, trying to use default one instead" ) if self._encoding_name is None: if len(register_solution.dict_attribute_to_type.keys()) == 0: raise Exception( "An encoding of type TypeAttribute should be specified or at least 1 TypeAttribute " "should be defined in the RegisterSolution of your Problem" ) print(register_solution.dict_attribute_to_type) print(register_solution.dict_attribute_to_type.keys()) self._encoding_name = list( register_solution.dict_attribute_to_type.keys())[0] self._encoding_variable_name = register_solution.dict_attribute_to_type[ self._encoding_name]["name"] self._encoding_type = register_solution.dict_attribute_to_type[ self._encoding_name]["type"][ 0] # TODO : while it's usually a list we could also have a unique value(not a list) self.n = register_solution.dict_attribute_to_type[ self._encoding_name]["n"] if self._encoding_type == TypeAttribute.LIST_INTEGER: self.arrity = register_solution.dict_attribute_to_type[ self._encoding_name]["arrity"] self.arrities = [self.arrity for i in range(self.n)] else: self.arrity = None if self._encoding_type == TypeAttribute.LIST_INTEGER_SPECIFIC_ARRITY: self.arrities = register_solution.dict_attribute_to_type[ self._encoding_name]["arrities"] # else: # self.arrities = None if self._encoding_type == TypeAttribute.LIST_BOOLEAN: self.arrity = 2 self.arities = [2 for i in range(self.n)] print("Encoding used by the GA: " + self._encoding_name + ": " + str(self._encoding_type) + " of length " + str(self.n)) # set objective handling stuff if objective_handling is None: self._objective_handling = ObjectiveHandling.SINGLE else: self._objective_handling = objective_handling self._objectives = objectives if (isinstance(self._objectives, List) and len(self._objectives) > 1 ) and self._objective_handling == ObjectiveHandling.SINGLE: print( "Many objectives specified but single objective handling, using the first objective in the dictionary" ) self._objective_weights = objective_weights if ((self._objective_weights is None) or self._objective_weights is not None and ((len(self._objective_weights) != len(self._objectives) and self._objective_handling == ObjectiveHandling.AGGREGATE))): print( "Objective weight issue: no weight given or size of weights and objectives lists mismatch. " "Setting all weights to default 1 value.") self._objective_weights = [1 for i in range(len(self._objectives))] if selection is None: self._selection_type = self._default_selection else: self._selection_type = selection # DEAP toolbox setup self._toolbox = base.Toolbox() # Define representation creator.create( "fitness", base.Fitness, weights=( 1.0, ), # we keep this to 1 and let the user provides the weights for each subobjective ) # (a negative weight defines the objective as a minimisation) creator.create( "individual", list, fitness=creator.fitness ) # associate the fitness function to the individual type # Create the individuals required by the encoding if self._encoding_type == TypeAttribute.LIST_BOOLEAN: self._toolbox.register( "bit", random.randint, 0, 1 ) # Each element of a solution is a bit (i.e. an int between 0 and 1 incl.) self._toolbox.register( "individual", tools.initRepeat, creator.individual, self._toolbox.bit, n=self.n, ) # An individual (aka solution) contains n bits elif self._encoding_type == TypeAttribute.PERMUTATION: self._toolbox.register("permutation_indices", random.sample, range(self.n), self.n) self._toolbox.register( "individual", tools.initIterate, creator.individual, self._toolbox.permutation_indices, ) elif self._encoding_type == TypeAttribute.LIST_INTEGER: self._toolbox.register("int_val", random.randint, 0, self.arrity - 1) self._toolbox.register( "individual", tools.initRepeat, creator.individual, self._toolbox.int_val, n=self.n, ) elif self._encoding_type == TypeAttribute.LIST_INTEGER_SPECIFIC_ARRITY: gen_idx = lambda: [ random.randint(0, arrity - 1) for arrity in self.arrities ] self._toolbox.register("individual", tools.initIterate, creator.individual, gen_idx) self._toolbox.register( "population", tools.initRepeat, list, self._toolbox.individual, n=self._pop_size, ) # A population is made of pop_size individuals # Define objective function self._toolbox.register( "evaluate", self.evaluate_problem, ) # Define crossover if crossover is None: self._crossover = self._default_crossovers[self._encoding_type] else: self._crossover = crossover # if self._encoding_type == TypeAttribute.LIST_BOOLEAN: if self._crossover == DeapCrossover.CX_UNIFORM: self._toolbox.register("mate", tools.cxUniform, indpb=self._crossover_rate) elif self._crossover == DeapCrossover.CX_ONE_POINT: self._toolbox.register("mate", tools.cxOnePoint) elif self._crossover == DeapCrossover.CX_TWO_POINT: self._toolbox.register("mate", tools.cxTwoPoint) # elif self._encoding_type == TypeAttribute.PERMUTATION: elif self._crossover == DeapCrossover.CX_UNIFORM_PARTIALY_MATCHED: self._toolbox.register("mate", tools.cxUniformPartialyMatched, indpb=0.5) elif self._crossover == DeapCrossover.CX_ORDERED: self._toolbox.register("mate", tools.cxOrdered) elif self._crossover == DeapCrossover.CX_PARTIALY_MATCHED: self._toolbox.register("mate", tools.cxPartialyMatched) else: print("Crossover of specified type not handled!") # Define mutation if mutation is None: self._mutation = self._default_mutations[self._encoding_type] else: self._mutation = mutation if isinstance(self._mutation, Mutation): self._toolbox.register( "mutate", generic_mutate_wrapper, problem=self.problem, encoding_name=self._encoding_variable_name, indpb=self._mut_rate, solution_fn=self.problem.get_solution_type(), custom_mutation=mutation, ) elif isinstance(self._mutation, DeapMutation): if self._mutation == DeapMutation.MUT_FLIP_BIT: self._toolbox.register( "mutate", tools.mutFlipBit, indpb=self._mut_rate) # Choice of mutation operator elif self._mutation == DeapMutation.MUT_SHUFFLE_INDEXES: self._toolbox.register( "mutate", tools.mutShuffleIndexes, indpb=self._mut_rate) # Choice of mutation operator elif self._mutation == DeapMutation.MUT_UNIFORM_INT: # print('DEAP-GA - self.arrities: ', self.arrities) # print('DEAP-GA - self.arrity: ', self.arrity) # self._toolbox.register("mutate", tools.mutUniformInt, low=0, up=self.arrity-1, indpb=self._mut_rate) self._toolbox.register( "mutate", tools.mutUniformInt, low=0, up=self.arrities, indpb=self._mut_rate, ) # Choice of selection if self._selection_type == DeapSelection.SEL_TOURNAMENT: self._toolbox.register( "select", tools.selTournament, tournsize=int(self._tournament_size * self._pop_size), ) elif self._selection_type == DeapSelection.SEL_RANDOM: self._toolbox.register("select", tools.selRandom) elif self._selection_type == DeapSelection.SEL_BEST: self._toolbox.register("select", tools.selBest) elif self._selection_type == DeapSelection.SEL_ROULETTE: self._toolbox.register("select", tools.selRoulette) elif self._selection_type == DeapSelection.SEL_WORST: self._toolbox.register("select", tools.selWorst) elif self._selection_type == DeapSelection.SEL_STOCHASTIC_UNIVERSAL_SAMPLING: self._toolbox.register("select", tools.selStochasticUniversalSampling) ( self.aggreg_from_sol, self.aggreg_dict, self.params_objective_function, ) = build_aggreg_function_and_params_objective( problem=self.problem, params_objective_function=None ) # TODO: That should probably be set to somthing else than None.
def solve_model(model, postpro=True, nb_iteration=500): dummy = model.get_dummy_solution() _, mutations = get_available_mutations(model, dummy) list_mutation = [ mutate[0].build(model, dummy, **mutate[1]) for mutate in mutations if mutate[0] == PermutationMutationRCPSP ] mixed_mutation = BasicPortfolioMutation(list_mutation, np.ones((len(list_mutation)))) objectives = ["makespan"] objective_weights = [-1] if postpro: params_objective_function = ParamsObjectiveFunction( objective_handling=ObjectiveHandling.AGGREGATE, objectives=objectives, weights=objective_weights, sense_function=ModeOptim.MAXIMIZATION, ) aggreg_sol, _, _ = build_aggreg_function_and_params_objective( model, params_objective_function) res = RestartHandlerLimit(200, cur_solution=dummy, cur_objective=aggreg_sol(dummy)) sa = SimulatedAnnealing( evaluator=model, mutator=mixed_mutation, restart_handler=res, temperature_handler=TemperatureSchedulingFactor( temperature=0.5, restart_handler=res, coefficient=0.9999), mode_mutation=ModeMutation.MUTATE, params_objective_function=params_objective_function, store_solution=True, nb_solutions=10000, ) result_ls = sa.solve(dummy, nb_iteration_max=nb_iteration, pickle_result=False) else: params_objective_function = ParamsObjectiveFunction( objective_handling=ObjectiveHandling.MULTI_OBJ, objectives=objectives, weights=objective_weights, sense_function=ModeOptim.MAXIMIZATION, ) aggreg_sol, _, _ = build_aggreg_function_and_params_objective( model, params_objective_function) res = RestartHandlerLimit(200, cur_solution=dummy, cur_objective=aggreg_sol(dummy)) sa = HillClimberPareto( evaluator=model, mutator=mixed_mutation, restart_handler=res, params_objective_function=params_objective_function, mode_mutation=ModeMutation.MUTATE, store_solution=True, nb_solutions=10000, ) result_ls = sa.solve( dummy, nb_iteration_max=nb_iteration, pickle_result=False, update_iteration_pareto=10000, ) return result_ls