TypeError: return arrays must be of ArrayType usin

2019-08-01 23:38发布

I have the following code:

x,y,z,t = var('x,y,z,t')
d = set([t])
rule = And(Or(x,y,z),t)
atoms = tuple(rule.atoms())
params = [True if i in d else False for i in atoms]
lam = lambdify(atoms, rule)
lam(*params)

which throws:

Traceback (most recent call last):
File "<pyshell#142>", line 7, in <module>
lam(*params)
File "<string>", line 1, in <lambda>
TypeError: return arrays must be of ArrayType

And I can't understand why, for other rules it works great.

1条回答
倾城 Initia
2楼-- · 2019-08-02 00:20

Update: This bug was fixed in SymPy 1.2, see its release notes. If you are experiencing this bug update your SymPy installation.


This one's pretty tricky, and surprising. Here's the docstring of your lambda named lam:

<lambda> lambda _Dummy_22, _Dummy_23, _Dummy_24, _Dummy_25
    Created with lambdify. Signature:

    func(z, x, y, t)

    Expression:

    And(Or(x, y, z), t)

So far so good. Well, I'd already note that your input arguments are being chosen automatically, and you don't know their order. I'd explicitly set an order such as lambdify((x,y,z,t),rule), but I don't know your actual application (I just thought I'd note this).

Anyway, trying it within sympy obviously works fine:

>>> And(Or(False,False,False),True)
False

On my system within IPython, this is the full error I get:

----> 1 lam(*params)

/usr/lib/python3/dist-packages/numpy/__init__.py in <lambda>(_Dummy_34, _Dummy_35, _Dummy_36, _Dummy_37)

TypeError: return arrays must be of ArrayType

Note the numpy path in the error. Since I have numpy installed, lambdify tries to map the symbolic expression to numpy functions. Since you only have And and Or in your expression, I can only assume these are numpy.logical_and and numpy.logical_or, respectively. But here's the deal (going back to the vanilla REPL for simplicity):

>>> import numpy as np
>>> np.logical_or(False,False,False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: return arrays must be of ArrayType

Oops, there's your problem: numpy's logical operators are binary! The same goes for operator.and_:

>>> import operator
>>> operator.and_(False,False,False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: op_and_ expected 2 arguments, got 3

The standard logical operators which lambdify uses to convert your symbolic expression to numerical don't accept more than two input arguments. The reason for the cryptic error message in the numpy case is that the third input argument of the binary ufunc logical_or is interpreted as an output array instead of a third operand, but in this sympy context this is entirely unexpected.

My suggestion is to use all/any or numpy.all/numpy.any for your specific example, passed as the modules keyword argument of lambdify:

>>> lam = lambdify(atoms, rule,modules={'And':all, 'Or':any})
>>> lam(*params)
False

This allows you to define your own functions that are used to do the mapping from symbolic to numerical.

查看更多
登录 后发表回答