0

I have created an ndarray from a sympy lambdify function in python and the actual values I need are tucked away within this array field of my result variable. To be clear, each index of array along axis=0 corresponds to the first derivative of a 7th order time polynomial at a particular time instant:

enter image description here

In my lambdify function, I passed a size-33 element time-vector and was expecting an 8x33 or 33x8 result but instead, it pushed my output to this array field and I am having difficulty accessing it. Right now, I can only access it by doing result[0], result[1], etc. but this is tedious as I can only access everything one at a time, implying that a loop is the only way to access everything. This is not the behavior I'd expect of an ndarray:

enter image description here

Can someone explain what is going on here and if possible, how I can access this array field so that I can vectorize any subsequent operations? My goal is to stack each element in array along axis=0 and compute subsequent derivatives and stack them according to their respective time.

smci
  • 32,567
  • 20
  • 113
  • 146
J_code
  • 356
  • 1
  • 5
  • 17
  • `lambdify` is a sympy thing, rather than numpy, so you also need to tag this [tag:sympy] – smci Mar 26 '21 at 00:22

1 Answers1

0

The doc of a lambdified function shows that actually numpy code. Sometimes it helps to look at that.

It took a bit to decipher your png (we generally dislike those on SO). I guess it's a pydev display of the result array. It looks like a shape (8,) object dtype array. Most of the elements are shape (33,) array, but the last 2 are scalars.

np.stack(result[:6])

should produce a (8,33) numeric dtype array.

An object dtype array is a lot like a list, with references to diverse elements.

Looking at your polynomial, I'm guessing the lambdified function returns something like:

np.array([7*t**6, ..., 2*t, 1, 0])

While 6 of the terms include t, the last 2 do not. The terms that include t will produce a (33,) array. sympy.lambdify is a relatively simple function, performing lexical translations from sympy to numpy. It does not have a "deep" understanding of numpy.


Example:

In [25]: exp = (3*t**3,2*t**2,1*t,1.0,0)
In [26]: f = lambdify(t, exp)
In [27]: print(f.__doc__)
Created with lambdify. Signature:

func(t)

Expression:

(3*t**3, 2*t**2, t, 1.0, 0)

Source code:

def _lambdifygenerated(t):
    return ((3*t**3, 2*t**2, t, 1.0, 0))

In [28]: f(np.arange(3))
Out[28]: (array([ 0,  3, 24]), array([0, 2, 8]), array([0, 1, 2]), 1.0, 0)
In [29]: np.array(_)
<ipython-input-29-7a2cd91c32ca>:1: 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.
  np.array(_)
Out[29]: 
array([array([ 0,  3, 24]), array([0, 2, 8]), array([0, 1, 2]), 1.0, 0],
      dtype=object)
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • note that in my testing, `np.stack(result[:6])` does not produce a 8x33 array but instead produces a 6x33 array which is slightly problematic, more annoying then anything else. This means I have to manually repeat them and add them back at the appropriate dimension. It would be great if for the terms that do not depend on `t`, that `lambdify` would return the appropriate dimension instead of truncating them to size 1. Doesn't make any sense. – J_code Mar 26 '21 at 17:31
  • 1
    You have to be smarter than `lambdify`. Like I said it is basically a lexical translation. In your polynomial `1.0` is a scalar, nothing that will translate to `np.ones_like(t)`. I"ve seen the same sort of problem when people use `sympy.Matrix`. You, in theory at least, know more `numpy` than `lambdify` does! – hpaulj Mar 26 '21 at 17:38