From 6fd3affeb11aa8d0db4adddcbffc67acafe47274 Mon Sep 17 00:00:00 2001
From: Leonardo de Moura <leonardo@microsoft.com>
Date: Tue, 11 Aug 2015 15:54:14 -0700
Subject: [PATCH] feat(library/data/finset/equiv): show that (finset nat) is
 isomorphic to nat

---
 library/data/finset/equiv.lean | 230 ++++++++++++++++++++++++++++++++-
 library/data/nat/div.lean      |  17 +++
 2 files changed, 242 insertions(+), 5 deletions(-)

diff --git a/library/data/finset/equiv.lean b/library/data/finset/equiv.lean
index ca093aca2..f8e477d47 100644
--- a/library/data/finset/equiv.lean
+++ b/library/data/finset/equiv.lean
@@ -51,12 +51,232 @@ iff.intro
    assert odd (s div 2^(succ n)),      by rewrite [pow_succ, mul.comm, -div_div_eq_div_mul]; assumption,
    show succ n ∈ of_nat s,             from mem_of_nat_of_odd this)
 
-/-
+private lemma odd_of_zero_mem (s : nat) : 0 ∈ of_nat s ↔ odd s :=
+begin
+  unfold of_nat, rewrite [mem_sep_eq, pow_zero, div_one, mem_upto_eq],
+  show 0 < succ s ∧ odd s ↔ odd s, from
+  iff.intro
+    (assume h, and.right h)
+    (assume h, and.intro (zero_lt_succ s) h)
+end
+
+private lemma even_of_not_zero_mem (s : nat) : 0 ∉ of_nat s ↔ even s :=
+have aux : 0 ∉ of_nat s ↔ ¬odd s, from not_iff_not_of_iff (odd_of_zero_mem s),
+iff.intro
+  (suppose 0 ∉ of_nat s, even_of_not_odd (iff.mp aux this))
+  (suppose even s, iff.mpr aux (not_odd_of_even this))
+
+private lemma even_to_nat (s : finset nat) : even (to_nat s) ↔ 0 ∉ s :=
+finset.induction_on s dec_trivial
+  (λ a s nains ih,
+    begin
+      rewrite [to_nat_insert nains], apply iff.intro,
+        suppose even (2^a + to_nat s), by_cases
+          (suppose e : even (2^a), by_cases
+            (suppose even (to_nat s),
+              assert 0 ∉ s, from iff.mp ih this,
+              suppose 0 ∈ insert a s, or.elim (eq_or_mem_of_mem_insert this)
+                (suppose 0 = a, begin rewrite [-this at e], exact absurd e not_even_one end)
+                (by contradiction))
+            (suppose odd  (to_nat s), absurd `even (2^a + to_nat s)` (odd_add_of_even_of_odd `even (2^a)` this)))
+          (suppose o : odd (2^a), by_cases
+            (suppose even (to_nat s), absurd `even (2^a + to_nat s)` (odd_add_of_odd_of_even `odd (2^a)` this))
+            (suppose odd  (to_nat s), suppose 0 ∈ insert a s, or.elim (eq_or_mem_of_mem_insert this)
+              (suppose 0 = a,
+                have even (to_nat s), from iff.mpr ih (by rewrite -this at nains; exact nains),
+                absurd this `odd (to_nat s)`)
+              (suppose 0 ∈ s,
+                assert a ≠ 0, from suppose a = 0, by subst a; contradiction,
+                begin
+                  cases a with a, contradiction,
+                  have odd (2*2^a),  by rewrite [pow_succ at o, mul.comm]; exact o,
+                  have even (2*2^a), from !even_two_mul,
+                  exact absurd `even (2*2^a)` `odd (2*2^a)`
+                end))),
+        suppose 0 ∉ insert a s,
+          have a ≠ 0, from suppose a = 0, absurd (by rewrite this; apply mem_insert) `0 ∉ insert a s`,
+          have 0 ∉ s, from suppose 0 ∈ s, absurd (mem_insert_of_mem _ this) `0 ∉ insert a s`,
+          have even (to_nat s), from iff.mpr ih this,
+          match a with
+          | 0         := suppose a = 0, absurd this `a ≠ 0`
+          | (succ a') := suppose a = succ a',
+            have even (2^(succ a')), by rewrite [pow_succ, mul.comm]; apply even_two_mul,
+            even_add_of_even_of_even this `even (to_nat s)`
+          end rfl
+    end)
+
+private lemma of_nat_eq_insert_zero {s : nat} : 0 ∉ of_nat s → of_nat (2^0 + s) = insert 0 (of_nat s) :=
+assume h : 0 ∉ of_nat s,
+assert even s,                  from iff.mp (even_of_not_zero_mem s) h,
+have   odd (s+1),               from odd_succ_of_even this,
+assert zmem : 0 ∈ of_nat (s+1), from iff.mpr (odd_of_zero_mem (s+1)) this,
+obtain w (hw : s = 2*w),        from exists_of_even `even s`,
+begin
+  rewrite [pow_zero, add.comm, hw],
+  show of_nat (2*w+1) = insert 0 (of_nat (2*w)), from
+  finset.ext (λ n,
+    match n with
+    | 0      := iff.intro (λ h, !mem_insert) (λ h, by rewrite [hw at zmem]; exact zmem)
+    | succ m :=
+       assert d₁  : 1 div 2 = 0,           from dec_trivial,
+       assert aux : _, from calc
+         succ m ∈ of_nat (2 * w + 1) ↔ m ∈ of_nat ((2*w+1) div 2) : succ_mem_of_nat
+                  ...                ↔ m ∈ of_nat w               : by rewrite [add.comm, add_mul_div_self_left _ _ (dec_trivial : 2 > 0), d₁, zero_add]
+                  ...                ↔ m ∈ of_nat (2*w div 2)     : by rewrite [mul.comm, mul_div_cancel _ (dec_trivial : 2 > 0)]
+                  ...                ↔ succ m ∈ of_nat (2*w)      : succ_mem_of_nat,
+       iff.intro
+         (λ hl, finset.mem_insert_of_mem _ (iff.mp aux hl))
+         (λ hr, or.elim (eq_or_mem_of_mem_insert hr)
+           (by contradiction)
+           (iff.mpr aux))
+    end)
+end
+
+private lemma of_nat_eq_insert : ∀ {n s : nat}, n ∉ of_nat s → of_nat (2^n + s) = insert n (of_nat s)
+| 0        s h := of_nat_eq_insert_zero h
+| (succ n) s h :=
+  have n ∉ of_nat (s div 2),                                        from iff.mp (not_iff_not_of_iff !succ_mem_of_nat) h,
+  assert ih : of_nat (2^n + s div 2) = insert n (of_nat (s div 2)), from of_nat_eq_insert this,
+  finset.ext (λ x,
+  have gen : ∀ m, m ∈ of_nat (2^(succ n) + s) ↔ m ∈ insert (succ n) (of_nat s)
+  | zero     :=
+    have even (2^(succ n)), by rewrite [pow_succ, mul.comm]; apply even_two_mul,
+    have aux₁ : odd (2^(succ n) + s) ↔ odd s, from iff.intro
+      (suppose odd (2^(succ n) + s), by_contradiction
+        (suppose ¬ odd s,
+         have even s,                from even_of_not_odd this,
+         have even (2^(succ n) + s), from even_add_of_even_of_even `even (2^(succ n))` this,
+         absurd `odd (2^(succ n) + s)` (not_odd_of_even this)))
+      (suppose odd s, odd_add_of_even_of_odd `even (2^(succ n))` this),
+    have aux₂ : odd s ↔ 0 ∈ insert (succ n) (of_nat s), from iff.intro
+      (suppose odd s, finset.mem_insert_of_mem _ (iff.mpr !odd_of_zero_mem this))
+      (suppose 0 ∈ insert (succ n) (of_nat s), or.elim (eq_or_mem_of_mem_insert this)
+         (by contradiction)
+         (suppose 0 ∈ of_nat s, iff.mp !odd_of_zero_mem this)),
+    calc
+      0 ∈ of_nat (2^(succ n) + s) ↔ odd (2^(succ n) + s)           : odd_of_zero_mem
+                             ...  ↔ odd s                          : aux₁
+                             ...  ↔ 0 ∈ insert (succ n) (of_nat s) : aux₂
+  | (succ m) :=
+    assert aux : m ∈ insert n (of_nat (s div 2)) ↔ succ m ∈ insert (succ n) (of_nat s), from iff.intro
+      (assume hl, or.elim (eq_or_mem_of_mem_insert hl)
+        (suppose m = n,                by subst m; apply mem_insert)
+        (suppose m ∈ of_nat (s div 2), finset.mem_insert_of_mem _ (iff.mpr !succ_mem_of_nat this)))
+      (assume hr, or.elim (eq_or_mem_of_mem_insert hr)
+        (suppose succ m = succ n,
+         assert m = n, by injection this; assumption,
+         by subst m; apply mem_insert)
+        (suppose succ m ∈ of_nat s, finset.mem_insert_of_mem _ (iff.mp !succ_mem_of_nat this))),
+    calc
+      succ m ∈ of_nat (2^(succ n) + s) ↔ succ m ∈ of_nat (2^n * 2 + s)       : by rewrite pow_succ
+                                 ...   ↔ m ∈ of_nat ((2^n * 2 + s) div 2)    : succ_mem_of_nat
+                                 ...   ↔ m ∈ of_nat (2^n + s div 2)          : by rewrite [add.comm, add_mul_div_self (dec_trivial : 2 > 0), add.comm]
+                                 ...   ↔ m ∈ insert n (of_nat (s div 2))     : by rewrite ih
+                                 ...   ↔ succ m ∈ insert (succ n) (of_nat s) : aux,
+  gen x)
+
 private lemma of_nat_to_nat (s : finset nat) : of_nat (to_nat s) = s :=
 finset.induction_on s rfl
+  (λ a s nains ih, by rewrite [to_nat_insert nains, -ih at nains, of_nat_eq_insert nains, ih])
+
+private definition predimage (s : finset nat) : finset nat :=
+{ n ∈ image pred s | succ n ∈ s }
+
+private lemma mem_image_pred_of_succ_mem {n : nat} {s : finset nat} : succ n ∈ s → n ∈ image pred s :=
+assume h,
+  assert pred (succ n) ∈ image pred s, from mem_image_of_mem _ h,
+  begin rewrite [pred_succ at this], assumption end
+
+private lemma mem_predimage_of_succ_mem {n : nat} {s : finset nat} : succ n ∈ s → n ∈ predimage s :=
+assume h, begin unfold predimage, rewrite [mem_sep_eq], exact and.intro (mem_image_pred_of_succ_mem h) h end
+
+private lemma succ_mem_of_mem_predimage {n : nat} {s : finset nat} : n ∈ predimage s → succ n ∈ s :=
+begin
+  unfold predimage, rewrite [mem_sep_eq],
+  suppose n ∈ image pred s ∧ succ n ∈ s, and.right this
+end
+
+private lemma predimage_insert_zero (s : finset nat) : predimage (insert 0 s) = predimage s :=
+finset.ext (λ n,
   begin
-    intro n s nains ih,
-    rewrite (to_nat_insert nains)
-  end
--/
+    unfold predimage, rewrite [*mem_sep_eq, image_insert, pred_zero], apply iff.intro,
+    suppose n ∈ insert 0 (image pred s) ∧ succ n ∈ insert 0 s,
+      have succ n ∈ s, from or.elim (eq_or_mem_of_mem_insert (and.right this))
+        (by contradiction)
+        (λ h, h),
+      and.intro (mem_image_pred_of_succ_mem this) this,
+    suppose n ∈ image pred s ∧ succ n ∈ s,
+      obtain h₁ h₂, from this,
+      and.intro (mem_insert_of_mem 0 h₁) (mem_insert_of_mem 0 h₂)
+  end)
+
+private lemma predimage_insert_succ (n : nat) (s : finset nat) : predimage (insert (succ n) s) = insert n (predimage s) :=
+finset.ext (λ m,
+  begin
+    unfold predimage, rewrite [*mem_sep_eq, *image_insert, pred_succ, *mem_insert_eq, *mem_sep_eq], apply iff.intro,
+      suppose (m = n ∨ m ∈ image pred s) ∧ (succ m = succ n ∨ succ m ∈ s),
+        obtain h₁ h₂, from this,
+        or.elim h₁
+          (suppose m = n, or.inl this)
+          (suppose m ∈ image pred s, or.elim h₂
+            (suppose succ m = succ n, by injection this; left; assumption)
+            (suppose succ m ∈ s, by right; split; repeat assumption)),
+      suppose m = n ∨ m ∈ image pred s ∧ succ m ∈ s, or.elim this
+        (suppose m = n, and.intro (or.inl this) (or.inl (by subst m)))
+        (suppose m ∈ image pred s ∧ succ m ∈ s,
+          obtain h₁ h₂, from this,
+          and.intro (or.inr h₁) (or.inr h₂))
+  end)
+
+private lemma of_nat_div2 (s : nat) : of_nat (s div 2) = predimage (of_nat s) :=
+finset.ext (λ n, iff.intro
+  (suppose n ∈ of_nat (s div 2),
+   have succ n ∈ of_nat s, from iff.mpr !succ_mem_of_nat this,
+   mem_predimage_of_succ_mem this)
+  (suppose n ∈ predimage (of_nat s),
+   have succ n ∈ of_nat s, from succ_mem_of_mem_predimage this,
+   iff.mp !succ_mem_of_nat this))
+
+private lemma to_nat_predimage (s : finset nat) : to_nat (predimage s) = (to_nat s) div 2 :=
+begin
+  induction s with a s nains ih,
+   reflexivity,
+   cases a with a,
+   { rewrite [predimage_insert_zero, ih, to_nat_insert nains, pow_zero],
+     have 0 ∉ of_nat (to_nat s), by rewrite of_nat_to_nat; assumption,
+     have even (to_nat s), from iff.mp !even_of_not_zero_mem this,
+     obtain w (hw : to_nat s = 2*w), from exists_of_even this,
+     begin
+       rewrite hw,
+       have d₁ : 1 div 2 = 0,                from dec_trivial,
+       show 2 * w div 2 = (1 + 2 * w) div 2, by
+         rewrite [add_mul_div_self_left _ _ (dec_trivial : 2 > 0), mul.comm,
+                  mul_div_cancel _ (dec_trivial : 2 > 0), d₁, zero_add]
+     end },
+   { have a ∉ predimage s, from suppose a ∈ predimage s, absurd (succ_mem_of_mem_predimage this) nains,
+     rewrite [predimage_insert_succ, to_nat_insert nains, pow_succ, add.comm,
+              add_mul_div_self (dec_trivial : 2 > 0), -ih, to_nat_insert this, add.comm] }
+end
+
+private lemma to_nat_of_nat (s : nat) : to_nat (of_nat s) = s :=
+nat.strong_induction_on s
+  (λ n ih, by_cases
+    (suppose n = 0, by rewrite this)
+    (suppose n ≠ 0,
+      have n div 2 < n, from div_lt_of_ne_zero this,
+      have to_nat (of_nat (n div 2)) = n div 2, from ih _ this,
+      have e₁ : to_nat (of_nat n) div 2 = n div 2, from calc
+        to_nat (of_nat n) div 2 = to_nat (predimage (of_nat n)) : by rewrite to_nat_predimage
+                          ...   = to_nat (of_nat (n div 2))     : by rewrite of_nat_div2
+                          ...   = n div 2                       : this,
+      have e₂ : even (to_nat (of_nat n)) ↔ even n, from calc
+        even (to_nat (of_nat n)) ↔ 0 ∉ of_nat n : even_to_nat
+                             ... ↔ even n       : even_of_not_zero_mem,
+      eq_of_div2_of_even e₁ e₂))
+
+open equiv
+
+lemma finset_nat_equiv_nat : finset nat ≃ nat :=
+mk to_nat of_nat of_nat_to_nat to_nat_of_nat
+
 end finset
diff --git a/library/data/nat/div.lean b/library/data/nat/div.lean
index d5a9a4a9a..9b586565e 100644
--- a/library/data/nat/div.lean
+++ b/library/data/nat/div.lean
@@ -594,4 +594,21 @@ begin
      rewrite [mul_zero, *div_zero],
      apply div_div_aux a (succ b) (succ c) dec_trivial dec_trivial
 end
+
+lemma div_lt_of_ne_zero : ∀ {n : nat}, n ≠ 0 → n div 2 < n
+| 0        h := absurd rfl h
+| (succ n) h :=
+  begin
+    apply div_lt_of_lt_mul,
+    rewrite [-add_one, mul.right_distrib],
+    change n + 1 < (n * 1 + n) + (1 + 1),
+    rewrite [mul_one, -add.assoc],
+    apply add_lt_add_right,
+    show n < n + n + 1,
+    begin
+      rewrite [add.assoc, -add_zero n at {1}],
+      apply add_lt_add_left,
+      apply zero_lt_succ
+    end
+  end
 end nat