Skip to content

Commit 883aa38

Browse files
committed
Add legacy API
1 parent 49aa43e commit 883aa38

File tree

6 files changed

+201
-19
lines changed

6 files changed

+201
-19
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ JuMP = "1.25"
1616
LinearAlgebra = "1.10"
1717
MathOptInterface = "1.40"
1818
NLPModels = "0.21.5"
19-
NLPModelsTest = "0.10.2"
19+
NLPModelsTest = "0.10.3"
2020
Percival = "0.7.3"
2121
Printf = "1.10"
2222
SolverCore = "0.3"

src/moi_nlp_model.jl

Lines changed: 162 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,23 +113,46 @@ end
113113

114114
function NLPModels.cons_nln!(nlp::MathOptNLPModel, x::AbstractVector, c::AbstractVector)
115115
increment!(nlp, :neval_cons_nln)
116-
for i = 1:(nlp.quadcon.nquad)
117-
qcon = nlp.quadcon.constraints[i]
118-
c[i] = 0.5 * coo_sym_dot(qcon.A.rows, qcon.A.cols, qcon.A.vals, x, x) + dot(qcon.b, x)
116+
if nlp.quadcon.nquad > 0
117+
for i = 1:(nlp.quadcon.nquad)
118+
qcon = nlp.quadcon.constraints[i]
119+
c[i] = 0.5 * coo_sym_dot(qcon.A.rows, qcon.A.cols, qcon.A.vals, x, x) + dot(qcon.b, x)
120+
end
119121
end
120122
if nlp.meta.nnln > nlp.quadcon.nquad
121123
MOI.eval_constraint(nlp.eval, view(c, (nlp.quadcon.nquad + 1):(nlp.meta.nnln)), x)
122124
end
123125
return c
124126
end
125127

128+
function NLPModels.cons!(nlp::MathOptNLPModel, x::AbstractVector, c::AbstractVector)
129+
increment!(nlp, :neval_cons)
130+
if nlp.meta.nlin > 0
131+
coo_prod!(nlp.lincon.jacobian.rows, nlp.lincon.jacobian.cols, nlp.lincon.jacobian.vals, x, c)
132+
end
133+
if nlp.meta.nnln > 0
134+
if nlp.quadcon.nquad > 0
135+
for i = 1:(nlp.quadcon.nquad)
136+
qcon = nlp.quadcon.constraints[i]
137+
c[nlp.meta.nlin + i] = 0.5 * coo_sym_dot(qcon.A.rows, qcon.A.cols, qcon.A.vals, x, x) + dot(qcon.b, x)
138+
end
139+
end
140+
if nlp.meta.nnln > nlp.quadcon.nquad
141+
index_nnln = (nlp.meta.nlin + nlp.quadcon.nquad + 1):(nlp.meta.ncon)
142+
MOI.eval_constraint(nlp.eval, view(c, index_nnln), x)
143+
end
144+
end
145+
return c
146+
end
147+
126148
function NLPModels.jac_lin_structure!(
127149
nlp::MathOptNLPModel,
128150
rows::AbstractVector{<:Integer},
129151
cols::AbstractVector{<:Integer},
130152
)
131-
view(rows, 1:(nlp.lincon.nnzj)) .= nlp.lincon.jacobian.rows
132-
view(cols, 1:(nlp.lincon.nnzj)) .= nlp.lincon.jacobian.cols
153+
index_lin = 1:(nlp.lincon.nnzj)
154+
view(rows, index_lin) .= nlp.lincon.jacobian.rows
155+
view(cols, index_lin) .= nlp.lincon.jacobian.cols
133156
return rows, cols
134157
end
135158

@@ -141,9 +164,11 @@ function NLPModels.jac_nln_structure!(
141164
if nlp.quadcon.nquad > 0
142165
index = 0
143166
for i = 1:(nlp.quadcon.nquad)
167+
# qcon.g is the sparsity pattern of the gradient of the quadratic constraint qcon
144168
qcon = nlp.quadcon.constraints[i]
145-
view(rows, (index + 1):(index + qcon.nnzg)) .= i
146-
view(cols, (index + 1):(index + qcon.nnzg)) .= qcon.g
169+
ind_quad = (index + 1):(index + qcon.nnzg)
170+
view(rows, ind_quad) .= i
171+
view(cols, ind_quad) .= qcon.g
147172
index += qcon.nnzg
148173
end
149174
end
@@ -155,17 +180,50 @@ function NLPModels.jac_nln_structure!(
155180
return rows, cols
156181
end
157182

183+
function NLPModels.jac_structure!(
184+
nlp::MathOptNLPModel,
185+
rows::AbstractVector{<:Integer},
186+
cols::AbstractVector{<:Integer},
187+
)
188+
if nlp.meta.nlin > 0
189+
index_lin = 1:(nlp.lincon.nnzj)
190+
view(rows, index_lin) .= nlp.lincon.jacobian.rows
191+
view(cols, index_lin) .= nlp.lincon.jacobian.cols
192+
end
193+
if nlp.meta.nnln > 0
194+
if nlp.quadcon.nquad > 0
195+
index = 0
196+
for i = 1:(nlp.quadcon.nquad)
197+
# qcon.g is the sparsity pattern of the gradient of the quadratic constraint qcon
198+
qcon = nlp.quadcon.constraints[i]
199+
ind_quad = (nlp.lincon.nnzj + index + 1):(nlp.lincon.nnzj + index + qcon.nnzg)
200+
view(rows, ind_quad) .= nlp.meta.nlin .+ i
201+
view(cols, ind_quad) .= qcon.g
202+
index += qcon.nnzg
203+
end
204+
end
205+
if nlp.meta.nnln > nlp.quadcon.nquad
206+
ind_nnln = (nlp.lincon.nnzj + nlp.quadcon.nnzj + 1):(nlp.meta.nnzj)
207+
view(rows, ind_nnln) .= nlp.meta.nlin .+ nlp.quadcon.nquad .+ nlp.nlcon.jac_rows
208+
view(cols, ind_nnln) .= nlp.nlcon.jac_cols
209+
end
210+
end
211+
return rows, cols
212+
end
213+
158214
function NLPModels.jac_lin_coord!(nlp::MathOptNLPModel, x::AbstractVector, vals::AbstractVector)
159215
increment!(nlp, :neval_jac_lin)
160-
view(vals, 1:(nlp.lincon.nnzj)) .= nlp.lincon.jacobian.vals
216+
index_lin = 1:(nlp.lincon.nnzj)
217+
view(vals, index_lin) .= nlp.lincon.jacobian.vals
161218
return vals
162219
end
163220

164221
function NLPModels.jac_nln_coord!(nlp::MathOptNLPModel, x::AbstractVector, vals::AbstractVector)
165222
increment!(nlp, :neval_jac_nln)
166223
if nlp.quadcon.nquad > 0
167224
index = 0
168-
view(vals, 1:(nlp.quadcon.nnzj)) .= 0.0
225+
ind_quad = 1:(nlp.quadcon.nnzj)
226+
view(vals, ind_quad) .= 0.0
169227
for i = 1:(nlp.quadcon.nquad)
170228
qcon = nlp.quadcon.constraints[i]
171229
for (j, ind) in enumerate(qcon.b.nzind)
@@ -193,12 +251,52 @@ function NLPModels.jac_nln_coord!(nlp::MathOptNLPModel, x::AbstractVector, vals:
193251
return vals
194252
end
195253

254+
function NLPModels.jac_coord!(nlp::MathOptNLPModel, x::AbstractVector, vals::AbstractVector)
255+
increment!(nlp, :neval_jac)
256+
if nlp.meta.nlin > 0
257+
index_lin = 1:(nlp.lincon.nnzj)
258+
view(vals, index_lin) .= nlp.lincon.jacobian.vals
259+
end
260+
if nlp.meta.nnln > 0
261+
if nlp.quadcon.nquad > 0
262+
ind_quad = (nlp.lincon.nnzj + 1):(nlp.lincon.nnzj + nlp.quadcon.nnzj)
263+
view(vals, ind_quad) .= 0.0
264+
index = nlp.lincon.nnzj
265+
for i = 1:(nlp.quadcon.nquad)
266+
qcon = nlp.quadcon.constraints[i]
267+
for (j, ind) in enumerate(qcon.b.nzind)
268+
k = qcon.dg[ind]
269+
vals[index + k] += qcon.b.nzval[j]
270+
end
271+
for j = 1:(qcon.nnzh)
272+
row = qcon.A.rows[j]
273+
col = qcon.A.cols[j]
274+
val = qcon.A.vals[j]
275+
k1 = qcon.dg[row]
276+
vals[index + k1] += val * x[col]
277+
if row != col
278+
k2 = qcon.dg[col]
279+
vals[index + k2] += val * x[row]
280+
end
281+
end
282+
index += qcon.nnzg
283+
end
284+
end
285+
if nlp.meta.nnln > nlp.quadcon.nquad
286+
ind_nnln = (nlp.lincon.nnzj + nlp.quadcon.nnzj + 1):(nlp.meta.nnzj)
287+
MOI.eval_constraint_jacobian(nlp.eval, view(vals, ind_nnln), x)
288+
end
289+
end
290+
return vals
291+
end
292+
196293
function NLPModels.jprod_lin!(
197294
nlp::MathOptNLPModel,
198295
x::AbstractVector,
199296
v::AbstractVector,
200297
Jv::AbstractVector,
201298
)
299+
increment!(nlp, :neval_jprod_lin)
202300
jprod_lin!(
203301
nlp,
204302
nlp.lincon.jacobian.rows,
@@ -217,18 +315,43 @@ function NLPModels.jprod_nln!(
217315
Jv::AbstractVector,
218316
)
219317
increment!(nlp, :neval_jprod_nln)
318+
if nlp.quadcon.nquad > 0
319+
for i = 1:(nlp.quadcon.nquad)
320+
# Jv[i] += (Aᵢ * x + bᵢ)ᵀ * v
321+
qcon = nlp.quadcon.constraints[i]
322+
Jv[i] = coo_sym_dot(qcon.A.rows, qcon.A.cols, qcon.A.vals, x, v) + dot(qcon.b, v)
323+
end
324+
end
220325
if nlp.meta.nnln > nlp.quadcon.nquad
221326
ind_nnln = (nlp.quadcon.nquad + 1):(nlp.meta.nnln)
222327
MOI.eval_constraint_jacobian_product(nlp.eval, view(Jv, ind_nnln), x, v)
223328
end
224-
(nlp.meta.nnln == nlp.quadcon.nquad) && (Jv .= 0.0)
329+
return Jv
330+
end
331+
332+
function NLPModels.jprod!(
333+
nlp::MathOptNLPModel,
334+
x::AbstractVector,
335+
v::AbstractVector,
336+
Jv::AbstractVector,
337+
)
338+
increment!(nlp, :neval_jprod)
339+
if nlp.meta.nlin > 0
340+
view(Jv, nlp.meta.lin) .= 0.0
341+
transpose = false
342+
coo_unsym_add_mul!(transpose, nlp.lincon.jacobian.rows, nlp.lincon.jacobian.cols, nlp.lincon.jacobian.vals, v, Jv, 1.0)
343+
end
225344
if nlp.quadcon.nquad > 0
226345
for i = 1:(nlp.quadcon.nquad)
227346
# Jv[i] = (Aᵢ * x + bᵢ)ᵀ * v
228347
qcon = nlp.quadcon.constraints[i]
229-
Jv[i] += coo_sym_dot(qcon.A.rows, qcon.A.cols, qcon.A.vals, x, v) + dot(qcon.b, v)
348+
Jv[nlp.meta.nlin + i] = coo_sym_dot(qcon.A.rows, qcon.A.cols, qcon.A.vals, x, v) + dot(qcon.b, v)
230349
end
231350
end
351+
if nlp.meta.nnln > nlp.quadcon.nquad
352+
ind_nnln = (nlp.meta.nlin + nlp.quadcon.nquad + 1):(nlp.meta.ncon)
353+
MOI.eval_constraint_jacobian_product(nlp.eval, view(Jv, ind_nnln), x, v)
354+
end
232355
return Jv
233356
end
234357

@@ -238,6 +361,7 @@ function NLPModels.jtprod_lin!(
238361
v::AbstractVector,
239362
Jtv::AbstractVector,
240363
)
364+
increment!(nlp, :neval_jtprod_lin)
241365
jtprod_lin!(
242366
nlp,
243367
nlp.lincon.jacobian.rows,
@@ -260,7 +384,7 @@ function NLPModels.jtprod_nln!(
260384
ind_nnln = (nlp.quadcon.nquad + 1):(nlp.meta.nnln)
261385
MOI.eval_constraint_jacobian_transpose_product(nlp.eval, Jtv, x, view(v, ind_nnln))
262386
end
263-
(nlp.meta.nnln == nlp.quadcon.nquad) && (Jtv .= 0.0)
387+
(nlp.quadcon.nquad == nlp.meta.nnln) && (Jtv .= 0.0)
264388
if nlp.quadcon.nquad > 0
265389
for i = 1:(nlp.quadcon.nquad)
266390
# Jtv += v[i] * (Aᵢ * x + bᵢ)
@@ -272,6 +396,32 @@ function NLPModels.jtprod_nln!(
272396
return Jtv
273397
end
274398

399+
function NLPModels.jtprod!(
400+
nlp::MathOptNLPModel,
401+
x::AbstractVector,
402+
v::AbstractVector,
403+
Jtv::AbstractVector,
404+
)
405+
increment!(nlp, :neval_jtprod)
406+
if nlp.meta.nnln > nlp.quadcon.nquad
407+
ind_nnln = (nlp.meta.nlin + nlp.quadcon.nquad + 1):(nlp.meta.ncon)
408+
MOI.eval_constraint_jacobian_transpose_product(nlp.eval, Jtv, x, view(v, ind_nnln))
409+
end
410+
(nlp.quadcon.nquad == nlp.meta.nnln) && (Jtv .= 0.0)
411+
if nlp.meta.nlin > 0
412+
transpose = true
413+
coo_unsym_add_mul!(transpose, nlp.lincon.jacobian.rows, nlp.lincon.jacobian.cols, nlp.lincon.jacobian.vals, v, Jtv, 1.0)
414+
end
415+
if nlp.quadcon.nquad > 0
416+
for i = 1:(nlp.quadcon.nquad)
417+
qcon = nlp.quadcon.constraints[i]
418+
coo_sym_add_mul!(qcon.A.rows, qcon.A.cols, qcon.A.vals, x, Jtv, v[nlp.meta.nlin + i])
419+
Jtv .+= v[nlp.meta.nlin + i] .* qcon.b
420+
end
421+
end
422+
return Jtv
423+
end
424+
275425
function NLPModels.hess_structure!(
276426
nlp::MathOptNLPModel,
277427
rows::AbstractVector{<:Integer},

src/moi_nls_model.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,11 @@ end
259259

260260
function NLPModels.cons_nln!(nls::MathOptNLSModel, x::AbstractVector, c::AbstractVector)
261261
increment!(nls, :neval_cons_nln)
262-
for i = 1:(nls.quadcon.nquad)
263-
qcon = nls.quadcon.constraints[i]
264-
c[i] = 0.5 * coo_sym_dot(qcon.A.rows, qcon.A.cols, qcon.A.vals, x, x) + dot(qcon.b, x)
262+
if nls.quadcon.nquad > 0
263+
for i = 1:(nls.quadcon.nquad)
264+
qcon = nls.quadcon.constraints[i]
265+
c[i] = 0.5 * coo_sym_dot(qcon.A.rows, qcon.A.cols, qcon.A.vals, x, x) + dot(qcon.b, x)
266+
end
265267
end
266268
if nls.meta.nnln > nls.quadcon.nquad
267269
MOI.eval_constraint(nls.ceval, view(c, (nls.quadcon.nquad + 1):(nls.meta.nnln)), x)
@@ -345,6 +347,7 @@ function NLPModels.jprod_lin!(
345347
v::AbstractVector,
346348
Jv::AbstractVector,
347349
)
350+
increment!(nls, :neval_jprod_lin)
348351
jprod_lin!(
349352
nls,
350353
nls.lincon.jacobian.rows,
@@ -384,6 +387,7 @@ function NLPModels.jtprod_lin!(
384387
v::AbstractVector,
385388
Jtv::AbstractVector,
386389
)
390+
increment!(nls, :neval_jtprod_lin)
387391
jtprod_lin!(
388392
nls,
389393
nls.lincon.jacobian.rows,

src/utils.jl

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,37 @@ function replace!(ex, x)
116116
end
117117
end
118118

119+
"""
120+
coo_unsym_add_mul!(transpose, rows, cols, vals, x, y, α)
121+
122+
Performs the update `y ← y + α * op(A) * x`, where `A` is an unsymmetric matrix in COO format given by `(rows, cols, vals)`.
123+
If `transpose == true`, then `op(A) = Aᵀ`; otherwise, `op(A) = A`.
124+
"""
125+
function coo_unsym_add_mul!(
126+
transpose::Bool,
127+
rows::AbstractVector{<:Integer},
128+
cols::AbstractVector{<:Integer},
129+
vals::AbstractVector,
130+
x::AbstractVector,
131+
y::AbstractVector,
132+
α::Float64,
133+
)
134+
nnz = length(vals)
135+
@inbounds for k = 1:nnz
136+
i, j, c = rows[k], cols[k], vals[k]
137+
if transpose
138+
y[j] += α * c * x[i]
139+
else
140+
y[i] += α * c * x[j]
141+
end
142+
end
143+
return y
144+
end
145+
119146
"""
120147
coo_sym_add_mul!(rows, cols, vals, x, y, α)
121148
122-
Update of the form `y ← y + αAx` where `A` is a symmetric matrix given by `(rows, cols, vals)`.
149+
Perform the update `y ← y + α * A * x` where `A` is a symmetric matrix in COO format given by `(rows, cols, vals)`.
123150
Only one triangle of `A` should be passed.
124151
"""
125152
function coo_sym_add_mul!(

test/nlp_consistency.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ for problem in nlp_problems
44
problem_f = eval(Symbol(lowercase(problem)))
55
nlp_moi = MathOptNLPModel(problem_f())
66
nlps = [nlp_manual; nlp_moi]
7-
consistent_nlps(nlps, linear_api = true, test_slack = false, exclude = [])
7+
consistent_nlps(nlps, linear_api = true, test_slack = false, test_counters = false, exclude = [])
8+
coord_memory_nlp(nlp_moi, linear_api = true)
89
view_subarray_nlp(nlp_moi)
910
end
1011
end

test/nls_consistency.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ for problem in nls_problems
88
if isdefined(Main, Symbol(spc))
99
push!(nlss, eval(Meta.parse(spc))())
1010
end
11-
consistent_nlss(nlss, linear_api = true, test_slack = false)
11+
consistent_nlss(nlss, linear_api = true, test_slack = false, test_counters = false)
1212
view_subarray_nls(nls_moi)
1313
end
1414
end

0 commit comments

Comments
 (0)