model.getVars() TypeError: unhashable type: 'slice'
回答済みgurobipy 11.0.3 is normal, but after I updated gurobipy 12.0.0, an error occurred when using model. getVars(). Thank you for your support and help:
allvars = m.getVars()
File "src\\gurobipy\\_model.pyx", line 491, in gurobipy._model.Model.getVars
TypeError: unhashable type: 'slice'
Exception ignored in: <cyfunction Model.__del__ at 0x000001CCD4B7E110>
Traceback (most recent call last):
File "src\\gurobipy\\_model.pyx", line 187, in gurobipy._model.Model.__del__
File "src\\gurobipy\\_model.pyx", line 287, in gurobipy._model.Model.close
File "src\\gurobipy\\_model.pyx", line 247, in gurobipy._model.Model.dispose
AttributeError: 'tuple' object has no attribute '_cmodel'
-
Hi James,
This issue arises if you use ._vars in your code. We will likely avoid this error occurring in the next release but a simple workaround is to rename ._vars to something else.
A better workaround is to avoid assigning any new attributes to an object (other than SimpleNamespace) - this is general Python advice - with one of the following patterns:
Using a closure
def make_callback(vars): def cb(model, where): if where == gp.GRB.Callback.MIPSOL: print("variables", vars) return cb m = gp.Model() # build model m.update() vars = m.getVars() m.optimize(make_callback(vars))
Using a function to create another function, which can be used to capture state, is called a closure. Note that "myvars" is not an argument to the cb function, but it knows that it exists and is able to use it because it exists in the same scope as when the cb function is defined.
Using the cbdata argument of a callback functionfrom functools import partial from types import SimpleNamespace def cb(model, where, *, cbdata): if where == gp.GRB.Callback.MIPSOL: print("variables", cbdata.vars) m = gp.Model() # build model m.update() userdata = SimpleNamespace() # or define and use your own empty class userdata.vars = m.getVars() callback_func = partial(cb, userdata=userdata) m.optimize(callback_func)
This is essentially using functools.partial to create a closure, and we demonstrate this approach in callback.py
Using a callback classclass Callback: def __init__(self, vars): self.vars = vars def __call__(self, model, where): if where == gp.GRB.Callback.MIPSOL: print("variables", self.vars) m = gp.Model() # build model m.update() cb = Callback(m.getVars()) m.optimize(cb)
We demonstrate this approach in tsp.py.
- Riley
0 -
Thank you, Riley. When I changed all `m._vars` to `m._varis`, the code worked fine.
I did use `m._vars` in the code because I need to obtain the variable names with values greater than 0 in the callback for the next step, for example:
`var_tupledict = m.cbGetSolution(m._vars) # returns tupledict`
Then I can use `varName = [i for i in var_tupledict.keys() if tupledict[i] > 0]`
But when I tried using a closure
```python
def make_callback(vars):
def cb(model, where):
if where == gp.GRB.Callback.MIPSOL:
print("variables", vars)
value_list = model.cbGetSolution(vars) # returns a list of values
return cb
vars = m.getVars()
m.optimize(make_callback(vars))
```
I can only use the corresponding index of the list to obtain the variable names.
`varName = [v.VarName for value, v in zip(value_list, vars) if value > 0]`
Why does `cbGetSolution` return different types of data?
Thank you again!0 -
Hi James,
No problem. The return type of cbGetSolution is determined by the input type. This is by design, see
https://docs.gurobi.com/projects/optimizer/en/current/reference/python/model.html#Model.cbGetSolutionThe getVars() method returns a list of variables then you are passing this to the make_callback function. If you prefer to work with tupledicts like you were doing then just use the tupledict as an argument to make_callback instead. There isn't anything you can do with the ._vars approach that can't be easily replicated with the other approaches.
- Riley
0
サインインしてコメントを残してください。
コメント
3件のコメント