Skip to content

Commit 99b6ebc

Browse files
jcommelinChrisHughes24zeramorphicJamesGallicchio
committed
feat: port Data.List.Permutation (#1445)
Co-authored-by: ChrisHughes24 <chrishughes24@gmail.com> Co-authored-by: thirdsgames <thirdsgames2018@gmail.com> Co-authored-by: zeramorphic <zeramorphic@proton.me> Co-authored-by: James <jamesgallicchio@gmail.com>
1 parent 07eef42 commit 99b6ebc

File tree

3 files changed

+277
-1
lines changed

3 files changed

+277
-1
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ import Mathlib.Data.List.Nodup
259259
import Mathlib.Data.List.Pairwise
260260
import Mathlib.Data.List.Palindrome
261261
import Mathlib.Data.List.Perm
262+
import Mathlib.Data.List.Permutation
262263
import Mathlib.Data.List.ProdSigma
263264
import Mathlib.Data.List.Range
264265
import Mathlib.Data.List.Sections

Mathlib/Data/List/Defs.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ defined) is the list of lists of the form `insert_nth n t (ys ++ ts)` for `0 ≤
249249
def permutationsAux2 (t : α) (ts : List α) (r : List β) : List α → (List α → β) → List α × List β
250250
| [], _ => (ts, r)
251251
| y :: ys, f =>
252-
let (us, zs) := permutationsAux2 t ys r ys (fun x: List α => f (y :: x))
252+
let (us, zs) := permutationsAux2 t ts r ys (fun x: List α => f (y :: x))
253253
(y :: us, f (t :: y :: us) :: zs)
254254
#align list.permutations_aux2 List.permutationsAux2
255255

Mathlib/Data/List/Permutation.lean

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
/-
2+
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro
5+
6+
! This file was ported from Lean 3 source module data.list.permutation
7+
! leanprover-community/mathlib commit dd71334db81d0bd444af1ee339a29298bef40734
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.Data.List.Join
12+
13+
/-!
14+
# Permutations of a list
15+
16+
In this file we prove properties about `List.Permutations`, a list of all permutations of a list. It
17+
is defined in `Data.List.Defs`.
18+
19+
## Order of the permutations
20+
21+
Designed for performance, the order in which the permutations appear in `List.Permutations` is
22+
rather intricate and not very amenable to induction. That's why we also provide `List.Permutations'`
23+
as a less efficient but more straightforward way of listing permutations.
24+
25+
### `List.Permutations`
26+
27+
TODO. In the meantime, you can try decrypting the docstrings.
28+
29+
### `List.Permutations'`
30+
31+
The list of partitions is built by recursion. The permutations of `[]` are `[[]]`. Then, the
32+
permutations of `a :: l` are obtained by taking all permutations of `l` in order and adding `a` in
33+
all positions. Hence, to build `[0, 1, 2, 3].permutations'`, it does
34+
* `[[]]`
35+
* `[[3]]`
36+
* `[[2, 3], [3, 2]]]`
37+
* `[[1, 2, 3], [2, 1, 3], [2, 3, 1], [1, 3, 2], [3, 1, 2], [3, 2, 1]]`
38+
* `[[0, 1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3], [1, 2, 3, 0],`
39+
`[0, 2, 1, 3], [2, 0, 1, 3], [2, 1, 0, 3], [2, 1, 3, 0],`
40+
`[0, 2, 3, 1], [2, 0, 3, 1], [2, 3, 0, 1], [2, 3, 1, 0],`
41+
`[0, 1, 3, 2], [1, 0, 3, 2], [1, 3, 0, 2], [1, 3, 2, 0],`
42+
`[0, 3, 1, 2], [3, 0, 1, 2], [3, 1, 0, 2], [3, 1, 2, 0],`
43+
`[0, 3, 2, 1], [3, 0, 2, 1], [3, 2, 0, 1], [3, 2, 1, 0]]`
44+
45+
## TODO
46+
47+
Show that `l.Nodup → l.permutations.Nodup`. See `Data.Fintype.List`.
48+
-/
49+
50+
51+
open Nat
52+
53+
variable {α β : Type _}
54+
55+
namespace List
56+
57+
theorem permutationsAux2_fst (t : α) (ts : List α) (r : List β) :
58+
∀ (ys : List α) (f : List α → β), (permutationsAux2 t ts r ys f).1 = ys ++ ts
59+
| [], f => rfl
60+
| y :: ys, f => by simp [permutationsAux2, permutationsAux2_fst t _ _ ys]
61+
#align list.permutations_aux2_fst List.permutationsAux2_fst
62+
63+
@[simp]
64+
theorem permutations_aux2_snd_nil (t : α) (ts : List α) (r : List β) (f : List α → β) :
65+
(permutationsAux2 t ts r [] f).2 = r :=
66+
rfl
67+
#align list.permutations_aux2_snd_nil List.permutations_aux2_snd_nil
68+
69+
@[simp]
70+
theorem permutationsAux2_snd_cons (t : α) (ts : List α) (r : List β) (y : α) (ys : List α)
71+
(f : List α → β) :
72+
(permutationsAux2 t ts r (y :: ys) f).2 =
73+
f (t :: y :: ys ++ ts) :: (permutationsAux2 t ts r ys fun x : List α => f (y :: x)).2 :=
74+
by simp [permutationsAux2, permutationsAux2_fst t _ _ ys]
75+
#align list.permutations_aux2_snd_cons List.permutationsAux2_snd_cons
76+
77+
/-- The `r` argument to `permutations_aux2` is the same as appending. -/
78+
theorem permutationsAux2_append (t : α) (ts : List α) (r : List β) (ys : List α) (f : List α → β) :
79+
(permutationsAux2 t ts nil ys f).2 ++ r = (permutationsAux2 t ts r ys f).2 := by
80+
induction ys generalizing f <;> simp [*]
81+
#align list.permutations_aux2_append List.permutationsAux2_append
82+
83+
/-- The `ts` argument to `permutations_aux2` can be folded into the `f` argument. -/
84+
theorem permutationsAux2_comp_append {t : α} {ts ys : List α} {r : List β} (f : List α → β) :
85+
((permutationsAux2 t [] r ys) fun x => f (x ++ ts)).2 = (permutationsAux2 t ts r ys f).2 := by
86+
induction' ys with ys_hd _ ys_ih generalizing f
87+
· simp
88+
· simp [ys_ih fun xs => f (ys_hd :: xs)]
89+
#align list.permutations_aux2_comp_append List.permutationsAux2_comp_append
90+
91+
theorem map_permutationsAux2' {α β α' β'} (g : α → α') (g' : β → β') (t : α) (ts ys : List α)
92+
(r : List β) (f : List α → β) (f' : List α' → β') (H : ∀ a, g' (f a) = f' (map g a)) :
93+
map g' (permutationsAux2 t ts r ys f).2 =
94+
(permutationsAux2 (g t) (map g ts) (map g' r) (map g ys) f').2 :=
95+
by
96+
induction' ys with ys_hd _ ys_ih generalizing f f'
97+
. simp
98+
. simp only [map, permutationsAux2_snd_cons, cons_append, cons.injEq]
99+
rw [ys_ih, permutationsAux2_fst]
100+
refine' ⟨_, rfl⟩
101+
. simp only [← map_cons, ← map_append]; apply H
102+
. intro a; apply H
103+
#align list.map_permutations_aux2' List.map_permutationsAux2'
104+
105+
/-- The `f` argument to `permutations_aux2` when `r = []` can be eliminated. -/
106+
theorem map_permutationsAux2 (t : α) (ts : List α) (ys : List α) (f : List α → β) :
107+
(permutationsAux2 t ts [] ys id).2.map f = (permutationsAux2 t ts [] ys f).2 :=
108+
by
109+
rw [map_permutationsAux2' id, map_id, map_id]; rfl
110+
simp
111+
#align list.map_permutations_aux2 List.map_permutationsAux2
112+
113+
/-- An expository lemma to show how all of `ts`, `r`, and `f` can be eliminated from
114+
`permutations_aux2`.
115+
116+
`(permutations_aux2 t [] [] ys id).2`, which appears on the RHS, is a list whose elements are
117+
produced by inserting `t` into every non-terminal position of `ys` in order. As an example:
118+
```lean
119+
#eval permutations_aux2 1 [] [] [2, 3, 4] id
120+
-- [[1, 2, 3, 4], [2, 1, 3, 4], [2, 3, 1, 4]]
121+
```
122+
-/
123+
theorem permutationsAux2_snd_eq (t : α) (ts : List α) (r : List β) (ys : List α) (f : List α → β) :
124+
(permutationsAux2 t ts r ys f).2 =
125+
((permutationsAux2 t [] [] ys id).2.map fun x => f (x ++ ts)) ++ r :=
126+
by rw [← permutationsAux2_append, map_permutationsAux2, permutationsAux2_comp_append]
127+
#align list.permutations_aux2_snd_eq List.permutationsAux2_snd_eq
128+
129+
theorem map_map_permutationsAux2 {α α'} (g : α → α') (t : α) (ts ys : List α) :
130+
map (map g) (permutationsAux2 t ts [] ys id).2 =
131+
(permutationsAux2 (g t) (map g ts) [] (map g ys) id).2 :=
132+
map_permutationsAux2' _ _ _ _ _ _ _ _ fun _ => rfl
133+
#align list.map_map_permutations_aux2 List.map_map_permutationsAux2
134+
135+
theorem map_map_permutations'Aux (f : α → β) (t : α) (ts : List α) :
136+
map (map f) (permutations'Aux t ts) = permutations'Aux (f t) (map f ts) := by
137+
induction' ts with a ts ih <;> [rfl,
138+
· simp [← ih]
139+
rfl]
140+
#align list.map_map_permutations'_aux List.map_map_permutations'Aux
141+
142+
theorem permutations'Aux_eq_permutationsAux2 (t : α) (ts : List α) :
143+
permutations'Aux t ts = (permutationsAux2 t [] [ts ++ [t]] ts id).2 :=
144+
by
145+
induction' ts with a ts ih; · rfl
146+
simp [permutations'Aux, permutationsAux2_snd_cons, ih]
147+
simp (config := { singlePass := true }) only [← permutationsAux2_append]
148+
simp [map_permutationsAux2]
149+
#align list.permutations'_aux_eq_permutations_aux2 List.permutations'Aux_eq_permutationsAux2
150+
151+
theorem mem_permutationsAux2 {t : α} {ts : List α} {ys : List α} {l l' : List α} :
152+
l' ∈ (permutationsAux2 t ts [] ys (l ++ .)).2
153+
∃ l₁ l₂, l₂ ≠ [] ∧ ys = l₁ ++ l₂ ∧ l' = l ++ l₁ ++ t :: l₂ ++ ts :=
154+
by
155+
induction' ys with y ys ih generalizing l
156+
· simp (config := { contextual := true })
157+
rw [permutationsAux2_snd_cons,
158+
show (fun x : List α => l ++ y :: x) = (l ++ [y] ++ .) by funext _; simp, mem_cons, ih]
159+
constructor
160+
· rintro (rfl | ⟨l₁, l₂, l0, rfl, rfl⟩)
161+
· exact ⟨[], y :: ys, by simp⟩
162+
· exact ⟨y :: l₁, l₂, l0, by simp⟩
163+
· rintro ⟨_ | ⟨y', l₁⟩, l₂, l0, ye, rfl⟩
164+
· simp [ye]
165+
· simp only [cons_append] at ye
166+
rcases ye with ⟨rfl, rfl⟩
167+
exact Or.inr ⟨l₁, l₂, l0, by simp⟩
168+
#align list.mem_permutations_aux2 List.mem_permutationsAux2
169+
170+
theorem mem_permutationsAux2' {t : α} {ts : List α} {ys : List α} {l : List α} :
171+
l ∈ (permutationsAux2 t ts [] ys id).2
172+
∃ l₁ l₂, l₂ ≠ [] ∧ ys = l₁ ++ l₂ ∧ l = l₁ ++ t :: l₂ ++ ts :=
173+
by rw [show @id (List α) = ([] ++ .) by funext _; rfl]; apply mem_permutationsAux2
174+
#align list.mem_permutations_aux2' List.mem_permutationsAux2'
175+
176+
theorem length_permutationsAux2 (t : α) (ts : List α) (ys : List α) (f : List α → β) :
177+
length (permutationsAux2 t ts [] ys f).2 = length ys := by
178+
induction ys generalizing f <;> simp [*]
179+
#align list.length_permutations_aux2 List.length_permutationsAux2
180+
181+
theorem foldr_permutationsAux2 (t : α) (ts : List α) (r L : List (List α)) :
182+
foldr (fun y r => (permutationsAux2 t ts r y id).2) r L =
183+
(L.bind fun y => (permutationsAux2 t ts [] y id).2) ++ r :=
184+
by
185+
induction' L with l L ih <;> [rfl,
186+
· simp [ih]
187+
rw [← permutationsAux2_append]]
188+
#align list.foldr_permutations_aux2 List.foldr_permutationsAux2
189+
190+
theorem mem_foldr_permutationsAux2 {t : α} {ts : List α} {r L : List (List α)} {l' : List α} :
191+
l' ∈ foldr (fun y r => (permutationsAux2 t ts r y id).2) r L ↔
192+
l' ∈ r ∨ ∃ l₁ l₂, l₁ ++ l₂ ∈ L ∧ l₂ ≠ [] ∧ l' = l₁ ++ t :: l₂ ++ ts := by
193+
have :
194+
(∃ a : List α,
195+
a ∈ L ∧ ∃ l₁ l₂ : List α, ¬l₂ = nil ∧ a = l₁ ++ l₂ ∧ l' = l₁ ++ t :: (l₂ ++ ts)) ↔
196+
∃ l₁ l₂ : List α, ¬l₂ = nil ∧ l₁ ++ l₂ ∈ L ∧ l' = l₁ ++ t :: (l₂ ++ ts) :=
197+
fun ⟨_, aL, l₁, l₂, l0, e, h⟩ => ⟨l₁, l₂, l0, e ▸ aL, h⟩, fun ⟨l₁, l₂, l0, aL, h⟩ =>
198+
⟨_, aL, l₁, l₂, l0, rfl, h⟩⟩
199+
rw [foldr_permutationsAux2]
200+
simp only [mem_permutationsAux2', ← this, or_comm, and_left_comm, mem_append, mem_bind,
201+
append_assoc, cons_append, exists_prop]
202+
#align list.mem_foldr_permutations_aux2 List.mem_foldr_permutationsAux2
203+
204+
theorem length_foldr_permutationsAux2 (t : α) (ts : List α) (r L : List (List α)) :
205+
length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) =
206+
sum (map length L) + length r :=
207+
by simp [foldr_permutationsAux2, (· ∘ ·), length_permutationsAux2]
208+
#align list.length_foldr_permutations_aux2 List.length_foldr_permutationsAux2
209+
210+
theorem length_foldr_permutationsAux2' (t : α) (ts : List α) (r L : List (List α)) (n)
211+
(H : ∀ l ∈ L, length l = n) :
212+
length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = n * length L + length r := by
213+
rw [length_foldr_permutationsAux2, (_ : List.sum (map length L) = n * length L)]
214+
induction' L with l L ih; · simp
215+
have sum_map : sum (map length L) = n * length L := ih fun l m => H l (mem_cons_of_mem _ m)
216+
have length_l : length l = n := H _ (mem_cons_self _ _)
217+
simp [sum_map, length_l, mul_add, add_comm, mul_succ]
218+
#align list.length_foldr_permutations_aux2' List.length_foldr_permutationsAux2'
219+
220+
@[simp]
221+
theorem permutationsAux_nil (is : List α) : permutationsAux [] is = [] := by
222+
rw [permutationsAux, permutationsAux.rec]
223+
#align list.permutations_aux_nil List.permutationsAux_nil
224+
225+
@[simp]
226+
theorem permutationsAux_cons (t : α) (ts is : List α) :
227+
permutationsAux (t :: ts) is =
228+
foldr (fun y r => (permutationsAux2 t ts r y id).2) (permutationsAux ts (t :: is))
229+
(permutations is) :=
230+
by rw [permutationsAux, permutationsAux.rec]; rfl
231+
#align list.permutations_aux_cons List.permutationsAux_cons
232+
233+
@[simp]
234+
theorem permutations_nil : permutations ([] : List α) = [[]] := by
235+
rw [permutations, permutationsAux_nil]
236+
#align list.permutations_nil List.permutations_nil
237+
238+
theorem map_permutationsAux (f : α → β) :
239+
∀ ts is : List α, map (map f) (permutationsAux ts is) = permutationsAux (map f ts) (map f is) :=
240+
by
241+
refine' permutationsAux.rec (by simp) _
242+
introv IH1 IH2; rw [map] at IH2
243+
simp only [foldr_permutationsAux2, map_append, map, map_map_permutationsAux2, permutations,
244+
bind_map, IH1, append_assoc, permutationsAux_cons, cons_bind, ← IH2, map_bind]
245+
#align list.map_permutations_aux List.map_permutationsAux
246+
247+
theorem map_permutations (f : α → β) (ts : List α) :
248+
map (map f) (permutations ts) = permutations (map f ts) := by
249+
rw [permutations, permutations, map, map_permutationsAux, map]
250+
#align list.map_permutations List.map_permutations
251+
252+
theorem map_permutations' (f : α → β) (ts : List α) :
253+
map (map f) (permutations' ts) = permutations' (map f ts) := by
254+
induction' ts with t ts ih <;> [rfl, simp [← ih, map_bind, ← map_map_permutations'Aux, bind_map]]
255+
#align list.map_permutations' List.map_permutations'
256+
257+
theorem permutationsAux_append (is is' ts : List α) :
258+
permutationsAux (is ++ ts) is' =
259+
(permutationsAux is is').map (· ++ ts) ++ permutationsAux ts (is.reverse ++ is') := by
260+
induction' is with t is ih generalizing is'; · simp
261+
simp only [foldr_permutationsAux2, ih, bind_map, cons_append, permutationsAux_cons, map_append,
262+
reverse_cons, append_assoc, singleton_append]
263+
congr 2
264+
funext _
265+
rw [map_permutationsAux2]
266+
simp (config := { singlePass := true }) only [← permutationsAux2_comp_append]
267+
simp only [id, append_assoc]
268+
#align list.permutations_aux_append List.permutationsAux_append
269+
270+
theorem permutations_append (is ts : List α) :
271+
permutations (is ++ ts) = (permutations is).map (· ++ ts) ++ permutationsAux ts is.reverse := by
272+
simp [permutations, permutationsAux_append]
273+
#align list.permutations_append List.permutations_append
274+
275+
end List

0 commit comments

Comments
 (0)