Skip to content

Commit

Permalink
Add ListOfVariablesWithAttributeSet and ListOfConstraintsWithAttribut…
Browse files Browse the repository at this point in the history
…eSet (#2331)
  • Loading branch information
odow authored Nov 1, 2023
1 parent 873d219 commit 46f1db1
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 4 deletions.
2 changes: 2 additions & 0 deletions docs/src/manual/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@ The following attributes are available:
* [`ListOfConstraintAttributesSet`](@ref)
* [`ListOfConstraintIndices`](@ref)
* [`ListOfConstraintTypesPresent`](@ref)
* [`ListOfConstraintsWithAttributeSet`](@ref)
* [`ListOfModelAttributesSet`](@ref)
* [`ListOfVariableAttributesSet`](@ref)
* [`ListOfVariableIndices`](@ref)
* [`ListOfVariablesWithAttributeSet`](@ref)
* [`NumberOfConstraints`](@ref)
* [`NumberOfVariables`](@ref)
* [`Name`](@ref)
Expand Down
2 changes: 2 additions & 0 deletions docs/src/reference/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ ListOfConstraintIndices
ListOfOptimizerAttributesSet
ListOfModelAttributesSet
ListOfVariableAttributesSet
ListOfVariablesWithAttributeSet
ListOfConstraintAttributesSet
ListOfConstraintsWithAttributeSet
UserDefinedFunction
ListOfSupportedNonlinearOperators
```
Expand Down
2 changes: 2 additions & 0 deletions docs/src/tutorials/implementing.md
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ Variable-related attributes:
| Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) |
| ---------------------- | --------------| ------------- | ------------------ |
| [`ListOfVariableAttributesSet`](@ref) | Yes | No | No |
| [`ListOfVariablesWithAttributeSet`](@ref) | Yes | No | No |
| [`NumberOfVariables`](@ref) | Yes | No | No |
| [`ListOfVariableIndices`](@ref) | Yes | No | No |

Expand All @@ -487,6 +488,7 @@ Constraint-related attributes:
| Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) |
| ---------------------- | --------------| ------------- | ------------------ |
| [`ListOfConstraintAttributesSet`](@ref) | Yes | No | No |
| [`ListOfConstraintsWithAttributeSet`](@ref) | Yes | No | No |
| [`NumberOfConstraints`](@ref) | Yes | No | No |
| [`ListOfConstraintTypesPresent`](@ref) | Yes | No | No |
| [`ConstraintFunction`](@ref) | Yes | Yes | No |
Expand Down
27 changes: 27 additions & 0 deletions src/Test/test_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1194,3 +1194,30 @@ function test_model_ModelFilter_ListOfConstraintTypesPresent(
@test MOI.get(dest, attr) == 4
return
end

function test_model_ListOfVariablesWithAttributeSet(
model::MOI.ModelLike,
::Config,
)
attr = MOI.VariableName()
@requires MOI.supports(model, attr, MOI.VariableIndex)
x = MOI.add_variables(model, 2)
MOI.set(model, attr, x[2], "y")
@test x[2] in MOI.get(model, MOI.ListOfVariablesWithAttributeSet(attr))
return
end

function test_model_ListOfConstraintsWithAttributeSet(
model::MOI.ModelLike,
::Config{T},
) where {T}
F, S = MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}
attr = MOI.ConstraintName()
@requires MOI.supports(model, attr, MOI.ConstraintIndex{F,S})
x = MOI.add_variables(model, 2)
c = MOI.add_constraint.(model, one(T) .* x, MOI.GreaterThan(zero(T)))
MOI.set(model, attr, c[2], "y")
ret = MOI.get(model, MOI.ListOfConstraintsWithAttributeSet{F,S}(attr))
@test c[2] in ret
return
end
54 changes: 50 additions & 4 deletions src/Utilities/universalfallback.jl
Original file line number Diff line number Diff line change
Expand Up @@ -373,11 +373,26 @@ function _get(
return MOI.get_fallback(uf, attr, ci)
end

function _model_supports_attribute(model, attr, index...)
return !MOI.is_copyable(attr) || MOI.supports(model, attr, index...)
end

function _model_supports_attribute(
model,
attr,
index::Type{MOI.ConstraintIndex{F,S}},
) where {F,S}
if !MOI.supports_constraint(model, F, S)
return false
end
return !MOI.is_copyable(attr) || MOI.supports(model, attr, index)
end

function MOI.get(
uf::UniversalFallback,
attr::Union{MOI.AbstractOptimizerAttribute,MOI.AbstractModelAttribute},
)
if !MOI.is_copyable(attr) || MOI.supports(uf.model, attr)
if _model_supports_attribute(uf.model, attr)
return MOI.get(uf.model, attr)
end
return _get(uf, attr)
Expand All @@ -388,8 +403,7 @@ function MOI.get(
attr::MOI.AbstractConstraintAttribute,
ci::MOI.ConstraintIndex{F,S},
) where {F,S}
if MOI.supports_constraint(uf.model, F, S) &&
(!MOI.is_copyable(attr) || MOI.supports(uf.model, attr, typeof(ci)))
if _model_supports_attribute(uf.model, attr, MOI.ConstraintIndex{F,S})
return MOI.get(uf.model, attr, ci)
end
return _get(uf, attr, ci)
Expand All @@ -400,7 +414,7 @@ function MOI.get(
attr::MOI.AbstractVariableAttribute,
vi::MOI.VariableIndex,
)
if !MOI.is_copyable(attr) || MOI.supports(uf.model, attr, MOI.VariableIndex)
if _model_supports_attribute(uf.model, attr, MOI.VariableIndex)
return MOI.get(uf.model, attr, vi)
end
return _get(uf, attr, vi)
Expand Down Expand Up @@ -939,3 +953,35 @@ end
MOI.add_variable(uf::UniversalFallback) = MOI.add_variable(uf.model)

MOI.add_variables(uf::UniversalFallback, n) = MOI.add_variables(uf.model, n)

function MOI.get(
uf::UniversalFallback,
attr::MOI.ListOfVariablesWithAttributeSet,
)
if _model_supports_attribute(uf.model, attr.attr, MOI.VariableIndex)
return MOI.get(uf.model, attr)
end
dict = get(uf.varattr, attr.attr, nothing)
if dict === nothing
return MOI.VariableIndex[]
end
return collect(keys(dict))
end

_constraint_attribute_dict(uf, ::MOI.ConstraintName) = uf.con_to_name
_constraint_attribute_dict(uf, attr) = get(uf.conattr, attr, nothing)

function MOI.get(
uf::UniversalFallback,
attr::MOI.ListOfConstraintsWithAttributeSet{F,S},
) where {F,S}
if _model_supports_attribute(uf.model, attr.attr, MOI.ConstraintIndex{F,S})
return MOI.get(uf.model, attr)
end
dict = _constraint_attribute_dict(uf, attr.attr)
if dict === nothing
return MOI.ConstraintIndex{F,S}[]
end
indices = collect(keys(dict))
return filter(Base.Fix2(isa, MOI.ConstraintIndex{F,S}), indices)
end
55 changes: 55 additions & 0 deletions src/attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,31 @@ attribute was set to variables.
"""
struct ListOfVariableAttributesSet <: AbstractModelAttribute end

"""
ListOfVariablesWithAttributeSet(attr::AbstractVariableAttribute)
A model attribute for the `Vector{VariableIndex}` of all variables with the
attribute `attr` set.
The returned list may not be minimal, so some elements may have their default
value set.
## Note
This is an optional attribute to implement. The default fallback is to get
[`ListOfVariableIndices`](@ref).
"""
struct ListOfVariablesWithAttributeSet{A} <: AbstractModelAttribute
attr::A
function ListOfVariablesWithAttributeSet(attr::AbstractVariableAttribute)
return new{typeof(attr)}(attr)
end
end

function get_fallback(model::ModelLike, ::ListOfVariablesWithAttributeSet)
return get(model, ListOfVariableIndices())
end

"""
VariableName()
Expand Down Expand Up @@ -1581,6 +1606,36 @@ not be included in the list even if then have been set with [`set`](@ref).
"""
struct ListOfConstraintAttributesSet{F,S} <: AbstractModelAttribute end

"""
ListOfConstraintsWithAttributeSet{F,S}(attr:AbstractConstraintAttribute)
A model attribute for the `Vector{ConstraintIndex{F,S}}` of all constraints with
the attribute `attr` set.
The returned list may not be minimal, so some elements may have their default
value set.
## Note
This is an optional attribute to implement. The default fallback is to get
[`ListOfConstraintIndices`](@ref).
"""
struct ListOfConstraintsWithAttributeSet{F,S,A} <: AbstractModelAttribute
attr::A
function ListOfConstraintsWithAttributeSet{F,S}(
attr::AbstractConstraintAttribute,
) where {F,S}
return new{F,S,typeof(attr)}(attr)
end
end

function get_fallback(
model::ModelLike,
::ListOfConstraintsWithAttributeSet{F,S},
) where {F,S}
return get(model, ListOfConstraintIndices{F,S}())
end

"""
ConstraintName()
Expand Down
37 changes: 37 additions & 0 deletions test/Utilities/universalfallback.jl
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,43 @@ function test_throw_unsupported_affine_constraint()
return
end

function test_ListOfVariablesWithAttributeSet()
model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())
x = MOI.add_variables(model, 2)
MOI.set(model, MOI.VariableName(), x[1], "x")
# Passed through to Model with no special support
attr = MOI.ListOfVariablesWithAttributeSet(MOI.VariableName())
@test MOI.get(model, attr) == x
# Handled by UniversalFallback
attr = MOI.ListOfVariablesWithAttributeSet(MOI.VariablePrimalStart())
# ... no attributes set
@test MOI.get(model, attr) == MOI.VariableIndex[]
# ... one attribute set
MOI.set(model, MOI.VariablePrimalStart(), x[2], 1.0)
@test MOI.get(model, attr) == [x[2]]
return
end

function test_ListOfConstraintsWithAttributeSet()
model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())
x = MOI.add_variables(model, 2)
c = MOI.add_constraint.(model, 1.0 * x, MOI.EqualTo(1.0))
F, S = MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}
MOI.set(model, MOI.ConstraintName(), c[1], "c")
# Passed through to Model with no special support
attr = MOI.ListOfConstraintsWithAttributeSet{F,S}(MOI.ConstraintName())
@test MOI.get(model, attr) == c
# Handled by UniversalFallback
attr =
MOI.ListOfConstraintsWithAttributeSet{F,S}(MOI.ConstraintPrimalStart())
# ... no attributes set
@test MOI.get(model, attr) == MOI.ConstraintIndex{F,S}[]
# ... one attribute set
MOI.set(model, MOI.ConstraintPrimalStart(), c[2], 1.0)
@test MOI.get(model, attr) == [c[2]]
return
end

end # module

TestUniversalFallback.runtests()

0 comments on commit 46f1db1

Please sign in to comment.