Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variable bounds not included in list of constraint indices #185

Open
LukasBarner opened this issue Sep 27, 2022 · 1 comment
Open

Variable bounds not included in list of constraint indices #185

LukasBarner opened this issue Sep 27, 2022 · 1 comment

Comments

@LukasBarner
Copy link

Currently, model.ctr_lower does not include variable bound references:

using JuMP, BilevelJuMP, Ipopt
model = BilevelModel(Ipopt.Optimizer, mode = BilevelJuMP.ProductMode())
@variable(Upper(model), x)
@variable(Lower(model), y>=0)
@objective(Upper(model), Min, -x + 4y)
@constraint(Upper(model), y + 2x <= 9)
@objective(Lower(model), Min, -x - y )
@constraint(Lower(model), x + y <= 8)
@constraint(Lower(model),  x <= 4)
optimize!(model)
model.ctr_lower
# Dict{Int64, ConstraintRef} with 2 entries:
#   4 => x ≤ 4.0
#   3 => x + y ≤ 8.0
model.lower_dual_to_sblm
# MathOptInterface.Utilities.IndexMap with 7 entries:
#   VariableIndex(3)                                                    => VariableIndex(3)
#   VariableIndex(1)                                                    => VariableIndex(4)
#   VariableIndex(2)                                                    => VariableIndex(5)
#   ConstraintIndex{VariableIndex, LessThan{Float64}}(2)                => ConstraintIndex{VariableIndex, LessThan{Float64}}(5)
#   ConstraintIndex{VariableIndex, LessThan{Float64}}(1)                => ConstraintIndex{VariableIndex, LessThan{Float64}}(4)
#   ConstraintIndex{VariableIndex, GreaterThan{Float64}}(3)             => ConstraintIndex{VariableIndex, GreaterThan{Float64}}(3)
#   ConstraintIndex{ScalarAffineFunction{Float64}, EqualTo{Float64}}(1) => ConstraintIndex{ScalarAffineFunction{Float64}, EqualTo{Float64}}(1)
model.lower_primal_dual_map.primal_con_dual_var
# Dict{MathOptInterface.ConstraintIndex, Vector{MathOptInterface.VariableIndex}} with 3 entries:
#   ConstraintIndex{ScalarAffineFunction{Float64}, LessThan{Float64}}(2) => [VariableIndex(2)]
#   ConstraintIndex{VariableIndex, GreaterThan{Float64}}(2)              => [VariableIndex(3)]
#   ConstraintIndex{ScalarAffineFunction{Float64}, LessThan{Float64}}(1) => [VariableIndex(1)]

This leads to unexpected behavior when passing starting values to duals of variable bounds, they are not passed in this code sequence:

BilevelJuMP.jl/src/jump.jl

Lines 515 to 524 in 2d25399

for (idx, info) in model.ctr_info
if haskey(model.ctr_lower, idx)
ctr = model.ctr_lower[idx]
# this fails for vector-constrained variables due dualization 0.3.5
# because of constrained variables that change the dual
pre_duals = lower_primal_dual_map.primal_con_dual_var[JuMP.index(ctr)] # vector
duals = map(x->lower_dual_to_sblm[x], pre_duals)
pass_dual_info(single_blm, duals, info)
end
end

Fixing this would be possible by:

a) adding lower level variable bounds to model.ctr_lower after the single_blm is built. The existing code could do the rest of the work as model.lower_dual_to_sblm and model.lower_primal_dual_map.primal_con_dual_var already include the bounds.
b) Passing start values for all constrained variables after the single_blm is built.

Approach b) works fine (and I guess hints could be added the same way), for a) I am not sure if this might mess other things up that I didn't notice...
If a) does not cause chaos on other ends, I think it should be preferred?
I could take care of this in a PR.

@LukasBarner
Copy link
Author

May be obsolete if #163

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant