Пример #1
0
    def CreatePlacementVariables(self, items, binDx, binDy):
        for i, item in enumerate(items):
            self.itemArea += item.Dx * item.Dy
            
            filteredStartX = [p for p in self.preprocess.GlobalPlacementPatternsX[i] if (p % binDx) + item.Dx <= binDx]
            globalStartX = self.model.NewIntVarFromDomain(Domain.FromValues(filteredStartX), f'xb1.{i}')

            self.startVariablesGlobalX.append(globalStartX)

            filteredStartY = [p for p in self.preprocess.ItemPlacementPatternsY[i] if p + item.Dy <= binDy]
            yStart = self.model.NewIntVarFromDomain(Domain.FromValues(filteredStartY),f'y1.{i}')

            self.startVariablesY.append(yStart)
Пример #2
0
    def CreateVariables(self):
        binDx = self.Bin.Dx
        binDy = self.Bin.Dy

        placementPointGenerator = PlacementPointGenerator(self.Items, self.Bin)
        placementPatternsX, placementPatternsY = placementPointGenerator.CreatePlacementPatterns(
            self.placementPointStrategy, self.Items, self.Bin)

        # Consider modifying domains according to Cote, Iori (2018): The meet-in-the-middle principle for cutting and packing problems.
        for i, item in enumerate(self.Items):

            #filteredItems = [itemJ for j, itemJ in enumerate(self.Items) if i != j]

            placementPatternX = placementPatternsX[i]
            placementPatternY = placementPatternsY[i]

            x1 = self.Model.NewIntVarFromDomain(
                Domain.FromValues(placementPatternX), f'x1.{i}')

            #placementPointsEndX = [p + item.Dx for p in placementPointsStartX]
            #x2 = self.Model.NewIntVarFromDomain(Domain.FromValues(placementPointsEndX), f'x2.{i}')

            self.StartX.append(x1)
            #self.EndX.append(x2)

            y1 = self.Model.NewIntVarFromDomain(
                Domain.FromValues(placementPatternY), f'y1.{i}')
            #placementPointsEndY = [p + item.Dy for p in placementPointsStartY]
            #y2 = self.Model.NewIntVarFromDomain(Domain.FromValues(placementPointsEndY), f'y2.{i}')

            self.StartY.append(y1)
            #self.EndY.append(y2)

            intervalX = self.Model.NewFixedSizeIntervalVar(
                x1, item.Dx, f'xI{i}')
            intervalY = self.Model.NewFixedSizeIntervalVar(
                y1, item.Dy, f'yI{i}')

            self.IntervalX.append(intervalX)
            self.IntervalY.append(intervalY)
Пример #3
0
    def CreateVariables(self):
        binDx = self.Bin.Dx

        placementPointGenerator = PlacementPointGenerator(self.Items, self.Bin)
        placementPatternsX, placementPatternsY = placementPointGenerator.CreatePlacementPatterns(
            self.placementPointStrategy, self.Items, self.Bin)

        for i, item in enumerate(self.Items):
            placementPatternX = placementPatternsX[i]

            x1 = self.Model.NewIntVarFromDomain(
                Domain.FromValues(placementPatternX), f'x1.{i}')

            self.StartX.append(x1)

            intervalX = self.Model.NewFixedSizeIntervalVar(
                x1, item.Dx, f'xI{i}')

            self.IntervalX.append(intervalX)
Пример #4
0
    def Solve(self,
              items,
              itemsToFix,
              objectiveCoefficients,
              bin,
              timeLimit=1.0):
        # TODO: reformulate with FixedSizeOptionalIntervalVariables and use placement patterns.
        n = len(items)
        H = bin.Dy
        W = bin.Dx

        model = cp_model.CpModel()

        #preprocessing
        binDomains = []
        fixItemToBin = [False] * len(items)
        for i, item in enumerate(items):
            binDomains.append([0])
            if item.Id not in itemsToFix:
                binDomains[i].extend([i + 1])
            else:
                fixItemToBin[i] = True

        # variables

        b = []
        xb1 = []
        xb2 = []
        y1 = []
        y2 = []
        for i, item in enumerate(items):

            f = model.NewBoolVar(f'b{i}')
            b.append(f)

            yStart = model.NewIntVar(0, H - item.Dy, f'y1.{i}')
            yEnd = model.NewIntVar(item.Dy, H, f'y2.{i}')

            y1.append(yStart)
            y2.append(yEnd)

            if fixItemToBin[i]:
                d = model.NewIntVar(0, bin.Dx - item.Dx, f'xb1.{i}')
                e = model.NewIntVar(item.Dx, bin.Dx, f'xb2.{i}')

                xb1.append(d)
                xb2.append(e)
            else:
                # TODO: apply bin domains to these variables
                binStart = (i + 1) * bin.Dx
                d = model.NewIntVarFromDomain(
                    Domain.FromIntervals([[0, bin.Dx - item.Dx],
                                          [binStart, binStart]]), f'xb1.{i}')
                e = model.NewIntVarFromDomain(
                    Domain.FromIntervals(
                        [[item.Dx, bin.Dx],
                         [binStart + item.Dx, binStart + item.Dx]]),
                    f'xb2.{i}')

                xb1.append(d)
                xb2.append(e)

        # interval variables
        xival = [
            model.NewIntervalVar(xb1[i], items[i].Dx, xb2[i], f'xival{i}')
            for i in range(n)
        ]
        yival = [
            model.NewIntervalVar(y1[i], items[i].Dy, y2[i], f'yival{i}')
            for i in range(n)
        ]

        # constraints
        model.AddNoOverlap2D(xival, yival)

        for i, item in enumerate(items):
            #model.AddImplication(xb2[i] <= bin.Dx, b[i])
            #model.AddImplication(xb2[i] >= bin.Dx + item.Dx, b[i].Not())

            #model.AddLessOrEqual(xb2[i], bin.Dx).OnlyEnforceIf(b[i])
            #model.AddGreaterOrEqual(xb2[i], bin.Dx + item.Dx).OnlyEnforceIf(b[i].Not())

            model.Add(xb2[i] <= bin.Dx).OnlyEnforceIf(b[i])
            model.Add(xb2[i] >= bin.Dx + item.Dx).OnlyEnforceIf(b[i].Not())

            #model.Add(b[i] == 1).OnlyEnforceIf(xb2[i] <= bin.Dx)
            #model.Add(b[i] == 0).OnlyEnforceIf(xb2[i] >= bin.Dx + item.Dx)
            if item.Id in itemsToFix:
                model.Add(b[i] == 1)

        #packedItems = model.NewIntVar(0, len(items), 'itemCount')
        #model.Add(packedItems == sum(b[i] * objectiveCoefficients[i] for i in range(len(items))))

        # objective
        #model.Maximize(cp_model.LinearExpr.Sum(b))
        #model.Maximize(cp_model.LinearExpr.Sum(sum(var for var in b)))
        #model.Maximize(cp_model.LinearExpr.BooleanSum(b))
        #model.Maximize(packedItems)
        model.Maximize(
            sum(b[i] * int(objectiveCoefficients[item.Id])
                for i, item in enumerate(items)))

        # solve model
        solver = cp_model.CpSolver()
        solver.parameters.log_search_progress = False
        solver.parameters.max_time_in_seconds = timeLimit
        solver.parameters.num_search_workers = 1

        #with open(f"Model_{0}.txt","a") as f:
        #    f.write(str(model.Proto()))

        rc = solver.Solve(model)

        return solver.StatusName(), solver.BestObjectiveBound(
        ), solver.ObjectiveValue()
Пример #5
0
def add_constraints(model):
    # HELPER CONSTRAINTS
    for f_int in range(model.max_stream_int):
        for v_int in range(model.max_node_int):
            f = model.tc.F_routed[model._IntToStreamIDMap[f_int]]
            v = model.tc.N[model._IntToNodeIDMap[v_int]]

            x_v_has_s = model.x_v_has_successor[f_int][v_int]
            if isinstance(v, end_system):
                if v.id == f.sender_es_id or v.id in f.receiver_es_ids:
                    # Sender and Receivers have guaranteed successor
                    model.model.Add(x_v_has_s == 1)
                    model.model.Add(
                        model.x[f_int][v_int] != -1).OnlyEnforceIf(x_v_has_s)
                else:
                    # All other ES have guaranteed no successor
                    model.model.Add(x_v_has_s == 0)
                    model.model.Add(model.x[f_int][v_int] == -1).OnlyEnforceIf(
                        x_v_has_s.Not())
            else:
                # All switches can, but don't have to have a successor
                model.model.Add(
                    model.x[f_int][v_int] != -1).OnlyEnforceIf(x_v_has_s)
                model.model.Add(model.x[f_int][v_int] == -1).OnlyEnforceIf(
                    x_v_has_s.Not())

            model.x_v_has_successor[f_int][v_int] = x_v_has_s

    # NORMAL CONSTRAINTS
    for f_int in range(model.max_stream_int):
        model.x_v_is_not_u.append([])  #
        model.x_v_is_u.append([])
        model.x_v_is_u_and_uses_bandwidth.append([])
        for v_int in range(model.max_node_int):
            model.x_v_is_not_u[f_int].append([])  #
            model.x_v_is_u[f_int].append([])  #
            model.x_v_is_u_and_uses_bandwidth[f_int].append([])
            f = model.tc.F_routed[model._IntToStreamIDMap[f_int]]
            v = model.tc.N[model._IntToNodeIDMap[v_int]]

            # Constraint 1: x(v) != -1 => y(v) = y(x(v)) + 1 -> Avoid cycles
            if v.id != f.sender_es_id:
                # necessary, because otherwise AddElement breaks if the possible domain of a node is only -1
                if (len(model.x_v_possible_domain[f.id][v.id]) > 1
                        or model.x_v_possible_domain[f.id][v.id][0] != -1):
                    x_v = model.model.NewIntVarFromDomain(
                        Domain.FromValues(
                            model.x_v_possible_domain[f.id][v.id]),
                        "x_{}({})_temp".format(f.id, v.id),
                    )
                    model.model.Add(
                        x_v == model.x[f_int][v_int]).OnlyEnforceIf(
                            model.x_v_has_successor[f_int][v_int])
                    y_of_x_v = model.model.NewIntVar(
                        -1, model.max_node_int,
                        "y(x({}))_{}".format(v.id, f.id))

                    model.model.AddElement(x_v, model.y[f_int], y_of_x_v)

                    y_v_is_y_x_v_plus_1 = model.model.NewBoolVar(
                        "y({})_f_plus_one".format(v.id, f.id))
                    model.model.Add(model.y[f_int][v_int] == y_of_x_v +
                                    1).OnlyEnforceIf(y_v_is_y_x_v_plus_1)
                    model.model.Add(
                        model.y[f_int][v_int] != y_of_x_v + 1).OnlyEnforceIf(
                            y_v_is_y_x_v_plus_1.Not())

                    model.model.AddImplication(
                        model.x_v_has_successor[f_int][v_int],
                        y_v_is_y_x_v_plus_1)

            # Constraint 2: x(u) == -1 => x(v) != u
            # If a node has no successor, it has no predecessor
            # Also means: x(v) == u => x(u) != -1 (Contrapositive) (a => b, !b => !a)
            # If a node has a predecessor, it has a successor
            for u_int in range(model.max_node_int):
                u = model.tc.N[model._IntToNodeIDMap[u_int]]
                x_u_has_successor = model.x_v_has_successor[f_int][u_int]
                x_v_is_u = model.x_v_is_u[f_int][v_int][u_int]
                x_v_is_not_u = model.x_v_is_not_u[f_int][v_int][u_int]

                model.model.Add(
                    model.x[f_int][v_int] != u_int).OnlyEnforceIf(x_v_is_not_u)
                model.model.Add(
                    model.x[f_int][v_int] == u_int).OnlyEnforceIf(x_v_is_u)

                x_v_is_u_and_uses_bandwidth = model.x_v_is_u_and_uses_bandwidth[
                    f_int][v_int][u_int]
                model.model.Add(x_v_is_u_and_uses_bandwidth ==
                                0).OnlyEnforceIf(x_v_is_not_u)

                # For each redundant copy of a stream, create a list of the x_v_is_u_and_uses_bandwidth boolean variables, and set their sum to 1
                # This will only allow one of the redundant copies to use bandwidth on a link
                # sum(x_v_is_u_list) > 0 => sum(x_v_is_u_and_uses_bw)  == 1
                x_v_is_u_and_uses_bandwidth_list = [
                    x_v_is_u_and_uses_bandwidth
                ]
                x_v_is_u_list = [x_v_is_u]
                if f.rl > 1:
                    for f_2 in model.tc.F_red[f.get_id_prefix()]:
                        if f_2.id != f.id:
                            f2_int = model._StreamIDToIntMap[f_2.id]
                            x_v_is_u_and_uses_bandwidth_list.append(
                                model.x_v_is_u_and_uses_bandwidth[f2_int]
                                [v_int][u_int])
                            x_v_is_u_list.append(
                                model.x_v_is_u[f2_int][v_int][u_int])
                stream_uses_link = model.model.NewBoolVar(
                    "sum_of_x_{}({})_is_{}_is_greater_0".format(
                        f_int, v_int, u_int))
                exactly_one_copy_uses_bw = model.model.NewBoolVar(
                    "sum_of_x_{}({})_is_{}_and_uses_bw_is_1".format(
                        f_int, v_int, u_int))
                model.model.Add(
                    sum(x_v_is_u_list) > 0).OnlyEnforceIf(stream_uses_link)
                model.model.Add(sum(x_v_is_u_list) == 0).OnlyEnforceIf(
                    stream_uses_link.Not())
                model.model.Add(sum(x_v_is_u_and_uses_bandwidth_list) ==
                                1).OnlyEnforceIf(exactly_one_copy_uses_bw)
                model.model.Add(
                    sum(x_v_is_u_and_uses_bandwidth_list) == 0).OnlyEnforceIf(
                        exactly_one_copy_uses_bw.Not())
                model.model.AddImplication(stream_uses_link,
                                           exactly_one_copy_uses_bw)

                # Constraint 7.1: Streams may not exceed link capacity
                # if f is not using the link, capacity use is 0
                model.model.Add(model.v_to_u_capc_use_of_f[v_int][u_int][f_int]
                                == 0).OnlyEnforceIf(x_v_is_not_u)
                model.model.Add(model.v_to_u_capc_use_of_f[v_int][u_int][f_int]
                                == 0).OnlyEnforceIf(
                                    x_v_is_u_and_uses_bandwidth.Not())
                # if there is link from u to v
                if (u.id in model.tc.N_conn_inv[v.id]
                        and v.id in model.tc.L_from_nodes[u.id]):
                    model.model.Add(
                        model.v_to_u_capc_use_of_f[v_int][u_int][f_int] == int(
                            (f.size / f.period) *
                            1000)).OnlyEnforceIf(x_v_is_u).OnlyEnforceIf(
                                x_v_is_u_and_uses_bandwidth)

                model.model.AddImplication(x_u_has_successor.Not(),
                                           x_v_is_not_u)

            # Constraint 3: x(v) != -1 for all stream destinations
            if v.id in f.receiver_es_ids:
                model.model.Add(model.x[f_int][v_int] != -1)

            # Constraint 4: x(v) = int(v) for stream source
            # Constraint 5: y(v) = 0 for stream source
            if v.id == f.sender_es_id:
                model.model.Add(model.x[f_int][v_int] == v_int)
                model.model.Add(model.y[f_int][v_int] == 0)

            # Constraint 6: Redundant copies of each streams should not have common links
            if f.rl > 1:
                if v.id != f.sender_es_id:
                    for f_2 in model.tc.F_red[f.get_id_prefix()]:
                        if f_2.id != f.id:
                            f_2_int = model._StreamIDToIntMap[f_2.id]
                            model.model.Add(
                                model.x[f_int][v_int] != model.x[f_2_int]
                                [v_int]).OnlyEnforceIf(
                                    model.x_v_has_successor[f_int][v_int]
                                ).OnlyEnforceIf(
                                    model.x_v_has_successor[f_2_int][v_int])

    # Constraint 7.2: Streams may not exceed link capacity (upper bound is implicit through link_capacity domain)
    for v_int in range(model.max_node_int):
        for u_int in range(model.max_node_int):
            model.model.Add(model.link_capacity[v_int][u_int] == sum(
                model.v_to_u_capc_use_of_f[v_int][u_int]))

    for f_int in range(model.max_stream_int):
        f = model.tc.F_routed[model._IntToStreamIDMap[f_int]]
        for u_int in range(model.max_node_int):
            u = model.tc.N[model._IntToNodeIDMap[u_int]]

            x_v_is_u_list = [
                model.x_v_is_u[f_int][v_int][u_int]
                for v_int in range(model.max_node_int)
            ]

            if not u.id in f.receiver_es_ids:

                model.model.Add(sum(x_v_is_u_list) == 0).OnlyEnforceIf(
                    model.x_v_has_predecessor[f_int][u_int].Not())
                model.model.Add(sum(x_v_is_u_list) > 0).OnlyEnforceIf(
                    model.x_v_has_predecessor[f_int][u_int])

                x_u_has_successor = model.x_v_has_successor[f_int][u_int]
                # If u has no predecessors, it can't have successor
                model.model.AddImplication(
                    model.x_v_has_predecessor[f_int][u_int].Not(),
                    x_u_has_successor.Not(),
                )
            else:
                model.model.Add(model.x_v_has_predecessor[f_int][u_int] == 0)
Пример #6
0
def init_optimization_variables(model):
    # link capacity
    for v_int in range(model.max_node_int):
        model.v_to_u_capc_use_of_f.append([])
        model.link_capacity.append([])
        for u_int in range(model.max_node_int):
            model.v_to_u_capc_use_of_f[v_int].append([])
            v_id = model._IntToNodeIDMap[v_int]
            u_id = model._IntToNodeIDMap[u_int]

            if (u_id in model.tc.N_conn_inv[v_id]
                    and v_id in model.tc.L_from_nodes[u_id]):
                # If there is link from u to v
                l = model.tc.L_from_nodes[u_id][v_id]
                model.link_capacity[v_int].append(
                    model.model.NewIntVar(
                        0, (int)(l.speed * 1000),
                        "capac_v({})_u({})".format(v_id, u_id)))

                for f_int in range(model.max_stream_int):
                    f_id = model._IntToStreamIDMap[f_int]
                    model.v_to_u_capc_use_of_f[v_int][u_int].append(
                        model.model.NewIntVar(
                            0,
                            (int)(l.speed * 1000),
                            "capac_v({})_u({})_f({})".format(v_id, u_id, f_id),
                        ))
            else:
                model.link_capacity[v_int].append(model.model.NewConstant(0))

                for f_int in range(model.max_stream_int):
                    model.v_to_u_capc_use_of_f[v_int][u_int].append(
                        model.model.NewConstant(0))

    # x,y, ...
    for f_int in range(model.max_stream_int):
        f = model.tc.F_routed[model._IntToStreamIDMap[f_int]]
        model.x.append([])
        model.y.append([])
        model.x_v_has_successor.append([])
        model.x_v_is_u.append([])
        model.x_v_is_not_u.append([])
        model.x_v_is_u_and_uses_bandwidth.append([])
        model.x_v_has_predecessor.append([])
        model.x_v_possible_domain_ids[f.id] = {}
        model.x_v_possible_domain[f.id] = {}
        for v_int in range(model.max_node_int):
            model.x_v_is_u[f_int].append([])
            model.x_v_is_not_u[f_int].append([])
            model.x_v_is_u_and_uses_bandwidth[f_int].append([])

            x_u_has_no_pred = model.model.NewBoolVar(
                "x_{}_{}_has_no_pred".format(f_int, v_int))
            model.x_v_has_predecessor[f_int].append(x_u_has_no_pred)
            v = model.tc.N[model._IntToNodeIDMap[v_int]]

            # x
            possible_domain = [-1]
            possible_domain_strings = ["-1"]

            for u_int in range(model.max_node_int):
                x_v_is_not_u = model.model.NewBoolVar(
                    "x_{}({})_is_not_{}".format(f_int, v_int, u_int))
                x_v_is_u = x_v_is_not_u.Not()
                model.x_v_is_not_u[f_int][v_int].append(x_v_is_not_u)
                model.x_v_is_u[f_int][v_int].append(x_v_is_u)

                x_v_is_u_and_uses_bandwidth = model.model.NewBoolVar(
                    "x_{}({})_is_{}_and_uses_bandwidth".format(
                        f_int, v_int, u_int))
                model.x_v_is_u_and_uses_bandwidth[f_int][v_int].append(
                    x_v_is_u_and_uses_bandwidth)

            for u_id in model.tc.N_conn_inv[v.id]:
                if u_id == v.id:
                    if v.id == f.sender_es_id:
                        # Only append node itself for sender
                        possible_domain.append(model._NodeIDToIntMap[u_id])
                        possible_domain_strings.append(u_id)
                else:
                    possible_domain.append(model._NodeIDToIntMap[u_id])
                    possible_domain_strings.append(u_id)
            model.x[f_int].append(
                model.model.NewIntVarFromDomain(
                    Domain.FromValues(possible_domain),
                    "x_{}({})".format(f.id, v.id)))
            model.x_v_possible_domain[f.id][v.id] = possible_domain
            model.x_v_possible_domain_ids[f.id][v.id] = possible_domain_strings

            # y
            model.y[f_int].append(
                model.model.NewIntVar(-1, model.max_node_int,
                                      "y_{}({})".format(f.id, v.id)))
            # has_successor
            x_v_has_s = model.model.NewBoolVar("x({})_{}_has_successor".format(
                v.id, f.id))
            model.x_v_has_successor[f_int].append(x_v_has_s)
Пример #7
0
 def CreateItemBinAssignmentVariables(self, items):
     binDomains = self.preprocess.BinDomains
     for i, item in enumerate(items):
         itemFeasibleBins = self.model.NewIntVarFromDomain(Domain.FromValues(binDomains[i]), f'b{i}')
         self.placedBinVariables.append(itemFeasibleBins)
Пример #8
0
 def CreateLocalStartVariablesX(self, items, binDx):
     itemNormalPatternsX = self.preprocess.ItemPlacementPatternsX
     for i, item in enumerate(items):
         filteredStartLocalX = [p for p in itemNormalPatternsX[i] if (p % binDx) + item.Dx <= binDx]
         xStart = self.model.NewIntVarFromDomain(Domain.FromValues(filteredStartLocalX),f'x{i}')
         self.startVariablesLocalX.append(xStart)