Skip to content

Commit 734f28f

Browse files
feat(Combinatorics/SimpleGraph/Inversion): Möbius inversion between copy counts and induced copy counts
Adds the bijection `Copy.equivSigmaEmbedding`, the labelled forward count identity `copyCount_eq_sum_embeddingCount`, and its Möbius inverse `embeddingCount_eq_sum_signed_copyCount` over ℤ. The Möbius direction reduces via the order-equivalence `iccEquivPowersetEdgeFinsetSdiff` between `Icc G K` and the powerset of the edge difference to `Finset.sum_powerset_neg_one_pow_card`. Supporting `Copy.inducedShape` (the pullback `H.comap f.toEmbedding`) and the per-fiber bijection `Copy.fiberInducedShapeEquiv` are kept inline in this file rather than split out, since neither has a standalone consumer outside this Möbius decomposition. Co-authored-by: Malte Jackisch <45597826+MaltyBlanket@users.noreply.github.com>
1 parent fa6e3bb commit 734f28f

2 files changed

Lines changed: 299 additions & 0 deletions

File tree

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3620,6 +3620,7 @@ public import Mathlib.Combinatorics.SimpleGraph.Hasse
36203620
public import Mathlib.Combinatorics.SimpleGraph.IncMatrix
36213621
public import Mathlib.Combinatorics.SimpleGraph.InducedCopy
36223622
public import Mathlib.Combinatorics.SimpleGraph.Init
3623+
public import Mathlib.Combinatorics.SimpleGraph.Inversion
36233624
public import Mathlib.Combinatorics.SimpleGraph.LapMatrix
36243625
public import Mathlib.Combinatorics.SimpleGraph.LineGraph
36253626
public import Mathlib.Combinatorics.SimpleGraph.Maps
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
/-
2+
Copyright (c) 2026 Christoph Spiegel. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Christoph Spiegel
5+
-/
6+
module
7+
8+
public import Mathlib.Algebra.BigOperators.Field
9+
public import Mathlib.Combinatorics.SimpleGraph.Automorphism
10+
public import Mathlib.Combinatorics.SimpleGraph.Finite
11+
public import Mathlib.Data.Nat.Choose.Sum
12+
public import Mathlib.Data.Rat.Cast.Defs
13+
14+
/-!
15+
# Möbius inversion between copy counts and induced copy counts
16+
17+
For a guest graph `G : SimpleGraph V` and a host graph `H : SimpleGraph W` with finite
18+
vertex types, this file establishes the standard summation identity expressing the copy
19+
count `H.copyCount G` as a sum over supergraphs of `G` (on the same vertex type `V`) of
20+
induced copy counts `H.embeddingCount G'`, together with its Möbius inverse expressing
21+
`H.embeddingCount G` as a signed sum of `H.copyCount G'`.
22+
23+
Following the convention from `Mathlib/Combinatorics/SimpleGraph/Copy.lean` and
24+
`Mathlib/Combinatorics/SimpleGraph/InducedCopy.lean`, counting operations are host-first
25+
(`H.copyCount G`, `H.embeddingCount G`); types are guest-first (`Copy G H`, `Embedding G H`).
26+
27+
## Main declarations
28+
29+
* `SimpleGraph.Copy.inducedShape` — for `f : Copy G H`, the supergraph of `G` on `V`
30+
recording the induced adjacency on the image, transported back via `f.toEmbedding`.
31+
* `SimpleGraph.Copy.fiberInducedShapeEquiv` — the per-fiber bijection between copies with a
32+
prescribed induced shape and graph embeddings of that shape.
33+
* `SimpleGraph.Copy.equivSigmaEmbedding` — the load-bearing bijection
34+
`Copy G H ≃ Σ G' ∈ Icc G ⊤, Embedding G'.val H`.
35+
* `SimpleGraph.iccEquivPowersetEdgeFinsetSdiff` — for `G ≤ K`, the equivalence
36+
`Finset.Icc G K ≃ (K.edgeFinset \ G.edgeFinset).powerset` used to reduce the inner
37+
alternating sum to `Finset.sum_powerset_neg_one_pow_card`.
38+
39+
## Main results
40+
41+
* `SimpleGraph.copyCount_eq_sum_embeddingCount` — forward identity:
42+
`H.copyCount G = ∑ G' ∈ Icc G ⊤, H.embeddingCount G'`.
43+
* `SimpleGraph.embeddingCount_eq_sum_signed_copyCount` — Möbius inverse over `ℤ`:
44+
`(H.embeddingCount G : ℤ) = ∑ G' ∈ Icc G ⊤,
45+
(-1) ^ #(G'.edgeFinset \ G.edgeFinset) * (H.copyCount G' : ℤ)`.
46+
47+
## Implementation notes
48+
49+
The forward bijection `Copy.equivSigmaEmbedding` is the only "real" content; the Möbius
50+
direction reduces to it via the classical alternating-sum identity
51+
`Finset.sum_powerset_neg_one_pow_card`, reindexed through the order-isomorphism
52+
`G' ∈ Icc G ⊤ ↔ S ⊆ E(⊤) \ E(G)`.
53+
54+
The Möbius identity is stated in `ℤ` (rather than `ℕ`) because the signs are essential.
55+
56+
The `LocallyFiniteOrder (SimpleGraph V)` instance consumed by `Finset.Icc G ⊤` comes from
57+
`SimpleGraph.Finite.instLocallyFiniteOrder`, which requires `[DecidableLE (SimpleGraph V)]`.
58+
The declarations below routinely invoke `Classical.decRel _` since the bijection is already
59+
noncomputable.
60+
-/
61+
62+
public section
63+
64+
open Finset Function
65+
66+
namespace SimpleGraph
67+
68+
variable {V W : Type*}
69+
70+
/-! ### Induced shape of a copy
71+
72+
The pullback `H.comap f.toEmbedding` records the induced adjacency on the image of a copy
73+
`f : Copy G H`, transported back to `V`. It is always a supergraph of `G`, and pinning it
74+
down to a specific supergraph `G'` promotes the copy to an embedding `G' ↪g H`. -/
75+
76+
namespace Copy
77+
78+
variable {G G' : SimpleGraph V} {H : SimpleGraph W}
79+
80+
/-- The pullback of the host graph along the underlying injection of a copy. -/
81+
def inducedShape (f : Copy G H) : SimpleGraph V :=
82+
H.comap f.toEmbedding
83+
84+
@[simp] lemma inducedShape_adj (f : Copy G H) {a b : V} :
85+
f.inducedShape.Adj a b ↔ H.Adj (f a) (f b) := Iff.rfl
86+
87+
lemma le_inducedShape (f : Copy G H) : G ≤ f.inducedShape :=
88+
fun _ _ => f.toHom.map_adj
89+
90+
/-- A copy with induced shape `G'` promotes to a graph embedding `G' ↪g H`. -/
91+
@[expose] def toEmbeddingOfInducedShapeEq (f : Copy G H) (h : f.inducedShape = G') :
92+
G' ↪g H where
93+
toFun := f
94+
inj' := f.injective
95+
map_rel_iff' {a b} := by
96+
change H.Adj (f a) (f b) ↔ G'.Adj a b
97+
rw [← h, inducedShape_adj]
98+
99+
@[simp] lemma toEmbeddingOfInducedShapeEq_apply (f : Copy G H) (h : f.inducedShape = G')
100+
(v : V) : f.toEmbeddingOfInducedShapeEq h v = f v := rfl
101+
102+
/-- The fiber of `inducedShape` over a supergraph `G' ≥ G` is canonically `Embedding G' H`. -/
103+
def fiberInducedShapeEquiv (hGG' : G ≤ G') :
104+
{f : Copy G H // f.inducedShape = G'} ≃ Embedding G' H where
105+
toFun f := f.val.toEmbeddingOfInducedShapeEq f.prop
106+
invFun e := ⟨e.toCopy.comp (Copy.ofLE G G' hGG'), by ext a b; simp [inducedShape]⟩
107+
left_inv f := by apply Subtype.ext; ext v; simp
108+
right_inv e := by apply DFunLike.ext; intro v; simp
109+
110+
end Copy
111+
112+
@[simp] lemma Embedding.inducedShape_toCopy {G : SimpleGraph V} {H : SimpleGraph W}
113+
(e : Embedding G H) : e.toCopy.inducedShape = G := by
114+
ext a b; rw [Copy.inducedShape_adj]; exact e.map_rel_iff
115+
116+
/-! ### Forward bijection and count identity -/
117+
118+
section Forward
119+
120+
variable {G : SimpleGraph V} {H : SimpleGraph W}
121+
122+
/-- The load-bearing equivalence: a copy of `G` in `H` is the same data as a choice of
123+
supergraph `G' ∈ Icc G ⊤` (the induced shape) together with a graph embedding
124+
`G' ↪g H`. This expresses every copy uniquely as an induced copy of some shape `G'`
125+
between `G` and the complete graph.
126+
127+
The proof goes via the canonical fiber decomposition `Equiv.sigmaFiberEquiv` for the map
128+
`Copy.inducedShape`. The index `K : SimpleGraph V` is restricted to `Icc G ⊤`, which is
129+
exactly the set of shapes with nonempty fiber. The per-fiber bijection is
130+
`Copy.fiberInducedShapeEquiv`. -/
131+
noncomputable def Copy.equivSigmaEmbedding (G : SimpleGraph V) (H : SimpleGraph W)
132+
[Fintype V] [DecidableEq V] [DecidableLE (SimpleGraph V)] :
133+
Copy G H ≃ Σ G' : ↥(Finset.Icc G ⊤), Embedding G'.val H :=
134+
(Equiv.sigmaFiberEquiv (Copy.inducedShape : Copy G H → SimpleGraph V)).symm.trans <|
135+
{ toFun := fun ⟨K, f⟩ =>
136+
let hGK : G ≤ K := f.prop ▸ f.val.le_inducedShape
137+
⟨⟨K, Finset.mem_Icc.mpr ⟨hGK, le_top⟩⟩,
138+
Copy.fiberInducedShapeEquiv hGK f⟩
139+
invFun := fun ⟨⟨K, hK⟩, e⟩ =>
140+
⟨K, (Copy.fiberInducedShapeEquiv (Finset.mem_Icc.mp hK).1).symm e⟩
141+
left_inv := by
142+
rintro ⟨K, f⟩
143+
simp
144+
right_inv := by
145+
rintro ⟨⟨K, hK⟩, e⟩
146+
simp only [Equiv.apply_symm_apply] }
147+
148+
/-- Forward identity: every copy of `G` in `H` is an induced copy of some unique
149+
supergraph `G' ∈ Icc G ⊤` of `G`. -/
150+
theorem copyCount_eq_sum_embeddingCount [Fintype V] [DecidableEq V]
151+
[DecidableLE (SimpleGraph V)] [Finite W] (G : SimpleGraph V) (H : SimpleGraph W) :
152+
H.copyCount G = ∑ G' ∈ Finset.Icc G ⊤, H.embeddingCount G' := by
153+
rw [copyCount_eq_nat_card, Nat.card_congr (Copy.equivSigmaEmbedding G H), Nat.card_sigma,
154+
← Finset.sum_attach (Finset.Icc G ⊤) (fun G' => H.embeddingCount G')]
155+
refine Finset.sum_congr rfl fun G' _ => ?_
156+
exact (embeddingCount_eq_nat_card _ _).symm
157+
158+
end Forward
159+
160+
/-! ### Möbius (signed-sum) inverse
161+
162+
The Möbius inverse to the forward identity, expressing `H.embeddingCount G` as a signed
163+
sum of `H.copyCount G'` over supergraphs `G' ∈ Icc G ⊤`. The proof reduces, via the
164+
order-isomorphism `iccEquivPowersetEdgeFinsetSdiff` below, to the alternating-sum
165+
identity `Finset.sum_powerset_neg_one_pow_card`.
166+
-/
167+
168+
section Mobius
169+
170+
open Classical in
171+
/-- Order-isomorphism between the closed interval `Finset.Icc G K` of graphs and the
172+
powerset of the edge difference `K.edgeFinset \ G.edgeFinset`, valid when `G ≤ K`.
173+
174+
The forward map sends a graph `G'` with `G ≤ G' ≤ K` to its "extra edges over `G`",
175+
namely `G'.edgeFinset \ G.edgeFinset`. The inverse sends a subset `S` of "missing edges
176+
of `G` inside `K`" to the graph whose edge set is `G.edgeFinset ∪ S`, constructed via
177+
`fromEdgeSet`. -/
178+
noncomputable def iccEquivPowersetEdgeFinsetSdiff [Fintype V] [DecidableEq V]
179+
[DecidableLE (SimpleGraph V)] {G K : SimpleGraph V} (hGK : G ≤ K) :
180+
↥(Finset.Icc G K) ≃ ↥(K.edgeFinset \ G.edgeFinset).powerset where
181+
toFun G' :=
182+
⟨G'.val.edgeFinset \ G.edgeFinset, by
183+
have h₁ : G ≤ G'.val := (Finset.mem_Icc.mp G'.prop).1
184+
have h₂ : G'.val ≤ K := (Finset.mem_Icc.mp G'.prop).2
185+
simp only [Finset.mem_powerset]
186+
exact Finset.sdiff_subset_sdiff (edgeFinset_mono h₂) (Finset.Subset.refl _)⟩
187+
invFun S :=
188+
⟨fromEdgeSet ((G.edgeFinset : Set (Sym2 V)) ∪ S.val), by
189+
have hSK : S.val ⊆ K.edgeFinset \ G.edgeFinset := Finset.mem_powerset.mp S.prop
190+
refine Finset.mem_Icc.mpr ⟨?_, ?_⟩
191+
· -- `G ≤ fromEdgeSet (G.edgeFinset ∪ S)`
192+
intro a b hab
193+
refine (fromEdgeSet_adj _).mpr ⟨Or.inl ?_, hab.ne⟩
194+
rw [mem_coe, mem_edgeFinset]; exact hab
195+
· -- `fromEdgeSet (G.edgeFinset ∪ S) ≤ K`
196+
rw [fromEdgeSet_le]
197+
intro e he
198+
rw [Set.mem_diff] at he
199+
obtain ⟨heGS, _⟩ := he
200+
rcases heGS with heG | heS
201+
· rw [mem_coe, mem_edgeFinset] at heG
202+
exact edgeSet_subset_edgeSet.mpr hGK heG
203+
· have : e ∈ K.edgeFinset := (Finset.mem_sdiff.mp (hSK heS)).1
204+
rwa [mem_edgeFinset] at this⟩
205+
left_inv := by
206+
rintro ⟨G', hG'⟩
207+
have hGG' : G ≤ G' := (Finset.mem_Icc.mp hG').1
208+
apply Subtype.ext
209+
ext a b
210+
simp only [fromEdgeSet_adj, Set.mem_union, mem_coe, mem_edgeFinset, Finset.coe_sdiff,
211+
Set.mem_diff]
212+
constructor
213+
· rintro ⟨h | ⟨h, _⟩, _⟩
214+
· exact hGG' h
215+
· exact h
216+
· intro h
217+
refine ⟨?_, h.ne⟩
218+
by_cases hG : G.Adj a b
219+
· exact Or.inl hG
220+
· exact Or.inr ⟨h, hG⟩
221+
right_inv := by
222+
rintro ⟨S, hS⟩
223+
have hSK : S ⊆ K.edgeFinset \ G.edgeFinset := Finset.mem_powerset.mp hS
224+
apply Subtype.ext
225+
ext e
226+
simp only [Finset.mem_sdiff, mem_edgeFinset, edgeSet_fromEdgeSet, Set.mem_diff,
227+
Set.mem_union, mem_coe]
228+
constructor
229+
· rintro ⟨⟨hGS, _⟩, heG⟩
230+
cases hGS with
231+
| inl h => exact absurd h heG
232+
| inr h => exact h
233+
· intro heS
234+
have heK : e ∈ K.edgeFinset := (Finset.mem_sdiff.mp (hSK heS)).1
235+
have heNotDiag : e ∉ Sym2.diagSet := fun hd =>
236+
K.not_isDiag_of_mem_edgeSet (mem_edgeFinset.mp heK) hd
237+
have heNotG : e ∉ G.edgeSet := fun heG =>
238+
(Finset.mem_sdiff.mp (hSK heS)).2 (mem_edgeFinset.mpr heG)
239+
exact ⟨⟨Or.inr heS, heNotDiag⟩, heNotG⟩
240+
241+
open Classical in
242+
/-- The Möbius (signed-sum) inverse to `copyCount_eq_sum_embeddingCount`: the induced
243+
copy count is recovered as an alternating sum of copy counts indexed by supergraphs
244+
`G' ∈ Icc G ⊤`, with sign `(-1) ^ #(G'.edgeFinset \ G.edgeFinset)`. -/
245+
theorem embeddingCount_eq_sum_signed_copyCount [Fintype V] [DecidableEq V]
246+
[DecidableLE (SimpleGraph V)] [Finite W] (G : SimpleGraph V) (H : SimpleGraph W) :
247+
(H.embeddingCount G : ℤ) =
248+
∑ G' ∈ Finset.Icc G ⊤,
249+
(-1 : ℤ) ^ #(G'.edgeFinset \ G.edgeFinset) * (H.copyCount G' : ℤ) := by
250+
-- (1) The inner alternating sum collapses to `if L = G then 1 else 0`.
251+
have hinner : ∀ L : SimpleGraph V, G ≤ L →
252+
∑ K' ∈ Finset.Icc G L, (-1 : ℤ) ^ #(K'.edgeFinset \ G.edgeFinset)
253+
= if L = G then 1 else 0 := by
254+
intro L hGL
255+
have key : ∑ K' ∈ Finset.Icc G L, (-1 : ℤ) ^ #(K'.edgeFinset \ G.edgeFinset)
256+
= ∑ S ∈ (L.edgeFinset \ G.edgeFinset).powerset, (-1 : ℤ) ^ #S := by
257+
rw [← Finset.sum_attach (Finset.Icc G L)
258+
(fun K' => (-1 : ℤ) ^ #(K'.edgeFinset \ G.edgeFinset)),
259+
← Finset.sum_attach (L.edgeFinset \ G.edgeFinset).powerset
260+
(fun S => (-1 : ℤ) ^ #S)]
261+
exact Finset.sum_equiv (iccEquivPowersetEdgeFinsetSdiff hGL)
262+
(fun _ => by simp) (fun _ _ => rfl)
263+
rw [key, Finset.sum_powerset_neg_one_pow_card]
264+
by_cases hLG : L = G
265+
· subst hLG; simp
266+
· have hne : L.edgeFinset \ G.edgeFinset ≠ ∅ := by
267+
intro hempty
268+
apply hLG
269+
have hsub : L ≤ G := by
270+
simpa [Finset.sdiff_eq_empty_iff_subset, edgeFinset_subset_edgeFinset] using hempty
271+
exact le_antisymm hsub hGL
272+
rw [if_neg hne, if_neg hLG]
273+
-- (2) Substitute the forward identity into the right-hand side.
274+
simp_rw [fun K' : SimpleGraph V => copyCount_eq_sum_embeddingCount K' H,
275+
Nat.cast_sum, Finset.mul_sum]
276+
-- (3) Swap the order of summation: pairs (K', L) with G ≤ K' ≤ L ≤ ⊤.
277+
rw [Finset.sum_comm' (s := Finset.Icc G (⊤ : SimpleGraph V))
278+
(t := fun K' => Finset.Icc K' ⊤)
279+
(s' := fun L => Finset.Icc G L) (t' := Finset.Icc G (⊤ : SimpleGraph V))
280+
(h := fun K' L => by
281+
simp only [Finset.mem_Icc]; constructor
282+
· rintro ⟨⟨hGK', _⟩, hKL, _⟩
283+
exact ⟨⟨hGK', hKL⟩, ⟨hGK'.trans hKL, le_top⟩⟩
284+
· rintro ⟨⟨hGK', hKL⟩, _⟩
285+
exact ⟨⟨hGK', le_top⟩, ⟨hKL, le_top⟩⟩)]
286+
-- (4) Pull `embeddingCount L` out of the inner sum and apply `hinner`.
287+
simp_rw [mul_comm ((-1 : ℤ) ^ _) ((H.embeddingCount _ : ℤ)), ← Finset.mul_sum]
288+
-- (5) Apply `hinner` to each inner sum.
289+
rw [Finset.sum_congr rfl fun L hL => by
290+
rw [hinner L (Finset.mem_Icc.mp hL).1]]
291+
-- (6) Collapse using `sum_ite_eq'`: only the `L = G` term survives.
292+
simp_rw [mul_ite, mul_one, mul_zero]
293+
rw [Finset.sum_ite_eq' (Finset.Icc G ⊤) G (fun L => (H.embeddingCount L : ℤ))]
294+
rw [if_pos (Finset.mem_Icc.mpr ⟨le_refl _, le_top⟩)]
295+
296+
end Mobius
297+
298+
end SimpleGraph

0 commit comments

Comments
 (0)