Skip to content

Commit

Permalink
Add ZeroOne and Integer support to lp_matrix_data (#3591)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Dec 3, 2023
1 parent 5e61f34 commit 20019f2
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 13 deletions.
24 changes: 19 additions & 5 deletions docs/src/manual/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,9 @@ matrix form of a linear program.
```jldoctest
julia> begin
model = Model()
@variable(model, x >= 1)
@variable(model, x >= 1, Bin)
@variable(model, 2 <= y)
@variable(model, 3 <= z <= 4)
@variable(model, 3 <= z <= 4, Int)
@constraint(model, x == 5)
@constraint(model, 2x + 3y <= 6)
@constraint(model, -4y >= 5z + 7)
Expand All @@ -461,10 +461,10 @@ julia> data = lp_matrix_data(model);
julia> data.A
4×3 SparseArrays.SparseMatrixCSC{Float64, Int64} with 7 stored entries:
1.0 ⋅ ⋅
1.0 ⋅ ⋅
⋅ -4.0 -5.0
2.0 3.0 ⋅
1.0 1.0 ⋅
2.0 3.0 ⋅
1.0 1.0 ⋅
julia> data.b_lower
4-element Vector{Float64}:
Expand Down Expand Up @@ -503,8 +503,22 @@ julia> data.c_offset
julia> data.sense
MAX_SENSE::OptimizationSense = 1
julia> data.integers
1-element Vector{Int64}:
3
julia> data.binaries
1-element Vector{Int64}:
1
```

!!! warning
[`lp_matrix_data`](@ref) is intentionally limited in the types of problems
that it supports and the structure of the matrices it outputs. It is mainly
intended as a pedagogical and debugging tool. It should not be used to
interface solvers, see [Implementing a solver interface](@ref) instead.

## Backends

!!! info
Expand Down
42 changes: 38 additions & 4 deletions src/lp_matrix_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ struct LPMatrixData{T}
c::Vector{T}
c_offset::T
sense::MOI.OptimizationSense
integers::Vector{Int}
binaries::Vector{Int}
variables::Vector{GenericVariableRef{T}}
affine_constraints::Vector{ConstraintRef}
variable_constraints::Vector{ConstraintRef}
Expand All @@ -35,6 +37,7 @@ struct storing data for an equivalent linear program in the form:
& x_l \\le x \\le x_u
\\end{aligned}
```
where elements in `x` may be continuous, integer, or binary variables.
## Fields
Expand All @@ -50,9 +53,13 @@ The struct returned by [`lp_matrix_data`](@ref) has the fields:
the value of `typemin(T)` is used.
* `x_upper::Vector{T}`: the dense vector of variable upper bounds. If missing,
the value of `typemax(T)` is used.
* `c::Vector{T}`: the dense vector of linear objective coefficiennts
* `c::Vector{T}`: the dense vector of linear objective coefficients
* `c_offset::T`: the constant term in the objective function.
* `sense::MOI.OptimizationSense`: the objective sense of the model.
* `integers::Vector{Int}`: the sorted list of column indices that are integer
variables.
* `binaries::Vector{Int}`: the sorted list of column indices that are binary
variables.
* `variables::Vector{GenericVariableRef{T}}`: a vector of [`GenericVariableRef`](@ref),
corresponding to order of the columns in the matrix form.
* `affine_constraints::Vector{ConstraintRef}`: a vector of [`ConstraintRef`](@ref),
Expand All @@ -62,9 +69,6 @@ The struct returned by [`lp_matrix_data`](@ref) has the fields:
The models supported by [`lp_matrix_data`](@ref) are intentionally limited
to linear programs.
If your model has integrality, use [`relax_integrality`](@ref) to remove integer
restrictions before calling [`lp_matrix_data`](@ref).
"""
function lp_matrix_data(model::GenericModel{T}) where {T}
variables = all_variables(model)
Expand All @@ -80,6 +84,8 @@ function lp_matrix_data(model::GenericModel{T}) where {T}
I = Int[],
J = Int[],
V = T[],
integers = Int[],
binaries = Int[],
variable_to_column = columns,
bound_constraints = ConstraintRef[],
affine_constraints = ConstraintRef[],
Expand All @@ -97,6 +103,8 @@ function lp_matrix_data(model::GenericModel{T}) where {T}
cache.c,
cache.c_offset[],
MOI.get(model, MOI.ObjectiveSense()),
sort!(cache.integers),
sort!(cache.binaries),
variables,
cache.affine_constraints,
cache.bound_constraints,
Expand Down Expand Up @@ -128,6 +136,32 @@ function _fill_standard_form(
return
end

function _fill_standard_form(
model::GenericModel{T},
::Type{GenericVariableRef{T}},
::Type{MOI.Integer},
cache::Any,
) where {T}
for c in all_constraints(model, GenericVariableRef{T}, MOI.Integer)
c_obj = constraint_object(c)
push!(cache.integers, cache.variable_to_column[c_obj.func])
end
return
end

function _fill_standard_form(
model::GenericModel{T},
::Type{GenericVariableRef{T}},
::Type{MOI.ZeroOne},
cache::Any,
) where {T}
for c in all_constraints(model, GenericVariableRef{T}, MOI.ZeroOne)
c_obj = constraint_object(c)
push!(cache.binaries, cache.variable_to_column[c_obj.func])
end
return
end

function _fill_standard_form(
model::GenericModel{T},
::Type{F},
Expand Down
15 changes: 11 additions & 4 deletions test/test_lp_matrix_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ using Test

function test_standard_matrix_form()
model = Model()
@variable(model, x >= 1)
@variable(model, x >= 1, Bin)
@variable(model, 2 <= y)
@variable(model, 3 <= z <= 4)
@variable(model, 3 <= z <= 4, Int)
@constraint(model, x == 5)
@constraint(model, 2x + 3y <= 6)
@constraint(model, -4y >= 5z + 7)
Expand All @@ -27,11 +27,17 @@ function test_standard_matrix_form()
@test a.c == [2, 0, 0]
@test a.c_offset == 1
@test a.sense == MOI.MAX_SENSE
@test a.integers == [3]
@test a.binaries == [1]
@objective(model, Min, y)
unset_binary(x)
set_integer(x)
b = lp_matrix_data(model)
b.sense == MOI.MIN_SENSE
b.c == [0, 1, 0]
b.c_offset == 0
@test b.integers == [1, 3]
@test b.binaries == Int[]
return
end

Expand Down Expand Up @@ -73,10 +79,11 @@ end

function test_standard_matrix_form_bad_constraint()
model = Model()
@variable(model, x, Bin)
@variable(model, x[1:3])
@constraint(model, x in SecondOrderCone())
@test_throws(
ErrorException(
"Unsupported constraint type in `lp_matrix_data`: $(VariableRef) -in- $(MOI.ZeroOne)",
"Unsupported constraint type in `lp_matrix_data`: $(Vector{VariableRef}) -in- $(MOI.SecondOrderCone)",
),
lp_matrix_data(model),
)
Expand Down

0 comments on commit 20019f2

Please sign in to comment.