Skip to content

Commit c320ca7

Browse files
authored
[Bridges] fix getting ConstraintPrimal if Variable bridges are present (#2396)
1 parent f09c7ff commit c320ca7

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

src/Bridges/bridge_optimizer.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,31 @@ function MOI.get(
14961496
return unbridged_function(b, func)
14971497
end
14981498

1499+
function MOI.get(
1500+
b::AbstractBridgeOptimizer,
1501+
attr::MOI.ConstraintPrimal,
1502+
ci::MOI.ConstraintIndex{F,S},
1503+
) where {F<:MOI.AbstractScalarFunction,S<:MOI.AbstractScalarSet}
1504+
if is_bridged(b, ci)
1505+
MOI.throw_if_not_valid(b, ci)
1506+
return call_in_context(MOI.get, b, ci, attr)
1507+
end
1508+
if Variable.has_bridges(Variable.bridges(b))
1509+
# In this case, the scalar constraint might contain bridged variables
1510+
# that include constants, like `x >= 1` being mapped to `y >= 0`,
1511+
# `x := y + 1`. If this is true, then `normalize_and_add_constraint`
1512+
# may move the constants into the set, and querying `ConstraintPrimal`
1513+
# from `b.model` will return the value of `y`, not `y + 1`. As a
1514+
# work-around, we use `get_fallback`, which first queries
1515+
# `ConstraintFunction` and then evaluates the function at the point
1516+
# defined by `VariablePrimal`. Querying `ConstraintFunction` accounts
1517+
# for the case where constants were moved to the set, so we return the
1518+
# correct value.
1519+
return MOI.Utilities.get_fallback(b, attr, ci)
1520+
end
1521+
return MOI.get(b.model, attr, ci)
1522+
end
1523+
14991524
function MOI.supports(
15001525
b::AbstractBridgeOptimizer,
15011526
attr::MOI.AbstractConstraintAttribute,

test/Bridges/lazy_bridge_optimizer.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,24 @@ function test_MOI_runtests_GeometricSDPAModel()
333333
return
334334
end
335335

336+
function test_get_primal_variable_bridge()
337+
cache = MOI.Utilities.Model{Float64}()
338+
x, c1 = MOI.add_constrained_variable(cache, MOI.GreaterThan(1.0))
339+
c2 = MOI.add_constraint(cache, 1.0x, MOI.EqualTo(2.0))
340+
inner = MOI.Utilities.MockOptimizer(StandardSDPAModel{Float64}())
341+
model = MOI.Bridges.full_bridge_optimizer(inner, Float64)
342+
index_map = MOI.copy_to(model, cache)
343+
MOI.Utilities.set_mock_optimize!(
344+
inner,
345+
mock -> MOI.Utilities.mock_optimize!(mock, [1.0]),
346+
)
347+
MOI.optimize!(model)
348+
@test MOI.get(model, MOI.VariablePrimal(), index_map[x]) == 2.0
349+
@test MOI.get(model, MOI.ConstraintPrimal(), index_map[c1]) == 2.0
350+
@test MOI.get(model, MOI.ConstraintPrimal(), index_map[c2]) == 2.0
351+
return
352+
end
353+
336354
function test_index_constraint_conflict()
337355
optimizer = StandardSDPAModel{Float64}()
338356
model = MOI.Bridges.full_bridge_optimizer(optimizer, Float64)

0 commit comments

Comments
 (0)