예제 #1
0
    def _init_edge_deps(self):
        self.delays = {node: self.model.addVar(name="delay_{}".format(node.node_id)) for node in self.nodes}
        for edge in self.forward_edges:
            src_node = self.id_to_node_lookup[edge.src]
            dst_node = self.id_to_node_lookup[edge.dst]
            # if they're not in the same partition, then guarantee inequality.
            dst_candidates = self._candidate_partitions(dst_node)
            enforce_inequality = self.model.addVar(name="enforce_inequality_{}".format(edge.out_id), vtype=GRB.BINARY)
            for partition_type in self._candidate_partitions(src_node):
                src_row = self._get_row(partition_type, src_node)
                if partition_type not in dst_candidates:
                    self.model.addConstr((enforce_inequality == 0) >> (gpy.quicksum(src_row) == 0),
                                         name="edge_dep_pt_constraint_{}_{}".format(edge.out_id,
                                                                                    partition_type.typename))
                    continue
                dst_row = self._get_row(partition_type, dst_node)
                for i, diff in enumerate(src_row - dst_row):
                    self.model.addConstr((enforce_inequality == 0) >> (diff == 0),
                                         name="edge_dep_pt_constraint_{}_{}_{}".format(edge.out_id,
                                                                                       partition_type.typename, i))
            self.model.addConstr(self.delays[src_node] + enforce_inequality <= self.delays[dst_node],
                                 name="edge_dep_{}".format(edge.out_id))

        # for each node, compute its partition delay. Then constrain that the partition delay and actual delay are
        # close.

        self.partition_delays = {
            partition_type: self._create_matrix("partition_delays_{}".format(partition_type.typename), (count,)) for
            partition_type, count in
            self.partition_counts.items()}

        max_delay = self.num_nodes
        for pt_type, delay_vec in self.partition_delays.items():
            for i, delay in enumerate(delay_vec.flatten()):
                self.model.addConstr(delay <= max_delay, name="max_delay_{}_{}".format(pt_type.typename, i))

        for node in self.nodes:
            target_delay_min = []
            target_delay_max = []
            for partition_type, node_to_loc in self.node_to_loc_map.items():
                if node not in node_to_loc:
                    continue

                # constrain that if node in partition, then delay[node] == delay[partition]
                loc = node_to_loc[node]
                row = self.partition_matrices[partition_type][loc, :]
                # we really just want row @ partition_delays[partition_type] but this is a quadratic constraint
                # instead, formulate as two sided constraint.
                activation = row * -max_delay + max_delay
                target_delay_min.extend(self.partition_delays[partition_type] + activation)

                activation = row * max_delay - max_delay
                target_delay_max.extend(self.partition_delays[partition_type] + activation)
            target_min = self._convert_to_var(gpy.min_(*self._convert_to_var(target_delay_min)),
                                              name="target_delay_min_{}".format(node.node_id))
            # target_max = self._convert_to_var(gpy.max_(*self._convert_to_var(target_delay_max)),
            #                                   name="target_delay_max_{}".format(node.node_id))
            self.model.addConstr(self.delays[node] == target_min, name="delay_target_min_{}".format(node.node_id))
예제 #2
0
# 方法2:使用Gurobi的接口
import gurobipy as grb

m = grb.Model()
x = m.addVar(name='x')
y = m.addVar(name='y')
z = m.addVar(name='z')
m.addConstr(x == 4, name='c4')
m.addConstr(y == 5, name='c5')
m.addConstr(z == grb.min_(x, y, 3))
m.setObjective(z)
m.optimize()
print("最小值是:z=", z.X)
# 输出 z= 3.0
예제 #3
0
def MIP(probType,
        K,
        numEdges,
        numNodes,
        maxTime,
        graph=None,
        Edges=None,
        prob=None,
        seed=None,
        improvements=None):
    if improvements == None:
        improvements = {
            "start_at_leaf_constraint": False,
            "start_at_leaf_BP": False,
            "start_at_leaf_hint": False,
            "dont_visit_searched_leaves": False,
            "travel_towards_unsearched": False,
            "barrier_log": False,
            "Y_cts": False,
            "early_X_BP": False,
            "Y_BP": False,
            "high_prob_edges_BP": False
        }
    # sets
    if seed is None:
        seed = random.seed()
    if graph is None:
        graph, prob, Edges, _ = generateNetwork(numEdges, numNodes, probType,
                                                seed)
    if prob is None:
        prob, Edges = generateProbabilities(graph, probType)
    if Edges is None:
        Edges = genEdges(graph)

    # gen set of arcs
    Arcs = genArcs(graph)
    # gen set of nodes
    Nodes = genNodes(graph)

    # set of leaf arcs
    leafArcs = genLeaf(graph)

    # dict containing all the arcs that start at the ending node of each arc
    arcCon = genSuccessors(graph, Arcs)

    T = range(maxTime + 1)
    S = {}  # whether arc a begins at node n
    E = {}  # whether arc a ends at node n
    O = {}  # whether arc a is on edge e

    # define values for functions S, E and O and store in dict.
    for a in Arcs:
        for e in Edges:
            if a == e or (a[1], a[0]) == e:
                O[a, e] = 1
            else:
                O[a, e] = 0
        for n in Nodes:
            if a[0] == n:
                S[a, n] = 1
                E[a, n] = 0
            elif a[1] == n:
                E[a, n] = 1
                S[a, n] = 0
            else:
                S[a, n] = 0
                E[a, n] = 0

    # model
    mip = Model("Model searchers searching for a randomly distributed immobile" \
                "target on a unit network")

    # variables

    # X[t, a] = 1 if we traverse arc a at time t, 0 otherwise
    X = {(t, a): mip.addVar(vtype=GRB.BINARY) for t in T[1:] for a in Arcs}

    if improvements['start_at_leaf_BP']:
        for (t, a) in X:
            if a in leafArcs and t == 1:
                for x in arcCon[a]:
                    # if a shares a node with another leaf arc
                    if x in leafArcs:
                        # higher branch priority than many other variables yet lower
                        # than the variables for leaf arcs that aren't next to
                        # another leaf
                        X[t, a].BranchPriority = 15
                    else:
                        # higher branch priority because these leaf arcs will have
                        # bigger impact on mip gap
                        X[t, a].BranchPriority = 25

    if improvements['early_X_BP']:
        for (t, a) in X:
            # for earlier times, these have highest branch priority, but as time
            # goes on their contribution gets less significant
            X[t, a].BranchPriority = max(1, 2 * maxTime - 5 * t)

    # constraints

    if improvements['Y_cts']:
        """ This improvement simplifies the MIP by removing the alpha variables
        and allowing the Y variables to be continuous """
        # Y is a continuous variable indicating whether an edge has been searched at
        # time t or not- it will take maximal value of 1 when edge has been searched
        Y = {(t, e): mip.addVar(ub=1) for t in T for e in Edges}

        # objective
        mip.setObjective(
            maxTime + 1 / 2 - quicksum(Y[t, e] * prob[e] for e in Edges
                                       for t in T[1:]), GRB.MINIMIZE)
    else:
        # Y[t, e] = 1 if we have searched edge e by time t, 0 otherwise
        Y = {(t, e): mip.addVar(vtype=GRB.BINARY) for t in T for e in Edges}

        #alpha[t] is the probability that the target is not found by time t
        alpha = {t: mip.addVar() for t in T}

        # objective
        mip.setObjective(
            quicksum((alpha[t - 1] + alpha[t]) / 2 for t in T[1:]),
            GRB.MINIMIZE)

        # define alpha as in paper
        defAlpha = {
            t: mip.addConstr(alpha[t] == 1 - quicksum(prob[e] * Y[t, e]
                                                      for e in Edges))
            for t in T
        }

    if improvements['Y_BP']:
        # YT[t] is the number of new edges we explore at time t- only defined for
        # early time points because these are the decisions with the most impact
        # when branched upon
        YT = {t: mip.addVar() for t in range(1, 4)}
        defYT = {
            t: mip.addConstr(quicksum(Y[t, e] for e in Edges) == YT[t])
            for t in YT
        }
        for t in YT:
            # branch priority starts at 10 (higher than many other variables but
            # lower than others we are setting branch priorities for) and decreases
            # with t
            YT[t].BranchPriority = 10 - 2 * t

    # num arcs searched can't exceed num searchers- implicitly defines capacity
    searcherLim = {
        t: mip.addConstr(quicksum(X[t, a] for a in Arcs) <= K)
        for t in T[1:]
    }

    # update search info after every time step
    updateSearch = {
        (t, e):
        mip.addConstr(Y[t, e] <= Y[t - 1, e] + quicksum(O[a, e] * X[t, a]
                                                        for a in Arcs))
        for t in T[1:] for e in Edges
    }

    # conserve arc flow on nodes
    consFlow = {(t, n): mip.addConstr(
        quicksum(E[a, n] * X[t, a]
                 for a in Arcs) == quicksum(S[a, n] * X[t + 1, a]
                                            for a in Arcs))
                for t in T[1:-1] for n in Nodes}

    # initially, no edges have been searched
    initY = {e: mip.addConstr(Y[0, e] == 0) for e in Edges}

    # limit y so that every edge is searched by T
    everyEdgeSearched = {e: mip.addConstr(Y[maxTime, e] == 1) for e in Edges}

    if improvements['start_at_leaf_constraint']:
        # must have at least 1 searcher beginning at a leaf
        if probType == UNIFORM and len(leafArcs) != 0:
            mip.addConstr(quicksum(X[1, l] for l in leafArcs) >= 1)

    if improvements['start_at_leaf_hint'] and probType == UNIFORM:
        # hint to gurobi to start searchers at leaf nodes
        for a in leafArcs:
            X[1, a].VarHintVal = 1

    if improvements['high_prob_edges_BP']:
        #if non-uniform, we preferably want to start by searching edges with high
        #probs first- branch on this
        if probType == NON_UNIFORM:
            maxEdges = getMaxEdges(Edges, prob)
            XE = mip.addVar(vtype=GRB.INTEGER)
            defXe = mip.addConstr(XE == quicksum(X[1, a] for a in Arcs
                                                 if getEdge(a, Edges, O)))
            XE.BranchPriority = 15

    if improvements['dont_visit_searched_leaves']:
        # don't search a leaf edge if it has already been searched
        leafConstraints = {
            (t, a): mip.addConstr(X[t, a] <= 1 - quicksum(O[a, e] * Y[t - 1, e]
                                                          for e in Edges))
            for t in T[1:] for a in Arcs if a[::-1] in leafArcs
        }

    if improvements['travel_towards_unsearched']:
        # add a constraint that only permits an arc to be searched if it either
        # a) puts us closer to an unsearched edge
        # b) all edges have already been searched

        distances = shortest_paths(graph)
        closer = {}
        further = {}
        for a in Arcs:
            closer[a] = []
            further[a] = []
            for e in Edges:
                if distance(a[1], e, distances) < distance(a[0], e, distances):
                    closer[a].append(e)
                elif a == e or a == e[::-1]:
                    closer[a].append(e)
                else:
                    further[a].append(e)

        numEdgesUnsearched = {t: mip.addVar(vtype=GRB.INTEGER) for t in T[1:]}
        someEdgesUnsearched = {t: mip.addVar(vtype=GRB.BINARY) for t in T[1:]}

        for t in T[1:]:
            mip.addConstr(numEdgesUnsearched[t] == quicksum(1 - Y[t, e]
                                                            for e in Edges))
            mip.addConstr(
                someEdgesUnsearched[t] == min_(1, numEdgesUnsearched[t]))

        moveTowardsUnsearched = {
            (t, a): mip.addConstr(X[t, a] <= quicksum(1 - Y[t - 1, e]
                                                      for e in closer[a]) + 1 -
                                  someEdgesUnsearched[t - 1])
            for t in T[2:] for a in Arcs
        }

    #Parameter Adjustments
    #Set the maximum time to 900 seconds
    mip.setParam('TimeLimit', 900.0)

    if improvements['barrier_log']:
        # Run barrier algorithm for mip root node
        mip.setParam("Method", 2)

    #set optimality gap to 0
    mip.setParam('MipGap', 0)
    mip.optimize()

    #Display Search Path
    state = {
        "X": X,
        "Y": Y,
        "T": T,
        "E": Edges,
        "L": leafArcs,
        "A": Arcs,
        "N": Nodes,
        "maxTime": maxTime,
        "seed": seed
    }
    # if you want to visualise the strategy, uncomment the below line
    #visualiseStrategy(state, graph)

    return mip, graph, state
    # Link Xi and notXi
    model.addConstrs((Lit[i] + NotLit[i] == 1.0 for i in range(NLITERALS)),
                     name="CNSTR_X")

    # Link clauses and literals
    for i, c in enumerate(Clauses):
        clause = []
        for l in c:
            if l >= n:
                clause.append(NotLit[l - n])
            else:
                clause.append(Lit[l])
        model.addConstr(Cla[i] == gp.or_(clause), "CNSTR_Clause" + str(i))

    # Link objs with clauses
    model.addConstr(Obj0 == gp.min_(Cla), name="CNSTR_Obj0")
    model.addConstr((Obj1 == 1) >> (Cla.sum() >= 4.0), name="CNSTR_Obj1")

    # Set optimization objective
    model.setObjective(Obj0 + Obj1, GRB.MAXIMIZE)

    # Save problem
    model.write("genconstr.mps")
    model.write("genconstr.lp")

    # Optimize
    model.optimize()

    # Status checking
    status = model.getAttr(GRB.Attr.Status)