I want to get all variables in my model organized in containers, whenever possible. I am currently using object_dictionary for that, which seems quite satisfactory, but the order does not follow the creation order, which is important for me.
I would expect the order to be :x → :y → :z, since that is (roughly) what I get from all_variables(m) (and that is the creation order, as per the documentation).
I am now recovering the creation order by backwards-searching the all_variables(m) list, but that seems quite sketchy. On top of that, I am not quite sure how reliable the object dictionary is for getting the variables as containers (when one exists), as I need to check whether every item is a VariableRef of an AbstractArray of it.
Is there a better way to get those containers and variablerefs in order of creation?
I noticed that the obj_dict is not stored as an ordered dict. Maybe converting it to an ordered dict could make things more intuitive? Although, I haven’t looked at non-GenericModels, so I have not idea how big the downstream impacts would be.
The input of my algorithm is a list of players (in a Nash game), each with a jump model (feasible space) and a function (payoff). Each payoff is a function of the player’s variables and is parameterized by the other players’ variables. Up to now, I was requiring the function to be defined over all_variables, but that gets really inconvenient if the variables are defined as containers. By using object_dictionary, the function could be defined over a more familiar structure, if the order was known.
Writing this made me realize maybe I should reconsider extending the Model.
Don’t rely on the variables being added in a particular order, or the fact that they are registered in the object_dictionary. Create a proper data structure that you control. For example, ask the user to provide a list of their arguments to the payoff function.
I think with some refactor that will do the trick!
On a side note, I have read a bit of the implementation of BilevelJuMP.jl and it seems their approach is very suitable for what I envision here. Generalizing it beyond two-player-Stackelberg games would work wonders for my case and would allow players to have constraints that depend on other players’ variables (completely out-of-scope for me right now, but very helpful for the community).
Now that I am handling the variable references in my custom struct, how can I create copies of it?
using JuMP
struct Foo
X::Model
vars::Vector{Union{VariableRef, AbstractArray{VariableRef}}}
end
function Base.copy(f::Foo)
X_copy = copy(f.X)
vars_copy = ?
return Foo(X_copy, vars_copy)
end
I feel like the only way would be to try and do a reverse search on object_dictionary, but that would again have to rely on variables being registered there, and I don’t even know how to do that for containers.
In my tests I check that a payoff function is working by comparing it to other payoff functions over the same Model, so that is when I define the model once and copy it multiple times.
That is also similar to a use case that I expect my user to have. A game in which all players have the same constraints, but different payoff functions. So it would be nice to have a way to copy the models and vars.