@@ -146,6 +146,7 @@ mutable struct Model <: MOI.ModelLike
146146 MOI. Utilities. UniversalFallback{MOI. Utilities. Model{Float64}},
147147 }
148148 use_nlp_block:: Bool
149+ complementarity_constraints:: Vector{Vector{Int}}
149150
150151 function Model (; use_nlp_block:: Bool = true )
151152 return new (
@@ -160,6 +161,7 @@ mutable struct Model <: MOI.ModelLike
160161 MOI. VariableIndex[],
161162 nothing ,
162163 use_nlp_block,
164+ Vector{Int}[],
163165 )
164166 end
165167end
@@ -185,6 +187,7 @@ function MOI.empty!(model::Model)
185187 end
186188 empty! (model. order)
187189 model. model = nothing
190+ empty! (model. complementarity_constraints)
188191 return
189192end
190193
@@ -222,6 +225,21 @@ function MOI.supports_constraint(
222225 return true
223226end
224227
228+ function MOI. supports_constraint (
229+ :: Model ,
230+ :: Type{F} ,
231+ :: Type{MOI.Complements} ,
232+ ) where {
233+ F<: Union {
234+ MOI. VectorOfVariables,
235+ MOI. VectorAffineFunction{Float64},
236+ MOI. VectorQuadraticFunction{Float64},
237+ MOI. VectorNonlinearFunction,
238+ },
239+ }
240+ return true
241+ end
242+
225243MOI. supports (:: Model , :: MOI.ObjectiveSense ) = true
226244MOI. supports (:: Model , :: MOI.ObjectiveFunction{<:_SCALAR_FUNCTIONS} ) = true
227245
@@ -493,6 +511,48 @@ function _process_constraint(
493511 return
494512end
495513
514+ _to_x (f) = convert (MOI. VariableIndex, f)
515+
516+ function _to_x (f:: MOI.ScalarNonlinearFunction )
517+ # Hacky way to ensure that f is a standalone variable
518+ @assert f isa MOI. ScalarNonlinearFunction
519+ @assert f. head == :+ && length (f. args) == 1
520+ @assert f. args[1 ] isa MOI. VariableIndex
521+ return return f. args[1 ]
522+ end
523+
524+ function _process_constraint (
525+ dest:: Model ,
526+ model,
527+ :: Type{F} ,
528+ :: Type{S} ,
529+ mapping,
530+ ) where {F,S<: MOI.Complements }
531+ ci_src = MOI. get (model, MOI. ListOfConstraintIndices {F,S} ())
532+ for ci in ci_src
533+ f_vec = MOI. get (model, MOI. ConstraintFunction (), ci)
534+ f_scalars = MOI. Utilities. scalarize (f_vec)
535+ n = div (MOI. output_dimension (f_vec), 2 )
536+ rows = Int[]
537+ for i in 1 : n
538+ fi, xi = f_scalars[i], _to_x (f_scalars[i+ n])
539+ con = _NLConstraint (Float64 (xi. value), Inf , 5 , _NLExpr (fi))
540+ if con. expr. is_linear
541+ push! (dest. h, con)
542+ push! (rows, - length (dest. h))
543+ else
544+ push! (dest. g, con)
545+ push! (rows, length (dest. g))
546+ end
547+ end
548+ push! (dest. complementarity_constraints, rows)
549+ mapping[ci] =
550+ MOI. ConstraintIndex {F,S} (length (dest. complementarity_constraints))
551+ end
552+ MOI. Utilities. pass_attributes (dest, model, mapping, ci_src)
553+ return
554+ end
555+
496556function _str (x:: Float64 )
497557 if isinteger (x) && (typemin (Int) <= x <= typemax (Int))
498558 return string (round (Int, x))
@@ -571,13 +631,19 @@ function Base.write(io::IO, model::Model)
571631 # Line 3: nonlinear constraints, objectives
572632 # Notes:
573633 # * We assume there is always one objective, even if it is just `min 0`.
574- # * `Writing .nl Files` lies! There are four extra integers here
634+ # * `Writing .nl Files` lies: there are four extra integers here
575635 # * Number of linear complementarity constraints
576636 # * Number of nonlinear complementarity constraints
577637 # * nd: I have no idea
578638 # * nzlb: I have no idea
579639 n_nlcon = length (model. g)
580- println (io, " " , n_nlcon, " 1 0 0 0 0" )
640+ ccon_lin = sum (c. opcode == 5 for c in model. h; init = 0 )
641+ ccon_nl = sum (c. opcode == 5 for c in model. g; init = 0 )
642+ if ccon_lin + ccon_nl > 0
643+ println (io, " " , n_nlcon, " 1 " , ccon_lin, " " , ccon_nl, " 0 0" )
644+ else
645+ println (io, " " , n_nlcon, " " , 1 )
646+ end
581647
582648 # Line 4: network constraints: nonlinear, linear
583649 # Notes:
@@ -699,9 +765,15 @@ function Base.write(io::IO, model::Model)
699765 println (io, " " , _str (g. lower))
700766 elseif g. opcode == 3
701767 println (io)
702- else
703- @assert g. opcode == 4
768+ elseif g. opcode == 4
704769 println (io, " " , _str (g. lower))
770+ else
771+ @assert g. opcode == 5
772+ @assert ! isfinite (g. upper)
773+ x = MOI. VariableIndex (g. lower)
774+ v = model. x[x]
775+ k = (- Inf < v. lower) + 2 * (v. upper < Inf )
776+ println (io, " " , k, " " , v. order + 1 )
705777 end
706778 end
707779 # Linear constraints
@@ -715,9 +787,15 @@ function Base.write(io::IO, model::Model)
715787 println (io, " " , _str (h. lower))
716788 elseif h. opcode == 3
717789 println (io)
718- else
719- @assert h. opcode == 4
790+ elseif h. opcode == 4
720791 println (io, " " , _str (h. lower))
792+ else
793+ @assert h. opcode == 5
794+ @assert ! isfinite (h. upper)
795+ x = MOI. VariableIndex (h. lower)
796+ v = model. x[x]
797+ k = (- Inf < v. lower) + 2 * (v. upper < Inf )
798+ println (io, " " , k, " " , v. order + 1 )
721799 end
722800 end
723801 end
0 commit comments