Search code examples
pythonpandasnumpytypeerrorpyomo

TypeError PYOMO: Defining constraints based on pandas dataframe


For an optimization problem, I am trying to define a constraint in PYOMO, where the the constraint expression includes some specific values from a pandas DataFrame.

I will try to explain my problem in a concise way.

Following are the imports.

from pyomo.environ import *
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt 
from pyomo.opt import SolverFactory

model = ConcreteModel()

The following are the decision variables.

model.d1 = Var(bounds=(0.8,1.0), initialize = 0.9)
model.t1 = Var(bounds=(0.1,0.3))

The objective function is given below:

model.Total_weight = Objective(expr=  model.t1*model.d1, sense= minimize )

To formulate a constraint expression, I am using some values from a DataFrame.

The DataFrame would look like this:

r1 = [50.05,60.0,70]
r2 = [100,150,200]

df = pd.DataFrame([r1,r2])

        0      1    2
0   50.05   60.0   70
1  100.00  150.0  200

Current Idea:

I am assigning some of the values from the df to variables, in order to be used in the constraint expression (as shown below).

v1 = df.iloc[0, 1]
v2 = df.iloc[1,1]

The only purpose of v1 and v2 is to input value to the constraint expression. It has nothing to do with the optimization model.

model.C1 = Constraint(expr =  v1 +  v2 *model.d1 <= 2.1)

But I got the following error while executing this idea

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-a9a7f2887bcb> in <module>
----> 1 model.C1 = Constraint(expr = v1 +  v2 *model.d1)

TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'

To my understanding, python considers v1 and v2 as 'float' and model.d1 is considered as 'NoneType'. I tried to run the model by adding initialize to the variable model.d1. But still it seems 'NoneType'.

Can someone please help me to solve this?

Thank you very much in advance.

PS: model.d1.display() gives following output.

d1 : Size=1, Index=None
    Key  : Lower : Value : Upper : Fixed : Stale : Domain
    None :   0.8 :   0.9 :   1.0 : False : False :  Reals

Solution

  • So you might have stumbled onto a small bug in how pyomo interacts with numpy values when the pyomo variable is a singleton.... I don't think this comes up too often as the problem does not expose itself when dealing with indexed pyomo variables, which is by far the majority case. Yours are non-indexed singletons.

    First, let's get your model working. Convert the values coming out of your df into floats and this works fine.

    from pyomo.environ import *
    #import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt 
    #from pyomo.opt import SolverFactory
    
    model = ConcreteModel()
    
    model.d1 = Var(bounds=(0.8,1.0), domain=NonNegativeReals)
    model.t1 = Var(bounds=(0.1,0.3), domain=NonNegativeReals)
    
    r1 = [50.05,60.0,70]
    r2 = [100,150,200]
    
    df = pd.DataFrame([r1,r2])
    
    v1 = float(df.iloc[0, 1])   # NOTE the float() conversion
    v2 = float(df.iloc[1, 1])   # NOTE the float() conversion
    
    model.C1 = Constraint(expr=v1 + v2 * model.d1 <= 2.1)
    
    model.pprint()
    

    The suspected bug...

    Both of these should execute by my understanding. I almost never deal w/ singleton variables (that are not indexed) so perhaps there is something else afoot here. I'll try to submit this to pyomo folks as a bug and see what comes of it.

    from pyomo.environ import *
    import numpy as np
    
    c = np.float64(1.5)  # a numpy float like what comes out of a pd dataframe...
    
    model_1 = ConcreteModel()
    
    model_1.x = Var()
    
    # a simple expression
    e = c * model_1.x     # FAILS!  TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'
    
    
    model_2 = ConcreteModel()
    
    model_2.S = Set(initialize = [1,])   # indexing set with 1 member
    
    model_2.x = Var(model_2.S)
    
    # same expression
    e2 = c * model_2.x[1]  # Works fine...