import data.real.basic

--OUTPUT 1
theorem nesbitt_inequality {a b c : ℝ} (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2) :=
begin
  -- $\dfrac a {b + c} + \dfrac b {a + c} + \dfrac c {a + b} \ge \dfrac 3 2$
  have h1 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2), from by {
    -- $\leadstoandfrom \dfrac {a + b + c} {b + c} + \dfrac {a + b + c} {a + c} + \dfrac {a + b + c} {a + b} \ge \dfrac 9 2$
    have h2 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (9 / 2), from by {
      calc (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (a + b + c) / (b + c) + (a + b + c) / (a + c) + (a + b + c) / (a + b) : by {
        apply add_le_add,
        apply add_le_add,
        apply add_le_add,
        apply div_le_div_of_le_of_pos,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
        apply add_le_add_left,
end --Needs more than 2000 tokens!

--OUTPUT 2
theorem nesbitt_inequality {a b c : ℝ} (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2) :=
begin
  -- $\dfrac a {b + c} + \dfrac b {a + c} + \dfrac c {a + b} \ge \dfrac 3 2$
  have h1 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2), from by {
    -- $\leadstoandfrom$
    have h2 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (9 / 2), from by {
      -- adding $3$
      have h3 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) = (a + b + c) / (b + c) + (a + b + c) / (a + c) + (a + b + c) / (a + b), from by {
        rw [div_add_div_same,div_add_div_same,div_add_div_same], ring,
      },
      -- as $\dfrac {a + b + c} {\paren {b + c} + \paren {a + c} + \paren {a + b} } = \dfrac 1 2$
      have h4 : (a + b + c) / (b + c) + (a + b + c) / (a + c) + (a + b + c) / (a + b) = (9 * (a + b + c)) / ((b + c) + (a + c) + (a + b)), from by {
        rw [div_add_div_same,div_add_div_same,div_add_div_same], ring,
      },
      -- dividing by $3 \paren {a + b + c}$
      have h5 : (9 * (a + b + c)) / ((b + c) + (a + c) + (a + b)) = (9 / 2), from by {
        rw [mul_comm,mul_div_assoc], ring,
      },
      show (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (9 / 2), from by {
        rw h3 at h4, rw h4 at h5, rw h5,
      },
    },
    -- These are the arithmetic mean and the harmonic mean of $\dfrac 1 {b + c}$, $\dfrac 1 {a + c}$ and $\dfrac 1 {a + b}$.
    have h6 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) = (1 / (b + c)) + (1 / (a + c)) + (1 / (a + b)) / 3, from by {
      rw [div_add_div_same,div_add_div_same,div_add_div_same], ring,
    },
    have h7 : (9 / 2) = (3 / ((b + c) + (a + c) + (a + b))), from by {
      rw [mul_comm,mul_div_assoc], ring,
    },
    -- From Arithmetic Mean is Never Less than Harmonic Mean the last inequality is true.
    have h8 : (1 / (b + c)) + (1 / (a + c)) + (1 / (a + b)) / 3 ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
      apply arithmetic_mean_never_less_than_harmonic_mean,
    },
    show (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2), from by {
      rw h6 at h2, rw h7 at h8, rw h8 at h2, rw h2,
    },
  },
  show (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2), from h1,
end

--OUTPUT 3
theorem nesbitt_inequality {a b c : ℝ} (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2) :=
begin
  -- $\dfrac a {b + c} + \dfrac b {a + c} + \dfrac c {a + b} \ge \dfrac 3 2$
  have h1 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2), from by {
    -- $\leadstoandfrom$
    have h2 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (9 / 2), from by {
      -- $\leadstoandfrom$
      have h3 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (9 / (2 * (b + c + a))), from by {
        -- $\leadstoandfrom$
        have h4 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
          -- $\leadstoandfrom$
          have h5 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
            -- $\leadstoandfrom$
            have h6 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
              -- $\leadstoandfrom$
              have h7 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                -- $\leadstoandfrom$
                have h8 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                  -- $\leadstoandfrom$
                  have h9 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                    -- $\leadstoandfrom$
                    have h10 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                      -- $\leadstoandfrom$
                      have h11 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                        -- $\leadstoandfrom$
                        have h12 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                          -- $\leadstoandfrom$
                          have h13 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                            -- $\leadstoandfrom$
                            have h14 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                              -- $\leadstoandfrom$
                              have h15 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                -- $\leadstoandfrom$
                                have h16 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                  -- $\leadstoandfrom$
                                  have h17 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                    -- $\leadstoandfrom$
                                    have h18 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                      -- $\leadstoandfrom$
                                      have h19 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                        -- $\leadstoandfrom$
                                        have h20 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                          -- $\leadstoandfrom$
                                          have h21 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                            -- $\leadstoandfrom$
                                            have h22 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                              -- $\leadstoandfrom$
                                              have h23 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                                -- $\leadstoandfrom$
                                                have h24 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                                  -- $\leadstoandfrom$
                                                  have h25 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                                    -- $\leadstoandfrom$
                                                    have h26 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                                      -- $\leadstoandfrom$
                                                      have h27 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                                        -- $\leadstoandfrom$
                                                        have h28 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                                          -- $\leadstoandfrom$
                                                          have h29 : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / ((b + c) + (a + c) + (a + b))), from by {
                                                            -- $\leadsto
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`
Nesbitt's inequality
Let $a$, $b$ and $c$ be positive real numbers.

Then:
:$\dfrac a {b + c} + \dfrac b {a + c} + \dfrac c {a + b} \ge \dfrac 3 2$

`proof`
{{begin-eqn}}
{{eqn | l = \frac a {b + c} + \frac b {a + c} + \frac c {a + b}
      | o = \ge
      | r = \dfrac 3 2
}}
{{eqn | ll= \leadstoandfrom
      | l = \frac {a + b + c} {b + c} + \frac {a + b + c} {a + c} + \frac {a + b + c} {a + b}
      | o = \ge
      | r = \frac 9 2
      | c = by adding $3$
}}
{{eqn | ll= \leadstoandfrom
      | l = \frac {a + b + c} {b + c} + \frac {a + b + c} {a + c} + \frac {a + b + c} {a + b}
      | o = \ge
      | r = \frac {9 \paren {a + b + c} } {\paren {b + c} + \paren {a + c} + \paren {a + b} }
      | c = as $\dfrac {a + b + c} {\paren {b + c} + \paren {a + c} + \paren {a + b} } = \dfrac 1 2$
}}
{{eqn | ll= \leadstoandfrom
      | l = \frac {\frac 1 {b + c} + \frac 1 {a + c} + \frac 1 {a + b} } 3
      | o = \ge
      | r = \frac 3 {\paren {b + c} + \paren {a + c} + \paren {a + b} }
      | c = dividing by $3 \paren {a + b + c}$
}}
{{end-eqn}}
These are the arithmetic mean and the harmonic mean of $\dfrac 1 {b + c}$, $\dfrac 1 {a + c}$ and $\dfrac 1 {a + b}$.

From Arithmetic Mean is Never Less than Harmonic Mean the last inequality is true.

Thus Nesbitt's Inequality holds.
{{qed}}

-/
theorem  nesbitt_inequality {a b c : ℝ} (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2) :=
FEW SHOT PROMPTS TO CODEX(END)-/


@[derive decidable_eq]
inductive N
| zero : N
| succ (n : N) : N

namespace N

instance : has_zero N := ⟨ N.zero ⟩
theorem zero_eq_zero : zero = 0 := rfl

def one : N := succ 0

instance : has_one N := ⟨ N.one ⟩
theorem one_eq_one : one = 1 := rfl

def nat_cast : ℕ -> N
| 0 := 0
| (nat.succ a) := succ (nat_cast a)

def to_N : N -> ℕ
| 0 := 0
| (N.succ a) := (to_N a) + 1

theorem eq (a : N) : a = a := rfl

theorem succ_eq (a b : N) : (succ a = succ b) -> (a = b) :=
begin
  intro h,
  cases h,
  refl,
end

theorem eq_succ (a b : N) : (a = b) -> (succ a = succ b) :=
begin
  intro h,
  cases h,
  refl,
end

theorem zero_neq_succ (a : N) : 0 ≠ succ a :=
begin
  intro h,
  cases h,
end

end N


/-
Copyright (c) 2021 Damiano Testa. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Damiano Testa

! This file was ported from Lean 3 source module algebra.covariant_and_contravariant
! leanprover-community/mathlib commit 2258b40dacd2942571c8ce136215350c702dc78f
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Algebra.Group.Defs
import Mathlib.Order.Basic
import Mathlib.Order.Monotone.Basic

/-!

# Covariants and contravariants

This file contains general lemmas and instances to work with the interactions between a relation and
an action on a Type.

The intended application is the splitting of the ordering from the algebraic assumptions on the
operations in the `Ordered[...]` hierarchy.

The strategy is to introduce two more flexible typeclasses, `CovariantClass` and
`ContravariantClass`:

* `CovariantClass` models the implication `a ≤ b → c * a ≤ c * b` (multiplication is monotone),
* `ContravariantClass` models the implication `a * b < a * c → b < c`.

Since `Co(ntra)variantClass` takes as input the operation (typically `(+)` or `(*)`) and the order
relation (typically `(≤)` or `(<)`), these are the only two typeclasses that I have used.

The general approach is to formulate the lemma that you are interested in and prove it, with the
`Ordered[...]` typeclass of your liking.  After that, you convert the single typeclass,
say `[OrderedCancelMonoid M]`, into three typeclasses, e.g.
`[LeftCancelSemigroup M] [PartialOrder M] [CovariantClass M M (Function.swap (*)) (≤)]`
and have a go at seeing if the proof still works!

Note that it is possible to combine several `Co(ntra)variantClass` assumptions together.
Indeed, the usual ordered typeclasses arise from assuming the pair
`[CovariantClass M M (*) (≤)] [ContravariantClass M M (*) (<)]`
on top of order/algebraic assumptions.

A formal remark is that normally `CovariantClass` uses the `(≤)`-relation, while
`ContravariantClass` uses the `(<)`-relation. This need not be the case in general, but seems to be
the most common usage. In the opposite direction, the implication
```lean
[Semigroup α] [PartialOrder α] [ContravariantClass α α (*) (≤)] => LeftCancelSemigroup α
```
holds -- note the `Co*ntra*` assumption on the `(≤)`-relation.

# Formalization notes

We stick to the convention of using `Function.swap (*)` (or `Function.swap (+)`), for the
typeclass assumptions, since `Function.swap` is slightly better behaved than `flip`.
However, sometimes as a **non-typeclass** assumption, we prefer `flip (*)` (or `flip (+)`),
as it is easier to use.

-/

-- TODO: convert `has_exists_mul_of_le`, `has_exists_add_of_le`?
-- TODO: relationship with `Con/AddCon`
-- TODO: include equivalence of `LeftCancelSemigroup` with
-- `Semigroup PartialOrder ContravariantClass α α (*) (≤)`?
-- TODO : use ⇒, as per Eric's suggestion?  See
-- https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/ordered.20stuff/near/236148738
-- for a discussion.
open Function

section Variants

variable {M N : Type _} (μ : M → N → N) (r : N → N → Prop)

variable (M N)

/-- `Covariant` is useful to formulate succintly statements about the interactions between an
action of a Type on another one and a relation on the acted-upon Type.

See the `CovariantClass` doc-string for its meaning. -/
def Covariant : Prop :=
  ∀ (m) {n₁ n₂}, r n₁ n₂ → r (μ m n₁) (μ m n₂)
#align covariant Covariant

/-- `Contravariant` is useful to formulate succintly statements about the interactions between an
action of a Type on another one and a relation on the acted-upon Type.

See the `ContravariantClass` doc-string for its meaning. -/
def Contravariant : Prop :=
  ∀ (m) {n₁ n₂}, r (μ m n₁) (μ m n₂) → r n₁ n₂
#align contravariant Contravariant

/-- Given an action `μ` of a Type `M` on a Type `N` and a relation `r` on `N`, informally, the
`CovariantClass` says that "the action `μ` preserves the relation `r`."

More precisely, the `CovariantClass` is a class taking two Types `M N`, together with an "action"
`μ : M → N → N` and a relation `r : N → N → Prop`.  Its unique field `elim` is the assertion that
for all `m ∈ M` and all elements `n₁, n₂ ∈ N`, if the relation `r` holds for the pair
`(n₁, n₂)`, then, the relation `r` also holds for the pair `(μ m n₁, μ m n₂)`,
obtained from `(n₁, n₂)` by acting upon it by `m`.

If `m : M` and `h : r n₁ n₂`, then `CovariantClass.elim m h : r (μ m n₁) (μ m n₂)`.
-/
class CovariantClass : Prop where
  /-- For all `m ∈ M` and all elements `n₁, n₂ ∈ N`, if the relation `r` holds for the pair
  `(n₁, n₂)`, then, the relation `r` also holds for the pair `(μ m n₁, μ m n₂)` -/
  protected elim : Covariant M N μ r
#align covariant_class CovariantClass

/-- Given an action `μ` of a Type `M` on a Type `N` and a relation `r` on `N`, informally, the
`ContravariantClass` says that "if the result of the action `μ` on a pair satisfies the
relation `r`, then the initial pair satisfied the relation `r`."

More precisely, the `ContravariantClass` is a class taking two Types `M N`, together with an
"action" `μ : M → N → N` and a relation `r : N → N → Prop`.  Its unique field `elim` is the
assertion that for all `m ∈ M` and all elements `n₁, n₂ ∈ N`, if the relation `r` holds for the
pair `(μ m n₁, μ m n₂)` obtained from `(n₁, n₂)` by acting upon it by `m`, then, the relation
`r` also holds for the pair `(n₁, n₂)`.

If `m : M` and `h : r (μ m n₁) (μ m n₂)`, then `ContravariantClass.elim m h : r n₁ n₂`.
-/
class ContravariantClass : Prop where
  /-- For all `m ∈ M` and all elements `n₁, n₂ ∈ N`, if the relation `r` holds for the
  pair `(μ m n₁, μ m n₂)` obtained from `(n₁, n₂)` by acting upon it by `m`, then, the relation
  `r` also holds for the pair `(n₁, n₂)`. -/
  protected elim : Contravariant M N μ r
#align contravariant_class ContravariantClass

theorem rel_iff_cov [CovariantClass M N μ r] [ContravariantClass M N μ r] (m : M) {a b : N} :
    r (μ m a) (μ m b) ↔ r a b :=
  ⟨ContravariantClass.elim _, CovariantClass.elim _⟩
#align rel_iff_cov rel_iff_cov

section flip

variable {M N μ r}

theorem Covariant.flip (h : Covariant M N μ r) : Covariant M N μ (flip r) :=
  fun a _ _ hbc ↦ h a hbc
#align covariant.flip Covariant.flip

theorem Contravariant.flip (h : Contravariant M N μ r) : Contravariant M N μ (flip r) :=
  fun a _ _ hbc ↦ h a hbc
#align contravariant.flip Contravariant.flip

end flip

section Covariant

variable {M N μ r} [CovariantClass M N μ r]

theorem act_rel_act_of_rel (m : M) {a b : N} (ab : r a b) : r (μ m a) (μ m b) :=
  CovariantClass.elim _ ab
#align act_rel_act_of_rel act_rel_act_of_rel

@[to_additive]
theorem Group.covariant_iff_contravariant [Group N] :
    Covariant N N (· * ·) r ↔ Contravariant N N (· * ·) r := by
  refine ⟨fun h a b c bc ↦ ?_, fun h a b c bc ↦ ?_⟩
  · rw [← inv_mul_cancel_left a b, ← inv_mul_cancel_left a c]
    exact h a⁻¹ bc
  · rw [← inv_mul_cancel_left a b, ← inv_mul_cancel_left a c] at bc
    exact h a⁻¹ bc
#align group.covariant_iff_contravariant Group.covariant_iff_contravariant
#align add_group.covariant_iff_contravariant AddGroup.covariant_iff_contravariant

@[to_additive]
instance (priority := 100) Group.covconv [Group N] [CovariantClass N N (· * ·) r] :
    ContravariantClass N N (· * ·) r :=
  ⟨Group.covariant_iff_contravariant.mp CovariantClass.elim⟩

@[to_additive]
theorem Group.covariant_swap_iff_contravariant_swap [Group N] :
    Covariant N N (swap (· * ·)) r ↔ Contravariant N N (swap (· * ·)) r := by
  refine ⟨fun h a b c bc ↦ ?_, fun h a b c bc ↦ ?_⟩
  · rw [← mul_inv_cancel_right b a, ← mul_inv_cancel_right c a]
    exact h a⁻¹ bc
  · rw [← mul_inv_cancel_right b a, ← mul_inv_cancel_right c a] at bc
    exact h a⁻¹ bc
#align group.covariant_swap_iff_contravariant_swap Group.covariant_swap_iff_contravariant_swap
#align add_group.covariant_swap_iff_contravariant_swap AddGroup.covariant_swap_iff_contravariant_swap

@[to_additive]
instance (priority := 100) Group.covconv_swap [Group N] [CovariantClass N N (swap (· * ·)) r] :
    ContravariantClass N N (swap (· * ·)) r :=
  ⟨Group.covariant_swap_iff_contravariant_swap.mp CovariantClass.elim⟩

section Trans

variable [IsTrans N r] (m n : M) {a b c d : N}

--  Lemmas with 3 elements.
theorem act_rel_of_rel_of_act_rel (ab : r a b) (rl : r (μ m b) c) : r (μ m a) c :=
  _root_.trans (act_rel_act_of_rel m ab) rl
#align act_rel_of_rel_of_act_rel act_rel_of_rel_of_act_rel

theorem rel_act_of_rel_of_rel_act (ab : r a b) (rr : r c (μ m a)) : r c (μ m b) :=
  _root_.trans rr (act_rel_act_of_rel _ ab)
#align rel_act_of_rel_of_rel_act rel_act_of_rel_of_rel_act

end Trans

end Covariant

--  Lemma with 4 elements.
section MEqN

variable {M N μ r} {mu : N → N → N} [IsTrans N r] [i : CovariantClass N N mu r]
  [i' : CovariantClass N N (swap mu) r] {a b c d : N}

theorem act_rel_act_of_rel_of_rel (ab : r a b) (cd : r c d) : r (mu a c) (mu b d) :=
  _root_.trans (@act_rel_act_of_rel _ _ (swap mu) r _ c _ _ ab) (act_rel_act_of_rel b cd)
#align act_rel_act_of_rel_of_rel act_rel_act_of_rel_of_rel

end MEqN

section Contravariant

variable {M N μ r} [ContravariantClass M N μ r]

theorem rel_of_act_rel_act (m : M) {a b : N} (ab : r (μ m a) (μ m b)) : r a b :=
  ContravariantClass.elim _ ab
#align rel_of_act_rel_act rel_of_act_rel_act

section Trans

variable [IsTrans N r] (m n : M) {a b c d : N}

--  Lemmas with 3 elements.
theorem act_rel_of_act_rel_of_rel_act_rel (ab : r (μ m a) b) (rl : r (μ m b) (μ m c)) :
    r (μ m a) c :=
  _root_.trans ab (rel_of_act_rel_act m rl)
#align act_rel_of_act_rel_of_rel_act_rel act_rel_of_act_rel_of_rel_act_rel

theorem rel_act_of_act_rel_act_of_rel_act (ab : r (μ m a) (μ m b)) (rr : r b (μ m c)) :
    r a (μ m c) :=
  _root_.trans (rel_of_act_rel_act m ab) rr
#align rel_act_of_act_rel_act_of_rel_act rel_act_of_act_rel_act_of_rel_act

end Trans

end Contravariant

section Monotone

variable {α : Type _} {M N μ} [Preorder α] [Preorder N]

variable {f : N → α}

/-- The partial application of a constant to a covariant operator is monotone. -/
theorem Covariant.monotone_of_const [CovariantClass M N μ (· ≤ ·)] (m : M) : Monotone (μ m) :=
  fun _ _ ha ↦ CovariantClass.elim m ha
#align covariant.monotone_of_const Covariant.monotone_of_const

/-- A monotone function remains monotone when composed with the partial application
of a covariant operator. E.g., `∀ (m : ℕ), Monotone f → Monotone (λ n, f (m + n))`. -/
theorem Monotone.covariant_of_const [CovariantClass M N μ (· ≤ ·)] (hf : Monotone f) (m : M) :
    Monotone fun n ↦ f (μ m n) :=
  fun _ _ x ↦ hf (Covariant.monotone_of_const m x)
#align monotone.covariant_of_const Monotone.covariant_of_const

/-- Same as `Monotone.covariant_of_const`, but with the constant on the other side of
the operator.  E.g., `∀ (m : ℕ), monotone f → monotone (λ n, f (n + m))`. -/
theorem Monotone.covariant_of_const' {μ : N → N → N} [CovariantClass N N (swap μ) (· ≤ ·)]
    (hf : Monotone f) (m : N) : Monotone fun n ↦ f (μ n m) :=
  fun _ _ x ↦ hf (@Covariant.monotone_of_const _ _ (swap μ) _ _ m _ _ x)
#align monotone.covariant_of_const' Monotone.covariant_of_const'

/-- Dual of `Monotone.covariant_of_const` -/
theorem Antitone.covariant_of_const [CovariantClass M N μ (· ≤ ·)] (hf : Antitone f) (m : M) :
    Antitone fun n ↦ f (μ m n) :=
  hf.comp_monotone <| Covariant.monotone_of_const m
#align antitone.covariant_of_const Antitone.covariant_of_const

/-- Dual of `Monotone.covariant_of_const'` -/
theorem Antitone.covariant_of_const' {μ : N → N → N} [CovariantClass N N (swap μ) (· ≤ ·)]
    (hf : Antitone f) (m : N) : Antitone fun n ↦ f (μ n m) :=
  hf.comp_monotone <| @Covariant.monotone_of_const _ _ (swap μ) _ _ m
#align antitone.covariant_of_const' Antitone.covariant_of_const'

end Monotone

theorem covariant_le_of_covariant_lt [PartialOrder N] :
    Covariant M N μ (· < ·) → Covariant M N μ (· ≤ ·) := by
  intro h a b c bc
  rcases le_iff_eq_or_lt.mp bc with (rfl | bc)
  · exact rfl.le
  · exact (h _ bc).le
#align covariant_le_of_covariant_lt covariant_le_of_covariant_lt

theorem contravariant_lt_of_contravariant_le [PartialOrder N] :
    Contravariant M N μ (· ≤ ·) → Contravariant M N μ (· < ·) := by
  refine fun h a b c bc ↦ lt_iff_le_and_ne.mpr ⟨h a bc.le, ?_⟩
  rintro rfl; exact lt_irrefl _ bc
#align contravariant_lt_of_contravariant_le contravariant_lt_of_contravariant_le

theorem covariant_le_iff_contravariant_lt [LinearOrder N] :
    Covariant M N μ (· ≤ ·) ↔ Contravariant M N μ (· < ·) :=
  ⟨fun h _ _ _ bc ↦ not_le.mp fun k ↦ not_le.mpr bc (h _ k),
   fun h _ _ _ bc ↦ not_lt.mp fun k ↦ not_lt.mpr bc (h _ k)⟩
#align covariant_le_iff_contravariant_lt covariant_le_iff_contravariant_lt

theorem covariant_lt_iff_contravariant_le [LinearOrder N] :
    Covariant M N μ (· < ·) ↔ Contravariant M N μ (· ≤ ·) :=
  ⟨fun h _ _ _ bc ↦ not_lt.mp fun k ↦ not_lt.mpr bc (h _ k),
   fun h _ _ _ bc ↦ not_le.mp fun k ↦ not_le.mpr bc (h _ k)⟩
#align covariant_lt_iff_contravariant_le covariant_lt_iff_contravariant_le

-- Porting note: `covariant_flip_mul_iff` used to use the `IsSymmOp` typeclass from Lean 3 core.
-- To avoid it, we prove the relevant lemma here.
@[to_additive]
lemma flip_mul [CommSemigroup N] : (flip (· * ·) : N → N → N) = (· * ·) :=
  funext fun a ↦ funext fun b ↦ mul_comm b a

@[to_additive]
theorem covariant_flip_mul_iff [CommSemigroup N] :
    Covariant N N (flip (· * ·)) r ↔ Covariant N N (· * ·) r := by rw [flip_mul]
#align covariant_flip_mul_iff covariant_flip_mul_iff
#align covariant_flip_add_iff covariant_flip_add_iff

@[to_additive]
theorem contravariant_flip_mul_iff [CommSemigroup N] :
    Contravariant N N (flip (· * ·)) r ↔ Contravariant N N (· * ·) r := by rw [flip_mul]
#align contravariant_flip_mul_iff contravariant_flip_mul_iff
#align contravariant_flip_add_iff contravariant_flip_add_iff

@[to_additive]
instance contravariant_mul_lt_of_covariant_mul_le [Mul N] [LinearOrder N]
    [CovariantClass N N (· * ·) (· ≤ ·)] : ContravariantClass N N (· * ·) (· < ·) where
  elim := (covariant_le_iff_contravariant_lt N N (· * ·)).mp CovariantClass.elim

@[to_additive]
instance covariant_mul_lt_of_contravariant_mul_le [Mul N] [LinearOrder N]
    [ContravariantClass N N (· * ·) (· ≤ ·)] : CovariantClass N N (· * ·) (· < ·) where
  elim := (covariant_lt_iff_contravariant_le N N (· * ·)).mpr ContravariantClass.elim

@[to_additive]
instance covariant_swap_mul_le_of_covariant_mul_le [CommSemigroup N] [LE N]
    [CovariantClass N N (· * ·) (· ≤ ·)] : CovariantClass N N (swap (· * ·)) (· ≤ ·) where
  elim := (covariant_flip_mul_iff N (· ≤ ·)).mpr CovariantClass.elim

@[to_additive]
instance contravariant_swap_mul_le_of_contravariant_mul_le [CommSemigroup N] [LE N]
    [ContravariantClass N N (· * ·) (· ≤ ·)] : ContravariantClass N N (swap (· * ·)) (· ≤ ·) where
  elim := (contravariant_flip_mul_iff N (· ≤ ·)).mpr ContravariantClass.elim

@[to_additive]
instance contravariant_swap_mul_lt_of_contravariant_mul_lt [CommSemigroup N] [LT N]
    [ContravariantClass N N (· * ·) (· < ·)] : ContravariantClass N N (swap (· * ·)) (· < ·) where
  elim := (contravariant_flip_mul_iff N (· < ·)).mpr ContravariantClass.elim

@[to_additive]
instance covariant_swap_mul_lt_of_covariant_mul_lt [CommSemigroup N] [LT N]
    [CovariantClass N N (· * ·) (· < ·)] : CovariantClass N N (swap (· * ·)) (· < ·) where
  elim := (covariant_flip_mul_iff N (· < ·)).mpr CovariantClass.elim

@[to_additive]
instance LeftCancelSemigroup.covariant_mul_lt_of_covariant_mul_le [LeftCancelSemigroup N]
    [PartialOrder N] [CovariantClass N N (· * ·) (· ≤ ·)] :
    CovariantClass N N (· * ·) (· < ·) where
  elim a b c bc := by
    cases' lt_iff_le_and_ne.mp bc with bc cb
    exact lt_iff_le_and_ne.mpr ⟨CovariantClass.elim a bc, (mul_ne_mul_right a).mpr cb⟩

@[to_additive]
instance RightCancelSemigroup.covariant_swap_mul_lt_of_covariant_swap_mul_le
    [RightCancelSemigroup N] [PartialOrder N] [CovariantClass N N (swap (· * ·)) (· ≤ ·)] :
    CovariantClass N N (swap (· * ·)) (· < ·) where
  elim a b c bc := by
    cases' lt_iff_le_and_ne.mp bc with bc cb
    exact lt_iff_le_and_ne.mpr ⟨CovariantClass.elim a bc, (mul_ne_mul_left a).mpr cb⟩

@[to_additive]
instance LeftCancelSemigroup.contravariant_mul_le_of_contravariant_mul_lt [LeftCancelSemigroup N]
    [PartialOrder N] [ContravariantClass N N (· * ·) (· < ·)] :
    ContravariantClass N N (· * ·) (· ≤ ·) where
  elim a b c bc := by
    cases' le_iff_eq_or_lt.mp bc with h h
    · exact ((mul_right_inj a).mp h).le
    · exact (ContravariantClass.elim _ h).le

@[to_additive]
instance RightCancelSemigroup.contravariant_swap_mul_le_of_contravariant_swap_mul_lt
    [RightCancelSemigroup N] [PartialOrder N] [ContravariantClass N N (swap (· * ·)) (· < ·)] :
    ContravariantClass N N (swap (· * ·)) (· ≤ ·) where
  elim a b c bc := by
    cases' le_iff_eq_or_lt.mp bc with h h
    · exact ((mul_left_inj a).mp h).le
    · exact (ContravariantClass.elim _ h).le

end Variants


/-
Copyright (c) 2019 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Mario Carneiro
-/

import data.rat.order
import data.int.sqrt
/-!
# Square root on rational numbers

This file defines the square root function on rational numbers `rat.sqrt`
and proves several theorems about it.

-/
namespace rat

/-- Square root function on rational numbers, defined by taking the (integer) square root of the
numerator and the square root (on natural numbers) of the denominator. -/
@[pp_nodot] def sqrt (q : ℚ) : ℚ := rat.mk (int.sqrt q.num) (nat.sqrt q.denom)

theorem sqrt_eq (q : ℚ) : rat.sqrt (q*q) = abs q :=
by rw [sqrt, mul_self_num, mul_self_denom, int.sqrt_eq, nat.sqrt_eq, abs_def]

theorem exists_mul_self (x : ℚ) : (∃ q, q * q = x) ↔ rat.sqrt x * rat.sqrt x = x :=
⟨λ ⟨n, hn⟩, by rw [← hn, sqrt_eq, abs_mul_abs_self],
λ h, ⟨rat.sqrt x, h⟩⟩

theorem sqrt_nonneg (q : ℚ) : 0 ≤ rat.sqrt q :=
nonneg_iff_zero_le.1 $ (mk_nonneg _ $ int.coe_nat_pos.2 $
nat.pos_of_ne_zero $ λ H, pos_iff_ne_zero.1 q.pos $ nat.sqrt_eq_zero.1 H).2
$ int.coe_nat_nonneg _

end rat


/-
Copyright (c) 2022 Aaron Anderson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Aaron Anderson
-/
import model_theory.semantics

/-!
# Ordered First-Ordered Structures
This file defines ordered first-order languages and structures, as well as their theories.

## Main Definitions
* `first_order.language.order` is the language consisting of a single relation representing `≤`.
* `first_order.language.order_Structure` is the structure on an ordered type, assigning the symbol
representing `≤` to the actual relation `≤`.
* `first_order.language.is_ordered` points out a specific symbol in a language as representing `≤`.
* `first_order.language.ordered_structure` indicates that the `≤` symbol in an ordered language
is interpreted as the actual relation `≤` in a particular structure.
* `first_order.language.linear_order_theory` and similar define the theories of preorders,
partial orders, and linear orders.
* `first_order.language.DLO` defines the theory of dense linear orders without endpoints, a
particularly useful example in model theory.

## Main Results
* `partial_order`s model the theory of partial orders, `linear_order`s model the theory of
linear orders, and dense linear orders without endpoints model `Theory.DLO`.

-/

universes u v w w'

namespace first_order
namespace language
open_locale first_order
open Structure

variables {L : language.{u v}} {α : Type w} {M : Type w'} {n : ℕ}

/-- The language consisting of a single relation representing `≤`. -/
protected def order : language :=
language.mk₂ empty empty empty empty unit

instance order_Structure [has_le M] : language.order.Structure M :=
Structure.mk₂ empty.elim empty.elim empty.elim empty.elim (λ _, (≤))

namespace order

instance : is_relational (language.order) := language.is_relational_mk₂

instance : subsingleton (language.order.relations n) :=
language.subsingleton_mk₂_relations

end order

/-- A language is ordered if it has a symbol representing `≤`. -/
class is_ordered (L : language.{u v}) := (le_symb : L.relations 2)

export is_ordered (le_symb)

section is_ordered

variables [is_ordered L]

/-- Joins two terms `t₁, t₂` in a formula representing `t₁ ≤ t₂`. -/
def term.le (t₁ t₂ : L.term (α ⊕ fin n)) : L.bounded_formula α n :=
le_symb.bounded_formula₂ t₁ t₂

/-- Joins two terms `t₁, t₂` in a formula representing `t₁ < t₂`. -/
def term.lt (t₁ t₂ : L.term (α ⊕ fin n)) : L.bounded_formula α n :=
(t₁.le t₂) ⊓ ∼ (t₂.le t₁)

variable (L)

/-- The language homomorphism sending the unique symbol `≤` of `language.order` to `≤` in an ordered
 language. -/
def order_Lhom : language.order →ᴸ L :=
Lhom.mk₂ empty.elim empty.elim empty.elim empty.elim (λ _, le_symb)

end is_ordered

instance : is_ordered language.order := ⟨unit.star⟩

@[simp] lemma order_Lhom_le_symb [L.is_ordered] :
  (order_Lhom L).on_relation le_symb = (le_symb : L.relations 2) := rfl

@[simp]
lemma order_Lhom_order : order_Lhom language.order = Lhom.id language.order :=
Lhom.funext (subsingleton.elim _ _) (subsingleton.elim _ _)

instance : is_ordered (L.sum language.order) := ⟨sum.inr is_ordered.le_symb⟩

section
variables (L) [is_ordered L]

/-- The theory of preorders. -/
def preorder_theory : L.Theory :=
{le_symb.reflexive, le_symb.transitive}

/-- The theory of partial orders. -/
def partial_order_theory : L.Theory :=
{le_symb.reflexive, le_symb.antisymmetric, le_symb.transitive}

/-- The theory of linear orders. -/
def linear_order_theory : L.Theory :=
{le_symb.reflexive, le_symb.antisymmetric, le_symb.transitive, le_symb.total}

/-- A sentence indicating that an order has no top element:
$\forall x, \exists y, \neg y \le x$.   -/
def no_top_order_sentence : L.sentence := ∀' ∃' ∼ ((&1).le &0)

/-- A sentence indicating that an order has no bottom element:
$\forall x, \exists y, \neg x \le y$. -/
def no_bot_order_sentence : L.sentence := ∀' ∃' ∼ ((&0).le &1)

/-- A sentence indicating that an order is dense:
$\forall x, \forall y, x < y \to \exists z, x < z \wedge z < y$. -/
def densely_ordered_sentence : L.sentence :=
∀' ∀' (((&0).lt &1) ⟹ (∃' (((&0).lt &2) ⊓ ((&2).lt &1))))

/-- The theory of dense linear orders without endpoints. -/
def DLO : L.Theory :=
L.linear_order_theory ∪
  {L.no_top_order_sentence, L.no_bot_order_sentence, L.densely_ordered_sentence}

end

variables (L M)

/-- A structure is ordered if its language has a `≤` symbol whose interpretation is -/
abbreviation ordered_structure [is_ordered L] [has_le M] [L.Structure M] : Prop :=
Lhom.is_expansion_on (order_Lhom L) M

variables {L M}

@[simp] lemma ordered_structure_iff [is_ordered L] [has_le M] [L.Structure M] :
  L.ordered_structure M ↔ Lhom.is_expansion_on (order_Lhom L) M := iff.rfl

instance ordered_structure_has_le [has_le M] :
  ordered_structure language.order M :=
begin
  rw [ordered_structure_iff, order_Lhom_order],
  exact Lhom.id_is_expansion_on M,
end

instance model_preorder [preorder M] :
  M ⊨ language.order.preorder_theory :=
begin
  simp only [preorder_theory, Theory.model_iff, set.mem_insert_iff, set.mem_singleton_iff,
    forall_eq_or_imp, relations.realize_reflexive, rel_map_apply₂, forall_eq,
    relations.realize_transitive],
  exact ⟨le_refl, λ _ _ _, le_trans⟩
end

instance model_partial_order [partial_order M] :
  M ⊨ language.order.partial_order_theory :=
begin
  simp only [partial_order_theory, Theory.model_iff, set.mem_insert_iff, set.mem_singleton_iff,
    forall_eq_or_imp, relations.realize_reflexive, rel_map_apply₂, relations.realize_antisymmetric,
    forall_eq, relations.realize_transitive],
  exact ⟨le_refl, λ _ _, le_antisymm, λ _ _ _, le_trans⟩,
end

instance model_linear_order [linear_order M] :
  M ⊨ language.order.linear_order_theory :=
begin
  simp only [linear_order_theory, Theory.model_iff, set.mem_insert_iff, set.mem_singleton_iff,
    forall_eq_or_imp, relations.realize_reflexive, rel_map_apply₂, relations.realize_antisymmetric,
    relations.realize_transitive, forall_eq, relations.realize_total],
  exact ⟨le_refl, λ _ _, le_antisymm, λ _ _ _, le_trans, le_total⟩,
end

section ordered_structure
variables [is_ordered L] [L.Structure M]

@[simp] lemma rel_map_le_symb [has_le M] [L.ordered_structure M] {a b : M} :
  rel_map (le_symb : L.relations 2) ![a, b] ↔ a ≤ b :=
begin
  rw [← order_Lhom_le_symb, Lhom.map_on_relation],
  refl,
end

@[simp] lemma term.realize_le [has_le M] [L.ordered_structure M]
  {t₁ t₂ : L.term (α ⊕ fin n)} {v : α → M} {xs : fin n → M} :
  (t₁.le t₂).realize v xs ↔ t₁.realize (sum.elim v xs) ≤ t₂.realize (sum.elim v xs) :=
by simp [term.le]

@[simp] lemma term.realize_lt [preorder M] [L.ordered_structure M]
  {t₁ t₂ : L.term (α ⊕ fin n)} {v : α → M} {xs : fin n → M} :
  (t₁.lt t₂).realize v xs ↔ t₁.realize (sum.elim v xs) < t₂.realize (sum.elim v xs) :=
by simp [term.lt, lt_iff_le_not_le]

end ordered_structure

section has_le
variables [has_le M]

theorem realize_no_top_order_iff : M ⊨ language.order.no_top_order_sentence ↔ no_top_order M :=
begin
  simp only [no_top_order_sentence, sentence.realize, formula.realize, bounded_formula.realize_all,
    bounded_formula.realize_ex, bounded_formula.realize_not, realize, term.realize_le,
    sum.elim_inr],
  refine ⟨λ h, ⟨λ a, h a⟩, _⟩,
  introsI h a,
  exact exists_not_le a,
end

@[simp] lemma realize_no_top_order [h : no_top_order M] :
  M ⊨ language.order.no_top_order_sentence :=
realize_no_top_order_iff.2 h

theorem realize_no_bot_order_iff : M ⊨ language.order.no_bot_order_sentence ↔ no_bot_order M :=
begin
  simp only [no_bot_order_sentence, sentence.realize, formula.realize, bounded_formula.realize_all,
    bounded_formula.realize_ex, bounded_formula.realize_not, realize, term.realize_le,
    sum.elim_inr],
  refine ⟨λ h, ⟨λ a, h a⟩, _⟩,
  introsI h a,
  exact exists_not_ge a,
end

@[simp] lemma realize_no_bot_order [h : no_bot_order M] :
  M ⊨ language.order.no_bot_order_sentence :=
realize_no_bot_order_iff.2 h

end has_le

theorem realize_densely_ordered_iff [preorder M] :
  M ⊨ language.order.densely_ordered_sentence ↔ densely_ordered M :=
begin
  simp only [densely_ordered_sentence, sentence.realize, formula.realize,
    bounded_formula.realize_imp, bounded_formula.realize_all, realize, term.realize_lt,
    sum.elim_inr, bounded_formula.realize_ex, bounded_formula.realize_inf],
  refine ⟨λ h, ⟨λ a b ab, h a b ab⟩, _⟩,
  introsI h a b ab,
  exact exists_between ab,
end

@[simp] lemma realize_densely_ordered [preorder M] [h : densely_ordered M] :
  M ⊨ language.order.densely_ordered_sentence :=
realize_densely_ordered_iff.2 h

instance model_DLO [linear_order M] [densely_ordered M] [no_top_order M] [no_bot_order M] :
  M ⊨ language.order.DLO :=
begin
  simp only [DLO, set.union_insert, set.union_singleton, Theory.model_iff,
    set.mem_insert_iff, forall_eq_or_imp, realize_no_top_order, realize_no_bot_order,
    realize_densely_ordered, true_and],
  rw ← Theory.model_iff,
  apply_instance,
end

end language
end first_order


import topology.subset_properties

/-
In this problem you will look at proving that the image of a compact set in a topological space
along a continuous map is also compact.

Some things you should know:
- A subset of a space `X` is an element of the type `set X` in Lean
- The notation for image of a set `U` along a map `f` is `f '' U`
- The simplifier `simp,`,
  is very useful, especially simplifying your hypotheses  `simp at ht` !
  You can use `simp at *,` to simplify as much as possible everywhere
- there is a new helpful lemma in the sidebar
-/
/- Hint : click here for the first few lines of the proof
```
rw is_compact_iff_finite_subcover, -- rewrite the definition of compactness
rw is_compact_iff_finite_subcover at h,  -- rewrite the definition of compactness
intros ι V hV hVu, -- we are proving a forall, so introduce everything
obtain ⟨t, ht⟩ := h (λ i, f ⁻¹' (V i)) _ _, -- pull back the open sets from Y to X
```
-/
/- Axiom : continuous.is_open_preimage : ∀ {α β : Type} [_inst_1 : topological_space α]
  [_inst_2 : topological_space β] {f : α → β},
  continuous f → ∀ (s : set β), is_open s → is_open (f ⁻¹' s)
-/
/- Lemma :
-/
lemma image_compact
  (X : Type)
  [topological_space X]
  (V : set X)
  (h : is_compact V)
  (Y : Type)
  [topological_space Y]
  (f : X → Y)
  (hf : continuous f) :
  is_compact (f '' V) :=
begin
  rw is_compact_iff_finite_subcover,
  rw is_compact_iff_finite_subcover at h,
  intros ι V hV hVu,
  obtain ⟨t, ht⟩ := h (λ i, f ⁻¹' (V i)) _ _,
  use t,
  simp [ht],
  intro i,
  simp,
  apply continuous.is_open_preimage hf (V i) (hV i),
  simp at hVu,
  simp [hVu],
end


/-
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Johannes Hölzl, Mario Carneiro
-/
import data.int.basic

/-!
# Square root of natural numbers

This file defines an efficient binary implementation of the square root function that returns the
unique `r` such that `r * r ≤ n < (r + 1) * (r + 1)`. It takes advantage of the binary
representation by replacing the multiplication by 2 appearing in
`(a + b)^2 = a^2 + 2 * a * b + b^2` by a bitmask manipulation.

## Reference

See [Wikipedia, *Methods of computing square roots*]
[https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)].
-/
namespace nat

theorem sqrt_aux_dec {b} (h : b ≠ 0) : shiftr b 2 < b :=
begin
  simp only [shiftr_eq_div_pow],
  apply (nat.div_lt_iff_lt_mul' (dec_trivial : 0 < 4)).2,
  have := nat.mul_lt_mul_of_pos_left
    (dec_trivial : 1 < 4) (nat.pos_of_ne_zero h),
  rwa mul_one at this
end

/-- Auxiliary function for `nat.sqrt`. See e.g.
<https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)> -/
def sqrt_aux : ℕ → ℕ → ℕ → ℕ
| b r n := if b0 : b = 0 then r else
  let b' := shiftr b 2 in
  have b' < b, from sqrt_aux_dec b0,
  match (n - (r + b : ℕ) : ℤ) with
  | (n' : ℕ) := sqrt_aux b' (div2 r + b) n'
  | _ := sqrt_aux b' (div2 r) n
  end

/-- `sqrt n` is the square root of a natural number `n`. If `n` is not a
  perfect square, it returns the largest `k:ℕ` such that `k*k ≤ n`. -/
@[pp_nodot] def sqrt (n : ℕ) : ℕ :=
match size n with
| 0      := 0
| succ s := sqrt_aux (shiftl 1 (bit0 (div2 s))) 0 n
end

theorem sqrt_aux_0 (r n) : sqrt_aux 0 r n = r :=
by rw sqrt_aux; simp
local attribute [simp] sqrt_aux_0

theorem sqrt_aux_1 {r n b} (h : b ≠ 0) {n'} (h₂ : r + b + n' = n) :
  sqrt_aux b r n = sqrt_aux (shiftr b 2) (div2 r + b) n' :=
by rw sqrt_aux; simp only [h, h₂.symm, int.coe_nat_add, if_false];
   rw [add_comm _ (n':ℤ), add_sub_cancel, sqrt_aux._match_1]

theorem sqrt_aux_2 {r n b} (h : b ≠ 0) (h₂ : n < r + b) :
  sqrt_aux b r n = sqrt_aux (shiftr b 2) (div2 r) n :=
begin
  rw sqrt_aux; simp only [h, h₂, if_false],
  cases int.eq_neg_succ_of_lt_zero
    (sub_lt_zero.2 (int.coe_nat_lt_coe_nat_of_lt h₂)) with k e,
  rw [e, sqrt_aux._match_1]
end

private def is_sqrt (n q : ℕ) : Prop := q*q ≤ n ∧ n < (q+1)*(q+1)

local attribute [-simp] mul_eq_mul_left_iff mul_eq_mul_right_iff

private lemma sqrt_aux_is_sqrt_lemma (m r n : ℕ)
  (h₁ : r*r ≤ n)
  (m') (hm : shiftr (2^m * 2^m) 2 = m')
  (H1 : n < (r + 2^m) * (r + 2^m) →
    is_sqrt n (sqrt_aux m' (r * 2^m) (n - r * r)))
  (H2 : (r + 2^m) * (r + 2^m) ≤ n →
    is_sqrt n (sqrt_aux m' ((r + 2^m) * 2^m) (n - (r + 2^m) * (r + 2^m)))) :
  is_sqrt n (sqrt_aux (2^m * 2^m) ((2*r)*2^m) (n - r*r)) :=
begin
  have b0 :=
    have b0:_, from ne_of_gt (pow_pos (show 0 < 2, from dec_trivial) m),
    nat.mul_ne_zero b0 b0,
  have lb : n - r * r < 2 * r * 2^m + 2^m * 2^m ↔
            n < (r+2^m)*(r+2^m),
  { rw [tsub_lt_iff_right h₁],
    simp [left_distrib, right_distrib, two_mul, mul_comm, mul_assoc,
      add_comm, add_assoc, add_left_comm] },
  have re : div2 (2 * r * 2^m) = r * 2^m,
  { rw [div2_val, mul_assoc,
        nat.mul_div_cancel_left _ (dec_trivial:2>0)] },
  cases lt_or_ge n ((r+2^m)*(r+2^m)) with hl hl,
  { rw [sqrt_aux_2 b0 (lb.2 hl), hm, re], apply H1 hl },
  { cases le.dest hl with n' e,
    rw [@sqrt_aux_1 (2 * r * 2^m) (n-r*r) (2^m * 2^m) b0 (n - (r + 2^m) * (r + 2^m)),
      hm, re, ← right_distrib],
    { apply H2 hl },
    apply eq.symm, apply tsub_eq_of_eq_add_rev,
    rw [← add_assoc, (_ : r*r + _ = _)],
    exact (add_tsub_cancel_of_le hl).symm,
    simp [left_distrib, right_distrib, two_mul, mul_comm, mul_assoc, add_assoc] },
end

private lemma sqrt_aux_is_sqrt (n) : ∀ m r,
  r*r ≤ n → n < (r + 2^(m+1)) * (r + 2^(m+1)) →
  is_sqrt n (sqrt_aux (2^m * 2^m) (2*r*2^m) (n - r*r))
| 0 r h₁ h₂ := by apply sqrt_aux_is_sqrt_lemma 0 r n h₁ 0 rfl;
  intro h; simp; [exact ⟨h₁, h⟩, exact ⟨h, h₂⟩]
| (m+1) r h₁ h₂ := begin
    apply sqrt_aux_is_sqrt_lemma
      (m+1) r n h₁ (2^m * 2^m)
      (by simp [shiftr, pow_succ, div2_val, mul_comm, mul_left_comm];
          repeat {rw @nat.mul_div_cancel_left _ 2 dec_trivial});
      intro h,
    { have := sqrt_aux_is_sqrt m r h₁ h,
      simpa [pow_succ, mul_comm, mul_assoc] },
    { rw [pow_succ', mul_two, ← add_assoc] at h₂,
      have := sqrt_aux_is_sqrt m (r + 2^(m+1)) h h₂,
      rwa show (r + 2^(m + 1)) * 2^(m+1) = 2 * (r + 2^(m + 1)) * 2^m,
          by simp [pow_succ, mul_comm, mul_left_comm] }
  end

private lemma sqrt_is_sqrt (n : ℕ) : is_sqrt n (sqrt n) :=
begin
  generalize e : size n = s, cases s with s; simp [e, sqrt],
  { rw [size_eq_zero.1 e, is_sqrt], exact dec_trivial },
  { have := sqrt_aux_is_sqrt n (div2 s) 0 (zero_le _),
    simp [show 2^div2 s * 2^div2 s = shiftl 1 (bit0 (div2 s)), by
    { generalize: div2 s = x,
      change bit0 x with x+x,
      rw [one_shiftl, pow_add] }] at this,
    apply this,
    rw [← pow_add, ← mul_two], apply size_le.1,
    rw e, apply (@div_lt_iff_lt_mul _ _ 2 dec_trivial).1,
    rw [div2_val], apply lt_succ_self }
end

theorem sqrt_le (n : ℕ) : sqrt n * sqrt n ≤ n :=
(sqrt_is_sqrt n).left

theorem sqrt_le' (n : ℕ) : (sqrt n) ^ 2 ≤ n :=
eq.trans_le (sq (sqrt n)) (sqrt_le n)

theorem lt_succ_sqrt (n : ℕ) : n < succ (sqrt n) * succ (sqrt n) :=
(sqrt_is_sqrt n).right

theorem lt_succ_sqrt' (n : ℕ) : n < (succ (sqrt n)) ^ 2 :=
trans_rel_left (λ i j, i < j) (lt_succ_sqrt n) (sq (succ (sqrt n))).symm

theorem sqrt_le_add (n : ℕ) : n ≤ sqrt n * sqrt n + sqrt n + sqrt n :=
by rw ← succ_mul; exact le_of_lt_succ (lt_succ_sqrt n)

theorem le_sqrt {m n : ℕ} : m ≤ sqrt n ↔ m*m ≤ n :=
⟨λ h, le_trans (mul_self_le_mul_self h) (sqrt_le n),
 λ h, le_of_lt_succ $ mul_self_lt_mul_self_iff.2 $
   lt_of_le_of_lt h (lt_succ_sqrt n)⟩

theorem le_sqrt' {m n : ℕ} : m ≤ sqrt n ↔ m ^ 2 ≤ n :=
by simpa only [pow_two] using le_sqrt

theorem sqrt_lt {m n : ℕ} : sqrt m < n ↔ m < n*n :=
lt_iff_lt_of_le_iff_le le_sqrt

theorem sqrt_lt' {m n : ℕ} : sqrt m < n ↔ m < n ^ 2 :=
lt_iff_lt_of_le_iff_le le_sqrt'

theorem sqrt_le_self (n : ℕ) : sqrt n ≤ n :=
le_trans (le_mul_self _) (sqrt_le n)

theorem sqrt_le_sqrt {m n : ℕ} (h : m ≤ n) : sqrt m ≤ sqrt n :=
le_sqrt.2 (le_trans (sqrt_le _) h)

@[simp] lemma sqrt_zero : sqrt 0 = 0 :=
by rw [sqrt, size_zero, sqrt._match_1]

theorem sqrt_eq_zero {n : ℕ} : sqrt n = 0 ↔ n = 0 :=
⟨λ h, nat.eq_zero_of_le_zero $ le_of_lt_succ $ (@sqrt_lt n 1).1 $
  by rw [h]; exact dec_trivial,
 by { rintro rfl, simp }⟩

theorem eq_sqrt {n q} : q = sqrt n ↔ q*q ≤ n ∧ n < (q+1)*(q+1) :=
⟨λ e, e.symm ▸ sqrt_is_sqrt n,
 λ ⟨h₁, h₂⟩, le_antisymm (le_sqrt.2 h₁) (le_of_lt_succ $ sqrt_lt.2 h₂)⟩

theorem eq_sqrt' {n q} : q = sqrt n ↔ q ^ 2 ≤ n ∧ n < (q+1) ^ 2 :=
by simpa only [pow_two] using eq_sqrt

theorem le_three_of_sqrt_eq_one {n : ℕ} (h : sqrt n = 1) : n ≤ 3 :=
le_of_lt_succ $ (@sqrt_lt n 2).1 $
by rw [h]; exact dec_trivial

theorem sqrt_lt_self {n : ℕ} (h : 1 < n) : sqrt n < n :=
sqrt_lt.2 $ by
  have := nat.mul_lt_mul_of_pos_left h (lt_of_succ_lt h);
  rwa [mul_one] at this

theorem sqrt_pos {n : ℕ} : 0 < sqrt n ↔ 0 < n := le_sqrt

theorem sqrt_add_eq (n : ℕ) {a : ℕ} (h : a ≤ n + n) : sqrt (n*n + a) = n :=
le_antisymm
  (le_of_lt_succ $ sqrt_lt.2 $ by rw [succ_mul, mul_succ, add_succ, add_assoc];
    exact lt_succ_of_le (nat.add_le_add_left h _))
  (le_sqrt.2 $ nat.le_add_right _ _)

theorem sqrt_add_eq' (n : ℕ) {a : ℕ} (h : a ≤ n + n) : sqrt (n ^ 2 + a) = n :=
(congr_arg (λ i, sqrt (i + a)) (sq n)).trans (sqrt_add_eq n h)

theorem sqrt_eq (n : ℕ) : sqrt (n*n) = n :=
sqrt_add_eq n (zero_le _)

theorem sqrt_eq' (n : ℕ) : sqrt (n ^ 2) = n :=
sqrt_add_eq' n (zero_le _)

theorem exists_mul_self (x : ℕ) :
  (∃ n, n * n = x) ↔ sqrt x * sqrt x = x :=
⟨λ ⟨n, hn⟩, by rw [← hn, sqrt_eq], λ h, ⟨sqrt x, h⟩⟩

theorem exists_mul_self' (x : ℕ) :
  (∃ n, n ^ 2 = x) ↔ (sqrt x) ^ 2 = x :=
by simpa only [pow_two] using exists_mul_self x

theorem sqrt_mul_sqrt_lt_succ (n : ℕ) : sqrt n * sqrt n < n + 1 :=
lt_succ_iff.mpr (sqrt_le _)

theorem sqrt_mul_sqrt_lt_succ' (n : ℕ) : (sqrt n) ^ 2 < n + 1 :=
lt_succ_iff.mpr (sqrt_le' _)

theorem succ_le_succ_sqrt (n : ℕ) : n + 1 ≤ (sqrt n + 1) * (sqrt n + 1) :=
le_of_pred_lt (lt_succ_sqrt _)

theorem succ_le_succ_sqrt' (n : ℕ) : n + 1 ≤ (sqrt n + 1) ^ 2 :=
le_of_pred_lt (lt_succ_sqrt' _)

/-- There are no perfect squares strictly between m² and (m+1)² -/
theorem not_exists_sq {n m : ℕ} (hl : m * m < n) (hr : n < (m + 1) * (m + 1)) :
  ¬ ∃ t, t * t = n :=
begin
  rintro ⟨t, rfl⟩,
  have h1 : m < t, from nat.mul_self_lt_mul_self_iff.mpr hl,
  have h2 : t < m + 1, from nat.mul_self_lt_mul_self_iff.mpr hr,
  exact (not_lt_of_ge $ le_of_lt_succ h2) h1
end

theorem not_exists_sq' {n m : ℕ} (hl : m ^ 2 < n) (hr : n < (m + 1) ^ 2) :
  ¬ ∃ t, t ^ 2 = n :=
  by simpa only [pow_two]
  using not_exists_sq (by simpa only [pow_two] using hl) (by simpa only [pow_two] using hr)

end nat


import analysis.real

-- Johannes' is_lub is the "bound ∧ all other bounds bigger" definition.
-- But Mario's real.exists_sup in the ℝ Lean files has conclusion
-- (H : ∀ y, x ≤ y ↔ ∀ z ∈ S, z ≤ y)

theorem maths_lub {S : set ℝ} (x : ℝ) :
  (∀ y, x ≤ y ↔ ∀ z ∈ S, z ≤ y) ↔ is_lub S x :=
begin
  split,
  { intro H,
    -- H : ∀ (y : ℝ), x ≤ y ↔ ∀ (z : ℝ), z ∈ S → z ≤ y
    -- ⊢ is_lub S x
    split,
    { -- ⊢ x ∈ upper_bounds S
      intros y Hy,
      exact (H x).1 (le_refl _) y Hy,
    },
    { -- ⊢ x ∈ lower_bounds (upper_bounds S)
      intros y Hy,
      exact (H y).2 Hy,
    }
  },
  intros H y,
  split,
  { intros Hxy z Hz,
    exact le_trans (H.1 z Hz : z ≤ x) Hxy,
  },
  { intro H2,
    apply H.2,
    exact H2
  }
end

-- is this too hard for tactics?

theorem maths_lub' {S : set ℝ} (x : ℝ) :
  (∀ y, x ≤ y ↔ ∀ z ∈ S, z ≤ y) ↔ is_lub S x :=
⟨λ H,⟨λ _ Hy,(H _).1 (le_refl _) _ Hy,λ _ Hy,(H _).2 Hy⟩,
  λ H y,⟨λ Hxy _ Hz,le_trans (H.1 _ Hz) Hxy,λ H2,H.2 _ H2⟩⟩

theorem maths_lub'' {S : set ℝ} (x : ℝ) :
  (∀ y, x ≤ y ↔ ∀ z ∈ S, z ≤ y) ↔ is_lub S x :=
⟨λ H,⟨λ y Hy,(H x).1 (le_refl x) y Hy,λ y Hy,(H y).2 Hy⟩,
  λ H y,⟨λ Hxy z Hz,le_trans (H.1 z Hz) Hxy,λ H2,H.2 y H2⟩⟩

theorem ex_lub_of_nonempty_bdd (S : set ℝ) (H1 : ∃ x, x ∈ S) (H2 : ∃ b, ∀ s, s ∈ S → s ≤ b) :
  ∃ b, is_lub S b := begin
  have H :=real.exists_sup S H1 H2,
  cases H with x H,
  existsi x,
  exact (maths_lub x).1 H,
end

theorem ex_lub_of_nonempty_bdd' (S : set ℝ) (H1 : ∃ x, x ∈ S) (H2 : ∃ b, ∀ s, s ∈ S → s ≤ b) :
  ∃ b, is_lub S b := let ⟨x,H⟩ := real.exists_sup S H1 H2 in ⟨x,(maths_lub x).1 H⟩


import algebra.order.ring

variables {R : Type*} [ordered_ring R]
variables a b c : R

#check sub_nonneg

-- BEGIN
example : 0 ≤ b - a → a ≤ b :=
begin
  intro h,
  rw sub_nonneg at h,
  sorry,
end

/- Alternatively -/
example : 0 ≤ b - a → a ≤ b :=
begin
  intro h,
  exact sub_nonneg.mp h,
end

example : a ≤ b → 0 ≤ b - a :=
begin
  intro h,
  rw ← sub_nonneg at h,
  sorry,
end

/- Alternatively -/
example : a ≤ b → 0 ≤ b - a :=
begin
  intro h,
  sorry,
end
-- END


example (p q r : Prop) : p ∧ (q ∨ r) ↔ (p ∧ q) ∨ (p ∧ r) :=
begin
  apply iff.intro,
    intro h,
    apply or.elim (and.right h),
      intro hq,
      apply or.inl,
      apply and.intro,
        exact and.left h,
        exact hq,
      intro hr,
      apply or.inr,
      apply and.intro,
        exact and.left h,
        exact hr,
    intro h,
    apply or.elim h,
      intro hpq,
      apply and.intro,
        exact and.left hpq,
        apply or.inl,
        exact and.right hpq,
      intro hpr,
      apply and.intro,
        exact and.left hpr,
        apply or.inr,
        exact and.right hpr
end