l3lab/ntp-mathlib huggingface dataset:
theorem lift_iInf [Nonempty ι] {f : ι → Filter α} {g : Set α → Filter β}
    (hg : ∀ s t, g (s ∩ t) = g s ⊓ g t) : (iInf f).lift g = ⨅ i, (f i).lift g := by
  refine' lift_iInf_le.antisymm fun s => _
  have H : ∀ t ∈ iInf f, ⨅ i, (f i).lift g ≤ g t := by
    intro t ht
    refine' iInf_sets_induct ht _ fun hs ht => _
    · inhabit ι
      exact iInf₂_le_of_le default univ (iInf_le _ univ_mem)
    · rw [hg]
      exact le_inf (iInf₂_le_of_le _ _ <| iInf_le _ hs) ht
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
g✝ g₁ g₂ : Set α → Filter β
inst✝ : Nonempty ι
f : ι → Filter α
g : Set α → Filter β
hg : ∀ (s t : Set α), g (s ∩ t) = g s ⊓ g t
s : Set β
H : ∀ t ∈ iInf f, ⨅ i, Filter.lift (f i) g ≤ g t
⊢ s ∈ Filter.lift (iInf f) g → s ∈ ⨅ i, Filter.lift (f i) g

Next tactic:
simp only [mem_lift_sets (Monotone.of_map_inf hg), exists_imp, and_imp]
theorem lift_iInf [Nonempty ι] {f : ι → Filter α} {g : Set α → Filter β}
    (hg : ∀ s t, g (s ∩ t) = g s ⊓ g t) : (iInf f).lift g = ⨅ i, (f i).lift g := by
  refine' lift_iInf_le.antisymm fun s => _
  have H : ∀ t ∈ iInf f, ⨅ i, (f i).lift g ≤ g t := by
    intro t ht
    refine' iInf_sets_induct ht _ fun hs ht => _
    · inhabit ι
      exact iInf₂_le_of_le default univ (iInf_le _ univ_mem)
    · rw [hg]
      exact le_inf (iInf₂_le_of_le _ _ <| iInf_le _ hs) ht
  simp only [mem_lift_sets (Monotone.of_map_inf hg), exists_imp, and_imp]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
g✝ g₁ g₂ : Set α → Filter β
inst✝ : Nonempty ι
f : ι → Filter α
g : Set α → Filter β
hg : ∀ (s t : Set α), g (s ∩ t) = g s ⊓ g t
s : Set β
H : ∀ t ∈ iInf f, ⨅ i, Filter.lift (f i) g ≤ g t
⊢ ∀ x ∈ iInf f, s ∈ g x → s ∈ ⨅ i, Filter.lift (f i) g

Next tactic:
exact fun t ht hs => H t ht hs
theorem lift_iInf_of_directed [Nonempty ι] {f : ι → Filter α} {g : Set α → Filter β}
    (hf : Directed (· ≥ ·) f) (hg : Monotone g) : (iInf f).lift g = ⨅ i, (f i).lift g :=
  lift_iInf_le.antisymm fun s => by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
g✝ g₁ g₂ : Set α → Filter β
inst✝ : Nonempty ι
f : ι → Filter α
g : Set α → Filter β
hf : Directed (fun x x_1 => x ≥ x_1) f
hg : Monotone g
s : Set β
⊢ s ∈ Filter.lift (iInf f) g → s ∈ ⨅ i, Filter.lift (f i) g

Next tactic:
simp only [mem_lift_sets hg, exists_imp, and_imp, mem_iInf_of_directed hf]
theorem lift_iInf_of_directed [Nonempty ι] {f : ι → Filter α} {g : Set α → Filter β}
    (hf : Directed (· ≥ ·) f) (hg : Monotone g) : (iInf f).lift g = ⨅ i, (f i).lift g :=
  lift_iInf_le.antisymm fun s => by
    simp only [mem_lift_sets hg, exists_imp, and_imp, mem_iInf_of_directed hf]
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
g✝ g₁ g₂ : Set α → Filter β
inst✝ : Nonempty ι
f : ι → Filter α
g : Set α → Filter β
hf : Directed (fun x x_1 => x ≥ x_1) f
hg : Monotone g
s : Set β
⊢ ∀ (x : Set α) (x_1 : ι), x ∈ f x_1 → s ∈ g x → s ∈ ⨅ i, Filter.lift (f i) g

Next tactic:
exact fun t i ht hs => mem_iInf_of_mem i <| mem_lift ht hs
theorem lift_iInf_of_map_univ {f : ι → Filter α} {g : Set α → Filter β}
    (hg : ∀ s t, g (s ∩ t) = g s ⊓ g t) (hg' : g univ = ⊤) :
    (iInf f).lift g = ⨅ i, (f i).lift g := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
g✝ g₁ g₂ : Set α → Filter β
f : ι → Filter α
g : Set α → Filter β
hg : ∀ (s t : Set α), g (s ∩ t) = g s ⊓ g t
hg' : g univ = ⊤
⊢ Filter.lift (iInf f) g = ⨅ i, Filter.lift (f i) g

Next tactic:
cases isEmpty_or_nonempty ι
theorem lift_iInf_of_map_univ {f : ι → Filter α} {g : Set α → Filter β}
    (hg : ∀ s t, g (s ∩ t) = g s ⊓ g t) (hg' : g univ = ⊤) :
    (iInf f).lift g = ⨅ i, (f i).lift g := by
  cases isEmpty_or_nonempty ι
  · 

Proof state:
case inl
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
g✝ g₁ g₂ : Set α → Filter β
f : ι → Filter α
g : Set α → Filter β
hg : ∀ (s t : Set α), g (s ∩ t) = g s ⊓ g t
hg' : g univ = ⊤
h✝ : IsEmpty ι
⊢ Filter.lift (iInf f) g = ⨅ i, Filter.lift (f i) g

Next tactic:
simp [iInf_of_empty, hg']
theorem lift_iInf_of_map_univ {f : ι → Filter α} {g : Set α → Filter β}
    (hg : ∀ s t, g (s ∩ t) = g s ⊓ g t) (hg' : g univ = ⊤) :
    (iInf f).lift g = ⨅ i, (f i).lift g := by
  cases isEmpty_or_nonempty ι
  · simp [iInf_of_empty, hg']
  · 

Proof state:
case inr
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
g✝ g₁ g₂ : Set α → Filter β
f : ι → Filter α
g : Set α → Filter β
hg : ∀ (s t : Set α), g (s ∩ t) = g s ⊓ g t
hg' : g univ = ⊤
h✝ : Nonempty ι
⊢ Filter.lift (iInf f) g = ⨅ i, Filter.lift (f i) g

Next tactic:
exact lift_iInf hg
theorem tendsto_lift' {m : γ → β} {l : Filter γ} :
    Tendsto m l (f.lift' h) ↔ ∀ s ∈ f, ∀ᶠ a in l, m a ∈ h s := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
m : γ → β
l : Filter γ
⊢ Tendsto m l (Filter.lift' f h) ↔ ∀ s ∈ f, ∀ᶠ (a : γ) in l, m a ∈ h s

Next tactic:
simp only [Filter.lift', tendsto_lift, tendsto_principal, comp]
theorem HasBasis.lift' {ι} {p : ι → Prop} {s} (hf : f.HasBasis p s) (hh : Monotone h) :
    (f.lift' h).HasBasis p (h ∘ s) :=
  ⟨fun t => (hf.mem_lift_iff (fun i => hasBasis_principal (h (s i)))
    (monotone_principal.comp hh)).trans <| by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι✝ : Sort u_4
f f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
ι : Sort u_5
p : ι → Prop
s : ι → Set α
hf : HasBasis f p s
hh : Monotone h
t : Set β
⊢ (∃ i, p i ∧ ∃ x, True ∧ h (s i) ⊆ t) ↔ ∃ i, p i ∧ (h ∘ s) i ⊆ t

Next tactic:
simp only [exists_const, true_and, comp]
theorem map_lift'_eq {m : β → γ} (hh : Monotone h) : map m (f.lift' h) = f.lift' (image m ∘ h) :=
  calc
    map m (f.lift' h) = f.lift (map m ∘ 𝓟 ∘ h) := map_lift_eq <| monotone_principal.comp hh
    _ = f.lift' (image m ∘ h) := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
m : β → γ
hh : Monotone h
⊢ Filter.lift f (map m ∘ 𝓟 ∘ h) = Filter.lift' f (image m ∘ h)

Next tactic:
simp only [comp, Filter.lift', map_principal]
theorem comap_lift'_eq {m : γ → β} : comap m (f.lift' h) = f.lift' (preimage m ∘ h) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
m : γ → β
⊢ comap m (Filter.lift' f h) = Filter.lift' f (preimage m ∘ h)

Next tactic:
simp only [Filter.lift', comap_lift_eq, (· ∘ ·), comap_principal]
theorem lift'_pure {a : α} (hh : Monotone h) : (pure a : Filter α).lift' h = 𝓟 (h {a}) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
a : α
hh : Monotone h
⊢ Filter.lift' (pure a) h = 𝓟 (h {a})

Next tactic:
rw [← principal_singleton, lift'_principal hh]
theorem lift'_bot (hh : Monotone h) : (⊥ : Filter α).lift' h = 𝓟 (h ∅) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
hh : Monotone h
⊢ Filter.lift' ⊥ h = 𝓟 (h ∅)

Next tactic:
rw [← principal_empty, lift'_principal hh]
theorem lift_lift'_assoc {g : Set α → Set β} {h : Set β → Filter γ} (hg : Monotone g)
    (hh : Monotone h) : (f.lift' g).lift h = f.lift fun s => h (g s) :=
  calc
    (f.lift' g).lift h = f.lift fun s => (𝓟 (g s)).lift h := lift_assoc (monotone_principal.comp hg)
    _ = f.lift fun s => h (g s) := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f f₁ f₂ : Filter α
h✝ h₁ h₂ g : Set α → Set β
h : Set β → Filter γ
hg : Monotone g
hh : Monotone h
⊢ (Filter.lift f fun s => Filter.lift (𝓟 (g s)) h) = Filter.lift f fun s => h (g s)

Next tactic:
simp only [lift_principal, hh, eq_self_iff_true]
theorem lift'_inf_principal_eq {h : Set α → Set β} {s : Set β} :
    f.lift' h ⊓ 𝓟 s = f.lift' fun t => h t ∩ s := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f f₁ f₂ : Filter α
h✝ h₁ h₂ h : Set α → Set β
s : Set β
⊢ Filter.lift' f h ⊓ 𝓟 s = Filter.lift' f fun t => h t ∩ s

Next tactic:
simp only [Filter.lift', Filter.lift, (· ∘ ·), ← inf_principal, iInf_subtype', ← iInf_inf]
theorem lift'_neBot_iff (hh : Monotone h) : NeBot (f.lift' h) ↔ ∀ s ∈ f, (h s).Nonempty :=
  calc
    NeBot (f.lift' h) ↔ ∀ s ∈ f, NeBot (𝓟 (h s)) := lift_neBot_iff (monotone_principal.comp hh)
    _ ↔ ∀ s ∈ f, (h s).Nonempty := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
hh : Monotone h
⊢ (∀ s ∈ f, NeBot (𝓟 (h s))) ↔ ∀ s ∈ f, Set.Nonempty (h s)

Next tactic:
simp only [principal_neBot_iff]
theorem lift'_iInf [Nonempty ι] {f : ι → Filter α} {g : Set α → Set β}
    (hg : ∀ s t, g (s ∩ t) = g s ∩ g t) : (iInf f).lift' g = ⨅ i, (f i).lift' g :=
  lift_iInf fun s t => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
inst✝ : Nonempty ι
f : ι → Filter α
g : Set α → Set β
hg : ∀ (s t : Set α), g (s ∩ t) = g s ∩ g t
s t : Set α
⊢ (𝓟 ∘ g) (s ∩ t) = (𝓟 ∘ g) s ⊓ (𝓟 ∘ g) t

Next tactic:
simp only [inf_principal, comp, hg]
theorem lift'_iInf_of_map_univ {f : ι → Filter α} {g : Set α → Set β}
    (hg : ∀ {s t}, g (s ∩ t) = g s ∩ g t) (hg' : g univ = univ) :
    (iInf f).lift' g = ⨅ i, (f i).lift' g :=
  lift_iInf_of_map_univ (fun s t => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
f : ι → Filter α
g : Set α → Set β
hg : ∀ {s t : Set α}, g (s ∩ t) = g s ∩ g t
hg' : g univ = univ
s t : Set α
⊢ (𝓟 ∘ g) (s ∩ t) = (𝓟 ∘ g) s ⊓ (𝓟 ∘ g) t

Next tactic:
simp only [inf_principal, comp, hg]
theorem lift'_iInf_of_map_univ {f : ι → Filter α} {g : Set α → Set β}
    (hg : ∀ {s t}, g (s ∩ t) = g s ∩ g t) (hg' : g univ = univ) :
    (iInf f).lift' g = ⨅ i, (f i).lift' g :=
  lift_iInf_of_map_univ (fun s t => by simp only [inf_principal, comp, hg])
    (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
f : ι → Filter α
g : Set α → Set β
hg : ∀ {s t : Set α}, g (s ∩ t) = g s ∩ g t
hg' : g univ = univ
⊢ (𝓟 ∘ g) univ = ⊤

Next tactic:
rw [Function.comp_apply, hg', principal_univ]
theorem lift'_inf (f g : Filter α) {s : Set α → Set β} (hs : ∀ t₁ t₂, s (t₁ ∩ t₂) = s t₁ ∩ s t₂) :
    (f ⊓ g).lift' s = f.lift' s ⊓ g.lift' s := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
f g : Filter α
s : Set α → Set β
hs : ∀ (t₁ t₂ : Set α), s (t₁ ∩ t₂) = s t₁ ∩ s t₂
⊢ Filter.lift' (f ⊓ g) s = Filter.lift' f s ⊓ Filter.lift' g s

Next tactic:
rw [inf_eq_iInf, inf_eq_iInf, lift'_iInf hs]
theorem lift'_inf (f g : Filter α) {s : Set α → Set β} (hs : ∀ t₁ t₂, s (t₁ ∩ t₂) = s t₁ ∩ s t₂) :
    (f ⊓ g).lift' s = f.lift' s ⊓ g.lift' s := by
  rw [inf_eq_iInf, inf_eq_iInf, lift'_iInf hs]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
f g : Filter α
s : Set α → Set β
hs : ∀ (t₁ t₂ : Set α), s (t₁ ∩ t₂) = s t₁ ∩ s t₂
⊢ ⨅ i, Filter.lift' (bif i then f else g) s = ⨅ b, bif b then Filter.lift' f s else Filter.lift' g s

Next tactic:
refine iInf_congr ?_
theorem lift'_inf (f g : Filter α) {s : Set α → Set β} (hs : ∀ t₁ t₂, s (t₁ ∩ t₂) = s t₁ ∩ s t₂) :
    (f ⊓ g).lift' s = f.lift' s ⊓ g.lift' s := by
  rw [inf_eq_iInf, inf_eq_iInf, lift'_iInf hs]
  refine iInf_congr ?_
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
f g : Filter α
s : Set α → Set β
hs : ∀ (t₁ t₂ : Set α), s (t₁ ∩ t₂) = s t₁ ∩ s t₂
⊢ ∀ (i : Bool), Filter.lift' (bif i then f else g) s = bif i then Filter.lift' f s else Filter.lift' g s

Next tactic:
rintro (_|_)
theorem lift'_inf (f g : Filter α) {s : Set α → Set β} (hs : ∀ t₁ t₂, s (t₁ ∩ t₂) = s t₁ ∩ s t₂) :
    (f ⊓ g).lift' s = f.lift' s ⊓ g.lift' s := by
  rw [inf_eq_iInf, inf_eq_iInf, lift'_iInf hs]
  refine iInf_congr ?_
  rintro (_|_) <;> 

Proof state:
case false
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
f g : Filter α
s : Set α → Set β
hs : ∀ (t₁ t₂ : Set α), s (t₁ ∩ t₂) = s t₁ ∩ s t₂
⊢ Filter.lift' (bif false then f else g) s = bif false then Filter.lift' f s else Filter.lift' g s

Next tactic:
rfl
theorem lift'_inf (f g : Filter α) {s : Set α → Set β} (hs : ∀ t₁ t₂, s (t₁ ∩ t₂) = s t₁ ∩ s t₂) :
    (f ⊓ g).lift' s = f.lift' s ⊓ g.lift' s := by
  rw [inf_eq_iInf, inf_eq_iInf, lift'_iInf hs]
  refine iInf_congr ?_
  rintro (_|_) <;> 

Proof state:
case true
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f₁ f₂ : Filter α
h h₁ h₂ : Set α → Set β
f g : Filter α
s : Set α → Set β
hs : ∀ (t₁ t₂ : Set α), s (t₁ ∩ t₂) = s t₁ ∩ s t₂
⊢ Filter.lift' (bif true then f else g) s = bif true then Filter.lift' f s else Filter.lift' g s

Next tactic:
rfl
theorem prod_def {f : Filter α} {g : Filter β} :
    f ×ˢ g = f.lift fun s => g.lift' fun t => s ×ˢ t := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ f : Filter α
g : Filter β
⊢ f ×ˢ g = Filter.lift f fun s => Filter.lift' g fun t => s ×ˢ t

Next tactic:
simpa only [Filter.lift', Filter.lift, (f.basis_sets.prod g.basis_sets).eq_biInf,
    iInf_prod, iInf_and] using iInf_congr fun i => iInf_comm
theorem tendsto_prod_self_iff {f : α × α → β} {x : Filter α} {y : Filter β} :
    Filter.Tendsto f (x ×ˢ x) y ↔ ∀ W ∈ y, ∃ U ∈ x, ∀ x x' : α, x ∈ U → x' ∈ U → f (x, x') ∈ W := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f✝ : Filter α
f : α × α → β
x : Filter α
y : Filter β
⊢ Tendsto f (x ×ˢ x) y ↔ ∀ W ∈ y, ∃ U ∈ x, ∀ (x x' : α), x ∈ U → x' ∈ U → f (x, x') ∈ W

Next tactic:
simp only [tendsto_def, mem_prod_same_iff, prod_sub_preimage_iff, exists_prop, iff_self_iff]
theorem prod_lift_lift {f₁ : Filter α₁} {f₂ : Filter α₂} {g₁ : Set α₁ → Filter β₁}
    {g₂ : Set α₂ → Filter β₂} (hg₁ : Monotone g₁) (hg₂ : Monotone g₂) :
    f₁.lift g₁ ×ˢ f₂.lift g₂ = f₁.lift fun s => f₂.lift fun t => g₁ s ×ˢ g₂ t := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f : Filter α
α₁ : Type u_5
α₂ : Type u_6
β₁ : Type u_7
β₂ : Type u_8
f₁ : Filter α₁
f₂ : Filter α₂
g₁ : Set α₁ → Filter β₁
g₂ : Set α₂ → Filter β₂
hg₁ : Monotone g₁
hg₂ : Monotone g₂
⊢ Filter.lift f₁ g₁ ×ˢ Filter.lift f₂ g₂ = Filter.lift f₁ fun s => Filter.lift f₂ fun t => g₁ s ×ˢ g₂ t

Next tactic:
simp only [prod_def, lift_assoc hg₁]
theorem prod_lift_lift {f₁ : Filter α₁} {f₂ : Filter α₂} {g₁ : Set α₁ → Filter β₁}
    {g₂ : Set α₂ → Filter β₂} (hg₁ : Monotone g₁) (hg₂ : Monotone g₂) :
    f₁.lift g₁ ×ˢ f₂.lift g₂ = f₁.lift fun s => f₂.lift fun t => g₁ s ×ˢ g₂ t := by
  simp only [prod_def, lift_assoc hg₁]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f : Filter α
α₁ : Type u_5
α₂ : Type u_6
β₁ : Type u_7
β₂ : Type u_8
f₁ : Filter α₁
f₂ : Filter α₂
g₁ : Set α₁ → Filter β₁
g₂ : Set α₂ → Filter β₂
hg₁ : Monotone g₁
hg₂ : Monotone g₂
⊢ (Filter.lift f₁ fun s => Filter.lift (g₁ s) fun s => Filter.lift' (Filter.lift f₂ g₂) fun t => s ×ˢ t) =
    Filter.lift f₁ fun s => Filter.lift f₂ fun t => Filter.lift (g₁ s) fun s => Filter.lift' (g₂ t) fun t => s ×ˢ t

Next tactic:
apply congr_arg
theorem prod_lift_lift {f₁ : Filter α₁} {f₂ : Filter α₂} {g₁ : Set α₁ → Filter β₁}
    {g₂ : Set α₂ → Filter β₂} (hg₁ : Monotone g₁) (hg₂ : Monotone g₂) :
    f₁.lift g₁ ×ˢ f₂.lift g₂ = f₁.lift fun s => f₂.lift fun t => g₁ s ×ˢ g₂ t := by
  simp only [prod_def, lift_assoc hg₁]
  apply congr_arg; 

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f : Filter α
α₁ : Type u_5
α₂ : Type u_6
β₁ : Type u_7
β₂ : Type u_8
f₁ : Filter α₁
f₂ : Filter α₂
g₁ : Set α₁ → Filter β₁
g₂ : Set α₂ → Filter β₂
hg₁ : Monotone g₁
hg₂ : Monotone g₂
⊢ (fun s => Filter.lift (g₁ s) fun s => Filter.lift' (Filter.lift f₂ g₂) fun t => s ×ˢ t) = fun s =>
    Filter.lift f₂ fun t => Filter.lift (g₁ s) fun s => Filter.lift' (g₂ t) fun t => s ×ˢ t

Next tactic:
funext x
theorem prod_lift_lift {f₁ : Filter α₁} {f₂ : Filter α₂} {g₁ : Set α₁ → Filter β₁}
    {g₂ : Set α₂ → Filter β₂} (hg₁ : Monotone g₁) (hg₂ : Monotone g₂) :
    f₁.lift g₁ ×ˢ f₂.lift g₂ = f₁.lift fun s => f₂.lift fun t => g₁ s ×ˢ g₂ t := by
  simp only [prod_def, lift_assoc hg₁]
  apply congr_arg; funext x
  

Proof state:
case h.h
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f : Filter α
α₁ : Type u_5
α₂ : Type u_6
β₁ : Type u_7
β₂ : Type u_8
f₁ : Filter α₁
f₂ : Filter α₂
g₁ : Set α₁ → Filter β₁
g₂ : Set α₂ → Filter β₂
hg₁ : Monotone g₁
hg₂ : Monotone g₂
x : Set α₁
⊢ (Filter.lift (g₁ x) fun s => Filter.lift' (Filter.lift f₂ g₂) fun t => s ×ˢ t) =
    Filter.lift f₂ fun t => Filter.lift (g₁ x) fun s => Filter.lift' (g₂ t) fun t => s ×ˢ t

Next tactic:
rw [lift_comm]
theorem prod_lift_lift {f₁ : Filter α₁} {f₂ : Filter α₂} {g₁ : Set α₁ → Filter β₁}
    {g₂ : Set α₂ → Filter β₂} (hg₁ : Monotone g₁) (hg₂ : Monotone g₂) :
    f₁.lift g₁ ×ˢ f₂.lift g₂ = f₁.lift fun s => f₂.lift fun t => g₁ s ×ˢ g₂ t := by
  simp only [prod_def, lift_assoc hg₁]
  apply congr_arg; funext x
  rw [lift_comm]
  

Proof state:
case h.h
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f : Filter α
α₁ : Type u_5
α₂ : Type u_6
β₁ : Type u_7
β₂ : Type u_8
f₁ : Filter α₁
f₂ : Filter α₂
g₁ : Set α₁ → Filter β₁
g₂ : Set α₂ → Filter β₂
hg₁ : Monotone g₁
hg₂ : Monotone g₂
x : Set α₁
⊢ (Filter.lift (g₁ x) fun s => Filter.lift' (Filter.lift f₂ g₂) fun t => s ×ˢ t) =
    Filter.lift (g₁ x) fun t => Filter.lift f₂ fun s => Filter.lift' (g₂ s) fun t_1 => t ×ˢ t_1

Next tactic:
apply congr_arg
theorem prod_lift_lift {f₁ : Filter α₁} {f₂ : Filter α₂} {g₁ : Set α₁ → Filter β₁}
    {g₂ : Set α₂ → Filter β₂} (hg₁ : Monotone g₁) (hg₂ : Monotone g₂) :
    f₁.lift g₁ ×ˢ f₂.lift g₂ = f₁.lift fun s => f₂.lift fun t => g₁ s ×ˢ g₂ t := by
  simp only [prod_def, lift_assoc hg₁]
  apply congr_arg; funext x
  rw [lift_comm]
  apply congr_arg; 

Proof state:
case h.h.h
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f : Filter α
α₁ : Type u_5
α₂ : Type u_6
β₁ : Type u_7
β₂ : Type u_8
f₁ : Filter α₁
f₂ : Filter α₂
g₁ : Set α₁ → Filter β₁
g₂ : Set α₂ → Filter β₂
hg₁ : Monotone g₁
hg₂ : Monotone g₂
x : Set α₁
⊢ (fun s => Filter.lift' (Filter.lift f₂ g₂) fun t => s ×ˢ t) = fun t =>
    Filter.lift f₂ fun s => Filter.lift' (g₂ s) fun t_1 => t ×ˢ t_1

Next tactic:
funext y
theorem prod_lift_lift {f₁ : Filter α₁} {f₂ : Filter α₂} {g₁ : Set α₁ → Filter β₁}
    {g₂ : Set α₂ → Filter β₂} (hg₁ : Monotone g₁) (hg₂ : Monotone g₂) :
    f₁.lift g₁ ×ˢ f₂.lift g₂ = f₁.lift fun s => f₂.lift fun t => g₁ s ×ˢ g₂ t := by
  simp only [prod_def, lift_assoc hg₁]
  apply congr_arg; funext x
  rw [lift_comm]
  apply congr_arg; funext y
  

Proof state:
case h.h.h.h
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f : Filter α
α₁ : Type u_5
α₂ : Type u_6
β₁ : Type u_7
β₂ : Type u_8
f₁ : Filter α₁
f₂ : Filter α₂
g₁ : Set α₁ → Filter β₁
g₂ : Set α₂ → Filter β₂
hg₁ : Monotone g₁
hg₂ : Monotone g₂
x : Set α₁
y : Set β₁
⊢ (Filter.lift' (Filter.lift f₂ g₂) fun t => y ×ˢ t) = Filter.lift f₂ fun s => Filter.lift' (g₂ s) fun t => y ×ˢ t

Next tactic:
apply lift'_lift_assoc hg₂
theorem prod_lift'_lift' {f₁ : Filter α₁} {f₂ : Filter α₂} {g₁ : Set α₁ → Set β₁}
    {g₂ : Set α₂ → Set β₂} (hg₁ : Monotone g₁) (hg₂ : Monotone g₂) :
    f₁.lift' g₁ ×ˢ f₂.lift' g₂ = f₁.lift fun s => f₂.lift' fun t => g₁ s ×ˢ g₂ t :=
  calc
    f₁.lift' g₁ ×ˢ f₂.lift' g₂ = f₁.lift fun s => f₂.lift fun t => 𝓟 (g₁ s) ×ˢ 𝓟 (g₂ t) :=
      prod_lift_lift (monotone_principal.comp hg₁) (monotone_principal.comp hg₂)
    _ = f₁.lift fun s => f₂.lift fun t => 𝓟 (g₁ s ×ˢ g₂ t) := by
      

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f : Filter α
α₁ : Type u_5
α₂ : Type u_6
β₁ : Type u_7
β₂ : Type u_8
f₁ : Filter α₁
f₂ : Filter α₂
g₁ : Set α₁ → Set β₁
g₂ : Set α₂ → Set β₂
hg₁ : Monotone g₁
hg₂ : Monotone g₂
⊢ (Filter.lift f₁ fun s => Filter.lift f₂ fun t => 𝓟 (g₁ s) ×ˢ 𝓟 (g₂ t)) =
    Filter.lift f₁ fun s => Filter.lift f₂ fun t => 𝓟 (g₁ s ×ˢ g₂ t)

Next tactic:
{ simp only [prod_principal_principal] }
theorem prod_lift'_lift' {f₁ : Filter α₁} {f₂ : Filter α₂} {g₁ : Set α₁ → Set β₁}
    {g₂ : Set α₂ → Set β₂} (hg₁ : Monotone g₁) (hg₂ : Monotone g₂) :
    f₁.lift' g₁ ×ˢ f₂.lift' g₂ = f₁.lift fun s => f₂.lift' fun t => g₁ s ×ˢ g₂ t :=
  calc
    f₁.lift' g₁ ×ˢ f₂.lift' g₂ = f₁.lift fun s => f₂.lift fun t => 𝓟 (g₁ s) ×ˢ 𝓟 (g₂ t) :=
      prod_lift_lift (monotone_principal.comp hg₁) (monotone_principal.comp hg₂)
    _ = f₁.lift fun s => f₂.lift fun t => 𝓟 (g₁ s ×ˢ g₂ t) := by
      { 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Sort u_4
f : Filter α
α₁ : Type u_5
α₂ : Type u_6
β₁ : Type u_7
β₂ : Type u_8
f₁ : Filter α₁
f₂ : Filter α₂
g₁ : Set α₁ → Set β₁
g₂ : Set α₂ → Set β₂
hg₁ : Monotone g₁
hg₂ : Monotone g₂
⊢ (Filter.lift f₁ fun s => Filter.lift f₂ fun t => 𝓟 (g₁ s) ×ˢ 𝓟 (g₂ t)) =
    Filter.lift f₁ fun s => Filter.lift f₂ fun t => 𝓟 (g₁ s ×ˢ g₂ t)

Next tactic:
simp only [prod_principal_principal]
theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
  

Proof state:
m n✝ a✝ b✝ c d : ℤ
a b n : ℕ
⊢ ↑a ≡ ↑b [ZMOD ↑n] ↔ a ≡ b [MOD n]

Next tactic:
unfold ModEq Nat.ModEq
theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
  unfold ModEq Nat.ModEq; 

Proof state:
m n✝ a✝ b✝ c d : ℤ
a b n : ℕ
⊢ ↑a % ↑n = ↑b % ↑n ↔ a % n = b % n

Next tactic:
rw [← Int.ofNat_inj]
theorem coe_nat_modEq_iff {a b n : ℕ} : a ≡ b [ZMOD n] ↔ a ≡ b [MOD n] := by
  unfold ModEq Nat.ModEq; rw [← Int.ofNat_inj]; 

Proof state:
m n✝ a✝ b✝ c d : ℤ
a b n : ℕ
⊢ ↑a % ↑n = ↑b % ↑n ↔ ↑(a % n) = ↑(b % n)

Next tactic:
simp [coe_nat_mod]
theorem modEq_zero_iff_dvd : a ≡ 0 [ZMOD n] ↔ n ∣ a := by
  

Proof state:
m n a b c d : ℤ
⊢ a ≡ 0 [ZMOD n] ↔ n ∣ a

Next tactic:
rw [ModEq, zero_emod, dvd_iff_emod_eq_zero]
theorem modEq_iff_dvd : a ≡ b [ZMOD n] ↔ n ∣ b - a := by
  

Proof state:
m n a b c d : ℤ
⊢ a ≡ b [ZMOD n] ↔ n ∣ b - a

Next tactic:
rw [ModEq, eq_comm]
theorem modEq_iff_dvd : a ≡ b [ZMOD n] ↔ n ∣ b - a := by
  rw [ModEq, eq_comm]
  

Proof state:
m n a b c d : ℤ
⊢ b % n = a % n ↔ n ∣ b - a

Next tactic:
simp [emod_eq_emod_iff_emod_sub_eq_zero, dvd_iff_emod_eq_zero]
theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n * t := by
  

Proof state:
m n✝ a✝ b✝ c d a b n : ℤ
⊢ a ≡ b [ZMOD n] ↔ ∃ t, b = a + n * t

Next tactic:
rw [modEq_iff_dvd]
theorem modEq_iff_add_fac {a b n : ℤ} : a ≡ b [ZMOD n] ↔ ∃ t, b = a + n * t := by
  rw [modEq_iff_dvd]
  

Proof state:
m n✝ a✝ b✝ c d a b n : ℤ
⊢ n ∣ b - a ↔ ∃ t, b = a + n * t

Next tactic:
exact exists_congr fun t => sub_eq_iff_eq_add'
@[simp]
theorem neg_modEq_neg : -a ≡ -b [ZMOD n] ↔ a ≡ b [ZMOD n] := by
--porting note: Restore old proof once #3309 is through
  

Proof state:
m n a b c d : ℤ
⊢ -a ≡ -b [ZMOD n] ↔ a ≡ b [ZMOD n]

Next tactic:
simp [-sub_neg_eq_add, neg_sub_neg, modEq_iff_dvd, dvd_sub_comm]
@[simp]
theorem modEq_neg : a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n] := by 

Proof state:
m n a b c d : ℤ
⊢ a ≡ b [ZMOD -n] ↔ a ≡ b [ZMOD n]

Next tactic:
simp [modEq_iff_dvd]
protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] := by
  

Proof state:
m n a b c d : ℤ
h : a ≡ b [ZMOD n]
⊢ c * a ≡ c * b [ZMOD c * n]

Next tactic:
obtain hc | rfl | hc := lt_trichotomy c 0
protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] := by
  obtain hc | rfl | hc := lt_trichotomy c 0
  · 

Proof state:
case inl
m n a b c d : ℤ
h : a ≡ b [ZMOD n]
hc : c < 0
⊢ c * a ≡ c * b [ZMOD c * n]

Next tactic:
rw [← neg_modEq_neg, ← modEq_neg, ← neg_mul, ← neg_mul, ← neg_mul]
protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] := by
  obtain hc | rfl | hc := lt_trichotomy c 0
  · rw [← neg_modEq_neg, ← modEq_neg, ← neg_mul, ← neg_mul, ← neg_mul]
    

Proof state:
case inl
m n a b c d : ℤ
h : a ≡ b [ZMOD n]
hc : c < 0
⊢ -c * a ≡ -c * b [ZMOD -c * n]

Next tactic:
simp only [ModEq, mul_emod_mul_of_pos _ _ (neg_pos.2 hc), h.eq]
protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] := by
  obtain hc | rfl | hc := lt_trichotomy c 0
  · rw [← neg_modEq_neg, ← modEq_neg, ← neg_mul, ← neg_mul, ← neg_mul]
    simp only [ModEq, mul_emod_mul_of_pos _ _ (neg_pos.2 hc), h.eq]
  · 

Proof state:
case inr.inl
m n a b d : ℤ
h : a ≡ b [ZMOD n]
⊢ 0 * a ≡ 0 * b [ZMOD 0 * n]

Next tactic:
simp only [zero_mul, ModEq.rfl]