Skip to content

DLE.compute_sequence fails under NumPy 2.4 (setting an array element with a sequence) #839

Description

@mmcky

Summary

quantecon.DLE.compute_sequence raises under NumPy 2.4 when it computes the asset-price terms R1_Price, R2_Price, R5_Price. The same code runs fine under NumPy 2.3.x, so this is a regression triggered by NumPy tightening size-1-array → scalar conversion on assignment.

Environment

  • quantecon latest (installed via pip install --upgrade quantecon)
  • numpy==2.4.6 (ships with anaconda=2026.06) — fails
  • numpy==2.3.5 (ships with anaconda=2025.12) — works
  • Python 3.13

Traceback

ValueError                                Traceback (most recent call last)
----> 1 econ1.compute_sequence(x0, ts_length=100)

File .../site-packages/quantecon/_dle.py:215, in DLE.compute_sequence(self, x0, ts_length, Pay)
    213     self.R5_Price = np.empty((ts_length + 1, 1))
    214     for i in range(ts_length + 1):
--> 215         self.R1_Price[i, 0] = self.beta * e1 @ self.Mc @ np.linalg.matrix_power(
    216             self.A0, 1) @ xp[:, i] / (e1 @ self.Mc @ xp[:, i])

TypeError: only 0-dimensional arrays can be converted to Python scalars
The above exception was the direct cause of the following exception:
ValueError: setting an array element with a sequence.

Root cause

In compute_sequence, the selector e1 is a 2-D row vector:

e1 = np.zeros((1, self.nc))
e1[0, 0] = 1

so each price expression e1 @ self.Mc @ ... @ xp[:, i] / (e1 @ self.Mc @ xp[:, i]) evaluates to a size-1 array (shape (1,)), not a Python scalar. Assigning that into the scalar slot self.R1_Price[i, 0] used to work because NumPy silently converted a size-1 array to a scalar, but NumPy 2.4 now raises (only 0-dimensional arrays can be converted to Python scalarssetting an array element with a sequence).

Suggested fix

Coerce each price term to a scalar with .item() (works regardless of e1's shape):

for i in range(ts_length + 1):
    self.R1_Price[i, 0] = (self.beta * e1 @ self.Mc @ np.linalg.matrix_power(
        self.A0, 1) @ xp[:, i] / (e1 @ self.Mc @ xp[:, i])).item()
    self.R2_Price[i, 0] = (self.beta**2 * (e1 @ self.Mc @
        np.linalg.matrix_power(self.A0, 2) @ xp[:, i]) / (e1 @ self.Mc @ xp[:, i])).item()
    self.R5_Price[i, 0] = (self.beta**5 * (e1 @ self.Mc @
        np.linalg.matrix_power(self.A0, 5) @ xp[:, i]) / (e1 @ self.Mc @ xp[:, i])).item()

Alternatively, define e1 as 1-D (e1 = np.zeros(self.nc); e1[0] = 1) so the matmul chain reduces to a 0-d scalar.

Downstream impact

This breaks 5 lectures in lecture-python-advanced.myst under anaconda=2026.06 (numpy 2.4.6): cattle_cycles, growth_in_dles, irfs_in_hall_model, lucas_asset_pricing_dles, permanent_income_dles. See the validation in QuantEcon/lecture-python-advanced.myst#346. It affects any DLE whose dimensions make the price expression size-1 (lectures that don't reach the price path, e.g. gorman_heterogeneous_households, hs_invertibility_example, rosen_schooling_model, are unaffected).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions