Pyomo Error: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Pyomo Error: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

我正在 pyomo 中构建优化模型,但一直面临这个我无法解决的错误。 这是发生错误的部分:

model.ct2demand = ConstraintList()
for n in model.N: 
    for s in model.S:
        for t in model.T: 
            for p in model.P:
                lhs = model.f[p,t,s,n]*1000 
                rhs = model.y[p,t,s,n] + model.sales[p,t,s,n] + model.error[p,t,s,n] 
                model.ct2demand.add (lhs == rhs) 

变量 f 和错误是多维参数(非负实数),我将其作为 numpy 数组输入,根据我的研究认为是导致此问题的原因,但我还没有真正弄清楚原因。 y 和 sales 是决策变量。以下是错误信息:

ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_21076/2031668078.py in <module>
    422             for p in model.P:
    423                 lhs = model.f[p,t,s,n]
--> 424                 rhs = model.y[p,t,s,n] + model.sales[p,t,s,n] + model.error[p,t,s,n]
    425                 model.ct2demand.add (lhs == rhs)
    426 

pyomo\core\expr\numvalue.pyx in pyomo.core.expr.numvalue.NumericValue.__add__()

pyomo\core\expr\numeric_expr.pyx in pyomo.core.expr.numeric_expr._generate_sum_expression()

pyomo\core\expr\numeric_expr.pyx in pyomo.core.expr.numeric_expr.SumExpression.add()

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

我做了一些研究,但仍然没有真正了解导致此问题的原因。 任何指导将不胜感激!

这就是正在发生的事情。当您初始化参数时,您无法传入 key:value 配对(如字典),因此 pyomo 只是将参数中的 each 元素初始化为整个数组 这显然不是你想要的。

大多数时候,索引集不仅仅是计算数字,所以这并不会经常弹出,因为如果你的索引是 {'A', 'B', 'C', ...} 那么很明显,您 必须 传递 key:value 映射才能理顺它。

这里有几行代码可以演示我在说什么。底线:从你的模型中获取 numpy 并制作一个你想在参数中使用的东西的字典。 (这也可以通过 pandas 完成,但这不是必需的)。如果您希望 copy/replicate/experiment.

,请在末尾列出命令
In [1]: import pyomo.environ as pyo

In [2]: import numpy as np

In [3]: np_data = np.array([[1, 2], [3, 4]])

In [4]: m = pyo.ConcreteModel()

In [5]: m.S = pyo.Set(initialize=range(2))

In [6]: m.T = pyo.Set(initialize=range(2))

In [7]: # let's make a parameter from the data...

In [8]: m.p = pyo.Param(m.S, m.T, initialize=np_data)
WARNING: DEPRECATED: The default domain for Param objects is 'Any'.  However,
    we will be changing that default to 'Reals' in the future.  If you really
    intend the domain of this Param (p) to be 'Any', you can suppress this
    warning by explicitly specifying 'within=Any' to the Param constructor.
    (deprecated in 5.6.9, will be removed in 6.0) (called from
    /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-
    packages/pyomo/core/base/indexed_component.py:665)

In [9]: # note we get this odd warning about an "any" type.  This is trigge
   ...: red by fact that we are initializing EACH item to the whole array

In [10]: m.p[0,1]
Out[10]: 
array([[1, 2],
       [3, 4]])

In [11]: m.p[1,1]
Out[11]: 
array([[1, 2],
       [3, 4]])

In [12]: # not good!  pyomo wants a key:value pair

In [13]: my_better_data = {(0, 0) : 1,
    ...:                   (0, 1) : 2,
    ...:                   (1, 0) : 3,
    ...:                   (1, 1) : 4}

In [14]: m.p2 = pyo.Param(m.S, m.T, initialize=my_better_data)

In [15]: m.p2[0,1]
Out[15]: 2

In [16]: %hist
import pyomo.environ as pyo
import numpy as np
np_data = np.array([[1, 2], [3, 4]])
m = pyo.ConcreteModel()
m.S = pyo.Set(initialize=range(2))
m.T = pyo.Set(initialize=range(2))
# let's make a parameter from the data...
m.p = pyo.Param(m.S, m.T, initialize=np_data)
# note we get this odd warning about an "any" type.  This is triggered by fact that we are initializing EACH item to the whole array
m.p[0,1]
m.p[1,1]
# not good!  pyomo wants a key:value pair
my_better_data = {(0, 0) : 1,
                  (0, 1) : 2,
                  (1, 0) : 3,
                  (1, 1) : 4}
m.p2 = pyo.Param(m.S, m.T, initialize=my_better_data)
m.p2[0,1]
%hist

In [17]: 

编辑以显示 multi-dim np 数组到字典的转换

您可以将 np.array 转换回字典,只有在索引很容易全部排列成等效集合的特殊情况下。 只需仔细检查 索引是否按您喜欢的方式进行,方法是对一些值进行采样或使用 model.p.pprint()

完全打印出参数
In [30]: data = list(range(12)) # some fake data

In [31]: data_np = np.array(data)

In [32]: data_np = data_np.reshape(3,2,2)

In [33]: data_np
Out[33]: 
array([[[ 0,  1],
        [ 2,  3]],

       [[ 4,  5],
        [ 6,  7]],

       [[ 8,  9],
        [10, 11]]])

In [34]: data_dict = dict(np.ndenumerate(data_np))

In [35]: data_dict
Out[35]: 
{(0, 0, 0): 0,
 (0, 0, 1): 1,
 (0, 1, 0): 2,
 (0, 1, 1): 3,
 (1, 0, 0): 4,
 (1, 0, 1): 5,
 (1, 1, 0): 6,
 (1, 1, 1): 7,
 (2, 0, 0): 8,
 (2, 0, 1): 9,
 (2, 1, 0): 10,
 (2, 1, 1): 11}

In [36]: