@@ -513,29 +513,47 @@ function _build_copy_variables_with_set_cache(
513
513
F = MOI. VariableIndex
514
514
indices = MOI. ConstraintIndex{F,S}[]
515
515
for ci in MOI. get (src, MOI. ListOfConstraintIndices {F,S} ())
516
- f = MOI. get (src, MOI. ConstraintFunction (), ci)
517
- if f in cache. variables_with_domain
516
+ x = MOI. get (src, MOI. ConstraintFunction (), ci)
517
+ if x in cache. variables_with_domain
518
+ # `x` is already assigned to a domain. Add this constraint via
519
+ # `add_constraint`.
518
520
push! (indices, ci)
519
521
else
520
- push! (cache. variables_with_domain, f)
521
- push! (cache. variable_cones, ([f], ci))
522
+ # `x` is not assigned to a domain. Choose to add this constraint via
523
+ # `x, ci = add_constraint_variable(model, set)`
524
+ push! (cache. variables_with_domain, x)
525
+ push! (cache. variable_cones, ([x], ci))
522
526
end
523
527
end
524
528
if ! isempty (indices)
529
+ # If indices is not empty, then we have some constraints to add.
525
530
push! (cache. constraints_not_added, indices)
526
531
end
527
532
return
528
533
end
529
534
530
- function _is_variable_cone (cache, f:: MOI.VectorOfVariables )
535
+ # This function is a heuristic that checks whether `f` should be added via
536
+ # `MOI.add_constrained_variables`.
537
+ function _is_variable_cone (
538
+ cache:: _CopyVariablesWithSetCache ,
539
+ f:: MOI.VectorOfVariables ,
540
+ )
531
541
if isempty (f. variables)
542
+ # If the dimension is `0`, `f` cannot be added via
543
+ # `add_constrained_variables`
532
544
return false
533
545
end
534
546
offset = cache. variable_to_column[f. variables[1 ]] - 1
535
547
for (i, xi) in enumerate (f. variables)
536
548
if xi in cache. variables_with_domain
549
+ # The function contains at least one element that is already
550
+ # assigned to a domain. We can't add `f` via
551
+ # `add_constrained_variables`
537
552
return false
538
553
elseif cache. variable_to_column[xi] != offset + i
554
+ # The variables in the function are not contiguous in their column
555
+ # ordering. In theory, we could add `f` via `add_constrained_variables`,
556
+ # but this would introduce a permutation so we choose not to.
539
557
return false
540
558
end
541
559
end
@@ -553,19 +571,53 @@ function _build_copy_variables_with_set_cache(
553
571
f = MOI. get (src, MOI. ConstraintFunction (), ci)
554
572
if _is_variable_cone (cache, f)
555
573
for fi in f. variables
574
+ # We need to assign each variable in `f` to a domain
556
575
push! (cache. variables_with_domain, fi)
557
576
end
577
+ # And we need to add the variables via `add_constrained_variables`.
558
578
push! (cache. variable_cones, (f. variables, ci))
559
579
else
580
+ # Not a variable cone, so add via `add_constraint`.
560
581
push! (indices, ci)
561
582
end
562
583
end
563
584
if ! isempty (indices)
585
+ # If indices is not empty, then we have some constraints to add.
564
586
push! (cache. constraints_not_added, indices)
565
587
end
566
588
return
567
589
end
568
590
591
+ function _add_variable_with_domain (
592
+ dest,
593
+ src,
594
+ index_map,
595
+ f,
596
+ ci:: MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.AbstractScalarSet} ,
597
+ )
598
+ set = MOI. get (src, MOI. ConstraintSet (), ci)
599
+ dest_x, dest_ci = MOI. add_constrained_variable (dest, set)
600
+ index_map[only (f)] = dest_x
601
+ index_map[ci] = dest_ci
602
+ return
603
+ end
604
+
605
+ function _add_variable_with_domain (
606
+ dest,
607
+ src,
608
+ index_map,
609
+ f,
610
+ ci:: MOI.ConstraintIndex{MOI.VectorOfVariables,<:MOI.AbstractVectorSet} ,
611
+ )
612
+ set = MOI. get (src, MOI. ConstraintSet (), ci)
613
+ dest_x, dest_ci = MOI. add_constrained_variables (dest, set)
614
+ for (fi, xi) in zip (f, dest_x)
615
+ index_map[fi] = xi
616
+ end
617
+ index_map[ci] = dest_ci
618
+ return
619
+ end
620
+
569
621
function _copy_variables_with_set (dest, src)
570
622
index_map = IndexMap ()
571
623
vis_src = MOI. get (src, MOI. ListOfVariableIndices ())
@@ -579,26 +631,16 @@ function _copy_variables_with_set(dest, src)
579
631
column (x:: MOI.VariableIndex ) = cache. variable_to_column[x]
580
632
start_column (x) = column (first (x[1 ]))
581
633
current_column = 0
582
- for (f, ci) in sort! (cache. variable_cones; by = start_column)
634
+ sort! (cache. variable_cones; by = start_column)
635
+ for (f, ci) in cache. variable_cones
583
636
offset = column (first (f)) - current_column - 1
584
637
if offset > 0
585
638
dest_x = MOI. add_variables (dest, offset)
586
639
for i in 1 : offset
587
640
index_map[vis_src[current_column+ i]] = dest_x[i]
588
641
end
589
642
end
590
- set = MOI. get (src, MOI. ConstraintSet (), ci)
591
- if set isa MOI. AbstractScalarSet
592
- dest_x, dest_ci = MOI. add_constrained_variable (dest, set)
593
- index_map[only (f)] = dest_x
594
- index_map[ci] = dest_ci
595
- else
596
- dest_x, dest_ci = MOI. add_constrained_variables (dest, set)
597
- for (fi, xi) in zip (f, dest_x)
598
- index_map[fi] = xi
599
- end
600
- index_map[ci] = dest_ci
601
- end
643
+ _add_variable_with_domain (dest, src, index_map, f, ci)
602
644
current_column = column (last (f))
603
645
end
604
646
offset = length (cache. variable_to_column) - current_column
0 commit comments