---
title: 'Lifting E-Graphs: Context-Aware Structures'
url: https://www.emergentmind.com/topics/lifting-e-graphs
type: topic
---

# Lifting E-Graphs: Context-Aware Structures

Lifting e-graphs are an e-graph architecture in which context-thinning, or lifting, is built into the representation of terms rather than treated as an external normalization device. In this formulation, the relevant semantic object is a term together with its context, and terms can be lifted to larger contexts by dropping variables through a thinning. The design is intended to support rigid $\alpha$ canonical variables, improve sharing across context dimensions, and preserve scope correctness in equality saturation [2606.22734].

## 1. Motivation and semantic perspective

The motivating problem is that ordinary e-graphs are effective for ground terms, but variables make representation subtle. Standard approaches either use names, which breaks sharing and can be scope-hygiene unsound in rewrites, or use nameless indices, which improves alpha-sharing but still misses common structure across terms that inhabit different-sized contexts [2606.22734]. Lifting e-graphs address this by making context an intrinsic part of the term.

The central design philosophy is stated explicitly: **“The context $x,y \mapsto \_$ is not where a term is; it is part of what a term is.”** In the paper’s running intuition, the expressions
$x \mapsto \sin(x) : \mathbb{R}^1 \to \mathbb{R}$ and $x,y \mapsto \sin(x) : \mathbb{R}^2 \to \mathbb{R}$ are neither equal nor type-compatible, even though ordinary notation can obscure that distinction [2606.22734]. This motivates a context-indexed, dimension-aware syntax in which variables are nameless, function symbols are interpreted at a specific context dimension, and lifting operations relate terms across contexts.

A plausible implication is that the representation is not merely an implementation refinement over de Bruijn-style encodings; it changes the unit of canonicalization from a syntax tree to a context-indexed semantic object. That interpretation is consistent with the paper’s insistence that different ambient dimensions correspond to different functions.

## 2. Context-indexed syntax and the role of lifting

The paper first presents a naive well-dimensioned nameless representation. A term in context size $d$ is interpreted as a function $\mathbb{R}^d \to \mathbb{R}$, and variables are written as $\operatorname{var}_{di}$, meaning the $i$-th variable in a $d$-variable context [2606.22734]. The semantics is pointwise and compositional:
$$
\begin{aligned}
\llbracket 42_d \rrbracket &= v_0, v_1, \ldots, v_{d-1} \mapsto 42 \\
\llbracket \operatorname{var}_{di} \rrbracket &= v_0, v_1, \ldots, v_{d-1} \mapsto v_i \\
\llbracket \sin_d(t) \rrbracket &= v_0, \ldots, v_{d-1} \mapsto \sin(\llbracket t \rrbracket(v_0, \ldots, v_{d-1})) \\
\llbracket t +_d s \rrbracket &= v_0, \ldots, v_{d-1} \mapsto \llbracket t \rrbracket(v_0, \ldots, v_{d-1}) + \llbracket s \rrbracket(v_0, \ldots, v_{d-1}).
\end{aligned}
$$

This representation already collapses alpha-renamings, but it does not identify terms related by dropping irrelevant variables. The paper’s basic example is that
$\sin_1(\operatorname{var}_{10})$ and $\sin_2(\operatorname{var}_{20})$
are related, but not shared [2606.22734]. Lifting is introduced precisely to close that gap.

The lifting combinator is defined using a thinning bitvector $t$:
$$
\operatorname{lift}_t : (\mathbb{R}^{\operatorname{popcnt}(t)} \to \mathbb{R}) \to (\mathbb{R}^{\operatorname{len}(t)} \to \mathbb{R}).
$$
Semantically, lifting applies the original function to the subsequence of arguments selected by the thinning. The Python sketch given is:

```python
def lift(thin : Thin):
    return lambda f: lambda *args: f(*act(thin, args))
```

The paper uses this to relate the one-variable and two-variable sine terms:
$$
\sin_1(\operatorname{var}_{10}) := \sin(\operatorname{var})
$$
and
$$
\sin_2(\operatorname{var}_{20}) := \operatorname{lift}_{10}(\sin(\operatorname{var})).
$$
The two-dimensional form is therefore represented as the one-dimensional form lifted into a larger context, rather than as an unrelated node [2606.22734].

## 3. Thinnings as context embeddings

A thinning is represented by a bitvector in which $1$ means “keep this variable” and $0$ means “drop this variable” [2606.22734]. The paper emphasizes three equivalent intuitions: thinnings are strictly monotone maps between finite ordered sets, subsequence selectors, and a compact representation of repeated de Bruijn shifts. They form a category under composition.

The basic interface is given as:

```python
type Thin = list[bool]

def dom(f : Thin) -> int:
    return len(f)

def cod(f : Thin) -> int:
    return sum(f)

def id(n : int) -> Thin:
    return [True]*n

def comp(f : Thin, g : Thin) -> Thin:
    assert cod(f) == dom(g)
    ...
```

This organization makes context inclusion explicit and compositional. In practical terms, a thinning records how a smaller context embeds into a larger one while preserving the order of retained variables. That representation underwrites two rewrite laws that the implementation treats as fundamental [2606.22734].

The first is the lift-pulling, or homomorphism, law:
$$
f(\operatorname{lift}_i(X), \operatorname{lift}_i(Y)) = \operatorname{lift}_i(f(X,Y)).
$$
The second is the lift-composition, or compaction, law:
$$
\operatorname{lift}_i(\operatorname{lift}_j(X)) = \operatorname{lift}_{i \cdot j}(X).
$$
The first expresses that adding redundant arguments and then applying a function pointwise commutes with applying the function first; the second states that nested context embeddings collapse to a single composed thinning. Together they provide the algebraic basis for canonicalization in the lifting e-graph [2606.22734].

A plausible implication is that the system internalizes free-variable control as a structural property of term formation. The paper itself notes that “thinness” can act as a kind of nameless free-variable analysis: if a term can be represented with a thinner lifting, then it is constant in the dropped directions.

## 4. Built-in lifting in the e-graph representation

The main implementation move is to bake lifting into the e-graph representation rather than represent it as an ordinary node or a separate normalization pass [2606.22734]. This begins with **fat identifiers**:

```python
type FatId = (list[bool], int)
```

A fat identifier carries both a thinning bitvector and the underlying e-class integer. Ordinary e-nodes then become:

```python
class ENode:
    f : str
    args : list[FatId]
```

Each child is therefore already context-aware. Because the lifting annotation sits on the identifier itself, lifting is not interned as a separate node and can be inspected immediately.

The operational center of the design is the lift-pulling smart constructor. When building a node, it:

1. examines the thinnings on all child IDs,
2. finds the common lifting they share,
3. peels that common lift off,
4. interns the node at the thinned or core level,
5. then reattaches the common lift to the resulting ID [2606.22734].

This realizes the rewrite
$$
f(\operatorname{lift}_i(X), \operatorname{lift}_i(Y)) \to \operatorname{lift}_i(f(X,Y))
$$
as a canonical construction procedure. The paper states that the smart constructor ensures that if an expression is “more lifted than necessary,” it still hashes to the same interned structure after normalization. The stated consequences are reduced memory use, better sharing, and faster comparison of lifting relationships [2606.22734].

Even without union-find, the paper characterizes this as an **alpha-aware hash cons**. The comparison to Co-de Bruijn normalization is explicit: context-management structure is pushed outward so that the core term becomes canonical. This suggests that the canonical form is defined not solely by syntactic shape, but by a normalized decomposition into core syntax plus a residual context embedding.

## 5. Thinning-aware union-find and equality management

Ordinary union-find is insufficient because equality must respect both e-class identity and thinning structure. The key observation is that if
$\operatorname{lift}_i(a) = \operatorname{lift}_i(b)$,
then, because lifting is injective, one may conclude $a = b$ [2606.22734]. The paper compares this to injective datatype reasoning of the form
$\operatorname{cons}(a,c) = \operatorname{cons}(b,c) \implies a = b$.
Accordingly, the union-find must be thinning-aware: shared lifts should be peeled away before merging base classes.

The formal shape is:

```python
type Id = tuple[Thin, int]

@dataclass
class ThinUF:
    parents : list[Id] = field(default_factory=list)
```

A new set is created in a specific scope by:

```python
def makeset(self, scope : int) -> Id:
    i = len(self.parents)
    id = ([True]*scope, i)
    self.parents.append(id)
    return id
```

Roots therefore begin with identity thinning in their current scope. The `find` operation composes thinnings along the parent path:

```python
def find(self, x : Id) -> Id:
    thin, xid = x
    while True:
        (thiny, yid) = self.parents[xid]
        if xid == yid:
            assert all(thiny)
            return (thin, xid)
        thin = comp(thiny, thin)
        xid = yid
```

The invariant is that the thinning associated with a node is the accumulated embedding from the node’s local context into the root context [2606.22734]. The paper also defines the weakest common thinning

```python
def wct(f : Thin, g : Thin) -> Thin:
    assert dom(f) == dom(g)
    return [a and b for a,b in zip(f,g)]
```

together with a helper `div(f : Thin, g : Thin)` that computes the residual thinning when $f$ is thinner than $g$. Union then computes the common thinning, creates a fresh set at its codomain, and points both representatives to it with residual annotations:

```python
thinz = wct(thinx,thiny)
(_, z) = self.makeset(cod(thinz))
self.parents[xid] = (div(thinz,thinx), z)
self.parents[yid] = (div(thinz,thiny), z)
return (thinz, z)
```

The paper isolates three special situations. In the ordinary injective case, a shared lift is peeled and the base classes are unioned:
$\operatorname{lift}_{01}(e_{17}) = \operatorname{lift}_{01}(e_{42}) \Rightarrow e_{17} = e_{42}$.
In the forced-orientation case, exemplified by
$(x \mapsto x * 0) = (x \mapsto 0)$,
the constant must be lifted into the one-variable context, yielding
$e_{92} = \operatorname{lift}_0(e_8)$,
and this can be oriented only as
$e_{92} \rightarrow \operatorname{lift}_0(e_8)$.
In the incompatible-but-related case, exemplified by
$(x,y \mapsto x * 0) = (x,y \mapsto 0 * y)$,
the union-find creates a fresh representative $e_{99}$ so that
$e_{92} \rightarrow \operatorname{lift}_0(e_{99})$ and
$e_{13} \rightarrow \operatorname{lift}_0(e_{99})$ [2606.22734].

These cases show that the union structure is not merely annotation-preserving; it may constrain orientation and may require the creation of a fresh “least common context.” The paper presents this as the thinning analogue of the fresh-meet behavior seen in factor union-find.

## 6. Matching behavior, related frameworks, and terminological scope

E-matching in a lifting e-graph is described as largely standard, but thinnings must be propagated during descent into a pattern [2606.22734]. The justification is lift-pushing:
$$
\operatorname{lift}_i(f(e_1,e_2)) \to f(\operatorname{lift}_i(e_1), \operatorname{lift}_i(e_2)).
$$
This allows matching to decompose a lifted pattern after pushing the lift inward. The paper notes, however, that union-find may contain redundant liftings such as nodes of the form
$e_{\text{child} \rightarrow \operatorname{lift}_k(e_{\text{parent}})}$.
A simple implementation choice is to fail matching on such nodes, since they typically correspond to redundant variables and are unlikely to be useful; in principle, equations involving thinnings may also be solved to obtain multiple matches [2606.22734].

The approach is positioned relative to several neighboring lines of work. Compared to ordinary e-graphs, it augments syntax-plus-equivalence-class structure with a first-class representation of context embeddings and can represent alpha-equivalent terms, context-shifted variants, and the “same core term, different number of dropped variables” while preserving canonical structure. Compared to slotted e-graphs, the difference is framed as one of emphasis: slotted e-graphs manage variables as first-class slots, whereas lifting e-graphs make context embeddings and thinnings first-class and bake lifting into the identifier. The work is also explicitly inspired by Co-De Bruijn notation: normalize by pulling lifts outward, represent context inclusion structurally, and treat variable omission as part of the term representation. The paper further remarks that while hashing modulo alpha-equivalence pursues similar sharing goals, it is unclear how to extend such techniques cleanly to highly shared e-graphs [2606.22734].

The paper identifies several advantages and limitations. The stated advantages are better sharing across context dimensions, canonical handling of variables without names, built-in support for rigid alpha-canonical variables, avoidance of scope bugs such as variable leakage, lift normalization that reduces redundant structure, thinness as a free-variable or dependency analysis, and support for e-graph-style equality saturation with context-sensitive terms. The stated limitations are greater complexity than ordinary e-graphs, possible multiple solutions or failures in e-matching over redundant liftings, constrained different-context unification, and the fact that binders such as $\lambda$, $\forall$, $\exists$, $\int$, and substitution would require related but slightly different transfer rules [2606.22734].

The terminology should also be distinguished from an unrelated graph-theoretic usage. In graph theory, the **lifting graph** is a graph on the edges incident with a vertex $s$, where adjacency records whether a pair of edges is $k$-liftable while preserving local edge-connectivity; its complement is the non-admissibility graph or bad graph [2212.03347]. That notion concerns splitting-off operations in edge-connected graphs rather than context-indexed e-graph representations. The shared word “lifting” therefore denotes different constructions in the two literatures.

A plausible overall interpretation is that lifting e-graphs convert context management from auxiliary bookkeeping into an algebraic invariant of the congruence structure itself. That interpretation follows the paper’s stated takeaway: contexts are intrinsic to terms, thinnings encode context inclusion, smart constructors hoist lifts, fat identifiers store thinning together with e-class identity, and thin-aware union-find preserves the injective structure of lifting while supporting equivalence saturation [2606.22734].

Source: https://www.emergentmind.com/topics/lifting-e-graphs