Skip to content

Commit

Permalink
[FileFormats.CBF] write some VectorOfVariables constraints in VAR blo…
Browse files Browse the repository at this point in the history
…ck (#2478)
  • Loading branch information
odow authored Apr 14, 2024
1 parent 0f250c0 commit 89be884
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 12 deletions.
79 changes: 75 additions & 4 deletions src/FileFormats/CBF/write.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ mutable struct _CBFDataStructure
bcoord::Vector{Tuple{Int,Float64}}
hcoord::Vector{Tuple{Int,Int,Int,Int,Float64}}
dcoord::Vector{Tuple{Int,Int,Int,Float64}}
variables_with_domain::Set{MOI.VariableIndex}
variable_cones::Vector{Tuple{Vector{MOI.VariableIndex},String}}

function _CBFDataStructure()
return new(
0,
Expand All @@ -30,6 +33,8 @@ mutable struct _CBFDataStructure
Tuple{Int,Float64}[],
Tuple{Int,Int,Int,Int,Float64}[],
Tuple{Int,Int,Int,Float64}[],
Set{MOI.VariableIndex}(),
Tuple{Vector{MOI.VariableIndex},String}[],
)
end
end
Expand Down Expand Up @@ -125,6 +130,57 @@ function _add_cones(
return
end

function _add_cones(
data::_CBFDataStructure,
model::Model,
::Type{F},
::Type{S},
) where {F<:MOI.VectorOfVariables,S}
for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
f = MOI.get(model, MOI.ConstraintFunction(), ci)
is_variable_cone = true
for (i, xi) in enumerate(f.variables)
if xi in data.variables_with_domain
is_variable_cone = false
break
elseif xi.value != f.variables[1].value + i - 1
is_variable_cone = false
break
end
push!(data.variables_with_domain, xi)
end
str = _cone_string(data, S)
if !is_variable_cone
_add_function(data, f, S)
set = MOI.get(model, MOI.ConstraintSet(), ci)
push!(data.cones, (str, MOI.dimension(set)))
else
push!(data.variable_cones, (f.variables, str))
end
end
return
end

function _add_cones(
data::_CBFDataStructure,
model::Model,
::Type{F},
::Type{S},
) where {
F<:MOI.VectorOfVariables,
S<:Union{MOI.ExponentialCone,MOI.DualExponentialCone},
}
# The Exponential cone in MOI and CBF are reversed. Instead of dealing with
# this complexity, just write them out as `Ax + b in K` constraints.
# TODO(odow): we should support this at some point. See #2478
for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
f = MOI.get(model, MOI.ConstraintFunction(), ci)
_add_function(data, f, S)
push!(data.cones, (_cone_string(data, S), 3))
end
return
end

function _add_cones(
data::_CBFDataStructure,
model::Model,
Expand Down Expand Up @@ -252,11 +308,26 @@ function _write_POWCONES(io::IO, model::Model, S, keyword)
return
end

function _write_VAR(io::IO, model::Model)
function _write_VAR(io::IO, model::Model, data)
num_var = MOI.get(model, MOI.NumberOfVariables())
cones = Tuple{String,Int}[]
current_variable = 0
for (f, str) in sort!(data.variable_cones; by = x -> first(x[1]).value)
offset = first(f).value - current_variable - 1
if offset > 0
push!(cones, ("F", offset))
end
push!(cones, (str, length(f)))
current_variable = last(f).value
end
if current_variable < num_var
push!(cones, ("F", num_var - current_variable))
end
println(io, "VAR")
println(io, num_var, " 1")
println(io, "F ", num_var)
println(io, num_var, " ", length(cones))
for (K, n) in cones
println(io, K, " ", n)
end
println(io)
return
end
Expand Down Expand Up @@ -417,7 +488,7 @@ function Base.write(io::IO, model::Model)
###
_write_OBJSENSE(io, model)
# _write_PSDVAR
_write_VAR(io, model)
_write_VAR(io, model, data)
_write_INT(io, model)
_write_PSDCON(io, data)
_write_CON(io, data)
Expand Down
62 changes: 54 additions & 8 deletions test/FileFormats/CBF/CBF.jl
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,6 @@ const _WRITE_READ_MODELS = [
variables: x, y
minobjective: x
c1: [x, y] in Zeros(2)
""",
),
(
"VectorOfVariables in Reals",
"""
variables: x, y
minobjective: x
c1: [x, y] in Reals(2)
""",
),
(
Expand Down Expand Up @@ -454,6 +446,60 @@ function test_example_models()
end
end

function test_write_variable_cones()
model = CBF.Model()
for set in (
MOI.Zeros(2),
MOI.Nonnegatives(3),
MOI.PowerCone(0.74),
MOI.Nonpositives(1),
MOI.DualPowerCone(0.25),
MOI.Nonnegatives(3),
MOI.PowerCone(0.5),
MOI.SecondOrderCone(3),
)
_ = MOI.add_constrained_variables(model, set)
end
io = IOBuffer()
write(io, model)
seekstart(io)
@test read(io, String) == """
VER
3
POWCONES
2 4
2
0.74
0.26
2
0.5
0.5
POW*CONES
1 2
2
0.25
0.75
OBJSENSE
MIN
VAR
21 8
L= 2
L+ 3
@0:POW 3
L- 1
@0:POW* 3
L+ 3
@1:POW 3
Q 3
"""
return
end

function runtests()
for name in names(@__MODULE__, all = true)
if startswith("$(name)", "test_")
Expand Down

0 comments on commit 89be884

Please sign in to comment.