如何控制根节点中的惰性约束数?

时间:2019-04-09 14:53:28

标签: python gurobi

我正在解决奖品收集TSP并生成削减以消除次要路线的方法。我想生成削减以消除断开的子循环(切削能力= 0),然后,如果没有,则生成“最小切削”切削(0 <切削能力<1)。 问题在于,即使在某些时候,即使子循环的剪切容量小于1,该程序也不会在根节点上添加更多剪切。

有什么办法解决这个问题?

预先感谢

import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from gurobipy import *

def ins_run(n, alpha, t=0):
    np.random.seed(t)

    depot = n + 1

    nodos = [i + 1 for i in range(depot)]
    pos = dict(zip([i for i in nodos],list(map(tuple,np.random.random([n, 2]) * 5))))
    pos[depot] = pos[1]

    c_cam = {(i, j): np.sqrt((pos[i][0] - pos[j][0]) ** 2 + (pos[i][1] - pos[j][1]) ** 2) 
             for i in nodos for j in nodos if i != j}

    c_drone = {e: alpha * c_cam[e] for e in c_cam}  # Velocidad del drone

    return pos, c_cam, c_drone

def delta_out(arcos, i):
    aux = list()
    for e in arcos:
        if e[0] == i:
            aux.append(e)
    return aux

def delta_in(arcos, i):
    aux = list()
    for e in arcos:
        if e[1] == i:
            aux.append(e)
    return aux

def delta_out_S(arcos, S):
    aux = list()
    for i in S:
        for e in delta_out(arcos, i):
            if e[1] not in S:
                aux.append(e)
    return aux

def run_DisconnectedCycle(G, nodos, capacity, peso):
    # Los arcos con valor no nulo tienen capacidad 1 y se determinan todos los subciclos desconectados
    G.remove_edges_from(list(G.edges))
    edges = list()
    for (i, j) in capacity:
        if capacity[i, j] > 1e-8:
            edges.append((i, j))
    G.add_edges_from(edges)
    st_list = list(nx.simple_cycles(G))
    subtour_list = list()
    for i in st_list:
        if 1 not in i:
            peso_subtour = {j: peso[j] for j in i}
            subtour_list.append((i, max(peso_subtour, key=peso_subtour.get)))
    return subtour_list

def run_MinCut(G, nodos, capacity, peso):
    # Para todo j != depot, se hace min-cut. Sobre todos, se elige el subtour mas violado, junto al peso respectivo (gamma)
    G.remove_edges_from(list(G.edges))
    G.add_edges_from(capacity)
    for (i, j) in capacity:
        G[i][j]['capacity'] = capacity[i, j]
    subtour_list = list()
    subtour = None
    for j in nodos:
        if j != 1:
            (cap, (S, S_c)) = nx.minimum_cut(G, 1, j)
            if cap - peso[j] < 0:
                subtour_list.append((cap - peso[j], j, S_c))
    if subtour_list:
        subtour = min(subtour_list, key=lambda x: x[0])
    return subtour     


if __name__ == '__main__':

    def PCTSP_CB(m, where):
        def get_sol(model):
            x_sol = list()
            for e in index_2:
                arco_x = model.cbGetSolution([x[e]])
                if arco_x[0] > 0.5:
                    x_sol.append(e)
            return x_sol

        if where == GRB.Callback.MIPSOL:
            x_recurso = {e: 0 for e in index_2}
            x_sol = get_sol(m)
            for e in x_sol:
                x_recurso[e] = 1

            # SEC en solucion entera  
            G = nx.DiGraph(x_sol)
            subtour_list = list(nx.simple_cycles(G))
            for i in subtour_list:
                if 1 in i:
                    subtour_list.remove(i)
                    break

            for subtour in subtour_list:
                m.cbLazy(quicksum(x[e] for e in delta_out_S(index_2, subtour)) >= gamma[subtour[0]])
                cuts.SEC_int += 1

        elif where == GRB.Callback.MIPNODE:
            depth = m.cbGet(GRB.Callback.MIPNODE_NODCNT)
            if depth == 0:
                x_rec = m.cbGetNodeRel(x)
                gamma_rec = m.cbGetNodeRel(gamma)
                st_DisconnectedCycle = run_DisconnectedCycle(graph.G, nodos, x_rec, gamma_rec)
                st_MinCut = run_MinCut(graph.G, nodos, x_rec, gamma_rec)
                if st_DisconnectedCycle:
                    for subtour in st_DisconnectedCycle:
                        m.cbLazy(quicksum(x[e] for e in delta_out_S(index_2, subtour[0])) >= gamma[subtour[1]])
                        cuts.SEC_frac_DC += 1
                else:
                    # Si no hay subciclos desconectados, se agrega un Min-Cut
                    if st_MinCut:
                        m.cbLazy(quicksum(x[e] for e in delta_out_S(index_2, st_MinCut[2])) >= gamma[st_MinCut[1]])
                        cuts.SEC_frac_MC += 1

    class Graph():
        def __init__(self):
            self.G = nx.DiGraph()
            self.S_track = list()

    class Cuts():
        def __init__(self):
            self.SEC_frac_DC = 0
            self.SEC_frac_MC = 0
            self.SEC_int = 0

    # Data
    n = 30
    seed = 11
    alpha = 0.5
    pos, c, d = ins_run(n, alpha, seed)
    depot = n + 1
    nodos = [i + 1 for i in range(depot)]
    index_2 = [(i, j) for i in nodos for j in nodos if i != j]   
    graph = Graph()
    cuts = Cuts()

    model = Model()
#    model.Params.OutputFlag = 0
    model.Params.LazyConstraints = 1

    x = model.addVars(index_2, vtype=GRB.BINARY, name='x')
    gamma = model.addVars(nodos, vtype=GRB.CONTINUOUS, ub=1, name='z')

    model.addConstrs(quicksum(x[e] for e in delta_in(index_2, i)) == gamma[i] for i in nodos)
    model.addConstrs(quicksum(x[e] for e in delta_out(index_2, i)) == gamma[i] for i in nodos)
    model.addConstr(x[depot, 1] == 1)
    model.addConstr(x[1, depot] == 0)
    model.addConstr(gamma[1] == 1)
    model.addConstr(gamma[depot] == 1)

    model.addConstrs(x[e] <= quicksum(x[r] for r in delta_in(index_2, depot) if r[0] <= e[1]) for e in delta_out(index_2, 1)) 
    model.addConstr(quicksum(gamma[i] for i in nodos) >= round((len(nodos) - 1) / 2 + 0.1) + 1)

    obj = quicksum(x[e] * c[e] for e in index_2)

    model.setObjective(obj, GRB.MINIMIZE)

    model.optimize(PCTSP_CB)

    print(cuts.SEC_frac_DC, cuts.SEC_frac_MC)

0 个答案:

没有答案