Skip to content

Commit 201fc6d

Browse files
authored
Merge pull request #28 from tmigot/abstract-meta
Add abstract meta
2 parents e240a92 + 842fe36 commit 201fc6d

7 files changed

Lines changed: 167 additions & 22 deletions

File tree

src/quasi-newton.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,28 @@ export QuasiNewtonModel, LBFGSModel, LSR1Model
22

33
abstract type QuasiNewtonModel{T, S} <: AbstractNLPModel{T, S} end
44

5-
mutable struct LBFGSModel{T, S, M <: AbstractNLPModel{T, S}} <: QuasiNewtonModel{T, S}
6-
meta::NLPModelMeta{T, S}
5+
mutable struct LBFGSModel{T, S, M <: AbstractNLPModel{T, S}, Meta <: AbstractNLPModelMeta{T, S}} <: QuasiNewtonModel{T, S}
6+
meta::Meta
77
model::M
88
op::LBFGSOperator
99
end
1010

11-
mutable struct LSR1Model{T, S, M <: AbstractNLPModel{T, S}} <: QuasiNewtonModel{T, S}
12-
meta::NLPModelMeta{T, S}
11+
mutable struct LSR1Model{T, S, M <: AbstractNLPModel{T, S}, Meta <: AbstractNLPModelMeta{T, S}} <: QuasiNewtonModel{T, S}
12+
meta::Meta
1313
model::M
1414
op::LSR1Operator
1515
end
1616

1717
"Construct a `LBFGSModel` from another type of model."
1818
function LBFGSModel(nlp::AbstractNLPModel{T, S}; kwargs...) where {T, S}
1919
op = LBFGSOperator(T, nlp.meta.nvar; kwargs...)
20-
return LBFGSModel{T, S, typeof(nlp)}(nlp.meta, nlp, op)
20+
return LBFGSModel{T, S, typeof(nlp), typeof(nlp.meta)}(nlp.meta, nlp, op)
2121
end
2222

2323
"Construct a `LSR1Model` from another type of nlp."
2424
function LSR1Model(nlp::AbstractNLPModel{T, S}; kwargs...) where {T, S}
2525
op = LSR1Operator(T, nlp.meta.nvar; kwargs...)
26-
return LSR1Model{T, S, typeof(nlp)}(nlp.meta, nlp, op)
26+
return LSR1Model{T, S, typeof(nlp), typeof(nlp.meta)}(nlp.meta, nlp, op)
2727
end
2828

2929
NLPModels.show_header(io::IO, nlp::QuasiNewtonModel) =

src/slack-model.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function Base.show(io::IO, nls::SlackNLSModel)
7575
show(io, nls.model.counters)
7676
end
7777

78-
function slack_meta(meta::NLPModelMeta{T, S}; name = meta.name * "-slack") where {T, S}
78+
function slack_meta(meta::AbstractNLPModelMeta{T, S}; name = meta.name * "-slack") where {T, S}
7979
ns = meta.ncon - length(meta.jfix)
8080
jlow = meta.jlow
8181
jupp = meta.jupp

test/nlp/quasi-newton.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
J(x) = [1.0 -2.0; -0.5x[1] -2.0x[2]]
77

88
for (QNM, QNO) in [(LSR1Model, LSR1Operator), (LBFGSModel, LBFGSOperator)],
9-
T in [Float64, Float32]
9+
T in [Float64, Float32], M in [NLPModelMeta, SimpleNLPMeta]
1010

11-
nlp = QNM(SimpleNLPModel(T))
11+
nlp = QNM(SimpleNLPModel(T, M))
1212
n = nlp.meta.nvar
1313
m = nlp.meta.ncon
1414

test/nlp/simple-model.jl

Lines changed: 150 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,144 @@ Modified problem 14 in the Hock-Schittkowski suite
1111
1212
x₀ = [2.0, 2.0].
1313
"""
14-
mutable struct SimpleNLPModel{T, S} <: AbstractNLPModel{T, S}
15-
meta::NLPModelMeta{T, S}
14+
mutable struct SimpleNLPModel{T, S, M <: AbstractNLPModelMeta{T, S}} <: AbstractNLPModel{T, S}
15+
meta::M
1616
counters::Counters
1717
end
1818

19-
function SimpleNLPModel(::Type{T}) where {T}
19+
mutable struct SimpleNLPMeta{T, S} <: AbstractNLPModelMeta{T, S}
20+
nvar::Int
21+
x0::S
22+
lvar::S
23+
uvar::S
24+
25+
ifix::Vector{Int}
26+
ilow::Vector{Int}
27+
iupp::Vector{Int}
28+
irng::Vector{Int}
29+
ifree::Vector{Int}
30+
iinf::Vector{Int}
31+
32+
nlvb::Int
33+
nlvo::Int
34+
nlvc::Int
35+
36+
ncon::Int
37+
y0::S
38+
lcon::S
39+
ucon::S
40+
41+
jfix::Vector{Int}
42+
jlow::Vector{Int}
43+
jupp::Vector{Int}
44+
jrng::Vector{Int}
45+
jfree::Vector{Int}
46+
jinf::Vector{Int}
47+
48+
nnzo::Int
49+
nnzj::Int
50+
nnzh::Int
51+
52+
nlin::Int
53+
nnln::Int
54+
55+
lin::Vector{Int}
56+
nln::Vector{Int}
57+
58+
minimize::Bool
59+
islp::Bool
60+
name::String
61+
function SimpleNLPMeta{T, S}(
62+
nvar::Int;
63+
x0::S = fill!(S(undef, nvar), zero(T)),
64+
lvar::S = fill!(S(undef, nvar), T(-Inf)),
65+
uvar::S = fill!(S(undef, nvar), T(Inf)),
66+
nlvb = nvar,
67+
nlvo = nvar,
68+
nlvc = nvar,
69+
ncon = 0,
70+
y0::S = fill!(S(undef, ncon), zero(T)),
71+
lcon::S = fill!(S(undef, ncon), T(-Inf)),
72+
ucon::S = fill!(S(undef, ncon), T(Inf)),
73+
nnzo = nvar,
74+
nnzj = nvar * ncon,
75+
nnzh = nvar * (nvar + 1) / 2,
76+
lin = Int[],
77+
nln = 1:ncon,
78+
nlin = length(lin),
79+
nnln = length(nln),
80+
minimize = true,
81+
islp = false,
82+
name = "Generic",
83+
) where {T, S}
84+
if (nvar < 1) || (ncon < 0)
85+
error("Nonsensical dimensions")
86+
end
87+
88+
@lencheck nvar x0 lvar uvar
89+
@lencheck ncon y0 lcon ucon
90+
@lencheck nlin lin
91+
@lencheck nnln nln
92+
@rangecheck 1 ncon lin nln
93+
94+
ifix = findall(lvar .== uvar)
95+
ilow = findall((lvar .> T(-Inf)) .& (uvar .== T(Inf)))
96+
iupp = findall((lvar .== T(-Inf)) .& (uvar .< T(Inf)))
97+
irng = findall((lvar .> T(-Inf)) .& (uvar .< T(Inf)) .& (lvar .< uvar))
98+
ifree = findall((lvar .== T(-Inf)) .& (uvar .== T(Inf)))
99+
iinf = findall(lvar .> uvar)
100+
101+
jfix = findall(lcon .== ucon)
102+
jlow = findall((lcon .> T(-Inf)) .& (ucon .== T(Inf)))
103+
jupp = findall((lcon .== T(-Inf)) .& (ucon .< T(Inf)))
104+
jrng = findall((lcon .> T(-Inf)) .& (ucon .< T(Inf)) .& (lcon .< ucon))
105+
jfree = findall((lcon .== T(-Inf)) .& (ucon .== T(Inf)))
106+
jinf = findall(lcon .> ucon)
107+
108+
nnzj = max(0, nnzj)
109+
nnzh = max(0, nnzh)
110+
111+
new{T, S}(
112+
nvar,
113+
x0,
114+
lvar,
115+
uvar,
116+
ifix,
117+
ilow,
118+
iupp,
119+
irng,
120+
ifree,
121+
iinf,
122+
nlvb,
123+
nlvo,
124+
nlvc,
125+
ncon,
126+
y0,
127+
lcon,
128+
ucon,
129+
jfix,
130+
jlow,
131+
jupp,
132+
jrng,
133+
jfree,
134+
jinf,
135+
nnzo,
136+
nnzj,
137+
nnzh,
138+
nlin,
139+
nnln,
140+
lin,
141+
nln,
142+
minimize,
143+
islp,
144+
name,
145+
)
146+
end
147+
end
148+
NLPModels.equality_constrained(meta::SimpleNLPMeta) = length(meta.jfix) == meta.ncon > 0
149+
NLPModels.unconstrained(meta::SimpleNLPMeta) = meta.ncon == 0 && !has_bounds(meta)
150+
151+
function SimpleNLPModel(::Type{T}, ::Type{NLPModelMeta}) where {T}
20152
meta = NLPModelMeta{T, Vector{T}}(
21153
2,
22154
nnzh = 2,
@@ -28,10 +160,23 @@ function SimpleNLPModel(::Type{T}) where {T}
28160
ucon = T[0; Inf],
29161
name = "Simple NLP Model",
30162
)
31-
32163
return SimpleNLPModel(meta, Counters())
33164
end
34-
SimpleNLPModel() = SimpleNLPModel(Float64)
165+
function SimpleNLPModel(::Type{T}, ::Type{SimpleNLPMeta}) where {T}
166+
meta = SimpleNLPMeta{T, Vector{T}}(
167+
2,
168+
nnzh = 2,
169+
ncon = 2,
170+
lvar = zeros(T, 2),
171+
uvar = ones(T, 2),
172+
x0 = T[2; 2],
173+
lcon = T[0; 0],
174+
ucon = T[0; Inf],
175+
name = "Simple NLP Model",
176+
)
177+
return SimpleNLPModel(meta, Counters())
178+
end
179+
SimpleNLPModel() = SimpleNLPModel(Float64, NLPModelMeta)
35180

36181
function NLPModels.obj(nlp::SimpleNLPModel, x::AbstractVector)
37182
@lencheck 2 x

test/nlp/slack-model.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
@testset "SlackModel NLP tests" begin
2-
@testset "API" for T in [Float64, Float32]
2+
@testset "API" for T in [Float64, Float32], M in [NLPModelMeta, SimpleNLPMeta]
33
f(x) = (x[1] - 2)^2 + (x[2] - 1)^2
44
∇f(x) = T[2 * (x[1] - 2); 2 * (x[2] - 1); 0]
55
H(x) = T[2.0 0 0; 0 2.0 0; 0 0 0]
66
c(x) = T[x[1] - 2x[2] + 1; -x[1]^2 / 4 - x[2]^2 + 1 - x[3]]
77
J(x) = T[1.0 -2.0 0; -0.5x[1] -2.0x[2] -1]
88
H(x, y) = H(x) + y[2] * T[-0.5 0 0; 0 -2.0 0; 0 0 0]
99

10-
nlp = SlackModel(SimpleNLPModel(T))
10+
nlp = SlackModel(SimpleNLPModel(T, M))
1111
n = nlp.meta.nvar
1212
m = nlp.meta.ncon
1313

test/nls/feasibility-form-nls.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@
183183
@test strip.(split(chomp(showed), "\n")) == strip.(split(chomp(expected), "\n"))
184184
end
185185

186-
@testset "FeasibilityFormNLS of a FeasibilityResidual" for T in [Float64, Float32]
187-
nlp = SimpleNLPModel(T)
186+
@testset "FeasibilityFormNLS of a FeasibilityResidual" for T in [Float64, Float32], M in [NLPModelMeta, SimpleNLPMeta]
187+
nlp = SimpleNLPModel(T, M)
188188
snlp = SlackModel(nlp)
189189
nls = FeasibilityResidual(nlp)
190190
fnlp = FeasibilityFormNLS(nls)

test/nls/feasibility-residual.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
@testset "FeasibilityResidual tests" begin
2-
@testset "NLS API" for T in [Float64, Float32]
2+
@testset "NLS API" for T in [Float64, Float32], M in [NLPModelMeta, SimpleNLPMeta]
33
F(x) = T[x[1] - 2x[2] + 1; -x[1]^2 / 4 - x[2]^2 + 1 - x[3]]
44
JF(x) = T[1.0 -2.0 0; -0.5x[1] -2.0x[2] -1]
55
HF(x, w) = w[2] * diagm(0 => T[-0.5; -2.0; 0.0])
66

7-
nls = FeasibilityResidual(SimpleNLPModel(T))
7+
nls = FeasibilityResidual(SimpleNLPModel(T, M))
88
n = nls.meta.nvar
99
ne = nls_meta(nls).nequ
1010

@@ -60,15 +60,15 @@
6060
@test grad(nls, x) JF(x)' * F(x) gx
6161
end
6262

63-
@testset "NLP API" for T in [Float64, Float32]
63+
@testset "NLP API" for T in [Float64, Float32], M in [NLPModelMeta, SimpleNLPMeta]
6464
F(x) = T[x[1] - 2x[2] + 1; -x[1]^2 / 4 - x[2]^2 + 1 - x[3]]
6565
JF(x) = T[1.0 -2.0 0; -0.5x[1] -2.0x[2] -1]
6666
HF(x, w) = w[2] * diagm(0 => T[-0.5; -2.0; 0.0])
6767
f(x) = norm(F(x))^2 / 2
6868
∇f(x) = JF(x)' * F(x)
6969
H(x) = JF(x)' * JF(x) + HF(x, F(x))
7070

71-
nls = FeasibilityResidual(SimpleNLPModel(T))
71+
nls = FeasibilityResidual(SimpleNLPModel(T, M))
7272
n = nls.meta.nvar
7373

7474
x = randn(T, n)

0 commit comments

Comments
 (0)