Skip to content

tile_arange() drops the last element when the range is not an exact multiple of the step #1774

Closed

Description

@christophercrouzet

Bug Description

wp.tile_arange() mirrors numpy.arange() in name, signature and exclusive-stop convention, but
computes its length with truncating division instead of ceil. Any range whose span is not an exact
multiple of step therefore silently loses its final element.

Repro

import numpy as np, warp as wp

@wp.kernel
def k(out: wp.array[wp.int32]):
    t = wp.tile_arange(0, 10, 3, dtype=int)
    wp.tile_store(out, t)

out = wp.zeros(4, dtype=wp.int32)
wp.launch_tiled(k, dim=1, outputs=[out], block_dim=32)
print(out.numpy(), "vs", np.arange(0, 10, 3))

The length is decided in Python at codegen time, so it can also be checked without a device:

>>> int((10 - 0) / 3)          # tile_arange_value_func
3
>>> len(np.arange(0, 10, 3))
4

Observed

range tile_arange numpy.arange
(0, 10, 3) 3 — [0, 3, 6] 4 — [0, 3, 6, 9]
(0, 5, 2) 2 — [0, 2] 3 — [0, 2, 4]
(10, 0, -3) 3 — [10, 7, 4] 4 — [10, 7, 4, 1]
(0, 9, 3) 3 3 ✔
(0, 10, 1) 10 10 ✔

Floating-point ranges are exposed twice over, because the same expression also inherits binary
rounding: (0.3 - 0.0) / 0.1 == 2.9999999999999996, so wp.tile_arange(0.0, 0.3, 0.1) yields 2
elements where numpy.arange yields 3.

Root cause

tile_arange_value_func() in warp/_src/builtins.py sizes the tile with

n = int((stop - start) / step)

int() truncates, while arange semantics require ceil((stop - start) / step). The two agree only
when the span divides evenly by the step. The native tile_arange then fills start + i * step for
i < n, so the shortfall comes entirely from this length.

This is not a regression: the identical expression existed in the pre-refactor TileRange type, so
the behavior dates from the introduction of tile_arange.

Expected

wp.tile_arange(start, stop, step) should produce ceil((stop - start) / step) elements, matching
numpy.arange(), rather than silently discarding the last one.

Activity

  1. added this to the 1.18.0 milestone on Aug 25, 2026
  2. christophercrouzet commented on Sep 13, 2026

    @christophercrouzet
    MemberAuthor

    Addressed in 69b75e2.

  3. shi-eric commented on Sep 13, 2026

    @shi-eric
    Contributor

    This is addressed by 69b75e2.

    wp.tile_arange() now computes the element count with ceiling semantics at the output element type. Ascending and descending ranges whose spans are not exact multiples of their steps retain the final element below stop, floating-point ranges such as (0.0, 0.3, 0.1) produce the expected count, and exact-multiple ranges remain unchanged.

    The issue is already closed as completed; this comment adds the full implementation and verification record without changing its state.

    Public API behavior

    Kernel scope

    • The existing kernel-only wp.tile_arange() builtin now sizes non-empty half-open ranges consistently with the values representable by the output element type.
    • Range arguments must remain compile-time constants, the output type must be a numeric scalar, and zero-length tile dimensions remain unsupported.

    Test coverage

    • warp/tests/tile/test_tile_construction.py covers ascending and descending integer ranges, floating-point ranges, one-, two-, and three-argument forms, exact multiples, output-type rounding, extreme bounds, constant handling, and invalid-call diagnostics across CPU and CUDA.
    • warp/tests/test_constant_precision.py verifies that converting a literal for a typed call does not alter later uses of the caller's constant.
    • warp/tests/tile/test_tile_struct.py verifies that tile_arange() rejects a nonnumeric struct element type with the expected diagnostic.

    Behavioral verification

    A targeted reproduction of the reported integer and floating-point ranges passed on CPU and CUDA. Register and shared storage both produced the complete expected ranges without omitting or adding elements.

    Related tile-shape validation

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

Metadata

Metadata

Labels

bugSomething isn't workingtileTile programming model

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions