メインコンテンツへスキップ

model.getVars() TypeError: unhashable type: 'slice'

回答済み

コメント

3件のコメント

  • Riley Clement
    Gurobi Staff Gurobi Staff

    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 function

    from 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 class

    class 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
  • james l
    First Comment
    First Question

    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
  • Riley Clement
    Gurobi Staff Gurobi Staff

    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.cbGetSolution

    The 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

サインインしてコメントを残してください。