@@ -701,6 +701,8 @@ function unsafe_add(
701
701
return T (t1. output_index, scalar_term)
702
702
end
703
703
704
+ is_canonical (:: MOI.AbstractFunction ) = false
705
+
704
706
is_canonical (:: Union{MOI.VariableIndex,MOI.VectorOfVariables} ) = true
705
707
706
708
"""
@@ -712,11 +714,7 @@ See [`canonical`](@ref).
712
714
function is_canonical (
713
715
f:: Union{MOI.ScalarAffineFunction,MOI.VectorAffineFunction} ,
714
716
)
715
- return is_strictly_sorted (
716
- f. terms,
717
- MOI. term_indices,
718
- t -> ! iszero (MOI. coefficient (t)),
719
- )
717
+ return _is_strictly_sorted (f. terms)
720
718
end
721
719
722
720
"""
@@ -728,39 +726,25 @@ See [`canonical`](@ref).
728
726
function is_canonical (
729
727
f:: Union{MOI.ScalarQuadraticFunction,MOI.VectorQuadraticFunction} ,
730
728
)
731
- v = is_strictly_sorted (
732
- f. affine_terms,
733
- MOI. term_indices,
734
- t -> ! iszero (MOI. coefficient (t)),
735
- )
736
- return v & is_strictly_sorted (
737
- f. quadratic_terms,
738
- MOI. term_indices,
739
- t -> ! iszero (MOI. coefficient (t)),
740
- )
729
+ return _is_strictly_sorted (f. affine_terms) &&
730
+ _is_strictly_sorted (f. quadratic_terms)
741
731
end
742
732
743
- """
744
- is_strictly_sorted(x::Vector, by, filter)
745
-
746
- Returns `true` if `by(x[i]) < by(x[i + 1])` and `filter(x[i]) == true` for
747
- all indices i.
748
- """
749
- function is_strictly_sorted (x:: Vector , by, filter)
733
+ function _is_strictly_sorted (x:: Vector )
750
734
if isempty (x)
751
735
return true
752
736
end
753
- @inbounds current_x = first (x)
754
- if ! filter ( current_x)
737
+ @inbounds current_x = x[ 1 ]
738
+ if iszero (MOI . coefficient ( current_x) )
755
739
return false
756
740
end
757
- current_fx = by (current_x)
758
- for i in eachindex (x)[ 2 : end ]
759
- @inbounds next_x = x[i]
760
- if ! filter ( next_x)
741
+ current_fx = MOI . term_indices (current_x)
742
+ @inbounds for i in 2 : length (x)
743
+ next_x = x[i]
744
+ if iszero (MOI . coefficient ( next_x) )
761
745
return false
762
746
end
763
- next_fx = by (next_x)
747
+ next_fx = MOI . term_indices (next_x)
764
748
if next_fx <= current_fx
765
749
return false
766
750
end
@@ -796,7 +780,13 @@ If `x` (resp. `y`, `z`) is `VariableIndex(1)` (resp. 2, 3). The canonical
796
780
representation of `ScalarAffineFunction([y, x, z, x, z], [2, 1, 3, -2, -3], 5)`
797
781
is `ScalarAffineFunction([x, y], [-1, 2], 5)`.
798
782
"""
799
- canonical (f:: MOI.AbstractFunction ) = canonicalize! (copy (f))
783
+ function canonical (f:: MOI.AbstractFunction )
784
+ g = copy (f)
785
+ if ! is_canonical (g)
786
+ canonicalize! (g)
787
+ end
788
+ return g
789
+ end
800
790
801
791
canonicalize! (f:: Union{MOI.VectorOfVariables,MOI.VariableIndex} ) = f
802
792
@@ -809,12 +799,7 @@ the result. See [`canonical`](@ref).
809
799
function canonicalize! (
810
800
f:: Union{MOI.ScalarAffineFunction,MOI.VectorAffineFunction} ,
811
801
)
812
- sort_and_compress! (
813
- f. terms,
814
- MOI. term_indices,
815
- t -> ! iszero (MOI. coefficient (t)),
816
- unsafe_add,
817
- )
802
+ _sort_and_compress! (f. terms)
818
803
return f
819
804
end
820
805
@@ -827,60 +812,40 @@ the result. See [`canonical`](@ref).
827
812
function canonicalize! (
828
813
f:: Union{MOI.ScalarQuadraticFunction,MOI.VectorQuadraticFunction} ,
829
814
)
830
- sort_and_compress! (
831
- f. affine_terms,
832
- MOI. term_indices,
833
- t -> ! iszero (MOI. coefficient (t)),
834
- unsafe_add,
835
- )
836
- sort_and_compress! (
837
- f. quadratic_terms,
838
- MOI. term_indices,
839
- t -> ! iszero (MOI. coefficient (t)),
840
- unsafe_add,
841
- )
815
+ _sort_and_compress! (f. affine_terms)
816
+ _sort_and_compress! (f. quadratic_terms)
842
817
return f
843
818
end
844
819
845
820
"""
846
- sort_and_compress!(
847
- x::AbstractVector,
848
- by::Function,
849
- keep::Function,
850
- combine::Function,
851
- )
821
+ _sort_and_compress!(x::Vector)
852
822
853
823
Sort the vector `x` in-place using `by` as the function from elements to
854
824
comparable keys, then combine all entries for which `by(x[i]) == by(x[j])` using
855
825
the function `x[i] = combine(x[i], x[j])`, and remove any entries for which
856
826
`keep(x[i]) == false`. This may result in `x` being resized to a shorter length.
857
827
"""
858
- function sort_and_compress! (x:: AbstractVector , by, keep, combine)
859
- if length (x) > 0
860
- sort! (
861
- x,
862
- QuickSort,
863
- Base. Order. ord (isless, by, false , Base. Sort. Forward),
864
- )
865
- i1 = firstindex (x)
866
- for i2 in eachindex (x)[2 : end ]
867
- if by (x[i1]) == by (x[i2])
868
- x[i1] = combine (x[i1], x[i2])
869
- else
870
- if ! keep (x[i1])
871
- x[i1] = x[i2]
872
- else
873
- x[i1+ 1 ] = x[i2]
874
- i1 += 1
875
- end
876
- end
877
- end
878
- if ! keep (x[i1])
879
- i1 -= 1
828
+ function _sort_and_compress! (x:: Vector )
829
+ if length (x) == 0
830
+ return
831
+ end
832
+ sort! (x, QuickSort, Base. Order. ord (isless, MOI. term_indices, false ))
833
+ i = 1
834
+ @inbounds for j in 2 : length (x)
835
+ if MOI. term_indices (x[i]) == MOI. term_indices (x[j])
836
+ x[i] = unsafe_add (x[i], x[j])
837
+ elseif iszero (MOI. coefficient (x[i]))
838
+ x[i] = x[j]
839
+ else
840
+ x[i+ 1 ] = x[j]
841
+ i += 1
880
842
end
881
- resize! (x, i1)
882
843
end
883
- return x
844
+ if iszero (MOI. coefficient (x[i]))
845
+ i -= 1
846
+ end
847
+ resize! (x, i)
848
+ return
884
849
end
885
850
886
851
"""
0 commit comments