diff --git a/docs/src/submodules/Bridges/list_of_bridges.md b/docs/src/submodules/Bridges/list_of_bridges.md index 3a7c8e2c4b..60e3236e65 100644 --- a/docs/src/submodules/Bridges/list_of_bridges.md +++ b/docs/src/submodules/Bridges/list_of_bridges.md @@ -88,8 +88,9 @@ These bridges are subtypes of [`Bridges.Objective.AbstractBridge`](@ref). ```@docs Bridges.Objective.FunctionizeBridge Bridges.Objective.QuadratizeBridge -Bridges.Objective.SlackBridge Bridges.Objective.VectorFunctionizeBridge +Bridges.Objective.FunctionConversionBridge +Bridges.Objective.SlackBridge Bridges.Objective.VectorSlackBridge ``` diff --git a/src/Bridges/Objective/Objective.jl b/src/Bridges/Objective/Objective.jl index 945ab057fc..ae0c72e5c5 100644 --- a/src/Bridges/Objective/Objective.jl +++ b/src/Bridges/Objective/Objective.jl @@ -12,10 +12,8 @@ include("bridge.jl") include("map.jl") include("single_bridge_optimizer.jl") -include("bridges/functionize.jl") -include("bridges/quadratize.jl") +include("bridges/conversion.jl") include("bridges/slack.jl") -include("bridges/vector_functionize.jl") include("bridges/vector_slack.jl") """ diff --git a/src/Bridges/Objective/bridges/conversion.jl b/src/Bridges/Objective/bridges/conversion.jl new file mode 100644 index 0000000000..c0e573f551 --- /dev/null +++ b/src/Bridges/Objective/bridges/conversion.jl @@ -0,0 +1,196 @@ +# Copyright (c) 2017: Miles Lubin and contributors +# Copyright (c) 2017: Google Inc. +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +""" + FunctionConversionBridge{T,F,G} <: AbstractBridge + +`FunctionConversionBridge` implements the following reformulations: + + * ``\\min \\{g(x)\\}`` into ``\\min\\{f(x)\\}`` + * ``\\max \\{g(x)\\}`` into ``\\max\\{f(x)\\}`` + +for these pairs of functions: + + * [`MOI.ScalarAffineFunction`](@ref)` to [`MOI.ScalarQuadraticFunction`](@ref) + * [`MOI.ScalarQuadraticFunction`](@ref) to [`MOI.ScalarNonlinearFunction`](@ref) + * [`MOI.VectorAffineFunction`](@ref) to [`MOI.VectorQuadraticFunction`](@ref) + +## Source node + +`FunctionConversionBridge` supports: + + * [`MOI.ObjectiveFunction{G}`](@ref) + +## Target nodes + +`FunctionConversionBridge` creates: + + * One objective node: [`MOI.ObjectiveFunction{F}`](@ref) +""" +struct FunctionConversionBridge{T,F,G} <: AbstractBridge end + +function bridge_objective( + ::Type{FunctionConversionBridge{T,F,G}}, + model::MOI.ModelLike, + func::G, +) where {T,F,G<:MOI.AbstractFunction} + MOI.set(model, MOI.ObjectiveFunction{F}(), convert(F, func)) + return FunctionConversionBridge{T,F,G}() +end + +function supports_objective_function( + ::Type{<:FunctionConversionBridge{T,F}}, + ::Type{G}, +) where {T,F,G<:MOI.AbstractFunction} + return isfinite(MOI.Bridges.Constraint.conversion_cost(F, G)) +end + +function MOI.Bridges.added_constrained_variable_types( + ::Type{<:FunctionConversionBridge}, +) + return Tuple{Type}[] +end + +function MOI.Bridges.added_constraint_types(::Type{<:FunctionConversionBridge}) + return Tuple{Type,Type}[] +end + +function MOI.Bridges.set_objective_function_type( + ::Type{<:FunctionConversionBridge{T,F}}, +) where {T,F} + return F +end + +function concrete_bridge_type( + ::Type{<:FunctionConversionBridge{T,F}}, + ::Type{G}, +) where {T,F,G<:MOI.AbstractFunction} + return FunctionConversionBridge{T,F,G} +end + +# Attributes, Bridge acting as a model +MOI.get(::FunctionConversionBridge, ::MOI.NumberOfVariables)::Int64 = 0 + +function MOI.get(::FunctionConversionBridge, ::MOI.ListOfVariableIndices) + return MOI.VariableIndex[] +end + +# No variables or constraints are created in this bridge so there is nothing to +# delete. +MOI.delete(::MOI.ModelLike, ::FunctionConversionBridge) = nothing + +function MOI.set( + ::MOI.ModelLike, + ::MOI.ObjectiveSense, + ::FunctionConversionBridge, + ::MOI.OptimizationSense, +) + # `FunctionConversionBridge` is sense agnostic, therefore, we don't need to + # change anything. + return +end + +function MOI.get( + model::MOI.ModelLike, + attr::MOI.Bridges.ObjectiveFunctionValue{G}, + ::FunctionConversionBridge{T,F,G}, +) where {T,F,G} + attr_f = MOI.Bridges.ObjectiveFunctionValue{F}(attr.result_index) + return MOI.get(model, attr_f) +end + +function MOI.get( + model::MOI.ModelLike, + ::MOI.ObjectiveFunction{G}, + ::FunctionConversionBridge{T,F,G}, +) where {T,F,G<:MOI.AbstractFunction} + func = MOI.get(model, MOI.ObjectiveFunction{F}()) + return MOI.Utilities.convert_approx(G, func) +end + +""" + FunctionizeBridge{T,G} <: FunctionConversionBridge{T,MOI.ScalarAffineFunction{T},G} + +`FunctionizeBridge` implements the following reformulations: + + * ``\\min \\{x\\}`` into ``\\min\\{1x + 0\\}`` + * ``\\max \\{x\\}`` into ``\\max\\{1x + 0\\}`` + +where `T` is the coefficient type of `1` and `0`. + +## Source node + +`FunctionizeBridge` supports: + + * [`MOI.ObjectiveFunction{G}`](@ref) + +## Target nodes + +`FunctionizeBridge` creates: + + * One objective node: [`MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}`](@ref) +""" +const FunctionizeBridge{T,G} = + FunctionConversionBridge{T,MOI.ScalarAffineFunction{T},G} + +const Functionize{T,OT<:MOI.ModelLike} = + SingleBridgeOptimizer{FunctionizeBridge{T},OT} + +""" + QuadratizeBridge{T,G} <: FunctionConversionBridge{T,MOI.ScalarQuadraticFunction{T},G} + +`QuadratizeBridge` implements the following reformulations: + + * ``\\min \\{a^\\top x + b\\}`` into ``\\min\\{x^\\top \\mathbf{0} x + a^\\top x + b\\}`` + * ``\\max \\{a^\\top x + b\\}`` into ``\\max\\{x^\\top \\mathbf{0} x + a^\\top x + b\\}`` + +where `T` is the coefficient type of `0`. + +## Source node + +`QuadratizeBridge` supports: + + * [`MOI.ObjectiveFunction{G}`](@ref) + +## Target nodes + +`QuadratizeBridge` creates: + + * One objective node: [`MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{T}}`](@ref) +""" +const QuadratizeBridge{T,G} = + FunctionConversionBridge{T,MOI.ScalarQuadraticFunction{T},G} + +const Quadratize{T,OT<:MOI.ModelLike} = + SingleBridgeOptimizer{QuadratizeBridge{T},OT} + +""" + VectorFunctionizeBridge{T,G} <: FunctionConversionBridge{T,MOI.VectorAffineFunction{T},G} + +`VectorFunctionizeBridge` implements the following reformulations: + + * ``\\min \\{x\\}`` into ``\\min\\{1x + 0\\}`` + * ``\\max \\{x\\}`` into ``\\max\\{1x + 0\\}`` + +where `T` is the coefficient type of `1` and `0`. + +## Source node + +`VectorFunctionizeBridge` supports: + + * [`MOI.ObjectiveFunction{G}`](@ref) + +## Target nodes + +`VectorFunctionizeBridge` creates: + + * One objective node: [`MOI.ObjectiveFunction{MOI.VectorAffineFunction{T}}`](@ref) +""" +const VectorFunctionizeBridge{T,G} = + FunctionConversionBridge{T,MOI.VectorAffineFunction{T},G} + +const VectorFunctionize{T,OT<:MOI.ModelLike} = + SingleBridgeOptimizer{VectorFunctionizeBridge{T},OT} diff --git a/src/Bridges/Objective/bridges/functionize.jl b/src/Bridges/Objective/bridges/functionize.jl deleted file mode 100644 index d30b2f361f..0000000000 --- a/src/Bridges/Objective/bridges/functionize.jl +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2017: Miles Lubin and contributors -# Copyright (c) 2017: Google Inc. -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -""" - FunctionizeBridge{T} - -`FunctionizeBridge` implements the following reformulations: - - * ``\\min \\{x\\}`` into ``\\min\\{1x + 0\\}`` - * ``\\max \\{x\\}`` into ``\\max\\{1x + 0\\}`` - -where `T` is the coefficient type of `1` and `0`. - -## Source node - -`FunctionizeBridge` supports: - - * [`MOI.ObjectiveFunction{MOI.VariableIndex}`](@ref) - -## Target nodes - -`FunctionizeBridge` creates: - - * One objective node: [`MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}`](@ref) -""" -struct FunctionizeBridge{T} <: AbstractBridge end - -const Functionize{T,OT<:MOI.ModelLike} = - SingleBridgeOptimizer{FunctionizeBridge{T},OT} - -function bridge_objective( - ::Type{FunctionizeBridge{T}}, - model::MOI.ModelLike, - func::MOI.VariableIndex, -) where {T} - F = MOI.ScalarAffineFunction{T} - MOI.set(model, MOI.ObjectiveFunction{F}(), convert(F, func)) - return FunctionizeBridge{T}() -end - -function supports_objective_function( - ::Type{<:FunctionizeBridge}, - ::Type{MOI.VariableIndex}, -) - return true -end - -function MOI.Bridges.added_constrained_variable_types( - ::Type{<:FunctionizeBridge}, -) - return Tuple{Type}[] -end - -function MOI.Bridges.added_constraint_types(::Type{<:FunctionizeBridge}) - return Tuple{Type,Type}[] -end - -function MOI.Bridges.set_objective_function_type( - ::Type{FunctionizeBridge{T}}, -) where {T} - return MOI.ScalarAffineFunction{T} -end - -# Attributes, Bridge acting as a model -MOI.get(::FunctionizeBridge, ::MOI.NumberOfVariables)::Int64 = 0 - -function MOI.get(::FunctionizeBridge, ::MOI.ListOfVariableIndices) - return MOI.VariableIndex[] -end - -# No variables or constraints are created in this bridge so there is nothing to -# delete. -MOI.delete(::MOI.ModelLike, ::FunctionizeBridge) = nothing - -function MOI.set( - ::MOI.ModelLike, - ::MOI.ObjectiveSense, - ::FunctionizeBridge, - ::MOI.OptimizationSense, -) - # `FunctionizeBridge` is sense agnostic, therefore, we don't need to change - # anything. - return -end - -function MOI.get( - model::MOI.ModelLike, - attr::MOI.Bridges.ObjectiveFunctionValue{MOI.VariableIndex}, - ::FunctionizeBridge{T}, -) where {T} - F = MOI.ScalarAffineFunction{T} - attr_f = MOI.Bridges.ObjectiveFunctionValue{F}(attr.result_index) - return MOI.get(model, attr_f) -end - -function MOI.get( - model::MOI.ModelLike, - ::MOI.ObjectiveFunction{MOI.VariableIndex}, - ::FunctionizeBridge{T}, -) where {T} - F = MOI.ScalarAffineFunction{T} - func = MOI.get(model, MOI.ObjectiveFunction{F}()) - return MOI.Utilities.convert_approx(MOI.VariableIndex, func) -end diff --git a/src/Bridges/Objective/bridges/quadratize.jl b/src/Bridges/Objective/bridges/quadratize.jl deleted file mode 100644 index 079260483f..0000000000 --- a/src/Bridges/Objective/bridges/quadratize.jl +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (c) 2017: Miles Lubin and contributors -# Copyright (c) 2017: Google Inc. -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -""" - QuadratizeBridge{T} - -`QuadratizeBridge` implements the following reformulations: - - * ``\\min \\{a^\\top x + b\\}`` into ``\\min\\{x^\\top \\mathbf{0} x + a^\\top x + b\\}`` - * ``\\max \\{a^\\top x + b\\}`` into ``\\max\\{x^\\top \\mathbf{0} x + a^\\top x + b\\}`` - -where `T` is the coefficient type of `0`. - -## Source node - -`QuadratizeBridge` supports: - - * [`MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}`](@ref) - -## Target nodes - -`QuadratizeBridge` creates: - - * One objective node: [`MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{T}}`](@ref) -""" -struct QuadratizeBridge{T} <: AbstractBridge end - -const Quadratize{T,OT<:MOI.ModelLike} = - SingleBridgeOptimizer{QuadratizeBridge{T},OT} - -function bridge_objective( - ::Type{QuadratizeBridge{T}}, - model::MOI.ModelLike, - func::MOI.ScalarAffineFunction{T}, -) where {T} - f = convert(MOI.ScalarQuadraticFunction{T}, func) - MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) - return QuadratizeBridge{T}() -end - -function supports_objective_function( - ::Type{<:QuadratizeBridge{T}}, - ::Type{MOI.ScalarAffineFunction{T}}, -) where {T} - return true -end - -function MOI.Bridges.added_constrained_variable_types( - ::Type{<:QuadratizeBridge}, -) - return Tuple{Type}[] -end - -function MOI.Bridges.added_constraint_types(::Type{<:QuadratizeBridge}) - return Tuple{Type,Type}[] -end - -function MOI.Bridges.set_objective_function_type( - ::Type{QuadratizeBridge{T}}, -) where {T} - return MOI.ScalarQuadraticFunction{T} -end - -# No variables or constraints are created in this bridge so there is nothing to -# delete. -MOI.delete(::MOI.ModelLike, ::QuadratizeBridge) = nothing - -function MOI.set( - ::MOI.ModelLike, - ::MOI.ObjectiveSense, - ::QuadratizeBridge, - ::MOI.OptimizationSense, -) - # `QuadratizeBridge` is sense agnostic, therefore, we don't need to change - # anything. - return -end - -function MOI.get( - model::MOI.ModelLike, - attr::MOI.Bridges.ObjectiveFunctionValue{MOI.ScalarAffineFunction{T}}, - ::QuadratizeBridge{T}, -) where {T} - F = MOI.ScalarQuadraticFunction{T} - attr_f = MOI.Bridges.ObjectiveFunctionValue{F}(attr.result_index) - return MOI.get(model, attr_f) -end - -function MOI.get( - model::MOI.ModelLike, - ::MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}, - ::QuadratizeBridge{T}, -) where {T} - F = MOI.ScalarQuadraticFunction{T} - func = MOI.get(model, MOI.ObjectiveFunction{F}()) - return convert(MOI.ScalarAffineFunction{T}, func) -end diff --git a/src/Bridges/Objective/bridges/vector_functionize.jl b/src/Bridges/Objective/bridges/vector_functionize.jl deleted file mode 100644 index 80ea13285f..0000000000 --- a/src/Bridges/Objective/bridges/vector_functionize.jl +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright (c) 2017: Miles Lubin and contributors -# Copyright (c) 2017: Google Inc. -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -""" - VectorFunctionizeBridge{T} - -`VectorFunctionizeBridge` implements the following reformulations: - - * ``\\min \\{x\\}`` into ``\\min\\{1x + 0\\}`` - * ``\\max \\{x\\}`` into ``\\max\\{1x + 0\\}`` - -where `T` is the coefficient type of `1` and `0`. - -## Source node - -`VectorFunctionizeBridge` supports: - - * [`MOI.ObjectiveFunction{MOI.VectorOfVariables}`](@ref) - -## Target nodes - -`VectorFunctionizeBridge` creates: - - * One objective node: [`MOI.ObjectiveFunction{MOI.VectorAffineFunction{T}}`](@ref) -""" -struct VectorFunctionizeBridge{T} <: AbstractBridge end - -const VectorFunctionize{T,OT<:MOI.ModelLike} = - SingleBridgeOptimizer{VectorFunctionizeBridge{T},OT} - -function bridge_objective( - ::Type{VectorFunctionizeBridge{T}}, - model::MOI.ModelLike, - f::MOI.VectorOfVariables, -) where {T} - F = MOI.VectorAffineFunction{T} - MOI.set(model, MOI.ObjectiveFunction{F}(), convert(F, f)) - return VectorFunctionizeBridge{T}() -end - -function supports_objective_function( - ::Type{<:VectorFunctionizeBridge}, - ::Type{MOI.VectorOfVariables}, -) - return true -end - -function MOI.Bridges.added_constrained_variable_types( - ::Type{<:VectorFunctionizeBridge}, -) - return Tuple{Type}[] -end - -function MOI.Bridges.added_constraint_types(::Type{<:VectorFunctionizeBridge}) - return Tuple{Type,Type}[] -end - -function MOI.Bridges.set_objective_function_type( - ::Type{VectorFunctionizeBridge{T}}, -) where {T} - return MOI.VectorAffineFunction{T} -end - -MOI.get(::VectorFunctionizeBridge, ::MOI.NumberOfVariables)::Int64 = 0 - -function MOI.get(::VectorFunctionizeBridge, ::MOI.ListOfVariableIndices) - return MOI.VariableIndex[] -end - -MOI.delete(::MOI.ModelLike, ::VectorFunctionizeBridge) = nothing - -function MOI.set( - ::MOI.ModelLike, - ::MOI.ObjectiveSense, - ::VectorFunctionizeBridge, - ::MOI.OptimizationSense, -) - # `VectorFunctionizeBridge` is sense agnostic, therefore, we don't need to - # change anything. - return -end - -function MOI.get( - model::MOI.ModelLike, - attr::MOI.Bridges.ObjectiveFunctionValue{MOI.VectorOfVariables}, - ::VectorFunctionizeBridge{T}, -) where {T} - F = MOI.VectorAffineFunction{T} - attr_f = MOI.Bridges.ObjectiveFunctionValue{F}(attr.result_index) - return MOI.get(model, attr_f) -end - -function MOI.get( - model::MOI.ModelLike, - ::MOI.ObjectiveFunction{MOI.VectorOfVariables}, - ::VectorFunctionizeBridge{T}, -) where {T} - f = MOI.get(model, MOI.ObjectiveFunction{MOI.VectorAffineFunction{T}}()) - return convert(MOI.VectorOfVariables, f) -end diff --git a/test/Bridges/Objective/conversion.jl b/test/Bridges/Objective/conversion.jl new file mode 100644 index 0000000000..02504aaf3f --- /dev/null +++ b/test/Bridges/Objective/conversion.jl @@ -0,0 +1,62 @@ +# Copyright (c) 2017: Miles Lubin and contributors +# Copyright (c) 2017: Google Inc. +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +module TestObjectiveConversion + +using Test + +import MathOptInterface as MOI + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$(name)", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end + end + return +end + +include("../utilities.jl") + +struct VariableDifference <: MOI.AbstractScalarFunction + x::MOI.VariableIndex + y::MOI.VariableIndex +end + +function MOI.Bridges.Constraint.conversion_cost( + ::Type{<:MOI.ScalarAffineFunction}, + ::Type{VariableDifference}, +) + return 1.0 +end + +function MOI.convert( + ::Type{MOI.ScalarAffineFunction{T}}, + f::VariableDifference, +) where {T} + return one(T) * f.x - one(T) * f.y +end + +function test_variable_difference(T = Float64) + F = MOI.ScalarAffineFunction{T} + B = MOI.Bridges.Objective.FunctionConversionBridge{T,F} + inner = MOI.Utilities.Model{T}() + model = MOI.Bridges.Objective.SingleBridgeOptimizer{B}(inner) + x = MOI.add_variable(model) + y = MOI.add_variable(model) + g = VariableDifference(x, y) + G = typeof(g) + MOI.set(model, MOI.ObjectiveFunction{G}(), g) + f = one(T) * x - one(T) * y + @test MOI.get(inner, MOI.ObjectiveFunction{F}()) ≈ f + return +end + +end # module + +TestObjectiveConversion.runtests() diff --git a/test/Bridges/debug.jl b/test/Bridges/debug.jl index e310ea3fa0..386116be21 100644 --- a/test/Bridges/debug.jl +++ b/test/Bridges/debug.jl @@ -73,7 +73,7 @@ function test_print_active_bridges() | may introduce: | * Unsupported objective: MOI.VariableIndex | | bridged by: - | | MOIB.Objective.FunctionizeBridge{Float64} + | | MOIB.Objective.FunctionConversionBridge{Float64, MOI.ScalarAffineFunction{Float64}, MOI.VariableIndex} | | may introduce: | | * Supported objective: MOI.ScalarAffineFunction{Float64} | * Unsupported constraint: MOI.ScalarQuadraticFunction{Float64}-in-MOI.GreaterThan{Float64} @@ -188,7 +188,7 @@ function test_print_active_bridges_objective_bridged() """ * Unsupported objective: MOI.VariableIndex | bridged by: - | MOIB.Objective.FunctionizeBridge{Float64} + | MOIB.Objective.FunctionConversionBridge{Float64, MOI.ScalarAffineFunction{Float64}, MOI.VariableIndex} | may introduce: | * Supported objective: MOI.ScalarAffineFunction{Float64} """ diff --git a/test/Bridges/lazy_bridge_optimizer.jl b/test/Bridges/lazy_bridge_optimizer.jl index 4695af4451..8fa70aa3e0 100644 --- a/test/Bridges/lazy_bridge_optimizer.jl +++ b/test/Bridges/lazy_bridge_optimizer.jl @@ -746,7 +746,7 @@ Bridge graph with 1 variable nodes, 3 constraint nodes and 0 objective nodes. MOI.Bridges.add_bridge(bridged, MOI.Bridges.Objective.FunctionizeBridge{T}) @test MOI.supports(bridged, MOI.ObjectiveFunction{MOI.VariableIndex}()) @test MOI.Bridges.bridge_type(bridged, MOI.VariableIndex) == - MOI.Bridges.Objective.FunctionizeBridge{T} + MOI.Bridges.Objective.FunctionizeBridge{T,MOI.VariableIndex} @test MOI.supports(bridged, attr) @test MOI.Bridges.bridge_type(bridged, F) == MOI.Bridges.Objective.SlackBridge{T,F,F} @@ -1085,7 +1085,7 @@ Bridge graph with 2 variable nodes, 5 constraint nodes and 2 objective nodes. (4) `MOI.VectorAffineFunction{$T}`-in-`MOI.Zeros` constraints are bridged (distance 1) by $(MOI.Bridges.Constraint.ScalarizeBridge{T,MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}). (5) `MOI.ScalarQuadraticFunction{$T}`-in-`MOI.LessThan{$T}` constraints are bridged (distance 5) by $(MOI.Bridges.Constraint.QuadtoSOCBridge{T}). |1| objective function of type `MOI.ScalarQuadraticFunction{$T}` is bridged (distance 13) by $(MOI.Bridges.Objective.SlackBridge{T,MOI.ScalarQuadraticFunction{T},MOI.ScalarQuadraticFunction{T}}). - |2| objective function of type `MOI.VariableIndex` is bridged (distance 1) by $(MOI.Bridges.Objective.FunctionizeBridge{T}). + |2| objective function of type `MOI.VariableIndex` is bridged (distance 1) by $(MOI.Bridges.Objective.FunctionizeBridge{T,MOI.VariableIndex}). """, ) end