-- TABLEAU

import data.finset.basic
import data.finset.pimage
import algebra.big_operators.order
import tactic
import order.well_founded_set

import syntax
import semantics
import setsimp

open formula
open hasLength

-- Definition 9, page 15
-- A set X is closed  iff  0 ∈ X or X contains a formula and its negation.
def closed : finset formula → Prop := λ X, ⊥ ∈ X ∨ ∃ f ∈ X, ~f ∈ X
-- A set X is simple  iff  all P ∈ X are (negated) atoms or [A]_ or ¬[A]_.
def simpleForm : formula → Prop
| ⊥       := true
| (~⊥)    := true -- added!
| (· _)   := true
| ~(· _)  := true
| (□ _)   := true
| ~(□ _)  := true
| _       := false
instance (ϕ) : decidable (simpleForm ϕ) := begin
  cases ϕ,
  case bottom: { apply decidable.is_true, tauto, },
  case atom_prop: { apply decidable.is_true, tauto, },
  case neg: { cases ϕ,
    case bottom: { apply decidable.is_true, tauto, },
    case atom_prop: { apply decidable.is_true, tauto, },
    case neg: { apply decidable.is_false, tauto, },
    case and: { apply decidable.is_false, tauto, },
    case box: { apply decidable.is_true, tauto, },
  },
  case and: { apply decidable.is_false, tauto, },
  case box: { apply decidable.is_true, tauto, },
end
@[derive decidable]
def simple : finset formula → Prop
| X := ∀ P ∈ X, simpleForm P
-- Let X_A := { R | [A]R ∈ X }.
@[simp]
def formProjection : formula → option formula
| (□f) := some f
| _    := none
def projection : finset formula → finset formula
| X := X.bUnion (λ x, (formProjection x).to_finset)

lemma proj { g: formula } { X : finset formula } :
  g ∈ projection X ↔ □g ∈ X :=
begin
  unfold projection,
  simp,
  split,
  { intro lhs,
    rcases lhs with ⟨ boxg, boxg_in_X, projboxg_is_g ⟩,
    cases boxg,
    repeat { finish },
  },
  { intro rhs,
    use □g,
    split,
    exact rhs,
    simp,
  },
end

lemma projSet {X : finset formula} : ↑(projection X) = { ϕ | □ϕ ∈ X } :=
begin
  ext1,
  unfold_coes,
  simp,
  exact proj,
end

lemma projection_length_leq : ∀ f, (projection {f}).sum lengthOfFormula ≤ lengthOfFormula f :=
begin
  intro f,
  cases f,
  { omega, },
  { exact dec_trivial, },
  { exact dec_trivial, },
  { exact dec_trivial, },
  { have subsubClaim : projection {□f} = {f}, {
      ext1, rw proj, simp,
    },
    rw subsubClaim,
    unfold lengthOfFormula, simp,
  },
end

lemma projection_set_length_leq : ∀ X, lengthOfSet (projection X) ≤ lengthOfSet X :=
begin
intro X,
apply finset.induction_on X,
{ unfold lengthOfSet, simp, intros f f_in_empty, cases f_in_empty, },
{ intros f S f_not_in_S IH,
  unfold lengthOfSet,
  rw finset.sum_insert f_not_in_S,
  simp,
  have insert_comm_proj : ∀ X f, projection (insert f X) = (projection {f}) ∪ (projection X), {
    intros X f,
    unfold projection,
    ext1 g,
    simp,
  },
  { calc (projection (insert f S)).sum lengthOfFormula
       = (projection (insert f S)).sum lengthOfFormula : refl _
   ... = (projection {f} ∪ projection S).sum lengthOfFormula : by { rw insert_comm_proj S f, }
   ... ≤ (projection {f}).sum lengthOfFormula + (projection S).sum lengthOfFormula : by { apply sum_union_le, }
   ... ≤ lengthOfFormula f + (projection S).sum lengthOfFormula : by { simp only [add_le_add_iff_right, projection_length_leq], }
   ... ≤ lengthOfFormula f + S.sum lengthOfFormula : by { simp, apply IH, },
  },
},
end

-- local rules: given this set, we get these sets as child nodes
inductive localRule : finset formula → finset (finset formula) → Type
-- closing rules:
| bot {X    } (h : ⊥          ∈ X) : localRule X ∅
| not {X ϕ  } (h : ϕ ∈ X ∧ ~ϕ ∈ X) : localRule X ∅
-- one-child rules:
| neg {X ϕ  } (h : ~~ϕ        ∈ X) : localRule X { X \ {~~ϕ}    ∪ {ϕ}   }
| con {X ϕ ψ} (h : ϕ ⋏ ψ      ∈ X) : localRule X { X \ {ϕ⋏ψ}    ∪ {ϕ,ψ} }
-- splitting rule:
| nCo {X ϕ ψ} (h : ~(ϕ ⋏ ψ)   ∈ X) : localRule X { X \ {~(ϕ⋏ψ)} ∪ {~ϕ}
                                                 , X \ {~(ϕ⋏ψ)} ∪ {~ψ}  }

-- If X is not simple, then a local rule can be applied.
-- (page 13)
lemma notSimpleThenLocalRule { X } :
  ¬ simple X → ∃ B, nonempty (localRule X B) :=
begin
  intro notSimple,
  unfold simple at notSimple,
  simp at notSimple,
  rcases notSimple with ⟨ ϕ , ϕ_in_X, ϕ_not_simple ⟩,
  cases ϕ,
  case bottom: { tauto },
  case atom_prop: { tauto },
  case neg: ψ {
    cases ψ,
    case bottom: { tauto, },
    case atom_prop: { tauto, },
    case neg: {
      use { (X \ {~~ψ}) ∪ { ψ } },
      use localRule.neg ϕ_in_X,
    },
    case and: ψ1 ψ2 {
      unfold simpleForm at *,
      use { X \ { ~ (ψ1 ⋏ ψ2) } ∪ {~ψ1}, X \ { ~ (ψ1 ⋏ ψ2) } ∪ {~ψ2} },
      use localRule.nCo ϕ_in_X,
    },
    case box: { unfold simpleForm at *, tauto, },
  },
  case and: ψ1 ψ2 {
      unfold simpleForm at *,
      use { (X \ {ψ1 ⋏ ψ2}) ∪ { ψ1, ψ2 } },
      use localRule.con ϕ_in_X,
  },
  case box: { tauto, },
end

lemma localRulesDecreaseLength { X : finset formula } { B : finset (finset formula) } (r : localRule X B) :
  ∀ Y ∈ B, lengthOfSet Y < lengthOfSet X :=
begin
  cases r,
  all_goals { intros β inB, simp at *, },
  case bot : {
    cases inB, -- no premises
  },
  case not : {
    cases inB, -- no premises
  },
  case neg : X ϕ notnot_in_X {
    subst inB,
    { calc lengthOfSet (insert ϕ (X.erase (~~ϕ)))
         ≤ lengthOfSet (X.erase (~~ϕ)) + lengthOf (ϕ) : by { apply lengthOf_insert_leq_plus, }
     ... < lengthOfSet (X.erase (~~ϕ)) + lengthOf (ϕ) + 2 : by { simp, }
     ... = lengthOfSet (X.erase (~~ϕ)) + lengthOf (~~ϕ) : by { unfold lengthOf, unfold lengthOfFormula, ring, }
     ... = lengthOfSet X : lengthRemove X (~~ϕ) notnot_in_X,
    },
  },
  case con : X ϕ ψ in_X {
    subst inB,
    { calc lengthOf (insert ϕ (insert ψ (X.erase (ϕ⋏ψ))))
         ≤ lengthOf (insert ψ (X.erase (ϕ⋏ψ))) + lengthOf ϕ : by { apply lengthOf_insert_leq_plus, }
     ... ≤ lengthOf (X.erase (ϕ⋏ψ)) + lengthOf ψ + lengthOf ϕ : by { simp, apply lengthOf_insert_leq_plus, }
     ... = lengthOf (X.erase (ϕ⋏ψ)) + lengthOf ϕ + lengthOf ψ : by { ring, }
     ... < lengthOf (X.erase (ϕ⋏ψ)) + lengthOf ϕ + lengthOf ψ + 1 : by { unfold lengthOf, simp, }
     ... = lengthOf (X.erase (ϕ⋏ψ)) + lengthOf (ϕ⋏ψ) : by { unfold lengthOf, unfold lengthOfFormula, ring, }
     ... = lengthOfSet X : (lengthRemove X (ϕ⋏ψ) in_X)
    },
  },
  case nCo : X ϕ ψ in_X {
    cases inB, -- splitting rule!
    all_goals {
      subst inB,
    },
    { -- f
    calc lengthOfSet (insert (~ϕ) (X.erase (~(ϕ⋏ψ))))
         ≤ lengthOfSet (X.erase (~(ϕ⋏ψ))) + lengthOf (~ϕ) : lengthOf_insert_leq_plus
     ... < lengthOfSet (X.erase (~(ϕ⋏ψ))) + 1 + 1 + lengthOf ϕ + lengthOf ψ :
           by { unfold lengthOf, unfold lengthOfFormula, ring_nf, simp, }
     ... = lengthOfSet (X.erase (~(ϕ⋏ψ))) + lengthOf (~(ϕ⋏ψ)) : by { unfold lengthOf, unfold lengthOfFormula, ring, }
     ... = lengthOfSet X : lengthRemove X (~(ϕ⋏ψ)) in_X,
    },
    { -- g
    calc lengthOfSet (insert (~ψ) (X.erase (~(ϕ⋏ψ))))
         ≤ lengthOfSet (X.erase (~(ϕ⋏ψ))) + lengthOf (~ψ) : lengthOf_insert_leq_plus
     ... < lengthOfSet (X.erase (~(ϕ⋏ψ))) + 1 + 1 + lengthOf ϕ + lengthOf ψ :
           by { unfold lengthOf, unfold lengthOfFormula, ring_nf, simp, }
     ... = lengthOfSet (X.erase (~(ϕ⋏ψ))) + lengthOf (~(ϕ⋏ψ)) : by { unfold lengthOf, unfold lengthOfFormula, ring, }
     ... = lengthOfSet X : lengthRemove X (~(ϕ⋏ψ)) in_X,
    },
  },
end

lemma atmRuleDecreasesLength { X : finset formula } { ϕ } :
  ~□ϕ ∈ X → lengthOfSet (projection X ∪ {~ϕ}) < lengthOfSet X :=
begin
  intro notBoxPhi_in_X,
  simp,
    have proj_form_lt : ∀ f g, some g = formProjection f → lengthOfFormula g < lengthOfFormula f, {
      intros f g g_is_fP_f, cases f, all_goals { finish, },
    },
    have lengthSingleton : ∀ f, lengthOfFormula f = lengthOfSet { f }, {
      intro f, unfold lengthOfSet, simp,
    },
    have otherClaim : projection X = projection (X.erase (~□ϕ)), {
      ext1 phi,
      rw proj, rw proj,
      simp,
    },
    { calc lengthOfSet (insert (~ϕ) (projection X))
         ≤ lengthOfSet (projection X) + lengthOf (~ϕ) : lengthOf_insert_leq_plus
     ... = lengthOfSet (projection X) + 1 + lengthOf ϕ : by { unfold lengthOf, unfold lengthOfFormula, ring, }
     ... < lengthOfSet (projection X) + 1 + 1 + lengthOf ϕ : by { simp, }
     ... = lengthOfSet (projection X) + lengthOf (~□ϕ) : by { unfold lengthOf, unfold lengthOfFormula, ring, }
     ... = lengthOfSet (projection (X.erase (~□ϕ))) + lengthOf (~□ϕ) : by { rw otherClaim, }
     ... ≤ lengthOfSet (X.erase (~□ϕ)) + lengthOf (~□ϕ) : by { simp, apply projection_set_length_leq, }
     ... = lengthOfSet X : lengthRemove X (~□ϕ) notBoxPhi_in_X,
    }
end

-- Definition 8, page 14
-- mixed with Definition 11 (with all PDL stuff missing for now)
-- a local tableau for X, must be maximal
inductive localTableau : finset formula → Type
| byLocalRule { X B } (_ : localRule X B) (next : Π Y ∈ B, localTableau Y) : localTableau X
| sim { X } : simple X → localTableau X

open localTableau

-- needed for endNodesOf
instance localTableau_has_sizeof : has_sizeof (Σ {X}, localTableau X) := ⟨ λ ⟨X, T⟩, lengthOfSet X ⟩

-- open end nodes of a given localTableau
@[simp]
def endNodesOf : (Σ X, localTableau X) → finset (finset formula)
| ⟨X, @byLocalRule _ B lr next⟩ := B.attach.bUnion (λ ⟨Y,h⟩, have lengthOfSet Y < lengthOfSet X := localRulesDecreaseLength lr Y h, endNodesOf ⟨Y, next Y h⟩)
| ⟨X, sim _                   ⟩ := { X }

@[simp]
lemma botNoEndNodes {X h n} : endNodesOf ⟨X, localTableau.byLocalRule (@localRule.bot X h) n⟩ = ∅ := by { unfold endNodesOf, simp, }

@[simp]
lemma notNoEndNodes {X h ϕ n} : endNodesOf ⟨X, localTableau.byLocalRule (@localRule.not X h ϕ) n⟩ = ∅ := by { unfold endNodesOf, simp, }

lemma negEndNodes {X ϕ h n} : endNodesOf ⟨X, localTableau.byLocalRule (@localRule.neg X ϕ h) n⟩ =
  endNodesOf ⟨X \ {~~ϕ} ∪ {ϕ}, n (X \ {~~ϕ} ∪ {ϕ}) (by simp)⟩ :=
begin
  ext1,
  simp only [endNodesOf, finset.mem_singleton, finset.mem_bUnion, finset.mem_attach, exists_true_left, subtype.exists],
  split,
  { intro lhs, rcases lhs with ⟨b,bDef,bIn⟩, subst bDef, exact bIn, },
  { intro rhs, use (X \ {~~ϕ} ∪ {ϕ}), split, exact rhs, refl, },
end

lemma conEndNodes {X ϕ ψ h n} : endNodesOf ⟨X, localTableau.byLocalRule (@localRule.con X ϕ ψ h) n⟩ =
  endNodesOf ⟨X \ {ϕ⋏ψ} ∪ {ϕ,ψ}, n (X \ {ϕ⋏ψ} ∪ {ϕ,ψ}) (by simp)⟩ :=
begin
  ext1,
  simp only [endNodesOf, finset.mem_singleton, finset.mem_bUnion, finset.mem_attach, exists_true_left, subtype.exists],
  split,
{ intro lhs, rcases lhs with ⟨b,bDef,bIn⟩, subst bDef, exact bIn, },
{ intro rhs, use (X \ {ϕ⋏ψ} ∪ {ϕ,ψ}), split, exact rhs, refl, },
end

lemma nCoEndNodes {X ϕ ψ h n} : endNodesOf ⟨X, localTableau.byLocalRule (@localRule.nCo X ϕ ψ h) n⟩ =
  endNodesOf ⟨X \ {~(ϕ⋏ψ)} ∪ {~ϕ}, n (X \ {~(ϕ⋏ψ)} ∪ {~ϕ}) (by simp)⟩
  ∪ endNodesOf ⟨X \ {~(ϕ⋏ψ)} ∪ {~ψ}, n (X \ {~(ϕ⋏ψ)} ∪ {~ψ}) (by simp)⟩ :=
begin
  ext1,
  simp only [endNodesOf, finset.mem_singleton, finset.mem_bUnion, finset.mem_attach, exists_true_left, subtype.exists],
  split,
  { intro lhs, rcases lhs with ⟨b,bDef,bIn⟩,
    simp only [finset.mem_insert, finset.mem_singleton] at bDef, cases bDef with bD1 bD2,
    { subst bD1, simp, left, exact bIn, },
    { subst bD2, simp, right, exact bIn, },
  },
  { intro rhs, rw finset.mem_union at rhs, cases rhs,
    { use (X \ {~(ϕ⋏ψ)} ∪ {~ϕ}), split, exact rhs, simp, },
    { use (X \ {~(ϕ⋏ψ)} ∪ {~ψ}), split, exact rhs, simp, },
  },
end

-- Definition 16, page 29
inductive closedTableau : finset formula → Type
| loc {X} (lt : localTableau X) : (Π Y ∈ endNodesOf ⟨X, lt⟩, closedTableau Y) → closedTableau X
| atm {X ϕ} : ~□ϕ ∈ X → simple X → closedTableau (projection X ∪ {~ϕ}) → closedTableau X

inductive provable : formula → Prop
| byTableau {φ : formula} : closedTableau { ~ φ } → provable φ

-- Definition 17, page 30
def inconsistent : finset formula → Prop
| X := nonempty (closedTableau X)

def consistent : finset formula → Prop
| X := ¬ inconsistent X

def existsLocalTableauFor : ∀ N α, N = lengthOf α → nonempty (localTableau α) :=
begin
  intro N,
  apply nat.strong_induction_on N,
  intros n IH α nDef,
  have canApplyRule := em (¬ ∃ B, nonempty (localRule α B)),
  cases canApplyRule,
  { split,
    apply localTableau.sim,
    by_contradiction hyp,
    have := notSimpleThenLocalRule hyp,
    tauto,
  },
  { simp at canApplyRule,
    cases canApplyRule with B r_exists,
    cases r_exists with r,
    cases r,
    case bot : _ h {
      have t := localTableau.byLocalRule (localRule.bot h) _, use t,
      intro Y, intro Y_in_empty, tauto,
    },
    case not : _ _ h {
      have t := localTableau.byLocalRule (localRule.not h) _, use t,
      intro Y, intro Y_in_empty, tauto,
    },
    case neg : _ f h {
      have t:= localTableau.byLocalRule (localRule.neg h) _, use t,
      intros Y Y_def,
      have rDec := localRulesDecreaseLength (localRule.neg h) Y Y_def,
      subst nDef,
      specialize IH (lengthOf Y) rDec Y (refl _),
      apply classical.choice IH,
    },
    case con : _ f g h {
      have t := localTableau.byLocalRule (localRule.con h) _, use t,
      intros Y Y_def,
      have rDec := localRulesDecreaseLength (localRule.con h) Y Y_def,
      subst nDef,
      specialize IH (lengthOf Y) rDec Y (refl _),
      apply classical.choice IH,
    },
    case nCo : _ f g h {
      have t := localTableau.byLocalRule (localRule.nCo h) _, use t,
      intros Y Y_def,
      have rDec := localRulesDecreaseLength (localRule.nCo h) Y Y_def,
      subst nDef,
      specialize IH (lengthOf Y) rDec Y (refl _),
      apply classical.choice IH,
    },
  }
end

lemma endNodesOfLEQ {X Z ltX} :
  Z ∈ endNodesOf ⟨X, ltX⟩ → lengthOf Z ≤ lengthOf X :=
begin
  induction ltX,
  case byLocalRule : Y B lr next IH {
    intro Z_endOf_Y,
    have foo := localRulesDecreaseLength lr Y,
    unfold endNodesOf at Z_endOf_Y,
    simp at Z_endOf_Y,
    rcases Z_endOf_Y with ⟨W, W_in_B, Z_endOf_W⟩,
    apply le_of_lt,
    { calc lengthOf Z
         ≤ lengthOf W : IH W W_in_B Z_endOf_W
     ... < lengthOf Y : localRulesDecreaseLength lr W W_in_B },
  },
  case sim : a b {
    intro Z_endOf_Y,
    unfold endNodesOf at Z_endOf_Y,
    finish,
  },
end

lemma endNodesOfLocalRuleLT {X Z B next lr} :
  Z ∈ endNodesOf ⟨X, (@localTableau.byLocalRule _ B lr next)⟩ → lengthOf Z < lengthOf X :=
begin
  intros ZisEndNode,
  rw endNodesOf at ZisEndNode,
  simp only [finset.mem_bUnion, finset.mem_attach, exists_true_left, subtype.exists] at ZisEndNode,
  rcases ZisEndNode with ⟨a,a_in_WS,Z_endOf_a⟩,
  change Z ∈ endNodesOf ⟨a, next a a_in_WS⟩ at Z_endOf_a,
  { calc lengthOf Z
       ≤ lengthOf a : endNodesOfLEQ Z_endOf_a
   ... < lengthOfSet X : localRulesDecreaseLength lr a a_in_WS },
end


/-
Copyright (c) 2021 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison

! This file was ported from Lean 3 source module category_theory.path_category
! leanprover-community/mathlib commit f47581155c818e6361af4e4fda60d27d020c226b
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.CategoryTheory.EqToHom
import Mathbin.CategoryTheory.Quotient
import Mathbin.Combinatorics.Quiver.Path

/-!
# The category paths on a quiver.

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.
When `C` is a quiver, `paths C` is the category of paths.

## When the quiver is itself a category
We provide `path_composition : paths C ⥤ C`.

We check that the quotient of the path category of a category by the canonical relation
(paths are related if they compose to the same path) is equivalent to the original category.
-/

universe v₁ v₂ u₁ u₂

namespace CategoryTheory

section

#print CategoryTheory.Paths /-
/-- A type synonym for the category of paths in a quiver.
-/
def Paths (V : Type u₁) : Type u₁ :=
  V
#align category_theory.paths CategoryTheory.Paths
-/

instance (V : Type u₁) [Inhabited V] : Inhabited (Paths V) :=
  ⟨(default : V)⟩

variable (V : Type u₁) [Quiver.{v₁ + 1} V]

namespace Paths

#print CategoryTheory.Paths.categoryPaths /-
instance categoryPaths : Category.{max u₁ v₁} (Paths V)
    where
  Hom := fun X Y : V => Quiver.Path X Y
  id X := Quiver.Path.nil
  comp X Y Z f g := Quiver.Path.comp f g
#align category_theory.paths.category_paths CategoryTheory.Paths.categoryPaths
-/

variable {V}

#print CategoryTheory.Paths.of /-
/-- The inclusion of a quiver `V` into its path category, as a prefunctor.
-/
@[simps]
def of : V ⥤q Paths V where
  obj X := X
  map X Y f := f.toPath
#align category_theory.paths.of CategoryTheory.Paths.of
-/

attribute [local ext] Functor.ext

#print CategoryTheory.Paths.lift /-
/-- Any prefunctor from `V` lifts to a functor from `paths V` -/
def lift {C} [Category C] (φ : V ⥤q C) : Paths V ⥤ C
    where
  obj := φ.obj
  map X Y f :=
    @Quiver.Path.rec V _ X (fun Y f => φ.obj X ⟶ φ.obj Y) (𝟙 <| φ.obj X)
      (fun Y Z p f ihp => ihp ≫ φ.map f) Y f
  map_id' X := by rfl
  map_comp' X Y Z f g := by
    induction' g with _ _ g' p ih _ _ _
    · rw [category.comp_id]
      rfl
    · have : f ≫ g'.cons p = (f ≫ g').cons p := by apply Quiver.Path.comp_cons
      rw [this]
      simp only
      rw [ih, category.assoc]
#align category_theory.paths.lift CategoryTheory.Paths.lift
-/

/- warning: category_theory.paths.lift_nil -> CategoryTheory.Paths.lift_nil is a dubious translation:
lean 3 declaration is
  forall {V : Type.{u2}} [_inst_1 : Quiver.{succ u1, u2} V] {C : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u4, u3} C] (φ : Prefunctor.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2))) (X : V), Eq.{succ u4} (Quiver.Hom.{succ u4, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2)) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) X) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) X)) (CategoryTheory.Functor.map.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) X X (Quiver.Path.nil.{succ u1, u2} V _inst_1 X)) (CategoryTheory.CategoryStruct.id.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2) (Prefunctor.obj.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2)) φ X))
but is expected to have type
  forall {V : Type.{u4}} [_inst_1 : Quiver.{succ u3, u4} V] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u1, u2} C] (φ : Prefunctor.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2))) (X : V), Eq.{succ u1} (Quiver.Hom.{succ u1, u2} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) X) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) X)) (Prefunctor.map.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) X X (Quiver.Path.nil.{succ u3, u4} V _inst_1 X)) (CategoryTheory.CategoryStruct.id.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2) (Prefunctor.obj.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) φ X))
Case conversion may be inaccurate. Consider using '#align category_theory.paths.lift_nil CategoryTheory.Paths.lift_nilₓ'. -/
@[simp]
theorem lift_nil {C} [Category C] (φ : V ⥤q C) (X : V) :
    (lift φ).map Quiver.Path.nil = 𝟙 (φ.obj X) :=
  rfl
#align category_theory.paths.lift_nil CategoryTheory.Paths.lift_nil

/- warning: category_theory.paths.lift_cons -> CategoryTheory.Paths.lift_cons is a dubious translation:
lean 3 declaration is
  forall {V : Type.{u2}} [_inst_1 : Quiver.{succ u1, u2} V] {C : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u4, u3} C] (φ : Prefunctor.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2))) {X : V} {Y : V} {Z : V} (p : Quiver.Path.{succ u1, u2} V _inst_1 X Y) (f : Quiver.Hom.{succ u1, u2} V _inst_1 Y Z), Eq.{succ u4} (Quiver.Hom.{succ u4, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2)) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) X) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) Z)) (CategoryTheory.Functor.map.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) X Z (Quiver.Path.cons.{succ u1, u2} V _inst_1 X Y Z p f)) (CategoryTheory.CategoryStruct.comp.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) X) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) Y) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) Z) (CategoryTheory.Functor.map.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) X Y p) (Prefunctor.map.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2)) φ Y Z f))
but is expected to have type
  forall {V : Type.{u4}} [_inst_1 : Quiver.{succ u3, u4} V] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u1, u2} C] (φ : Prefunctor.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2))) {X : V} {Y : V} {Z : V} (p : Quiver.Path.{succ u3, u4} V _inst_1 X Y) (f : Quiver.Hom.{succ u3, u4} V _inst_1 Y Z), Eq.{succ u1} (Quiver.Hom.{succ u1, u2} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) X) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) Z)) (Prefunctor.map.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) X Z (Quiver.Path.cons.{succ u3, u4} V _inst_1 X Y Z p f)) (CategoryTheory.CategoryStruct.comp.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) X) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) Y) (Prefunctor.obj.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) φ Z) (Prefunctor.map.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) X Y p) (Prefunctor.map.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) φ Y Z f))
Case conversion may be inaccurate. Consider using '#align category_theory.paths.lift_cons CategoryTheory.Paths.lift_consₓ'. -/
@[simp]
theorem lift_cons {C} [Category C] (φ : V ⥤q C) {X Y Z : V} (p : Quiver.Path X Y) (f : Y ⟶ Z) :
    (lift φ).map (p.cons f) = (lift φ).map p ≫ φ.map f :=
  rfl
#align category_theory.paths.lift_cons CategoryTheory.Paths.lift_cons

/- warning: category_theory.paths.lift_to_path -> CategoryTheory.Paths.lift_toPath is a dubious translation:
lean 3 declaration is
  forall {V : Type.{u2}} [_inst_1 : Quiver.{succ u1, u2} V] {C : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u4, u3} C] (φ : Prefunctor.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2))) {X : V} {Y : V} (f : Quiver.Hom.{succ u1, u2} V _inst_1 X Y), Eq.{succ u4} (Quiver.Hom.{succ u4, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2)) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) X) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) Y)) (CategoryTheory.Functor.map.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ) X Y (Quiver.Hom.toPath.{u2, succ u1} V _inst_1 X Y f)) (Prefunctor.map.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2)) φ X Y f)
but is expected to have type
  forall {V : Type.{u4}} [_inst_1 : Quiver.{succ u3, u4} V] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u1, u2} C] (φ : Prefunctor.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2))) {X : V} {Y : V} (f : Quiver.Hom.{succ u3, u4} V _inst_1 X Y), Eq.{succ u1} (Quiver.Hom.{succ u1, u2} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) X) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) Y)) (Prefunctor.map.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ)) X Y (Quiver.Hom.toPath.{u4, succ u3} V _inst_1 X Y f)) (Prefunctor.map.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) φ X Y f)
Case conversion may be inaccurate. Consider using '#align category_theory.paths.lift_to_path CategoryTheory.Paths.lift_toPathₓ'. -/
@[simp]
theorem lift_toPath {C} [Category C] (φ : V ⥤q C) {X Y : V} (f : X ⟶ Y) :
    (lift φ).map f.toPath = φ.map f :=
  by
  dsimp [Quiver.Hom.toPath, lift]
  simp
#align category_theory.paths.lift_to_path CategoryTheory.Paths.lift_toPath

/- warning: category_theory.paths.lift_spec -> CategoryTheory.Paths.lift_spec is a dubious translation:
lean 3 declaration is
  forall {V : Type.{u2}} [_inst_1 : Quiver.{succ u1, u2} V] {C : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u4, u3} C] (φ : Prefunctor.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2))), Eq.{max (max (succ u2) (succ u1) (succ u4)) (succ u2) (succ u3)} (Prefunctor.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2))) (Prefunctor.comp.{u2, succ u1, u2, succ (max u2 u1), u3, succ u4} V _inst_1 (CategoryTheory.Paths.{u2} V) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u1, u2} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Category.toCategoryStruct.{max u2 u1, u2} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2)) (CategoryTheory.Paths.of.{u1, u2} V _inst_1) (CategoryTheory.Functor.toPrefunctor.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ))) φ
but is expected to have type
  forall {V : Type.{u4}} [_inst_1 : Quiver.{succ u3, u4} V] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u1, u2} C] (φ : Prefunctor.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2))), Eq.{max (max (max (succ u4) (succ u3)) (succ u2)) (succ u1)} (Prefunctor.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2))) (Prefunctor.comp.{u4, succ u3, u4, max (succ u4) (succ u3), u2, succ u1} V _inst_1 (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Paths.of.{u3, u4} V _inst_1) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ))) φ
Case conversion may be inaccurate. Consider using '#align category_theory.paths.lift_spec CategoryTheory.Paths.lift_specₓ'. -/
theorem lift_spec {C} [Category C] (φ : V ⥤q C) : of ⋙q (lift φ).toPrefunctor = φ :=
  by
  apply Prefunctor.ext; rotate_left
  · rintro X
    rfl
  · rintro X Y f
    rcases φ with ⟨φo, φm⟩
    dsimp [lift, Quiver.Hom.toPath]
    simp only [category.id_comp]
#align category_theory.paths.lift_spec CategoryTheory.Paths.lift_spec

/- warning: category_theory.paths.lift_unique -> CategoryTheory.Paths.lift_unique is a dubious translation:
lean 3 declaration is
  forall {V : Type.{u2}} [_inst_1 : Quiver.{succ u1, u2} V] {C : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u4, u3} C] (φ : Prefunctor.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2))) (Φ : CategoryTheory.Functor.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2), (Eq.{max (max (succ u2) (succ u1) (succ u4)) (succ u2) (succ u3)} (Prefunctor.{succ u1, succ u4, u2, u3} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2))) (Prefunctor.comp.{u2, succ u1, u2, succ (max u2 u1), u3, succ u4} V _inst_1 (CategoryTheory.Paths.{u2} V) (CategoryTheory.CategoryStruct.toQuiver.{max u2 u1, u2} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Category.toCategoryStruct.{max u2 u1, u2} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2)) (CategoryTheory.Paths.of.{u1, u2} V _inst_1) (CategoryTheory.Functor.toPrefunctor.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 Φ)) φ) -> (Eq.{succ (max (max u2 u1) u4 u2 u3)} (CategoryTheory.Functor.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2) Φ (CategoryTheory.Paths.lift.{u1, u2, u3, u4} V _inst_1 C _inst_2 φ))
but is expected to have type
  forall {V : Type.{u4}} [_inst_1 : Quiver.{succ u3, u4} V] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u1, u2} C] (φ : Prefunctor.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2))) (Φ : CategoryTheory.Functor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2), (Eq.{max (max (max (succ u4) (succ u3)) (succ u2)) (succ u1)} (Prefunctor.{succ u3, succ u1, u4, u2} V _inst_1 C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2))) (Prefunctor.comp.{u4, succ u3, u4, max (succ u4) (succ u3), u2, succ u1} V _inst_1 (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Paths.of.{u3, u4} V _inst_1) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 Φ)) φ) -> (Eq.{max (max (max (succ u4) (succ u3)) (succ u2)) (succ u1)} (CategoryTheory.Functor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2) Φ (CategoryTheory.Paths.lift.{u3, u4, u2, u1} V _inst_1 C _inst_2 φ))
Case conversion may be inaccurate. Consider using '#align category_theory.paths.lift_unique CategoryTheory.Paths.lift_uniqueₓ'. -/
theorem lift_unique {C} [Category C] (φ : V ⥤q C) (Φ : Paths V ⥤ C)
    (hΦ : of ⋙q Φ.toPrefunctor = φ) : Φ = lift φ :=
  by
  subst_vars
  apply Functor.ext; rotate_left
  · rintro X
    rfl
  · rintro X Y f
    dsimp [lift]
    induction' f with _ _ p f' ih
    · simp only [category.comp_id]
      apply Functor.map_id
    · simp only [category.comp_id, category.id_comp] at ih⊢
      have : Φ.map (p.cons f') = Φ.map p ≫ Φ.map f'.to_path := by
        convert functor.map_comp Φ p f'.to_path
      rw [this, ih]
#align category_theory.paths.lift_unique CategoryTheory.Paths.lift_unique

/- warning: category_theory.paths.ext_functor -> CategoryTheory.Paths.ext_functor is a dubious translation:
lean 3 declaration is
  forall {V : Type.{u2}} [_inst_1 : Quiver.{succ u1, u2} V] {C : Type.{u3}} [_inst_2 : CategoryTheory.Category.{u4, u3} C] {F : CategoryTheory.Functor.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2} {G : CategoryTheory.Functor.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2} (h_obj : Eq.{max (succ u2) (succ u3)} ((CategoryTheory.Paths.{u2} V) -> C) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G)), (forall (a : V) (b : V) (e : Quiver.Hom.{succ u1, u2} V _inst_1 a b), Eq.{succ u4} (Quiver.Hom.{succ u4, u3} C (CategoryTheory.CategoryStruct.toQuiver.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2)) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F a) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F b)) (CategoryTheory.Functor.map.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F a b (Quiver.Hom.toPath.{u2, succ u1} V _inst_1 a b e)) (CategoryTheory.CategoryStruct.comp.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F a) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G a) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F b) (CategoryTheory.eqToHom.{u4, u3} C _inst_2 (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F a) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G a) (congr_fun.{succ u2, succ u3} V (fun (x : V) => C) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G) h_obj a)) (CategoryTheory.CategoryStruct.comp.{u4, u3} C (CategoryTheory.Category.toCategoryStruct.{u4, u3} C _inst_2) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G a) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G b) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F b) (CategoryTheory.Functor.map.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G a b (Quiver.Hom.toPath.{u2, succ u1} V _inst_1 a b e)) (CategoryTheory.eqToHom.{u4, u3} C _inst_2 (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G b) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F b) (congr_fun.{succ u2, succ u3} V (fun (x : V) => C) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G) (fun (b : V) => CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F b) (Eq.symm.{max (succ u2) (succ u3)} ((CategoryTheory.Paths.{u2} V) -> C) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 F) (CategoryTheory.Functor.obj.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2 G) h_obj) b))))) -> (Eq.{succ (max (max u2 u1) u4 u2 u3)} (CategoryTheory.Functor.{max u2 u1, u4, u2, u3} (CategoryTheory.Paths.{u2} V) (CategoryTheory.Paths.categoryPaths.{u1, u2} V _inst_1) C _inst_2) F G)
but is expected to have type
  forall {V : Type.{u4}} [_inst_1 : Quiver.{succ u3, u4} V] {C : Type.{u2}} [_inst_2 : CategoryTheory.Category.{u1, u2} C] {F : CategoryTheory.Functor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2} {G : CategoryTheory.Functor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2} (h_obj : Eq.{max (succ u4) (succ u2)} ((CategoryTheory.Paths.{u4} V) -> C) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F)) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G))), (forall (a : V) (b : V) (e : Quiver.Hom.{succ u3, u4} V _inst_1 a b), Eq.{succ u1} (Quiver.Hom.{succ u1, u2} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F) a) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F) b)) (Prefunctor.map.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F) a b (Quiver.Hom.toPath.{u4, succ u3} V _inst_1 a b e)) (CategoryTheory.CategoryStruct.comp.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F) a) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G) a) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F) b) (CategoryTheory.eqToHom.{u1, u2} C _inst_2 (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F) a) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G) a) (congr_fun.{succ u4, succ u2} (CategoryTheory.Paths.{u4} V) (fun (x : CategoryTheory.Paths.{u4} V) => C) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F)) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G)) h_obj a)) (CategoryTheory.CategoryStruct.comp.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G) a) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G) b) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F) b) (Prefunctor.map.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G) a b (Quiver.Hom.toPath.{u4, succ u3} V _inst_1 a b e)) (CategoryTheory.eqToHom.{u1, u2} C _inst_2 (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G) b) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F) b) (congr_fun.{succ u4, succ u2} (CategoryTheory.Paths.{u4} V) (fun (x : CategoryTheory.Paths.{u4} V) => C) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G)) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F)) (Eq.symm.{max (succ u4) (succ u2)} ((CategoryTheory.Paths.{u4} V) -> C) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 F)) (Prefunctor.obj.{max (succ u4) (succ u3), succ u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.CategoryStruct.toQuiver.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Category.toCategoryStruct.{max u4 u3, u4} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1))) C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_2)) (CategoryTheory.Functor.toPrefunctor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2 G)) h_obj) b))))) -> (Eq.{max (max (max (succ u4) (succ u3)) (succ u2)) (succ u1)} (CategoryTheory.Functor.{max u4 u3, u1, u4, u2} (CategoryTheory.Paths.{u4} V) (CategoryTheory.Paths.categoryPaths.{u3, u4} V _inst_1) C _inst_2) F G)
Case conversion may be inaccurate. Consider using '#align category_theory.paths.ext_functor CategoryTheory.Paths.ext_functorₓ'. -/
/-- Two functors out of a path category are equal when they agree on singleton paths. -/
@[ext]
theorem ext_functor {C} [Category C] {F G : Paths V ⥤ C} (h_obj : F.obj = G.obj)
    (h :
      ∀ (a b : V) (e : a ⟶ b),
        F.map e.toPath =
          eqToHom (congr_fun h_obj a) ≫ G.map e.toPath ≫ eqToHom (congr_fun h_obj.symm b)) :
    F = G := by
  ext (X Y f)
  · induction' f with Y' Z' g e ih
    · erw [F.map_id, G.map_id, category.id_comp, eq_to_hom_trans, eq_to_hom_refl]
    · erw [F.map_comp g e.to_path, G.map_comp g e.to_path, ih, h]
      simp only [category.id_comp, eq_to_hom_refl, eq_to_hom_trans_assoc, category.assoc]
  · intro X
    rw [h_obj]
#align category_theory.paths.ext_functor CategoryTheory.Paths.ext_functor

end Paths

variable (W : Type u₂) [Quiver.{v₂ + 1} W]

#print CategoryTheory.Prefunctor.mapPath_comp' /-
-- A restatement of `prefunctor.map_path_comp` using `f ≫ g` instead of `f.comp g`.
@[simp]
theorem Prefunctor.mapPath_comp' (F : V ⥤q W) {X Y Z : Paths V} (f : X ⟶ Y) (g : Y ⟶ Z) :
    F.mapPath (f ≫ g) = (F.mapPath f).comp (F.mapPath g) :=
  Prefunctor.mapPath_comp _ _ _
#align category_theory.prefunctor.map_path_comp' CategoryTheory.Prefunctor.mapPath_comp'
-/

end

section

variable {C : Type u₁} [Category.{v₁} C]

open Quiver

#print CategoryTheory.composePath /-
/-- A path in a category can be composed to a single morphism. -/
@[simp]
def composePath {X : C} : ∀ {Y : C} (p : Path X Y), X ⟶ Y
  | _, path.nil => 𝟙 X
  | _, path.cons p e => compose_path p ≫ e
#align category_theory.compose_path CategoryTheory.composePath
-/

#print CategoryTheory.composePath_toPath /-
@[simp]
theorem composePath_toPath {X Y : C} (f : X ⟶ Y) : composePath f.toPath = f :=
  Category.id_comp _
#align category_theory.compose_path_to_path CategoryTheory.composePath_toPath
-/

#print CategoryTheory.composePath_comp /-
@[simp]
theorem composePath_comp {X Y Z : C} (f : Path X Y) (g : Path Y Z) :
    composePath (f.comp g) = composePath f ≫ composePath g :=
  by
  induction' g with Y' Z' g e ih
  · simp
  · simp [ih]
#align category_theory.compose_path_comp CategoryTheory.composePath_comp
-/

#print CategoryTheory.composePath_id /-
@[simp]
theorem composePath_id {X : Paths C} : composePath (𝟙 X) = 𝟙 X :=
  rfl
#align category_theory.compose_path_id CategoryTheory.composePath_id
-/

#print CategoryTheory.composePath_comp' /-
@[simp]
theorem composePath_comp' {X Y Z : Paths C} (f : X ⟶ Y) (g : Y ⟶ Z) :
    composePath (f ≫ g) = composePath f ≫ composePath g :=
  composePath_comp f g
#align category_theory.compose_path_comp' CategoryTheory.composePath_comp'
-/

variable (C)

#print CategoryTheory.pathComposition /-
/-- Composition of paths as functor from the path category of a category to the category. -/
@[simps]
def pathComposition : Paths C ⥤ C where
  obj X := X
  map X Y f := composePath f
#align category_theory.path_composition CategoryTheory.pathComposition
-/

#print CategoryTheory.pathsHomRel /-
-- TODO: This, and what follows, should be generalized to
-- the `hom_rel` for the kernel of any functor.
-- Indeed, this should be part of an equivalence between congruence relations on a category `C`
-- and full, essentially surjective functors out of `C`.
/-- The canonical relation on the path category of a category:
two paths are related if they compose to the same morphism. -/
@[simp]
def pathsHomRel : HomRel (Paths C) := fun X Y p q =>
  (pathComposition C).map p = (pathComposition C).map q
#align category_theory.paths_hom_rel CategoryTheory.pathsHomRel
-/

#print CategoryTheory.toQuotientPaths /-
/-- The functor from a category to the canonical quotient of its path category. -/
@[simps]
def toQuotientPaths : C ⥤ Quotient (pathsHomRel C)
    where
  obj X := Quotient.mk X
  map X Y f := Quot.mk _ f.toPath
  map_id' X := Quot.sound (Quotient.CompClosure.of _ _ _ (by simp))
  map_comp' X Y Z f g := Quot.sound (Quotient.CompClosure.of _ _ _ (by simp))
#align category_theory.to_quotient_paths CategoryTheory.toQuotientPaths
-/

#print CategoryTheory.quotientPathsTo /-
/-- The functor from the canonical quotient of a path category of a category
to the original category. -/
@[simps]
def quotientPathsTo : Quotient (pathsHomRel C) ⥤ C :=
  Quotient.lift _ (pathComposition C) fun X Y p q w => w
#align category_theory.quotient_paths_to CategoryTheory.quotientPathsTo
-/

/- warning: category_theory.quotient_paths_equiv -> CategoryTheory.quotientPathsEquiv is a dubious translation:
lean 3 declaration is
  forall (C : Type.{u2}) [_inst_1 : CategoryTheory.Category.{u1, u2} C], CategoryTheory.Equivalence.{max u2 u1, u1, u2, u2} (CategoryTheory.Quotient.{u2, max u2 u1} (CategoryTheory.Paths.{u2} C) (CategoryTheory.Paths.categoryPaths.{u1, u2} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_1))) (CategoryTheory.pathsHomRel.{u1, u2} C _inst_1)) (CategoryTheory.Quotient.category.{u2, max u2 u1} (CategoryTheory.Paths.{u2} C) (CategoryTheory.Paths.categoryPaths.{u1, u2} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_1))) (CategoryTheory.pathsHomRel.{u1, u2} C _inst_1)) C _inst_1
but is expected to have type
  forall (C : Type.{u2}) [_inst_1 : CategoryTheory.Category.{u1, u2} C], CategoryTheory.Equivalence.{max u2 u1, u1, u2, u2} (CategoryTheory.Quotient.{u2, max u2 u1} (CategoryTheory.Paths.{u2} C) (CategoryTheory.Paths.categoryPaths.{u1, u2} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_1))) (CategoryTheory.pathsHomRel.{u1, u2} C _inst_1)) C (CategoryTheory.Quotient.category.{u2, max u2 u1} (CategoryTheory.Paths.{u2} C) (CategoryTheory.Paths.categoryPaths.{u1, u2} C (CategoryTheory.CategoryStruct.toQuiver.{u1, u2} C (CategoryTheory.Category.toCategoryStruct.{u1, u2} C _inst_1))) (CategoryTheory.pathsHomRel.{u1, u2} C _inst_1)) _inst_1
Case conversion may be inaccurate. Consider using '#align category_theory.quotient_paths_equiv CategoryTheory.quotientPathsEquivₓ'. -/
/-- The canonical quotient of the path category of a category
is equivalent to the original category. -/
def quotientPathsEquiv : Quotient (pathsHomRel C) ≌ C
    where
  Functor := quotientPathsTo C
  inverse := toQuotientPaths C
  unitIso :=
    NatIso.ofComponents
      (fun X => by
        cases X
        rfl)
      (by
        intros
        cases X; cases Y
        induction f
        dsimp
        simp only [category.comp_id, category.id_comp]
        apply Quot.sound
        apply quotient.comp_closure.of
        simp [paths_hom_rel])
  counitIso := NatIso.ofComponents (fun X => Iso.refl _) (by tidy)
  functor_unitIso_comp' := by
    intros
    cases X
    dsimp
    simp
    rfl
#align category_theory.quotient_paths_equiv CategoryTheory.quotientPathsEquiv

end

end CategoryTheory


structure A where
  a : Nat

structure B where
  a : Nat
  b : Nat
  c : Nat := a + b

structure C extends B where
  d : Nat := 0
  e : Nat := 0

structure D extends A, C

def f (a b : Nat) : D :=
  { a, b }

theorem ex1 (a b : Nat) : (f a b |>.c) = a + b :=
  rfl

structure C' extends B where
  d : Nat
  e : Nat
  c := d + e

structure D' extends A, C'

def f' (a b d e: Nat) : D' :=
  { a, b, d, e }

theorem ex2 (a b d e: Nat) : (f' a b d e |>.c) = d + e :=
  rfl

structure D'' extends A, C' where
  c := a

def f'' (a b d e : Nat) : D'' :=
  { a, b, d, e }

theorem ex3 (a b d e: Nat) : (f'' a b d e |>.c) = a :=
  rfl

structure B1 where
  a : Nat
  b : Nat

structure C1 extends B1 where
  d : Nat
  e : Nat
  c : Nat := b + e

structure D1 extends A, C1

def f1 (a b d e : Nat) : D1 :=
  { a, b, d, e }

theorem ex4 (a b d e: Nat) : (f1 a b d e |>.c) = b + e :=
  rfl

structure B2 where
  a : Nat
  b : Nat
  c : Nat

structure C2 extends B2 where
  d : Nat
  e : Nat
  c := b + e

structure D2 extends A, C2

def f2 (a b d e : Nat) : D2 :=
  { a, b, d, e }

theorem ex5 (a b d e: Nat) : (f2 a b d e |>.c) = b + e :=
  rfl


theorem ex (n : Nat) (h : n = 0) : 0 + n = 0 := by
  let m := n + 1
  let v := m + 1
  have : v = n + 2 := rfl
  trace_state
  subst h
  trace_state
  rfl


/-
Copyright (c) 2020 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Mario Carneiro
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.data.num.lemmas
import Mathlib.data.nat.prime
import Mathlib.tactic.ring
import Mathlib.PostPort

namespace Mathlib

/-!
# Primality for binary natural numbers

This file defines versions of `nat.min_fac` and `nat.prime` for `num` and `pos_num`. As with other
`num` definitions, they are not intended for general use (`nat` should be used instead of `num` in
most cases) but they can be used in contexts where kernel computation is required, such as proofs
by `rfl` and `dec_trivial`, as well as in `#reduce`.

The default decidable instance for `nat.prime` is optimized for VM evaluation, so it should be
preferred within `#eval` or in tactic execution, while for proofs the `norm_num` tactic can be used
to construct primality and non-primality proofs more efficiently than kernel computation.

Nevertheless, sometimes proof by computational reflection requires natural number computations, and
`num` implements algorithms directly on binary natural numbers for this purpose.
-/

namespace pos_num

/-- Auxiliary function for computing the smallest prime factor of a `pos_num`. Unlike
`nat.min_fac_aux`, we use a natural number `fuel` variable that is set to an upper bound on the
number of iterations. It is initialized to the number `n` we are determining primality for. Even
though this is exponential in the input (since it is a `nat`, not a `num`), it will get lazily
evaluated during kernel reduction, so we will only require about `sqrt n` unfoldings, for the
`sqrt n` iterations of the loop. -/
def min_fac_aux (n : pos_num) : ℕ → pos_num → pos_num := sorry

theorem min_fac_aux_to_nat {fuel : ℕ} {n : pos_num} {k : pos_num}
    (h : nat.sqrt ↑n < fuel + ↑(bit1 k)) : ↑(min_fac_aux n fuel k) = nat.min_fac_aux ↑n ↑(bit1 k) :=
  sorry

/-- Returns the smallest prime factor of `n ≠ 1`. -/
def min_fac : pos_num → pos_num := sorry

@[simp] theorem min_fac_to_nat (n : pos_num) : ↑(min_fac n) = nat.min_fac ↑n := sorry

/-- Primality predicate for a `pos_num`. -/
@[simp] def prime (n : pos_num) := nat.prime ↑n

protected instance decidable_prime : decidable_pred prime := sorry

end pos_num

namespace num

/-- Returns the smallest prime factor of `n ≠ 1`. -/
def min_fac : num → pos_num := sorry

@[simp] theorem min_fac_to_nat (n : num) : ↑(min_fac n) = nat.min_fac ↑n :=
  num.cases_on n (idRhs (↑(min_fac 0) = ↑(min_fac 0)) rfl)
    fun (n : pos_num) => idRhs (↑(pos_num.min_fac n) = nat.min_fac ↑n) (pos_num.min_fac_to_nat n)

/-- Primality predicate for a `num`. -/
@[simp] def prime (n : num) := nat.prime ↑n

protected instance decidable_prime : decidable_pred prime := sorry

end Mathlib


import .quantum_state
import .inner_product
import .operators
import .paired_states

namespace quantum

variables {n m p q : ℕ}

/-
 No unitary operator can exist that transforms any given quantum state
 into a copy of another quantum state

 - "Raw materials", |r⟩ : an arbitrary quantum state to be transformed by U.
 Since the specific value of r is nor important, we simply set it to the |z₊⟩ state
 - "Charlie", |c⟩ : a  quantum state to be cloned

 This proof is specifically for spin-1/2 particles (2D vectors) but is true in general
 and could be extened to any n if lean's sum library was more cooperative.
-/

theorem no_cloning :
 ¬∃(U : matrix (fin (4)) (fin (4)) ℂ), unitary U ∧ (∀(c : matrix (fin 2) (fin 1) ℂ), U ⬝ (c ⊗ z₊) = (c ⊗ c)) :=
begin
  apply not.intro,
  intro U_exists,
  apply exists.elim U_exists,
  intros U U_conds,
  apply and.elim U_conds,
  intros U_unitary U_clones,
  rw [unitary] at U_unitary,
  -- take two nonequal, nonorthogonal quantum states
  let c1 : QState 2 1 := z_plus,
  let c2 : QState 2 1 := x_plus,
  -- derive contradiction by showing that their inner product must be 0 or 1
  have clone_c1 : U ⬝ c1 ⊗ z₊ = c1 ⊗ c1, by apply U_clones c1,
  have clone_c2 : U ⬝ c2 ⊗ z₊ = c2 ⊗ c2, by apply U_clones c2,

  have ip_eq_square : ⟪c1|c2⟫ = ⟪c1|c2⟫*⟪c1|c2⟫,
  calc ⟪c1|c2⟫
   = ⟪c1|c2⟫ * 1 : by ring
   ... = ⟪c1|c2⟫ * ⟪z₊|z₊⟫ : by rw [eq.symm z_plus_prod_z_plus']
   ... = ⟪(c1 ⊗ z₊)|(c2 ⊗ z₊)⟫ : by rw [inner_prod_indep_states_eq_prod]
   ... = ⟪(c1 ⊗ z₊)|(1 ⬝ (c2 ⊗ z₊))⟫ : by simp
   ... = ⟪(c1 ⊗ z₊)|((U† ⬝ U) ⬝ (c2 ⊗ z₊))⟫ : by rw [U_unitary]
   ... = ⟪(c1 ⊗ z₊)|(U† ⬝ (U ⬝ (c2 ⊗ z₊)))⟫ : by  rw [matrix.mul_assoc]
   ... = ⟪(c1 ⊗ z₊)|(U† ⬝ (c2 ⊗ c2))⟫ : by rw [clone_c2]
   ... = ⟪(U ⬝ (c1 ⊗ z₊))|(c2 ⊗ c2)⟫ : by rw [inner_prod_matrix_ct]
   ... = ⟪(c1 ⊗ c1)|(c2 ⊗ c2)⟫ : by rw [clone_c1]
   ...= ⟪c1|c2⟫*⟪c1|c2⟫ : by rw [inner_prod_indep_states_eq_prod],

  -- if the inner product equals its own square, must be 0 or 1
  have ip_eq_zero_or_one : ⟪c1|c2⟫ = 0 ∨ ⟪c1|c2⟫ = 1, by begin
    apply or_iff_not_imp_left.mpr,
    intro not_zero,
    calc ⟪c1|c2⟫
     = ⟪c1|c2⟫ * 1 : by ring
     ... = ⟪c1|c2⟫ * (⟪c1|c2⟫ * ⟪c1|c2⟫⁻¹) : by rw [complex.mul_inv_cancel not_zero]
     ... = (⟪c1|c2⟫ * ⟪c1|c2⟫) * ⟪c1|c2⟫⁻¹ : by rw [mul_assoc]
     ... = ⟪c1|c2⟫ * ⟪c1|c2⟫⁻¹ : by rw [eq.symm ip_eq_square]
     ... = 1 : by rw [complex.mul_inv_cancel not_zero],
  end,

  -- hoerver, already know since nonequal, nonorthogonal, inner product must not equal 0 or 1
  -- (in this case 1/2)
  have ip_c1_c2 : 1/2 = |⟪c1|c2⟫|², from eq.symm z_plus_prod_x_plus,
  apply or.elim ip_eq_zero_or_one,
  {intro ip_eq_zero,
   simp [ip_eq_zero] at ip_c1_c2,
   exact ip_c1_c2},
   {intro ip_eq_one,
   simp [ip_eq_one] at ip_c1_c2,
   exact (succ_ne_self 1) ip_c1_c2},
end

end quantum


/-
# The Natural Number Game, version 1.3.3

## By Kevin Buzzard and Mohammad Pedramfar.

# What is this game?

Welcome to the natural number game -- a part-book part-game which shows the power of induction.
Blue nodes on the graph are ones that you are ready to enter. Grey nodes you should stay away
from -- a grey node turns blue when *all* nodes above it are complete. Green nodes are completed.
(Actually you can try any level at any time, but you might not know enough to complete it if it's grey).

In this game, you get own version of the natural numbers, called `mynat`, in an interactive
theorem prover called Lean. Your version of the natural numbers satisfies something called
the principle of mathematical induction, and a couple of other things too (Peano's axioms).
Unfortunately, nobody has proved any theorems about these
natural numbers yet! For example, addition will be defined for you,
but nobody has proved that `x + y = y + x` yet. This is your job. You're going to
prove mathematical theorems using the Lean theorem prover. In other words, you're going to solve
levels in a computer game.

You're going to prove these theorems using *tactics*. The introductory world, Tutorial World,
will take you through some of these tactics. During your proofs, your "goal" (i.e. what you're
supposed to be proving) will be displayed with  a `⊢` symbol in front of it. If the top
right hand box reports "Theorem Proved!", you have closed all the goals in the level
and can move on to the next level in the world you're in. When you've finished a world,
hit "main menu" in the top left to get back here.

For more info, see the FAQ.

# What's new in v1.3?

The game now saves your progress! Thanks to everyone who asked for it,
and to Mohammad for making it happen :-)

Cute little clipboard to copy your solutions.

# Thanks

Special thanks to Rob Lewis for tactic hackery, Bryan Gin-Ge Chen for
javascript hackery, Patrick Massot for his
Lean to html formatter,
Sian Carey for Power World,
and, last but not least, all the people who fed back comments, including
the 2019-20 Imperial College 1st year maths beta tester students, Marie-Amélie Lawn,
Toby Gee, Joseph Myers, and all the people who have been in touch
via the Lean Zulip chat
 or the Xena Project blog
 or via Twitter.
The natural number game is brought to you by the Xena project, a project based at Imperial College London
whose aim is to get mathematics undergraduates using computer theorem provers.
Lean is a computer theorem prover being developed at Microsoft Research.

Prove a theorem. Write a function. @XenaProject.
-/