I am working on lagrangian relaxation of a particular problem, and I meet the following error.
The original problem consists of 10 almost independent subproblems, where 10 subproblems are only linked by 1 simple linking constraint.
Hence the linking constraint is penalized, moved to objective, and then 10 independent subproblems are solved with modified objective.
read problem input W
m = Vector{Model}( undef, 10 )
# add variables and constraints
# to define feasible region for each subproblem
for k in 1:10
m[ k ] = Model( solver = GurobiSolver() )
@variable( m[ k ] , c )
end
# outter loop for update lagrangian dual variables
for it in 1:50
set up lagrangian dual variable \lambda
# inner loop for solving decomposed subproblem
# with modified objective
for k in 1:10
@objective( m[ k ] , Min , c - \lambda )
solve( m[ k ] )
end
end
But julia says c is not defined when it encoutner the second loop. Can anyone help me on this?
ERROR: LoadError: UndefVarError: c not defined
Stacktrace:
[1] top-level scope at C:\Users\tommyricardo\.julia\packages\JuMP\PbnIJ\src\parseExpr_staged.jl:508
[2] top-level scope at C:\Users\tommyricardo\.julia\packages\JuMP\PbnIJ\src\macros.jl:859
[3] top-level scope at F:\a__top_secret\lagrangian_relaxation_TypeExperiment_SingleUnitQIP.jl:173
in expression starting at F:\a__top_secret\lagrangian_relaxation_TypeExperiment_SingleUnitQIP.jl:171
There are a couple of problems you’re running into. The first has nothing to do with JuMP and is simply the fact that loops in Julia create their own scope:
julia> for k in 1:10
c = 5
end
julia> c
ERROR: UndefVarError: c not defined
But even if they didn’t, after your k in 1:10 loop completes, c would just refer to the variable in the last iteration (that is, the variable in model m[10]). That’s almost certainly not what you want.
You probably want to also maintain a collection of variables c like your collection of models m. That way you can refer to the variable c belonging to the correct model each time. For example:
cs = Vector{Variable}()
for k in 1:10
m[k] = Model()
@variable(m[k], c)
push!(cs, c)
end
...
for k in 1:10
@objective(m[k], Min, cs[k] - \lambda)
end
Thanks very much! I saved those variables into Vector, and the code could be excuted.
But then I am a bit confused in this case… this is also related to reply from @nitu0317. From @rdeits’s comment I have the following understanding.
Since I have decleared a Vector of model m. When a variable c is added to m[ k ] in the way @variable( m[ k ] , c ), some variable is added to model m[ k ] but it is not particularly named by c. And we could only refer to that variable by the name c under current scope.
When I use @objective( m[ k ] , c ) at second loop, julia is looking for c as a variable at current scope , rather than a variable from the model m[ k ].
I did the following small experiment
m = Model( solver = GurobiSolver( ) )
@variable( m , b )
@constraint( m , b >= 1 )
b = 4
@constraint( m , b >= 3 )
@objective( m , Min , b )
print( m )
The resulting model is
Min 4
Subject to
b >= 1
0 >= -1
b
This is quite suprising to me… Is there any way to give a “global fixed” name to a variable in some models ? So that for the rest of the code we can tell julia we are refering to that particular variable.
If I understand your question correctly, then the answer is no. When you write @constraint(m, b >= 3), you are telling JuMP to create a constraint involving whatever value has the name b in your current scope. That has nothing to do with the fact that in your model, you happened to have a JuMp variable also named “b”.
However, you can ask the model to look up a variable by its name. For example:
for k in 1:10
b = m[:b] # get the JuMP variable named "b" and assign it to the Julia variable `b`
@objective(m, Min, b)
end
in the latest version of JuMP, I believe you can use JuMP.variable_by_name(m, "b") instead of m[:b].