简体   繁体   English

PuLP 仅显示 __dummy 变量

[英]PuLP only shows __dummy variable

I am trying to use PuLP on dummy graph coloring problem.我正在尝试在虚拟图形着色问题上使用 PuLP。 To solve the problem, we need to assign a colour to each node such that any adjacent nodes don't share a common colour while minimising the total number of colours used.为了解决这个问题,我们需要为每个节点分配一种颜色,这样任何相邻节点都不会共享一个公共颜色,同时尽量减少使用的颜色总数。

Here's a dummy data:这是一个虚拟数据:

edges = [('A', 'H'), ('A', 'B'), ('H', 'G'), ('H', 'K'), ('H', 'J'), 
         ('H', 'I'), ('G', 'F'), ('G', 'K'), ('F', 'E'), ('K', 'E'), 
         ('K', 'J'), ('K', 'D'), ('I', 'J'), ('I', 'D'), ('D', 'C'), 
         ('D', 'B')]
nodes = set(sum(edges, ()))
n_nodes = len(nodes)

Using Google's OR-Tools, I can find a solution:使用谷歌的 OR-Tools,我可以找到一个解决方案:

from ortools.sat.python import cp_model

model = cp_model.CpModel()

# Set decision variables
var = {}
for node in nodes:
    var[node] = model.NewIntVar(0, n_nodes-1, node)

# Set objective
model.Minimize(len(set(var.values())))

# Add constraints
for edge in edges:
    model.Add(var[edge[0]] != var[edge[1]])

# Solve
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
    print('Status: Optimal \n')

for node in nodes:
    print(f"{node}: {solver.Value(var[node])}")

Returns:回报:

Status: Optimal 

C: 0
A: 5
H: 4
K: 2
F: 1
E: 0
D: 1
J: 0
I: 2
B: 0
G: 3

Side note: While the status says optimal, I feel less colours could be used.旁注:虽然状态显示为最佳,但我觉得可以使用的颜色更少。

However, when using the similar approach with PuLP, I am unable to see any solution.但是,当对 PuLP 使用类似的方法时,我看不到任何解决方案。

from pulp import *

model = LpProblem("coloring", LpMinimize)

# Set decision variables
var = {}
for node in nodes:
    var[node] = LpVariable(node, lowBound=0, upBound=n_nodes-1, cat=LpInteger)

# Set objective
model += len(set(var.values()))

# Add constraints
for edge in edges:
    model += var[edge[0]] != var[edge[1]]

# Solve
status = model.solve()
print(f'Status: {LpStatus[status]} \n')

for variable in prob.variables():
    print(f"{variable.name}, {v.varValue}")

Returns:回报:

Status: Optimal 

__dummy, None

Any help on where I have gone wrong would be greatly appreciated.任何关于我哪里出错的帮助将不胜感激。

So you've got 2 issues in your formulation that are causing you problems.因此,您的配方中有两个问题会导致您出现问题。 First the len(set(...)) is a non-linear operation.首先len(set(...))是一个非线性操作。 when you add expressions to the problem they need to be expressed as linear equations.当您将表达式添加到问题中时,它们需要表示为线性方程。 Your constraint has the same issue.你的约束有同样的问题。 Your logic is correct, but you cannot pass x != y to the solver, that is also non-linear.您的逻辑是正确的,但您不能将x != y传递给求解器,这也是非线性的。 You have to look at how to formulate these pieces of logic with linear expressions to reformulate.你必须看看如何用线性表达式来重新制定这些逻辑。

Note, that you can always print(model) in pulp to see what was built, if you print yours, nothing useful comes up... who knows how these things are evaluated and put into the model.请注意,您始终可以在纸浆中print(model)以查看构建的内容,如果您打印自己的,则没有任何有用的东西出现……谁知道如何评估这些东西并将其放入模型中。 I suspect they are evaluated once at construction and you are throwing trivial expressions into the model like x = True or something, and not getting errors.我怀疑它们在构造时会被评估一次,并且您将琐碎的表达式投入到模型中,例如 x = True 或其他东西,并且不会出错。

So here is an alternate formulation of your problem with linear expressions.因此,这是线性表达式问题的另一种表述。 The this_color != that_color constraint is a little complex and relies on an indicator variable to enable the either-or construct. this_color != that_color约束有点复杂,它依赖于指示变量来启用非此即彼的构造。

I don't use Google's OR Tools much, but it is mostly just syntactic sugar on top of these concepts, so perhaps there is a way to elegantly state it in OR Tools, but at the end of the day, something like this is getting generated and passed to the solver.我很少使用 Google 的 OR 工具,但它主要是这些概念之上的语法糖,所以也许有一种方法可以在 OR 工具中优雅地陈述它,但归根结底,这样的事情正在发生生成并传递给求解器。

There may be a better formulation of this in graph theory, but this works fine for simple ILP.图论中可能对此有更好的表述,但这对于简单的 ILP 来说效果很好。 3 colors is the answer. 3种颜色就是答案。

from pulp import *

edges = [('A', 'H'), ('A', 'B'), ('H', 'G'), ('H', 'K'), ('H', 'J'), 
         ('H', 'I'), ('G', 'F'), ('G', 'K'), ('F', 'E'), ('K', 'E'), 
         ('K', 'J'), ('K', 'D'), ('I', 'J'), ('I', 'D'), ('D', 'C'), 
         ('D', 'B')]
nodes = set(sum(edges, ()))
n_nodes = len(nodes)
M = n_nodes + 1

model = LpProblem("coloring", LpMinimize)

# Set decision variables
color = {}
for node in nodes:
    color[node] = LpVariable(node, lowBound=1, cat=LpInteger)
num_colors = LpVariable('count', cat = LpInteger)

color_diff = {}
for idx, edge in enumerate(edges):
    color_diff[edge] = LpVariable(str(idx), cat=LpBinary)

# Set objective
# model += len(set(var.values()))
model += num_colors   # seek to minimize the maximal color index

# Add constraints

# get the max value of the colors...
for node in nodes:
    model += num_colors >= color[node]

# ensure the adjacent nodes are different color
for edge in edges:
    # force one or the other of these to be true, based on the color_diff
    # variable, which is just a binary indicator
    model += -M * color_diff[edge] + 1 <= color[edge[0]] - color[edge[1]]
    model += -M * (1-color_diff[edge]) + 1 <= color[edge[1]] - color[edge[0]]  

# Solve
status = model.solve()
print(f'Status: {LpStatus[status]} \n')

for variable in model.variables():
    print(f"{variable.name}, {variable.varValue}")

Yields产量

Result - Optimal solution found

Objective value:                3.00000000
Enumerated nodes:               0
Total iterations:               0
Time (CPU seconds):             0.01
Time (Wallclock seconds):       0.01

Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.01   (Wallclock seconds):       0.01

Status: Optimal 

0, 1.0
1, 0.0
10, 0.0
11, 1.0
12, 0.0
13, 1.0
14, 0.0
15, 0.0
2, 0.0
3, 0.0
4, 0.0
5, 0.0
6, 1.0
7, 1.0
8, 0.0
9, 0.0
A, 2.0
B, 1.0
C, 1.0
D, 3.0
E, 1.0
F, 3.0
G, 1.0
H, 3.0
I, 2.0
J, 1.0
K, 2.0
count, 3.0
[Finished in 96ms]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM