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
1 change: 0 additions & 1 deletion docs/src/submodules/Utilities/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ Utilities.latex_formulation
## Copy utilities

```@docs
Utilities.automatic_copy_to
Utilities.default_copy_to
Utilities.IndexMap
Utilities.identity_index_map
Expand Down
2 changes: 1 addition & 1 deletion docs/src/tutorials/implementing.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ MOI.supports_incremental_interface(::Optimizer, copy_names::Bool) = true
MOI.supports_incremental_interface(::Optimizer, copy_names::Bool) = !copy_names

function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike; kwargs...)
return MOI.Utilities.automatic_copy_to(dest, src; kwargs...)
return MOI.Utilities.default_copy_to(dest, src; kwargs...)
end
```
See [`supports_incremental_interface`](@ref) for more details on whether to
Expand Down
8 changes: 6 additions & 2 deletions src/Bridges/bridge_optimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,12 @@ function MOIU.pass_nonvariable_constraints(
return
end

function MOI.copy_to(b::AbstractBridgeOptimizer, src::MOI.ModelLike; kwargs...)
return MOIU.automatic_copy_to(b, src; kwargs...)
function MOI.copy_to(
dest::AbstractBridgeOptimizer,
src::MOI.ModelLike;
kwargs...,
)
return MOIU.default_copy_to(dest, src; kwargs...)
end

function MOI.supports_incremental_interface(
Expand Down
89 changes: 37 additions & 52 deletions src/Utilities/copy.jl
Original file line number Diff line number Diff line change
@@ -1,39 +1,7 @@
# This file contains default implementations for the `MOI.copy_to` function that
# can be used by a model.

"""
automatic_copy_to(
dest::MOI.ModelLike,
src::MOI.ModelLike;
copy_names::Bool=true,
filter_constraints::Union{Nothing,Function} = nothing,
)

A default fallback for [`MOI.copy_to`](@ref).

To use this method, define
[`MathOptInterface.supports_incremental_interface`](@ref).

If the `filter_constraints` arguments is given, only the constraints for which
this function returns `true` will be copied. This function is given a
constraint index as argument.
"""
function automatic_copy_to(
dest::MOI.ModelLike,
src::MOI.ModelLike;
copy_names::Bool = true,
filter_constraints::Union{Nothing,Function} = nothing,
)
if !MOI.supports_incremental_interface(dest, copy_names)
error(
"Model $(typeof(dest)) does not support copy",
copy_names ? " with names" : "",
".",
)
end
return default_copy_to(dest, src, copy_names, filter_constraints)
end

@deprecate automatic_copy_to default_copy_to
@deprecate supports_default_copy_to MOI.supports_incremental_interface

include("copy/index_map.jl")
Expand Down Expand Up @@ -486,14 +454,6 @@ function copy_free_variables(
return
end

function default_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike)
Base.depwarn(
"default_copy_to(dest, src) is deprecated, use default_copy_to(dest, src, true) instead or default_copy_to(dest, src, false) if you do not want to copy names.",
:default_copy_to,
)
return default_copy_to(dest, src, true)
end
Copy link
Member Author

Choose a reason for hiding this comment

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

It seems crazy, but this has been sitting here since MOI 0.2.0! 1ae8661


function sorted_variable_sets_by_cost(dest::MOI.ModelLike, src::MOI.ModelLike)
constraint_types = MOI.get(src, MOI.ListOfConstraintTypesPresent())
single_or_vector_variables_types = [
Expand Down Expand Up @@ -575,29 +535,54 @@ only once all the model information is gathered.
"""
function final_touch(::MOI.ModelLike, idxmap) end

function default_copy_to(
dest::MOI.ModelLike,
src::MOI.ModelLike,
copy_names::Bool,
filter_constraints::Union{Nothing,Function} = nothing,
)
@warn(
"The `copy_names` and `filter_constraints` arguments to " *
"`default_copy_to` are now keyword arguments.",
maxlog = 1,
)
return default_copy_to(
dest,
src;
copy_names = copy_names,
filter_constraints = filter_constraints,
)
end

"""
default_copy_to(
dest::MOI.ModelLike,
src::MOI.ModelLike,
copy_names::Bool,
src::MOI.ModelLike;
copy_names::Bool = true,
filter_constraints::Union{Nothing,Function} = nothing,
)

Implements `MOI.copy_to(dest, src)` by adding the variables and then the
constraints and attributes incrementally. The function
[`MathOptInterface.supports_incremental_interface`](@ref) can be used to check
whether `dest` supports the copying a model incrementally.
A default implementation of `MOI.copy_to(dest, src)` for models that implement
the incremental interface, i.e., [`MOI.supports_incremental_interface`](@ref)
returns `true`.

If the `filter_constraints` arguments is given, only the constraints for which
this function returns `true` will be copied. This function is given a
constraint index as argument.
If `filter_constraints` is a `Function`, only constraints for which
`filter_constraints(ci)` returns `true` will be copied, where `ci` is the
[`MOI.ConstraintIndex`](@ref) of the constraint.
"""
function default_copy_to(
dest::MOI.ModelLike,
src::MOI.ModelLike,
copy_names::Bool,
src::MOI.ModelLike;
copy_names::Bool = true,
filter_constraints::Union{Nothing,Function} = nothing,
)
if !MOI.supports_incremental_interface(dest, copy_names)
error(
Copy link
Member

Choose a reason for hiding this comment

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

I'm wondering whether it makes sense to remove this error.
MOI.supports_incremental_interface is what is used by instantiate.
Would there be a case where you want instantiate to add a cache but you would still like to be able to call default_copy_to?
Removing the error is nonbreaking so it might be fine for now

Copy link
Member Author

Choose a reason for hiding this comment

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

This check is trivial and will be in-lined. It also prevents a later error like "add variable not allowed" in some cases. I'd suggest we leave it in, at least until all the solvers are updated. We could remove it for 1.0 if it's not needed.

Copy link
Member

Choose a reason for hiding this comment

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

This check is trivial and will be in-lined

Yes, I was not worried about peformance

I'd suggest we leave it in, at least until all the solvers are updated. We could remove it for 1.0 if it's not needed.

Sounds good

"Model $(typeof(dest)) does not support copy",
copy_names ? " with names" : "",
".",
)
end
MOI.empty!(dest)

vis_src = MOI.get(src, MOI.ListOfVariableIndices())
Expand Down
8 changes: 4 additions & 4 deletions src/Utilities/mockoptimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ struct MockConstraintAttribute <: MOI.AbstractConstraintAttribute end
"""
MockOptimizer

`MockOptimizer` is a fake optimizer especially useful for testing. Its main
feature is that it can store the values that should be returned for each
`MockOptimizer` is a fake optimizer especially useful for testing. Its main
feature is that it can store the values that should be returned for each
attribute.
"""
mutable struct MockOptimizer{MT<:MOI.ModelLike} <: MOI.AbstractOptimizer
Expand Down Expand Up @@ -920,8 +920,8 @@ function MOI.supports_add_constrained_variables(
return MOI.supports_add_constrained_variables(mock.inner_model, MOI.Reals)
end

function MOI.copy_to(mock::MockOptimizer, src::MOI.ModelLike; kws...)
return automatic_copy_to(mock, src; kws...)
function MOI.copy_to(dest::MockOptimizer, src::MOI.ModelLike; kwargs...)
return default_copy_to(dest, src; kwargs...)
end

function MOI.supports_incremental_interface(
Expand Down
5 changes: 3 additions & 2 deletions src/Utilities/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -575,9 +575,10 @@ function pass_nonvariable_constraints(
)
end

function MOI.copy_to(dest::AbstractModel, src::MOI.ModelLike; kws...)
return automatic_copy_to(dest, src; kws...)
function MOI.copy_to(dest::AbstractModel, src::MOI.ModelLike; kwargs...)
return default_copy_to(dest, src; kwargs...)
end

MOI.supports_incremental_interface(::AbstractModel, ::Bool) = true
function final_touch(model::AbstractModel, index_map)
return final_touch(model.constraints, index_map)
Expand Down
4 changes: 2 additions & 2 deletions src/Utilities/universalfallback.jl
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ function pass_nonvariable_constraints(
)
end

function MOI.copy_to(uf::UniversalFallback, src::MOI.ModelLike; kws...)
return MOIU.automatic_copy_to(uf, src; kws...)
function MOI.copy_to(dest::UniversalFallback, src::MOI.ModelLike; kwargs...)
return MOIU.default_copy_to(dest, src; kwargs...)
end

function MOI.supports_incremental_interface(
Expand Down
2 changes: 1 addition & 1 deletion test/DeprecatedTest/modellike.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ using Test
import MathOptInterface
const MOI = MathOptInterface
const MOIT = MOI.DeprecatedTest
const MOU = MOI.Utilities
const MOIU = MOI.Utilities

@testset "Start value attributes and nothing" begin
model = MOIU.MockOptimizer(MOIU.UniversalFallback(MOIU.Model{Float64}()))
Expand Down
2 changes: 1 addition & 1 deletion test/Utilities/cachingoptimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ end
MOI.supports_incremental_interface(::NoFreeVariables, names::Bool) = !names

function MOI.copy_to(dest::NoFreeVariables, src::MOI.ModelLike; kwargs...)
return MOI.Utilities.automatic_copy_to(dest, src; kwargs...)
return MOI.Utilities.default_copy_to(dest, src; kwargs...)
end

###
Expand Down
22 changes: 11 additions & 11 deletions test/Utilities/copy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ function MOI.empty!(::AbstractDummyModel) end
function MOI.copy_to(
dest::AbstractDummyModel,
src::MOI.ModelLike;
copy_names = true,
copy_names::Bool = true,
)
return MOIU.default_copy_to(dest, src, copy_names)
return MOIU.default_copy_to(dest, src; copy_names = copy_names)
end

MOI.supports(::AbstractDummyModel, ::MOI.ObjectiveSense) = true
Expand Down Expand Up @@ -124,12 +124,12 @@ end
function test_AUTOMATIC()
src = DummyModel()
dest = DummyModel()
@test_throws ErrorException MOIU.automatic_copy_to(dest, src)
@test_throws ErrorException MOIU.default_copy_to(dest, src)
try
@test_throws ErrorException MOIU.automatic_copy_to(dest, src)
@test_throws ErrorException MOIU.default_copy_to(dest, src)
catch err
@test sprint(showerror, err) ==
"Model DummyModel does not" * " support copy with names."
"Model DummyModel does not support copy with names."
end
end

Expand All @@ -151,7 +151,7 @@ function test_issue_849()
)
MOI.set(model, MOI.NLPBlock(), nlp_data)
copy = MOIU.UniversalFallback(MOIU.Model{Float64}())
index_map = MOIU.default_copy_to(copy, model, true)
index_map = MOIU.default_copy_to(copy, model; copy_names = true)
for vi in [a, b, c, x, y[1]]
@test index_map[vi] == vi
end
Expand Down Expand Up @@ -186,9 +186,9 @@ end
function MOI.copy_to(
dest::ConstrainedVariablesModel,
src::MOI.ModelLike;
kws...,
kwargs...,
)
return MOIU.automatic_copy_to(dest, src; kws...)
return MOIU.default_copy_to(dest, src; kwargs...)
end

function MOI.add_variables(model::ConstrainedVariablesModel, n)
Expand Down Expand Up @@ -283,7 +283,7 @@ function MOI.copy_to(
src::MOI.ModelLike;
kwargs...,
)
return MOIU.automatic_copy_to(dest, src; kwargs...)
return MOIU.default_copy_to(dest, src; kwargs...)
end

function MOI.supports_incremental_interface(
Expand Down Expand Up @@ -669,8 +669,8 @@ end

MOI.supports_incremental_interface(::BoundModel, ::Bool) = true

function MOI.copy_to(dest::BoundModel, src::MOI.ModelLike; kws...)
return MOIU.automatic_copy_to(dest, src; kws...)
function MOI.copy_to(dest::BoundModel, src::MOI.ModelLike; kwargs...)
return MOIU.default_copy_to(dest, src; kwargs...)
end

MOI.empty!(model::BoundModel) = MOI.empty!(model.inner)
Expand Down
7 changes: 7 additions & 0 deletions test/deprecate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ function test_RawOptimizerAttribute()
@test_logs (:warn,) MOI.RawParameter(:a) == MOI.RawOptimizerAttribute("a")
end

function test_default_copy_to()
dest = MOI.Utilities.Model{Float64}()
src = MOI.Utilities.Model{Float64}()
@test_logs (:warn,) MOI.Utilities.default_copy_to(dest, src, true)
return
end

function runtests()
for name in names(@__MODULE__; all = true)
if startswith("$name", "test_")
Expand Down
7 changes: 6 additions & 1 deletion test/dummy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@ const MOIU = MOI.Utilities
abstract type AbstractDummyModel <: MOI.ModelLike end

function MOI.empty!(::AbstractDummyModel) end

function MOI.copy_to(
dest::AbstractDummyModel,
src::MOI.ModelLike;
copy_names = true,
copy_names::Bool = true,
)
return MOIU.default_copy_to(dest, src, copy_names)
end

MOI.supports_incremental_interface(::AbstractDummyModel, ::Bool) = true

MOI.supports(::AbstractDummyModel, ::MOI.ObjectiveSense) = true

function MOI.supports(
::AbstractDummyModel,
::MOI.ConstraintPrimalStart,
Expand Down