图着色 Gurobi 约束
Graph coloring Gurobi constraints
我正在尝试使用 networkx 和 gurobi 解决图形着色问题的一些限制。这是我写的所有代码:
import networkx as nx
import gurobi as gb
from itertools import combinations, chain
import pygraphviz as pygv
import os
import matplotlib.pyplot as plt
from IPython.display import SVG, display
创建图,添加节点和边以及两个列表。
G = nx.Graph()
G.add_nodes_from ([1,2,3,4,5])
G.add_edge(1,2)
G.add_edge(1,3)
G.add_edge(1,4)
G.add_edge(1,5)
G.add_edge(2,3)
G.add_edge(2,4)
G.add_edge(3,5)
G.add_edge(4,5)
U = list(G.nodes)
K = G.number_of_edges()
Z = []
正在创建一个包含颜色的列表。我们假设 K = {0, 1, . . . , K − 1} 且 K ≤ |E|
def nrofCol():
Z.clear()
z = 0
while z < K - 1:
Z.append(z)
z = z+1
return Z
Z = nrofCol()
为每条边添加颜色属性
for colored_arc in ((u,v,z) for u,v in G.edges() for z in Z):
G[colored_arc[0]][colored_arc[1]][colored_arc[2]] = colored_arc
并使用 Gurobi 向模型添加变量:
mdic = gb.Model()
indices = []
for u,v in G.edges():
for z in Z:
indices.append((u,v,z))
# binary variable that assing 1.0 to the color associated to the edge and 0.0 to the others
x = mdic.addVars(indices, vtype = gb.GRB.BINARY)
# decision variable S i for i ∈ V represents the maximum color in the set of colors assigned to edges incident to vertex i
S_i = []
for u in U:
S_i.append(mdic.addVar(vtype=gb.GRB.CONTINUOUS, lb = G.degree[u] - 1, ub = K - 1, \
name = 'max_color'+str(u)))
# decision variable s_i for i ∈ V represents the minimum color in the set of colors assigned to edges incident to vertex i
s_i = []
for u in U:
s_i.append(mdic.addVar(vtype=gb.GRB.CONTINUOUS, lb = 0.0, ub = K - G.degree[u], \
name='min_color'+str(u)))
mdic.update()
然后是约束:
# 1a- Guarantee that adjacent edges take different colors
for u in U:
for z in Z:
mdic.addConstr(x.sum(u,'*',z) <= 1, name='different_color')
mdic.update()
# 1a- Guarantee that adjacent edges take different colors
for u in U:
for z in Z:
mdic.addConstr(x.sum('*',u,z) <= 1, name='different_color')
mdic.update()
# 1b- Guarantee that every edge takes exactly one color
for u,v in G.edges():
mdic.addConstr(x.sum(u,v) == 1, name='one_color')
mdic.update()
# 1c- Enforce Si to be greater than or equal to the max color assigned to the edges incident to vertex i
expr = 0
for u,v in G.edges():
for z in Z:
expr += z * x[u,v,z]
mdic.addConstr(S_i[u] >= expr, name='max')
expr = 0
# 1d- Enforce si to be less than or equal to the min color assigned to the edges incident to vertex i
expr = 0
for u,v in G.edges():
for z in Z:
expr += z * x[u,v,z]
mdic.addConstr(s_i[u] <= expr, name='min')
expr = 0
mdic.update()
其中 Z 是一组可用颜色。
# objective function
expr20=0
for u in U:
expr20+=(S_i[u] - s_i[u] - G.degree[u] + 1)
mdic.setObjective(expr20, gb.GRB.MINIMIZE)
mdic.update()
mdic.optimize()
Constraints
第一个是objective函数,1a到1d是约束,其他是ub和lb。
假设你用的是无向图,我发现了几个问题:
屏幕截图中的约束 (1a) 可确保相邻边具有不同的颜色。但是,随着您实施此约束,可能会发生传入和传出边缘具有相同颜色的情况。例如,边 {1,3} 和 {3,5} 可以具有相同的颜色。那是因为您分别处理传入和传出边缘。作为解决方案,您可以将循环合并为一个:
for u in U:
for z in Z:
mdic.addConstr(x.sum(u,'*',z) + x.sum('*',u,z) <= 1, name='different_color')
约束 (1c) 在您的实现中也只考虑传出边。例如,S_i[5]
不会被分配,因为它只有传入边。这应该有效:
expr = 0
for u,v in G.edges():
for z in Z:
expr += z * x[u,v,z]
mdic.addConstr(S_i[u] >= expr, name='max')
mdic.addConstr(S_i[v] >= expr, name='max')
expr = 0
约束(1d)也是如此。此外 addConstr
行在循环之外,但这可能只是格式错误:
expr = 0
for u,v in G.edges():
for z in Z:
expr += z * x[u,v,z]
mdic.addConstr(s_i[u] <= expr, name='min')
mdic.addConstr(s_i[v] <= expr, name='min')
expr = 0
我正在尝试使用 networkx 和 gurobi 解决图形着色问题的一些限制。这是我写的所有代码:
import networkx as nx
import gurobi as gb
from itertools import combinations, chain
import pygraphviz as pygv
import os
import matplotlib.pyplot as plt
from IPython.display import SVG, display
创建图,添加节点和边以及两个列表。
G = nx.Graph()
G.add_nodes_from ([1,2,3,4,5])
G.add_edge(1,2)
G.add_edge(1,3)
G.add_edge(1,4)
G.add_edge(1,5)
G.add_edge(2,3)
G.add_edge(2,4)
G.add_edge(3,5)
G.add_edge(4,5)
U = list(G.nodes)
K = G.number_of_edges()
Z = []
正在创建一个包含颜色的列表。我们假设 K = {0, 1, . . . , K − 1} 且 K ≤ |E|
def nrofCol():
Z.clear()
z = 0
while z < K - 1:
Z.append(z)
z = z+1
return Z
Z = nrofCol()
为每条边添加颜色属性
for colored_arc in ((u,v,z) for u,v in G.edges() for z in Z):
G[colored_arc[0]][colored_arc[1]][colored_arc[2]] = colored_arc
并使用 Gurobi 向模型添加变量:
mdic = gb.Model()
indices = []
for u,v in G.edges():
for z in Z:
indices.append((u,v,z))
# binary variable that assing 1.0 to the color associated to the edge and 0.0 to the others
x = mdic.addVars(indices, vtype = gb.GRB.BINARY)
# decision variable S i for i ∈ V represents the maximum color in the set of colors assigned to edges incident to vertex i
S_i = []
for u in U:
S_i.append(mdic.addVar(vtype=gb.GRB.CONTINUOUS, lb = G.degree[u] - 1, ub = K - 1, \
name = 'max_color'+str(u)))
# decision variable s_i for i ∈ V represents the minimum color in the set of colors assigned to edges incident to vertex i
s_i = []
for u in U:
s_i.append(mdic.addVar(vtype=gb.GRB.CONTINUOUS, lb = 0.0, ub = K - G.degree[u], \
name='min_color'+str(u)))
mdic.update()
然后是约束:
# 1a- Guarantee that adjacent edges take different colors
for u in U:
for z in Z:
mdic.addConstr(x.sum(u,'*',z) <= 1, name='different_color')
mdic.update()
# 1a- Guarantee that adjacent edges take different colors
for u in U:
for z in Z:
mdic.addConstr(x.sum('*',u,z) <= 1, name='different_color')
mdic.update()
# 1b- Guarantee that every edge takes exactly one color
for u,v in G.edges():
mdic.addConstr(x.sum(u,v) == 1, name='one_color')
mdic.update()
# 1c- Enforce Si to be greater than or equal to the max color assigned to the edges incident to vertex i
expr = 0
for u,v in G.edges():
for z in Z:
expr += z * x[u,v,z]
mdic.addConstr(S_i[u] >= expr, name='max')
expr = 0
# 1d- Enforce si to be less than or equal to the min color assigned to the edges incident to vertex i
expr = 0
for u,v in G.edges():
for z in Z:
expr += z * x[u,v,z]
mdic.addConstr(s_i[u] <= expr, name='min')
expr = 0
mdic.update()
其中 Z 是一组可用颜色。
# objective function
expr20=0
for u in U:
expr20+=(S_i[u] - s_i[u] - G.degree[u] + 1)
mdic.setObjective(expr20, gb.GRB.MINIMIZE)
mdic.update()
mdic.optimize()
Constraints
第一个是objective函数,1a到1d是约束,其他是ub和lb。
假设你用的是无向图,我发现了几个问题:
屏幕截图中的约束 (1a) 可确保相邻边具有不同的颜色。但是,随着您实施此约束,可能会发生传入和传出边缘具有相同颜色的情况。例如,边 {1,3} 和 {3,5} 可以具有相同的颜色。那是因为您分别处理传入和传出边缘。作为解决方案,您可以将循环合并为一个:
for u in U:
for z in Z:
mdic.addConstr(x.sum(u,'*',z) + x.sum('*',u,z) <= 1, name='different_color')
约束 (1c) 在您的实现中也只考虑传出边。例如,S_i[5]
不会被分配,因为它只有传入边。这应该有效:
expr = 0
for u,v in G.edges():
for z in Z:
expr += z * x[u,v,z]
mdic.addConstr(S_i[u] >= expr, name='max')
mdic.addConstr(S_i[v] >= expr, name='max')
expr = 0
约束(1d)也是如此。此外 addConstr
行在循环之外,但这可能只是格式错误:
expr = 0
for u,v in G.edges():
for z in Z:
expr += z * x[u,v,z]
mdic.addConstr(s_i[u] <= expr, name='min')
mdic.addConstr(s_i[v] <= expr, name='min')
expr = 0