Gurobi / gurobipy-pandas

Convenience wrapper for building optimization models from pandas data
https://gurobipy-pandas.readthedocs.io/en/stable/
Apache License 2.0
83 stars 15 forks source link

Pandas accessor functionality for setting attributes #37

Closed rrandall1471 closed 1 year ago

rrandall1471 commented 1 year ago

I like the current attribute functionality for many functions when updating attributes like LB or UB but there are times when I think that it would be nice to be able to do it using chaining similarly to creating constraints. As an example let's say I have a df that has two variable columns v1 and v2 and I have a subset of those variables I need to set an UB for, so I could do the following:

df.query("i == 'A'")['v1'].grb.UB = X
df.query("i == 'A'")['v2'].grb.UB = Y

however, I think a cleaner format would be:

df.query("i == 'A'").grb.set(m, 'v1', grb.GRB.UB, X).grb.set(m, 'v2', grb.GRB.UB, Y)
Dr-Irv commented 1 year ago

Or get setAttr to work. This code raises an exception:

>>> df=pd.DataFrame(index=range(5))
>>> df
Empty DataFrame
Columns: []
Index: [0, 1, 2, 3, 4]
>>> m=grb.Model()
>>> x=df.grb.pd_add_vars(m, "x")
>>> x
                                      x
0  <gurobi.Var *Awaiting Model Update*>
1  <gurobi.Var *Awaiting Model Update*>
2  <gurobi.Var *Awaiting Model Update*>
3  <gurobi.Var *Awaiting Model Update*>
4  <gurobi.Var *Awaiting Model Update*>
>>> m.update()
>>> x
                   x
0  <gurobi.Var x[0]>
1  <gurobi.Var x[1]>
2  <gurobi.Var x[2]>
3  <gurobi.Var x[3]>
4  <gurobi.Var x[4]>
>>> x.grb.setAttr("LB", 10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'GRBDataFrameAccessor' object has no attribute 'setAttr'
>>> x["x"].grb.setAttr("LB", 10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Anaconda3\envs\gurobi\lib\site-packages\gurobipy_pandas\accessors.py", line 259, in __getattr__
    data=[v.getAttr(attr) for v in self._obj],
  File "C:\Anaconda3\envs\gurobi\lib\site-packages\gurobipy_pandas\accessors.py", line 259, in <listcomp>
    data=[v.getAttr(attr) for v in self._obj],
  File "src\gurobipy\var.pxi", line 153, in gurobipy.Var.getAttr
  File "src\gurobipy\attrutil.pxi", line 35, in gurobipy.__getattr
  File "src\gurobipy\attrutil.pxi", line 23, in gurobipy.__getattrinfo
AttributeError: 'gurobipy.Var' object has no attribute 'setAttr'
>>> x["x"].iloc[0]
<gurobi.Var x[0]>
>>> x["x"].iloc[0].setAttr("LB", 10)

The error message doesn't make sense, as gurobipy.Var does have setAttr !!

simonbowly commented 1 year ago

I agree, it makes sense to have getAttr/setAttr work intuitively for gurobipy users. These methods on the series accessor now return the original series so you can do for example:

>>> m = gp.Model()
>>> x = pd.RangeIndex(3).grb.pd_add_vars(m, name='x')
>>> m.update()
>>> x.grb.setAttr("LB", 3.0).grb.setAttr("UB", 5.0)
0    <gurobi.Var x[0]>
1    <gurobi.Var x[1]>
2    <gurobi.Var x[2]>
Name: x, dtype: object
>>> m.update()
>>> x.grb.getAttr("LB")
0    3.0
1    3.0
2    3.0
Name: x, dtype: float64
>>> x.grb.getAttr("UB")
0    5.0
1    5.0
2    5.0
Name: x, dtype: float64