Python 写入COIN-OR CBC日志文件

Python 写入COIN-OR CBC日志文件,python,python-2.7,mathematical-optimization,pulp,coin-or-cbc,Python,Python 2.7,Mathematical Optimization,Pulp,Coin Or Cbc,我正在使用COIN-OR的CBC解算器来解决一些数值优化问题。我正在用Python通过纸浆构建优化问题 我注意到像GUROBI和CPLEX这样的解算器会创建日志文件,但我似乎不知道如何让CBC创建日志文件(而不是将优化器的进度打印到屏幕上) 有人知道CBC中有设置日志文件的选项吗?将所有stdout重新定向到一个文件对我来说不起作用,因为我并行地解决了一系列问题,并且希望将它们的日志文件分开 下面是我如何调用解算器的示例。这非常有效,可以将进度打印到终端 prob.solve(pulp.COIN

我正在使用COIN-OR的CBC解算器来解决一些数值优化问题。我正在用Python通过纸浆构建优化问题

我注意到像GUROBI和CPLEX这样的解算器会创建日志文件,但我似乎不知道如何让CBC创建日志文件(而不是将优化器的进度打印到屏幕上)

有人知道CBC中有设置日志文件的选项吗?将所有stdout重新定向到一个文件对我来说不起作用,因为我并行地解决了一系列问题,并且希望将它们的日志文件分开

下面是我如何调用解算器的示例。这非常有效,可以将进度打印到终端

prob.solve(pulp.COIN_CMD(msg=1, options=['DivingVectorlength on','DivingSome on']))
下面是我认为应该如何构造解决方案(尽管LogFileName显然不是有效的CBC选项)


在此方面的任何帮助都将不胜感激。我在互联网、文档和CBC互动会话中花了几个小时试图弄明白这一点。

如果不更改
源代码,我无法找到答案,但如果您不介意,请采取以下方法:

导航到pulp安装库的目录并查看
solvers.py
文件

感兴趣的函数是
COIN\u CMD
类中的
solve\u CBC
。在该方法中,参数形成一个命令,传递给
cbc-64
solver程序,然后使用
subprocess.Popen
方法调用该程序。此方法的
stdout
参数设置为
None
os.devnull
,这两个参数对我们都不是很有用。您可以在第1340行(纸浆1.5.6)上看到流程调用

此来源还显示问题(mps)和解决方案(sol)文件被写入
/tmp
目录(在UNIX机器上),并且文件名包括调用它的解释器的
pid
。我使用这个id打开一个文件并将其传递给那个参数。像这样:

logFilename = os.path.join(self.tmpDir, "%d-cbc.log" % pid)
logFile = open(logFilename, 'a')
cbc = subprocess.Popen((self.path + cmds).split(), stdout = logFile,
                     stderr = pipe)

果然,在
/tmp
目录中,我看到了运行后的日志文件。您可以使用
log N
设置详细性,有关更多文档,请参阅cbc帮助。由于这将为每个进程id创建不同的文件,我认为这将解决并行运行多个解算器的问题。

对于只需要脚本中几行代码即可调用纸浆和CBC的解决方案,请参阅James Vogel(,可能)在的解决方案,它基于
os.dup()
os.dup2()

我希望在这里复制它来防止linkrot不是不合适的,但是请参阅原始文章中逐行的解释和一些我从tempfile包中不了解的复杂内容。我自己的用法不太复杂,使用的是实际的永久文件名:

from os import dup, dup2, close
f = open('capture.txt', 'w')
orig_std_out = dup(1)
dup2(f.fileno(), 1)

status = prob.solve (PULP_CBC_CMD(maxSeconds = i_max_sec, fracGap = d_opt_gap, msg=1))  #  CBC time limit and relative optimality gap tolerance
print('Completion code: %d; Solution status: %s; Best obj value found: %s' % (status, LpStatus[prob.status], value(prob.objective)))    

dup2(orig_std_out, 1)
close(orig_std_out)
f.close()

这将为您在当前目录中的
capture.txt
中留下有用的信息。

重用@Mike的答案,PuLP(从2.2开始)现在可以通过传递
logPath
参数和要写入的文件路径,将日志写入文件

因此,您现在可以执行以下操作:

prob.solve(pulp.COIN_CMD(msg=1, logPath="stats.log", options=['DivingVectorlength on', 'DivingSome on']))
唯一需要注意的是,您不能再“在屏幕上”看到它,因为它将输出重定向到文件。在这种情况下,您不需要给出
msg=1
,只需给出
logPath


在几个解算器中,
logPath
参数是一致的(在palp>=2.2):palp\u CBC\u CMD、COIN\u CMD、palp\u COIN\u CMD、GUROBI、CPLEX、CPLEX\u CMD、GUROBI\u CMD。

以这种方式重定向stdout是正确的做法-谢谢!迈克,这也是一个很好的解决方案-谢谢你的方法!
from os import dup, dup2, close
f = open('capture.txt', 'w')
orig_std_out = dup(1)
dup2(f.fileno(), 1)

status = prob.solve (PULP_CBC_CMD(maxSeconds = i_max_sec, fracGap = d_opt_gap, msg=1))  #  CBC time limit and relative optimality gap tolerance
print('Completion code: %d; Solution status: %s; Best obj value found: %s' % (status, LpStatus[prob.status], value(prob.objective)))    

dup2(orig_std_out, 1)
close(orig_std_out)
f.close()
prob.solve(pulp.COIN_CMD(msg=1, logPath="stats.log", options=['DivingVectorlength on', 'DivingSome on']))