@@ -478,25 +478,8 @@ function default_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike)
478478 error (" Model $(typeof (dest)) does not support copy_to." )
479479 end
480480 MOI. empty! (dest)
481- vis_src = MOI. get (src, MOI. ListOfVariableIndices ())
482- index_map = IndexMap ()
483- # The `NLPBlock` assumes that the order of variables does not change (#849)
484- # Therefore, all VariableIndex and VectorOfVariable constraints are added
485- # seprately, and no variables constrained-on-creation are added.
486- has_nlp = MOI. NLPBlock () in MOI. get (src, MOI. ListOfModelAttributesSet ())
487- constraints_not_added = if has_nlp
488- Any[
489- MOI. get (src, MOI. ListOfConstraintIndices {F,S} ()) for
490- (F, S) in MOI. get (src, MOI. ListOfConstraintTypesPresent ()) if
491- _is_variable_function (F)
492- ]
493- else
494- Any[
495- _try_constrain_variables_on_creation (dest, src, index_map, S)
496- for S in sorted_variable_sets_by_cost (dest, src)
497- ]
498- end
499- _copy_free_variables (dest, index_map, vis_src)
481+ index_map, vis_src, constraints_not_added =
482+ _copy_variables_with_set (dest, src)
500483 # Copy variable attributes
501484 pass_attributes (dest, src, index_map, vis_src)
502485 # Copy model attributes
@@ -507,6 +490,119 @@ function default_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike)
507490 return index_map
508491end
509492
493+ struct _CopyVariablesWithSetCache
494+ variable_to_column:: Dict{MOI.VariableIndex,Int}
495+ constraints_not_added:: Vector{Any}
496+ variables_with_domain:: Set{MOI.VariableIndex}
497+ variable_cones:: Vector{Tuple{Vector{MOI.VariableIndex},Any}}
498+ function _CopyVariablesWithSetCache ()
499+ return new (
500+ Dict {MOI.VariableIndex,Int} (),
501+ Any[],
502+ Set {MOI.VariableIndex} (),
503+ Tuple{Vector{MOI. VariableIndex},Any}[]
504+ )
505+ end
506+ end
507+
508+ function _build_copy_variables_with_set_cache (
509+ src:: MOI.ModelLike ,
510+ cache:: _CopyVariablesWithSetCache ,
511+ :: Type{S} ,
512+ ) where {S<: MOI.AbstractScalarSet }
513+ F = MOI. VariableIndex
514+ for ci in MOI. get (src, MOI. ListOfConstraintIndices {F,S} ())
515+ f = MOI. get (src, MOI. ConstraintFunction (), ci)
516+ if f in cache. variables_with_domain
517+ push! (cache. constraints_not_added, ci)
518+ else
519+ push! (cache. variables_with_domain, f)
520+ push! (cache. variable_cones, ([f], ci))
521+ end
522+ end
523+ return
524+ end
525+
526+ function _is_variable_cone (cache, f:: MOI.VectorOfVariables )
527+ if isempty (f. variables)
528+ return false
529+ end
530+ offset = cache. variable_to_column[f. variables[1 ]] - 1
531+ for (i, xi) in enumerate (f. variables)
532+ if xi in cache. variables_with_domain
533+ return false
534+ elseif cache. variable_to_column[xi] != offset + i
535+ return false
536+ end
537+ end
538+ return true
539+ end
540+
541+ function _build_copy_variables_with_set_cache (
542+ src:: MOI.ModelLike ,
543+ cache:: _CopyVariablesWithSetCache ,
544+ :: Type{S} ,
545+ ) where {S<: MOI.AbstractVectorSet }
546+ F = MOI. VectorOfVariables
547+ for ci in MOI. get (src, MOI. ListOfConstraintIndices {F,S} ())
548+ f = MOI. get (src, MOI. ConstraintFunction ())
549+ if _is_variable_cone (cache, f)
550+ for fi in f. variables
551+ push! (cache. variables_with_domain, fi)
552+ end
553+ push! (cache. variable_cones, (f. variables, ci))
554+ else
555+ push! (cache. constraints_not_added, ci)
556+ end
557+ end
558+ return
559+ end
560+
561+ function _copy_variables_with_set (dest, src)
562+ vis_src = MOI. get (src, MOI. ListOfVariableIndices ())
563+ index_map = IndexMap ()
564+ cache = _CopyVariablesWithSetCache ()
565+ for (i, v) in enumerate (vis_src)
566+ cache. variable_to_column[v] = i
567+ end
568+ for S in sorted_variable_sets_by_cost (dest, src)
569+ _build_copy_variables_with_set_cache (src, cache, S)
570+ end
571+ column (x:: MOI.VariableIndex ) = cache. variable_to_column[x]
572+ start_column (x) = column (first (x[1 ]))
573+ current_column = 0
574+ for (f, ci) in sort! (cache. variable_cones; by = start_column)
575+ offset = column (first (f)) - current_column - 1
576+ if offset > 0
577+ dest_x = MOI. add_variables (dest, offset)
578+ for i in 1 : offset
579+ index_map[vis_src[current_column + i]] = dest_x[i]
580+ end
581+ end
582+ set = MOI. get (src, MOI. ConstraintSet (), ci)
583+ if set isa MOI. AbstractScalarSet
584+ dest_x, dest_ci = MOI. add_constrained_variable (dest, set)
585+ index_map[only (f)] = dest_x
586+ index_map[ci] = dest_ci
587+ else
588+ dest_x, dest_ci = MOI. add_constrained_variables (dest, set)
589+ for (fi, xi) in zip (f, dest_x)
590+ index_map[fi] = xi
591+ end
592+ index_map[ci] = dest_ci
593+ end
594+ current_column = column (last (f))
595+ end
596+ offset = length (cache. variable_to_column) - current_column
597+ if offset > 0
598+ dest_x = MOI. add_variables (dest, offset)
599+ for i in 1 : offset
600+ index_map[vis_src[current_column + i]] = dest_x[i]
601+ end
602+ end
603+ return index_map, vis_src, cache. constraints_not_added
604+ end
605+
510606"""
511607 ModelFilter(filter::Function, model::MOI.ModelLike)
512608
0 commit comments