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
12 changes: 6 additions & 6 deletions src/Utilities/cachingoptimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -939,11 +939,11 @@ function MOI.get(
model.model_to_optimizer_map[index],
)
catch err
if err isa ArgumentError # Thrown if .optimizer doesn't support attr
return get_fallback(model, attr, index)
else
# Thrown if .optimizer doesn't support attr
if !(err isa MOI.GetAttributeNotAllowed)
rethrow(err)
end
return get_fallback(model, attr, index)
end
end

Expand All @@ -965,11 +965,11 @@ function MOI.get(
[model.model_to_optimizer_map[i] for i in indices],
)
catch err
if err isa ArgumentError # Thrown if .optimizer doesn't support attr
return [get_fallback(model, attr, i) for i in indices]
else
# Thrown if .optimizer doesn't support attr
if !(err isa MOI.GetAttributeNotAllowed)
rethrow(err)
end
return [get_fallback(model, attr, i) for i in indices]
end
end

Expand Down
34 changes: 30 additions & 4 deletions src/attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,28 @@ SetAttributeNotAllowed(attr::AnyAttribute) = SetAttributeNotAllowed(attr, "")
operation_name(err::SetAttributeNotAllowed) = "Setting attribute $(err.attr)"
message(err::SetAttributeNotAllowed) = err.message

"""
struct GetAttributeNotAllowed{AttrType} <: NotAllowedError
attr::AttrType
message::String
end

An error indicating that the attribute `attr` cannot be got for some reason (see
the error string).
"""
struct GetAttributeNotAllowed{AttrType<:AnyAttribute} <: NotAllowedError
attr::AttrType
message::String

function GetAttributeNotAllowed(attr::AnyAttribute, message::String = "")
return new{typeof(attr)}(attr, message)
end
end

operation_name(err::GetAttributeNotAllowed) = "Getting attribute $(err.attr)"

message(err::GetAttributeNotAllowed) = err.message

"""
AbstractSubmittable

Expand Down Expand Up @@ -341,7 +363,8 @@ function get_fallback(
attr::Union{AbstractModelAttribute,AbstractOptimizerAttribute},
)
return throw(
ArgumentError(
GetAttributeNotAllowed(
attr,
"$(typeof(model)) does not support getting the attribute $(attr).",
),
)
Expand All @@ -353,7 +376,8 @@ function get_fallback(
::VariableIndex,
)
return throw(
ArgumentError(
GetAttributeNotAllowed(
attr,
"$(typeof(model)) does not support getting the attribute $(attr).",
),
)
Expand All @@ -365,15 +389,17 @@ function get_fallback(
::ConstraintIndex,
)
return throw(
ArgumentError(
GetAttributeNotAllowed(
attr,
"$(typeof(model)) does not support getting the attribute $(attr).",
),
)
end

function get_fallback(::ModelLike, attr::AnyAttribute, args...)
return throw(
ArgumentError(
GetAttributeNotAllowed(
attr,
"Unable to get attribute $(attr): invalid arguments $(args).",
),
)
Expand Down
97 changes: 83 additions & 14 deletions test/attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -150,30 +150,48 @@ function test_get_fallback()
model = DummyModelWithAdd()
x = MOI.add_variable(model)
c = MOI.add_constraint(model, x, MOI.EqualTo(0.0))
err = ArgumentError(
"$(typeof(model)) does not support getting the attribute " *
"$(MOI.SolveTimeSec()).",
@test_throws(
MOI.GetAttributeNotAllowed(
MOI.SolveTimeSec(),
"$(typeof(model)) does not support getting the attribute " *
"$(MOI.SolveTimeSec()).",
),
MOI.get(model, MOI.SolveTimeSec()),
)
@test_throws(err, MOI.get(model, MOI.SolveTimeSec()))
output = Ref{Cdouble}()
@test_throws(err, MOI.get!(output, model, MOI.SolveTimeSec()))
errv = ArgumentError(
"$(typeof(model)) does not support getting the attribute " *
"$(MOI.VariablePrimal()).",
@test_throws(
MOI.GetAttributeNotAllowed(
MOI.SolveTimeSec(),
"$(typeof(model)) does not support getting the attribute " *
"$(MOI.SolveTimeSec()).",
),
MOI.get!(output, model, MOI.SolveTimeSec()),
)
@test_throws(errv, MOI.get(model, MOI.VariablePrimal(), x))
errc = ArgumentError(
"$(typeof(model)) does not support getting the attribute " *
"$(MOI.ConstraintPrimal()).",
@test_throws(
MOI.GetAttributeNotAllowed(
MOI.VariablePrimal(),
"$(typeof(model)) does not support getting the attribute " *
"$(MOI.VariablePrimal()).",
),
MOI.get(model, MOI.VariablePrimal(), x),
)
@test_throws(
MOI.GetAttributeNotAllowed(
MOI.ConstraintPrimal(),
"$(typeof(model)) does not support getting the attribute " *
"$(MOI.ConstraintPrimal()).",
),
MOI.get(model, MOI.ConstraintPrimal(), c),
)
@test_throws(errc, MOI.get(model, MOI.ConstraintPrimal(), c))
@test_throws(
ArgumentError(
MOI.GetAttributeNotAllowed(
MOI.VariablePrimal(),
"Unable to get attribute $(MOI.VariablePrimal()): invalid " *
"arguments $((c,)).",
),
MOI.get(model, MOI.VariablePrimal(), c),
)
return
end

function test_ConstraintBasisStatus_fallback()
Expand Down Expand Up @@ -215,6 +233,57 @@ function test_attribute_value_type()
Float64
end

MOI.Utilities.@model(
_Model1777,
(),
(MOI.LessThan,),
(MOI.Nonnegatives,),
(),
(),
(MOI.ScalarAffineFunction,),
(MOI.VectorOfVariables,),
()
)

function MOI.supports_constraint(
::_Model1777,
::Type{MOI.VectorOfVariables},
::Type{MOI.Reals},
)
return false
end

function MOI.supports_add_constrained_variables(
::_Model1777,
::Type{MOI.Nonnegatives},
)
return true
end

MOI.supports_add_constrained_variables(::_Model1777, ::Type{MOI.Reals}) = false

function MOI.get(
model::_Model1777,
attr::MOI.ConstraintFunction,
ci::MOI.ConstraintIndex,
)
return MOI.get_fallback(model, attr, ci)
end

function test_issue_1777()
model = MOI.Utilities.CachingOptimizer(
MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()),
MOI.Bridges.full_bridge_optimizer(_Model1777{Float64}(), Float64),
)
x = MOI.add_variable(model)
c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(1.0))
MOI.Utilities.attach_optimizer(model)
MOI.set(model, MOI.ConstraintSet(), c, MOI.LessThan(2.0))
@test MOI.get(model, MOI.ConstraintSet(), c) == MOI.LessThan(2.0)
@test MOI.Utilities.state(model) == MOI.Utilities.EMPTY_OPTIMIZER
return
end

function runtests()
for name in names(@__MODULE__; all = true)
if startswith("$name", "test_")
Expand Down
15 changes: 15 additions & 0 deletions test/errors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,21 @@ function test_compute_conflict_fallback()
return
end

function test_get_fallback_error()
model = MOI.Utilities.Model{Float64}()
@test_throws(
MOI.GetAttributeNotAllowed,
MOI.get(model, MOI.SolveTimeSec()),
)
err = MOI.GetAttributeNotAllowed(MOI.SolveTimeSec(), "")
@test sprint(showerror, err) ==
"$(typeof(err)): Getting attribute $(MOI.SolveTimeSec()) cannot be " *
"performed. You may want to use a `CachingOptimizer` in " *
"`AUTOMATIC` mode or you may need to call `reset_optimizer` before " *
"doing this operation if the `CachingOptimizer` is in `MANUAL` mode."
return
end

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