@@ -4,7 +4,9 @@ mutable struct MathOptNLPModel <: AbstractNLPModel{Float64, Vector{Float64}}
44 meta:: NLPModelMeta{Float64, Vector{Float64}}
55 eval:: MOI.Nonlinear.Evaluator
66 lincon:: LinearConstraints
7+ quadcon:: QuadraticConstraints
78 nlcon:: NonLinearStructure
9+ λ:: Vector{Float64}
810 obj:: Objective
911 counters:: Counters
1012end
2729
2830function nlp_model (moimodel:: MOI.ModelLike ; hessian:: Bool = true , name:: String = " Generic" )
2931 index_map, nvar, lvar, uvar, x0 = parser_variables (moimodel)
30- nlin, lincon, lin_lcon, lin_ucon = parser_MOI (moimodel, index_map)
32+ nlin, lincon, lin_lcon, lin_ucon, quadcon, quad_lcon, quad_ucon = parser_MOI (moimodel, index_map, nvar )
3133
3234 nlp_data = _nlp_block (moimodel)
3335 nnln, nlcon, nl_lcon, nl_ucon = parser_NL (nlp_data, hessian = hessian)
36+ λ = zeros (nnln) # Lagrange multipliers for hess_coord! and hprod! without y
3437
3538 if nlp_data. has_objective
3639 obj = Objective (" NONLINEAR" , 0.0 , spzeros (Float64, nvar), COO (), 0 )
3740 else
3841 obj = parser_objective_MOI (moimodel, nvar, index_map)
3942 end
4043
41- ncon = nlin + nnln
42- lcon = vcat (lin_lcon, nl_lcon)
43- ucon = vcat (lin_ucon, nl_ucon)
44- nnzj = lincon. nnzj + nlcon. nnzj
45- nnzh = obj. nnzh + nlcon. nnzh
44+ ncon = nlin + quadcon . nquad + nnln
45+ lcon = vcat (lin_lcon, quad_lcon, nl_lcon)
46+ ucon = vcat (lin_ucon, quad_ucon, nl_ucon)
47+ nnzj = lincon. nnzj + quadcon . nnzj + nlcon. nnzj
48+ nnzh = obj. nnzh + quadcon . nnzh + nlcon. nnzh
4649
4750 meta = NLPModelMeta (
4851 nvar,
@@ -57,13 +60,13 @@ function nlp_model(moimodel::MOI.ModelLike; hessian::Bool = true, name::String =
5760 nnzh = nnzh,
5861 lin = collect (1 : nlin),
5962 lin_nnzj = lincon. nnzj,
60- nln_nnzj = nlcon. nnzj,
63+ nln_nnzj = quadcon . nnzj + nlcon. nnzj,
6164 minimize = MOI. get (moimodel, MOI. ObjectiveSense ()) == MOI. MIN_SENSE,
62- islp = (obj. type == " LINEAR" ) && (nnln == 0 ),
65+ islp = (obj. type == " LINEAR" ) && (nnln == 0 ) && (quadcon . nquad == 0 ) ,
6366 name = name,
6467 )
6568
66- return MathOptNLPModel (meta, nlp_data. evaluator, lincon, nlcon, obj, Counters ()), index_map
69+ return MathOptNLPModel (meta, nlp_data. evaluator, lincon, quadcon, nlcon, λ , obj, Counters ()), index_map
6770end
6871
6972function NLPModels. obj (nlp:: MathOptNLPModel , x:: AbstractVector )
106109
107110function NLPModels. cons_nln! (nlp:: MathOptNLPModel , x:: AbstractVector , c:: AbstractVector )
108111 increment! (nlp, :neval_cons_nln )
109- MOI. eval_constraint (nlp. eval, c, x)
112+ for i = 1 : (nlp. quadcon. nquad)
113+ qcon = nlp. quadcon. constraints[i]
114+ c[i] = 0.5 * coo_sym_dot (qcon. A. rows, qcon. A. cols, qcon. A. vals, x, x) + dot (qcon. b, x)
115+ end
116+ if nlp. meta. nnln > nlp. quadcon. nquad
117+ MOI. eval_constraint (nlp. eval, view (c, (nlp. quadcon. nquad + 1 ): (nlp. meta. nnln)), x)
118+ end
110119 return c
111120end
112121
@@ -125,8 +134,20 @@ function NLPModels.jac_nln_structure!(
125134 rows:: AbstractVector{<:Integer} ,
126135 cols:: AbstractVector{<:Integer} ,
127136)
128- view (rows, 1 : (nlp. nlcon. nnzj)) .= nlp. nlcon. jac_rows
129- view (cols, 1 : (nlp. nlcon. nnzj)) .= nlp. nlcon. jac_cols
137+ if nlp. quadcon. nquad > 0
138+ index = 0
139+ for i = 1 : (nlp. quadcon. nquad)
140+ qcon = nlp. quadcon. constraints[i]
141+ view (rows, index+ 1 : index+ qcon. nnzg) .= i
142+ view (cols, index+ 1 : index+ qcon. nnzg) .= qcon. g
143+ index += qcon. nnzg
144+ end
145+ end
146+ if nlp. meta. nnln > nlp. quadcon. nquad
147+ ind_nnln = (nlp. quadcon. nnzj + 1 ): (nlp. quadcon. nnzj + nlp. nlcon. nnzj)
148+ view (rows, ind_nnln) .= nlp. quadcon. nquad .+ nlp. nlcon. jac_rows
149+ view (cols, ind_nnln) .= nlp. nlcon. jac_cols
150+ end
130151 return rows, cols
131152end
132153
138159
139160function NLPModels. jac_nln_coord! (nlp:: MathOptNLPModel , x:: AbstractVector , vals:: AbstractVector )
140161 increment! (nlp, :neval_jac_nln )
141- MOI. eval_constraint_jacobian (nlp. eval, view (vals, 1 : (nlp. nlcon. nnzj)), x)
162+ if nlp. quadcon. nquad > 0
163+ index = 0
164+ view (vals, 1 : nlp. quadcon. nnzj) .= 0.0
165+ for i = 1 : (nlp. quadcon. nquad)
166+ qcon = nlp. quadcon. constraints[i]
167+ for (j, ind) in enumerate (qcon. b. nzind)
168+ k = qcon. dg[ind]
169+ vals[index+ k] += qcon. b. nzval[j]
170+ end
171+ for j = 1 : qcon. nnzh
172+ row = qcon. A. rows[j]
173+ col = qcon. A. cols[j]
174+ val = qcon. A. vals[j]
175+ k1 = qcon. dg[row]
176+ vals[index+ k1] += val * x[col]
177+ if row != col
178+ k2 = qcon. dg[col]
179+ vals[index+ k2] += val * x[row]
180+ end
181+ end
182+ index += qcon. nnzg
183+ end
184+ end
185+ if nlp. meta. nnln > nlp. quadcon. nquad
186+ ind_nnln = (nlp. quadcon. nnzj + 1 ): (nlp. quadcon. nnzj + nlp. nlcon. nnzj)
187+ MOI. eval_constraint_jacobian (nlp. eval, view (vals, ind_nnln), x)
188+ end
142189 return vals
143190end
144191
@@ -166,7 +213,18 @@ function NLPModels.jprod_nln!(
166213 Jv:: AbstractVector ,
167214)
168215 increment! (nlp, :neval_jprod_nln )
169- MOI. eval_constraint_jacobian_product (nlp. eval, Jv, x, v)
216+ if nlp. meta. nnln > nlp. quadcon. nquad
217+ ind_nnln = (nlp. quadcon. nquad + 1 ): (nlp. meta. nnln)
218+ MOI. eval_constraint_jacobian_product (nlp. eval, view (Jv, ind_nnln), x, v)
219+ end
220+ (nlp. meta. nnln == nlp. quadcon. nquad) && (Jv .= 0.0 )
221+ if nlp. quadcon. nquad > 0
222+ for i = 1 : (nlp. quadcon. nquad)
223+ # Jv[i] = (Aᵢ * x + bᵢ)ᵀ * v
224+ qcon = nlp. quadcon. constraints[i]
225+ Jv[i] += coo_sym_dot (qcon. A. rows, qcon. A. cols, qcon. A. vals, x, v) + dot (qcon. b, v)
226+ end
227+ end
170228 return Jv
171229end
172230
@@ -194,7 +252,19 @@ function NLPModels.jtprod_nln!(
194252 Jtv:: AbstractVector ,
195253)
196254 increment! (nlp, :neval_jtprod_nln )
197- MOI. eval_constraint_jacobian_transpose_product (nlp. eval, Jtv, x, v)
255+ if nlp. meta. nnln > nlp. quadcon. nquad
256+ ind_nnln = (nlp. quadcon. nquad + 1 ): (nlp. meta. nnln)
257+ MOI. eval_constraint_jacobian_transpose_product (nlp. eval, Jtv, x, view (v, ind_nnln))
258+ end
259+ (nlp. meta. nnln == nlp. quadcon. nquad) && (Jtv .= 0.0 )
260+ if nlp. quadcon. nquad > 0
261+ for i = 1 : (nlp. quadcon. nquad)
262+ # Jtv += v[i] * (Aᵢ * x + bᵢ)
263+ qcon = nlp. quadcon. constraints[i]
264+ coo_sym_add_mul! (qcon. A. rows, qcon. A. cols, qcon. A. vals, x, Jtv, v[i])
265+ Jtv .+ = v[i] .* qcon. b
266+ end
267+ end
198268 return Jtv
199269end
200270
@@ -207,9 +277,18 @@ function NLPModels.hess_structure!(
207277 view (rows, 1 : (nlp. obj. nnzh)) .= nlp. obj. hessian. rows
208278 view (cols, 1 : (nlp. obj. nnzh)) .= nlp. obj. hessian. cols
209279 end
210- if (nlp. obj. type == " NONLINEAR" ) || (nlp. meta. nnln > 0 )
211- view (rows, (nlp. obj. nnzh + 1 ): (nlp. meta. nnzh)) .= nlp. nlcon. hess_rows
212- view (cols, (nlp. obj. nnzh + 1 ): (nlp. meta. nnzh)) .= nlp. nlcon. hess_cols
280+ if (nlp. obj. type == " NONLINEAR" ) || (nlp. meta. nnln > nlp. quadcon. nquad)
281+ view (rows, (nlp. obj. nnzh + nlp. quadcon. nnzh + 1 ): (nlp. meta. nnzh)) .= nlp. nlcon. hess_rows
282+ view (cols, (nlp. obj. nnzh + nlp. quadcon. nnzh + 1 ): (nlp. meta. nnzh)) .= nlp. nlcon. hess_cols
283+ end
284+ if nlp. quadcon. nquad > 0
285+ index = nlp. obj. nnzh
286+ for i = 1 : (nlp. quadcon. nquad)
287+ qcon = nlp. quadcon. constraints[i]
288+ view (rows, (index + 1 ): (index + qcon. nnzh)) .= qcon. A. rows
289+ view (cols, (index + 1 ): (index + qcon. nnzh)) .= qcon. A. cols
290+ index += qcon. nnzh
291+ end
213292 end
214293 return rows, cols
215294end
@@ -225,15 +304,23 @@ function NLPModels.hess_coord!(
225304 if nlp. obj. type == " QUADRATIC"
226305 view (vals, 1 : (nlp. obj. nnzh)) .= obj_weight .* nlp. obj. hessian. vals
227306 end
228- if (nlp. obj. type == " NONLINEAR" ) || (nlp. meta. nnln > 0 )
229- MOI . eval_hessian_lagrangian (
230- nlp. eval,
231- view (vals, (nlp. obj. nnzh + 1 ): (nlp. meta. nnzh)),
307+ if (nlp. obj. type == " NONLINEAR" ) || (nlp. meta. nnln > nlp . quadcon . nquad )
308+ λ = view (y, (nlp . meta . nlin + nlp . quadcon . nquad + 1 ) : (nlp . meta . ncon))
309+ MOI . eval_hessian_lagrangian ( nlp. eval,
310+ view (vals, (nlp. obj. nnzh + nlp . quadcon . nnzh + 1 ): (nlp. meta. nnzh)),
232311 x,
233312 obj_weight,
234- view (y, nlp . meta . nln),
313+ λ
235314 )
236315 end
316+ if nlp. quadcon. nquad > 0
317+ index = nlp. obj. nnzh
318+ for i = 1 : (nlp. quadcon. nquad)
319+ qcon = nlp. quadcon. constraints[i]
320+ view (vals, (index + 1 ): (index + qcon. nnzh)) .= y[nlp. meta. nlin + i] .* qcon. A. vals
321+ index += qcon. nnzh
322+ end
323+ end
237324 return vals
238325end
239326
@@ -252,7 +339,9 @@ function NLPModels.hess_coord!(
252339 view (vals, (nlp. obj. nnzh + 1 ): (nlp. meta. nnzh)) .= 0.0
253340 end
254341 if nlp. obj. type == " NONLINEAR"
255- MOI. eval_hessian_lagrangian (nlp. eval, vals, x, obj_weight, zeros (nlp. meta. nnln))
342+ view (vals, 1 : (nlp. obj. nnzh + nlp. quadcon. nnzh)) .= 0.0
343+ ind_nnln = (nlp. obj. nnzh + nlp. quadcon. nnzh + 1 ): (nlp. meta. nnzh)
344+ MOI. eval_hessian_lagrangian (nlp. eval, view (vals, ind_nnln), x, obj_weight, nlp. λ)
256345 end
257346 return vals
258347end
@@ -269,19 +358,20 @@ function NLPModels.hprod!(
269358 if (nlp. obj. type == " LINEAR" ) && (nlp. meta. nnln == 0 )
270359 hv .= 0.0
271360 end
272- if (nlp. obj. type == " NONLINEAR" ) || (nlp. meta. nnln > 0 )
273- MOI. eval_hessian_lagrangian_product (nlp. eval, hv, x, v, obj_weight, view (y, nlp. meta. nln))
361+ if (nlp. obj. type == " NONLINEAR" ) || (nlp. meta. nnln > nlp. quadcon. nquad)
362+ λ = view (y, (nlp. meta. nlin + nlp. quadcon. nquad + 1 ): (nlp. meta. ncon))
363+ MOI. eval_hessian_lagrangian_product (nlp. eval, hv, x, v, obj_weight, λ)
274364 end
275365 if nlp. obj. type == " QUADRATIC"
276- nlp. meta. nnln == 0 && (hv .= 0.0 )
277- coo_sym_add_mul! (
278- nlp . obj . hessian . rows,
279- nlp. obj . hessian . cols,
280- nlp. obj. hessian . vals,
281- v,
282- hv,
283- obj_weight,
284- )
366+ ( nlp. meta. nnln == nlp . quadcon . nquad) && (hv .= 0.0 )
367+ coo_sym_add_mul! (nlp . obj . hessian . rows, nlp . obj . hessian . cols, nlp . obj . hessian . vals, v, hv, obj_weight)
368+ end
369+ if nlp. quadcon . nquad > 0
370+ ( nlp. obj. type == " LINEAR " ) && (hv . = 0.0 )
371+ for i = 1 : (nlp . quadcon . nquad)
372+ qcon = nlp . quadcon . constraints[i]
373+ coo_sym_add_mul! (qcon . A . rows, qcon . A . cols, qcon . A . vals, v, hv, y[nlp . meta . nlin + i])
374+ end
285375 end
286376 return hv
287377end
@@ -302,7 +392,7 @@ function NLPModels.hprod!(
302392 coo_sym_add_mul! (nlp. obj. hessian. rows, nlp. obj. hessian. cols, nlp. obj. hessian. vals, v, hv, obj_weight)
303393 end
304394 if nlp. obj. type == " NONLINEAR"
305- MOI. eval_hessian_lagrangian_product (nlp. eval, hv, x, v, obj_weight, zeros ( nlp. meta . nnln) )
395+ MOI. eval_hessian_lagrangian_product (nlp. eval, hv, x, v, obj_weight, nlp. λ )
306396 end
307397 return hv
308398end
0 commit comments