Skip to content

Commit 89be884

Browse files
authored
[FileFormats.CBF] write some VectorOfVariables constraints in VAR block (#2478)
1 parent 0f250c0 commit 89be884

File tree

2 files changed

+129
-12
lines changed

2 files changed

+129
-12
lines changed

src/FileFormats/CBF/write.jl

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ mutable struct _CBFDataStructure
1919
bcoord::Vector{Tuple{Int,Float64}}
2020
hcoord::Vector{Tuple{Int,Int,Int,Int,Float64}}
2121
dcoord::Vector{Tuple{Int,Int,Int,Float64}}
22+
variables_with_domain::Set{MOI.VariableIndex}
23+
variable_cones::Vector{Tuple{Vector{MOI.VariableIndex},String}}
24+
2225
function _CBFDataStructure()
2326
return new(
2427
0,
@@ -30,6 +33,8 @@ mutable struct _CBFDataStructure
3033
Tuple{Int,Float64}[],
3134
Tuple{Int,Int,Int,Int,Float64}[],
3235
Tuple{Int,Int,Int,Float64}[],
36+
Set{MOI.VariableIndex}(),
37+
Tuple{Vector{MOI.VariableIndex},String}[],
3338
)
3439
end
3540
end
@@ -125,6 +130,57 @@ function _add_cones(
125130
return
126131
end
127132

133+
function _add_cones(
134+
data::_CBFDataStructure,
135+
model::Model,
136+
::Type{F},
137+
::Type{S},
138+
) where {F<:MOI.VectorOfVariables,S}
139+
for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
140+
f = MOI.get(model, MOI.ConstraintFunction(), ci)
141+
is_variable_cone = true
142+
for (i, xi) in enumerate(f.variables)
143+
if xi in data.variables_with_domain
144+
is_variable_cone = false
145+
break
146+
elseif xi.value != f.variables[1].value + i - 1
147+
is_variable_cone = false
148+
break
149+
end
150+
push!(data.variables_with_domain, xi)
151+
end
152+
str = _cone_string(data, S)
153+
if !is_variable_cone
154+
_add_function(data, f, S)
155+
set = MOI.get(model, MOI.ConstraintSet(), ci)
156+
push!(data.cones, (str, MOI.dimension(set)))
157+
else
158+
push!(data.variable_cones, (f.variables, str))
159+
end
160+
end
161+
return
162+
end
163+
164+
function _add_cones(
165+
data::_CBFDataStructure,
166+
model::Model,
167+
::Type{F},
168+
::Type{S},
169+
) where {
170+
F<:MOI.VectorOfVariables,
171+
S<:Union{MOI.ExponentialCone,MOI.DualExponentialCone},
172+
}
173+
# The Exponential cone in MOI and CBF are reversed. Instead of dealing with
174+
# this complexity, just write them out as `Ax + b in K` constraints.
175+
# TODO(odow): we should support this at some point. See #2478
176+
for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
177+
f = MOI.get(model, MOI.ConstraintFunction(), ci)
178+
_add_function(data, f, S)
179+
push!(data.cones, (_cone_string(data, S), 3))
180+
end
181+
return
182+
end
183+
128184
function _add_cones(
129185
data::_CBFDataStructure,
130186
model::Model,
@@ -252,11 +308,26 @@ function _write_POWCONES(io::IO, model::Model, S, keyword)
252308
return
253309
end
254310

255-
function _write_VAR(io::IO, model::Model)
311+
function _write_VAR(io::IO, model::Model, data)
256312
num_var = MOI.get(model, MOI.NumberOfVariables())
313+
cones = Tuple{String,Int}[]
314+
current_variable = 0
315+
for (f, str) in sort!(data.variable_cones; by = x -> first(x[1]).value)
316+
offset = first(f).value - current_variable - 1
317+
if offset > 0
318+
push!(cones, ("F", offset))
319+
end
320+
push!(cones, (str, length(f)))
321+
current_variable = last(f).value
322+
end
323+
if current_variable < num_var
324+
push!(cones, ("F", num_var - current_variable))
325+
end
257326
println(io, "VAR")
258-
println(io, num_var, " 1")
259-
println(io, "F ", num_var)
327+
println(io, num_var, " ", length(cones))
328+
for (K, n) in cones
329+
println(io, K, " ", n)
330+
end
260331
println(io)
261332
return
262333
end
@@ -417,7 +488,7 @@ function Base.write(io::IO, model::Model)
417488
###
418489
_write_OBJSENSE(io, model)
419490
# _write_PSDVAR
420-
_write_VAR(io, model)
491+
_write_VAR(io, model, data)
421492
_write_INT(io, model)
422493
_write_PSDCON(io, data)
423494
_write_CON(io, data)

test/FileFormats/CBF/CBF.jl

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,6 @@ const _WRITE_READ_MODELS = [
218218
variables: x, y
219219
minobjective: x
220220
c1: [x, y] in Zeros(2)
221-
""",
222-
),
223-
(
224-
"VectorOfVariables in Reals",
225-
"""
226-
variables: x, y
227-
minobjective: x
228-
c1: [x, y] in Reals(2)
229221
""",
230222
),
231223
(
@@ -454,6 +446,60 @@ function test_example_models()
454446
end
455447
end
456448

449+
function test_write_variable_cones()
450+
model = CBF.Model()
451+
for set in (
452+
MOI.Zeros(2),
453+
MOI.Nonnegatives(3),
454+
MOI.PowerCone(0.74),
455+
MOI.Nonpositives(1),
456+
MOI.DualPowerCone(0.25),
457+
MOI.Nonnegatives(3),
458+
MOI.PowerCone(0.5),
459+
MOI.SecondOrderCone(3),
460+
)
461+
_ = MOI.add_constrained_variables(model, set)
462+
end
463+
io = IOBuffer()
464+
write(io, model)
465+
seekstart(io)
466+
@test read(io, String) == """
467+
VER
468+
3
469+
470+
POWCONES
471+
2 4
472+
2
473+
0.74
474+
0.26
475+
2
476+
0.5
477+
0.5
478+
479+
POW*CONES
480+
1 2
481+
2
482+
0.25
483+
0.75
484+
485+
OBJSENSE
486+
MIN
487+
488+
VAR
489+
21 8
490+
L= 2
491+
L+ 3
492+
@0:POW 3
493+
L- 1
494+
@0:POW* 3
495+
L+ 3
496+
@1:POW 3
497+
Q 3
498+
499+
"""
500+
return
501+
end
502+
457503
function runtests()
458504
for name in names(@__MODULE__, all = true)
459505
if startswith("$(name)", "test_")

0 commit comments

Comments
 (0)