[英]Writing COIN-OR CBC Log File
我正在使用 COIN-OR 的 CBC 求解器来解决一些数值优化问题。 我正在通过 PuLP 在 Python 中构建优化问题。
我注意到像 GUROBI 和 CPLEX 这样的求解器会创建日志文件,但我似乎无法弄清楚如何让 CBC 创建日志文件(而不是将优化器的进度打印到屏幕上)。
有人知道 CBC 中设置日志文件的选项吗? 将所有标准输出重定向到一个文件对我来说不起作用,因为我正在并行解决一堆问题并希望将它们的日志文件分开。
这是我如何调用求解器的示例。 这很好用,并将进度打印到终端。
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 互动会议,试图弄清楚这一点。
我无法在不更改pulp
源代码的情况下找到答案,但如果这不打扰您,那么请走以下路线:
导航到您的纸浆安装库的目录并查看solvers.py
文件。
感兴趣的功能是solve_CBC
在COIN_CMD
类。 在该方法中,参数形成单个命令传递给cbc-64
求解器程序,然后使用subprocess.Popen
方法调用它。 此方法的stdout
参数要么设置为None
要么os.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 创建一个不同的文件,我认为它将解决您并行运行多个求解器的问题。
有关在调用 PuLP 和 CBC 的脚本中只需要几行代码的解决方案,请参阅 James Vogel( https://github.com/voglster ,也许)在https://groups.google.com/forum 上的解决方案/#!topic/pulp-or-discuss/itbmTC7uNCQ ,基于os.dup()
和os.dup2()
。
我希望将它复制到这里以防止链接腐烂不是不合适的,但是请参阅原始帖子以获取逐行解释以及我从 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
参数在以下几个求解器中是一致的(在 PuLP >= 2.2 中):PULP_CBC_CMD、COIN_CMD、PULP_COIN_CMD、GUROBI、CPLEX、CPLEX_CMD、GUROBI_CMD。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.