Skip to content

feat[next]: Implement embedded as_offset#2612

Open
havogt wants to merge 16 commits into
GridTools:mainfrom
havogt:as_offset_on_premap
Open

feat[next]: Implement embedded as_offset#2612
havogt wants to merge 16 commits into
GridTools:mainfrom
havogt:as_offset_on_premap

Conversation

@havogt
Copy link
Copy Markdown
Contributor

@havogt havogt commented May 29, 2026

No description provided.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements embedded as_offset support for NdArrayField execution, enabling dynamic offset field premaps in the embedded backend and un-xfailing related embedded tests.

Changes:

  • Adds an embedded as_offset builtin implementation that builds a gather connectivity from integer offset fields.
  • Adds type-deduction validation for unsupported non-single-target offsets.
  • Adds unit coverage for embedded as_offset premapping and removes the dynamic-offset embedded xfail.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/gt4py/next/embedded/nd_array_field.py Registers and implements embedded as_offset connectivity construction.
src/gt4py/next/ffront/foast_passes/type_deduction.py Adds compile-time rejection for unsupported as_offset offset shapes.
tests/next_tests/definitions.py Enables dynamic-offset tests for embedded backends.
tests/next_tests/unit_tests/embedded_tests/test_nd_array_field.py Adds embedded runtime tests for as_offset premap behavior and unsupported neighbor offsets.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/gt4py/next/ffront/foast_passes/type_deduction.py Outdated
Comment thread src/gt4py/next/embedded/nd_array_field.py Outdated
Comment thread src/gt4py/next/embedded/nd_array_field.py Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Comment thread src/gt4py/next/embedded/nd_array_field.py Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comment thread src/gt4py/next/ffront/foast_passes/type_deduction.py
Copy link
Copy Markdown
Contributor Author

@havogt havogt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review notes (via /code-review skill, xhigh effort)

9 finder angles → 7 verifiers → sweep. Two candidates were refuted before posting:

  • Missing source ∈ offset_field.dims checkDomain.__getitem__ already raises a clean KeyError("No Dimension of type 'X' is present in the Domain.") (common.py:528-529), so a defensive check would be redundant.
  • Cartesian-only check is a backward-incompatible tightening — non-Cartesian as_offset never compiled on any backend (gtfn/dace/roundtrip all hit downstream asserts; ICON4py only uses Koff). The new check just improves diagnostics.

Inline findings below. One finding does not fit any changed line (_hyperslice reachability) — recorded here:

Pre-existing: inverse_image raises bare numpy ValueError when offset range is fully disjoint

src/gt4py/next/embedded/nd_array_field.py:704 (in _hyperslice, unchanged code). When offset_field.domain[source_dim] is fully disjoint from the data field's range (e.g. f on I=[0,10), offset_field on I=[100,110)), select_mask is all-False, xp.nonzero returns empty, and xp.min(empty) raises ValueError: zero-size array to reduction operation minimum which has no identity. Pre-existing bug in _hyperslice; this PR's new as_offset builtin makes it more reachable from user code.

Comment thread src/gt4py/next/ffront/fbuiltins.py Outdated
Comment thread src/gt4py/next/embedded/nd_array_field.py Outdated
Comment thread src/gt4py/next/ffront/foast_passes/type_deduction.py
domain = offset_field.domain
xp = offset_field.array_ns
src_range = domain[source_dim].unit_range
shape = tuple(len(src_range) if dim == source_dim else 1 for dim in domain.dims)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same value-only Dimension.__eq__ issue as the predicate (see comment on fbuiltins.py:514): if domain.dims ever contained two dims sharing .value with different .kind, both axes would get len(src_range) instead of just the source axis.

Currently shielded by Domain's uniqueness check (common.py:495) which uses the same value-only equality — so unreachable today, but coupled to that invariant. If uniqueness is ever relaxed (e.g. to allow same-name dims of different kinds), this shape computation breaks silently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't fix in this PR. Shielded by Domain's uniqueness invariant (which uses the same value-only equality), so unreachable today. The predicate-level tightening in fbuiltins.is_cartesian_offset blocks the construction one layer up. Worth revisiting only if Domain uniqueness is ever relaxed.

Comment thread tests/next_tests/unit_tests/embedded_tests/test_nd_array_field.py

def _as_offset(offset: fbuiltins.FieldOffset, offset_field: NdArrayField) -> common.Connectivity:
if not fbuiltins.is_cartesian_offset(offset):
target_dims = ", ".join(d.value for d in offset.target)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The full error-message string (lines 899–903) is verbatim-duplicated with type_deduction.py:894–899. Unified messaging was intentional, but the contract is currently enforced by hand; a small fbuiltins._not_cartesian_message(offset) -> str shared by both raisers would enforce it by construction. Each call site still controls its own exception type and location wrapping. Minor — flag only if you expect future drift.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't fix in this PR — the hand-unified messages are intentional. Easy follow-up if reviewers later prefer a shared helper, but the contract is only two raisers right now.

@havogt
Copy link
Copy Markdown
Contributor Author

havogt commented May 29, 2026

Re: the pre-existing _hyperslice disjoint-range ValueError flagged in the self-review body — fix in #2616.

@havogt havogt requested a review from Copilot May 29, 2026 16:41
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Comment thread src/gt4py/next/embedded/nd_array_field.py
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.

2 participants