Skip to content

Commit

Permalink
WIP: refactor: factor out a QPFExpr abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
alexkeizer committed Nov 1, 2024
1 parent fc4fe05 commit 2b3efc0
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 70 deletions.
86 changes: 20 additions & 66 deletions Qpf/Macro/Comp.lean
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import Mathlib.Data.Vector.Basic

import Qpf.Qpf
import Qpf.Macro.Common
import Qpf.Macro.QpfExpr

import Qq

Expand Down Expand Up @@ -110,9 +111,6 @@ where
let _ ← synthQPF F functor
return ⟨depth, F, args⟩




def List.indexOf' {α : Type} [BEq α] : α → (as : List α) → Option (Fin2 (as.length))
| _, [] => none
| a, b :: bs => if a == b then
Expand All @@ -123,77 +121,34 @@ def List.indexOf' {α : Type} [BEq α] : α → (as : List α) → Option (Fin2
| some i => some <| .fs i


def Fin2.toExpr {n : Nat} : Fin2 n → Q(Fin2 $n)
| .fz => q(Fin2.fz)
| .fs i => q(Fin2.fs $(toExpr i))

instance {n : Nat} : ToExpr (Fin2 n) where
toExpr := Fin2.toExpr
toTypeExpr := q(Fin2 $n)


def Vec.toExpr {α : Q(Type u)} : {n : Nat} → Vec Q($α) n → Q(Vec $α $n)
| 0, _ => q(Vec.nil)
| _+1, as =>
let a : Q($α) := as.last
let as := toExpr as.drop
q(Vec.append1 $as $a)

instance {α : Q(Type u)} {n : Nat} : ToExpr (Vec Q($α) n) where
toExpr := Vec.toExpr
toTypeExpr := q(Vec $α $n)

def DVec.toExpr {n : Nat} {αs : Q(Fin2 $n → Type u)} (xs : DVec (fun (i : Fin2 n) => Q($αs $i))) :
Q(DVec.{u} $αs) :=
match n with
| 0 => q(Fin2.elim0)
| _+1 =>
let a : Q($αs 0) := xs.last
let as := toExpr xs.drop
q(fun
| .fz => $a
| .fs i => $as i
)

/-! ## instances
Our automation needs to refer to instances of `MvQPF` by name.
Since the name of those instances might change, we define our own aliasses
to guard against this.
-/
protected def instMvQPFComp (F : TypeFun n) (Gs : Fin2 n → TypeFun m)
[q : MvQPF F] [qG : ∀ i, MvQPF (Gs i)] :
MvQPF (Comp F Gs) :=
inferInstance

structure ElabQpfResult (u : Level) (arity : Nat) where
F : Q(TypeFun.{u,u} $arity)
qpf : Q(@MvQPF _ $F) := by exact q(by infer_instance)
deriving Inhabited
-- structure QpfExpr (u : Level) (arity : Nat) where
-- F : Q(TypeFun.{u,u} $arity)
-- qpf : Q(@MvQPF _ $F) := by exact q(by infer_instance)
-- deriving Inhabited

def isLiveVar (varIds : Vector FVarId n) (id : FVarId) := varIds.toList.contains id

open PrettyPrinter in
mutual
partial def handleLiveFVar (vars : Vector FVarId arity) (target : FVarId) : TermElabM (ElabQpfResult u arity) := do
partial def handleLiveFVar (vars : Vector FVarId arity) (target : FVarId) : TermElabM (QpfExpr u arity) := do
trace[QPF] f!"target {Expr.fvar target} is a free variable"
let ind ← match List.indexOf' target vars.toList with
| none => throwError "Free variable {Expr.fvar target} is not one of the qpf arguments"
| some ind => pure ind

let ind : Fin2 arity := cast (by simp) ind.inv
let prj := q(@Prj.{u} $arity $ind)
let prj := QpfExpr.prj ind
trace[QPF] "represented by: {prj}"
return prj

pure { F := prj, qpf := q(Prj.mvqpf _) }

partial def handleConst (target : Q(Type u)) : TermElabM (ElabQpfResult u arity) := do
partial def handleConst (target : Q(Type u)) : TermElabM (QpfExpr u arity) := do
trace[QPF] "target {target} is a constant"
let const := q(Const.{u} $arity $target)
let const := QpfExpr.const _ target
trace[QPF] "represented by: {const}"
pure { F := const, qpf := q(Const.mvqpf)}

return const

partial def handleApp (vars : Vector FVarId arity) (target : Q(Type u)) : TermElabM (ElabQpfResult u arity) := do
partial def handleApp (vars : Vector FVarId arity) (target : Q(Type u)) : TermElabM (QpfExpr u arity) := do
let vars' := vars.toList

let ⟨numArgs, F, args⟩ ← (Comp.parseApp (isLiveVar vars) target)
Expand All @@ -208,40 +163,39 @@ partial def handleApp (vars : Vector FVarId arity) (target : Q(Type u)) : TermEl

if is_trivial then
trace[QPF] "The application is trivial"
let qpf ← synthInstanceQ q(MvQPF $F)
return { F, qpf }
QpfExpr.ofTypeFun F
else
-- let F ← QpfExpr.ofTypeFun F
let G ← args.mmap (elabQpf vars · none false)

let Ffunctor ← synthInstanceQ q(MvFunctor $F)
let Fqpf ← synthInstanceQ q(@MvQPF _ $F)

let G : Vec _ numArgs := fun i => G.get i.inv
let GExpr : Q(Vec (TypeFun.{u,u} $arity) $numArgs) :=
Vec.toExpr (fun i => (G i).F)
Vec.toExpr (fun i => (G i).typeFun)
let GQpf : Q(∀ i, MvQPF.{u,u} ($GExpr i)) :=
let αs := q(fun i => MvQPF.{u,u} ($GExpr i))
@DVec.toExpr _ _ αs (fun i => (G i).qpf)
@DVec.toExpr _ _ αs (fun i => (G i).qpfInstance)

let comp := q(@Comp $numArgs _ $F $GExpr)
trace[QPF] "G := {GExpr}"
trace[QPF] "comp := {comp}"

let qpf := q(
let qpfInstance := q(
@Macro.Comp.instMvQPFComp (q := $Fqpf) (qG := $GQpf)
)
return { F := comp, qpf }
return QpfExpr.qpf comp qpfInstance


partial def handleArrow (binderType body : Expr) (vars : Vector FVarId arity) (targetStx : Option Term := none) (normalized := false) : TermElabM (ElabQpfResult u arity) := do
partial def handleArrow (binderType body : Expr) (vars : Vector FVarId arity) (targetStx : Option Term := none) (normalized := false) : TermElabM (QpfExpr u arity) := do
let newTarget ← mkAppM ``MvQPF.Arrow.Arrow #[binderType, body]
elabQpf vars newTarget targetStx normalized

/--
Elaborate the body of a qpf
-/
partial def elabQpf {arity : Nat} (vars : Vector FVarId arity) (target : Q(Type u)) (targetStx : Option Term := none) (normalized := false) :
TermElabM (ElabQpfResult u arity) := do
TermElabM (QpfExpr u arity) := do
trace[QPF] "elabQPF :: {(vars.map Expr.fvar).toList} -> {target}"
let isLiveVar := isLiveVar vars

Expand Down
5 changes: 1 addition & 4 deletions Qpf/Macro/Data.lean
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import Mathlib.Data.QPF.Multivariate.Constructions.Cofix
import Mathlib.Data.QPF.Multivariate.Constructions.Fix

import Qpf.Macro.Data.Constructors
import Qpf.Macro.Data.Replace
import Qpf.Macro.Data.Count
import Qpf.Macro.Data.View
import Qpf.Macro.Data.Ind
import Qpf.Macro.Common
import Qpf.Macro.Comp
import Qpf.Macro.QpfExpr

open Lean Meta Elab.Command
open Elab (Modifiers elabModifiers)
Expand All @@ -32,7 +30,6 @@ private def Fin2.quoteOfNat : Nat → Term
| 0 => mkIdent ``Fin2.fz
| n+1 => Syntax.mkApp (mkIdent ``Fin2.fs) #[(quoteOfNat n)]


namespace Data.Command

/-!
Expand Down
139 changes: 139 additions & 0 deletions Qpf/Macro/QpfExpr.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import Lean
import Qq

import Mathlib.Data.QPF.Multivariate.Constructions.Comp
import Mathlib.Data.QPF.Multivariate.Constructions.Const
import Mathlib.Data.QPF.Multivariate.Constructions.Prj
import Mathlib.Data.QPF.Multivariate.Constructions.Cofix
import Mathlib.Data.QPF.Multivariate.Constructions.Fix

import Qpf.Util.TypeFun

/-!
## QpfExpr
We build an abstraction to bundle a Lean expression of type `TypeFun n` with
the corresponding `MvQPF` instance, and define methods for the various
constructions under which QPFs are closed ((co)fixpoints, composition, etc.).
-/

open Lean Qq

/-- A Lean expression of type `TypeFun n`, with a bundled `MvQPF` instance -/
inductive QpfExpr (u : Level) (n : Nat)
| qpf
(F : Q(TypeFun.{u, u} $n))
(qpf : Q(MvQPF $F) := by exact q(inferInstance))
/- TODO: add a pfunctor special case, as follows:
/-- In `.pfunctor P`, `P` is a Lean Expr of type `MvPFunctor n`.
This is a specialization, which serves to preserve the fact that a QPF is
actually polynomial -/
| pfunctor (P : Expr)
-/
deriving Inhabited

/-! ## Preliminaries -/

def Fin2.toExpr {n : Nat} : Fin2 n → Q(Fin2 $n)
| .fz => q(Fin2.fz)
| .fs i => q(Fin2.fs $(toExpr i))
instance {n : Nat} : ToExpr (Fin2 n) where
toExpr := Fin2.toExpr
toTypeExpr := q(Fin2 $n)

def Vec.toExpr {α : Q(Type u)} : {n : Nat} → Vec Q($α) n → Q(Vec $α $n)
| 0, _ => q(Vec.nil)
| _+1, as =>
let a : Q($α) := as.last
let as := toExpr as.drop
q(Vec.append1 $as $a)
instance {α : Q(Type u)} {n : Nat} : ToExpr (Vec Q($α) n) where
toExpr := Vec.toExpr
toTypeExpr := q(Vec $α $n)

def DVec.toExpr {n : Nat} {αs : Q(Fin2 $n → Type u)} (xs : DVec (fun (i : Fin2 n) => Q($αs $i))) :
Q(DVec.{u} $αs) :=
match n with
| 0 => q(Fin2.elim0)
| _+1 =>
let a : Q($αs 0) := xs.last
let as := toExpr xs.drop
q(fun
| .fz => $a
| .fs i => $as i
)

namespace QpfExpr

/-! ## Basic Fields -/

/-- The raw type function, i.e., an expression of type `TypeFun n` -/
def typeFun {n : Nat} : QpfExpr u n → Q(TypeFun.{u, u} $n)
| qpf F _ => F

/-- The bundled QPF instance, i.e., an expression of type `MvQPF ($typeFun)` -/
def qpfInstance {n : Nat} : (q : QpfExpr u n) → Q(MvQPF $q.typeFun)
| qpf _ q => q


variable {m} [Monad m] [MonadLiftT MetaM m] in
/-- Construct a `QPFExpr` from an expression of type `TypeFun n`, by
synthesizing the corresponding MvQPF instance.
Throws an error if synthesis fails. -/
def ofTypeFun {n : Nat} (F : Q(TypeFun.{u, u} $n)) : m (QpfExpr u n) := do
let qpf ← synthInstanceQ q(MvQPF $F)
return QpfExpr.qpf F qpf

/-! ## Tracing-/

def toMessageData : QpfExpr u n → MessageData
| qpf F q => m!"qpf ({F}) ({q})"
instance : ToMessageData (QpfExpr u n) := { toMessageData }

/-! ## Constructions -/

/-! ### Basic Functors (Constants and Projections) -/

/-- A constant functor, see `MvQPF.Const` -/
def const (n : Nat) (A : Q(Type u)) : QpfExpr u n :=
qpf q(MvQPF.Const $n $A)

/-- `prj i` is a functor that projects to the i-th argument, see `MvQPF.Prj` -/
def prj {u : Level} {n : Nat} (i : Fin2 n) : QpfExpr u n :=
qpf q(MvQPF.Prj $i)

/-! ### (Co)Fixpoint -/

/-- The (inductive) fixpoint of a QPF, see `MvQPF.Fix` -/
def fix : QpfExpr u (n+1) → QpfExpr u n
| qpf F _q => qpf q(MvQPF.Fix $F)

/-- The (coinductive) cofixpoint of a QPF, see `MvQPF.Cofix` -/
def cofix : QpfExpr u (n+1) → QpfExpr u n
| qpf F _q => qpf q(MvQPF.Cofix $F)

/-! ### Composition -/

/--
Our automation needs to refer to this instance by name.
Since the name of this instances might change, we define our own aliasses.
-/
private def instMvQPFComp (F : TypeFun n) (Gs : Fin2 n → TypeFun m)
[q : MvQPF F] [qG : ∀ i, MvQPF (Gs i)] :
MvQPF (MvQPF.Comp F Gs) := by
infer_instance

/-- Compositions of QPFs, see `MvQPF.comp` -/
def comp (F : QpfExpr u n) (Gs : Vec (QpfExpr u m) n) : QpfExpr u m :=
let GExpr : Q(Vec (TypeFun.{u,u} $m) $n) :=
Vec.toExpr (fun i => (Gs i).typeFun)
let GQpf : Q(∀ i, MvQPF.{u,u} ($GExpr i)) :=
let αs := q(fun i => MvQPF.{u,u} ($GExpr i))
@DVec.toExpr _ _ αs (fun i => (Gs i).qpfInstance)

let comp := q(@MvQPF.Comp $n _ $F.typeFun $GExpr)
let qpfInstance := q(
@instMvQPFComp (q := $F.qpfInstance) (qG := $GQpf)
)
qpf comp qpfInstance

0 comments on commit 2b3efc0

Please sign in to comment.