File: Mathlib/GroupTheory/FreeGroup/NielsenSchreier.lean

full_name: IsFreeGroupoid.Generators
code: /-- `IsFreeGroupoid.Generators G` is a type synonym for `G`. We think of this as
the vertices of the generating quiver of `G` when `G` is free. We can't use `G` directly,
since `G` already has a quiver instance from being a groupoid. -/
-- Porting note(#5171): @[nolint has_nonempty_instance]
@[nolint unusedArguments]
def IsFreeGroupoid.Generators (G) [Groupoid G] 
goal: Type u_1

full_name: IsFreeGroupoid.of
code: /-- A groupoid `G` is free when we have the following data:
 - a quiver on `IsFreeGroupoid.Generators G` (a type synonym for `G`)
 - a function `of` taking a generating arrow to a morphism in `G`
 - such that a functor from `G` to any group `X` is uniquely determined
   by assigning labels in `X` to the generating arrows.

   This definition is nonstandard. Normally one would require that functors `G ⥤ X`
   to any _groupoid_ `X` are given by graph homomorphisms from `generators`. -/
class IsFreeGroupoid (G) [Groupoid.{v} G] where
  quiverGenerators : Quiver.{v + 1} (IsFreeGroupoid.Generators G)
  of : ∀ {a b : IsFreeGroupoid.Generators G}, (a ⟶ b) → ((show G from a) ⟶ b)
  unique_lift :
    ∀ {X : Type v} [Group X] (f : Labelling (IsFreeGroupoid.Generators G) X),
      ∃! F : G ⥤ CategoryTheory.SingleObj X, ∀ (a b) (g : a ⟶ b), F.map (of g) = f g
goal: (a ⟶ b) →
  ((let_fun this := a;
    this) ⟶
    b)

full_name: IsFreeGroupoid.unique_lift
code: /-- A groupoid `G` is free when we have the following data:
 - a quiver on `IsFreeGroupoid.Generators G` (a type synonym for `G`)
 - a function `of` taking a generating arrow to a morphism in `G`
 - such that a functor from `G` to any group `X` is uniquely determined
   by assigning labels in `X` to the generating arrows.

   This definition is nonstandard. Normally one would require that functors `G ⥤ X`
   to any _groupoid_ `X` are given by graph homomorphisms from `generators`. -/
class IsFreeGroupoid (G) [Groupoid.{v} G] where
  quiverGenerators : Quiver.{v + 1} (IsFreeGroupoid.Generators G)
  of : ∀ {a b : IsFreeGroupoid.Generators G}, (a ⟶ b) → ((show G from a) ⟶ b)
  unique_lift :
    ∀ {X : Type v} [Group X] (f : Labelling (IsFreeGroupoid.Generators G) X),
      ∃! F : G ⥤ CategoryTheory.SingleObj X, ∀ (a b) (g : a ⟶ b), F.map (of g) = f g
goal: ∃! F, ∀ (a b : IsFreeGroupoid.Generators G) (g : a ⟶ b), F.map (IsFreeGroupoid.of g) = f g

full_name: IsFreeGroupoid.quiverGenerators
code: /-- A groupoid `G` is free when we have the following data:
 - a quiver on `IsFreeGroupoid.Generators G` (a type synonym for `G`)
 - a function `of` taking a generating arrow to a morphism in `G`
 - such that a functor from `G` to any group `X` is uniquely determined
   by assigning labels in `X` to the generating arrows.

   This definition is nonstandard. Normally one would require that functors `G ⥤ X`
   to any _groupoid_ `X` are given by graph homomorphisms from `generators`. -/
class IsFreeGroupoid (G) [Groupoid.{v} G] where
  quiverGenerators : Quiver.{v + 1} (IsFreeGroupoid.Generators G)
  of : ∀ {a b : IsFreeGroupoid.Generators G}, (a ⟶ b) → ((show G from a) ⟶ b)
  unique_lift :
    ∀ {X : Type v} [Group X] (f : Labelling (IsFreeGroupoid.Generators G) X),
      ∃! F : G ⥤ CategoryTheory.SingleObj X, ∀ (a b) (g : a ⟶ b), F.map (of g) = f g
goal: Quiver (IsFreeGroupoid.Generators G)

full_name: IsFreeGroupoid
code: /-- A groupoid `G` is free when we have the following data:
 - a quiver on `IsFreeGroupoid.Generators G` (a type synonym for `G`)
 - a function `of` taking a generating arrow to a morphism in `G`
 - such that a functor from `G` to any group `X` is uniquely determined
   by assigning labels in `X` to the generating arrows.

   This definition is nonstandard. Normally one would require that functors `G ⥤ X`
   to any _groupoid_ `X` are given by graph homomorphisms from `generators`. -/
class IsFreeGroupoid (G) [Groupoid.{v} G] where
  quiverGenerators : Quiver.{v + 1} (IsFreeGroupoid.Generators G)
  of : ∀ {a b : IsFreeGroupoid.Generators G}, (a ⟶ b) → ((show G from a) ⟶ b)
  unique_lift :
    ∀ {X : Type v} [Group X] (f : Labelling (IsFreeGroupoid.Generators G) X),
      ∃! F : G ⥤ CategoryTheory.SingleObj X, ∀ (a b) (g : a ⟶ b), F.map (of g) = f g
goal: Type (max u_1 (v + 1))

full_name: IsFreeGroupoid.ext_functor
code: /-- Two functors from a free groupoid to a group are equal when they agree on the generating
quiver. -/
@[ext]
theorem ext_functor {G} [Groupoid.{v} G] [IsFreeGroupoid G] {X : Type v} [Group X]
    (f g : G ⥤ CategoryTheory.SingleObj X) (h : ∀ (a b) (e : a ⟶ b), f.map (of e) = g.map (of e)) :
    f = g 
goal: f = g

full_name: IsFreeGroupoid.actionGroupoidIsFree
code: /-- An action groupoid over a free group is free. More generally, one could show that the groupoid
of elements over a free groupoid is free, but this version is easier to prove and suffices for our
purposes.

Analogous to the fact that a covering space of a graph is a graph. (A free groupoid is like a graph,
and a groupoid of elements is like a covering space.) -/
instance actionGroupoidIsFree {G A : Type u} [Group G] [IsFreeGroup G] [MulAction G A] :
    IsFreeGroupoid (ActionCategory G A) 
goal: IsFreeGroupoid (CategoryTheory.ActionCategory G A)

full_name: _private.Mathlib.GroupTheory.FreeGroup.NielsenSchreier.0.IsFreeGroupoid.SpanningTree.root'
code: /-- The root of `T`, except its type is `G` instead of the type synonym `T`. -/
private def root' : G 
goal: G

full_name: IsFreeGroupoid.SpanningTree.homOfPath
code: /-- A path in the tree gives a hom, by composition. -/
-- Porting note: removed noncomputable. This is already declared at the beginning of the section.
def homOfPath : ∀ {a : G}, Path (root T) a → (root' T ⟶ a)
  
goal: Quiver.Path (Quiver.root (WideSubquiver.toType (Quiver.Symmetrify (IsFreeGroupoid.Generators G)) T)) a →
  (IsFreeGroupoid.SpanningTree.root' T ⟶ a)

full_name: IsFreeGroupoid.SpanningTree.treeHom
code: /-- For every vertex `a`, there is a canonical hom from the root, given by the path in the tree. -/
def treeHom (a : G) : root' T ⟶ a 
goal: IsFreeGroupoid.SpanningTree.root' T ⟶ a

full_name: IsFreeGroupoid.SpanningTree.treeHom_eq
code: /-- Any path to `a` gives `treeHom T a`, since paths in the tree are unique. -/
theorem treeHom_eq {a : G} (p : Path (root T) a) : treeHom T a = homOfPath T p 
goal: IsFreeGroupoid.SpanningTree.treeHom T a = IsFreeGroupoid.SpanningTree.homOfPath T p

full_name: IsFreeGroupoid.SpanningTree.treeHom_root
code: @[simp]
theorem treeHom_root : treeHom T (root' T) = 𝟙 _ 
goal: IsFreeGroupoid.SpanningTree.treeHom T (IsFreeGroupoid.SpanningTree.root' T) = 𝟙 (IsFreeGroupoid.SpanningTree.root' T)

full_name: IsFreeGroupoid.SpanningTree.loopOfHom
code: /-- Any hom in `G` can be made into a loop, by conjugating with `treeHom`s. -/
def loopOfHom {a b : G} (p : a ⟶ b) : End (root' T) 
goal: CategoryTheory.End (IsFreeGroupoid.SpanningTree.root' T)

full_name: IsFreeGroupoid.SpanningTree.loopOfHom_eq_id
code: /-- Turning an edge in the spanning tree into a loop gives the identity loop. -/
theorem loopOfHom_eq_id {a b : Generators G} (e) (H : e ∈ wideSubquiverSymmetrify T a b) :
    loopOfHom T (of e) = 𝟙 (root' T) 
goal: IsFreeGroupoid.SpanningTree.loopOfHom T (IsFreeGroupoid.of e) = 𝟙 (IsFreeGroupoid.SpanningTree.root' T)

full_name: IsFreeGroupoid.SpanningTree.functorOfMonoidHom_obj
code: /-- Since a hom gives a loop, any homomorphism from the vertex group at the root
    extends to a functor on the whole groupoid. -/
@[simps]
def functorOfMonoidHom {X} [Monoid X] (f : End (root' T) →* X) :
    G ⥤ CategoryTheory.SingleObj X 
goal: ∀ (x : G), (IsFreeGroupoid.SpanningTree.functorOfMonoidHom T f).obj x = ()

full_name: IsFreeGroupoid.SpanningTree.functorOfMonoidHom
code: /-- Since a hom gives a loop, any homomorphism from the vertex group at the root
    extends to a functor on the whole groupoid. -/
@[simps]
def functorOfMonoidHom {X} [Monoid X] (f : End (root' T) →* X) :
    G ⥤ CategoryTheory.SingleObj X 
goal: G ⥤ CategoryTheory.SingleObj X

full_name: IsFreeGroupoid.SpanningTree.functorOfMonoidHom_map
code: /-- Since a hom gives a loop, any homomorphism from the vertex group at the root
    extends to a functor on the whole groupoid. -/
@[simps]
def functorOfMonoidHom {X} [Monoid X] (f : End (root' T) →* X) :
    G ⥤ CategoryTheory.SingleObj X 
goal: ∀ {X_1 Y : G} (p : X_1 ⟶ Y),
  (IsFreeGroupoid.SpanningTree.functorOfMonoidHom T f).map p = f (IsFreeGroupoid.SpanningTree.loopOfHom T p)

full_name: IsFreeGroupoid.SpanningTree.endIsFree
code: /-- Given a free groupoid and an arborescence of its generating quiver, the vertex
    group at the root is freely generated by loops coming from generating arrows
    in the complement of the tree. -/
lemma endIsFree : IsFreeGroup (End (root' T)) 
goal: IsFreeGroup (CategoryTheory.End (IsFreeGroupoid.SpanningTree.root' T))

full_name: _private.Mathlib.GroupTheory.FreeGroup.NielsenSchreier.0.IsFreeGroupoid.symgen
code: /-- Another name for the identity function `G → G`, to help type checking. -/
private def symgen {G : Type u} [Groupoid.{v} G] [IsFreeGroupoid G] :
    G → Symmetrify (Generators G) 
goal: G → Quiver.Symmetrify (IsFreeGroupoid.Generators G)

full_name: IsFreeGroupoid.path_nonempty_of_hom
code: /-- If there exists a morphism `a → b` in a free groupoid, then there also exists a zigzag
from `a` to `b` in the generating quiver. -/
theorem path_nonempty_of_hom {G} [Groupoid.{u, u} G] [IsFreeGroupoid G] {a b : G} :
    Nonempty (a ⟶ b) → Nonempty (Path (symgen a) (symgen b)) 
goal: Nonempty (a ⟶ b) → Nonempty (Quiver.Path (IsFreeGroupoid.symgen a) (IsFreeGroupoid.symgen b))

full_name: IsFreeGroupoid.generators_connected
code: /-- Given a connected free groupoid, its generating quiver is rooted-connected. -/
instance generators_connected (G) [Groupoid.{u, u} G] [IsConnected G] [IsFreeGroupoid G] (r : G) :
    RootedConnected (symgen r) 
goal: Quiver.RootedConnected (IsFreeGroupoid.symgen r)

full_name: IsFreeGroupoid.endIsFreeOfConnectedFree
code: /-- A vertex group in a free connected groupoid is free. With some work one could drop the
connectedness assumption, by looking at connected components. -/
instance endIsFreeOfConnectedFree
    {G : Type u} [Groupoid G] [IsConnected G] [IsFreeGroupoid G] (r : G) :
    IsFreeGroup.{u} (End r) 
goal: IsFreeGroup (CategoryTheory.End r)

full_name: subgroupIsFreeOfIsFree
code: /-- The Nielsen-Schreier theorem: a subgroup of a free group is free. -/
instance subgroupIsFreeOfIsFree {G : Type u} [Group G] [IsFreeGroup G] (H : Subgroup G) :
    IsFreeGroup H 
goal: IsFreeGroup ↥H