@@ -43,7 +43,10 @@ function update_bin!(bin, e, p)
4343 if _update_bin! (bin, e, p) # if update succeeded, return the original bin
4444 return bin
4545 else # if update has failed, return a new bin
46- return Bin (e, [p], bin)
46+ if p isa Tuple
47+ p = [p]
48+ end
49+ return Bin (e, p, bin)
4750 end
4851end
4952function _update_bin! (bin:: Bin{E,P,I} , e, p) where {E,P,I}
6164function check_supported (T, moim)
6265 con_types = MOI. get (moim, MOI. ListOfConstraintTypesPresent ())
6366 for (F, S) in con_types
67+ if ExaModels. is_extension_type (F)
68+ continue
69+ end
6470 ! (F <: SUPPORTED_FUNC_TYPE_WITH_VAR ) && error (" Unsupported function type $F ." )
6571 if F <: MOI.VariableIndex
6672 ! (S <: SUPPORTED_VAR_SET_TYPE ) &&
@@ -71,7 +77,7 @@ function check_supported(T, moim)
7177 end
7278
7379 obj_type = MOI. get (moim, MOI. ObjectiveFunctionType ())
74- ! (obj_type <: SUPPORTED_FUNC_TYPE_WITH_VAR ) &&
80+ ! (obj_type <: SUPPORTED_FUNC_TYPE_WITH_VAR || ExaModels . is_extension_type (obj_type) ) &&
7581 error (" Unsupported objective function type $obj_type ." )
7682
7783 obj_sense = MOI. get (moim, MOI. ObjectiveSense ())
@@ -204,23 +210,19 @@ function copy_constraints!(c, moim, var_to_idx, T)
204210
205211 con_types = MOI. get (moim, MOI. ListOfConstraintTypesPresent ())
206212 for (F, S) in con_types
213+ F <: MOI.VariableIndex && continue
214+ ExaModels. is_extension_type (F) && continue
207215 cis = MOI. get (moim, MOI. ListOfConstraintIndices {F,S} ())
208- if F <: MOI.VariableIndex
209- for ci in cis
210- vi = MOI. get (moim, MOI. ConstraintFunction (), ci)
211- vartype, var_idx = var_to_idx[vi]
212- if vartype === :variable
213- con_to_idx[ci] = var_idx
214- end
215- end
216- continue
217- end
218- bin, offset =
219- exafy_con (moim, cis, bin, offset, lcon, ucon, y0, var_to_idx, con_to_idx)
216+ bin, offset = exafy_con (moim, cis, bin, offset, lcon, ucon, y0, var_to_idx, con_to_idx)
220217 end
221218 c, cons = ExaModels. add_con (c, offset; start = y0, lcon = lcon, ucon = ucon)
222219 c = build_constraint! (c, cons, bin)
223220
221+ # Hook for extensions (e.g. GenOpt) to add their constraint types
222+ if applicable (ExaModels. copy_extra_constraints!, c, moim, var_to_idx, con_to_idx, T)
223+ c = ExaModels. copy_extra_constraints! (c, moim, var_to_idx, con_to_idx, T)
224+ end
225+
224226 return c, con_to_idx
225227end
226228
@@ -323,15 +325,17 @@ function exafy_con(
323325 var_to_idx,
324326 con_to_idx,
325327) where {V<: Vector{<:MOI.ConstraintIndex} }
326- l = length (cons)
328+ l = sum (cons) do ci
329+ MOI. dimension (MOI. get (moim, MOI. ConstraintSet (), ci))
330+ end
327331
328332 resize! (lcon, offset + l)
329333 resize! (ucon, offset + l)
330334 resize! (y0, offset + l)
331335 for (i, ci) in enumerate (cons)
332336 func = MOI. get (moim, MOI. ConstraintFunction (), ci)
333337 set = MOI. get (moim, MOI. ConstraintSet (), ci)
334- con_to_idx[ci] = offset + i
338+ con_to_idx[ci] = offset + 1
335339 start = if MOI. supports (
336340 moim, MOI. ConstraintPrimalStart (), typeof (ci)
337341 )
@@ -342,8 +346,9 @@ function exafy_con(
342346 _exafy_con_update_start (ci, start, y0, con_to_idx)
343347 _exafy_con_update_vector (ci, set, lcon, ucon, con_to_idx)
344348 bin = _exafy_con (ci, func, bin, var_to_idx, con_to_idx)
349+ offset += MOI. dimension (set)
345350 end
346- return bin, ( offset += l)
351+ return bin, offset
347352end
348353
349354function _exafy_con_update_start (i, start, y0, con_to_idx)
@@ -451,9 +456,12 @@ function exafy_obj(o::MOI.ScalarNonlinearFunction, bin, var_to_idx)
451456 bin = update_bin! (bin, e, p)
452457 end
453458 constant += m. constant
454- else
459+ elseif m isa MOI . ScalarNonlinearFunction
455460 e, p = _exafy (m, var_to_idx)
456461 bin = update_bin! (bin, e, p)
462+ else
463+ e, p = ExaModels. exafy_extension_obj_arg (m, var_to_idx)
464+ bin = update_bin! (bin, e, p)
457465 end
458466 end
459467 else
@@ -464,6 +472,15 @@ function exafy_obj(o::MOI.ScalarNonlinearFunction, bin, var_to_idx)
464472 return update_bin! (bin, ExaModels. Null (constant), (1 ,)) # TODO see if this can be empty tuple
465473end
466474
475+ # Fallback for extension objective types (e.g. SumGenerator as top-level objective)
476+ function exafy_obj (o, bin, var_to_idx)
477+ if ! ExaModels. is_extension_type (typeof (o))
478+ throw (MOI. UnsupportedAttribute (MOI. ObjectiveFunction {typeof(o)} ()))
479+ end
480+ e, p = ExaModels. exafy_extension_obj_arg (o, var_to_idx)
481+ return update_bin! (bin, e, p)
482+ end
483+
467484function _exafy (v:: MOI.VariableIndex , var_to_idx, p = ())
468485 i = ExaModels. DataIndexed (ExaModels. DataSource (), length (p) + 1 )
469486 vartype, idx = var_to_idx[v]
@@ -481,7 +498,7 @@ function _exafy(i::R, var_to_idx, p) where {R<:Real}
481498end
482499
483500function _exafy (e:: MOI.ScalarNonlinearFunction , var_to_idx, p = ())
484- return op (e. head)((begin
501+ return ExaModels . op (e. head)((begin
485502 c, p = _exafy (e, var_to_idx, p)
486503 c
487504 end for e in e. args). .. ), p
@@ -542,8 +559,7 @@ function _exafy(e::MOI.ScalarQuadraticTerm{T}, var_to_idx, p = ()) where {T}
542559 end
543560end
544561
545- # eval can be a performance killer -- we want to explicitly include symbols for frequently used operations.
546- function op (s:: Symbol )
562+ function ExaModels. op (s:: Symbol )
547563 # uni/multi
548564 if s === :+
549565 return +
710726
711727MOI. is_empty (model:: Optimizer ) = isnothing (model. model)
712728
729+ function MOI. supports_constraint (
730+ :: Optimizer ,
731+ :: Type{F} ,
732+ :: Type{S} ,
733+ ) where {F<: MOI.AbstractFunction , S<: MOI.AbstractSet }
734+ return ExaModels. is_extension_type (F)
735+ end
736+
713737function MOI. supports_constraint (
714738 :: Optimizer ,
715739 :: Type{<:SUPPORTED_FUNC_TYPE} ,
730754function MOI. supports (:: Optimizer , :: MOI.ObjectiveFunction{<:SUPPORTED_FUNC_TYPE_WITH_VAR} )
731755 return true
732756end
757+ function MOI. supports (:: Optimizer , :: MOI.ObjectiveFunction{F} ) where {F}
758+ return ExaModels. is_extension_type (F)
759+ end
733760function MOI. supports (:: Optimizer , :: MOI.VariablePrimalStart , :: Type{MOI.VariableIndex} )
734761 return true
735762end
@@ -884,17 +911,35 @@ function _make_index_map(model::MOI.ModelLike, var_to_idx, con_to_idx)
884911 end
885912 end
886913 for (F, S) in MOI. get (model, MOI. ListOfConstraintTypesPresent ())
887- _make_constraints_map (model, map. con_map[F, S], con_to_idx)
914+ _make_constraints_map (model, map. con_map[F, S], con_to_idx, var_to_idx )
888915 end
889916 return map
890917end
891918function _make_constraints_map (
892919 model,
893920 map:: MOI.Utilities.DoubleDicts.IndexDoubleDictInner{F,S} ,
894921 con_to_idx,
922+ var_to_idx,
895923) where {F,S}
896924 for c in MOI. get (model, MOI. ListOfConstraintIndices {F,S} ())
897- map[c] = typeof (c)(con_to_idx[c])
925+ if haskey (con_to_idx, c)
926+ map[c] = typeof (c)(con_to_idx[c])
927+ end
928+ end
929+ return
930+ end
931+ function _make_constraints_map (
932+ model,
933+ map:: MOI.Utilities.DoubleDicts.IndexDoubleDictInner{MOI.VariableIndex,S} ,
934+ con_to_idx,
935+ var_to_idx,
936+ ) where {S}
937+ for c in MOI. get (model, MOI. ListOfConstraintIndices {MOI.VariableIndex,S} ())
938+ vi = MOI. get (model, MOI. ConstraintFunction (), c)
939+ entry = var_to_idx[vi]
940+ if entry. type === :variable
941+ map[c] = typeof (c)(entry. idx)
942+ end
898943 end
899944 return
900945end
0 commit comments