Skip to content

Scalar / Array mismatches in iosys not compatible with NumPy 1.24 #853

Description

@bnavigator

Discussed in #852

Originally posted by codeFighter2022 January 26, 2023
Hi,
First of all, thanks a lot for this amazing toolbox!

I think, I found a bug, or a suggestion for improvement, when running the prey example:
https://python-control.readthedocs.io/en/0.9.3.post2/iosys.html#example

When I run the code of the prey example, in particular the linearization,
lin_predprey = ct.linearize(io_predprey, xeq, 0)
I get the following error
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2,) + inhomogeneous part.

After analyzing the code, I think the origin of the error is that in predprey_rhs() dH is of type numpy arrary, while dL is not.

I think others ones are much deeper in the code than me. That is why I post this topic instead of a pull request.

Maybe a type check with dummy input/output data already solves these kind of issues when initializing the constructor. I think such a feature could save people some time.

Best,
codeFighter2022

Python: 3.810
Control: 0.9.3.post2
I installed the toolbox via pip

Activity

  1. bnavigator commented on Jan 26, 2023

    @bnavigator
    ContributorAuthor

    When executing the example:

    In [4]: eqpt = ct.find_eqpt(io_predprey, X0, 0)
       ...: xeq = eqpt[0]                         # choose the nonzero equilibrium point
       ...: lin_predprey = ct.linearize(io_predprey, xeq, 0)
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    Cell In[4], line 3
          1 eqpt = ct.find_eqpt(io_predprey, X0, 0)
          2 xeq = eqpt[0]                         # choose the nonzero equilibrium point
    ----> 3 lin_predprey = ct.linearize(io_predprey, xeq, 0)
    
    File /usr/lib/python3.10/site-packages/control/iosys.py:2252, in linearize(sys, xeq, ueq, t, params, **kw)
       2250 if not isinstance(sys, InputOutputSystem):
       2251     raise TypeError("Can only linearize InputOutputSystem types")
    -> 2252 return sys.linearize(xeq, ueq, t=t, params=params, **kw)
    
    File /usr/lib/python3.10/site-packages/control/iosys.py:580, in InputOutputSystem.linearize(self, x0, u0, t, params, eps, name, copy_names, **kwargs)
        578     du = np.zeros((ninputs,))
        579     du[i] = eps
    --> 580     B[:, i] = (self._rhs(t, x0, u0 + du) - F0) / eps
        581     D[:, i] = (self._out(t, x0, u0 + du) - H0) / eps
        583 # Create the state space system
    
    File /usr/lib/python3.10/site-packages/control/iosys.py:866, in NonlinearIOSystem._rhs(self, t, x, u)
        863 def _rhs(self, t, x, u):
        864     xdot = self.updfcn(t, x, u, self._current_params) \
        865         if self.updfcn is not None else []
    --> 866     return np.array(xdot).reshape((-1,))
    
    ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2,) + inhomogeneous part.
  2. changed the title [-]Avoid ragged shapes in linearize()[/-] [+]Avoid ragged shapes in linearize() / iosys[/+] on Jan 26, 2023
  3. bnavigator commented on Jan 26, 2023

    @bnavigator
    ContributorAuthor

    This would fix the error:

    def predprey_rhs(t, x, u, params):
        # Parameter setup
        a = params.get('a', 3.2)
        b = params.get('b', 0.6)
        c = params.get('c', 50.)
        d = params.get('d', 0.56)
        k = params.get('k', 125)
        r = params.get('r', 1.6)
    
        # Map the states into local variable names
        H = x[0]
        L = x[1]
    
        # Compute the control action (only allow addition of food)
        u_0 = u[0] if u[0] > 0 else 0
    
        # Compute the discrete updates
        dH = (r + u_0) * H * (1 - H/k) - (a * H * L)/(c + H)
        dL = b * (a * H *  L)/(c + H) - d * L
    
        return np.array([dH, dL])

    Documentation says, that the update function's u must be an array. As well as the ueq for linearize:

    def linearize(sys, xeq, ueq=None, t=0, params=None, **kw):
    """Linearize an input/output system at a given state and input.
    This function computes the linearization of an input/output system at a
    given state and input value and returns a :class:`~control.StateSpace`
    object. The evaluation point need not be an equilibrium point.
    Parameters
    ----------
    sys : InputOutputSystem
    The system to be linearized
    xeq : array
    The state at which the linearization will be evaluated (does not need
    to be an equilibrium state).
    ueq : array
    The input at which the linearization will be evaluated (does not need
    to correspond to an equlibrium state).

    Strictly speaking, the zero us from the example would not be allowed:

    eqpt = ct.find_eqpt(io_predprey, X0, 0)
    xeq = eqpt[0]                         # choose the nonzero equilibrium point
    lin_predprey = ct.linearize(io_predprey, xeq, 0)

    But we have this:

    # Convert x0, u0 to arrays, if needed
    if np.isscalar(x0):
    x0 = np.ones((nstates,)) * x0
    if np.isscalar(u0):
    u0 = np.ones((ninputs,)) * u0

  4. changed the title [-]Avoid ragged shapes in linearize() / iosys[/-] [+]Scalar / Array mismatches in iosys not compatible with NumPy 1.24[/+] on Jan 26, 2023
  5. bnavigator commented on Jan 26, 2023

    @bnavigator
    ContributorAuthor

    The test suite has a different predprey model:

    def predprey(t, x, u, params={}):
    """Predator prey dynamics"""
    r = params.get('r', 2)
    d = params.get('d', 0.7)
    b = params.get('b', 0.3)
    k = params.get('k', 10)
    a = params.get('a', 8)
    c = params.get('c', 4)
    # Dynamics for the system
    dx0 = r * x[0] * (1 - x[0]/k) - a * x[1] * x[0]/(c + x[0])
    dx1 = b * a * x[1] * x[0] / (c + x[0]) - d * x[1]
    return np.array([dx0, dx1])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions