def callback_inner(model, where):

        if where == grb.GRB.Callback.MIPSOL:

            # Update sub-problem's RHS based on incumbent solution
            facility_cols = list(master.facility_to_column.values())
            mp_facility_values = model.cbGetSolution(facility_cols)
            facility_names = master.facility_to_column.keys()

            sub_problem_rhs = {facility_name: -data.supply(facility_name) if utils.is_non_zero(val) else 0.0
                               for facility_name, val in zip(facility_names, mp_facility_values)}

            sub_problem.set_supply_constraint_rhs(sub_problem_rhs)

            # Solve sub-problem
            sub_problem.solve()

            logging.debug(f'Subproblem status: {sub_problem.model.getAttr(grb.GRB.Attr.Status)}')

            # Add cuts (lazy constraints) based on sub-problem status
            if sub_problem.status() == grb.GRB.Status.INFEASIBLE:

                # Add feasibility cut
                cut = []
                for facility_name, row in sub_problem.facility_to_supply_constraint.items():
                    dual_farkas = row.getAttr(grb.GRB.Attr.FarkasDual)
                    logging.debug(f'{facility_name}: {dual_farkas}')
                    cut.append(dual_farkas * mapping[row])

                for customer_name, row in sub_problem.customer_to_demand_constraint.items():
                    dual_farkas = row.getAttr(grb.GRB.Attr.FarkasDual)
                    logging.debug(f'{customer_name}: {dual_farkas}')
                    cut.append(dual_farkas * mapping[row])

                logging.debug("Adding feasibility cut: ", grb.quicksum(cut) >= 0)
                model.cbLazy(grb.quicksum(cut) >= 0)

            elif sub_problem.status() == grb.GRB.Status.OPTIMAL:
                sub_problem_obj_val = sub_problem.model.getAttr(grb.GRB.Attr.ObjVal)
                z = master.name_to_column[master.aux_var_name]
                z_val = model.cbGetSolution(z)
                if utils.is_non_zero(sub_problem_obj_val - z_val):

                    # Add optimality cut
                    cut = []
                    for _, row in sub_problem.facility_to_supply_constraint.items():
                        dual_supply = row.getAttr(grb.GRB.Attr.Pi)
                        cut.append(dual_supply * mapping[row])
                    for _, row in sub_problem.customer_to_demand_constraint.items():
                        dual_demand = row.getAttr(grb.GRB.Attr.Pi)
                        cut.append(dual_demand * mapping[row])

                    cut.append(-z)
                    model.cbLazy(grb.quicksum(cut) <= 0)
                    logging.debug("Adding optimality cut: ", grb.quicksum(cut) <= 0)
Exemplo n.º 2
0
def build_supply_constraints(
        data: InputData, model: grb.Model,
        facility_customer_pair_to_column: Dict[Tuple[str, str], grb.Var],
        facility_name_to_column: Dict[str, grb.Var]) -> Dict[str, grb.Constr]:
    """
    Build constraints s_i y_i - \sum_{j=0}^{m} x_ij >= 0, for all i = 1, ..., n
    :param data:
    :param model:
    :param facility_customer_pair_to_column:
    :param facility_name_to_column:
    :return:
    """

    facility_to_row = dict()
    for facility in data.facilities:
        lhs = [
            -facility_customer_pair_to_column[(facility.name, customer_name)]
            for customer_name in facility.transport_cost.keys()
        ]

        facility_var = facility_name_to_column.get(facility.name, 1)
        lhs.append(1 * facility.supply * facility_var)
        lhs = grb.quicksum(lhs)
        name = f'supply_{facility.name}'

        row = model.addConstr(lhs >= 0.0, name=name)
        facility_to_row[facility.name] = row

    return facility_to_row
 def adding_constraint(
     self,
     constraint_description: Union[ConstraintTaskIndividual,
                                   ConstraintWorkDuration],
     constraint_name: str = "",
 ):
     if isinstance(constraint_description, ConstraintTaskIndividual):
         if constraint_name == "":
             constraint_name = str(ConstraintTaskIndividual.__name__)
         for tupl in constraint_description.list_tuple:
             ressource, ressource_individual, task, has_to_do = tupl
             if ressource in self.ressource_id_usage:
                 if ressource_individual in self.ressource_id_usage[
                         ressource]:
                     if (task in self.ressource_id_usage[ressource]
                         [ressource_individual]):
                         if constraint_name not in self.constraint_additionnal:
                             self.constraint_additionnal[
                                 constraint_name] = []
                         self.constraint_additionnal[constraint_name] += [
                             self.model.addConstr(
                                 self.ressource_id_usage[ressource]
                                 [ressource_individual][task] == has_to_do)
                         ]
     if isinstance(constraint_description, ConstraintWorkDuration):
         if constraint_name == "":
             constraint_name = str(ConstraintWorkDuration.__name__)
         if constraint_name not in self.constraint_additionnal:
             self.constraint_additionnal[constraint_name] = []
         tasks_of_interest = [
             t for t in self.rcpsp_schedule
             if t in self.ressource_id_usage.get(
                 constraint_description.ressource, {}).get(
                     constraint_description.individual, {}) and
             (constraint_description.time_bounds[0] <= self.
              rcpsp_schedule[t]["start_time"] <= constraint_description.
              time_bounds[1] or constraint_description.time_bounds[0] <=
              self.rcpsp_schedule[t]["end_time"] <=
              constraint_description.time_bounds[1])
         ]
         print(tasks_of_interest)
         self.constraint_additionnal[constraint_name] += [
             self.model.addConstr(
                 gurobi.quicksum([
                     self.ressource_id_usage[
                         constraint_description.ressource][
                             constraint_description.individual][t] * (min(
                                 constraint_description.time_bounds[1],
                                 self.rcpsp_schedule[t]["end_time"],
                             ) - max(
                                 constraint_description.time_bounds[0],
                                 self.rcpsp_schedule[t]["start_time"],
                             )) for t in tasks_of_interest
                 ]) <= constraint_description.working_time_upper_bound)
         ]
         self.model.update()
Exemplo n.º 4
0
def add_gprs_cnf_weak_(tiger,
                       model,
                       gene_ub=None,
                       gpr_suffix="__GPR",
                       **kwargs):
    rxns = get_vars_by_name(model, tiger.rxns)

    if gene_ub is None:
        ub = GRB.INFINITY
    else:
        ub = gene_ub
    for gene in tiger.genes:
        model.addVar(lb=0.0, ub=ub, name=gene)
    model.update()
    g = get_vars_by_name(model, tiger.genes, "dict")

    for v, gpr in zip(rxns, tiger.gprs):
        if gpr.is_empty():
            continue

        cnfs = parsing.make_cnf(gpr, names_only=True)
        for i, cnf in enumerate(cnfs):
            genes = [g[name] for name in cnf]
            if gene_ub is None:
                model.addConstr(v <= gp.quicksum(genes),
                                name=v.varname + gpr_suffix + '-UB[' + str(i) +
                                ']')
                model.addConstr(v >= -gp.quicksum(genes),
                                name=v.varname + gpr_suffix + '-LB[' + str(i) +
                                ']')
            else:
                model.addConstr(v <= v.ub / ub * gp.quicksum(genes),
                                name=v.varname + gpr_suffix + '-UB[' + str(i) +
                                ']')
                model.addConstr(v >= v.lb / ub * gp.quicksum(genes),
                                name=v.varname + gpr_suffix + '-LB[' + str(i) +
                                ']')

    model.update()
Exemplo n.º 5
0
def build_demand_constraints(data: InputData,
                             model: grb.Model,
                             facility_customer_pair_to_column: Dict[Tuple[str, str], grb.Var]) \
        -> Dict[str, grb.Constr]:

    customer_to_row = dict()
    for customer in data.customers:
        lhs = grb.quicksum([
            facility_customer_pair_to_column[(facility.name, customer.name)]
            for facility in data.facilities
        ])
        rhs = customer.demand
        name = f'demand_{customer.name}'
        row = model.addConstr(lhs >= rhs, name=name)

        customer_to_row[customer.name] = row

    return customer_to_row
Exemplo n.º 6
0
 def init_model(self, **args):
     warm_start = args.get('warm_start', {})
     self.model = Model("Knapsack")
     self.variable_decision = {"x": {}}
     self.description_variable_description = {
         "x": {
             "shape":
             self.knapsack_model.nb_items,
             "type":
             bool,
             "descr":
             "dictionary with key the item index \
                                                              and value the boolean value corresponding \
                                                              to taking the item or not"
         }
     }
     self.description_constraint["weight"] = {
         "descr": "sum of weight of used items doesn't exceed max capacity"
     }
     weight = {}
     list_item = self.knapsack_model.list_items
     max_capacity = self.knapsack_model.max_capacity
     x = {}
     for item in list_item:
         i = item.index
         x[i] = self.model.addVar(vtype=GRB.BINARY,
                                  obj=item.value,
                                  name="x_" + str(i))
         if i in warm_start:
             x[i].start = warm_start[i]
             x[i].varhinstval = warm_start[i]
         weight[i] = item.weight
     self.variable_decision["x"] = x
     self.model.update()
     self.constraints_dict["weight"] = self.model.addConstr(
         quicksum([weight[i] * x[i] for i in x]) <= max_capacity)
     self.model.update()
     self.model.setParam("TimeLimit", 200)
     self.model.modelSense = GRB.MAXIMIZE
     self.model.setParam(GRB.Param.PoolSolutions, 10000)
     self.model.setParam("MIPGapAbs", 0.00001)
     self.model.setParam("MIPGap", 0.00000001)
 def init_model(self, **kwargs):
     greedy_start = kwargs.get("greedy_start", True)
     verbose = kwargs.get("verbose", False)
     use_cliques = kwargs.get("use_cliques", False)
     if greedy_start:
         if verbose:
             print("Computing greedy solution")
         greedy_solver = GreedyColoring(self.coloring_problem,
                                        params_objective_function=self.params_objective_function)
         result_store = greedy_solver.solve(strategy=NXGreedyColoringMethod.best, verbose=verbose)
         self.start_solution = result_store.get_best_solution_fit()[0]
     else:
         if verbose:
             print("Get dummy solution")
         solution = self.coloring_problem.get_dummy_solution()
         self.start_solution = solution
     nb_colors = self.start_solution.nb_color
     color_model = Model("color")
     colors_var = {}
     range_node = range(self.number_of_nodes)
     range_color = range(nb_colors)
     for node in self.nodes_name:
         for color in range_color:
             colors_var[node, color] = color_model.addVar(vtype=GRB.BINARY,
                                                          obj=0,
                                                          name="x_" + str((node, color)))
     one_color_constraints = {}
     for n in range_node:
         one_color_constraints[n] = color_model.addConstr(quicksum([colors_var[n, c] for c in range_color]) == 1)
     color_model.update()
     cliques = []
     g = self.graph.to_networkx()
     if use_cliques:
         for c in nx.algorithms.clique.find_cliques(g):
             cliques += [c]
         cliques = sorted(cliques, key=lambda x: len(x), reverse=True)
     else:
         cliques = [[e[0], e[1]] for e in g.edges()]
     cliques_constraint = {}
     index_c = 0
     opt = color_model.addVar(vtype=GRB.INTEGER, lb=0, ub=nb_colors, obj=1)
     if use_cliques:
         for c in cliques[:100]:
             cliques_constraint[index_c] = color_model.addConstr(quicksum([(color_i + 1) * colors_var[node, color_i]
                                                                           for node in c
                                                                           for color_i in range_color])
                                                                 >= sum([i + 1 for i in range(len(c))]))
             cliques_constraint[(index_c, 1)] = color_model.addConstr(quicksum([colors_var[node, color_i]
                                                                               for node in c
                                                                               for color_i in range_color])
                                                                      <= opt)
             index_c += 1
     edges = g.edges()
     constraints_neighbors = {}
     for e in edges:
         for c in range_color:
             constraints_neighbors[(e[0], e[1], c)] = \
                 color_model.addConstr(colors_var[e[0], c] + colors_var[e[1], c] <= 1)
     for n in range_node:
         color_model.addConstr(quicksum([(color_i + 1) * colors_var[n, color_i] for color_i in range_color]) <= opt)
     color_model.update()
     color_model.modelSense = GRB.MINIMIZE
     color_model.setParam(GRB.Param.Threads, 8)
     color_model.setParam(GRB.Param.PoolSolutions, 10000)
     color_model.setParam(GRB.Param.Method, -1)
     color_model.setParam("MIPGapAbs", 0.001)
     color_model.setParam("MIPGap", 0.001)
     color_model.setParam("Heuristics", 0.01)
     self.model = color_model
     self.variable_decision = {"colors_var": colors_var}
     self.constraints_dict = {"one_color_constraints": one_color_constraints,
                              "constraints_neighbors": constraints_neighbors}
     self.description_variable_description = {"colors_var": {"shape": (self.number_of_nodes, nb_colors),
                                                             "type": bool,
                                                             "descr": "for each node and each color,"
                                                                      " a binary indicator"}}
     self.description_constraint["one_color_constraints"] = {"descr": "one and only one color "
                                                                      "should be assignated to a node"}
     self.description_constraint["constraints_neighbors"] = {"descr": "no neighbors can have same color"}
    def init_model(self, **args):
        self.model = gurobi.Model("Gantt")
        self.ressource_id_usage = {
            k:
            {i: {}
             for i in range(len(self.rcpsp_model.calendar_details[k]))}
            for k in self.rcpsp_model.calendar_details.keys()
        }
        variables_per_task = {}
        variables_per_individual = {}
        constraints_ressource_need = {}

        for task in self.jobs:
            start = self.rcpsp_schedule[task]["start_time"]
            end = self.rcpsp_schedule[task]["end_time"]
            for k in self.ressource_id_usage:  # typically worker
                needed_ressource = (self.rcpsp_model.mode_details[task][
                    self.modes_dict[task]][k] > 0)
                if needed_ressource:
                    for individual in self.ressource_id_usage[k]:
                        available = all([
                            self.rcpsp_model.calendar_details[k][individual]
                            [time] for time in range(start, end)
                        ])
                        if available:
                            key_variable = (k, individual, task)
                            self.ressource_id_usage[k][individual][
                                task] = self.model.addVar(
                                    name=str(key_variable),
                                    vtype=gurobi.GRB.BINARY)
                            if task not in variables_per_task:
                                variables_per_task[task] = set()
                            if k not in variables_per_individual:
                                variables_per_individual[k] = {}
                            if individual not in variables_per_individual[k]:
                                variables_per_individual[k][individual] = set()
                            variables_per_task[task].add(key_variable)
                            variables_per_individual[k][individual].add(
                                key_variable)
                    ressource_needed = self.rcpsp_model.mode_details[task][
                        self.modes_dict[task]][k]
                    if k not in constraints_ressource_need:
                        constraints_ressource_need[k] = {}
                    constraints_ressource_need[k][task] = self.model.addConstr(
                        gurobi.quicksum([
                            self.ressource_id_usage[k][key[1]][key[2]]
                            for key in variables_per_task[task] if key[0] == k
                        ]) == ressource_needed,
                        name="ressource_" + str(k) + "_" + str(task),
                    )
        overlaps_constraints = {}

        for i in range(len(self.cliques)):
            tasks = set(self.cliques[i])
            for k in variables_per_individual:
                for individual in variables_per_individual[k]:
                    keys_variable = [
                        variable
                        for variable in variables_per_individual[k][individual]
                        if variable[2] in tasks
                    ]
                    if len(keys_variable) > 0:
                        overlaps_constraints[(
                            i, k, individual
                        )] = self.model.addConstr(
                            gurobi.quicksum([
                                self.ressource_id_usage[key[0]][key[1]][key[2]]
                                for key in keys_variable
                            ]) <= 1)
Exemplo n.º 9
0
    def init_model(self, **args):
        greedy_start = args.get("greedy_start", True)
        start_solution = args.get("start_solution", None)
        max_horizon = args.get("max_horizon", None)
        verbose = args.get("verbose", False)
        if start_solution is None:
            if greedy_start:
                if verbose:
                    print("Computing greedy solution")
                if isinstance(self.rcpsp_model, RCPSPModelCalendar):
                    greedy_solver = PileSolverRCPSP_Calendar(self.rcpsp_model)
                else:
                    greedy_solver = PileSolverRCPSP(self.rcpsp_model)
                store_solution = greedy_solver.solve(
                    greedy_choice=GreedyChoice.MOST_SUCCESSORS
                )
                self.start_solution = store_solution.get_best_solution_fit()[0]
                makespan = self.rcpsp_model.evaluate(self.start_solution)["makespan"]
            else:
                if verbose:
                    print("Get dummy solution")
                solution = self.rcpsp_model.get_dummy_solution()
                self.start_solution = solution
                makespan = self.rcpsp_model.evaluate(solution)["makespan"]
        else:
            self.start_solution = start_solution
            makespan = self.rcpsp_model.evaluate(start_solution)["makespan"]

        # p = [0, 3, 2, 5, 4, 2, 3, 4, 2, 4, 6, 0]
        sorted_tasks = sorted(self.rcpsp_model.mode_details.keys())
        p = [
            int(
                max(
                    [
                        self.rcpsp_model.mode_details[key][mode]["duration"]
                        for mode in self.rcpsp_model.mode_details[key]
                    ]
                )
            )
            for key in sorted_tasks
        ]
        # c = [6, 8]
        c = [x for x in self.rcpsp_model.resources.values()]
        renewable = {
            r: self.rcpsp_model.resources[r]
            for r in self.rcpsp_model.resources
            if r not in self.rcpsp_model.non_renewable_resources
        }
        non_renewable = {
            r: self.rcpsp_model.resources[r]
            for r in self.rcpsp_model.non_renewable_resources
        }
        # print('c: ', c)
        # S = [[0, 1], [0, 2], [0, 3], [1, 4], [1, 5], [2, 9], [2, 10], [3, 8], [4, 6],
        #      [4, 7], [5, 9], [5, 10], [6, 8], [6, 9], [7, 8], [8, 11], [9, 11], [10, 11]]
        S = []
        print("successors: ", self.rcpsp_model.successors)
        for task in sorted_tasks:
            for suc in self.rcpsp_model.successors[task]:
                S.append([task, suc])
        # print('S: ', S)
        (R, self.J, self.T) = (range(len(c)), range(len(p)), list(range(sum(p))))
        # we have a better self.T to limit the number of variables :
        if self.start_solution.rcpsp_schedule_feasible:
            self.T = list(range(int(makespan + 1)))
        if max_horizon is not None:
            self.T = list(range(max_horizon + 1))
            print("Hey")
            print(self.T)
        # model = Model()
        self.model = gurobi.Model("MRCPSP")
        self.x: Dict[gurobi.Var] = {}
        last_task = max(self.rcpsp_model.mode_details.keys())
        variable_per_task = {}
        keys_for_t = {}
        for task in sorted_tasks:
            if task not in variable_per_task:
                variable_per_task[task] = []
            for mode in self.rcpsp_model.mode_details[task]:
                for t in self.T:
                    self.x[(task, mode, t)] = self.model.addVar(
                        name="x({},{}, {})".format(task, mode, t),
                        vtype=gurobi.GRB.BINARY,
                    )
                    for tt in range(
                        t, t + self.rcpsp_model.mode_details[task][mode]["duration"]
                    ):
                        if tt not in keys_for_t:
                            keys_for_t[tt] = set()
                        keys_for_t[tt].add((task, mode, t))
                    variable_per_task[task] += [(task, mode, t)]
        self.model.update()
        self.model.setObjective(
            gurobi.quicksum(
                self.x[key] * key[2] for key in variable_per_task[last_task]
            )
        )
        self.model.addConstrs(
            gurobi.quicksum(self.x[key] for key in variable_per_task[j]) == 1
            for j in variable_per_task
        )

        if isinstance(self.rcpsp_model, RCPSPModelCalendar):
            renewable_quantity = {r: renewable[r] for r in renewable}
        else:
            renewable_quantity = {r: [renewable[r]] * len(self.T) for r in renewable}

        if isinstance(self.rcpsp_model, RCPSPModelCalendar):
            non_renewable_quantity = {r: non_renewable[r] for r in non_renewable}
        else:
            non_renewable_quantity = {
                r: [non_renewable[r]] * len(self.T) for r in non_renewable
            }

        # for r, t in product(renewable, self.T):
        #    self.model.addConstr(gurobi.quicksum(int(self.rcpsp_model.mode_details[key[0]][key[1]][r]) * self.x[key]
        #                                          for key in keys_for_t[t])
        #                          <= renewable_quantity[r][t])
        #    print(r, t)

        self.model.addConstrs(
            gurobi.quicksum(
                int(self.rcpsp_model.mode_details[key[0]][key[1]][r]) * self.x[key]
                for key in keys_for_t[t]
            )
            <= renewable_quantity[r][t]
            for (r, t) in product(renewable, self.T)
        )

        self.model.addConstrs(
            gurobi.quicksum(
                int(self.rcpsp_model.mode_details[key[0]][key[1]][r]) * self.x[key]
                for key in self.x
            )
            <= non_renewable_quantity[r][0]
            for r in non_renewable
        )
        self.model.update()
        durations = {
            j: self.model.addVar(name="duration_" + str(j), vtype=gurobi.GRB.INTEGER)
            for j in variable_per_task
        }
        self.durations = durations
        self.variable_per_task = variable_per_task
        self.model.addConstrs(
            gurobi.quicksum(
                self.rcpsp_model.mode_details[key[0]][key[1]]["duration"] * self.x[key]
                for key in variable_per_task[j]
            )
            == durations[j]
            for j in variable_per_task
        )
        self.model.addConstrs(
            gurobi.quicksum(
                [key[2] * self.x[key] for key in variable_per_task[s]]
                + [-key[2] * self.x[key] for key in variable_per_task[j]]
            )
            >= durations[j]
            for (j, s) in S
        )

        start = []
        self.starts = {}
        for task in sorted_tasks:
            self.starts[task] = self.model.addVar(
                name="start({})".format(task),
                vtype=gurobi.GRB.INTEGER,
                lb=0,
                ub=self.T[-1],
            )
            self.starts[task].start = self.start_solution.rcpsp_schedule[task][
                "start_time"
            ]
            self.model.addConstr(
                gurobi.quicksum(
                    [self.x[key] * key[2] for key in variable_per_task[task]]
                )
                == self.starts[task]
            )
        for j in self.start_solution.rcpsp_schedule:
            start_time_j = self.start_solution.rcpsp_schedule[j]["start_time"]
            mode_j = (
                1
                if j == 1 or j == self.rcpsp_model.n_jobs + 2
                else self.start_solution.rcpsp_modes[j - 2]
            )
            start += [
                (
                    self.durations[j],
                    self.rcpsp_model.mode_details[j][mode_j]["duration"],
                )
            ]
            for k in self.variable_per_task[j]:
                task, mode, time = k
                if start_time_j == time and mode == mode_j:
                    start += [(self.x[k], 1)]
                    self.x[k].start = 1
                else:
                    start += [(self.x[k], 0)]
                    self.x[k].start = 0

        # self.model.start = start
        p_s: Union[PartialSolution, None] = args.get("partial_solution", None)
        self.constraints_partial_solutions = []
        self.model.update()
        if p_s is not None:
            constraints = []
            if p_s.start_times is not None:
                constraints = self.model.addConstrs(
                    gurobi.quicksum(
                        [
                            self.x[k]
                            for k in self.variable_per_task[task]
                            if k[2] == p_s.start_times[task]
                        ]
                    )
                    == 1
                    for task in p_s.start_times
                )
            if p_s.partial_permutation is not None:
                for t1, t2 in zip(
                    p_s.partial_permutation[:-1], p_s.partial_permutation[1:]
                ):
                    constraints += [
                        self.model.addConstr(
                            gurobi.quicksum(
                                [key[2] * self.x[key] for key in variable_per_task[t1]]
                                + [
                                    -key[2] * self.x[key]
                                    for key in variable_per_task[t2]
                                ]
                            )
                            <= 0
                        )
                    ]
            if p_s.list_partial_order is not None:
                for l in p_s.list_partial_order:
                    for t1, t2 in zip(l[:-1], l[1:]):
                        constraints += [
                            self.model.addConstr(
                                gurobi.quicksum(
                                    [
                                        key[2] * self.x[key]
                                        for key in variable_per_task[t1]
                                    ]
                                    + [
                                        -key[2] * self.x[key]
                                        for key in variable_per_task[t2]
                                    ]
                                )
                                <= 0
                            )
                        ]
            if p_s.start_at_end is not None:
                for i, j in p_s.start_at_end:
                    constraints += [
                        self.model.addConstr(
                            self.starts[j] == self.starts[i] + durations[i]
                        )
                    ]
            if p_s.start_together is not None:
                for i, j in p_s.start_together:
                    constraints += [
                        self.model.addConstr(self.starts[j] == self.starts[i])
                    ]
            if p_s.start_after_nunit is not None:
                for t1, t2, delta in p_s.start_after_nunit:
                    constraints += [
                        self.model.addConstr(self.starts[t2] >= self.starts[t1] + delta)
                    ]
            if p_s.start_at_end_plus_offset is not None:
                for t1, t2, delta in p_s.start_at_end_plus_offset:
                    constraints += [
                        self.model.addConstr(
                            self.starts[t2] >= self.starts[t1] + delta + durations[t1]
                        )
                    ]
            self.constraints_partial_solutions = constraints
            print("Partial solution constraints : ", self.constraints_partial_solutions)
            self.model.update()
 def init_model(self, **kwargs):
     nb_facilities = self.facility_problem.facility_count
     nb_customers = self.facility_problem.customer_count
     use_matrix_indicator_heuristic = kwargs.get("use_matrix_indicator_heuristic", True)
     if use_matrix_indicator_heuristic:
         n_shortest = kwargs.get("n_shortest", 10)
         n_cheapest = kwargs.get("n_cheapest", 10)
         matrix_fc_indicator, matrix_length = prune_search_space(self.facility_problem,
                                                                 n_cheapest=n_cheapest,
                                                                 n_shortest=n_shortest)
     else:
         matrix_fc_indicator, matrix_length = prune_search_space(self.facility_problem,
                                                                 n_cheapest=nb_facilities,
                                                                 n_shortest=nb_facilities)
     s = Model("facilities")
     x = {}
     for f in range(nb_facilities):
         for c in range(nb_customers):
             if matrix_fc_indicator[f, c] == 0:
                 x[f, c] = 0
             elif matrix_fc_indicator[f, c] == 1:
                 x[f, c] = 1
             elif matrix_fc_indicator[f, c] == 2:
                 x[f, c] = s.addVar(vtype=GRB.BINARY,
                                    obj=0,
                                    name="x_" + str((f, c)))
     facilities = self.facility_problem.facilities
     customers = self.facility_problem.customers
     used = s.addVars(nb_facilities, vtype=GRB.BINARY, name="y")
     constraints_customer = {}
     for c in range(nb_customers):
         constraints_customer[c] = s.addConstr(quicksum([x[f, c] for f in range(nb_facilities)]) == 1)
         # one facility
     constraint_capacity = {}
     for f in range(nb_facilities):
         s.addConstrs(used[f] >= x[f, c] for c in range(nb_customers))
         constraint_capacity[f] = s.addConstr(quicksum([x[f, c] * customers[c].demand
                                                        for c in range(nb_customers)]) <= facilities[f].capacity)
     s.update()
     new_obj_f = LinExpr(0.)
     new_obj_f += quicksum([facilities[f].setup_cost * used[f] for f in range(nb_facilities)])
     new_obj_f += quicksum([matrix_length[f, c] * x[f, c]
                            for f in range(nb_facilities)
                            for c in range(nb_customers)])
     s.setObjective(new_obj_f)
     s.update()
     s.modelSense = GRB.MINIMIZE
     s.setParam(GRB.Param.Threads, 4)
     s.setParam(GRB.Param.PoolSolutions, 10000)
     s.setParam(GRB.Param.Method, 1)
     s.setParam("MIPGapAbs", 0.00001)
     s.setParam("MIPGap", 0.00000001)
     self.model = s
     self.variable_decision = {"x": x}
     self.constraints_dict = {"constraint_customer": constraints_customer,
                              "constraint_capacity": constraint_capacity}
     self.description_variable_description = {"x": {"shape": (nb_facilities, nb_customers),
                                                    "type": bool,
                                                    "descr": "for each facility/customer indicate"
                                                             " if the pair is active, meaning "
                                                             "that the customer c is dealt with facility f"}}
     self.description_constraint = {"Im lazy."}
     print("Initialized")
Exemplo n.º 11
0
def _create_model(job_num, machine_num, job_ids, r_times, d_times, p_intervals, p_cost):
    """ Prepare the index for decision variables """
    # start time of process
    jobs = tuple(job_ids)
    # print("inside:", jobs)
    machines = tuple(range(machine_num))
    # print(machines)
    # sequence of processing jobs: tuple list
    job_pairs = [(i, j) for i in jobs for j in jobs if i != j]
    # print(job_pairs)
    # assignment of jobs on machines
    job_machine_pairs = [(i, m) for i in jobs for m in machines]
    # print(job_machine_pairs)
    # dissimilar parallel machine-machine pair
    machine_pairs = [(m, n) for m in machines for n in machines if m != n]
    
    """ Parameters model (dictionary) """
    # 1. release time
    release_time = dict(zip(jobs, tuple(r_times)))
    # print("release time:", release_time)
    # 2. due time
    due_time = dict(zip(jobs, tuple(d_times)))
    # print("due time:", due_time)
    # 3. processing time
    process_time = dict(zip(jobs, tuple(p_intervals)))
    # print("process time:", process_time)
    # 4. processing cost
    job_cost = dict(zip(jobs, tuple(p_cost)))
    # print("processing cost:", job_cost)
    # 5. define BigU
    U = sum([max(p_intervals[i]) for i in range(job_num)])
    # print("test U:", U)
    
    """ Create model """
    model = grb.Model("SSJSP")
    
    """ Create decision variables """
    # 1. Assignments of jobs on machines
    x = model.addVars(job_machine_pairs, vtype=grb.GRB.BINARY, name="assign")
    # 2. Sequence (Order) of executing jobs
    y = model.addVars(job_pairs, vtype=grb.GRB.BINARY, name="sequence")
    # 3. Start time of executing each job (ts = time_start)
    ts = model.addVars(jobs, lb=0, name="start_time")

    """ Create the objective function """
    model.setObjective(grb.quicksum([(job_cost[i][m]*x[(i,m)]) for m in machines for i in jobs]),
                       sense=grb.GRB.MINIMIZE)
    
    """ Create constraints """
    # 1. job release time constraint
    model.addConstrs((ts[i] >= release_time[i] for i in jobs), name="job release constraint")
    # 2. job due time constraint
    model.addConstrs((ts[i] <= due_time[i] - grb.quicksum([process_time[i][m]*x[(i,m)] for m in machines]) 
                      for i in jobs), name="job due constraint")
    # 3. one job is assigned to one and only one machine
    model.addConstrs((grb.quicksum([x[(i,m)] for m in machines]) == 1 for i in jobs), 
                     name="job non-splitting constraint")
    # 4. job 'j' is processed after job 'i' when both jobs are assigned to same machine
    model.addConstrs((y[(i,j)] + y[(j,i)] >= x[(i,m)] + x[(j,m)] - 1 for m in machines for (i,j) in job_pairs if j > i), 
                      name="assignment-sequencing vars constraint")
    # 5. sequencing constraint
    model.addConstrs((ts[j] >= ts[i] + grb.quicksum([process_time[i][m]*x[(i,m)] for m in machines]) 
                      - U*(1 - y[(i,j)]) for (i,j) in job_pairs), 
                     name="sequence constraint")
    # 6. either job 'i' is processed before job 'j' or vice versa
    model.addConstrs((y[(i,j)] + y[(j,i)] <= 1 for (i,j) in job_pairs if j > i), name="sequence of jobs")
    # 7. sequencing varibles = 0 when job 'i' and 'j' are assigned to different machines
    model.addConstrs((y[(i,j)] + y[(j,i)] + x[(i,m)] + x[(j,n)] <= 2 
                      for (m,n) in machine_pairs for (i,j) in job_pairs if j > i), 
                     name="different machine constraint")
    
    return model, x, y, ts