Skip to content

Commit 6579da0

Browse files
CFLs not closed under intersection — explicit witnesses (cfl_not_closed_inter) (#109)
Completes §7.3: the explicit **"context-free languages are not closed under intersection"** theorem, built from scratch in core Lean (Mathlib-free, single-file). Follow-up to #108 (`aⁿbⁿcⁿ ∉ CFL`). ## `cfl_not_closed_inter` ``` ∃ K₁ K₂, IsCFL K₁ ∧ IsCFL K₂ ∧ ¬ IsCFL (fun w => K₁ w ∧ K₂ w) ``` Witnesses `L₁ = {aⁱbⁱcʲ : i,j ≥ 1}` and `L₂ = {aᵐbⁿcⁿ : m,n ≥ 1}`: - **Each is context-free** — an explicit ε-free binary-normal-form grammar (`R1`, `R2`, 7 nonterminals each: start, the balanced-pair recursion, the star recursion, three terminals) with **full exact generation**: - *soundness* (`sound_all1` / `sound_all2`): one structural induction over the parse tree with inversion on the root production — every tree's yield lies in its nonterminal's language (`Char1` / `Char2`); - *completeness* (`tree_X1`/`tree_Y1`, `tree_A2'`/`tree_W2`): a parse tree built for every word in the language. - **Their intersection is `{aⁿbⁿcⁿ}`** (`inter_eq`): `L₁` forces `#a = #b`, `L₂` forces `#b = #c`; equating the three letter-counts (`count_tri_a/b/c`) forces all three equal. - `{aⁿbⁿcⁿ}` is **not** context-free (`anbncn_not_cfl`, #108) — contradiction. Closure under **complement** is refuted by the same witnesses via De Morgan against CFL ∪-closure (noted in the docstring). ## Trust base Standard classical kernel constants only: `cfl_not_closed_inter` → `propext, Classical.choice, Quot.sound`; `isCFL_L1`/`isCFL_L2`/`inter_eq` → `propext, Quot.sound`. No holes, no project-specific assumptions (axiom table in `GRAMMAR-PROOF-INVENTORY.md`). ## Verification `lean docs/proofs/verification/WokeGrammarPumping.lean` exits 0, no warnings. With this, **§7 is fully machine-checked end-to-end**: Chomsky position, non-regularity (DFA fooling-set), CFL positive closure (∪, ·, *), the CFL pumping lemma, `aⁿbⁿcⁿ ∉ CFL`, and ∩ non-closure — all from scratch, Mathlib-free. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_015oyMquf4daB6hMhmqB1wAL --- _Generated by [Claude Code](https://claude.ai/code/session_015oyMquf4daB6hMhmqB1wAL)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent ff575b1 commit 6579da0

4 files changed

Lines changed: 294 additions & 24 deletions

File tree

RESUME.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,18 @@ Done (in `WokeGrammarPumping.lean`):
8989
gives `|vwx| > p`, contradicting `|vwx| ≤ p`. This is the canonical non-CFL and
9090
the crux of the ∩/¬ non-closure result.
9191

92-
Remaining (next increment):
93-
94-
3. **The explicit ∩ / ¬ non-closure statement** — exhibit the two witness CFLs
95-
`L₁ = {aⁿbⁿcᵐ}` and `L₂ = {aᵐbⁿcⁿ}` (each: a BNF grammar + an exact-generation
96-
proof, i.e. soundness + completeness), with `L₁ ∩ L₂ = {aⁿbⁿcⁿ}` discharged by
97-
`anbncn_not_cfl`. This is mechanical grammar-construction plumbing on top of the
98-
verified crux.
92+
3. **The explicit ∩ non-closure statement** (`cfl_not_closed_inter`) — the two
93+
witness CFLs `L₁ = {aⁱbⁱcʲ}` and `L₂ = {aᵐbⁿcⁿ}` are each proved context-free by
94+
an explicit ε-free BNF grammar (`R1`, `R2`) with full exact generation
95+
(soundness via tree inversion `sound_all1`/`sound_all2`, completeness via tree
96+
builders), and `L₁ ∩ L₂ = {aⁿbⁿcⁿ}` (`inter_eq`) is discharged by
97+
`anbncn_not_cfl`. **Done.**
98+
99+
§7 is now fully machine-checked end-to-end. The only further extension one could
100+
add is closure under **complement** as a standalone theorem, which needs CFL
101+
∪-closure for this BNF `IsCFL` (the positive closure exists in
102+
`WokeGrammarCFL.lean` under a relation-based `IsCFL`); the De Morgan corollary is
103+
noted in `cfl_not_closed_inter`'s docstring.
99104

100105
Plan: land it as its own follow-up PR (incremental, same as the pumping lemma).
101106

docs/proofs/formal-semantics/grammar-proofs.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,10 @@ The binding power comparison ensures this:
336336
> application, the same file machine-checks **`aⁿbⁿcⁿ ∉ CFL`** (`anbncn_not_cfl`) —
337337
> the standard witness that the CFLs are not closed under ∩ / ¬ (pump down to
338338
> `i = 0` ⇒ equal letter-counts ⇒ the window spans `a``c``|vwx| > p`). The
339-
> remaining §7.3 *non*-closure step is purely the two witness-grammar constructions
340-
> `{aⁿbⁿcᵐ}`, `{aᵐbⁿcⁿ}`; status in
339+
> full §7.3 **non-closure under ∩** is then machine-checked too
340+
> (`cfl_not_closed_inter`): the witnesses `L₁ = {aⁱbⁱcʲ}` and `L₂ = {aᵐbⁿcⁿ}` are
341+
> each proved context-free by an explicit ε-free binary-normal-form grammar (with
342+
> soundness + completeness), and `L₁ ∩ L₂ = {aⁿbⁿcⁿ}` is not. Status in
341343
> `../verification/GRAMMAR-PROOF-INVENTORY.md`.
342344
343345
### 7.1 Chomsky Hierarchy Position

docs/proofs/verification/GRAMMAR-PROOF-INVENTORY.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ reach here, with reason).
7373
| T7.1 | §7.1 Not regular (pumping lemma) | ✅ done from scratch | **P6→done** | `WokeGrammarRegular.lean`: bespoke finite pigeonhole + `Fin k` DFA + fooling-set on `aⁿbⁿ` (≅ `(ⁿ)ⁿ`), Mathlib-free | MACHINE-CHECKED |
7474
| T7.0 | CFL pumping lemma (Mathlib-gap) | ✅ done from scratch | **Ext** | `WokeGrammarPumping.lean`: `cfl_pumping``descend`/`ht_descend`/`nodeNT_add` spine navigation + `Ctx.comp` + pigeonhole ⇒ `z = uvwxy`, `1≤|vx|`, `|vwx|≤2^(card+1)`, `uvⁱwxⁱy ∈ L`; classical kernel constants only | MACHINE-CHECKED |
7575
| T7.0b | `aⁿbⁿcⁿ ∉ CFL` (canonical non-CFL) | ✅ done from scratch | **Ext** | `WokeGrammarPumping.lean`: `anbncn_not_cfl` via `cfl_pumping` (pump `i=0` ⇒ equal counts ⇒ window spans `a``c` ⇒ `|vwx|>p`); positional core `prefix_pure`/`abc_window`; classical kernel constants only | MACHINE-CHECKED |
76-
| T7.3b | §7.3 CFL **not** closed under ∩, ¬ | ⚠️ canonical witness done; wrapper remaining | **P6** | `aⁿbⁿcⁿ ∉ CFL` (T7.0b) is the crux and is proved; remaining: the two witness CFLs `{aⁿbⁿcᵐ}`,`{aᵐbⁿcⁿ}` (BNF grammars + exact generation) whose intersection is `aⁿbⁿcⁿ` | IN PROGRESS |
76+
| T7.3b | §7.3 CFL **not** closed under ∩ |done from scratch | **P6→done** | `WokeGrammarPumping.lean`: `cfl_not_closed_inter` — witnesses `L₁={aⁱbⁱcʲ}`, `L₂={aᵐbⁿcⁿ}` are CFL (explicit BNF grammars `R1`,`R2` + soundness via tree inversion + completeness via tree building), `L₁∩L₂={aⁿbⁿcⁿ}` not CFL (T7.0b) | MACHINE-CHECKED |
7777

7878
## Priority order (execution)
7979

@@ -85,7 +85,9 @@ reach here, with reason).
8585
3. **P3 — lexer maximal-munch + keyword-priority** (T4.1, T4.2).
8686
4. **P4 — classification** (T1.1 CFG, T1.2 LL(1)✗, T2.3 LL(2) witness).
8787
5. **P5 — CFL positive closure** (T7.3a).
88-
6. **P6 — honest flags** (T7.1, T7.3b): partial kernel + documented reason.
88+
6. **P6 — non-regularity + non-closure** (T7.1, T7.0/T7.0b, T7.3b): originally
89+
flagged, now all machine-checked from scratch (DFA fooling-set; CFL pumping
90+
lemma; `aⁿbⁿcⁿ ∉ CFL`; ∩ non-closure with explicit witness grammars).
8991

9092
Then **mirror P1–P5 to Coq** (the repo keeps Lean/Coq in lockstep) and **gate
9193
both in CI**.
@@ -100,8 +102,8 @@ both in CI**.
100102
extraction.
101103
- **Full-CFG unambiguity** (T2.2 for the *entire* grammar) is undecidable; only
102104
the core is proven unambiguous (via parser determinism).
103-
- The **non-regularity / non-closure** results (T7.1, T7.3b) are flagged, not
104-
faked — see P6.
105+
- The **non-regularity / non-closure** results (T7.1, T7.3b) were initially
106+
flagged; they are now fully machine-checked from scratch (see P6) — never faked.
105107

106108
## Landed — P1 (`WokeGrammar.lean`, Lean 4.30.0)
107109

@@ -196,11 +198,16 @@ identical" per `AUDIT.md`.)
196198
`i = 0` forces `count_a = count_b = count_c` in the deleted part, so the pumped
197199
window contains an `a` and a `c`; the positional core (`prefix_pure` by induction
198200
on the prefix, `abc_window`) then gives `|vwx| > p`, contradicting `|vwx| ≤ p`.
199-
- **§7.3 *non-closure* under ∩ / ¬** — the remaining wrapper. With `aⁿbⁿcⁿ ∉ CFL`
200-
proved, the explicit statement follows from the two witness CFLs `{aⁿbⁿcᵐ}` and
201-
`{aᵐbⁿcⁿ}` (whose intersection is `aⁿbⁿcⁿ`); each needs a BNF grammar plus an
202-
exact-generation (soundness + completeness) proof — mechanical grammar-construction
203-
plumbing on top of the verified crux.
201+
- **§7.3 *non-closure* under ∩ — DONE** (`WokeGrammarPumping.lean`,
202+
`cfl_not_closed_inter`): the context-free languages are not closed under
203+
intersection. Witnesses `L₁ = {aⁱbⁱcʲ}` and `L₂ = {aᵐbⁿcⁿ}` are each shown
204+
context-free by an explicit ε-free binary-normal-form grammar (`R1`, `R2`) with
205+
full *exact generation* — soundness (`sound_all1`/`sound_all2`, one structural
206+
induction with inversion on the root production) and completeness (tree builders
207+
`tree_X1`/`tree_Y1`, `tree_A2'`/`tree_W2`). Their intersection is `{aⁿbⁿcⁿ}`
208+
(`inter_eq`, by equating the three letter-counts), which `anbncn_not_cfl` rules
209+
out. Closure under **complement** is refuted by the same witnesses via De Morgan
210+
against CFL ∪-closure (the standard corollary).
204211

205212
## Axiom audit (`#print axioms`, verified in-toolchain)
206213

@@ -218,6 +225,9 @@ project-specific constants:
218225
| `prefix_pure` | `propext` |
219226
| `abc_window` | `propext`, `Quot.sound` |
220227
| `anbncn_not_cfl` | `propext`, `Classical.choice`, `Quot.sound` |
228+
| `isCFL_L1`, `isCFL_L2` | `propext`, `Quot.sound` |
229+
| `inter_eq` | `propext`, `Quot.sound` |
230+
| `cfl_not_closed_inter` | `propext`, `Classical.choice`, `Quot.sound` |
221231

222232
`Classical.choice` enters only through the finite `pigeon`hole's case split; the
223233
rest are the kernel constants Mathlib itself rests on. The other files' headline

docs/proofs/verification/WokeGrammarPumping.lean

Lines changed: 259 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,18 @@ What is proved here (complete proofs — no holes, no escape hatches):
2525
context-free. Apply `cfl_pumping` to `aᵖbᵖcᵖ`; pumping down to `i = 0` forces
2626
equal letter-counts in the pumped part, so it spans an `a` and a `c`, which
2727
(positional core `prefix_pure`/`abc_window`) makes `|v w x| > p` — contradicting
28-
`|v w x| ≤ p`. This is the standard witness that the CFLs are not closed under
29-
intersection / complement.
28+
`|v w x| ≤ p`.
29+
• `cfl_not_closed_inter` : THE non-closure theorem — the context-free languages
30+
are not closed under intersection. Witnesses `L₁ = {aⁱbⁱcʲ}` and `L₂ = {aᵐbⁿcⁿ}`
31+
are both context-free (explicit ε-free binary-normal-form grammars `R1`, `R2`,
32+
each with full soundness via tree inversion + completeness via tree building),
33+
but `L₁ ∩ L₂ = {aⁿbⁿcⁿ}`, which `anbncn_not_cfl` rules out. (With CFL ∪-closure
34+
and De Morgan this also refutes closure under complement.)
3035
3136
Trust base: only the three standard classical kernel constants `propext`,
3237
`Classical.choice`, and `Quot.sound` — the same foundations Mathlib relies on
3338
(`Classical.choice` enters through the `pigeon` case split). There are no holes
3439
and no project-specific assumptions; every step is checked by Lean's kernel.
35-
36-
NEXT: wrap `anbncn_not_cfl` into the explicit ∩ / ¬ non-closure statement by
37-
exhibiting the two witness CFLs `{aⁿbⁿcᵐ}`, `{aᵐbⁿcⁿ}` (BNF grammars + exact
38-
generation) whose intersection is `aⁿbⁿcⁿ`.
3940
-/
4041

4142
-- A grammar in binary normal form: every production is A → B C, A → t, or A → ε.
@@ -535,4 +536,256 @@ theorem anbncn_not_cfl : ¬ IsCFL (fun z => ∃ n, 1 ≤ n ∧ z = abc n) := by
535536
have hgt := abc_window hwin hain hcin
536537
omega
537538

539+
/-! ### CFLs are not closed under intersection / complement — explicit witnesses
540+
541+
`L₁ = { aⁱbⁱcʲ : i,j ≥ 1 }` and `L₂ = { aᵐbⁿcⁿ : m,n ≥ 1 }` are both context-free
542+
(ε-free binary-normal-form grammars below), but `L₁ ∩ L₂ = { aⁿbⁿcⁿ }`, which is
543+
not (`anbncn_not_cfl`). -/
544+
545+
/-- `aⁱbⁱ`. -/
546+
def ab (i : Nat) : List Letter := replicate i a ++ replicate i b
547+
548+
theorem ab_cons (i : Nat) : [a] ++ (ab i ++ [b]) = ab (i + 1) := by
549+
have hb : replicate i b ++ [b] = replicate (i + 1) b := replicate_succ'.symm
550+
have ha : [a] ++ replicate i a = replicate (i + 1) a := by rw [replicate_succ]; rfl
551+
simp only [ab, List.append_assoc]
552+
rw [hb, ← List.append_assoc, ha]
553+
554+
/-- Nonterminals for `L₁`'s grammar. -/
555+
inductive M1 | S | X | Z | Y | Ta | Tb | Tc
556+
deriving DecidableEq
557+
558+
/-- Productions: `S → X Y`, `X → a b | a Z`, `Z → X b`, `Y → c | c Y`, plus the
559+
single-terminal rules. Binary normal form, ε-free. -/
560+
inductive R1 : M1 → BProd M1 Letter → Prop
561+
| s : R1 .S (.bin .X .Y)
562+
| xab : R1 .X (.bin .Ta .Tb)
563+
| xaz : R1 .X (.bin .Ta .Z)
564+
| zxb : R1 .Z (.bin .X .Tb)
565+
| ycy : R1 .Y (.bin .Tc .Y)
566+
| yc : R1 .Y (.term .c)
567+
| ta : R1 .Ta (.term .a)
568+
| tb : R1 .Tb (.term .b)
569+
| tc : R1 .Tc (.term .c)
570+
571+
/-- Per-nonterminal language characterization. -/
572+
def Char1 : M1 → List Letter → Prop
573+
| .S, w => ∃ i j, 1 ≤ i ∧ 1 ≤ j ∧ w = ab i ++ replicate j c
574+
| .X, w => ∃ i, 1 ≤ i ∧ w = ab i
575+
| .Z, w => ∃ i, 1 ≤ i ∧ w = ab i ++ [b]
576+
| .Y, w => ∃ j, 1 ≤ j ∧ w = replicate j c
577+
| .Ta, w => w = [a]
578+
| .Tb, w => w = [b]
579+
| .Tc, w => w = [c]
580+
581+
/-- **Soundness.** Every parse tree's yield lies in its nonterminal's language —
582+
proved by one structural induction with inversion on the root production. -/
583+
theorem sound_all1 {A : M1} {w : List Letter} (t : PT R1 A w) : Char1 A w := by
584+
induction t with
585+
| @bin A B C w1 w2 h _ _ ih1 ih2 =>
586+
cases h with
587+
| s => obtain ⟨i, hi, e1⟩ := ih1; obtain ⟨j, hj, e2⟩ := ih2
588+
exact ⟨i, j, hi, hj, by rw [e1, e2]⟩
589+
| xab => exact ⟨1, Nat.le_refl 1,
590+
by rw [show w1 = [a] from ih1, show w2 = [b] from ih2]; simp [ab, replicate_succ]⟩
591+
| xaz => obtain ⟨i, hi, e2⟩ := ih2
592+
exact ⟨i + 1, by omega, by rw [show w1 = [a] from ih1, e2, ab_cons]⟩
593+
| zxb => obtain ⟨i, hi, e1⟩ := ih1
594+
exact ⟨i, hi, by rw [e1, show w2 = [b] from ih2]⟩
595+
| ycy => obtain ⟨j, hj, e2⟩ := ih2
596+
exact ⟨j + 1, by omega, by rw [show w1 = [c] from ih1, e2]; simp [replicate_succ]⟩
597+
| @term A ltr h =>
598+
cases h with
599+
| yc => exact ⟨1, Nat.le_refl 1, by simp [replicate_succ]⟩
600+
| ta => rfl
601+
| tb => rfl
602+
| tc => rfl
603+
| @eps A h => cases h
604+
605+
def enum1 : M1 → Nat
606+
| .S => 0 | .X => 1 | .Z => 2 | .Y => 3 | .Ta => 4 | .Tb => 5 | .Tc => 6
607+
608+
/-- **Completeness for `X`:** a tree for every `aⁱ⁺¹bⁱ⁺¹`. -/
609+
theorem tree_X1 : ∀ i, Nonempty (PT R1 .X (ab (i + 1))) := by
610+
intro i
611+
induction i with
612+
| zero => exact ⟨(PT.bin .xab (.term .ta) (.term .tb) : PT R1 .X ([a] ++ [b]))⟩
613+
| succ m ih =>
614+
obtain ⟨tx⟩ := ih
615+
have tz : PT R1 .Z (ab (m + 1) ++ [b]) := .bin .zxb tx (.term .tb)
616+
have tx2 : PT R1 .X ([a] ++ (ab (m + 1) ++ [b])) := .bin .xaz (.term .ta) tz
617+
rw [ab_cons] at tx2; exact ⟨tx2⟩
618+
619+
/-- **Completeness for `Y`:** a tree for every `cʲ⁺¹`. -/
620+
theorem tree_Y1 : ∀ j, Nonempty (PT R1 .Y (replicate (j + 1) c)) := by
621+
intro j
622+
induction j with
623+
| zero => exact ⟨.term .yc⟩
624+
| succ m ih =>
625+
obtain ⟨ty⟩ := ih
626+
have h : PT R1 .Y ([c] ++ replicate (m + 1) c) := .bin .ycy (.term .tc) ty
627+
rw [show [c] ++ replicate (m + 1) c = replicate (m + 2) c from by simp [replicate_succ]] at h
628+
exact ⟨h⟩
629+
630+
/-- `L₁ = { aⁱbⁱcʲ : i,j ≥ 1 }`. -/
631+
def L1 : List Letter → Prop := fun w => ∃ i j, 1 ≤ i ∧ 1 ≤ j ∧ w = ab i ++ replicate j c
632+
633+
theorem isCFL_L1 : IsCFL L1 := by
634+
refine ⟨M1, R1, .S, enum1, 7, ?_, ?_, ?_, ?_⟩
635+
· intro A; cases A <;> decide
636+
· intro A B; cases A <;> cases B <;> decide
637+
· intro A; cases A <;> (intro h; cases h)
638+
· intro w
639+
constructor
640+
· rintro ⟨i, j, hi, hj, rfl⟩
641+
obtain ⟨i', rfl⟩ : ∃ i', i = i' + 1 := ⟨i - 1, by omega⟩
642+
obtain ⟨j', rfl⟩ : ∃ j', j = j' + 1 := ⟨j - 1, by omega⟩
643+
obtain ⟨tx⟩ := tree_X1 i'; obtain ⟨ty⟩ := tree_Y1 j'
644+
exact ⟨.bin .s tx ty⟩
645+
· rintro ⟨t⟩; exact sound_all1 t
646+
647+
/-! #### `L₂ = { aᵐbⁿcⁿ : m,n ≥ 1 }` — mirror grammar (a⁺ then balanced bc) -/
648+
649+
/-- `bⁿcⁿ`. -/
650+
def bc (i : Nat) : List Letter := replicate i b ++ replicate i c
651+
652+
theorem bc_cons (i : Nat) : [b] ++ (bc i ++ [c]) = bc (i + 1) := by
653+
have hc : replicate i c ++ [c] = replicate (i + 1) c := replicate_succ'.symm
654+
have hb : [b] ++ replicate i b = replicate (i + 1) b := by rw [replicate_succ]; rfl
655+
simp only [bc, List.append_assoc]
656+
rw [hc, ← List.append_assoc, hb]
657+
658+
inductive M2 | S | A2 | W | Z2 | Ta | Tb | Tc
659+
deriving DecidableEq
660+
661+
inductive R2 : M2 → BProd M2 Letter → Prop
662+
| s : R2 .S (.bin .A2 .W)
663+
| aa : R2 .A2 (.term .a)
664+
| aaa : R2 .A2 (.bin .Ta .A2)
665+
| wbc : R2 .W (.bin .Tb .Tc)
666+
| wbz : R2 .W (.bin .Tb .Z2)
667+
| zwc : R2 .Z2 (.bin .W .Tc)
668+
| ta : R2 .Ta (.term .a)
669+
| tb : R2 .Tb (.term .b)
670+
| tc : R2 .Tc (.term .c)
671+
672+
def Char2 : M2 → List Letter → Prop
673+
| .S, w => ∃ m n, 1 ≤ m ∧ 1 ≤ n ∧ w = replicate m a ++ bc n
674+
| .A2, w => ∃ m, 1 ≤ m ∧ w = replicate m a
675+
| .W, w => ∃ n, 1 ≤ n ∧ w = bc n
676+
| .Z2, w => ∃ n, 1 ≤ n ∧ w = bc n ++ [c]
677+
| .Ta, w => w = [a]
678+
| .Tb, w => w = [b]
679+
| .Tc, w => w = [c]
680+
681+
theorem sound_all2 {A : M2} {w : List Letter} (t : PT R2 A w) : Char2 A w := by
682+
induction t with
683+
| @bin A B C w1 w2 h _ _ ih1 ih2 =>
684+
cases h with
685+
| s => obtain ⟨m, hm, e1⟩ := ih1; obtain ⟨n, hn, e2⟩ := ih2
686+
exact ⟨m, n, hm, hn, by rw [e1, e2]⟩
687+
| aaa => obtain ⟨m, hm, e2⟩ := ih2
688+
exact ⟨m + 1, by omega, by rw [show w1 = [a] from ih1, e2]; simp [replicate_succ]⟩
689+
| wbc => exact ⟨1, Nat.le_refl 1,
690+
by rw [show w1 = [b] from ih1, show w2 = [c] from ih2]; simp [bc, replicate_succ]⟩
691+
| wbz => obtain ⟨n, hn, e2⟩ := ih2
692+
exact ⟨n + 1, by omega, by rw [show w1 = [b] from ih1, e2, bc_cons]⟩
693+
| zwc => obtain ⟨n, hn, e1⟩ := ih1
694+
exact ⟨n, hn, by rw [e1, show w2 = [c] from ih2]⟩
695+
| @term A ltr h =>
696+
cases h with
697+
| aa => exact ⟨1, Nat.le_refl 1, by simp [replicate_succ]⟩
698+
| ta => rfl
699+
| tb => rfl
700+
| tc => rfl
701+
| @eps A h => cases h
702+
703+
def enum2 : M2 → Nat
704+
| .S => 0 | .A2 => 1 | .W => 2 | .Z2 => 3 | .Ta => 4 | .Tb => 5 | .Tc => 6
705+
706+
theorem tree_A2' : ∀ m, Nonempty (PT R2 .A2 (replicate (m + 1) a)) := by
707+
intro m
708+
induction m with
709+
| zero => exact ⟨.term .aa⟩
710+
| succ k ih =>
711+
obtain ⟨ta2⟩ := ih
712+
have h : PT R2 .A2 ([a] ++ replicate (k + 1) a) := .bin .aaa (.term .ta) ta2
713+
rw [show [a] ++ replicate (k + 1) a = replicate (k + 2) a from by simp [replicate_succ]] at h
714+
exact ⟨h⟩
715+
716+
theorem tree_W2 : ∀ n, Nonempty (PT R2 .W (bc (n + 1))) := by
717+
intro n
718+
induction n with
719+
| zero => exact ⟨(PT.bin .wbc (.term .tb) (.term .tc) : PT R2 .W ([b] ++ [c]))⟩
720+
| succ k ih =>
721+
obtain ⟨tw⟩ := ih
722+
have tz : PT R2 .Z2 (bc (k + 1) ++ [c]) := .bin .zwc tw (.term .tc)
723+
have tw2 : PT R2 .W ([b] ++ (bc (k + 1) ++ [c])) := .bin .wbz (.term .tb) tz
724+
rw [bc_cons] at tw2; exact ⟨tw2⟩
725+
726+
/-- `L₂ = { aᵐbⁿcⁿ : m,n ≥ 1 }`. -/
727+
def L2 : List Letter → Prop := fun w => ∃ m n, 1 ≤ m ∧ 1 ≤ n ∧ w = replicate m a ++ bc n
728+
729+
theorem isCFL_L2 : IsCFL L2 := by
730+
refine ⟨M2, R2, .S, enum2, 7, ?_, ?_, ?_, ?_⟩
731+
· intro A; cases A <;> decide
732+
· intro A B; cases A <;> cases B <;> decide
733+
· intro A; cases A <;> (intro h; cases h)
734+
· intro w
735+
constructor
736+
· rintro ⟨m, n, hm, hn, rfl⟩
737+
obtain ⟨m', rfl⟩ : ∃ m', m = m' + 1 := ⟨m - 1, by omega⟩
738+
obtain ⟨n', rfl⟩ : ∃ n', n = n' + 1 := ⟨n - 1, by omega⟩
739+
obtain ⟨ta2⟩ := tree_A2' m'; obtain ⟨tw⟩ := tree_W2 n'
740+
exact ⟨.bin .s ta2 tw⟩
741+
· rintro ⟨t⟩; exact sound_all2 t
742+
743+
/-! #### The intersection is `aⁿbⁿcⁿ`, hence not context-free -/
744+
745+
/-- `aᵖbᵠcʳ` normal form. -/
746+
def tri (p q r : Nat) : List Letter := replicate p a ++ replicate q b ++ replicate r c
747+
748+
theorem count_tri_a (p q r : Nat) : count a (tri p q r) = p := by
749+
unfold tri
750+
rw [count_append, count_append, count_replicate_self, count_repl_ne _ (by decide),
751+
count_repl_ne _ (by decide)]; omega
752+
theorem count_tri_b (p q r : Nat) : count b (tri p q r) = q := by
753+
unfold tri
754+
rw [count_append, count_append, count_repl_ne _ (by decide), count_replicate_self,
755+
count_repl_ne _ (by decide)]; omega
756+
theorem count_tri_c (p q r : Nat) : count c (tri p q r) = r := by
757+
unfold tri
758+
rw [count_append, count_append, count_repl_ne _ (by decide), count_repl_ne _ (by decide),
759+
count_replicate_self]; omega
760+
761+
/-- `L₁ ∩ L₂ = { aⁿbⁿcⁿ : n ≥ 1 }`: the equal-a-b constraint of `L₁` and the
762+
equal-b-c constraint of `L₂` together force all three counts equal. -/
763+
theorem inter_eq (w : List Letter) :
764+
(L1 w ∧ L2 w) ↔ ∃ n, 1 ≤ n ∧ w = abc n := by
765+
constructor
766+
· rintro ⟨⟨i, j, hi, hj, e1⟩, ⟨m, n, hm, hn, e2⟩⟩
767+
have h1 : w = tri i i j := e1
768+
have h2 : w = tri m n n := by rw [e2]; simp [bc, tri, List.append_assoc]
769+
have key : tri i i j = tri m n n := h1.symm.trans h2
770+
have cb : i = n := by have := congrArg (count b) key; rwa [count_tri_b, count_tri_b] at this
771+
have cc : j = n := by have := congrArg (count c) key; rwa [count_tri_c, count_tri_c] at this
772+
exact ⟨i, hi, by rw [h1, show j = i from by omega]; rfl⟩
773+
· rintro ⟨n, hn, rfl⟩
774+
exact ⟨⟨n, n, hn, hn, rfl⟩, ⟨n, n, hn, hn, by simp [abc, bc, List.append_assoc]⟩⟩
775+
776+
/-- **The context-free languages are not closed under intersection.** Witnesses
777+
`L₁ = {aⁱbⁱcʲ}` and `L₂ = {aᵐbⁿcⁿ}` are both context-free, but their intersection
778+
`{aⁿbⁿcⁿ}` is not (`anbncn_not_cfl`). (Closure under complement would, with the
779+
∪-closure of CFLs and De Morgan, give ∩-closure — so this also refutes
780+
complement-closure.) -/
781+
theorem cfl_not_closed_inter :
782+
∃ K₁ K₂ : List Letter → Prop,
783+
IsCFL K₁ ∧ IsCFL K₂ ∧ ¬ IsCFL (fun w => K₁ w ∧ K₂ w) := by
784+
refine ⟨L1, L2, isCFL_L1, isCFL_L2, ?_⟩
785+
intro hcfl
786+
apply anbncn_not_cfl
787+
have heq : (fun w => L1 w ∧ L2 w) = (fun z => ∃ n, 1 ≤ n ∧ z = abc n) := by
788+
funext w; exact propext (inter_eq w)
789+
rwa [heq] at hcfl
790+
538791
end Pump

0 commit comments

Comments
 (0)