import Lib.Algebra.Monoid
import Lib.Data.Array.Basic
import Lib.Function

class Foldable (F : Type u → Type v) where
  foldl {α β : Type u} (f : β → α → β) (x₀ : β) (t : F α) : β
  foldr {α β : Type u} (f : α → β → β) (x₀ : β) (t : F α) : β
  toList {α} (x : F α) : List α := foldl (flip (.::.)) [] x |>.reverse
  toArray {α} (x : F α) : Array α := toList x |>.toArray
  length {α} (x : F α) : Nat :=
    ULift.down <| foldl (λ n _ => ⟨n.1.succ⟩) ⟨0⟩ x

namespace Foldable

variable {F} [Foldable F]
variable {α : Type u}

def foldMap [One m] [Mul m] (f : α → m) (x : F α) : m :=
foldl (λ acc x => f x * acc) 1 x

def sum [Zero α] [Add α] : F α → α :=
foldl (.+.) 0

def product [One α] [Mul α] : F α → α :=
foldl (.*.) 1

end Foldable

open One

open Foldable

macro "prove_length_toList" sim:ident α:ident x:ident : tactic =>
  `(tactic|
       -- intros α x;
       suffices H : ((foldl (flip (.::.)) [] x).length =
                 ULift.down (foldl (β := ULift Nat)
                            (λ ⟨n⟩ _ => ⟨n.succ⟩) ⟨0⟩ x))
                by {trans <;> try assumption};
       let R :=
         λ (x : List α) (y : ULift Nat) => x.length = y.down;
       apply sim (SIM := R)
       . apply Reflexive.refl
       . simp [flip]; auto)

macro "prove_foldl_toList" sim:term : tactic =>
  `(tactic|
       intros α β f x₀ x;
       suffices H : ((foldl (flip (.::.)) [] x).foldl f x₀ x =
                 foldl f x₀ x)
                by {trans <;> try assumption};
       let R :=
         λ (x : List α) (y : β) => x.reverse.foldl f x₀ x = y;
       apply sim (SIM := R)
       . apply Reflexive.refl
       . simp [flip]; auto)

class LawfulFoldable (F : Type u → Type v) [Foldable F] where
  foldl_sim {α β γ : Type u} {f : β → α → β} {g : γ → α → γ} {SIM : β → γ → Prop} {x₀ y₀} (t : F α) :
    SIM x₀ y₀ →
    (∀ a x y, SIM x y → SIM (f x a) (g y a)) →
    SIM (foldl f x₀ t) (foldl g y₀ t)
  foldr_eq_foldMap {α β} (f : α → β → β) (x : F α) (x₀ : β) :
    foldr f x₀ x =
    (foldMap (λ x => Op.mk $ Endo.mk (f x)) x).run.run x₀
  toArray_toList {α} (x : F α) : (toList x).toArray = toArray x
    -- by apply Reflexive.refl
  length_toList {α} (x : F α) : (toList x).length = length x
 -- :=
 --    -- let H := @foldl_sim
 --    -- by prove_length_toList H α x
 --       have H' : ∀ xs n, List.length xs = n → List.length xs.reverse = n := sorry
 --       suffices H : ((foldl (flip (.::.)) [] x).length =
 --                 ULift.down (foldl (β := ULift Nat)
 --                            (λ ⟨n⟩ _ => ⟨n.succ⟩) ⟨0⟩ x))
 --                by apply H' _ _ H
 --       let R :=
 --         λ (x : List α) (y : ULift Nat) => x.length = y.down;
 --       by apply foldl_sim (SIM := R)
 --          . apply Reflexive.refl
 --          . simp [flip]; auto
  foldl_toList {α β} (f : β → α → β) (x₀ : β) (x : F α) :
    (toList x).foldl f x₀ = foldl f x₀ x
 -- :=
 --    -- let H := @foldl_sim
 --    -- by prove_foldl_toList H
 --       suffices H : ((foldl (flip (.::.)) [] x).reverse.foldl f x₀ =
 --                 foldl f x₀ x)
 --                by {trans <;> try assumption}
 --       let R :=
 --         λ (l : List α) (y : β) => l.reverse.foldl f x₀ = y;
 --       by
 --          apply foldl_sim (SIM := R) x
 --       -- apply sim (SIM := R)
 --          . apply Reflexive.refl
 --          focus simp [flip]

namespace LawfulFoldable
attribute [simp] length_toList toArray_toList

variable {F} [Foldable F] [LawfulFoldable F]

theorem foldl_hom {α β γ : Type u} {f : β → α → β} {g : γ → α → γ} {h : β → γ} {x₀ y₀} (t : F α) :
    h x₀ = y₀ →
    (∀ x y, h (f x y) = g (h x) y) →
    h (foldl f x₀ t) = foldl g y₀ t := by
let R x y := h x = y
intros h₀ h₁
apply foldl_sim (SIM := R)
. assumption
. simp only; intros; substAll; apply h₁

variable [Monoid α] [Monoid β]
variable (f : MonoidHom α β)

variable {γ : Type u}

theorem foldMap_hom (g₀ : γ → α) (x : F γ) :
  f (foldMap g₀ x) = foldMap (f ∘ g₀) x := by
apply foldl_hom <;> intros <;> simp

@[simp]
theorem toList_toArray {α} (x : F α) : (toArray x).toList = toList x := by
rw [← toArray_toList, Array.toList_toArray]

@[simp]
theorem size_toArray {α} (x : F α) : (toArray x).size = length x := by
rw [← toArray_toList]; simp [-toArray_toList]

theorem foldl_toArray {α β} (f : β → α → β) (x₀ : β) (x : F α) :
    (toArray x).foldl f x₀ = foldl f x₀ x := by
rw [← toArray_toList]; simp [-toArray_toList]
rw [Array.foldl_toArray, foldl_toList]
rw [length_toList]

theorem toList_eq (x : F α) :
  toList x = (foldl (flip (.::.)) [] x).reverse := by
rw [← foldl_toList, List.foldl_eq_self]

theorem toArray_eq (x : F α) :
  toArray x = (foldl Array.push #[] x) := by
rw [← toArray_toList, ← foldl_toList]
generalize toList x = xs; clear x
simp only [List.toArray]
simp [List.toArrayAux, Array.mkEmpty_eq_mkEmpty 0]
generalize (Array.mkEmpty 0) = ar
induction xs generalizing ar
 <;> simp [List.toArrayAux, List.foldl, *]

theorem length_eq (x : F α) :
  length x = ULift.down (foldl (λ ⟨n⟩ _ => ⟨n.succ⟩) ⟨0⟩ x) := by
rw [← length_toList, toList_eq, List.length_reverse]
let R (x : List α) (y : ULift Nat) := x.length = y.down
apply foldl_sim (SIM := R)
. apply Reflexive.refl
intros a xs n; cases n with
  | up n =>
simp [flip]; auto

theorem foldl_eq_foldMap (f : β → α → β) (x₀ : β) (x : F α) :
  foldl f x₀ x = (foldMap (λ a => Endo.mk (f . a)) x).run x₀ := by
  intros; simp [foldMap]
  let g := (fun acc x => Endo.mk (λ a => f a x) * acc)
  symmetry
  apply foldl_hom (h := λ x => Endo.run x x₀) (f := g) (g := f)
  . refl
  intros; simp

theorem foldr_toList
  (f : α → β → β) (x₀ : β) (x : F α) :
  List.foldr f x₀ (toList x) = foldr f x₀ x := by
rw [← flip_flip f, ← List.foldl_reverse, foldr_eq_foldMap]
simp only [foldMap]
rw [← foldl_toList]
symmetry
generalize toList x = l
rw [flip_flip]
have : ∀ x y : β, x = Endo.run (Op.run 1) y → x = y :=
  by auto
apply this; clear this
generalize (1 : Op (Endo β)) = k
induction l generalizing k
 <;> simp [List.foldl, *]

theorem foldr_eq_foldl_reverse_toList
  (f : α → β → β) (x₀ : β) (x : F α) :
  foldr f x₀ x = List.foldl (flip f) x₀ (toList x).reverse := by
simp [← foldr_toList]

theorem foldr_sim {SIM : β → γ → Prop}
        {f : α → β → β} {g : α → γ → γ}
        {x₀ : β} {y₀ : γ} {x : F α}
        (H₀ : SIM x₀ y₀)
        (Hstep : ∀ x y y', SIM y y' → SIM (f x y) (g x y')) :
  SIM (foldr f x₀ x) (foldr g y₀ x) := by
repeat rw [foldr_eq_foldl_reverse_toList]
auto [List.foldl_sim]

theorem foldr_hom {f : α → β → β} {g : α → γ → γ}
        {h : β → γ} {x₀ y₀} (t : F α) :
    h x₀ = y₀ →
    (∀ x y, h (f x y) = g x (h y)) →
    h (foldr f x₀ t) = foldr g y₀ t := by
let R x y := h x = y
intros h₀ h₁
apply foldr_sim (SIM := R)
. assumption
. simp only; intros; substAll; apply h₁
done

-- def OpRun : MonoidHom (Op (Endo α)) (Endo α) where
--   fn := Op.run
--   fn_id := _
--   fn_mul := _

-- example x y : x + Nat.succ y = y → x = y := by
-- assume' h : Nat.succ (x + y) = y
-- rw [← h]

theorem product_eq_foldr (x : F α) :
  product x = foldr (.*.) 1 x := by
simp [product, foldMap]
rw [foldr_eq_foldl_reverse_toList, ← foldl_toList]
generalize (toList x) = xs
generalize hz : (1 : α) = z
suffices hz' : List.foldl (.*.) z xs =
         z * List.foldl (flip (.*.)) 1 (List.reverse xs) by
  rw [hz', ← hz, Monoid.one_mul]
clear hz
induction xs generalizing z
<;> simp only [List.foldl, List.reverse_cons, List.foldl_app, *, flip]
<;> simp only [Monoid.mul_assoc, Monoid.mul_one]

-- let
-- let f (y : Op (Endo α)) := y.run.run 1
-- let g (x y : α) := x * y
-- let R (x : α) (y : Op (Endo α)) := x = y.run.run 1
-- apply foldl_sim (SIM := R)
-- next => rfl
-- next =>
--   intros a x y
--   assume Hsim : _ = _
--   show _ = _
--   simp [Hsim]
-- -- symmetry

-- apply foldl_hom (h := f)
-- next => rfl
-- next =>
  -- intros
  -- simp
  -- simp [1]
-- let f : MonoidHom (Op (Endo α)) (Endo α)
-- apply congr _ rfl; apply congrArg
-- rw [foldMap_hom (f := Op.run) ]
-- -- apply foldMap

end LawfulFoldable

class IdxFoldable (ι : outParam <| Type w)
      (F : Type u → Type v) where
  foldl {α β : Type u} (f : β → ι → α → β) (x₀ : β) (t : F α) : β
  foldr {α β : Type u} (f : ι → α → β → β) (x₀ : β) (t : F α) : β
  toList {α} (x : F α) : List α :=
    foldl (λ xs i x => x :: xs) [] x |>.reverse
  toArray {α} (x : F α) : Array α := toList x |>.toArray
  length {α} (x : F α) : Nat :=
    ULift.down <| foldl (λ n _ _ => ⟨n.1.succ⟩) ⟨0⟩ x

namespace IdxFoldable

variable {F} [IdxFoldable ι F]
variable {α : Type u}

def foldMap [One m] [Mul m] (f : ι → α → m) (x : F α) : m :=
foldl (λ acc i x => f i x * acc) 1 x

def sum [Zero α] [Add α] : F α → α :=
foldl (λ acc _ x => acc + x) 0

def product [One α] [Mul α] : F α → α :=
foldl (λ acc _ x => acc * x) 1

end IdxFoldable

section IdxFoldable
open IdxFoldable

class LawfulIdxFoldable (ι : outParam <| Type w)
      (F : Type u → Type v) [outParam <| IdxFoldable ι F] where
  foldl_sim {α β γ : Type u} {f : β → ι → α → β} {g : γ → ι → α → γ}
            {SIM : β → γ → Prop} {x₀ y₀} (t : F α) :
    SIM x₀ y₀ →
    (∀ i a x y, SIM x y → SIM (f x i a) (g y i a)) →
    SIM (foldl f x₀ t)
        (foldl g y₀ t)
  -- foldr_eq_foldMap {α β} (f : ι → α → β → β) (x : F α) (x₀ : β) :
  --   foldr f x₀ x =
  --   (foldMap (λ i x => Op.mk $ Endo.mk (f i x)) x).run.run x₀
  -- -- toArray_toList {α} (x : F α) : (toList x).toArray = toArray x
    -- by apply Reflexive.refl
  -- length_toList {α} (x : F α) : (toList x).length = length x
 -- :=
 --    -- let H := @foldl_sim
 --    -- by prove_length_toList H α x
 --       have H' : ∀ xs n, List.length xs = n → List.length xs.reverse = n := sorry
 --       suffices H : ((foldl (flip (.::.)) [] x).length =
 --                 ULift.down (foldl (β := ULift Nat)
 --                            (λ ⟨n⟩ _ => ⟨n.succ⟩) ⟨0⟩ x))
 --                by apply H' _ _ H
 --       let R :=
 --         λ (x : List α) (y : ULift Nat) => x.length = y.down;
 --       by apply foldl_sim (SIM := R)
 --          . apply Reflexive.refl
 --          . simp [flip]; auto
  -- foldl_toList {α β} (f : β → ι → α → β) (x₀ : β) (x : F α) :
    -- (toList x).foldl f x₀ = foldl f x₀ x
 -- :=
 --    -- let H := @foldl_sim
 --    -- by prove_foldl_toList H
 --       suffices H : ((foldl (flip (.::.)) [] x).reverse.foldl f x₀ =
 --                 foldl f x₀ x)
 --                by {trans <;> try assumption}
 --       let R :=
 --         λ (l : List α) (y : β) => l.reverse.foldl f x₀ = y;
 --       by
 --          apply foldl_sim (SIM := R) x
 --       -- apply sim (SIM := R)
 --          . apply Reflexive.refl
 --          focus simp [flip]

end IdxFoldable

namespace LawfulIdxFoldable
-- attribute [simp] length_toList toArray_toList
open IdxFoldable
variable {F} [IdxFoldable ι F] [LawfulIdxFoldable ι F]

theorem foldl_hom {α β γ : Type u}
        {f : β → ι → α → β} {g : γ → ι → α → γ}
        {h : β → γ} {x₀ y₀} (t : F α) :
    h x₀ = y₀ →
    (∀ i x y, h (f x i y) = g (h x) i y) →
    h (foldl f x₀ t) = foldl g y₀ t := by
let R x y := h x = y
intros h₀ h₁
apply foldl_sim (SIM := R)
. assumption
. simp only; intros; substAll; apply h₁

variable [Monoid α] [Monoid β]
variable (f : MonoidHom α β)

variable {γ : Type u}

theorem foldMap_hom (g₀ : ι → γ → α) (x : F γ) :
  f (foldMap g₀ x) = foldMap (f ∘ g₀ .) x := by
apply foldl_hom <;> intros <;> simp

theorem foldl_eq_foldMap (f : β → ι → α → β) (x₀ : β) (x : F α) :
  foldl f x₀ x =
  (foldMap (λ i a => Endo.mk (f . i a)) x).run x₀ := by
  intros; simp [IdxFoldable.foldMap]
  let g := (fun acc i x => Endo.mk (λ a => f a i x) * acc)
  symmetry
  apply foldl_hom (h := λ x => Endo.run x x₀) (f := g) (g := f)
  . refl
  intros; simp

end LawfulIdxFoldable


import algebra.ring algebra.group_power data.nat.prime data.nat.prime data.nat.basic data.int.modeq algebra.group_power group_theory.subgroup algebra.group data.set.basic
open nat

variables {R : Type*} [ring R]
-- 1. (a) Suppose n > 1 is a power of a prime number. Give a formula for the number of elements in the group (Z×n ; ·), explaining your answer.
-- euler totient function
--ef euler_tot (n : ℕ)
--theorem (ha: prime p) (n α : nat) (hp : n = p^α) :

-- (b) Find natural numbers n,m such that the residue class [m]n ∈ Z×n has order 5.
-- theorem sheet8_q1_b (m n : ℕ)

-- *2. Show that the following sets are rings with the given binary operations. In each case, describe the units.
-- (a) The set {a/b ∈ Q| b odd} ,with the usual + and ·  b
--def s₁ : {a/b ∈ ℚ ∣ b = 2k+1}
-- (b) The set of all functions f : [0,1] −→ C, with + and · given by (f₁  + f₂)(x) = f₁(x) + f₂(x), (f₁ · f₂)(x) = f₁(x)f₂(x).
--def s₂ :
-- (c) The set P(N) of all subsets of N, with the operations X+Y=X∪Y\X∩Y (the symmetric difference of X and Y), X·Y =X∩Y.

-- 3. Suppose R is a ring and S ⊆ R. Devise a criterion which enables you to check whether S with the operations inherited from R is a ring (i.e. invent a test for being a subring). If R is a ring with unity, does your criterion imply that S is a ring with unity? √√√

-- 4. Let d ∈ Z and Q[√d] = {x+y d|x,y∈Q}. Prove that Q[√d]is a ring with the usual operations + and · in C.
-- Show that every non-zero element of Q[√d]is a unit (so Q[√d] is a field).

-- 5. (a) Suppose that f(x) ∈ C[x] is non-zero and has n distinct roots. Prove that deg f ≥ n.
-- (b) Let f(x) ∈ R[x] be a polynomial with real coefficients. Show that if a ∈ C is a root of f(x), then its complex conjugate a is also a root of f(x). Deduce that if f(x) is an irreducible polynomial in R[x] then deg f ≤ 2.

-- 6. (a) Let f(x) ∈ Q[x] be a polynomial of degree at most 3 which has no rational root. Prove that f(x) is irreducible.
-- (b) Show that the polynomial f(x) = x^3 + x^2 + x + 3 is irreducible in Q[x].


/-
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 order.antichain
! leanprover-community/mathlib commit c227d107bbada5d0d9d20287e3282c0a7f1651a0
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Set.Pairwise.Basic
import Mathbin.Order.Bounds.Basic
import Mathbin.Order.Directed
import Mathbin.Order.Hom.Set

/-!
# Antichains

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

This file defines antichains. An antichain is a set where any two distinct elements are not related.
If the relation is `(≤)`, this corresponds to incomparability and usual order antichains. If the
relation is `G.adj` for `G : simple_graph α`, this corresponds to independent sets of `G`.

## Definitions

* `is_antichain r s`: Any two elements of `s : set α` are unrelated by `r : α → α → Prop`.
* `is_strong_antichain r s`: Any two elements of `s : set α` are not related by `r : α → α → Prop`
  to a common element.
* `is_antichain.mk r s`: Turns `s` into an antichain by keeping only the "maximal" elements.
-/

open Function Set

section General

variable {α β : Type _} {r r₁ r₂ : α → α → Prop} {r' : β → β → Prop} {s t : Set α} {a b : α}

#print Symmetric.compl /-
protected theorem Symmetric.compl (h : Symmetric r) : Symmetric (rᶜ) := fun x y hr hr' =>
  hr <| h hr'
#align symmetric.compl Symmetric.compl
-/

#print IsAntichain /-
/-- An antichain is a set such that no two distinct elements are related. -/
def IsAntichain (r : α → α → Prop) (s : Set α) : Prop :=
  s.Pairwise (rᶜ)
#align is_antichain IsAntichain
-/

namespace IsAntichain

#print IsAntichain.subset /-
protected theorem subset (hs : IsAntichain r s) (h : t ⊆ s) : IsAntichain r t :=
  hs.mono h
#align is_antichain.subset IsAntichain.subset
-/

#print IsAntichain.mono /-
theorem mono (hs : IsAntichain r₁ s) (h : r₂ ≤ r₁) : IsAntichain r₂ s :=
  hs.mono' <| compl_le_compl h
#align is_antichain.mono IsAntichain.mono
-/

#print IsAntichain.mono_on /-
theorem mono_on (hs : IsAntichain r₁ s) (h : s.Pairwise fun ⦃a b⦄ => r₂ a b → r₁ a b) :
    IsAntichain r₂ s :=
  hs.imp_on <| h.imp fun a b h h₁ h₂ => h₁ <| h h₂
#align is_antichain.mono_on IsAntichain.mono_on
-/

#print IsAntichain.eq /-
protected theorem eq (hs : IsAntichain r s) {a b : α} (ha : a ∈ s) (hb : b ∈ s) (h : r a b) :
    a = b :=
  hs.Eq ha hb <| not_not_intro h
#align is_antichain.eq IsAntichain.eq
-/

#print IsAntichain.eq' /-
protected theorem eq' (hs : IsAntichain r s) {a b : α} (ha : a ∈ s) (hb : b ∈ s) (h : r b a) :
    a = b :=
  (hs.Eq hb ha h).symm
#align is_antichain.eq' IsAntichain.eq'
-/

#print IsAntichain.isAntisymm /-
protected theorem isAntisymm (h : IsAntichain r univ) : IsAntisymm α r :=
  ⟨fun a b ha _ => h.Eq trivial trivial ha⟩
#align is_antichain.is_antisymm IsAntichain.isAntisymm
-/

#print IsAntichain.subsingleton /-
protected theorem subsingleton [IsTrichotomous α r] (h : IsAntichain r s) : s.Subsingleton :=
  by
  rintro a ha b hb
  obtain hab | hab | hab := trichotomous_of r a b
  · exact h.eq ha hb hab
  · exact hab
  · exact h.eq' ha hb hab
#align is_antichain.subsingleton IsAntichain.subsingleton
-/

#print IsAntichain.flip /-
protected theorem flip (hs : IsAntichain r s) : IsAntichain (flip r) s := fun a ha b hb h =>
  hs hb ha h.symm
#align is_antichain.flip IsAntichain.flip
-/

#print IsAntichain.swap /-
theorem swap (hs : IsAntichain r s) : IsAntichain (swap r) s :=
  hs.flip
#align is_antichain.swap IsAntichain.swap
-/

/- warning: is_antichain.image -> IsAntichain.image is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u1} α}, (IsAntichain.{u1} α r s) -> (forall (f : α -> β), (forall {{a : α}} {{b : α}}, (r' (f a) (f b)) -> (r a b)) -> (IsAntichain.{u2} β r' (Set.image.{u1, u2} α β f s)))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u2} α}, (IsAntichain.{u2} α r s) -> (forall (f : α -> β), (forall {{a : α}} {{b : α}}, (r' (f a) (f b)) -> (r a b)) -> (IsAntichain.{u1} β r' (Set.image.{u2, u1} α β f s)))
Case conversion may be inaccurate. Consider using '#align is_antichain.image IsAntichain.imageₓ'. -/
theorem image (hs : IsAntichain r s) (f : α → β) (h : ∀ ⦃a b⦄, r' (f a) (f b) → r a b) :
    IsAntichain r' (f '' s) :=
  by
  rintro _ ⟨b, hb, rfl⟩ _ ⟨c, hc, rfl⟩ hbc hr
  exact hs hb hc (ne_of_apply_ne _ hbc) (h hr)
#align is_antichain.image IsAntichain.image

/- warning: is_antichain.preimage -> IsAntichain.preimage is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u1} α}, (IsAntichain.{u1} α r s) -> (forall {f : β -> α}, (Function.Injective.{succ u2, succ u1} β α f) -> (forall {{a : β}} {{b : β}}, (r' a b) -> (r (f a) (f b))) -> (IsAntichain.{u2} β r' (Set.preimage.{u2, u1} β α f s)))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u2} α}, (IsAntichain.{u2} α r s) -> (forall {f : β -> α}, (Function.Injective.{succ u1, succ u2} β α f) -> (forall {{a : β}} {{b : β}}, (r' a b) -> (r (f a) (f b))) -> (IsAntichain.{u1} β r' (Set.preimage.{u1, u2} β α f s)))
Case conversion may be inaccurate. Consider using '#align is_antichain.preimage IsAntichain.preimageₓ'. -/
theorem preimage (hs : IsAntichain r s) {f : β → α} (hf : Injective f)
    (h : ∀ ⦃a b⦄, r' a b → r (f a) (f b)) : IsAntichain r' (f ⁻¹' s) := fun b hb c hc hbc hr =>
  hs hb hc (hf.Ne hbc) <| h hr
#align is_antichain.preimage IsAntichain.preimage

#print isAntichain_insert /-
theorem isAntichain_insert :
    IsAntichain r (insert a s) ↔ IsAntichain r s ∧ ∀ ⦃b⦄, b ∈ s → a ≠ b → ¬r a b ∧ ¬r b a :=
  Set.pairwise_insert
#align is_antichain_insert isAntichain_insert
-/

#print IsAntichain.insert /-
protected theorem insert (hs : IsAntichain r s) (hl : ∀ ⦃b⦄, b ∈ s → a ≠ b → ¬r b a)
    (hr : ∀ ⦃b⦄, b ∈ s → a ≠ b → ¬r a b) : IsAntichain r (insert a s) :=
  isAntichain_insert.2 ⟨hs, fun b hb hab => ⟨hr hb hab, hl hb hab⟩⟩
#align is_antichain.insert IsAntichain.insert
-/

#print isAntichain_insert_of_symmetric /-
theorem isAntichain_insert_of_symmetric (hr : Symmetric r) :
    IsAntichain r (insert a s) ↔ IsAntichain r s ∧ ∀ ⦃b⦄, b ∈ s → a ≠ b → ¬r a b :=
  pairwise_insert_of_symmetric hr.compl
#align is_antichain_insert_of_symmetric isAntichain_insert_of_symmetric
-/

#print IsAntichain.insert_of_symmetric /-
theorem insert_of_symmetric (hs : IsAntichain r s) (hr : Symmetric r)
    (h : ∀ ⦃b⦄, b ∈ s → a ≠ b → ¬r a b) : IsAntichain r (insert a s) :=
  (isAntichain_insert_of_symmetric hr).2 ⟨hs, h⟩
#align is_antichain.insert_of_symmetric IsAntichain.insert_of_symmetric
-/

/- warning: is_antichain.image_rel_embedding -> IsAntichain.image_relEmbedding is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u1} α}, (IsAntichain.{u1} α r s) -> (forall (φ : RelEmbedding.{u1, u2} α β r r'), IsAntichain.{u2} β r' (Set.image.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelEmbedding.{u1, u2} α β r r') (fun (_x : RelEmbedding.{u1, u2} α β r r') => α -> β) (RelEmbedding.hasCoeToFun.{u1, u2} α β r r') φ) s))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u2} α}, (IsAntichain.{u2} α r s) -> (forall (φ : RelEmbedding.{u2, u1} α β r r'), IsAntichain.{u1} β r' (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β r r' φ)) s))
Case conversion may be inaccurate. Consider using '#align is_antichain.image_rel_embedding IsAntichain.image_relEmbeddingₓ'. -/
theorem image_relEmbedding (hs : IsAntichain r s) (φ : r ↪r r') : IsAntichain r' (φ '' s) :=
  by
  intro b hb b' hb' h₁ h₂
  rw [Set.mem_image] at hb hb'
  obtain ⟨⟨a, has, rfl⟩, ⟨a', has', rfl⟩⟩ := hb, hb'
  exact hs has has' (fun haa' => h₁ (haa'.subst (by rfl))) (φ.map_rel_iff.mp h₂)
#align is_antichain.image_rel_embedding IsAntichain.image_relEmbedding

/- warning: is_antichain.preimage_rel_embedding -> IsAntichain.preimage_relEmbedding is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {t : Set.{u2} β}, (IsAntichain.{u2} β r' t) -> (forall (φ : RelEmbedding.{u1, u2} α β r r'), IsAntichain.{u1} α r (Set.preimage.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelEmbedding.{u1, u2} α β r r') (fun (_x : RelEmbedding.{u1, u2} α β r r') => α -> β) (RelEmbedding.hasCoeToFun.{u1, u2} α β r r') φ) t))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {t : Set.{u2} β}, (IsAntichain.{u2} β r' t) -> (forall (φ : RelEmbedding.{u1, u2} α β r r'), IsAntichain.{u1} α r (Set.preimage.{u1, u2} α β (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u1, succ u2} α β)) (RelEmbedding.toEmbedding.{u1, u2} α β r r' φ)) t))
Case conversion may be inaccurate. Consider using '#align is_antichain.preimage_rel_embedding IsAntichain.preimage_relEmbeddingₓ'. -/
theorem preimage_relEmbedding {t : Set β} (ht : IsAntichain r' t) (φ : r ↪r r') :
    IsAntichain r (φ ⁻¹' t) := fun a ha a' ha' hne hle =>
  ht ha ha' (fun h => hne (φ.Injective h)) (φ.map_rel_iff.mpr hle)
#align is_antichain.preimage_rel_embedding IsAntichain.preimage_relEmbedding

/- warning: is_antichain.image_rel_iso -> IsAntichain.image_relIso is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u1} α}, (IsAntichain.{u1} α r s) -> (forall (φ : RelIso.{u1, u2} α β r r'), IsAntichain.{u2} β r' (Set.image.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelIso.{u1, u2} α β r r') (fun (_x : RelIso.{u1, u2} α β r r') => α -> β) (RelIso.hasCoeToFun.{u1, u2} α β r r') φ) s))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u2} α}, (IsAntichain.{u2} α r s) -> (forall (φ : RelIso.{u2, u1} α β r r'), IsAntichain.{u1} β r' (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β r r' (RelIso.toRelEmbedding.{u2, u1} α β r r' φ))) s))
Case conversion may be inaccurate. Consider using '#align is_antichain.image_rel_iso IsAntichain.image_relIsoₓ'. -/
theorem image_relIso (hs : IsAntichain r s) (φ : r ≃r r') : IsAntichain r' (φ '' s) :=
  hs.image_relEmbedding φ
#align is_antichain.image_rel_iso IsAntichain.image_relIso

/- warning: is_antichain.preimage_rel_iso -> IsAntichain.preimage_relIso is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {t : Set.{u2} β}, (IsAntichain.{u2} β r' t) -> (forall (φ : RelIso.{u1, u2} α β r r'), IsAntichain.{u1} α r (Set.preimage.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelIso.{u1, u2} α β r r') (fun (_x : RelIso.{u1, u2} α β r r') => α -> β) (RelIso.hasCoeToFun.{u1, u2} α β r r') φ) t))
but is expected to have type
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {t : Set.{u2} β}, (IsAntichain.{u2} β r' t) -> (forall (φ : RelIso.{u1, u2} α β r r'), IsAntichain.{u1} α r (Set.preimage.{u1, u2} α β (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u1) (succ u2), succ u1, succ u2} (Function.Embedding.{succ u1, succ u2} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u1, succ u2} α β)) (RelEmbedding.toEmbedding.{u1, u2} α β r r' (RelIso.toRelEmbedding.{u1, u2} α β r r' φ))) t))
Case conversion may be inaccurate. Consider using '#align is_antichain.preimage_rel_iso IsAntichain.preimage_relIsoₓ'. -/
theorem preimage_relIso {t : Set β} (hs : IsAntichain r' t) (φ : r ≃r r') :
    IsAntichain r (φ ⁻¹' t) :=
  hs.preimage_relEmbedding φ
#align is_antichain.preimage_rel_iso IsAntichain.preimage_relIso

/- warning: is_antichain.image_rel_embedding_iff -> IsAntichain.image_relEmbedding_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u1} α} {φ : RelEmbedding.{u1, u2} α β r r'}, Iff (IsAntichain.{u2} β r' (Set.image.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelEmbedding.{u1, u2} α β r r') (fun (_x : RelEmbedding.{u1, u2} α β r r') => α -> β) (RelEmbedding.hasCoeToFun.{u1, u2} α β r r') φ) s)) (IsAntichain.{u1} α r s)
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u2} α} {φ : RelEmbedding.{u2, u1} α β r r'}, Iff (IsAntichain.{u1} β r' (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β r r' φ)) s)) (IsAntichain.{u2} α r s)
Case conversion may be inaccurate. Consider using '#align is_antichain.image_rel_embedding_iff IsAntichain.image_relEmbedding_iffₓ'. -/
theorem image_relEmbedding_iff {φ : r ↪r r'} : IsAntichain r' (φ '' s) ↔ IsAntichain r s :=
  ⟨fun h => (φ.Injective.preimage_image s).subst (h.preimage_relEmbedding φ), fun h =>
    h.image_relEmbedding φ⟩
#align is_antichain.image_rel_embedding_iff IsAntichain.image_relEmbedding_iff

/- warning: is_antichain.image_rel_iso_iff -> IsAntichain.image_relIso_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u1} α} {φ : RelIso.{u1, u2} α β r r'}, Iff (IsAntichain.{u2} β r' (Set.image.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RelIso.{u1, u2} α β r r') (fun (_x : RelIso.{u1, u2} α β r r') => α -> β) (RelIso.hasCoeToFun.{u1, u2} α β r r') φ) s)) (IsAntichain.{u1} α r s)
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u2} α} {φ : RelIso.{u2, u1} α β r r'}, Iff (IsAntichain.{u1} β r' (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β r r' (RelIso.toRelEmbedding.{u2, u1} α β r r' φ))) s)) (IsAntichain.{u2} α r s)
Case conversion may be inaccurate. Consider using '#align is_antichain.image_rel_iso_iff IsAntichain.image_relIso_iffₓ'. -/
theorem image_relIso_iff {φ : r ≃r r'} : IsAntichain r' (φ '' s) ↔ IsAntichain r s :=
  @image_relEmbedding_iff _ _ _ _ _ (φ : r ↪r r')
#align is_antichain.image_rel_iso_iff IsAntichain.image_relIso_iff

/- warning: is_antichain.image_embedding -> IsAntichain.image_embedding is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {s : Set.{u1} α} [_inst_1 : LE.{u1} α] [_inst_2 : LE.{u2} β], (IsAntichain.{u1} α (LE.le.{u1} α _inst_1) s) -> (forall (φ : OrderEmbedding.{u1, u2} α β _inst_1 _inst_2), IsAntichain.{u2} β (LE.le.{u2} β _inst_2) (Set.image.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (OrderEmbedding.{u1, u2} α β _inst_1 _inst_2) (fun (_x : RelEmbedding.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) => α -> β) (RelEmbedding.hasCoeToFun.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) φ) s))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {s : Set.{u2} α} [_inst_1 : LE.{u2} α] [_inst_2 : LE.{u1} β], (IsAntichain.{u2} α (fun (x._@.Mathlib.Order.Antichain._hyg.1625 : α) (x._@.Mathlib.Order.Antichain._hyg.1627 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Antichain._hyg.1625 x._@.Mathlib.Order.Antichain._hyg.1627) s) -> (forall (φ : OrderEmbedding.{u2, u1} α β _inst_1 _inst_2), IsAntichain.{u1} β (fun (x._@.Mathlib.Order.Antichain._hyg.1647 : β) (x._@.Mathlib.Order.Antichain._hyg.1649 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Antichain._hyg.1647 x._@.Mathlib.Order.Antichain._hyg.1649) (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.680 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.682 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.680 x._@.Mathlib.Order.Hom.Basic._hyg.682) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.695 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.697 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.695 x._@.Mathlib.Order.Hom.Basic._hyg.697) φ)) s))
Case conversion may be inaccurate. Consider using '#align is_antichain.image_embedding IsAntichain.image_embeddingₓ'. -/
theorem image_embedding [LE α] [LE β] (hs : IsAntichain (· ≤ ·) s) (φ : α ↪o β) :
    IsAntichain (· ≤ ·) (φ '' s) :=
  image_relEmbedding hs _
#align is_antichain.image_embedding IsAntichain.image_embedding

/- warning: is_antichain.preimage_embedding -> IsAntichain.preimage_embedding is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : LE.{u1} α] [_inst_2 : LE.{u2} β] {t : Set.{u2} β}, (IsAntichain.{u2} β (LE.le.{u2} β _inst_2) t) -> (forall (φ : OrderEmbedding.{u1, u2} α β _inst_1 _inst_2), IsAntichain.{u1} α (LE.le.{u1} α _inst_1) (Set.preimage.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (OrderEmbedding.{u1, u2} α β _inst_1 _inst_2) (fun (_x : RelEmbedding.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) => α -> β) (RelEmbedding.hasCoeToFun.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) φ) t))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} [_inst_1 : LE.{u2} α] [_inst_2 : LE.{u1} β] {t : Set.{u1} β}, (IsAntichain.{u1} β (fun (x._@.Mathlib.Order.Antichain._hyg.1712 : β) (x._@.Mathlib.Order.Antichain._hyg.1714 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Antichain._hyg.1712 x._@.Mathlib.Order.Antichain._hyg.1714) t) -> (forall (φ : OrderEmbedding.{u2, u1} α β _inst_1 _inst_2), IsAntichain.{u2} α (fun (x._@.Mathlib.Order.Antichain._hyg.1734 : α) (x._@.Mathlib.Order.Antichain._hyg.1736 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Antichain._hyg.1734 x._@.Mathlib.Order.Antichain._hyg.1736) (Set.preimage.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.680 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.682 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.680 x._@.Mathlib.Order.Hom.Basic._hyg.682) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.695 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.697 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.695 x._@.Mathlib.Order.Hom.Basic._hyg.697) φ)) t))
Case conversion may be inaccurate. Consider using '#align is_antichain.preimage_embedding IsAntichain.preimage_embeddingₓ'. -/
theorem preimage_embedding [LE α] [LE β] {t : Set β} (ht : IsAntichain (· ≤ ·) t) (φ : α ↪o β) :
    IsAntichain (· ≤ ·) (φ ⁻¹' t) :=
  preimage_relEmbedding ht _
#align is_antichain.preimage_embedding IsAntichain.preimage_embedding

/- warning: is_antichain.image_embedding_iff -> IsAntichain.image_embedding_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {s : Set.{u1} α} [_inst_1 : LE.{u1} α] [_inst_2 : LE.{u2} β] {φ : OrderEmbedding.{u1, u2} α β _inst_1 _inst_2}, Iff (IsAntichain.{u2} β (LE.le.{u2} β _inst_2) (Set.image.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (OrderEmbedding.{u1, u2} α β _inst_1 _inst_2) (fun (_x : RelEmbedding.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) => α -> β) (RelEmbedding.hasCoeToFun.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) φ) s)) (IsAntichain.{u1} α (LE.le.{u1} α _inst_1) s)
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {s : Set.{u2} α} [_inst_1 : LE.{u2} α] [_inst_2 : LE.{u1} β] {φ : OrderEmbedding.{u2, u1} α β _inst_1 _inst_2}, Iff (IsAntichain.{u1} β (fun (x._@.Mathlib.Order.Antichain._hyg.1805 : β) (x._@.Mathlib.Order.Antichain._hyg.1807 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Antichain._hyg.1805 x._@.Mathlib.Order.Antichain._hyg.1807) (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.680 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.682 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.680 x._@.Mathlib.Order.Hom.Basic._hyg.682) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.695 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.697 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.695 x._@.Mathlib.Order.Hom.Basic._hyg.697) φ)) s)) (IsAntichain.{u2} α (fun (x._@.Mathlib.Order.Antichain._hyg.1829 : α) (x._@.Mathlib.Order.Antichain._hyg.1831 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Antichain._hyg.1829 x._@.Mathlib.Order.Antichain._hyg.1831) s)
Case conversion may be inaccurate. Consider using '#align is_antichain.image_embedding_iff IsAntichain.image_embedding_iffₓ'. -/
theorem image_embedding_iff [LE α] [LE β] {φ : α ↪o β} :
    IsAntichain (· ≤ ·) (φ '' s) ↔ IsAntichain (· ≤ ·) s :=
  image_relEmbedding_iff
#align is_antichain.image_embedding_iff IsAntichain.image_embedding_iff

/- warning: is_antichain.image_iso -> IsAntichain.image_iso is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {s : Set.{u1} α} [_inst_1 : LE.{u1} α] [_inst_2 : LE.{u2} β], (IsAntichain.{u1} α (LE.le.{u1} α _inst_1) s) -> (forall (φ : OrderIso.{u1, u2} α β _inst_1 _inst_2), IsAntichain.{u2} β (LE.le.{u2} β _inst_2) (Set.image.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (OrderIso.{u1, u2} α β _inst_1 _inst_2) (fun (_x : RelIso.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) => α -> β) (RelIso.hasCoeToFun.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) φ) s))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {s : Set.{u2} α} [_inst_1 : LE.{u2} α] [_inst_2 : LE.{u1} β], (IsAntichain.{u2} α (fun (x._@.Mathlib.Order.Antichain._hyg.1883 : α) (x._@.Mathlib.Order.Antichain._hyg.1885 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Antichain._hyg.1883 x._@.Mathlib.Order.Antichain._hyg.1885) s) -> (forall (φ : OrderIso.{u2, u1} α β _inst_1 _inst_2), IsAntichain.{u1} β (fun (x._@.Mathlib.Order.Antichain._hyg.1905 : β) (x._@.Mathlib.Order.Antichain._hyg.1907 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Antichain._hyg.1905 x._@.Mathlib.Order.Antichain._hyg.1907) (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) (RelIso.toRelEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) φ))) s))
Case conversion may be inaccurate. Consider using '#align is_antichain.image_iso IsAntichain.image_isoₓ'. -/
theorem image_iso [LE α] [LE β] (hs : IsAntichain (· ≤ ·) s) (φ : α ≃o β) :
    IsAntichain (· ≤ ·) (φ '' s) :=
  image_relEmbedding hs _
#align is_antichain.image_iso IsAntichain.image_iso

/- warning: is_antichain.image_iso_iff -> IsAntichain.image_iso_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {s : Set.{u1} α} [_inst_1 : LE.{u1} α] [_inst_2 : LE.{u2} β] {φ : OrderIso.{u1, u2} α β _inst_1 _inst_2}, Iff (IsAntichain.{u2} β (LE.le.{u2} β _inst_2) (Set.image.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (OrderIso.{u1, u2} α β _inst_1 _inst_2) (fun (_x : RelIso.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) => α -> β) (RelIso.hasCoeToFun.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) φ) s)) (IsAntichain.{u1} α (LE.le.{u1} α _inst_1) s)
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {s : Set.{u2} α} [_inst_1 : LE.{u2} α] [_inst_2 : LE.{u1} β] {φ : OrderIso.{u2, u1} α β _inst_1 _inst_2}, Iff (IsAntichain.{u1} β (fun (x._@.Mathlib.Order.Antichain._hyg.1976 : β) (x._@.Mathlib.Order.Antichain._hyg.1978 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Antichain._hyg.1976 x._@.Mathlib.Order.Antichain._hyg.1978) (Set.image.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) (RelIso.toRelEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) φ))) s)) (IsAntichain.{u2} α (fun (x._@.Mathlib.Order.Antichain._hyg.2000 : α) (x._@.Mathlib.Order.Antichain._hyg.2002 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Antichain._hyg.2000 x._@.Mathlib.Order.Antichain._hyg.2002) s)
Case conversion may be inaccurate. Consider using '#align is_antichain.image_iso_iff IsAntichain.image_iso_iffₓ'. -/
theorem image_iso_iff [LE α] [LE β] {φ : α ≃o β} :
    IsAntichain (· ≤ ·) (φ '' s) ↔ IsAntichain (· ≤ ·) s :=
  image_relEmbedding_iff
#align is_antichain.image_iso_iff IsAntichain.image_iso_iff

/- warning: is_antichain.preimage_iso -> IsAntichain.preimage_iso is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : LE.{u1} α] [_inst_2 : LE.{u2} β] {t : Set.{u2} β}, (IsAntichain.{u2} β (LE.le.{u2} β _inst_2) t) -> (forall (φ : OrderIso.{u1, u2} α β _inst_1 _inst_2), IsAntichain.{u1} α (LE.le.{u1} α _inst_1) (Set.preimage.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (OrderIso.{u1, u2} α β _inst_1 _inst_2) (fun (_x : RelIso.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) => α -> β) (RelIso.hasCoeToFun.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) φ) t))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} [_inst_1 : LE.{u2} α] [_inst_2 : LE.{u1} β] {t : Set.{u1} β}, (IsAntichain.{u1} β (fun (x._@.Mathlib.Order.Antichain._hyg.2056 : β) (x._@.Mathlib.Order.Antichain._hyg.2058 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Antichain._hyg.2056 x._@.Mathlib.Order.Antichain._hyg.2058) t) -> (forall (φ : OrderIso.{u2, u1} α β _inst_1 _inst_2), IsAntichain.{u2} α (fun (x._@.Mathlib.Order.Antichain._hyg.2078 : α) (x._@.Mathlib.Order.Antichain._hyg.2080 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Antichain._hyg.2078 x._@.Mathlib.Order.Antichain._hyg.2080) (Set.preimage.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) (RelIso.toRelEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) φ))) t))
Case conversion may be inaccurate. Consider using '#align is_antichain.preimage_iso IsAntichain.preimage_isoₓ'. -/
theorem preimage_iso [LE α] [LE β] {t : Set β} (ht : IsAntichain (· ≤ ·) t) (φ : α ≃o β) :
    IsAntichain (· ≤ ·) (φ ⁻¹' t) :=
  preimage_relEmbedding ht _
#align is_antichain.preimage_iso IsAntichain.preimage_iso

/- warning: is_antichain.preimage_iso_iff -> IsAntichain.preimage_iso_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} [_inst_1 : LE.{u1} α] [_inst_2 : LE.{u2} β] {t : Set.{u2} β} {φ : OrderIso.{u1, u2} α β _inst_1 _inst_2}, Iff (IsAntichain.{u1} α (LE.le.{u1} α _inst_1) (Set.preimage.{u1, u2} α β (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (OrderIso.{u1, u2} α β _inst_1 _inst_2) (fun (_x : RelIso.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) => α -> β) (RelIso.hasCoeToFun.{u1, u2} α β (LE.le.{u1} α _inst_1) (LE.le.{u2} β _inst_2)) φ) t)) (IsAntichain.{u2} β (LE.le.{u2} β _inst_2) t)
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} [_inst_1 : LE.{u2} α] [_inst_2 : LE.{u1} β] {t : Set.{u1} β} {φ : OrderIso.{u2, u1} α β _inst_1 _inst_2}, Iff (IsAntichain.{u2} α (fun (x._@.Mathlib.Order.Antichain._hyg.2151 : α) (x._@.Mathlib.Order.Antichain._hyg.2153 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Antichain._hyg.2151 x._@.Mathlib.Order.Antichain._hyg.2153) (Set.preimage.{u2, u1} α β (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α (fun (_x : α) => (fun (x._@.Mathlib.Data.FunLike.Embedding._hyg.19 : α) => β) _x) (EmbeddingLike.toFunLike.{max (succ u2) (succ u1), succ u2, succ u1} (Function.Embedding.{succ u2, succ u1} α β) α β (Function.instEmbeddingLikeEmbedding.{succ u2, succ u1} α β)) (RelEmbedding.toEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) (RelIso.toRelEmbedding.{u2, u1} α β (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1281 : α) (x._@.Mathlib.Order.Hom.Basic._hyg.1283 : α) => LE.le.{u2} α _inst_1 x._@.Mathlib.Order.Hom.Basic._hyg.1281 x._@.Mathlib.Order.Hom.Basic._hyg.1283) (fun (x._@.Mathlib.Order.Hom.Basic._hyg.1296 : β) (x._@.Mathlib.Order.Hom.Basic._hyg.1298 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Hom.Basic._hyg.1296 x._@.Mathlib.Order.Hom.Basic._hyg.1298) φ))) t)) (IsAntichain.{u1} β (fun (x._@.Mathlib.Order.Antichain._hyg.2175 : β) (x._@.Mathlib.Order.Antichain._hyg.2177 : β) => LE.le.{u1} β _inst_2 x._@.Mathlib.Order.Antichain._hyg.2175 x._@.Mathlib.Order.Antichain._hyg.2177) t)
Case conversion may be inaccurate. Consider using '#align is_antichain.preimage_iso_iff IsAntichain.preimage_iso_iffₓ'. -/
theorem preimage_iso_iff [LE α] [LE β] {t : Set β} {φ : α ≃o β} :
    IsAntichain (· ≤ ·) (φ ⁻¹' t) ↔ IsAntichain (· ≤ ·) t :=
  ⟨fun h => (φ.image_preimage t).subst (h.image_iso φ), fun h => h.preimage_iso _⟩
#align is_antichain.preimage_iso_iff IsAntichain.preimage_iso_iff

#print IsAntichain.to_dual /-
theorem to_dual [LE α] (hs : IsAntichain (· ≤ ·) s) : @IsAntichain αᵒᵈ (· ≤ ·) s :=
  fun a ha b hb hab => hs hb ha hab.symm
#align is_antichain.to_dual IsAntichain.to_dual
-/

#print IsAntichain.to_dual_iff /-
theorem to_dual_iff [LE α] : IsAntichain (· ≤ ·) s ↔ @IsAntichain αᵒᵈ (· ≤ ·) s :=
  ⟨to_dual, to_dual⟩
#align is_antichain.to_dual_iff IsAntichain.to_dual_iff
-/

#print IsAntichain.image_compl /-
theorem image_compl [BooleanAlgebra α] (hs : IsAntichain (· ≤ ·) s) :
    IsAntichain (· ≤ ·) (compl '' s) :=
  (hs.image_embedding (OrderIso.compl α).toOrderEmbedding).flip
#align is_antichain.image_compl IsAntichain.image_compl
-/

#print IsAntichain.preimage_compl /-
theorem preimage_compl [BooleanAlgebra α] (hs : IsAntichain (· ≤ ·) s) :
    IsAntichain (· ≤ ·) (compl ⁻¹' s) := fun a ha a' ha' hne hle =>
  hs ha' ha (fun h => hne (compl_inj_iff.mp h.symm)) (compl_le_compl hle)
#align is_antichain.preimage_compl IsAntichain.preimage_compl
-/

end IsAntichain

#print isAntichain_singleton /-
theorem isAntichain_singleton (a : α) (r : α → α → Prop) : IsAntichain r {a} :=
  pairwise_singleton _ _
#align is_antichain_singleton isAntichain_singleton
-/

#print Set.Subsingleton.isAntichain /-
theorem Set.Subsingleton.isAntichain (hs : s.Subsingleton) (r : α → α → Prop) : IsAntichain r s :=
  hs.Pairwise _
#align set.subsingleton.is_antichain Set.Subsingleton.isAntichain
-/

section Preorder

variable [Preorder α]

#print IsAntichain.not_lt /-
theorem IsAntichain.not_lt (hs : IsAntichain (· ≤ ·) s) (ha : a ∈ s) (hb : b ∈ s) : ¬a < b :=
  fun h => hs ha hb h.Ne h.le
#align is_antichain.not_lt IsAntichain.not_lt
-/

#print isAntichain_and_least_iff /-
theorem isAntichain_and_least_iff : IsAntichain (· ≤ ·) s ∧ IsLeast s a ↔ s = {a} :=
  ⟨fun h => eq_singleton_iff_unique_mem.2 ⟨h.2.1, fun b hb => h.1.eq'' hb h.2.1 (h.2.2 hb)⟩,
    by
    rintro rfl
    exact ⟨isAntichain_singleton _ _, isLeast_singleton⟩⟩
#align is_antichain_and_least_iff isAntichain_and_least_iff
-/

#print isAntichain_and_greatest_iff /-
theorem isAntichain_and_greatest_iff : IsAntichain (· ≤ ·) s ∧ IsGreatest s a ↔ s = {a} :=
  ⟨fun h => eq_singleton_iff_unique_mem.2 ⟨h.2.1, fun b hb => h.1.Eq hb h.2.1 (h.2.2 hb)⟩,
    by
    rintro rfl
    exact ⟨isAntichain_singleton _ _, isGreatest_singleton⟩⟩
#align is_antichain_and_greatest_iff isAntichain_and_greatest_iff
-/

#print IsAntichain.least_iff /-
theorem IsAntichain.least_iff (hs : IsAntichain (· ≤ ·) s) : IsLeast s a ↔ s = {a} :=
  (and_iff_right hs).symm.trans isAntichain_and_least_iff
#align is_antichain.least_iff IsAntichain.least_iff
-/

#print IsAntichain.greatest_iff /-
theorem IsAntichain.greatest_iff (hs : IsAntichain (· ≤ ·) s) : IsGreatest s a ↔ s = {a} :=
  (and_iff_right hs).symm.trans isAntichain_and_greatest_iff
#align is_antichain.greatest_iff IsAntichain.greatest_iff
-/

#print IsLeast.antichain_iff /-
theorem IsLeast.antichain_iff (hs : IsLeast s a) : IsAntichain (· ≤ ·) s ↔ s = {a} :=
  (and_iff_left hs).symm.trans isAntichain_and_least_iff
#align is_least.antichain_iff IsLeast.antichain_iff
-/

#print IsGreatest.antichain_iff /-
theorem IsGreatest.antichain_iff (hs : IsGreatest s a) : IsAntichain (· ≤ ·) s ↔ s = {a} :=
  (and_iff_left hs).symm.trans isAntichain_and_greatest_iff
#align is_greatest.antichain_iff IsGreatest.antichain_iff
-/

/- warning: is_antichain.bot_mem_iff -> IsAntichain.bot_mem_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {s : Set.{u1} α} [_inst_1 : Preorder.{u1} α] [_inst_2 : OrderBot.{u1} α (Preorder.toLE.{u1} α _inst_1)], (IsAntichain.{u1} α (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1)) s) -> (Iff (Membership.Mem.{u1, u1} α (Set.{u1} α) (Set.hasMem.{u1} α) (Bot.bot.{u1} α (OrderBot.toHasBot.{u1} α (Preorder.toLE.{u1} α _inst_1) _inst_2)) s) (Eq.{succ u1} (Set.{u1} α) s (Singleton.singleton.{u1, u1} α (Set.{u1} α) (Set.hasSingleton.{u1} α) (Bot.bot.{u1} α (OrderBot.toHasBot.{u1} α (Preorder.toLE.{u1} α _inst_1) _inst_2)))))
but is expected to have type
  forall {α : Type.{u1}} {s : Set.{u1} α} [_inst_1 : Preorder.{u1} α] [_inst_2 : OrderBot.{u1} α (Preorder.toLE.{u1} α _inst_1)], (IsAntichain.{u1} α (fun (x._@.Mathlib.Order.Antichain._hyg.3493 : α) (x._@.Mathlib.Order.Antichain._hyg.3495 : α) => LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) x._@.Mathlib.Order.Antichain._hyg.3493 x._@.Mathlib.Order.Antichain._hyg.3495) s) -> (Iff (Membership.mem.{u1, u1} α (Set.{u1} α) (Set.instMembershipSet.{u1} α) (Bot.bot.{u1} α (OrderBot.toBot.{u1} α (Preorder.toLE.{u1} α _inst_1) _inst_2)) s) (Eq.{succ u1} (Set.{u1} α) s (Singleton.singleton.{u1, u1} α (Set.{u1} α) (Set.instSingletonSet.{u1} α) (Bot.bot.{u1} α (OrderBot.toBot.{u1} α (Preorder.toLE.{u1} α _inst_1) _inst_2)))))
Case conversion may be inaccurate. Consider using '#align is_antichain.bot_mem_iff IsAntichain.bot_mem_iffₓ'. -/
theorem IsAntichain.bot_mem_iff [OrderBot α] (hs : IsAntichain (· ≤ ·) s) : ⊥ ∈ s ↔ s = {⊥} :=
  isLeast_bot_iff.symm.trans hs.least_iff
#align is_antichain.bot_mem_iff IsAntichain.bot_mem_iff

/- warning: is_antichain.top_mem_iff -> IsAntichain.top_mem_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {s : Set.{u1} α} [_inst_1 : Preorder.{u1} α] [_inst_2 : OrderTop.{u1} α (Preorder.toLE.{u1} α _inst_1)], (IsAntichain.{u1} α (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1)) s) -> (Iff (Membership.Mem.{u1, u1} α (Set.{u1} α) (Set.hasMem.{u1} α) (Top.top.{u1} α (OrderTop.toHasTop.{u1} α (Preorder.toLE.{u1} α _inst_1) _inst_2)) s) (Eq.{succ u1} (Set.{u1} α) s (Singleton.singleton.{u1, u1} α (Set.{u1} α) (Set.hasSingleton.{u1} α) (Top.top.{u1} α (OrderTop.toHasTop.{u1} α (Preorder.toLE.{u1} α _inst_1) _inst_2)))))
but is expected to have type
  forall {α : Type.{u1}} {s : Set.{u1} α} [_inst_1 : Preorder.{u1} α] [_inst_2 : OrderTop.{u1} α (Preorder.toLE.{u1} α _inst_1)], (IsAntichain.{u1} α (fun (x._@.Mathlib.Order.Antichain._hyg.3571 : α) (x._@.Mathlib.Order.Antichain._hyg.3573 : α) => LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) x._@.Mathlib.Order.Antichain._hyg.3571 x._@.Mathlib.Order.Antichain._hyg.3573) s) -> (Iff (Membership.mem.{u1, u1} α (Set.{u1} α) (Set.instMembershipSet.{u1} α) (Top.top.{u1} α (OrderTop.toTop.{u1} α (Preorder.toLE.{u1} α _inst_1) _inst_2)) s) (Eq.{succ u1} (Set.{u1} α) s (Singleton.singleton.{u1, u1} α (Set.{u1} α) (Set.instSingletonSet.{u1} α) (Top.top.{u1} α (OrderTop.toTop.{u1} α (Preorder.toLE.{u1} α _inst_1) _inst_2)))))
Case conversion may be inaccurate. Consider using '#align is_antichain.top_mem_iff IsAntichain.top_mem_iffₓ'. -/
theorem IsAntichain.top_mem_iff [OrderTop α] (hs : IsAntichain (· ≤ ·) s) : ⊤ ∈ s ↔ s = {⊤} :=
  isGreatest_top_iff.symm.trans hs.greatest_iff
#align is_antichain.top_mem_iff IsAntichain.top_mem_iff

end Preorder

section PartialOrder

variable [PartialOrder α]

#print isAntichain_iff_forall_not_lt /-
theorem isAntichain_iff_forall_not_lt :
    IsAntichain (· ≤ ·) s ↔ ∀ ⦃a⦄, a ∈ s → ∀ ⦃b⦄, b ∈ s → ¬a < b :=
  ⟨fun hs a ha b => hs.not_lt ha, fun hs a ha b hb h h' => hs ha hb <| h'.lt_of_ne h⟩
#align is_antichain_iff_forall_not_lt isAntichain_iff_forall_not_lt
-/

end PartialOrder

/-! ### Strong antichains -/

#print IsStrongAntichain /-
/-- A strong (upward) antichain is a set such that no two distinct elements are related to a common
element. -/
def IsStrongAntichain (r : α → α → Prop) (s : Set α) : Prop :=
  s.Pairwise fun a b => ∀ c, ¬r a c ∨ ¬r b c
#align is_strong_antichain IsStrongAntichain
-/

namespace IsStrongAntichain

#print IsStrongAntichain.subset /-
protected theorem subset (hs : IsStrongAntichain r s) (h : t ⊆ s) : IsStrongAntichain r t :=
  hs.mono h
#align is_strong_antichain.subset IsStrongAntichain.subset
-/

#print IsStrongAntichain.mono /-
theorem mono (hs : IsStrongAntichain r₁ s) (h : r₂ ≤ r₁) : IsStrongAntichain r₂ s :=
  hs.mono' fun a b hab c => (hab c).imp (compl_le_compl h _ _) (compl_le_compl h _ _)
#align is_strong_antichain.mono IsStrongAntichain.mono
-/

#print IsStrongAntichain.eq /-
theorem eq (hs : IsStrongAntichain r s) {a b c : α} (ha : a ∈ s) (hb : b ∈ s) (hac : r a c)
    (hbc : r b c) : a = b :=
  hs.Eq ha hb fun h => False.elim <| (h c).elim (not_not_intro hac) (not_not_intro hbc)
#align is_strong_antichain.eq IsStrongAntichain.eq
-/

#print IsStrongAntichain.isAntichain /-
protected theorem isAntichain [IsRefl α r] (h : IsStrongAntichain r s) : IsAntichain r s :=
  h.imp fun a b hab => (hab b).resolve_right (not_not_intro <| refl _)
#align is_strong_antichain.is_antichain IsStrongAntichain.isAntichain
-/

#print IsStrongAntichain.subsingleton /-
protected theorem subsingleton [IsDirected α r] (h : IsStrongAntichain r s) : s.Subsingleton :=
  fun a ha b hb =>
  let ⟨c, hac, hbc⟩ := directed_of r a b
  h.Eq ha hb hac hbc
#align is_strong_antichain.subsingleton IsStrongAntichain.subsingleton
-/

#print IsStrongAntichain.flip /-
protected theorem flip [IsSymm α r] (hs : IsStrongAntichain r s) : IsStrongAntichain (flip r) s :=
  fun a ha b hb h c => (hs ha hb h c).imp (mt <| symm_of r) (mt <| symm_of r)
#align is_strong_antichain.flip IsStrongAntichain.flip
-/

#print IsStrongAntichain.swap /-
theorem swap [IsSymm α r] (hs : IsStrongAntichain r s) : IsStrongAntichain (swap r) s :=
  hs.flip
#align is_strong_antichain.swap IsStrongAntichain.swap
-/

/- warning: is_strong_antichain.image -> IsStrongAntichain.image is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u1} α}, (IsStrongAntichain.{u1} α r s) -> (forall {f : α -> β}, (Function.Surjective.{succ u1, succ u2} α β f) -> (forall (a : α) (b : α), (r' (f a) (f b)) -> (r a b)) -> (IsStrongAntichain.{u2} β r' (Set.image.{u1, u2} α β f s)))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u2} α}, (IsStrongAntichain.{u2} α r s) -> (forall {f : α -> β}, (Function.Surjective.{succ u2, succ u1} α β f) -> (forall (a : α) (b : α), (r' (f a) (f b)) -> (r a b)) -> (IsStrongAntichain.{u1} β r' (Set.image.{u2, u1} α β f s)))
Case conversion may be inaccurate. Consider using '#align is_strong_antichain.image IsStrongAntichain.imageₓ'. -/
theorem image (hs : IsStrongAntichain r s) {f : α → β} (hf : Surjective f)
    (h : ∀ a b, r' (f a) (f b) → r a b) : IsStrongAntichain r' (f '' s) :=
  by
  rintro _ ⟨a, ha, rfl⟩ _ ⟨b, hb, rfl⟩ hab c
  obtain ⟨c, rfl⟩ := hf c
  exact (hs ha hb (ne_of_apply_ne _ hab) _).imp (mt <| h _ _) (mt <| h _ _)
#align is_strong_antichain.image IsStrongAntichain.image

/- warning: is_strong_antichain.preimage -> IsStrongAntichain.preimage is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {β : Type.{u2}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u1} α}, (IsStrongAntichain.{u1} α r s) -> (forall {f : β -> α}, (Function.Injective.{succ u2, succ u1} β α f) -> (forall (a : β) (b : β), (r' a b) -> (r (f a) (f b))) -> (IsStrongAntichain.{u2} β r' (Set.preimage.{u2, u1} β α f s)))
but is expected to have type
  forall {α : Type.{u2}} {β : Type.{u1}} {r : α -> α -> Prop} {r' : β -> β -> Prop} {s : Set.{u2} α}, (IsStrongAntichain.{u2} α r s) -> (forall {f : β -> α}, (Function.Injective.{succ u1, succ u2} β α f) -> (forall (a : β) (b : β), (r' a b) -> (r (f a) (f b))) -> (IsStrongAntichain.{u1} β r' (Set.preimage.{u1, u2} β α f s)))
Case conversion may be inaccurate. Consider using '#align is_strong_antichain.preimage IsStrongAntichain.preimageₓ'. -/
theorem preimage (hs : IsStrongAntichain r s) {f : β → α} (hf : Injective f)
    (h : ∀ a b, r' a b → r (f a) (f b)) : IsStrongAntichain r' (f ⁻¹' s) := fun a ha b hb hab c =>
  (hs ha hb (hf.Ne hab) _).imp (mt <| h _ _) (mt <| h _ _)
#align is_strong_antichain.preimage IsStrongAntichain.preimage

#print isStrongAntichain_insert /-
theorem isStrongAntichain_insert :
    IsStrongAntichain r (insert a s) ↔
      IsStrongAntichain r s ∧ ∀ ⦃b⦄, b ∈ s → a ≠ b → ∀ c, ¬r a c ∨ ¬r b c :=
  Set.pairwise_insert_of_symmetric fun a b h c => (h c).symm
#align is_strong_antichain_insert isStrongAntichain_insert
-/

#print IsStrongAntichain.insert /-
protected theorem insert (hs : IsStrongAntichain r s)
    (h : ∀ ⦃b⦄, b ∈ s → a ≠ b → ∀ c, ¬r a c ∨ ¬r b c) : IsStrongAntichain r (insert a s) :=
  isStrongAntichain_insert.2 ⟨hs, h⟩
#align is_strong_antichain.insert IsStrongAntichain.insert
-/

end IsStrongAntichain

#print Set.Subsingleton.isStrongAntichain /-
theorem Set.Subsingleton.isStrongAntichain (hs : s.Subsingleton) (r : α → α → Prop) :
    IsStrongAntichain r s :=
  hs.Pairwise _
#align set.subsingleton.is_strong_antichain Set.Subsingleton.isStrongAntichain
-/

end General

/-! ### Weak antichains -/

section Pi

variable {ι : Type _} {α : ι → Type _} [∀ i, Preorder (α i)] {s t : Set (∀ i, α i)}
  {a b c : ∀ i, α i}

-- mathport name: «expr ≺ »
local infixl:50 " ≺ " => StrongLT

#print IsWeakAntichain /-
/-- A weak antichain in `Π i, α i` is a set such that no two distinct elements are strongly less
than each other. -/
def IsWeakAntichain (s : Set (∀ i, α i)) : Prop :=
  IsAntichain (· ≺ ·) s
#align is_weak_antichain IsWeakAntichain
-/

namespace IsWeakAntichain

/- warning: is_weak_antichain.subset -> IsWeakAntichain.subset is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] {s : Set.{max u1 u2} (forall (i : ι), α i)} {t : Set.{max u1 u2} (forall (i : ι), α i)}, (IsWeakAntichain.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s) -> (HasSubset.Subset.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasSubset.{max u1 u2} (forall (i : ι), α i)) t s) -> (IsWeakAntichain.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) t)
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] {s : Set.{max u2 u1} (forall (i : ι), α i)} {t : Set.{max u2 u1} (forall (i : ι), α i)}, (IsWeakAntichain.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s) -> (HasSubset.Subset.{max u2 u1} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instHasSubsetSet.{max u2 u1} (forall (i : ι), α i)) t s) -> (IsWeakAntichain.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) t)
Case conversion may be inaccurate. Consider using '#align is_weak_antichain.subset IsWeakAntichain.subsetₓ'. -/
protected theorem subset (hs : IsWeakAntichain s) : t ⊆ s → IsWeakAntichain t :=
  hs.Subset
#align is_weak_antichain.subset IsWeakAntichain.subset

/- warning: is_weak_antichain.eq -> IsWeakAntichain.eq is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] {s : Set.{max u1 u2} (forall (i : ι), α i)} {a : forall (i : ι), α i} {b : forall (i : ι), α i}, (IsWeakAntichain.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s) -> (Membership.Mem.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasMem.{max u1 u2} (forall (i : ι), α i)) a s) -> (Membership.Mem.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasMem.{max u1 u2} (forall (i : ι), α i)) b s) -> (StrongLT.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u2} (α i) (_inst_1 i)) a b) -> (Eq.{max (succ u1) (succ u2)} (forall (i : ι), α i) a b)
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] {s : Set.{max u2 u1} (forall (i : ι), α i)} {a : forall (i : ι), α i} {b : forall (i : ι), α i}, (IsWeakAntichain.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s) -> (Membership.mem.{max u2 u1, max u2 u1} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instMembershipSet.{max u2 u1} (forall (i : ι), α i)) a s) -> (Membership.mem.{max u2 u1, max u2 u1} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instMembershipSet.{max u2 u1} (forall (i : ι), α i)) b s) -> (StrongLT.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u1} (α i) (_inst_1 i)) a b) -> (Eq.{max (succ u2) (succ u1)} (forall (i : ι), α i) a b)
Case conversion may be inaccurate. Consider using '#align is_weak_antichain.eq IsWeakAntichain.eqₓ'. -/
protected theorem eq (hs : IsWeakAntichain s) : a ∈ s → b ∈ s → a ≺ b → a = b :=
  hs.Eq
#align is_weak_antichain.eq IsWeakAntichain.eq

/- warning: is_weak_antichain.insert -> IsWeakAntichain.insert is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] {s : Set.{max u1 u2} (forall (i : ι), α i)} {a : forall (i : ι), α i}, (IsWeakAntichain.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s) -> (forall {{b : forall (i : ι), α i}}, (Membership.Mem.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasMem.{max u1 u2} (forall (i : ι), α i)) b s) -> (Ne.{max (succ u1) (succ u2)} (forall (i : ι), α i) a b) -> (Not (StrongLT.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u2} (α i) (_inst_1 i)) b a))) -> (forall {{b : forall (i : ι), α i}}, (Membership.Mem.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasMem.{max u1 u2} (forall (i : ι), α i)) b s) -> (Ne.{max (succ u1) (succ u2)} (forall (i : ι), α i) a b) -> (Not (StrongLT.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u2} (α i) (_inst_1 i)) a b))) -> (IsWeakAntichain.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) (Insert.insert.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasInsert.{max u1 u2} (forall (i : ι), α i)) a s))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] {s : Set.{max u2 u1} (forall (i : ι), α i)} {a : forall (i : ι), α i}, (IsWeakAntichain.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s) -> (forall {{b : forall (i : ι), α i}}, (Membership.mem.{max u2 u1, max u2 u1} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instMembershipSet.{max u2 u1} (forall (i : ι), α i)) b s) -> (Ne.{max (succ u2) (succ u1)} (forall (i : ι), α i) a b) -> (Not (StrongLT.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u1} (α i) (_inst_1 i)) b a))) -> (forall {{b : forall (i : ι), α i}}, (Membership.mem.{max u2 u1, max u2 u1} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instMembershipSet.{max u2 u1} (forall (i : ι), α i)) b s) -> (Ne.{max (succ u2) (succ u1)} (forall (i : ι), α i) a b) -> (Not (StrongLT.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u1} (α i) (_inst_1 i)) a b))) -> (IsWeakAntichain.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) (Insert.insert.{max u2 u1, max u1 u2} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instInsertSet.{max u2 u1} (forall (i : ι), α i)) a s))
Case conversion may be inaccurate. Consider using '#align is_weak_antichain.insert IsWeakAntichain.insertₓ'. -/
protected theorem insert (hs : IsWeakAntichain s) :
    (∀ ⦃b⦄, b ∈ s → a ≠ b → ¬b ≺ a) →
      (∀ ⦃b⦄, b ∈ s → a ≠ b → ¬a ≺ b) → IsWeakAntichain (insert a s) :=
  hs.insert
#align is_weak_antichain.insert IsWeakAntichain.insert

end IsWeakAntichain

/- warning: is_weak_antichain_insert -> isWeakAntichain_insert is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] {s : Set.{max u1 u2} (forall (i : ι), α i)} {a : forall (i : ι), α i}, Iff (IsWeakAntichain.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) (Insert.insert.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasInsert.{max u1 u2} (forall (i : ι), α i)) a s)) (And (IsWeakAntichain.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s) (forall {{b : forall (i : ι), α i}}, (Membership.Mem.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasMem.{max u1 u2} (forall (i : ι), α i)) b s) -> (Ne.{max (succ u1) (succ u2)} (forall (i : ι), α i) a b) -> (And (Not (StrongLT.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u2} (α i) (_inst_1 i)) a b)) (Not (StrongLT.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u2} (α i) (_inst_1 i)) b a)))))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] {s : Set.{max u2 u1} (forall (i : ι), α i)} {a : forall (i : ι), α i}, Iff (IsWeakAntichain.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) (Insert.insert.{max u2 u1, max u1 u2} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instInsertSet.{max u2 u1} (forall (i : ι), α i)) a s)) (And (IsWeakAntichain.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s) (forall {{b : forall (i : ι), α i}}, (Membership.mem.{max u2 u1, max u2 u1} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instMembershipSet.{max u2 u1} (forall (i : ι), α i)) b s) -> (Ne.{max (succ u2) (succ u1)} (forall (i : ι), α i) a b) -> (And (Not (StrongLT.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u1} (α i) (_inst_1 i)) a b)) (Not (StrongLT.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLT.{u1} (α i) (_inst_1 i)) b a)))))
Case conversion may be inaccurate. Consider using '#align is_weak_antichain_insert isWeakAntichain_insertₓ'. -/
theorem isWeakAntichain_insert :
    IsWeakAntichain (insert a s) ↔ IsWeakAntichain s ∧ ∀ ⦃b⦄, b ∈ s → a ≠ b → ¬a ≺ b ∧ ¬b ≺ a :=
  isAntichain_insert
#align is_weak_antichain_insert isWeakAntichain_insert

/- warning: is_antichain.is_weak_antichain -> IsAntichain.isWeakAntichain is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] {s : Set.{max u1 u2} (forall (i : ι), α i)}, (IsAntichain.{max u1 u2} (forall (i : ι), α i) (LE.le.{max u1 u2} (forall (i : ι), α i) (Pi.hasLe.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLE.{u2} (α i) (_inst_1 i)))) s) -> (IsWeakAntichain.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s)
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] {s : Set.{max u2 u1} (forall (i : ι), α i)}, (IsAntichain.{max u2 u1} (forall (i : ι), α i) (fun (x._@.Mathlib.Order.Antichain._hyg.6025 : forall (i : ι), α i) (x._@.Mathlib.Order.Antichain._hyg.6027 : forall (i : ι), α i) => LE.le.{max u2 u1} (forall (i : ι), α i) (Pi.hasLe.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => Preorder.toLE.{u1} (α i) (_inst_1 i))) x._@.Mathlib.Order.Antichain._hyg.6025 x._@.Mathlib.Order.Antichain._hyg.6027) s) -> (IsWeakAntichain.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s)
Case conversion may be inaccurate. Consider using '#align is_antichain.is_weak_antichain IsAntichain.isWeakAntichainₓ'. -/
protected theorem IsAntichain.isWeakAntichain (hs : IsAntichain (· ≤ ·) s) : IsWeakAntichain s :=
  hs.mono fun a b => le_of_strongLT
#align is_antichain.is_weak_antichain IsAntichain.isWeakAntichain

/- warning: set.subsingleton.is_weak_antichain -> Set.Subsingleton.isWeakAntichain is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] {s : Set.{max u1 u2} (forall (i : ι), α i)}, (Set.Subsingleton.{max u1 u2} (forall (i : ι), α i) s) -> (IsWeakAntichain.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s)
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] {s : Set.{max u2 u1} (forall (i : ι), α i)}, (Set.Subsingleton.{max u2 u1} (forall (i : ι), α i) s) -> (IsWeakAntichain.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i) s)
Case conversion may be inaccurate. Consider using '#align set.subsingleton.is_weak_antichain Set.Subsingleton.isWeakAntichainₓ'. -/
theorem Set.Subsingleton.isWeakAntichain (hs : s.Subsingleton) : IsWeakAntichain s :=
  hs.IsAntichain _
#align set.subsingleton.is_weak_antichain Set.Subsingleton.isWeakAntichain

end Pi


/-
Copyright (c) 2021 Rémy Degenne. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Rémy Degenne
-/
import algebra.big_operators.intervals
import measure_theory.measure.measure_space

/-!
# Independence of sets of sets and measure spaces (σ-algebras)

* A family of sets of sets `π : ι → set (set α)` is independent with respect to a measure `μ` if for
  any finite set of indices `s = {i_1, ..., i_n}`, for any sets `f i_1 ∈ π i_1, ..., f i_n ∈ π i_n`,
  `μ (⋂ i in s, f i) = ∏ i in s, μ (f i) `. It will be used for families of π-systems.
* A family of measurable space structures (i.e. of σ-algebras) is independent with respect to a
  measure `μ` (typically defined on a finer σ-algebra) if the family of sets of measurable sets they
  define is independent. I.e., `m : ι → measurable_space α` is independent with respect to a
  measure `μ` if for any finite set of indices `s = {i_1, ..., i_n}`, for any sets
  `f i_1 ∈ m i_1, ..., f i_n ∈ m i_n`, then `μ (⋂ i in s, f i) = ∏ i in s, μ (f i)`.
* Independence of sets (or events in probabilistic parlance) is defined as independence of the
  measurable space structures they generate: a set `s` generates the measurable space structure with
  measurable sets `∅, s, sᶜ, univ`.
* Independence of functions (or random variables) is also defined as independence of the measurable
  space structures they generate: a function `f` for which we have a measurable space `m` on the
  codomain generates `measurable_space.comap f m`.

## Main statements

* `Indep_sets.Indep`: if π-systems are independent as sets of sets, then the
measurable space structures they generate are independent.
* `indep_sets.indep`: variant with two π-systems.

## Implementation notes

We provide one main definition of independence:
* `Indep_sets`: independence of a family of sets of sets `pi : ι → set (set α)`.
Three other independence notions are defined using `Indep_sets`:
* `Indep`: independence of a family of measurable space structures `m : ι → measurable_space α`,
* `Indep_set`: independence of a family of sets `s : ι → set α`,
* `Indep_fun`: independence of a family of functions. For measurable spaces
  `m : Π (i : ι), measurable_space (β i)`, we consider functions `f : Π (i : ι), α → β i`.

Additionally, we provide four corresponding statements for two measurable space structures (resp.
sets of sets, sets, functions) instead of a family. These properties are denoted by the same names
as for a family, but without a capital letter, for example `indep_fun` is the version of `Indep_fun`
for two functions.

The definition of independence for `Indep_sets` uses finite sets (`finset`). An alternative and
equivalent way of defining independence would have been to use countable sets.
TODO: prove that equivalence.

Most of the definitions and lemma in this file list all variables instead of using the `variables`
keyword at the beginning of a section, for example
`lemma indep.symm {α} {m₁ m₂ : measurable_space α} [measurable_space α] {μ : measure α} ...` .
This is intentional, to be able to control the order of the `measurable_space` variables. Indeed
when defining `μ` in the example above, the measurable space used is the last one defined, here
`[measurable_space α]`, and not `m₁` or `m₂`.

## References

* Williams, David. Probability with martingales. Cambridge university press, 1991.
Part A, Chapter 4.
-/

open measure_theory measurable_space
open_locale big_operators classical measure_theory

namespace probability_theory

section definitions

/-- A family of sets of sets `π : ι → set (set α)` is independent with respect to a measure `μ` if
for any finite set of indices `s = {i_1, ..., i_n}`, for any sets
`f i_1 ∈ π i_1, ..., f i_n ∈ π i_n`, then `μ (⋂ i in s, f i) = ∏ i in s, μ (f i) `.
It will be used for families of pi_systems. -/
def Indep_sets {α ι} [measurable_space α] (π : ι → set (set α)) (μ : measure α . volume_tac) :
  Prop :=
∀ (s : finset ι) {f : ι → set α} (H : ∀ i, i ∈ s → f i ∈ π i), μ (⋂ i ∈ s, f i) = ∏ i in s, μ (f i)

/-- Two sets of sets `s₁, s₂` are independent with respect to a measure `μ` if for any sets
`t₁ ∈ p₁, t₂ ∈ s₂`, then `μ (t₁ ∩ t₂) = μ (t₁) * μ (t₂)` -/
def indep_sets {α} [measurable_space α] (s1 s2 : set (set α)) (μ : measure α . volume_tac) : Prop :=
∀ t1 t2 : set α, t1 ∈ s1 → t2 ∈ s2 → μ (t1 ∩ t2) = μ t1 * μ t2

/-- A family of measurable space structures (i.e. of σ-algebras) is independent with respect to a
measure `μ` (typically defined on a finer σ-algebra) if the family of sets of measurable sets they
define is independent. `m : ι → measurable_space α` is independent with respect to measure `μ` if
for any finite set of indices `s = {i_1, ..., i_n}`, for any sets
`f i_1 ∈ m i_1, ..., f i_n ∈ m i_n`, then `μ (⋂ i in s, f i) = ∏ i in s, μ (f i) `. -/
def Indep {α ι} (m : ι → measurable_space α) [measurable_space α] (μ : measure α . volume_tac) :
  Prop :=
Indep_sets (λ x, {s | measurable_set[m x] s}) μ

/-- Two measurable space structures (or σ-algebras) `m₁, m₂` are independent with respect to a
measure `μ` (defined on a third σ-algebra) if for any sets `t₁ ∈ m₁, t₂ ∈ m₂`,
`μ (t₁ ∩ t₂) = μ (t₁) * μ (t₂)` -/
def indep {α} (m₁ m₂ : measurable_space α) [measurable_space α] (μ : measure α . volume_tac) :
  Prop :=
indep_sets {s | measurable_set[m₁] s} {s | measurable_set[m₂] s} μ

/-- A family of sets is independent if the family of measurable space structures they generate is
independent. For a set `s`, the generated measurable space has measurable sets `∅, s, sᶜ, univ`. -/
def Indep_set {α ι} [measurable_space α] (s : ι → set α) (μ : measure α . volume_tac) : Prop :=
Indep (λ i, generate_from {s i}) μ

/-- Two sets are independent if the two measurable space structures they generate are independent.
For a set `s`, the generated measurable space structure has measurable sets `∅, s, sᶜ, univ`. -/
def indep_set {α} [measurable_space α] (s t : set α) (μ : measure α . volume_tac) : Prop :=
indep (generate_from {s}) (generate_from {t}) μ

/-- A family of functions defined on the same space `α` and taking values in possibly different
spaces, each with a measurable space structure, is independent if the family of measurable space
structures they generate on `α` is independent. For a function `g` with codomain having measurable
space structure `m`, the generated measurable space structure is `measurable_space.comap g m`. -/
def Indep_fun {α ι} [measurable_space α] {β : ι → Type*} (m : Π (x : ι), measurable_space (β x))
  (f : Π (x : ι), α → β x) (μ : measure α . volume_tac) : Prop :=
Indep (λ x, measurable_space.comap (f x) (m x)) μ

/-- Two functions are independent if the two measurable space structures they generate are
independent. For a function `f` with codomain having measurable space structure `m`, the generated
measurable space structure is `measurable_space.comap f m`. -/
def indep_fun {α β γ} [measurable_space α] [mβ : measurable_space β] [mγ : measurable_space γ]
  (f : α → β) (g : α → γ) (μ : measure α . volume_tac) : Prop :=
indep (measurable_space.comap f mβ) (measurable_space.comap g mγ) μ

end definitions

section indep

lemma indep_sets.symm {α} {s₁ s₂ : set (set α)} [measurable_space α] {μ : measure α}
  (h : indep_sets s₁ s₂ μ) :
  indep_sets s₂ s₁ μ :=
by { intros t1 t2 ht1 ht2, rw [set.inter_comm, mul_comm], exact h t2 t1 ht2 ht1, }

lemma indep.symm {α} {m₁ m₂ : measurable_space α} [measurable_space α] {μ : measure α}
  (h : indep m₁ m₂ μ) :
  indep m₂ m₁ μ :=
indep_sets.symm h

lemma indep_sets_of_indep_sets_of_le_left {α} {s₁ s₂ s₃: set (set α)} [measurable_space α]
  {μ : measure α} (h_indep : indep_sets s₁ s₂ μ) (h31 : s₃ ⊆ s₁) :
  indep_sets s₃ s₂ μ :=
λ t1 t2 ht1 ht2, h_indep t1 t2 (set.mem_of_subset_of_mem h31 ht1) ht2

lemma indep_sets_of_indep_sets_of_le_right {α} {s₁ s₂ s₃: set (set α)} [measurable_space α]
  {μ : measure α} (h_indep : indep_sets s₁ s₂ μ) (h32 : s₃ ⊆ s₂) :
  indep_sets s₁ s₃ μ :=
λ t1 t2 ht1 ht2, h_indep t1 t2 ht1 (set.mem_of_subset_of_mem h32 ht2)

lemma indep_of_indep_of_le_left {α} {m₁ m₂ m₃: measurable_space α} [measurable_space α]
  {μ : measure α} (h_indep : indep m₁ m₂ μ) (h31 : m₃ ≤ m₁) :
  indep m₃ m₂ μ :=
λ t1 t2 ht1 ht2, h_indep t1 t2 (h31 _ ht1) ht2

lemma indep_of_indep_of_le_right {α} {m₁ m₂ m₃: measurable_space α} [measurable_space α]
  {μ : measure α} (h_indep : indep m₁ m₂ μ) (h32 : m₃ ≤ m₂) :
  indep m₁ m₃ μ :=
λ t1 t2 ht1 ht2, h_indep t1 t2 ht1 (h32 _ ht2)

lemma indep_sets.union {α} [measurable_space α] {s₁ s₂ s' : set (set α)} {μ : measure α}
  (h₁ : indep_sets s₁ s' μ) (h₂ : indep_sets s₂ s' μ) :
  indep_sets (s₁ ∪ s₂) s' μ :=
begin
  intros t1 t2 ht1 ht2,
  cases (set.mem_union _ _ _).mp ht1 with ht1₁ ht1₂,
  { exact h₁ t1 t2 ht1₁ ht2, },
  { exact h₂ t1 t2 ht1₂ ht2, },
end

@[simp] lemma indep_sets.union_iff {α} [measurable_space α] {s₁ s₂ s' : set (set α)}
  {μ : measure α} :
  indep_sets (s₁ ∪ s₂) s' μ ↔ indep_sets s₁ s' μ ∧ indep_sets s₂ s' μ :=
⟨λ h, ⟨indep_sets_of_indep_sets_of_le_left h (set.subset_union_left s₁ s₂),
    indep_sets_of_indep_sets_of_le_left h (set.subset_union_right s₁ s₂)⟩,
  λ h, indep_sets.union h.left h.right⟩

lemma indep_sets.Union {α ι} [measurable_space α] {s : ι → set (set α)} {s' : set (set α)}
  {μ : measure α} (hyp : ∀ n, indep_sets (s n) s' μ) :
  indep_sets (⋃ n, s n) s' μ :=
begin
  intros t1 t2 ht1 ht2,
  rw set.mem_Union at ht1,
  cases ht1 with n ht1,
  exact hyp n t1 t2 ht1 ht2,
end

lemma indep_sets.inter {α} [measurable_space α] {s₁ s' : set (set α)} (s₂ : set (set α))
  {μ : measure α} (h₁ : indep_sets s₁ s' μ) :
  indep_sets (s₁ ∩ s₂) s' μ :=
λ t1 t2 ht1 ht2, h₁ t1 t2 ((set.mem_inter_iff _ _ _).mp ht1).left ht2

lemma indep_sets.Inter {α ι} [measurable_space α] {s : ι → set (set α)} {s' : set (set α)}
  {μ : measure α} (h : ∃ n, indep_sets (s n) s' μ) :
  indep_sets (⋂ n, s n) s' μ :=
by {intros t1 t2 ht1 ht2, cases h with n h, exact h t1 t2 (set.mem_Inter.mp ht1 n) ht2 }

lemma indep_sets_singleton_iff {α} [measurable_space α] {s t : set α} {μ : measure α} :
  indep_sets {s} {t} μ ↔ μ (s ∩ t) = μ s * μ t :=
⟨λ h, h s t rfl rfl,
  λ h s1 t1 hs1 ht1, by rwa [set.mem_singleton_iff.mp hs1, set.mem_singleton_iff.mp ht1]⟩

end indep

/-! ### Deducing `indep` from `Indep` -/
section from_Indep_to_indep

lemma Indep_sets.indep_sets {α ι} {s : ι → set (set α)} [measurable_space α] {μ : measure α}
  (h_indep : Indep_sets s μ) {i j : ι} (hij : i ≠ j) :
  indep_sets (s i) (s j) μ :=
begin
  intros t₁ t₂ ht₁ ht₂,
  have hf_m : ∀ (x : ι), x ∈ {i, j} → (ite (x=i) t₁ t₂) ∈ s x,
  { intros x hx,
    cases finset.mem_insert.mp hx with hx hx,
    { simp [hx, ht₁], },
    { simp [finset.mem_singleton.mp hx, hij.symm, ht₂], }, },
  have h1 : t₁ = ite (i = i) t₁ t₂, by simp only [if_true, eq_self_iff_true],
  have h2 : t₂ = ite (j = i) t₁ t₂, by simp only [hij.symm, if_false],
  have h_inter : (⋂ (t : ι) (H : t ∈ ({i, j} : finset ι)), ite (t = i) t₁ t₂)
      = (ite (i = i) t₁ t₂) ∩ (ite (j = i) t₁ t₂),
    by simp only [finset.set_bInter_singleton, finset.set_bInter_insert],
  have h_prod : (∏ (t : ι) in ({i, j} : finset ι), μ (ite (t = i) t₁ t₂))
      = μ (ite (i = i) t₁ t₂) * μ (ite (j = i) t₁ t₂),
    by simp only [hij, finset.prod_singleton, finset.prod_insert, not_false_iff,
      finset.mem_singleton],
  rw h1,
  nth_rewrite 1 h2,
  nth_rewrite 3 h2,
  rw [←h_inter, ←h_prod, h_indep {i, j} hf_m],
end

lemma Indep.indep {α ι} {m : ι → measurable_space α} [measurable_space α] {μ : measure α}
  (h_indep : Indep m μ) {i j : ι} (hij : i ≠ j) :
  indep (m i) (m j) μ :=
begin
  change indep_sets ((λ x, measurable_set[m x]) i) ((λ x, measurable_set[m x]) j) μ,
  exact Indep_sets.indep_sets h_indep hij,
end

end from_Indep_to_indep

/-!
## π-system lemma

Independence of measurable spaces is equivalent to independence of generating π-systems.
-/

section from_measurable_spaces_to_sets_of_sets
/-! ### Independence of measurable space structures implies independence of generating π-systems -/

lemma Indep.Indep_sets {α ι} [measurable_space α] {μ : measure α} {m : ι → measurable_space α}
  {s : ι → set (set α)} (hms : ∀ n, m n = generate_from (s n))
  (h_indep : Indep m μ) :
  Indep_sets s μ :=
λ S f hfs, h_indep S $ λ x hxS,
  ((hms x).symm ▸ measurable_set_generate_from (hfs x hxS) : measurable_set[m x] (f x))

lemma indep.indep_sets {α} [measurable_space α] {μ : measure α} {s1 s2 : set (set α)}
  (h_indep : indep (generate_from s1) (generate_from s2) μ) :
  indep_sets s1 s2 μ :=
λ t1 t2 ht1 ht2, h_indep t1 t2 (measurable_set_generate_from ht1) (measurable_set_generate_from ht2)

end from_measurable_spaces_to_sets_of_sets

section from_pi_systems_to_measurable_spaces
/-! ### Independence of generating π-systems implies independence of measurable space structures -/

private lemma indep_sets.indep_aux {α} {m2 : measurable_space α}
  {m : measurable_space α} {μ : measure α} [is_probability_measure μ] {p1 p2 : set (set α)}
  (h2 : m2 ≤ m) (hp2 : is_pi_system p2) (hpm2 : m2 = generate_from p2)
  (hyp : indep_sets p1 p2 μ) {t1 t2 : set α} (ht1 : t1 ∈ p1) (ht2m : measurable_set[m2] t2) :
  μ (t1 ∩ t2) = μ t1 * μ t2 :=
begin
  let μ_inter := μ.restrict t1,
  let ν := (μ t1) • μ,
  have h_univ : μ_inter set.univ = ν set.univ,
  by rw [measure.restrict_apply_univ, measure.smul_apply, smul_eq_mul, measure_univ, mul_one],
  haveI : is_finite_measure μ_inter := @restrict.is_finite_measure α _ t1 μ ⟨measure_lt_top μ t1⟩,
  rw [set.inter_comm, ←@measure.restrict_apply α _ μ t1 t2 (h2 t2 ht2m)],
  refine ext_on_measurable_space_of_generate_finite m p2 (λ t ht, _) h2 hpm2 hp2 h_univ ht2m,
  have ht2 : measurable_set[m] t,
  { refine h2 _ _,
    rw hpm2,
    exact measurable_set_generate_from ht, },
  rw [measure.restrict_apply ht2, measure.smul_apply, set.inter_comm],
  exact hyp t1 t ht1 ht,
end

lemma indep_sets.indep {α} {m1 m2 : measurable_space α} {m : measurable_space α}
  {μ : measure α} [is_probability_measure μ] {p1 p2 : set (set α)} (h1 : m1 ≤ m) (h2 : m2 ≤ m)
  (hp1 : is_pi_system p1) (hp2 : is_pi_system p2) (hpm1 : m1 = generate_from p1)
  (hpm2 : m2 = generate_from p2) (hyp : indep_sets p1 p2 μ) :
  indep m1 m2 μ :=
begin
  intros t1 t2 ht1 ht2,
  let μ_inter := μ.restrict t2,
  let ν := (μ t2) • μ,
  have h_univ : μ_inter set.univ = ν set.univ,
  by rw [measure.restrict_apply_univ, measure.smul_apply, smul_eq_mul, measure_univ, mul_one],
  haveI : is_finite_measure μ_inter := @restrict.is_finite_measure α _ t2 μ ⟨measure_lt_top μ t2⟩,
  rw [mul_comm, ←@measure.restrict_apply α _ μ t2 t1 (h1 t1 ht1)],
  refine ext_on_measurable_space_of_generate_finite m p1 (λ t ht, _) h1 hpm1 hp1 h_univ ht1,
  have ht1 : measurable_set[m] t,
  { refine h1 _ _,
    rw hpm1,
    exact measurable_set_generate_from ht, },
  rw [measure.restrict_apply ht1, measure.smul_apply, smul_eq_mul, mul_comm],
  exact indep_sets.indep_aux h2 hp2 hpm2 hyp ht ht2,
end

variables {α ι : Type*} {m0 : measurable_space α} {μ : measure α}

lemma Indep_sets.pi_Union_Inter_singleton {π : ι → set (set α)} {a : ι} {S : finset ι}
  (hp_ind : Indep_sets π μ) (haS : a ∉ S) :
  indep_sets (pi_Union_Inter π {S}) (π a) μ :=
begin
  rintros t1 t2 ⟨s, hs_mem, ft1, hft1_mem, ht1_eq⟩ ht2_mem_pia,
  rw set.mem_singleton_iff at hs_mem,
  subst hs_mem,
  let f := λ n, ite (n = a) t2 (ite (n ∈ s) (ft1 n) set.univ),
  have h_f_mem : ∀ n ∈ insert a s, f n ∈ π n,
  { intros n hn_mem_insert,
    simp_rw f,
    cases (finset.mem_insert.mp hn_mem_insert) with hn_mem hn_mem,
    { simp [hn_mem, ht2_mem_pia], },
    { have hn_ne_a : n ≠ a, by { rintro rfl, exact haS hn_mem, },
      simp [hn_ne_a, hn_mem, hft1_mem n hn_mem], }, },
  have h_f_mem_pi : ∀ n ∈ s, f n ∈ π n, from λ x hxS, h_f_mem x (by simp [hxS]),
  have h_t1 : t1 = ⋂ n ∈ s, f n,
  { suffices h_forall : ∀ n ∈ s, f n = ft1 n,
    { rw ht1_eq,
      congr' with n x,
      congr' with hns y,
      simp only [(h_forall n hns).symm], },
    intros n hnS,
    have hn_ne_a : n ≠ a, by { rintro rfl, exact haS hnS, },
    simp_rw [f, if_pos hnS, if_neg hn_ne_a], },
  have h_μ_t1 : μ t1 = ∏ n in s, μ (f n), by rw [h_t1, ←hp_ind s h_f_mem_pi],
  have h_t2 : t2 = f a, by { simp_rw [f], simp, },
  have h_μ_inter : μ (t1 ∩ t2) = ∏ n in insert a s, μ (f n),
  { have h_t1_inter_t2 : t1 ∩ t2 = ⋂ n ∈ insert a s, f n,
      by rw [h_t1, h_t2, finset.set_bInter_insert, set.inter_comm],
    rw [h_t1_inter_t2, ←hp_ind (insert a s) h_f_mem], },
  rw [h_μ_inter, finset.prod_insert haS, h_t2, mul_comm, h_μ_t1],
end

/-- Auxiliary lemma for `Indep_sets.Indep`. -/
theorem Indep_sets.Indep_aux [is_probability_measure μ] (m : ι → measurable_space α)
  (h_le : ∀ i, m i ≤ m0) (π : ι → set (set α)) (h_pi : ∀ n, is_pi_system (π n))
  (hp_univ : ∀ i, set.univ ∈ π i) (h_generate : ∀ i, m i = generate_from (π i))
  (h_ind : Indep_sets π μ) :
  Indep m μ :=
begin
  refine finset.induction (by simp [measure_univ]) _,
  intros a S ha_notin_S h_rec f hf_m,
  have hf_m_S : ∀ x ∈ S, measurable_set[m x] (f x) := λ x hx, hf_m x (by simp [hx]),
  rw [finset.set_bInter_insert, finset.prod_insert ha_notin_S, ←h_rec hf_m_S],
  let p := pi_Union_Inter π {S},
  set m_p := generate_from p with hS_eq_generate,
  have h_indep : indep m_p (m a) μ,
  { have hp : is_pi_system p := is_pi_system_pi_Union_Inter π h_pi {S} (sup_closed_singleton S),
    have h_le' : ∀ i, generate_from (π i) ≤ m0 := λ i, (h_generate i).symm.trans_le (h_le i),
    have hm_p : m_p ≤ m0 := generate_from_pi_Union_Inter_le π h_le' {S},
    exact indep_sets.indep hm_p (h_le a) hp (h_pi a) hS_eq_generate (h_generate a)
      (h_ind.pi_Union_Inter_singleton ha_notin_S), },
  refine h_indep.symm (f a) (⋂ n ∈ S, f n) (hf_m a (finset.mem_insert_self a S)) _,
  have h_le_p : ∀ i ∈ S, m i ≤ m_p,
  { intros n hn,
    rw [hS_eq_generate, h_generate n],
    exact le_generate_from_pi_Union_Inter {S} hp_univ (set.mem_singleton _) hn, },
  have h_S_f : ∀ i ∈ S, measurable_set[m_p] (f i) := λ i hi, (h_le_p i hi) (f i) (hf_m_S i hi),
  exact S.measurable_set_bInter h_S_f,
end

/-- The measurable space structures generated by independent pi-systems are independent. -/
theorem Indep_sets.Indep [is_probability_measure μ] (m : ι → measurable_space α)
  (h_le : ∀ i, m i ≤ m0) (π : ι → set (set α)) (h_pi : ∀ n, is_pi_system (π n))
  (h_generate : ∀ i, m i = generate_from (π i)) (h_ind : Indep_sets π μ) :
  Indep m μ :=
begin
  -- We want to apply `Indep_sets.Indep_aux`, but `π i` does not contain `univ`, hence we replace
  -- `π` with a new augmented pi-system `π'`, and prove all hypotheses for that pi-system.
  let π' := λ i, insert set.univ (π i),
  have h_subset : ∀ i, π i ⊆ π' i := λ i, set.subset_insert _ _,
  have h_pi' : ∀ n, is_pi_system (π' n) := λ n, (h_pi n).insert_univ,
  have h_univ' : ∀ i, set.univ ∈ π' i, from λ i, set.mem_insert _ _,
  have h_gen' : ∀ i, m i = generate_from (π' i),
  { intros i,
    rw [h_generate i, generate_from_insert_univ (π i)], },
  have h_ind' : Indep_sets π' μ,
  { intros S f hfπ',
    let S' := finset.filter (λ i, f i ≠ set.univ) S,
    have h_mem : ∀ i ∈ S', f i ∈ π i,
    { intros i hi,
      simp_rw [S', finset.mem_filter] at hi,
      cases hfπ' i hi.1,
      { exact absurd h hi.2, },
      { exact h, }, },
    have h_left : (⋂ i ∈ S, f i) = ⋂ i ∈ S', f i,
    { ext1 x,
      simp only [set.mem_Inter, finset.mem_filter, ne.def, and_imp],
      split,
      { exact λ h i hiS hif, h i hiS, },
      { intros h i hiS,
        by_cases hfi_univ : f i = set.univ,
        { rw hfi_univ, exact set.mem_univ _, },
        { exact h i hiS hfi_univ, }, }, },
    have h_right : ∏ i in S, μ (f i) = ∏ i in S', μ (f i),
    { rw ← finset.prod_filter_mul_prod_filter_not S (λ i, f i ≠ set.univ),
      simp only [ne.def, finset.filter_congr_decidable, not_not],
      suffices : ∏ x in finset.filter (λ x, f x = set.univ) S, μ (f x) = 1,
      { rw [this, mul_one], },
      calc ∏ x in finset.filter (λ x, f x = set.univ) S, μ (f x)
          = ∏ x in finset.filter (λ x, f x = set.univ) S, μ set.univ :
            finset.prod_congr rfl (λ x hx, by { rw finset.mem_filter at hx, rw hx.2, })
      ... = ∏ x in finset.filter (λ x, f x = set.univ) S, 1 :
            finset.prod_congr rfl (λ _ _, measure_univ)
      ... = 1 : finset.prod_const_one, },
    rw [h_left, h_right],
    exact h_ind S' h_mem, },
  exact Indep_sets.Indep_aux m h_le π' h_pi' h_univ' h_gen' h_ind',
end

end from_pi_systems_to_measurable_spaces

section indep_set
/-! ### Independence of measurable sets

We prove the following equivalences on `indep_set`, for measurable sets `s, t`.
* `indep_set s t μ ↔ μ (s ∩ t) = μ s * μ t`,
* `indep_set s t μ ↔ indep_sets {s} {t} μ`.
-/

variables {α : Type*} [measurable_space α] {s t : set α} (S T : set (set α))

lemma indep_set_iff_indep_sets_singleton (hs_meas : measurable_set s) (ht_meas : measurable_set t)
  (μ : measure α . volume_tac) [is_probability_measure μ] :
  indep_set s t μ ↔ indep_sets {s} {t} μ :=
⟨indep.indep_sets,  λ h, indep_sets.indep
  (generate_from_le (λ u hu, by rwa set.mem_singleton_iff.mp hu))
  (generate_from_le (λ u hu, by rwa set.mem_singleton_iff.mp hu)) (is_pi_system.singleton s)
  (is_pi_system.singleton t) rfl rfl h⟩

lemma indep_set_iff_measure_inter_eq_mul (hs_meas : measurable_set s) (ht_meas : measurable_set t)
  (μ : measure α . volume_tac) [is_probability_measure μ] :
  indep_set s t μ ↔ μ (s ∩ t) = μ s * μ t :=
(indep_set_iff_indep_sets_singleton hs_meas ht_meas μ).trans indep_sets_singleton_iff

lemma indep_sets.indep_set_of_mem (hs : s ∈ S) (ht : t ∈ T) (hs_meas : measurable_set s)
  (ht_meas : measurable_set t) (μ : measure α . volume_tac) [is_probability_measure μ]
  (h_indep : indep_sets S T μ) :
  indep_set s t μ :=
(indep_set_iff_measure_inter_eq_mul hs_meas ht_meas μ).mpr (h_indep s t hs ht)

end indep_set

section indep_fun

/-! ### Independence of random variables

-/

variables {α β β' γ γ' : Type*} {mα : measurable_space α} {μ : measure α} {f : α → β} {g : α → β'}

lemma indep_fun_iff_measure_inter_preimage_eq_mul
  {mβ : measurable_space β} {mβ' : measurable_space β'} [is_probability_measure μ]
  (hf : measurable f) (hg : measurable g) :
  indep_fun f g μ
    ↔ ∀ s t, measurable_set s → measurable_set t
      → μ (f ⁻¹' s ∩ g ⁻¹' t) = μ (f ⁻¹' s) * μ (g ⁻¹' t) :=
begin
  let Sf := {t1 | ∃ s, measurable_set s ∧ f ⁻¹' s = t1},
  let Sg := {t1 | ∃ t, measurable_set t ∧ g ⁻¹' t = t1},
  suffices : indep_fun f g μ ↔ indep_sets Sf Sg μ,
  { refine this.trans _,
    simp_rw [indep_sets, Sf, Sg, set.mem_set_of_eq],
    split; intro h,
    { exact λ s t hs ht, h (f ⁻¹' s) (g ⁻¹' t) ⟨s, hs, rfl⟩ ⟨t, ht, rfl⟩, },
    { rintros t1 t2 ⟨s, hs, rfl⟩ ⟨t, ht, rfl⟩,
      exact h s t hs ht, }, },
  have hSf_pi : is_pi_system Sf,
  { rintros s ⟨s', hs', rfl⟩ t ⟨t', ht', rfl⟩ hst_nonempty,
    exact ⟨s' ∩ t', hs'.inter ht', rfl⟩, },
  have hSg_pi : is_pi_system Sg,
  { rintros s ⟨s', hs', rfl⟩ t ⟨t', ht', rfl⟩ hst_nonempty,
    exact ⟨s' ∩ t', hs'.inter ht', rfl⟩, },
  have hSf_gen : mβ.comap f = generate_from Sf := mβ.comap_eq_generate_from f,
  have hSg_gen : mβ'.comap g = generate_from Sg := mβ'.comap_eq_generate_from g,
  rw indep_fun,
  split; intro h,
  { rw [hSf_gen, hSg_gen] at h,
    exact indep.indep_sets h, },
  { exact indep_sets.indep hf.comap_le hg.comap_le hSf_pi hSg_pi hSf_gen hSg_gen h, },
end

lemma indep_fun_iff_indep_set_preimage {mβ : measurable_space β} {mβ' : measurable_space β'}
  [is_probability_measure μ] (hf : measurable f) (hg : measurable g) :
  indep_fun f g μ ↔ ∀ s t, measurable_set s → measurable_set t → indep_set (f ⁻¹' s) (g ⁻¹' t) μ :=
begin
  refine (indep_fun_iff_measure_inter_preimage_eq_mul hf hg).trans _,
  split; intros h s t hs ht; specialize h s t hs ht,
  { rwa indep_set_iff_measure_inter_eq_mul (hf hs) (hg ht) μ, },
  { rwa ← indep_set_iff_measure_inter_eq_mul (hf hs) (hg ht) μ, },
end

lemma indep_fun.ae_eq {mβ : measurable_space β} {f g f' g' : α → β}
  (hfg : indep_fun f g μ) (hf : f =ᵐ[μ] f') (hg : g =ᵐ[μ] g') :
  indep_fun f' g' μ :=
begin
  rintro _ _ ⟨A, hA, rfl⟩ ⟨B, hB, rfl⟩,
  have h1 : f ⁻¹' A =ᵐ[μ] f' ⁻¹' A := hf.fun_comp A,
  have h2 : g ⁻¹' B =ᵐ[μ] g' ⁻¹' B := hg.fun_comp B,
  rw [←measure_congr h1, ←measure_congr h2, ←measure_congr (h1.inter h2)],
  exact hfg _ _ ⟨_, hA, rfl⟩ ⟨_, hB, rfl⟩
end

lemma indep_fun.comp {mβ : measurable_space β} {mβ' : measurable_space β'}
  {mγ : measurable_space γ} {mγ' : measurable_space γ'} {φ : β → γ} {ψ : β' → γ'}
  (hfg : indep_fun f g μ) (hφ : measurable φ) (hψ : measurable ψ) :
  indep_fun (φ ∘ f) (ψ ∘ g) μ :=
begin
  rintro _ _ ⟨A, hA, rfl⟩ ⟨B, hB, rfl⟩,
  apply hfg,
  { exact ⟨φ ⁻¹' A, hφ hA, set.preimage_comp.symm⟩ },
  { exact ⟨ψ ⁻¹' B, hψ hB, set.preimage_comp.symm⟩ }
end

end indep_fun

end probability_theory