@@ -112,6 +112,7 @@ function MOI.supports_constraint(
112112) where {F<: MOI.AbstractFunction ,S<: MOI.AbstractSet }
113113 return MOI. supports_constraint (model. model, F, S)
114114end
115+
115116function MOI. supports_constraint (
116117 model:: Optimizer{T} ,
117118 :: Type{<:PolyJuMP.ScalarPolynomialFunction{T}} ,
@@ -131,6 +132,7 @@ function MOI.add_constraint(
131132)
132133 return MOI. add_constraint (model. model, func, set)
133134end
135+
134136function MOI. add_constraint (
135137 model:: Optimizer{T} ,
136138 func:: PolyJuMP.ScalarPolynomialFunction{T,P} ,
@@ -250,31 +252,65 @@ function _add_variables!(
250252 return d
251253end
252254
255+ import IntervalArithmetic
256+
253257function monomial_variable_index (
254258 model:: Optimizer{T} ,
255259 d:: Dict ,
256260 div,
257261 mono:: MP.AbstractMonomialLike ,
258262) where {T}
259263 if ! haskey (d, mono)
264+ # If we don't have a variable for `mono` yet,
265+ # we create one now by equal to `x * y`.
266+ mono_bounds = IntervalArithmetic. interval (one (T))
267+ for var in MP. variables (mono)
268+ deg = MP. degree (mono, var)
269+ if deg == 0
270+ continue
271+ end
272+ vi = monomial_variable_index (model, d, div, var)
273+ lb_var, ub_var = MOI. Utilities. get_bounds (model, T, vi)
274+ F = float (T)
275+ var_bounds = IntervalArithmetic. interval (
276+ lb_var == typemin (lb_var) ? typemin (F) : float (lb_var),
277+ ub_var == typemax (ub_var) ? typemax (F) : float (ub_var),
278+ )
279+ mono_bounds *= var_bounds^ deg
280+ end
260281 x = div[mono]
261282 vx = monomial_variable_index (model, d, div, x)
262283 y = MP. div_multiple (mono, x)
263284 vy = monomial_variable_index (model, d, div, y)
264- lx, ux = MOI. Utilities. get_bounds (model, T, vx)
265- ly, uy = MOI. Utilities. get_bounds (model, T, vy)
266- bounds = (lx * ly, lx * uy, ux * ly, ux * uy)
267- l = min (bounds... )
268- if vx == vy
269- l = max (l, zero (T))
285+ lb = IntervalArithmetic. inf (mono_bounds)
286+ ub = IntervalArithmetic. sup (mono_bounds)
287+ if isfinite (lb)
288+ if isfinite (ub)
289+ if lb == ub
290+ set = MOI. EqualTo (T (lb))
291+ else
292+ set = MOI. Interval (T (lb), T (ub))
293+ end
294+ else
295+ set = MOI. GreaterThan (T (lb))
296+ end
297+ else
298+ if isfinite (ub)
299+ set = MOI. LessThan (T (ub))
300+ else
301+ set = nothing
302+ end
270303 end
271- u = max (bounds... )
272- d[mono], _ =
273- MOI. add_constrained_variable (model. model, MOI. Interval (l, u))
274- MOI. add_constraint (
304+ if isnothing (set)
305+ d[mono] = MOI. add_variable (model. model)
306+ else
307+ d[mono], _ = MOI. add_constrained_variable (model. model, set)
308+ end
309+ MOI. Utilities. normalize_and_add_constraint (
275310 model,
276311 MA. @rewrite (one (T) * d[mono] - one (T) * vx * vy),
277- MOI. EqualTo (zero (T)),
312+ MOI. EqualTo (zero (T));
313+ allow_modify_function = true ,
278314 )
279315 end
280316 return d[mono]
@@ -286,8 +322,9 @@ function _add_constraints(model::Optimizer, cis, index_to_var, d, div)
286322 set = MOI. get (model, MOI. ConstraintSet (), ci)
287323 func, index_to_var = _subs! (func, index_to_var)
288324 quad = _quad_convert (func. polynomial, d, div)
289- MOI. add_constraint (model, quad, set)
325+ MOI. Utilities . normalize_and_add_constraint (model, quad, set)
290326 end
327+ return
291328end
292329
293330function MOI. Utilities. final_touch (model:: Optimizer{T} , _) where {T}
0 commit comments