l3lab/ntp-mathlib huggingface dataset:
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  

Proof state:
case left
n : ℕ
f✝ : Vector ℕ n → ℕ
f : ℕ → ℕ
⊢ Primrec' fun v => (fun n => (unpair n).1) (Vector.head v)
case right
n : ℕ
f✝ : Vector ℕ n → ℕ
f : ℕ → ℕ
⊢ Primrec' fun v => (fun n => (unpair n).2) (Vector.head v)
case pair
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => (fun n => pair (f✝ n) (g✝ n)) (Vector.head v)
case comp
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => (fun n => f✝ (g✝ n)) (Vector.head v)
case prec
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => unpaired (fun z n => Nat.rec (f✝ z) (fun y IH => g✝ (pair z (pair y IH))) n) (Vector.head v)

Next tactic:
case left => exact unpair₁ head
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  

Proof state:
n : ℕ
f✝ : Vector ℕ n → ℕ
f : ℕ → ℕ
⊢ Primrec' fun v => (fun n => (unpair n).1) (Vector.head v)

Next tactic:
case left => exact unpair₁ head
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => 

Proof state:
n : ℕ
f✝ : Vector ℕ n → ℕ
f : ℕ → ℕ
⊢ Primrec' fun v => (fun n => (unpair n).1) (Vector.head v)

Next tactic:
exact unpair₁ head
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  

Proof state:
case right
n : ℕ
f✝ : Vector ℕ n → ℕ
f : ℕ → ℕ
⊢ Primrec' fun v => (fun n => (unpair n).2) (Vector.head v)
case pair
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => (fun n => pair (f✝ n) (g✝ n)) (Vector.head v)
case comp
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => (fun n => f✝ (g✝ n)) (Vector.head v)
case prec
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => unpaired (fun z n => Nat.rec (f✝ z) (fun y IH => g✝ (pair z (pair y IH))) n) (Vector.head v)

Next tactic:
case right => exact unpair₂ head
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  

Proof state:
n : ℕ
f✝ : Vector ℕ n → ℕ
f : ℕ → ℕ
⊢ Primrec' fun v => (fun n => (unpair n).2) (Vector.head v)

Next tactic:
case right => exact unpair₂ head
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => 

Proof state:
n : ℕ
f✝ : Vector ℕ n → ℕ
f : ℕ → ℕ
⊢ Primrec' fun v => (fun n => (unpair n).2) (Vector.head v)

Next tactic:
exact unpair₂ head
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => exact unpair₂ head
  

Proof state:
case pair
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => (fun n => pair (f✝ n) (g✝ n)) (Vector.head v)
case comp
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => (fun n => f✝ (g✝ n)) (Vector.head v)
case prec
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => unpaired (fun z n => Nat.rec (f✝ z) (fun y IH => g✝ (pair z (pair y IH))) n) (Vector.head v)

Next tactic:
case pair f g _ _ hf hg => exact natPair.comp₂ _ hf hg
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => exact unpair₂ head
  

Proof state:
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f✝ f g : ℕ → ℕ
a✝¹ : Nat.Primrec f
a✝ : Nat.Primrec g
hf : Primrec' fun v => f (Vector.head v)
hg : Primrec' fun v => g (Vector.head v)
⊢ Primrec' fun v => (fun n => pair (f n) (g n)) (Vector.head v)

Next tactic:
case pair f g _ _ hf hg => exact natPair.comp₂ _ hf hg
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => exact unpair₂ head
  case pair f g _ _ hf hg => 

Proof state:
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f✝ f g : ℕ → ℕ
a✝¹ : Nat.Primrec f
a✝ : Nat.Primrec g
hf : Primrec' fun v => f (Vector.head v)
hg : Primrec' fun v => g (Vector.head v)
⊢ Primrec' fun v => (fun n => pair (f n) (g n)) (Vector.head v)

Next tactic:
exact natPair.comp₂ _ hf hg
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => exact unpair₂ head
  case pair f g _ _ hf hg => exact natPair.comp₂ _ hf hg
  

Proof state:
case comp
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => (fun n => f✝ (g✝ n)) (Vector.head v)
case prec
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => unpaired (fun z n => Nat.rec (f✝ z) (fun y IH => g✝ (pair z (pair y IH))) n) (Vector.head v)

Next tactic:
case comp f g _ _ hf hg => exact hf.comp₁ _ hg
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => exact unpair₂ head
  case pair f g _ _ hf hg => exact natPair.comp₂ _ hf hg
  

Proof state:
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f✝ f g : ℕ → ℕ
a✝¹ : Nat.Primrec f
a✝ : Nat.Primrec g
hf : Primrec' fun v => f (Vector.head v)
hg : Primrec' fun v => g (Vector.head v)
⊢ Primrec' fun v => (fun n => f (g n)) (Vector.head v)

Next tactic:
case comp f g _ _ hf hg => exact hf.comp₁ _ hg
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => exact unpair₂ head
  case pair f g _ _ hf hg => exact natPair.comp₂ _ hf hg
  case comp f g _ _ hf hg => 

Proof state:
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f✝ f g : ℕ → ℕ
a✝¹ : Nat.Primrec f
a✝ : Nat.Primrec g
hf : Primrec' fun v => f (Vector.head v)
hg : Primrec' fun v => g (Vector.head v)
⊢ Primrec' fun v => (fun n => f (g n)) (Vector.head v)

Next tactic:
exact hf.comp₁ _ hg
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => exact unpair₂ head
  case pair f g _ _ hf hg => exact natPair.comp₂ _ hf hg
  case comp f g _ _ hf hg => exact hf.comp₁ _ hg
  

Proof state:
case prec
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f f✝ g✝ : ℕ → ℕ
a✝¹ : Nat.Primrec f✝
a✝ : Nat.Primrec g✝
a_ih✝¹ : Primrec' fun v => f✝ (Vector.head v)
a_ih✝ : Primrec' fun v => g✝ (Vector.head v)
⊢ Primrec' fun v => unpaired (fun z n => Nat.rec (f✝ z) (fun y IH => g✝ (pair z (pair y IH))) n) (Vector.head v)

Next tactic:
case prec f g _ _ hf hg =>
    simpa using
      prec' (unpair₂ head) (hf.comp₁ _ (unpair₁ head))
        (hg.comp₁ _ <|
          natPair.comp₂ _ (unpair₁ <| tail <| tail head) (natPair.comp₂ _ head (tail head)))
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => exact unpair₂ head
  case pair f g _ _ hf hg => exact natPair.comp₂ _ hf hg
  case comp f g _ _ hf hg => exact hf.comp₁ _ hg
  

Proof state:
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f✝ f g : ℕ → ℕ
a✝¹ : Nat.Primrec f
a✝ : Nat.Primrec g
hf : Primrec' fun v => f (Vector.head v)
hg : Primrec' fun v => g (Vector.head v)
⊢ Primrec' fun v => unpaired (fun z n => Nat.rec (f z) (fun y IH => g (pair z (pair y IH))) n) (Vector.head v)

Next tactic:
case prec f g _ _ hf hg =>
    simpa using
      prec' (unpair₂ head) (hf.comp₁ _ (unpair₁ head))
        (hg.comp₁ _ <|
          natPair.comp₂ _ (unpair₁ <| tail <| tail head) (natPair.comp₂ _ head (tail head)))
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by simp [encodek]
  fun f hf => by
  induction hf
  case zero => exact const 0
  case succ => exact succ
  case left => exact unpair₁ head
  case right => exact unpair₂ head
  case pair f g _ _ hf hg => exact natPair.comp₂ _ hf hg
  case comp f g _ _ hf hg => exact hf.comp₁ _ hg
  case prec f g _ _ hf hg =>
    

Proof state:
n : ℕ
f✝¹ : Vector ℕ n → ℕ
f✝ f g : ℕ → ℕ
a✝¹ : Nat.Primrec f
a✝ : Nat.Primrec g
hf : Primrec' fun v => f (Vector.head v)
hg : Primrec' fun v => g (Vector.head v)
⊢ Primrec' fun v => unpaired (fun z n => Nat.rec (f z) (fun y IH => g (pair z (pair y IH))) n) (Vector.head v)

Next tactic:
simpa using
      prec' (unpair₂ head) (hf.comp₁ _ (unpair₁ head))
        (hg.comp₁ _ <|
          natPair.comp₂ _ (unpair₁ <| tail <| tail head) (natPair.comp₂ _ head (tail head)))
theorem of_prim {n f} : Primrec f → @Primrec' n f :=
  suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf =>
    (pred.comp₁ _ <|
          (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f)
            Primrec'.encode).of_eq
      fun i => by 

Proof state:
n : ℕ
f : Vector ℕ n → ℕ
this : ∀ (f : ℕ → ℕ), Nat.Primrec f → Primrec' fun v => f (Vector.head v)
hf : Primrec f
i : Vector ℕ n
⊢ Nat.pred ((fun m => encode (Option.map f (decode m))) (encode i)) = f i

Next tactic:
simp [encodek]
theorem prim_iff₁ {f : ℕ → ℕ} : (@Primrec' 1 fun v => f v.head) ↔ Primrec f :=
  prim_iff.trans
    ⟨fun h => (h.comp <| .vector_ofFn fun _ => .id).of_eq fun v => by 

Proof state:
f : ℕ → ℕ
h : Primrec fun v => f (Vector.head v)
v : ℕ
⊢ f (Vector.head (ofFn fun i => id v)) = f v

Next tactic:
simp
theorem prim_iff₂ {f : ℕ → ℕ → ℕ} : (@Primrec' 2 fun v => f v.head v.tail.head) ↔ Primrec₂ f :=
  prim_iff.trans
    ⟨fun h => (h.comp <| Primrec.vector_cons.comp .fst <|
      Primrec.vector_cons.comp .snd (.const nil)).of_eq fun v => by 

Proof state:
f : ℕ → ℕ → ℕ
h : Primrec fun v => f (Vector.head v) (Vector.head (Vector.tail v))
v : ℕ × ℕ
⊢ f (Vector.head (v.1 ::ᵥ v.2 ::ᵥ nil)) (Vector.head (Vector.tail (v.1 ::ᵥ v.2 ::ᵥ nil))) = f v.1 v.2

Next tactic:
simp
theorem vec_iff {m n f} : @Vec m n f ↔ Primrec f :=
  ⟨fun h => by 

Proof state:
m n : ℕ
f : Vector ℕ m → Vector ℕ n
h : Vec f
⊢ Primrec f

Next tactic:
simpa using Primrec.vector_ofFn fun i => to_prim (h i)
@[simp]
theorem isConj_iff_eq {α : Type*} [CommMonoid α] {a b : α} : IsConj a b ↔ a = b :=
  ⟨fun ⟨c, hc⟩ => by
    

Proof state:
α✝ : Type u
β : Type v
inst✝² : Monoid α✝
inst✝¹ : Monoid β
α : Type u_1
inst✝ : CommMonoid α
a b : α
x✝ : IsConj a b
c : αˣ
hc : SemiconjBy (↑c) a b
⊢ a = b

Next tactic:
rw [SemiconjBy, mul_comm, ← Units.mul_inv_eq_iff_eq_mul, mul_assoc, c.mul_inv, mul_one] at hc
@[simp]
theorem isConj_iff_eq {α : Type*} [CommMonoid α] {a b : α} : IsConj a b ↔ a = b :=
  ⟨fun ⟨c, hc⟩ => by
    rw [SemiconjBy, mul_comm, ← Units.mul_inv_eq_iff_eq_mul, mul_assoc, c.mul_inv, mul_one] at hc
    

Proof state:
α✝ : Type u
β : Type v
inst✝² : Monoid α✝
inst✝¹ : Monoid β
α : Type u_1
inst✝ : CommMonoid α
a b : α
x✝ : IsConj a b
c : αˣ
hc : a = b
⊢ a = b

Next tactic:
exact hc
@[simp]
theorem isConj_iff_eq {α : Type*} [CommMonoid α] {a b : α} : IsConj a b ↔ a = b :=
  ⟨fun ⟨c, hc⟩ => by
    rw [SemiconjBy, mul_comm, ← Units.mul_inv_eq_iff_eq_mul, mul_assoc, c.mul_inv, mul_one] at hc
    exact hc, fun h => by 

Proof state:
α✝ : Type u
β : Type v
inst✝² : Monoid α✝
inst✝¹ : Monoid β
α : Type u_1
inst✝ : CommMonoid α
a b : α
h : a = b
⊢ IsConj a b

Next tactic:
rw [h]
protected theorem MonoidHom.map_isConj (f : α →* β) {a b : α} : IsConj a b → IsConj (f a) (f b)
  | ⟨c, hc⟩ => ⟨Units.map f c, by 

Proof state:
α : Type u
β : Type v
inst✝¹ : Monoid α
inst✝ : Monoid β
f : α →* β
a b : α
c : αˣ
hc : SemiconjBy (↑c) a b
⊢ SemiconjBy (↑((Units.map f) c)) (f a) (f b)

Next tactic:
rw [Units.coe_map, SemiconjBy, ← f.map_mul, hc.eq, f.map_mul]
@[simp]
theorem isConj_one_right {a : α} : IsConj 1 a ↔ a = 1 :=
  ⟨fun ⟨c, hc⟩ => mul_right_cancel (hc.symm.trans ((mul_one _).trans (one_mul _).symm)), fun h => by
    

Proof state:
α : Type u
β : Type v
inst✝ : CancelMonoid α
a : α
h : a = 1
⊢ IsConj 1 a

Next tactic:
rw [h]
@[simp]
theorem conj_pow {i : ℕ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹ := by
  

Proof state:
α : Type u
β : Type v
inst✝ : Group α
i : ℕ
a b : α
⊢ (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹

Next tactic:
induction' i with i hi
@[simp]
theorem conj_pow {i : ℕ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹ := by
  induction' i with i hi
  · 

Proof state:
case zero
α : Type u
β : Type v
inst✝ : Group α
a b : α
⊢ (a * b * a⁻¹) ^ Nat.zero = a * b ^ Nat.zero * a⁻¹

Next tactic:
simp
@[simp]
theorem conj_pow {i : ℕ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹ := by
  induction' i with i hi
  · simp
  · 

Proof state:
case succ
α : Type u
β : Type v
inst✝ : Group α
a b : α
i : ℕ
hi : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹
⊢ (a * b * a⁻¹) ^ Nat.succ i = a * b ^ Nat.succ i * a⁻¹

Next tactic:
simp [pow_succ, hi]
@[simp]
theorem conj_zpow {i : ℤ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹ := by
  

Proof state:
α : Type u
β : Type v
inst✝ : Group α
i : ℤ
a b : α
⊢ (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹

Next tactic:
induction' i
@[simp]
theorem conj_zpow {i : ℤ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹ := by
  induction' i
  · 

Proof state:
case ofNat
α : Type u
β : Type v
inst✝ : Group α
a b : α
a✝ : ℕ
⊢ (a * b * a⁻¹) ^ Int.ofNat a✝ = a * b ^ Int.ofNat a✝ * a⁻¹

Next tactic:
change (a * b * a⁻¹) ^ (_ : ℤ) = a * b ^ (_ : ℤ) * a⁻¹
@[simp]
theorem conj_zpow {i : ℤ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹ := by
  induction' i
  · change (a * b * a⁻¹) ^ (_ : ℤ) = a * b ^ (_ : ℤ) * a⁻¹
    

Proof state:
case ofNat
α : Type u
β : Type v
inst✝ : Group α
a b : α
a✝ : ℕ
⊢ (a * b * a⁻¹) ^ Int.ofNat a✝ = a * b ^ Int.ofNat a✝ * a⁻¹

Next tactic:
simp [zpow_ofNat]
@[simp]
theorem conj_zpow {i : ℤ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹ := by
  induction' i
  · change (a * b * a⁻¹) ^ (_ : ℤ) = a * b ^ (_ : ℤ) * a⁻¹
    simp [zpow_ofNat]
  · 

Proof state:
case negSucc
α : Type u
β : Type v
inst✝ : Group α
a b : α
a✝ : ℕ
⊢ (a * b * a⁻¹) ^ Int.negSucc a✝ = a * b ^ Int.negSucc a✝ * a⁻¹

Next tactic:
simp [zpow_negSucc, conj_pow]
@[simp]
theorem conj_zpow {i : ℤ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹ := by
  induction' i
  · change (a * b * a⁻¹) ^ (_ : ℤ) = a * b ^ (_ : ℤ) * a⁻¹
    simp [zpow_ofNat]
  · simp [zpow_negSucc, conj_pow]
    

Proof state:
case negSucc
α : Type u
β : Type v
inst✝ : Group α
a b : α
a✝ : ℕ
⊢ a * ((b ^ (a✝ + 1))⁻¹ * a⁻¹) = a * (b ^ (a✝ + 1))⁻¹ * a⁻¹

Next tactic:
rw [mul_assoc]
@[simp]
theorem isConj_iff₀ [GroupWithZero α] {a b : α} : IsConj a b ↔ ∃ c : α, c ≠ 0 ∧ c * a * c⁻¹ = b :=
  ⟨fun ⟨c, hc⟩ =>
    ⟨c, by
      

Proof state:
α : Type u
β : Type v
inst✝ : GroupWithZero α
a b : α
x✝ : IsConj a b
c : αˣ
hc : SemiconjBy (↑c) a b
⊢ ↑c ≠ 0 ∧ ↑c * a * (↑c)⁻¹ = b

Next tactic:
rw [← Units.val_inv_eq_inv_val, Units.mul_inv_eq_iff_eq_mul]
@[simp]
theorem isConj_iff₀ [GroupWithZero α] {a b : α} : IsConj a b ↔ ∃ c : α, c ≠ 0 ∧ c * a * c⁻¹ = b :=
  ⟨fun ⟨c, hc⟩ =>
    ⟨c, by
      rw [← Units.val_inv_eq_inv_val, Units.mul_inv_eq_iff_eq_mul]
      

Proof state:
α : Type u
β : Type v
inst✝ : GroupWithZero α
a b : α
x✝ : IsConj a b
c : αˣ
hc : SemiconjBy (↑c) a b
⊢ ↑c ≠ 0 ∧ ↑c * a = b * ↑c

Next tactic:
exact ⟨c.ne_zero, hc⟩
@[simp]
theorem isConj_iff₀ [GroupWithZero α] {a b : α} : IsConj a b ↔ ∃ c : α, c ≠ 0 ∧ c * a * c⁻¹ = b :=
  ⟨fun ⟨c, hc⟩ =>
    ⟨c, by
      rw [← Units.val_inv_eq_inv_val, Units.mul_inv_eq_iff_eq_mul]
      exact ⟨c.ne_zero, hc⟩⟩,
    fun ⟨c, c0, hc⟩ =>
    ⟨Units.mk0 c c0, by
      

Proof state:
α : Type u
β : Type v
inst✝ : GroupWithZero α
a b : α
x✝ : ∃ c, c ≠ 0 ∧ c * a * c⁻¹ = b
c : α
c0 : c ≠ 0
hc : c * a * c⁻¹ = b
⊢ SemiconjBy (↑(Units.mk0 c c0)) a b

Next tactic:
rw [SemiconjBy, ← Units.mul_inv_eq_iff_eq_mul, Units.val_inv_eq_inv_val, Units.val_mk0]
@[simp]
theorem isConj_iff₀ [GroupWithZero α] {a b : α} : IsConj a b ↔ ∃ c : α, c ≠ 0 ∧ c * a * c⁻¹ = b :=
  ⟨fun ⟨c, hc⟩ =>
    ⟨c, by
      rw [← Units.val_inv_eq_inv_val, Units.mul_inv_eq_iff_eq_mul]
      exact ⟨c.ne_zero, hc⟩⟩,
    fun ⟨c, c0, hc⟩ =>
    ⟨Units.mk0 c c0, by
      rw [SemiconjBy, ← Units.mul_inv_eq_iff_eq_mul, Units.val_inv_eq_inv_val, Units.val_mk0]
      

Proof state:
α : Type u
β : Type v
inst✝ : GroupWithZero α
a b : α
x✝ : ∃ c, c ≠ 0 ∧ c * a * c⁻¹ = b
c : α
c0 : c ≠ 0
hc : c * a * c⁻¹ = b
⊢ c * a * c⁻¹ = b

Next tactic:
exact hc
theorem map_surjective {f : α →* β} (hf : Function.Surjective f) :
    Function.Surjective (ConjClasses.map f) := by
  

Proof state:
α : Type u
β : Type v
inst✝¹ : Monoid α
inst✝ : Monoid β
f : α →* β
hf : Function.Surjective ⇑f
⊢ Function.Surjective (map f)

Next tactic:
intro b
theorem map_surjective {f : α →* β} (hf : Function.Surjective f) :
    Function.Surjective (ConjClasses.map f) := by
  intro b
  

Proof state:
α : Type u
β : Type v
inst✝¹ : Monoid α
inst✝ : Monoid β
f : α →* β
hf : Function.Surjective ⇑f
b : ConjClasses β
⊢ ∃ a, map f a = b

Next tactic:
obtain ⟨b, rfl⟩ := ConjClasses.mk_surjective b
theorem map_surjective {f : α →* β} (hf : Function.Surjective f) :
    Function.Surjective (ConjClasses.map f) := by
  intro b
  obtain ⟨b, rfl⟩ := ConjClasses.mk_surjective b
  

Proof state:
case intro
α : Type u
β : Type v
inst✝¹ : Monoid α
inst✝ : Monoid β
f : α →* β
hf : Function.Surjective ⇑f
b : β
⊢ ∃ a, map f a = ConjClasses.mk b

Next tactic:
obtain ⟨a, rfl⟩ := hf b
theorem map_surjective {f : α →* β} (hf : Function.Surjective f) :
    Function.Surjective (ConjClasses.map f) := by
  intro b
  obtain ⟨b, rfl⟩ := ConjClasses.mk_surjective b
  obtain ⟨a, rfl⟩ := hf b
  

Proof state:
case intro.intro
α : Type u
β : Type v
inst✝¹ : Monoid α
inst✝ : Monoid β
f : α →* β
hf : Function.Surjective ⇑f
a : α
⊢ ∃ a_1, map f a_1 = ConjClasses.mk (f a)

Next tactic:
exact ⟨ConjClasses.mk a, rfl⟩
/-- The bijection between a `CommGroup` and its `ConjClasses`. -/
def mkEquiv : α ≃ ConjClasses α :=
  ⟨ConjClasses.mk, Quotient.lift id fun (a : α) b => isConj_iff_eq.1, Quotient.lift_mk _ _, by
    

Proof state:
α : Type u
β : Type v
inst✝ : CommMonoid α
⊢ Function.RightInverse (Quotient.lift id (_ : ∀ (a b : α), IsConj a b → a = b)) ConjClasses.mk

Next tactic:
rw [Function.RightInverse, Function.LeftInverse, forall_isConj]
/-- The bijection between a `CommGroup` and its `ConjClasses`. -/
def mkEquiv : α ≃ ConjClasses α :=
  ⟨ConjClasses.mk, Quotient.lift id fun (a : α) b => isConj_iff_eq.1, Quotient.lift_mk _ _, by
    rw [Function.RightInverse, Function.LeftInverse, forall_isConj]
    

Proof state:
α : Type u
β : Type v
inst✝ : CommMonoid α
⊢ ∀ (a : α),
    ConjClasses.mk (Quotient.lift id (_ : ∀ (a b : α), IsConj a b → a = b) (ConjClasses.mk a)) = ConjClasses.mk a

Next tactic:
intro x