@@ -74,12 +74,12 @@ function mapvariables(varmap::Function, f::MOI.VectorOfVariables)
74
74
return MOI. VectorOfVariables (varmap .(f. variables))
75
75
end
76
76
function mapvariables (varmap:: Function , f:: Union{SAF, VAF} )
77
- typeof (f)(mapvariable .(varmap, f. terms), _constant (f))
77
+ typeof (f)(mapvariable .(varmap, f. terms), MOI . _constant (f))
78
78
end
79
79
function mapvariables (varmap:: Function , f:: Union{SQF, VQF} )
80
80
lin = mapvariable .(varmap, f. affine_terms)
81
81
quad = mapvariable .(varmap, f. quadratic_terms)
82
- return typeof (f)(lin, quad, _constant (f))
82
+ return typeof (f)(lin, quad, MOI . _constant (f))
83
83
end
84
84
mapvariables (varmap, f:: MOI.AbstractFunction ) = mapvariables (vi -> varmap[vi], f)
85
85
mapvariables (varmap:: Function , change:: Union{MOI.ScalarConstantChange, MOI.VectorConstantChange} ) = change
@@ -93,9 +93,6 @@ function mapvariables(varmap, f::MOI.AbstractFunctionModification)
93
93
return mapvariables (vi -> varmap[vi], f)
94
94
end
95
95
96
- # Constant field
97
- _constant (f:: Union{SAF, SQF} ) = f. constant
98
- _constant (f:: Union{VAF, VQF} ) = f. constants
99
96
# Vector of constants
100
97
constant (f:: Union{SAF, SQF} ) = [f. constant]
101
98
constant (f:: Union{VAF, VQF} ) = f. constants
@@ -181,14 +178,6 @@ function Base.getindex(it::ScalarFunctionIterator{VAF{T}}, I::AbstractVector) wh
181
178
VAF (terms, constant)
182
179
end
183
180
184
- """
185
- termindices(t::Union{MOI.ScalarAffineTerm, MOI.VectorAffineTerm})
186
-
187
- Returns the indices of the input term `t` as a tuple of `Int`s. For `t::MOI.ScalarAffineTerm`, this is a 1-tuple of the variable index. For `t::MOI.VectorAffineTerm`, this is a 2-tuple of the row/output and variable indices of the term.
188
- """
189
- termindices (t:: MOI.ScalarAffineTerm ) = (t. variable_index. value,)
190
- termindices (t:: MOI.VectorAffineTerm ) = (t. output_index, termindices (t. scalar_term)... )
191
-
192
181
"""
193
182
unsafe_add(t1::MOI.ScalarAffineTerm, t2::MOI.ScalarAffineTerm)
194
183
@@ -199,33 +188,40 @@ function unsafe_add(t1::MOI.ScalarAffineTerm, t2::MOI.ScalarAffineTerm)
199
188
end
200
189
201
190
"""
202
- unsafe_add(t1::MOI.VectorAffineTerm , t2::MOI.VectorAffineTerm )
191
+ unsafe_add(t1::MOI.ScalarQuadraticTerm , t2::MOI.ScalarQuadraticTerm )
203
192
204
- Sums the coefficients of `t1` and `t2` and returns an output `MOI.VectorAffineTerm`. It is unsafe because it uses the `output_index` and `variable_index` of `t1` as the `output_index` and `variable_index` of the output term without checking that they are equal to those of `t2`.
193
+ Sums the coefficients of `t1` and `t2` and returns an output
194
+ `MOI.ScalarQuadraticTerm`. It is unsafe because it uses the `variable_index`'s
195
+ of `t1` as the `variable_index`'s of the output without checking that they are
196
+ the same (up to permutation) to those of `t2`.
205
197
"""
206
- function unsafe_add (t1:: MOI.VectorAffineTerm , t2:: MOI.VectorAffineTerm )
207
- coefficient = t1. scalar_term . coefficient + t2. scalar_term . coefficient
208
- scalar_term = MOI . ScalarAffineTerm (coefficient, t1. scalar_term . variable_index)
209
- return MOI . VectorAffineTerm ( t1. output_index, scalar_term )
198
+ function unsafe_add (t1:: MOI.ScalarQuadraticTerm , t2:: MOI.ScalarQuadraticTerm )
199
+ return MOI . ScalarQuadraticTerm ( t1. coefficient + t2. coefficient,
200
+ t1. variable_index_1,
201
+ t1. variable_index_2 )
210
202
end
211
203
212
204
"""
213
- coefficient(t::Union{ MOI.ScalarAffineTerm, MOI.VectorAffineTerm} )
205
+ unsafe_add(t1:: MOI.VectorAffineTerm, t2:: MOI.VectorAffineTerm)
214
206
215
- Finds the coefficient associated with the term `t `.
207
+ Sums the coefficients of `t1` and `t2` and returns an output `MOI.VectorAffineTerm`. It is unsafe because it uses the `output_index` and `variable_index` of `t1` as the `output_index` and `variable_index` of the output term without checking that they are equal to those of `t2 `.
216
208
"""
217
- coefficient (t:: MOI.ScalarAffineTerm ) = t. coefficient
218
- coefficient (t:: MOI.VectorAffineTerm ) = t. scalar_term. coefficient
219
-
209
+ function unsafe_add (t1:: VT , t2:: VT ) where VT <: Union {MOI. VectorAffineTerm,
210
+ MOI. VectorQuadraticTerm}
211
+ scalar_term = unsafe_add (t1. scalar_term, t2. scalar_term)
212
+ return MOI. VectorAffineTerm (t1. output_index, scalar_term)
213
+ end
220
214
221
215
"""
222
- iscanonical(f::Union{ScalarAffineFunction, VectorAffineFunction})
216
+ iscanonical(f::Union{ScalarAffineFunction, ScalarQuadraticFunction
217
+ VectorAffineFunction, VectorQuadraticTerm})
223
218
224
219
Returns a Bool indicating whether the function is in canonical form.
225
220
See [`canonical`](@ref).
226
221
"""
227
- function iscanonical (f:: Union{SAF, VAF} )
228
- is_strictly_sorted (f. terms, termindices, t -> ! iszero (coefficient (t)))
222
+ function iscanonical (f:: Union{SAF, VAF, SQF, VQF} )
223
+ is_strictly_sorted (f. terms, MOI. term_indices,
224
+ t -> ! iszero (MOI. coefficient (t)))
229
225
end
230
226
231
227
"""
@@ -266,16 +262,31 @@ If `x` (resp. `y`, `z`) is `VariableIndex(1)` (resp. 2, 3).
266
262
The canonical representation of `ScalarAffineFunction([y, x, z, x, z], [2, 1, 3, -2, -3], 5)` is `ScalarAffineFunction([x, y], [-1, 2], 5)`.
267
263
268
264
"""
269
- canonical (f:: Union{SAF, VAF} ) = canonicalize! (copy (f))
265
+ canonical (f:: Union{SAF, VAF, SQF, VQF } ) = canonicalize! (copy (f))
270
266
271
267
"""
272
268
canonicalize!(f::Union{ScalarAffineFunction, VectorAffineFunction})
273
269
274
- Convert a function to canonical form in-place, without allocating a copy to hold the result.
275
- See [`canonical`](@ref).
270
+ Convert a function to canonical form in-place, without allocating a copy to hold
271
+ the result. See [`canonical`](@ref).
276
272
"""
277
273
function canonicalize! (f:: Union{SAF, VAF} )
278
- sort_and_compress! (f. terms, termindices, t -> ! iszero (coefficient (t)), unsafe_add)
274
+ sort_and_compress! (f. terms, MOI. term_indices,
275
+ t -> ! iszero (MOI. coefficient (t)), unsafe_add)
276
+ return f
277
+ end
278
+
279
+ """
280
+ canonicalize!(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})
281
+
282
+ Convert a function to canonical form in-place, without allocating a copy to hold
283
+ the result. See [`canonical`](@ref).
284
+ """
285
+ function canonicalize! (f:: Union{SQF, VQF} )
286
+ sort_and_compress! (f. affine_terms, MOI. term_indices,
287
+ t -> ! iszero (MOI. coefficient (t)), unsafe_add)
288
+ sort_and_compress! (f. quadratic_terms, MOI. term_indices,
289
+ t -> ! iszero (MOI. coefficient (t)), unsafe_add)
279
290
return f
280
291
end
281
292
@@ -355,7 +366,7 @@ isapprox_zero(α::AbstractFloat, tol) = -tol < α < tol
355
366
isapprox_zero (α:: Union{Integer, Rational} , tol) = iszero (α)
356
367
function isapprox_zero (t:: Union {MOI. ScalarAffineTerm,
357
368
MOI. ScalarQuadraticTerm}, tol)
358
- isapprox_zero (t . coefficient, tol)
369
+ isapprox_zero (MOI . coefficient (t) , tol)
359
370
end
360
371
361
372
"""
@@ -453,11 +464,11 @@ function removevariable(f::VVF, vi)
453
464
VVF (_rmvar (f. variables, vi))
454
465
end
455
466
function removevariable (f:: Union{SAF, VAF} , vi)
456
- typeof (f)(_rmvar (f. terms, vi), _constant (f))
467
+ typeof (f)(_rmvar (f. terms, vi), MOI . _constant (f))
457
468
end
458
469
function removevariable (f:: Union{SQF, VQF} , vi)
459
470
terms = _rmvar .((f. affine_terms, f. quadratic_terms), Ref (vi))
460
- typeof (f)(terms... , _constant (f))
471
+ typeof (f)(terms... , MOI . _constant (f))
461
472
end
462
473
463
474
"""
@@ -592,6 +603,11 @@ function operate_term(::typeof(*), α::T, t::MOI.ScalarQuadraticTerm{T}) where T
592
603
MOI. ScalarQuadraticTerm (α * t. coefficient, t. variable_index_1,
593
604
t. variable_index_2)
594
605
end
606
+ function operate_term (:: typeof (* ), t1:: MOI.ScalarAffineTerm ,
607
+ t2:: MOI.ScalarAffineTerm )
608
+ MOI. ScalarQuadraticTerm (t1. coefficient * t2. coefficient, t1. variable_index,
609
+ t2. variable_index)
610
+ end
595
611
596
612
function operate_term (:: typeof (/ ), t:: MOI.ScalarAffineTerm{T} , α:: T ) where T
597
613
MOI. ScalarAffineTerm (t. coefficient / α, t. variable_index)
@@ -641,6 +657,12 @@ function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T},
641
657
end
642
658
643
659
# # operate!
660
+ # + with at least 3 arguments
661
+ function operate! (op:: typeof (+ ), :: Type{T} , f, g, h, args... ) where T
662
+ operate! (op, T, f, g)
663
+ return operate! (+ , T, f, h, args... )
664
+ end
665
+
644
666
# Scalar Variable +/- ...
645
667
function operate! (op:: Union{typeof(+), typeof(-)} , :: Type{T} ,
646
668
f:: MOI.SingleVariable ,
@@ -667,6 +689,11 @@ function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T},
667
689
f. constant = op (f. constant, g. constant)
668
690
return f
669
691
end
692
+ function operate! (op:: Union{typeof(+), typeof(-)} , :: Type{T} ,
693
+ f:: MOI.ScalarAffineFunction{T} ,
694
+ g:: MOI.ScalarQuadraticFunction{T} ) where T
695
+ return operate (op, T, f, g)
696
+ end
670
697
# Scalar Quadratic +/-! ...
671
698
function operate! (op:: Union{typeof(+), typeof(-)} , :: Type{T} ,
672
699
f:: MOI.ScalarQuadraticFunction{T} ,
@@ -697,7 +724,27 @@ function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T},
697
724
end
698
725
699
726
# # operate
727
+ # + with at least 3 arguments, can use in-place as the user cannot use
728
+ # intermediate results
729
+ function operate (op:: typeof (+ ), :: Type{T} , f, g, h, args... ) where T
730
+ return operate! (+ , T, operate (+ , T, f, g), h, args... )
731
+ end
732
+
733
+ # Scalar number +/- ...
734
+ function operate (op:: typeof (+ ), :: Type{T} , α:: T , f:: ScalarLike{T} ) where T
735
+ return operate (op, T, f, α)
736
+ end
737
+ function operate (op:: typeof (- ), :: Type{T} , α:: T , f:: ScalarLike{T} ) where T
738
+ return operate! (+ , T, operate (- , T, f), α)
739
+ end
740
+
700
741
# Scalar Variable +/- ...
742
+ function operate (op:: Union{typeof(+), typeof(-)} , :: Type{T} ,
743
+ f:: MOI.SingleVariable , α:: T ) where T
744
+ return MOI. ScalarAffineFunction {T} ([MOI. ScalarAffineTerm (one (T),
745
+ f. variable)],
746
+ op (α))
747
+ end
701
748
function operate (op:: Union{typeof(+), typeof(-)} , :: Type{T} ,
702
749
f:: MOI.SingleVariable ,
703
750
g:: MOI.SingleVariable ) where T
@@ -745,14 +792,20 @@ end
745
792
function Base.:+ (args:: ScalarLike{T} ...) where T
746
793
return operate (+ , T, args... )
747
794
end
748
- function Base.:+ (f:: ScalarLike{T} , g:: T ) where T
749
- return operate (+ , T, f, g)
795
+ function Base.:+ (α:: T , f:: ScalarLike{T} ...) where T
796
+ return operate (+ , T, α, f... )
797
+ end
798
+ function Base.:+ (f:: ScalarLike{T} , α:: T ) where T
799
+ return operate (+ , T, f, α)
750
800
end
751
801
function Base.:- (args:: ScalarLike{T} ...) where T
752
802
return operate (- , T, args... )
753
803
end
754
- function Base.:- (f:: ScalarLike{T} , g:: T ) where T
755
- return operate (- , T, f, g)
804
+ function Base.:- (f:: ScalarLike{T} , α:: T ) where T
805
+ return operate (- , T, f, α)
806
+ end
807
+ function Base.:- (α:: T , f:: ScalarLike{T} ) where T
808
+ return operate (- , T, α, f)
756
809
end
757
810
758
811
# ###################################### * ######################################
@@ -761,6 +814,14 @@ function promote_operation(::typeof(*), ::Type{T}, ::Type{T},
761
814
MOI. ScalarAffineFunction{T}}}) where T
762
815
return MOI. ScalarAffineFunction{T}
763
816
end
817
+ function promote_operation (:: typeof (* ), :: Type{T} ,
818
+ :: Type {<: Union {MOI. SingleVariable,
819
+ MOI. ScalarAffineFunction{T}}},
820
+ :: Type {<: Union {MOI. SingleVariable,
821
+ MOI. ScalarAffineFunction{T}}}) where T
822
+ return MOI. ScalarQuadraticFunction{T}
823
+ end
824
+
764
825
765
826
function operate! (:: typeof (* ), :: Type{T} , f:: MOI.SingleVariable , α:: T ) where T
766
827
return operate (* , T, α, f)
@@ -785,6 +846,60 @@ function operate(::typeof(*), ::Type{T}, α::T,
785
846
return operate! (* , T, copy (f), α)
786
847
end
787
848
849
+ function operate (:: typeof (* ), :: Type{T} , f:: MOI.SingleVariable ,
850
+ g:: MOI.SingleVariable ) where T
851
+ return MOI. ScalarQuadraticFunction (MOI. ScalarAffineTerm{T}[],
852
+ [MOI. ScalarQuadraticTerm (one (T),
853
+ f. variable,
854
+ g. variable)],
855
+ zero (T))
856
+ end
857
+
858
+ function operate (:: typeof (* ), :: Type{T} , f:: MOI.ScalarAffineFunction{T} ,
859
+ g:: MOI.SingleVariable ) where T
860
+ aff_terms = [MOI. ScalarAffineTerm (f. constant, g. variable)]
861
+ quad_terms = map (t -> MOI. ScalarQuadraticTerm (t. coefficient,
862
+ t. variable_index,
863
+ g. variable),
864
+ f. terms)
865
+ return MOI. ScalarQuadraticFunction (aff_terms, quad_terms, zero (T))
866
+ end
867
+
868
+ function operate (:: typeof (* ), :: Type{T} , f:: MOI.ScalarAffineFunction{T} ,
869
+ g:: MOI.ScalarAffineFunction{T} ) where T
870
+ nfterms = length (f. terms)
871
+ ngterms = length (g. terms)
872
+ quad_terms = Vector {MOI.ScalarQuadraticTerm{T}} (undef, nfterms * ngterms)
873
+ k = 0
874
+ for t1 in f. terms
875
+ for t2 in g. terms
876
+ k += 1
877
+ quad_terms[k] = operate_term (* , t1, t2)
878
+ end
879
+ end
880
+ @assert k == length (quad_terms)
881
+ if iszero (f. constant)
882
+ if iszero (g. constant)
883
+ aff_terms = MOI. ScalarAffineTerm{T}[]
884
+ else
885
+ aff_terms = operate_term .(* , g. constant, f. terms)
886
+ end
887
+ else
888
+ if iszero (g. constant)
889
+ aff_terms = operate_term .(* , f. constant, g. terms)
890
+ else
891
+ aff_terms = Vector {MOI.ScalarAffineTerm{T}} (undef,
892
+ nfterms + ngterms)
893
+ map! (t -> operate_term (* , g. constant, t), aff_terms, f. terms)
894
+ for i in 1 : ngterms
895
+ aff_terms[nfterms + i] = operate_term (* , f. constant, g. terms[i])
896
+ end
897
+ end
898
+ end
899
+ constant = f. constant * g. constant
900
+ return MOI. ScalarQuadraticFunction (aff_terms, quad_terms, constant)
901
+ end
902
+
788
903
function Base.:* (args:: ScalarLike{T} ...) where T
789
904
return operate (* , T, args... )
790
905
end
0 commit comments