6

我正在使用 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 交互会话数小时试图弄清楚这一点。

4

3 回答 3

3

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

导航到您的纸浆安装库的目录并查看该solvers.py文件。

感兴趣的功能solve_CBCCOIN_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 创建一个不同的文件,我认为它将解决您并行运行多个求解器的问题。

于 2015-02-11T23:07:57.583 回答
3

对于在调用 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这会在当前目录中为您留下有用的信息。

于 2018-01-26T20:47:40.433 回答
1

重用@Mike 的答案,PuLP(自 2.2 起)现在包括通过将logPath参数与要写入的文件的路径一起传递来将日志写入文件的可能性。

所以你现在可以这样做:

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

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

The logPath argument is consistent (in PuLP >= 2.2) among several solvers: PULP_CBC_CMD, COIN_CMD, PULP_COIN_CMD, GUROBI, CPLEX, CPLEX_CMD, GUROBI_CMD.

于 2020-07-05T22:02:55.300 回答