Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions src/Utilities/matrix_of_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -413,16 +413,19 @@ function _load_constants(
set::MOI.AbstractScalarSet,
)
MOI.throw_if_scalar_and_constant_not_zero(func, typeof(set))
return load_constants(constants, offset, set)
load_constants(constants, offset, set)
return
end

function _load_constants(
constants,
offset,
func::MOI.AbstractVectorFunction,
::MOI.AbstractVectorSet,
set::MOI.AbstractVectorSet,
)
return load_constants(constants, offset, func)
load_constants(constants, offset, func)
load_constants(constants, offset, set)
return
end

function _load_constraints(
Expand Down Expand Up @@ -523,6 +526,19 @@ function load_constants(
return
end

load_constants(::Vector, ::Any, ::MOI.AbstractVectorSet) = nothing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be safer to be opt-in rather than opt-out here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's breaking. And it's a bit of a pain to have to enumerate everything. Really, the failing tests in SCS should have picked this up earlier. But I obviously excluded them during development and didn't revisit them :(


function load_constants(
::Vector,
::Any,
S::Union{MOI.PowerCone,MOI.DualPowerCone},
)
return error(
"`$(typeof(S))` cannot be used with `Vector` as the set type in " *
"MatrixOfConstraints",
)
end

function_constants(b::Vector, rows) = b[rows]

"""
Expand Down
142 changes: 142 additions & 0 deletions test/Utilities/matrix_of_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,148 @@ function test_matrix_sets(::Type{T} = Int) where {T}
return
end

MOI.Utilities.@product_of_sets(
PowerSets,
MOI.PowerCone{T},
MOI.DualPowerCone{T},
)

function test_power_cone_error()
model = MOI.Utilities.Model{Float64}()
x = MOI.add_variables(model, 3)
f = MOI.Utilities.operate(vcat, Float64, 1.0 .* x...)
s = MOI.PowerCone(0.2)
MOI.add_constraint(model, f, s)
cache = MOI.Utilities.GenericOptimizer{
Float64,
MOI.Utilities.ObjectiveContainer{Float64},
MOI.Utilities.VariablesContainer{Float64},
MOI.Utilities.MatrixOfConstraints{
Float64,
MOI.Utilities.MutableSparseMatrixCSC{
Float64,
Int,
MOI.Utilities.OneBasedIndexing,
},
Vector{Float64},
PowerSets{Float64},
},
}()
@test_throws(
ErrorException(
"`$(typeof(s))` cannot be used with `Vector` as the set type in " *
"MatrixOfConstraints",
),
MOI.copy_to(cache, model),
)
return
end

function test_dual_power_cone_error()
model = MOI.Utilities.Model{Float64}()
x = MOI.add_variables(model, 3)
f = MOI.Utilities.operate(vcat, Float64, 1.0 .* x...)
s = MOI.DualPowerCone(0.2)
MOI.add_constraint(model, f, s)
cache = MOI.Utilities.GenericOptimizer{
Float64,
MOI.Utilities.ObjectiveContainer{Float64},
MOI.Utilities.VariablesContainer{Float64},
MOI.Utilities.MatrixOfConstraints{
Float64,
MOI.Utilities.MutableSparseMatrixCSC{
Float64,
Int,
MOI.Utilities.OneBasedIndexing,
},
Vector{Float64},
PowerSets{Float64},
},
}()
@test_throws(
ErrorException(
"`$(typeof(s))` cannot be used with `Vector` as the set type in " *
"MatrixOfConstraints",
),
MOI.copy_to(cache, model),
)
return
end

struct _SetConstants{T}
b::Vector{T}
power_coefficients::Dict{Int,T}
_SetConstants{T}() where {T} = new{T}(T[], Dict{Int,T}())
end

function Base.empty!(x::_SetConstants)
empty!(x.b)
empty!(x.power_coefficients)
return x
end

Base.resize!(x::_SetConstants, n) = resize!(x.b, n)

function MOI.Utilities.load_constants(x::_SetConstants, offset, f)
MOI.Utilities.load_constants(x.b, offset, f)
return
end

function MOI.Utilities.load_constants(
x::_SetConstants{T},
offset,
set::Union{MOI.PowerCone{T},MOI.DualPowerCone{T}},
) where {T}
x.power_coefficients[offset+1] = set.exponent
return
end

function MOI.Utilities.function_constants(x::_SetConstants, rows)
return MOI.Utilities.function_constants(x.b, rows)
end

function MOI.Utilities.set_from_constants(x::_SetConstants, S, rows)
return MOI.Utilities.set_from_constants(x.b, S, rows)
end

function MOI.Utilities.set_from_constants(
x::_SetConstants{T},
::Type{S},
rows,
) where {T,S<:Union{MOI.PowerCone{T},MOI.DualPowerCone{T}}}
@assert length(rows) == 3
return S(x.power_coefficients[first(rows)])
end

function test_dual_power_cone()
model = MOI.Utilities.Model{Float64}()
x = MOI.add_variables(model, 3)
f = MOI.Utilities.operate(vcat, Float64, 1.0 .* x...)
p_cone = MOI.PowerCone(0.1)
p_ref = MOI.add_constraint(model, f, p_cone)
d_cone = MOI.DualPowerCone(0.2)
d_ref = MOI.add_constraint(model, f, d_cone)
cache = MOI.Utilities.GenericOptimizer{
Float64,
MOI.Utilities.ObjectiveContainer{Float64},
MOI.Utilities.VariablesContainer{Float64},
MOI.Utilities.MatrixOfConstraints{
Float64,
MOI.Utilities.MutableSparseMatrixCSC{
Float64,
Int,
MOI.Utilities.OneBasedIndexing,
},
_SetConstants{Float64},
PowerSets{Float64},
},
}()
map = MOI.copy_to(cache, model)
@test MOI.get(cache, MOI.ConstraintSet(), map[p_ref]) == p_cone
@test MOI.get(cache, MOI.ConstraintSet(), map[d_ref]) == d_cone
return
end

end

TestMatrixOfConstraints.runtests()