/-
Copyright (c) 2022 Junyan Xu. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Junyan Xu

! This file was ported from Lean 3 source module data.dfinsupp.well_founded
! leanprover-community/mathlib commit 1dac236edca9b4b6f5f00b1ad831e35f89472837
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Dfinsupp.Lex
import Mathbin.Order.GameAdd
import Mathbin.Order.Antisymmetrization
import Mathbin.SetTheory.Ordinal.Basic

/-!
# Well-foundedness of the lexicographic and product orders on `dfinsupp` and `pi`

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

The primary results are `dfinsupp.lex.well_founded` and the two variants that follow it,
which essentially say that if `(>)` is a well order on `ι`, `(<)` is well-founded on each
`α i`, and `0` is a bottom element in `α i`, then the lexicographic `(<)` is well-founded
on `Π₀ i, α i`. The proof is modelled on the proof of `well_founded.cut_expand`.

The results are used to prove `pi.lex.well_founded` and two variants, which say that if
`ι` is finite and equipped with a linear order and `(<)` is well-founded on each `α i`,
then the lexicographic `(<)` is well-founded on `Π i, α i`, and the same is true for
`Π₀ i, α i` (`dfinsupp.lex.well_founded_of_finite`), because `dfinsupp` is order-isomorphic
to `pi` when `ι` is finite.

Finally, we deduce `dfinsupp.well_founded_lt`, `pi.well_founded_lt`,
`dfinsupp.well_founded_lt_of_finite` and variants, which concern the product order
rather than the lexicographic one. An order on `ι` is not required in these results,
but we deduce them from the well-foundedness of the lexicographic order by choosing
a well order on `ι` so that the product order `(<)` becomes a subrelation
of the lexicographic `(<)`.

All results are provided in two forms whenever possible: a general form where the relations
can be arbitrary (not the `(<)` of a preorder, or not even transitive, etc.) and a specialized
form provided as `well_founded_lt` instances where the `(d)finsupp/pi` type (or their `lex`
type synonyms) carries a natural `(<)`.

Notice that the definition of `dfinsupp.lex` says that `x < y` according to `dfinsupp.lex r s`
iff there exists a coordinate `i : ι` such that `x i < y i` according to `s i`, and at all
`r`-smaller coordinates `j` (i.e. satisfying `r j i`), `x` remains unchanged relative to `y`;
in other words, coordinates `j` such that `¬ r j i` and `j ≠ i` are exactly where changes
can happen arbitrarily. This explains the appearance of `rᶜ ⊓ (≠)` in
`dfinsupp.acc_single` and `dfinsupp.well_founded`. When `r` is trichotomous (e.g. the `(<)`
of a linear order), `¬ r j i ∧ j ≠ i` implies `r i j`, so it suffices to require `r.swap`
to be well-founded.
-/

variable {ι : Type _} {α : ι → Type _}

namespace Dfinsupp

variable [hz : ∀ i, Zero (α i)] (r : ι → ι → Prop) (s : ∀ i, α i → α i → Prop)

include hz

open Relation Prod

/- warning: dfinsupp.lex_fibration -> Dfinsupp.lex_fibration is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [hz : forall (i : ι), Zero.{u2} (α i)] (r : ι -> ι -> Prop) (s : forall (i : ι), (α i) -> (α i) -> Prop) [_inst_1 : forall (i : ι) (s : Set.{u1} ι), Decidable (Membership.Mem.{u1, u1} ι (Set.{u1} ι) (Set.hasMem.{u1} ι) i s)], Relation.Fibration.{max u1 u2, max u1 u2} (Prod.{u1, max u1 u2} (Set.{u1} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)))) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (InvImage.{succ (max u1 u2), succ (max u1 u2)} (Prod.{u1, max u1 u2} (Set.{u1} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)))) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) (Prod.GameAdd.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s)) (Prod.snd.{u1, max u1 u2} (Set.{u1} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))))) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (fun (x : Prod.{u1, max u1 u2} (Set.{u1} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)))) => Dfinsupp.piecewise.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) (Prod.fst.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Prod.snd.{u1, max u1 u2} (Set.{u1} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) x)) (Prod.snd.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Prod.snd.{u1, max u1 u2} (Set.{u1} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) x)) (Prod.fst.{u1, max u1 u2} (Set.{u1} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) x) (fun (i : ι) => _inst_1 i (Prod.fst.{u1, max u1 u2} (Set.{u1} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) x)))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [hz : forall (i : ι), Zero.{u1} (α i)] (r : ι -> ι -> Prop) (s : forall (i : ι), (α i) -> (α i) -> Prop) [_inst_1 : forall (i : ι) (s : Set.{u2} ι), Decidable (Membership.mem.{u2, u2} ι (Set.{u2} ι) (Set.instMembershipSet.{u2} ι) i s)], Relation.Fibration.{max u2 u1, max u1 u2} (Prod.{u2, max u2 u1} (Set.{u2} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)))) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (InvImage.{succ (max u2 u1), succ (max u1 u2)} (Prod.{u2, max u2 u1} (Set.{u2} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)))) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) (Prod.GameAdd.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s)) (Prod.snd.{u2, max u2 u1} (Set.{u2} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))))) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (fun (x : Prod.{u2, max u2 u1} (Set.{u2} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)))) => Dfinsupp.piecewise.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) (Prod.fst.{max u2 u1, max u2 u1} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Prod.snd.{u2, max u2 u1} (Set.{u2} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) x)) (Prod.snd.{max u2 u1, max u2 u1} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Prod.snd.{u2, max u2 u1} (Set.{u2} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) x)) (Prod.fst.{u2, max u2 u1} (Set.{u2} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) x) (fun (i : ι) => _inst_1 i (Prod.fst.{u2, max u2 u1} (Set.{u2} ι) (Prod.{max u1 u2, max u1 u2} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i))) x)))
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex_fibration Dfinsupp.lex_fibrationₓ'. -/
/-- This key lemma says that if a finitely supported dependent function `x₀` is obtained by merging
  two such functions `x₁` and `x₂`, and if we evolve `x₀` down the `dfinsupp.lex` relation one
  step and get `x`, we can always evolve one of `x₁` and `x₂` down the `dfinsupp.lex` relation
  one step while keeping the other unchanged, and merge them back (possibly in a different way)
  to get back `x`. In other words, the two parts evolve essentially independently under
  `dfinsupp.lex`. This is used to show that a function `x` is accessible if
  `dfinsupp.single i (x i)` is accessible for each `i` in the (finite) support of `x`
  (`dfinsupp.lex.acc_of_single`). -/
theorem lex_fibration [∀ (i) (s : Set ι), Decidable (i ∈ s)] :
    Fibration (InvImage (GameAdd (Dfinsupp.Lex r s) (Dfinsupp.Lex r s)) snd) (Dfinsupp.Lex r s)
      fun x => piecewise x.2.1 x.2.2 x.1 :=
  by
  rintro ⟨p, x₁, x₂⟩ x ⟨i, hr, hs⟩
  simp_rw [piecewise_apply] at hs hr
  split_ifs  at hs
  classical
    on_goal 1 =>
      refine' ⟨⟨{ j | r j i → j ∈ p }, piecewise x₁ x { j | r j i }, x₂⟩, game_add.fst ⟨i, _⟩, _⟩
    on_goal 3 =>
      refine' ⟨⟨{ j | r j i ∧ j ∈ p }, x₁, piecewise x₂ x { j | r j i }⟩, game_add.snd ⟨i, _⟩, _⟩
    pick_goal 3
    iterate 2
      simp_rw [piecewise_apply]
      refine' ⟨fun j h => if_pos h, _⟩
      convert hs
      refine' ite_eq_right_iff.2 fun h' => (hr i h').symm ▸ _
      first |rw [if_neg h]|rw [if_pos h]
    all_goals ext j; simp_rw [piecewise_apply]; split_ifs with h₁ h₂
    · rw [hr j h₂, if_pos (h₁ h₂)]
    · rfl
    · rw [Set.mem_setOf, not_imp] at h₁
      rw [hr j h₁.1, if_neg h₁.2]
    · rw [hr j h₁.1, if_pos h₁.2]
    · rw [hr j h₂, if_neg fun h' => h₁ ⟨h₂, h'⟩]
    · rfl
#align dfinsupp.lex_fibration Dfinsupp.lex_fibration

variable {r s}

/- warning: dfinsupp.lex.acc_of_single_erase -> Dfinsupp.Lex.acc_of_single_erase is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [hz : forall (i : ι), Zero.{u2} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop} [_inst_1 : DecidableEq.{succ u1} ι] {x : Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)} (i : ι), (Acc.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.single.{u1, u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) i (coeFn.{succ (max u1 u2), max (succ u1) (succ u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (fun (_x : Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) => forall (i : ι), α i) (Dfinsupp.hasCoeToFun.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) x i))) -> (Acc.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.erase.{u1, u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) i x)) -> (Acc.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) x)
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [hz : forall (i : ι), Zero.{u1} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop} [_inst_1 : DecidableEq.{succ u2} ι] {x : Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)} (i : ι), (Acc.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.single.{u2, u1} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) i (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Dfinsupp.{u2, u1} ι (fun (i : ι) => (fun (i : ι) => α i) i) (fun (i : ι) => (fun (i : ι) => hz i) i)) ι (fun (_x : ι) => (fun (i : ι) => (fun (i : ι) => α i) i) _x) (Dfinsupp.funLike.{u2, u1} ι (fun (i : ι) => (fun (i : ι) => α i) i) (fun (i : ι) => (fun (i : ι) => hz i) i)) x i))) -> (Acc.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.erase.{u2, u1} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) i x)) -> (Acc.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) x)
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex.acc_of_single_erase Dfinsupp.Lex.acc_of_single_eraseₓ'. -/
theorem Lex.acc_of_single_erase [DecidableEq ι] {x : Π₀ i, α i} (i : ι)
    (hs : Acc (Dfinsupp.Lex r s) <| single i (x i)) (hu : Acc (Dfinsupp.Lex r s) <| x.eraseₓ i) :
    Acc (Dfinsupp.Lex r s) x := by
  classical
    convert←
      @Acc.of_fibration _ _ _ _ _ (lex_fibration r s) ⟨{i}, _⟩
        (InvImage.accessible snd <| hs.prod_game_add hu)
    convert piecewise_single_erase x i
#align dfinsupp.lex.acc_of_single_erase Dfinsupp.Lex.acc_of_single_erase

variable (hbot : ∀ ⦃i a⦄, ¬s i a 0)

include hbot

#print Dfinsupp.Lex.acc_zero /-
theorem Lex.acc_zero : Acc (Dfinsupp.Lex r s) 0 :=
  Acc.intro 0 fun x ⟨_, _, h⟩ => (hbot h).elim
#align dfinsupp.lex.acc_zero Dfinsupp.Lex.acc_zero
-/

/- warning: dfinsupp.lex.acc_of_single -> Dfinsupp.Lex.acc_of_single is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [hz : forall (i : ι), Zero.{u2} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u2} (α i) 0 (OfNat.mk.{u2} (α i) 0 (Zero.zero.{u2} (α i) (hz i)))))) -> (forall [_inst_1 : DecidableEq.{succ u1} ι] [_inst_2 : forall (i : ι) (x : α i), Decidable (Ne.{succ u2} (α i) x (OfNat.ofNat.{u2} (α i) 0 (OfNat.mk.{u2} (α i) 0 (Zero.zero.{u2} (α i) (hz i)))))] (x : Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)), (forall (i : ι), (Membership.Mem.{u1, u1} ι (Finset.{u1} ι) (Finset.hasMem.{u1} ι) i (Dfinsupp.support.{u1, u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) (fun (i : ι) (x : α i) => _inst_2 i x) x)) -> (Acc.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.single.{u1, u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) i (coeFn.{succ (max u1 u2), max (succ u1) (succ u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (fun (_x : Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) => forall (i : ι), α i) (Dfinsupp.hasCoeToFun.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) x i)))) -> (Acc.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) x))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [hz : forall (i : ι), Zero.{u1} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u1} (α i) 0 (Zero.toOfNat0.{u1} (α i) (hz i))))) -> (forall [_inst_1 : DecidableEq.{succ u2} ι] [_inst_2 : forall (i : ι) (x : α i), Decidable (Ne.{succ u1} (α i) x (OfNat.ofNat.{u1} (α i) 0 (Zero.toOfNat0.{u1} (α i) (hz i))))] (x : Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)), (forall (i : ι), (Membership.mem.{u2, u2} ι (Finset.{u2} ι) (Finset.instMembershipFinset.{u2} ι) i (Dfinsupp.support.{u2, u1} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) (fun (i : ι) (x : α i) => _inst_2 i x) x)) -> (Acc.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.single.{u2, u1} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) i (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Dfinsupp.{u2, u1} ι (fun (i : ι) => (fun (i : ι) => α i) i) (fun (i : ι) => (fun (i : ι) => hz i) i)) ι (fun (_x : ι) => (fun (i : ι) => (fun (i : ι) => α i) i) _x) (Dfinsupp.funLike.{u2, u1} ι (fun (i : ι) => (fun (i : ι) => α i) i) (fun (i : ι) => (fun (i : ι) => hz i) i)) x i)))) -> (Acc.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) x))
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex.acc_of_single Dfinsupp.Lex.acc_of_singleₓ'. -/
theorem Lex.acc_of_single [DecidableEq ι] [∀ (i) (x : α i), Decidable (x ≠ 0)] (x : Π₀ i, α i) :
    (∀ i ∈ x.support, Acc (Dfinsupp.Lex r s) <| single i (x i)) → Acc (Dfinsupp.Lex r s) x :=
  by
  generalize ht : x.support = t; revert x
  classical
    induction' t using Finset.induction with b t hb ih
    · intro x ht
      rw [support_eq_empty.1 ht]
      exact fun _ => lex.acc_zero hbot
    refine' fun x ht h => lex.acc_of_single_erase b (h b <| t.mem_insert_self b) _
    refine' ih _ (by rw [support_erase, ht, Finset.erase_insert hb]) fun a ha => _
    rw [erase_ne (ha.ne_of_not_mem hb)]
    exact h a (Finset.mem_insert_of_mem ha)
#align dfinsupp.lex.acc_of_single Dfinsupp.Lex.acc_of_single

variable (hs : ∀ i, WellFounded (s i))

include hs

/- warning: dfinsupp.lex.acc_single -> Dfinsupp.Lex.acc_single is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [hz : forall (i : ι), Zero.{u2} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u2} (α i) 0 (OfNat.mk.{u2} (α i) 0 (Zero.zero.{u2} (α i) (hz i)))))) -> (forall (i : ι), WellFounded.{succ u2} (α i) (s i)) -> (forall [_inst_1 : DecidableEq.{succ u1} ι] {i : ι}, (Acc.{succ u1} ι (Inf.inf.{u1} (ι -> ι -> Prop) (Pi.hasInf.{u1, u1} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.hasInf.{u1, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => SemilatticeInf.toHasInf.{0} Prop (Lattice.toSemilatticeInf.{0} Prop (ConditionallyCompleteLattice.toLattice.{0} Prop (CompleteLattice.toConditionallyCompleteLattice.{0} Prop Prop.completeLattice)))))) (HasCompl.compl.{u1} (ι -> ι -> Prop) (Pi.hasCompl.{u1, u1} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.hasCompl.{u1, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => Prop.hasCompl))) r) (Ne.{succ u1} ι)) i) -> (forall (a : α i), Acc.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.single.{u1, u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) i a)))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [hz : forall (i : ι), Zero.{u1} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u1} (α i) 0 (Zero.toOfNat0.{u1} (α i) (hz i))))) -> (forall (i : ι), WellFounded.{succ u1} (α i) (s i)) -> (forall [_inst_1 : DecidableEq.{succ u2} ι] {i : ι}, (Acc.{succ u2} ι (Inf.inf.{u2} (ι -> ι -> Prop) (Pi.instInfForAll.{u2, u2} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.instInfForAll.{u2, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => Lattice.toInf.{0} Prop (ConditionallyCompleteLattice.toLattice.{0} Prop (ConditionallyCompleteLinearOrder.toConditionallyCompleteLattice.{0} Prop (ConditionallyCompleteLinearOrderBot.toConditionallyCompleteLinearOrder.{0} Prop (CompleteLinearOrder.toConditionallyCompleteLinearOrderBot.{0} Prop Prop.completeLinearOrder))))))) (HasCompl.compl.{u2} (ι -> ι -> Prop) (Pi.hasCompl.{u2, u2} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.hasCompl.{u2, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => Prop.hasCompl))) r) (fun (x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1466 : ι) (x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1468 : ι) => Ne.{succ u2} ι x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1466 x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1468)) i) -> (forall (a : α i), Acc.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) (Dfinsupp.single.{u2, u1} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) i a)))
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex.acc_single Dfinsupp.Lex.acc_singleₓ'. -/
theorem Lex.acc_single [DecidableEq ι] {i : ι} (hi : Acc (rᶜ ⊓ (· ≠ ·)) i) :
    ∀ a, Acc (Dfinsupp.Lex r s) (single i a) :=
  by
  induction' hi with i hi ih
  refine' fun a => (hs i).induction a fun a ha => _
  refine' Acc.intro _ fun x => _
  rintro ⟨k, hr, hs⟩
  classical
    rw [single_apply] at hs
    split_ifs  at hs with hik
    swap
    · exact (hbot hs).elim
    subst hik
    refine' lex.acc_of_single hbot x fun j hj => _
    obtain rfl | hij := eq_or_ne i j
    · exact ha _ hs
    by_cases r j i
    · rw [hr j h, single_eq_of_ne hij, single_zero]
      exact lex.acc_zero hbot
    · exact ih _ ⟨h, hij.symm⟩ _
#align dfinsupp.lex.acc_single Dfinsupp.Lex.acc_single

/- warning: dfinsupp.lex.acc -> Dfinsupp.Lex.acc is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [hz : forall (i : ι), Zero.{u2} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u2} (α i) 0 (OfNat.mk.{u2} (α i) 0 (Zero.zero.{u2} (α i) (hz i)))))) -> (forall (i : ι), WellFounded.{succ u2} (α i) (s i)) -> (forall [_inst_1 : DecidableEq.{succ u1} ι] [_inst_2 : forall (i : ι) (x : α i), Decidable (Ne.{succ u2} (α i) x (OfNat.ofNat.{u2} (α i) 0 (OfNat.mk.{u2} (α i) 0 (Zero.zero.{u2} (α i) (hz i)))))] (x : Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)), (forall (i : ι), (Membership.Mem.{u1, u1} ι (Finset.{u1} ι) (Finset.hasMem.{u1} ι) i (Dfinsupp.support.{u1, u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) (fun (i : ι) (x : α i) => _inst_2 i x) x)) -> (Acc.{succ u1} ι (Inf.inf.{u1} (ι -> ι -> Prop) (Pi.hasInf.{u1, u1} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.hasInf.{u1, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => SemilatticeInf.toHasInf.{0} Prop (Lattice.toSemilatticeInf.{0} Prop (ConditionallyCompleteLattice.toLattice.{0} Prop (CompleteLattice.toConditionallyCompleteLattice.{0} Prop Prop.completeLattice)))))) (HasCompl.compl.{u1} (ι -> ι -> Prop) (Pi.hasCompl.{u1, u1} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.hasCompl.{u1, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => Prop.hasCompl))) r) (Ne.{succ u1} ι)) i)) -> (Acc.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) x))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [hz : forall (i : ι), Zero.{u1} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u1} (α i) 0 (Zero.toOfNat0.{u1} (α i) (hz i))))) -> (forall (i : ι), WellFounded.{succ u1} (α i) (s i)) -> (forall [_inst_1 : DecidableEq.{succ u2} ι] [_inst_2 : forall (i : ι) (x : α i), Decidable (Ne.{succ u1} (α i) x (OfNat.ofNat.{u1} (α i) 0 (Zero.toOfNat0.{u1} (α i) (hz i))))] (x : Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)), (forall (i : ι), (Membership.mem.{u2, u2} ι (Finset.{u2} ι) (Finset.instMembershipFinset.{u2} ι) i (Dfinsupp.support.{u2, u1} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) (fun (i : ι) => hz i) (fun (i : ι) (x : α i) => _inst_2 i x) x)) -> (Acc.{succ u2} ι (Inf.inf.{u2} (ι -> ι -> Prop) (Pi.instInfForAll.{u2, u2} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.instInfForAll.{u2, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => Lattice.toInf.{0} Prop (ConditionallyCompleteLattice.toLattice.{0} Prop (ConditionallyCompleteLinearOrder.toConditionallyCompleteLattice.{0} Prop (ConditionallyCompleteLinearOrderBot.toConditionallyCompleteLinearOrder.{0} Prop (CompleteLinearOrder.toConditionallyCompleteLinearOrderBot.{0} Prop Prop.completeLinearOrder))))))) (HasCompl.compl.{u2} (ι -> ι -> Prop) (Pi.hasCompl.{u2, u2} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.hasCompl.{u2, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => Prop.hasCompl))) r) (fun (x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1795 : ι) (x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1797 : ι) => Ne.{succ u2} ι x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1795 x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1797)) i)) -> (Acc.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s) x))
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex.acc Dfinsupp.Lex.accₓ'. -/
theorem Lex.acc [DecidableEq ι] [∀ (i) (x : α i), Decidable (x ≠ 0)] (x : Π₀ i, α i)
    (h : ∀ i ∈ x.support, Acc (rᶜ ⊓ (· ≠ ·)) i) : Acc (Dfinsupp.Lex r s) x :=
  Lex.acc_of_single hbot x fun i hi => Lex.acc_single hbot hs (h i hi) _
#align dfinsupp.lex.acc Dfinsupp.Lex.acc

/- warning: dfinsupp.lex.well_founded -> Dfinsupp.Lex.wellFounded is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [hz : forall (i : ι), Zero.{u2} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u2} (α i) 0 (OfNat.mk.{u2} (α i) 0 (Zero.zero.{u2} (α i) (hz i)))))) -> (forall (i : ι), WellFounded.{succ u2} (α i) (s i)) -> (WellFounded.{succ u1} ι (Inf.inf.{u1} (ι -> ι -> Prop) (Pi.hasInf.{u1, u1} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.hasInf.{u1, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => SemilatticeInf.toHasInf.{0} Prop (Lattice.toSemilatticeInf.{0} Prop (ConditionallyCompleteLattice.toLattice.{0} Prop (CompleteLattice.toConditionallyCompleteLattice.{0} Prop Prop.completeLattice)))))) (HasCompl.compl.{u1} (ι -> ι -> Prop) (Pi.hasCompl.{u1, u1} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.hasCompl.{u1, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => Prop.hasCompl))) r) (Ne.{succ u1} ι))) -> (WellFounded.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [hz : forall (i : ι), Zero.{u1} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u1} (α i) 0 (Zero.toOfNat0.{u1} (α i) (hz i))))) -> (forall (i : ι), WellFounded.{succ u1} (α i) (s i)) -> (WellFounded.{succ u2} ι (Inf.inf.{u2} (ι -> ι -> Prop) (Pi.instInfForAll.{u2, u2} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.instInfForAll.{u2, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => Lattice.toInf.{0} Prop (ConditionallyCompleteLattice.toLattice.{0} Prop (ConditionallyCompleteLinearOrder.toConditionallyCompleteLattice.{0} Prop (ConditionallyCompleteLinearOrderBot.toConditionallyCompleteLinearOrder.{0} Prop (CompleteLinearOrder.toConditionallyCompleteLinearOrderBot.{0} Prop Prop.completeLinearOrder))))))) (HasCompl.compl.{u2} (ι -> ι -> Prop) (Pi.hasCompl.{u2, u2} ι (fun (ᾰ : ι) => ι -> Prop) (fun (i : ι) => Pi.hasCompl.{u2, 0} ι (fun (ᾰ : ι) => Prop) (fun (i : ι) => Prop.hasCompl))) r) (fun (x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1897 : ι) (x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1899 : ι) => Ne.{succ u2} ι x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1897 x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.1899))) -> (WellFounded.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s))
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex.well_founded Dfinsupp.Lex.wellFoundedₓ'. -/
theorem Lex.wellFounded (hr : WellFounded <| rᶜ ⊓ (· ≠ ·)) : WellFounded (Dfinsupp.Lex r s) :=
  ⟨fun x => by classical exact lex.acc hbot hs x fun i _ => hr.apply i⟩
#align dfinsupp.lex.well_founded Dfinsupp.Lex.wellFounded

/- warning: dfinsupp.lex.well_founded' -> Dfinsupp.Lex.wellFounded' is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [hz : forall (i : ι), Zero.{u2} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u2} (α i) 0 (OfNat.mk.{u2} (α i) 0 (Zero.zero.{u2} (α i) (hz i)))))) -> (forall (i : ι), WellFounded.{succ u2} (α i) (s i)) -> (forall [_inst_1 : IsTrichotomous.{u1} ι r], (WellFounded.{succ u1} ι (Function.swap.{succ u1, succ u1, 1} ι ι (fun (ᾰ : ι) (ᾰ : ι) => Prop) r)) -> (WellFounded.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s)))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [hz : forall (i : ι), Zero.{u1} (α i)] {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall {{i : ι}} {{a : α i}}, Not (s i a (OfNat.ofNat.{u1} (α i) 0 (Zero.toOfNat0.{u1} (α i) (hz i))))) -> (forall (i : ι), WellFounded.{succ u1} (α i) (s i)) -> (forall [_inst_1 : IsTrichotomous.{u2} ι r], (WellFounded.{succ u2} ι (Function.swap.{succ u2, succ u2, 1} ι ι (fun (ᾰ : ι) (ᾰ : ι) => Prop) r)) -> (WellFounded.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => hz i) r s)))
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex.well_founded' Dfinsupp.Lex.wellFounded'ₓ'. -/
theorem Lex.wellFounded' [IsTrichotomous ι r] (hr : WellFounded r.symm) :
    WellFounded (Dfinsupp.Lex r s) :=
  Lex.wellFounded hbot hs <|
    Subrelation.wf
      (fun i j h => ((@IsTrichotomous.trichotomous ι r _ i j).resolve_left h.1).resolve_left h.2) hr
#align dfinsupp.lex.well_founded' Dfinsupp.Lex.wellFounded'

omit hz hbot hs

/- warning: dfinsupp.lex.well_founded_lt -> Dfinsupp.Lex.wellFoundedLT is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : LT.{u1} ι] [_inst_2 : IsTrichotomous.{u1} ι (LT.lt.{u1} ι _inst_1)] [hι : WellFoundedGT.{u1} ι _inst_1] [_inst_3 : forall (i : ι), CanonicallyOrderedAddMonoid.{u2} (α i)] [hα : forall (i : ι), WellFoundedLT.{u2} (α i) (Preorder.toLT.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (OrderedAddCommMonoid.toPartialOrder.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_3 i)))))], WellFoundedLT.{max u1 u2} (Lex.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddZeroClass.toHasZero.{u2} (α i) (AddMonoid.toAddZeroClass.{u2} (α i) (AddCommMonoid.toAddMonoid.{u2} (α i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_3 i)))))))) (Dfinsupp.Lex.hasLt.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddZeroClass.toHasZero.{u2} (α i) (AddMonoid.toAddZeroClass.{u2} (α i) (AddCommMonoid.toAddMonoid.{u2} (α i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_3 i)))))) _inst_1 (fun (i : ι) => Preorder.toLT.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (OrderedAddCommMonoid.toPartialOrder.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_3 i))))))
but is expected to have type
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : LT.{u1} ι] [_inst_2 : IsTrichotomous.{u1} ι (fun (x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.2054 : ι) (x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.2056 : ι) => LT.lt.{u1} ι _inst_1 x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.2054 x._@.Mathlib.Data.Dfinsupp.WellFounded._hyg.2056)] [hι : WellFoundedGT.{u1} ι _inst_1] [_inst_3 : forall (i : ι), CanonicallyOrderedAddMonoid.{u2} (α i)] [hα : forall (i : ι), WellFoundedLT.{u2} (α i) (Preorder.toLT.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (OrderedAddCommMonoid.toPartialOrder.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_3 i)))))], WellFoundedLT.{max u2 u1} (Lex.{max u2 u1} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddMonoid.toZero.{u2} ((fun (i : ι) => α i) i) (AddCommMonoid.toAddMonoid.{u2} ((fun (i : ι) => α i) i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (_inst_3 i))))))) (Dfinsupp.instLTLexDfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddMonoid.toZero.{u2} ((fun (i : ι) => α i) i) (AddCommMonoid.toAddMonoid.{u2} ((fun (i : ι) => α i) i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (_inst_3 i))))) _inst_1 (fun (i : ι) => Preorder.toLT.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (OrderedAddCommMonoid.toPartialOrder.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_3 i))))))
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex.well_founded_lt Dfinsupp.Lex.wellFoundedLTₓ'. -/
instance Lex.wellFoundedLT [LT ι] [IsTrichotomous ι (· < ·)] [hι : WellFoundedGT ι]
    [∀ i, CanonicallyOrderedAddMonoid (α i)] [hα : ∀ i, WellFoundedLT (α i)] :
    WellFoundedLT (Lex (Π₀ i, α i)) :=
  ⟨Lex.wellFounded' (fun i a => (zero_le a).not_lt) (fun i => (hα i).wf) hι.wf⟩
#align dfinsupp.lex.well_founded_lt Dfinsupp.Lex.wellFoundedLT

end Dfinsupp

open Dfinsupp

variable (r : ι → ι → Prop) {s : ∀ i, α i → α i → Prop}

/- warning: pi.lex.well_founded -> Pi.Lex.wellFounded is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} (r : ι -> ι -> Prop) {s : forall (i : ι), (α i) -> (α i) -> Prop} [_inst_1 : IsStrictTotalOrder.{u1} ι r] [_inst_2 : Finite.{succ u1} ι], (forall (i : ι), WellFounded.{succ u2} (α i) (s i)) -> (WellFounded.{max (succ u1) (succ u2)} (forall (i : ι), α i) (Pi.Lex.{u1, u2} ι (fun (i : ι) => α i) r s))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} (r : ι -> ι -> Prop) {s : forall (i : ι), (α i) -> (α i) -> Prop} [_inst_1 : IsStrictTotalOrder.{u2} ι r] [_inst_2 : Finite.{succ u2} ι], (forall (i : ι), WellFounded.{succ u1} (α i) (s i)) -> (WellFounded.{max (succ u1) (succ u2)} (forall (i : ι), α i) (Pi.Lex.{u2, u1} ι (fun {i : ι} => α i) r (fun {i : ι} => s i)))
Case conversion may be inaccurate. Consider using '#align pi.lex.well_founded Pi.Lex.wellFoundedₓ'. -/
theorem Pi.Lex.wellFounded [IsStrictTotalOrder ι r] [Finite ι] (hs : ∀ i, WellFounded (s i)) :
    WellFounded (Pi.Lex r s) :=
  by
  obtain h | ⟨⟨x⟩⟩ := isEmpty_or_nonempty (∀ i, α i)
  · convert empty_wf
    ext1 x
    exact (h.1 x).elim
  letI : ∀ i, Zero (α i) := fun i => ⟨(hs i).min ⊤ ⟨x i, trivial⟩⟩
  haveI := IsTrans.swap r; haveI := IsIrrefl.swap r; haveI := Fintype.ofFinite ι
  refine' InvImage.wf equiv_fun_on_fintype.symm (lex.well_founded' (fun i a => _) hs _)
  exacts[(hs i).not_lt_min ⊤ _ trivial, Finite.wellFounded_of_trans_of_irrefl r.swap]
#align pi.lex.well_founded Pi.Lex.wellFounded

#print Pi.Lex.wellFoundedLT /-
instance Pi.Lex.wellFoundedLT [LinearOrder ι] [Finite ι] [∀ i, LT (α i)]
    [hwf : ∀ i, WellFoundedLT (α i)] : WellFoundedLT (Lex (∀ i, α i)) :=
  ⟨Pi.Lex.wellFounded (· < ·) fun i => (hwf i).1⟩
#align pi.lex.well_founded_lt Pi.Lex.wellFoundedLT
-/

#print Function.Lex.wellFoundedLT /-
instance Function.Lex.wellFoundedLT {α} [LinearOrder ι] [Finite ι] [LT α] [WellFoundedLT α] :
    WellFoundedLT (Lex (ι → α)) :=
  Pi.Lex.wellFoundedLT
#align function.lex.well_founded_lt Function.Lex.wellFoundedLT
-/

/- warning: dfinsupp.lex.well_founded_of_finite -> Dfinsupp.Lex.wellFounded_of_finite is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} (r : ι -> ι -> Prop) {s : forall (i : ι), (α i) -> (α i) -> Prop} [_inst_1 : IsStrictTotalOrder.{u1} ι r] [_inst_2 : Finite.{succ u1} ι] [_inst_3 : forall (i : ι), Zero.{u2} (α i)], (forall (i : ι), WellFounded.{succ u2} (α i) (s i)) -> (WellFounded.{succ (max u1 u2)} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_3 i)) (Dfinsupp.Lex.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_3 i) r s))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} (r : ι -> ι -> Prop) {s : forall (i : ι), (α i) -> (α i) -> Prop} [_inst_1 : IsStrictTotalOrder.{u2} ι r] [_inst_2 : Finite.{succ u2} ι] [_inst_3 : forall (i : ι), Zero.{u1} (α i)], (forall (i : ι), WellFounded.{succ u1} (α i) (s i)) -> (WellFounded.{max (succ u1) (succ u2)} (Dfinsupp.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_3 i)) (Dfinsupp.Lex.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_3 i) r s))
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex.well_founded_of_finite Dfinsupp.Lex.wellFounded_of_finiteₓ'. -/
theorem Dfinsupp.Lex.wellFounded_of_finite [IsStrictTotalOrder ι r] [Finite ι] [∀ i, Zero (α i)]
    (hs : ∀ i, WellFounded (s i)) : WellFounded (Dfinsupp.Lex r s) :=
  have := Fintype.ofFinite ι
  InvImage.wf equiv_fun_on_fintype (Pi.Lex.wellFounded r hs)
#align dfinsupp.lex.well_founded_of_finite Dfinsupp.Lex.wellFounded_of_finite

/- warning: dfinsupp.lex.well_founded_lt_of_finite -> Dfinsupp.Lex.wellFoundedLT_of_finite is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : LinearOrder.{u1} ι] [_inst_2 : Finite.{succ u1} ι] [_inst_3 : forall (i : ι), Zero.{u2} (α i)] [_inst_4 : forall (i : ι), LT.{u2} (α i)] [hwf : forall (i : ι), WellFoundedLT.{u2} (α i) (_inst_4 i)], WellFoundedLT.{max u1 u2} (Lex.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_3 i))) (Dfinsupp.Lex.hasLt.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_3 i) (Preorder.toLT.{u1} ι (PartialOrder.toPreorder.{u1} ι (SemilatticeInf.toPartialOrder.{u1} ι (Lattice.toSemilatticeInf.{u1} ι (LinearOrder.toLattice.{u1} ι _inst_1))))) (fun (i : ι) => _inst_4 i))
but is expected to have type
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : LinearOrder.{u1} ι] [_inst_2 : Finite.{succ u1} ι] [_inst_3 : forall (i : ι), Zero.{u2} (α i)] [_inst_4 : forall (i : ι), LT.{u2} (α i)] [hwf : forall (i : ι), WellFoundedLT.{u2} (α i) (_inst_4 i)], WellFoundedLT.{max u2 u1} (Lex.{max u2 u1} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_3 i))) (Dfinsupp.instLTLexDfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_3 i) (Preorder.toLT.{u1} ι (PartialOrder.toPreorder.{u1} ι (SemilatticeInf.toPartialOrder.{u1} ι (Lattice.toSemilatticeInf.{u1} ι (DistribLattice.toLattice.{u1} ι (instDistribLattice.{u1} ι _inst_1)))))) (fun (i : ι) => _inst_4 i))
Case conversion may be inaccurate. Consider using '#align dfinsupp.lex.well_founded_lt_of_finite Dfinsupp.Lex.wellFoundedLT_of_finiteₓ'. -/
instance Dfinsupp.Lex.wellFoundedLT_of_finite [LinearOrder ι] [Finite ι] [∀ i, Zero (α i)]
    [∀ i, LT (α i)] [hwf : ∀ i, WellFoundedLT (α i)] : WellFoundedLT (Lex (Π₀ i, α i)) :=
  ⟨Dfinsupp.Lex.wellFounded_of_finite (· < ·) fun i => (hwf i).1⟩
#align dfinsupp.lex.well_founded_lt_of_finite Dfinsupp.Lex.wellFoundedLT_of_finite

/- warning: dfinsupp.well_founded_lt -> Dfinsupp.wellFoundedLT is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Zero.{u2} (α i)] [_inst_2 : forall (i : ι), Preorder.{u2} (α i)] [_inst_3 : forall (i : ι), WellFoundedLT.{u2} (α i) (Preorder.toLT.{u2} (α i) (_inst_2 i))], (forall {{i : ι}} {{a : α i}}, Not (LT.lt.{u2} (α i) (Preorder.toLT.{u2} (α i) (_inst_2 i)) a (OfNat.ofNat.{u2} (α i) 0 (OfNat.mk.{u2} (α i) 0 (Zero.zero.{u2} (α i) (_inst_1 i)))))) -> (WellFoundedLT.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) (Preorder.toLT.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) (Dfinsupp.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) (fun (i : ι) => _inst_2 i))))
but is expected to have type
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Zero.{u2} (α i)] [_inst_2 : forall (i : ι), Preorder.{u2} (α i)] [_inst_3 : forall (i : ι), WellFoundedLT.{u2} (α i) (Preorder.toLT.{u2} (α i) (_inst_2 i))], (forall {{i : ι}} {{a : α i}}, Not (LT.lt.{u2} (α i) (Preorder.toLT.{u2} (α i) (_inst_2 i)) a (OfNat.ofNat.{u2} (α i) 0 (Zero.toOfNat0.{u2} (α i) (_inst_1 i))))) -> (WellFoundedLT.{max u2 u1} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) (Preorder.toLT.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) (Dfinsupp.instPreorderDfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) (fun (i : ι) => _inst_2 i))))
Case conversion may be inaccurate. Consider using '#align dfinsupp.well_founded_lt Dfinsupp.wellFoundedLTₓ'. -/
protected theorem Dfinsupp.wellFoundedLT [∀ i, Zero (α i)] [∀ i, Preorder (α i)]
    [∀ i, WellFoundedLT (α i)] (hbot : ∀ ⦃i⦄ ⦃a : α i⦄, ¬a < 0) : WellFoundedLT (Π₀ i, α i) :=
  ⟨by
    letI : ∀ i, Zero (Antisymmetrization (α i) (· ≤ ·)) := fun i => ⟨toAntisymmetrization (· ≤ ·) 0⟩
    let f := map_range (fun i => @toAntisymmetrization (α i) (· ≤ ·) _) fun i => rfl
    refine' Subrelation.wf (fun x y h => _) (InvImage.wf f <| lex.well_founded' _ (fun i => _) _)
    · exact well_ordering_rel.swap; · exact fun i => (· < ·)
    · haveI := IsStrictOrder.swap (@WellOrderingRel ι)
      obtain ⟨i, he, hl⟩ := lex_lt_of_lt_of_preorder well_ordering_rel.swap h
      exact ⟨i, fun j hj => Quot.sound (he j hj), hl⟩
    · rintro i ⟨a⟩
      apply hbot
    exacts[IsWellFounded.wf, IsTrichotomous.swap _, IsWellFounded.wf]⟩
#align dfinsupp.well_founded_lt Dfinsupp.wellFoundedLT

/- warning: dfinsupp.well_founded_lt' -> Dfinsupp.well_founded_lt' is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), CanonicallyOrderedAddMonoid.{u2} (α i)] [_inst_2 : forall (i : ι), WellFoundedLT.{u2} (α i) (Preorder.toLT.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (OrderedAddCommMonoid.toPartialOrder.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_1 i)))))], WellFoundedLT.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddZeroClass.toHasZero.{u2} (α i) (AddMonoid.toAddZeroClass.{u2} (α i) (AddCommMonoid.toAddMonoid.{u2} (α i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_1 i))))))) (Preorder.toLT.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddZeroClass.toHasZero.{u2} (α i) (AddMonoid.toAddZeroClass.{u2} (α i) (AddCommMonoid.toAddMonoid.{u2} (α i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_1 i))))))) (Dfinsupp.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddZeroClass.toHasZero.{u2} (α i) (AddMonoid.toAddZeroClass.{u2} (α i) (AddCommMonoid.toAddMonoid.{u2} (α i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_1 i)))))) (fun (i : ι) => PartialOrder.toPreorder.{u2} (α i) (OrderedAddCommMonoid.toPartialOrder.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_1 i))))))
but is expected to have type
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), CanonicallyOrderedAddMonoid.{u2} (α i)] [_inst_2 : forall (i : ι), WellFoundedLT.{u2} (α i) (Preorder.toLT.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (OrderedAddCommMonoid.toPartialOrder.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_1 i)))))], WellFoundedLT.{max u2 u1} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddMonoid.toZero.{u2} ((fun (i : ι) => α i) i) (AddCommMonoid.toAddMonoid.{u2} ((fun (i : ι) => α i) i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (_inst_1 i)))))) (Preorder.toLT.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddMonoid.toZero.{u2} ((fun (i : ι) => α i) i) (AddCommMonoid.toAddMonoid.{u2} ((fun (i : ι) => α i) i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (_inst_1 i)))))) (Dfinsupp.instPreorderDfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => AddMonoid.toZero.{u2} ((fun (i : ι) => α i) i) (AddCommMonoid.toAddMonoid.{u2} ((fun (i : ι) => α i) i) (OrderedAddCommMonoid.toAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} ((fun (i : ι) => α i) i) (_inst_1 i))))) (fun (i : ι) => PartialOrder.toPreorder.{u2} (α i) (OrderedAddCommMonoid.toPartialOrder.{u2} (α i) (CanonicallyOrderedAddMonoid.toOrderedAddCommMonoid.{u2} (α i) (_inst_1 i))))))
Case conversion may be inaccurate. Consider using '#align dfinsupp.well_founded_lt' Dfinsupp.well_founded_lt'ₓ'. -/
instance Dfinsupp.well_founded_lt' [∀ i, CanonicallyOrderedAddMonoid (α i)]
    [∀ i, WellFoundedLT (α i)] : WellFoundedLT (Π₀ i, α i) :=
  Dfinsupp.wellFoundedLT fun i a => (zero_le a).not_lt
#align dfinsupp.well_founded_lt' Dfinsupp.well_founded_lt'

#print Pi.wellFoundedLT /-
instance Pi.wellFoundedLT [Finite ι] [∀ i, Preorder (α i)] [hw : ∀ i, WellFoundedLT (α i)] :
    WellFoundedLT (∀ i, α i) :=
  ⟨by
    obtain h | ⟨⟨x⟩⟩ := isEmpty_or_nonempty (∀ i, α i)
    · convert empty_wf
      ext1 x
      exact (h.1 x).elim
    letI : ∀ i, Zero (α i) := fun i => ⟨(hw i).wf.min ⊤ ⟨x i, trivial⟩⟩
    haveI := Fintype.ofFinite ι
    refine' InvImage.wf equiv_fun_on_fintype.symm (Dfinsupp.wellFoundedLT fun i a => _).wf
    exact (hw i).wf.not_lt_min ⊤ _ trivial⟩
#align pi.well_founded_lt Pi.wellFoundedLT
-/

#print Function.wellFoundedLT /-
instance Function.wellFoundedLT {α} [Finite ι] [Preorder α] [WellFoundedLT α] :
    WellFoundedLT (ι → α) :=
  Pi.wellFoundedLT
#align function.well_founded_lt Function.wellFoundedLT
-/

/- warning: dfinsupp.well_founded_lt_of_finite -> Dfinsupp.wellFoundedLT_of_finite is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : Finite.{succ u1} ι] [_inst_2 : forall (i : ι), Zero.{u2} (α i)] [_inst_3 : forall (i : ι), Preorder.{u2} (α i)] [_inst_4 : forall (i : ι), WellFoundedLT.{u2} (α i) (Preorder.toLT.{u2} (α i) (_inst_3 i))], WellFoundedLT.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_2 i)) (Preorder.toLT.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_2 i)) (Dfinsupp.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_2 i) (fun (i : ι) => _inst_3 i)))
but is expected to have type
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : Finite.{succ u1} ι] [_inst_2 : forall (i : ι), Zero.{u2} (α i)] [_inst_3 : forall (i : ι), Preorder.{u2} (α i)] [_inst_4 : forall (i : ι), WellFoundedLT.{u2} (α i) (Preorder.toLT.{u2} (α i) (_inst_3 i))], WellFoundedLT.{max u2 u1} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_2 i)) (Preorder.toLT.{max u1 u2} (Dfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_2 i)) (Dfinsupp.instPreorderDfinsupp.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_2 i) (fun (i : ι) => _inst_3 i)))
Case conversion may be inaccurate. Consider using '#align dfinsupp.well_founded_lt_of_finite Dfinsupp.wellFoundedLT_of_finiteₓ'. -/
instance Dfinsupp.wellFoundedLT_of_finite [Finite ι] [∀ i, Zero (α i)] [∀ i, Preorder (α i)]
    [∀ i, WellFoundedLT (α i)] : WellFoundedLT (Π₀ i, α i) :=
  have := Fintype.ofFinite ι
  ⟨InvImage.wf equiv_fun_on_fintype pi.well_founded_lt.wf⟩
#align dfinsupp.well_founded_lt_of_finite Dfinsupp.wellFoundedLT_of_finite


/-
Copyright (c) 2020 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison, Bhavik Mehta

! This file was ported from Lean 3 source module category_theory.limits.preserves.limits
! leanprover-community/mathlib commit e97cf15cd1aec9bd5c193b2ffac5a6dc9118912b
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.CategoryTheory.Limits.Preserves.Basic

/-!
# Isomorphisms about functors which preserve (co)limits

If `G` preserves limits, and `C` and `D` have limits, then for any diagram `F : J ⥤ C` we have a
canonical isomorphism `preservesLimitsIso : G.obj (Limit F) ≅ Limit (F ⋙ G)`.
We also show that we can commute `IsLimit.lift` of a preserved limit with `functor.map_cone`:
`(PreservesLimit.preserves t).lift (G.mapCone c₂) = G.map (t.lift c₂)`.

The duals of these are also given. For functors which preserve (co)limits of specific shapes, see
`preserves/shapes.lean`.
-/

universe w' w v₁ v₂ u₁ u₂

noncomputable section

namespace CategoryTheory

open Category Limits

variable {C : Type u₁} [Category.{v₁} C]

variable {D : Type u₂} [Category.{v₂} D]

variable (G : C ⥤ D)

variable {J : Type w} [Category.{w'} J]

variable (F : J ⥤ C)

section

variable [PreservesLimit F G]

@[simp]
theorem preserves_lift_mapCone (c₁ c₂ : Cone F) (t : IsLimit c₁) :
    (PreservesLimit.preserves t).lift (G.mapCone c₂) = G.map (t.lift c₂) :=
  ((PreservesLimit.preserves t).uniq (G.mapCone c₂) _ (by simp [← G.map_comp])).symm
#align category_theory.preserves_lift_map_cone CategoryTheory.preserves_lift_mapCone

variable [HasLimit F] [HasLimit (F ⋙ G)]

/-- If `G` preserves limits, we have an isomorphism from the image of the limit of a functor `F`
to the limit of the functor `F ⋙ G`.
-/
def preservesLimitIso : G.obj (limit F) ≅ limit (F ⋙ G) :=
  (PreservesLimit.preserves (limit.isLimit _)).conePointUniqueUpToIso (limit.isLimit _)
#align category_theory.preserves_limit_iso CategoryTheory.preservesLimitIso

@[reassoc (attr := simp)]
theorem preservesLimitsIso_hom_π (j) :
    (preservesLimitIso G F).hom ≫ limit.π _ j = G.map (limit.π F j) :=
  IsLimit.conePointUniqueUpToIso_hom_comp _ _ j
#align category_theory.preserves_limits_iso_hom_π CategoryTheory.preservesLimitsIso_hom_π

@[reassoc (attr := simp)]
theorem preservesLimitsIso_inv_π (j) :
    (preservesLimitIso G F).inv ≫ G.map (limit.π F j) = limit.π _ j :=
  IsLimit.conePointUniqueUpToIso_inv_comp _ _ j
#align category_theory.preserves_limits_iso_inv_π CategoryTheory.preservesLimitsIso_inv_π

@[reassoc (attr := simp)]
theorem lift_comp_preservesLimitsIso_hom (t : Cone F) :
    G.map (limit.lift _ t) ≫ (preservesLimitIso G F).hom =
    limit.lift (F ⋙ G) (G.mapCone _) := by
  ext
  simp [← G.map_comp]
#align category_theory.lift_comp_preserves_limits_iso_hom CategoryTheory.lift_comp_preservesLimitsIso_hom

variable [PreservesLimitsOfShape J G] [HasLimitsOfShape J D] [HasLimitsOfShape J C]

/-- If `C, D` has all limits of shape `J`, and `G` preserves them, then `preservesLimitsIso` is
functorial wrt `F`. -/
@[simps!]
def preservesLimitNatIso : lim ⋙ G ≅ (whiskeringRight J C D).obj G ⋙ lim :=
  NatIso.ofComponents (fun F => preservesLimitIso G F)
    (by
      intro _ _ f
      apply Limits.limit.hom_ext; intro j
      dsimp
      simp only [preservesLimitsIso_hom_π, whiskerRight_app, limMap_π, Category.assoc,
        preservesLimitsIso_hom_π_assoc, ← G.map_comp])
#align category_theory.preserves_limit_nat_iso CategoryTheory.preservesLimitNatIso

end

section

variable [PreservesColimit F G]

@[simp]
theorem preserves_desc_mapCocone (c₁ c₂ : Cocone F) (t : IsColimit c₁) :
    (PreservesColimit.preserves t).desc (G.mapCocone _) = G.map (t.desc c₂) :=
  ((PreservesColimit.preserves t).uniq (G.mapCocone _) _ (by simp [← G.map_comp])).symm
#align category_theory.preserves_desc_map_cocone CategoryTheory.preserves_desc_mapCocone

variable [HasColimit F] [HasColimit (F ⋙ G)]

-- TODO: think about swapping the order here
/-- If `G` preserves colimits, we have an isomorphism from the image of the colimit of a functor `F`
to the colimit of the functor `F ⋙ G`.
-/
def preservesColimitIso : G.obj (colimit F) ≅ colimit (F ⋙ G) :=
  (PreservesColimit.preserves (colimit.isColimit _)).coconePointUniqueUpToIso (colimit.isColimit _)
#align category_theory.preserves_colimit_iso CategoryTheory.preservesColimitIso

@[reassoc (attr := simp)]
theorem ι_preservesColimitsIso_inv (j : J) :
    colimit.ι _ j ≫ (preservesColimitIso G F).inv = G.map (colimit.ι F j) :=
  IsColimit.comp_coconePointUniqueUpToIso_inv _ (colimit.isColimit (F ⋙ G)) j
#align category_theory.ι_preserves_colimits_iso_inv CategoryTheory.ι_preservesColimitsIso_inv

@[reassoc (attr := simp)]
theorem ι_preservesColimitsIso_hom (j : J) :
    G.map (colimit.ι F j) ≫ (preservesColimitIso G F).hom = colimit.ι (F ⋙ G) j :=
  (PreservesColimit.preserves (colimit.isColimit _)).comp_coconePointUniqueUpToIso_hom _ j
#align category_theory.ι_preserves_colimits_iso_hom CategoryTheory.ι_preservesColimitsIso_hom

@[reassoc (attr := simp)]
theorem preservesColimitsIso_inv_comp_desc (t : Cocone F) :
    (preservesColimitIso G F).inv ≫ G.map (colimit.desc _ t) =
    colimit.desc _ (G.mapCocone t) := by
  ext
  simp [← G.map_comp]
#align category_theory.preserves_colimits_iso_inv_comp_desc CategoryTheory.preservesColimitsIso_inv_comp_desc

variable [PreservesColimitsOfShape J G] [HasColimitsOfShape J D] [HasColimitsOfShape J C]

/-- If `C, D` has all colimits of shape `J`, and `G` preserves them, then `preservesColimitIso`
is functorial wrt `F`. -/
@[simps!]
def preservesColimitNatIso : colim ⋙ G ≅ (whiskeringRight J C D).obj G ⋙ colim :=
  NatIso.ofComponents (fun F => preservesColimitIso G F)
    (by
      intro _ _ f
      rw [← Iso.inv_comp_eq, ← Category.assoc, ← Iso.eq_comp_inv]
      apply Limits.colimit.hom_ext; intro j
      dsimp
      erw [ι_colimMap_assoc]
      simp only [ι_preservesColimitsIso_inv, whiskerRight_app, Category.assoc,
        ι_preservesColimitsIso_inv_assoc, ← G.map_comp]
      erw [ι_colimMap])
#align category_theory.preserves_colimit_nat_iso CategoryTheory.preservesColimitNatIso

end

end CategoryTheory


import .rank

noncomputable theory
open_locale classical

variables {E : Type*} [finite E] {M M₁ M₂ : matroid E}
  {I C C' C₁ C₂ X : set E} {e : E}

open set

namespace matroid

lemma circuit_def :
  M.circuit C ↔ ¬M.indep C ∧ ∀ I ⊂ C, M.indep I :=
iff.rfl

lemma circuit.dep (hC : M.circuit C) :
  ¬M.indep C :=
hC.1

lemma circuit.ssubset_indep (hC : M.circuit C) (hXC : X ⊂ C) :
  M.indep X :=
hC.2 _ hXC

lemma circuit.diff_singleton_indep (hC : M.circuit C) (he : e ∈ C) :
  M.indep (C \ {e}) :=
hC.ssubset_indep (diff_singleton_ssubset he)

lemma circuit.eq_of_dep_subset (hC : M.circuit C) (hX : ¬M.indep X) (hXC : X ⊆ C) :
  X = C :=
eq_of_le_of_not_lt hXC (hX ∘ hC.ssubset_indep)

lemma circuit.not_ssubset (hC : M.circuit C) (hC' : M.circuit C') :
  ¬ (C' ⊂ C) :=
λ h, hC'.1 (hC.2 _ h)

lemma circuit.nonempty (hC : M.circuit C) :
  C.nonempty :=
by {rw set.nonempty_iff_ne_empty, rintro rfl, exact hC.1 M.empty_indep}

lemma empty_not_circuit (M : matroid E) :
  ¬M.circuit ∅ :=
λ h, by simpa using h.nonempty

lemma circuit.card (hC : M.circuit C) :
  C.ncard = M.r C + 1 :=
begin
  obtain ⟨e,he⟩ := hC.nonempty,
  have hss : C \ {e} ⊂ C, by {refine ssubset_of_ne_of_subset _ (diff_subset _ _),
    simpa only [ne.def, sdiff_eq_left, disjoint_singleton_right, not_not_mem]},
  have hlb := M.r_mono hss.subset,
  have hub := r_lt_card_of_dep hC.dep,
  rw [←nat.add_one_le_iff] at hub,
  rw [(hC.ssubset_indep hss).r] at hlb,
  have := ncard_diff_singleton_add_one he,
  linarith,
end

lemma circuit_iff_dep_forall_diff_singleton_indep :
  M.circuit C ↔ (¬M.indep C) ∧ ∀ e ∈ C, M.indep (C \ {e}) :=
begin
  rw [circuit_def, and.congr_right_iff],
  refine λ hdep, ⟨λ h e heC, (h _ (diff_singleton_ssubset heC)), λ h I hIC, _⟩,
  obtain ⟨e, heC,heI⟩ := exists_of_ssubset hIC,
  exact (h e heC).subset (subset_diff_singleton hIC.subset heI),
end

lemma circuit.r (hC : M.circuit C) :
  M.r C = C.ncard - 1 :=
by rw [hC.card, nat.add_succ_sub_one, add_zero]

lemma circuit.coe_r_eq (hC : M.circuit C) :
  (M.r C : ℤ) = C.ncard - 1 :=
by rw [hC.card, nat.cast_add, nat.cast_one, add_tsub_cancel_right]

lemma circuit.eq_of_dep_subset_self (hC : M.circuit C) (hX : ¬M.indep X) (hXC : X ⊆ C) :
  C = X :=
by_contra (λ h, hX (hC.ssubset_indep (ssubset_of_subset_of_ne hXC (ne.symm h))))

lemma circuit.eq_of_subset_circuit (hC₁ : M.circuit C₁) (hC₂ : M.circuit C₂) (h : C₁ ⊆ C₂) :
  C₁ = C₂ :=
(hC₂.eq_of_dep_subset_self hC₁.dep h).symm

lemma exists_circuit_subset_of_dep (hX : ¬M.indep X) :
  ∃ C ⊆ X, M.circuit C :=
begin
  obtain ⟨C,⟨hCX,hCdep⟩,hmin⟩ := finite.exists_minimal (λ Y, Y ⊆ X ∧ ¬M.indep Y) ⟨_,rfl.subset,hX⟩,
  exact ⟨C, hCX, ⟨hCdep,λ I hIC,
    by_contra (λ hI, hIC.ne ((hmin I ⟨hIC.subset.trans hCX,hI⟩ hIC.subset).symm))⟩⟩,
end

lemma dep_iff_supset_circuit :
  ¬ M.indep X ↔ ∃ C ⊆ X, M.circuit C  :=
⟨exists_circuit_subset_of_dep, λ ⟨C, hCX, hC⟩ hX, hC.dep (hX.subset hCX)⟩

lemma indep_iff_forall_subset_not_circuit :
  M.indep I ↔ ∀ C ⊆ I, ¬ M.circuit C :=
by {rw ← not_iff_not, simp_rw [dep_iff_supset_circuit, not_forall, not_not]}

lemma exists_circuit_iff_card_lt_rk :
  M.rk < (univ : set E).ncard ↔ ∃ C, M.circuit C :=
begin
  rw [matroid.rk, r_lt_card_iff_dep, dep_iff_supset_circuit],
  split,
  { rintro ⟨C,-,hC⟩, exact ⟨C,hC⟩},
  rintro ⟨C,hC⟩,
  exact ⟨C, subset_univ _, hC⟩
end

/-- The circuit eliminiation axiom : for any pair of distinct circuits `C₁,C₂` and any `e`, some
  circuit is contained in `C₁ ∪ C₂ \ {e}`. Traditionally this includes the stipulation that
  `e ∈ C₁ ∩ C₂`, but we can derive the stronger version. -/
lemma circuit.elimination (hC₁ : M.circuit C₁) (hC₂ : M.circuit C₂) (h : C₁ ≠ C₂) (e : E) :
  ∃ C ⊆ (C₁ ∪ C₂) \ {e}, M.circuit C  :=
begin
  by_cases he : e ∈ (C₁ ∪ C₂), swap,
  { have h' := subset_union_left C₁ C₂,
    exact ⟨C₁, subset_diff_singleton h' (λ he', he (h' he')), hC₁⟩},
  simp_rw [←dep_iff_supset_circuit, ←r_lt_card_iff_dep, nat.lt_iff_add_one_le],

  have hss : C₁ ∩ C₂ ⊂ C₁ := ssubset_of_ne_of_subset
    (by {simp only [ne.def, inter_eq_left_iff_subset],
      exact λ h', h (hC₁.eq_of_subset_circuit hC₂ h')}) (inter_subset_left _ _),
  linarith [hC₁.card, hC₂.card, ncard_inter_add_ncard_union C₁ C₂,
      (hC₁.ssubset_indep hss).r, M.r_inter_add_r_union_le_r_add_r C₁ C₂,
      ncard_diff_singleton_add_one he,
      M.r_mono (diff_subset (C₁ ∪ C₂) {e})],
end

lemma set.mem_of_nsubset_insert_iff {s t : set E} {a : E} (h : s ⊆ insert a t ∧ ¬ s ⊆ t) : a ∈ s :=
begin
  contrapose h,
  push_neg,
  intros h2,
  exact (subset_insert_iff_of_not_mem h).1 h2,
end

lemma indep.unique_circuit_of_insert (hX : M.indep X) (a : E) (hXa : ¬ M.indep (insert a X) ):
  ∃! C, C ⊆ insert a X ∧ M.circuit C ∧ a ∈ C :=
begin
  apply exists_unique_of_exists_of_unique,
  { refine (dep_iff_supset_circuit.mp hXa).imp (λ C, _),
    rintro ⟨hCX,hC⟩,
    refine ⟨hCX ,hC, by_contra (λ haC, _)⟩,
    exact hC.dep (hX.subset ((subset_insert_iff_of_not_mem haC).mp hCX))},
  simp only [exists_unique_iff_exists, exists_prop, and_imp],
  refine λ  C₁ C₂ hC₁X hC₁ haC₁ hC₂X hC₂ haC₂, by_contra (λ hne, _),
  obtain ⟨C,hCss,hC⟩ := hC₁.elimination hC₂ hne a,
  have h := hCss.trans (@diff_subset_diff_left _ _ _ {a} (union_subset hC₁X hC₂X)),
  simp only [insert_diff_of_mem, mem_singleton] at h,
  refine hC.dep (hX.subset (h.trans (diff_subset _ _))),
end

-- this needs some cleaning up (as do the other lemmas it uses)
-- lemma base_exchange2 {M : matroid E} {X Y : set E} {a : E}
-- (hX : M.base X) (hY : M.base Y) (haX : a ∈ Y) (haY : a ∉ X) :
--   ∃ b, (b ∈ X ∧ b ∉ Y) ∧ M.base (X \ {b} ∪ {a})   :=
-- begin
--   have h1 : ¬ M.indep (insert a X),
--   apply base.insert_dep hX haY,
--   -- X ∪ {a} has unique circuit C(a, X)
--   have h3 := indep.unique_circuit_of_insert (base.indep hX) a h1,
--   rcases (indep.unique_circuit_of_insert (base.indep hX) a h1) with ⟨C, ⟨hC1, hC2⟩⟩,
--   /-have h5 := exists_of_exists_unique h3,
--   simp at h5,
--   rcases h5 with ⟨C2, ⟨hC, ⟨hCaX⟩⟩⟩,-/
--   -- C(a, X) dep, Y indep
--   have h4 := circuit.dep hC1.2.1,
--   have h5 := base.indep hY,
--   -- C(a, X) \ Y ≠ ∅
--   have h6 : set.nonempty (C \ Y),
--   apply nonempty_of_not_subset,
--   by_contra,
--   apply h4,
--   apply indep_mono h h5,
--   -- let b ∈ C(a, X) \ Y
--   rw set.nonempty at h6,
--   cases h6 with b hb,
--   rw mem_diff at hb,
--   have h7 : b ∈ X,
--   have h8 := mem_of_subset_of_mem hC1.1 hb.1,
--   simp at h8,
--   have h9 := ne.symm (has_mem.mem.ne_of_not_mem haX hb.2),
--   cc,
--   -- then b ∈ X ∧ b ∉ Y
--   have h10 : ¬ C ⊆ (X \ {b} ∪ {a}),
--   simp,
--   rw not_subset,
--   use b,
--   refine ⟨hb.1, _⟩,
--   simp,
--   exact ne.symm (has_mem.mem.ne_of_not_mem haX hb.2),
--   -- then (X \ {b} ∪ {a}) indep since it doesn't contain C(a, X)
--   use b,
--   refine ⟨⟨h7, hb.2⟩, _⟩,
--   have h11 : M.indep (X \ {b} ∪ {a}),
--   by_contra h12,
--   rw dep_iff_supset_circuit at h12,
--   rcases h12 with ⟨C', ⟨hC1', hC2'⟩⟩,
--   have h12 := union_subset_union (diff_subset X {b}) (subset.refl {a}),
--   have h13 := subset_trans hC1' h12,
--   specialize hC2 C',
--   simp at hC2,
--   simp at h13,
--   have hCX : ¬ C' ⊆ X,
--   by_contra hCX',
--   apply circuit.dep hC2' (indep_mono hCX' (base.indep hX)),
--   specialize hC2 h13 hC2' (set.mem_of_nsubset_insert_iff ⟨h13, hCX⟩),
--   rw hC2 at hC1',
--   apply h10,
--   exact hC1',
--   -- therefore it is basis
--   have h14 := base_of_ncard_eq_indep hX ⟨h11, _⟩,
--   apply h14,
--   rw ncard_union_eq,
--   rw ncard_diff,
--   simp_rw ncard_singleton,
--   have h15 : 0 < X.ncard,
--   rw ncard_pos,
--   use ⟨b, h7⟩,
--   rw nat.sub_add_cancel,
--   rw nat.add_one_le_iff,
--   exact h15,
--   simp,
--   exact h7,
--   simp only [disjoint_singleton_right, mem_diff, mem_singleton_iff, not_and_distrib],
--   left,
--   exact haY,
-- end

end matroid

section from_axioms

/-- A collection of sets satisfying the circuit axioms determines a matroid -/
def matroid_of_circuit
  (circuit : set E → Prop)
  (empty_not_circuit : ¬ circuit ∅)
  (antichain : ∀ C₁ C₂, circuit C₁ → circuit C₂ → C₁ ⊆ C₂ → C₁ = C₂)
  (elimination : ∀ C₁ C₂ e,
    circuit C₁ → circuit C₂ → C₁ ≠ C₂ → e ∈ C₁ ∩ C₂ → ∃ C ⊆ (C₁ ∪ C₂) \ {e}, circuit C) :
matroid E :=
matroid_of_indep (λ I, ∀ C ⊆ I, ¬circuit C) ⟨∅, λ C hC, (by rwa subset_empty_iff.mp hC)⟩
(λ I J hIJ hJ C hCI, hJ C (hCI.trans hIJ))
begin
  by_contra' h,
  obtain ⟨I,J,hI,hJ,hIJ,Hbad⟩ := h,
  set indep := (λ I, ∀ C ⊆ I, ¬circuit C) with hi,

  /- Choose an independent set `K ⊆ I ∪ J`, larger than `I`, for which `I \ K` is minimized -/
  set sbad := {K : set E | indep K ∧ K ⊆ I ∪ J ∧ I.ncard < K.ncard} with hsbad,
  have hbad_ne : sbad.nonempty := ⟨J, hJ, subset_union_right _ _, hIJ⟩,
  obtain ⟨K, ⟨hK, hKIJ, hIK⟩, hKmin⟩ :=
    @set.finite.exists_minimal_wrt (set E) _ _ (λ X, (I \ X).ncard) sbad (to_finite sbad) hbad_ne,
  simp only [hsbad, mem_set_of_eq, and_imp] at hKmin,

  obtain hIK_empty | ⟨e, heI, heK⟩ := (I \ K).eq_empty_or_nonempty,
  /- If `I \ K` is empty then we get an easy contradiction by augmenting `I` into `K`. -/
  { obtain ⟨e,heK,heI⟩ := exists_mem_not_mem_of_ncard_lt_ncard hIK,
    have heJ : e ∈ J := by_contra (λ heJ, not_or heI heJ (hKIJ heK)),
    obtain ⟨C, hCeI, hC⟩ := Hbad e heJ heI,
    exact hK C (hCeI.trans (insert_subset.mpr ⟨heK, diff_eq_empty.mp hIK_empty⟩)) hC},

  have hCf : ∀ f ∈ K \ I, ∃ Cf ⊆ (insert e K), circuit Cf ∧ f ∉ Cf ∧ e ∈ Cf,
  { rintro f ⟨hfK,hfI⟩,
    have hef : e ≠ f, from λ h, hfI (h ▸heI ),
    set T := ((insert e K) \ {f}) with hT,
    have hTIJ : T ⊆ I ∪ J, from
      ((diff_subset _ _).trans (insert_subset.mpr ⟨or.inl heI,hKIJ⟩)),
    have hTcard : T.ncard = K.ncard, by rw [hT, ncard_exchange' heK hfK],
    have hITcard : (I \ T).ncard < (I \ K).ncard,
    { rw [nat.lt_iff_add_one_le, hT, ←insert_diff_singleton_comm hef, ←union_singleton, ←diff_diff,
        ncard_diff_singleton_add_one ],
      { convert rfl.le using 2,
        rw [diff_eq_compl_inter, diff_eq_compl_inter, diff_eq_compl_inter, compl_inter,
          inter_distrib_right, compl_compl, singleton_inter_eq_empty.mpr hfI, empty_union]},
      exact ⟨heI,λ he', heK he'.1⟩},

    have hTi : ¬indep T, from
      λ hTi, hITcard.ne (hKmin _ hTi hTIJ (hIK.trans_eq hTcard.symm) hITcard.le).symm,

    push_neg at hTi,
    obtain ⟨Cf, hCfT, hCf⟩ := hTi,
    refine ⟨Cf, hCfT.trans (diff_subset _ _), hCf, _, _⟩,
    { exact mt (@hCfT f) (not_mem_diff_of_mem (mem_singleton f))},

    refine by_contra (λ heCf, hK Cf (λ x hxCf, _) hCf),

    exact mem_of_mem_insert_of_ne (hCfT hxCf).1 (by {rintro rfl, exact heCf hxCf})},

  obtain ⟨g,hgK,hgI⟩ := exists_mem_not_mem_of_ncard_lt_ncard hIK,
  obtain ⟨Cg, hCgss, hCg, hgCg, heCg⟩ := hCf g ⟨hgK,hgI⟩,

  have hg_ex : ∃ g', g' ∈ Cg ∧ g' ∈ K \ I,
  { by_contra' hg',
    exact hI _ (λ x hx,
      or.elim (hCgss hx) (λ h, h.symm ▸ heI) (λ hxK, by_contra (λ hxI, hg' _ hx ⟨hxK, hxI⟩))) hCg},
  obtain ⟨g', hg', hg'KI⟩ := hg_ex,

  obtain ⟨Cg', hCg'ss, hCg', hgCg', heCg'⟩ := hCf g' hg'KI,
  have hne : Cg ≠ Cg',
  { intro heq, rw ←heq at hgCg', exact hgCg' hg', },
  obtain ⟨C, hCss, hC⟩ := elimination _ _ e hCg hCg' hne ⟨heCg, heCg'⟩,
  refine hK C (hCss.trans _) hC,
  rw [diff_subset_iff, singleton_union],
  exact union_subset hCgss hCg'ss,
end

@[simp] lemma matroid_of_circuit_apply
  (circuit : set E → Prop)
  (empty_not_circuit : ¬ circuit ∅)
  (antichain : ∀ C₁ C₂, circuit C₁ → circuit C₂ → C₁ ⊆ C₂ → C₁ = C₂)
  (elimination : ∀ C₁ C₂ e,
    circuit C₁ → circuit C₂ → C₁ ≠ C₂ → e ∈ C₁ ∩ C₂ → ∃ C ⊆ (C₁ ∪ C₂) \ {e}, circuit C) :
(matroid_of_circuit circuit empty_not_circuit antichain elimination).circuit = circuit :=
begin
  ext C,
  simp_rw [matroid_of_circuit, matroid.circuit_def, matroid_of_indep_apply, not_forall, not_not,
    exists_prop],
  refine ⟨λ h, _,λ h, ⟨⟨_,rfl.subset, h⟩,λ I hIC C' hC'I hC',
    hIC.not_subset ((antichain C' C hC' h (hC'I.trans hIC.subset)) ▸ hC'I )⟩⟩,
  obtain ⟨⟨C₀,hC₀C, hC₀⟩,hI⟩ := h,
  obtain rfl | hC₀C := eq_or_ssubset_of_subset hC₀C,
    assumption,
  exact (hI _ hC₀C _ rfl.subset hC₀).elim,
end

end from_axioms


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

! This file was ported from Lean 3 source module data.sigma.lex
! leanprover-community/mathlib commit 448144f7ae193a8990cb7473c9e9a01990f64ac7
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Sigma.Basic
import Mathbin.Order.RelClasses

/-!
# Lexicographic order on a sigma type

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

This defines the lexicographical order of two arbitrary relations on a sigma type and proves some
lemmas about `psigma.lex`, which is defined in core Lean.

Given a relation in the index type and a relation on each summand, the lexicographical order on the
sigma type relates `a` and `b` if their summands are related or they are in the same summand and
related by the summand's relation.

## See also

Related files are:
* `data.finset.colex`: Colexicographic order on finite sets.
* `data.list.lex`: Lexicographic order on lists.
* `data.sigma.order`: Lexicographic order on `Σ i, α i` per say.
* `data.psigma.order`: Lexicographic order on `Σ' i, α i`.
* `data.prod.lex`: Lexicographic order on `α × β`. Can be thought of as the special case of
  `sigma.lex` where all summands are the same
-/

namespace Sigma

variable {ι : Type _} {α : ι → Type _} {r r₁ r₂ : ι → ι → Prop} {s s₁ s₂ : ∀ i, α i → α i → Prop}
  {a b : Σi, α i}

#print Sigma.Lex /-
/-- The lexicographical order on a sigma type. It takes in a relation on the index type and a
relation for each summand. `a` is related to `b` iff their summands are related or they are in the
same summand and are related through the summand's relation. -/
inductive Lex (r : ι → ι → Prop) (s : ∀ i, α i → α i → Prop) : ∀ a b : Σi, α i, Prop
  | left {i j : ι} (a : α i) (b : α j) : r i j → Lex ⟨i, a⟩ ⟨j, b⟩
  | right {i : ι} (a b : α i) : s i a b → Lex ⟨i, a⟩ ⟨i, b⟩
#align sigma.lex Sigma.Lex
-/

/- warning: sigma.lex_iff -> Sigma.lex_iff is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop} {a : Sigma.{u1, u2} ι (fun (i : ι) => α i)} {b : Sigma.{u1, u2} ι (fun (i : ι) => α i)}, Iff (Sigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r s a b) (Or (r (Sigma.fst.{u1, u2} ι (fun (i : ι) => α i) a) (Sigma.fst.{u1, u2} ι (fun (i : ι) => α i) b)) (Exists.{0} (Eq.{succ u1} ι (Sigma.fst.{u1, u2} ι (fun (i : ι) => α i) a) (Sigma.fst.{u1, u2} ι (fun (i : ι) => α i) b)) (fun (h : Eq.{succ u1} ι (Sigma.fst.{u1, u2} ι (fun (i : ι) => α i) a) (Sigma.fst.{u1, u2} ι (fun (i : ι) => α i) b)) => s (Sigma.fst.{u1, u2} ι (fun (i : ι) => α i) b) (Eq.ndrec.{succ u2, succ u1} ι (Sigma.fst.{u1, u2} ι (fun (i : ι) => α i) a) α (Sigma.snd.{u1, u2} ι (fun (i : ι) => α i) a) (Sigma.fst.{u1, u2} ι (fun (i : ι) => α i) b) h) (Sigma.snd.{u1, u2} ι (fun (i : ι) => α i) b))))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop} {a : Sigma.{u2, u1} ι (fun (i : ι) => α i)} {b : Sigma.{u2, u1} ι (fun (i : ι) => α i)}, Iff (Sigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r s a b) (Or (r (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) b)) (Exists.{0} (Eq.{succ u2} ι (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) b)) (fun (h : Eq.{succ u2} ι (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) b)) => s (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) b) (Eq.rec.{succ u1, succ u2} ι (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) (fun (x._@.Mathlib.Data.Sigma.Lex._hyg.390 : ι) (x._@.Mathlib.Data.Sigma.Lex._hyg.389 : Eq.{succ u2} ι (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) x._@.Mathlib.Data.Sigma.Lex._hyg.390) => α x._@.Mathlib.Data.Sigma.Lex._hyg.390) (Sigma.snd.{u2, u1} ι (fun (i : ι) => α i) a) (Sigma.fst.{u2, u1} ι (fun (i : ι) => α i) b) h) (Sigma.snd.{u2, u1} ι (fun (i : ι) => α i) b))))
Case conversion may be inaccurate. Consider using '#align sigma.lex_iff Sigma.lex_iffₓ'. -/
theorem lex_iff : Lex r s a b ↔ r a.1 b.1 ∨ ∃ h : a.1 = b.1, s _ (h.rec a.2) b.2 :=
  by
  constructor
  · rintro (⟨a, b, hij⟩ | ⟨a, b, hab⟩)
    · exact Or.inl hij
    · exact Or.inr ⟨rfl, hab⟩
  · obtain ⟨i, a⟩ := a
    obtain ⟨j, b⟩ := b
    dsimp only
    rintro (h | ⟨rfl, h⟩)
    · exact lex.left _ _ h
    · exact lex.right _ _ h
#align sigma.lex_iff Sigma.lex_iff

#print Sigma.Lex.decidable /-
instance Lex.decidable (r : ι → ι → Prop) (s : ∀ i, α i → α i → Prop) [DecidableEq ι]
    [DecidableRel r] [∀ i, DecidableRel (s i)] : DecidableRel (Lex r s) := fun a b =>
  decidable_of_decidable_of_iff inferInstance lex_iff.symm
#align sigma.lex.decidable Sigma.Lex.decidable
-/

/- warning: sigma.lex.mono -> Sigma.Lex.mono is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} {r₁ : ι -> ι -> Prop} {r₂ : ι -> ι -> Prop} {s₁ : forall (i : ι), (α i) -> (α i) -> Prop} {s₂ : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (a : ι) (b : ι), (r₁ a b) -> (r₂ a b)) -> (forall (i : ι) (a : α i) (b : α i), (s₁ i a b) -> (s₂ i a b)) -> (forall {a : Sigma.{u1, u2} ι (fun (i : ι) => α i)} {b : Sigma.{u1, u2} ι (fun (i : ι) => α i)}, (Sigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r₁ s₁ a b) -> (Sigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r₂ s₂ a b))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} {r₁ : ι -> ι -> Prop} {r₂ : ι -> ι -> Prop} {s₁ : forall (i : ι), (α i) -> (α i) -> Prop} {s₂ : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (a : ι) (b : ι), (r₁ a b) -> (r₂ a b)) -> (forall (i : ι) (a : α i) (b : α i), (s₁ i a b) -> (s₂ i a b)) -> (forall {a : Sigma.{u2, u1} ι (fun (i : ι) => α i)} {b : Sigma.{u2, u1} ι (fun (i : ι) => α i)}, (Sigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r₁ s₁ a b) -> (Sigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r₂ s₂ a b))
Case conversion may be inaccurate. Consider using '#align sigma.lex.mono Sigma.Lex.monoₓ'. -/
theorem Lex.mono (hr : ∀ a b, r₁ a b → r₂ a b) (hs : ∀ i a b, s₁ i a b → s₂ i a b) {a b : Σi, α i}
    (h : Lex r₁ s₁ a b) : Lex r₂ s₂ a b :=
  by
  obtain ⟨a, b, hij⟩ | ⟨a, b, hab⟩ := h
  · exact lex.left _ _ (hr _ _ hij)
  · exact lex.right _ _ (hs _ _ _ hab)
#align sigma.lex.mono Sigma.Lex.mono

/- warning: sigma.lex.mono_left -> Sigma.Lex.mono_left is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} {r₁ : ι -> ι -> Prop} {r₂ : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (a : ι) (b : ι), (r₁ a b) -> (r₂ a b)) -> (forall {a : Sigma.{u1, u2} ι (fun (i : ι) => α i)} {b : Sigma.{u1, u2} ι (fun (i : ι) => α i)}, (Sigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r₁ s a b) -> (Sigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r₂ s a b))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} {r₁ : ι -> ι -> Prop} {r₂ : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (a : ι) (b : ι), (r₁ a b) -> (r₂ a b)) -> (forall {a : Sigma.{u2, u1} ι (fun (i : ι) => α i)} {b : Sigma.{u2, u1} ι (fun (i : ι) => α i)}, (Sigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r₁ s a b) -> (Sigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r₂ s a b))
Case conversion may be inaccurate. Consider using '#align sigma.lex.mono_left Sigma.Lex.mono_leftₓ'. -/
theorem Lex.mono_left (hr : ∀ a b, r₁ a b → r₂ a b) {a b : Σi, α i} (h : Lex r₁ s a b) :
    Lex r₂ s a b :=
  h.mono hr fun _ _ _ => id
#align sigma.lex.mono_left Sigma.Lex.mono_left

/- warning: sigma.lex.mono_right -> Sigma.Lex.mono_right is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} {r : ι -> ι -> Prop} {s₁ : forall (i : ι), (α i) -> (α i) -> Prop} {s₂ : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (i : ι) (a : α i) (b : α i), (s₁ i a b) -> (s₂ i a b)) -> (forall {a : Sigma.{u1, u2} ι (fun (i : ι) => α i)} {b : Sigma.{u1, u2} ι (fun (i : ι) => α i)}, (Sigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r s₁ a b) -> (Sigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r s₂ a b))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} {r : ι -> ι -> Prop} {s₁ : forall (i : ι), (α i) -> (α i) -> Prop} {s₂ : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (i : ι) (a : α i) (b : α i), (s₁ i a b) -> (s₂ i a b)) -> (forall {a : Sigma.{u2, u1} ι (fun (i : ι) => α i)} {b : Sigma.{u2, u1} ι (fun (i : ι) => α i)}, (Sigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r s₁ a b) -> (Sigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r s₂ a b))
Case conversion may be inaccurate. Consider using '#align sigma.lex.mono_right Sigma.Lex.mono_rightₓ'. -/
theorem Lex.mono_right (hs : ∀ i a b, s₁ i a b → s₂ i a b) {a b : Σi, α i} (h : Lex r s₁ a b) :
    Lex r s₂ a b :=
  h.mono (fun _ _ => id) hs
#align sigma.lex.mono_right Sigma.Lex.mono_right

/- warning: sigma.lex_swap -> Sigma.lex_swap is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop} {a : Sigma.{u1, u2} ι (fun (i : ι) => α i)} {b : Sigma.{u1, u2} ι (fun (i : ι) => α i)}, Iff (Sigma.Lex.{u1, u2} ι (fun (i : ι) => α i) (Function.swap.{succ u1, succ u1, 1} ι ι (fun (ᾰ : ι) (ᾰ : ι) => Prop) r) s a b) (Sigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r (fun (i : ι) => Function.swap.{succ u2, succ u2, 1} (α i) (α i) (fun (ᾰ : α i) (ᾰ : α i) => Prop) (s i)) b a)
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop} {a : Sigma.{u2, u1} ι (fun (i : ι) => α i)} {b : Sigma.{u2, u1} ι (fun (i : ι) => α i)}, Iff (Sigma.Lex.{u2, u1} ι (fun (i : ι) => α i) (Function.swap.{succ u2, succ u2, 1} ι ι (fun (ᾰ : ι) (ᾰ : ι) => Prop) r) s a b) (Sigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r (fun (i : ι) => Function.swap.{succ u1, succ u1, 1} (α i) (α i) (fun (ᾰ : α i) (ᾰ : α i) => Prop) (s i)) b a)
Case conversion may be inaccurate. Consider using '#align sigma.lex_swap Sigma.lex_swapₓ'. -/
theorem lex_swap : Lex r.symm s a b ↔ Lex r (fun i => (s i).symm) b a := by
  constructor <;>
    · rintro (⟨a, b, h⟩ | ⟨a, b, h⟩)
      exacts[lex.left _ _ h, lex.right _ _ h]
#align sigma.lex_swap Sigma.lex_swap

instance [∀ i, IsRefl (α i) (s i)] : IsRefl _ (Lex r s) :=
  ⟨fun ⟨i, a⟩ => Lex.right _ _ <| refl _⟩

instance [IsIrrefl ι r] [∀ i, IsIrrefl (α i) (s i)] : IsIrrefl _ (Lex r s) :=
  ⟨by
    rintro _ (⟨a, b, hi⟩ | ⟨a, b, ha⟩)
    · exact irrefl _ hi
    · exact irrefl _ ha⟩

instance [IsTrans ι r] [∀ i, IsTrans (α i) (s i)] : IsTrans _ (Lex r s) :=
  ⟨by
    rintro _ _ _ (⟨a, b, hij⟩ | ⟨a, b, hab⟩) (⟨_, c, hk⟩ | ⟨_, c, hc⟩)
    · exact lex.left _ _ (trans hij hk)
    · exact lex.left _ _ hij
    · exact lex.left _ _ hk
    · exact lex.right _ _ (trans hab hc)⟩

instance [IsSymm ι r] [∀ i, IsSymm (α i) (s i)] : IsSymm _ (Lex r s) :=
  ⟨by
    rintro _ _ (⟨a, b, hij⟩ | ⟨a, b, hab⟩)
    · exact lex.left _ _ (symm hij)
    · exact lex.right _ _ (symm hab)⟩

attribute [local instance] IsAsymm.isIrrefl

instance [IsAsymm ι r] [∀ i, IsAntisymm (α i) (s i)] : IsAntisymm _ (Lex r s) :=
  ⟨by
    rintro _ _ (⟨a, b, hij⟩ | ⟨a, b, hab⟩) (⟨_, _, hji⟩ | ⟨_, _, hba⟩)
    · exact (asymm hij hji).elim
    · exact (irrefl _ hij).elim
    · exact (irrefl _ hji).elim
    · exact ext rfl (hEq_of_eq <| antisymm hab hba)⟩

instance [IsTrichotomous ι r] [∀ i, IsTotal (α i) (s i)] : IsTotal _ (Lex r s) :=
  ⟨by
    rintro ⟨i, a⟩ ⟨j, b⟩
    obtain hij | rfl | hji := trichotomous_of r i j
    · exact Or.inl (lex.left _ _ hij)
    · obtain hab | hba := total_of (s i) a b
      · exact Or.inl (lex.right _ _ hab)
      · exact Or.inr (lex.right _ _ hba)
    · exact Or.inr (lex.left _ _ hji)⟩

instance [IsTrichotomous ι r] [∀ i, IsTrichotomous (α i) (s i)] : IsTrichotomous _ (Lex r s) :=
  ⟨by
    rintro ⟨i, a⟩ ⟨j, b⟩
    obtain hij | rfl | hji := trichotomous_of r i j
    · exact Or.inl (lex.left _ _ hij)
    · obtain hab | rfl | hba := trichotomous_of (s i) a b
      · exact Or.inl (lex.right _ _ hab)
      · exact Or.inr (Or.inl rfl)
      · exact Or.inr (Or.inr <| lex.right _ _ hba)
    · exact Or.inr (Or.inr <| lex.left _ _ hji)⟩

end Sigma

/-! ### `psigma` -/

namespace PSigma

variable {ι : Sort _} {α : ι → Sort _} {r r₁ r₂ : ι → ι → Prop} {s s₁ s₂ : ∀ i, α i → α i → Prop}

/- warning: psigma.lex_iff -> PSigma.lex_iff is a dubious translation:
lean 3 declaration is
  forall {ι : Sort.{u1}} {α : ι -> Sort.{u2}} {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop} {a : PSigma.{u1, u2} ι (fun (i : ι) => α i)} {b : PSigma.{u1, u2} ι (fun (i : ι) => α i)}, Iff (PSigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r s a b) (Or (r (PSigma.fst.{u1, u2} ι (fun (i : ι) => α i) a) (PSigma.fst.{u1, u2} ι (fun (i : ι) => α i) b)) (Exists.{0} (Eq.{u1} ι (PSigma.fst.{u1, u2} ι (fun (i : ι) => α i) a) (PSigma.fst.{u1, u2} ι (fun (i : ι) => α i) b)) (fun (h : Eq.{u1} ι (PSigma.fst.{u1, u2} ι (fun (i : ι) => α i) a) (PSigma.fst.{u1, u2} ι (fun (i : ι) => α i) b)) => s (PSigma.fst.{u1, u2} ι (fun (i : ι) => α i) b) (Eq.ndrec.{u2, u1} ι (PSigma.fst.{u1, u2} ι (fun (i : ι) => α i) a) α (PSigma.snd.{u1, u2} ι (fun (i : ι) => α i) a) (PSigma.fst.{u1, u2} ι (fun (i : ι) => α i) b) h) (PSigma.snd.{u1, u2} ι (fun (i : ι) => α i) b))))
but is expected to have type
  forall {ι : Sort.{u2}} {α : ι -> Sort.{u1}} {r : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop} {a : PSigma.{u2, u1} ι (fun (i : ι) => α i)} {b : PSigma.{u2, u1} ι (fun (i : ι) => α i)}, Iff (PSigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r s a b) (Or (r (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) b)) (Exists.{0} (Eq.{u2} ι (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) b)) (fun (h : Eq.{u2} ι (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) b)) => s (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) b) (Eq.rec.{u1, u2} ι (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) (fun (x._@.Mathlib.Data.Sigma.Lex._hyg.2408 : ι) (x._@.Mathlib.Data.Sigma.Lex._hyg.2407 : Eq.{u2} ι (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) a) x._@.Mathlib.Data.Sigma.Lex._hyg.2408) => α x._@.Mathlib.Data.Sigma.Lex._hyg.2408) (PSigma.snd.{u2, u1} ι (fun (i : ι) => α i) a) (PSigma.fst.{u2, u1} ι (fun (i : ι) => α i) b) h) (PSigma.snd.{u2, u1} ι (fun (i : ι) => α i) b))))
Case conversion may be inaccurate. Consider using '#align psigma.lex_iff PSigma.lex_iffₓ'. -/
theorem lex_iff {a b : Σ'i, α i} : Lex r s a b ↔ r a.1 b.1 ∨ ∃ h : a.1 = b.1, s _ (h.rec a.2) b.2 :=
  by
  constructor
  · rintro (⟨a, b, hij⟩ | ⟨i, hab⟩)
    · exact Or.inl hij
    · exact Or.inr ⟨rfl, hab⟩
  · obtain ⟨i, a⟩ := a
    obtain ⟨j, b⟩ := b
    dsimp only
    rintro (h | ⟨rfl, h⟩)
    · exact lex.left _ _ h
    · exact lex.right _ h
#align psigma.lex_iff PSigma.lex_iff

#print PSigma.Lex.decidable /-
instance Lex.decidable (r : ι → ι → Prop) (s : ∀ i, α i → α i → Prop) [DecidableEq ι]
    [DecidableRel r] [∀ i, DecidableRel (s i)] : DecidableRel (Lex r s) := fun a b =>
  decidable_of_decidable_of_iff inferInstance lex_iff.symm
#align psigma.lex.decidable PSigma.Lex.decidable
-/

/- warning: psigma.lex.mono -> PSigma.Lex.mono is a dubious translation:
lean 3 declaration is
  forall {ι : Sort.{u1}} {α : ι -> Sort.{u2}} {r₁ : ι -> ι -> Prop} {r₂ : ι -> ι -> Prop} {s₁ : forall (i : ι), (α i) -> (α i) -> Prop} {s₂ : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (a : ι) (b : ι), (r₁ a b) -> (r₂ a b)) -> (forall (i : ι) (a : α i) (b : α i), (s₁ i a b) -> (s₂ i a b)) -> (forall {a : PSigma.{u1, u2} ι (fun (i : ι) => α i)} {b : PSigma.{u1, u2} ι (fun (i : ι) => α i)}, (PSigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r₁ s₁ a b) -> (PSigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r₂ s₂ a b))
but is expected to have type
  forall {ι : Sort.{u2}} {α : ι -> Sort.{u1}} {r₁ : ι -> ι -> Prop} {r₂ : ι -> ι -> Prop} {s₁ : forall (i : ι), (α i) -> (α i) -> Prop} {s₂ : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (a : ι) (b : ι), (r₁ a b) -> (r₂ a b)) -> (forall (i : ι) (a : α i) (b : α i), (s₁ i a b) -> (s₂ i a b)) -> (forall {a : PSigma.{u2, u1} ι (fun (i : ι) => α i)} {b : PSigma.{u2, u1} ι (fun (i : ι) => α i)}, (PSigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r₁ s₁ a b) -> (PSigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r₂ s₂ a b))
Case conversion may be inaccurate. Consider using '#align psigma.lex.mono PSigma.Lex.monoₓ'. -/
theorem Lex.mono {r₁ r₂ : ι → ι → Prop} {s₁ s₂ : ∀ i, α i → α i → Prop}
    (hr : ∀ a b, r₁ a b → r₂ a b) (hs : ∀ i a b, s₁ i a b → s₂ i a b) {a b : Σ'i, α i}
    (h : Lex r₁ s₁ a b) : Lex r₂ s₂ a b :=
  by
  obtain ⟨a, b, hij⟩ | ⟨i, hab⟩ := h
  · exact lex.left _ _ (hr _ _ hij)
  · exact lex.right _ (hs _ _ _ hab)
#align psigma.lex.mono PSigma.Lex.mono

/- warning: psigma.lex.mono_left -> PSigma.Lex.mono_left is a dubious translation:
lean 3 declaration is
  forall {ι : Sort.{u1}} {α : ι -> Sort.{u2}} {r₁ : ι -> ι -> Prop} {r₂ : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (a : ι) (b : ι), (r₁ a b) -> (r₂ a b)) -> (forall {a : PSigma.{u1, u2} ι (fun (i : ι) => α i)} {b : PSigma.{u1, u2} ι (fun (i : ι) => α i)}, (PSigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r₁ s a b) -> (PSigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r₂ s a b))
but is expected to have type
  forall {ι : Sort.{u2}} {α : ι -> Sort.{u1}} {r₁ : ι -> ι -> Prop} {r₂ : ι -> ι -> Prop} {s : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (a : ι) (b : ι), (r₁ a b) -> (r₂ a b)) -> (forall {a : PSigma.{u2, u1} ι (fun (i : ι) => α i)} {b : PSigma.{u2, u1} ι (fun (i : ι) => α i)}, (PSigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r₁ s a b) -> (PSigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r₂ s a b))
Case conversion may be inaccurate. Consider using '#align psigma.lex.mono_left PSigma.Lex.mono_leftₓ'. -/
theorem Lex.mono_left {r₁ r₂ : ι → ι → Prop} {s : ∀ i, α i → α i → Prop}
    (hr : ∀ a b, r₁ a b → r₂ a b) {a b : Σ'i, α i} (h : Lex r₁ s a b) : Lex r₂ s a b :=
  h.mono hr fun _ _ _ => id
#align psigma.lex.mono_left PSigma.Lex.mono_left

/- warning: psigma.lex.mono_right -> PSigma.Lex.mono_right is a dubious translation:
lean 3 declaration is
  forall {ι : Sort.{u1}} {α : ι -> Sort.{u2}} {r : ι -> ι -> Prop} {s₁ : forall (i : ι), (α i) -> (α i) -> Prop} {s₂ : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (i : ι) (a : α i) (b : α i), (s₁ i a b) -> (s₂ i a b)) -> (forall {a : PSigma.{u1, u2} ι (fun (i : ι) => α i)} {b : PSigma.{u1, u2} ι (fun (i : ι) => α i)}, (PSigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r s₁ a b) -> (PSigma.Lex.{u1, u2} ι (fun (i : ι) => α i) r s₂ a b))
but is expected to have type
  forall {ι : Sort.{u2}} {α : ι -> Sort.{u1}} {r : ι -> ι -> Prop} {s₁ : forall (i : ι), (α i) -> (α i) -> Prop} {s₂ : forall (i : ι), (α i) -> (α i) -> Prop}, (forall (i : ι) (a : α i) (b : α i), (s₁ i a b) -> (s₂ i a b)) -> (forall {a : PSigma.{u2, u1} ι (fun (i : ι) => α i)} {b : PSigma.{u2, u1} ι (fun (i : ι) => α i)}, (PSigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r s₁ a b) -> (PSigma.Lex.{u2, u1} ι (fun (i : ι) => α i) r s₂ a b))
Case conversion may be inaccurate. Consider using '#align psigma.lex.mono_right PSigma.Lex.mono_rightₓ'. -/
theorem Lex.mono_right {r : ι → ι → Prop} {s₁ s₂ : ∀ i, α i → α i → Prop}
    (hs : ∀ i a b, s₁ i a b → s₂ i a b) {a b : Σ'i, α i} (h : Lex r s₁ a b) : Lex r s₂ a b :=
  h.mono (fun _ _ => id) hs
#align psigma.lex.mono_right PSigma.Lex.mono_right

end PSigma