Запись файла журнала 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, пытаясь понять это.


person Andrew    schedule 29.10.2014    source источник


Ответы (3)


Для решения, требующего всего нескольких строк кода в вашем сценарии, который вызывает PuLP и CBC, см. Решение Джеймса Фогеля (https://github.com/voglster, возможно) на https://groups.google.com/forum/#!topic/pulp-or-discuss/itbmTC7uNCQ на основе 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 в текущем каталоге.

person David Kaufman    schedule 26.01.2018
comment
Перенаправление стандартного вывода таким образом было правильным шагом - спасибо! - person Andrew; 04.02.2018

Мне не удалось найти ответ, не изменив pulp исходный код, но если вас это не беспокоит, то воспользуйтесь следующим маршрутом:

перейдите в каталог вашей библиотеки установки 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. Поскольку это создает отдельный файл для каждого идентификатора процесса, я думаю, что это решит вашу проблему параллельного запуска нескольких решателей.

person Mike    schedule 11.02.2015
comment
Майк, это тоже хорошее решение - спасибо за ваш подход! - person Andrew; 04.02.2018

Повторно используя ответ @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.

person pchtsp    schedule 05.07.2020