11import MathOptInterface as MOI
22
3+ const _Model{F,S} =
4+ MOI. Utilities. UniversalFallback{MOI. Utilities. VectorOfConstraints{F,S}}
5+
36mutable struct Optimizer{T,O<: MOI.ModelLike } <: MOI.AbstractOptimizer
47 model:: O
58 objective:: Union{Nothing,PolyJuMP.ScalarPolynomialFunction{T}}
6- constraints:: DataStructures.OrderedDict {
7- Type,
8- Tuple{Type,MOI. Utilities. VectorOfConstraints},
9- }
9+ constraints:: DataStructures.OrderedDict{Type,Tuple{Type,_Model}}
10+ index_map:: Dict{MOI.ConstraintIndex,MOI.ConstraintIndex}
1011end
1112
1213function Optimizer {T} (model:: MOI.ModelLike ) where {T}
1314 return Optimizer {T,typeof(model)} (
1415 model,
1516 nothing ,
1617 DataStructures. OrderedDict {Type,MOI.Utilities.VectorOfConstraints} (),
18+ Dict {MOI.ConstraintIndex,MOI.ConstraintIndex} (),
1719 )
1820end
1921
@@ -34,18 +36,45 @@ function MOI.empty!(model::Optimizer)
3436 MOI. empty! (model. model)
3537 model. objective = nothing
3638 empty! (model. constraints)
39+ empty! (model. index_map)
3740 return
3841end
3942
4043MOI. is_valid (model:: Optimizer , i:: MOI.Index ) = MOI. is_valid (model. model, i)
4144function MOI. is_valid (
4245 model:: Optimizer{T} ,
43- :: MOI.ConstraintIndex{PolyJuMP.ScalarPolynomialFunction{T},S} ,
46+ ci :: MOI.ConstraintIndex{<: PolyJuMP.ScalarPolynomialFunction{T},S} ,
4447) where {T,S<: MOI.AbstractScalarSet }
4548 return haskey (model. constraints, S) &&
4649 MOI. is_valid (model. constraints[S][2 ], ci)
4750end
4851
52+ function MOI. supports (
53+ model:: Optimizer ,
54+ attr:: MOI.AbstractConstraintAttribute ,
55+ C:: Type{<:MOI.ConstraintIndex} ,
56+ )
57+ return MOI. supports (model. model, attr, C)
58+ end
59+
60+ function MOI. set (
61+ model:: Optimizer ,
62+ attr:: MOI.AbstractConstraintAttribute ,
63+ ci:: MOI.ConstraintIndex ,
64+ value,
65+ )
66+ return MOI. set (model. model, attr, ci, value)
67+ end
68+
69+ function MOI. set (
70+ model:: Optimizer{T} ,
71+ attr:: MOI.AbstractConstraintAttribute ,
72+ ci:: MOI.ConstraintIndex{<:PolyJuMP.ScalarPolynomialFunction{T},S} ,
73+ value,
74+ ) where {T,S<: MOI.AbstractScalarSet }
75+ return MOI. get (model. constraints[S][2 ], attr, model. index_map[ci], value)
76+ end
77+
4978function MOI. get (
5079 model:: Optimizer ,
5180 attr:: MOI.AbstractConstraintAttribute ,
@@ -54,8 +83,28 @@ function MOI.get(
5483 return MOI. get (model. model, attr, ci)
5584end
5685
86+ function MOI. get (
87+ model:: Optimizer{T} ,
88+ attr:: MOI.AbstractConstraintAttribute ,
89+ ci:: MOI.ConstraintIndex{<:PolyJuMP.ScalarPolynomialFunction{T},S} ,
90+ ) where {T,S<: MOI.AbstractScalarSet }
91+ if MOI. is_set_by_optimize (attr)
92+ return MOI. get (model. model, attr, model. index_map[ci])
93+ else
94+ return MOI. get (model. constraints[S][2 ], attr, ci)
95+ end
96+ end
97+
5798MOI. add_variable (model:: Optimizer ) = MOI. add_variable (model. model)
5899
100+ function MOI. supports (
101+ model:: Optimizer ,
102+ attr:: MOI.AbstractVariableAttribute ,
103+ :: Type{MOI.VariableIndex} ,
104+ )
105+ return MOI. supports (model. model, attr, MOI. VariableIndex)
106+ end
107+
59108function MOI. set (
60109 model:: Optimizer ,
61110 attr:: MOI.AbstractVariableAttribute ,
@@ -158,7 +207,9 @@ function MOI.add_constraint(
158207 F = typeof (func)
159208 S = typeof (set)
160209 if ! haskey (model. constraints, S)
161- con = MOI. Utilities. VectorOfConstraints {F,S} ()
210+ con = MOI. Utilities. UniversalFallback (
211+ MOI. Utilities. VectorOfConstraints {F,S} (),
212+ )
162213 model. constraints[S] = (P, con)
163214 end
164215 return MOI. add_constraint (model. constraints[S][2 ], func, set)
@@ -168,7 +219,7 @@ function MOI.get(
168219 model:: Optimizer{T} ,
169220 attr:: Union{MOI.ConstraintFunction,MOI.ConstraintSet} ,
170221 ci:: MOI.ConstraintIndex{<:PolyJuMP.ScalarPolynomialFunction{T},S} ,
171- ) where {T,S}
222+ ) where {T,S<: MOI.AbstractScalarSet }
172223 return MOI. get (model. constraints[S][2 ], attr, ci)
173224end
174225
@@ -296,6 +347,7 @@ function monomial_variable_index(
296347 # If we don't have a variable for `mono` yet,
297348 # we create one now by equal to `x * y`.
298349 mono_bounds = IntervalArithmetic. interval (one (T))
350+ mono_start = one (T)
299351 for var in MP. variables (mono)
300352 deg = MP. degree (mono, var)
301353 if deg == 0
@@ -309,6 +361,16 @@ function monomial_variable_index(
309361 ub_var == typemax (ub_var) ? typemax (F) : float (ub_var),
310362 )
311363 mono_bounds *= var_bounds^ deg
364+ attr = MOI. VariablePrimalStart ()
365+ if ! isnothing (mono_start) &&
366+ MOI. supports (model, attr, MOI. VariableIndex)
367+ start = MOI. get (model, attr, vi)
368+ if isnothing (start)
369+ mono_start = nothing
370+ else
371+ mono_start *= start^ deg
372+ end
373+ end
312374 end
313375 x = div[mono]
314376 vx = monomial_variable_index (model, d, div, x)
@@ -338,6 +400,10 @@ function monomial_variable_index(
338400 else
339401 d[mono], _ = MOI. add_constrained_variable (model. model, set)
340402 end
403+ if ! isnothing (mono_start) &&
404+ MOI. supports (model, MOI. VariablePrimalStart (), MOI. VariableIndex)
405+ MOI. set (model. model, MOI. VariablePrimalStart (), d[mono], mono_start)
406+ end
341407 MOI. Utilities. normalize_and_add_constraint (
342408 model,
343409 MA. @rewrite (one (T) * d[mono] - one (T) * vx * vy),
@@ -348,14 +414,44 @@ function monomial_variable_index(
348414 return d[mono]
349415end
350416
351- function _add_constraints (model:: Optimizer , cis, index_to_var, d, div)
352- for ci in cis
353- func = MOI. get (model, MOI. ConstraintFunction (), ci)
354- set = MOI. get (model, MOI. ConstraintSet (), ci)
417+ function _add_constraints (
418+ dest,
419+ src,
420+ index_map,
421+ cis_src:: Vector{MOI.ConstraintIndex{F,S}} ,
422+ index_to_var,
423+ d,
424+ div,
425+ ) where {F,S}
426+ for ci in cis_src
427+ func = MOI. get (src, MOI. ConstraintFunction (), ci)
428+ set = MOI. get (src, MOI. ConstraintSet (), ci)
355429 func, index_to_var = _subs! (func, index_to_var)
356430 quad = _quad_convert (func. polynomial, d, div)
357- MOI. Utilities. normalize_and_add_constraint (model, quad, set)
431+ dest_ci = MOI. Utilities. normalize_and_add_constraint (dest, quad, set)
432+ index_map[ci] = dest_ci
358433 end
434+ # `Utilities.pass_attributes` needs `index_map` to be an `IndexMap` :(
435+ # MOI.Utilities.pass_attributes(dest, src, index_map, cis_src)
436+ # `ListOfConstraintAttributesSet` not defined for `VectorOfConstraints`
437+ # for attr in MOI.get(src, MOI.ListOfConstraintAttributesSet{F,S}())
438+ # if !MOI.supports(dest, attr)
439+ # if attr == MOI.Name()
440+ # continue # Skipping names is okay.
441+ # end
442+ # end
443+ # for ci in cis_src
444+ # value = MOI.get(src, attr, ci)
445+ # if value !== nothing
446+ # MOI.set(
447+ # dest,
448+ # attr,
449+ # index_map[ci],
450+ # MOI.Utilities.map_indices(index_map, attr, value),
451+ # )
452+ # end
453+ # end
454+ # end
359455 return
360456end
361457
@@ -396,7 +492,16 @@ function MOI.Utilities.final_touch(model::Optimizer{T}, _) where {T}
396492 for S in keys (model. constraints)
397493 F = PolyJuMP. ScalarPolynomialFunction{T,model. constraints[S][1 ]}
398494 cis = MOI. get (model, MOI. ListOfConstraintIndices {F,S} ())
399- _add_constraints (model, cis, index_to_var, vars, div)
495+ src = model. constraints[S][2 ]
496+ _add_constraints (
497+ model. model,
498+ src,
499+ model. index_map,
500+ cis,
501+ index_to_var,
502+ vars,
503+ div,
504+ )
400505 end
401506 end
402507 return
0 commit comments