Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 1f428f3

Browse files
committed
feat(data/list/basic): Split and intercalate are inverses (#12466)
Show that split and intercalate are inverses of each other (under suitable conditions)
1 parent cd001b2 commit 1f428f3

File tree

1 file changed

+74
-5
lines changed

1 file changed

+74
-5
lines changed

src/data/list/basic.lean

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,10 @@ begin
854854
{ simpa }
855855
end
856856

857+
@[simp] lemma modify_head_modify_head (l : list α) (f g : α → α) :
858+
(l.modify_head f).modify_head g = l.modify_head (g ∘ f) :=
859+
by cases l; simp
860+
857861
/-! ### Induction from the right -/
858862

859863
/-- Induction principle from the right for lists: if a property holds for the empty list, and
@@ -2456,12 +2460,17 @@ end mfoldl_mfoldr
24562460

24572461
/-! ### split_at and split_on -/
24582462

2463+
section split_at_on
2464+
variables (p : α → Prop) [decidable_pred p] (xs ys : list α)
2465+
(ls : list (list α)) (f : list α → list α)
2466+
24592467
@[simp] theorem split_at_eq_take_drop : ∀ (n : ℕ) (l : list α), split_at n l = (take n l, drop n l)
24602468
| 0 a := rfl
24612469
| (succ n) [] := rfl
24622470
| (succ n) (x :: xs) := by simp only [split_at, split_at_eq_take_drop n xs, take, drop]
24632471

24642472
@[simp] lemma split_on_nil {α : Type u} [decidable_eq α] (a : α) : [].split_on a = [[]] := rfl
2473+
@[simp] lemma split_on_p_nil : [].split_on_p p = [[]] := rfl
24652474

24662475
/-- An auxiliary definition for proving a specification lemma for `split_on_p`.
24672476
@@ -2474,22 +2483,20 @@ def split_on_p_aux' {α : Type u} (P : α → Prop) [decidable_pred P] : list α
24742483
if P h then xs :: split_on_p_aux' t []
24752484
else split_on_p_aux' t (xs ++ [h])
24762485

2477-
lemma split_on_p_aux_eq {α : Type u} (P : α → Prop) [decidable_pred P] (xs ys : list α) :
2478-
split_on_p_aux' P xs ys = split_on_p_aux P xs ((++) ys) :=
2486+
lemma split_on_p_aux_eq : split_on_p_aux' p xs ys = split_on_p_aux p xs ((++) ys) :=
24792487
begin
24802488
induction xs with a t ih generalizing ys; simp! only [append_nil, eq_self_iff_true, and_self],
24812489
split_ifs; rw ih,
24822490
{ refine ⟨rfl, rfl⟩ },
24832491
{ congr, ext, simp }
24842492
end
24852493

2486-
lemma split_on_p_aux_nil {α : Type u} (P : α → Prop) [decidable_pred P] (xs : list α) :
2487-
split_on_p_aux P xs id = split_on_p_aux' P xs [] :=
2494+
lemma split_on_p_aux_nil : split_on_p_aux p xs id = split_on_p_aux' p xs [] :=
24882495
by { rw split_on_p_aux_eq, refl }
24892496

24902497
/-- The original list `L` can be recovered by joining the lists produced by `split_on_p p L`,
24912498
interspersed with the elements `L.filter p`. -/
2492-
lemma split_on_p_spec {α : Type u} (p : α → Prop) [decidable_pred p] (as : list α) :
2499+
lemma split_on_p_spec (as : list α) :
24932500
join (zip_with (++) (split_on_p p as) ((as.filter p).map (λ x, [x]) ++ [[]])) = as :=
24942501
begin
24952502
rw [split_on_p, split_on_p_aux_nil],
@@ -2500,6 +2507,68 @@ begin
25002507
split_ifs; simp [zip_with, join, *],
25012508
end
25022509

2510+
lemma split_on_p_aux_ne_nil : split_on_p_aux p xs f ≠ [] :=
2511+
begin
2512+
induction xs with _ _ ih generalizing f, { trivial, },
2513+
simp only [split_on_p_aux], split_ifs, { trivial, }, exact ih _,
2514+
end
2515+
2516+
lemma split_on_p_aux_spec : split_on_p_aux p xs f = (xs.split_on_p p).modify_head f :=
2517+
begin
2518+
simp only [split_on_p],
2519+
induction xs with hd tl ih generalizing f, { simp [split_on_p_aux], },
2520+
simp only [split_on_p_aux], split_ifs, { simp, },
2521+
rw [ih (λ l, f (hd :: l)), ih (λ l, id (hd :: l))],
2522+
simp,
2523+
end
2524+
2525+
lemma split_on_p_ne_nil : xs.split_on_p p ≠ [] := split_on_p_aux_ne_nil _ _ id
2526+
2527+
@[simp] lemma split_on_p_cons (x : α) (xs : list α) :
2528+
(x :: xs).split_on_p p =
2529+
if p x then [] :: xs.split_on_p p else (xs.split_on_p p).modify_head (cons x) :=
2530+
by { simp only [split_on_p, split_on_p_aux], split_ifs, { simp }, rw split_on_p_aux_spec, refl, }
2531+
2532+
/-- If no element satisfies `p` in the list `xs`, then `xs.split_on_p p = [xs]` -/
2533+
lemma split_on_p_eq_single (h : ∀ x ∈ xs, ¬p x) : xs.split_on_p p = [xs] :=
2534+
by { induction xs with hd tl ih, { refl, }, simp [h hd _, ih (λ t ht, h t (or.inr ht))], }
2535+
2536+
/-- When a list of the form `[...xs, sep, ...as]` is split on `p`, the first element is `xs`,
2537+
assuming no element in `xs` satisfies `p` but `sep` does satisfy `p` -/
2538+
lemma split_on_p_first (h : ∀ x ∈ xs, ¬p x) (sep : α) (hsep : p sep)
2539+
(as : list α) : (xs ++ sep :: as).split_on_p p = xs :: as.split_on_p p :=
2540+
by { induction xs with hd tl ih, { simp [hsep], }, simp [h hd _, ih (λ t ht, h t (or.inr ht))], }
2541+
2542+
/-- `intercalate [x]` is the left inverse of `split_on x` -/
2543+
lemma intercalate_split_on (x : α) [decidable_eq α] : [x].intercalate (xs.split_on x) = xs :=
2544+
begin
2545+
simp only [intercalate, split_on],
2546+
induction xs with hd tl ih, { simp [join], }, simp only [split_on_p_cons],
2547+
cases h' : split_on_p (=x) tl with hd' tl', { exact (split_on_p_ne_nil _ tl h').elim, },
2548+
rw h' at ih, split_ifs, { subst h, simp [ih, join], },
2549+
cases tl'; simpa [join] using ih,
2550+
end
2551+
2552+
/-- `split_on x` is the left inverse of `intercalate [x]`, on the domain
2553+
consisting of each nonempty list of lists `ls` whose elements do not contain `x` -/
2554+
lemma split_on_intercalate [decidable_eq α] (x : α) (hx : ∀ l ∈ ls, x ∉ l) (hls : ls ≠ []) :
2555+
([x].intercalate ls).split_on x = ls :=
2556+
begin
2557+
simp only [intercalate],
2558+
induction ls with hd tl ih, { contradiction, },
2559+
cases tl,
2560+
{ suffices : hd.split_on x = [hd], { simpa [join], },
2561+
refine split_on_p_eq_single _ _ _, intros y hy H, rw H at hy,
2562+
refine hx hd _ hy, simp, },
2563+
{ simp only [intersperse_cons_cons, singleton_append, join],
2564+
specialize ih _ _, { intros l hl, apply hx l, simp at hl ⊢, tauto, }, { trivial, },
2565+
have := split_on_p_first (=x) hd _ x rfl _,
2566+
{ simp only [split_on] at ⊢ ih, rw this, rw ih, },
2567+
intros y hy H, rw H at hy, exact hx hd (or.inl rfl) hy, }
2568+
end
2569+
2570+
end split_at_on
2571+
25032572
/-! ### map for partial functions -/
25042573

25052574
/-- Partial map. If `f : Π a, p a → β` is a partial function defined on

0 commit comments

Comments
 (0)