Запись файла журнала COIN-OR CBC
Я использую CBC-решатель COIN-OR для решения некоторых задач численной оптимизации. Я структурирую проблему оптимизации в Python через PuLP.
Я заметил, что решатели, такие как 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, пытаясь понять это.
2 ответа
Для решения, требующего всего несколько строк кода в вашем сценарии, который вызывает PuLP и CBC, см. Решение Джеймса Фогеля (возможно, https://github.com/voglster) по адресу https://groups.google.com/forum/, основываясь на 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
аргумент согласован (в PuLP >= 2.2) среди нескольких решателей: PULP_CBC_CMD, COIN_CMD, PULP_COIN_CMD, GUROBI, CPLEX, CPLEX_CMD, GUROBI_CMD.
Я не смог найти ответ без изменения 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
переводчик называет это. Я открываю файл, используя этот идентификатор, и передаю его этому аргументу. как это:
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 для получения дополнительной документации. Так как это создает разные файлы для каждого идентификатора процесса, я думаю, что это решит вашу проблему параллельного запуска нескольких решателей.