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).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions