From 6125b94403314bd249a883af2426977fa5cc60ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateus=20Ara=C3=BAjo?= Date: Fri, 7 Aug 2026 16:31:43 +0200 Subject: [PATCH 1/4] add DualGeometricMeanCone and bridge --- docs/src/manual/standard_form.md | 1 + docs/src/reference/standard_form.md | 1 + src/Bridges/Constraint/Constraint.jl | 1 + .../Constraint/bridges/DualGeoMeanBridge.jl | 160 ++++++++++++++++++ src/Test/test_basic_constraint.jl | 2 + src/Test/test_conic.jl | 160 ++++++++++++++++++ src/Utilities/distance_to_set.jl | 34 +++- src/Utilities/model.jl | 1 + src/sets.jl | 52 +++++- test/General/test_sets.jl | 11 ++ test/Utilities/test_distance_to_set.jl | 13 ++ 11 files changed, 428 insertions(+), 8 deletions(-) create mode 100644 src/Bridges/Constraint/bridges/DualGeoMeanBridge.jl diff --git a/docs/src/manual/standard_form.md b/docs/src/manual/standard_form.md index 5cb28941bc..a0ebcf0a82 100644 --- a/docs/src/manual/standard_form.md +++ b/docs/src/manual/standard_form.md @@ -76,6 +76,7 @@ The vector-valued set types implemented in MathOptInterface.jl are: | [`ExponentialCone()`](@ref) | ``\{ (x,y,z) \in \mathbb{R}^3 : y \exp (x/y) \le z, y > 0 \}`` | | [`DualExponentialCone()`](@ref) | ``\{ (u,v,w) \in \mathbb{R}^3 : -u \exp (v/u) \le \exp(1) w, u < 0 \}`` | | [`GeometricMeanCone(d)`](@ref) | ``\{ (t,x) \in \mathbb{R}^{1+n} : x \ge 0, t \le \sqrt[n]{x_1 x_2 \cdots x_n} \}`` where ``n`` is ``d - 1`` | +| [`DualGeometricMeanCone(d)`](@ref) | ``\{ (u,v) \in \mathbb{R}^{1+n} : v \\ge 0, 0 \\ge u \\ge -n \\sqrt[n]{\\prod_i v_i} \\}``, where ``n`` is ``d - 1`` | | [`PowerCone(α)`](@ref) | ``\{ (x,y,z) \in \mathbb{R}^3 : x^{\alpha} y^{1-\alpha} \ge \|z\|, x \ge 0,y \ge 0 \}`` | | [`DualPowerCone(α)`](@ref) | ``\{ (u,v,w) \in \mathbb{R}^3 : \left(\frac{u}{\alpha}\right)^{\alpha}\left(\frac{v}{1-\alpha}\right)^{1-\alpha} \ge \|w\|, u,v \ge 0 \}`` | | [`NormOneCone(d)`](@ref) | ``\{ (t,x) \in \mathbb{R}^{d} : t \ge \sum_i \lvert x_i \rvert \}`` | diff --git a/docs/src/reference/standard_form.md b/docs/src/reference/standard_form.md index d78681869e..2008be8cd0 100644 --- a/docs/src/reference/standard_form.md +++ b/docs/src/reference/standard_form.md @@ -88,6 +88,7 @@ NormCone SecondOrderCone RotatedSecondOrderCone GeometricMeanCone +DualGeometricMeanCone ExponentialCone DualExponentialCone PowerCone diff --git a/src/Bridges/Constraint/Constraint.jl b/src/Bridges/Constraint/Constraint.jl index f24f3b14b0..c2f4338110 100644 --- a/src/Bridges/Constraint/Constraint.jl +++ b/src/Bridges/Constraint/Constraint.jl @@ -39,6 +39,7 @@ function add_all_bridges(model, ::Type{T}) where {T} MOI.Bridges.add_bridge(model, CountBelongsToMILPBridge{T}) MOI.Bridges.add_bridge(model, CountDistinctToMILPBridge{T}) MOI.Bridges.add_bridge(model, CountGreaterThanToMILPBridge{T}) + MOI.Bridges.add_bridge(model, DualGeoMeanBridge{T}) # * ExponentialConeToScalarNonlinearFunctionBridge{T} # This bridge is not added by default because it starts with a convex # conic constraint and adds a nonlinear constraint that local NLP diff --git a/src/Bridges/Constraint/bridges/DualGeoMeanBridge.jl b/src/Bridges/Constraint/bridges/DualGeoMeanBridge.jl new file mode 100644 index 0000000000..919820d15d --- /dev/null +++ b/src/Bridges/Constraint/bridges/DualGeoMeanBridge.jl @@ -0,0 +1,160 @@ +# 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. + +""" + DualGeoMeanBridge{T,G,H} <: Bridges.Constraint.AbstractBridge + +`DualGeoMeanBridge` implements the following reformulation: + + * ``(u, v) \\in DualGeometricMeanCone`` into + ``(-u/length(v), v) \\in GeometricMeanCone`` and ``u \\le 0`` + +## Source node + +`DualGeoMeanBridge` supports: + + * `H` in [`MOI.DualGeometricMeanCone`](@ref) + +## Target nodes + +`DualGeoMeanBridge` creates: + + * `G` in [`MOI.GeometricMeanCone`](@ref) + * `G` in [`MOI.Nonnegatives`](@ref) +""" +struct DualGeoMeanBridge{T,G,H} <: AbstractBridge + nn_index::MOI.ConstraintIndex{G,MOI.Nonnegatives} + geomean_index::MOI.ConstraintIndex{G,MOI.GeometricMeanCone} +end + +const DualGeoMean{T,OT<:MOI.ModelLike} = + SingleBridgeOptimizer{DualGeoMeanBridge{T},OT} + +function bridge_constraint( + ::Type{DualGeoMeanBridge{T,G,H}}, + model::MOI.ModelLike, + f::H, + s::MOI.DualGeometricMeanCone, +) where {T,G,H} + f_scalars = MOI.Utilities.eachscalar(f) + nn_index = MOI.add_constraint( + model, + MOI.Utilities.vectorize([MOI.Utilities.operate(-, T, f_scalars[1])]), + MOI.Nonnegatives(1), + ) + geomean_func = MOI.Utilities.operate( + vcat, + T, + MOI.Utilities.operate(/, T, f_scalars[1], -T(MOI.dimension(s) - 1)), + f_scalars[2:end], + ) + geomean_index = MOI.add_constraint( + model, + geomean_func, + MOI.GeometricMeanCone(MOI.dimension(s)), + ) + return DualGeoMeanBridge{T,G,H}(nn_index, geomean_index) +end + +function MOI.supports_constraint( + ::Type{<:DualGeoMeanBridge{T}}, + ::Type{<:MOI.AbstractVectorFunction}, + ::Type{MOI.DualGeometricMeanCone}, +) where {T} + return true +end + +function MOI.Bridges.added_constrained_variable_types( + ::Type{<:DualGeoMeanBridge}, +) + return Tuple{Type}[] +end + +function MOI.Bridges.added_constraint_types( + ::Type{<:DualGeoMeanBridge{T,G}}, +) where {T,G} + return Tuple{Type,Type,Type}[(G, MOI.Nonnegatives, MOI.GeometricMeanCone)] +end + +function concrete_bridge_type( + ::Type{<:DualGeoMeanBridge{T}}, + H::Type{<:MOI.AbstractVectorFunction}, + ::Type{MOI.DualGeometricMeanCone}, +) where {T} + S = MOI.Utilities.scalar_type(H) + G = MOI.Utilities.promote_operation( + vcat, + T, + T, + S, + MOI.Utilities.promote_operation(+, T, S, MOI.VariableIndex), + ) + return DualGeoMeanBridge{T,G,H} +end + +MOI.get(::DualGeoMeanBridge, ::MOI.NumberOfVariables)::Int64 = 0 + +function MOI.get( + ::DualGeoMeanBridge{T,G}, + ::MOI.NumberOfConstraints{G,MOI.Nonnegatives}, +)::Int64 where {T,G} + return 1 +end + +function MOI.get( + ::DualGeoMeanBridge{T,G}, + ::MOI.NumberOfConstraints{G,MOI.GeometricMeanCone}, +)::Int64 where {T,G} + return 1 +end + +function MOI.get( + bridge::DualGeoMeanBridge{T,G}, + ::MOI.ListOfConstraintIndices{G,MOI.Nonnegatives}, +) where {T,G} + return [bridge.nn_index] +end + +function MOI.get( + bridge::DualGeoMeanBridge{T,G}, + ::MOI.ListOfConstraintIndices{G,MOI.GeometricMeanCone}, +) where {T,G} + return [bridge.geomean_index] +end + +function MOI.delete(model::MOI.ModelLike, bridge::DualGeoMeanBridge) + MOI.delete(model, bridge.geomean_index) + MOI.delete(model, bridge.nn_index) + return +end + +function MOI.get( + model::MOI.ModelLike, + ::MOI.ConstraintFunction, + bridge::DualGeoMeanBridge{T,G,H}, +) where {T,G,H} + geomean_func = MOI.Utilities.eachscalar( + MOI.get(model, MOI.ConstraintFunction(), bridge.geomean_index), + ) + d = length(geomean_func) - 1 + u = MOI.Utilities.operate(*, T, geomean_func[1], T(-d)) + return MOI.Utilities.convert_approx( + H, + MOI.Utilities.operate(vcat, T, u, geomean_func[2:end]), + ) +end + +function MOI.get( + model::MOI.ModelLike, + ::MOI.ConstraintSet, + bridge::DualGeoMeanBridge, +) + return MOI.DualGeometricMeanCone( + MOI.dimension( + MOI.get(model, MOI.ConstraintSet(), bridge.geomean_index) + ) + ) +end diff --git a/src/Test/test_basic_constraint.jl b/src/Test/test_basic_constraint.jl index 4bb529ac6a..a8bd8588ca 100644 --- a/src/Test/test_basic_constraint.jl +++ b/src/Test/test_basic_constraint.jl @@ -115,6 +115,7 @@ _set(::Type{MOI.NormCone}) = MOI.NormCone(4.0, 3) _set(::Type{MOI.SecondOrderCone}) = MOI.SecondOrderCone(3) _set(::Type{MOI.RotatedSecondOrderCone}) = MOI.RotatedSecondOrderCone(3) _set(::Type{MOI.GeometricMeanCone}) = MOI.GeometricMeanCone(3) +_set(::Type{MOI.DualGeometricMeanCone}) = MOI.DualGeometricMeanCone(3) _set(::Type{MOI.ExponentialCone}) = MOI.ExponentialCone() _set(::Type{MOI.DualExponentialCone}) = MOI.DualExponentialCone() _set(::Type{T}, ::Type{MOI.PowerCone}) where {T} = MOI.PowerCone(T(1//2)) @@ -403,6 +404,7 @@ for s in [ :SecondOrderCone, :RotatedSecondOrderCone, :GeometricMeanCone, + :DualGeometricMeanCone, :ExponentialCone, :DualExponentialCone, :PowerCone, diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index 3d69c2abbf..2549853fdc 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -2850,6 +2850,7 @@ function _test_conic_GeometricMeanCone_helper( ) @test ≈(MOI.get(model, MOI.ConstraintPrimal(), c), n, config) if _supports(config, MOI.ConstraintDual) + display(MOI.get(model, MOI.ConstraintDual(), gmc)) @test ≈( MOI.get(model, MOI.ConstraintDual(), gmc), vcat(T(-1), fill(inv(T(n)), n)), @@ -3216,6 +3217,165 @@ function setup_test( return end +function _test_conic_DualGeometricMeanCone_helper( + model::MOI.ModelLike, + config::Config{T}, + use_VectorOfVariables, + n = 3, +) where {T<:Real} + # Problem DualGeoMean1 + # min -3(xyz)^(1/3) + # s.t. + # x + y + z ≤ 3 + # in conic form: + # max t + # s.t. + # (t,x,y,z) ∈ DualGeometricMeanCone(4) + # x+y+z-3 ∈ LessThan(0.) + # By the arithmetic-geometric mean inequality, + # (xyz)^(1/3) ≤ (x+y+z)/3 = 1 + # Therefore xyz ≤ 1 + # This can be attained using x = y = z = 1 so it is optimal. + @requires MOI.supports_incremental_interface(model) + @requires MOI.supports( + model, + MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}(), + ) + @requires MOI.supports(model, MOI.ObjectiveSense()) + if use_VectorOfVariables + @requires MOI.supports_constraint( + model, + MOI.VectorOfVariables, + MOI.DualGeometricMeanCone, + ) + else + @requires MOI.supports_constraint( + model, + MOI.VectorAffineFunction{T}, + MOI.DualGeometricMeanCone, + ) + end + @requires MOI.supports_constraint( + model, + MOI.ScalarAffineFunction{T}, + MOI.LessThan{T}, + ) + t = MOI.add_variable(model) + x = MOI.add_variables(model, n) + vov = MOI.VectorOfVariables([t; x]) + if use_VectorOfVariables + gmc = MOI.add_constraint(model, vov, MOI.DualGeometricMeanCone(n + 1)) + else + gmc = MOI.add_constraint( + model, + MOI.VectorAffineFunction{T}(vov), + MOI.DualGeometricMeanCone(n + 1), + ) + end + c = MOI.add_constraint( + model, + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(T(1), x), T(0)), + MOI.LessThan(T(n)), + ) + if _supports(config, MOI.NumberOfConstraints) + @test MOI.get( + model, + MOI.NumberOfConstraints{ + use_VectorOfVariables ? MOI.VectorOfVariables : + MOI.VectorAffineFunction{T}, + MOI.DualGeometricMeanCone, + }(), + ) == 1 + @test MOI.get( + model, + MOI.NumberOfConstraints{ + MOI.ScalarAffineFunction{T}, + MOI.LessThan{T}, + }(), + ) == 1 + end + MOI.set( + model, + MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}(), + MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(T(1), t)], T(0)), + ) + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + if _supports(config, MOI.optimize!) + @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED + MOI.optimize!(model) + @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status + @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT + @test ≈(MOI.get(model, MOI.ObjectiveValue()), -3, config) + @test ≈(MOI.get(model, MOI.VariablePrimal(), t), -3, config) + @test ≈(MOI.get(model, MOI.VariablePrimal(), x), ones(T, n), config) + @test ≈( + MOI.get(model, MOI.ConstraintPrimal(), gmc), + T[-3, 1, 1, 1], + config, + ) + @test ≈(MOI.get(model, MOI.ConstraintPrimal(), c), n, config) + if _supports(config, MOI.ConstraintDual) + display(MOI.get(model, MOI.ConstraintDual(), gmc)) + @test ≈( + MOI.get(model, MOI.ConstraintDual(), gmc), + ones(T, n + 1), + config, + ) + @test ≈(MOI.get(model, MOI.ConstraintDual(), c), -T(1), config) + end + end + return +end + +function test_conic_DualGeometricMeanCone_VectorOfVariables( + model::MOI.ModelLike, + config::Config{T}, +) where {T<:Real} + _test_conic_DualGeometricMeanCone_helper(model, config, true) + return +end + +function setup_test( + ::typeof(test_conic_DualGeometricMeanCone_VectorOfVariables), + model::MOIU.MockOptimizer, + ::Config{T}, +) where {T<:Real} + MOIU.set_mock_optimize!( + model, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( + mock, + T[-3, 1, 1, 1]::Vector{T}, + (MOI.ScalarAffineFunction{T}, MOI.LessThan{T}) => [-T(1)], + ), + ) + return +end + +function test_conic_DualGeometricMeanCone_VectorAffineFunction( + model::MOI.ModelLike, + config::Config{T}, +) where {T<:Real} + _test_conic_DualGeometricMeanCone_helper(model, config, false) + return +end + +function setup_test( + ::typeof(test_conic_DualGeometricMeanCone_VectorAffineFunction), + model::MOIU.MockOptimizer, + ::Config{T}, +) where {T<:Real} + MOIU.set_mock_optimize!( + model, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( + mock, + T[-3, 1, 1, 1]::Vector{T}, + (MOI.ScalarAffineFunction{T}, MOI.LessThan{T}) => [-T(1)], + (MOI.VectorAffineFunction{T}, MOI.DualGeometricMeanCone) => [ones(T, 4)], + ), + ) + return +end + function _test_conic_Exponential_helper( model::MOI.ModelLike, config::Config{T}, diff --git a/src/Utilities/distance_to_set.jl b/src/Utilities/distance_to_set.jl index 451656fb21..a200f5d2f0 100644 --- a/src/Utilities/distance_to_set.jl +++ b/src/Utilities/distance_to_set.jl @@ -359,8 +359,8 @@ end """ distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.GeometricMeanCone) -Let `(t, y...) = x`. If all `y` are non-negative, return the epigraph distance -`d` such that `(t + d, y...)` belongs to the set. +Let `(t, y...) = x`. If all `y` are non-negative, return the hypograph distance +`d` such that `(t - d, y...)` belongs to the set. If any `y` are strictly negative, return the 2-norm of the vector `d` that projects negative `y` elements to `0` and `t` to `ℝ₋`. @@ -379,6 +379,36 @@ function distance_to_set( return max(t - prod(xs)^inv(MOI.dimension(set) - 1), zero(T)) end +""" + distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.DualGeometricMeanCone) + +Let `(t, y...) = x`. If all `y` are non-negative, return the absolute value of +`d` such that `(t + d, y...)` belongs to the set. + +If any `y` are strictly negative, return the 2-norm of the vector `d` that +projects negative `y` elements to `0` and `t` to `0`. +""" +function distance_to_set( + ::ProjectionUpperBoundDistance, + x::AbstractVector{T}, + set::MOI.DualGeometricMeanCone, +) where {T<:Real} + Base.require_one_based_indexing(x) + _check_dimension(x, set) + t, xs = x[1], @view(x[2:end]) + if any(<(zero(T)), xs) # Project to x = 0 + return LinearAlgebra.norm((min.(xs, zero(T)), abs(t)), 2) + else + n = T(MOI.dimension(set)) - 1 + G = n * prod(xs)^inv(n) + if t < -G + return -G - t + else + return max(t, zero(T)) + end + end +end + """ distance_to_set(::ProjectionUpperBoundDistance, x, ::MOI.PowerCone) diff --git a/src/Utilities/model.jl b/src/Utilities/model.jl index fe06b53763..b3285189ae 100644 --- a/src/Utilities/model.jl +++ b/src/Utilities/model.jl @@ -813,6 +813,7 @@ const EqualToIndicatorZero{T} = MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, MOI.GeometricMeanCone, + MOI.DualGeometricMeanCone, MOI.ExponentialCone, MOI.DualExponentialCone, MOI.RelativeEntropyCone, diff --git a/src/sets.jl b/src/sets.jl index aaf69260bd..78235fdfa7 100644 --- a/src/sets.jl +++ b/src/sets.jl @@ -767,12 +767,6 @@ The geometric mean cone ``\\{ (t,x) \\in \\mathbb{R}^{n+1} : x \\ge 0, t \\le \\sqrt[n]{x_1 x_2 \\cdots x_n} \\}``, where `dimension = n + 1 >= 2`. -## Duality note - -The dual of the geometric mean cone is -``\\{ (u, v) \\in \\mathbb{R}^{n+1} : u \\le 0, v \\ge 0, -u \\le n \\sqrt[n]{\\prod_i v_i} \\}``, -where `dimension = n + 1 >= 2`. - ## Example ```jldoctest @@ -806,6 +800,52 @@ struct GeometricMeanCone <: AbstractVectorSet end end +dual_set(s::GeometricMeanCone) = DualGeometricMeanCone(s.dimension) +dual_set_type(::Type{GeometricMeanCone}) = DualGeometricMeanCone + +""" + DualGeometricMeanCone(dimension::Int) + +The dual geometric mean cone +``\\{ (u, v) \\in \\mathbb{R}^{n+1} : v \\ge 0, 0 \\ge u \\ge -n \\sqrt[n]{\\prod_i v_i} \\}``, +where `dimension = n + 1 >= 2`. + +## Example + +```jldoctest +julia> model = MOI.Utilities.Model{Float64}(); + +julia> t = MOI.add_variable(model) +MOI.VariableIndex(1) + +julia> x = MOI.add_variables(model, 3); + +julia> MOI.add_constraint( + model, + MOI.VectorOfVariables([t; x]), + MOI.DualGeometricMeanCone(4), + ) +MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualGeometricMean/Cone}(1) +``` +""" +struct DualGeometricMeanCone <: AbstractVectorSet + dimension::Int + function DualGeometricMeanCone(dimension::Base.Integer) + if !(dimension >= 2) + throw( + DimensionMismatch( + "Dimension of DualGeometricMeanCone must be >= 2, not " * + "$(dimension).", + ), + ) + end + return new(dimension) + end +end + +dual_set(s::DualGeometricMeanCone) = GeometricMeanCone(s.dimension) +dual_set_type(::Type{DualGeometricMeanCone}) = GeometricMeanCone + """ ExponentialCone() diff --git a/test/General/test_sets.jl b/test/General/test_sets.jl index cffd2d985d..76b1b8e6da 100644 --- a/test/General/test_sets.jl +++ b/test/General/test_sets.jl @@ -137,6 +137,7 @@ function test_sets_DimensionMismatch() (MOI.SecondOrderCone, 1), (MOI.RotatedSecondOrderCone, 2), (MOI.GeometricMeanCone, 2), + (MOI.DualGeometricMeanCone, 2), (MOI.Complements, 0), (MOI.RelativeEntropyCone, 1), (MOI.ScaledPositiveSemidefiniteConeTriangle, 0), @@ -286,6 +287,16 @@ function test_sets_dual_psdtriangle() return end +function test_sets_dual_geometric() + geo = MOI.GeometricMeanCone(4) + dual_geo = MOI.DualGeometricMeanCone(4) + _dual_set_test(geo, dual_geo) + @test MOI.dual_set(geo) != geo + _dual_set_test(dual_geo, geo) + @test MOI.dual_set(dual_geo) != dual_geo + return +end + function test_sets_dual_exponential() exp = MOI.ExponentialCone() dual_exp = MOI.DualExponentialCone() diff --git a/test/Utilities/test_distance_to_set.jl b/test/Utilities/test_distance_to_set.jl index c9499b1895..a4d9f28d05 100644 --- a/test/Utilities/test_distance_to_set.jl +++ b/test/Utilities/test_distance_to_set.jl @@ -199,6 +199,19 @@ function test_geometricmeancone() return end +function test_dualgeometricmeancone() + _test_set( + MOI.DualGeometricMeanCone(3), + [-2.0, 1.0, 1.0] => 0.0, + [3.0, 1.0, 2.0] => 3.0, + [-3.0, 1.0, 2.0] => 3.0 - 2sqrt(2), + [1.5, -1.0, 2.0] => sqrt(1 + 1.5^2), + [-1.5, -1.0, 2.0] => sqrt(1 + 1.5^2); + mismatch = [1.0], + ) + return +end + function test_powercone() _test_set( MOI.PowerCone(0.5), From 1ba78a1a5b250124e3c8aead29990753e813d384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateus=20Ara=C3=BAjo?= Date: Fri, 7 Aug 2026 17:03:48 +0200 Subject: [PATCH 2/4] formatting --- src/Bridges/Constraint/bridges/DualGeoMeanBridge.jl | 6 +++--- src/Test/test_conic.jl | 3 ++- src/sets.jl | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Bridges/Constraint/bridges/DualGeoMeanBridge.jl b/src/Bridges/Constraint/bridges/DualGeoMeanBridge.jl index 919820d15d..6682ebea7d 100644 --- a/src/Bridges/Constraint/bridges/DualGeoMeanBridge.jl +++ b/src/Bridges/Constraint/bridges/DualGeoMeanBridge.jl @@ -153,8 +153,8 @@ function MOI.get( bridge::DualGeoMeanBridge, ) return MOI.DualGeometricMeanCone( - MOI.dimension( - MOI.get(model, MOI.ConstraintSet(), bridge.geomean_index) - ) + MOI.dimension( + MOI.get(model, MOI.ConstraintSet(), bridge.geomean_index), + ), ) end diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index 2549853fdc..ead44b9bd0 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -3370,7 +3370,8 @@ function setup_test( mock, T[-3, 1, 1, 1]::Vector{T}, (MOI.ScalarAffineFunction{T}, MOI.LessThan{T}) => [-T(1)], - (MOI.VectorAffineFunction{T}, MOI.DualGeometricMeanCone) => [ones(T, 4)], + (MOI.VectorAffineFunction{T}, MOI.DualGeometricMeanCone) => + [ones(T, 4)], ), ) return diff --git a/src/sets.jl b/src/sets.jl index 78235fdfa7..184f63361e 100644 --- a/src/sets.jl +++ b/src/sets.jl @@ -825,7 +825,7 @@ julia> MOI.add_constraint( MOI.VectorOfVariables([t; x]), MOI.DualGeometricMeanCone(4), ) -MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualGeometricMean/Cone}(1) +MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.DualGeometricMeanCone}(1) ``` """ struct DualGeometricMeanCone <: AbstractVectorSet From bc5e264d65354f8cf2aa949d594f48bdffd30ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateus=20Ara=C3=BAjo?= Date: Fri, 7 Aug 2026 18:27:21 +0200 Subject: [PATCH 3/4] Update test_conic.jl --- src/Test/test_conic.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index ead44b9bd0..58a83fb4be 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -2850,7 +2850,6 @@ function _test_conic_GeometricMeanCone_helper( ) @test ≈(MOI.get(model, MOI.ConstraintPrimal(), c), n, config) if _supports(config, MOI.ConstraintDual) - display(MOI.get(model, MOI.ConstraintDual(), gmc)) @test ≈( MOI.get(model, MOI.ConstraintDual(), gmc), vcat(T(-1), fill(inv(T(n)), n)), @@ -3315,7 +3314,6 @@ function _test_conic_DualGeometricMeanCone_helper( ) @test ≈(MOI.get(model, MOI.ConstraintPrimal(), c), n, config) if _supports(config, MOI.ConstraintDual) - display(MOI.get(model, MOI.ConstraintDual(), gmc)) @test ≈( MOI.get(model, MOI.ConstraintDual(), gmc), ones(T, n + 1), From 703f993552b0f4213272ba909daf85e41bfc4099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateus=20Ara=C3=BAjo?= Date: Fri, 7 Aug 2026 19:31:49 +0200 Subject: [PATCH 4/4] fix docs --- docs/src/manual/standard_form.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/manual/standard_form.md b/docs/src/manual/standard_form.md index a0ebcf0a82..c1817d33f1 100644 --- a/docs/src/manual/standard_form.md +++ b/docs/src/manual/standard_form.md @@ -76,7 +76,7 @@ The vector-valued set types implemented in MathOptInterface.jl are: | [`ExponentialCone()`](@ref) | ``\{ (x,y,z) \in \mathbb{R}^3 : y \exp (x/y) \le z, y > 0 \}`` | | [`DualExponentialCone()`](@ref) | ``\{ (u,v,w) \in \mathbb{R}^3 : -u \exp (v/u) \le \exp(1) w, u < 0 \}`` | | [`GeometricMeanCone(d)`](@ref) | ``\{ (t,x) \in \mathbb{R}^{1+n} : x \ge 0, t \le \sqrt[n]{x_1 x_2 \cdots x_n} \}`` where ``n`` is ``d - 1`` | -| [`DualGeometricMeanCone(d)`](@ref) | ``\{ (u,v) \in \mathbb{R}^{1+n} : v \\ge 0, 0 \\ge u \\ge -n \\sqrt[n]{\\prod_i v_i} \\}``, where ``n`` is ``d - 1`` | +| [`DualGeometricMeanCone(d)`](@ref) | ``\{ (u,v) \in \mathbb{R}^{1+n} : v \ge 0, 0 \ge u \ge -n \sqrt[n]{\prod_i v_i} \}``, where ``n`` is ``d - 1`` | | [`PowerCone(α)`](@ref) | ``\{ (x,y,z) \in \mathbb{R}^3 : x^{\alpha} y^{1-\alpha} \ge \|z\|, x \ge 0,y \ge 0 \}`` | | [`DualPowerCone(α)`](@ref) | ``\{ (u,v,w) \in \mathbb{R}^3 : \left(\frac{u}{\alpha}\right)^{\alpha}\left(\frac{v}{1-\alpha}\right)^{1-\alpha} \ge \|w\|, u,v \ge 0 \}`` | | [`NormOneCone(d)`](@ref) | ``\{ (t,x) \in \mathbb{R}^{d} : t \ge \sum_i \lvert x_i \rvert \}`` |