Example #1
0
 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,
     )
Example #2
0
 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,
     )
Example #3
0
 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}
Example #4
0
 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
Example #5
0
 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)
Example #6
0
 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
Example #7
0
 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
Example #8
0
 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,
     )
Example #9
0
 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
     )
Example #10
0
    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)
Example #11
0
    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.
Example #12
0
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