Skip to content

must a by= that only partitions name a groupable lookup? shift says yes and position says no #280

Description

@FBumann

Prompt: "Can we create constraints or expressions that are indexed over sth thats not a dim? Because a lookup enables a reduction over sth else? Whats the precise split between dims and lookups?"

Note

The following content was generated by AI.

Must a by= that only partitions rows name a groupable lookup? Three of the four say yes and one says no:

call a label space in by=
sum(x, by=l) refused
at(x, by=l) refused
shift(x, over=d, offset=n, by=l) refused
position(d, by=l) accepted

sum and at need into: because they produce a dim — nothing to decide there. shift and position produce none: both only cut the rows of d into groups. They disagree anyway, and the split is an implementation accident — sum, at and shift route through _resolve_lookup_ref, which consults Namespace.groupable(); _resolve_position is its own function and checks only that the name is a lookup over the counted dimension.

For loosening shift. Promoting a label space to a dimension just to group a walk buys a dimension nothing is indexed by and nothing aggregates into — and advice then answers never-an-axis and tells you to declare it as a label space, which is what you had. Being a lookup's target is not enough to escape that note. The strict reading is a loop, and position is accidentally on the right side of it.

For tightening position. One rule for one keyword, a much smaller diff, and the pages become true as written. It leaves the advice loop standing for shift.

What loosening costs, which is why this is a decision rather than a patch — by.into is load-bearing:

  • dimensions.py:393 — groups = frozenset(partition.into): a named offset= / within= may vary over the target dimension, which is how each group gets its own offset. A label space has no target, so that capability cannot exist for it and the combination has to be refused explicitly.
  • lowering.py:315 — the Window plan node would carry an empty into, a new shape every consumer has to accept.
  • walk.py:368 — zip(by.names, by.into, strict=True) in the typesetter needs a branch.
  • expression_parser.py:101 — into: tuple[str, ...] is not optional today.

Current behaviour is pinned by tests as of #281, so whichever way this goes, the other side fails loudly.

The probe
base = {
    'dimensions': {'snapshot': {'dtype': 'int'}},
    'lookups': {'season': {'over': 'snapshot', 'dtype': 'str'}},   # a label space
    'parameters': {'d': {'dims': ['snapshot']}},
    'variables': {'soc': {'foreach': ['snapshot']}},
}
sum(by=label space)       : refused — 'season' is a label space over 'snapshot', not a groupable lookup
at(by=label space)        : refused — 'season' is a label space over 'snapshot', not a groupable lookup
shift(by=label space)     : refused — 'season' is a label space over 'snapshot', not a groupable lookup
position(by=label space)  : ACCEPTED

No activity

Activity on this issue will appear here.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: relationsrelations and dimensions: the relation designdesign: openIn scope; the spelling is undecided

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions