/-
Change the below line to
import week_2.kb_solutions.Part_A_groups_solutions
(once the solutions are posted) if you want to get rid of the warning
-/

import wk4.groups

/-!
## Subgroups
We define the structure `subgroup G`, whose terms are subgroups of `G`.
A subgroup of `G` is implemented as a subset of `G` closed under
`1`, `*` and `⁻¹`.
-/

namespace xena

/-- A subgroup of a group G is a subset containing 1
and closed under multiplication and inverse. -/
structure subgroup (G : Type) [group G] :=
(carrier : set G)
(one_mem' : (1 : G) ∈ carrier)
(mul_mem' {x y} : x ∈ carrier → y ∈ carrier → x * y ∈ carrier)
(inv_mem' {x} : x ∈ carrier → x⁻¹ ∈ carrier)

/-
At this point, here's what we have.
A term `H` of type `subgroup G`, written `H : subgroup G`, is a
*quadruple*. To give a term `H : subgroup G` is to give the following four things:
1) `H.carrier` (a subset of `G`),
2) `H.one_mem'` (a proof that `1 ∈ H.carrier`),
3) `H.mul_mem'` (a proof that `H` is closed under multiplication)
4) `H.inv_mem'` (a proof that `H` is closed under inverses).
Note in particular that Lean, being super-pedantic, *distinguishes* between
the subgroup `H` and the subset `H.carrier`. One is a subgroup, one is
a subset. When we get going we will start by setting up some infrastructure
so that this difference will be hard to notice.
Note also that if `x` is in the subgroup `H` of `H` then the _type_ of `x` is still `G`,
and `x ∈ carrier` is a Proposition. Note also that `x : carrier` doesn't
make sense (`carrier` is a term, not a type, rather counterintuitively).
-/

namespace subgroup

open xena.group

-- let G be a group and let H and K be subgroups
variables {G : Type} [group G] (H J K : subgroup G)

/-
This `h ∈ H.carrier` notation kind of stinks. I don't want to write `H.carrier`
everywhere, because I want to be able to identify the subgroup `H` with
its underlying subset `H.carrier`. Note that these things are not _equal_,
firstly because `H` contains the proof that `H.carrier` is a subgroup, and
secondly because these terms have different types! `H` has type `subgroup G`
and `H.carrier` has type `set G`. Let's start by sorting this out.
-/

-- If `x : G` and `H : subgroup G` then let's define the notation
-- `x ∈ H` to mean `x ∈ H.carrier`
instance : has_mem G (subgroup G) := ⟨λ m H, m ∈ H.carrier⟩

-- Let's also define a "coercion", a.k.a. an "invisible map"
-- from subgroups of `G` to subsets of `G`, sending `H` to `H.carrier`.
-- The map is not completely invisible -- it's a little ↑. So
-- if you see `↑H` in the future, it means the subset `H.carrier` by definition.
instance : has_coe (subgroup G) (set G) := ⟨λ H, H.carrier⟩

-- `λ` is just computer science notation for ↦ (mapsto); so
-- `λ H, H.carrier` is the function `H ↦ H.carrier`.

-- Let's check we have this working, and also tell the simplifier that we
-- would rather talk about `g ∈ H` than any other way of saying it.

/-- `g` is in the underlying subset of `H` iff `g ∈ H`. -/
@[simp] lemma mem_carrier {g : G} : g ∈ H.carrier ↔ g ∈ H :=
begin
  -- true by definition
  refl
end

/-- `g` is in `H` considered as a subset of `G`, iff `g` is in `H` considered
as subgroup of `G`. -/
@[simp] lemma mem_coe {g : G} : g ∈ (↑H : set G) ↔ g ∈ H :=
begin
  -- true by definition
  refl
end

-- Now let's define theorems without the `'`s in, which use this
-- more natural notation

/-- A subgroup contains the group's 1. -/
theorem one_mem : (1 : G) ∈ H := H.one_mem'

/-- A subgroup is closed under multiplication. -/
theorem mul_mem {x y : G} : x ∈ H → y ∈ H → x * y ∈ H :=
begin
  apply H.mul_mem'
end

/-
begin
  intros x y,
  apply mul_mem';
  rw mem_carrier,
  { exact x},
  { exact y},
  -- what do you think?
end
-/

/-- A subgroup is closed under inverse -/
theorem inv_mem {x : G} : x ∈ H → x⁻¹ ∈ H :=
begin
  apply H.inv_mem',
  -- what do you think?
end

/-
So here are the three theorems which you need to remember about subgroups.
Say `H : subgroup G`. Then:
`H.one_mem : (1 : G) ∈ H`
`H.mul_mem {x y : G} : x ∈ H → y ∈ H → x * y ∈ H`
`H.inv_mem {x : G} : x ∈ H → x⁻¹ ∈ H`
These now look like the way a mathematician would write things.
Now let's start to prove basic theorems about subgroups (or, as a the computer
scientists would say, make a basic _interface_ or _API_ for subgroups),
using this sensible notation.
Here's an example; let's prove `x ∈ H ↔ x⁻¹ ∈ H`. Let's put the more
complicated expression on the left hand side of the `↔` though, because then
we can make it a `simp` lemma.
-/

-- Remember that `xena.group.inv_inv x` is the statement that `x⁻¹⁻¹ = x`

@[simp] theorem inv_mem_iff {x : G} : x⁻¹ ∈ H ↔ x ∈ H :=
begin
  split,
  { intros H,
  -- fiddled around with using inv_mem, doesn't work, so I need another inv
    rw ← inv_inv x, -- this adds another inv
    apply inv_mem, -- this gets rid of one of the inv
    exact H,
  },
  { apply inv_mem,}
end

-- We could prove a bunch more theorems here. Let's just do one more.
-- Let's show that if x and xy are in H then so is y.

theorem mem_of_mem_mul_mem {x y : G} (hx : x ∈ H) (hxy : x * y ∈ H) : y ∈ H :=
begin
  rw ← inv_mem_iff at hx,
  convert H.mul_mem hx hxy,
  simp only [eq_self_iff_true, xena.group.inv_mul_cancel_left],
end

/-
Subgroups are extensional objects (like most things in mathematics):
two subgroups are equal if they have the same underlying subset,
and also if they have the same underlying elements.
Let's prove variants of this triviality now. The first one is rather
un-mathematical: it takes a subgroup apart into its pieces. I'll see if
you can do the other two!
-/

/-- Two subgroups are equal if the underlying subsets are equal. -/
theorem ext' {H K : subgroup G} (h : H.carrier = K.carrier) : H = K :=
begin
  -- first take H and K apart
  cases H, -- H now broken up into its underlying 3-tuple.
  cases K,
  -- and now it must be obvious, so let's see if the simplifier can do it.
  simp * at *, -- it can!
end

-- here's a variant. You can prove it using `ext'`.

/-- Two subgroups are equal if and only if the underlying subsets are equal. -/
theorem ext'_iff {H K : subgroup G} :
  H.carrier = K.carrier ↔ H = K :=
begin
  split,
  { exact ext',},
  { intro h,
    rw h,
  }
end

-- to do this next one, first apply the `ext'` theorem we just proved,
-- and then use the `ext` tactic (which works on sets)

/-- Two subgroups are equal if they have the same elements. -/
@[ext] theorem ext {H K : subgroup G} (h : ∀ x, x ∈ H ↔ x ∈ K) : H = K :=
begin
  apply ext',
  ext,
  apply h,
end

/-
We tagged that theorem with `ext`, so now the `ext` tactic works on subgroups
too: if you ever have a goal of proving that two subgroups are equal, you can
use the `ext` tactic to reduce to showing that they have the same elements.
-/

/-
## The lattice structure on subgroups
Subgroups of a group form what is known as a *lattice*.
This is a partially ordered set with a sensible notion of
max and min. We partially order subgroups by saying `H ≤ K` if
`H.carrier ⊆ K.carrier`. Subgroups even have a good notion of an infinite
Sup and Inf (the Inf of a bunch of subgroups is just their intersection;
their Sup is the subgroup generated by their union).
This combinatorial structure (a partially ordered set with good
finite and infinite notions of Sup and Inf) is called a "complete lattice",
and Lean has this structure inbuilt into it. We will construct
a complete lattice structure on `subgroup G`.
We start by defining a relation ≤ on the type of subgroups of a group.
We say H ≤ K iff H.carrier ⊆ K.carrier .
-/

/-- If `H` and `K` are subgroups of `G`, we write `H ≤ K` to
  mean `H.carrier ⊆ K.carrier` -/
instance : has_le (subgroup G) := ⟨λ H K, H.carrier ⊆ K.carrier⟩

-- useful to restate the definition so we can `rw` it
lemma le_def : H ≤ K ↔ H.carrier ⊆ K.carrier :=
begin
  -- true by definition
  refl
end

-- another useful variant
lemma le_iff : H ≤ K ↔ ∀ g, g ∈ H → g ∈ K :=
begin
  -- true by definition
  refl,
end

-- Now let's check the axioms for a partial order.
-- These are not hard, they just reduce immediately to the
-- fact that ⊆ is a partial order
@[refl] lemma le_refl : H ≤ H :=
begin
  rw le_def,
  -- Lean knows ⊆ is reflexive so the sneaky `refl` which Lean tries after `rw`
  -- has closed the goal!
end

lemma le_antisymm : H ≤ K → K ≤ H → H = K :=
begin
  rw [le_def, le_def, ← ext'_iff],
  intros HK KH,
  -- now this is antisymmetry of ⊆, which Lean knows
  exact set.subset.antisymm HK KH,
end

@[trans] lemma le_trans : H ≤ J → J ≤ K → H ≤ K :=
begin
  rw [le_def, le_def, le_def],
  -- now this is transitivity of ⊆, which Lean knows
  exact set.subset.trans,
end

-- We've made `subgroup G` into a partial order!
instance : partial_order (subgroup G) :=
{ le := (≤),
  le_refl := le_refl,
  le_antisymm := le_antisymm,
  le_trans := le_trans }

/-
### intersections
Let's prove that the intersection of two subgroups is a subgroup. In Lean
this is a definition: given two subgroups, we define a new subgroup whose
underlying subset is the intersection of the subsets, and then prove
the axioms.
-/

/-- The intersection of two subgroups is also a subgroup -/
def inf (H K : subgroup G) : subgroup G :=
{ carrier := H.carrier ∩ K.carrier, -- the carrier is the intersection
  one_mem' :=
  begin
    -- recall that x ∈ Y ∩ Z is _by definition_ x ∈ Y ∧ x ∈ Z, so you can `split` this.
    split,
    { exact H.one_mem,},
    { exact K.one_mem,},
  end,
  mul_mem' :=
  begin
    intros x y hx hy,
    cases hx with hx1 hx2,
    cases hy with hy1 hy2,
    exact ⟨H.mul_mem hx1 hy1, K.mul_mem hx2 hy2⟩
  end,
  inv_mem' :=
  begin
    rintros x ⟨h1, h2⟩,
    exact ⟨ H.inv_mem h1, K.inv_mem h2 ⟩,
  end }

-- Notation for `inf` in computer science circles is ⊓.

instance : has_inf (subgroup G) := ⟨inf⟩

/-- The underlying set of the inf of two subgroups is just their intersection -/
lemma inf_def (H K : subgroup G) : (H ⊓ K : set G) = (H : set G) ∩ K :=
begin
  -- true by definition
  refl
end

/-
## Subgroup generated by a subset.
To do the sup of two subgroups is harder, because we don't just take
the union, we need to then look at the subgroup generated by this union
(e.g. the union of the x and y axes in ℝ² is not a subgroup). So we need
to have a machine to spit out the subgroup of `G` generated by a subset `S : set G`.
There are two completely different ways to do this. The first is a "top-down"
approach. We could define the subgroup generated by `S` to be the intersection of
all the subgroups of `G` that contain `S`. The second is a "bottom-up" approach.
We could define the subgroup generated by `S` "by induction" (or more precisely
by recursion), saying that `S` is in the subgroup, 1 is in the subgroup,
the product of two things in the subgroup is in the subgroup, the
inverse of something in the subgroup is in the subgroup, and that's it.
Both methods come out rather nicely in Lean. Let's do the first one.
We are going to be using a bunch of theorems about "bounded intersections",
a.k.a. `set.bInter`. We will soon get tired of writing `set.blah` so let's
`open set` so that we can skip it.
-/

open set

/-
Here is the API for `set.bInter` (or `bInter`, as we can now call it):
Notation: `⋂` (type with `\I`)
If `X : set (subgroup G)`, i.e. if `X` is a set of subgroups of `G`, then
`⋂ K ∈ X, (K : set G)` means "take the intersection of the underlying subsets".
-- mem_bInter_iff says you're in the intersection iff you're in
-- all the things you're intersecting. Very useful for rewriting.
`mem_bInter_iff : (g ∈ ⋂ (K ∈ S), f K) ↔ (∀ K, K ∈ s → g ∈ f K)`
-- mem_bInter is just the one way implication. Very useful for `apply`ing.
`mem_bInter : (∀ K, K ∈ s → g ∈ f K) → (g ∈ ⋂ (K ∈ S), f K)`
-/
/-
We will consider the closure of a set as the intersect of all subgroups
containing the set
-/

/-- The Inf of a set of subgroups of G is their intersection. -/
def Inf (X : set (subgroup G)) : subgroup G :=
{ carrier := ⋂ K ∈ X, (K : set G), -- carrier is the intersection of the underlying sets
  one_mem' :=
  begin
    rw mem_bInter_iff,
    intros x hxX,
    apply x.one_mem,
    end,
  mul_mem' := begin
    intros x y hx hy,
    rw mem_bInter_iff at hx hy ⊢,
    intros a haX,
    -- specialize hx a haX,
    -- specialize hy a haX,
    apply a.mul_mem (hx a haX) (hy a haX),  -- a.mul_mem hx hy
  end,
  inv_mem' := begin
    intros x hx,
    rw mem_bInter_iff at hx ⊢,
    intros a haX,
    apply a.inv_mem (hx a haX),
  end,
}

/-- The *closure* of a subset `S` of `G` is the `Inf` of the subgroups of `G`
  which contain `S`. -/
def closure (S : set G) : subgroup G := Inf {H : subgroup G | S ⊆ H}

-- we can restate mem_bInter_iff using our new "closure" language:
lemma mem_closure_iff {S : set G} {x : G} :
  x ∈ closure S ↔ ∀ H : subgroup G, S ⊆ H → x ∈ H := mem_bInter_iff

/-
There is an underlying abstraction here, which you may not know about.
A "closure operator" in mathematics
https://en.wikipedia.org/wiki/Closure_operator
is something mapping subsets of a set X to subsets of X, and satisfying three
axioms:
1) `subset_closure : S ⊆ closure S`
2) `closure_mono : (S ⊆ T) → (closure S ⊆ closure T)`
3) `closure_closure : closure (closure S) = closure S`
It works for closure in topological spaces, and it works here too.
It also works for algebraic closures of fields, and there are several
other places in mathematics where it shows up. This idea, of "abstracting"
and axiomatising a phenomenon which shows up in more than one place,
is really key in Lean.
Let's prove these three lemmas in the case where `X = G` and `closure S`
is the subgroup generated by `S`.
Here are some things you might find helpful.
Remember
`mem_coe : g ∈ ↑H ↔ g ∈ H`
`mem_carrier : g ∈ H.carrier ↔ g ∈ H`
There's
`mem_closure_iff : x ∈ closure S ↔ ∀ (H : subgroup G), S ⊆ ↑H → x ∈ H`
(`closure S` is a subgroup so you might need to use `mem_coe` or `mem_carrier` first)
For subsets there's
`subset.trans : X ⊆ Y → Y ⊆ Z → X ⊆ Z`
You might find `le_antisymm : H ≤ K → K ≤ H → H = K` from above useful
-/

/-
Reminder: X ⊆ Y means `∀ g, g ∈ X → g ∈ Y` and it's definitional,
so you can just start this with `intro g`.
-/
lemma subset_closure (S : set G) : S ⊆ ↑(closure S) :=
begin
  intros g hgS,
  rw [mem_coe, mem_closure_iff],
  intros H hSH,
  exact hSH hgS, -- as X ⊆ Y means `∀ g, g ∈ X → g ∈ Y`, then giving hSH hgS
                  -- will just return a term of type that is the same as the goal
end

-- It's useful to know `subset.trans : X ⊆ Y → Y ⊆ Z → X ⊆ Z`
lemma closure_mono {S T : set G} (hST : S ⊆ T) : closure S ≤ closure T :=
begin
  intros x hxS,
  rw [mem_carrier, mem_closure_iff] at ⊢ hxS,
  -- apply hST hxS, -- has type x ∈ closure S but is expected to have type ?m_1 ∈ S
  -- so this is useful, but after we have something like a ∈ S.
  --rw mem_closure_iff at hxS ⊢,
  intros H hH,
  -- have hH2 := subset.trans hST hH,
  -- rw mem_closure_iff at hxS,
  -- specialize hxS H (subset.trans hST hH),
  exact (hxS H (subset.trans hST hH)),
end

-- not one of the axioms, but sometimes handy
lemma closure_le (S : set G) (H : subgroup G) : closure S ≤ H ↔ S ⊆ ↑H :=
begin
  split,
  { intros hSH,
    apply subset.trans (subset_closure S) hSH,
  },
  { intros hSH g hg,
    rw mem_carrier,
    rw [mem_carrier, mem_closure_iff] at hg,
    apply hg H hSH,
  },
end

-- You can start this one by applying `le_antisymm`,
lemma closure_closure (S : set G) : closure S = closure (closure S) :=
begin
  apply le_antisymm,
  { apply subset_closure,},
  { rw closure_le,
    intros x hx,
    exact hx,
  },
end

-- This shows that every subgroup is the closure of something, namely its
-- underlying subset.
lemma closure_self {H : subgroup G} : closure ↑H = H :=
begin
  apply le_antisymm,
  { rw le_iff,
    intros g hg,
    rw mem_closure_iff at hg,
    apply hg H, refl,
  },
  { apply subset_closure,},
end

/-
Recall the second proposed construction of the subgroup closure of a subset `S`;
it is the smallest subgroup `H` of `G` such that `S ⊆ H` and which contains
`1` and is closed under `*` and `⁻¹`. This inductive constuction (which we
did not make) comes with a so-called "recursor": if we have a true/false
statement `p g` attached to each element `g` of G with the following properties:
1) `p s` is true for all `s ∈ S`,
2) `p 1` is true,
3) If `p x` and `p y` then `p (x * y)`,
4) If `p x` then `p x⁻¹`
Then `p` is true on all of `closure S`.
If we had made an inductive definition of `closure S` then this would have been true
by definition! We used another definition, so we will have to prove it
ourselves.
-/

/-- An induction principle for closures. -/
lemma closure_induction {p : G → Prop} {S : set G}
  (HS : ∀ x ∈ S, p x)
  (H1 : p 1)
  (Hmul : ∀ x y, p x → p y → p (x * y))
  (Hinv : ∀ x, p x → p x⁻¹) :
  -- conclusion after colon
  ∀ x, x ∈ closure S → p x :=
begin
  -- the subset of G where `p` is true is a subgroup. Let's call it H
  let H : subgroup G :=
  { carrier := p,
    one_mem' := H1,
    mul_mem' := Hmul,
    inv_mem' := Hinv },
  -- The goal is just that closure S ≤ H, by definition.
  change closure S ≤ H,
  -- Our hypothesis HS is just that S ⊆ ↑H, by definition
  change S ⊆ ↑H at HS,
  -- I think you can take it from here!
  rw closure_le,
  exact HS, -- assumption
end

/-
Finally we prove that the `closure` and `coe` maps form a `galois_insertion`.
This is another abstraction, it generalises `galois_connection`, which is
something that shows up all over the place (algebraic geometry, Galois theory etc).
See
https://en.wikipedia.org/wiki/Galois_connection
A partial order can be considered as a category, with Hom(A,B) having
one element if A ≤ B and no elements otherwise. A Galois connection between
two partial orders is just a pair of adjoint functors between the categories.
Adjointness in our case is `S ⊆ ↑H ↔ closure S ≤ H`.
The reason it's an insertion and not just a connection is that if you start
with a subgroup, take the underlying subset, and then look at the subgroup
generated by that set, you get back to where you started. So it's like one
of the adjoint functors being a forgetful functor.
-/

/-- THIS IS A DOCSTRING -/
def gi : galois_insertion (closure : set G → subgroup G) (coe : subgroup G → set G) :=
{ choice := λ S _, closure S,
  gc := closure_le,
  le_l_u := λ H, subset_closure (H : set G),
  choice_eq := λ _ _, rfl }

/-
One use of this abstraction is that now we can pull back the complete
lattice structure on `set G` to get a complete lattice structure on `subgroup G`.
-/

instance : complete_lattice (subgroup G) :=
{.. galois_insertion.lift_complete_lattice gi}

/-
We just proved loads of lemmas about Infs and Sups of subgroups automatically,
and have access to a ton more because the `complete_lattice` structure in
Lean has a big API. See for example
https://leanprover-community.github.io/mathlib_docs/order/complete_lattice.html#complete_lattice
All those theorems are now true for subgroups. None are particularly hard to prove,
but the point is that we don't now have to prove any of them ourselves.
-/
end subgroup

end xena

/-
Further work: `bot` and `top` (would have to explain the
API for `singleton` and `univ`)
-/


import MyNat.Definition
import MyNat.Addition
namespace MyNat
open MyNat

/-!

# Advanced Addition World

## Level 3: `succ_eq_succ_of_eq`.

We are going to prove something completely obvious: if `a=b` then
`succ a = succ b`. This is *not* `succ_inj`!
This is trivial -- we can just rewrite our proof of `a=b`.
But how do we get to that proof? Use the `intro` tactic.

## Theorem
For all naturals `a` and `b`, `a = b ⟹ succ a = succ b`.
-/
theorem succ_eq_succ_of_eq {a b : MyNat} : a = b → succ a = succ b := by
  intro h
  rw [h]

/-!
Next up [Level 4](./Level4.lean.md)
-/


import MyNat.Definition
import MyNat.Addition -- add_zero
import MyNat.Inequality -- le_iff_exists_add
import Mathlib.Tactic.Use -- use tactic
import AdditionWorld.Level2 -- add_assoc
import AdditionWorld.Level3 -- succ_add
import InequalityWorld.Level2 -- le_refl
namespace MyNat
open MyNat
/-!

# Inequality world.

## Level 15: introducing `<`

To get the remaining collectibles in this world, we need to
give a definition of `<`. By default, the definition of `a < b`
in Lean, once `≤` is defined, is this:

`a < b := a ≤ b ∧ ¬ (b ≤ a)`

But a much more usable definition would be this:

`a < b := succ a ≤ b`

Let's prove that these two definitions are the same

## Lemma : lt_aux₁
For all naturals `a` and `b`, `a ≤ b ∧ ¬(b ≤ a) ⟹ succ a ≤ b.`
-/
lemma lt_aux₁ (a b : MyNat) : a ≤ b ∧ ¬ (b ≤ a) → succ a ≤ b := by
  intro h
  cases h with
  | _ h1 h2 =>
    cases h1 with
    | _ c hc =>
      cases c with
      | zero =>
        exfalso
        rw [zero_is_0, add_zero] at hc
        apply h2
        rw [hc]
      | succ d =>
        use d
        rw [hc]
        rw [add_succ]
        rw [succ_add]

/-!
Next up [Level 16](./Level16.lean.md)
-/


/-
Copyright (c) 2021 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
import analysis.box_integral.box.subbox_induction
import analysis.box_integral.partition.tagged

/-!
# Induction on subboxes

In this file we prove (see
`box_integral.tagged_partition.exists_is_Henstock_is_subordinate_homothetic`) that for every box `I`
in `ℝⁿ` and a function `r : ℝⁿ → ℝ` positive on `I` there exists a tagged partition `π` of `I` such
that

* `π` is a Henstock partition;
* `π` is subordinate to `r`;
* each box in `π` is homothetic to `I` with coefficient of the form `1 / 2 ^ n`.

Later we will use this lemma to prove that the Henstock filter is nontrivial, hence the Henstock
integral is well-defined.

## Tags

partition, tagged partition, Henstock integral
-/

namespace box_integral

open set metric
open_locale classical topology
noncomputable theory

variables {ι : Type*} [fintype ι] {I J : box ι}

namespace prepartition

/-- Split a box in `ℝⁿ` into `2 ^ n` boxes by hyperplanes passing through its center. -/
def split_center (I : box ι) : prepartition I :=
{ boxes := finset.univ.map (box.split_center_box_emb I),
  le_of_mem' := by simp [I.split_center_box_le],
  pairwise_disjoint :=
    begin
      rw [finset.coe_map, finset.coe_univ, image_univ],
      rintro _ ⟨s, rfl⟩ _ ⟨t, rfl⟩ Hne,
      exact I.disjoint_split_center_box (mt (congr_arg _) Hne)
    end }

@[simp] lemma mem_split_center : J ∈ split_center I ↔ ∃ s, I.split_center_box s = J :=
by simp [split_center]

lemma is_partition_split_center (I : box ι) : is_partition (split_center I) :=
λ x hx, by simp [hx]

lemma upper_sub_lower_of_mem_split_center (h : J ∈ split_center I) (i : ι) :
  J.upper i - J.lower i = (I.upper i - I.lower i) / 2 :=
let ⟨s, hs⟩ := mem_split_center.1 h in hs ▸ I.upper_sub_lower_split_center_box s i

end prepartition

namespace box

open prepartition tagged_prepartition

/-- Let `p` be a predicate on `box ι`, let `I` be a box. Suppose that the following two properties
hold true.

* Consider a smaller box `J ≤ I`. The hyperplanes passing through the center of `J` split it into
  `2 ^ n` boxes. If `p` holds true on each of these boxes, then it true on `J`.
* For each `z` in the closed box `I.Icc` there exists a neighborhood `U` of `z` within `I.Icc` such
  that for every box `J ≤ I` such that `z ∈ J.Icc ⊆ U`, if `J` is homothetic to `I` with a
  coefficient of the form `1 / 2 ^ m`, then `p` is true on `J`.

Then `p I` is true. See also `box_integral.box.subbox_induction_on'` for a version using
`box_integral.box.split_center_box` instead of `box_integral.prepartition.split_center`. -/
@[elab_as_eliminator]
lemma subbox_induction_on {p : box ι → Prop} (I : box ι)
  (H_ind : ∀ J ≤ I, (∀ J' ∈ split_center J, p J') → p J)
  (H_nhds : ∀ z ∈ I.Icc, ∃ (U ∈ 𝓝[I.Icc] z), ∀ (J ≤ I) (m : ℕ), z ∈ J.Icc → J.Icc ⊆ U →
    (∀ i, J.upper i - J.lower i = (I.upper i - I.lower i) / 2 ^ m) → p J) :
  p I :=
begin
  refine subbox_induction_on' I (λ J hle hs, H_ind J hle $ λ J' h', _) H_nhds,
  rcases mem_split_center.1 h' with ⟨s, rfl⟩,
  exact hs s
end

/-- Given a box `I` in `ℝⁿ` and a function `r : ℝⁿ → (0, ∞)`, there exists a tagged partition `π` of
`I` such that

* `π` is a Henstock partition;
* `π` is subordinate to `r`;
* each box in `π` is homothetic to `I` with coefficient of the form `1 / 2 ^ m`.

This lemma implies that the Henstock filter is nontrivial, hence the Henstock integral is
well-defined. -/
lemma exists_tagged_partition_is_Henstock_is_subordinate_homothetic (I : box ι)
  (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  ∃ π : tagged_prepartition I, π.is_partition ∧ π.is_Henstock ∧ π.is_subordinate r ∧
    (∀ J ∈ π, ∃ m : ℕ, ∀ i, (J : _).upper i - J.lower i = (I.upper i - I.lower i) / 2 ^ m) ∧
    π.distortion = I.distortion :=
begin
  refine subbox_induction_on I (λ J hle hJ, _) (λ z hz, _),
  { choose! πi hP hHen hr Hn Hd using hJ, choose! n hn using Hn,
    have hP : ((split_center J).bUnion_tagged πi).is_partition,
      from (is_partition_split_center _).bUnion_tagged hP,
    have hsub : ∀ (J' ∈ (split_center J).bUnion_tagged πi), ∃ n : ℕ, ∀ i,
      (J' : _).upper i - J'.lower i = (J.upper i - J.lower i) / 2 ^ n,
    { intros J' hJ',
      rcases (split_center J).mem_bUnion_tagged.1 hJ' with ⟨J₁, h₁, h₂⟩,
      refine ⟨n J₁ J' + 1, λ i, _⟩,
      simp only [hn J₁ h₁ J' h₂, upper_sub_lower_of_mem_split_center h₁, pow_succ, div_div] },
    refine ⟨_, hP, is_Henstock_bUnion_tagged.2 hHen, is_subordinate_bUnion_tagged.2 hr, hsub, _⟩,
    refine tagged_prepartition.distortion_of_const _ hP.nonempty_boxes (λ J' h', _),
    rcases hsub J' h' with ⟨n, hn⟩,
    exact box.distortion_eq_of_sub_eq_div hn },
  { refine ⟨I.Icc ∩ closed_ball z (r z),
      inter_mem_nhds_within _ (closed_ball_mem_nhds _ (r z).coe_prop), _⟩,
    intros J Hle n Hmem HIcc Hsub,
    rw set.subset_inter_iff at HIcc,
    refine ⟨single _ _ le_rfl _ Hmem, is_partition_single _, is_Henstock_single _,
      (is_subordinate_single _ _).2 HIcc.2, _, distortion_single _ _⟩,
    simp only [tagged_prepartition.mem_single, forall_eq],
    refine ⟨0, λ i, _⟩, simp }
end

end box

namespace prepartition

open tagged_prepartition finset function

/-- Given a box `I` in `ℝⁿ`, a function `r : ℝⁿ → (0, ∞)`, and a prepartition `π` of `I`, there
exists a tagged prepartition `π'` of `I` such that

* each box of `π'` is included in some box of `π`;
* `π'` is a Henstock partition;
* `π'` is subordinate to `r`;
* `π'` covers exactly the same part of `I` as `π`;
* the distortion of `π'` is equal to the distortion of `π`.
-/
lemma exists_tagged_le_is_Henstock_is_subordinate_Union_eq {I : box ι} (r : (ι → ℝ) → Ioi (0 : ℝ))
  (π : prepartition I) :
  ∃ π' : tagged_prepartition I, π'.to_prepartition ≤ π ∧
    π'.is_Henstock ∧ π'.is_subordinate r ∧ π'.distortion = π.distortion ∧
    π'.Union = π.Union :=
begin
  have := λ J, box.exists_tagged_partition_is_Henstock_is_subordinate_homothetic J r,
  choose! πi πip πiH πir hsub πid, clear hsub,
  refine ⟨π.bUnion_tagged πi, bUnion_le _ _, is_Henstock_bUnion_tagged.2 (λ J _, πiH J),
    is_subordinate_bUnion_tagged.2 (λ J _, πir J), _, π.Union_bUnion_partition (λ J _, πip J)⟩,
  rw [distortion_bUnion_tagged],
  exact sup_congr rfl (λ J _, πid J)
end

/-- Given a prepartition `π` of a box `I` and a function `r : ℝⁿ → (0, ∞)`, `π.to_subordinate r`
is a tagged partition `π'` such that

* each box of `π'` is included in some box of `π`;
* `π'` is a Henstock partition;
* `π'` is subordinate to `r`;
* `π'` covers exactly the same part of `I` as `π`;
* the distortion of `π'` is equal to the distortion of `π`.
-/
def to_subordinate (π : prepartition I) (r : (ι → ℝ) → Ioi (0 : ℝ)) : tagged_prepartition I :=
(π.exists_tagged_le_is_Henstock_is_subordinate_Union_eq r).some

lemma is_Henstock_to_subordinate (π : prepartition I) (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  (π.to_subordinate r).is_Henstock :=
(π.exists_tagged_le_is_Henstock_is_subordinate_Union_eq r).some_spec.2.1

lemma is_subordinate_to_subordinate (π : prepartition I) (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  (π.to_subordinate r).is_subordinate r :=
(π.exists_tagged_le_is_Henstock_is_subordinate_Union_eq r).some_spec.2.2.1

@[simp] lemma distortion_to_subordinate (π : prepartition I) (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  (π.to_subordinate r).distortion = π.distortion :=
(π.exists_tagged_le_is_Henstock_is_subordinate_Union_eq r).some_spec.2.2.2.1

@[simp] lemma Union_to_subordinate (π : prepartition I) (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  (π.to_subordinate r).Union = π.Union :=
(π.exists_tagged_le_is_Henstock_is_subordinate_Union_eq r).some_spec.2.2.2.2

end prepartition

namespace tagged_prepartition

/-- Given a tagged prepartition `π₁`, a prepartition `π₂` that covers exactly `I \ π₁.Union`, and
a function `r : ℝⁿ → (0, ∞)`, returns the union of `π₁` and `π₂.to_subordinate r`. This partition
`π` has the following properties:

* `π` is a partition, i.e. it covers the whole `I`;
* `π₁.boxes ⊆ π.boxes`;
* `π.tag J = π₁.tag J` whenever `J ∈ π₁`;
* `π` is Henstock outside of `π₁`: `π.tag J ∈ J.Icc` whenever `J ∈ π`, `J ∉ π₁`;
* `π` is subordinate to `r` outside of `π₁`;
* the distortion of `π` is equal to the maximum of the distortions of `π₁` and `π₂`.
-/
def union_compl_to_subordinate (π₁ : tagged_prepartition I) (π₂ : prepartition I)
  (hU : π₂.Union = I \ π₁.Union) (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  tagged_prepartition I :=
π₁.disj_union (π₂.to_subordinate r)
  (((π₂.Union_to_subordinate r).trans hU).symm ▸ disjoint_sdiff_self_right)

lemma is_partition_union_compl_to_subordinate (π₁ : tagged_prepartition I) (π₂ : prepartition I)
  (hU : π₂.Union = I \ π₁.Union) (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  is_partition (π₁.union_compl_to_subordinate π₂ hU r) :=
prepartition.is_partition_disj_union_of_eq_diff ((π₂.Union_to_subordinate r).trans hU)

@[simp] lemma union_compl_to_subordinate_boxes (π₁ : tagged_prepartition I) (π₂ : prepartition I)
  (hU : π₂.Union = I \ π₁.Union) (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  (π₁.union_compl_to_subordinate π₂ hU r).boxes = π₁.boxes ∪ (π₂.to_subordinate r).boxes :=
rfl

@[simp] lemma Union_union_compl_to_subordinate_boxes (π₁ : tagged_prepartition I)
  (π₂ : prepartition I) (hU : π₂.Union = I \ π₁.Union) (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  (π₁.union_compl_to_subordinate π₂ hU r).Union = I :=
(is_partition_union_compl_to_subordinate _ _ _ _).Union_eq

@[simp] lemma distortion_union_compl_to_subordinate (π₁ : tagged_prepartition I)
  (π₂ : prepartition I) (hU : π₂.Union = I \ π₁.Union) (r : (ι → ℝ) → Ioi (0 : ℝ)) :
  (π₁.union_compl_to_subordinate π₂ hU r).distortion = max π₁.distortion π₂.distortion :=
by simp [union_compl_to_subordinate]

end tagged_prepartition

end box_integral


-- ---------------------------------------------------------------------
-- Ejercicio . Demostrar que si f es una función suprayectiva de ℝ en ℝ,
-- entonces existe un x tal que (f x)^2 = 4.
-- ----------------------------------------------------------------------

import data.real.basic

open function

example
  {f : ℝ → ℝ}
  (h : surjective f)
  : ∃ x, (f x)^2 = 4 :=
begin
  cases h 2 with x hx,
  use x,
  rw hx,
  norm_num,
end

-- La prueba es
--
-- f : ℝ → ℝ,
-- h : surjective f
-- ⊢ ∃ (x : ℝ), f x ^ 2 = 4
--    >> cases h 2 with x hx,
-- x : ℝ,
-- hx : f x = 2
-- ⊢ ∃ (x : ℝ), f x ^ 2 = 4
--    >> use x,
-- ⊢ f x ^ 2 = 4
--    >> rw hx,
-- ⊢ 2 ^ 2 = 4
--    >> norm_num,
-- no goals


def fact : Nat → Nat
| 0     => 1
| (n+1) => (n+1)*fact n

def v1 := fact 10
theorem v1Eq : v1 = fact 10 :=
Eq.refl (fact 10)


-- Ley_de_absorcion_1.lean
-- Si R es un retículo y x, y ∈ R, entonces x ⊓ (x ⊔ y) = x
-- José A. Alonso Jiménez <https://jaalonso.github.io>
-- Sevilla, 20-octubre-2022
-- ---------------------------------------------------------------------

import order.lattice
variables {R : Type*} [lattice R]
variables x y : R

-- 1ª demostración
-- ===============

example : x ⊓ (x ⊔ y) = x :=
begin
  have h1 : x ⊓ (x ⊔ y) ≤ x, finish,
  have h2 : x ≤ x ⊓ (x ⊔ y), finish,
  show x ⊓ (x ⊔ y) = x,
    by exact le_antisymm h1 h2,
end

-- 2ª demostración
-- ===============

example : x ⊓ (x ⊔ y) = x :=
begin
  have h1 : x ⊓ (x ⊔ y) ≤ x := inf_le_left,
  have h2 : x ≤ x ⊓ (x ⊔ y),
  { have h2a : x ≤ x := rfl.ge,
    have h2b : x ≤ x ⊔ y := le_sup_left,
    show x ≤ x ⊓ (x ⊔ y),
      by exact le_inf h2a h2b, },
  show x ⊓ (x ⊔ y) = x,
    by exact le_antisymm h1 h2,
end

-- 3ª demostración
-- ===============

example : x ⊓ (x ⊔ y) = x :=
begin
  apply le_antisymm,
  { apply inf_le_left },
  { apply le_inf,
    { apply le_refl },
    { apply le_sup_left }},
end

-- 4ª demostración
example : x ⊓ (x ⊔ y) = x :=
-- by library_search
inf_sup_self

-- 5ª demostración
-- ===============

example : x ⊓ (x ⊔ y) = x :=
-- by hint
by simp


import Mathlib.Tactic.Basic
import Mathlib.Tactic.Cases

/-!
## Induction by Pattern Matching

In [Proofs by Mathematical Induction](../BackwardProofs/Induction.lean.md), we reviewed the use of
the induction’ tactic to perform proofs by induction. An alternative, more flexible style relies on
pattern matching and the Curry–Howard correspondence.

Recall the definition of the reverse of a list from [Function Definitions](../Basics/FunctionDefinitions.lean.md):

-/
def reverse {α : Type} : List α → List α
| [] => []
| (x :: xs) => reverse xs ++ [x]

/-!
In fact, `reverse` exists in Lean’s standard library, as `List.reverse`, but our definition is
optimized for reasoning. A useful property to prove is that `reverse` is its own inverse: `reverse
(reverse xs) = xs` for all lists `xs`. However, if we try to prove it by induction, we quickly run
into an obstacle. The induction step is
```lean
ih : ∀xs, reverse (reverse xs) = xs ⊢ reverse (reverse xs ++ [x]) = x :: xs
```
What is unpleasant about this subgoal is the presence of `++ [x]` inside the double
`reverse` sandwich. We need a way to “distribute” the outer `reverse` over `++` to
obtain a term that matches the induction hypothesis’s left-hand side. The trick is
to prove and use the following lemma:
-/
lemma reverse_append {α : Type} :
  ∀ xs ys : List α, reverse (xs ++ ys) = reverse ys ++ reverse xs
  | [], ys => by simp [reverse]
  | (x :: xs), ys => by simp [reverse, reverse_append xs, List.append_assoc]

/-!
In the proof of the lemma, the patterns on the left, `[]` and `x :: xs`, correspond to
the two constructors of the ∀-quantified variable `xs :: List α`. On the right-hand
side of each `=>` symbol is a proof for the corresponding case.

Inside the induction step’s proof, the induction hypothesis is available under
the same name as the lemma we are proving (`reverse_append`). We explicitly
pass `xs` as argument to the induction hypothesis. This is useful as documentation,
and it also prevents Lean from accidentally invoking the induction hypothesis in
a circular fashion on `x :: xs`. Lean’s termination checker would notice that the
argument is ill-founded and raise an error.

For reference, the corresponding tactical proof is as follows:
-/
lemma reverse_append₂ {α : Type} (xs ys : List α) :
  reverse (xs ++ ys) = reverse ys ++ reverse xs := by
  induction' xs
  case nil => simp [reverse]
  case cons x xs ih => simp [reverse, ih, List.append_assoc]
/-!
which can also be written
-/

lemma reverse_append₃ (as bs : List α) :
  (as ++ bs).reverse = bs.reverse ++ as.reverse := by
  induction as generalizing bs with
  | nil => simp
  | cons a as ih => simp [ih, List.append_assoc]

/-!
The lemma would also be provable, and useful, if we put `[y]` instead of `ys`. But it is a good
habit to state lemmas as generally as possible. This results in more reusable libraries. Moreover,
this is often necessary to obtain a strong enough induction hypothesis in a proof by induction. In
general, finding the right inductions and lemmas can be diffcult, requiring thought and creativity.

Simultaneous pattern matching on multiple variables is supported (e.g., `xs` and `ys` above). The
patterns are then separated by spaces. This explains why Lean requires us to put parentheses around
complex patterns, even when we match on a single variable. The general format is

```lean
lemma name (params₁ : type1₁) . . . (paramsₘ : typeₘ) :
statement
| patterns₁ := proof₁
.
.
.
| patternsₙ := proofₙ
```
Notice the strong similarity with the syntax of `def` (Section 1.3). The two commands are, in fact,
almost the same, the main exception being that `lemma` considers the defined term or the proof opaque,
whereas `def` keeps it transparent. Since the actual proofs are irrelevant once a lemma is proven
(Section 11), there is no need to expand them later. A similar distinction exists between `let` and
`have`.

By the Curry–Howard correspondence, a proof by induction by pattern matching is the same as a
recursive proof term. When we invoke the induction hypothesis, we are really just invoking a
recursive function recursively. This explains why the induction hypothesis has the same name as the
lemma we prove. Lean’s termination checker is used to establish well-foundedness of the proof by
induction.

With the reverse_append lemma in place, we can return to our initial goal:
-/
lemma reverse_reverse {α : Type} :
  ∀ xs : List α, reverse (reverse xs) = xs
  | [] => by rfl
  | (x :: xs) =>
  by simp [reverse, reverse_append, reverse_reverse xs]

/-!
Induction by pattern matching is highly popular among Lean users. Its main advantages are its
convenient syntax and its support for well-founded induction and not only structural induction, as
provided by the [induction’ tactic](../BackwardProofs/InductionTactic.lean.md). However, in this
guide, we will not need the full power of well-founded induction. Furthermore, for subtle logical
reasons, induction by pattern matching is not available for inductive predicates, which are the
topic of Chapter 5.

--BUGBUG: is this still true in lean4?
-/


import algebra.ring.basic
import data.rat.basic
import tactic.ring

/-
Bulgarian Mathematical Olympiad 1998, Problem 8

The polynomials Pₙ(x,y) for n = 1, 2, ... are defined by P₁(x,y) = 1 and

  Pₙ₊₁(x,y) = (x + y - 1)(y + 1)Pₙ(x,y+2) + (y - y²)Pₙ(x,y)

Prove that Pₙ(x,y) = Pₙ(y,x) for all x,y,n.

-/

variables {R : Type} [comm_ring R]

def P : ℕ → R → R → R
| 0 _ _ := 1
| (n+1) x y := (x + y - 1) * (y + 1) * P n x (y + 2) + (y - y^2) * P n x y

/- helper function
   Sₙ₋₁(x,y) = [(x + y)² - 1](y + 1)(x + 1)Pₙ₋₁(y+2, x+2).
-/
def S : ℕ → R → R → R
| n x y := ((x + y)^2 - 1) * (y + 1) * (x + 1) * P n (y + 2) (x + 2)

/- helper function
   Tₙ₋₁(x,y) = (y - y²)(x - x²)Pₙ₋₁(y, x).
-/
def T : ℕ → R → R → R
| n x y := (y - y^2) * (x - x^2) * P n y x

/- helper function
   Uₙ₋₁(x,y) = (x + y - 1) [(y + 1)(x - x²)Pₙ₋₁(y + 2, x)
                           + (x + 1)(y - y²) Pₙ₋₁(y, x + 2)]
-/
def U : ℕ → R → R → R
| n x y := (x + y - 1) *((y + 1)*(x - x^2) * P n (y + 2) x
                           + (x + 1) * (y - y^2) * P n y (x + 2))

theorem bulgaria1998_q8 (n : ℕ) (x y : R) : P n x y = P n y x :=
begin
  -- We induct on n. For n = 1,2 the result is evident.
  -- So we take n > 1 and suppose that the result is true for
  -- Pₙ₋₁(x,y) and Pₙ₋₂(x,y).
  revert x y,
  induction n using nat.strong_induction_on with n ih,
  cases n, { intros, refl },
  cases n,
  { intros, unfold P, ring },
  -- in the informal proof at this point, we're trying to
  -- prove the end result at n+1.
  -- In our formal version, that corresponds to proving the result for
  -- n.succ.succ

  /- We have
     Pₙ₊₁(x,y) = (x + y - 1)(y + 1)Pₙ(x,y+2) + (y - y²)Pₙ(x,y)
               = (x + y - 1)(y + 1)Pₙ(y+2,x) + (y - y²)Pₙ(y,x)
  -/

  have ih1 := ih n.succ (lt_add_one (nat.succ n)),
  have h1 : ∀ x y : R, P n.succ.succ x y =
             (x + y - 1) * (y + 1) * (P n.succ (y + 2) x) +
                 (y - y^2) * (P n.succ y x),
  { intros x y,
    calc P (n.succ.succ) x y
               = (x + y - 1) * (y + 1) * (P n.succ x (y + 2)) +
                   (y - y^2) * (P n.succ x y) : rfl
           ... = (x + y - 1) * (y + 1) * (P n.succ (y + 2) x) +
                   (y - y^2) * (P n.succ y x) : by {rw[ih1 x y,ih1 x (y+2)]} },

  have h2 : ∀ x y : R, (x + y - 1) * (y + 1) * P n.succ (y + 2) x
      = S n x y + (x + y - 1)* (y + 1) * (x - x^2)* P n (y+2) x,
  {intros x y, unfold S P, ring},

  have h_s_symm : ∀ m : ℕ, m < n.succ.succ → ∀ x y : R, S m x y = S m y x,
  { intros m hm x y, unfold S, rw[ih m hm (x + 2) (y + 2)], ring },

  have h4 : ∀ x y : R, (y - y^2) * P n.succ y x =
            (y - y^2) * (x + y -1) * (x + 1) * P n y (x + 2) + T n x y,
  { intros x y, unfold T P, ring },

  have h_t_symm : ∀ m : ℕ, m < n.succ.succ → ∀ x y : R, T m x y = T m y x,
  { intros m hm x y, unfold T, rw[ih m hm x y], ring },

  have h_u_symm : ∀ m : ℕ, m < n.succ.succ → ∀ x y : R, U m x y = U m y x,
  { intros m hm x y, unfold U, rw[ih m hm (y+2) x, ih m hm (x+2) y], ring },

  have h7 : ∀ x y : R, P n.succ.succ x y = S n x y + T n x y + U n x y,
  { intros x y, rw[h1 x y, h2 x y, h4 x y], unfold U, ring,},

  have h9 : n < n.succ.succ := nat.lt.step (lt_add_one n),

  intros x y,
  calc P n.succ.succ x y = S n x y + T n x y + U n x y : h7 x y
                     ... = S n y x + T n x y + U n x y : by rw[h_s_symm n h9 x y]
                     ... = S n y x + T n y x + U n x y : by rw[h_t_symm n h9 x y]
                     ... = S n y x + T n y x + U n y x : by rw[h_u_symm n h9 x y]
                     ... = P n.succ.succ y x : (h7 y x).symm
end


/- ** Inference rules ** -/

/-
So how do we decide whether a given proposition
can be judged to be true or not? Here is where
the semantics of a logic come into play.

The semantics of a logic comprises a set of rules,
called inference rules, that define the conditions
under which a given proposition can be judged to
be true.

Oversimplifying a bit, if you can apply one or more
inference rules to propositions you already know
to be true, and if by doing this you "deduce" some
new proposition, then you can conclude that that
new proposition must also be true. Such a "chain"
of inference rules, linking things already known
to be true to propositions that you want to prove
to be true because they follow logically is called
a proof. A valid proof is incontrovertible evidence
that the final proposition is true.

An inference rule is like a little program: it says,
if you can give me evidence (i.e., proofs) showing
that certain "input" propositions can be judged to
be true, then I will hand you back evidence (i.e.,
a proof) that shows that some new proposition can
also be judged to be true. We would say that from
the  proofs of the premises (the input propositions
already known to be true), the rule derives or deduces
a proof of the conclusion.

Logicians often write inference rules like this:

  list of input truth judgments
  ----------------------------- (name-of-rule)
  truth judgment for conclusion

The required input judgments, called premises (or
antecedents), are listed above the line. The name
of the rule is given to the right of the line. And
the proposition (or consequent) that can thereby
be judged to be true (the conclusion of the rule)
is written below the line.

For example, if we already have the truth judgment,
(0 = 0 : true), and another, (1 = 1: true), then the
inference rule that logicians call "and introduction"
(or "conjunction introduction") can be used to derive
a truth judgment for the new proposition, "0 = 0 and
1 = 1", typically written as 0 = 0 ∧ 1 = 1. (Hover
your mouse over special symbols in this editor to
learn how to use them in your work.)

Predicate logic will thus (in effect) include such
inference rules as this:

0 = 0 : true, 1 = 1 : true
-------------------------- and-introduction-*
      0 = 0 ∧ 1 = 1

This can be pronounced as, "If you already have
evidence (a proof) supporting the judgment that
0 = 0 is true, and if you also have evidence (a
proof) supporting the judgment that 1 = 1 is true,
then by applying the and-introduction-* rule,
you can deduce (obtain a proof justifying a truth
judgment for) the proposition, 0 = 0 ∧  1 = 1".

We've put a * on the name of this rule to indicate
that it's really just a special case of a far more
general inference rule for reasoning about equality.

Inference rules are usually written not in terms of
very specific propositions, such as 0 = 0, but in
terms of variables that can refer to any arbitrary
propositions. They are often called meta-variables.

In this way, inference rules become program-like, in
that they can take arbitrary inputs (of the correct
types), and whenever they are given such inputs, they
produce result of a promised type.

Here's a simple example of such a parameterized and
thereby generalized rule. If P is *any* proposition
(e.g., it could be 0 = 0 but might be some other
proposition), and Q is another proposition (e.g.,
1 = 1), and if both propositions are already known
to be true, then you can always conclude that the
proposition "P and Q", written P ∧ Q, must also be
true, for whatever propositions P and Q happen to
be.

Here is how the general form of this inference rule
would typically be written in a book on logic.

P : true, Q : true
------------------ (and.intro)
   P ∧ Q : true

The inference rule is called "and introduction"
because it produces a proof of a proposition
that now contains an "and" (∧). The rule can be
read as follows. If P and Q are propositions,
and if you have judged P to be true and you
have judged Q to be true, then you can judge
P ∧ Q to be true.
-/


/-
Copyright (c) 2021 Ivan Sadofschi Costa. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Ivan Sadofschi Costa
-/
import data.finsupp.defs

/-!
# `cons` and `tail` for maps `fin n →₀ M`

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

We interpret maps `fin n →₀ M` as `n`-tuples of elements of `M`,
We define the following operations:
* `finsupp.tail` : the tail of a map `fin (n + 1) →₀ M`, i.e., its last `n` entries;
* `finsupp.cons` : adding an element at the beginning of an `n`-tuple, to get an `n + 1`-tuple;

In this context, we prove some usual properties of `tail` and `cons`, analogous to those of
`data.fin.tuple.basic`.
-/

noncomputable theory

namespace finsupp

variables {n : ℕ} (i : fin n) {M : Type*} [has_zero M] (y : M)
  (t : fin (n + 1) →₀ M) (s : fin n →₀ M)

/-- `tail` for maps `fin (n + 1) →₀ M`. See `fin.tail` for more details. -/
def tail (s : fin (n + 1) →₀ M) : fin n →₀ M :=
finsupp.equiv_fun_on_finite.symm (fin.tail s)

/-- `cons` for maps `fin n →₀ M`. See `fin.cons` for more details. -/
def cons (y : M) (s : fin n →₀ M) : fin (n + 1) →₀ M :=
finsupp.equiv_fun_on_finite.symm (fin.cons y s : fin (n + 1) → M)

lemma tail_apply : tail t i = t i.succ := rfl

@[simp] lemma cons_zero : cons y s 0 = y := rfl

@[simp] lemma cons_succ : cons y s i.succ = s i := fin.cons_succ _ _ _

@[simp] lemma tail_cons : tail (cons y s) = s :=
ext $ λ k, by simp only [tail_apply, cons_succ]

@[simp] lemma cons_tail : cons (t 0) (tail t) = t :=
begin
  ext,
  by_cases c_a : a = 0,
  { rw [c_a, cons_zero] },
  { rw [←fin.succ_pred a c_a, cons_succ, ←tail_apply] },
end

@[simp] lemma cons_zero_zero : cons 0 (0 : fin n →₀ M) = 0 :=
begin
  ext,
  by_cases c : a = 0,
  { simp [c] },
  { rw [←fin.succ_pred a c, cons_succ],
    simp },
end

variables {s} {y}

lemma cons_ne_zero_of_left (h : y ≠ 0) : cons y s ≠ 0 :=
begin
  contrapose! h with c,
  rw [←cons_zero y s, c, finsupp.coe_zero, pi.zero_apply],
end

lemma cons_ne_zero_of_right (h : s ≠ 0) : cons y s ≠ 0 :=
begin
  contrapose! h with c,
  ext,
  simp [ ← cons_succ a y s, c],
end

lemma cons_ne_zero_iff : cons y s ≠ 0 ↔ y ≠ 0 ∨ s ≠ 0 :=
begin
  refine ⟨λ h, _, λ h, h.cases_on cons_ne_zero_of_left cons_ne_zero_of_right⟩,
  refine imp_iff_not_or.1 (λ h' c, h _),
  rw [h', c, finsupp.cons_zero_zero],
end

end finsupp


/-
Copyright (c) 2014 Robert Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Robert Lewis, Leonardo de Moura, Mario Carneiro, Floris van Doorn
-/
import algebra.field.basic
import algebra.group_power.lemmas
import algebra.group_power.order
import algebra.order.ring
import order.bounds
import tactic.monotonicity.basic

/-!
# Linear ordered (semi)fields

A linear ordered (semi)field is a (semi)field equipped with a linear order such that
* addition respects the order: `a ≤ b → c + a ≤ c + b`;
* multiplication of positives is positive: `0 < a → 0 < b → 0 < a * b`;
* `0 < 1`.

## Main Definitions

* `linear_ordered_semifield`: Typeclass for linear order semifields.
* `linear_ordered_field`: Typeclass for linear ordered fields.
-/

set_option old_structure_cmd true

variables {α β : Type*}

/-- A linear ordered semifield is a field with a linear order respecting the operations. -/
@[protect_proj] class linear_ordered_semifield (α : Type*)
  extends linear_ordered_semiring α, semifield α

/-- A linear ordered field is a field with a linear order respecting the operations. -/
@[protect_proj] class linear_ordered_field (α : Type*) extends linear_ordered_comm_ring α, field α

@[priority 100] -- See note [lower instance priority]
instance linear_ordered_field.to_linear_ordered_semifield [linear_ordered_field α] :
  linear_ordered_semifield α :=
{ ..linear_ordered_ring.to_linear_ordered_semiring, ..‹linear_ordered_field α› }

namespace function

/-- Pullback a `linear_ordered_semifield` under an injective map. -/
@[reducible] -- See note [reducible non-instances]
def injective.linear_ordered_semifield [linear_ordered_semifield α] [has_zero β] [has_one β]
  [has_add β] [has_mul β] [has_pow β ℕ] [has_smul ℕ β] [has_nat_cast β] [has_inv β] [has_div β]
  [has_pow β ℤ] (f : β → α) (hf : injective f) (zero : f 0 = 0) (one : f 1 = 1)
  (add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y)
  (inv : ∀ x, f (x⁻¹) = (f x)⁻¹) (div : ∀ x y, f (x / y) = f x / f y)
  (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x)
  (npow : ∀ x (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ x (n : ℤ), f (x ^ n) = f x ^ n)
  (nat_cast : ∀ n : ℕ, f n = n) :
  linear_ordered_semifield β :=
{ ..hf.linear_ordered_semiring f zero one add mul nsmul npow nat_cast,
  ..hf.semifield f zero one add mul inv div nsmul npow zpow nat_cast }

/-- Pullback a `linear_ordered_field` under an injective map. -/
@[reducible] -- See note [reducible non-instances]
def injective.linear_ordered_field [linear_ordered_field α] [has_zero β] [has_one β] [has_add β]
  [has_mul β] [has_neg β] [has_sub β] [has_pow β ℕ] [has_smul ℕ β] [has_smul ℤ β]
  [has_nat_cast β] [has_int_cast β][has_inv β] [has_div β] [has_pow β ℤ]
  (f : β → α) (hf : injective f) (zero : f 0 = 0) (one : f 1 = 1)
  (add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y)
  (neg : ∀ x, f (-x) = -f x) (sub : ∀ x y, f (x - y) = f x - f y)
  (inv : ∀ x, f (x⁻¹) = (f x)⁻¹) (div : ∀ x y, f (x / y) = f x / f y)
  (nsmul : ∀ x (n : ℕ), f (n • x) = n • f x) (zsmul : ∀ x (n : ℤ), f (n • x) = n • f x)
  (npow : ∀ x (n : ℕ), f (x ^ n) = f x ^ n) (zpow : ∀ x (n : ℤ), f (x ^ n) = f x ^ n)
  (nat_cast : ∀ n : ℕ, f n = n) (int_cast : ∀ n : ℤ, f n = n) :
  linear_ordered_field β :=
{ .. hf.linear_ordered_ring f zero one add mul neg sub nsmul zsmul npow nat_cast int_cast,
  .. hf.field f zero one add mul neg sub inv div nsmul zsmul npow zpow nat_cast int_cast }

end function

section linear_ordered_semifield
variables [linear_ordered_semifield α] {a b c d e : α}

/-- `equiv.mul_left₀` as an order_iso. -/
@[simps {simp_rhs := tt}]
def order_iso.mul_left₀ (a : α) (ha : 0 < a) : α ≃o α :=
{ map_rel_iff' := λ _ _, mul_le_mul_left ha, ..equiv.mul_left₀ a ha.ne' }

/-- `equiv.mul_right₀` as an order_iso. -/
@[simps {simp_rhs := tt}]
def order_iso.mul_right₀ (a : α) (ha : 0 < a) : α ≃o α :=
{ map_rel_iff' := λ _ _, mul_le_mul_right ha, ..equiv.mul_right₀ a ha.ne' }

/-!
### Lemmas about pos, nonneg, nonpos, neg
-/

@[simp] lemma inv_pos : 0 < a⁻¹ ↔ 0 < a :=
suffices ∀ a : α, 0 < a → 0 < a⁻¹,
from ⟨λ h, inv_inv a ▸ this _ h, this a⟩,
assume a ha, flip lt_of_mul_lt_mul_left ha.le $ by simp [ne_of_gt ha, zero_lt_one]

@[simp] lemma inv_nonneg : 0 ≤ a⁻¹ ↔ 0 ≤ a :=
by simp only [le_iff_eq_or_lt, inv_pos, zero_eq_inv]

@[simp] lemma inv_lt_zero : a⁻¹ < 0 ↔ a < 0 :=
by simp only [← not_le, inv_nonneg]

@[simp] lemma inv_nonpos : a⁻¹ ≤ 0 ↔ a ≤ 0 :=
by simp only [← not_lt, inv_pos]

lemma one_div_pos : 0 < 1 / a ↔ 0 < a :=
inv_eq_one_div a ▸ inv_pos

lemma one_div_neg : 1 / a < 0 ↔ a < 0 :=
inv_eq_one_div a ▸ inv_lt_zero

lemma one_div_nonneg : 0 ≤ 1 / a ↔ 0 ≤ a :=
inv_eq_one_div a ▸ inv_nonneg

lemma one_div_nonpos : 1 / a ≤ 0 ↔ a ≤ 0 :=
inv_eq_one_div a ▸ inv_nonpos

lemma div_pos (ha : 0 < a) (hb : 0 < b) : 0 < a / b :=
by { rw div_eq_mul_inv, exact mul_pos ha (inv_pos.2 hb) }

lemma div_nonneg (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a / b :=
by { rw div_eq_mul_inv, exact mul_nonneg ha (inv_nonneg.2 hb) }

lemma div_nonpos_of_nonpos_of_nonneg (ha : a ≤ 0) (hb : 0 ≤ b) : a / b ≤ 0 :=
by { rw div_eq_mul_inv, exact mul_nonpos_of_nonpos_of_nonneg ha (inv_nonneg.2 hb) }

lemma div_nonpos_of_nonneg_of_nonpos (ha : 0 ≤ a) (hb : b ≤ 0) : a / b ≤ 0 :=
by { rw div_eq_mul_inv, exact mul_nonpos_of_nonneg_of_nonpos ha (inv_nonpos.2 hb) }

/-!
### Relating one division with another term.
-/

lemma le_div_iff (hc : 0 < c) : a ≤ b / c ↔ a * c ≤ b :=
⟨λ h, div_mul_cancel b (ne_of_lt hc).symm ▸ mul_le_mul_of_nonneg_right h hc.le,
  λ h, calc
    a   = a * c * (1 / c) : mul_mul_div a (ne_of_lt hc).symm
    ... ≤ b * (1 / c)     : mul_le_mul_of_nonneg_right h (one_div_pos.2 hc).le
    ... = b / c           : (div_eq_mul_one_div b c).symm⟩

lemma le_div_iff' (hc : 0 < c) : a ≤ b / c ↔ c * a ≤ b :=
by rw [mul_comm, le_div_iff hc]

lemma div_le_iff (hb : 0 < b) : a / b ≤ c ↔ a ≤ c * b :=
⟨λ h, calc
  a = a / b * b : by rw (div_mul_cancel _ (ne_of_lt hb).symm)
  ... ≤ c * b     : mul_le_mul_of_nonneg_right h hb.le,
  λ h, calc
  a / b = a * (1 / b)     : div_eq_mul_one_div a b
  ... ≤ (c * b) * (1 / b) : mul_le_mul_of_nonneg_right h (one_div_pos.2 hb).le
  ... = (c * b) / b       : (div_eq_mul_one_div (c * b) b).symm
  ... = c                 : by refine (div_eq_iff (ne_of_gt hb)).mpr rfl⟩

lemma div_le_iff' (hb : 0 < b) : a / b ≤ c ↔ a ≤ b * c :=
by rw [mul_comm, div_le_iff hb]

lemma lt_div_iff (hc : 0 < c) : a < b / c ↔ a * c < b :=
lt_iff_lt_of_le_iff_le $ div_le_iff hc

lemma lt_div_iff' (hc : 0 < c) : a < b / c ↔ c * a < b :=
by rw [mul_comm, lt_div_iff hc]

lemma div_lt_iff (hc : 0 < c) : b / c < a ↔ b < a * c :=
lt_iff_lt_of_le_iff_le (le_div_iff hc)

lemma div_lt_iff' (hc : 0 < c) : b / c < a ↔ b < c * a :=
by rw [mul_comm, div_lt_iff hc]

lemma inv_mul_le_iff (h : 0 < b) : b⁻¹ * a ≤ c ↔ a ≤ b * c :=
begin
  rw [inv_eq_one_div, mul_comm, ← div_eq_mul_one_div],
  exact div_le_iff' h,
end

lemma inv_mul_le_iff' (h : 0 < b) : b⁻¹ * a ≤ c ↔ a ≤ c * b :=
by rw [inv_mul_le_iff h, mul_comm]

lemma mul_inv_le_iff (h : 0 < b) : a * b⁻¹ ≤ c ↔ a ≤ b * c :=
by rw [mul_comm, inv_mul_le_iff h]

lemma mul_inv_le_iff' (h : 0 < b) : a * b⁻¹ ≤ c ↔ a ≤ c * b :=
by rw [mul_comm, inv_mul_le_iff' h]

lemma div_self_le_one (a : α) : a / a ≤ 1 :=
if h : a = 0 then by simp [h] else by simp [h]

lemma inv_mul_lt_iff (h : 0 < b) : b⁻¹ * a < c ↔ a < b * c :=
begin
  rw [inv_eq_one_div, mul_comm, ← div_eq_mul_one_div],
  exact div_lt_iff' h,
end

lemma inv_mul_lt_iff' (h : 0 < b) : b⁻¹ * a < c ↔ a < c * b :=
by rw [inv_mul_lt_iff h, mul_comm]

lemma mul_inv_lt_iff (h : 0 < b) : a * b⁻¹ < c ↔ a < b * c :=
by rw [mul_comm, inv_mul_lt_iff h]

lemma mul_inv_lt_iff' (h : 0 < b) : a * b⁻¹ < c ↔ a < c * b :=
by rw [mul_comm, inv_mul_lt_iff' h]

lemma inv_pos_le_iff_one_le_mul (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ b * a :=
by { rw [inv_eq_one_div], exact div_le_iff ha }

lemma inv_pos_le_iff_one_le_mul' (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ a * b :=
by { rw [inv_eq_one_div], exact div_le_iff' ha }

lemma inv_pos_lt_iff_one_lt_mul (ha : 0 < a) : a⁻¹ < b ↔ 1 < b * a :=
by { rw [inv_eq_one_div], exact div_lt_iff ha }

lemma inv_pos_lt_iff_one_lt_mul' (ha : 0 < a) : a⁻¹ < b ↔ 1 < a * b :=
by { rw [inv_eq_one_div], exact div_lt_iff' ha }

/-- One direction of `div_le_iff` where `b` is allowed to be `0` (but `c` must be nonnegative) -/
lemma div_le_of_nonneg_of_le_mul (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ c * b) : a / b ≤ c :=
by { rcases eq_or_lt_of_le hb with rfl|hb', simp [hc], rwa [div_le_iff hb'] }

lemma div_le_one_of_le (h : a ≤ b) (hb : 0 ≤ b) : a / b ≤ 1 :=
div_le_of_nonneg_of_le_mul hb zero_le_one $ by rwa one_mul

/-!
### Bi-implications of inequalities using inversions
-/

lemma inv_le_inv_of_le (ha : 0 < a) (h : a ≤ b) : b⁻¹ ≤ a⁻¹ :=
by rwa [← one_div a, le_div_iff' ha, ← div_eq_mul_inv, div_le_iff (ha.trans_le h), one_mul]

/-- See `inv_le_inv_of_le` for the implication from right-to-left with one fewer assumption. -/
lemma inv_le_inv (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b⁻¹ ↔ b ≤ a :=
by rw [← one_div, div_le_iff ha, ← div_eq_inv_mul, le_div_iff hb, one_mul]

/-- In a linear ordered field, for positive `a` and `b` we have `a⁻¹ ≤ b ↔ b⁻¹ ≤ a`.
See also `inv_le_of_inv_le` for a one-sided implication with one fewer assumption. -/
lemma inv_le (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b ↔ b⁻¹ ≤ a :=
by rw [← inv_le_inv hb (inv_pos.2 ha), inv_inv]

lemma inv_le_of_inv_le (ha : 0 < a) (h : a⁻¹ ≤ b) : b⁻¹ ≤ a :=
(inv_le ha ((inv_pos.2 ha).trans_le h)).1 h

lemma le_inv (ha : 0 < a) (hb : 0 < b) : a ≤ b⁻¹ ↔ b ≤ a⁻¹ :=
by rw [← inv_le_inv (inv_pos.2 hb) ha, inv_inv]

/-- See `inv_lt_inv_of_lt` for the implication from right-to-left with one fewer assumption. -/
lemma inv_lt_inv (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b⁻¹ ↔ b < a :=
lt_iff_lt_of_le_iff_le (inv_le_inv hb ha)

lemma inv_lt_inv_of_lt (hb : 0 < b) (h : b < a) : a⁻¹ < b⁻¹ :=
(inv_lt_inv (hb.trans h) hb).2 h

/-- In a linear ordered field, for positive `a` and `b` we have `a⁻¹ < b ↔ b⁻¹ < a`.
See also `inv_lt_of_inv_lt` for a one-sided implication with one fewer assumption. -/
lemma inv_lt (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b ↔ b⁻¹ < a :=
lt_iff_lt_of_le_iff_le (le_inv hb ha)

lemma inv_lt_of_inv_lt (ha : 0 < a) (h : a⁻¹ < b) : b⁻¹ < a :=
(inv_lt ha ((inv_pos.2 ha).trans h)).1 h

lemma lt_inv (ha : 0 < a) (hb : 0 < b) : a < b⁻¹ ↔ b < a⁻¹ :=
lt_iff_lt_of_le_iff_le (inv_le hb ha)

lemma inv_lt_one (ha : 1 < a) : a⁻¹ < 1 :=
by rwa [inv_lt ((@zero_lt_one α _ _).trans ha) zero_lt_one, inv_one]

lemma one_lt_inv (h₁ : 0 < a) (h₂ : a < 1) : 1 < a⁻¹ :=
by rwa [lt_inv (@zero_lt_one α _ _) h₁, inv_one]

lemma inv_le_one (ha : 1 ≤ a) : a⁻¹ ≤ 1 :=
by rwa [inv_le ((@zero_lt_one α _ _).trans_le ha) zero_lt_one, inv_one]

lemma one_le_inv (h₁ : 0 < a) (h₂ : a ≤ 1) : 1 ≤ a⁻¹ :=
by rwa [le_inv (@zero_lt_one α _ _) h₁, inv_one]

lemma inv_lt_one_iff_of_pos (h₀ : 0 < a) : a⁻¹ < 1 ↔ 1 < a :=
⟨λ h₁, inv_inv a ▸ one_lt_inv (inv_pos.2 h₀) h₁, inv_lt_one⟩

lemma inv_lt_one_iff : a⁻¹ < 1 ↔ a ≤ 0 ∨ 1 < a :=
begin
  cases le_or_lt a 0 with ha ha,
  { simp [ha, (inv_nonpos.2 ha).trans_lt zero_lt_one] },
  { simp only [ha.not_le, false_or, inv_lt_one_iff_of_pos ha] }
end

lemma one_lt_inv_iff : 1 < a⁻¹ ↔ 0 < a ∧ a < 1 :=
⟨λ h, ⟨inv_pos.1 (zero_lt_one.trans h), inv_inv a ▸ inv_lt_one h⟩, and_imp.2 one_lt_inv⟩

lemma inv_le_one_iff : a⁻¹ ≤ 1 ↔ a ≤ 0 ∨ 1 ≤ a :=
begin
  rcases em (a = 1) with (rfl|ha),
  { simp [le_rfl] },
  { simp only [ne.le_iff_lt (ne.symm ha), ne.le_iff_lt (mt inv_eq_one.1 ha), inv_lt_one_iff] }
end

lemma one_le_inv_iff : 1 ≤ a⁻¹ ↔ 0 < a ∧ a ≤ 1 :=
⟨λ h, ⟨inv_pos.1 (zero_lt_one.trans_le h), inv_inv a ▸ inv_le_one h⟩, and_imp.2 one_le_inv⟩

/-!
### Relating two divisions.
-/

@[mono] lemma div_le_div_of_le (hc : 0 ≤ c) (h : a ≤ b) : a / c ≤ b / c :=
begin
  rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c],
  exact mul_le_mul_of_nonneg_right h (one_div_nonneg.2 hc)
end

-- Not a `mono` lemma b/c `div_le_div` is strictly more general
lemma div_le_div_of_le_left (ha : 0 ≤ a) (hc : 0 < c) (h : c ≤ b) : a / b ≤ a / c :=
begin
  rw [div_eq_mul_inv, div_eq_mul_inv],
  exact mul_le_mul_of_nonneg_left ((inv_le_inv (hc.trans_le h) hc).mpr h) ha
end

lemma div_le_div_of_le_of_nonneg (hab : a ≤ b) (hc : 0 ≤ c) : a / c ≤ b / c :=
div_le_div_of_le hc hab

lemma div_lt_div_of_lt (hc : 0 < c) (h : a < b) : a / c < b / c :=
begin
  rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c],
  exact mul_lt_mul_of_pos_right h (one_div_pos.2 hc)
end

lemma div_le_div_right (hc : 0 < c) : a / c ≤ b / c ↔ a ≤ b :=
⟨le_imp_le_of_lt_imp_lt $ div_lt_div_of_lt hc, div_le_div_of_le $ hc.le⟩

lemma div_lt_div_right (hc : 0 < c) : a / c < b / c ↔ a < b :=
lt_iff_lt_of_le_iff_le $ div_le_div_right hc

lemma div_lt_div_left (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : a / b < a / c ↔ c < b :=
by simp only [div_eq_mul_inv, mul_lt_mul_left ha, inv_lt_inv hb hc]

lemma div_le_div_left (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : a / b ≤ a / c ↔ c ≤ b :=
le_iff_le_iff_lt_iff_lt.2 (div_lt_div_left ha hc hb)

lemma div_lt_div_iff (b0 : 0 < b) (d0 : 0 < d) :
  a / b < c / d ↔ a * d < c * b :=
by rw [lt_div_iff d0, div_mul_eq_mul_div, div_lt_iff b0]

lemma div_le_div_iff (b0 : 0 < b) (d0 : 0 < d) : a / b ≤ c / d ↔ a * d ≤ c * b :=
by rw [le_div_iff d0, div_mul_eq_mul_div, div_le_iff b0]

@[mono] lemma div_le_div (hc : 0 ≤ c) (hac : a ≤ c) (hd : 0 < d) (hbd : d ≤ b) : a / b ≤ c / d :=
by { rw div_le_div_iff (hd.trans_le hbd) hd, exact mul_le_mul hac hbd hd.le hc }

lemma div_lt_div (hac : a < c) (hbd : d ≤ b) (c0 : 0 ≤ c) (d0 : 0 < d) :
  a / b < c / d :=
(div_lt_div_iff (d0.trans_le hbd) d0).2 (mul_lt_mul hac hbd d0 c0)

lemma div_lt_div' (hac : a ≤ c) (hbd : d < b) (c0 : 0 < c) (d0 : 0 < d) :
  a / b < c / d :=
(div_lt_div_iff (d0.trans hbd) d0).2 (mul_lt_mul' hac hbd d0.le c0)

lemma div_lt_div_of_lt_left (hc : 0 < c) (hb : 0 < b) (h : b < a) : c / a < c / b :=
(div_lt_div_left hc (hb.trans h) hb).mpr h

/-!
### Relating one division and involving `1`
-/

lemma div_le_self (ha : 0 ≤ a) (hb : 1 ≤ b) : a / b ≤ a :=
by simpa only [div_one] using div_le_div_of_le_left ha zero_lt_one hb

lemma div_lt_self (ha : 0 < a) (hb : 1 < b) : a / b < a :=
by simpa only [div_one] using div_lt_div_of_lt_left ha zero_lt_one hb

lemma le_div_self (ha : 0 ≤ a) (hb₀ : 0 < b) (hb₁ : b ≤ 1) : a ≤ a / b :=
by simpa only [div_one] using div_le_div_of_le_left ha hb₀ hb₁

lemma one_le_div (hb : 0 < b) : 1 ≤ a / b ↔ b ≤ a :=
by rw [le_div_iff hb, one_mul]

lemma div_le_one (hb : 0 < b) : a / b ≤ 1 ↔ a ≤ b :=
by rw [div_le_iff hb, one_mul]

lemma one_lt_div (hb : 0 < b) : 1 < a / b ↔ b < a :=
by rw [lt_div_iff hb, one_mul]

lemma div_lt_one (hb : 0 < b) : a / b < 1 ↔ a < b :=
by rw [div_lt_iff hb, one_mul]

lemma one_div_le (ha : 0 < a) (hb : 0 < b) : 1 / a ≤ b ↔ 1 / b ≤ a :=
by simpa using inv_le ha hb

lemma one_div_lt (ha : 0 < a) (hb : 0 < b) : 1 / a < b ↔ 1 / b < a :=
by simpa using inv_lt ha hb

lemma le_one_div (ha : 0 < a) (hb : 0 < b) : a ≤ 1 / b ↔ b ≤ 1 / a :=
by simpa using le_inv ha hb

lemma lt_one_div (ha : 0 < a) (hb : 0 < b) : a < 1 / b ↔ b < 1 / a :=
by simpa using lt_inv ha hb

/-!
### Relating two divisions, involving `1`
-/
lemma one_div_le_one_div_of_le (ha : 0 < a) (h : a ≤ b) : 1 / b ≤ 1 / a :=
by simpa using inv_le_inv_of_le ha h

lemma one_div_lt_one_div_of_lt (ha : 0 < a) (h : a < b) : 1 / b < 1 / a :=
by rwa [lt_div_iff' ha, ← div_eq_mul_one_div, div_lt_one (ha.trans h)]

lemma le_of_one_div_le_one_div (ha : 0 < a) (h : 1 / a ≤ 1 / b) : b ≤ a :=
le_imp_le_of_lt_imp_lt (one_div_lt_one_div_of_lt ha) h

lemma lt_of_one_div_lt_one_div (ha : 0 < a) (h : 1 / a < 1 / b) : b < a :=
lt_imp_lt_of_le_imp_le (one_div_le_one_div_of_le ha) h

/-- For the single implications with fewer assumptions, see `one_div_le_one_div_of_le` and
  `le_of_one_div_le_one_div` -/
lemma one_div_le_one_div (ha : 0 < a) (hb : 0 < b) : 1 / a ≤ 1 / b ↔ b ≤ a :=
div_le_div_left zero_lt_one ha hb

/-- For the single implications with fewer assumptions, see `one_div_lt_one_div_of_lt` and
  `lt_of_one_div_lt_one_div` -/
lemma one_div_lt_one_div (ha : 0 < a) (hb : 0 < b) : 1 / a < 1 / b ↔ b < a :=
div_lt_div_left zero_lt_one ha hb

lemma one_lt_one_div (h1 : 0 < a) (h2 : a < 1) : 1 < 1 / a :=
by rwa [lt_one_div (@zero_lt_one α _ _) h1, one_div_one]

lemma one_le_one_div (h1 : 0 < a) (h2 : a ≤ 1) : 1 ≤ 1 / a :=
by rwa [le_one_div (@zero_lt_one α _ _) h1, one_div_one]

/-!
### Results about halving.

The equalities also hold in semifields of characteristic `0`.
-/

/- TODO: Unify `add_halves` and `add_halves'` into a single lemma about
`division_semiring` + `char_zero` -/
lemma add_halves (a : α) : a / 2 + a / 2 = a :=
by rw [div_add_div_same, ← two_mul, mul_div_cancel_left a two_ne_zero]

-- TODO: Generalize to `division_semiring`
lemma add_self_div_two (a : α) : (a + a) / 2 = a :=
by rw [← mul_two, mul_div_cancel a two_ne_zero]

lemma half_pos (h : 0 < a) : 0 < a / 2 := div_pos h zero_lt_two

lemma one_half_pos : (0:α) < 1 / 2 := half_pos zero_lt_one

lemma div_two_lt_of_pos (h : 0 < a) : a / 2 < a :=
by { rw [div_lt_iff (@zero_lt_two α _ _)], exact lt_mul_of_one_lt_right h one_lt_two }

lemma half_lt_self : 0 < a → a / 2 < a := div_two_lt_of_pos

lemma half_le_self (ha_nonneg : 0 ≤ a) : a / 2 ≤ a :=
begin
  by_cases h0 : a = 0,
  { simp [h0], },
  { rw ← ne.def at h0,
    exact (half_lt_self (lt_of_le_of_ne ha_nonneg h0.symm)).le, },
end

lemma one_half_lt_one : (1 / 2 : α) < 1 := half_lt_self zero_lt_one

lemma left_lt_add_div_two : a < (a + b) / 2 ↔ a < b := by simp [lt_div_iff, mul_two]

lemma add_div_two_lt_right : (a + b) / 2 < b ↔ a < b := by simp [div_lt_iff, mul_two]

/-!
### Miscellaneous lemmas
-/

lemma mul_le_mul_of_mul_div_le (h : a * (b / c) ≤ d) (hc : 0 < c) : b * a ≤ d * c :=
begin
  rw [← mul_div_assoc] at h,
  rwa [mul_comm b, ← div_le_iff hc],
end

lemma div_mul_le_div_mul_of_div_le_div (h : a / b ≤ c / d) (he : 0 ≤ e) :
  a / (b * e) ≤ c / (d * e) :=
begin
  rw [div_mul_eq_div_mul_one_div, div_mul_eq_div_mul_one_div],
  exact mul_le_mul_of_nonneg_right h (one_div_nonneg.2 he)
end

lemma exists_pos_mul_lt {a : α} (h : 0 < a) (b : α) : ∃ c : α, 0 < c ∧ b * c < a :=
begin
  have : 0 < a / max (b + 1) 1, from div_pos h (lt_max_iff.2 (or.inr zero_lt_one)),
  refine ⟨a / max (b + 1) 1, this, _⟩,
  rw [← lt_div_iff this, div_div_cancel' h.ne'],
  exact lt_max_iff.2 (or.inl $ lt_add_one _)
end

lemma monotone.div_const {β : Type*} [preorder β] {f : β → α} (hf : monotone f)
  {c : α} (hc : 0 ≤ c) : monotone (λ x, (f x) / c) :=
by simpa only [div_eq_mul_inv] using hf.mul_const (inv_nonneg.2 hc)

lemma strict_mono.div_const {β : Type*} [preorder β] {f : β → α} (hf : strict_mono f)
  {c : α} (hc : 0 < c) :
  strict_mono (λ x, (f x) / c) :=
by simpa only [div_eq_mul_inv] using hf.mul_const (inv_pos.2 hc)

@[priority 100] -- see Note [lower instance priority]
instance linear_ordered_field.to_densely_ordered : densely_ordered α :=
{ dense := λ a₁ a₂ h, ⟨(a₁ + a₂) / 2,
  calc a₁ = (a₁ + a₁) / 2 : (add_self_div_two a₁).symm
      ... < (a₁ + a₂) / 2 : div_lt_div_of_lt zero_lt_two (add_lt_add_left h _),
  calc (a₁ + a₂) / 2 < (a₂ + a₂) / 2 : div_lt_div_of_lt zero_lt_two (add_lt_add_right h _)
                 ... = a₂            : add_self_div_two a₂⟩ }

lemma min_div_div_right {c : α} (hc : 0 ≤ c) (a b : α) : min (a / c) (b / c) = (min a b) / c :=
eq.symm $ monotone.map_min (λ x y, div_le_div_of_le hc)

lemma max_div_div_right {c : α} (hc : 0 ≤ c) (a b : α) : max (a / c) (b / c) = (max a b) / c :=
eq.symm $ monotone.map_max (λ x y, div_le_div_of_le hc)

lemma one_div_strict_anti_on : strict_anti_on (λ x : α, 1 / x) (set.Ioi 0) :=
λ x x1 y y1 xy, (one_div_lt_one_div (set.mem_Ioi.mp y1) (set.mem_Ioi.mp x1)).mpr xy

lemma one_div_pow_le_one_div_pow_of_le (a1 : 1 ≤ a) {m n : ℕ} (mn : m ≤ n) :
  1 / a ^ n ≤ 1 / a ^ m :=
by refine (one_div_le_one_div _ _).mpr (pow_le_pow a1 mn);
  exact pow_pos (zero_lt_one.trans_le a1) _

lemma one_div_pow_lt_one_div_pow_of_lt (a1 : 1 < a) {m n : ℕ} (mn : m < n) :
  1 / a ^ n < 1 / a ^ m :=
by refine (one_div_lt_one_div _ _).mpr (pow_lt_pow a1 mn);
  exact pow_pos (trans zero_lt_one a1) _

lemma one_div_pow_anti (a1 : 1 ≤ a) : antitone (λ n : ℕ, 1 / a ^ n) :=
λ m n, one_div_pow_le_one_div_pow_of_le a1

lemma one_div_pow_strict_anti (a1 : 1 < a) : strict_anti (λ n : ℕ, 1 / a ^ n) :=
λ m n, one_div_pow_lt_one_div_pow_of_lt a1

lemma inv_strict_anti_on : strict_anti_on (λ x : α, x⁻¹) (set.Ioi 0) :=
λ x hx y hy xy, (inv_lt_inv hy hx).2 xy

lemma inv_pow_le_inv_pow_of_le (a1 : 1 ≤ a) {m n : ℕ} (mn : m ≤ n) :
  (a ^ n)⁻¹ ≤ (a ^ m)⁻¹ :=
by convert one_div_pow_le_one_div_pow_of_le a1 mn; simp

lemma inv_pow_lt_inv_pow_of_lt (a1 : 1 < a) {m n : ℕ} (mn : m < n) :
  (a ^ n)⁻¹ < (a ^ m)⁻¹ :=
by convert one_div_pow_lt_one_div_pow_of_lt a1 mn; simp

lemma inv_pow_anti (a1 : 1 ≤ a) : antitone (λ n : ℕ, (a ^ n)⁻¹) :=
λ m n, inv_pow_le_inv_pow_of_le a1

lemma inv_pow_strict_anti (a1 : 1 < a) : strict_anti (λ n : ℕ, (a ^ n)⁻¹) :=
λ m n, inv_pow_lt_inv_pow_of_lt a1

/-! ### Results about `is_lub` and `is_glb` -/

lemma is_glb.mul_left {s : set α} (ha : 0 ≤ a) (hs : is_glb s b) :
  is_glb ((λ b, a * b) '' s) (a * b) :=
begin
  rcases lt_or_eq_of_le ha with ha | rfl,
  { exact (order_iso.mul_left₀ _ ha).is_glb_image'.2 hs, },
  { simp_rw zero_mul,
    rw hs.nonempty.image_const,
    exact is_glb_singleton },
end

lemma is_glb.mul_right {s : set α} (ha : 0 ≤ a) (hs : is_glb s b) :
  is_glb ((λ b, b * a) '' s) (b * a) :=
by simpa [mul_comm] using hs.mul_left ha

end linear_ordered_semifield

section
variables [linear_ordered_field α] {a b c d : α}

/-! ### Lemmas about pos, nonneg, nonpos, neg -/

lemma div_pos_iff : 0 < a / b ↔ 0 < a ∧ 0 < b ∨ a < 0 ∧ b < 0 := by simp [division_def, mul_pos_iff]
lemma div_neg_iff : a / b < 0 ↔ 0 < a ∧ b < 0 ∨ a < 0 ∧ 0 < b := by simp [division_def, mul_neg_iff]

lemma div_nonneg_iff : 0 ≤ a / b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 :=
by simp [division_def, mul_nonneg_iff]

lemma div_nonpos_iff : a / b ≤ 0 ↔ 0 ≤ a ∧ b ≤ 0 ∨ a ≤ 0 ∧ 0 ≤ b :=
by simp [division_def, mul_nonpos_iff]

lemma div_nonneg_of_nonpos (ha : a ≤ 0) (hb : b ≤ 0) : 0 ≤ a / b :=
div_nonneg_iff.2 $ or.inr ⟨ha, hb⟩

lemma div_pos_of_neg_of_neg (ha : a < 0) (hb : b < 0) : 0 < a / b :=
div_pos_iff.2 $ or.inr ⟨ha, hb⟩

lemma div_neg_of_neg_of_pos (ha : a < 0) (hb : 0 < b) : a / b < 0 :=
div_neg_iff.2 $ or.inr ⟨ha, hb⟩

lemma div_neg_of_pos_of_neg (ha : 0 < a) (hb : b < 0) : a / b < 0 :=
div_neg_iff.2 $ or.inl ⟨ha, hb⟩

/-! ### Relating one division with another term -/

lemma div_le_iff_of_neg (hc : c < 0) : b / c ≤ a ↔ a * c ≤ b :=
⟨λ h, div_mul_cancel b (ne_of_lt hc) ▸ mul_le_mul_of_nonpos_right h hc.le,
  λ h, calc
    a = a * c * (1 / c) : mul_mul_div a (ne_of_lt hc)
  ... ≥ b * (1 / c)     : mul_le_mul_of_nonpos_right h (one_div_neg.2 hc).le
  ... = b / c           : (div_eq_mul_one_div b c).symm⟩

lemma div_le_iff_of_neg' (hc : c < 0) : b / c ≤ a ↔ c * a ≤ b :=
by rw [mul_comm, div_le_iff_of_neg hc]

lemma le_div_iff_of_neg (hc : c < 0) : a ≤ b / c ↔ b ≤ a * c :=
by rw [← neg_neg c, mul_neg, div_neg, le_neg,
    div_le_iff (neg_pos.2 hc), neg_mul]

lemma le_div_iff_of_neg' (hc : c < 0) : a ≤ b / c ↔ b ≤ c * a :=
by rw [mul_comm, le_div_iff_of_neg hc]

lemma div_lt_iff_of_neg (hc : c < 0) : b / c < a ↔ a * c < b :=
lt_iff_lt_of_le_iff_le $ le_div_iff_of_neg hc

lemma div_lt_iff_of_neg' (hc : c < 0) : b / c < a ↔ c * a < b :=
by rw [mul_comm, div_lt_iff_of_neg hc]

lemma lt_div_iff_of_neg (hc : c < 0) : a < b / c ↔ b < a * c :=
lt_iff_lt_of_le_iff_le $ div_le_iff_of_neg hc

lemma lt_div_iff_of_neg' (hc : c < 0) : a < b / c ↔ b < c * a :=
by rw [mul_comm, lt_div_iff_of_neg hc]

/-! ### Bi-implications of inequalities using inversions -/

lemma inv_le_inv_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ ≤ b⁻¹ ↔ b ≤ a :=
by rw [← one_div, div_le_iff_of_neg ha, ← div_eq_inv_mul, div_le_iff_of_neg hb, one_mul]

lemma inv_le_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ ≤ b ↔ b⁻¹ ≤ a :=
by rw [← inv_le_inv_of_neg hb (inv_lt_zero.2 ha), inv_inv]

lemma le_inv_of_neg (ha : a < 0) (hb : b < 0) : a ≤ b⁻¹ ↔ b ≤ a⁻¹ :=
by rw [← inv_le_inv_of_neg (inv_lt_zero.2 hb) ha, inv_inv]

lemma inv_lt_inv_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ < b⁻¹ ↔ b < a :=
lt_iff_lt_of_le_iff_le (inv_le_inv_of_neg hb ha)

lemma inv_lt_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ < b ↔ b⁻¹ < a :=
lt_iff_lt_of_le_iff_le (le_inv_of_neg hb ha)

lemma lt_inv_of_neg (ha : a < 0) (hb : b < 0) : a < b⁻¹ ↔ b < a⁻¹ :=
lt_iff_lt_of_le_iff_le (inv_le_of_neg hb ha)

/-! ### Relating two divisions -/

lemma div_le_div_of_nonpos_of_le (hc : c ≤ 0) (h : b ≤ a) : a / c ≤ b / c :=
begin
  rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c],
  exact mul_le_mul_of_nonpos_right h (one_div_nonpos.2 hc)
end

lemma div_lt_div_of_neg_of_lt (hc : c < 0) (h : b < a) : a / c < b / c :=
begin
  rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c],
  exact mul_lt_mul_of_neg_right h (one_div_neg.2 hc)
end

lemma div_le_div_right_of_neg (hc : c < 0) : a / c ≤ b / c ↔ b ≤ a :=
⟨le_imp_le_of_lt_imp_lt $ div_lt_div_of_neg_of_lt hc, div_le_div_of_nonpos_of_le $ hc.le⟩

lemma div_lt_div_right_of_neg (hc : c < 0) : a / c < b / c ↔ b < a :=
lt_iff_lt_of_le_iff_le $ div_le_div_right_of_neg hc

/-! ### Relating one division and involving `1` -/

lemma one_le_div_of_neg (hb : b < 0) : 1 ≤ a / b ↔ a ≤ b :=
by rw [le_div_iff_of_neg hb, one_mul]

lemma div_le_one_of_neg (hb : b < 0) : a / b ≤ 1 ↔ b ≤ a :=
by rw [div_le_iff_of_neg hb, one_mul]

lemma one_lt_div_of_neg (hb : b < 0) : 1 < a / b ↔ a < b :=
by rw [lt_div_iff_of_neg hb, one_mul]

lemma div_lt_one_of_neg (hb : b < 0) : a / b < 1 ↔ b < a :=
by rw [div_lt_iff_of_neg hb, one_mul]

lemma one_div_le_of_neg (ha : a < 0) (hb : b < 0) : 1 / a ≤ b ↔ 1 / b ≤ a :=
by simpa using inv_le_of_neg ha hb

lemma one_div_lt_of_neg (ha : a < 0) (hb : b < 0) : 1 / a < b ↔ 1 / b < a :=
by simpa using inv_lt_of_neg ha hb

lemma le_one_div_of_neg (ha : a < 0) (hb : b < 0) : a ≤ 1 / b ↔ b ≤ 1 / a :=
by simpa using le_inv_of_neg ha hb

lemma lt_one_div_of_neg (ha : a < 0) (hb : b < 0) : a < 1 / b ↔ b < 1 / a :=
by simpa using lt_inv_of_neg ha hb

lemma one_lt_div_iff : 1 < a / b ↔ 0 < b ∧ b < a ∨ b < 0 ∧ a < b :=
begin
  rcases lt_trichotomy b 0 with (hb|rfl|hb),
  { simp [hb, hb.not_lt, one_lt_div_of_neg] },
  { simp [lt_irrefl, zero_le_one] },
  { simp [hb, hb.not_lt, one_lt_div] }
end

lemma one_le_div_iff : 1 ≤ a / b ↔ 0 < b ∧ b ≤ a ∨ b < 0 ∧ a ≤ b :=
begin
  rcases lt_trichotomy b 0 with (hb|rfl|hb),
  { simp [hb, hb.not_lt, one_le_div_of_neg] },
  { simp [lt_irrefl, zero_lt_one.not_le, zero_lt_one] },
  { simp [hb, hb.not_lt, one_le_div] }
end

lemma div_lt_one_iff : a / b < 1 ↔ 0 < b ∧ a < b ∨ b = 0 ∨ b < 0 ∧ b < a :=
begin
  rcases lt_trichotomy b 0 with (hb|rfl|hb),
  { simp [hb, hb.not_lt, hb.ne, div_lt_one_of_neg] },
  { simp [zero_lt_one], },
  { simp [hb, hb.not_lt, div_lt_one, hb.ne.symm] }
end

lemma div_le_one_iff : a / b ≤ 1 ↔ 0 < b ∧ a ≤ b ∨ b = 0 ∨ b < 0 ∧ b ≤ a :=
begin
  rcases lt_trichotomy b 0 with (hb|rfl|hb),
  { simp [hb, hb.not_lt, hb.ne, div_le_one_of_neg] },
  { simp [zero_le_one], },
  { simp [hb, hb.not_lt, div_le_one, hb.ne.symm] }
end

/-! ### Relating two divisions, involving `1` -/

lemma one_div_le_one_div_of_neg_of_le (hb : b < 0) (h : a ≤ b) : 1 / b ≤ 1 / a :=
by rwa [div_le_iff_of_neg' hb, ← div_eq_mul_one_div, div_le_one_of_neg (h.trans_lt hb)]

lemma one_div_lt_one_div_of_neg_of_lt (hb : b < 0) (h : a < b) : 1 / b < 1 / a :=
by rwa [div_lt_iff_of_neg' hb, ← div_eq_mul_one_div, div_lt_one_of_neg (h.trans hb)]

lemma le_of_neg_of_one_div_le_one_div (hb : b < 0) (h : 1 / a ≤ 1 / b) : b ≤ a :=
le_imp_le_of_lt_imp_lt (one_div_lt_one_div_of_neg_of_lt hb) h

lemma lt_of_neg_of_one_div_lt_one_div (hb : b < 0) (h : 1 / a < 1 / b) : b < a :=
lt_imp_lt_of_le_imp_le (one_div_le_one_div_of_neg_of_le hb) h

/-- For the single implications with fewer assumptions, see `one_div_lt_one_div_of_neg_of_lt` and
  `lt_of_one_div_lt_one_div` -/
lemma one_div_le_one_div_of_neg (ha : a < 0) (hb : b < 0) : 1 / a ≤ 1 / b ↔ b ≤ a :=
by simpa [one_div] using inv_le_inv_of_neg ha hb

/-- For the single implications with fewer assumptions, see `one_div_lt_one_div_of_lt` and
  `lt_of_one_div_lt_one_div` -/
lemma one_div_lt_one_div_of_neg (ha : a < 0) (hb : b < 0) : 1 / a < 1 / b ↔ b < a :=
lt_iff_lt_of_le_iff_le (one_div_le_one_div_of_neg hb ha)

lemma one_div_lt_neg_one (h1 : a < 0) (h2 : -1 < a) : 1 / a < -1 :=
suffices 1 / a < 1 / -1, by rwa one_div_neg_one_eq_neg_one at this,
one_div_lt_one_div_of_neg_of_lt h1 h2

lemma one_div_le_neg_one (h1 : a < 0) (h2 : -1 ≤ a) : 1 / a ≤ -1 :=
suffices 1 / a ≤ 1 / -1, by rwa one_div_neg_one_eq_neg_one at this,
one_div_le_one_div_of_neg_of_le h1 h2

/-! ### Results about halving -/

lemma sub_self_div_two (a : α) : a - a / 2 = a / 2 :=
suffices a / 2 + a / 2 - a / 2 = a / 2, by rwa add_halves at this,
by rw [add_sub_cancel]

lemma div_two_sub_self (a : α) : a / 2 - a = - (a / 2) :=
suffices a / 2 - (a / 2 + a / 2) = - (a / 2), by rwa add_halves at this,
by rw [sub_add_eq_sub_sub, sub_self, zero_sub]

lemma add_sub_div_two_lt (h : a < b) : a + (b - a) / 2 < b :=
begin
  rwa [← div_sub_div_same, sub_eq_add_neg, add_comm (b/2), ← add_assoc, ← sub_eq_add_neg,
    ← lt_sub_iff_add_lt, sub_self_div_two, sub_self_div_two, div_lt_div_right (@zero_lt_two α _ _)]
end

/--  An inequality involving `2`. -/
lemma sub_one_div_inv_le_two (a2 : 2 ≤ a) : (1 - 1 / a)⁻¹ ≤ 2 :=
begin
  -- Take inverses on both sides to obtain `2⁻¹ ≤ 1 - 1 / a`
  refine (inv_le_inv_of_le (inv_pos.2 zero_lt_two) _).trans_eq (inv_inv (2 : α)),
  -- move `1 / a` to the left and `1 - 1 / 2 = 1 / 2` to the right to obtain `1 / a ≤ ⅟ 2`
  refine (le_sub_iff_add_le.2 (_ : _ + 2⁻¹ = _ ).le).trans ((sub_le_sub_iff_left 1).2 _),
  { -- show 2⁻¹ + 2⁻¹ = 1
    exact (two_mul _).symm.trans (mul_inv_cancel two_ne_zero) },
  { -- take inverses on both sides and use the assumption `2 ≤ a`.
    exact (one_div a).le.trans (inv_le_inv_of_le zero_lt_two a2) }
end

/-! ### Results about `is_lub` and `is_glb` -/

-- TODO: Generalize to `linear_ordered_semifield`
lemma is_lub.mul_left {s : set α} (ha : 0 ≤ a) (hs : is_lub s b) :
  is_lub ((λ b, a * b) '' s) (a * b) :=
begin
  rcases lt_or_eq_of_le ha with ha | rfl,
  { exact (order_iso.mul_left₀ _ ha).is_lub_image'.2 hs, },
  { simp_rw zero_mul,
    rw hs.nonempty.image_const,
    exact is_lub_singleton },
end

-- TODO: Generalize to `linear_ordered_semifield`
lemma is_lub.mul_right {s : set α} (ha : 0 ≤ a) (hs : is_lub s b) :
  is_lub ((λ b, b * a) '' s) (b * a) :=
by simpa [mul_comm] using hs.mul_left ha

/-! ### Miscellaneous lemmmas -/

lemma mul_sub_mul_div_mul_neg_iff (hc : c ≠ 0) (hd : d ≠ 0) :
  (a * d - b * c) / (c * d) < 0 ↔ a / c < b / d :=
by rw [mul_comm b c, ← div_sub_div _ _ hc hd, sub_lt_zero]

lemma mul_sub_mul_div_mul_nonpos_iff (hc : c ≠ 0) (hd : d ≠ 0) :
  (a * d - b * c) / (c * d) ≤ 0 ↔ a / c ≤ b / d :=
by rw [mul_comm b c, ← div_sub_div _ _ hc hd, sub_nonpos]

alias mul_sub_mul_div_mul_neg_iff ↔ div_lt_div_of_mul_sub_mul_div_neg mul_sub_mul_div_mul_neg
alias mul_sub_mul_div_mul_nonpos_iff ↔
  div_le_div_of_mul_sub_mul_div_nonpos mul_sub_mul_div_mul_nonpos

lemma exists_add_lt_and_pos_of_lt (h : b < a) : ∃ c, b + c < a ∧ 0 < c :=
⟨(a - b) / 2, add_sub_div_two_lt h, div_pos (sub_pos_of_lt h) zero_lt_two⟩

lemma le_of_forall_sub_le (h : ∀ ε > 0, b - ε ≤ a) : b ≤ a :=
begin
  contrapose! h,
  simpa only [and_comm ((0 : α) < _), lt_sub_iff_add_lt, gt_iff_lt]
    using exists_add_lt_and_pos_of_lt h,
end

lemma mul_self_inj_of_nonneg (a0 : 0 ≤ a) (b0 : 0 ≤ b) : a * a = b * b ↔ a = b :=
mul_self_eq_mul_self_iff.trans $ or_iff_left_of_imp $
  λ h, by { subst a, have : b = 0 := le_antisymm (neg_nonneg.1 a0) b0, rw [this, neg_zero] }

lemma min_div_div_right_of_nonpos (hc : c ≤ 0) (a b : α) : min (a / c) (b / c) = (max a b) / c :=
eq.symm $ antitone.map_max $ λ x y, div_le_div_of_nonpos_of_le hc

lemma max_div_div_right_of_nonpos (hc : c ≤ 0) (a b : α) : max (a / c) (b / c) = (min a b) / c :=
eq.symm $ antitone.map_min $ λ x y, div_le_div_of_nonpos_of_le hc

lemma abs_inv (a : α) : |a⁻¹| = (|a|)⁻¹ := (abs_hom : α →*₀ α).map_inv a
lemma abs_div (a b : α) : |a / b| = |a| / |b| := (abs_hom : α →*₀ α).map_div a b
lemma abs_one_div (a : α) : |1 / a| = 1 / |a| := by rw [abs_div, abs_one]

lemma pow_minus_two_nonneg : 0 ≤ a^(-2 : ℤ) :=
begin
  simp only [inv_nonneg, zpow_neg],
  change 0 ≤ a ^ ((2 : ℕ) : ℤ),
  rw zpow_coe_nat,
  apply sq_nonneg,
end

/-- Bernoulli's inequality reformulated to estimate `(n : α)`. -/
lemma nat.cast_le_pow_sub_div_sub (H : 1 < a)  (n : ℕ) : (n : α) ≤ (a ^ n - 1) / (a - 1) :=
(le_div_iff (sub_pos.2 H)).2 $ le_sub_left_of_add_le $
  one_add_mul_sub_le_pow ((neg_le_self zero_le_one).trans H.le) _

/-- For any `a > 1` and a natural `n` we have `n ≤ a ^ n / (a - 1)`. See also
`nat.cast_le_pow_sub_div_sub` for a stronger inequality with `a ^ n - 1` in the numerator. -/
theorem nat.cast_le_pow_div_sub (H : 1 < a) (n : ℕ) : (n : α) ≤ a ^ n / (a - 1) :=
(n.cast_le_pow_sub_div_sub H).trans $ div_le_div_of_le (sub_nonneg.2 H.le)
  (sub_le_self _ zero_le_one)

end


/-
Copyright (c) 2020 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Robert Y. Lewis
-/
import data.mv_polynomial.monad

/-!
## Expand multivariate polynomials

Given a multivariate polynomial `φ`, one may replace every occurence of `X i` by `X i ^ n`,
for some natural number `n`.
This operation is called `mv_polynomial.expand` and it is an algebra homomorphism.

### Main declaration

* `mv_polynomial.expand`: expand a polynomial by a factor of p, so `∑ aₙ xⁿ` becomes `∑ aₙ xⁿᵖ`.
-/

open_locale big_operators

namespace mv_polynomial

variables {σ τ R S : Type*} [comm_semiring R] [comm_semiring S]

/-- Expand the polynomial by a factor of p, so `∑ aₙ xⁿ` becomes `∑ aₙ xⁿᵖ`.

See also `polynomial.expand`. -/
noncomputable def expand (p : ℕ) : mv_polynomial σ R →ₐ[R] mv_polynomial σ R :=
{ commutes' := λ r, eval₂_hom_C _ _ _,
  .. (eval₂_hom C (λ i, (X i) ^ p) : mv_polynomial σ R →+* mv_polynomial σ R) }

@[simp] lemma expand_C (p : ℕ) (r : R) : expand p (C r : mv_polynomial σ R) = C r :=
eval₂_hom_C _ _ _

@[simp] lemma expand_X (p : ℕ) (i : σ) : expand p (X i : mv_polynomial σ R) = X i ^ p :=
eval₂_hom_X' _ _ _

@[simp] lemma expand_monomial (p : ℕ) (d : σ →₀ ℕ) (r : R) :
  expand p (monomial d r) = C r * ∏ i in d.support, (X i ^ p) ^ d i :=
bind₁_monomial _ _ _

lemma expand_one_apply (f : mv_polynomial σ R) : expand 1 f = f :=
by simp only [expand, bind₁_X_left, alg_hom.id_apply, ring_hom.to_fun_eq_coe,
  eval₂_hom_C_left, alg_hom.coe_to_ring_hom, pow_one, alg_hom.coe_mk]

@[simp] lemma expand_one : expand 1 = alg_hom.id R (mv_polynomial σ R) :=
by { ext1 f, rw [expand_one_apply, alg_hom.id_apply] }

lemma expand_comp_bind₁ (p : ℕ) (f : σ → mv_polynomial τ R) :
  (expand p).comp (bind₁ f) = bind₁ (λ i, expand p (f i)) :=
by { apply alg_hom_ext, intro i, simp only [alg_hom.comp_apply, bind₁_X_right], }

lemma expand_bind₁ (p : ℕ) (f : σ → mv_polynomial τ R) (φ : mv_polynomial σ R) :
  expand p (bind₁ f φ) = bind₁ (λ i, expand p (f i)) φ :=
by rw [← alg_hom.comp_apply, expand_comp_bind₁]

@[simp]
lemma map_expand (f : R →+* S) (p : ℕ) (φ : mv_polynomial σ R) :
  map f (expand p φ) = expand p (map f φ) :=
by simp [expand, map_bind₁]

@[simp]
lemma rename_expand (f : σ → τ) (p : ℕ) (φ : mv_polynomial σ R) :
  rename f (expand p φ) = expand p (rename f φ) :=
by simp [expand, bind₁_rename, rename_bind₁]

@[simp] lemma rename_comp_expand (f : σ → τ) (p : ℕ) :
  (rename f).comp (expand p) =
    (expand p).comp (rename f : mv_polynomial σ R →ₐ[R] mv_polynomial τ R) :=
by { ext1 φ, simp only [rename_expand, alg_hom.comp_apply] }

end mv_polynomial


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

! This file was ported from Lean 3 source module algebra.order.group.abs
! leanprover-community/mathlib commit 2196ab363eb097c008d4497125e0dde23fb36db2
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Algebra.Abs
import Mathlib.Algebra.Order.Group.OrderIso
import Mathlib.Order.MinMax

/-!
# Absolute values in ordered groups.
-/

variable {α : Type _}

open Function

section CovariantAddLe

section Neg

-- see Note [lower instance priority]
/-- `abs a` is the absolute value of `a`. -/
@[to_additive "`abs a` is the absolute value of `a`"]
instance (priority := 100) Inv.toHasAbs [Inv α] [Sup α] : Abs α :=
  ⟨fun a => a ⊔ a⁻¹⟩
#align has_inv.to_has_abs Inv.toHasAbs
#align has_neg.to_has_abs Neg.toHasAbs

@[to_additive]
theorem abs_eq_sup_inv [Inv α] [Sup α] (a : α) : |a| = a ⊔ a⁻¹ :=
  rfl
#align abs_eq_sup_inv abs_eq_sup_inv
#align abs_eq_sup_neg abs_eq_sup_neg

variable [Neg α] [LinearOrder α] {a b : α}

theorem abs_eq_max_neg : abs a = max a (-a) :=
  rfl
#align abs_eq_max_neg abs_eq_max_neg

theorem abs_choice (x : α) : |x| = x ∨ |x| = -x :=
  max_choice _ _
#align abs_choice abs_choice

theorem abs_le' : |a| ≤ b ↔ a ≤ b ∧ -a ≤ b :=
  max_le_iff
#align abs_le' abs_le'

theorem le_abs : a ≤ |b| ↔ a ≤ b ∨ a ≤ -b :=
  le_max_iff
#align le_abs le_abs

theorem le_abs_self (a : α) : a ≤ |a| :=
  le_max_left _ _
#align le_abs_self le_abs_self

theorem neg_le_abs_self (a : α) : -a ≤ |a| :=
  le_max_right _ _
#align neg_le_abs_self neg_le_abs_self

theorem lt_abs : a < |b| ↔ a < b ∨ a < -b :=
  lt_max_iff
#align lt_abs lt_abs

theorem abs_le_abs (h₀ : a ≤ b) (h₁ : -a ≤ b) : |a| ≤ |b| :=
  (abs_le'.2 ⟨h₀, h₁⟩).trans (le_abs_self b)
#align abs_le_abs abs_le_abs

theorem abs_by_cases (P : α → Prop) {a : α} (h1 : P a) (h2 : P (-a)) : P (|a|) :=
  sup_ind _ _ h1 h2
#align abs_by_cases abs_by_cases

end Neg

section AddGroup

variable [AddGroup α] [LinearOrder α]

@[simp]
theorem abs_neg (a : α) : |(-a)| = |a| := by rw [abs_eq_max_neg, max_comm, neg_neg, abs_eq_max_neg]
#align abs_neg abs_neg

theorem eq_or_eq_neg_of_abs_eq {a b : α} (h : |a| = b) : a = b ∨ a = -b := by
  simpa only [← h, eq_comm (a := |a|), neg_eq_iff_eq_neg] using abs_choice a
#align eq_or_eq_neg_of_abs_eq eq_or_eq_neg_of_abs_eq

theorem abs_eq_abs {a b : α} : |a| = |b| ↔ a = b ∨ a = -b := by
  refine' ⟨fun h => _, fun h => _⟩
  · obtain rfl | rfl := eq_or_eq_neg_of_abs_eq h <;>
      simpa only [neg_eq_iff_eq_neg (a := |b|), neg_inj, or_comm] using abs_choice b
  · cases' h with h h <;>
    simp [h, abs_neg]
#align abs_eq_abs abs_eq_abs

theorem abs_sub_comm (a b : α) : |a - b| = |b - a| :=
  calc
    |a - b| = |(-(b - a))| := congr_arg _ (neg_sub b a).symm
    _ = |b - a| := abs_neg (b - a)

#align abs_sub_comm abs_sub_comm

variable [CovariantClass α α (· + ·) (· ≤ ·)] {a b c : α}

theorem abs_of_nonneg (h : 0 ≤ a) : |a| = a :=
  max_eq_left <| (neg_nonpos.2 h).trans h
#align abs_of_nonneg abs_of_nonneg

theorem abs_of_pos (h : 0 < a) : |a| = a :=
  abs_of_nonneg h.le
#align abs_of_pos abs_of_pos

theorem abs_of_nonpos (h : a ≤ 0) : |a| = -a :=
  max_eq_right <| h.trans (neg_nonneg.2 h)
#align abs_of_nonpos abs_of_nonpos

theorem abs_of_neg (h : a < 0) : |a| = -a :=
  abs_of_nonpos h.le
#align abs_of_neg abs_of_neg

theorem abs_le_abs_of_nonneg (ha : 0 ≤ a) (hab : a ≤ b) : |a| ≤ |b| := by
  rwa [abs_of_nonneg ha, abs_of_nonneg (ha.trans hab)]
#align abs_le_abs_of_nonneg abs_le_abs_of_nonneg

@[simp]
theorem abs_zero : |0| = (0 : α) :=
  abs_of_nonneg le_rfl
#align abs_zero abs_zero

@[simp]
theorem abs_pos : 0 < |a| ↔ a ≠ 0 := by
  rcases lt_trichotomy a 0 with (ha | rfl | ha)
  · simp [abs_of_neg ha, neg_pos, ha.ne, ha]
  · simp
  · simp [abs_of_pos ha, ha, ha.ne.symm]
#align abs_pos abs_pos

theorem abs_pos_of_pos (h : 0 < a) : 0 < |a| :=
  abs_pos.2 h.ne.symm
#align abs_pos_of_pos abs_pos_of_pos

theorem abs_pos_of_neg (h : a < 0) : 0 < |a| :=
  abs_pos.2 h.ne
#align abs_pos_of_neg abs_pos_of_neg

theorem neg_abs_le_self (a : α) : -|a| ≤ a := by
  cases' le_total 0 a with h h
  · calc
      -|a| = -a := congr_arg Neg.neg (abs_of_nonneg h)
      _ ≤ 0 := neg_nonpos.mpr h
      _ ≤ a := h

  · calc
      -|a| = - -a := congr_arg Neg.neg (abs_of_nonpos h)
      _ ≤ a := (neg_neg a).le

#align neg_abs_le_self neg_abs_le_self

theorem add_abs_nonneg (a : α) : 0 ≤ a + |a| := by
  rw [← add_right_neg a]
  apply add_le_add_left
  exact neg_le_abs_self a
#align add_abs_nonneg add_abs_nonneg

theorem neg_abs_le_neg (a : α) : -|a| ≤ -a := by simpa using neg_abs_le_self (-a)
#align neg_abs_le_neg neg_abs_le_neg

@[simp]
theorem abs_nonneg (a : α) : 0 ≤ |a| :=
  (le_total 0 a).elim (fun h => h.trans (le_abs_self a)) fun h =>
    (neg_nonneg.2 h).trans <| neg_le_abs_self a
#align abs_nonneg abs_nonneg

@[simp]
theorem abs_abs (a : α) : |(|a|)| = |a| :=
  abs_of_nonneg <| abs_nonneg a
#align abs_abs abs_abs

@[simp]
theorem abs_eq_zero : |a| = 0 ↔ a = 0 :=
  Decidable.not_iff_not.1 <| ne_comm.trans <| (abs_nonneg a).lt_iff_ne.symm.trans abs_pos
#align abs_eq_zero abs_eq_zero

@[simp]
theorem abs_nonpos_iff {a : α} : |a| ≤ 0 ↔ a = 0 :=
  (abs_nonneg a).le_iff_eq.trans abs_eq_zero
#align abs_nonpos_iff abs_nonpos_iff

variable [CovariantClass α α (swap (· + ·)) (· ≤ ·)]

theorem abs_le_abs_of_nonpos (ha : a ≤ 0) (hab : b ≤ a) : |a| ≤ |b| := by
  rw [abs_of_nonpos ha, abs_of_nonpos (hab.trans ha)]
  exact neg_le_neg_iff.mpr hab
#align abs_le_abs_of_nonpos abs_le_abs_of_nonpos

theorem abs_lt : |a| < b ↔ -b < a ∧ a < b :=
  max_lt_iff.trans <| and_comm.trans <| by rw [neg_lt]
#align abs_lt abs_lt

theorem neg_lt_of_abs_lt (h : |a| < b) : -b < a :=
  (abs_lt.mp h).1
#align neg_lt_of_abs_lt neg_lt_of_abs_lt

theorem lt_of_abs_lt (h : |a| < b) : a < b :=
  (abs_lt.mp h).2
#align lt_of_abs_lt lt_of_abs_lt

theorem max_sub_min_eq_abs' (a b : α) : max a b - min a b = |a - b| := by
  cases' le_total a b with ab ba
  · rw [max_eq_right ab, min_eq_left ab, abs_of_nonpos, neg_sub]
    rwa [sub_nonpos]
  · rw [max_eq_left ba, min_eq_right ba, abs_of_nonneg]
    rwa [sub_nonneg]
#align max_sub_min_eq_abs' max_sub_min_eq_abs'

theorem max_sub_min_eq_abs (a b : α) : max a b - min a b = |b - a| := by
  rw [abs_sub_comm]
  exact max_sub_min_eq_abs' _ _
#align max_sub_min_eq_abs max_sub_min_eq_abs

end AddGroup

end CovariantAddLe

section LinearOrderedAddCommGroup

variable [LinearOrderedAddCommGroup α] {a b c d : α}

-- Porting note:
-- Lean can perfectly well find this instance,
-- but in the rewrites below it is going looking for it without having fixed `α`.
example : CovariantClass α α (swap fun x y ↦ x + y) fun x y ↦ x ≤ y := inferInstance

theorem abs_le : |a| ≤ b ↔ -b ≤ a ∧ a ≤ b := by rw [abs_le', and_comm, @neg_le α]
#align abs_le abs_le

theorem le_abs' : a ≤ |b| ↔ b ≤ -a ∨ a ≤ b := by rw [le_abs, or_comm, @le_neg α]
#align le_abs' le_abs'

theorem neg_le_of_abs_le (h : |a| ≤ b) : -b ≤ a :=
  (abs_le.mp h).1
#align neg_le_of_abs_le neg_le_of_abs_le

theorem le_of_abs_le (h : |a| ≤ b) : a ≤ b :=
  (abs_le.mp h).2
#align le_of_abs_le le_of_abs_le

@[to_additive]
theorem apply_abs_le_mul_of_one_le' {β : Type _} [MulOneClass β] [Preorder β]
    [CovariantClass β β (· * ·) (· ≤ ·)] [CovariantClass β β (swap (· * ·)) (· ≤ ·)] {f : α → β}
    {a : α} (h₁ : 1 ≤ f a) (h₂ : 1 ≤ f (-a)) : f (|a|) ≤ f a * f (-a) :=
  (le_total a 0).rec (fun ha => (abs_of_nonpos ha).symm ▸ le_mul_of_one_le_left' h₁) fun ha =>
    (abs_of_nonneg ha).symm ▸ le_mul_of_one_le_right' h₂
#align apply_abs_le_mul_of_one_le' apply_abs_le_mul_of_one_le'
#align apply_abs_le_add_of_nonneg' apply_abs_le_add_of_nonneg'

@[to_additive]
theorem apply_abs_le_mul_of_one_le {β : Type _} [MulOneClass β] [Preorder β]
    [CovariantClass β β (· * ·) (· ≤ ·)] [CovariantClass β β (swap (· * ·)) (· ≤ ·)] {f : α → β}
    (h : ∀ x, 1 ≤ f x) (a : α) : f (|a|) ≤ f a * f (-a) :=
  apply_abs_le_mul_of_one_le' (h _) (h _)
#align apply_abs_le_mul_of_one_le apply_abs_le_mul_of_one_le
#align apply_abs_le_add_of_nonneg apply_abs_le_add_of_nonneg

/-- The **triangle inequality** in `LinearOrderedAddCommGroup`s. -/
theorem abs_add (a b : α) : |a + b| ≤ |a| + |b| :=
  abs_le.2
    ⟨(neg_add (|a|) (|b|)).symm ▸
        add_le_add ((@neg_le α ..).2 <| neg_le_abs_self _) ((@neg_le α ..).2 <| neg_le_abs_self _),
      add_le_add (le_abs_self _) (le_abs_self _)⟩
#align abs_add abs_add

theorem abs_add' (a b : α) : |a| ≤ |b| + |b + a| := by simpa using abs_add (-b) (b + a)
#align abs_add' abs_add'

theorem abs_sub (a b : α) : |a - b| ≤ |a| + |b| := by
  rw [sub_eq_add_neg, ← abs_neg b]
  exact abs_add a _
#align abs_sub abs_sub

theorem abs_sub_le_iff : |a - b| ≤ c ↔ a - b ≤ c ∧ b - a ≤ c := by
  rw [abs_le, neg_le_sub_iff_le_add, sub_le_iff_le_add', and_comm, sub_le_iff_le_add']
#align abs_sub_le_iff abs_sub_le_iff

theorem abs_sub_lt_iff : |a - b| < c ↔ a - b < c ∧ b - a < c := by
  rw [@abs_lt α, neg_lt_sub_iff_lt_add', sub_lt_iff_lt_add', and_comm, sub_lt_iff_lt_add']
#align abs_sub_lt_iff abs_sub_lt_iff

theorem sub_le_of_abs_sub_le_left (h : |a - b| ≤ c) : b - c ≤ a :=
  sub_le_comm.1 <| (abs_sub_le_iff.1 h).2
#align sub_le_of_abs_sub_le_left sub_le_of_abs_sub_le_left

theorem sub_le_of_abs_sub_le_right (h : |a - b| ≤ c) : a - c ≤ b :=
  sub_le_of_abs_sub_le_left (abs_sub_comm a b ▸ h)
#align sub_le_of_abs_sub_le_right sub_le_of_abs_sub_le_right

theorem sub_lt_of_abs_sub_lt_left (h : |a - b| < c) : b - c < a :=
  sub_lt_comm.1 <| (abs_sub_lt_iff.1 h).2
#align sub_lt_of_abs_sub_lt_left sub_lt_of_abs_sub_lt_left

theorem sub_lt_of_abs_sub_lt_right (h : |a - b| < c) : a - c < b :=
  sub_lt_of_abs_sub_lt_left (abs_sub_comm a b ▸ h)
#align sub_lt_of_abs_sub_lt_right sub_lt_of_abs_sub_lt_right

theorem abs_sub_abs_le_abs_sub (a b : α) : |a| - |b| ≤ |a - b| :=
  (@sub_le_iff_le_add α ..).2 <|
    calc
      |a| = |a - b + b| := by rw [sub_add_cancel]
      _ ≤ |a - b| + |b| := abs_add _ _

#align abs_sub_abs_le_abs_sub abs_sub_abs_le_abs_sub

theorem abs_abs_sub_abs_le_abs_sub (a b : α) : |(|a| - |b|)| ≤ |a - b| :=
  abs_sub_le_iff.2
    ⟨abs_sub_abs_le_abs_sub _ _, by rw [abs_sub_comm]; apply abs_sub_abs_le_abs_sub⟩
#align abs_abs_sub_abs_le_abs_sub abs_abs_sub_abs_le_abs_sub

theorem abs_eq (hb : 0 ≤ b) : |a| = b ↔ a = b ∨ a = -b := by
  refine' ⟨eq_or_eq_neg_of_abs_eq, _⟩
  rintro (rfl | rfl) <;> simp only [abs_neg, abs_of_nonneg hb]
#align abs_eq abs_eq

theorem abs_le_max_abs_abs (hab : a ≤ b) (hbc : b ≤ c) : |b| ≤ max (|a|) (|c|) :=
  abs_le'.2
    ⟨by simp [hbc.trans (le_abs_self c)], by
      simp [((@neg_le_neg_iff α ..).mpr hab).trans (neg_le_abs_self a)]⟩
#align abs_le_max_abs_abs abs_le_max_abs_abs

theorem min_abs_abs_le_abs_max : min (|a|) (|b|) ≤ |max a b| :=
  (le_total a b).elim (fun h => (min_le_right _ _).trans_eq <| congr_arg _ (max_eq_right h).symm)
    fun h => (min_le_left _ _).trans_eq <| congr_arg _ (max_eq_left h).symm
#align min_abs_abs_le_abs_max min_abs_abs_le_abs_max

theorem min_abs_abs_le_abs_min : min (|a|) (|b|) ≤ |min a b| :=
  (le_total a b).elim (fun h => (min_le_left _ _).trans_eq <| congr_arg _ (min_eq_left h).symm)
    fun h => (min_le_right _ _).trans_eq <| congr_arg _ (min_eq_right h).symm
#align min_abs_abs_le_abs_min min_abs_abs_le_abs_min

theorem abs_max_le_max_abs_abs : |max a b| ≤ max (|a|) (|b|) :=
  (le_total a b).elim (fun h => (congr_arg _ <| max_eq_right h).trans_le <| le_max_right _ _)
    fun h => (congr_arg _ <| max_eq_left h).trans_le <| le_max_left _ _
#align abs_max_le_max_abs_abs abs_max_le_max_abs_abs

theorem abs_min_le_max_abs_abs : |min a b| ≤ max (|a|) (|b|) :=
  (le_total a b).elim (fun h => (congr_arg _ <| min_eq_left h).trans_le <| le_max_left _ _) fun h =>
    (congr_arg _ <| min_eq_right h).trans_le <| le_max_right _ _
#align abs_min_le_max_abs_abs abs_min_le_max_abs_abs

theorem eq_of_abs_sub_eq_zero {a b : α} (h : |a - b| = 0) : a = b :=
  sub_eq_zero.1 <| abs_eq_zero.1 h
#align eq_of_abs_sub_eq_zero eq_of_abs_sub_eq_zero

theorem abs_sub_le (a b c : α) : |a - c| ≤ |a - b| + |b - c| :=
  calc
    |a - c| = |a - b + (b - c)| := by rw [sub_add_sub_cancel]
    _ ≤ |a - b| + |b - c| := abs_add _ _

#align abs_sub_le abs_sub_le

theorem abs_add_three (a b c : α) : |a + b + c| ≤ |a| + |b| + |c| :=
  (abs_add _ _).trans (add_le_add_right (abs_add _ _) _)
#align abs_add_three abs_add_three

theorem dist_bdd_within_interval {a b lb ub : α} (hal : lb ≤ a) (hau : a ≤ ub) (hbl : lb ≤ b)
    (hbu : b ≤ ub) : |a - b| ≤ ub - lb :=
  abs_sub_le_iff.2 ⟨sub_le_sub hau hbl, sub_le_sub hbu hal⟩
#align dist_bdd_within_interval dist_bdd_within_interval

theorem eq_of_abs_sub_nonpos (h : |a - b| ≤ 0) : a = b :=
  eq_of_abs_sub_eq_zero (le_antisymm h (abs_nonneg (a - b)))
#align eq_of_abs_sub_nonpos eq_of_abs_sub_nonpos

end LinearOrderedAddCommGroup