Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retract of weak equivalences is a weak equivalence #1

Open
wants to merge 4 commits into
base: top-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 64 additions & 3 deletions src/category_theory/model/category.lean
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,75 @@ structure is_model_category (W C F : morphism_class M) : Prop :=
-- TODO: Show that it follows that W is closed under retracts. See
-- https://ncatlab.org/nlab/show/model+category#ClosureOfMorphisms

lemma is_model_category.weq_of_weq_retract_fib { W C F : morphism_class M } ( h : is_model_category W C F )
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be more natural to state this as a "theorem about model categories", rather than a "theorem about classes of maps that form a model category structure", and maybe in a separate file like category_theory.model.lemmas. Something like:

lemma weq_of_weq_retract_fib {M : Type u} [model_category.{v} M] {a b a' b'} ...

Currently there aren't any examples of this here because I didn't actually prove any theorems about model categories! But there are a bunch in the lean-homotopy-theory project, e.g. in https://github.com/rwbarton/lean-homotopy-theory/tree/lean-3.4.2/src/homotopy_theory/formal/cofibrations.

There might be some rough edges in the way the model_category class is set up given that it's not currently used as a hypothesis anywhere.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I have a question about this. Trying to rephrase this to use model_category.{v} M rather than is_model_category W C F (and omitting \MCM from the context) I end up with

lemma weq_of_weq_retract_fib [ h : model_category.{v} M ]
 {a b a' b': M} {f : a ⟶ b} {f' : a' ⟶ b'} (r : retract f f') (hf : h.W f) (hf': h.F f') : h.W f'

but h.W and h.F produce the following error:

"invalid field notation, function 'category_theory.model_category.W' does not have explicit argument with type (category_theory.model_category ...)".

I don't understand this - if I #check h.W, it's a morphism class on M like I expect.

{a b a' b'} {f : a ⟶ b} {f' : a' ⟶ b'} (r : retract f f') (hf : W f) (hf': F f') : W f' := begin
rcases h.acf.fact f with ⟨ c, α, β, WCα, Fβ, f_fact ⟩,
rw h.acf.llp at WCα,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you undo this rw later, maybe it's more natural to just use h.acf.lp WCα hf' ... on the next line instead.
(General principle: try to use lemmas (like is_wfs.lp) rather than unfolding definitions. In this library, though, the supporting lemmas that ought to be there might not exist because I only proved what I needed to construct model structures.)

choose l hl using WCα hf' r.ra (β ≫ r.rb) (by { rw [← category.assoc, f_fact], exact r.hr }),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

choose is kind of overkill here. The usual purpose of choose is to take a hypothesis of a form like ∀ (x₁ x₂ : X), ∃ (y : Y), P x₁ x₂ y and produce a choice function f : X → X → Y, which needs the axiom of choice.
Here the hypothesis WCα hf' ... already has the form ∃ l, P l with zero s before it, and the overall goal W f' is a proposition. So, you could just extract a witness using rcases. In modern mathlib, it's nicer to use obtain because it puts the new variables at the start, like have or let. choose also has this advantage, so I suppose it's fine to use it here too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could have sworn I tried rcases first, but it does work. I've never encountered obtain, I'll look it up

have rβf' : retract β f' := {
ia := (r.ia) ≫ α,
ra := l,
ib := r.ib,
rb := r.rb,
ha := by { simp, rw hl.1, exact r.ha },
hb := r.hb,
hi := by { rw [category.assoc, f_fact], exact r.hi },
hr := hl.2,
},
rw ← h.acf.llp at WCα,
rw ← f_fact at hf,
exact (is_wfs.retract_right h.caf rβf' ⟨ Fβ, h.weq.weq_cancel_left WCα.2 hf ⟩).2
end

#check @Is_pushout.uniqueness
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be left over.


lemma is_model_category.weq_of_weq_retract { W C F : morphism_class M } [ @has_pushouts M 𝓜] ( h : is_model_category W C F )
{a b a' b'} {f : a ⟶ b} {f' : a' ⟶ b'} (r : retract f f') (hf : W f) : W f' := begin
rcases h.acf.fact f' with ⟨ c, α, β, WCα, Fβ, f'_fact ⟩,
cases has_pushouts.pushout α r.ia with z γ δ po,
have WCδ : (C ∩ W) δ := by { rw h.acf.llp, rw h.acf.llp at WCα, exact llp_pushout F po WCα },
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can abbreviate the start of this proof to rw h.acf.llp at ⊢ WCo ( is \|-).

have uq := @Is_pushout.uniqueness M 𝓜 a' c a z α r.ia γ δ po,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't actually appear to be necessary: it worked fine if I replaced the single use of uq below by po.uniqueness.

have rεβ : retract (po.induced (β ≫ r.ib) f (by { rw [← category.assoc, f'_fact], exact r.hi.symm})) β := {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would probably name this map po.induced ... with a let for clarity, even though you never actually need to refer to it later.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah great - I was trying to do this with have rather than let, but have appears to only remember the type, not the definition

ia := γ,
ra := po.induced (𝟙 c) (r.ra ≫ α) (by { rw [category.comp_id, ← category.assoc, r.ha, category.id_comp] }),
ib := r.ib,
rb := r.rb,
ha := by simp,
hb := r.hb,
hi := by simp,
hr := by {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a style thing, we normally only use by for things that fit on one line--for longer blocks begin/end is clearer (it's easier to distinguish from other meanings of {}).

refine uq _ _,
rw [← category.assoc,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good habit to use { } whenever there are multiple goals, unless you want to treat multiple goals at once with something like all_goals. Even when you're going to kill each goal with a single tactic anyways, it makes the structure of the proof more apparent to the reader.

Is_pushout.induced_commutes₀ po _ _ _,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since po : Is_pushout ..., you can abbreviate this to po.induced_commutes₀.

← category.assoc,
Is_pushout.induced_commutes₀ po _ _ _,
category.assoc,
category.id_comp,
r.hb,
category.comp_id],
rw [← category.assoc,
Is_pushout.induced_commutes₁ po _ _ _,
← category.assoc,
Is_pushout.induced_commutes₁ po _ _ _,
category.assoc,
f'_fact,
r.hr],
}
},
rw ← f'_fact,
apply h.weq.weq_comp a' c b' α β WCα.2,
refine is_model_category.weq_of_weq_retract_fib h rεβ _ Fβ,
apply h.weq.weq_cancel_left WCδ.2,
rw Is_pushout.induced_commutes₁ po _ _ _,
assumption,
end

omit 𝓜
class model_category (M : Type u) extends category.{v} M :=
(complete : has_limits M)
(cocomplete : has_colimits M)
(W C F : morphism_class M)
(h : is_model_category W C F)

variables {M}
include 𝓜

/-- We can skip checking the condition C ∩ W ⊆ AC. Compare Hirschhorn, Theorem 11.3.1. -/
Expand Down Expand Up @@ -63,7 +124,7 @@ begin
have : retract g f,
{ refine ⟨𝟙 a, 𝟙 a, l, h, _, _, _, _⟩,
all_goals { tidy } },
exact acf.retract this g_ac
exact acf.retract_left this g_ac
end

def model_category.mk' [has_limits M] [has_colimits M] {W C AF AC F : morphism_class M}
Expand Down
16 changes: 15 additions & 1 deletion src/category_theory/model/wfs.lean
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import category_theory.morphism_class_closure
import category_theory.retract
import category_theory.colimits
import category_theory.transfinite.composition
import category_theory.opposites
import logic.crec

universes v u
Expand Down Expand Up @@ -30,14 +31,15 @@ structure is_wfs (L R : morphism_class M) : Prop :=
(fact : ∀ {x y} (f : x ⟶ y), ∃ z (g : x ⟶ z) (h : z ⟶ y),
L g ∧ R h ∧ g ≫ h = f)


lemma is_wfs.lp {L R : morphism_class M} (w : is_wfs L R)
{a b x y} {f : a ⟶ b} {g : x ⟶ y} (hf : L f) (hg : R g) : lp f g :=
begin
rw w.llp at hf,
exact hf hg
end

lemma is_wfs.retract {L R : morphism_class M} (w : is_wfs L R)
lemma is_wfs.retract_left {L R : morphism_class M} (w : is_wfs L R)
{a b a' b'} {f : a ⟶ b} {f' : a' ⟶ b'} (r : retract f f') (hf : L f) : L f' :=
begin
rw w.llp,
Expand All @@ -47,6 +49,18 @@ begin
refine ⟨r.ib ≫ l, _, _⟩,
{ rw [←category.assoc, ←r.hi, category.assoc, hl₁, ←category.assoc, r.ha, category.id_comp] },
{ rw [category.assoc, hl₂, ←category.assoc, r.hb, category.id_comp] }
end

lemma is_wfs.retract_right {L R :morphism_class M } (w : is_wfs L R)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up copying the proof of the previous lemma for this. I first tried to prove it by applying the previous lemma to the opposite category, but I quickly got bogged down.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It was probably made more difficult by the way that the opposite category was implemented at the time. We later found that it was very easy to get confused about whether we were considering objects and morphisms in a category or in its opposite. Nowadays we have a design in which you need to apply specific functions to convert between a category and its opposite, which helps keep things straight.

Ideally we will some day have a method to automatically dualize theorems, but this doesn't exist yet.

{a b a' b'} {f : a ⟶ b} {f' : a' ⟶ b'} (r : retract f f') (hf : R f) : R f' :=
begin
rw w.rlp,
intros x y g hg h k s,
rcases w.lp hg hf (h ≫ r.ia) (k ≫ r.ib)
(by rw [← category.assoc, ←s, category.assoc, category.assoc, r.hi]) with ⟨l, hl₁, hl₂⟩,
refine ⟨l ≫ r.ra, _, _⟩,
{ rw [←category.assoc, hl₁, category.assoc, r.ha, category.comp_id] },
{ rw [category.assoc, r.hr, ←category.assoc, hl₂, category.assoc, r.hb, category.comp_id] }
end

lemma llp_rlp_self (L : morphism_class M) : L ⊆ llp (rlp L) :=
Expand Down
3 changes: 3 additions & 0 deletions src/category_theory/morphism_class.lean
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import category_theory.category
import category_theory.isomorphism
import category_theory.eq_to_hom
import category_theory.opposites

universes v v' u u'

Expand All @@ -16,6 +17,8 @@ instance : has_inter (morphism_class C) := ⟨λ I J X Y f, I f ∧ J f⟩

instance : has_subset (morphism_class C) := ⟨λ I J, ∀ ⦃X Y⦄ ⦃f : X ⟶ Y⦄, I f → J f⟩

def morphism_class.op (I : morphism_class C) : morphism_class Cᵒᵖ := λ Y X f, I f

def morphism_class.univ : morphism_class C := λ X Y f, true

def morphism_class.isos : morphism_class C := λ X Y f, nonempty (is_iso f)
Expand Down