From 33952c8279c4c7a0c7185a35faa1bf5a131bce4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 27 Feb 2026 09:01:37 +0100 Subject: [PATCH 1/8] Avoid extra copies of functions in copy_to --- src/Utilities/copy.jl | 19 ++++++++++++++++++- src/Utilities/model.jl | 4 ++-- src/Utilities/objective_container.jl | 10 ++++++++++ src/Utilities/vector_of_constraints.jl | 18 ++++++++++++++++-- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/Utilities/copy.jl b/src/Utilities/copy.jl index 76a34dc75f..3b8e29d4ef 100644 --- a/src/Utilities/copy.jl +++ b/src/Utilities/copy.jl @@ -40,6 +40,20 @@ function pass_attributes(dest::MOI.ModelLike, src::MOI.ModelLike, index_map) return end +function _pass_attribute( + dest::MOI.ModelLike, + src::MOI.ModelLike, + index_map, + ::MOI.ConstraintFunction{F}, +) where {F} + return _pass_attribute( + dest, + src, + index_map, + UnsafeConstraintFunction{F}(), + ) +end + function _pass_attribute( dest::MOI.ModelLike, src::MOI.ModelLike, @@ -175,7 +189,10 @@ function _copy_constraints( cis_src::Vector{<:MOI.ConstraintIndex}, ) for ci in cis_src - f = MOI.get(src, MOI.ConstraintFunction(), ci) + # MOI does not allows the implementation of `MOI.constraint` + # to modify it or hold a copy of it. + # `map_indices` is also often going to copy it anyway + f = MOI.get(src, UnsafeConstraintFunction(), ci) s = MOI.get(src, MOI.ConstraintSet(), ci) index_map_FS[ci] = MOI.add_constraint(dest, map_indices(index_map, f), s) diff --git a/src/Utilities/model.jl b/src/Utilities/model.jl index fe06b53763..f11c0625d1 100644 --- a/src/Utilities/model.jl +++ b/src/Utilities/model.jl @@ -402,7 +402,7 @@ end function MOI.get( model::AbstractModel, - attr::Union{MOI.ConstraintFunction,MOI.ConstraintSet}, + attr::Union{UnsafeConstraintFunction,MOI.ConstraintFunction,MOI.ConstraintSet}, ci::MOI.ConstraintIndex, ) return MOI.get(constraints(model, ci), attr, ci) @@ -530,7 +530,7 @@ function MOI.supports(model::AbstractModel, attr::MOI.ObjectiveFunction) return MOI.supports(model.objective, attr) end -function MOI.get(model::AbstractModel, attr::MOI.ObjectiveFunction) +function MOI.get(model::AbstractModel, attr::Union{UnsafeObjectiveFunction,MOI.ObjectiveFunction}) return MOI.get(model.objective, attr) end diff --git a/src/Utilities/objective_container.jl b/src/Utilities/objective_container.jl index 5ebce67930..cd32188780 100644 --- a/src/Utilities/objective_container.jl +++ b/src/Utilities/objective_container.jl @@ -116,6 +116,12 @@ function MOI.supports( return true end +struct UnsafeObjectiveFunction{F<:MOI.AbstractFunction} end + +function MOI.get(model::MOI.ModelLike, ::UnsafeObjectiveFunction{F}) where {F} + return MOI.get(model, MOI.ObjectiveFunction{F}()) +end + function MOI.get( o::ObjectiveContainer{T}, attr::MOI.ObjectiveFunction{F}, @@ -153,6 +159,10 @@ function MOI.get( return convert(F, zero(MOI.ScalarAffineFunction{T})) end +function MOI.get(o::ObjectiveContainer, ::MOI.ObjectiveFunction{F}) where {F} + return copy(MOI.get(o, UnsafeObjectiveFunction{F}())) +end + function _empty_keeping_sense(o::ObjectiveContainer) sense, is_sense_set = o.sense, o.is_sense_set MOI.empty!(o) diff --git a/src/Utilities/vector_of_constraints.jl b/src/Utilities/vector_of_constraints.jl index b12b97bd85..e91e58c50e 100644 --- a/src/Utilities/vector_of_constraints.jl +++ b/src/Utilities/vector_of_constraints.jl @@ -96,14 +96,28 @@ function MOI.delete( return end +struct UnsafeConstraintFunction end + +function MOI.get(model::MOI.ModelLike, ::UnsafeConstraintFunction, ci::MOI.ConstraintIndex) + return MOI.get(model, MOI.ConstraintFunction, ci) +end + function MOI.get( v::VectorOfConstraints{F,S}, - ::MOI.ConstraintFunction, + ::UnsafeConstraintFunction, ci::MOI.ConstraintIndex{F,S}, ) where {F,S} MOI.throw_if_not_valid(v, ci) f, _ = v.constraints[ci]::Tuple{F,S} - return copy(f) + return f +end + +function MOI.get( + v::VectorOfConstraints{F,S}, + ::MOI.ConstraintFunction, + ci::MOI.ConstraintIndex{F,S}, +) where {F,S} + return copy(MOI.get(v, MOI.UnsafeConstraintFunction, ci)) end function MOI.get( From 79ede2cbcde8946728d7d1037edb0465aad88f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 28 Feb 2026 09:08:55 +0100 Subject: [PATCH 2/8] Fix --- src/Utilities/copy.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Utilities/copy.jl b/src/Utilities/copy.jl index 3b8e29d4ef..51982463aa 100644 --- a/src/Utilities/copy.jl +++ b/src/Utilities/copy.jl @@ -44,13 +44,13 @@ function _pass_attribute( dest::MOI.ModelLike, src::MOI.ModelLike, index_map, - ::MOI.ConstraintFunction{F}, -) where {F} + ::MOI.ConstraintFunction, +) return _pass_attribute( dest, src, index_map, - UnsafeConstraintFunction{F}(), + UnsafeConstraintFunction(), ) end From e5014a79799afd6b2f1f22a0f0f6eb71b706372c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 28 Feb 2026 09:13:17 +0100 Subject: [PATCH 3/8] Fixes --- src/Utilities/vector_of_constraints.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Utilities/vector_of_constraints.jl b/src/Utilities/vector_of_constraints.jl index e91e58c50e..aaf7e4d5de 100644 --- a/src/Utilities/vector_of_constraints.jl +++ b/src/Utilities/vector_of_constraints.jl @@ -99,7 +99,7 @@ end struct UnsafeConstraintFunction end function MOI.get(model::MOI.ModelLike, ::UnsafeConstraintFunction, ci::MOI.ConstraintIndex) - return MOI.get(model, MOI.ConstraintFunction, ci) + return MOI.get(model, MOI.ConstraintFunction(), ci) end function MOI.get( @@ -117,7 +117,7 @@ function MOI.get( ::MOI.ConstraintFunction, ci::MOI.ConstraintIndex{F,S}, ) where {F,S} - return copy(MOI.get(v, MOI.UnsafeConstraintFunction, ci)) + return copy(MOI.get(v, UnsafeConstraintFunction(), ci)) end function MOI.get( From de616d68482342f86c610baf7cd7c8f3a76b3eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 28 Feb 2026 09:13:22 +0100 Subject: [PATCH 4/8] Fix format --- src/Utilities/copy.jl | 7 +------ src/Utilities/model.jl | 11 +++++++++-- src/Utilities/vector_of_constraints.jl | 6 +++++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Utilities/copy.jl b/src/Utilities/copy.jl index 51982463aa..af74f3d907 100644 --- a/src/Utilities/copy.jl +++ b/src/Utilities/copy.jl @@ -46,12 +46,7 @@ function _pass_attribute( index_map, ::MOI.ConstraintFunction, ) - return _pass_attribute( - dest, - src, - index_map, - UnsafeConstraintFunction(), - ) + return _pass_attribute(dest, src, index_map, UnsafeConstraintFunction()) end function _pass_attribute( diff --git a/src/Utilities/model.jl b/src/Utilities/model.jl index f11c0625d1..e0022104c2 100644 --- a/src/Utilities/model.jl +++ b/src/Utilities/model.jl @@ -402,7 +402,11 @@ end function MOI.get( model::AbstractModel, - attr::Union{UnsafeConstraintFunction,MOI.ConstraintFunction,MOI.ConstraintSet}, + attr::Union{ + UnsafeConstraintFunction, + MOI.ConstraintFunction, + MOI.ConstraintSet, + }, ci::MOI.ConstraintIndex, ) return MOI.get(constraints(model, ci), attr, ci) @@ -530,7 +534,10 @@ function MOI.supports(model::AbstractModel, attr::MOI.ObjectiveFunction) return MOI.supports(model.objective, attr) end -function MOI.get(model::AbstractModel, attr::Union{UnsafeObjectiveFunction,MOI.ObjectiveFunction}) +function MOI.get( + model::AbstractModel, + attr::Union{UnsafeObjectiveFunction,MOI.ObjectiveFunction}, +) return MOI.get(model.objective, attr) end diff --git a/src/Utilities/vector_of_constraints.jl b/src/Utilities/vector_of_constraints.jl index aaf7e4d5de..cd4b069c0d 100644 --- a/src/Utilities/vector_of_constraints.jl +++ b/src/Utilities/vector_of_constraints.jl @@ -98,7 +98,11 @@ end struct UnsafeConstraintFunction end -function MOI.get(model::MOI.ModelLike, ::UnsafeConstraintFunction, ci::MOI.ConstraintIndex) +function MOI.get( + model::MOI.ModelLike, + ::UnsafeConstraintFunction, + ci::MOI.ConstraintIndex, +) return MOI.get(model, MOI.ConstraintFunction(), ci) end From bfdfe42758b360a813354f75addc09faae15ac20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sun, 1 Mar 2026 09:00:06 +0100 Subject: [PATCH 5/8] Avoid ambiguity --- src/Utilities/vector_of_constraints.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utilities/vector_of_constraints.jl b/src/Utilities/vector_of_constraints.jl index cd4b069c0d..b0533a340e 100644 --- a/src/Utilities/vector_of_constraints.jl +++ b/src/Utilities/vector_of_constraints.jl @@ -98,7 +98,7 @@ end struct UnsafeConstraintFunction end -function MOI.get( +function MOI.get_fallback( model::MOI.ModelLike, ::UnsafeConstraintFunction, ci::MOI.ConstraintIndex, From bf9cd60564d99ad0d7d20c668cc0d600edb2964d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sun, 1 Mar 2026 09:15:51 +0100 Subject: [PATCH 6/8] Fix --- src/Utilities/objective_container.jl | 2 +- src/Utilities/universalfallback.jl | 4 ++-- src/Utilities/vector_of_constraints.jl | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Utilities/objective_container.jl b/src/Utilities/objective_container.jl index cd32188780..efcd7f8d47 100644 --- a/src/Utilities/objective_container.jl +++ b/src/Utilities/objective_container.jl @@ -116,7 +116,7 @@ function MOI.supports( return true end -struct UnsafeObjectiveFunction{F<:MOI.AbstractFunction} end +struct UnsafeObjectiveFunction{F<:MOI.AbstractFunction} <: MOI.AbstractModelAttribute end function MOI.get(model::MOI.ModelLike, ::UnsafeObjectiveFunction{F}) where {F} return MOI.get(model, MOI.ObjectiveFunction{F}()) diff --git a/src/Utilities/universalfallback.jl b/src/Utilities/universalfallback.jl index 8a6f9aa063..d0b6eaa5d7 100644 --- a/src/Utilities/universalfallback.jl +++ b/src/Utilities/universalfallback.jl @@ -534,7 +534,7 @@ end function MOI.get( uf::UniversalFallback, - attr::MOI.ObjectiveFunction{F}, + attr::Union{MOI.UnsafeObjectiveFunction{F},MOI.ObjectiveFunction{F}}, )::F where {F} if uf.objective === nothing return MOI.get(uf.model, attr) @@ -866,7 +866,7 @@ end function MOI.get( uf::UniversalFallback, - attr::Union{MOI.ConstraintFunction,MOI.ConstraintSet}, + attr::Union{MOI.UnsafeConstraintFunction,MOI.ConstraintFunction,MOI.ConstraintSet}, ci::MOI.ConstraintIndex, ) return MOI.get(constraints(uf, ci), attr, ci) diff --git a/src/Utilities/vector_of_constraints.jl b/src/Utilities/vector_of_constraints.jl index b0533a340e..3940271adc 100644 --- a/src/Utilities/vector_of_constraints.jl +++ b/src/Utilities/vector_of_constraints.jl @@ -96,7 +96,7 @@ function MOI.delete( return end -struct UnsafeConstraintFunction end +struct UnsafeConstraintFunction <: MOI.AbstractConstraintAttribute end function MOI.get_fallback( model::MOI.ModelLike, From 4011ace34c4fd9a3ea73f7e5a1ee144ae2ee8093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sun, 1 Mar 2026 12:44:31 +0100 Subject: [PATCH 7/8] Fixes --- src/Utilities/objective_container.jl | 3 ++- src/Utilities/universalfallback.jl | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Utilities/objective_container.jl b/src/Utilities/objective_container.jl index efcd7f8d47..94f8697875 100644 --- a/src/Utilities/objective_container.jl +++ b/src/Utilities/objective_container.jl @@ -116,7 +116,8 @@ function MOI.supports( return true end -struct UnsafeObjectiveFunction{F<:MOI.AbstractFunction} <: MOI.AbstractModelAttribute end +struct UnsafeObjectiveFunction{F<:MOI.AbstractFunction} <: + MOI.AbstractModelAttribute end function MOI.get(model::MOI.ModelLike, ::UnsafeObjectiveFunction{F}) where {F} return MOI.get(model, MOI.ObjectiveFunction{F}()) diff --git a/src/Utilities/universalfallback.jl b/src/Utilities/universalfallback.jl index d0b6eaa5d7..972c060f5a 100644 --- a/src/Utilities/universalfallback.jl +++ b/src/Utilities/universalfallback.jl @@ -534,7 +534,7 @@ end function MOI.get( uf::UniversalFallback, - attr::Union{MOI.UnsafeObjectiveFunction{F},MOI.ObjectiveFunction{F}}, + attr::Union{UnsafeObjectiveFunction{F},MOI.ObjectiveFunction{F}}, )::F where {F} if uf.objective === nothing return MOI.get(uf.model, attr) @@ -866,7 +866,11 @@ end function MOI.get( uf::UniversalFallback, - attr::Union{MOI.UnsafeConstraintFunction,MOI.ConstraintFunction,MOI.ConstraintSet}, + attr::Union{ + UnsafeConstraintFunction, + MOI.ConstraintFunction, + MOI.ConstraintSet, + }, ci::MOI.ConstraintIndex, ) return MOI.get(constraints(uf, ci), attr, ci) From e1996861b1963a32b9f1f78b5411b446972e5c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sun, 1 Mar 2026 12:52:30 +0100 Subject: [PATCH 8/8] Fixes --- src/Utilities/copy.jl | 17 +++++++++++++++++ src/Utilities/objective_container.jl | 7 ------- src/Utilities/variables_container.jl | 2 +- src/Utilities/vector_of_constraints.jl | 10 ---------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Utilities/copy.jl b/src/Utilities/copy.jl index af74f3d907..644552bd78 100644 --- a/src/Utilities/copy.jl +++ b/src/Utilities/copy.jl @@ -40,6 +40,23 @@ function pass_attributes(dest::MOI.ModelLike, src::MOI.ModelLike, index_map) return end +struct UnsafeObjectiveFunction{F<:MOI.AbstractFunction} <: + MOI.AbstractModelAttribute end + +function MOI.get(model::MOI.ModelLike, ::UnsafeObjectiveFunction{F}) where {F} + return MOI.get(model, MOI.ObjectiveFunction{F}()) +end + +struct UnsafeConstraintFunction <: MOI.AbstractConstraintAttribute end + +function MOI.get_fallback( + model::MOI.ModelLike, + ::UnsafeConstraintFunction, + ci::MOI.ConstraintIndex, +) + return MOI.get(model, MOI.ConstraintFunction(), ci) +end + function _pass_attribute( dest::MOI.ModelLike, src::MOI.ModelLike, diff --git a/src/Utilities/objective_container.jl b/src/Utilities/objective_container.jl index 94f8697875..b7103196e2 100644 --- a/src/Utilities/objective_container.jl +++ b/src/Utilities/objective_container.jl @@ -116,13 +116,6 @@ function MOI.supports( return true end -struct UnsafeObjectiveFunction{F<:MOI.AbstractFunction} <: - MOI.AbstractModelAttribute end - -function MOI.get(model::MOI.ModelLike, ::UnsafeObjectiveFunction{F}) where {F} - return MOI.get(model, MOI.ObjectiveFunction{F}()) -end - function MOI.get( o::ObjectiveContainer{T}, attr::MOI.ObjectiveFunction{F}, diff --git a/src/Utilities/variables_container.jl b/src/Utilities/variables_container.jl index 23f60c71f9..da8f2ef6e9 100644 --- a/src/Utilities/variables_container.jl +++ b/src/Utilities/variables_container.jl @@ -310,7 +310,7 @@ MOI.is_valid(::VariablesContainer, ::MOI.ConstraintIndex) = false function MOI.get( model::VariablesContainer, - ::MOI.ConstraintFunction, + ::Union{UnsafeConstraintFunction,MOI.ConstraintFunction}, ci::MOI.ConstraintIndex{MOI.VariableIndex}, ) MOI.throw_if_not_valid(model, ci) diff --git a/src/Utilities/vector_of_constraints.jl b/src/Utilities/vector_of_constraints.jl index 3940271adc..7ca1d18d1c 100644 --- a/src/Utilities/vector_of_constraints.jl +++ b/src/Utilities/vector_of_constraints.jl @@ -96,16 +96,6 @@ function MOI.delete( return end -struct UnsafeConstraintFunction <: MOI.AbstractConstraintAttribute end - -function MOI.get_fallback( - model::MOI.ModelLike, - ::UnsafeConstraintFunction, - ci::MOI.ConstraintIndex, -) - return MOI.get(model, MOI.ConstraintFunction(), ci) -end - function MOI.get( v::VectorOfConstraints{F,S}, ::UnsafeConstraintFunction,