Skip to content

ltm: subscripted reverse-declared mapped reference classifies DynamicIndex, keeping the cross-product despite the compiler's diagonal #757

@bpowers

Description

@bpowers

Summary

classify_iterated_dim_shape's mapped arm (src/simlin-engine/src/db/ltm_ir.rs, ~line 270) accepts a mapped iterated-dim subscript only when the mapping is declared on the target equation's iterated dimension toward the source's dimension -- has_mapping_to(index_dim, source_dim). When the mapping is declared in the REVERSE direction, on the source's dimension (Region→State, with x over Region, target over State), a SUBSCRIPTED reference target[State] = x[State] * c fails that check, classifies DynamicIndex, and keeps the conservative full Region × State cross-product of element edges -- even though the compiler's translate_via_mapping handles both declaration directions and resolves the reference through the same mapping diagonal (x[a]→target[s1], x[b]→target[s2]).

The BARE form in the reverse direction already gets the diagonal: target[State] = x * c classifies Bare (no subscript to inspect) and expand_same_element's mapping-aware projection (commit a010931e on ltm-core-batch, the #527 fix) consults DimensionsContext::mapped_element_correspondence, which handles both directions. So the residual asymmetry is: bare reverse-declared = diagonal, subscripted reverse-declared = cross-product, while the compiled simulation semantics are identical for both.

Current behavior is pinned by element_graph_mapped_reverse_declared_subscripted_stays_cross_product in src/simlin-engine/src/db/element_graph_tests.rs (~line 1371), which documents the classification ⟺ expansion agreement: the diagonal is only emitted for shapes the classifier calls Bare. The classifier arm's own comment (ltm_ir.rs ~line 262) records the direction restriction deliberately, to keep classification and expansion consistent rather than to model anything real.

Why it matters

Low severity -- over-conservatism only. The spurious cross-product edges carry near-zero runtime link scores (same flavor as pre-#448 FixedIndex N×N and pre-#527 mapped broadcast), so loops/edges are over-enumerated, never under-enumerated, and no scores are wrong. Only positional mappings are in scope: different-cardinality element-map references currently fail to compile outright (#753), so the element-map flavor of this asymmetry is moot until that is fixed.

Components affected

  • src/simlin-engine/src/db/ltm_ir.rs -- classify_iterated_dim_shape's mapped arm (the has_mapping_to(d_canon, src_canon) single-direction check, ~line 270)
  • src/simlin-engine/src/dimensions.rs -- DimensionsContext::mapped_element_correspondence already resolves both declaration directions; has_mapping_to is the one-directional primitive
  • src/simlin-engine/src/db/element_graph_tests.rs -- element_graph_mapped_reverse_declared_subscripted_stays_cross_product (~line 1371) pins current behavior and should flip to asserting the diagonal when fixed

Fix shape

Extend the classifier's mapped arm to accept the reverse declaration direction -- e.g. has_mapping_to(d, src) || has_mapping_to(src, d), or better, gate on the same mapped_element_correspondence(d, src).is_some() the expansion uses -- so classification and expansion consult the SAME correspondence data and stay consistent by construction (the invariant the current arm's comment is protecting). Then update the pinning test to assert the diagonal, mirroring element_graph_mapped_reverse_declared_bare_is_diagonal.

Discovery context

Identified during adversarial review of the #527 work on branch ltm-core-batch (commit a010931e, which made expand_same_element mapping-aware and covered the bare reverse-declared case). Residual conservatism, not a regression.

Tracking

Part of LTM tracking epic #488 (Core algorithm group, alongside #527). Related: #527 (the parent mapped-diagonal projection fix), #534 (mapped-dimension sliced reducers -- the reducer-path flavor of "honor the mapping"), #753 (different-cardinality element-map references fail to compile -- bounds this issue to positional mappings), #755 (mapped-diagonal loop-family grouping downstream of #527).

Metadata

Metadata

Assignees

No one assigned

    Labels

    ltmLoops that Matter (LTM) analysis subsystem

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions