简体   繁体   中英

Writing COIN-OR CBC Log File

I'm using COIN-OR's CBC solver to solve some numerical optimization problems. I'm structuring the optimization problem in Python via PuLP.

I've noticed that solvers like GUROBI and CPLEX create log files, but I can't seem to figure out how to get CBC to create a log file (as opposed to printing the optimizer's progress to the screen).

Does anybody know of an option in CBC to set a log file? Re-directing all stdout to a file doesn't work for me, since I'm solving a bunch of problems in parallel and want to keep their log files separate.

Here's an example of how I'm calling the solver. This works great and prints progress to the terminal.

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

Here's how I think a solution should be structured (though obviously LogFileName isn't a valid CBC option).

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

Any help on this would be greatly appreciated. I've been going through the internet, docs, and the CBC interactive session for hours trying to figure this out.

I was unable to find an answer without changing the pulp source code, but if that does not bother you, then take the following route:

navigate to the directory of your pulp install library and look at the solvers.py file.

The function of interest is solve_CBC in the COIN_CMD class. In that method, the arguments are formed into a single command to pass to the cbc-64 solver program, it is then called using the subprocess.Popen method. The stdout argument for this method is either set to None or os.devnull neither of which is very useful for us. You can see the process call on line 1340 (for PuLP 1.5.6).

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

This source also reveals that the problem (mps) and solution (sol) files are written to the /tmp directory (on UNIX machines) and that the file names include the pid of the interpreter calling it. I open a file using this id and pass it to that argument. like this:

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)

Sure enough, in the /tmp directory I see my log files after running. You can set the verbosity with log N see the cbc help for more documentation there. Since this creates a different file for each process id, I think it will solve your problem of running multiple solvers in parallel.

For a solution requiring only a few lines of code in your script that invokes PuLP and CBC, see the solution by James Vogel ( https://github.com/voglster , maybe) at https://groups.google.com/forum/#!topic/pulp-or-discuss/itbmTC7uNCQ , based on os.dup() and os.dup2() .

I hope it isn't inappropriate to copy it here to guard against linkrot, but see the original post for line-by-line explanation and some sophisticated things I don't understand from the tempfile package. My own usage is less sophisticated, using an actual permanent filename:

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()

This leaves you with useful information in capture.txt in the current directory.

Reusing @Mike's answer, PuLP (since 2.2) now includes the possibility to write the log to a file by passing the logPath argument with the path to the file to write.

So you can now do:

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

The only caveat is that you cannot longer see it "on screen", since it redirects the output to the file. You are not required to give msg=1 , just logPath in this case.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM