为图形着色问题定义CVXPY变量

时间:2019-05-04 19:04:49

标签: python-3.x linear-programming cvxpy mixed-integer-programming

我正在尝试解决最小的图形着色问题。我正在尝试使用cvxpy将其解决为mip。我正在遵循此网址中描述的解决方案的概述:

https://manas.tech/blog/2010/09/16/modelling-graph-coloring-with-integer-linear-programming.html

我不确定我是否了解如何正确创建cvxpy变量以及如何定义约束。下面有示例输入数据,以及创建变量,约束和目标函数,解决问题和返回解决方案的代码。

我认为此输入的正确答案应该是:

‘2 1\n0 1 0 0’

这是要求的最小颜色数为2,除节点1外,所有节点都为相同颜色。

我正在创建w变量以计算所用颜色的数量:

w = cvxpy.Variable(j, boolean=True)

我想我正在做的是创建一个长度等于节点数的二进制变量。这样的想法是,您可以使用的最大颜色数将等于节点数。所以最大颜色:

w=[1,1,1,1]

我将w描绘成一个二进制变量,例如一个列表,其中的值可以是0或1,表示该颜色是否被任何节点使用。

然后创建目标函数:

obj=cvxpy.sum(w,axis=0)

我想我正在对行中的条目求和,因此,例如:

w=[1,1,0,0]

obj=2

我还创建了一个变量x来指示给定节点的颜色:

x = cvxpy.Variable((j,int(first_line[0])), boolean=True)

我将其描述为带有二进制值的二维数组,其中列表示节点,行表示颜色。

因此,例如,如果节点0的颜色为0,节点1的颜色为1,节点2的颜色为2,节点3的颜色为2,我可以想象x看起来像:

[[1,0,0,0],[0,1,0,0],[0,0,1,1],[0,0,0,0]]

有人可以告诉我我是否正确理解并正确创建了选择变量?我也理解并正确创建了目标函数吗?这就是我描述目标函数的方式是否与我创建目标函数的方式相匹配?并感谢您对我定义的其他约束或代码的任何输入。我正在学习线性编程,并且试图理解cvxpy语法。

样本数据:

input_data

'4 3\n0 1\n1 2\n1 3\n'


# parse the input
lines = input_data.split('\n')

first_line = lines[0].split()
node_count = int(first_line[0])
edge_count = int(first_line[1])

edges = []
for i in range(1, edge_count + 1):
    line = lines[i]
    parts = line.split()
    edges.append((int(parts[0]), int(parts[1])))


edges

# Output:
[(0, 1), (1, 2), (1, 3)]


# solution using cvxpy solver
import numpy as np
import cvxpy

from collections import namedtuple


# selection variables
# binary variable if at least one node is color j

j=int(first_line[0])


# w=1 if at least one node has color j
w = cvxpy.Variable(j, boolean=True)


# x=1 if node i is color j

x = cvxpy.Variable((j,int(first_line[0])), boolean=True)


# Objective function
# minimize number of colors needed

obj=cvxpy.sum(w,axis=0)



# constraints

# 1 color per node

node_color=cvxpy.sum(x,axis=1)==1



# for adjacent nodes at most 1 node has color
diff_col = []

for edge in edges:
    for k in range(node_count):
        diff_col += [
            # x[edge[0],k]+x[edge[1],k]<=1
            x[k,edge[0]]+x[k,edge[1]]<=1
        ]


# w is upper bound for color of node x<=w

upper_bound = []

for i in range(j):
    for k in range(j):
        upper_bound += [
            x[k,i]<=w[i]
        ]


# constraints
constraints=[node_color]+diff_col+upper_bound



# solving problem

# cvxpy must be passed as a list
graph_problem = cvxpy.Problem(cvxpy.Minimize(obj), constraints)

# Solving the problem
graph_problem.solve(solver=cvxpy.GLPK_MI)

value2=int(graph_problem.solve(solver=cvxpy.GLPK_MI))
# taken2=[int(i) for i in selection.value.tolist()]
# taken2=[int(i) for i in w.value.tolist()]
taken2=[int(i) for i in w.value.tolist()]

# prepare the solution in the specified output format
output_data2 = str(value2) + ' ' + str(0) + '\n'
output_data2 += ' '.join(map(str, taken2))


output_data2

'1 0\n0 0 0 1'

1 个答案:

答案 0 :(得分:0)

您的解决方案几乎是正确的。这里的主要问题是变量x的定义。根据博客文章

  

x_ {ij}变量,当且仅当节点i被分配了颜色j时才会为真

表示x的大小为(节点nb,颜色nb)。

在您的代码中,您需要将x更改为:

x = cvxpy.Variable((node_count, j), boolean=True)

,然后是第二和第三个约束:

# for adjacent nodes at most 1 node has color
diff_col = []

for edge in edges:
    for k in range(j):
        diff_col += [
            x[edge[0],k]+x[edge[1],k]<=1
        ]


# w is upper bound for color of node x<=w

upper_bound = []

for i in range(node_count):
    for k in range(j):
        upper_bound += [
            x[i,k]<=w[k]
        ]

然后输出是预期的,即使用2种颜色:节点1的一种颜色和节点0、2、3的另一种颜色(因为它们不相邻)。