Skip to content

The need for copy_names #1533

@odow

Description

@odow

copy_to has a copy_names argument:

copy_to(dest::ModelLike, src::ModelLike; copy_names=true, warn_attributes=true)
Copy the model from `src` into `dest`. The target `dest` is emptied, and all
previous indices to variables or constraints in `dest` are invalidated. Returns
a dictionary-like object that translates variable and constraint indices from
the `src` model to the corresponding indices in the `dest` model.
If `copy_names` is `false`, the `Name`, `VariableName` and `ConstraintName`
attributes are not copied even if they are set in `src`. If a constraint that

This also leads to things like

supports_incremental_interface(model::ModelLike, copy_names::Bool)
Return a `Bool` indicating whether `model` supports building incrementally via
[`add_variable`](@ref) and [`add_constraint`](@ref).
`copy_names` is a `Bool` indicating whether the user wishes to set
[`VariableName`](@ref) and [`ConstraintName`](@ref) attributes.
If `model` supports the incremental interface but does not support name
attributes, define
```julia
supports_incremental_interface(::MyNewModel, copy_names::Bool) = !copy_names
```

The conceptual understanding of when and why these are used is a bit confusing.

It was added here, without much explanation of why:
#297

As far as I can tell, the reason this was added was because we want to add names to the cache of a CachingOptimizer but not the optimizer:

function _attach_optimizer(
model::CachingOptimizer,
copy_to::F,
) where {F<:Function}
@assert model.state == EMPTY_OPTIMIZER
# We do not need to copy names because name-related operations are handled
# by `m.model_cache`
indexmap = copy_to(
model.optimizer,
model.model_cache;
copy_names = false,
)::MOI.Utilities.IndexMap

This leads to confusion:
#1225
and supporting names is hard:
#674

Why do we need copy_names? Can we just ask the optimizer if it supports names? And if so, shouldn't we set them? This would make optimizer errors much nicer instead of C21 was infeasible.

We already skip some attributes if they aren't supported, so why not copy?

if attr isa MOI.VariablePrimalStart ||
attr isa MOI.ConstraintPrimalStart ||
attr isa MOI.ConstraintDualStart
# As starting values are simply *hints* for the optimization, not
# supporting them gives a warning, not an error
if !MOI.supports(dest, attr, supports_args...)
@warn(
"$attr is not supported by $(typeof(dest)). This " *
"information will be discarded."
)
continue
end

We should either:

  • Remove copy_names
  • Document why it is needed

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions