编写COIN-OR CBC日志文件

时间:2014-10-29 22:51:21

标签: python python-2.7 mathematical-optimization pulp coin-or-cbc

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

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

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

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

prob.solve(pulp.COIN_CMD(msg=1, options=['DivingVectorlength on','DivingSome on']))

以下是我认为应该构建解决方案的方法(虽然显然 LogFileName 不是有效的CBC选项)。

prob.solve(pulp.COIN_CMD(msg=1, options=['DivingVectorlength on', 'DivingSome on', 'LogFileName stats.log']))

对此的任何帮助将不胜感激。我一直在浏览互联网,文档和CBC互动会议几个小时试图解决这个问题。

3 个答案:

答案 0 :(得分:2)

我无法在不更改pulp源代码的情况下找到答案,但如果这不打扰您,请采取以下路线:

导航到纸浆安装库的目录,然后查看solvers.py文件。

感兴趣的功能是solve_CBC类中的COIN_CMD。在该方法中,参数形成一个命令以传递给cbc-64求解程序,然后使用subprocess.Popen方法调用它。此方法的stdout参数设置为Noneos.devnull,这两个参数对我们都没有用。您可以在1340行看到过程调用(对于PuLP 1.5.6)。

cbc = subprocess.Popen((self.path + cmds).split(), stdout = pipe,
                     stderr = pipe)

此源还显示问题(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创建一个不同的文件,我认为它将解决您并行运行多个解算器的问题。

答案 1 :(得分:1)

对于只需要在脚本中调用PuLP和CBC的几行代码的解决方案,请参阅Python subprocess command with pipehttps://github.com/voglster的James Vogel(https://groups.google.com/forum/#!topic/pulp-or-discuss/itbmTC7uNCQ)的解决方案,基于{{1} }和os.dup()

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

os.dup2()

这会在当前目录的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() 中为您提供有用的信息。

答案 2 :(得分:0)

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

所以您现在可以这样做:

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

唯一的警告是您不能再在“屏幕上”看到它,因为它会将输出重定向到文件。在这种情况下,您无需提供msg=1,只需提供logPath

logPath参数在以下几个求解器中是一致的(在PuLP> = 2.2中):PULP_CBC_CMD,COIN_CMD,PULP_COIN_CMD,GUROBI,CPLEX,CPLEX_CMD,GUROBI_CMD。