forked from leanprover-community/mathlib4
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathInversion.lean
More file actions
364 lines (306 loc) · 16.7 KB
/
Copy pathInversion.lean
File metadata and controls
364 lines (306 loc) · 16.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/-
Copyright (c) 2026 Christoph Spiegel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Christoph Spiegel
-/
module
public import Mathlib.Combinatorics.SimpleGraph.Finite
public import Mathlib.Combinatorics.SimpleGraph.InducedCopy
public import Mathlib.Data.Nat.Choose.Sum
public import Mathlib.Data.Set.Card
/-!
# Möbius inversion between copy counts and induced copy counts
For a guest graph `G : SimpleGraph V` and a host graph `H : SimpleGraph W` with finite
vertex types, this file establishes the standard summation identity expressing the copy
count `H.copyCount G` as a sum over supergraphs of `G` (on the same vertex type `V`) of
induced copy counts `H.embeddingCount G'`, together with its Möbius inverse expressing
`H.embeddingCount G` as a signed sum of `H.copyCount G'`.
Following the convention from `Mathlib/Combinatorics/SimpleGraph/Copy.lean` and
`Mathlib/Combinatorics/SimpleGraph/InducedCopy.lean`, counting operations are host-first
(`H.copyCount G`, `H.embeddingCount G`); types are guest-first (`Copy G H`, `Embedding G H`).
## Main declarations
* `SimpleGraph.Copy.inducedShape` — for `f : Copy G H`, the supergraph of `G` on `V`
recording the induced adjacency on the image, transported back via `f.toEmbedding`.
* `SimpleGraph.Copy.fiberInducedShapeEquiv` — the per-fiber bijection between copies with a
prescribed induced shape and graph embeddings of that shape.
* `SimpleGraph.Copy.equivSigmaEmbedding` — the load-bearing bijection
`Copy G H ≃ Σ G' ∈ Icc G ⊤, Embedding G'.val H`.
* `SimpleGraph.iccEquivPowersetEdgeFinsetSdiff` — for `G ≤ K`, the equivalence
`Finset.Icc G K ≃ (K.edgeFinset \ G.edgeFinset).powerset` used to reduce the inner
alternating sum to `Finset.sum_powerset_neg_one_pow_card`.
## Main results
* `SimpleGraph.copyCount_eq_sum_embeddingCount` — forward identity:
`H.copyCount G = ∑ G' ∈ Icc G ⊤, H.embeddingCount G'`.
* `SimpleGraph.embeddingCount_eq_sum_signed_copyCount` — Möbius inverse over `ℤ`:
`(H.embeddingCount G : ℤ) = (-1) ^ Nat.card G.edgeSet *
∑ G' ∈ Icc G ⊤, (-1) ^ Nat.card G'.edgeSet * (H.copyCount G' : ℤ)`.
## Implementation notes
The forward bijection `Copy.equivSigmaEmbedding` is the only "real" content; the Möbius
direction reduces to it via the classical alternating-sum identity
`Finset.sum_powerset_neg_one_pow_card`, reindexed through the order-isomorphism
`G' ∈ Icc G ⊤ ↔ S ⊆ E(⊤) \ E(G)`.
The Möbius identity is stated in `ℤ` (rather than `ℕ`) because the signs are essential.
The user-facing form uses `Nat.card G.edgeSet` rather than `#(G'.edgeFinset \ G.edgeFinset)`
in the sign exponent: equivalent under `G ≤ G'` by parity, but `Nat.card` has no per-graph
`Fintype` hypothesis, keeping the theorem signature free of `Classical`.
The `LocallyFiniteOrder (SimpleGraph V)` instance consumed by `Finset.Icc G ⊤` comes from
`SimpleGraph.Finite.instLocallyFiniteOrder`, which requires `[DecidableLE (SimpleGraph V)]`.
-/
public section
open Finset Function
namespace SimpleGraph
variable {V W : Type*}
/-! ### Induced shape of a copy
The pullback `H.comap f.toEmbedding` records the induced adjacency on the image of a copy
`f : Copy G H`, transported back to `V`. It is always a supergraph of `G`, and pinning it
down to a specific supergraph `G'` promotes the copy to an embedding `G' ↪g H`. -/
namespace Copy
variable {G G' : SimpleGraph V} {H : SimpleGraph W}
/-- The pullback of the host graph along the underlying injection of a copy. -/
def inducedShape (f : Copy G H) : SimpleGraph V :=
H.comap f.toEmbedding
@[simp] lemma inducedShape_adj (f : Copy G H) {a b : V} :
f.inducedShape.Adj a b ↔ H.Adj (f a) (f b) := Iff.rfl
lemma le_inducedShape (f : Copy G H) : G ≤ f.inducedShape :=
fun _ _ => f.toHom.map_adj
/-- A copy with induced shape `G'` promotes to a graph embedding `G' ↪g H`. -/
@[expose] def toEmbeddingOfInducedShapeEq (f : Copy G H) (h : f.inducedShape = G') :
G' ↪g H where
toFun := f
inj' := f.injective
map_rel_iff' {a b} := by
change H.Adj (f a) (f b) ↔ G'.Adj a b
rw [← h, inducedShape_adj]
@[simp] lemma toEmbeddingOfInducedShapeEq_apply (f : Copy G H) (h : f.inducedShape = G')
(v : V) : f.toEmbeddingOfInducedShapeEq h v = f v := rfl
/-- The fiber of `inducedShape` over a supergraph `G' ≥ G` is canonically `Embedding G' H`. -/
def fiberInducedShapeEquiv (hGG' : G ≤ G') :
{f : Copy G H // f.inducedShape = G'} ≃ Embedding G' H where
toFun f := f.val.toEmbeddingOfInducedShapeEq f.prop
invFun e := ⟨e.toCopy.comp (Copy.ofLE G G' hGG'), by ext a b; simp [inducedShape]⟩
left_inv f := by apply Subtype.ext; ext v; simp
right_inv e := by apply DFunLike.ext; intro v; simp
end Copy
@[simp] lemma Embedding.inducedShape_toCopy {G : SimpleGraph V} {H : SimpleGraph W}
(e : Embedding G H) : e.toCopy.inducedShape = G := by
ext a b; rw [Copy.inducedShape_adj]; exact e.map_rel_iff
/-! ### Forward bijection and count identity -/
section Forward
variable {G : SimpleGraph V} {H : SimpleGraph W}
/-- The load-bearing equivalence: a copy of `G` in `H` is the same data as a choice of
supergraph `G' ∈ Icc G ⊤` (the induced shape) together with a graph embedding
`G' ↪g H`. This expresses every copy uniquely as an induced copy of some shape `G'`
between `G` and the complete graph.
The proof goes via the canonical fiber decomposition `Equiv.sigmaFiberEquiv` for the map
`Copy.inducedShape`. The index `K : SimpleGraph V` is restricted to `Icc G ⊤`, which is
exactly the set of shapes with nonempty fiber. The per-fiber bijection is
`Copy.fiberInducedShapeEquiv`. -/
noncomputable def Copy.equivSigmaEmbedding (G : SimpleGraph V) (H : SimpleGraph W)
[Fintype V] [DecidableEq V] [DecidableLE (SimpleGraph V)] :
Copy G H ≃ Σ G' : ↥(Finset.Icc G ⊤), Embedding G'.val H :=
(Equiv.sigmaFiberEquiv (Copy.inducedShape : Copy G H → SimpleGraph V)).symm.trans <|
{ toFun := fun ⟨K, f⟩ =>
let hGK : G ≤ K := f.prop ▸ f.val.le_inducedShape
⟨⟨K, Finset.mem_Icc.mpr ⟨hGK, le_top⟩⟩,
Copy.fiberInducedShapeEquiv hGK f⟩
invFun := fun ⟨⟨K, hK⟩, e⟩ =>
⟨K, (Copy.fiberInducedShapeEquiv (Finset.mem_Icc.mp hK).1).symm e⟩
left_inv := by
rintro ⟨K, f⟩
simp
right_inv := by
rintro ⟨⟨K, hK⟩, e⟩
simp only [Equiv.apply_symm_apply] }
/-- Forward identity: every copy of `G` in `H` is an induced copy of some unique
supergraph `G' ∈ Icc G ⊤` of `G`. -/
theorem copyCount_eq_sum_embeddingCount [Fintype V] [DecidableEq V]
[DecidableLE (SimpleGraph V)] [Finite W] (G : SimpleGraph V) (H : SimpleGraph W) :
H.copyCount G = ∑ G' ∈ Finset.Icc G ⊤, H.embeddingCount G' := by
rw [copyCount_eq_nat_card, Nat.card_congr (Copy.equivSigmaEmbedding G H), Nat.card_sigma,
← Finset.sum_attach (Finset.Icc G ⊤) (fun G' => H.embeddingCount G')]
refine Finset.sum_congr rfl fun G' _ => ?_
exact (embeddingCount_eq_nat_card _ _).symm
end Forward
/-! ### Möbius (signed-sum) inverse
The Möbius inverse to the forward identity, expressing `H.embeddingCount G` as a signed
sum of `H.copyCount G'` over supergraphs `G' ∈ Icc G ⊤`. The proof reduces, via the
order-isomorphism `iccEquivPowersetEdgeFinsetSdiff` below, to the alternating-sum
identity `Finset.sum_powerset_neg_one_pow_card`.
-/
section Mobius
variable [Fintype V] [DecidableEq V] [DecidableLE (SimpleGraph V)]
/-! ### Finset of extra edges
Helper construction giving the Finset of edges in `K` but not in `G`, without requiring a
per-graph `Fintype` instance on the edge sets. Uses `Set.Finite.toFinset` (noncomputable). -/
omit [Fintype V] [DecidableEq V] [DecidableLE (SimpleGraph V)] in
/-- The set difference of edge sets on a finite vertex type is finite. -/
lemma edgeSet_sdiff_finite [Finite V] (G K : SimpleGraph V) : (K.edgeSet \ G.edgeSet).Finite :=
Set.finite_univ.subset (Set.subset_univ _)
/-- The Finset of edges in `K` but not in `G`. Constructed via `Set.Finite.toFinset`,
so noncomputable, but requires no per-graph `Fintype` synthesis. -/
noncomputable def edgeSetSdiffFinset (G K : SimpleGraph V) : Finset (Sym2 V) :=
(edgeSet_sdiff_finite G K).toFinset
omit [DecidableEq V] [DecidableLE (SimpleGraph V)] in
@[simp] lemma mem_edgeSetSdiffFinset {G K : SimpleGraph V} {e : Sym2 V} :
e ∈ edgeSetSdiffFinset G K ↔ e ∈ K.edgeSet ∧ e ∉ G.edgeSet :=
Set.Finite.mem_toFinset _
omit [DecidableEq V] [DecidableLE (SimpleGraph V)] in
/-- Under `G ≤ K`, `Nat.card K.edgeSet = Nat.card G.edgeSet + #(edgeSetSdiffFinset G K)`. -/
lemma natCard_edgeSet_eq_add_card_sdiff {G K : SimpleGraph V} (hGK : G ≤ K) :
Nat.card K.edgeSet = Nat.card G.edgeSet + #(edgeSetSdiffFinset G K) := by
rw [Nat.card_coe_set_eq, Nat.card_coe_set_eq,
show #(edgeSetSdiffFinset G K) = (K.edgeSet \ G.edgeSet).ncard from
(Set.ncard_eq_toFinset_card _ (edgeSet_sdiff_finite G K)).symm,
add_comm]
exact (Set.ncard_sdiff_add_ncard_of_subset (edgeSet_subset_edgeSet.mpr hGK)).symm
/-! ### Bijection between Icc and powerset of extra edges -/
/-- Equivalence between the closed interval `Finset.Icc G K` of graphs and the powerset of
the Finset of edges in `K` not in `G`, when `G ≤ K`.
Forward: `G' ∈ [G, K]` maps to the Finset `edgeSetSdiffFinset G G'.val` (its extra edges
over `G`, automatically a subset of `edgeSetSdiffFinset G K` since `G' ≤ K`).
Inverse: a subset `S ⊆ edgeSetSdiffFinset G K` maps to `fromEdgeSet (G.edgeSet ∪ ↑S)`. -/
noncomputable def iccEquivPowersetEdgeFinsetSdiff
{G K : SimpleGraph V} (hGK : G ≤ K) :
↥(Finset.Icc G K) ≃ ↥(edgeSetSdiffFinset G K).powerset where
toFun G' :=
⟨edgeSetSdiffFinset G G'.val, by
rw [Finset.mem_powerset]
intro e he
rw [mem_edgeSetSdiffFinset] at he ⊢
exact ⟨edgeSet_subset_edgeSet.mpr (Finset.mem_Icc.mp G'.prop).2 he.1, he.2⟩⟩
invFun S :=
⟨fromEdgeSet (G.edgeSet ∪ ↑S.val), by
have hSK : ∀ e ∈ S.val, e ∈ K.edgeSet ∧ e ∉ G.edgeSet := fun e he => by
have := Finset.mem_powerset.mp S.prop he
rwa [mem_edgeSetSdiffFinset] at this
refine Finset.mem_Icc.mpr ⟨fun a b hab => ?_, ?_⟩
· exact (fromEdgeSet_adj _).mpr ⟨.inl hab, hab.ne⟩
· rw [fromEdgeSet_le]
rintro e ⟨heGS | heGS, _⟩
· exact edgeSet_subset_edgeSet.mpr hGK heGS
· exact (hSK e (Finset.mem_coe.mp heGS)).1⟩
left_inv := by
rintro ⟨G', hG'⟩
have hGG' : G ≤ G' := (Finset.mem_Icc.mp hG').1
apply Subtype.ext
ext a b
rw [fromEdgeSet_adj]
simp only [Set.mem_union, Finset.mem_coe, mem_edgeSetSdiffFinset]
refine ⟨fun ⟨h, _⟩ => h.elim (edgeSet_subset_edgeSet.mpr hGG' ·) (·.1),
fun h => ⟨?_, h.ne⟩⟩
by_cases hG : G.Adj a b
· exact .inl hG
· exact .inr ⟨h, hG⟩
right_inv := by
rintro ⟨S, hS⟩
have hSK : ∀ e ∈ S, e ∈ K.edgeSet ∧ e ∉ G.edgeSet := fun e he => by
have := Finset.mem_powerset.mp hS he
rwa [mem_edgeSetSdiffFinset] at this
apply Subtype.ext
apply Finset.ext
intro e
rw [mem_edgeSetSdiffFinset, edgeSet_fromEdgeSet, Set.mem_sdiff, Set.mem_union]
refine ⟨?_, fun heS => ?_⟩
· rintro ⟨⟨h | h, _⟩, heG⟩
· exact absurd h heG
· exact Finset.mem_coe.mp h
· have ⟨heK, heG⟩ := hSK e heS
exact ⟨⟨.inr (Finset.mem_coe.mpr heS), fun hd =>
K.not_isDiag_of_mem_edgeSet heK hd⟩, heG⟩
/-! ### Combinatorial kernel
Split into two pieces, avoiding `if-then-else` (which would require `DecidableEq` on
`SimpleGraph V`). Consumers case-split on `G = L vs G < L` via `eq_or_lt_of_le`. -/
/-- Degenerate case: the alternating sum over a singleton interval. -/
lemma sum_Icc_self_neg_one_pow_natCard_edgeSet (G : SimpleGraph V) :
∑ K' ∈ Finset.Icc G G, (-1 : ℤ) ^ Nat.card K'.edgeSet
= (-1 : ℤ) ^ Nat.card G.edgeSet := by
rw [Finset.Icc_self, Finset.sum_singleton]
/-- Strictly-larger case: the alternating sum over `Icc G L` with `G < L` is zero.
Reindexes via `iccEquivPowersetEdgeFinsetSdiff`, factors out the `(-1)^Nat.card G.edgeSet`
constant via the cardinality bridge, then collapses via `Finset.sum_powerset_neg_one_pow_card`
(which is zero on a non-empty powerset). -/
lemma sum_Icc_neg_one_pow_natCard_edgeSet_of_lt
{G L : SimpleGraph V} (hGL : G < L) :
∑ K' ∈ Finset.Icc G L, (-1 : ℤ) ^ Nat.card K'.edgeSet = 0 := by
have hGL' : G ≤ L := hGL.le
-- Reindex the sum via `iccEquiv` and factor out `(-1)^Nat.card G.edgeSet`.
have key : ∑ K' ∈ Finset.Icc G L, (-1 : ℤ) ^ Nat.card K'.edgeSet
= (-1 : ℤ) ^ Nat.card G.edgeSet *
∑ S ∈ (edgeSetSdiffFinset G L).powerset, (-1 : ℤ) ^ #S := by
rw [Finset.mul_sum,
← Finset.sum_attach (Finset.Icc G L)
(fun K' => (-1 : ℤ) ^ Nat.card K'.edgeSet),
← Finset.sum_attach (edgeSetSdiffFinset G L).powerset
(fun S => (-1 : ℤ) ^ Nat.card G.edgeSet * (-1 : ℤ) ^ #S)]
refine Finset.sum_equiv (iccEquivPowersetEdgeFinsetSdiff hGL')
(fun _ => by simp) ?_
intro K' _
have hGK' : G ≤ K'.val := (Finset.mem_Icc.mp K'.prop).1
rw [natCard_edgeSet_eq_add_card_sdiff hGK', pow_add]
rfl
rw [key, Finset.sum_powerset_neg_one_pow_card, if_neg, mul_zero]
-- Remaining goal: `edgeSetSdiffFinset G L ≠ ∅`, which would imply `L ≤ G`.
intro hempty
have hLsubG : L.edgeSet ⊆ G.edgeSet :=
Set.sdiff_eq_empty.mp ((edgeSet_sdiff_finite G L).toFinset_eq_empty.mp hempty)
exact absurd (le_antisymm (edgeSet_subset_edgeSet.mp hLsubG) hGL') hGL.ne'
/-! ### Main Möbius identity -/
/-- The Möbius (signed-sum) inverse to `copyCount_eq_sum_embeddingCount`. The induced copy
count is expressed as a signed sum of copy counts over supergraphs `G' ∈ Icc G ⊤`, with the
sign factored as `(-1)^Nat.card G.edgeSet * (-1)^Nat.card G'.edgeSet`.
The `Nat.card` form keeps the signature free of per-graph `Fintype` synthesis on edge sets
(and hence free of `Classical`). -/
theorem embeddingCount_eq_sum_signed_copyCount [Finite W]
(G : SimpleGraph V) (H : SimpleGraph W) :
(H.embeddingCount G : ℤ) =
(-1 : ℤ) ^ Nat.card G.edgeSet *
∑ G' ∈ Finset.Icc G ⊤,
(-1 : ℤ) ^ Nat.card G'.edgeSet * (H.copyCount G' : ℤ) := by
symm
calc (-1 : ℤ) ^ Nat.card G.edgeSet *
∑ G' ∈ Finset.Icc G ⊤,
(-1 : ℤ) ^ Nat.card G'.edgeSet * (H.copyCount G' : ℤ)
-- Substitute the forward identity into each `copyCount G'`.
= (-1 : ℤ) ^ Nat.card G.edgeSet *
∑ G' ∈ Finset.Icc G ⊤, ∑ L ∈ Finset.Icc G' ⊤,
(-1 : ℤ) ^ Nat.card G'.edgeSet * (H.embeddingCount L : ℤ) := by
simp_rw [copyCount_eq_sum_embeddingCount, Nat.cast_sum, Finset.mul_sum]
-- Distribute `(-1)^Nat.card G.edgeSet` into the double sum.
_ = ∑ G' ∈ Finset.Icc G ⊤, ∑ L ∈ Finset.Icc G' ⊤,
(-1 : ℤ) ^ Nat.card G.edgeSet *
((-1 : ℤ) ^ Nat.card G'.edgeSet * (H.embeddingCount L : ℤ)) := by
rw [Finset.mul_sum]
refine Finset.sum_congr rfl fun G' _ => ?_
rw [Finset.mul_sum]
-- Swap the order of summation over the triangle `G ≤ G' ≤ L ≤ ⊤`.
_ = ∑ L ∈ Finset.Icc G ⊤, ∑ G' ∈ Finset.Icc G L,
(-1 : ℤ) ^ Nat.card G.edgeSet *
((-1 : ℤ) ^ Nat.card G'.edgeSet * (H.embeddingCount L : ℤ)) := by
rw [Finset.sum_comm' (s := Finset.Icc G (⊤ : SimpleGraph V))
(t := fun G' => Finset.Icc G' ⊤)
(s' := fun L => Finset.Icc G L) (t' := Finset.Icc G (⊤ : SimpleGraph V))
(h := fun G' L => by
simp only [Finset.mem_Icc]
exact ⟨fun ⟨⟨hGG', _⟩, hG'L, _⟩ => ⟨⟨hGG', hG'L⟩, hGG'.trans hG'L, le_top⟩,
fun ⟨⟨hGG', hG'L⟩, _⟩ => ⟨⟨hGG', le_top⟩, hG'L, le_top⟩⟩)]
-- Factor `H.embeddingCount L` out of each inner sum.
_ = ∑ L ∈ Finset.Icc G ⊤, (H.embeddingCount L : ℤ) *
((-1 : ℤ) ^ Nat.card G.edgeSet *
∑ G' ∈ Finset.Icc G L, (-1 : ℤ) ^ Nat.card G'.edgeSet) := by
refine Finset.sum_congr rfl fun L _ => ?_
rw [Finset.mul_sum, Finset.mul_sum]
refine Finset.sum_congr rfl fun G' _ => ?_
ring
-- Isolate the `L = G` term: all others vanish via the strict-`G < L` kernel.
_ = (H.embeddingCount G : ℤ) := by
rw [Finset.sum_eq_single G]
· rw [sum_Icc_self_neg_one_pow_natCard_edgeSet, ← pow_add,
Even.neg_one_pow ⟨_, rfl⟩, mul_one]
· intro L hL hLG
rcases eq_or_lt_of_le (Finset.mem_Icc.mp hL).1 with rfl | hGL
· exact absurd rfl hLG
· rw [sum_Icc_neg_one_pow_natCard_edgeSet_of_lt hGL, mul_zero, mul_zero]
· intro hG
exact absurd (Finset.mem_Icc.mpr ⟨le_refl _, le_top⟩) hG
end Mobius
end SimpleGraph