-
Notifications
You must be signed in to change notification settings - Fork 92
Add emptycopy #387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add emptycopy #387
Conversation
Codecov Report
@@ Coverage Diff @@
## master #387 +/- ##
==========================================
+ Coverage 96.35% 96.37% +0.02%
==========================================
Files 39 39
Lines 4913 4913
==========================================
+ Hits 4734 4735 +1
+ Misses 179 178 -1
Continue to review full report at Codecov.
|
""" | ||
emptycopy(model::ModelLike) | ||
|
||
Return an independent empty copy of `model`. This can be used to duplicate a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is exactly is copied over, if anything? Solver parameters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, nothing at all. The solver parameters will be copied if it is followed by copy!
(as we will do in JuMP).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the license environment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the issue with license environment ?
Maybe the easiest is to say that JuMP
uses this by doing emptycopy
followed by copy!
so everything that will not be carried over by copy!
need to be copied by emptycopy
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gurobi has an Env
that needs to be copied when you create a new model. The Env
has both license information and solver parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bump
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emptycopy is not needed anymore thanks to JuMP factories
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a useful function to have, but we're blocked until we define a clear concept for what is copied over to the empty model and how licences should be handled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is still useful, should I open an issue? Or can this PR be closed without one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, we could just close, there is no need for it even if it could be useful
I vote for reviving this proposal and removing |
An argument for factories is that when you do model = Model(Solver.Optimizer()) and internally it does function Model(opt::Optimizer)
new_opt = MOI.empty_copy(opt)
return Model(..., new_opt, ...)
end It seems less clean because the user has to create an optimizer that is not even used. The counter-argument is that an empty optimizer object is light-weight so it does not matter. |
Why not define MOI solver factories? |
Yes, we could do that also. The underlying issue is that most modeling interfaces would typically use strings or enums to select solvers because they have a finite number of solvers available. We don't have that luxury. |
We can make the problem a bit simpler by normalizing the constructors for optimizers. For example, suppose we say that every optimizer needs to have a constructor like: function MyOptimizer(solver_parameters::Array{Pair{String, Any}})
...
end Then we can instantiate an optimizer given its type and its list of parameters (which is plain data). No need for a closure. No In JuMP this could look like: model = Model(optimizer=Ipopt.Optimizer, solve_parameters=["print_level" => 10])
...
set_optimizer(Gurobi.Optimizer, solve_parameters=["env" => my_env, "NodeLimit" => 10])
...
set_optimizer(Pajarito.Optimizer, solve_parameters=["mip_optimizer" => Gurobi.Optimizer, "mip_parameters" => ["NodeLimit" => 10]]) Note I chose to use strings instead of symbols because parameter names aren't identifiers (http://www.juliaopt.org/JuMP.jl/v0.19.0/style/#@enum-vs.-Symbol-1). Ipopt has parameter names with periods in them, for example. Another option is to avoid taking parameters in the constructor when they're not needed at construction time, e.g., set_optimizer(model, Ipopt.Optimizer)
set_solve_parameter(model, "print_level", 10) Some values like license contexts are needed at construction time, but most parameters are not. You then wouldn't have long awkward lists passed to |
That would work
Setting parameters after model creation is not an option if you give a factory to a function which creates a model internally. You can solve it with closure by creating a closure that creates the optimizer, set parameters and return it but this is painful |
I'm proposing this: function instantiate_solver(optimizer_type, constructor_kwargs, solve_params)
optimizer = optimizer_type(;constructor_kwargs...)
for (k, v) in solve_params
set(optimizer, RawParameter(k), v)
end
return optimizer
end You pass |
Defining MOI solver factories fixes this: Juniper.Optimizer(mip_solver = MOI.with_optimizer(Gurobi.Optimizer, OutputFlag=0)) |
I don't support moving OptimizerFactory as-is to MOI. It's a confusing data structure to work with. Look at the definition: I'm more convinced now that we should stop using constructor keyword arguments as the main way to pass solver-specific parameters. Using something like |
I like the idea of simplifying the optimizer constructor. For most solvers, that means that the constructors will now be empty as they don't need any parameter at construction time. However, asking for with_optimizer(MOIU.MockOptimizer, JuMP._MOIModel{Float64}()) Note that if we do |
Exactly.
I'd argue to just delete the The motivation for |
Moving it to v0.10. If someone is willing to do this in the next days, we can move it back to v0.9. |
Can this be closed since we now have |
SGTM |
This is needed to implement
Base.copy
in JuMP. (see jump-dev/JuMP.jl#1300).