Skip to content

fix[next]: Fix premap between same dimensions#2607

Merged
havogt merged 8 commits into
GridTools:mainfrom
havogt:premap_clean_1583
May 29, 2026
Merged

fix[next]: Fix premap between same dimensions#2607
havogt merged 8 commits into
GridTools:mainfrom
havogt:premap_clean_1583

Conversation

@havogt
Copy link
Copy Markdown
Contributor

@havogt havogt commented May 27, 2026

Description

Fixes #1583: embedded premap produced wrong results / errors when a connectivity's source
dimension equals its target dimension while introducing a LOCAL neighbor dimension (e.g.
C2E2CO: domain (Cell, C2E2CO), codomain Cell). Such a connectivity was misclassified as
reshuffling (dimension-preserving) instead of remapping (dimension-introducing).

Root cause: the reshuffling-vs-remapping choice was driven by ConnectivityKind.ALTER_DIMS,
computed as a property of the connectivity alone. Whether premap changes dimensions is actually a
property of the (connectivity, field) pair, so any connectivity-only heuristic is wrong for some
field.

Changes:

  • Unify _reshuffling_premap and _remapping_premap into a single _gather_premap — the general
    n-dimensional advanced-index pullback. The output domain is derived from the connectivity and
    the field (the codomain is replaced by the connectivity's domain dims; dims already present are
    narrowed in place), so the reshuffling/remapping distinction — and the bug — disappear. This also
    lifts the previous "single connectivity only" restriction on dimension-introducing premaps.
  • Remove ConnectivityKind and all kind properties. Dispatch is now on connectivity type:
    affine connectivities (CartesianConnectivity; cartesian shift / relocation) keep the no-copy
    domain-only path (_domain_premap), everything else is a GatherConnectivity (the
    connectivity-intrinsic "premap rearranges data" property) and goes through _gather_premap.
  • Collapse NeighborConnectivity into NeighborTable (there is no non-ndarray-backed neighbor
    connectivity); is_neighbor_connectivityis_neighbor_table (single structural check).

No behavior change for previously-supported premaps; the gather is strictly more general. Adds
regression tests for the source == target + LOCAL case (incl. with an extra kept dimension) and
a multi-connectivity gather test.

Requirements

  • All fixes and/or new features come with corresponding tests.
  • Important design decisions have been documented in the appropriate ADR inside the docs/development/ADRs/ folder.

@havogt havogt requested a review from Copilot May 27, 2026 11:37
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.

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


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

Copy link
Copy Markdown
Contributor

@egparedes egparedes left a comment

Choose a reason for hiding this comment

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

A couple of questions about the comments and design. I haven't looked at the actual embedded implementation yet

A table showing the relation between the connectivity kind and the supported cases
is shown in :class:`common.ConnectivityKind`.
domain translation (i.e. only transform the domain without altering the data). Such
connectivities are not :class:`common.GatherConnectivity` and dispatch to `_domain_premap`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Question: is this the most correct way to express it ("they are NOT GatherConnectivities") instead of saying "they are Cartesian Connectivites" or something along these lines?

Comment thread src/gt4py/next/common.py
# Reordering the bases would fix that but then `NdArrayField`'s arithmetic operators would
# shadow `Connectivity`'s raising stubs (connectivities would start accepting `+` etc.). A bare
# annotation documents the contract for type checkers with no runtime effect.
ndarray: core_defs.NDArrayObject
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Isn't it needed a TODO comment somewhere saying the root Field or Connectivity classes shouldn't have the .ndarray property?

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.

It's already on the Field.ndarray property, I'll link from here.

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 10 out of 10 changed files in this pull request and generated no new comments.

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 10 out of 10 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/gt4py/next/embedded/nd_array_field.py:275

  • This Args section still documents the pre-PR restrictions and is now inconsistent with the new behavior. The bullets "be of the same kind or encode only compact domain transformations" and "for reshuffling operations, all connectivities must have the same domain", as well as the parenthetical "remapping operations only support a single connectivity argument", no longer apply: the unified _gather_premap supports multiple dimension-introducing connectivities and does not require them to share a domain (as demonstrated by new tests like test_gather_premap_multiple_connectivities and test_gather_premap_shared_domain_dim). Please update this Args section to describe the actual current contract (e.g. the gather vs. affine mixing rule and the chained-remap rejection implemented at lines 309–328).
        Args:
            *connectivities: connectivities to be used for the `premap` operation. If only one
                connectivity is passed, it will be expanded to fully defined connectivities for
                each dimension in the domain of the field according to the rules described above.
                If more than one connectivity is passed, they all must satisfy:
                - be of the same kind or encode only compact domain transformations
                - the codomain of each connectivity must be different
                - for reshuffling operations, all connectivities must have the same domain
                (Note that remapping operations only support a single connectivity argument.)

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

@egparedes egparedes left a comment

Choose a reason for hiding this comment

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

In general looks good, just a couple of comments to make docstrings more readable

Comment on lines +263 to +265
domain translation (i.e. only transform the domain without altering the data). Such affine
connectivities only relabel the domain; data-rearranging cases are handled as
advanced-indexing gathers (:class:`common.GatherConnectivity`).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Very minor nitpick:

Suggested change
domain translation (i.e. only transform the domain without altering the data). Such affine
connectivities only relabel the domain; data-rearranging cases are handled as
advanced-indexing gathers (:class:`common.GatherConnectivity`).
domain translation (i.e. only transform the domain without altering the data).
Such affine connectivities only relabel the domain; data-rearranging cases are
handled as advanced-indexing gathers (:class:`common.GatherConnectivity`).

Comment thread src/gt4py/next/embedded/nd_array_field.py Outdated
def _gather_output_domain(
field_domain: common.Domain, connectivities: Sequence[common.GatherConnectivity]
) -> common.Domain:
"""Output domain of a gather: each connectivity's codomain becomes its own domain dimensions."""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't understand this docstring and would rephrase it.

@havogt
Copy link
Copy Markdown
Contributor Author

havogt commented May 29, 2026

beverin green, santis offline

@havogt havogt merged commit 8b3f022 into GridTools:main May 29, 2026
23 of 24 checks passed
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.

[next] Bug in embedded implementation of premap

3 participants