Suppose I have a Dict
where I store a config with the optimisation I want to do. So something like the below:
portfolio = Model(Ipopt.Optimizer)
@variable(portfolio, x[1:5])
max_ = 10.0
min_ = [1,2,3,4,5]
constraints = Dict{String, String}()
constraints["max_constraint"] = "x .<= max_"
constraints["min_constraint"] = "x >= min_"
I want to loop through everything in constraints and put it into model as a constraint with the name as per the name of the key in the dict. So basically I want to do:
for k in keys(constraints)
@constraint(portfolio, k, constraints[k])
end
This doesnt work for either constraint but I can copy paste the contents of the Dict
to make it work:
@constraint(portfolio, max_constraint, x .<= max_)
@constraint(portfolio, min_constraint, x >= min_)
So how can I add the constraints using the strings directly from the Dict
? In addition is there a way to do this that is robust to if max_
and min_
fall out of scope (for instance the additional of constraints are added in a function call with the model being returned).
In order to get from strings describing the constraint to expressions, there needs to be a parsing stage. After parsing, the macro/function to add the constraint expression needs to be called. So the following did work for me in a test:
for (name, con) in constraints
e = Meta.parse("@constraint(portfolio, $name, $con)")
@eval $e
end
In any case, JuMP allows to produce constraints programmatically, and that may be something to explore.
Finally, if the strings describing the constraints are coming from an external file or source, using @eval
introduces risks (security and such) and you may want to control the strings parsed and evaluated somehow.