Skip to content

Commit 8c0f4c3

Browse files
Merge pull request #1021 from SebastianM-C/smc/ipopt2
IpoptOptimizer now stores solver specific options and the callbacks are faster
2 parents b32c9be + 848da41 commit 8c0f4c3

File tree

9 files changed

+468
-119
lines changed

9 files changed

+468
-119
lines changed

docs/src/optimization_packages/ipopt.md

Lines changed: 108 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -42,61 +42,130 @@ The algorithm supports:
4242
- Box constraints via `lb` and `ub` in the `OptimizationProblem`
4343
- General nonlinear equality and inequality constraints via `lcons` and `ucons`
4444

45+
### Basic Usage
46+
47+
```julia
48+
using Optimization, OptimizationIpopt
49+
50+
# Create optimizer with default settings
51+
opt = IpoptOptimizer()
52+
53+
# Or configure Ipopt-specific options
54+
opt = IpoptOptimizer(
55+
acceptable_tol = 1e-8,
56+
mu_strategy = "adaptive"
57+
)
58+
59+
# Solve the problem
60+
sol = solve(prob, opt)
61+
```
62+
4563
## Options and Parameters
4664

47-
### Common Options
65+
### Common Interface Options
4866

49-
The following options can be passed as keyword arguments to `solve`:
67+
The following options can be passed as keyword arguments to `solve` and follow the common Optimization.jl interface:
5068

51-
- `maxiters`: Maximum number of iterations (maps to Ipopt's `max_iter`)
52-
- `maxtime`: Maximum wall time in seconds (maps to Ipopt's `max_wall_time`)
69+
- `maxiters`: Maximum number of iterations (overrides Ipopt's `max_iter`)
70+
- `maxtime`: Maximum wall time in seconds (overrides Ipopt's `max_wall_time`)
5371
- `abstol`: Absolute tolerance (not directly used by Ipopt)
54-
- `reltol`: Convergence tolerance (maps to Ipopt's `tol`)
55-
- `verbose`: Control output verbosity
72+
- `reltol`: Convergence tolerance (overrides Ipopt's `tol`)
73+
- `verbose`: Control output verbosity (overrides Ipopt's `print_level`)
5674
- `false` or `0`: No output
5775
- `true` or `5`: Standard output
58-
- Integer values 0-12: Different verbosity levels (maps to `print_level`)
59-
- `hessian_approximation`: Method for Hessian computation
60-
- `"exact"` (default): Use exact Hessian
61-
- `"limited-memory"`: Use L-BFGS approximation
76+
- Integer values 0-12: Different verbosity levels
6277

63-
### Advanced Ipopt Options
78+
### IpoptOptimizer Constructor Options
6479

65-
Any Ipopt option can be passed directly as keyword arguments. The full list of available options is documented in the [Ipopt Options Reference](https://coin-or.github.io/Ipopt/OPTIONS.html). Common options include:
80+
Ipopt-specific options are passed to the `IpoptOptimizer` constructor. The most commonly used options are available as struct fields:
6681

67-
#### Convergence Options
68-
- `tol`: Desired convergence tolerance (relative)
69-
- `dual_inf_tol`: Dual infeasibility tolerance
70-
- `constr_viol_tol`: Constraint violation tolerance
71-
- `compl_inf_tol`: Complementarity tolerance
82+
#### Termination Options
83+
- `acceptable_tol::Float64 = 1e-6`: Acceptable convergence tolerance (relative)
84+
- `acceptable_iter::Int = 15`: Number of acceptable iterations before termination
85+
- `dual_inf_tol::Float64 = 1.0`: Desired threshold for dual infeasibility
86+
- `constr_viol_tol::Float64 = 1e-4`: Desired threshold for constraint violation
87+
- `compl_inf_tol::Float64 = 1e-4`: Desired threshold for complementarity conditions
7288

73-
#### Algorithm Options
74-
- `linear_solver`: Linear solver to use
89+
#### Linear Solver Options
90+
- `linear_solver::String = "mumps"`: Linear solver to use
7591
- Default: "mumps" (included with Ipopt)
7692
- HSL solvers: "ma27", "ma57", "ma86", "ma97" (require [separate installation](https://github.com/jump-dev/Ipopt.jl?tab=readme-ov-file#linear-solvers))
7793
- Others: "pardiso", "spral" (require [separate installation](https://github.com/jump-dev/Ipopt.jl?tab=readme-ov-file#linear-solvers))
78-
- `nlp_scaling_method`: Scaling method ("gradient-based", "none", "equilibration-based")
79-
- `limited_memory_max_history`: History size for L-BFGS (when using `hessian_approximation="limited-memory"`)
80-
- `mu_strategy`: Update strategy for barrier parameter ("monotone", "adaptive")
94+
- `linear_system_scaling::String = "none"`: Method for scaling linear system. Use "mc19" for HSL solvers.
95+
96+
#### NLP Scaling Options
97+
- `nlp_scaling_method::String = "gradient-based"`: Scaling method for NLP
98+
- Options: "none", "user-scaling", "gradient-based", "equilibration-based"
99+
- `nlp_scaling_max_gradient::Float64 = 100.0`: Maximum gradient after scaling
100+
101+
#### Barrier Parameter Options
102+
- `mu_strategy::String = "monotone"`: Update strategy for barrier parameter ("monotone", "adaptive")
103+
- `mu_init::Float64 = 0.1`: Initial value for barrier parameter
104+
- `mu_oracle::String = "quality-function"`: Oracle for adaptive mu strategy
105+
106+
#### Hessian Options
107+
- `hessian_approximation::String = "exact"`: How to approximate the Hessian
108+
- `"exact"`: Use exact Hessian
109+
- `"limited-memory"`: Use L-BFGS approximation
110+
- `limited_memory_max_history::Int = 6`: History size for L-BFGS
111+
- `limited_memory_update_type::String = "bfgs"`: Quasi-Newton update formula ("bfgs", "sr1")
81112

82113
#### Line Search Options
83-
- `line_search_method`: Line search method ("filter", "penalty")
84-
- `alpha_for_y`: Step size for constraint multipliers
85-
- `recalc_y`: Control when multipliers are recalculated
114+
- `line_search_method::String = "filter"`: Line search method ("filter", "penalty")
115+
- `accept_every_trial_step::String = "no"`: Accept every trial step (disables line search)
86116

87117
#### Output Options
88-
- `print_timing_statistics`: Print detailed timing information ("yes"/"no")
89-
- `print_info_string`: Print user-defined info string ("yes"/"no")
118+
- `print_timing_statistics::String = "no"`: Print detailed timing information
119+
- `print_info_string::String = "no"`: Print algorithm info string
120+
121+
#### Warm Start Options
122+
- `warm_start_init_point::String = "no"`: Use warm start from previous solution
90123

91-
Example with advanced options:
124+
#### Restoration Phase Options
125+
- `expect_infeasible_problem::String = "no"`: Enable if problem is expected to be infeasible
126+
127+
### Additional Options Dictionary
128+
129+
For Ipopt options not available as struct fields, use the `additional_options` dictionary:
92130

93131
```julia
94-
sol = solve(prob, IpoptOptimizer();
95-
maxiters = 1000,
96-
tol = 1e-8,
132+
opt = IpoptOptimizer(
97133
linear_solver = "ma57",
98-
mu_strategy = "adaptive",
99-
print_timing_statistics = "yes"
134+
additional_options = Dict(
135+
"derivative_test" => "first-order",
136+
"derivative_test_tol" => 1e-4,
137+
"fixed_variable_treatment" => "make_parameter",
138+
"alpha_for_y" => "primal"
139+
)
140+
)
141+
```
142+
143+
The full list of available options is documented in the [Ipopt Options Reference](https://coin-or.github.io/Ipopt/OPTIONS.html).
144+
145+
### Option Priority
146+
147+
Options follow this priority order (highest to lowest):
148+
1. Common interface arguments passed to `solve` (e.g., `reltol`, `maxiters`)
149+
2. Options in `additional_options` dictionary
150+
3. Struct field values in `IpoptOptimizer`
151+
152+
Example with multiple option sources:
153+
154+
```julia
155+
opt = IpoptOptimizer(
156+
acceptable_tol = 1e-6, # Struct field
157+
mu_strategy = "adaptive", # Struct field
158+
linear_solver = "ma57", # Struct field (needs HSL)
159+
print_timing_statistics = "yes", # Struct field
160+
additional_options = Dict(
161+
"alpha_for_y" => "primal", # Not a struct field
162+
"max_iter" => 500 # Will be overridden by maxiters below
163+
)
164+
)
165+
166+
sol = solve(prob, opt;
167+
maxiters = 1000, # Overrides max_iter in additional_options
168+
reltol = 1e-8 # Sets Ipopt's tol
100169
)
101170
```
102171

@@ -189,9 +258,9 @@ optfunc = OptimizationFunction(rosenbrock_nd, AutoZygote())
189258
prob = OptimizationProblem(optfunc, x0, p)
190259
191260
# Use L-BFGS approximation for Hessian
192-
sol = solve(prob, IpoptOptimizer();
261+
sol = solve(prob, IpoptOptimizer(
193262
hessian_approximation = "limited-memory",
194-
limited_memory_max_history = 10,
263+
limited_memory_max_history = 10);
195264
maxiters = 1000)
196265
```
197266

@@ -235,8 +304,8 @@ prob = OptimizationProblem(optfunc, w0;
235304
ucons = [0.0, Inf])
236305
237306
sol = solve(prob, IpoptOptimizer();
238-
tol = 1e-8,
239-
print_level = 5)
307+
reltol = 1e-8,
308+
verbose = 5)
240309
241310
println("Optimal weights: ", sol.u)
242311
println("Expected return: ", dot(μ, sol.u))
@@ -249,13 +318,13 @@ println("Portfolio variance: ", sol.objective)
249318

250319
2. **Initial Points**: Provide good initial guesses when possible. Ipopt is a local optimizer and the solution quality depends on the starting point.
251320

252-
3. **Hessian Approximation**: For large problems or when Hessian computation is expensive, use `hessian_approximation = "limited-memory"`.
321+
3. **Hessian Approximation**: For large problems or when Hessian computation is expensive, use `hessian_approximation = "limited-memory"` in the `IpoptOptimizer` constructor.
253322

254323
4. **Linear Solver Selection**: The choice of linear solver can significantly impact performance. For large problems, consider using HSL solvers (ma27, ma57, ma86, ma97). Note that HSL solvers require [separate installation](https://github.com/jump-dev/Ipopt.jl?tab=readme-ov-file#linear-solvers) - see the Ipopt.jl documentation for setup instructions. The default MUMPS solver works well for small to medium problems.
255324

256325
5. **Constraint Formulation**: Ipopt handles equality constraints well. When possible, formulate constraints as equalities rather than pairs of inequalities.
257326

258-
6. **Warm Starting**: When solving a sequence of similar problems, use the solution from the previous problem as the initial point for the next.
327+
6. **Warm Starting**: When solving a sequence of similar problems, use the solution from the previous problem as the initial point for the next. You can enable warm starting with `IpoptOptimizer(warm_start_init_point = "yes")`.
259328

260329
## References
261330

lib/OptimizationIpopt/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OptimizationIpopt"
22
uuid = "43fad042-7963-4b32-ab19-e2a4f9a67124"
33
authors = ["Sebastian Micluța-Câmpeanu <[email protected]> and contributors"]
4-
version = "0.1.2"
4+
version = "0.2.0"
55

66
[deps]
77
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"

0 commit comments

Comments
 (0)