Add function back in to Embedding

This commit is contained in:
2026-08-09 21:43:20 -05:00
parent fd371ba175
commit 53f8bd47dc
2 changed files with 25 additions and 50 deletions

View File

@@ -229,55 +229,47 @@ because of the offset-based embedding, we can determine whether a node
came from a particular subgraph simply by examining its offset and sub-graph
size. This is captured by `Embed.mem_range_iff`. -/
/-- Translate an index of `g` into `h` by a constant offset. -/
private def shift {g h : GGraph α} (off : ) (hle : g.size + off h.size) (i : g.Index) :
h.Index := off + i.val, by omega
@[simp] lemma shift_val {g h : GGraph α} {off : } (hle : g.size + off h.size)
(i : g.Index) : (shift (h := h) off hle i).val = off + i.val := rfl
/-- A special-case embedding of `g` into `h` in which all edges and nodes
of `g` are present in `h` at a given offset `off`. -/
structure Embed (g h : GGraph α) where
f : g.Index h.Index
off :
size_le : g.size + off h.size
nodes_eq : i, h.nodes (shift off size_le i) = g.nodes i
edges_mem : {e : g.Edge}, e g.edges
(shift off size_le e.1, shift off size_le e.2) h.edges
f_val : i, (f i).val = off + i.val
nodes_eq : i, h.nodes (f i) = g.nodes i
edges_mem : {e : g.Edge}, e g.edges (f e.1, f e.2) h.edges
/-- The index translation of an embedding. -/
abbrev Embed.f {g h : GGraph α} (e : Embed g h) (i : g.Index) : h.Index :=
shift e.off e.size_le i
lemma Embed.f_inj {g h : GGraph α} (e : Embed g h) : Function.Injective e.f :=
fun _ _ hij => Fin.ext (by simpa using congrArg Fin.val hij)
lemma Embed.f_inj {g h : GGraph α} (e : Embed g h) : Function.Injective e.f := by
intro i j hij
have := congrArg Fin.val hij
rw [e.f_val, e.f_val] at this
exact Fin.ext (by omega)
/-- An embedding's range is the interval `[off, off + g.size)`. -/
lemma Embed.mem_range_iff {g h : GGraph α} (e : Embed g h) (j : h.Index) :
( i, e.f i = j) e.off j.val j.val < e.off + g.size := by
constructor
· rintro i, rfl; have := i.isLt; simp only [Embed.f, shift_val]; omega
· rintro i, rfl; have := i.isLt; rw [e.f_val]; omega
· rintro hlo, hhi
exact j.val - e.off, by omega, Fin.ext (by simp only [Embed.f, shift_val]; omega)
refine j.val - e.off, by omega, Fin.ext ?_
rw [e.f_val]
show e.off + (j.val - e.off) = j.val
omega
/-- Build an embedding from an index map that is pointwise the shift. The five
inclusions below are naturally written with `Fin.castAdd`/`Fin.natAdd` — the form
the `Fin.append` lemmas are stated in — so this lets them keep those proofs
verbatim while `Embed` stores only the offset. The trailing two arguments are
boilerplate at every call site and default to discharging themselves. -/
verbatim. The trailing argument is boilerplate at every call site and defaults
to discharging itself. -/
private def Embed.ofIndexMap {g h : GGraph α} (off : ) (k : g.Index h.Index)
(hn : i, h.nodes (k i) = g.nodes i)
(hem : {e : g.Edge}, e g.edges (k e.1, k e.2) h.edges)
(hle : g.size + off h.size := by
first | omega | (simp [GGraph.sequence, GGraph.overlay, GGraph.loop] <;> omega))
(hk : i, (k i).val = off + i.val := by intro i; simp) :
Embed g h where
f := k
off := off
size_le := hle
nodes_eq i := by rw [show shift off hle i = k i from Fin.ext (by simp [hk])]; exact hn i
edges_mem hmem := by
have hs : i, shift (h := h) off hle i = k i := fun i => Fin.ext (by simp [hk])
rw [hs, hs]; exact hem hmem
f_val := hk
nodes_eq := hn
edges_mem := hem
/-- Embeddings compose (offsets add). -/
def Embed.trans {g₁ g₂ g₃ : GGraph α} (e₁ : Embed g₁ g₂) (e₂ : Embed g₂ g₃) :
@@ -285,8 +277,7 @@ def Embed.trans {g₁ g₂ g₃ : GGraph α} (e₁ : Embed g₁ g₂) (e₂ : Em
ofIndexMap (e₂.off + e₁.off) (fun i => e₂.f (e₁.f i))
(fun i => (e₂.nodes_eq (e₁.f i)).trans (e₁.nodes_eq i))
(fun he => e₂.edges_mem (e₁.edges_mem he))
(hle := by have := e₁.size_le; have := e.size_le; omega)
(hk := fun i => by simp; omega)
(hk := fun i => by rw [e₂.f_val, e.f_val]; omega)
/-- The left operand's inclusion into a sequenced graph. -/
def Embed.sequenceLeft (g₁ g₂ : GGraph α) : Embed g₁ (g₁ g₂) :=
@@ -322,20 +313,6 @@ def Embed.singletonIndex {a : α} {h : GGraph α} (e : Embed (singleton a) h) :
(e : Embed (singleton a) h) : h.nodes e.singletonIndex = a :=
e.nodes_eq 0, Nat.zero_lt_one
/-! `shift` puts the offset on the left (`off + i.val`), matching `Fin.natAdd`, so
every right inclusion is *definitionally* the form `Spa/Language/Properties.lean`
states its trace indices in. Only the left inclusions need a bridge, since their
offset is `0` and `0 + i.val` does not reduce.
Deliberately not `@[simp]`: they rewrite `Embed.f` back into `Fin.castAdd` form,
discarding the offset that `Embed.mem_range_iff` — and the subgraph-containment
tests built on it — reason with. -/
lemma Embed.sequenceLeft_f (g₁ g₂ : GGraph α) (i : g₁.Index) :
(Embed.sequenceLeft g₁ g₂).f i = i.castAdd g₂.size := Fin.ext (Nat.zero_add _)
lemma Embed.overlayLeft_f (g₁ g₂ : GGraph α) (i : g₁.Index) :
(Embed.overlayLeft g₁ g₂).f i = i.castAdd g₂.size := Fin.ext (Nat.zero_add _)
variable (g : GGraph α)
/-- All the nodes in the graph. -/

View File

@@ -41,9 +41,8 @@ noncomputable def Trace.embed {g h : Graph} (e : GGraph.Embed g h)
a corresponding trace exists in the combined graph. -/
noncomputable def Trace.overlay_left {idx₁ idx₂ : g₁.Index}
(tr : Trace g₁ idx₁ idx₂ ρ₁ ρ₂) :
Trace (g₁ g₂) (idx₁.castAdd g₂.size) (idx₂.castAdd g₂.size) ρ₁ ρ₂ := by
have h := tr.embed (GGraph.Embed.overlayLeft g₁ g₂)
rwa [GGraph.Embed.overlayLeft_f, GGraph.Embed.overlayLeft_f] at h
Trace (g₁ g₂) (idx₁.castAdd g₂.size) (idx₂.castAdd g₂.size) ρ₁ ρ₂ :=
tr.embed (GGraph.Embed.overlayLeft g₁ g₂)
/-- When two graphs are overlaid, for each trace in the right graph,
a corresponding trace exists in the combined graph. -/
@@ -56,9 +55,8 @@ noncomputable def Trace.overlay_right {idx₁ idx₂ : g₂.Index}
a corresponding trace exists in the combined graph. -/
noncomputable def Trace.sequence_left {idx₁ idx₂ : g₁.Index}
(tr : Trace g₁ idx₁ idx₂ ρ₁ ρ₂) :
Trace (g₁ g₂) (idx₁.castAdd g₂.size) (idx₂.castAdd g₂.size) ρ₁ ρ₂ := by
have h := tr.embed (GGraph.Embed.sequenceLeft g₁ g₂)
rwa [GGraph.Embed.sequenceLeft_f, GGraph.Embed.sequenceLeft_f] at h
Trace (g₁ g₂) (idx₁.castAdd g₂.size) (idx₂.castAdd g₂.size) ρ₁ ρ₂ :=
tr.embed (GGraph.Embed.sequenceLeft g₁ g₂)
/-- When two graphs are sequenced, for each trace in the second graph,
a corresponding trace exists in the combined graph. -/