Theory FreeGroups

section ‹The Free Group›

theory "FreeGroups"
imports
   "HOL-Algebra.Group"
   Cancelation
   Generators
begin

text ‹
Based on the work in @{theory "Free-Groups.Cancelation"}, the free group is now easily defined
over the set of fully canceled words with the corresponding operations.
›

subsection ‹Inversion›

text ‹
To define the inverse of a word, we first create a helper function that inverts
a single generator, and show that it is self-inverse.
›

definition inv1 :: "'a g_i  'a g_i"
 where "inv1 = apfst Not"

lemma inv1_inv1: "inv1  inv1 = id"
  by (simp add: fun_eq_iff comp_def inv1_def)

lemmas inv1_inv1_simp [simp] = inv1_inv1[unfolded id_def]

lemma snd_inv1: "snd  inv1 = snd"
  by(simp add: fun_eq_iff comp_def inv1_def)

text ‹
The inverse of a word is obtained by reversing the order of the generators and
inverting each generator using @{term inv1}. Some properties of @{term inv_fg}
are noted.
›

definition inv_fg :: "'a word_g_i  'a word_g_i"
 where "inv_fg l = rev (map inv1 l)"

lemma cancelling_inf[simp]: "canceling (inv1 a) (inv1 b) = canceling a b"
  by(simp add: canceling_def inv1_def)

lemma inv_idemp: "inv_fg (inv_fg l) = l"
  by (auto simp add:inv_fg_def rev_map)

lemma inv_fg_cancel: "normalize (l @ inv_fg l) = []"
proof(induct l rule:rev_induct)
  case Nil thus ?case
    by (auto simp add: inv_fg_def)
next
  case (snoc x xs)
  have "canceling x (inv1 x)" by (simp add:inv1_def canceling_def)
  moreover
  let ?i = "length xs"
  have "Suc ?i < length xs + 1 + 1 + length xs"
    by auto
  moreover
  have "inv_fg (xs @ [x]) = [inv1 x] @ inv_fg xs"
    by (auto simp add:inv_fg_def)
  ultimately
  have "cancels_to_1_at ?i (xs @ [x] @ (inv_fg (xs @ [x]))) (xs @ inv_fg xs)"
    by (auto simp add:cancels_to_1_at_def cancel_at_def nth_append)
  hence "cancels_to_1 (xs @ [x] @ (inv_fg (xs @ [x]))) (xs @ inv_fg xs)"
    by (auto simp add: cancels_to_1_def)
  hence "cancels_to (xs @ [x] @ (inv_fg (xs @ [x]))) (xs @ inv_fg xs)"
    by (auto simp add:cancels_to_def)
  with normalize (xs @ (inv_fg xs)) = []
  show "normalize ((xs @ [x]) @ (inv_fg (xs @ [x]))) = []"
    by auto
qed

lemma inv_fg_cancel2: "normalize (inv_fg l @ l) = []"
proof-
  have "normalize (inv_fg l @ inv_fg (inv_fg l)) = []" by (rule inv_fg_cancel)
  thus "normalize (inv_fg l @ l) = []" by (simp add: inv_idemp)
qed

lemma canceled_rev:
  assumes "canceled l"
  shows "canceled (rev l)"
proof(rule ccontr)
  assume "¬canceled (rev l)"
  hence "Domainp cancels_to_1 (rev l)" by (simp add: canceled_def)
  then obtain l' where "cancels_to_1 (rev l) l'" by auto
  then obtain i where "cancels_to_1_at i (rev l) l'" by (auto simp add:cancels_to_1_def)
  hence "Suc i < length (rev l)"
    and "canceling (rev l ! i) (rev l ! Suc i)"
    by (auto simp add:cancels_to_1_at_def)
  let ?x = "length l - i - 2"
  from Suc i < length (rev l)
  have "Suc ?x < length l" by auto
  moreover
  from Suc i < length (rev l)
  have "i < length l" and "length l - Suc i = Suc(length l - Suc (Suc i))" by auto
  hence "rev l ! i = l ! Suc ?x" and "rev l ! Suc i = l ! ?x"
    by (auto simp add: rev_nth map_nth)
  with canceling (rev l ! i) (rev l ! Suc i)
  have "canceling (l ! Suc ?x) (l ! ?x)" by auto
  hence "canceling (l ! ?x) (l ! Suc ?x)" by (rule cancel_sym)
  hence "canceling (l ! ?x) (l ! Suc ?x)" by simp
  ultimately
  have "cancels_to_1_at ?x l (cancel_at ?x l)" 
    by (auto simp add:cancels_to_1_at_def)
  hence "cancels_to_1 l (cancel_at ?x l)"
    by (auto simp add:cancels_to_1_def)
  hence "¬canceled l"
    by (auto simp add:canceled_def)
  with canceled l show False by contradiction
qed

lemma inv_fg_closure1:
  assumes "canceled l"
  shows "canceled (inv_fg l)"
unfolding inv_fg_def and inv1_def and apfst_def
proof-
  have "inj Not" by (auto intro:injI)
  moreover
  have "inj_on id (snd ` set l)" by auto
  ultimately
  have "canceled (map (map_prod Not id) l)" 
    using canceled l 
    by -(rule rename_gens_canceled)
  thus "canceled (rev (map (map_prod Not id) l))" by (rule canceled_rev)
qed

lemma inv_fg_closure2:
  "l  lists (UNIV × gens)  inv_fg l  lists (UNIV × gens)"
  by (auto iff:lists_eq_set simp add:inv1_def inv_fg_def)

subsection ‹The definition›

text ‹
Finally, we can define the Free Group over a set of generators, and show that it
is indeed a group.
›

definition free_group :: "'a set => ((bool * 'a) list) monoid" ("ı")
where 
  "gens 
     carrier = {llists (UNIV × gens). canceled l },
     mult = λ x y. normalize (x @ y),
     one = []
  "


lemma occuring_gens_in_element:
  "x  carrier gens x  lists (UNIV × gens)"
by(auto simp add:free_group_def)

theorem free_group_is_group: "group gens⇙"
proof
  fix x y
  assume "x  carrier gens⇙" hence x: "x  lists (UNIV × gens)" by
    (rule occuring_gens_in_element)
  assume "y  carrier gens⇙" hence y: "y  lists (UNIV × gens)" by
    (rule occuring_gens_in_element)
  from x and y
  have "x gens⇙⇙ y  lists (UNIV × gens)"
    by (auto intro!: normalize_preserves_generators simp add:free_group_def append_in_lists_conv)
  thus "x gens⇙⇙ y  carrier gens⇙"
    by (auto simp add:free_group_def)
next
  fix x y z
  have "cancels_to (x @ y) (normalize (x @ (y::'a word_g_i)))"
   and "cancels_to z (z::'a word_g_i)"
    by auto
  hence "normalize (normalize (x @ y) @ z) = normalize ((x @ y) @ z)"
    by (rule normalize_append_cancel_to[THEN sym])
  also
  have " = normalize (x @ (y @ z))" by auto
  also
  have "cancels_to (y @ z) (normalize (y @ (z::'a word_g_i)))"
   and "cancels_to x (x::'a word_g_i)"
    by auto
  hence "normalize (x @ (y @ z)) = normalize (x @ normalize (y @ z))"
    by -(rule normalize_append_cancel_to)
  finally
  show "x gens⇙⇙ y gens⇙⇙ z =
        x gens⇙⇙ (y gens⇙⇙ z)"
    by (auto simp add:free_group_def)
next
  show "𝟭gens⇙⇙  carrier gens⇙"
    by (auto simp add:free_group_def)
next
  fix x
  assume "x  carrier gens⇙"
  thus "𝟭gens⇙⇙ gens⇙⇙ x = x"
    by (auto simp add:free_group_def)
next
  fix x
  assume "x  carrier gens⇙"
  thus "x gens⇙⇙ 𝟭gens⇙⇙ = x"
    by (auto simp add:free_group_def)
next
  show "carrier gens Units gens⇙"
  proof (simp add:free_group_def Units_def, rule subsetI)
    fix x :: "'a word_g_i"
    let ?x' = "inv_fg x"
    assume "x  {ylists(UNIV×gens). canceled y}"
    hence "?x'  lists(UNIV×gens)  canceled ?x'"
      by (auto elim:inv_fg_closure1 simp add:inv_fg_closure2)
    moreover
    have "normalize (?x' @ x) = []"
     and "normalize (x @ ?x') = []"
      by (auto simp add:inv_fg_cancel inv_fg_cancel2)
    ultimately
    have "y. y  lists (UNIV × gens) 
                  canceled y 
                  normalize (y @ x) = []  normalize (x @ y) = []"
      by auto
    with x  {ylists(UNIV×gens). canceled y}
    show "x  {y  lists (UNIV × gens).  canceled y  
          (x. x  lists (UNIV × gens) 
                  canceled x 
                  normalize (x @ y) = []  normalize (y @ x) = [])}"
      by auto
  qed
qed

lemma inv_is_inv_fg[simp]:
  "x  carrier gens invgens⇙⇙ x = inv_fg x"
by (rule group.inv_equality,auto simp add:free_group_is_group,auto simp add: free_group_def inv_fg_cancel inv_fg_cancel2 inv_fg_closure1 inv_fg_closure2)


subsection ‹The universal property›

text ‹Free Groups are important due to their universal property: Every map of
the set of generators to another group can be extended uniquely to an
homomorphism from the Free Group.›

definition insert ("ι")
  where "ι g = [(False, g)]"

lemma insert_closed:
  "g  gens  ι g  carrier gens⇙"
  by (auto simp add:insert_def free_group_def)

definition (in group) lift_gi
  where "lift_gi f gi = (if fst gi then inv (f (snd gi)) else f (snd gi))"

lemma (in group) lift_gi_closed:
  assumes cl: "f  gens  carrier G"
      and "snd gi  gens"
  shows "lift_gi f gi  carrier G"
using assms by (auto simp add:lift_gi_def)

definition (in group) lift
  where "lift f w = m_concat (map (lift_gi f) w)"

lemma (in group) lift_nil[simp]: "lift f [] = 𝟭"
 by (auto simp add:lift_def)

lemma (in group) lift_closed[simp]:
  assumes cl: "f  gens  carrier G"
      and "x  lists (UNIV × gens)"
  shows "lift f x  carrier G"
proof-
  have "set (map (lift_gi f) x)  carrier G"
    using x  lists (UNIV × gens)
    by (auto simp add:lift_gi_closed[OF cl])
  thus "lift f x  carrier G"
    by (auto simp add:lift_def)
qed

lemma (in group) lift_append[simp]:
  assumes cl: "f  gens  carrier G"
      and "x  lists (UNIV × gens)"
      and "y  lists (UNIV × gens)"
  shows "lift f (x @ y) = lift f x  lift f y"
proof-
  from x  lists (UNIV × gens)
  have "set (map snd x)  gens" by auto
  hence "set (map (lift_gi f) x)  carrier G"
    by (induct x)(auto simp add:lift_gi_closed[OF cl])
  moreover
  from y  lists (UNIV × gens)
  have "set (map snd y)  gens" by auto
  hence "set (map (lift_gi f) y)  carrier G"
    by (induct y)(auto simp add:lift_gi_closed[OF cl])
  ultimately
  show "lift f (x @ y) = lift f x  lift f y"
    by (auto simp add:lift_def m_assoc simp del:set_map foldr_append)
qed

lemma (in group) lift_cancels_to:
  assumes "cancels_to x y"
      and "x  lists (UNIV × gens)"
      and cl: "f  gens  carrier G"
  shows "lift f x = lift f y"
using assms
unfolding cancels_to_def
proof(induct rule:rtranclp_induct)
  case (step y z)
    from cancels_to_1** x y
    and x  lists (UNIV × gens)
    have "y  lists (UNIV × gens)"
      by -(rule cancels_to_preserves_generators, simp add:cancels_to_def)
    hence "lift f x = lift f y"
      using step by auto
    also
    from cancels_to_1 y z
    obtain ys1 y1 y2 ys2
      where y: "y = ys1 @ y1 # y2 # ys2"
      and "z = ys1 @ ys2"
      and "canceling y1 y2"
    by (rule cancels_to_1_unfold)
    have "lift f y  = lift f (ys1 @ [y1] @ [y2] @ ys2)"
      using y by simp
    also
    from y and cl and y  lists (UNIV × gens)
    have "lift f (ys1 @ [y1] @ [y2] @ ys2)
        = lift f ys1  (lift f [y1]  lift f [y2])  lift f ys2"
      by (auto intro:lift_append[OF cl] simp del: append_Cons simp add:m_assoc iff:lists_eq_set)
    also
    from cl[THEN funcset_image]
     and y and y  lists (UNIV × gens)
     and canceling y1 y2
    have "(lift f [y1]  lift f [y2]) = 𝟭"
      by (auto simp add:lift_def lift_gi_def canceling_def iff:lists_eq_set)
    hence "lift f ys1  (lift f [y1]  lift f [y2])  lift f ys2
           = lift f ys1  𝟭  lift f ys2"
      by simp
    also
    from y and y  lists (UNIV × gens)
     and cl
     have "lift f ys1  𝟭  lift f ys2 = lift f (ys1 @ ys2)"
      by (auto intro:lift_append iff:lists_eq_set)
    also
    from z = ys1 @ ys2
    have "lift f (ys1 @ ys2) = lift f z" by simp
    finally show "lift f x = lift f z" .
qed auto

lemma (in group) lift_is_hom:
  assumes cl: "f  gens  carrier G"
  shows "lift f  hom gensG"
proof-
  {
    fix x
    assume "x  carrier gens⇙"
    hence "x  lists (UNIV × gens)"
      unfolding free_group_def by simp
    hence "lift f x  carrier G"
     by (induct x, auto simp add:lift_def lift_gi_closed[OF cl])
  } 
  moreover
  { fix x
    assume "x  carrier gens⇙"
    fix y
    assume "y  carrier gens⇙"

    from x  carrier gens⇙› and y  carrier gens⇙›
    have "x  lists (UNIV × gens)" and "y  lists (UNIV × gens)"
      by (auto simp add:free_group_def)

    have "cancels_to (x @ y) (normalize (x @ y))" by simp
    from x  lists (UNIV × gens) and y  lists (UNIV × gens)
     and lift_cancels_to[THEN sym, OF cancels_to (x @ y) (normalize (x @ y))] and cl
    have "lift f (x gens⇙⇙ y) = lift f (x @ y)"
      by (auto simp add:free_group_def iff:lists_eq_set)
    also
    from x  lists (UNIV × gens) and y  lists (UNIV × gens) and cl
    have "lift f (x @ y) = lift f x  lift f y"
      by simp
    finally
    have "lift f (x gens⇙⇙ y) = lift f x  lift f y" .
  }
  ultimately
  show "lift f  hom gensG"
    by auto
qed

lemma gens_span_free_group:
shows "ι ` gensgens⇙⇙ = carrier gens⇙"
proof
  interpret group "gens⇙" by (rule free_group_is_group)
  show "ι ` gensgens⇙⇙  carrier gens⇙"
  by(rule gen_span_closed, auto simp add:insert_def free_group_def)

  show "carrier gens ι ` gensgens⇙⇙"
  proof
    fix x
    show "x  carrier gens x  ι ` gensgens⇙⇙"
    proof(induct x)
    case Nil
      have "one gens ι ` gensgens⇙⇙"
        by simp
      thus "[]  ι ` gensgens⇙⇙"
        by (simp add:free_group_def)
    next
    case (Cons a x)
      from a # x  carrier gens⇙›
      have "x  carrier gens⇙"
        by (auto intro:cons_canceled simp add:free_group_def)
      hence "x  ι ` gensgens⇙⇙"
        using Cons by simp
      moreover

      from a # x  carrier gens⇙›
      have "snd a  gens"
        by (auto simp add:free_group_def)
      hence isa: "ι (snd a)  ι ` gensgens⇙⇙"
        by (auto simp add:insert_def intro:gen_gens)
      have "[a]  ι ` gensgens⇙⇙"
      proof(cases "fst a")
        case False
          hence "[a] = ι (snd a)" by (cases a, auto simp add:insert_def)
           with isa show "[a]  ι ` gensgens⇙⇙" by simp
       next
        case True
          from snd a  gens
          have "ι (snd a)  carrier gens⇙" 
            by (auto simp add:free_group_def insert_def)
          with True
          have "[a] = invgens⇙⇙ (ι (snd a))"
            by (cases a, auto simp add:insert_def inv_fg_def inv1_def)
          moreover
          from isa
          have "invgens⇙⇙ (ι (snd a))  ι ` gensgens⇙⇙"
            by (auto intro:gen_inv)
          ultimately
          show "[a]  ι ` gensgens⇙⇙"
            by simp
      qed
      ultimately 
      have "mult gens[a] x  ι ` gensgens⇙⇙"
        by (auto intro:gen_mult)
      with
      a # x  carrier gens⇙›
      show "a # x  ι ` gensgens⇙⇙" by (simp add:free_group_def)
    qed
  qed
qed

lemma (in group) lift_is_unique:
  assumes "group G"
  and cl: "f  gens  carrier G"
  and "h  hom gensG"
  and " g  gens. h (ι g) = f g"
  shows "x  carrier gens. h x = lift f x"
unfolding gens_span_free_group[THEN sym]
proof(rule hom_unique_on_span[of "gens⇙" G])
  show "group gens⇙" by (rule free_group_is_group)
next
  show "group G" by fact
next
  show "ι ` gens  carrier gens⇙"
    by(auto intro:insert_closed)
next
  show "h  hom gensG" by fact
next
  show "lift f  hom gensG" by (rule lift_is_hom[OF cl])
next
  from g gens. h (ι g) = f g and cl[THEN funcset_image]
  show "g ι ` gens. h g = lift f g"
    by(auto simp add:insert_def lift_def lift_gi_def)
qed

end