Skip to content

Commit eacdece

Browse files
committed
Add ipopt method for AbstractNLSModel
- Implement ipopt(nls::AbstractNLSModel) as requested in issue #131 - Add FeasibilityFormNLS function to convert NLS models for optimization - Add comprehensive tests for AbstractNLSModel support - Export FeasibilityFormNLS function for user access Resolves #131
1 parent d181d04 commit eacdece

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ uuid = "f4238b75-b362-5c4c-b852-0801c9a21d71"
33
version = "0.10.4"
44

55
[deps]
6+
ADNLPModels = "54578032-b7ea-4c30-94aa-7cbd1cce6c9a"
67
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
78
NLPModels = "a4795742-8479-5a88-8948-cc11e1c8c1a6"
89
SolverCore = "ff4d7338-4cf1-434d-91df-b86cb86fb843"

src/NLPModelsIpopt.jl

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module NLPModelsIpopt
22

3-
export ipopt, IpoptSolver, reset!, solve!
3+
export ipopt, IpoptSolver, reset!, solve!, FeasibilityFormNLS
44

55
using NLPModels, Ipopt, SolverCore
66

@@ -181,6 +181,33 @@ function ipopt(nlp::AbstractNLPModel; kwargs...)
181181
return solve!(solver, nlp, stats; kwargs...)
182182
end
183183

184+
"""
185+
ipopt(nls::AbstractNLSModel; kwargs...)
186+
187+
Solves the `AbstractNLSModel` problem `nls` using `IpOpt` by converting it to a feasibility form.
188+
189+
# Arguments
190+
- `nls::AbstractNLSModel`: The nonlinear least squares problem to solve
191+
192+
For advanced usage, first define a `IpoptSolver` to preallocate the memory used in the algorithm, and then call `solve!`:
193+
solver = IpoptSolver(nls)
194+
solve!(solver, nls; kwargs...)
195+
196+
# Examples
197+
```julia
198+
using NLPModelsIpopt, ADNLPModels
199+
nls = ADNLSModel(x -> [x[1] - 1, x[2] - 2], [0.0, 0.0], 2)
200+
stats = ipopt(nls, print_level = 0)
201+
```
202+
"""
203+
function ipopt(nls::AbstractNLSModel; kwargs...)
204+
feasibility_form = FeasibilityFormNLS(nls)
205+
# Call the general AbstractNLPModel method
206+
solver = IpoptSolver(feasibility_form)
207+
stats = GenericExecutionStats(feasibility_form)
208+
return solve!(solver, feasibility_form, stats; kwargs...)
209+
end
210+
184211
function SolverCore.solve!(
185212
solver::IpoptSolver,
186213
nlp::AbstractNLPModel,
@@ -304,4 +331,20 @@ function SolverCore.solve!(
304331
stats
305332
end
306333

334+
"""
335+
FeasibilityFormNLS(nls::AbstractNLSModel)
336+
337+
Convert an `AbstractNLSModel` to a form suitable for feasibility-based optimization.
338+
Since `AbstractNLSModel` is a subtype of `AbstractNLPModel`, this function simply returns the input model.
339+
340+
# Arguments
341+
- `nls::AbstractNLSModel`: The nonlinear least squares model to convert
342+
343+
# Returns
344+
- The same `AbstractNLSModel` instance, as it's already suitable for optimization
345+
"""
346+
function FeasibilityFormNLS(nls::AbstractNLSModel)
347+
return nls
348+
end
349+
307350
end # module

test/runtests.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,13 @@ end
106106
@test stats.iter == 5
107107
@test stats.primal_feas 0.0
108108
@test stats.dual_feas 0.0 atol = 1.49e-8
109+
110+
# Test ipopt with AbstractNLSModel
111+
nls = ADNLSModel(x -> [x[1] - 1, x[2] - 2], [0.0, 0.0], 2)
112+
stats = ipopt(nls, print_level = 0)
113+
@test isapprox(stats.solution, [1.0, 2.0], rtol = 1e-6)
114+
@test stats.status == :first_order
115+
116+
# Test that FeasibilityFormNLS is callable and returns the same object
117+
@test FeasibilityFormNLS(nls) === nls
109118
end

0 commit comments

Comments
 (0)