From cd46a39219097c808e54d83ff703598ad942b3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Tue, 16 Feb 2021 00:09:28 +0100 Subject: [PATCH 01/15] first draft --- src/Utilities/mutable_arithmetics.jl | 9 ++ src/functions.jl | 130 ++++++++++++++++++++++----- 2 files changed, 115 insertions(+), 24 deletions(-) diff --git a/src/Utilities/mutable_arithmetics.jl b/src/Utilities/mutable_arithmetics.jl index a212dce1b8..c9b93de203 100644 --- a/src/Utilities/mutable_arithmetics.jl +++ b/src/Utilities/mutable_arithmetics.jl @@ -13,6 +13,15 @@ function MA.mutable_copy(func::MOI.ScalarAffineFunction) ] return MOI.ScalarAffineFunction(terms, MA.copy_if_mutable(func.constant)) end + +function MA.mutable_copy(func::MOI.ScalarAffineColumnFunction{T}) where {T} + coefficients = [ + MA.copy_if_mutable(c) for c in func.coefficients + ] + variable_indices = copy(func.variable_indices) + return MOI.ScalarAffineColumnFunction{T}(coefficients, variable_indices, MA.copy_if_mutable(func.constant)) +end + function MA.mutable_copy(func::MOI.ScalarQuadraticFunction) affine_terms = [ MOI.ScalarAffineTerm( diff --git a/src/functions.jl b/src/functions.jl index c5cb64c440..6b9df18ba3 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -71,10 +71,23 @@ struct ScalarAffineTerm{T} variable_index::VariableIndex end +""" + AbstractScalarAffineFunction{T} + +Abstract type for functions representing ``a^T x + b``. +The concrete implementations are [`ScalarAffineTerm`](@ref) +which stores ``a^T x`` as a vector of `ScalarAffineTerm` +and [`ScalarAffineColumnFunction`](@ref) storing `a` and `x` +in separate terms. +""" +abstract type AbstractScalarAffineFunction{T} <: AbstractScalarFunction +end + # Note: ScalarAffineFunction is mutable because its `constant` field is likely of an immutable # type, while its `terms` field is of a mutable type, meaning that creating a `ScalarAffineFunction` # allocates, and it is desirable to provide a zero-allocation option for working with # ScalarAffineFunctions. See https://github.com/jump-dev/MathOptInterface.jl/pull/343. + """ ScalarAffineFunction{T}(terms, constant) @@ -86,11 +99,47 @@ The scalar-valued affine function ``a^T x + b``, where: Duplicate variable indices in `terms` are accepted, and the corresponding coefficients are summed together. """ -mutable struct ScalarAffineFunction{T} <: AbstractScalarFunction +mutable struct ScalarAffineFunction{T} <: AbstractScalarAffineFunction{T} terms::Vector{ScalarAffineTerm{T}} constant::T end +""" + ScalarAffineColumnFunction{T} + +Represents a scalar-valued affine function ``a^T x + b``. +Unlike `ScalarAffineFunction`, it maintains the coefficients and variables in separate vectors. +""" +mutable struct ScalarAffineColumnFunction{T} <: AbstractScalarAffineFunction{T} + coefficients::Vector{T} + variable_indices::Vector{VariableIndex} + constant::T +end + +function ScalarAffineColumnFunction(terms::AbstractVector{ScalarAffineTerm{T1}}, constant::T2) where {T1, T2} + T = promote_type(T1, T2) + coefficients = Vector{T}(undef, length(terms)) + v_indices = Vector{VariableIndex}(undef, length(terms)) + for idx in eachindex(terms) + coefficients[idx] = terms[idx].coefficient + v_indices[idx] = terms[idx].variable_index + end + return ScalarAffineColumnFunction{T}(coefficients, v_indices, constant) +end + +scalar_terms(func::ScalarAffineFunction) = func.terms +function scalar_terms(func::ScalarAffineColumnFunction) + return [ + ScalarAffineTerm(coef, vi) for (coef, vi) in zip(func.coefficients, func.variable_indices) + ] +end + +coefficients(func::ScalarAffineFunction) = [term.coefficient for term in func.terms] +variable_indices(func::ScalarAffineFunction) = [term.variable_index for term in func.terms] + +coefficients(func::ScalarAffineColumnFunction) = func.coefficients +variable_indices(func::ScalarAffineColumnFunction) = func.variable_indices + """ struct VectorAffineTerm{T} output_index::Int64 @@ -307,11 +356,10 @@ function dict_compare(d1::Dict, d2::Dict{<:Any,T}, compare::Function) where {T} end # Build a dictionary where the duplicate keys are summed -function sum_dict(kvs::Vector{Pair{K,V}}) where {K,V} +function sum_dict(kvs::Union{Vector{Pair{K,V}}, Iterators.Zip{Tuple{Vector{K},Vector{V}}}}) where {K,V} d = Dict{K,V}() - for kv in kvs - key = kv.first - d[key] = kv.second + Base.get(d, key, zero(V)) + for (key, v) in kvs + d[key] = v + Base.get(d, key, zero(V)) end return d end @@ -374,6 +422,10 @@ function _dicts(f::Union{ScalarAffineFunction,VectorAffineFunction}) return (sum_dict(term_pair.(f.terms)),) end +function _dicts(f::ScalarAffineColumnFunction) + return (sum_dict(zip(f.variable_indices, f.coefficients)),) +end + function _dicts(f::Union{ScalarQuadraticFunction,VectorQuadraticFunction}) return ( sum_dict(term_pair.(f.affine_terms)), @@ -386,7 +438,7 @@ end Returns the constant term of the scalar function """ -constant(f::Union{ScalarAffineFunction,ScalarQuadraticFunction}) = f.constant +constant(f::Union{AbstractScalarAffineFunction,ScalarQuadraticFunction}) = f.constant """ constant(f::Union{VectorAffineFunction, VectorQuadraticFunction}) @@ -401,13 +453,13 @@ function Base.isapprox( kwargs..., ) where { F<:Union{ - ScalarAffineFunction, + AbstractScalarAffineFunction, ScalarQuadraticFunction, VectorAffineFunction, VectorQuadraticFunction, }, G<:Union{ - ScalarAffineFunction, + AbstractScalarAffineFunction, ScalarQuadraticFunction, VectorAffineFunction, VectorQuadraticFunction, @@ -421,7 +473,7 @@ function Base.isapprox( end function constant( - f::Union{ScalarAffineFunction,ScalarQuadraticFunction}, + f::Union{AbstractScalarAffineFunction,ScalarQuadraticFunction}, T::DataType, ) return constant(f) @@ -466,6 +518,14 @@ function Base.copy( return F(copy(func.terms), copy(constant(func))) end +function Base.copy(func::ScalarAffineColumnFunction) + return ScalarAffineColumnFunction( + copy(func.coefficients), + copy(func.variable_indices), + copy(func.constant), + ) +end + """ copy(func::Union{ScalarQuadraticFunction, VectorQuadraticFunction}) @@ -487,6 +547,15 @@ end function ScalarAffineFunction{T}(f::SingleVariable) where {T} return ScalarAffineFunction([ScalarAffineTerm(one(T), f.variable)], zero(T)) end + +function ScalarAffineColumnFunction{T}(f::SingleVariable) where {T} + return ScalarAffineColumnFunction{T}( + [one(T)], + [f.variable], + zero(T), + ) +end + # VectorOfVariables -> VectorAffineFunction function VectorAffineFunction{T}(f::VectorOfVariables) where {T} n = length(f.variables) @@ -512,6 +581,19 @@ function Base.convert(::Type{SingleVariable}, f::ScalarAffineFunction) return SingleVariable(f.terms[1].variable_index) end +function Base.convert(::Type{SingleVariable}, f::ScalarAffineColumnFunction) + # just one of the two vectors checked + # since must remain consistent + if ( + !iszero(f.constant) || + !isone(length(f.coefficients)) || + !isone(f.coefficients[1]) + ) + throw(InexactError(:convert, SingleVariable, f)) + end + return SingleVariable(f.variable_indices[1]) +end + function Base.convert( ::Type{SingleVariable}, f::ScalarQuadraticFunction{T}, @@ -520,15 +602,15 @@ function Base.convert( end # Conversion to ScalarAffineFunction -function Base.convert(::Type{ScalarAffineFunction{T}}, α::T) where {T} - return ScalarAffineFunction{T}(ScalarAffineTerm{T}[], α) +function Base.convert(::Type{SF}, α::T) where {T, SF <: AbstractScalarAffineFunction{T}} + return SF(ScalarAffineTerm{T}[], α) end function Base.convert( - ::Type{ScalarAffineFunction{T}}, + ::Type{SF}, f::SingleVariable, -) where {T} - return ScalarAffineFunction{T}(f) +) where {T, SF <: AbstractScalarAffineFunction{T}} + return SF(f) end function Base.convert( @@ -546,27 +628,27 @@ function Base.convert( end function Base.convert( - ::Type{ScalarAffineFunction{T}}, - f::ScalarAffineFunction{T}, -) where {T} + ::Type{SF}, + f::SF, +) where {T, SF <: AbstractScalarAffineFunction{T}} return f end function Base.convert( - ::Type{ScalarAffineFunction{T}}, - f::ScalarAffineFunction, -) where {T} - return ScalarAffineFunction{T}(f.terms, f.constant) + ::Type{SF}, + f::AbstractScalarAffineFunction, +) where {T, SF <: Union{ScalarAffineFunction{T}, ScalarAffineColumnFunction{T}}} + return SF(f.terms, f.constant) end function Base.convert( - ::Type{ScalarAffineFunction{T}}, + ::Type{SF}, f::ScalarQuadraticFunction{T}, -) where {T} +) where {T, SF <: Union{ScalarAffineFunction{T}, ScalarAffineColumnFunction{T}}} if !Base.isempty(f.quadratic_terms) throw(InexactError(:convert, ScalarAffineFunction{T}, f)) end - return ScalarAffineFunction{T}(f.affine_terms, f.constant) + return SF(f.affine_terms, f.constant) end # Conversion to ScalarQuadraticFunction From ddabe1dd8109ba7bf9aca5c0ebe3b92e97ea55bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Tue, 16 Feb 2021 00:34:39 +0100 Subject: [PATCH 02/15] remove union --- src/functions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions.jl b/src/functions.jl index 6b9df18ba3..aeb7cf3bf6 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -637,7 +637,7 @@ end function Base.convert( ::Type{SF}, f::AbstractScalarAffineFunction, -) where {T, SF <: Union{ScalarAffineFunction{T}, ScalarAffineColumnFunction{T}}} +) where {T, SF <: AbstractScalarAffineFunction} return SF(f.terms, f.constant) end From df344bae7f83421c65dc7e79a49e5c41065dc58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Tue, 16 Feb 2021 00:36:07 +0100 Subject: [PATCH 03/15] remove union for quadratic conversion --- src/functions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions.jl b/src/functions.jl index aeb7cf3bf6..ddb2594655 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -644,7 +644,7 @@ end function Base.convert( ::Type{SF}, f::ScalarQuadraticFunction{T}, -) where {T, SF <: Union{ScalarAffineFunction{T}, ScalarAffineColumnFunction{T}}} +) where {T, SF <: AbstractScalarAffineFunction{T}} if !Base.isempty(f.quadratic_terms) throw(InexactError(:convert, ScalarAffineFunction{T}, f)) end From 955724868df5cf7ebb4b36977febb11f46dc42fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Tue, 16 Feb 2021 23:05:16 +0100 Subject: [PATCH 04/15] fix methods --- src/Utilities/Utilities.jl | 1 + src/Utilities/constraints.jl | 6 +- src/Utilities/functions.jl | 104 +++++++++++++++++++++++++++-------- test/Utilities/functions.jl | 30 ++++++++++ 4 files changed, 116 insertions(+), 25 deletions(-) diff --git a/src/Utilities/Utilities.jl b/src/Utilities/Utilities.jl index c52d20e5ec..cbbb0a2676 100644 --- a/src/Utilities/Utilities.jl +++ b/src/Utilities/Utilities.jl @@ -14,6 +14,7 @@ const MOIU = MOI.Utilities # used in macro const SVF = MOI.SingleVariable const VVF = MOI.VectorOfVariables const SAF{T} = MOI.ScalarAffineFunction{T} +const SACF{T} = MOI.ScalarAffineColumnFunction{T} const VAF{T} = MOI.VectorAffineFunction{T} const SQF{T} = MOI.ScalarQuadraticFunction{T} const VQF{T} = MOI.VectorQuadraticFunction{T} diff --git a/src/Utilities/constraints.jl b/src/Utilities/constraints.jl index f20936c31b..e9e23646e4 100644 --- a/src/Utilities/constraints.jl +++ b/src/Utilities/constraints.jl @@ -15,7 +15,7 @@ function normalize_and_add_constraint( func::MOI.AbstractScalarFunction, set::MOI.AbstractScalarSet; allow_modify_function::Bool = false, -) where {T} +) return MOI.add_constraint( model, normalize_constant( @@ -45,11 +45,11 @@ function normalize_constant( return func, set end function normalize_constant( - func::Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}}, + func::Union{MOI.AbstractScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}}, set::MOI.AbstractScalarSet; allow_modify_function::Bool = false, ) where {T} - set = shift_constant(set, -func.constant) + set = shift_constant(set, -MOI.constant(func)) if !allow_modify_function func = copy(func) end diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index bebb872752..1da8754a04 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -14,9 +14,14 @@ function. function eval_variables end eval_variables(varval::Function, f::SVF) = varval(f.variable) eval_variables(varval::Function, f::VVF) = varval.(f.variables) + function eval_variables(varval::Function, f::SAF) return mapreduce(t -> eval_term(varval, t), +, f.terms, init = f.constant) end +function eval_variables(varval::Function, f::SACF) + return sum(c * varval(v) for (c, v) in zip(f.coefficients, f.variable_indices)) +end + function eval_variables(varval::Function, f::VAF) out = copy(f.constants) for t in f.terms @@ -133,9 +138,14 @@ end function map_indices(index_map::Function, f::MOI.VectorOfVariables) return MOI.VectorOfVariables(index_map.(f.variables)) end -function map_indices(index_map::Function, f::Union{SAF,VAF}) - return typeof(f)(map_indices.(index_map, f.terms), MOI.constant(f)) +function map_indices(index_map::Function, f::F) where {F <: VAF} + return F(map_indices.(index_map, f.terms), MOI.constant(f)) +end + +function map_indices(index_map::Function, f::F) where {F <: MOI.AbstractScalarAffineFunction} + return F(map_indices.(index_map, MOI.scalar_terms(f)), MOI.constant(f)) end + function map_indices(index_map::Function, f::Union{SQF,VQF}) lin = map_indices.(index_map, f.affine_terms) quad = map_indices.(index_map, f.quadratic_terms) @@ -226,10 +236,10 @@ function substitute_variables( end function substitute_variables( variable_map::Function, - func::MOI.ScalarAffineFunction{T}, -) where {T} - g = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{T}[], MOI.constant(func)) - for term in func.terms + func::FT, +) where {T, FT <: MOI.AbstractScalarAffineFunction{T}} + g = FT(MOI.ScalarAffineTerm{T}[], MOI.constant(func)) + for term in MOI.scalar_terms(func) operate!( +, T, @@ -301,7 +311,7 @@ function substitute_variables( end # Vector of constants -constant_vector(f::Union{SAF,SQF}) = [f.constant] +constant_vector(f::Union{SAF,SQF,SACF}) = [f.constant] constant_vector(f::Union{VAF,VQF}) = f.constants # Implements iterator interface @@ -567,6 +577,29 @@ function canonicalize!(f::Union{SAF,VAF}) return f end +function canonicalize!(f::SACF) + delete_indices = BitSet() + for i in 1:length(f.variable_indices)-1 + if iszero(f.coefficients[i]) + push!(delete_indices, i) + continue + end + for j in i+1:length(f.variable_indices) + if j in delete_indices + continue + end + if f.variable_indices[i] == f.variable_indices[j] + f.coefficients[i] += f.coefficients[j] + f.coefficients[j] = 0 + push!(delete_indices, j) + end + end + end + deleteat!(f.coefficients, delete_indices) + deleteat!(f.variable_indices, delete_indices) + return f +end + """ canonicalize!(f::Union{ScalarQuadraticFunction, VectorQuadraticFunction}) @@ -676,6 +709,9 @@ function all_coefficients end function all_coefficients(p::Function, f::MOI.ScalarAffineFunction) return p(f.constant) && all(t -> p(MOI.coefficient(t)), f.terms) end +function all_coefficients(p::Function, f::MOI.ScalarAffineColumnFunction) + return all(p, f.coefficients) +end function all_coefficients(p::Function, f::MOI.ScalarQuadraticFunction) return p(f.constant) && all(t -> p(MOI.coefficient(t)), f.affine_terms) && @@ -708,20 +744,22 @@ function isapprox_zero(f::MOI.AbstractFunction, tol) end _is_constant(f::MOI.ScalarAffineFunction) = isempty(f.terms) +_is_constant(f::MOI.ScalarAffineColumnFunction) = isempty(f.variable_indices) + function _is_constant(f::MOI.ScalarQuadraticFunction) return isempty(f.affine_terms) && isempty(f.quadratic_terms) end Base.iszero(::MOI.SingleVariable) = false function Base.iszero( - f::Union{MOI.ScalarAffineFunction,MOI.ScalarQuadraticFunction}, + f::Union{MOI.AbstractScalarAffineFunction,MOI.ScalarQuadraticFunction}, ) return iszero(MOI.constant(f)) && _is_constant(canonical(f)) end Base.isone(::MOI.SingleVariable) = false function Base.isone( - f::Union{MOI.ScalarAffineFunction,MOI.ScalarQuadraticFunction}, + f::Union{MOI.AbstractScalarAffineFunction,MOI.ScalarQuadraticFunction}, ) return isone(MOI.constant(f)) && _is_constant(canonical(f)) end @@ -816,6 +854,14 @@ function filter_variables( ) return typeof(f)(_filter_variables(keep, f.terms), MOI.constant(f)) end +function filter_variables(keep::Function, f::MOI.ScalarAffineColumnFunction) + keep_filter = keep.(f.variable_indices) + typeof(f)( + f.coefficients[keep_filter], + f.variable_indices[keep_filter], + MOI.constant(f), + ) +end function filter_variables( keep, f::Union{MOI.ScalarQuadraticFunction,MOI.VectorQuadraticFunction}, @@ -849,8 +895,8 @@ end Return a new function `f` modified according to `change`. """ -function modify_function(f::SAF, change::MOI.ScalarConstantChange) - return SAF(f.terms, change.new_constant) +function modify_function(f::MOI.AbstractScalarAffineFunction, change::MOI.ScalarConstantChange) + return SAF(MOI.scalar_terms(f), change.new_constant) end function modify_function(f::VAF, change::MOI.VectorConstantChange) return VAF(f.terms, change.new_constant) @@ -891,11 +937,11 @@ function _modifycoefficient( end function modify_function( - f::MOI.ScalarAffineFunction{T}, + f::F, change::MOI.ScalarCoefficientChange{T}, -) where {T} - terms = _modifycoefficient(f.terms, change.variable, change.new_coefficient) - return MOI.ScalarAffineFunction(terms, f.constant) +) where {T, F <: MOI.AbstractScalarAffineFunction{T}} + terms = _modifycoefficient(MOI.scalar_terms(f), change.variable, change.new_coefficient) + return F(terms, MOI.constant(f)) end function modify_function( @@ -1279,7 +1325,7 @@ end # Functions convertible to a ScalarAffineFunction const ScalarAffineLike{T} = - Union{T,MOI.SingleVariable,MOI.ScalarAffineFunction{T}} + Union{T,MOI.SingleVariable,MOI.AbstractScalarAffineFunction{T}} # Functions convertible to a ScalarQuadraticFunction const ScalarQuadraticLike{T} = Union{ScalarAffineLike{T},MOI.ScalarQuadraticFunction{T}} @@ -2155,7 +2201,7 @@ function Base.:*(f::TypedLike, g::Bool) end Base.:*(f::Bool, g::TypedLike) = g * f -function Base.:^(func::MOI.ScalarAffineFunction{T}, p::Integer) where {T} +function Base.:^(func::MOI.AbstractScalarAffineFunction{T}, p::Integer) where {T} if iszero(p) return one(MOI.ScalarQuadraticFunction{T}) elseif isone(p) @@ -2195,7 +2241,7 @@ LinearAlgebra.symmetric(f::ScalarLike, ::Symbol) = f function promote_operation( ::typeof(/), ::Type{T}, - ::Type{<:Union{MOI.SingleVariable,MOI.ScalarAffineFunction{T}}}, + ::Type{<:Union{MOI.SingleVariable,MOI.AbstractScalarAffineFunction{T}}}, ::Type{T}, ) where {T} return MOI.ScalarAffineFunction{T} @@ -2391,13 +2437,17 @@ number_of_affine_terms(::Type, f::VVF) = length(f.variables) function number_of_affine_terms(::Type{T}, f::Union{SAF{T},VAF{T}}) where {T} return length(f.terms) end +function number_of_affine_terms(::Type{T}, f::SACF{T}) where {T} + return length(f.variable_indices) +end + function number_of_affine_terms(::Type{T}, f::Union{SQF{T},VQF{T}}) where {T} return length(f.affine_terms) end function number_of_quadratic_terms( ::Type{T}, - ::Union{T,SVF,VVF,SAF{T},VAF{T}}, + ::Union{T,SVF,VVF,SAF{T},SACF{T},VAF{T}}, ) where {T} return 0 end @@ -2455,6 +2505,16 @@ function fill_terms( n = number_of_affine_terms(T, func) return terms[offset.+(1:n)] .= offset_term.(func.terms, output_offset) end +function fill_terms( + terms::Vector{MOI.VectorAffineTerm{T}}, + offset::Int, + output_offset::Int, + func::Union{SACF{T}}, +) where {T} + n = number_of_affine_terms(T, func) + return terms[offset.+(1:n)] .= offset_term.(MOI.scalar_terms(func), output_offset) +end + function fill_terms( terms::Vector{MOI.VectorAffineTerm{T}}, offset::Int, @@ -2503,9 +2563,9 @@ function fill_constant( constant::Vector{T}, offset::Int, output_offset::Int, - func::Union{SAF{T},SQF{T}}, + func::Union{SAF{T},SACF{T},SQF{T}}, ) where {T} - return constant[offset+1] = func.constant + return constant[offset+1] = MOI.constant(func) end function fill_constant( constant::Vector{T}, @@ -2534,7 +2594,7 @@ end Returns the vector of scalar affine functions in the form of a `MOI.VectorAffineFunction{T}`. """ -function vectorize(funcs::AbstractVector{MOI.ScalarAffineFunction{T}}) where {T} +function vectorize(funcs::AbstractVector{<:MOI.AbstractScalarAffineFunction{T}}) where {T} nterms = mapreduce(func -> number_of_affine_terms(T, func), +, funcs, init = 0) out_dim = mapreduce(func -> output_dim(T, func), +, funcs, init = 0) diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index 40876c57a3..98eb848c84 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -52,6 +52,36 @@ end @test MOI.output_dimension(quad) == 0 @test quad isa MOI.VectorQuadraticFunction{Int} end + @testset "vectorize pure column affine" begin + g1 = MOI.ScalarAffineColumnFunction([MOI.ScalarAffineTerm(2, x)], 3) + g2 = MOI.ScalarAffineColumnFunction(Int[], MOI.VariableIndex[], 1) + g3 = MOI.ScalarAffineColumnFunction([5], [y], 4) + @test g ≈ MOIU.vectorize([g1, g2, g3]) + vov = MOIU.vectorize(MOI.SingleVariable[]) + @test MOI.output_dimension(vov) == 0 + @test vov isa MOI.VectorOfVariables + aff = MOIU.vectorize(MOI.ScalarAffineColumnFunction{Int}[]) + @test MOI.output_dimension(aff) == 0 + @test aff isa MOI.VectorAffineFunction{Int} + quad = MOIU.vectorize(MOI.ScalarQuadraticFunction{Int}[]) + @test MOI.output_dimension(quad) == 0 + @test quad isa MOI.VectorQuadraticFunction{Int} + end + @testset "vectorize mixed affine functions" begin + g1 = MOI.ScalarAffineColumnFunction([MOI.ScalarAffineTerm(2, x)], 3) + g2 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Int}[], 1) + g3 = MOI.ScalarAffineColumnFunction([5], [y], 4) + @test g ≈ MOIU.vectorize([g1, g2, g3]) + vov = MOIU.vectorize(MOI.SingleVariable[]) + @test MOI.output_dimension(vov) == 0 + @test vov isa MOI.VectorOfVariables + aff = MOIU.vectorize(MOI.ScalarAffineColumnFunction{Int}[]) + @test MOI.output_dimension(aff) == 0 + @test aff isa MOI.VectorAffineFunction{Int} + quad = MOIU.vectorize(MOI.ScalarQuadraticFunction{Int}[]) + @test MOI.output_dimension(quad) == 0 + @test quad isa MOI.VectorQuadraticFunction{Int} + end @testset "operate vcat" begin v = MOI.VectorOfVariables([y, w]) wf = MOI.SingleVariable(w) From e177ef40f3e42e61071fbc6e7478f5efb6908e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 4 Mar 2021 21:07:16 +0100 Subject: [PATCH 05/15] begin replacement --- src/Utilities/Utilities.jl | 3 +- src/Utilities/constraints.jl | 2 +- src/Utilities/functions.jl | 53 +++-------- src/Utilities/mutable_arithmetics.jl | 14 +-- src/functions.jl | 129 ++++++++++++--------------- 5 files changed, 76 insertions(+), 125 deletions(-) diff --git a/src/Utilities/Utilities.jl b/src/Utilities/Utilities.jl index cbbb0a2676..352f130509 100644 --- a/src/Utilities/Utilities.jl +++ b/src/Utilities/Utilities.jl @@ -13,8 +13,7 @@ const MOIU = MOI.Utilities # used in macro const SVF = MOI.SingleVariable const VVF = MOI.VectorOfVariables -const SAF{T} = MOI.ScalarAffineFunction{T} -const SACF{T} = MOI.ScalarAffineColumnFunction{T} +const SAF{T} = MOI.GenericScalarAffineFunction{T} const VAF{T} = MOI.VectorAffineFunction{T} const SQF{T} = MOI.ScalarQuadraticFunction{T} const VQF{T} = MOI.VectorQuadraticFunction{T} diff --git a/src/Utilities/constraints.jl b/src/Utilities/constraints.jl index e9e23646e4..19012e533c 100644 --- a/src/Utilities/constraints.jl +++ b/src/Utilities/constraints.jl @@ -45,7 +45,7 @@ function normalize_constant( return func, set end function normalize_constant( - func::Union{MOI.AbstractScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}}, + func::Union{MOI.GenericScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}}, set::MOI.AbstractScalarSet; allow_modify_function::Bool = false, ) where {T} diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index 1da8754a04..6aea11b6ce 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -142,7 +142,7 @@ function map_indices(index_map::Function, f::F) where {F <: VAF} return F(map_indices.(index_map, f.terms), MOI.constant(f)) end -function map_indices(index_map::Function, f::F) where {F <: MOI.AbstractScalarAffineFunction} +function map_indices(index_map::Function, f::F) where {F <: MOI.GenericScalarAffineFunction} return F(map_indices.(index_map, MOI.scalar_terms(f)), MOI.constant(f)) end @@ -237,7 +237,7 @@ end function substitute_variables( variable_map::Function, func::FT, -) where {T, FT <: MOI.AbstractScalarAffineFunction{T}} +) where {T, FT <: MOI.GenericScalarAffineFunction{T}} g = FT(MOI.ScalarAffineTerm{T}[], MOI.constant(func)) for term in MOI.scalar_terms(func) operate!( @@ -709,9 +709,6 @@ function all_coefficients end function all_coefficients(p::Function, f::MOI.ScalarAffineFunction) return p(f.constant) && all(t -> p(MOI.coefficient(t)), f.terms) end -function all_coefficients(p::Function, f::MOI.ScalarAffineColumnFunction) - return all(p, f.coefficients) -end function all_coefficients(p::Function, f::MOI.ScalarQuadraticFunction) return p(f.constant) && all(t -> p(MOI.coefficient(t)), f.affine_terms) && @@ -743,8 +740,7 @@ function isapprox_zero(f::MOI.AbstractFunction, tol) return all_coefficients(α -> isapprox_zero(α, tol), f) end -_is_constant(f::MOI.ScalarAffineFunction) = isempty(f.terms) -_is_constant(f::MOI.ScalarAffineColumnFunction) = isempty(f.variable_indices) +_is_constant(f::MOI.GenericScalarAffineFunction) = isempty(f.terms) function _is_constant(f::MOI.ScalarQuadraticFunction) return isempty(f.affine_terms) && isempty(f.quadratic_terms) @@ -752,14 +748,14 @@ end Base.iszero(::MOI.SingleVariable) = false function Base.iszero( - f::Union{MOI.AbstractScalarAffineFunction,MOI.ScalarQuadraticFunction}, + f::Union{MOI.GenericScalarAffineFunction,MOI.ScalarQuadraticFunction}, ) return iszero(MOI.constant(f)) && _is_constant(canonical(f)) end Base.isone(::MOI.SingleVariable) = false function Base.isone( - f::Union{MOI.AbstractScalarAffineFunction,MOI.ScalarQuadraticFunction}, + f::Union{MOI.GenericScalarAffineFunction,MOI.ScalarQuadraticFunction}, ) return isone(MOI.constant(f)) && _is_constant(canonical(f)) end @@ -854,14 +850,6 @@ function filter_variables( ) return typeof(f)(_filter_variables(keep, f.terms), MOI.constant(f)) end -function filter_variables(keep::Function, f::MOI.ScalarAffineColumnFunction) - keep_filter = keep.(f.variable_indices) - typeof(f)( - f.coefficients[keep_filter], - f.variable_indices[keep_filter], - MOI.constant(f), - ) -end function filter_variables( keep, f::Union{MOI.ScalarQuadraticFunction,MOI.VectorQuadraticFunction}, @@ -895,7 +883,7 @@ end Return a new function `f` modified according to `change`. """ -function modify_function(f::MOI.AbstractScalarAffineFunction, change::MOI.ScalarConstantChange) +function modify_function(f::MOI.GenericScalarAffineFunction, change::MOI.ScalarConstantChange) return SAF(MOI.scalar_terms(f), change.new_constant) end function modify_function(f::VAF, change::MOI.VectorConstantChange) @@ -939,7 +927,7 @@ end function modify_function( f::F, change::MOI.ScalarCoefficientChange{T}, -) where {T, F <: MOI.AbstractScalarAffineFunction{T}} +) where {T, F <: MOI.GenericScalarAffineFunction{T}} terms = _modifycoefficient(MOI.scalar_terms(f), change.variable, change.new_coefficient) return F(terms, MOI.constant(f)) end @@ -1325,7 +1313,7 @@ end # Functions convertible to a ScalarAffineFunction const ScalarAffineLike{T} = - Union{T,MOI.SingleVariable,MOI.AbstractScalarAffineFunction{T}} + Union{T,MOI.SingleVariable,MOI.GenericScalarAffineFunction{T}} # Functions convertible to a ScalarQuadraticFunction const ScalarQuadraticLike{T} = Union{ScalarAffineLike{T},MOI.ScalarQuadraticFunction{T}} @@ -1334,7 +1322,7 @@ const ScalarQuadraticLike{T} = # `+(::SingleVariable, ::Any)` which should rather be # `+(::SingleVariable, ::Number)`. const TypedScalarLike{T} = - Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} + Union{MOI.GenericScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} # Used for overloading Base operator functions so `T` is not in the union to # avoid overloading e.g. `+(::Float64, ::Float64)` const ScalarLike{T} = Union{MOI.SingleVariable,TypedScalarLike{T}} @@ -2201,7 +2189,7 @@ function Base.:*(f::TypedLike, g::Bool) end Base.:*(f::Bool, g::TypedLike) = g * f -function Base.:^(func::MOI.AbstractScalarAffineFunction{T}, p::Integer) where {T} +function Base.:^(func::MOI.GenericScalarAffineFunction{T}, p::Integer) where {T} if iszero(p) return one(MOI.ScalarQuadraticFunction{T}) elseif isone(p) @@ -2241,7 +2229,7 @@ LinearAlgebra.symmetric(f::ScalarLike, ::Symbol) = f function promote_operation( ::typeof(/), ::Type{T}, - ::Type{<:Union{MOI.SingleVariable,MOI.AbstractScalarAffineFunction{T}}}, + ::Type{<:Union{MOI.SingleVariable,MOI.GenericScalarAffineFunction{T}}}, ::Type{T}, ) where {T} return MOI.ScalarAffineFunction{T} @@ -2437,17 +2425,13 @@ number_of_affine_terms(::Type, f::VVF) = length(f.variables) function number_of_affine_terms(::Type{T}, f::Union{SAF{T},VAF{T}}) where {T} return length(f.terms) end -function number_of_affine_terms(::Type{T}, f::SACF{T}) where {T} - return length(f.variable_indices) -end - function number_of_affine_terms(::Type{T}, f::Union{SQF{T},VQF{T}}) where {T} return length(f.affine_terms) end function number_of_quadratic_terms( ::Type{T}, - ::Union{T,SVF,VVF,SAF{T},SACF{T},VAF{T}}, + ::Union{T,SVF,VVF,SAF{T},VAF{T}}, ) where {T} return 0 end @@ -2505,15 +2489,6 @@ function fill_terms( n = number_of_affine_terms(T, func) return terms[offset.+(1:n)] .= offset_term.(func.terms, output_offset) end -function fill_terms( - terms::Vector{MOI.VectorAffineTerm{T}}, - offset::Int, - output_offset::Int, - func::Union{SACF{T}}, -) where {T} - n = number_of_affine_terms(T, func) - return terms[offset.+(1:n)] .= offset_term.(MOI.scalar_terms(func), output_offset) -end function fill_terms( terms::Vector{MOI.VectorAffineTerm{T}}, @@ -2563,7 +2538,7 @@ function fill_constant( constant::Vector{T}, offset::Int, output_offset::Int, - func::Union{SAF{T},SACF{T},SQF{T}}, + func::Union{SAF{T},SQF{T}}, ) where {T} return constant[offset+1] = MOI.constant(func) end @@ -2594,7 +2569,7 @@ end Returns the vector of scalar affine functions in the form of a `MOI.VectorAffineFunction{T}`. """ -function vectorize(funcs::AbstractVector{<:MOI.AbstractScalarAffineFunction{T}}) where {T} +function vectorize(funcs::AbstractVector{<:MOI.GenericScalarAffineFunction{T}}) where {T} nterms = mapreduce(func -> number_of_affine_terms(T, func), +, funcs, init = 0) out_dim = mapreduce(func -> output_dim(T, func), +, funcs, init = 0) diff --git a/src/Utilities/mutable_arithmetics.jl b/src/Utilities/mutable_arithmetics.jl index c9b93de203..291e162356 100644 --- a/src/Utilities/mutable_arithmetics.jl +++ b/src/Utilities/mutable_arithmetics.jl @@ -4,22 +4,14 @@ MA.mutability(::Type{<:TypedLike}) = MA.IsMutable() -function MA.mutable_copy(func::MOI.ScalarAffineFunction) +function MA.mutable_copy(func::F) where {F <: MOI.GenericScalarAffineFunction} terms = [ MOI.ScalarAffineTerm( MA.copy_if_mutable(t.coefficient), t.variable_index, ) for t in func.terms ] - return MOI.ScalarAffineFunction(terms, MA.copy_if_mutable(func.constant)) -end - -function MA.mutable_copy(func::MOI.ScalarAffineColumnFunction{T}) where {T} - coefficients = [ - MA.copy_if_mutable(c) for c in func.coefficients - ] - variable_indices = copy(func.variable_indices) - return MOI.ScalarAffineColumnFunction{T}(coefficients, variable_indices, MA.copy_if_mutable(func.constant)) + return F(terms, MA.copy_if_mutable(func.constant)) end function MA.mutable_copy(func::MOI.ScalarQuadraticFunction) @@ -85,7 +77,7 @@ function MA.promote_operation( op::PROMOTE_IMPLEMENTED_OP, F::Type{<:ScalarLike{T}}, G::Type{<:ScalarLike{T}}, -) where {T,N} +) where {T} return promote_operation(op, T, F, G) end function MA.promote_operation( diff --git a/src/functions.jl b/src/functions.jl index ddb2594655..a7cabaff01 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -71,23 +71,16 @@ struct ScalarAffineTerm{T} variable_index::VariableIndex end -""" - AbstractScalarAffineFunction{T} - -Abstract type for functions representing ``a^T x + b``. -The concrete implementations are [`ScalarAffineTerm`](@ref) -which stores ``a^T x`` as a vector of `ScalarAffineTerm` -and [`ScalarAffineColumnFunction`](@ref) storing `a` and `x` -in separate terms. -""" -abstract type AbstractScalarAffineFunction{T} <: AbstractScalarFunction -end - -# Note: ScalarAffineFunction is mutable because its `constant` field is likely of an immutable +# Note: GenericScalarAffineFunction is mutable because its `constant` field is likely of an immutable # type, while its `terms` field is of a mutable type, meaning that creating a `ScalarAffineFunction` # allocates, and it is desirable to provide a zero-allocation option for working with # ScalarAffineFunctions. See https://github.com/jump-dev/MathOptInterface.jl/pull/343. +mutable struct GenericScalarAffineFunction{T, VT<:AbstractVector{ScalarAffineTerm{T}}} + terms::VT + constant::T +end + """ ScalarAffineFunction{T}(terms, constant) @@ -99,46 +92,50 @@ The scalar-valued affine function ``a^T x + b``, where: Duplicate variable indices in `terms` are accepted, and the corresponding coefficients are summed together. """ -mutable struct ScalarAffineFunction{T} <: AbstractScalarAffineFunction{T} - terms::Vector{ScalarAffineTerm{T}} - constant::T -end +const ScalarAffineFunction{T} = GenericScalarAffineFunction{T, Vector{ScalarAffineTerm{T}}} -""" - ScalarAffineColumnFunction{T} -Represents a scalar-valued affine function ``a^T x + b``. -Unlike `ScalarAffineFunction`, it maintains the coefficients and variables in separate vectors. -""" -mutable struct ScalarAffineColumnFunction{T} <: AbstractScalarAffineFunction{T} +struct ZipTermVector{T} <: AbstractVector{ScalarAffineTerm{T}} coefficients::Vector{T} - variable_indices::Vector{VariableIndex} - constant::T + variables::Vector{VariableIndex} end +const ZippedAffineFunction{T} = GenericScalarAffineFunction{T, ZipTermVector{T}} -function ScalarAffineColumnFunction(terms::AbstractVector{ScalarAffineTerm{T1}}, constant::T2) where {T1, T2} - T = promote_type(T1, T2) - coefficients = Vector{T}(undef, length(terms)) - v_indices = Vector{VariableIndex}(undef, length(terms)) - for idx in eachindex(terms) - coefficients[idx] = terms[idx].coefficient - v_indices[idx] = terms[idx].variable_index - end - return ScalarAffineColumnFunction{T}(coefficients, v_indices, constant) +Base.getindex(zv::ZipTermVector, i::Integer) = ScalarAffineTerm(zv.coefficients[i], zv.variables[i]) +Base.size(zv::ZipTermVector) = size(zv.coefficients) + +function Base.push!(zv::ZipTermVector, term::ScalarAffineTerm) + push!(zv.coefficients, term.coefficient) + push!(zv.variables, term.variables) + return zv +end + +function Base.empty!(zv::ZipTermVector) + empty!(zv.coefficients) + empty!(zv.variables) + return zv +end + +function Base.setindex!(zv::ZipTermVector, term::ScalarAffineTerm, idx::Integer) + zv.coefficients[idx] = term.coefficient + zv.variables[idx] = term.variable_index + return term end scalar_terms(func::ScalarAffineFunction) = func.terms -function scalar_terms(func::ScalarAffineColumnFunction) + +function scalar_terms(func::ZippedAffineFunction) return [ - ScalarAffineTerm(coef, vi) for (coef, vi) in zip(func.coefficients, func.variable_indices) + ScalarAffineTerm(func.terms.coefficients[idx], func.terms.variables[idx]) + for idx in eachindex(func.terms) ] end coefficients(func::ScalarAffineFunction) = [term.coefficient for term in func.terms] variable_indices(func::ScalarAffineFunction) = [term.variable_index for term in func.terms] -coefficients(func::ScalarAffineColumnFunction) = func.coefficients -variable_indices(func::ScalarAffineColumnFunction) = func.variable_indices +coefficients(func::ZippedAffineFunction) = func.terms.coefficients +variable_indices(func::ZippedAffineFunction) = func.terms.variable_indices """ struct VectorAffineTerm{T} @@ -422,8 +419,8 @@ function _dicts(f::Union{ScalarAffineFunction,VectorAffineFunction}) return (sum_dict(term_pair.(f.terms)),) end -function _dicts(f::ScalarAffineColumnFunction) - return (sum_dict(zip(f.variable_indices, f.coefficients)),) +function _dicts(f::ZippedAffineFunction) + return (sum_dict(zip(f.terms.variable_indices, f.terms.coefficients)),) end function _dicts(f::Union{ScalarQuadraticFunction,VectorQuadraticFunction}) @@ -438,7 +435,7 @@ end Returns the constant term of the scalar function """ -constant(f::Union{AbstractScalarAffineFunction,ScalarQuadraticFunction}) = f.constant +constant(f::Union{GenericScalarAffineFunction,ScalarQuadraticFunction}) = f.constant """ constant(f::Union{VectorAffineFunction, VectorQuadraticFunction}) @@ -453,13 +450,13 @@ function Base.isapprox( kwargs..., ) where { F<:Union{ - AbstractScalarAffineFunction, + GenericScalarAffineFunction, ScalarQuadraticFunction, VectorAffineFunction, VectorQuadraticFunction, }, G<:Union{ - AbstractScalarAffineFunction, + GenericScalarAffineFunction, ScalarQuadraticFunction, VectorAffineFunction, VectorQuadraticFunction, @@ -473,7 +470,7 @@ function Base.isapprox( end function constant( - f::Union{AbstractScalarAffineFunction,ScalarQuadraticFunction}, + f::Union{GenericScalarAffineFunction,ScalarQuadraticFunction}, T::DataType, ) return constant(f) @@ -518,10 +515,9 @@ function Base.copy( return F(copy(func.terms), copy(constant(func))) end -function Base.copy(func::ScalarAffineColumnFunction) - return ScalarAffineColumnFunction( - copy(func.coefficients), - copy(func.variable_indices), +function Base.copy(func::ZippedAffineFunction) + return ZippedAffineFunction( + copy(func.terms), copy(func.constant), ) end @@ -548,10 +544,12 @@ function ScalarAffineFunction{T}(f::SingleVariable) where {T} return ScalarAffineFunction([ScalarAffineTerm(one(T), f.variable)], zero(T)) end -function ScalarAffineColumnFunction{T}(f::SingleVariable) where {T} - return ScalarAffineColumnFunction{T}( - [one(T)], - [f.variable], +function ZippedAffineFunction{T}(f::SingleVariable) where {T} + return ZippedAffineFunction{T}( + ZipTermVector( + [one(T)], + [f.variable], + ), zero(T), ) end @@ -570,7 +568,7 @@ end # Conversion between scalar functions # Conversion to SingleVariable -function Base.convert(::Type{SingleVariable}, f::ScalarAffineFunction) +function Base.convert(::Type{SingleVariable}, f::Union{ScalarAffineFunction, ZippedAffineFunction}) if ( !iszero(f.constant) || !isone(length(f.terms)) || @@ -581,19 +579,6 @@ function Base.convert(::Type{SingleVariable}, f::ScalarAffineFunction) return SingleVariable(f.terms[1].variable_index) end -function Base.convert(::Type{SingleVariable}, f::ScalarAffineColumnFunction) - # just one of the two vectors checked - # since must remain consistent - if ( - !iszero(f.constant) || - !isone(length(f.coefficients)) || - !isone(f.coefficients[1]) - ) - throw(InexactError(:convert, SingleVariable, f)) - end - return SingleVariable(f.variable_indices[1]) -end - function Base.convert( ::Type{SingleVariable}, f::ScalarQuadraticFunction{T}, @@ -602,14 +587,14 @@ function Base.convert( end # Conversion to ScalarAffineFunction -function Base.convert(::Type{SF}, α::T) where {T, SF <: AbstractScalarAffineFunction{T}} +function Base.convert(::Type{SF}, α::T) where {T, SF <: GenericScalarAffineFunction{T}} return SF(ScalarAffineTerm{T}[], α) end function Base.convert( ::Type{SF}, f::SingleVariable, -) where {T, SF <: AbstractScalarAffineFunction{T}} +) where {T, SF <: GenericScalarAffineFunction{T}} return SF(f) end @@ -630,21 +615,21 @@ end function Base.convert( ::Type{SF}, f::SF, -) where {T, SF <: AbstractScalarAffineFunction{T}} +) where {T, SF <: GenericScalarAffineFunction{T}} return f end function Base.convert( ::Type{SF}, - f::AbstractScalarAffineFunction, -) where {T, SF <: AbstractScalarAffineFunction} + f::GenericScalarAffineFunction, +) where {SF <: GenericScalarAffineFunction} return SF(f.terms, f.constant) end function Base.convert( ::Type{SF}, f::ScalarQuadraticFunction{T}, -) where {T, SF <: AbstractScalarAffineFunction{T}} +) where {T, SF <: GenericScalarAffineFunction{T}} if !Base.isempty(f.quadratic_terms) throw(InexactError(:convert, ScalarAffineFunction{T}, f)) end From b75f0ffa959cc52072d73dc0718bc64e022c054c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 4 Mar 2021 22:04:35 +0100 Subject: [PATCH 06/15] rename with GenericScalarAffine --- src/Utilities/functions.jl | 26 +++++++++++--------------- src/Utilities/mutable_arithmetics.jl | 2 +- src/functions.jl | 16 +++++++++------- test/Utilities/functions.jl | 4 ++-- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index 6aea11b6ce..011f2bcccc 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -18,10 +18,6 @@ eval_variables(varval::Function, f::VVF) = varval.(f.variables) function eval_variables(varval::Function, f::SAF) return mapreduce(t -> eval_term(varval, t), +, f.terms, init = f.constant) end -function eval_variables(varval::Function, f::SACF) - return sum(c * varval(v) for (c, v) in zip(f.coefficients, f.variable_indices)) -end - function eval_variables(varval::Function, f::VAF) out = copy(f.constants) for t in f.terms @@ -311,7 +307,7 @@ function substitute_variables( end # Vector of constants -constant_vector(f::Union{SAF,SQF,SACF}) = [f.constant] +constant_vector(f::Union{SAF,SQF}) = [f.constant] constant_vector(f::Union{VAF,VQF}) = f.constants # Implements iterator interface @@ -567,7 +563,7 @@ canonicalize!(f::Union{MOI.VectorOfVariables,MOI.SingleVariable}) = f Convert a function to canonical form in-place, without allocating a copy to hold the result. See [`canonical`](@ref). """ -function canonicalize!(f::Union{SAF,VAF}) +function canonicalize!(f::Union{MOI.ScalarAffineFunction,VAF}) sort_and_compress!( f.terms, MOI.term_indices, @@ -577,26 +573,26 @@ function canonicalize!(f::Union{SAF,VAF}) return f end -function canonicalize!(f::SACF) +function canonicalize!(f::MOI.ZippedAffineFunction) delete_indices = BitSet() - for i in 1:length(f.variable_indices)-1 - if iszero(f.coefficients[i]) + for i in 1:length(f.terms.variable_indices)-1 + if iszero(f.terms.coefficients[i]) push!(delete_indices, i) continue end - for j in i+1:length(f.variable_indices) + for j in i+1:length(f.terms.variable_indices) if j in delete_indices continue end - if f.variable_indices[i] == f.variable_indices[j] - f.coefficients[i] += f.coefficients[j] - f.coefficients[j] = 0 + if f.terms.variable_indices[i] == f.terms.variable_indices[j] + f.terms.coefficients[i] += f.terms.coefficients[j] + f.terms.coefficients[j] = 0 push!(delete_indices, j) end end end - deleteat!(f.coefficients, delete_indices) - deleteat!(f.variable_indices, delete_indices) + deleteat!(f.terms.coefficients, delete_indices) + deleteat!(f.terms.variable_indices, delete_indices) return f end diff --git a/src/Utilities/mutable_arithmetics.jl b/src/Utilities/mutable_arithmetics.jl index 291e162356..61a9a19ae6 100644 --- a/src/Utilities/mutable_arithmetics.jl +++ b/src/Utilities/mutable_arithmetics.jl @@ -84,7 +84,7 @@ function MA.promote_operation( op::PROMOTE_IMPLEMENTED_OP, F::Type{T}, G::Type{<:TypedLike{T}}, -) where {T,N} +) where {T} return promote_operation(op, T, F, G) end function MA.promote_operation( diff --git a/src/functions.jl b/src/functions.jl index a7cabaff01..4bdbfd2170 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -97,28 +97,28 @@ const ScalarAffineFunction{T} = GenericScalarAffineFunction{T, Vector{ScalarAffi struct ZipTermVector{T} <: AbstractVector{ScalarAffineTerm{T}} coefficients::Vector{T} - variables::Vector{VariableIndex} + variable_indices::Vector{VariableIndex} end const ZippedAffineFunction{T} = GenericScalarAffineFunction{T, ZipTermVector{T}} -Base.getindex(zv::ZipTermVector, i::Integer) = ScalarAffineTerm(zv.coefficients[i], zv.variables[i]) +Base.getindex(zv::ZipTermVector, i::Integer) = ScalarAffineTerm(zv.coefficients[i], zv.variable_indices[i]) Base.size(zv::ZipTermVector) = size(zv.coefficients) function Base.push!(zv::ZipTermVector, term::ScalarAffineTerm) push!(zv.coefficients, term.coefficient) - push!(zv.variables, term.variables) + push!(zv.variable_indices, term.variable_index) return zv end function Base.empty!(zv::ZipTermVector) empty!(zv.coefficients) - empty!(zv.variables) + empty!(zv.variable_indices) return zv end function Base.setindex!(zv::ZipTermVector, term::ScalarAffineTerm, idx::Integer) zv.coefficients[idx] = term.coefficient - zv.variables[idx] = term.variable_index + zv.variable_indices[idx] = term.variable_index return term end @@ -126,7 +126,7 @@ scalar_terms(func::ScalarAffineFunction) = func.terms function scalar_terms(func::ZippedAffineFunction) return [ - ScalarAffineTerm(func.terms.coefficients[idx], func.terms.variables[idx]) + ScalarAffineTerm(func.terms.coefficients[idx], func.terms.variable_indices[idx]) for idx in eachindex(func.terms) ] end @@ -541,7 +541,9 @@ end # Define shortcuts for # SingleVariable -> ScalarAffineFunction function ScalarAffineFunction{T}(f::SingleVariable) where {T} - return ScalarAffineFunction([ScalarAffineTerm(one(T), f.variable)], zero(T)) + return ScalarAffineFunction( + [ScalarAffineTerm(one(T), f.variable)], zero(T), + ) end function ZippedAffineFunction{T}(f::SingleVariable) where {T} diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index 98eb848c84..026606da05 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -65,7 +65,7 @@ end @test aff isa MOI.VectorAffineFunction{Int} quad = MOIU.vectorize(MOI.ScalarQuadraticFunction{Int}[]) @test MOI.output_dimension(quad) == 0 - @test quad isa MOI.VectorQuadraticFunction{Int} + @test quad isa MOI.VectorQuadraticFunction{Int} end @testset "vectorize mixed affine functions" begin g1 = MOI.ScalarAffineColumnFunction([MOI.ScalarAffineTerm(2, x)], 3) @@ -80,7 +80,7 @@ end @test aff isa MOI.VectorAffineFunction{Int} quad = MOIU.vectorize(MOI.ScalarQuadraticFunction{Int}[]) @test MOI.output_dimension(quad) == 0 - @test quad isa MOI.VectorQuadraticFunction{Int} + @test quad isa MOI.VectorQuadraticFunction{Int} end @testset "operate vcat" begin v = MOI.VectorOfVariables([y, w]) From c1c19366f60383584a071357c8952ce09bccb8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 4 Mar 2021 23:05:02 +0100 Subject: [PATCH 07/15] fixed Integer bug and constructors --- src/functions.jl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/functions.jl b/src/functions.jl index 4bdbfd2170..42ee6c2bff 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -76,11 +76,15 @@ end # allocates, and it is desirable to provide a zero-allocation option for working with # ScalarAffineFunctions. See https://github.com/jump-dev/MathOptInterface.jl/pull/343. -mutable struct GenericScalarAffineFunction{T, VT<:AbstractVector{ScalarAffineTerm{T}}} +mutable struct GenericScalarAffineFunction{T, VT<:AbstractVector{ScalarAffineTerm{T}}} <: AbstractScalarFunction terms::VT constant::T end +function GenericScalarAffineFunction{T}(terms::VT, constant::T) where {T, VT <: AbstractVector{ScalarAffineTerm{T}}} + return GenericScalarAffineFunction{T,VT}(terms::VT, constant::T) +end + """ ScalarAffineFunction{T}(terms, constant) @@ -93,7 +97,9 @@ Duplicate variable indices in `terms` are accepted, and the corresponding coefficients are summed together. """ const ScalarAffineFunction{T} = GenericScalarAffineFunction{T, Vector{ScalarAffineTerm{T}}} - +function ScalarAffineFunction(terms::Vector{ScalarAffineTerm{T}}, constant::T) where {T} + ScalarAffineFunction{T}(terms, constant) +end struct ZipTermVector{T} <: AbstractVector{ScalarAffineTerm{T}} coefficients::Vector{T} @@ -101,7 +107,8 @@ struct ZipTermVector{T} <: AbstractVector{ScalarAffineTerm{T}} end const ZippedAffineFunction{T} = GenericScalarAffineFunction{T, ZipTermVector{T}} -Base.getindex(zv::ZipTermVector, i::Integer) = ScalarAffineTerm(zv.coefficients[i], zv.variable_indices[i]) +# Use `Base.Integer` here to disambiguate from the MOI set of the same name. +Base.getindex(zv::ZipTermVector, i::Base.Integer) = ScalarAffineTerm(zv.coefficients[i], zv.variable_indices[i]) Base.size(zv::ZipTermVector) = size(zv.coefficients) function Base.push!(zv::ZipTermVector, term::ScalarAffineTerm) @@ -116,7 +123,8 @@ function Base.empty!(zv::ZipTermVector) return zv end -function Base.setindex!(zv::ZipTermVector, term::ScalarAffineTerm, idx::Integer) +# Use `Base.Integer` here to disambiguate from the MOI set of the same name. +function Base.setindex!(zv::ZipTermVector, term::ScalarAffineTerm, idx::Base.Integer) zv.coefficients[idx] = term.coefficient zv.variable_indices[idx] = term.variable_index return term From 18205014f9771e0cd279e96ba85c301488f8d583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Fri, 5 Mar 2021 10:22:48 +0100 Subject: [PATCH 08/15] fixed specifier SAF to specific generic function --- src/Utilities/functions.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index 011f2bcccc..d71c2e44b4 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -879,8 +879,8 @@ end Return a new function `f` modified according to `change`. """ -function modify_function(f::MOI.GenericScalarAffineFunction, change::MOI.ScalarConstantChange) - return SAF(MOI.scalar_terms(f), change.new_constant) +function modify_function(f::F, change::MOI.ScalarConstantChange) where {F <: MOI.GenericScalarAffineFunction} + return F(MOI.scalar_terms(f), change.new_constant) end function modify_function(f::VAF, change::MOI.VectorConstantChange) return VAF(f.terms, change.new_constant) From 5aaa7dfd0b308443aa92ff652e349360cd5c61eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Fri, 5 Mar 2021 11:12:46 +0100 Subject: [PATCH 09/15] constructor from other affine function --- src/functions.jl | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/functions.jl b/src/functions.jl index 42ee6c2bff..cd709bfcdd 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -107,6 +107,7 @@ struct ZipTermVector{T} <: AbstractVector{ScalarAffineTerm{T}} end const ZippedAffineFunction{T} = GenericScalarAffineFunction{T, ZipTermVector{T}} +ZipTermVector{T}() where {T} = ZipTermVector{T}(T[], VariableIndex[]) # Use `Base.Integer` here to disambiguate from the MOI set of the same name. Base.getindex(zv::ZipTermVector, i::Base.Integer) = ScalarAffineTerm(zv.coefficients[i], zv.variable_indices[i]) Base.size(zv::ZipTermVector) = size(zv.coefficients) @@ -122,6 +123,30 @@ function Base.empty!(zv::ZipTermVector) empty!(zv.variable_indices) return zv end +function Base.sizehint!(zv::ZipTermVector, n) + Base.sizehint!(zv.coefficients, n) + Base.sizehint!(zv.variable_indices, n) + return +end + +function ZippedAffineFunction{T}(saf::GenericScalarAffineFunction) where {T} + zv = ZipTermVector{T}() + Base.sizehint!(zv, length(saf.terms)) + for term in saf.terms + push!(zv, term) + end + return ZippedAffineFunction{T}(zv, saf.constant) +end + +function ZippedAffineFunction{T}(zaf::ZippedAffineFunction) where {T} + return ZippedAffineFunction{T}( + ZipTermVector{T}( + copy(zaf.terms.coefficients), + copy(zaf.terms.variable_indices) + ), + zaf.constant, + ) +end # Use `Base.Integer` here to disambiguate from the MOI set of the same name. function Base.setindex!(zv::ZipTermVector, term::ScalarAffineTerm, idx::Base.Integer) From 40b9ba3140ba6bd6e97607722358ce12e3d35f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 11 Mar 2021 13:37:00 +0100 Subject: [PATCH 10/15] correct interpolation --- test/Bridges/lazy_bridge_optimizer.jl | 62 +++++++++++++-------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/test/Bridges/lazy_bridge_optimizer.jl b/test/Bridges/lazy_bridge_optimizer.jl index 6ea48ec426..e2101183a4 100644 --- a/test/Bridges/lazy_bridge_optimizer.jl +++ b/test/Bridges/lazy_bridge_optimizer.jl @@ -357,9 +357,9 @@ Bridge graph with 1 variable nodes, 1 constraint nodes and 0 objective nodes. @test sprint(MOIB.print_graph, bridged) == MOI.Utilities.replace_acronym(""" Bridge graph with 1 variable nodes, 3 constraint nodes and 0 objective nodes. [1] constrained variables in `MOI.PositiveSemidefiniteConeSquare` are supported (distance 6) by adding free variables and then constrain them, see (1). - (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.PositiveSemidefiniteConeSquare` constraints are bridged (distance 3) by $(MOIB.Constraint.SquareBridge{T,MOI.VectorAffineFunction{T},MOI.ScalarAffineFunction{T},MOI.PositiveSemidefiniteConeTriangle,MOI.PositiveSemidefiniteConeSquare}). - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarizeBridge{T,MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}). - (3) `MOI.VectorAffineFunction{$T}`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are bridged (distance 2) by $(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.PositiveSemidefiniteConeTriangle}). + (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.PositiveSemidefiniteConeSquare` constraints are bridged (distance 3) by $(MOIB.Constraint.SquareBridge{T,MOI.VectorAffineFunction{T},MOI.ScalarAffineFunction{T},MOI.PositiveSemidefiniteConeTriangle,MOI.PositiveSemidefiniteConeSquare}). + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarizeBridge{T,MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}). + (3) `$(MOI.VectorAffineFunction{T})`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are bridged (distance 2) by $(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.PositiveSemidefiniteConeTriangle}). """) end @testset "Vectorize" begin @@ -567,11 +567,11 @@ Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported an Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported and cannot be bridged into a supported objective function by adding only supported constrained variables and constraints. See details below: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because no added bridge supports bridging it. + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because no added bridge supports bridging it. (3) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported |1| objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported because: Cannot use `$(MOIB.Objective.SlackBridge{T,MOI.ScalarQuadraticFunction{T},MOI.ScalarQuadraticFunction{T}})` because: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported @@ -584,15 +584,15 @@ Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported an Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because: + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because: Cannot use `$(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.RotatedSecondOrderCone})` because: [1] constrained variables in `MOI.RotatedSecondOrderCone` are not supported - (3) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported - (3) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. + (3) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported + (3) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. (4) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported |1| objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported because: Cannot use `$(MOIB.Objective.SlackBridge{T,MOI.ScalarQuadraticFunction{T},MOI.ScalarQuadraticFunction{T}})` because: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported @@ -604,14 +604,14 @@ Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported an Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported and cannot be bridged into a supported objective function by adding only supported constrained variables and constraints. See details below: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because: + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because: Cannot use `$(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.RotatedSecondOrderCone})` because: - (4) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported - (4) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. + (4) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported + (4) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. (5) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported |1| objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported because: Cannot use `$(MOIB.Objective.SlackBridge{T,MOI.ScalarQuadraticFunction{T},MOI.ScalarQuadraticFunction{T}})` because: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported @@ -623,9 +623,9 @@ Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported an Bridge graph with 1 variable nodes, 5 constraint nodes and 2 objective nodes. [1] constrained variables in `MOI.RotatedSecondOrderCone` are bridged (distance 2) by $(MOIB.Variable.RSOCtoPSDBridge{T}). (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are bridged (distance 5) by $(MOIB.Constraint.QuadtoSOCBridge{T}). - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 4) by $(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.RotatedSecondOrderCone}). + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 4) by $(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.RotatedSecondOrderCone}). (3) `MOI.SingleVariable`-in-`MOI.EqualTo{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarFunctionizeBridge{T,MOI.EqualTo{T}}). - (4) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarizeBridge{T,MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}). + (4) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarizeBridge{T,MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}). (5) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.LessThan{$T}` constraints are bridged (distance 5) by $(MOIB.Constraint.QuadtoSOCBridge{T}). |1| objective function of type `MOI.ScalarQuadraticFunction{$T}` is bridged (distance 12) by $(MOIB.Objective.SlackBridge{T,MOI.ScalarQuadraticFunction{T},MOI.ScalarQuadraticFunction{T}}). |2| objective function of type `MOI.SingleVariable` is bridged (distance 1) by $(MOIB.Objective.FunctionizeBridge{T}). @@ -637,31 +637,31 @@ Bridge graph with 1 variable nodes, 5 constraint nodes and 2 objective nodes. S = MOI.ExponentialCone @test debug_string(MOIB.debug_supports_constraint, F, S) == """ -`MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: - (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported because no added bridge supports bridging it. +`$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: + (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported because no added bridge supports bridging it. """ MOIB.add_bridge(bridged, MOIB.Constraint.VectorSlackBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) == MOI.Utilities.replace_acronym(""" -`MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: +`$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [1] constrained variables in `MOI.ExponentialCone` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. - (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported because: + (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported because: Cannot use `$(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.ExponentialCone})` because: [1] constrained variables in `MOI.ExponentialCone` are not supported - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. """) MOIB.add_bridge(bridged, MOIB.Constraint.VectorFunctionizeBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) ==MOI.Utilities.replace_acronym(""" -`MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: +`$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [1] constrained variables in `MOI.ExponentialCone` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because: - (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported - (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported because: + (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported + (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported because: Cannot use `$(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.ExponentialCone})` because: [1] constrained variables in `MOI.ExponentialCone` are not supported - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. """) end end @@ -775,9 +775,9 @@ Bridge graph with 5 variable nodes, 11 constraint nodes and 0 objective nodes. [4] constrained variables in `MOI.Nonnegatives` are supported (distance 2) by adding free variables and then constrain them, see (6). [5] constrained variables in `MOI.Interval{$T}` are supported (distance 3) by adding free variables and then constrain them, see (8). (1) `MOI.VectorOfVariables`-in-`MOI.SecondOrderCone` constraints are bridged (distance 1) by $(MOIB.Constraint.VectorFunctionizeBridge{T,MOI.SecondOrderCone}). - (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 1) by $(MOIB.Constraint.RSOCBridge{T,MOI.VectorAffineFunction{T},MOI.VectorAffineFunction{T}}). + (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 1) by $(MOIB.Constraint.RSOCBridge{T,MOI.VectorAffineFunction{T},MOI.VectorAffineFunction{T}}). (3) `MOI.VectorOfVariables`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 1) by $(MOIB.Constraint.RSOCBridge{T,MOI.VectorAffineFunction{T},MOI.VectorOfVariables}). - (4) `MOI.VectorAffineFunction{$T}`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are not supported + (4) `$(MOI.VectorAffineFunction{T})`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are not supported (5) `MOI.VectorOfVariables`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are not supported (6) `MOI.VectorOfVariables`-in-`MOI.Nonnegatives` constraints are bridged (distance 1) by $(MOIB.Constraint.NonnegToNonposBridge{T,MOI.VectorAffineFunction{T},MOI.VectorOfVariables}). (7) `MOI.SingleVariable`-in-`MOI.GreaterThan{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.GreaterToLessBridge{T,MOI.ScalarAffineFunction{T},MOI.SingleVariable}). From 2f5d42de8799b443115851c1192f6a955a4463b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 11 Mar 2021 13:39:02 +0100 Subject: [PATCH 11/15] Revert "constructor from other affine function" This reverts commit 5aaa7dfd0b308443aa92ff652e349360cd5c61eb. --- src/functions.jl | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/functions.jl b/src/functions.jl index cd709bfcdd..42ee6c2bff 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -107,7 +107,6 @@ struct ZipTermVector{T} <: AbstractVector{ScalarAffineTerm{T}} end const ZippedAffineFunction{T} = GenericScalarAffineFunction{T, ZipTermVector{T}} -ZipTermVector{T}() where {T} = ZipTermVector{T}(T[], VariableIndex[]) # Use `Base.Integer` here to disambiguate from the MOI set of the same name. Base.getindex(zv::ZipTermVector, i::Base.Integer) = ScalarAffineTerm(zv.coefficients[i], zv.variable_indices[i]) Base.size(zv::ZipTermVector) = size(zv.coefficients) @@ -123,30 +122,6 @@ function Base.empty!(zv::ZipTermVector) empty!(zv.variable_indices) return zv end -function Base.sizehint!(zv::ZipTermVector, n) - Base.sizehint!(zv.coefficients, n) - Base.sizehint!(zv.variable_indices, n) - return -end - -function ZippedAffineFunction{T}(saf::GenericScalarAffineFunction) where {T} - zv = ZipTermVector{T}() - Base.sizehint!(zv, length(saf.terms)) - for term in saf.terms - push!(zv, term) - end - return ZippedAffineFunction{T}(zv, saf.constant) -end - -function ZippedAffineFunction{T}(zaf::ZippedAffineFunction) where {T} - return ZippedAffineFunction{T}( - ZipTermVector{T}( - copy(zaf.terms.coefficients), - copy(zaf.terms.variable_indices) - ), - zaf.constant, - ) -end # Use `Base.Integer` here to disambiguate from the MOI set of the same name. function Base.setindex!(zv::ZipTermVector, term::ScalarAffineTerm, idx::Base.Integer) From e1a4a0bafa54444614c8d2d8d804db84aec0caa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 11 Mar 2021 14:27:05 +0100 Subject: [PATCH 12/15] fix first part interpolation --- test/Bridges/lazy_bridge_optimizer.jl | 52 +++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/test/Bridges/lazy_bridge_optimizer.jl b/test/Bridges/lazy_bridge_optimizer.jl index e2101183a4..3fcfee818b 100644 --- a/test/Bridges/lazy_bridge_optimizer.jl +++ b/test/Bridges/lazy_bridge_optimizer.jl @@ -449,13 +449,13 @@ Bridge graph with 2 variable nodes, 0 constraint nodes and 0 objective nodes. Constrained variables in `MOI.LessThan{$T}` are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [1] constrained variables in `MOI.LessThan{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because: - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. """ @test sprint(MOIB.print_graph, bridged) == """ Bridge graph with 1 variable nodes, 1 constraint nodes and 0 objective nodes. [1] constrained variables in `MOI.LessThan{$T}` are not supported - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported """ MOIB.add_bridge(bridged, MOIB.Variable.VectorizeBridge{T}) @test debug_string(MOIB.debug_supports_add_constrained_variable, S) == MOI.Utilities.replace_acronym(""" @@ -464,10 +464,10 @@ Constrained variables in `MOI.LessThan{$T}` are not supported and cannot be brid Cannot use `$(MOIB.Variable.VectorizeBridge{T,MOI.Nonpositives})` because: [2] constrained variables in `MOI.Nonpositives` are not supported Cannot add free variables and then constrain them because: - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported [2] constrained variables in `MOI.Nonpositives` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. """) MOIB.add_bridge(bridged, MOIB.Variable.NonposToNonnegBridge{T}) @test debug_string(MOIB.debug_supports_add_constrained_variable, S) == "Constrained variables in `MOI.LessThan{$T}` are supported.\n" @@ -475,7 +475,7 @@ Constrained variables in `MOI.LessThan{$T}` are not supported and cannot be brid Bridge graph with 2 variable nodes, 1 constraint nodes and 0 objective nodes. [1] constrained variables in `MOI.LessThan{$T}` are bridged (distance 2) by $(MOIB.Variable.VectorizeBridge{T,MOI.Nonpositives}). [2] constrained variables in `MOI.Nonpositives` are bridged (distance 1) by $(MOIB.Variable.NonposToNonnegBridge{T}). - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported """) end bridged = MOIB.LazyBridgeOptimizer(model) @@ -483,44 +483,44 @@ Bridge graph with 2 variable nodes, 1 constraint nodes and 0 objective nodes. F = MOI.ScalarAffineFunction{T} S = MOI.Interval{T} @test debug_string(MOIB.debug_supports_constraint, F, S) == """ -`MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are not supported because no added bridge supports bridging it. +`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported because no added bridge supports bridging it. """ MOIB.add_bridge(bridged, MOIB.Constraint.SplitIntervalBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) == MOI.Utilities.replace_acronym(""" -`MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are not supported because: +`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}})` because: - (2) `MOI.ScalarAffineFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported - (3) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported - (2) `MOI.ScalarAffineFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported because no added bridge supports bridging it. - (3) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. + (2) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.GreaterThan{$T}` constraints are not supported + (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported + (2) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.GreaterThan{$T}` constraints are not supported because no added bridge supports bridging it. + (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. """) MOIB.add_bridge(bridged, MOIB.Constraint.ScalarSlackBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) == MOI.Utilities.replace_acronym(""" -`MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: +`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [1] constrained variables in `MOI.GreaterThan{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. [2] constrained variables in `MOI.LessThan{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. [3] constrained variables in `MOI.Interval{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are not supported because: + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}})` because: - (2) `MOI.ScalarAffineFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported - (3) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported + (2) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.GreaterThan{$T}` constraints are not supported + (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T}})` because: [3] constrained variables in `MOI.Interval{$T}` are not supported - (2) `MOI.ScalarAffineFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported because: + (2) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.GreaterThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.GreaterThan{T}})` because: [1] constrained variables in `MOI.GreaterThan{$T}` are not supported - (3) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because: + (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.LessThan{T}})` because: [2] constrained variables in `MOI.LessThan{$T}` are not supported """) MOIB.add_bridge(bridged, MOIB.Variable.VectorizeBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) == MOI.Utilities.replace_acronym(""" -`MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: +`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [2] constrained variables in `MOI.LessThan{$T}` are not supported because: Cannot use `$(MOIB.Variable.VectorizeBridge{T,MOI.Nonpositives})` because: [3] constrained variables in `MOI.Nonpositives` are not supported @@ -529,17 +529,17 @@ Bridge graph with 2 variable nodes, 1 constraint nodes and 0 objective nodes. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. [4] constrained variables in `MOI.Interval{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. - (1) `MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are not supported because: + (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}})` because: - (3) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported + (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T}})` because: [4] constrained variables in `MOI.Interval{$T}` are not supported - (3) `MOI.ScalarAffineFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because: + (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.LessThan{T}})` because: [2] constrained variables in `MOI.LessThan{$T}` are not supported """) MOIB.add_bridge(bridged, MOIB.Variable.NonposToNonnegBridge{T}) - @test debug_string(MOIB.debug_supports_constraint, F, S) == "`MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are supported.\n" + @test debug_string(MOIB.debug_supports_constraint, F, S) == "`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are supported.\n" end bridged = MOIB.LazyBridgeOptimizer(model) @testset "Quadratic objective" begin @@ -782,7 +782,7 @@ Bridge graph with 5 variable nodes, 11 constraint nodes and 0 objective nodes. (6) `MOI.VectorOfVariables`-in-`MOI.Nonnegatives` constraints are bridged (distance 1) by $(MOIB.Constraint.NonnegToNonposBridge{T,MOI.VectorAffineFunction{T},MOI.VectorOfVariables}). (7) `MOI.SingleVariable`-in-`MOI.GreaterThan{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.GreaterToLessBridge{T,MOI.ScalarAffineFunction{T},MOI.SingleVariable}). (8) `MOI.SingleVariable`-in-`MOI.Interval{$T}` constraints are bridged (distance 2) by $(MOIB.Constraint.ScalarFunctionizeBridge{T,MOI.Interval{T}}). - (9) `MOI.ScalarAffineFunction{$T}`-in-`MOI.Interval{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}}). + (9) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}}). (10) `MOI.SingleVariable`-in-`MOI.LessThan{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.LessToGreaterBridge{T,MOI.ScalarAffineFunction{T},MOI.SingleVariable}). (11) `MOI.SingleVariable`-in-`MOI.EqualTo{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.VectorizeBridge{T,MOI.VectorAffineFunction{T},MOI.Zeros,MOI.SingleVariable}). """) From cc41effc3ff3db725df2211c11e518258e34d466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 11 Mar 2021 21:15:34 +0100 Subject: [PATCH 13/15] undo VAF rename --- test/Bridges/lazy_bridge_optimizer.jl | 114 +++++++++++++------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/test/Bridges/lazy_bridge_optimizer.jl b/test/Bridges/lazy_bridge_optimizer.jl index 3fcfee818b..034cbcffd0 100644 --- a/test/Bridges/lazy_bridge_optimizer.jl +++ b/test/Bridges/lazy_bridge_optimizer.jl @@ -357,9 +357,9 @@ Bridge graph with 1 variable nodes, 1 constraint nodes and 0 objective nodes. @test sprint(MOIB.print_graph, bridged) == MOI.Utilities.replace_acronym(""" Bridge graph with 1 variable nodes, 3 constraint nodes and 0 objective nodes. [1] constrained variables in `MOI.PositiveSemidefiniteConeSquare` are supported (distance 6) by adding free variables and then constrain them, see (1). - (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.PositiveSemidefiniteConeSquare` constraints are bridged (distance 3) by $(MOIB.Constraint.SquareBridge{T,MOI.VectorAffineFunction{T},MOI.ScalarAffineFunction{T},MOI.PositiveSemidefiniteConeTriangle,MOI.PositiveSemidefiniteConeSquare}). - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarizeBridge{T,MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}). - (3) `$(MOI.VectorAffineFunction{T})`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are bridged (distance 2) by $(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.PositiveSemidefiniteConeTriangle}). + (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.PositiveSemidefiniteConeSquare` constraints are bridged (distance 3) by $(MOIB.Constraint.SquareBridge{T,MOI.VectorAffineFunction{T},MOI.ScalarAffineFunction{T},MOI.PositiveSemidefiniteConeTriangle,MOI.PositiveSemidefiniteConeSquare}). + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarizeBridge{T,MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}). + (3) `MOI.VectorAffineFunction{$T}`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are bridged (distance 2) by $(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.PositiveSemidefiniteConeTriangle}). """) end @testset "Vectorize" begin @@ -449,13 +449,13 @@ Bridge graph with 2 variable nodes, 0 constraint nodes and 0 objective nodes. Constrained variables in `MOI.LessThan{$T}` are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [1] constrained variables in `MOI.LessThan{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because: - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. """ @test sprint(MOIB.print_graph, bridged) == """ Bridge graph with 1 variable nodes, 1 constraint nodes and 0 objective nodes. [1] constrained variables in `MOI.LessThan{$T}` are not supported - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported """ MOIB.add_bridge(bridged, MOIB.Variable.VectorizeBridge{T}) @test debug_string(MOIB.debug_supports_add_constrained_variable, S) == MOI.Utilities.replace_acronym(""" @@ -464,10 +464,10 @@ Constrained variables in `MOI.LessThan{$T}` are not supported and cannot be brid Cannot use `$(MOIB.Variable.VectorizeBridge{T,MOI.Nonpositives})` because: [2] constrained variables in `MOI.Nonpositives` are not supported Cannot add free variables and then constrain them because: - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported [2] constrained variables in `MOI.Nonpositives` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. """) MOIB.add_bridge(bridged, MOIB.Variable.NonposToNonnegBridge{T}) @test debug_string(MOIB.debug_supports_add_constrained_variable, S) == "Constrained variables in `MOI.LessThan{$T}` are supported.\n" @@ -475,7 +475,7 @@ Constrained variables in `MOI.LessThan{$T}` are not supported and cannot be brid Bridge graph with 2 variable nodes, 1 constraint nodes and 0 objective nodes. [1] constrained variables in `MOI.LessThan{$T}` are bridged (distance 2) by $(MOIB.Variable.VectorizeBridge{T,MOI.Nonpositives}). [2] constrained variables in `MOI.Nonpositives` are bridged (distance 1) by $(MOIB.Variable.NonposToNonnegBridge{T}). - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported """) end bridged = MOIB.LazyBridgeOptimizer(model) @@ -483,44 +483,44 @@ Bridge graph with 2 variable nodes, 1 constraint nodes and 0 objective nodes. F = MOI.ScalarAffineFunction{T} S = MOI.Interval{T} @test debug_string(MOIB.debug_supports_constraint, F, S) == """ -`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported because no added bridge supports bridging it. +`MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are not supported because no added bridge supports bridging it. """ MOIB.add_bridge(bridged, MOIB.Constraint.SplitIntervalBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) == MOI.Utilities.replace_acronym(""" -`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported because: +`MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}})` because: - (2) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.GreaterThan{$T}` constraints are not supported - (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported - (2) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.GreaterThan{$T}` constraints are not supported because no added bridge supports bridging it. - (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. + (2) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.GreaterThan{$T}` constraints are not supported + (3) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported + (2) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.GreaterThan{$T}` constraints are not supported because no added bridge supports bridging it. + (3) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported because no added bridge supports bridging it. """) MOIB.add_bridge(bridged, MOIB.Constraint.ScalarSlackBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) == MOI.Utilities.replace_acronym(""" -`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: +`MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [1] constrained variables in `MOI.GreaterThan{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. [2] constrained variables in `MOI.LessThan{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. [3] constrained variables in `MOI.Interval{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported because: + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}})` because: - (2) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.GreaterThan{$T}` constraints are not supported - (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported + (2) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.GreaterThan{$T}` constraints are not supported + (3) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T}})` because: [3] constrained variables in `MOI.Interval{$T}` are not supported - (2) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.GreaterThan{$T}` constraints are not supported because: + (2) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.GreaterThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.GreaterThan{T}})` because: [1] constrained variables in `MOI.GreaterThan{$T}` are not supported - (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because: + (3) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.LessThan{T}})` because: [2] constrained variables in `MOI.LessThan{$T}` are not supported """) MOIB.add_bridge(bridged, MOIB.Variable.VectorizeBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) == MOI.Utilities.replace_acronym(""" -`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: +`MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [2] constrained variables in `MOI.LessThan{$T}` are not supported because: Cannot use `$(MOIB.Variable.VectorizeBridge{T,MOI.Nonpositives})` because: [3] constrained variables in `MOI.Nonpositives` are not supported @@ -529,17 +529,17 @@ Bridge graph with 2 variable nodes, 1 constraint nodes and 0 objective nodes. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. [4] constrained variables in `MOI.Interval{$T}` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. - (1) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are not supported because: + (1) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}})` because: - (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported + (3) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T}})` because: [4] constrained variables in `MOI.Interval{$T}` are not supported - (3) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.LessThan{$T}` constraints are not supported because: + (3) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.ScalarSlackBridge{T,MOI.ScalarAffineFunction{T},MOI.LessThan{T}})` because: [2] constrained variables in `MOI.LessThan{$T}` are not supported """) MOIB.add_bridge(bridged, MOIB.Variable.NonposToNonnegBridge{T}) - @test debug_string(MOIB.debug_supports_constraint, F, S) == "`$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are supported.\n" + @test debug_string(MOIB.debug_supports_constraint, F, S) == "`MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are supported.\n" end bridged = MOIB.LazyBridgeOptimizer(model) @testset "Quadratic objective" begin @@ -567,11 +567,11 @@ Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported an Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported and cannot be bridged into a supported objective function by adding only supported constrained variables and constraints. See details below: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because no added bridge supports bridging it. + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because no added bridge supports bridging it. (3) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported |1| objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported because: Cannot use `$(MOIB.Objective.SlackBridge{T,MOI.ScalarQuadraticFunction{T},MOI.ScalarQuadraticFunction{T}})` because: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported @@ -584,15 +584,15 @@ Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported an Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because: + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because: Cannot use `$(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.RotatedSecondOrderCone})` because: [1] constrained variables in `MOI.RotatedSecondOrderCone` are not supported - (3) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported - (3) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. + (3) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported + (3) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. (4) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported |1| objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported because: Cannot use `$(MOIB.Objective.SlackBridge{T,MOI.ScalarQuadraticFunction{T},MOI.ScalarQuadraticFunction{T}})` because: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported @@ -604,14 +604,14 @@ Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported an Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported and cannot be bridged into a supported objective function by adding only supported constrained variables and constraints. See details below: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because: + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported because: Cannot use `$(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.RotatedSecondOrderCone})` because: - (4) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported - (4) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. + (4) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported + (4) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. (5) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.LessThan{$T}` constraints are not supported because: Cannot use `$(MOIB.Constraint.QuadtoSOCBridge{T})` because: - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are not supported + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are not supported |1| objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported because: Cannot use `$(MOIB.Objective.SlackBridge{T,MOI.ScalarQuadraticFunction{T},MOI.ScalarQuadraticFunction{T}})` because: (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are not supported @@ -623,9 +623,9 @@ Objective function of type `MOI.ScalarQuadraticFunction{$T}` is not supported an Bridge graph with 1 variable nodes, 5 constraint nodes and 2 objective nodes. [1] constrained variables in `MOI.RotatedSecondOrderCone` are bridged (distance 2) by $(MOIB.Variable.RSOCtoPSDBridge{T}). (1) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.GreaterThan{$T}` constraints are bridged (distance 5) by $(MOIB.Constraint.QuadtoSOCBridge{T}). - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 4) by $(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.RotatedSecondOrderCone}). + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 4) by $(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.RotatedSecondOrderCone}). (3) `MOI.SingleVariable`-in-`MOI.EqualTo{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarFunctionizeBridge{T,MOI.EqualTo{T}}). - (4) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarizeBridge{T,MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}). + (4) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are bridged (distance 1) by $(MOIB.Constraint.ScalarizeBridge{T,MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}). (5) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.LessThan{$T}` constraints are bridged (distance 5) by $(MOIB.Constraint.QuadtoSOCBridge{T}). |1| objective function of type `MOI.ScalarQuadraticFunction{$T}` is bridged (distance 12) by $(MOIB.Objective.SlackBridge{T,MOI.ScalarQuadraticFunction{T},MOI.ScalarQuadraticFunction{T}}). |2| objective function of type `MOI.SingleVariable` is bridged (distance 1) by $(MOIB.Objective.FunctionizeBridge{T}). @@ -637,31 +637,31 @@ Bridge graph with 1 variable nodes, 5 constraint nodes and 2 objective nodes. S = MOI.ExponentialCone @test debug_string(MOIB.debug_supports_constraint, F, S) == """ -`$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: - (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported because no added bridge supports bridging it. +`MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: + (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported because no added bridge supports bridging it. """ MOIB.add_bridge(bridged, MOIB.Constraint.VectorSlackBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) == MOI.Utilities.replace_acronym(""" -`$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: +`MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [1] constrained variables in `MOI.ExponentialCone` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because free variables are bridged but no functionize bridge was added. - (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported because: + (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported because: Cannot use `$(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.ExponentialCone})` because: [1] constrained variables in `MOI.ExponentialCone` are not supported - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. """) MOIB.add_bridge(bridged, MOIB.Constraint.VectorFunctionizeBridge{T}) @test debug_string(MOIB.debug_supports_constraint, F, S) ==MOI.Utilities.replace_acronym(""" -`$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: +`MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: [1] constrained variables in `MOI.ExponentialCone` are not supported because no added bridge supports bridging it. Cannot add free variables and then constrain them because: - (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported - (1) `$(MOI.VectorAffineFunction{T})`-in-`MOI.ExponentialCone` constraints are not supported because: + (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported + (1) `MOI.VectorAffineFunction{$T}`-in-`MOI.ExponentialCone` constraints are not supported because: Cannot use `$(MOIB.Constraint.VectorSlackBridge{T,MOI.VectorAffineFunction{T},MOI.ExponentialCone})` because: [1] constrained variables in `MOI.ExponentialCone` are not supported - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are not supported because no added bridge supports bridging it. """) end end @@ -775,14 +775,14 @@ Bridge graph with 5 variable nodes, 11 constraint nodes and 0 objective nodes. [4] constrained variables in `MOI.Nonnegatives` are supported (distance 2) by adding free variables and then constrain them, see (6). [5] constrained variables in `MOI.Interval{$T}` are supported (distance 3) by adding free variables and then constrain them, see (8). (1) `MOI.VectorOfVariables`-in-`MOI.SecondOrderCone` constraints are bridged (distance 1) by $(MOIB.Constraint.VectorFunctionizeBridge{T,MOI.SecondOrderCone}). - (2) `$(MOI.VectorAffineFunction{T})`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 1) by $(MOIB.Constraint.RSOCBridge{T,MOI.VectorAffineFunction{T},MOI.VectorAffineFunction{T}}). + (2) `MOI.VectorAffineFunction{$T}`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 1) by $(MOIB.Constraint.RSOCBridge{T,MOI.VectorAffineFunction{T},MOI.VectorAffineFunction{T}}). (3) `MOI.VectorOfVariables`-in-`MOI.RotatedSecondOrderCone` constraints are bridged (distance 1) by $(MOIB.Constraint.RSOCBridge{T,MOI.VectorAffineFunction{T},MOI.VectorOfVariables}). - (4) `$(MOI.VectorAffineFunction{T})`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are not supported + (4) `MOI.VectorAffineFunction{$T}`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are not supported (5) `MOI.VectorOfVariables`-in-`MOI.PositiveSemidefiniteConeTriangle` constraints are not supported (6) `MOI.VectorOfVariables`-in-`MOI.Nonnegatives` constraints are bridged (distance 1) by $(MOIB.Constraint.NonnegToNonposBridge{T,MOI.VectorAffineFunction{T},MOI.VectorOfVariables}). (7) `MOI.SingleVariable`-in-`MOI.GreaterThan{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.GreaterToLessBridge{T,MOI.ScalarAffineFunction{T},MOI.SingleVariable}). (8) `MOI.SingleVariable`-in-`MOI.Interval{$T}` constraints are bridged (distance 2) by $(MOIB.Constraint.ScalarFunctionizeBridge{T,MOI.Interval{T}}). - (9) `$(MOI.ScalarAffineFunction{T})`-in-`MOI.Interval{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}}). + (9) `MOI.GenericScalarAffineFunction{$T, Vector{MOI.ScalarAffineTerm{$T}}}`-in-`MOI.Interval{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.SplitIntervalBridge{T,MOI.ScalarAffineFunction{T},MOI.Interval{T},MOI.GreaterThan{T},MOI.LessThan{T}}). (10) `MOI.SingleVariable`-in-`MOI.LessThan{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.LessToGreaterBridge{T,MOI.ScalarAffineFunction{T},MOI.SingleVariable}). (11) `MOI.SingleVariable`-in-`MOI.EqualTo{$T}` constraints are bridged (distance 1) by $(MOIB.Constraint.VectorizeBridge{T,MOI.VectorAffineFunction{T},MOI.Zeros,MOI.SingleVariable}). """) From cdc586716a2a19fb71762dafbdfacfb51227f043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Thu, 11 Mar 2021 21:37:20 +0100 Subject: [PATCH 14/15] adapt tests --- test/Utilities/functions.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index 026606da05..bfc2eee4cf 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -53,9 +53,9 @@ end @test quad isa MOI.VectorQuadraticFunction{Int} end @testset "vectorize pure column affine" begin - g1 = MOI.ScalarAffineColumnFunction([MOI.ScalarAffineTerm(2, x)], 3) - g2 = MOI.ScalarAffineColumnFunction(Int[], MOI.VariableIndex[], 1) - g3 = MOI.ScalarAffineColumnFunction([5], [y], 4) + g1 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(2, x)], 3) + g2 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Int}[], 1) + g3 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(5, y)], 4) @test g ≈ MOIU.vectorize([g1, g2, g3]) vov = MOIU.vectorize(MOI.SingleVariable[]) @test MOI.output_dimension(vov) == 0 @@ -68,9 +68,9 @@ end @test quad isa MOI.VectorQuadraticFunction{Int} end @testset "vectorize mixed affine functions" begin - g1 = MOI.ScalarAffineColumnFunction([MOI.ScalarAffineTerm(2, x)], 3) + g1 = MOI.ZippedAffineFunction([MOI.ScalarAffineTerm(2, x)], 3) g2 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Int}[], 1) - g3 = MOI.ScalarAffineColumnFunction([5], [y], 4) + g3 = MOI.ZippedAffineFunction{T}([5], [y], 4) @test g ≈ MOIU.vectorize([g1, g2, g3]) vov = MOIU.vectorize(MOI.SingleVariable[]) @test MOI.output_dimension(vov) == 0 From dad7b866703e49ea386d6437ab4fa7384e28550e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Besan=C3=A7on?= Date: Fri, 12 Mar 2021 12:45:50 +0100 Subject: [PATCH 15/15] change SAF to generic in utilities --- src/Utilities/Utilities.jl | 3 ++- src/Utilities/functions.jl | 10 +++++----- src/functions.jl | 33 +++++++++++++++++++++++++++++++++ test/Utilities/functions.jl | 6 +++--- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/Utilities/Utilities.jl b/src/Utilities/Utilities.jl index a23622af3e..a3425a920f 100644 --- a/src/Utilities/Utilities.jl +++ b/src/Utilities/Utilities.jl @@ -13,7 +13,8 @@ const MOIU = MOI.Utilities # used in macro const SVF = MOI.SingleVariable const VVF = MOI.VectorOfVariables -const SAF{T} = MOI.GenericScalarAffineFunction{T} +const SAF{T} = MOI.ScalarAffineFunction{T} +const GAF{T} = MOI.GenericScalarAffineFunction{T} const VAF{T} = MOI.VectorAffineFunction{T} const SQF{T} = MOI.ScalarQuadraticFunction{T} const VQF{T} = MOI.VectorQuadraticFunction{T} diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index 2ea698c342..a3df950940 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -2590,7 +2590,7 @@ end number_of_affine_terms(::Type{T}, ::T) where {T} = 0 number_of_affine_terms(::Type, ::SVF) = 1 number_of_affine_terms(::Type, f::VVF) = length(f.variables) -function number_of_affine_terms(::Type{T}, f::Union{SAF{T},VAF{T}}) where {T} +function number_of_affine_terms(::Type{T}, f::Union{GAF{T},VAF{T}}) where {T} return length(f.terms) end function number_of_affine_terms(::Type{T}, f::Union{SQF{T},VQF{T}}) where {T} @@ -2599,7 +2599,7 @@ end function number_of_quadratic_terms( ::Type{T}, - ::Union{T,SVF,VVF,SAF{T},VAF{T}}, + ::Union{T,SVF,VVF,GAF{T},VAF{T}}, ) where {T} return 0 end @@ -2652,7 +2652,7 @@ function fill_terms( terms::Vector{MOI.VectorAffineTerm{T}}, offset::Int, output_offset::Int, - func::Union{SAF{T},VAF{T}}, + func::Union{GAF{T},VAF{T}}, ) where {T} n = number_of_affine_terms(T, func) return terms[offset.+(1:n)] .= offset_term.(func.terms, output_offset) @@ -2706,7 +2706,7 @@ function fill_constant( constant::Vector{T}, offset::Int, output_offset::Int, - func::Union{SAF{T},SQF{T}}, + func::Union{GAF{T},SQF{T}}, ) where {T} return constant[offset+1] = MOI.constant(func) end @@ -2732,7 +2732,7 @@ function vectorize(funcs::AbstractVector{MOI.SingleVariable}) end """ - vectorize(funcs::AbstractVector{MOI.ScalarAffineFunction{T}}) where T + vectorize(funcs::AbstractVector{<:MOI.GenericScalarAffineFunction{T}}) where {T} Returns the vector of scalar affine functions in the form of a `MOI.VectorAffineFunction{T}`. diff --git a/src/functions.jl b/src/functions.jl index 42ee6c2bff..59c7b2beef 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -111,6 +111,21 @@ const ZippedAffineFunction{T} = GenericScalarAffineFunction{T, ZipTermVector{T}} Base.getindex(zv::ZipTermVector, i::Base.Integer) = ScalarAffineTerm(zv.coefficients[i], zv.variable_indices[i]) Base.size(zv::ZipTermVector) = size(zv.coefficients) +function ZipTermVector(terms::AbstractVector{ScalarAffineTerm{T}}) where {T} + coefficients = Vector{T}() + variable_indices = Vector{VariableIndex}() + Base.sizehint!(coefficients, length(terms)) + Base.sizehint!(variable_indices, length(terms)) + for term in terms + push!(coefficients, term.coefficient) + push!(variable_indices, term.variable_index) + end + return ZipTermVector{T}( + coefficients, + variable_indices, + ) +end + function Base.push!(zv::ZipTermVector, term::ScalarAffineTerm) push!(zv.coefficients, term.coefficient) push!(zv.variable_indices, term.variable_index) @@ -145,6 +160,24 @@ variable_indices(func::ScalarAffineFunction) = [term.variable_index for term in coefficients(func::ZippedAffineFunction) = func.terms.coefficients variable_indices(func::ZippedAffineFunction) = func.terms.variable_indices +function ZippedAffineFunction(terms::AbstractVector{MathOptInterface.ScalarAffineTerm{T}}, c::T) where {T} + return ZippedAffineFunction{T}( + ZipTermVector(terms), + c, + ) +end + +function ZippedAffineFunction(coefficients::Vector{T}, variable_indices::Vector{MathOptInterface.VariableIndex}, c::T = zero(T)) where {T} + return ZippedAffineFunction( + ZipTermVector( + coefficients, + variable_indices, + ), + c, + ) +end + + """ struct VectorAffineTerm{T} output_index::Int64 diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index bfc2eee4cf..50c0c17e3c 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -60,7 +60,7 @@ end vov = MOIU.vectorize(MOI.SingleVariable[]) @test MOI.output_dimension(vov) == 0 @test vov isa MOI.VectorOfVariables - aff = MOIU.vectorize(MOI.ScalarAffineColumnFunction{Int}[]) + aff = MOIU.vectorize(MOI.ZippedAffineFunction{Int}[]) @test MOI.output_dimension(aff) == 0 @test aff isa MOI.VectorAffineFunction{Int} quad = MOIU.vectorize(MOI.ScalarQuadraticFunction{Int}[]) @@ -70,12 +70,12 @@ end @testset "vectorize mixed affine functions" begin g1 = MOI.ZippedAffineFunction([MOI.ScalarAffineTerm(2, x)], 3) g2 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Int}[], 1) - g3 = MOI.ZippedAffineFunction{T}([5], [y], 4) + g3 = MOI.ZippedAffineFunction([5], [y], 4) @test g ≈ MOIU.vectorize([g1, g2, g3]) vov = MOIU.vectorize(MOI.SingleVariable[]) @test MOI.output_dimension(vov) == 0 @test vov isa MOI.VectorOfVariables - aff = MOIU.vectorize(MOI.ScalarAffineColumnFunction{Int}[]) + aff = MOIU.vectorize(MOI.ZippedAffineFunction{Int}[]) @test MOI.output_dimension(aff) == 0 @test aff isa MOI.VectorAffineFunction{Int} quad = MOIU.vectorize(MOI.ScalarQuadraticFunction{Int}[])