diff --git a/src/Bridges/Constraint/bridges/RSOCtoSOCBridge.jl b/src/Bridges/Constraint/bridges/RSOCtoSOCBridge.jl index 718675d02f..7c08ad40c3 100644 --- a/src/Bridges/Constraint/bridges/RSOCtoSOCBridge.jl +++ b/src/Bridges/Constraint/bridges/RSOCtoSOCBridge.jl @@ -59,12 +59,17 @@ end function MOI.Bridges.map_function(::Type{<:RSOCtoSOCBridge{T}}, func) where {T} scalars = MOI.Utilities.eachscalar(func) - # We cannot construct MOI.RotatedSecondOrderCone(1) @assert length(scalars) >= 2 t, u, x = scalars[1], scalars[2], scalars[3:end] ts = MOI.Utilities.operate!(/, T, t, sqrt(T(2))) us = MOI.Utilities.operate!(/, T, u, sqrt(T(2))) - return MOI.Utilities.operate(vcat, T, ts + us, ts - us, x) + return MOI.Utilities.operate( + vcat, + T, + MOI.Utilities.operate(+, T, ts, us), + MOI.Utilities.operate(-, T, ts, us), + x, + ) end # The map is an involution diff --git a/src/Bridges/Variable/bridges/RSOCtoSOCBridge.jl b/src/Bridges/Variable/bridges/RSOCtoSOCBridge.jl index bb0ba39aac..efc5f424bb 100644 --- a/src/Bridges/Variable/bridges/RSOCtoSOCBridge.jl +++ b/src/Bridges/Variable/bridges/RSOCtoSOCBridge.jl @@ -70,10 +70,17 @@ end function MOI.Bridges.map_function(::Type{<:RSOCtoSOCBridge{T}}, func) where {T} scalars = MOI.Utilities.eachscalar(func) + @assert length(scalars) >= 2 t, u, x = scalars[1], scalars[2], scalars[3:end] ts = MOI.Utilities.operate!(/, T, t, sqrt(T(2))) us = MOI.Utilities.operate!(/, T, u, sqrt(T(2))) - return MOI.Utilities.operate(vcat, T, ts + us, ts - us, x) + return MOI.Utilities.operate( + vcat, + T, + MOI.Utilities.operate(+, T, ts, us), + MOI.Utilities.operate(-, T, ts, us), + x, + ) end # The map is an involution diff --git a/src/Bridges/Variable/bridges/SOCtoRSOCBridge.jl b/src/Bridges/Variable/bridges/SOCtoRSOCBridge.jl index c54992130c..593edd0c7f 100644 --- a/src/Bridges/Variable/bridges/SOCtoRSOCBridge.jl +++ b/src/Bridges/Variable/bridges/SOCtoRSOCBridge.jl @@ -83,10 +83,17 @@ end function MOI.Bridges.map_function(::Type{<:SOCtoRSOCBridge{T}}, func) where {T} scalars = MOI.Utilities.eachscalar(func) + @assert length(scalars) >= 2 t, u, x = scalars[1], scalars[2], scalars[3:end] ts = MOI.Utilities.operate!(/, T, t, sqrt(T(2))) us = MOI.Utilities.operate!(/, T, u, sqrt(T(2))) - return MOI.Utilities.operate(vcat, T, ts + us, ts - us, x) + return MOI.Utilities.operate( + vcat, + T, + MOI.Utilities.operate(+, T, ts, us), + MOI.Utilities.operate(-, T, ts, us), + x, + ) end # The map is an involution diff --git a/test/Bridges/Constraint/test_RSOCBridge.jl b/test/Bridges/Constraint/test_RSOCBridge.jl index 8bc4bc15c5..f52e20f3d2 100644 --- a/test/Bridges/Constraint/test_RSOCBridge.jl +++ b/test/Bridges/Constraint/test_RSOCBridge.jl @@ -199,6 +199,42 @@ function test_dimension_mismatch_RSOC() return end +function test_map_function_SOC() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Constraint.SOCR{Float64}(inner) + x = MOI.add_variables(model, 3) + ci = MOI.add_constraint( + model, + MOI.VectorOfVariables(x), + MOI.SecondOrderCone(3), + ) + y = MOI.VectorNonlinearFunction([ + MOI.ScalarNonlinearFunction(:+, Any[x[i]]) for i in 1:3 + ]) + g = MOI.Bridges.map_function(model.map[ci], y) + @test MOI.Utilities.eval_variables(xi -> abs(xi.value), model, g) == + [3 / sqrt(2), -1 / sqrt(2), 3] + return +end + +function test_map_function_RSOC() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Constraint.RSOC{Float64}(inner) + x = MOI.add_variables(model, 3) + ci = MOI.add_constraint( + model, + MOI.VectorOfVariables(x), + MOI.RotatedSecondOrderCone(3), + ) + y = MOI.VectorNonlinearFunction([ + MOI.ScalarNonlinearFunction(:+, Any[x[i]]) for i in 1:3 + ]) + g = MOI.Bridges.map_function(model.map[ci], y) + @test MOI.Utilities.eval_variables(xi -> abs(xi.value), model, g) == + [3 / sqrt(2), -1 / sqrt(2), 3] + return +end + end # module TestConstraintRSOC.runtests() diff --git a/test/Bridges/Variable/test_RSOCtoSOCBridge.jl b/test/Bridges/Variable/test_RSOCtoSOCBridge.jl index ca397beb6c..cebdb98484 100644 --- a/test/Bridges/Variable/test_RSOCtoSOCBridge.jl +++ b/test/Bridges/Variable/test_RSOCtoSOCBridge.jl @@ -177,6 +177,19 @@ function test_ConstraintDualStart() return end +function test_map_function() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Variable.RSOCtoSOC{Float64}(inner) + x, _ = MOI.add_constrained_variables(model, MOI.RotatedSecondOrderCone(3)) + y = MOI.VectorNonlinearFunction([ + MOI.ScalarNonlinearFunction(:+, Any[x[i]]) for i in 1:3 + ]) + g = MOI.Bridges.map_function(model.map[first(x)], y) + @test MOI.Utilities.eval_variables(xi -> abs(xi.value), model, g) == + [3 / sqrt(2), -1 / sqrt(2), 3] + return +end + end # module TestVariableRSOCtoSOC.runtests() diff --git a/test/Bridges/Variable/test_SOCtoRSOCBridge.jl b/test/Bridges/Variable/test_SOCtoRSOCBridge.jl index 788a709eda..1d56254eae 100644 --- a/test/Bridges/Variable/test_SOCtoRSOCBridge.jl +++ b/test/Bridges/Variable/test_SOCtoRSOCBridge.jl @@ -184,6 +184,19 @@ function test_ConstraintDualStart() return end +function test_map_function() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Variable.SOCtoRSOC{Float64}(inner) + x, _ = MOI.add_constrained_variables(model, MOI.SecondOrderCone(3)) + y = MOI.VectorNonlinearFunction([ + MOI.ScalarNonlinearFunction(:+, Any[x[i]]) for i in 1:3 + ]) + g = MOI.Bridges.map_function(model.map[first(x)], y) + @test MOI.Utilities.eval_variables(xi -> abs(xi.value), model, g) == + [3 / sqrt(2), -1 / sqrt(2), 3] + return +end + end # module TestVariableSOCtoRSOC.runtests()