help(f)
displays:
Help on function _lambdifygenerated:
_lambdifygenerated(x)
Created with lambdify. Signature:
func(x)
Expression:
Max(1, x)
Source code:
def _lambdifygenerated(x):
return (amax((1,x), axis=0))
Trying to apply this to 1d array has a couple of problems.
In [62]: a
Out[62]: array([-1, 0, 1])
First it tries to make an array from (1,x)
, resulting in the ragged array warning.
In [63]: f(a)
/usr/local/lib/python3.8/dist-packages/numpy/core/fromnumeric.py:87: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
return ufunc.reduce(obj, axis, dtype, out, **passkwargs)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-63-730f2a0fa0b7> in <module>
----> 1 f(a)
<lambdifygenerated-4> in _lambdifygenerated(x)
1 def _lambdifygenerated(x):
----> 2 return (amax((1,x), axis=0))
<__array_function__ internals> in amax(*args, **kwargs)
....
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
And then it gets the ambiguity from error from trying to compare a
to 1
, the result of which is a boolean array.
lambdify
is a relatively 'dumb' lexicographic translator from sympy
to numpy
, and easily fails.
The code for Add
is
def _lambdifygenerated(x):
return (x + 1)
which is a valid numpy
expression.
Your symarray
case:
In [72]: a = symarray('a', (3,))
In [73]: a
Out[73]: array([a_0, a_1, a_2], dtype=object)
Again, np.array((1,a))
makes a ragged array. and the max.reduce
is comparing array with a scalar.
The Add
works, in effect doing a list comprehension on the elements of the a
array:
In [74]: g=lambdify([x], Add(x, 1), 'numpy')
In [75]: g(a)
Out[75]: array([a_0 + 1, a_1 + 1, a_2 + 1], dtype=object)
But we don't need lambdify
to do this:
In [83]: a+1
Out[83]: array([a_0 + 1, a_1 + 1, a_2 + 1], dtype=object)
And A*A.T
kind of calculation:
In [89]: a*a[:,None]
Out[89]:
array([[a_0**2, a_0*a_1, a_0*a_2],
[a_0*a_1, a_1**2, a_1*a_2],
[a_0*a_2, a_1*a_2, a_2**2]], dtype=object)
In [90]: _.sum(axis=1)
Out[90]:
array([a_0**2 + a_0*a_1 + a_0*a_2, a_0*a_1 + a_1**2 + a_1*a_2,
a_0*a_2 + a_1*a_2 + a_2**2], dtype=object)
Your Max
could be applied to a
via frompyfunc
:
In [91]: f=np.frompyfunc(lambda x: Max(1,x),1,1)
In [93]: f(a)
Out[93]: array([Max(1, a_0), Max(1, a_1), Max(1, a_2)], dtype=object)
this is similar to:
In [94]: np.array([Max(1,x) for x in a])
Out[94]: array([Max(1, a_0), Max(1, a_1), Max(1, a_2)], dtype=object)
with about the same speed, but a bit more flexibility when using broadcasting
and such.