Skip to content
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

feat: add flexibility for solvers besides Gurobi #99

Merged
merged 3 commits into from
Jan 29, 2021

Conversation

danielolsen
Copy link
Contributor

@danielolsen danielolsen commented Jan 27, 2021

Purpose

Add flexibility for solvers besides Gurobi. Closes #97

What is the code doing

In loop.jl:

  • we add a function symbolize (unrelated refactor to clean up the manual conversion from a Dict of strings to a NamedTuple within interval_loop).
  • we add a function new_model, which returns a new JuMP model. This function can take either a Gurobi environment, or an optimizer factory.
  • in interval_loop:
    • we change the inputs, so that we can pass either a Gurobi environment or any other optimizer factory.
    • instead of hardcoding that we create a new model from the passed Gurobi environment, we use the new_model function.
    • we only activate `BarHomogeneous if we are using Gurobi
    • we use our new symbolize function for succinctness (unrelated)

In REISE.jl, we add a new optional input optimizer_factory

  • if this is not given, we start a Gurobi environment, just like before. We also put Gurobi-specific stuff within if block.
  • if this is given, we pass this to interval_loop

Testing

This has been tested with both Clp.jl and GLPK.jl, as well as in the default mode with Gurobi.

with GLPK.jl installed:

import REISE
import GLPK
REISE.run_scenario(; interval=1, n_interval=3, start_index=1, inputfolder="path_to_your_local_input_files", optimizer_factory=GLPK.Optimizer)

with Clp.jl installed:

import REISE
import Clp
REISE.run_scenario(; interval=1, n_interval=3, start_index=1, inputfolder="path_to_your_local_input_files", optimizer_factory=Clp.Optimizer)

Time to review

30 minutes.

@danielolsen danielolsen added the new feature Feature that is currently in progress. label Jan 27, 2021
println("Connection closed successfully!")
if isa(optimizer_factory, Gurobi.Env)
Gurobi.finalize(optimizer_factory)
println("Connection closed successfully!")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to do similar thing for other solvers or this is something to explore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know that other solvers have a similar 'environment' feature that needs to be managed.

Comment on lines +7 to +11
function new_model(factory_like)::Union{JuMP.Model, JuMP.MOI.AbstractOptimizer}
if isa(factory_like, Gurobi.Env)
return JuMP.direct_model(Gurobi.Optimizer(factory_like))
else
return JuMP.Model(factory_like)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this implies JuMP treats Gurobi differently but all the other solvers in the same way?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to use the direct_model feature to be able to pass the Gurobi environment to the Gurobi.Optimizer.

@danielolsen
Copy link
Contributor Author

@BainanXia we can have JuMP treat Gurobi the same as all of the other optimizers if we call

import REISE
import Gurobi
REISE.run_scenario(; interval=1, n_interval=3, start_index=1, inputfolder="path_to_your_local_input_files", optimizer_factory=Gurobi.Optimizer)

@BainanXia
Copy link
Collaborator

@BainanXia we can have JuMP treat Gurobi the same as all of the other optimizers if we call

import REISE
import Gurobi
REISE.run_scenario(; interval=1, n_interval=3, start_index=1, inputfolder="path_to_your_local_input_files", optimizer_factory=Gurobi.Optimizer)

Good to know. I think it is better to make Gurobi one of the options instead of one special option?

@danielolsen
Copy link
Contributor Author

Good to know. I think it is better to make Gurobi one of the options instead of one special option?

The reason that we have the 'special' code for Gurobi is because we want to have the ability to reuse a single Gurobi environment for all of the solves, for performance reasons. I don't think there's any convenient way to pass this to run_scenario though, unless we handle the creation of the Gurobi environment and the related cleanup section outside of this function.

For example, we could refactor run_scenario/interval_loop/new_model to take either an optimizer factory, or an optimizer factory + a list of arguments + solver settings, and then we would call some new function run_scenario_gurobi_env which would create an env, pass it with the solver_kwargs and Gurobi.Optimizer to run_scenario etc., and then clean up afterwards. Then run_scenario wouldn't have anything Gurobi-specific in it, although interval_loop still requires us to know which solver we are using to be able to know which solver settings are available and how to modify them as we run into infeasibilities.

@BainanXia
Copy link
Collaborator

Good to know. I think it is better to make Gurobi one of the options instead of one special option?

The reason that we have the 'special' code for Gurobi is because we want to have the ability to reuse a single Gurobi environment for all of the solves, for performance reasons. I don't think there's any convenient way to pass this to run_scenario though, unless we handle the creation of the Gurobi environment and the related cleanup section outside of this function.

For example, we could refactor run_scenario/interval_loop/new_model to take either an optimizer factory, or an optimizer factory + a list of arguments + solver settings, and then we would call some new function run_scenario_gurobi_env which would create an env, pass it with the solver_kwargs and Gurobi.Optimizer to run_scenario etc., and then clean up afterwards. Then run_scenario wouldn't have anything Gurobi-specific in it, although interval_loop still requires us to know which solver we are using to be able to know which solver settings are available and how to modify them as we run into infeasibilities.

For other solvers, if possible, we also want to reuse the environment setup for all of the solves to improve the performance, right?

@danielolsen
Copy link
Contributor Author

For other solvers, if possible, we also want to reuse the environment setup for all of the solves to improve the performance, right?

It depends. Some solvers have that capability, some do not. Some solvers don't even let you reassign values for constraints, etc. Using JuMP.Model is the most general way to interface with a variety of different solvers. direct_model lets you do some things that can improve performance (if they are supported by the solver), with some drawbacks (see https://jump.dev/JuMP.jl/stable/solvers/#JuMP.direct_model). I don't think there are any commands in JuMP to make the 'reuse the same environment' calls generalizeable across many different solvers.

Copy link
Collaborator

@BainanXia BainanXia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given @danielolsen has tested with optimizations, I think for now this is good enough to have such capability only. We may explore in the future on how to support other solvers better, but given we are focusing on Gurobi, it is reasonable to say our framework is optimized based on Gurobi, which is obviously the suggested solver.

start_index, inputfolder, outputfolder)

Given:
- a Gurobi environment `env`
- optimizer instantiation object `factory_like`:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering about the term factory_like...I'm not sure exactly what it communicates. Maybe something like factory_spec or factory_env or optimization_factory_env, etc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's either an optimization factory or a Gurobi environment.

@danielolsen danielolsen merged commit 3ef5619 into develop Jan 29, 2021
@danielolsen danielolsen deleted the daniel/other_solvers branch January 29, 2021 02:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature Feature that is currently in progress.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add functionality to select the solver to be used
3 participants