@@ -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,39 @@ 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. ScalarAffineTerm (t1. coefficient + t2. coefficient,
200
+ t1. variable_index)
210
201
end
211
202
212
203
"""
213
- coefficient(t::Union{ MOI.ScalarAffineTerm, MOI.VectorAffineTerm} )
204
+ unsafe_add(t1:: MOI.VectorAffineTerm, t2:: MOI.VectorAffineTerm)
214
205
215
- Finds the coefficient associated with the term `t `.
206
+ 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
207
"""
217
- coefficient (t:: MOI.ScalarAffineTerm ) = t. coefficient
218
- coefficient (t:: MOI.VectorAffineTerm ) = t. scalar_term. coefficient
219
-
208
+ function unsafe_add (t1:: VT , t2:: VT ) where VT <: Union {MOI. VectorAffineTerm,
209
+ MOI. VectorQuadraticTerm}
210
+ scalar_term = unsafe_add (t1. scalar_term, t2. scalar_term)
211
+ return MOI. VectorAffineTerm (t1. output_index, scalar_term)
212
+ end
220
213
221
214
"""
222
- iscanonical(f::Union{ScalarAffineFunction, VectorAffineFunction})
215
+ iscanonical(f::Union{ScalarAffineFunction, ScalarQuadraticFunction
216
+ VectorAffineFunction, VectorQuadraticTerm})
223
217
224
218
Returns a Bool indicating whether the function is in canonical form.
225
219
See [`canonical`](@ref).
226
220
"""
227
- function iscanonical (f:: Union{SAF, VAF} )
228
- is_strictly_sorted (f. terms, termindices, t -> ! iszero (coefficient (t)))
221
+ function iscanonical (f:: Union{SAF, VAF, SQF, VQF} )
222
+ is_strictly_sorted (f. terms, MOI. term_indices,
223
+ t -> ! iszero (MOI. coefficient (t)))
229
224
end
230
225
231
226
"""
@@ -266,16 +261,31 @@ If `x` (resp. `y`, `z`) is `VariableIndex(1)` (resp. 2, 3).
266
261
The canonical representation of `ScalarAffineFunction([y, x, z, x, z], [2, 1, 3, -2, -3], 5)` is `ScalarAffineFunction([x, y], [-1, 2], 5)`.
267
262
268
263
"""
269
- canonical (f:: Union{SAF, VAF} ) = canonicalize! (copy (f))
264
+ canonical (f:: Union{SAF, VAF, SQF, VQF } ) = canonicalize! (copy (f))
270
265
271
266
"""
272
267
canonicalize!(f::Union{ScalarAffineFunction, VectorAffineFunction})
273
268
274
- Convert a function to canonical form in-place, without allocating a copy to hold the result.
275
- See [`canonical`](@ref).
269
+ Convert a function to canonical form in-place, without allocating a copy to hold
270
+ the result. See [`canonical`](@ref).
276
271
"""
277
272
function canonicalize! (f:: Union{SAF, VAF} )
278
- sort_and_compress! (f. terms, termindices, t -> ! iszero (coefficient (t)), unsafe_add)
273
+ sort_and_compress! (f. terms, MOI. term_indices,
274
+ t -> ! iszero (MOI. coefficient (t)), unsafe_add)
275
+ return f
276
+ end
277
+
278
+ """
279
+ canonicalize!(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction})
280
+
281
+ Convert a function to canonical form in-place, without allocating a copy to hold
282
+ the result. See [`canonical`](@ref).
283
+ """
284
+ function canonicalize! (f:: Union{SQF, VQF} )
285
+ sort_and_compress! (f. affine_terms, MOI. term_indices,
286
+ t -> ! iszero (MOI. coefficient (t)), unsafe_add)
287
+ sort_and_compress! (f. quadratic_terms, MOI. term_indices,
288
+ t -> ! iszero (MOI. coefficient (t)), unsafe_add)
279
289
return f
280
290
end
281
291
@@ -355,7 +365,7 @@ isapprox_zero(α::AbstractFloat, tol) = -tol < α < tol
355
365
isapprox_zero (α:: Union{Integer, Rational} , tol) = iszero (α)
356
366
function isapprox_zero (t:: Union {MOI. ScalarAffineTerm,
357
367
MOI. ScalarQuadraticTerm}, tol)
358
- isapprox_zero (t . coefficient, tol)
368
+ isapprox_zero (MOI . coefficient (t) , tol)
359
369
end
360
370
361
371
"""
@@ -453,11 +463,11 @@ function removevariable(f::VVF, vi)
453
463
VVF (_rmvar (f. variables, vi))
454
464
end
455
465
function removevariable (f:: Union{SAF, VAF} , vi)
456
- typeof (f)(_rmvar (f. terms, vi), _constant (f))
466
+ typeof (f)(_rmvar (f. terms, vi), MOI . _constant (f))
457
467
end
458
468
function removevariable (f:: Union{SQF, VQF} , vi)
459
469
terms = _rmvar .((f. affine_terms, f. quadratic_terms), Ref (vi))
460
- typeof (f)(terms... , _constant (f))
470
+ typeof (f)(terms... , MOI . _constant (f))
461
471
end
462
472
463
473
"""
@@ -592,6 +602,11 @@ function operate_term(::typeof(*), α::T, t::MOI.ScalarQuadraticTerm{T}) where T
592
602
MOI. ScalarQuadraticTerm (α * t. coefficient, t. variable_index_1,
593
603
t. variable_index_2)
594
604
end
605
+ function operate_term (:: typeof (* ), t1:: MOI.ScalarAffineTerm ,
606
+ t2:: MOI.ScalarAffineTerm )
607
+ MOI. ScalarQuadraticTerm (t1. coefficient * t2. coefficient, t1. variable_index,
608
+ t2. variable_index)
609
+ end
595
610
596
611
function operate_term (:: typeof (/ ), t:: MOI.ScalarAffineTerm{T} , α:: T ) where T
597
612
MOI. ScalarAffineTerm (t. coefficient / α, t. variable_index)
@@ -641,6 +656,12 @@ function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T},
641
656
end
642
657
643
658
# # operate!
659
+ # + with at least 3 arguments
660
+ function operate! (op:: typeof (+ ), :: Type{T} , f, g, h, args... ) where T
661
+ operate! (op, T, f, g)
662
+ return operate! (+ , T, f, h, args... )
663
+ end
664
+
644
665
# Scalar Variable +/- ...
645
666
function operate! (op:: Union{typeof(+), typeof(-)} , :: Type{T} ,
646
667
f:: MOI.SingleVariable ,
@@ -697,7 +718,27 @@ function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T},
697
718
end
698
719
699
720
# # operate
721
+ # + with at least 3 arguments, can use in-place as the user cannot use
722
+ # intermediate results
723
+ function operate (op:: typeof (+ ), :: Type{T} , f, g, h, args... ) where T
724
+ return operate! (+ , T, operate (+ , T, f, g), h, args... )
725
+ end
726
+
727
+ # Scalar number +/- ...
728
+ function operate (op:: typeof (+ ), :: Type{T} , α:: T , f:: ScalarLike{T} ) where T
729
+ return operate (op, T, f, α)
730
+ end
731
+ function operate (op:: typeof (- ), :: Type{T} , α:: T , f:: ScalarLike{T} ) where T
732
+ return operate! (+ , T, operate (- , T, f), α)
733
+ end
734
+
700
735
# Scalar Variable +/- ...
736
+ function operate (op:: Union{typeof(+), typeof(-)} , :: Type{T} ,
737
+ f:: MOI.SingleVariable , α:: T ) where T
738
+ return MOI. ScalarAffineFunction {T} ([MOI. ScalarAffineTerm (one (T),
739
+ f. variable)],
740
+ op (α))
741
+ end
701
742
function operate (op:: Union{typeof(+), typeof(-)} , :: Type{T} ,
702
743
f:: MOI.SingleVariable ,
703
744
g:: MOI.SingleVariable ) where T
@@ -745,14 +786,20 @@ end
745
786
function Base.:+ (args:: ScalarLike{T} ...) where T
746
787
return operate (+ , T, args... )
747
788
end
748
- function Base.:+ (f:: ScalarLike{T} , g:: T ) where T
749
- return operate (+ , T, f, g)
789
+ function Base.:+ (α:: T , f:: ScalarLike{T} ) where T
790
+ return operate (+ , T, α, f)
791
+ end
792
+ function Base.:+ (f:: ScalarLike{T} , α:: T ) where T
793
+ return operate (+ , T, f, α)
750
794
end
751
795
function Base.:- (args:: ScalarLike{T} ...) where T
752
796
return operate (- , T, args... )
753
797
end
754
- function Base.:- (f:: ScalarLike{T} , g:: T ) where T
755
- return operate (- , T, f, g)
798
+ function Base.:- (f:: ScalarLike{T} , α:: T ) where T
799
+ return operate (- , T, f, α)
800
+ end
801
+ function Base.:- (α:: T , f:: ScalarLike{T} ) where T
802
+ return operate (- , T, α, f)
756
803
end
757
804
758
805
# ###################################### * ######################################
@@ -761,6 +808,14 @@ function promote_operation(::typeof(*), ::Type{T}, ::Type{T},
761
808
MOI. ScalarAffineFunction{T}}}) where T
762
809
return MOI. ScalarAffineFunction{T}
763
810
end
811
+ function promote_operation (:: typeof (* ), :: Type{T} ,
812
+ :: Type {<: Union {MOI. SingleVariable,
813
+ MOI. ScalarAffineFunction{T}}},
814
+ :: Type {<: Union {MOI. SingleVariable,
815
+ MOI. ScalarAffineFunction{T}}}) where T
816
+ return MOI. ScalarQuadraticFunction{T}
817
+ end
818
+
764
819
765
820
function operate! (:: typeof (* ), :: Type{T} , f:: MOI.SingleVariable , α:: T ) where T
766
821
return operate (* , T, α, f)
@@ -785,6 +840,60 @@ function operate(::typeof(*), ::Type{T}, α::T,
785
840
return operate! (* , T, copy (f), α)
786
841
end
787
842
843
+ function operate (:: typeof (* ), :: Type{T} , f:: MOI.SingleVariable ,
844
+ g:: MOI.SingleVariable ) where T
845
+ return MOI. ScalarQuadraticFunction (MOI. ScalarAffineTerm{T}[],
846
+ [MOI. ScalarQuadraticTerm (one (T),
847
+ f. variable,
848
+ g. variable)],
849
+ zero (T))
850
+ end
851
+
852
+ function operate (:: typeof (* ), :: Type{T} , f:: MOI.ScalarAffineFunction{T} ,
853
+ g:: MOI.SingleVariable ) where T
854
+ aff_terms = [MOI. ScalarAffineTerm (f. constant, g. variable)]
855
+ quad_terms = map (t -> MOI. ScalarQuadraticTerm (t. coefficient,
856
+ t. variable_index,
857
+ g. variable),
858
+ f. terms)
859
+ return MOI. ScalarQuadraticFunction (aff_terms, quad_terms, zero (T))
860
+ end
861
+
862
+ function operate (:: typeof (* ), :: Type{T} , f:: MOI.ScalarAffineFunction{T} ,
863
+ g:: MOI.ScalarAffineFunction{T} ) where T
864
+ nfterms = length (f. terms)
865
+ ngterms = length (g. terms)
866
+ quad_terms = Vector {MOI.ScalarQuadraticTerm{T}} (undef, nfterms * ngterms)
867
+ k = 0
868
+ for t1 in f. terms
869
+ for t2 in g. terms
870
+ k += 1
871
+ quad_terms[k] = operate_term (* , t1, t2)
872
+ end
873
+ end
874
+ @assert k == length (quad_terms)
875
+ if iszero (f. constant)
876
+ if iszero (g. constant)
877
+ aff_terms = MOI. ScalarAffineTerm{T}[]
878
+ else
879
+ aff_terms = operate_term .(* , g. constant, f. terms)
880
+ end
881
+ else
882
+ if iszero (g. constant)
883
+ aff_terms = operate_term .(* , f. constant, g. terms)
884
+ else
885
+ aff_terms = Vector {MOI.ScalarAffineTerm{T}} (undef,
886
+ nfterms + ngterms)
887
+ map! (t -> operate_term (* , g. constant, t), aff_terms, f. terms)
888
+ for i in 1 : ngterms
889
+ aff_terms[nfterms + i] = operate_term (* , f. constant, g. terms[i])
890
+ end
891
+ end
892
+ end
893
+ constant = f. constant * g. constant
894
+ return MOI. ScalarQuadraticFunction (aff_terms, quad_terms, constant)
895
+ end
896
+
788
897
function Base.:* (args:: ScalarLike{T} ...) where T
789
898
return operate (* , T, args... )
790
899
end
0 commit comments