/-
Copyright (c) 2022 Anne Baanen. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Anne Baanen, Alex J. Best

! This file was ported from Lean 3 source module linear_algebra.quotient_pi
! leanprover-community/mathlib commit 398f60f60b43ef42154bd2bdadf5133daf1577a4
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.LinearAlgebra.Pi
import Mathbin.LinearAlgebra.Quotient

/-!
# Submodule quotients and direct sums

This file contains some results on the quotient of a module by a direct sum of submodules,
and the direct sum of quotients of modules by submodules.

# Main definitions

 * `submodule.pi_quotient_lift`: create a map out of the direct sum of quotients
 * `submodule.quotient_pi_lift`: create a map out of the quotient of a direct sum
 * `submodule.quotient_pi`: the quotient of a direct sum is the direct sum of quotients.

-/

namespace Submodule

open LinearMap

variable {ι R : Type _} [CommRing R]

variable {Ms : ι → Type _} [∀ i, AddCommGroup (Ms i)] [∀ i, Module R (Ms i)]

variable {N : Type _} [AddCommGroup N] [Module R N]

variable {Ns : ι → Type _} [∀ i, AddCommGroup (Ns i)] [∀ i, Module R (Ns i)]

/-- Lift a family of maps to the direct sum of quotients. -/
def piQuotientLift [Fintype ι] [DecidableEq ι] (p : ∀ i, Submodule R (Ms i)) (q : Submodule R N)
    (f : ∀ i, Ms i →ₗ[R] N) (hf : ∀ i, p i ≤ q.comap (f i)) : (∀ i, Ms i ⧸ p i) →ₗ[R] N ⧸ q :=
  lsum R (fun i => Ms i ⧸ p i) R fun i => (p i).mapQ q (f i) (hf i)
#align submodule.pi_quotient_lift Submodule.piQuotientLift

@[simp]
theorem piQuotientLift_mk [Fintype ι] [DecidableEq ι] (p : ∀ i, Submodule R (Ms i))
    (q : Submodule R N) (f : ∀ i, Ms i →ₗ[R] N) (hf : ∀ i, p i ≤ q.comap (f i)) (x : ∀ i, Ms i) :
    (piQuotientLift p q f hf fun i => Quotient.mk (x i)) = Quotient.mk (lsum _ _ R f x) := by
  rw [pi_quotient_lift, lsum_apply, sum_apply, ← mkq_apply, lsum_apply, sum_apply,
      _root_.map_sum] <;>
    simp only [coe_proj, mapq_apply, mkq_apply, comp_apply]
#align submodule.pi_quotient_lift_mk Submodule.piQuotientLift_mk

@[simp]
theorem piQuotientLift_single [Fintype ι] [DecidableEq ι] (p : ∀ i, Submodule R (Ms i))
    (q : Submodule R N) (f : ∀ i, Ms i →ₗ[R] N) (hf : ∀ i, p i ≤ q.comap (f i)) (i)
    (x : Ms i ⧸ p i) : piQuotientLift p q f hf (Pi.single i x) = mapQ _ _ (f i) (hf i) x :=
  by
  simp_rw [pi_quotient_lift, lsum_apply, sum_apply, comp_apply, proj_apply]
  rw [Finset.sum_eq_single i]
  · rw [Pi.single_eq_same]
  · rintro j - hj
    rw [Pi.single_eq_of_ne hj, _root_.map_zero]
  · intros
    have := Finset.mem_univ i
    contradiction
#align submodule.pi_quotient_lift_single Submodule.piQuotientLift_single

/-- Lift a family of maps to a quotient of direct sums. -/
def quotientPiLift (p : ∀ i, Submodule R (Ms i)) (f : ∀ i, Ms i →ₗ[R] Ns i)
    (hf : ∀ i, p i ≤ ker (f i)) : (∀ i, Ms i) ⧸ pi Set.univ p →ₗ[R] ∀ i, Ns i :=
  (pi Set.univ p).liftQ (LinearMap.pi fun i => (f i).comp (proj i)) fun x hx =>
    mem_ker.mpr <| by
      ext i
      simpa using hf i (mem_pi.mp hx i (Set.mem_univ i))
#align submodule.quotient_pi_lift Submodule.quotientPiLift

@[simp]
theorem quotientPiLift_mk (p : ∀ i, Submodule R (Ms i)) (f : ∀ i, Ms i →ₗ[R] Ns i)
    (hf : ∀ i, p i ≤ ker (f i)) (x : ∀ i, Ms i) :
    quotientPiLift p f hf (Quotient.mk x) = fun i => f i (x i) :=
  rfl
#align submodule.quotient_pi_lift_mk Submodule.quotientPiLift_mk

/-- The quotient of a direct sum is the direct sum of quotients. -/
@[simps]
def quotientPi [Fintype ι] [DecidableEq ι] (p : ∀ i, Submodule R (Ms i)) :
    ((∀ i, Ms i) ⧸ pi Set.univ p) ≃ₗ[R] ∀ i, Ms i ⧸ p i :=
  {
    quotientPiLift p (fun i => (p i).mkQ) fun i => by
      simp with
    toFun := quotientPiLift p (fun i => (p i).mkQ) fun i => by simp
    invFun := piQuotientLift p (pi Set.univ p) single fun i => le_comap_single_pi p
    left_inv := fun x =>
      Quotient.inductionOn' x fun x' => by
        simp_rw [Quotient.mk''_eq_mk', quotient_pi_lift_mk, mkq_apply, pi_quotient_lift_mk,
          lsum_single, id_apply]
    right_inv := by
      rw [Function.rightInverse_iff_comp, ← coe_comp, ← @id_coe R]
      refine' congr_arg _ (pi_ext fun i x => Quotient.inductionOn' x fun x' => funext fun j => _)
      rw [comp_apply, pi_quotient_lift_single, Quotient.mk''_eq_mk', mapq_apply,
        quotient_pi_lift_mk, id_apply]
      by_cases hij : i = j <;> simp only [mkq_apply, coe_single]
      · subst hij
        simp only [Pi.single_eq_same]
      · simp only [Pi.single_eq_of_ne (Ne.symm hij), quotient.mk_zero] }
#align submodule.quotient_pi Submodule.quotientPi

end Submodule


/-
Copyright (c) 2021-2023 by the authors listed in the file AUTHORS and their
institutional affiliations. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Abdalrhman Mohamed
-/

import Std.Data.Int.Lemmas
import Smt.Reconstruction.Rewrites.Simp

namespace Smt.Reconstruction.Rewrites.Arith

scoped notation "const " c => fun _ => c

variable {xs w ys zs t x s r : Int}

-- Basic Rules

@[smt_simp] theorem arith_plus_zero : t + 0 + s = t + s :=
  t.add_zero.symm ▸ rfl

@[smt_simp] theorem arith_mul_one : t * 1 * s = t * s :=
  t.mul_one.symm ▸ rfl
@[smt_simp] theorem arith_mul_zero : t * 0 * s = 0 :=
  t.mul_zero.symm ▸ s.zero_mul.symm ▸ rfl

@[smt_simp] theorem arith_uminus_elim : -t = -1 * t :=
  t.neg_eq_neg_one_mul
@[smt_simp] theorem arith_neg_neg_one : -1 * (-1 * t) = t :=
  Int.mul_assoc (-1) (-1) t ▸ t.one_mul.symm ▸ rfl

-- Eliminations

@[smt_simp] theorem arith_elim_minus : t - s = t + -1 * s :=
  s.neg_eq_neg_one_mul ▸ rfl
@[smt_simp] theorem arith_elim_gt : (t > s) = ¬(t ≤ s) :=
  propext Int.not_le.symm
@[smt_simp] theorem arith_elim_lt : (t < s) = ¬(t ≥ s) :=
  propext Int.not_le.symm
@[smt_simp] theorem arith_elim_leq : (t ≤ s) = ¬(t ≥ s + 1) :=
  propext Int.not_lt.symm

@[smt_simp] theorem arith_geq_tighten : (¬(t ≥ s)) = (s ≥ t + 1) :=
  propext Int.not_le

@[smt_simp] theorem arith_geq_norm: (t ≥ s) = (t - s ≥ 0) :=
  propext ⟨Int.sub_nonneg_of_le, Int.le_of_sub_nonneg⟩

@[smt_simp] theorem arith_refl_leq : (t ≤ t) = True :=
  propext ⟨const trivial, const t.le_refl⟩
@[smt_simp] theorem arith_refl_lt : (t < t) = False :=
  propext ⟨t.lt_irrefl, False.elim⟩
@[smt_simp] theorem arith_refl_geq : (t ≥ t) = True :=
  propext ⟨const trivial, const t.le_refl⟩
@[smt_simp] theorem arith_refl_gt : (t > t) = False :=
  propext ⟨t.lt_irrefl, False.elim⟩

@[smt_simp] theorem plus_flatten : xs + (w + ys) + zs = xs + w + ys + zs :=
  Int.add_assoc xs w ys ▸ rfl

@[smt_simp] theorem mult_flatten : xs * (w * ys) * zs = xs * w * ys * zs :=
  Int.mul_assoc xs w ys ▸ rfl

@[smt_simp] theorem mult_dist : x * (y + z + w) = x * y + x * (z + w) :=
  Int.add_assoc y z w ▸ Int.mul_add x y (z + w) ▸ rfl

-- TEMPORARY

@[smt_simp] theorem arith_plus_cancel1 : t + x + s + (-1 * x) + r = t + s + r :=
  arith_uminus_elim ▸ Int.add_assoc t x s ▸ Int.add_assoc t (x + s) (-x) ▸
  Int.add_comm x s ▸ (Int.add_neg_cancel_right s x).symm ▸ rfl

@[smt_simp] theorem arith_plus_cancel2 : t + (-1 * x) + s + x + r = t + s + r :=
  arith_uminus_elim ▸ Int.add_assoc t (-x) s ▸ Int.add_assoc t (-x + s) x ▸
  Int.add_comm (-x) s ▸ (Int.neg_add_cancel_right s x).symm ▸ rfl

end Smt.Reconstruction.Rewrites.Arith


/-
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
-/
import data.finset.locally_finite
import data.finset.pointwise
import data.dfinsupp.order

/-!
# Finite intervals of finitely supported functions

This file provides the `locally_finite_order` instance for `Π₀ i, α i` when `α` itself is locally
finite and calculates the cardinality of its finite intervals.
-/

open dfinsupp finset
open_locale big_operators pointwise

variables {ι : Type*} {α : ι → Type*}

namespace finset
variables [decidable_eq ι] [Π i, has_zero (α i)] {s : finset ι} {f : Π₀ i, α i}
  {t : Π i, finset (α i)}

/-- Finitely supported product of finsets. -/
def dfinsupp (s : finset ι) (t : Π i, finset (α i)) : finset (Π₀ i, α i) :=
(s.pi t).map ⟨λ f, dfinsupp.mk s $ λ i, f i i.2, begin
  refine (mk_injective _).comp (λ f g h, _),
  ext i hi,
  convert congr_fun h ⟨i, hi⟩,
  end⟩

@[simp] lemma card_dfinsupp (s : finset ι) (t : Π i, finset (α i)) :
  (s.dfinsupp t).card = ∏ i in s, (t i).card :=
(card_map _).trans $ card_pi _ _

variables [Π i, decidable_eq (α i)]

lemma mem_dfinsupp_iff : f ∈ s.dfinsupp t ↔ f.support ⊆ s ∧ ∀ i ∈ s, f i ∈ t i :=
begin
  refine mem_map.trans ⟨_, _⟩,
  { rintro ⟨f, hf, rfl⟩,
    refine ⟨support_mk_subset, λ i hi, _⟩,
    convert mem_pi.1 hf i hi,
    exact mk_of_mem hi },
  { refine λ h, ⟨λ i _, f i, mem_pi.2 h.2, _⟩,
    ext i,
    dsimp,
    exact ite_eq_left_iff.2 (λ hi, (not_mem_support_iff.1 $ λ H, hi $ h.1 H).symm) }
end

/-- When `t` is supported on `s`, `f ∈ s.dfinsupp t` precisely means that `f` is pointwise in `t`.
-/
@[simp] lemma mem_dfinsupp_iff_of_support_subset {t : Π₀ i, finset (α i)} (ht : t.support ⊆ s) :
  f ∈ s.dfinsupp t ↔ ∀ i, f i ∈ t i :=
begin
  refine mem_dfinsupp_iff.trans (forall_and_distrib.symm.trans $ forall_congr $ λ i, ⟨λ h, _,
    λ h, ⟨λ hi, ht $ mem_support_iff.2 $ λ H, mem_support_iff.1 hi _, λ _, h⟩⟩),
  { by_cases hi : i ∈ s,
    { exact h.2 hi },
    { rw [not_mem_support_iff.1 (mt h.1 hi), not_mem_support_iff.1 (not_mem_mono ht hi)],
      exact zero_mem_zero } },
  { rwa [H, mem_zero] at h }
end

end finset

open finset

namespace dfinsupp
variables [decidable_eq ι] [Π i, decidable_eq (α i)]

section bundled_singleton
variables [Π i, has_zero (α i)] {f : Π₀ i, α i} {i : ι} {a : α i}

/-- Pointwise `finset.singleton` bundled as a `dfinsupp`. -/
def singleton (f : Π₀ i, α i) : Π₀ i, finset (α i) :=
⟦{ to_fun := λ i, {f i},
  pre_support := f.support.1,
  zero := λ i, (ne_or_eq (f i) 0).imp mem_support_iff.2 (congr_arg _) }⟧

lemma mem_singleton_apply_iff : a ∈ f.singleton i ↔ a = f i := mem_singleton

end bundled_singleton

section bundled_Icc
variables [Π i, has_zero (α i)] [Π i, partial_order (α i)] [Π i, locally_finite_order (α i)]
  {f g : Π₀ i, α i} {i : ι} {a : α i}

/-- Pointwise `finset.Icc` bundled as a `dfinsupp`. -/
def range_Icc (f g : Π₀ i, α i) : Π₀ i, finset (α i) :=
⟦{ to_fun := λ i, Icc (f i) (g i),
  pre_support := f.support.1 + g.support.1,
  zero := λ i, begin
    refine or_iff_not_imp_left.2 (λ h, _),
    rw [not_mem_support_iff.1 (multiset.not_mem_mono (multiset.le_add_right _ _).subset h),
      not_mem_support_iff.1 (multiset.not_mem_mono (multiset.le_add_left _ _).subset h)],
    exact Icc_self _,
  end }⟧

@[simp] lemma range_Icc_apply (f g : Π₀ i, α i) (i : ι) : f.range_Icc g i = Icc (f i) (g i) := rfl

lemma mem_range_Icc_apply_iff : a ∈ f.range_Icc g i ↔ f i ≤ a ∧ a ≤ g i := mem_Icc

lemma support_range_Icc_subset : (f.range_Icc g).support ⊆ f.support ∪ g.support :=
begin
  refine λ x hx, _,
  by_contra,
  refine not_mem_support_iff.2 _ hx,
  rw [range_Icc_apply,
    not_mem_support_iff.1 (not_mem_mono (subset_union_left _ _) h),
      not_mem_support_iff.1 (not_mem_mono (subset_union_right _ _) h)],
  exact Icc_self _,
end

end bundled_Icc

section pi
variables [Π i, has_zero (α i)]

/-- Given a finitely supported function `f : Π₀ i, finset (α i)`, one can define the finset
`f.pi` of all finitely supported functions whose value at `i` is in `f i` for all `i`. -/
def pi (f : Π₀ i, finset (α i)) : finset (Π₀ i, α i) := f.support.dfinsupp f

@[simp] lemma mem_pi {f : Π₀ i, finset (α i)} {g : Π₀ i, α i} : g ∈ f.pi ↔ ∀ i, g i ∈ f i :=
mem_dfinsupp_iff_of_support_subset $ subset.refl _

@[simp] lemma card_pi (f : Π₀ i, finset (α i)) : f.pi.card = f.prod (λ i, (f i).card) :=
begin
  rw [pi, card_dfinsupp],
  exact finset.prod_congr rfl (λ i _, by simp only [pi.nat_apply, nat.cast_id]),
end

end pi

section locally_finite
variables [Π i, partial_order (α i)] [Π i, has_zero (α i)] [Π i, locally_finite_order (α i)]

instance : locally_finite_order (Π₀ i, α i) :=
locally_finite_order.of_Icc (Π₀ i, α i)
  (λ f g, (f.support ∪ g.support).dfinsupp $ f.range_Icc g)
  (λ f g x, begin
    refine (mem_dfinsupp_iff_of_support_subset $ support_range_Icc_subset).trans _,
    simp_rw [mem_range_Icc_apply_iff, forall_and_distrib],
    refl,
  end)

variables (f g : Π₀ i, α i)

lemma card_Icc : (Icc f g).card = ∏ i in f.support ∪ g.support, (Icc (f i) (g i)).card :=
card_dfinsupp _ _

lemma card_Ico : (Ico f g).card = ∏ i in f.support ∪ g.support, (Icc (f i) (g i)).card - 1 :=
by rw [card_Ico_eq_card_Icc_sub_one, card_Icc]

lemma card_Ioc : (Ioc f g).card = ∏ i in f.support ∪ g.support, (Icc (f i) (g i)).card - 1 :=
by rw [card_Ioc_eq_card_Icc_sub_one, card_Icc]

end locally_finite
end dfinsupp


/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Mario Carneiro
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.data.finset.fold
import Mathlib.data.multiset.lattice
import Mathlib.order.order_dual
import Mathlib.order.complete_lattice
import Mathlib.PostPort

universes u_1 u_2 u_3 u_4 u_5

namespace Mathlib

/-!
# Lattice operations on finsets
-/

namespace finset

/-! ### sup -/

/-- Supremum of a finite set: `sup {a, b, c} f = f a ⊔ f b ⊔ f c` -/
def sup {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] (s : finset β) (f : β → α) : α :=
  fold has_sup.sup ⊥ f s

theorem sup_def {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s : finset β} {f : β → α} :
    sup s f = multiset.sup (multiset.map f (val s)) :=
  rfl

@[simp] theorem sup_empty {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {f : β → α} :
    sup ∅ f = ⊥ :=
  fold_empty

@[simp] theorem sup_insert {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s : finset β}
    {f : β → α} [DecidableEq β] {b : β} : sup (insert b s) f = f b ⊔ sup s f :=
  fold_insert_idem

@[simp] theorem sup_singleton {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {f : β → α}
    {b : β} : sup (singleton b) f = f b :=
  multiset.sup_singleton

theorem sup_union {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s₁ : finset β}
    {s₂ : finset β} {f : β → α} [DecidableEq β] : sup (s₁ ∪ s₂) f = sup s₁ f ⊔ sup s₂ f :=
  sorry

theorem sup_congr {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s₁ : finset β}
    {s₂ : finset β} {f : β → α} {g : β → α} (hs : s₁ = s₂) (hfg : ∀ (a : β), a ∈ s₂ → f a = g a) :
    sup s₁ f = sup s₂ g :=
  Eq._oldrec (fun (hfg : ∀ (a : β), a ∈ s₁ → f a = g a) => fold_congr hfg) hs hfg

@[simp] theorem sup_le_iff {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s : finset β}
    {f : β → α} {a : α} : sup s f ≤ a ↔ ∀ (b : β), b ∈ s → f b ≤ a :=
  sorry

theorem sup_const {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s : finset β}
    (h : finset.nonempty s) (c : α) : (sup s fun (_x : β) => c) = c :=
  eq_of_forall_ge_iff fun (b : α) => iff.trans sup_le_iff (nonempty.forall_const h)

theorem sup_le {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s : finset β} {f : β → α}
    {a : α} : (∀ (b : β), b ∈ s → f b ≤ a) → sup s f ≤ a :=
  iff.mpr sup_le_iff

theorem le_sup {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s : finset β} {f : β → α}
    {b : β} (hb : b ∈ s) : f b ≤ sup s f :=
  iff.mp sup_le_iff (le_refl (sup s f)) b hb

theorem sup_mono_fun {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s : finset β}
    {f : β → α} {g : β → α} (h : ∀ (b : β), b ∈ s → f b ≤ g b) : sup s f ≤ sup s g :=
  sup_le fun (b : β) (hb : b ∈ s) => le_trans (h b hb) (le_sup hb)

theorem sup_mono {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s₁ : finset β}
    {s₂ : finset β} {f : β → α} (h : s₁ ⊆ s₂) : sup s₁ f ≤ sup s₂ f :=
  sup_le fun (b : β) (hb : b ∈ s₁) => le_sup (h hb)

@[simp] theorem sup_lt_iff {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {s : finset β}
    {f : β → α} [is_total α LessEq] {a : α} (ha : ⊥ < a) :
    sup s f < a ↔ ∀ (b : β), b ∈ s → f b < a :=
  sorry

theorem comp_sup_eq_sup_comp {α : Type u_1} {β : Type u_2} {γ : Type u_3} [semilattice_sup_bot α]
    [semilattice_sup_bot γ] {s : finset β} {f : β → α} (g : α → γ)
    (g_sup : ∀ (x y : α), g (x ⊔ y) = g x ⊔ g y) (bot : g ⊥ = ⊥) : g (sup s f) = sup s (g ∘ f) :=
  sorry

theorem comp_sup_eq_sup_comp_of_is_total {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α]
    {s : finset β} {f : β → α} [is_total α LessEq] {γ : Type} [semilattice_sup_bot γ] (g : α → γ)
    (mono_g : monotone g) (bot : g ⊥ = ⊥) : g (sup s f) = sup s (g ∘ f) :=
  comp_sup_eq_sup_comp g (monotone.map_sup mono_g) bot

/-- Computating `sup` in a subtype (closed under `sup`) is the same as computing it in `α`. -/
theorem sup_coe {α : Type u_1} {β : Type u_2} [semilattice_sup_bot α] {P : α → Prop} {Pbot : P ⊥}
    {Psup : ∀ {x y : α}, P x → P y → P (x ⊔ y)} (t : finset β)
    (f : β → Subtype fun (x : α) => P x) : ↑(sup t f) = sup t fun (x : β) => ↑(f x) :=
  sorry

@[simp] theorem sup_to_finset {α : Type u_1} {β : Type u_2} [DecidableEq β] (s : finset α)
    (f : α → multiset β) :
    multiset.to_finset (sup s f) = sup s fun (x : α) => multiset.to_finset (f x) :=
  comp_sup_eq_sup_comp multiset.to_finset multiset.to_finset_union rfl

theorem subset_range_sup_succ (s : finset ℕ) : s ⊆ range (Nat.succ (sup s id)) :=
  fun (n : ℕ) (hn : n ∈ s) => iff.mpr mem_range (nat.lt_succ_of_le (le_sup hn))

theorem exists_nat_subset_range (s : finset ℕ) : ∃ (n : ℕ), s ⊆ range n :=
  Exists.intro (Nat.succ (sup s id)) (subset_range_sup_succ s)

theorem sup_subset {α : Type u_1} {β : Type u_2} [semilattice_sup_bot β] {s : finset α}
    {t : finset α} (hst : s ⊆ t) (f : α → β) : sup s f ≤ sup t f :=
  sorry

theorem sup_closed_of_sup_closed {α : Type u_1} [semilattice_sup_bot α] {s : set α} (t : finset α)
    (htne : finset.nonempty t) (h_subset : ↑t ⊆ s) (h : ∀ {a b : α}, a ∈ s → b ∈ s → a ⊔ b ∈ s) :
    sup t id ∈ s :=
  sorry

theorem sup_le_of_le_directed {α : Type u_1} [semilattice_sup_bot α] (s : set α)
    (hs : set.nonempty s) (hdir : directed_on LessEq s) (t : finset α) :
    (∀ (x : α) (H : x ∈ t), ∃ (y : α), ∃ (H : y ∈ s), x ≤ y) → ∃ (x : α), x ∈ s ∧ sup t id ≤ x :=
  sorry

theorem sup_eq_supr {α : Type u_1} {β : Type u_2} [complete_lattice β] (s : finset α) (f : α → β) :
    sup s f = supr fun (a : α) => supr fun (H : a ∈ s) => f a :=
  le_antisymm
    (sup_le fun (a : α) (ha : a ∈ s) => le_supr_of_le a (le_supr (fun (ha : a ∈ s) => f a) ha))
    (supr_le fun (a : α) => supr_le fun (ha : a ∈ s) => le_sup ha)

theorem sup_eq_Sup {α : Type u_1} [complete_lattice α] (s : finset α) : sup s id = Sup ↑s := sorry

/-! ### inf -/

/-- Infimum of a finite set: `inf {a, b, c} f = f a ⊓ f b ⊓ f c` -/
def inf {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] (s : finset β) (f : β → α) : α :=
  fold has_inf.inf ⊤ f s

theorem inf_def {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s : finset β} {f : β → α} :
    inf s f = multiset.inf (multiset.map f (val s)) :=
  rfl

@[simp] theorem inf_empty {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {f : β → α} :
    inf ∅ f = ⊤ :=
  fold_empty

theorem le_inf_iff {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s : finset β} {f : β → α}
    {a : α} : a ≤ inf s f ↔ ∀ (b : β), b ∈ s → a ≤ f b :=
  sup_le_iff

@[simp] theorem inf_insert {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s : finset β}
    {f : β → α} [DecidableEq β] {b : β} : inf (insert b s) f = f b ⊓ inf s f :=
  fold_insert_idem

@[simp] theorem inf_singleton {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {f : β → α}
    {b : β} : inf (singleton b) f = f b :=
  multiset.inf_singleton

theorem inf_union {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s₁ : finset β}
    {s₂ : finset β} {f : β → α} [DecidableEq β] : inf (s₁ ∪ s₂) f = inf s₁ f ⊓ inf s₂ f :=
  sup_union

theorem inf_congr {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s₁ : finset β}
    {s₂ : finset β} {f : β → α} {g : β → α} (hs : s₁ = s₂) (hfg : ∀ (a : β), a ∈ s₂ → f a = g a) :
    inf s₁ f = inf s₂ g :=
  Eq._oldrec (fun (hfg : ∀ (a : β), a ∈ s₁ → f a = g a) => fold_congr hfg) hs hfg

theorem inf_le {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s : finset β} {f : β → α}
    {b : β} (hb : b ∈ s) : inf s f ≤ f b :=
  iff.mp le_inf_iff (le_refl (inf s f)) b hb

theorem le_inf {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s : finset β} {f : β → α}
    {a : α} : (∀ (b : β), b ∈ s → a ≤ f b) → a ≤ inf s f :=
  iff.mpr le_inf_iff

theorem inf_mono_fun {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s : finset β}
    {f : β → α} {g : β → α} (h : ∀ (b : β), b ∈ s → f b ≤ g b) : inf s f ≤ inf s g :=
  le_inf fun (b : β) (hb : b ∈ s) => le_trans (inf_le hb) (h b hb)

theorem inf_mono {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s₁ : finset β}
    {s₂ : finset β} {f : β → α} (h : s₁ ⊆ s₂) : inf s₂ f ≤ inf s₁ f :=
  le_inf fun (b : β) (hb : b ∈ s₁) => inf_le (h hb)

theorem lt_inf_iff {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {s : finset β} {f : β → α}
    [h : is_total α LessEq] {a : α} (ha : a < ⊤) : a < inf s f ↔ ∀ (b : β), b ∈ s → a < f b :=
  sup_lt_iff ha

theorem comp_inf_eq_inf_comp {α : Type u_1} {β : Type u_2} {γ : Type u_3} [semilattice_inf_top α]
    [semilattice_inf_top γ] {s : finset β} {f : β → α} (g : α → γ)
    (g_inf : ∀ (x y : α), g (x ⊓ y) = g x ⊓ g y) (top : g ⊤ = ⊤) : g (inf s f) = inf s (g ∘ f) :=
  comp_sup_eq_sup_comp g g_inf top

theorem comp_inf_eq_inf_comp_of_is_total {α : Type u_1} {β : Type u_2} [semilattice_inf_top α]
    {s : finset β} {f : β → α} [h : is_total α LessEq] {γ : Type} [semilattice_inf_top γ]
    (g : α → γ) (mono_g : monotone g) (top : g ⊤ = ⊤) : g (inf s f) = inf s (g ∘ f) :=
  comp_inf_eq_inf_comp g (monotone.map_inf mono_g) top

/-- Computating `inf` in a subtype (closed under `inf`) is the same as computing it in `α`. -/
theorem inf_coe {α : Type u_1} {β : Type u_2} [semilattice_inf_top α] {P : α → Prop} {Ptop : P ⊤}
    {Pinf : ∀ {x y : α}, P x → P y → P (x ⊓ y)} (t : finset β)
    (f : β → Subtype fun (x : α) => P x) : ↑(inf t f) = inf t fun (x : β) => ↑(f x) :=
  sorry

theorem inf_eq_infi {α : Type u_1} {β : Type u_2} [complete_lattice β] (s : finset α) (f : α → β) :
    inf s f = infi fun (a : α) => infi fun (H : a ∈ s) => f a :=
  sup_eq_supr s f

theorem inf_eq_Inf {α : Type u_1} [complete_lattice α] (s : finset α) : inf s id = Inf ↑s := sorry

/-! ### max and min of finite sets -/

/-- Let `s` be a finset in a linear order. Then `s.max` is the maximum of `s` if `s` is not empty,
and `none` otherwise. It belongs to `option α`. If you want to get an element of `α`, see
`s.max'`. -/
protected def max {α : Type u_1} [linear_order α] : finset α → Option α :=
  fold (option.lift_or_get max) none some

theorem max_eq_sup_with_bot {α : Type u_1} [linear_order α] (s : finset α) :
    finset.max s = sup s some :=
  rfl

@[simp] theorem max_empty {α : Type u_1} [linear_order α] : finset.max ∅ = none := rfl

@[simp] theorem max_insert {α : Type u_1} [linear_order α] {a : α} {s : finset α} :
    finset.max (insert a s) = option.lift_or_get max (some a) (finset.max s) :=
  fold_insert_idem

@[simp] theorem max_singleton {α : Type u_1} [linear_order α] {a : α} :
    finset.max (singleton a) = some a :=
  eq.mpr
    (id (Eq._oldrec (Eq.refl (finset.max (singleton a) = some a)) (Eq.symm (insert_emptyc_eq a))))
    max_insert

theorem max_of_mem {α : Type u_1} [linear_order α] {s : finset α} {a : α} (h : a ∈ s) :
    ∃ (b : α), b ∈ finset.max s :=
  Exists.imp (fun (b : α) => Exists.fst) (le_sup h a rfl)

theorem max_of_nonempty {α : Type u_1} [linear_order α] {s : finset α} (h : finset.nonempty s) :
    ∃ (a : α), a ∈ finset.max s :=
  (fun (_a : finset.nonempty s) =>
      Exists.dcases_on _a
        fun (w : α) (h_1 : w ∈ s) => idRhs (∃ (a : α), a ∈ finset.max s) (max_of_mem h_1))
    h

theorem max_eq_none {α : Type u_1} [linear_order α] {s : finset α} : finset.max s = none ↔ s = ∅ :=
  sorry

theorem mem_of_max {α : Type u_1} [linear_order α] {s : finset α} {a : α} :
    a ∈ finset.max s → a ∈ s :=
  sorry

theorem le_max_of_mem {α : Type u_1} [linear_order α] {s : finset α} {a : α} {b : α} (h₁ : a ∈ s)
    (h₂ : b ∈ finset.max s) : a ≤ b :=
  sorry

/-- Let `s` be a finset in a linear order. Then `s.min` is the minimum of `s` if `s` is not empty,
and `none` otherwise. It belongs to `option α`. If you want to get an element of `α`, see
`s.min'`. -/
protected def min {α : Type u_1} [linear_order α] : finset α → Option α :=
  fold (option.lift_or_get min) none some

theorem min_eq_inf_with_top {α : Type u_1} [linear_order α] (s : finset α) :
    finset.min s = inf s some :=
  rfl

@[simp] theorem min_empty {α : Type u_1} [linear_order α] : finset.min ∅ = none := rfl

@[simp] theorem min_insert {α : Type u_1} [linear_order α] {a : α} {s : finset α} :
    finset.min (insert a s) = option.lift_or_get min (some a) (finset.min s) :=
  fold_insert_idem

@[simp] theorem min_singleton {α : Type u_1} [linear_order α] {a : α} :
    finset.min (singleton a) = some a :=
  eq.mpr
    (id (Eq._oldrec (Eq.refl (finset.min (singleton a) = some a)) (Eq.symm (insert_emptyc_eq a))))
    min_insert

theorem min_of_mem {α : Type u_1} [linear_order α] {s : finset α} {a : α} (h : a ∈ s) :
    ∃ (b : α), b ∈ finset.min s :=
  Exists.imp (fun (b : α) => Exists.fst) (inf_le h a rfl)

theorem min_of_nonempty {α : Type u_1} [linear_order α] {s : finset α} (h : finset.nonempty s) :
    ∃ (a : α), a ∈ finset.min s :=
  (fun (_a : finset.nonempty s) =>
      Exists.dcases_on _a
        fun (w : α) (h_1 : w ∈ s) => idRhs (∃ (a : α), a ∈ finset.min s) (min_of_mem h_1))
    h

theorem min_eq_none {α : Type u_1} [linear_order α] {s : finset α} : finset.min s = none ↔ s = ∅ :=
  sorry

theorem mem_of_min {α : Type u_1} [linear_order α] {s : finset α} {a : α} :
    a ∈ finset.min s → a ∈ s :=
  sorry

theorem min_le_of_mem {α : Type u_1} [linear_order α] {s : finset α} {a : α} {b : α} (h₁ : b ∈ s)
    (h₂ : a ∈ finset.min s) : a ≤ b :=
  sorry

/-- Given a nonempty finset `s` in a linear order `α `, then `s.min' h` is its minimum, as an
element of `α`, where `h` is a proof of nonemptiness. Without this assumption, use instead `s.min`,
taking values in `option α`. -/
def min' {α : Type u_1} [linear_order α] (s : finset α) (H : finset.nonempty s) : α :=
  option.get sorry

/-- Given a nonempty finset `s` in a linear order `α `, then `s.max' h` is its maximum, as an
element of `α`, where `h` is a proof of nonemptiness. Without this assumption, use instead `s.max`,
taking values in `option α`. -/
def max' {α : Type u_1} [linear_order α] (s : finset α) (H : finset.nonempty s) : α :=
  option.get sorry

theorem min'_mem {α : Type u_1} [linear_order α] (s : finset α) (H : finset.nonempty s) :
    min' s H ∈ s :=
  sorry

theorem min'_le {α : Type u_1} [linear_order α] (s : finset α) (x : α) (H2 : x ∈ s) :
    min' s (Exists.intro x H2) ≤ x :=
  min_le_of_mem H2 (option.get_mem (min'._match_2 s (Exists.intro x H2)))

theorem le_min' {α : Type u_1} [linear_order α] (s : finset α) (H : finset.nonempty s) (x : α)
    (H2 : ∀ (y : α), y ∈ s → x ≤ y) : x ≤ min' s H :=
  H2 (min' s H) (min'_mem s H)

/-- `{a}.min' _` is `a`. -/
@[simp] theorem min'_singleton {α : Type u_1} [linear_order α] (a : α) :
    min' (singleton a) (singleton_nonempty a) = a :=
  sorry

theorem max'_mem {α : Type u_1} [linear_order α] (s : finset α) (H : finset.nonempty s) :
    max' s H ∈ s :=
  sorry

theorem le_max' {α : Type u_1} [linear_order α] (s : finset α) (x : α) (H2 : x ∈ s) :
    x ≤ max' s (Exists.intro x H2) :=
  le_max_of_mem H2 (option.get_mem (max'._match_2 s (Exists.intro x H2)))

theorem max'_le {α : Type u_1} [linear_order α] (s : finset α) (H : finset.nonempty s) (x : α)
    (H2 : ∀ (y : α), y ∈ s → y ≤ x) : max' s H ≤ x :=
  H2 (max' s H) (max'_mem s H)

/-- `{a}.max' _` is `a`. -/
@[simp] theorem max'_singleton {α : Type u_1} [linear_order α] (a : α) :
    max' (singleton a) (singleton_nonempty a) = a :=
  sorry

theorem min'_lt_max' {α : Type u_1} [linear_order α] (s : finset α) {i : α} {j : α} (H1 : i ∈ s)
    (H2 : j ∈ s) (H3 : i ≠ j) : min' s (Exists.intro i H1) < max' s (Exists.intro i H1) :=
  sorry

/--
If there's more than 1 element, the min' is less than the max'. An alternate version of
`min'_lt_max'` which is sometimes more convenient.
-/
theorem min'_lt_max'_of_card {α : Type u_1} [linear_order α] (s : finset α) (h₂ : 1 < card s) :
    min' s (iff.mp card_pos (lt_trans zero_lt_one h₂)) <
        max' s (iff.mp card_pos (lt_trans zero_lt_one h₂)) :=
  sorry

theorem max'_eq_of_dual_min' {α : Type u_1} [linear_order α] {s : finset α}
    (hs : finset.nonempty s) :
    max' s hs =
        coe_fn order_dual.of_dual
          (min' (image (⇑order_dual.to_dual) s) (nonempty.image hs ⇑order_dual.to_dual)) :=
  sorry

theorem min'_eq_of_dual_max' {α : Type u_1} [linear_order α] {s : finset α}
    (hs : finset.nonempty s) :
    min' s hs =
        coe_fn order_dual.of_dual
          (max' (image (⇑order_dual.to_dual) s) (nonempty.image hs ⇑order_dual.to_dual)) :=
  sorry

@[simp] theorem of_dual_max_eq_min_of_dual {α : Type u_1} [linear_order α] {a : α} {b : α} :
    coe_fn order_dual.of_dual (max a b) =
        min (coe_fn order_dual.of_dual a) (coe_fn order_dual.of_dual b) :=
  rfl

@[simp] theorem of_dual_min_eq_max_of_dual {α : Type u_1} [linear_order α] {a : α} {b : α} :
    coe_fn order_dual.of_dual (min a b) =
        max (coe_fn order_dual.of_dual a) (coe_fn order_dual.of_dual b) :=
  rfl

theorem exists_max_image {α : Type u_1} {β : Type u_2} [linear_order α] (s : finset β) (f : β → α)
    (h : finset.nonempty s) : ∃ (x : β), ∃ (H : x ∈ s), ∀ (x' : β), x' ∈ s → f x' ≤ f x :=
  sorry

theorem exists_min_image {α : Type u_1} {β : Type u_2} [linear_order α] (s : finset β) (f : β → α)
    (h : finset.nonempty s) : ∃ (x : β), ∃ (H : x ∈ s), ∀ (x' : β), x' ∈ s → f x ≤ f x' :=
  exists_max_image s f h

end finset

namespace multiset

theorem count_sup {α : Type u_1} {β : Type u_2} [DecidableEq β] (s : finset α) (f : α → multiset β)
    (b : β) : count b (finset.sup s f) = finset.sup s fun (a : α) => count b (f a) :=
  sorry

theorem mem_sup {α : Type u_1} {β : Type u_2} [DecidableEq β] {s : finset α} {f : α → multiset β}
    {x : β} : x ∈ finset.sup s f ↔ ∃ (v : α), ∃ (H : v ∈ s), x ∈ f v :=
  sorry

end multiset

namespace finset

theorem mem_sup {α : Type u_1} {β : Type u_2} [DecidableEq β] {s : finset α} {f : α → finset β}
    {x : β} : x ∈ sup s f ↔ ∃ (v : α), ∃ (H : v ∈ s), x ∈ f v :=
  sorry

theorem sup_eq_bUnion {α : Type u_1} {β : Type u_2} [DecidableEq β] (s : finset α)
    (t : α → finset β) : sup s t = finset.bUnion s t :=
  sorry

end finset

/-- Supremum of `s i`, `i : ι`, is equal to the supremum over `t : finset ι` of suprema
`⨆ i ∈ t, s i`. This version assumes `ι` is a `Type*`. See `supr_eq_supr_finset'` for a version
that works for `ι : Sort*`. -/
theorem supr_eq_supr_finset {α : Type u_1} {ι : Type u_4} [complete_lattice α] (s : ι → α) :
    (supr fun (i : ι) => s i) =
        supr fun (t : finset ι) => supr fun (i : ι) => supr fun (H : i ∈ t) => s i :=
  sorry

/-- Supremum of `s i`, `i : ι`, is equal to the supremum over `t : finset ι` of suprema
`⨆ i ∈ t, s i`. This version works for `ι : Sort*`. See `supr_eq_supr_finset` for a version
that assumes `ι : Type*` but has no `plift`s. -/
theorem supr_eq_supr_finset' {α : Type u_1} {ι' : Sort u_5} [complete_lattice α] (s : ι' → α) :
    (supr fun (i : ι') => s i) =
        supr
          fun (t : finset (plift ι')) =>
            supr fun (i : plift ι') => supr fun (H : i ∈ t) => s (plift.down i) :=
  sorry

/-- Infimum of `s i`, `i : ι`, is equal to the infimum over `t : finset ι` of infima
`⨆ i ∈ t, s i`. This version assumes `ι` is a `Type*`. See `infi_eq_infi_finset'` for a version
that works for `ι : Sort*`. -/
theorem infi_eq_infi_finset {α : Type u_1} {ι : Type u_4} [complete_lattice α] (s : ι → α) :
    (infi fun (i : ι) => s i) =
        infi fun (t : finset ι) => infi fun (i : ι) => infi fun (H : i ∈ t) => s i :=
  supr_eq_supr_finset fun (i : ι) => s i

/-- Infimum of `s i`, `i : ι`, is equal to the infimum over `t : finset ι` of infima
`⨆ i ∈ t, s i`. This version works for `ι : Sort*`. See `infi_eq_infi_finset` for a version
that assumes `ι : Type*` but has no `plift`s. -/
theorem infi_eq_infi_finset' {α : Type u_1} {ι' : Sort u_5} [complete_lattice α] (s : ι' → α) :
    (infi fun (i : ι') => s i) =
        infi
          fun (t : finset (plift ι')) =>
            infi fun (i : plift ι') => infi fun (H : i ∈ t) => s (plift.down i) :=
  supr_eq_supr_finset' fun (i : ι') => s i

namespace set

/-- Union of an indexed family of sets `s : ι → set α` is equal to the union of the unions
of finite subfamilies. This version assumes `ι : Type*`. See also `Union_eq_Union_finset'` for
a version that works for `ι : Sort*`. -/
theorem Union_eq_Union_finset {α : Type u_1} {ι : Type u_4} (s : ι → set α) :
    (Union fun (i : ι) => s i) =
        Union fun (t : finset ι) => Union fun (i : ι) => Union fun (H : i ∈ t) => s i :=
  supr_eq_supr_finset s

/-- Union of an indexed family of sets `s : ι → set α` is equal to the union of the unions
of finite subfamilies. This version works for `ι : Sort*`. See also `Union_eq_Union_finset` for
a version that assumes `ι : Type*` but avoids `plift`s in the right hand side. -/
theorem Union_eq_Union_finset' {α : Type u_1} {ι' : Sort u_5} (s : ι' → set α) :
    (Union fun (i : ι') => s i) =
        Union
          fun (t : finset (plift ι')) =>
            Union fun (i : plift ι') => Union fun (H : i ∈ t) => s (plift.down i) :=
  supr_eq_supr_finset' s

/-- Intersection of an indexed family of sets `s : ι → set α` is equal to the intersection of the
intersections of finite subfamilies. This version assumes `ι : Type*`. See also
`Inter_eq_Inter_finset'` for a version that works for `ι : Sort*`. -/
theorem Inter_eq_Inter_finset {α : Type u_1} {ι : Type u_4} (s : ι → set α) :
    (Inter fun (i : ι) => s i) =
        Inter fun (t : finset ι) => Inter fun (i : ι) => Inter fun (H : i ∈ t) => s i :=
  infi_eq_infi_finset s

/-- Intersection of an indexed family of sets `s : ι → set α` is equal to the intersection of the
intersections of finite subfamilies. This version works for `ι : Sort*`. See also
`Inter_eq_Inter_finset` for a version that assumes `ι : Type*` but avoids `plift`s in the right
hand side. -/
theorem Inter_eq_Inter_finset' {α : Type u_1} {ι' : Sort u_5} (s : ι' → set α) :
    (Inter fun (i : ι') => s i) =
        Inter
          fun (t : finset (plift ι')) =>
            Inter fun (i : plift ι') => Inter fun (H : i ∈ t) => s (plift.down i) :=
  infi_eq_infi_finset' s

end set

namespace finset

/-! ### Interaction with big lattice/set operations -/

theorem supr_coe {α : Type u_1} {β : Type u_2} [has_Sup β] (f : α → β) (s : finset α) :
    (supr fun (x : α) => supr fun (H : x ∈ ↑s) => f x) =
        supr fun (x : α) => supr fun (H : x ∈ s) => f x :=
  rfl

theorem infi_coe {α : Type u_1} {β : Type u_2} [has_Inf β] (f : α → β) (s : finset α) :
    (infi fun (x : α) => infi fun (H : x ∈ ↑s) => f x) =
        infi fun (x : α) => infi fun (H : x ∈ s) => f x :=
  rfl

theorem supr_singleton {α : Type u_1} {β : Type u_2} [complete_lattice β] (a : α) (s : α → β) :
    (supr fun (x : α) => supr fun (H : x ∈ singleton a) => s x) = s a :=
  sorry

theorem infi_singleton {α : Type u_1} {β : Type u_2} [complete_lattice β] (a : α) (s : α → β) :
    (infi fun (x : α) => infi fun (H : x ∈ singleton a) => s x) = s a :=
  sorry

theorem supr_option_to_finset {α : Type u_1} {β : Type u_2} [complete_lattice β] (o : Option α)
    (f : α → β) :
    (supr fun (x : α) => supr fun (H : x ∈ option.to_finset o) => f x) =
        supr fun (x : α) => supr fun (H : x ∈ o) => f x :=
  sorry

theorem infi_option_to_finset {α : Type u_1} {β : Type u_2} [complete_lattice β] (o : Option α)
    (f : α → β) :
    (infi fun (x : α) => infi fun (H : x ∈ option.to_finset o) => f x) =
        infi fun (x : α) => infi fun (H : x ∈ o) => f x :=
  supr_option_to_finset o fun (x : α) => f x

theorem supr_union {α : Type u_1} {β : Type u_2} [complete_lattice β] [DecidableEq α] {f : α → β}
    {s : finset α} {t : finset α} :
    (supr fun (x : α) => supr fun (H : x ∈ s ∪ t) => f x) =
        (supr fun (x : α) => supr fun (H : x ∈ s) => f x) ⊔
          supr fun (x : α) => supr fun (H : x ∈ t) => f x :=
  sorry

theorem infi_union {α : Type u_1} {β : Type u_2} [complete_lattice β] [DecidableEq α] {f : α → β}
    {s : finset α} {t : finset α} :
    (infi fun (x : α) => infi fun (H : x ∈ s ∪ t) => f x) =
        (infi fun (x : α) => infi fun (H : x ∈ s) => f x) ⊓
          infi fun (x : α) => infi fun (H : x ∈ t) => f x :=
  sorry

theorem supr_insert {α : Type u_1} {β : Type u_2} [complete_lattice β] [DecidableEq α] (a : α)
    (s : finset α) (t : α → β) :
    (supr fun (x : α) => supr fun (H : x ∈ insert a s) => t x) =
        t a ⊔ supr fun (x : α) => supr fun (H : x ∈ s) => t x :=
  sorry

theorem infi_insert {α : Type u_1} {β : Type u_2} [complete_lattice β] [DecidableEq α] (a : α)
    (s : finset α) (t : α → β) :
    (infi fun (x : α) => infi fun (H : x ∈ insert a s) => t x) =
        t a ⊓ infi fun (x : α) => infi fun (H : x ∈ s) => t x :=
  sorry

theorem supr_finset_image {α : Type u_1} {β : Type u_2} {γ : Type u_3} [complete_lattice β]
    [DecidableEq α] {f : γ → α} {g : α → β} {s : finset γ} :
    (supr fun (x : α) => supr fun (H : x ∈ image f s) => g x) =
        supr fun (y : γ) => supr fun (H : y ∈ s) => g (f y) :=
  sorry

theorem sup_finset_image {α : Type u_1} {β : Type u_2} {γ : Type u_3} [complete_lattice β]
    [DecidableEq α] {f : γ → α} {g : α → β} {s : finset γ} : sup s (g ∘ f) = sup (image f s) g :=
  sorry

theorem infi_finset_image {α : Type u_1} {β : Type u_2} {γ : Type u_3} [complete_lattice β]
    [DecidableEq α] {f : γ → α} {g : α → β} {s : finset γ} :
    (infi fun (x : α) => infi fun (H : x ∈ image f s) => g x) =
        infi fun (y : γ) => infi fun (H : y ∈ s) => g (f y) :=
  sorry

theorem supr_insert_update {α : Type u_1} {β : Type u_2} [complete_lattice β] [DecidableEq α]
    {x : α} {t : finset α} (f : α → β) {s : β} (hx : ¬x ∈ t) :
    (supr fun (i : α) => supr fun (H : i ∈ insert x t) => function.update f x s i) =
        s ⊔ supr fun (i : α) => supr fun (H : i ∈ t) => f i :=
  sorry

theorem infi_insert_update {α : Type u_1} {β : Type u_2} [complete_lattice β] [DecidableEq α]
    {x : α} {t : finset α} (f : α → β) {s : β} (hx : ¬x ∈ t) :
    (infi fun (i : α) => infi fun (H : i ∈ insert x t) => function.update f x s i) =
        s ⊓ infi fun (i : α) => infi fun (H : i ∈ t) => f i :=
  supr_insert_update f hx

theorem supr_bUnion {α : Type u_1} {β : Type u_2} {γ : Type u_3} [complete_lattice β]
    [DecidableEq α] (s : finset γ) (t : γ → finset α) (f : α → β) :
    (supr fun (y : α) => supr fun (H : y ∈ finset.bUnion s t) => f y) =
        supr
          fun (x : γ) =>
            supr fun (H : x ∈ s) => supr fun (y : α) => supr fun (H : y ∈ t x) => f y :=
  sorry

theorem infi_bUnion {α : Type u_1} {β : Type u_2} {γ : Type u_3} [complete_lattice β]
    [DecidableEq α] (s : finset γ) (t : γ → finset α) (f : α → β) :
    (infi fun (y : α) => infi fun (H : y ∈ finset.bUnion s t) => f y) =
        infi
          fun (x : γ) =>
            infi fun (H : x ∈ s) => infi fun (y : α) => infi fun (H : y ∈ t x) => f y :=
  supr_bUnion s t fun (y : α) => f y

@[simp] theorem set_bUnion_coe {α : Type u_1} {β : Type u_2} (s : finset α) (t : α → set β) :
    (set.Union fun (x : α) => set.Union fun (H : x ∈ ↑s) => t x) =
        set.Union fun (x : α) => set.Union fun (H : x ∈ s) => t x :=
  rfl

@[simp] theorem set_bInter_coe {α : Type u_1} {β : Type u_2} (s : finset α) (t : α → set β) :
    (set.Inter fun (x : α) => set.Inter fun (H : x ∈ ↑s) => t x) =
        set.Inter fun (x : α) => set.Inter fun (H : x ∈ s) => t x :=
  rfl

@[simp] theorem set_bUnion_singleton {α : Type u_1} {β : Type u_2} (a : α) (s : α → set β) :
    (set.Union fun (x : α) => set.Union fun (H : x ∈ singleton a) => s x) = s a :=
  supr_singleton a s

@[simp] theorem set_bInter_singleton {α : Type u_1} {β : Type u_2} (a : α) (s : α → set β) :
    (set.Inter fun (x : α) => set.Inter fun (H : x ∈ singleton a) => s x) = s a :=
  infi_singleton a s

@[simp] theorem set_bUnion_preimage_singleton {α : Type u_1} {β : Type u_2} (f : α → β)
    (s : finset β) :
    (set.Union fun (y : β) => set.Union fun (H : y ∈ s) => f ⁻¹' singleton y) = f ⁻¹' ↑s :=
  set.bUnion_preimage_singleton f ↑s

@[simp] theorem set_bUnion_option_to_finset {α : Type u_1} {β : Type u_2} (o : Option α)
    (f : α → set β) :
    (set.Union fun (x : α) => set.Union fun (H : x ∈ option.to_finset o) => f x) =
        set.Union fun (x : α) => set.Union fun (H : x ∈ o) => f x :=
  supr_option_to_finset o f

@[simp] theorem set_bInter_option_to_finset {α : Type u_1} {β : Type u_2} (o : Option α)
    (f : α → set β) :
    (set.Inter fun (x : α) => set.Inter fun (H : x ∈ option.to_finset o) => f x) =
        set.Inter fun (x : α) => set.Inter fun (H : x ∈ o) => f x :=
  infi_option_to_finset o f

theorem set_bUnion_union {α : Type u_1} {β : Type u_2} [DecidableEq α] (s : finset α) (t : finset α)
    (u : α → set β) :
    (set.Union fun (x : α) => set.Union fun (H : x ∈ s ∪ t) => u x) =
        (set.Union fun (x : α) => set.Union fun (H : x ∈ s) => u x) ∪
          set.Union fun (x : α) => set.Union fun (H : x ∈ t) => u x :=
  supr_union

theorem set_bInter_inter {α : Type u_1} {β : Type u_2} [DecidableEq α] (s : finset α) (t : finset α)
    (u : α → set β) :
    (set.Inter fun (x : α) => set.Inter fun (H : x ∈ s ∪ t) => u x) =
        (set.Inter fun (x : α) => set.Inter fun (H : x ∈ s) => u x) ∩
          set.Inter fun (x : α) => set.Inter fun (H : x ∈ t) => u x :=
  infi_union

@[simp] theorem set_bUnion_insert {α : Type u_1} {β : Type u_2} [DecidableEq α] (a : α)
    (s : finset α) (t : α → set β) :
    (set.Union fun (x : α) => set.Union fun (H : x ∈ insert a s) => t x) =
        t a ∪ set.Union fun (x : α) => set.Union fun (H : x ∈ s) => t x :=
  supr_insert a s t

@[simp] theorem set_bInter_insert {α : Type u_1} {β : Type u_2} [DecidableEq α] (a : α)
    (s : finset α) (t : α → set β) :
    (set.Inter fun (x : α) => set.Inter fun (H : x ∈ insert a s) => t x) =
        t a ∩ set.Inter fun (x : α) => set.Inter fun (H : x ∈ s) => t x :=
  infi_insert a s t

@[simp] theorem set_bUnion_finset_image {α : Type u_1} {β : Type u_2} {γ : Type u_3} [DecidableEq α]
    {f : γ → α} {g : α → set β} {s : finset γ} :
    (set.Union fun (x : α) => set.Union fun (H : x ∈ image f s) => g x) =
        set.Union fun (y : γ) => set.Union fun (H : y ∈ s) => g (f y) :=
  supr_finset_image

@[simp] theorem set_bInter_finset_image {α : Type u_1} {β : Type u_2} {γ : Type u_3} [DecidableEq α]
    {f : γ → α} {g : α → set β} {s : finset γ} :
    (set.Inter fun (x : α) => set.Inter fun (H : x ∈ image f s) => g x) =
        set.Inter fun (y : γ) => set.Inter fun (H : y ∈ s) => g (f y) :=
  infi_finset_image

theorem set_bUnion_insert_update {α : Type u_1} {β : Type u_2} [DecidableEq α] {x : α}
    {t : finset α} (f : α → set β) {s : set β} (hx : ¬x ∈ t) :
    (set.Union fun (i : α) => set.Union fun (H : i ∈ insert x t) => function.update f x s i) =
        s ∪ set.Union fun (i : α) => set.Union fun (H : i ∈ t) => f i :=
  supr_insert_update f hx

theorem set_bInter_insert_update {α : Type u_1} {β : Type u_2} [DecidableEq α] {x : α}
    {t : finset α} (f : α → set β) {s : set β} (hx : ¬x ∈ t) :
    (set.Inter fun (i : α) => set.Inter fun (H : i ∈ insert x t) => function.update f x s i) =
        s ∩ set.Inter fun (i : α) => set.Inter fun (H : i ∈ t) => f i :=
  infi_insert_update f hx

@[simp] theorem set_bUnion_bUnion {α : Type u_1} {β : Type u_2} {γ : Type u_3} [DecidableEq α]
    (s : finset γ) (t : γ → finset α) (f : α → set β) :
    (set.Union fun (y : α) => set.Union fun (H : y ∈ finset.bUnion s t) => f y) =
        set.Union
          fun (x : γ) =>
            set.Union
              fun (H : x ∈ s) => set.Union fun (y : α) => set.Union fun (H : y ∈ t x) => f y :=
  supr_bUnion s t f

@[simp] theorem set_bInter_bUnion {α : Type u_1} {β : Type u_2} {γ : Type u_3} [DecidableEq α]
    (s : finset γ) (t : γ → finset α) (f : α → set β) :
    (set.Inter fun (y : α) => set.Inter fun (H : y ∈ finset.bUnion s t) => f y) =
        set.Inter
          fun (x : γ) =>
            set.Inter
              fun (H : x ∈ s) => set.Inter fun (y : α) => set.Inter fun (H : y ∈ t x) => f y :=
  infi_bUnion s t f

end Mathlib