Search code examples
pythonvalueerror

ddeint - problem with reproducing examples provided in pypi


I wanted to use the ddeint in my project. I copied the two examples provided on https://pypi.org/project/ddeint/ and only the second one works. When I'm running the first one:

from pylab import cos, linspace, subplots
from ddeint import ddeint


def model(Y, t):
    return -Y(t - 3 * cos(Y(t)) ** 2)


def values_before_zero(t):
    return 1


tt = linspace(0, 30, 2000)
yy = ddeint(model, values_before_zero, tt)

fig, ax = subplots(1, figsize=(4, 4))
ax.plot(tt, yy)
ax.figure.savefig("variable_delay.jpeg")

The following error occures:

Traceback (most recent call last):
  File "C:\Users\piobo\PycharmProjects\pythonProject\main.py", line 14, in <module>
    yy = ddeint(model, values_before_zero, tt)
  File "C:\Users\piobo\PycharmProjects\pythonProject\venv\lib\site-packages\ddeint\ddeint.py", line 145, in ddeint
    return np.array([g(tt[0])] + results)
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2000,) + inhomogeneous part.

I'm using python 3.9. Could anyone advise us on what I'm doing wrong? I didn't manipulate the code in any way.


Solution

  • Reproduction

    Could not reproduce - the code runs when using following versions:

    • Python 3.6.9 (python3 --version)
    • ddeint 0.2 (pip3 show ddeint)
    • Numpy 1.18.3 (pip3 show numpy)

    Upgrading numpy to 1.19

    Then I got following warning:

    /.local/lib/python3.6/site-packages/ddeint/ddeint.py:145: 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 np.array([g(tt[0])] + results)

    But the output JPEG was created successfully.

    Using Python 3.8 with latest numpy

    Using Python 3.8 with a fresh install of ddeint using numpy 1.24.0:

    • Python 3.8
    • ddeint 0.2
    • Numpy 1.24.0

    Now I could reproduce the error.

    Hypotheses

    Since this example does not run successfully out-of-the-box in the question's environment, I assume it is an issue with numpy versions.

    Issue with versions

    See Numpy 1.19 deprecation warning · Issue #9 · Zulko/ddeint · GitHub which seems related to this code line that we see in the error stacktrace:

        return np.array([g(tt[0])] + results)
    

    Directly using numpy

    I suppose the tt value is the issue here. It is returned by pylab's linspace() function call (below written with module prefix):

    tt = pylab.linspace(0, 30, 2000)
    

    On MatPlotLib's pylab docs there is a warning:

    Since heavily importing into the global namespace may result in unexpected behavior, the use of pylab is strongly discouraged. Use matplotlib.pyplot instead.

    Furthermore the module pylab is explained as mixed bag:

    pylab is a module that includes matplotlib.pyplot, numpy, numpy.fft, numpy.linalg, numpy.random, and some additional functions, all within a single namespace. Its original purpose was to mimic a MATLAB-like way of working by importing all functions into the global namespace. This is considered bad style nowadays.

    Maybe you can use numpy.linspace() function directly.

    Attention: There was a change for the dtype default:

    The type of the output array. If dtype is not given, the data type is inferred from start and stop. The inferred dtype will never be an integer; float is chosen even if the arguments would produce an array of integers.

    Since here arguments start and stop are given as 0 and 30, also the dtype should be integer (like in previous numpy version 1.19).

    Note the braking-change:

    Since 1.20.0

    Values are rounded towards -inf instead of 0 when an integer dtype is specified. The old behavior can still be obtained with np.linspace(start, stop, num).astype(int)

    So, we could replace the tt-assignment line with:

    from numpy import np
    
    tt = np.linspace(0, 30, 2000).astype(int)