@@ -27,18 +27,41 @@ function _print_shortest(io::IO, x::Float64)
2727 return
2828end
2929
30+ const _ILT1{T} = MOI. Indicator{MOI. ACTIVATE_ON_ONE,MOI. LessThan{T}}
31+ const _IGT1{T} = MOI. Indicator{MOI. ACTIVATE_ON_ONE,MOI. GreaterThan{T}}
32+ const _IET1{T} = MOI. Indicator{MOI. ACTIVATE_ON_ONE,MOI. EqualTo{T}}
33+ const _ILT0{T} = MOI. Indicator{MOI. ACTIVATE_ON_ZERO,MOI. LessThan{T}}
34+ const _IGT0{T} = MOI. Indicator{MOI. ACTIVATE_ON_ZERO,MOI. GreaterThan{T}}
35+ const _IET0{T} = MOI. Indicator{MOI. ACTIVATE_ON_ZERO,MOI. EqualTo{T}}
36+
3037MOI. Utilities. @model (
3138 Model,
3239 (MOI. ZeroOne, MOI. Integer),
3340 (MOI. EqualTo, MOI. GreaterThan, MOI. LessThan, MOI. Interval),
3441 (),
35- (MOI. SOS1, MOI. SOS2),
42+ (MOI. SOS1, MOI. SOS2, _ILT1, _IET1, _IGT1, _ILT0, _IGT0, _IET0 ),
3643 (),
3744 (MOI. ScalarQuadraticFunction, MOI. ScalarAffineFunction),
3845 (MOI. VectorOfVariables,),
39- ()
46+ (MOI . VectorAffineFunction, )
4047)
4148
49+ function MOI. supports_constraint (
50+ :: Model{T} ,
51+ :: Type{MOI.VectorAffineFunction{T}} ,
52+ :: Type{MOI.SOS1{T}} ,
53+ ) where {T}
54+ return false
55+ end
56+
57+ function MOI. supports_constraint (
58+ :: Model{T} ,
59+ :: Type{MOI.VectorAffineFunction{T}} ,
60+ :: Type{MOI.SOS2{T}} ,
61+ ) where {T}
62+ return false
63+ end
64+
4265struct Options
4366 maximum_length:: Int
4467 warn:: Bool
@@ -98,6 +121,7 @@ function _write_function(
98121 :: Model ,
99122 func:: MOI.ScalarAffineFunction{Float64} ,
100123 variable_names:: Dict{MOI.VariableIndex,String} ;
124+ print_one:: Bool = true ,
101125 kwargs... ,
102126)
103127 is_first_item = true
@@ -108,7 +132,9 @@ function _write_function(
108132 for term in func. terms
109133 if ! (term. coefficient ≈ 0.0 )
110134 if is_first_item
111- _print_shortest (io, term. coefficient)
135+ if print_one || ! isone (term. coefficient)
136+ _print_shortest (io, term. coefficient)
137+ end
112138 is_first_item = false
113139 else
114140 print (io, term. coefficient < 0 ? " - " : " + " )
@@ -338,6 +364,62 @@ function _write_constraint(
338364 return
339365end
340366
367+ function _write_indicator_constraints (
368+ io,
369+ model,
370+ :: Type{S} ,
371+ variable_names,
372+ ) where {S}
373+ F = MOI. VectorAffineFunction{Float64}
374+ for A in (MOI. ACTIVATE_ON_ONE, MOI. ACTIVATE_ON_ZERO)
375+ Set = MOI. Indicator{A,S}
376+ for index in MOI. get (model, MOI. ListOfConstraintIndices {F,Set} ())
377+ _write_constraint (
378+ io,
379+ model,
380+ index,
381+ variable_names;
382+ write_name = true ,
383+ )
384+ end
385+ end
386+ F = MOI. VectorOfVariables
387+ for A in (MOI. ACTIVATE_ON_ONE, MOI. ACTIVATE_ON_ZERO)
388+ Set = MOI. Indicator{A,S}
389+ for index in MOI. get (model, MOI. ListOfConstraintIndices {F,Set} ())
390+ _write_constraint (
391+ io,
392+ model,
393+ index,
394+ variable_names;
395+ write_name = true ,
396+ )
397+ end
398+ end
399+ return
400+ end
401+
402+ function _write_constraint (
403+ io:: IO ,
404+ model:: Model{T} ,
405+ index:: MOI.ConstraintIndex{F,MOI.Indicator{A,S}} ,
406+ variable_names:: Dict{MOI.VariableIndex,String} ;
407+ write_name:: Bool = true ,
408+ ) where {T,F<: Union{MOI.VectorOfVariables,MOI.VectorAffineFunction{T}} ,A,S}
409+ func = MOI. get (model, MOI. ConstraintFunction (), index)
410+ set = MOI. get (model, MOI. ConstraintSet (), index)
411+ if write_name
412+ print (io, MOI. get (model, MOI. ConstraintName (), index), " : " )
413+ end
414+ z, f = MOI. Utilities. scalarize (func)
415+ flag = A == MOI. ACTIVATE_ON_ONE ? 1 : 0
416+ _write_function (io, model, z, variable_names; print_one = false )
417+ print (io, " = " , flag, " -> " )
418+ _write_function (io, model, f, variable_names)
419+ _write_constraint_suffix (io, set. set)
420+ return
421+ end
422+
341423"""
342424 Base.write(io::IO, model::FileFormats.LP.Model)
343425
@@ -364,6 +446,7 @@ function Base.write(io::IO, model::Model)
364446 println (io, " subject to" )
365447 for S in _SCALAR_SETS
366448 _write_constraints (io, model, S, variable_names)
449+ _write_indicator_constraints (io, model, S, variable_names)
367450 end
368451 println (io, " Bounds" )
369452 CI = MOI. ConstraintIndex{MOI. VariableIndex,MOI. ZeroOne}
@@ -456,6 +539,7 @@ mutable struct _ReadCache
456539 num_constraints:: Int
457540 name_to_variable:: Dict{String,MOI.VariableIndex}
458541 has_default_bound:: Set{MOI.VariableIndex}
542+ indicator:: Union{Nothing,Pair{MOI.VariableIndex,MOI.ActivationCondition}}
459543 function _ReadCache ()
460544 return new (
461545 MOI. ScalarAffineFunction (MOI. ScalarAffineTerm{Float64}[], 0.0 ),
@@ -466,6 +550,7 @@ mutable struct _ReadCache
466550 0 ,
467551 Dict {String,MOI.VariableIndex} (),
468552 Set {MOI.VariableIndex} (),
553+ nothing ,
469554 )
470555 end
471556end
@@ -684,6 +769,14 @@ function _parse_section(
684769 cache. constraint_name = " R$(cache. num_constraints) "
685770 end
686771 end
772+ if cache. indicator === nothing
773+ if (m = match (r" \s *(.+?)\s *=\s *(0|1)\s *->(.+)" , line)) != = nothing
774+ z = _get_variable_from_name (model, cache, String (m[1 ]))
775+ cond = m[2 ] == " 0" ? MOI. ACTIVATE_ON_ZERO : MOI. ACTIVATE_ON_ONE
776+ cache. indicator = z => cond
777+ line = String (m[3 ])
778+ end
779+ end
687780 if occursin (" ^" , line)
688781 # Simplify parsing of constraints with ^2 terms by turning them into
689782 # explicit " ^ 2" terms. This avoids ambiguity when parsing names.
@@ -723,13 +816,18 @@ function _parse_section(
723816 cache. constraint_function. constant,
724817 )
725818 end
819+ if cache. indicator != = nothing
820+ f = MOI. Utilities. operate (vcat, Float64, cache. indicator[1 ], f)
821+ constraint_set = MOI. Indicator {cache.indicator[2]} (constraint_set)
822+ end
726823 c = MOI. add_constraint (model, f, constraint_set)
727824 MOI. set (model, MOI. ConstraintName (), c, cache. constraint_name)
728825 cache. num_constraints += 1
729826 empty! (cache. constraint_function. terms)
730827 empty! (cache. quad_terms)
731828 cache. constraint_function. constant = 0.0
732829 cache. constraint_name = " "
830+ cache. indicator = nothing
733831 end
734832 return
735833end
0 commit comments