Skip to content

Bug: changes to suppress deprecation warning on float of 1-element array - #210

Merged
mrava87 merged 1 commit into
PyLops:mainfrom
mrava87:fix-float_conversion_warning
Aug 30, 2026
Merged

mrava87 merged 1 commit into
PyLops:mainfrom
mrava87:fix-float_conversion_warning

Conversation

@mrava87

@mrava87 mrava87 commented Aug 28, 2026 •

Copy link
Copy Markdown
Contributor

NumPy ndim > 0 to-scalar deprecation: root cause and fix

The warning

DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated,
and will error in future. Ensure you extract a single element from your array before
performing this operation. (Deprecated NumPy 1.25.)

Triggered by any caller doing float(...) on the result of DistributedArray.norm(), because norm() never actually returned a scalar.

Root cause

DistributedArray.norm() documented a float return but returned a shape-(1,) array:

  1. norm(axis=None) flattens the local array and calls
    _compute_vector_norm(..., axis=0, ord=ord).
  2. That reduces via _allreduce_subcomm.
  3. mpi_allreduce (pylops_mpi/utils/_mpi.py:104) always allocates
    recv_buf = ncp.zeros(send_buf.size, dtype=...) — a 1-D buffer. For a scalar
    reduction send_buf.size == 1, so the result is array([...]) with
    ndim == 1, size == 1.

float() on such an array is the deprecated implicit array-to-scalar conversion (an error in a future NumPy).

DistributedArray.dot() had the identical issue: it returned the raw size-1 allreduce buffer.

The fix

New module-level helper in pylops_mpi/DistributedArray.py:

def to_scalar(x) -> Union[bool, int, float, complex]:
    return x.item() if hasattr(x, "item") else x
  • Backend-agnostic: .item() works for numpy and cupy arrays, and the
    hasattr guard covers the non-buffered-MPI paths that already return a
    plain scalar.
  • Dtype-preserving — returns float in most cases, but for example
    a complex vdot stays complex.

Applied to:

Location Change
DistributedArray.norm (axis=None branch) returns float; docstring notes scalar vs array per axis
DistributedArray.dot returns float/complex; docstring return type fixed
StackedDistributedArray.norm returns float; return annotation bool | float -> float

norm(axis=...) is unchanged and still returns an array.

StackedDistributedArray.norm had to change beyond the return value: it aggregated the per-array norms with ncp.hstack(...), and since those are now host scalars, cupy.hstack on them would raise. It now aggregates with numpy (correct, because the inputs are host scalars).

Call sites updated

float has no .item(), so every .norm().item() / .dot(...).item() chain had to be simplified.

  • pylops_mpi/optimization/cls_basic.py — 10 spots across CG/CGLS. Note
    a = float((self.kold / cOpc).item()) -> float(self.kold / cOpc) would have
    raised AttributeError otherwise (both operands are plain scalars now).
  • pylops_mpi/optimization/cls_sparsity.py — 6 spots in ISTA/FISTA
    (xupdate, costdata, costreg).
  • pylops_mpi/optimization/eigs.py:86 — b_k.dot(b1_k, vdot=True).item() ->
    b_k.dot(b1_k, vdot=True).
  • tests_nccl/test_distributedarray_nccl.py, tests_nccl/test_stackedarray_nccl.py
    — the GPU tests called .get() on dot() / axis-less norm() results, which
    would now be AttributeError on a Python scalar. Removed on the 3 dot and 9
    norm assertions; kept on norm(axis=...), which still returns a cupy array.

Behaviour change to be aware of (cupy)

norm(axis=None) and dot() now return host scalars instead of device size-1 arrays, so they force a device-to-host sync. Nearly every call site already did .item() (same sync); the rest only divide a DistributedArray by the result, which is fine with a host scalar.

@mrava87
mrava87 marked this pull request as draft August 28, 2026 20:26
@mrava87
mrava87 requested a review from rohanbabbar04 August 29, 2026 13:18
@mrava87 mrava87 self-assigned this Aug 29, 2026
@mrava87
mrava87 marked this pull request as ready for review August 29, 2026 13:18
@mrava87

mrava87 commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor Author

@rohanbabbar04 do you mind reviewing this 😄

Note that:

  • I was getting a lot of annoying warnings in the tests I am writing for the proximal operators/solvers, most of which are related to using float(np.array), which is now a deprecated behavior... so I decided to see if I could fix them without making a lot of code changes
  • the PR is mostly driven by Claude after we agreed on the approach (the new to_scalar method), so I am quite sure I did remove all .item() that we had scattered here and there as now norm/dot are by design always returning a pure float/complex scalar.
  • the PR is quite noisy as we have recently introduced .precommit that operates on files with at least one change, and since our style was a bit all over the place, a lot of the changes are purely stylistic

@mrava87 mrava87 changed the title Fix: changes to suppress deprecation warning on float of 1-element array Bug: changes to suppress deprecation warning on float of 1-element array Aug 29, 2026
@mrava87
mrava87 merged commit 413acfe into PyLops:main Aug 30, 2026
123 of 126 checks passed
@mrava87
mrava87 deleted the fix-float_conversion_warning branch August 30, 2026 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants