Skip to content

Commit 0c08da4

Browse files
authored
[Bridges] fix VectorNonlinearFunction support in NormOne and NormInfinty bridges (#2324)
1 parent cab3440 commit 0c08da4

File tree

3 files changed

+112
-6
lines changed

3 files changed

+112
-6
lines changed

src/Bridges/Constraint/bridges/norm_infinity.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ function MOI.Bridges.inverse_map_function(
7575
) where {T}
7676
# func is [t - x; t + x]
7777
scalars = MOI.Utilities.eachscalar(func)
78+
sum_f = MOI.Utilities.operate(+, T, scalars...)
7879
# Get t by `(t - x) + (t + x)`, then dividing by the number of rows.
79-
t = MOI.Utilities.operate!(/, T, sum(scalars), T(length(scalars)))
80+
t = MOI.Utilities.operate!(/, T, sum_f, T(length(scalars)))
8081
d = div(length(scalars), 2)
8182
# Get x by (t + x) - (t - x) = 2x
8283
x = MOI.Utilities.operate!(-, T, scalars[(d+1):end], scalars[1:d])

src/Bridges/Constraint/bridges/norm_one.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,10 @@ function MOI.get(
113113
::MOI.ConstraintFunction,
114114
c::NormOneBridge{T,F,G},
115115
) where {T,F,G}
116-
nn_func = MOI.Utilities.eachscalar(
117-
MOI.get(model, MOI.ConstraintFunction(), c.nn_index),
118-
)
119-
t = MOI.Utilities.operate!(/, T, nn_func[1] + sum(nn_func), T(2))
116+
nn_f = MOI.get(model, MOI.ConstraintFunction(), c.nn_index)
117+
nn_func = MOI.Utilities.eachscalar(nn_f)
118+
sum_nn_func = MOI.Utilities.operate(+, T, nn_func[1], nn_func...)
119+
t = MOI.Utilities.operate!(/, T, sum_nn_func, T(2))
120120
d = div(length(nn_func) - 1, 2)
121121
x = MOI.Utilities.operate!(
122122
/,

test/Bridges/Constraint/norm_to_lp.jl

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ function test_conic_NormOneCone()
572572
return
573573
end
574574

575-
function test_runtests()
575+
function test_runtests_vector_of_variables()
576576
MOI.Bridges.runtests(
577577
MOI.Bridges.Constraint.NormOneBridge,
578578
"""
@@ -598,6 +598,111 @@ function test_runtests()
598598
return
599599
end
600600

601+
function test_runtests_vector_affine_function()
602+
MOI.Bridges.runtests(
603+
MOI.Bridges.Constraint.NormOneBridge,
604+
"""
605+
variables: t, x
606+
[t, 2.0 * x + 1.0] in NormOneCone(2)
607+
""",
608+
"""
609+
variables: t, x, y
610+
[t + -1.0 * y, y + -2.0 * x + -1.0, y + 2.0 * x + 1.0] in Nonnegatives(3)
611+
""",
612+
)
613+
MOI.Bridges.runtests(
614+
MOI.Bridges.Constraint.NormInfinityBridge,
615+
"""
616+
variables: t, x
617+
[t, 2.0 * x + 1.0] in NormInfinityCone(2)
618+
""",
619+
"""
620+
variables: t, x
621+
[t + -2.0 * x + -1.0, t + 2.0 * x + 1.0] in Nonnegatives(2)
622+
""",
623+
)
624+
return
625+
end
626+
627+
function test_NormInfinity_VectorNonlinearFunction()
628+
# We can't use the standard runtests because ScalarNonlinearFunction does
629+
# not preserve f(x) ≈ (f(x) - g(x)) + g(x)
630+
inner = MOI.Utilities.Model{Float64}()
631+
model = MOI.Bridges.Constraint.NormInfinity{Float64}(inner)
632+
t = MOI.add_variable(model)
633+
x = MOI.add_variable(model)
634+
f = MOI.VectorNonlinearFunction([
635+
MOI.ScalarNonlinearFunction(:+, Any[t]),
636+
MOI.ScalarNonlinearFunction(:sin, Any[x]),
637+
])
638+
c = MOI.add_constraint(model, f, MOI.NormInfinityCone(2))
639+
F, S = MOI.VectorNonlinearFunction, MOI.Nonnegatives
640+
indices = MOI.get(inner, MOI.ListOfConstraintIndices{F,S}())
641+
@test length(indices) == 1
642+
inner_variables = MOI.get(inner, MOI.ListOfVariableIndices())
643+
@test length(inner_variables) == 2
644+
u, v = inner_variables
645+
u_p = MOI.ScalarNonlinearFunction(:+, Any[u])
646+
v_sin = MOI.ScalarNonlinearFunction(:sin, Any[v])
647+
g = MOI.VectorNonlinearFunction([
648+
MOI.ScalarNonlinearFunction(
649+
:+,
650+
Any[MOI.ScalarNonlinearFunction(:-, Any[v_sin]), u_p],
651+
),
652+
MOI.ScalarNonlinearFunction(:+, Any[v_sin, u_p]),
653+
])
654+
@test (MOI.get(inner, MOI.ConstraintFunction(), indices[1]), g)
655+
h = MOI.VectorNonlinearFunction([
656+
MOI.ScalarNonlinearFunction(:+, Any[t]),
657+
MOI.ScalarNonlinearFunction(:cos, Any[x]),
658+
])
659+
MOI.set(model, MOI.ConstraintFunction(), c, h)
660+
v_cos = MOI.ScalarNonlinearFunction(:cos, Any[v])
661+
g_2 = MOI.VectorNonlinearFunction([
662+
MOI.ScalarNonlinearFunction(
663+
:+,
664+
Any[MOI.ScalarNonlinearFunction(:-, Any[v_cos]), u_p],
665+
),
666+
MOI.ScalarNonlinearFunction(:+, Any[v_cos, u_p]),
667+
])
668+
@test (MOI.get(inner, MOI.ConstraintFunction(), indices[1]), g_2)
669+
return
670+
end
671+
672+
function test_NormOne_VectorNonlinearFunction()
673+
# We can't use the standard runtests because ScalarNonlinearFunction does
674+
# not preserve f(x) ≈ (f(x) - g(x)) + g(x)
675+
inner = MOI.Utilities.Model{Float64}()
676+
model = MOI.Bridges.Constraint.NormOne{Float64}(inner)
677+
t = MOI.add_variable(model)
678+
x = MOI.add_variable(model)
679+
f = MOI.VectorNonlinearFunction([
680+
MOI.ScalarNonlinearFunction(:+, Any[t]),
681+
MOI.ScalarNonlinearFunction(:sin, Any[x]),
682+
])
683+
c = MOI.add_constraint(model, f, MOI.NormOneCone(2))
684+
F, S = MOI.VectorNonlinearFunction, MOI.Nonnegatives
685+
indices = MOI.get(inner, MOI.ListOfConstraintIndices{F,S}())
686+
@test length(indices) == 1
687+
inner_variables = MOI.get(inner, MOI.ListOfVariableIndices())
688+
@test length(inner_variables) == 3
689+
u, v, w = inner_variables
690+
v_sin = MOI.ScalarNonlinearFunction(:sin, Any[v])
691+
g = MOI.VectorNonlinearFunction([
692+
MOI.ScalarNonlinearFunction(
693+
:-,
694+
Any[MOI.ScalarNonlinearFunction(:+, Any[u]), 0.0+1.0*w],
695+
),
696+
MOI.ScalarNonlinearFunction(
697+
:+,
698+
Any[MOI.ScalarNonlinearFunction(:-, Any[v_sin]), w],
699+
),
700+
MOI.ScalarNonlinearFunction(:+, Any[v_sin, w]),
701+
])
702+
@test (MOI.get(inner, MOI.ConstraintFunction(), indices[1]), g)
703+
return
704+
end
705+
601706
end # module
602707

603708
TestConstraintNormInfinity.runtests()

0 commit comments

Comments
 (0)