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

Improving the Performance of IPOPT in EAGO #130

Open
stumarcus314 opened this issue May 31, 2024 · 7 comments
Open

Improving the Performance of IPOPT in EAGO #130

stumarcus314 opened this issue May 31, 2024 · 7 comments

Comments

@stumarcus314
Copy link

There is some advice here for improving the performance of the version of IPOPT used by EAGO by compiling an optimized version of IPOPT.
https://psorlab.github.io/EAGO.jl/dev/optimizer/high_performance/#Ipopt-Build

Rather than compiling a new version of IPOPT, is it possible to instead improve the peformance of IPOPT in EAGO, by using set_attribute to select the linear solver, as described here?
https://github.com/jump-dev/Ipopt.jl?tab=readme-ov-file#linear-solvers

Is it possible to select MKL instead of OpenBLAS for the BLAS & LAPACK backend library used by IPOPT and the linear solvers in EAGO by using the code below before creating the EAGO model? https://github.com/jump-dev/Ipopt.jl?tab=readme-ov-file#blas-and-lapack
using MKL # Replace OpenBLAS by Intel MKL
using Ipopt
using EAGO
model = Model(EAGO.Optimizer)

@RXGottlieb
Copy link
Member

Based on the README for Ipopt, it looks like it should be possible as of Julia v1.9. We're still in the process of updating our overall documentation---we'll look into this as well to make sure it works as intended and update accordingly.

@stumarcus314
Copy link
Author

How would one set the IPOPT linear solver to SPRAL? Based on the IPOPT subsolver code in EAGO.jl (https://github.com/PSORLab/EAGO.jl/blob/master/src/subsolvers/ipopt.jl), the following attempt does not work.

using IntervalArithmetic; setrounding(Interval, :accurate)
using EAGO, COPT
eago_factory = () -> EAGO.Optimizer(SubSolvers(; r = COPT.Optimizer()))
model = Model(eago_factory)
MOI.set(model, MOI.RawOptimizerAttribute("linear_solver"), "spral") # Try to set IPOPT's linear solver to SPRAL.
MOI.set(model, MOI.RawOptimizerAttribute("spral_use_gpu"), "yes") # Run SPRAL on the GPU.


$ julia create_model.jl
Number of pulses: 256.
Cardinal Optimizer v7.1.3. Build date Apr 29 2024
Copyright Cardinal Operations 2024. All Rights Reserved
ERROR: LoadError: type Optimizer has no field linear_solver
Stacktrace:
[1] set(m::Optimizer{EAGO.Incremental{COPT.Optimizer}, EAGO.Incremental{Ipopt.Optimizer}, EAGO.DefaultExt}, p::MathOptInterface.RawOptimizerAttribute, x::String)
@ EAGO ~/.julia/packages/EAGO/7BNFB/src/eago_optimizer/moi_wrapper.jl:212
[2] set
@ ~/.julia/packages/MathOptInterface/2CULs/src/Bridges/bridge_optimizer.jl:955 [inlined]
[3] set(model::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{Optimizer{EAGO.Incremental{COPT.Optimizer}, EAGO.Incremental{Ipopt.Optimizer}, EAGO.DefaultExt}}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, attr::MathOptInterface.RawOptimizerAttribute, value::String)
@ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/2CULs/src/Utilities/cachingoptimizer.jl:1059
[4] set(m::Model, attr::MathOptInterface.RawOptimizerAttribute, value::String)
@ JuMP ~/.julia/packages/JuMP/Gwn88/src/optimizer_interface.jl:794
[5] macro expansion
@ ~/julia_code/Gen7_BPM/create_model.jl:156 [inlined]
[6] top-level scope
@ ./timing.jl:395
in expression starting at /home/stuart/julia_code/Gen7_BPM/create_model.jl:85

@RXGottlieb
Copy link
Member

EAGO sets subsolver parameters in two ways. The first is by overloading set_default_config! where the m field is the subsolver whose properties you are trying to set. The src/subsolvers/ipopt.jl file is an example of this: when EAGO solves upper problems, the settings in ipopt.jl are the settings that get passed to IPOPT. If you want to change the default parameters for IPOPT using this method, you would need to overload the set_default_config! function from ipopt.jl to reflect the different parameters you want.

The second way EAGO sets subsolver parameters is by setting the EAGOParameter called "user_solver_config" to true, and then setting parameters using MOI.set with the subsolver as the object. You need to set "user_solver_config" => true, or else your settings will be overwritten by set_default_config! when the subsolver is used. For your case, it might look something like this:

using IntervalArithmetic; setrounding(Interval, :accurate)
using JuMP, EAGO # (and COPT, if you want that as the subsolver)

eago_factory = () -> EAGO.Optimizer(SubSolvers())
model = Model(optimizer_with_attributes(eago_factory, "user_solver_config" => true))

upper_optimizer = model.moi_backend.optimizer.model.subsolver_block.upper_optimizer.optimizer.model

MOI.set(upper_optimizer, MOI.RawOptimizerAttribute("linear_solver"), "spral") # Try to set IPOPT's linear solver to SPRAL.
MOI.set(upper_optimizer, MOI.RawOptimizerAttribute("spral_use_gpu"), "yes") # Run SPRAL on the GPU.

#[variables/constraints/objective]

optimize!(model)

@stumarcus314
Copy link
Author

Thanks for the advice. I have used the second method. In the second method, are the default parameters (such as "tol" and "constr_viol_tol") set in src/subsolvers/ipopt.jl used by IPOPT, if those parameters are not set in upper_optimizer by MOI.set? That is, are the upper_optimizer parameters set after first calling set_default_config!?

@RXGottlieb
Copy link
Member

The default parameters in set_default_config! are only used if "user_solver_config" is set to false (which is the default). If you want parameters such as tol to be set, and you have "user_solver_config" => true, you'll need to set those yourself as well.

@stumarcus314
Copy link
Author

If I modify the file ~/.julia/packages/EAGO/7BNFB/src/subsolvers/ipopt.jl in my Julia installation, will those changes be reflected when I use EAGO.jl to solve a JuMP model? Does the input parameter local_solver to the function set_default_config! equal true?

@RXGottlieb
Copy link
Member

If you're looking to change the default behavior of EAGO, it's probably a better idea to create your own fork of EAGO and modify/use that. If you're only making changes for solving individual optimization problems, you should use one of the methods I described earlier to change subsolver parameters without changing the default EAGO operation.

The input parameter local_solver is there to indicate whether the settings are being used for a relaxed optimizer (local_solver=false) or upper optimizer (local_solver=true). IPOPT is the default upper optimizer, so the version of set_default_config! in src/subsolvers/ipopt.jl will typically be called with local_solver=true.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants