3

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
  • 1
    Can you add a little more information here or a more complete code snippet. It is unclear what you are trying to do and it is unclear what type of things `model.disp`, `model.d1` and what is in the `df`. Please edit your post, define everything and give a sample of `df`. – AirSquid Apr 01 '21 at 16:07
  • @AirSquid Thank you for your comment. I have modified the description to make it more clear. Please let me know if it still lacks any information. – Wilson Mendes Apr 01 '21 at 20:11
  • 1
    try indexing to get v1 and v2 without the inner brackets. Doing it the way you are in pandas will get you a `Series` object. So, try this: `v1 = df.iloc[0,1]` – AirSquid Apr 01 '21 at 21:22
  • @AirSquid Thank you for the support. I tried your suggestion. Unfortunately it gave a different kind of type error. `TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'` – Wilson Mendes Apr 01 '21 at 23:00
  • Ok. You'll need to post more of your code to figure out why python thinks your `model.d1` is a NoneType. Post as much of your code as needed to reproduce the error in an edit to your post, including imports, etc. And include the stack trace that shows the line of the error for same. – AirSquid Apr 01 '21 at 23:09
  • @AirSquid I have added maximum information as possible to the post. Please go through the edited post. Thanks. – Wilson Mendes Apr 02 '21 at 09:36
  • I don’t see anything wrong... I’m away from my terminal for a couple of days, so I can’t trial run it. I do see in your error note that you are in the ipython environment? That is usually OK, but you might want to put it all in a separate script and run it to check again as sometimes re-running things in ipython has some collisions with older elements, etc. – AirSquid Apr 03 '21 at 14:01
  • @AirSquid Thank you for your kindness and support. Yes, I am using jupyter notebook which is an ipython environment. I tried re-running the code several times. There was no progress. In case if I find any solution, I will update it here. Thank you. – Wilson Mendes Apr 03 '21 at 19:05

1 Answers1

2

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...
AirSquid
  • 10,214
  • 2
  • 7
  • 31