Trying to save MPS from raw solver and problems with MOI.RawSolver()

I am having problems with JuMP.write_to_file which calls MOI.write_to_file. I had some problems using Model with no solver attached (because this calls the MOI function mentioned above and, at the moment, it seems a little memory-hungry and limited, not supporting .rew and the like), so I wanted to try having a solver attached (CPLEX or Gurobi), and using it to write the MPS and started writing an alternative to JuMP.write_to_file that tried to be native if possible, however I am hitting some problems.

My code is here, the highlighted line emphasizes my current problem. Independently of the the model being a direct_model or a Model, I hit a ERROR: OptimizeNotCalled() for trying to get the MOI.RawSolver() from the model object to call the specific solver saving/writing method. I tried MOI.attach_optimizer when it is a Model (and has a CachingOptimizer underlying) but this had no effect.

I guess you need something like:

native_write(model::Model) = native_write(backend(model))
function native_write(model::MOI.Utilities.CachingOptimizer)
    MOI.Utilities.attach_optimizer(model)
    return native_write(model.optimizer)
end
native_write(model::MOI.Bridges.LazyBridgeOptimizer) = native_write(model.model)

function native_write(model::Gurobi.Optimizer)
    # ...
end
function native_write(model::CPLEX.Optimizer)
    # ...
end
1 Like

Thank you very much odow, I thought about pinging you, but it is easter and I did not want to be a bother.

1 Like

Worked like a charm. I kept my old logic to be able to fallback to JuMP.write_to_file if the solver is not recognized by the module (i.e., nobody extended the right functions), so I used your idea to be able to get the raw solver from a Model or direct_model in lines 22–33 of this file.

Now I just need to check if JuMP.read_from_file is able to parse back the native MPS files, XD.

Do you think JuMP/MOI may want to have this functionality in the future? I did not open a issua/PR because I had no time to go through the approval process this time, but in the future I can port this feature to JuMP/MOI.

Just a follow-up, @odow. My version of write_to_file has helped me in a way I did not foresee: debugging Gurobi.

I have found some strange behavior from Gurobi (described in this small Github repo). Basically, if I solve a model that I know to be feasible with three harmless parameters, Gurobi says it is unfeasible, but ditching any the three parameters (that are Threads = 1, Method = 2, and Seed = 1) will make Gurobi find a feasible solution. I sent a message to the Gurobi forums and they opened a request because of it.

The JuMP.write_to_file was unable to create an MPS that replicated this behavior: I had the problem running from Julia, but reading it from the MPS of JuMP.write_to_file did not trigger the same strange behavior. Only when I used my version of the write_to_file that uses Gurobi native machinery, I was able to put my hands on an MPS that replicated the strange behavior (and guaranteed that the problem was not some very strange bug within JuMP/MOI).

@odow, do you think it would be interesting to add a feature request to JuMP asking for a native_write or even a flag passed to write_to_file so it uses the native machinery available? The code I am using is here, I have little time on my hands right now (finding this bug has delayed me), but if the feature request is approved I can slowly dot it through the weekends.

I’m not in favor of native_write.

But what I am in favor of is better documenting how to call the solver APIs. See also How to use feasRelax in Gurobi ? · Issue #407 · jump-dev/Gurobi.jl · GitHub.

We could also define MOI.write_to_file(model::Gurobi.Optimizer, filename::String) inside Gurobi.jl.

The next version of JuMP should include a way to get the Gurobi.Optimizer object, even if there are multiple cache in the way, which should make this easier.

1 Like