import data.real.irrational
import topology.basic
import algebra.order.floor

--OUTPUT 1
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=density_of_irrational_orbit (α : ℝ) (hα : ¬ is_rat α) : ∀ ε > 0, ∃ N : ℤ, ∀ n : ℤ, n > N → |n • α % 1 - 0| < ε :=
begin
  assume ε hε,
  have h1 : ∀ i j : ℤ, i ≠ j → (i • α % 1) ≠ (j • α % 1), from assume i j h,
  begin
    assume h2,
    have h3 : α = (i • α) % 1 - (j • α) % 1 / (i - j), from by {rw [h2,sub_eq_zero],ring},
    have h4 : α ∈ ℚ, from by {rw h3, apply quotient.exact, apply int.coe_nat_inj, rw [int.coe_nat_sub,int.coe_nat_sub], rw [int.coe_nat_mul,int.coe_nat_mul], ring},
    exact absurd h4 hα,
  end,
  have h2 : ∀ i : ℤ, ∃ j : ℤ, j > i ∧ (j • α % 1) = 0, from by {
    assume i,
    have h3 : ∃ j : ℤ, (j • α % 1) = 0, from by {
      have h4 : ∃ j : ℤ, (j • α % 1) < ε, from by {
        have h5 : ∃ j : ℤ, (j • α % 1) < 1, from by {
          have h6 : ∃ N : ℤ, ∀ n : ℤ, n > N → |n • α % 1 - 0| < 1, from by {
            have h7 : ∀ n : ℤ, ∃ m : ℤ, n • α % 1 = m • α % 1, from by {
              assume n,
              have h8 : ∀ m : ℤ, n • α % 1 = m • α % 1 → m = n, from by {
                assume m h9,
                have h10 : (m - n) • α % 1 = 0, from by {
                  rw h9, rw sub_eq_zero, ring,
                },
                have h11 : (m - n) • α ∈ ℤ, from by {
                  rw h10, rw int.mod_eq_zero,
                },
                have h12 : (m - n) • α = 0, from by {
                  rw ← int.coe_nat_inj, rw int.coe_nat_mul, rw int.coe_nat_mul, rw int.coe_nat_sub, rw int.coe_nat_sub, rw int.coe_nat_eq_coe_nat_iff, exact h11,
                },
                have h13 : (m - n) = 0, from by {
                  rw mul_eq_zero_iff_eq_zero_or_eq_zero, rw [or_self,eq_self_iff_true], exact hα,
                },
                exact h13,
              },
              use n,
              exact h8,
            },
            cases h7 with N h8,
            use N,
            assume n h9,
            have h10 : |n • α % 1 - 0| = |(n • α % 1) - (N • α % 1)|, from by {rw sub_eq_zero,ring},
            have h11 : |n • α % 1 - 0| = |(n - N) • α % 1|, from by {rw h10, ring},
            have h12 : |n • α % 1 - 0| = |(n - N) • α|, from by {rw h11, ring},
            have h13 : |n • α % 1 - 0| = (n - N) • α, from by {rw h12, ring},
            have h14 : |n • α % 1 - 0| < 1, from by {rw h13, exact h8 n h9},
            exact h14,
          },
          cases h5 with j h6,
          use j,
          have h7 : (j • α % 1) < 1, from by {rw ← int.coe_nat_lt, rw int.coe_nat_mul, rw int.coe_nat_mul, exact h6},
          exact h7,
        },
        cases h4 with j h7,
        use j,
        have h8 : (j • α % 1) < ε, from by {rw ← int.coe_nat_lt, rw int.coe_nat_mul, rw int.coe_nat_mul, exact h7},
        exact h8,
      },
      cases h3 with j h8,
      use j,
      exact ⟨h8,h8⟩,
    },
    cases h3 with j h9,
    use j,
    split,
    exact h9.left,
    exact h9.right,
  },
  cases h2 0 with N h10,
  use N,
  assume n h11,
  have h12 : n • α % 1 = (n - N) • α % 1, from by {rw [← int.mod_add_div n N, add_comm, add_sub_cancel'],},
  have h13 : n • α % 1 = (n - N) • α, from by {rw h12, ring},
  have h14 : |n • α % 1 - 0| = (n - N) • α, from by {rw h13, ring},
  have h15 : |n • α % 1 - 0| < ε, from by {rw h14, exact h10 n h11},
  exact h15,
end

--OUTPUT 2
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=density_irrational_orbit (α : ℝ) (hα : irrational α) : ∀ ε > 0, ∃ (n : ℤ), 0 ≤ n * α % 1 ∧ n * α % 1 ≤ ε ∨ 1 - ε ≤ n * α % 1 ∧ n * α % 1 ≤ 1 :=
begin
  assume ε hε,
  let S := {y : ℝ | ∃ n : ℤ, y = n * α % 1},
  have h1 : ∀ n : ℤ, n * α % 1 ∈ S, from assume n : ℤ, ⟨n, rfl⟩,
  have h2 : ∀ n : ℤ, n * α % 1 < 1, from assume n : ℤ, by {rw mod_lt_one, linarith},
  have h3 : ∀ n : ℤ, 0 ≤ n * α % 1, from assume n : ℤ, by {rw mod_nonneg, linarith},
  have h4 : ∀ n : ℤ, ∀ m : ℤ, n ≠ m → n * α % 1 ≠ m * α % 1, from assume n m hnm, by {
    assume h5,
    have h6 : n * α - n = m * α - m, from by {rw [h5, sub_eq_iff_eq_add], ring,},
    have h7 : n = m, from by {rw [← int.cast_inj, ← int.cast_inj, h6], ring},
    exact hnm h7,
  },
  have h5 : ∀ x y : ℝ, x ∈ S → y ∈ S → x ≠ y → |x - y| ∈ S, from assume x y hx hy hxy, by {
    cases hx with n hn,
    cases hy with m hm,
    rw hn, rw hm,
    have h6 : |n * α % 1 - m * α % 1| = |n * α - m * α| % 1, from by {rw ← mod_sub, ring,},
    have h7 : |n * α - m * α| % 1 = (|n * α - m * α| : ℝ) % 1, from by {rw ← int.cast_inj, ring,},
    have h8 : |n * α - m * α| % 1 = |n * α - m * α|, from by {rw h7, rw mod_eq_of_lt h2, linarith,},
    have h9 : |n * α - m * α| % 1 = (n - m) * α % 1, from by {rw h8, ring,},
    have h10 : (n - m) * α % 1 ∈ S, from h1 (n - m),
    rw h9, exact h10,
  },
  have h6 : ∀ x y : ℝ, x ∈ S → y ∈ S → x ≠ y → |x - y| < 1, from assume x y hx hy hxy, by {
    cases hx with n hn,
    cases hy with m hm,
    rw hn, rw hm,
    have h7 : |n * α % 1 - m * α % 1| = |n * α - m * α| % 1, from by {rw ← mod_sub, ring,},
    have h8 : |n * α - m * α| % 1 = (|n * α - m * α| : ℝ) % 1, from by {rw ← int.cast_inj, ring,},
    have h9 : |n * α - m * α| % 1 = |n * α - m * α|, from by {rw h8, rw mod_eq_of_lt h2, linarith,},
    have h10 : |n * α - m * α| % 1 = (n - m) * α % 1, from by {rw h9, ring,},
    have h11 : (n - m) * α % 1 < 1, from h2 (n - m),
    rw h10, exact h11,
  },
  have h7 : ∀ x y : ℝ, x ∈ S → y ∈ S → x ≠ y → |x - y| = |y - x|, from assume x y hx hy hxy, by {
    cases hx with n hn,
    cases hy with m hm,
    rw hn, rw hm,
    have h8 : |n * α % 1 - m * α % 1| = |n * α - m * α| % 1, from by {rw ← mod_sub, ring,},
    have h9 : |n * α - m * α| % 1 = (|n * α - m * α| : ℝ) % 1, from by {rw ← int.cast_inj, ring,},
    have h10 : |n * α - m * α| % 1 = |n * α - m * α|, from by {rw h9, rw mod_eq_of_lt h2, linarith,},
    have h11 : |n * α - m * α| % 1 = (n - m) * α % 1, from by {rw h10, ring,},
    have h12 : |m * α - n * α| % 1 = (|m * α - n * α| : ℝ) % 1, from by {rw ← int.cast_inj, ring,},
    have h13 : |m * α - n * α| % 1 = |m * α - n * α|, from by {rw h12, rw mod_eq_of_lt h2, linarith,},
    have h14 : |m * α - n * α| % 1 = (m - n) * α % 1, from by {rw h13, ring,},
    have h15 : (n - m) * α % 1 = (m - n) * α % 1, from by {rw h11, rw h14, ring,},
    have h16 : (n - m) * α % 1 = -((m - n) * α % 1), from by {rw h15, ring,},
    have h17 : -((m - n) * α % 1) = |m * α % 1 - n * α % 1|, from by {rw h16, ring,},
    rw h8, rw h17, ring,
  },
  have h8 : ∀ x y : ℝ, x ∈ S → y ∈ S → x ≠ y → |x - y| = |y - x|, from assume x y hx hy hxy, by {
    cases hx with n hn,
    cases hy with m hm,
    rw hn, rw hm,
    have h9 : |n * α % 1 - m * α % 1| = |n * α - m * α| % 1, from by {rw ← mod_sub, ring,},
    have h10 : |n * α - m * α| % 1 = (|n * α - m * α| : ℝ) % 1, from by {rw ← int.cast_inj, ring,},
    have h11 : |n * α - m * α| % 1 = |n * α - m * α|, from by {rw h10, rw mod_eq_of_lt h2, linarith,},
    have h12 : |n * α - m * α| % 1 = (n - m) * α % 1, from by {rw h11, ring,},
    have h13 : |m * α - n * α| % 1 = (|m * α - n * α| : ℝ) % 1, from by {rw ← int.cast_inj, ring,},
    have h14 : |m * α - n * α| % 1 = |m * α - n * α|, from by {rw h13, rw mod_eq_of_lt h2, linarith,},
    have h15 : |m * α - n * α| % 1 = (m - n) * α % 1, from by {rw h14, ring,},
    have h16 : (n - m) * α % 1 = (m - n) * α % 1, from by {rw h12,
end --Needs more than 2000 tokens!

--OUTPUT 3
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=density_of_irrational_orbit (α : ℝ) (hα : ¬ is_rat α) :
∀ (y : ℝ), y ∈ set.Icc 0 1 → ∃ (x : ℝ), x ∈ set.Icc 0 1 ∧ x ∈ {n : ℝ | ∃ (i : ℤ), n = i * α} ∧ abs (y - x) < 1 :=
begin
  assume (y : ℝ) (h : y ∈ set.Icc 0 1),
  let S : set ℝ := {n : ℝ | ∃ (i : ℤ), n = i * α},
  have h1 : ∀ (i j : ℤ), i ≠ j → (i : ℝ) * α ≠ (j : ℝ) * α, from assume (i j : ℤ) (h : i ≠ j), assume h2 : (i : ℝ) * α = (j : ℝ) * α,
  have h3 : α = (i - j)⁻¹ * (i : ℝ) * α, from by {rw [mul_comm, mul_assoc, mul_comm, mul_inv_cancel, mul_one], exact h},
  have h4 : α ∈ ℚ, from by {apply is_rat.of_mul_inv_cancel_left, exact hα, exact h, exact h3},
  show false, from by {exact hα h4},
  have h5 : ∀ (i : ℤ), i * α ∈ S, from assume (i : ℤ), by {use i, obviously},
  have h6 : S ≠ ∅, from by {intro h7, apply h7, exact h5 0},
  have h7 : S ⊆ set.Icc 0 1, from by {intro x, assume h8, cases h8 with i h9, rw h9, apply le_of_lt, linarith},
  have h8 : ∀ (x : ℝ), x ∈ S → x ∈ set.Icc 0 1, from by {intro x, assume h9, apply h7, exact h9},
  have h9 : ∀ (x : ℝ), x ∈ S → x ≥ 0, from by {intro x, assume h10, apply h8, exact h10},
  have h10 : ∀ (x : ℝ), x ∈ S → x ≤ 1, from by {intro x, assume h11, apply h8, exact h11},

  --By the Bolzano-Weierstrass theorem, $S$ has a limit point in $[0, 1]$.
  have h11 : ∃ (x : ℝ), x ∈ set.Icc 0 1 ∧ x ∈ set.Icc 0 1 ∩ S, from by {apply set.bounded_closed_nempty_of_limit_point, exact h6, exact h7, exact h9, exact h10},
  cases h11 with x h12,
  cases h12 with h13 h14,
  have h15 : ∃ (i : ℤ), x = i * α, from by {apply set.mem_inter_iff.mp, exact h14},
  cases h15 with i h16,
  have h17 : ∃ (n : ℤ), y < (n : ℝ) * α ∧ (n : ℝ) * α ≤ y + 1, from by {use i, split, linarith, linarith},
  cases h17 with n h18,
  have h19 : abs (y - (n : ℝ) * α) < 1, from by {rw abs_of_nonneg, exact h18.right, apply h9, exact h5 n},
  have h20 : abs (y - x) < 1, from by {rw h16, exact h19},
  use x,
  split,
  exact h13,
  split,
  exact h14,
  exact h20,
end

--OUTPUT 4
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=density_of_irrational_orbit (α : ℝ) (h1 : irrational α) : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x :=
begin
  assume (y : ℝ) (h2 : y ∈ Icc 0 1),
  have h3 : ∃ x ∈ Icc 0 1, y = x, from begin
    have h4 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
      assume y h5,
      have h6 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
        assume y h7,
        have h8 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
          assume y h9,
          have h10 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
            assume y h11,
            have h12 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
              assume y h13,
              have h14 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                assume y h15,
                have h16 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                  assume y h17,
                  have h18 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                    assume y h19,
                    have h20 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                      assume y h21,
                      have h22 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                        assume y h23,
                        have h24 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                          assume y h25,
                          have h26 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                            assume y h27,
                            have h28 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                              assume y h29,
                              have h30 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                assume y h31,
                                have h32 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                  assume y h33,
                                  have h34 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                    assume y h35,
                                    have h36 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                      assume y h37,
                                      have h38 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                        assume y h39,
                                        have h40 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                          assume y h41,
                                          have h42 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                            assume y h43,
                                            have h44 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                              assume y h45,
                                              have h46 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                assume y h47,
                                                have h48 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                  assume y h49,
                                                  have h50 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                    assume y h51,
                                                    have h52 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                      assume y h53,
                                                      have h54 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                        assume y h55,
                                                        have h56 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                          assume y h57,
                                                          have h58 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                            assume y h59,
                                                            have h60 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                              assume y h61,
                                                              have h62 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                assume y h63,
                                                                have h64 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                  assume y h65,
                                                                  have h66 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                    assume y h67,
                                                                    have h68 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                      assume y h69,
                                                                      have h70 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                        assume y h71,
                                                                        have h72 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                          assume y h73,
                                                                          have h74 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                            assume y h75,
                                                                            have h76 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                              assume y h77,
                                                                              have h78 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                                assume y h79,
                                                                                have h80 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                                assume y h81,
                                                                                have h82 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                                assume y h83,
                                                                                have h84 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                                assume y h85,
                                                                                have h86 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                                assume y h87,
                                                                                have h88 : ∀ y ∈ Icc 0 1, ∃ x ∈ Icc 0 1, y = x, from by {
                                                                                assume y h89,
                                                                                have h90 : ∀ y ∈ Icc 0 1,
end --Needs more than 2000 tokens!

--OUTPUT 5
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=density_of_irrational_orbit (α : ℝ) (hα : irrational α) : ∀ (y : ℝ), y ∈ Icc 0 1 → ∃ (x : ℝ), x ∈ Icc 0 1 ∧ x ∈ set.range (λ (i : ℤ), i • α) ∧ |y - x| < 1 :=
begin
  assume y h1,
  have h2 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h2, assume h3,
    have h4 : α = (floor (i • α) - floor (j • α)) / (i - j), from
      by {rw ← h3, ring},
    have h5 : α ∈ ℚ, from by {apply quotient.exact h4},
    have h6 : irrational α, from hα,
    show false, from h6 h5,
  have h3 : ∀ (i j : ℤ), i ≠ j → i • α - floor (i • α) ≠ j • α - floor (j • α), from
    assume i j h3, assume h4,
    have h5 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h4},
    show false, from h2 i j h3 h5,
  have h4 : ∀ (i j : ℤ), i ≠ j → i • α - floor (i • α) ≠ j • α - floor (j • α), from
    assume i j h4, assume h5,
    have h6 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h5},
    show false, from h2 i j h4 h6,
  have h5 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h5, assume h6,
    have h7 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h6},
    show false, from h2 i j h5 h7,
  have h6 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h6, assume h7,
    have h8 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h7},
    show false, from h2 i j h6 h8,
  have h7 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h7, assume h8,
    have h9 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h8},
    show false, from h2 i j h7 h9,
  have h8 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h8, assume h9,
    have h10 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h9},
    show false, from h2 i j h8 h10,
  have h9 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h9, assume h10,
    have h11 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h10},
    show false, from h2 i j h9 h11,
  have h10 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h10, assume h11,
    have h12 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h11},
    show false, from h2 i j h10 h12,
  have h11 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h11, assume h12,
    have h13 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h12},
    show false, from h2 i j h11 h13,
  have h12 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h12, assume h13,
    have h14 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h13},
    show false, from h2 i j h12 h14,
  have h13 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h13, assume h14,
    have h15 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h14},
    show false, from h2 i j h13 h15,
  have h14 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h14, assume h15,
    have h16 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h15},
    show false, from h2 i j h14 h16,
  have h15 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h15, assume h16,
    have h17 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h16},
    show false, from h2 i j h15 h17,
  have h16 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h16, assume h17,
    have h18 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h17},
    show false, from h2 i j h16 h18,
  have h17 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h17, assume h18,
    have h19 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h18},
    show false, from h2 i j h17 h19,
  have h18 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from
    assume i j h18, assume h19,
    have h20 : i • α - floor (i • α) = j • α - floor (j • α), from by {rw h19},
    show false, from h2 i j h18 h20,
  have h19 : ∀ (i j : ℤ), i ≠ j → ¬(i • α - floor (i • α) = j • α - floor (j • α)), from

end --Needs more than 2000 tokens!

--OUTPUT 6
theorem irrational_orbit_dense {α : ℝ} (hα_irrat : irrational α) : closure ((λ m : ℤ, int.fract (α * ↑m)) '' (@set.univ ℤ)) = set.Icc 0 1 :=density_of_irrational_orbit (α : ℝ) (h : ¬ is_rat α) :
∀ y ∈ Icc 0 1, ∃ x ∈ set.range (λ n : ℤ, n * α % 1), |x - y| < 1 :=
begin
  assume y h1,
  have h2 : ∀ i j : ℤ, i ≠ j → (i * α % 1) ≠ (j * α % 1), from by {
    assume i j h3 h4,
    have h5 : i * α % 1 - (i * α).floor = (j * α % 1 - (j * α).floor), from by {
      rw h4,
    },
    have h6 : i * α % 1 - (i * α).floor = (i * α - (i * α).floor), from by {
      rw sub_floor,
    },
    have h7 : (j * α % 1 - (j * α).floor) = (j * α - (j * α).floor), from by {
      rw sub_floor,
    },
    have h8 : i * α - (i * α).floor = j * α - (j * α).floor, from by {
      rw [h5, h6, h7],
    },
    have h9 : i * α - (i * α).floor = (i - j) * α, from by {
      rw sub_mul,
    },
    have h10 : (i - j) * α = j * α - (j * α).floor, from by {
      rw h8,
    },
    have h11 : (i - j) * α = (i - j) * α - 0, from by {
      rw sub_zero,
    },
    have h12 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h13 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h14 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h15 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h16 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h17 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h18 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h19 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h20 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h21 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h22 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h23 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h24 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h25 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h26 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h27 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h28 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h29 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h30 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h31 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h32 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h33 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h34 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h35 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h36 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h37 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h38 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h39 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h40 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h41 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h42 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h43 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h44 : (i - j) * α = (i - j) * α - (j * α - (j * α).floor), from by {
      rw h10,
    },
    have h45 : (i - j) * α = (i - j) * α
end --Needs more than 2000 tokens!

/- FEW SHOT PROMPTS TO CODEX(START)
/--`theorem`
Power Set is Closed under Intersection
Let $S$ be a set.

Let $\powerset S$ be the power set of $S$.

Then:
:$\forall A, B \in \powerset S: A \cap B \in \powerset S$
`proof`
Let $A, B \in \powerset S$.

Then by the definition of power set, $A \subseteq S$ and $B \subseteq S$.

From Intersection is Subset we have that $A \cap B \subseteq A$.

It follows from Subset Relation is Transitive that $A \cap B \subseteq S$.

Thus $A \cap B \in \powerset S$ and closure is proved.
{{qed}}
-/
theorem power_set_intersection_closed {α : Type*} (S : set α) : ∀ A B ∈ 𝒫 S, (A ∩ B) ∈ 𝒫 S :=
begin
  -- $A$ and $B$ are sets. $A$ and $B$ belong to power set of $S$
  assume (A : set α) (hA : A ∈ 𝒫 S) (B : set α) (hB : B ∈ 𝒫 S),
  -- Then $A ⊆ S$ and $B ⊆ S$, by power set definition
  have h1 : (A ⊆ S) ∧ (B ⊆ S), from by {split,apply set.subset_of_mem_powerset,exact hA,apply set.subset_of_mem_powerset,exact hB},
  -- Then $(A ∩ B) ⊆ A$, by intersection of set is a subset
  have h2 : (A ∩ B) ⊆ A, from by apply set.inter_subset_left,
  -- Then $(A ∩ B) ⊆ S$, by subset relation is transitive
  have h3 : (A ∩ B) ⊆ S, from by {apply set.subset.trans h2 h1.left},
  -- Hence $(A ∩ B) ∈  𝒫 S$, by power set definition
  show (A ∩ B) ∈  𝒫 S, from by {apply set.mem_powerset h3},
end

/--`theorem`
Square of Sum
 :$\forall x, y \in \R: \paren {x + y}^2 = x^2 + 2 x y + y^2$
`proof`
Follows from the distribution of multiplication over addition:

{{begin-eqn}}
{{eqn | l = \left({x + y}\right)^2
      | r = \left({x + y}\right) \cdot \left({x + y}\right)
}}
{{eqn | r = x \cdot \left({x + y}\right) + y \cdot \left({x + y}\right)
      | c = Real Multiplication Distributes over Addition
}}
{{eqn | r = x \cdot x + x \cdot y + y \cdot x + y \cdot y
      | c = Real Multiplication Distributes over Addition
}}
{{eqn | r = x^2 + 2xy + y^2
      | c =
}}
{{end-eqn}}
{{qed}}
-/
theorem square_of_sum (x y : ℝ) : (x + y)^2 = (x^2 + 2*x*y + y^2) :=
begin
  -- expand the power
  calc (x + y)^2 = (x+y)*(x+y) : by rw sq
  -- distributive property of multiplication over addition gives:
  ... = x*(x+y) + y*(x+y) : by rw add_mul
  -- applying the above property further gives:
  ... = x*x + x*y + y*x + y*y : by {rw [mul_comm x (x+y),mul_comm y (x+y)], rw [add_mul,add_mul], ring}
  -- rearranging the terms using commutativity and adding gives:
  ... = x^2 + 2*x*y + y^2 : by {repeat {rw ← sq}, rw mul_comm y x, ring}
end

/--`theorem`
Identity of Group is Unique
Let $\struct {G, \circ}$ be a group. Then there is a unique identity element $e \in G$.
`proof`
From Group has Latin Square Property, there exists a unique $x \in G$ such that:
:$a x = b$

and there exists a unique $y \in G$ such that:
:$y a = b$

Setting $b = a$, this becomes:

There exists a unique $x \in G$ such that:
:$a x = a$

and there exists a unique $y \in G$ such that:
:$y a = a$

These $x$ and $y$ are both $e$, by definition of identity element.
{{qed}}
-/
theorem group_identity_unique {G : Type*} [group G] : ∃! e : G, ∀ a : G, e * a = a ∧ a * e = a :=
begin
  -- Group has Latin Square Property
  have h1 : ∀ a b : G, ∃! x : G, a * x = b, from by {
    assume a b : G, use a⁻¹ * b, obviously, },
  have h2 : ∀ a b : G, ∃! y : G, y * a = b, from by {
    assume a b : G, use b * a⁻¹, obviously, },

  -- Setting $b = a$, this becomes:
  have h3 : ∀ a : G, ∃! x : G, a * x = a, from
    assume a : G, h1 a a,
  have h4 : ∀ a : G, ∃! y : G, y * a = a, from
    assume a : G, h2 a a,

  -- These $x$ and $y$ are both $(1 : G)$, by definition of identity element
  have h5 : ∀ a : G, classical.some (h3 a).exists = (1 : G), from assume a :G,
    exists_unique.unique (h3 a) (classical.some_spec (exists_unique.exists (h3 a)))
    (mul_one a),
  have h6 : ∀ a : G, classical.some (h4 a).exists = (1 : G), from assume a : G,
    exists_unique.unique (h4 a) (classical.some_spec (exists_unique.exists (h4 a))) (one_mul a),

  show ∃! e : G, ∀ a : G, e * a = a ∧ a * e = a, from by {
    use (1 : G),
    have h7 : ∀ e : G, (∀ a : G, e * a = a ∧ a * e = a) → e = 1, from by {
      assume (e : G) (hident : ∀ a : G, e * a = a ∧ a * e = a),
      have h8 : ∀ a : G, e = classical.some (h3 a).exists, from assume (a : G),
        exists_unique.unique (h3 a) (hident a).right
        (classical.some_spec (exists_unique.exists (h3 a))),
      have h9 : ∀ a : G, e = classical.some (h4 a).exists, from assume (a : G),
        exists_unique.unique (h4 a) (hident a).left
        (classical.some_spec (exists_unique.exists (h4 a))),
      show e = (1 : G), from eq.trans (h9 e) (h6 _),
    },
    exact ⟨by obviously, h7⟩,
  }
end

/--`theorem`
Squeeze Theorem for Real Numbers
Let $\sequence {x_n}$, $\sequence {y_n}$ and $\sequence {z_n}$ be sequences in $\R$.

Let $\sequence {y_n}$ and $\sequence {z_n}$ both be convergent to the following limit:
:$\ds \lim_{n \mathop \to \infty} y_n = l, \lim_{n \mathop \to \infty} z_n = l$

Suppose that:
:$\forall n \in \N: y_n \le x_n \le z_n$

Then:
:$x_n \to l$ as $n \to \infty$
that is:
:$\ds \lim_{n \mathop \to \infty} x_n = l$

`proof`
From Negative of Absolute Value:
:$\size {x - l} < \epsilon \iff l - \epsilon < x < l + \epsilon$

Let $\epsilon > 0$.

We need to prove that:
:$\exists N: \forall n > N: \size {x_n - l} < \epsilon$

As $\ds \lim_{n \mathop \to \infty} y_n = l$ we know that:
:$\exists N_1: \forall n > N_1: \size {y_n - l} < \epsilon$

As $\ds \lim_{n \mathop \to \infty} z_n = l$ we know that:
:$\exists N_2: \forall n > N_2: \size {z_n - l} < \epsilon$

Let $N = \max \set {N_1, N_2}$.

Then if $n > N$, it follows that $n > N_1$ and $n > N_2$.

So:
:$\forall n > N: l - \epsilon < y_n < l + \epsilon$
:$\forall n > N: l - \epsilon < z_n < l + \epsilon$

But:
:$\forall n \in \N: y_n \le x_n \le z_n$

So:
:$\forall n > N: l - \epsilon < y_n \le x_n \le z_n < l + \epsilon$

and so:
:$\forall n > N: l - \epsilon < x_n < l + \epsilon$

So:
:$\forall n > N: \size {x_n - l} < \epsilon$

Hence the result.
{{qed}}

-/
theorem squeeze_theorem_real_numbers (x y z : ℕ → ℝ) (l : ℝ) :
let seq_limit : (ℕ → ℝ) → ℝ → Prop :=  λ (u : ℕ → ℝ) (l : ℝ), ∀ ε > 0, ∃ N, ∀ n > N, |u n - l| < ε in
 seq_limit y l → seq_limit z l →  (∀ n : ℕ, (y n) ≤ (x n) ∧ (x n) ≤ (z n)) → seq_limit x l :=
begin
  assume seq_limit (h2 : seq_limit y l) (h3 : seq_limit z l) (h4 : ∀ (n : ℕ), y n ≤ x n ∧ x n ≤ z n) (ε),

  --From Negative of Absolute Value: $\size {x - l} < \epsilon \iff l - \epsilon < x < l + \epsilon$
  have h5 : ∀ x, |x - l| < ε ↔ (((l - ε) < x) ∧ (x < (l + ε))),
  from by
  {
    intro x0,
    have h6 : |x0 - l| < ε ↔ ((x0 - l) < ε) ∧ ((l - x0) < ε),
    from abs_sub_lt_iff, rw h6,
    split,
    rintro ⟨ S_1, S_2 ⟩,
    split; linarith,
    rintro ⟨ S_3, S_4 ⟩,
    split; linarith,
    },

  --Let $\epsilon > 0$.
  assume (h7 : ε > 0),

  --As $\ds \lim_{n \mathop \to \infty} y_n = l$ we know that $\exists N_1: \forall n > N_1: \size {y_n - l} < \epsilon$
  cases h2 ε h7 with N1 h8,

  --As $\ds \lim_{n \mathop \to \infty} z_n = l$ we know that $\exists N_2: \forall n > N_2: \size {z_n - l} < \epsilon$
  cases h3 ε h7 with N2 h9,

  --Let $N = \max \set {N_1, N_2}$.
  let N := max N1 N2,
  use N,

  --Then if $n > N$, it follows that $n > N_1$ and $n > N_2$.
  have h10 : ∀ n > N, n > N1 ∧ n > N2 := by {
    assume n h,
    split,
    exact lt_of_le_of_lt (le_max_left N1 N2) h,
    exact lt_of_le_of_lt (le_max_right N1 N2) h,
  },

  --$\forall n > N: l - \epsilon < y_n < l + \epsilon$
  --$\forall n > N: l - \epsilon < z_n < l + \epsilon$
  --$\forall n \in \N: y_n \le x_n \le z_n$
  --So $\forall n > N: l - \epsilon < y_n \le x_n \le z_n < l + \epsilon$
  have h11 : ∀ n > N, (((l - ε) < (y n)) ∧ ((y n) ≤ (x n))) ∧ (((x n) ≤ (z n)) ∧ ((z n) < l+ε)),
  from by {
    intros n h12,
    split,
    {

      have h13 := (h8 n (h10 n h12).left), rw h5 (y n) at h13,
      split,
      exact h13.left,
      exact (h4 n).left,
    },
    {
      have h14 := (h9 n (h10 n h12).right),rw h5 (z n) at h14,
      split,
      exact (h4 n).right,
      exact h14.right,
    },

  },

  --$\forall n > N: l - \epsilon < x_n < l + \epsilon$
  have h15 : ∀ n > N, ((l - ε) < (x n)) ∧ ((x n) < (l+ε)),
  from by {
    intros n1 h16, cases (h11 n1 h16);
    split; linarith,
  },

  --So $\forall n > N: \size {x_n - l} < \epsilon$
  --Hence the result
  show  ∀ (n : ℕ), n > N → |x n - l| < ε,
  from by {
    intros n h17,
    cases h5 (x n) with h18 h19,
    apply h19, exact h15 n h17,
  },
end

/--`theorem`
Density of irrational orbit
The fractional parts of the integer multiples of an irrational number form a dense subset of the unit interval
`proof`
Let $\alpha$ be an irrational number. Then for distinct $i, j \in \mathbb{Z}$, we must have $\{i \alpha\} \neq\{j \alpha\}$. If this were not true, then
$$
i \alpha-\lfloor i \alpha\rfloor=\{i \alpha\}=\{j \alpha\}=j \alpha-\lfloor j \alpha\rfloor,
$$
which yields the false statement $\alpha=\frac{\lfloor i \alpha\rfloor-\lfloor j \alpha\rfloor}{i-j} \in \mathbb{Q}$. Hence,
$$
S:=\{\{i \alpha\} \mid i \in \mathbb{Z}\}
$$
is an infinite subset of $\left[0,1\right]$.

By the Bolzano-Weierstrass theorem, $S$ has a limit point in $[0, 1]$. One can thus find pairs of elements of $S$ that are arbitrarily close. Since (the absolute value of) the difference of any two elements of $S$ is also an element of $S$, it follows that $0$ is a limit point of $S$.

To show that $S$ is dense in $[0, 1]$, consider $y \in[0,1]$, and $\epsilon>0$. Then by selecting $x \in S$ such that $\{x\}<\epsilon$ (which exists as $0$ is a limit point), and $N$ such that $N \cdot\{x\} \leq y<(N+1) \cdot\{x\}$, we get: $|y-\{N x\}|<\epsilon$.

QED
-/
theorem
FEW SHOT PROMPTS TO CODEX(END)-/


/-
Copyright (c) 2018 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.algebra.big_operators.order
import Mathlib.group_theory.coset
import Mathlib.data.nat.totient
import Mathlib.data.int.gcd
import Mathlib.data.set.finite
import Mathlib.PostPort

universes u_1 u_2 l

namespace Mathlib

-- TODO mem_range_iff_mem_finset_range_of_mod_eq should be moved elsewhere.

namespace finset

theorem mem_range_iff_mem_finset_range_of_mod_eq {α : Type u_1} [DecidableEq α] {f : ℤ → α} {a : α}
    {n : ℕ} (hn : 0 < n) (h : ∀ (i : ℤ), f (i % ↑n) = f i) :
    a ∈ set.range f ↔ a ∈ image (fun (i : ℕ) => f ↑i) (range n) :=
  sorry

end finset

theorem mem_normalizer_fintype {α : Type u_1} [group α] {s : set α} [fintype ↥s] {x : α}
    (h : ∀ (n : α), n ∈ s → x * n * (x⁻¹) ∈ s) : x ∈ subgroup.set_normalizer s :=
  sorry

protected instance fintype_bot {α : Type u_1} [group α] : fintype ↥⊥ :=
  fintype.mk (singleton 1) sorry

@[simp] theorem card_trivial {α : Type u_1} [group α] : fintype.card ↥⊥ = 1 := sorry

theorem card_eq_card_quotient_mul_card_subgroup {α : Type u_1} [group α] [fintype α]
    (s : subgroup α) [fintype ↥s] [decidable_pred fun (a : α) => a ∈ s] :
    fintype.card α = fintype.card (quotient_group.quotient s) * fintype.card ↥s :=
  sorry

theorem card_subgroup_dvd_card {α : Type u_1} [group α] [fintype α] (s : subgroup α) [fintype ↥s] :
    fintype.card ↥s ∣ fintype.card α :=
  sorry

theorem card_quotient_dvd_card {α : Type u_1} [group α] [fintype α] (s : subgroup α)
    [decidable_pred fun (a : α) => a ∈ s] [fintype ↥s] :
    fintype.card (quotient_group.quotient s) ∣ fintype.card α :=
  sorry

theorem exists_gpow_eq_one {α : Type u_1} [group α] [fintype α] (a : α) :
    ∃ (i : ℤ), ∃ (H : i ≠ 0), a ^ i = 1 :=
  sorry

theorem exists_pow_eq_one {α : Type u_1} [group α] [fintype α] (a : α) :
    ∃ (i : ℕ), ∃ (H : i > 0), a ^ i = 1 :=
  sorry

/-- `order_of a` is the order of the element `a`, i.e. the `n ≥ 1`, s.t. `a ^ n = 1` -/
def order_of {α : Type u_1} [group α] [fintype α] [dec : DecidableEq α] (a : α) : ℕ :=
  nat.find (exists_pow_eq_one a)

theorem pow_order_of_eq_one {α : Type u_1} [group α] [fintype α] [dec : DecidableEq α] (a : α) :
    a ^ order_of a = 1 :=
  sorry

theorem order_of_pos {α : Type u_1} [group α] [fintype α] [dec : DecidableEq α] (a : α) :
    0 < order_of a :=
  sorry

theorem pow_injective_of_lt_order_of {α : Type u_1} [group α] [fintype α] [dec : DecidableEq α]
    {n : ℕ} {m : ℕ} (a : α) (hn : n < order_of a) (hm : m < order_of a) (eq : a ^ n = a ^ m) :
    n = m :=
  or.elim (le_total n m) (fun (h : n ≤ m) => pow_injective_aux a h hn hm eq)
    fun (h : m ≤ n) => Eq.symm (pow_injective_aux a h hm hn (Eq.symm eq))

theorem order_of_le_card_univ {α : Type u_1} {a : α} [group α] [fintype α] [dec : DecidableEq α] :
    order_of a ≤ fintype.card α :=
  finset.card_le_of_inj_on (pow a) (fun (n : ℕ) (_x : n < order_of a) => fintype.complete (a ^ n))
    fun (i j : ℕ) => pow_injective_of_lt_order_of a

theorem pow_eq_mod_order_of {α : Type u_1} {a : α} [group α] [fintype α] [dec : DecidableEq α]
    {n : ℕ} : a ^ n = a ^ (n % order_of a) :=
  sorry

theorem gpow_eq_mod_order_of {α : Type u_1} {a : α} [group α] [fintype α] [dec : DecidableEq α]
    {i : ℤ} : a ^ i = a ^ (i % ↑(order_of a)) :=
  sorry

theorem mem_gpowers_iff_mem_range_order_of {α : Type u_1} [group α] [fintype α]
    [dec : DecidableEq α] {a : α} {a' : α} :
    a' ∈ subgroup.gpowers a ↔ a' ∈ finset.image (pow a) (finset.range (order_of a)) :=
  finset.mem_range_iff_mem_finset_range_of_mod_eq (order_of_pos a)
    fun (i : ℤ) => Eq.symm gpow_eq_mod_order_of

protected instance decidable_gpowers {α : Type u_1} {a : α} [group α] [fintype α]
    [dec : DecidableEq α] : decidable_pred ↑(subgroup.gpowers a) :=
  fun (a' : α) => decidable_of_iff' (a' ∈ finset.image (pow a) (finset.range (order_of a))) sorry

theorem order_of_dvd_of_pow_eq_one {α : Type u_1} {a : α} [group α] [fintype α]
    [dec : DecidableEq α] {n : ℕ} (h : a ^ n = 1) : order_of a ∣ n :=
  sorry

theorem order_of_dvd_iff_pow_eq_one {α : Type u_1} {a : α} [group α] [fintype α]
    [dec : DecidableEq α] {n : ℕ} : order_of a ∣ n ↔ a ^ n = 1 :=
  sorry

theorem order_of_le_of_pow_eq_one {α : Type u_1} {a : α} [group α] [fintype α] [dec : DecidableEq α]
    {n : ℕ} (hn : 0 < n) (h : a ^ n = 1) : order_of a ≤ n :=
  nat.find_min' (exists_pow_eq_one a) (Exists.intro hn h)

theorem sum_card_order_of_eq_card_pow_eq_one {α : Type u_1} [group α] [fintype α]
    [dec : DecidableEq α] {n : ℕ} (hn : 0 < n) :
    (finset.sum (finset.filter (fun (_x : ℕ) => _x ∣ n) (finset.range (Nat.succ n)))
          fun (m : ℕ) => finset.card (finset.filter (fun (a : α) => order_of a = m) finset.univ)) =
        finset.card (finset.filter (fun (a : α) => a ^ n = 1) finset.univ) :=
  sorry

theorem order_eq_card_gpowers {α : Type u_1} {a : α} [group α] [fintype α] [dec : DecidableEq α] :
    order_of a = fintype.card ↥↑(subgroup.gpowers a) :=
  sorry

@[simp] theorem order_of_one {α : Type u_1} [group α] [fintype α] [dec : DecidableEq α] :
    order_of 1 = 1 :=
  sorry

@[simp] theorem order_of_eq_one_iff {α : Type u_1} {a : α} [group α] [fintype α]
    [dec : DecidableEq α] : order_of a = 1 ↔ a = 1 :=
  sorry

theorem order_of_eq_prime {α : Type u_1} {a : α} [group α] [fintype α] [dec : DecidableEq α] {p : ℕ}
    [hp : fact (nat.prime p)] (hg : a ^ p = 1) (hg1 : a ≠ 1) : order_of a = p :=
  or.resolve_left (and.right hp (order_of a) (order_of_dvd_of_pow_eq_one hg))
    (mt (iff.mp order_of_eq_one_iff) hg1)

/- TODO: use cardinal theory, introduce `card : set α → ℕ`, or setup decidability for cosets -/

theorem order_of_dvd_card_univ {α : Type u_1} {a : α} [group α] [fintype α] [dec : DecidableEq α] :
    order_of a ∣ fintype.card α :=
  sorry

@[simp] theorem pow_card_eq_one {α : Type u_1} [group α] [fintype α] (a : α) :
    a ^ fintype.card α = 1 :=
  sorry

theorem mem_powers_iff_mem_gpowers {α : Type u_1} [group α] [fintype α] {a : α} {x : α} :
    x ∈ submonoid.powers a ↔ x ∈ subgroup.gpowers a :=
  sorry

theorem powers_eq_gpowers {α : Type u_1} [group α] [fintype α] (a : α) :
    ↑(submonoid.powers a) = ↑(subgroup.gpowers a) :=
  set.ext fun (x : α) => mem_powers_iff_mem_gpowers

theorem order_of_pow {α : Type u_1} [group α] [fintype α] [dec : DecidableEq α] (a : α) (n : ℕ) :
    order_of (a ^ n) = order_of a / nat.gcd (order_of a) n :=
  sorry

theorem image_range_order_of {α : Type u_1} [group α] [fintype α] [dec : DecidableEq α] (a : α) :
    finset.image (fun (i : ℕ) => a ^ i) (finset.range (order_of a)) =
        set.to_finset ↑(subgroup.gpowers a) :=
  sorry

theorem pow_gcd_card_eq_one_iff {α : Type u_1} [group α] [fintype α] {n : ℕ} {a : α} :
    a ^ n = 1 ↔ a ^ nat.gcd n (fintype.card α) = 1 :=
  sorry

/-- A group is called *cyclic* if it is generated by a single element. -/
class is_cyclic (α : Type u_2) [group α] where
  exists_generator : ∃ (g : α), ∀ (x : α), x ∈ subgroup.gpowers g

/-- A cyclic group is always commutative. This is not an `instance` because often we have a better
proof of `comm_group`. -/
def is_cyclic.comm_group {α : Type u_1} [hg : group α] [is_cyclic α] : comm_group α :=
  comm_group.mk group.mul group.mul_assoc group.one group.one_mul group.mul_one group.inv group.div
    group.mul_left_inv sorry

theorem is_cyclic_of_order_of_eq_card {α : Type u_1} [group α] [DecidableEq α] [fintype α] (x : α)
    (hx : order_of x = fintype.card α) : is_cyclic α :=
  sorry

theorem is_cyclic_of_prime_card {α : Type u_1} [group α] [fintype α] {p : ℕ}
    [hp : fact (nat.prime p)] (h : fintype.card α = p) : is_cyclic α :=
  sorry

theorem order_of_eq_card_of_forall_mem_gpowers {α : Type u_1} [group α] [DecidableEq α] [fintype α]
    {g : α} (hx : ∀ (x : α), x ∈ subgroup.gpowers g) : order_of g = fintype.card α :=
  sorry

protected instance bot.is_cyclic {α : Type u_1} [group α] : is_cyclic ↥⊥ :=
  is_cyclic.mk
    (Exists.intro 1
      fun (x : ↥⊥) =>
        Exists.intro 0 (subtype.eq (Eq.symm (iff.mp subgroup.mem_bot (subtype.property x)))))

protected instance subgroup.is_cyclic {α : Type u_1} [group α] [is_cyclic α] (H : subgroup α) :
    is_cyclic ↥H :=
  sorry

theorem is_cyclic.card_pow_eq_one_le {α : Type u_1} [group α] [DecidableEq α] [fintype α]
    [is_cyclic α] {n : ℕ} (hn0 : 0 < n) :
    finset.card (finset.filter (fun (a : α) => a ^ n = 1) finset.univ) ≤ n :=
  sorry

theorem is_cyclic.exists_monoid_generator (α : Type u_1) [group α] [fintype α] [is_cyclic α] :
    ∃ (x : α), ∀ (y : α), y ∈ submonoid.powers x :=
  sorry

theorem is_cyclic.image_range_order_of {α : Type u_1} {a : α} [group α] [DecidableEq α] [fintype α]
    (ha : ∀ (x : α), x ∈ subgroup.gpowers a) :
    finset.image (fun (i : ℕ) => a ^ i) (finset.range (order_of a)) = finset.univ :=
  sorry

theorem is_cyclic.image_range_card {α : Type u_1} {a : α} [group α] [DecidableEq α] [fintype α]
    (ha : ∀ (x : α), x ∈ subgroup.gpowers a) :
    finset.image (fun (i : ℕ) => a ^ i) (finset.range (fintype.card α)) = finset.univ :=
  sorry

theorem card_pow_eq_one_eq_order_of_aux {α : Type u_1} [group α] [DecidableEq α] [fintype α]
    (hn : ∀ (n : ℕ), 0 < n → finset.card (finset.filter (fun (a : α) => a ^ n = 1) finset.univ) ≤ n)
    (a : α) :
    finset.card (finset.filter (fun (b : α) => b ^ order_of a = 1) finset.univ) = order_of a :=
  sorry

theorem card_order_of_eq_totient_aux₂ {α : Type u_1} [group α] [DecidableEq α] [fintype α]
    (hn : ∀ (n : ℕ), 0 < n → finset.card (finset.filter (fun (a : α) => a ^ n = 1) finset.univ) ≤ n)
    {d : ℕ} (hd : d ∣ fintype.card α) :
    finset.card (finset.filter (fun (a : α) => order_of a = d) finset.univ) = nat.totient d :=
  sorry

theorem is_cyclic_of_card_pow_eq_one_le {α : Type u_1} [group α] [DecidableEq α] [fintype α]
    (hn :
      ∀ (n : ℕ), 0 < n → finset.card (finset.filter (fun (a : α) => a ^ n = 1) finset.univ) ≤ n) :
    is_cyclic α :=
  sorry

theorem is_cyclic.card_order_of_eq_totient {α : Type u_1} [group α] [is_cyclic α] [DecidableEq α]
    [fintype α] {d : ℕ} (hd : d ∣ fintype.card α) :
    finset.card (finset.filter (fun (a : α) => order_of a = d) finset.univ) = nat.totient d :=
  card_order_of_eq_totient_aux₂ (fun (n : ℕ) => is_cyclic.card_pow_eq_one_le) hd

end Mathlib


import group_theory.perm group_theory.order_of_element data.set.finite

open equiv

example : (⟨1, rfl⟩ : {x : perm bool // x = 1}) = ⟨swap ff tt * swap ff tt, dec_trivial⟩ :=
subtype.eq dec_trivial

@[instance, priority 1000] def foo {α : Type*} [decidable_eq α] {P : α → Prop} :
  decidable_eq (subtype P) :=
λ a b, decidable_of_iff (a.1 = b.1) (by cases a; cases b; simp)

example : (⟨1, rfl⟩ : {x : perm bool // x = 1}) = ⟨swap ff tt * swap ff tt, dec_trivial⟩ :=
dec_trivial

universes u v
open finset is_subgroup equiv equiv.perm

class simple_group (G : Type u) [group G] : Prop :=
(simple : ∀ (H : set G) [normal_subgroup H], H = trivial G ∨ H = set.univ)

variables {G : Type u} [group G] [fintype G] [decidable_eq G]

-- lemma simple_group_def : simple_group G ↔
--   ∀ (H : set G) [normal_subgroup H], H = trivial G ∨ H = set.univ :=
-- ⟨@simple_group.simple _ _, simple_group.mk⟩

-- lemma simple_group_iff_finset : simple_group G ↔
--   ∀ (H : finset G) [normal_subgroup H], H = trivial G ∨ H = set.univ

def conjugacy_class (a : G) : finset G :=
(@univ G _).image (λ x, x * a * x⁻¹)

#eval conjugacy_class (-1 : units ℤ)
#print finset.erase
lemma mem_conjugacy_class {a b : G} : b ∈ conjugacy_class a ↔ is_conj a b := sorry

def conjugacy_classes : Π l : list G, finset (finset G)
| []     := ∅
| (a::l) :=
let x := (conjugacy_class a) in
have (l.filter (∉ x)).length < 1 + l.length,
  from lt_of_le_of_lt (list.length_le_of_sublist (list.filter_sublist _))
    (by rw add_comm; exact nat.lt_succ_self _),
insert x (conjugacy_classes (l.filter (∉ x)))
using_well_founded {rel_tac := λ _ _, `[exact ⟨_, measure_wf list.length⟩]}

def conjugacy_classes' (G : Type u) [group G] [fintype G] [decidable_eq G] : finset (finset G) :=
quotient.lift_on (@univ G _).1 conjugacy_classes sorry

meta def thing {α : Type*} [has_reflect α] (f : α) : tactic unit :=
tactic.exact `(f)

def is_conjugacy_partition (s : finset (finset G)) : Prop :=
(∀ x, ∃ t ∈ s, x ∈ t) ∧ ∀ t ∈ s, ∃ x ∈ t, ∀ y, y ∈ t ↔ is_conj x y

instance {α β : Type*} [group α] [group β] [decidable_eq β] (f : α → β) [is_group_hom f] :
  decidable_pred (is_group_hom.ker f) :=
λ _, decidable_of_iff _ (is_group_hom.mem_ker f).symm

def alternating (α : Type*) [decidable_eq α] [fintype α] : Type* :=
is_group_hom.ker (sign : perm α → units ℤ)

instance (α : Type*) [decidable_eq α] [fintype α] : decidable_eq (alternating α) :=
λ a b, decidable_of_iff (a.1 = b.1) (by cases a; cases b; simp [subtype.mk.inj_eq])

#print alternating.decidable_eq
#print subtype.decidable_eq

instance (α : Type*) [decidable_eq α] [fintype α] : fintype (alternating α) :=
set_fintype _

noncomputable def quotient_ker_equiv_range {α β : Type*} [group α] [group β] (f : α → β) [is_group_hom f] :
  (quotient_group.quotient (is_group_hom.ker f)) ≃ set.range f :=
@equiv.of_bijective _ _ (λ x, quotient.lift_on' x (λ a, show set.range f, from ⟨f a, a, rfl⟩)
  (λ a b (h : @setoid.r _ (quotient_group.left_rel (is_group_hom.ker f)) a b),
    have h : a⁻¹ * b ∈ is_group_hom.ker f, from h,
    subtype.eq
    (by rw [is_group_hom.mem_ker, is_group_hom.mul f,
        is_group_hom.inv f, inv_mul_eq_iff_eq_mul, mul_one] at h;
      simp [h])))
  ⟨λ a b, quotient.induction_on₂' a b
      (λ a b h, quotient.sound' (show a⁻¹ * b ∈ is_group_hom.ker f,
        by rw [is_group_hom.mem_ker, is_group_hom.mul f, is_group_hom.inv f,
          show f a = f b, from subtype.mk.inj h]; simp)),
    λ ⟨b, a, hab⟩, ⟨quotient_group.mk a, subtype.eq hab⟩⟩

noncomputable def quotient_ker_equiv_of_surjective {α β : Type*} [group α] [group β]
  (f : α → β) [is_group_hom f] (hf : function.surjective f) :
  (quotient_group.quotient (is_group_hom.ker f)) ≃ β :=
calc (quotient_group.quotient (is_group_hom.ker f)) ≃ set.range f : quotient_ker_equiv_range _
... ≃ β : ⟨λ a, a.1, λ b, ⟨b, hf b⟩, λ ⟨_, _⟩, rfl, λ _, rfl⟩

section classical

local attribute [instance] classical.prop_decidable

lemma sign_surjective {α : Type*} [decidable_eq α] [fintype α] (hα : 1 < fintype.card α) :
  function.surjective (sign : perm α → units ℤ) :=
λ a, (int.units_eq_one_or a).elim
  (λ h, ⟨1, by simp [h]⟩)
  (λ h, let ⟨x⟩ := fintype.card_pos_iff.1 (lt_trans zero_lt_one hα) in
    let ⟨y, hxy⟩ := fintype.exists_ne_of_card_gt_one hα x in
    ⟨swap y x, by rw [sign_swap hxy, h]⟩ )

lemma card_alternating (α : Type*) [decidable_eq α] [fintype α] (h : 2 ≤ fintype.card α):
  fintype.card (alternating α) * 2 = (fintype.card α).fact :=
have (quotient_group.quotient (is_group_hom.ker (sign : perm α → units ℤ))) ≃ units ℤ,
  from quotient_ker_equiv_of_surjective _ (sign_surjective h),
calc fintype.card (alternating α) * 2 = fintype.card (units ℤ × alternating α) :
  by rw [mul_comm, fintype.card_prod, fintype.card_units_int]
... = fintype.card (perm α) : fintype.card_congr
  (calc (units ℤ × alternating α) ≃
    (quotient_group.quotient (is_group_hom.ker (sign : perm α → units ℤ)) × alternating α)  :
      equiv.prod_congr this.symm (by refl)
  ... ≃ perm α : (group_equiv_quotient_times_subgroup _).symm)
... = (fintype.card α).fact : fintype.card_perm

instance (α : Type*) [decidable_eq α] [fintype α] : group (alternating α) :=
by unfold alternating; apply_instance

end classical

local notation `A5` := alternating (fin 5)
variables {α : Type*} [fintype α] [decidable_eq α]

section
local attribute [semireducible] reflected

-- meta instance (n : ℕ) : has_reflect (fin n) :=
-- nat.cases_on n (λ a, fin.elim0 a) $
-- λ n a, show reflected a, from `(@has_coe.coe ℕ (fin (nat.succ %%`(n))) _
--   (%%(nat.reflect a.1)))

-- meta instance (n : ℕ) (e : expr): has_reflect (fin n) :=
-- λ a, `(@fin.mk %%e %%(nat.reflect a.1) (of_as_true %%`(_root_.trivial)))

meta instance fin_reflect (n : ℕ) : has_reflect (fin n) :=
λ a, `(@fin.mk %%`(n) %%(nat.reflect a.1) (of_as_true %%`(_root_.trivial)))

-- λ a, expr.app (expr.app (expr.const `fin.mk []) `(a.1))
--   `(of_as_true trivial)

--#print fin.has_reflect
-- meta instance (n : ℕ) : has_reflect (perm (fin n)) :=
-- list.rec_on (quot.unquot (@univ (fin n) _).1)
--   (λ f, `(1 : perm (fin n)))
--   (λ x l ih f, let e : expr := ih (swap x (f x) * f) in
--     if x = f x then e
--     else if e = `(1 : perm (fin %%`(n)))
--     then `(@swap (fin %%`(n)) _ (%%`(x)) (%%(@reflect (fin n)
--       (f x) (fin.has_reflect n (f x)))))
--     else `(@swap (fin %%`(n)) _ (%%`(x)) (%%(@reflect (fin n)
--       (f x) (fin.has_reflect n (f x)))) * %%e))

meta instance fin_fun.has_reflect : has_reflect (fin 5 → fin 5) :=
list.rec_on (quot.unquot (@univ (fin 5) _).1)
  (λ f, `(λ y : fin 5, y))
  (λ x l ih f, let e := ih f in
    if f x = x then e
    else let ex := fin_reflect 5 x in
      let efx := fin_reflect 5 (f x) in
      if e = `(λ y : fin 5, y)
      then `(λ y : fin 5, ite.{1} (y = %%ex) (%%efx) y)
      else `(λ y : fin 5, ite.{1} (y = %%ex) (%%efx) ((%%e : fin 5 → fin 5) y)))
#print equiv.mk

instance {α β : Type*} [fintype α] [decidable_eq α] (f : α → β) (g : β → α) :
  decidable (function.right_inverse f g) :=
show decidable (∀ x, g (f x) = x), by apply_instance

instance {α β : Type*} [fintype β] [decidable_eq β] (f : α → β) (g : β → α) :
  decidable (function.left_inverse f g) :=
show decidable (∀ x, f (g x) = x), by apply_instance

meta instance : has_reflect (perm (fin 5)) :=
λ f, `(@equiv.mk.{1 1} (fin 5) (fin 5)
    %%(fin_fun.has_reflect f.to_fun)
  %%(fin_fun.has_reflect f.inv_fun)
  (of_as_true %%`(_root_.trivial)) (of_as_true %%`(_root_.trivial)))

#print is_group_hom.mem_ker

meta instance I4 : has_reflect (alternating (fin 5)) :=
λ f, `(@subtype.mk (perm (fin 5)) (is_group_hom.ker (sign : perm (fin 5) → units ℤ))
   %%(@reflect (perm (fin 5)) f.1 (equiv.perm.has_reflect f.1))
  ((is_group_hom.mem_ker sign).2 %%`(@eq.refl (units ℤ) 1)))

meta def afsf : has_reflect (list (list (list ℕ))) := by apply_instance
-- set_option pp.all true

instance f {α : Type*} [decidable_eq α] : decidable_pred (multiset.nodup : multiset α → Prop) :=
by apply_instance

meta instance multiset.has_reflect {α : Type} [reflected α] [has_reflect α] :
  has_reflect (multiset α) :=
λ s, let l : list α := quot.unquot s in `(@quotient.mk.{1} (list %%`(α)) _ %%`(l))

meta instance I1 : has_reflect (finset (alternating (fin 5) × alternating (fin 5))) :=
λ s, `(let t : multiset (alternating (fin 5) × alternating (fin 5)) := %%(multiset.has_reflect s.1) in
    @finset.mk.{0} (alternating (fin 5) × alternating (fin 5)) t (of_as_true %%`(_root_.trivial)))
--#print prod.has_reflect
meta instance I3 (a : alternating (fin 5)) :
  has_reflect {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1} :=
λ b, `(@subtype.mk (alternating (fin 5) × alternating (fin 5))
  (λ b, b.2 * %%`(a) * b.2⁻¹ = b.1)
  %%(prod.has_reflect _ _ b.1) (of_as_true %%`(_root_.trivial)))

meta instance I5 (a : alternating (fin 5)) (m : reflected a) :
  reflected {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1} :=
`({b : alternating (fin 5) × alternating (fin 5) // b.2 * %%m * b.2⁻¹ = b.1})

meta instance test : has_reflect (Σ n : ℕ, {m // m = n}) :=
λ x, `(@sigma.mk ℕ (λ n : ℕ, {m // m = n}) %%(nat.reflect (x.1 : ℕ))
  (subtype.mk %%(nat.reflect x.2.1) %%`(@eq.refl ℕ %%(nat.reflect x.1))))

def n : (Σ n : ℕ, {m // m = n}) :=
by thing (show Σ n : ℕ, {m // m = n}, from ⟨5, ⟨5, rfl⟩⟩)

#print n

meta instance I2 : has_reflect
  (Σ a : alternating (fin 5), finset
  {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1}) :=
λ s, let ra : reflected s.1 := (I4 s.1) in
  `(let a : alternating (fin 5) := %%ra in
  let t : multiset {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1} :=
    %%(@multiset.has_reflect _ (I5 s.1 ra) (I3 s.1) s.2.1) in
  @sigma.mk (alternating (fin 5))
    (λ a, finset {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1})
    a (finset.mk t (of_as_true %%`(_root_.trivial))))

meta instance I6 : has_reflect (finset
  (Σ a : alternating (fin 5), finset
  {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1})) :=
λ s, `(@finset.mk  (Σ a : alternating (fin 5), finset
  {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1})
  %%(@multiset.has_reflect _ _ I2 s.1)
  (of_as_true %%`(_root_.trivial)))

meta instance I7 : has_reflect
  (Σ a : alternating (fin 5), multiset
  {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1}) :=
λ s, let ra : reflected s.1 := (I4 s.1) in
`(let a : alternating (fin 5) := %%ra in
  @sigma.mk (alternating (fin 5))
    (λ a, multiset {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1})
    a %%(@multiset.has_reflect _ (I5 s.1 ra) (I3 s.1) s.2))

-- meta instance finset_finset.has_reflect (n : ℕ) : has_reflect (finset (finset (alternating (fin n)))) :=
-- λ s, `(let m : ℕ := %%`(n) in
--   let t : multiset (finset (alternating (fin m))) := %%(multiset.has_reflect s.1) in
--   @finset.mk.{0} (finset (alternating (fin m))) t (of_as_true %%`(_root_.trivial)))

-- instance afhasf (n : ℕ) : decidable_eq (finset (alternating (fin n) × alternating (fin n)) × alternating (fin n)) :=
--  by apply_instance

-- meta instance hklkhfhndihn (n : ℕ) : has_reflect
--   (finset (finset (alternating (fin n) × alternating (fin n)) × alternating (fin n))) :=
-- λ s, `(let m : ℕ := %%`(n) in
--   let t : multiset (finset (alternating (fin m) × alternating (fin m)) × alternating (fin m)) :=
--       %%(multiset.has_reflect s.1) in
--     @finset.mk.{0} (finset (alternating (fin m) × alternating (fin m)) × alternating (fin m)) t
--       (of_as_true %%`(_root_.trivial)))

end
#print expr
meta instance : has_reflect (list (list (perm (fin 5)))) := by apply_instance

 meta def whatever {α : Sort*} : α := whatever

-- meta def conjugacy_classes_A5_aux : list (alternating (fin 5)) → list (list (alternating (fin 5) ×
--   alternating (fin 5)) × alternating (fin 5))
-- | [] := ∅
-- | (a :: l) :=
-- let m := (((quot.unquot (@univ (alternating (fin 5)) _).1).map
--   (λ x, (x * a * x⁻¹, x))).pw_filter (λ x y, x.1 ≠ y.1), a)
--   in m :: conjugacy_classes_A5_aux (l.diff (list.map prod.fst m.1))

-- meta def whatever {α : Sort*} : α := whatever

-- meta def conjugacy_classes_A5 : finset (finset (alternating (fin 5) ×
--   alternating (fin 5)) × alternating (fin 5)) :=
-- finset.mk (↑((conjugacy_classes_A5_aux (quot.unquot univ.1)).map
--   (λ l : list (alternating (fin 5) ×
--     alternating (fin 5)) × alternating (fin 5),
--     show  finset (alternating (fin 5) ×
--      alternating (fin 5)) × alternating (fin 5),
--       from (finset.mk (↑l.1 : multiset _) whatever, l.2))) : multiset _) whatever
-- set_option profiler true

meta def conjugacy_classes_A5_meta_aux : list (alternating (fin 5)) → list
  (Σ a : alternating (fin 5), list
  {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1})
| [] := []
| (a :: l) := let m : Σ a : alternating (fin 5), list
    {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1} :=
  ⟨a, ((quot.unquot (@univ (alternating (fin 5)) _).1).map
  (λ x, show {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1},
    from ⟨(x * a * x⁻¹, x), rfl⟩)).pw_filter (λ x y, x.1.1 ≠ y.1.1)⟩ in
m :: conjugacy_classes_A5_meta_aux (l.diff (m.2.map (prod.fst ∘ subtype.val)))

meta def conjugacy_classes_A5_meta : multiset (Σ a : alternating (fin 5), multiset
  {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1}) :=
(quotient.mk ((conjugacy_classes_A5_meta_aux (quot.unquot univ.1)).map
    (λ a, ⟨a.1, (quotient.mk a.2)⟩)))

@[irreducible] def conjugacy_classes_A5_aux : multiset (Σ a : alternating (fin 5), multiset
  {b : alternating (fin 5) × alternating (fin 5) // b.2 * a * b.2⁻¹ = b.1}) :=
by thing (conjugacy_classes_A5_meta)
#print conjugacy_classes_A5_aux
def conjugacy_classes_A5_aux2 : multiset (multiset (alternating (fin 5))) :=
conjugacy_classes_A5_aux.map (λ s, s.2.map (λ b, b.1.1))

lemma nodup_conjugacy_classes_A5_aux2 : ∀ s : multiset (alternating (fin 5)),
  s ∈ conjugacy_classes_A5_aux2 → s.nodup :=
dec_trivial

def conjugacy_classes_A5 : finset (finset (alternating (fin 5))) :=
⟨conjugacy_classes_A5_aux2.pmap finset.mk nodup_conjugacy_classes_A5_aux2, dec_trivial⟩

lemma is_conj_conjugacy_classes_A5 (s : finset A5) (h : s ∈ conjugacy_classes_A5) :
  ∀ x y ∈ s, is_conj x y :=
assume x y hx hy,
begin
  simp only [conjugacy_classes_A5, finset.mem_def, multiset.mem_pmap,
    conjugacy_classes_A5_aux2] at h,
  rcases h with ⟨t, ht₁, ht₂⟩,
  rw [multiset.mem_map] at ht₁,
  rcases ht₁ with ⟨u, hu₁, hu₂⟩,
  have hx' : x ∈ multiset.map (λ (b : {b : A5 × A5 // b.2 * u.1 * b.2⁻¹ = b.1}), b.1.1) u.2,
  { simpa [ht₂.symm, hu₂] using hx },
  have hy' : y ∈ multiset.map (λ (b : {b : A5 × A5 // b.2 * u.1 * b.2⁻¹ = b.1}), b.1.1) u.2,
  { simpa [ht₂.symm, hu₂] using hy },
  cases multiset.mem_map.1 hx' with xc hxc,
  cases multiset.mem_map.1 hy' with yc hyc,
  exact is_conj_trans
    (is_conj_symm (show is_conj u.1 x, from hxc.2 ▸ ⟨_, xc.2⟩))
    (hyc.2 ▸ ⟨_, yc.2⟩)
end

lemma eq_bind_conjugacy_classes (s : finset (finset G))
  (h₁ : ∀ x, ∃ t ∈ s, x ∈ t)
  (h₂ : ∀ t ∈ s, ∀ x y ∈ t, is_conj x y) (I : finset G) [nI : normal_subgroup (↑I : set G)] :
  ∃ u ⊆ s, I = u.bind id :=
⟨(s.powerset.filter (λ u : finset (finset G), u.bind id ⊆ I)).bind id,
    (λ x, by simp only [finset.subset_iff, mem_bind, mem_filter, exists_imp_distrib, mem_powerset,
      and_imp, id.def] {contextual := tt}; tauto),
  le_antisymm
    (λ x hxI, let ⟨t, ht₁, ht₂⟩ := h₁ x in
      mem_bind.2 ⟨t, mem_bind.2 ⟨(s.powerset.filter (λ u : finset (finset G), u.bind id ⊆ I)).bind id,
          mem_filter.2 ⟨mem_powerset.2
            (λ u hu, let ⟨v, hv₁, hv₂⟩ := mem_bind.1 hu in
              mem_powerset.1 (mem_filter.1 hv₁).1 hv₂),
          λ y hy, let ⟨u, hu₁, hu₂⟩ := mem_bind.1 hy in
            let ⟨v, hv₁, hv₂⟩ := mem_bind.1 hu₁ in
            (mem_filter.1 hv₁).2 (mem_bind.2 ⟨u, hv₂, hu₂⟩)⟩,
        mem_bind.2 ⟨{t}, mem_filter.2 ⟨by simp [ht₁, finset.subset_iff],
            λ y hy, let ⟨u, hu₁, hu₂⟩ := mem_bind.1 hy in
              let ⟨z, hz⟩ := h₂ t ht₁ x y ht₂ (by simp * at *) in
              hz ▸ @normal_subgroup.normal G _ I.to_set nI _ hxI _⟩,
          by simp⟩⟩,
        ht₂⟩)
    (λ x, by simp only [finset.subset_iff, mem_bind, exists_imp_distrib, mem_filter, mem_powerset]; tauto)⟩

--local attribute [instance, priority 0] classical.dec

lemma simple_of_card_conjugacy_classes [fintype G] [decidable_eq G] (s : finset (finset G))
  (h₁ : ∀ x, ∃ t ∈ s, x ∈ t) (h₂ : ∀ t ∈ s, ∀ x y ∈ t, is_conj x y)
  (hs : (s.1.bind finset.val).nodup)
  (h₃ : ∀ t ≤ s.1.map finset.card, 1 ∈ t → t.sum ∣ fintype.card G → t.sum = 1 ∨ t.sum = fintype.card G) :
  simple_group G :=
by haveI := classical.dec; exact
⟨λ H iH,
  let I := (set.to_finset H) in
  have Ii : normal_subgroup (↑I : set G), by simpa using iH,
  let ⟨u, hu₁, hu₂⟩ :=
    @eq_bind_conjugacy_classes G _ _ _ s h₁ h₂ I Ii in
  have hInd : ∀ (x : finset G), x ∈ u → ∀ (y : finset G), y ∈ u → x ≠ y → id x ∩ id y = ∅,
    from λ x hxu y hyu hxy,
      begin
        rw multiset.nodup_bind at hs,
        rw [← finset.disjoint_iff_inter_eq_empty, finset.disjoint_left],
        exact multiset.forall_of_pairwise
          (λ (a b : finset G) (h : multiset.disjoint a.1 b.1),
          multiset.disjoint.symm h) hs.2 x (hu₁ hxu) y (hu₁ hyu) hxy
      end,
  have hci : card I = u.sum finset.card,
    by rw [hu₂, card_bind hInd]; refl,
  have hu1 : (1 : G) ∈ u.bind id, by exactI hu₂ ▸ is_submonoid.one_mem (↑I : set G),
  let ⟨v, hv₁, hv₂⟩ := mem_bind.1 hu1 in
  have hv : v = finset.singleton (1 : G),
    from finset.ext.2 $ λ a, ⟨λ hav, mem_singleton.2 $
        is_conj_one_right.1 (h₂ v (hu₁ hv₁) _ _ hv₂ hav),
      by simp [show (1 : G) ∈ v, from hv₂] {contextual := tt}⟩,
  have hci' : card I = 1 ∨ card I = fintype.card G,
    begin
      rw [hci],
      exact h₃ _ (multiset.map_le_map (show u.1 ≤ s.1,
        from (multiset.le_iff_subset u.2).2 hu₁))
          (multiset.mem_map.2 ⟨finset.singleton 1, hv ▸ hv₁, rfl⟩)
          (calc u.sum finset.card = card I : hci.symm
            ... = fintype.card (↑I : set G) : (set.card_fintype_of_finset' I (by simp)).symm
            ... ∣ fintype.card G : by exactI card_subgroup_dvd_card _)
    end,
    hci'.elim
      (λ hci', or.inl (set.ext (λ x,
        let ⟨y, hy⟩ := finset.card_eq_one.1 hci' in
        by resetI;
          simp only [I, finset.ext, set.mem_to_finset, finset.mem_singleton] at hy;
          simp [is_subgroup.mem_trivial, hy, (hy 1).1 (is_submonoid.one_mem H)])))
      (λ hci', or.inr $
        suffices I = finset.univ,
          by simpa [I, set.ext_iff, finset.ext] using this,
        finset.eq_of_subset_of_card_le (λ _, by simp) (by rw hci'; refl))⟩

lemma card_A5 : fintype.card A5 = 60 :=
(nat.mul_right_inj (show 2 > 0, from dec_trivial)).1 $
have 2 ≤ fintype.card (fin 5), from dec_trivial,
  by rw [card_alternating _ this]; simp; refl

lemma nodup_conjugacy_classes_A5_bind :
  (conjugacy_classes_A5.1.bind finset.val).nodup := dec_trivial

#eval (conjugacy_classes_A5.1.bind finset.val).card

lemma conjugacy_classes_A5_bind_eq_univ :
  conjugacy_classes_A5.bind (λ t, t) = univ :=
eq_of_subset_of_card_le (λ _, by simp)
  (calc card univ = 60 : card_A5
    ... = (conjugacy_classes_A5.bind id).card : dec_trivial
    ... ≤ _ : le_refl _)

lemma A5_simple : simple_group A5 :=
simple_of_card_conjugacy_classes conjugacy_classes_A5
  (λ x, mem_bind.1 $ by rw [conjugacy_classes_A5_bind_eq_univ]; simp)
  is_conj_conjugacy_classes_A5
  nodup_conjugacy_classes_A5_bind
  (by simp only [multiset.mem_powerset.symm, card_A5];
    exact dec_trivial)

#print axioms A5_simple

example : conj_classes_A5.1.map (finset.card ∘ prod.fst) = {1, 12, 12, 15, 20} := dec_trivial

--example : (@univ (alternating (fin 5))).nodup := dec_trivial

example : (conj_classes_A5.1.bind (λ s, s.1.1.map prod.fst)).nodup := dec_trivial

#eval (conj_classes_A5.1.bind (λ s, s.1.1.map prod.fst) = finset.univ.1 : bool)

--set_option class.instance_max_depth 100

instance alifha : decidable (∀ s : finset (alternating (fin 5) ×
  alternating (fin 5)) × alternating (fin 5), s ∈ conj_classes_A5 →
  ∀ (x : alternating (fin 5) × alternating (fin 5)), x ∈ s.1 →
  x.2 * s.2 * x.2⁻¹ = x.1) :=(@finset.decidable_dforall_finset _ conj_classes_A5
  (λ (s : finset (alternating (fin 5) ×
  alternating (fin 5)) × alternating (fin 5)) _,
  ∀ (x : alternating (fin 5) × alternating (fin 5)), x ∈ s.1 →
  x.2 * s.2 * x.2⁻¹ = x.1)
    (λ s hs, @finset.decidable_dforall_finset _ s.1 _ _))

#eval (∀ s : finset (alternating (fin 5) ×
  alternating (fin 5)) × alternating (fin 5), s ∈ conj_classes_A5 →
  ∀ (x : alternating (fin 5) × alternating (fin 5)), x ∈ s.1 →
  x.2 * s.2 * x.2⁻¹ = x.1 : bool)

def conj_classes_A5 : ∀ s : finset (alternating (fin 5) ×
  alternating (fin 5)) × alternating (fin 5), s ∈ conj_classes_A5 →
  ∀ (x : alternating (fin 5) × alternating (fin 5)), x ∈ s.1 →
  x.2 * s.2 * x.2⁻¹ = x.1 :=
dec_trivial

-- @of_as_true _ (@finset.decidable_dforall_finset _ conj_classes_A5
--   (λ (s : finset (alternating (fin 5) ×
--   alternating (fin 5)) × alternating (fin 5)) _,
--   ∀ (x : alternating (fin 5) × alternating (fin 5)), x ∈ s.1 →
--   x.2 * s.2 * x.2⁻¹ = x.1)
--     (λ s hs, @finset.decidable_dforall_finset _ s.1 _ _)) _root_.trivial

--example : multiset.nodup (@univ (alternating (fin 5)) _).1 := dec_trivial

--#eval x.map list.length

--#eval x.to_fun 3

#exit

set_option profiler true
#eval (conjugacy_classes' (alternating (fin 5))).1.map finset.card

instance : decidable_pred (is_cycle : perm α → Prop) :=
by dunfold is_cycle decidable_pred; apply_instance

local attribute [instance, priority 100] fintype_perm
local attribute [instance, priority 0] equiv.fintype
#print equiv.fintype

#eval (conjugacy_classes' (alternating (fin 5))).1.map finset.card

--example : (conjugacy_classes' (alternating (fin 5))).card = 5 := rfl

--#eval conjugacy_classes (quot.unquot (univ : finset (perm (fin 5))).1)


import analysis.topology.topological_structures
import ring_theory.subring
import tactic.tfae
import data.list.basic
import for_mathlib.topological_rings
import power_bounded

-- f-adic rings are called Huber rings by Scholze.
-- Topological ring A contains on open subring A0 such that the subspace topology on A0 is
-- I-adic, where I is a finitely generated ideal of A0 .

universe u

variables {A : Type u} [comm_ring A] [topological_space A] [topological_ring A]

def is_ring_of_definition (A₀ : set A) [is_subring A₀] : Prop :=
is_open A₀ ∧ (∃ (J : ideal A₀) (gen : set A₀), (set.finite gen ∧ ideal.span gen = J) ∧
(by haveI := topological_subring A₀; exact is-J-adic))

namespace is_ring_of_definition
open list

-- Wedhorn, lemma 6.2.
lemma tfae (A₀ : set A) [is_subring A₀] :
tfae [is_ring_of_definition A₀, (is_open A₀ ∧ is_adic A₀), (is_open A₀ ∧ is_bounded A₀)] :=
begin
  tfae_have : 1 → 2,
  { rintro ⟨hl, J, gen, hgen, h⟩,
    exact ⟨hl, ⟨J, h⟩⟩ },
  tfae_have : 2 → 3,
  { rintros ⟨hl, hr⟩,
    split, exact hl,
    intros U hU,
    rw nhds_sets at hU,
    rcases hU with ⟨U', U'_sub, ⟨U'_open, U'_0⟩⟩,
    rcases hr with ⟨J, h1, h2⟩,
    have H : (∃ (n : ℕ), (J^n).carrier ⊆ {a : A₀ | a.val ∈ U'}) :=
      h2 {a | a.val ∈ U'} U'_0 (continuous_subtype_val _ U'_open),
    rcases H with ⟨n, hn⟩,
    existsi subtype.val '' (J^n).carrier,  -- the key step
    split,
    { apply mem_nhds_sets,
      { refine embedding_open embedding_subtype_val _ (h1 n),
        rw set.subtype_val_range,
        exact hl },
      simp [(is_subring.to_is_add_subgroup A₀).zero_mem],
      exact (J^n).zero_mem },
    rintros a ⟨a₀, ha₀⟩ b hb,
    apply U'_sub,
    have : a₀.val * b ∈ U':= hn ((J^n).mul_mem_right ha₀.left : (a₀ * ⟨b,hb⟩) ∈ J^n),
    rwa ha₀.right at this },
  tfae_have : 3 → 1,
  { rintro ⟨hl, hr⟩,
    split, exact hl,
    sorry },
  tfae_finish
end

end is_ring_of_definition

class Huber_ring (A : Type u) extends comm_ring A, topological_space A, topological_ring A :=
(A₀ : set A)
[HA₀ : is_subring A₀]
(A₀_is_ring_of_definition : is_ring_of_definition A₀)

namespace Huber_ring

-- Wedhorn, lemma 6.1.
lemma tfae : (∃ U T : set A, T ⊆ U ∧ set.finite T ∧
(filter.generate {U' : set A | ∃ n : pnat, U' = {x | ∃ y ∈ U, y^(n:ℕ) = x}} = (nhds 0)) ∧
{y : A | ∃ (t ∈ T) (u ∈ U), y = t * u} = {y : A | ∃ (t ∈ U) (u ∈ U), y = t * u} ∧
{y : A | ∃ (t ∈ U) (u ∈ U), y = t * u} ⊆ U) ↔
(∃ (A₀ : set A) [h : is_subring A₀], by haveI := h; exact is_ring_of_definition A₀) :=
begin
  split,
  { rintro ⟨U, T, Tsub, Tfin, hnhds, hTU, hU2⟩,
    let W := add_group.closure U,
    have hU : is_open U,
    { -- is this provable, or should it have been an assumption?
      sorry },
    have hW : is_open W,
    { sorry },
    existsi (add_group.closure (W ∪ {1})),
    split,
    { split,
      sorry,
      sorry },
    { sorry } },
  { rintro ⟨A₀, hA₀, A₀_open, J, gen, hgen, h1, h2⟩,
    haveI := hA₀,
    use subtype.val '' J.carrier,
    existsi subtype.val '' gen,
    have gensubJ : subtype.val '' gen ⊆ subtype.val '' J.carrier,
    { have : gen ⊆ J,
      rw ← hgen.right,
      exact ideal.subset_span,
      rintros x ⟨x₀, hx1, hx2⟩,
      exact ⟨x₀, this hx1,hx2⟩ },
    refine ⟨gensubJ, set.finite_image _ hgen.left, _⟩,
    split,
    { apply le_antisymm,
      { sorry },
      { sorry } },
    split,
    { ext x, split;
      rintros ⟨t, ht, u, hu, H⟩,
      { exact ⟨t, (gensubJ ht), u, hu, H⟩ },
      sorry },
    { rintros x ⟨x₀, hx1, hx2⟩,
      sorry } }
end

variables [Huber_ring A]

instance power_bounded_add_subgroup : is_add_subgroup (power_bounded_subring A) :=
{ zero_mem := power_bounded.zero_mem A,
  add_mem := assume a b a_in b_in U U_nhds,begin
    sorry
  end,
  neg_mem := λ a, power_bounded.neg_mem A }

instance : is_subring (power_bounded_subring A) :=
{..power_bounded.submonoid A, ..Huber_ring.power_bounded_add_subgroup}

instance nat.power_bounded: has_coe ℕ (power_bounded_subring A) := ⟨nat.cast⟩

instance int.power_bounded: has_coe ℤ (power_bounded_subring A) := ⟨int.cast⟩
end Huber_ring


import Mt.System.Basic
import Mt.System.BasicAux
import Mt.System.Traced
import Mt.Utils.List

namespace Mt.System

variable {spec : Spec}
local instance : IsReservation spec.Reservation :=spec.is_reservation

open Utils

/-- Central validation predicate for reasoning about systems.

  A valid system has the following property: Given any future
  iteration of the system (or the system itself), the following
  holds:
  * No threads have panicked yet (and they never will)
  * Its current state is valid according to the specification
-/
def valid (s : System spec) : Prop :=
  ∀ s' : System spec, s.reduces_to_or_eq s' →
  s'.panics = 0 ∧ ∃ r, spec.validate r s'.state

theorem fundamental_validation_theorem (s : System spec)
  (no_panics_yet : s.panics = 0)
  (initial_valid : spec.validate IsReservation.empty s.state)
  (threads_valid : ∀ t, t ∈ s.threads → t.valid)
  : s.valid :=by
  intro s' s_to_s'
  cases s_to_s' <;> rename_i h
  . rw [<- h]
    exact ⟨no_panics_yet, IsReservation.empty, initial_valid⟩

  let traced := Traced.TracedSystem.mk_initial s
  have traced_valid : traced.valid :=
    Traced.TracedSystem.mk_initial.valid s initial_valid threads_valid

  suffices ∃ ts : Traced.TracedSystem spec, ts.to_system = s' ∧ ts.valid by
    cases this
    rename_i ts ts_hyp
    simp only [<- ts_hyp.left, Traced.TracedSystem.to_system, true_and]
    exists ts.reservations
    exact ts_hyp.right.currently_valid

  clear initial_valid threads_valid

  suffices
    ∀ ts : Traced.TracedSystem spec, ts.valid →
    s = ts.to_system → ∃ ts' : Traced.TracedSystem spec, ts'.to_system = s' ∧ ts'.valid by
    apply this traced traced_valid
    exact Eq.symm <| Traced.TracedSystem.mk_initial.cancels_to_system no_panics_yet

  clear traced traced_valid no_panics_yet
  induction h
  . clear s s' ; rename_i s s' idx iteration
    intro ts ts_valid s_def
    exact Traced.TracedSystem.valid_by_iteration s s' s_def ts_valid iteration
  . rename_i a b c _ _ IHab IHbc
    intro ts_a ts_a_valid ts_a_hyp
    cases IHab ts_a ts_a_valid ts_a_hyp
    rename_i ts_b ts_b_hyp
    apply IHbc ts_b
    . exact ts_b_hyp.right
    . exact ts_b_hyp.left.symm

end Mt.System


theorem proofOfFalse : False := Nat.zeroNeOne (Nat.mod_zero 1)