Describe the bug
The distributed cross-rank reduce uses std::max / std::min
(mlx/distributed/reduction_ops.h:17-35), which are not NaN-propagating
(std::max(nan, x) returns x when nan is the first argument). So if
exactly one rank has a NaN at a position, all_max / all_min return
the other ranks' non-NaN value and the NaN vanishes — the failure is
silently swallowed.
To Reproduce
import mlx.core as mx
# 2-rank group
nan = float("nan")
x = mx.array([1.0, nan if rank == 0 else 2.0, 3.0]) # rank 0 has NaN at idx 1
m = mx.distributed.all_max(x)
mx.eval(m) # -> array([1.0, 2.0, 3.0]) WRONG: should be [1.0, nan, 3.0]
Expected behavior
[rank 0] AMAX [1.0, 2.0, 3.0]
[rank 0] AMIN [1.0, 0.5, 3.0]
[rank 1] AMAX [1.0, 2.0, 3.0]
[rank 1] AMIN [1.0, 0.5, 3.0]
local mx.max([1,nan,3]) = nan (propagates NaN)
local mx.min([1,nan,3]) = nan (propagates NaN)
BUG REPRODUCED: all_max dropped the single-rank NaN (mx.max would propagate it).
Describe the bug
The distributed cross-rank reduce uses
std::max/std::min(
mlx/distributed/reduction_ops.h:17-35), which are not NaN-propagating(
std::max(nan, x)returnsxwhennanis the first argument). So ifexactly one rank has a
NaNat a position,all_max/all_minreturnthe other ranks' non-
NaNvalue and theNaNvanishes — the failure issilently swallowed.
To Reproduce
Expected behavior