|
| 1 | +/- |
| 2 | +Copyright (c) 2025 Patrick Massot. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Patrick Massot, Michael Rothgang, Thomas Murrills |
| 5 | +-/ |
| 6 | +module |
| 7 | + |
| 8 | +-- TODO: minimise! |
| 9 | +public import Mathlib.Geometry.Manifold.ContMDiff.Defs |
| 10 | +--public import Mathlib.Topology.VectorBundle.Basic -- new |
| 11 | +public import Mathlib.Geometry.Manifold.MFDeriv.Defs |
| 12 | + |
| 13 | +/-! |
| 14 | +# Notation for Elaborators for differential geometry |
| 15 | +
|
| 16 | +This file defines custom notation for vector bundles: we introduce an elaborator `T%` to ease |
| 17 | +working with sections in a fibre bundle, scoped to the `Bundle` namespace. |
| 18 | +
|
| 19 | +It converts a section `s : Π x : B, V x` to a non-dependent function into the total space of the |
| 20 | +bundle. (Mathematically, this is the same as post-composing with the inclusion map from each fiber |
| 21 | +into the total space.) |
| 22 | +```lean |
| 23 | +-- omitted: let `V` be a fibre bundle over `B` |
| 24 | +
|
| 25 | +variable {σ : Π x : B, V x} in |
| 26 | +#check T% σ -- `(fun x ↦ TotalSpace.mk' F x (σ x)) : M → TotalSpace F V` |
| 27 | +
|
| 28 | +-- Note how the name of the bound variable `x` is preserved. |
| 29 | +variable {σ : (x : E) → Trivial E E' x} in |
| 30 | +#check T% σ -- `(fun x ↦ TotalSpace.mk' E' x (σ x)) : E → TotalSpace E' (Trivial E E')` |
| 31 | +
|
| 32 | +variable {s : E → E'} in |
| 33 | +#check T% s -- `(fun a ↦ TotalSpace.mk' E' a (s a)) : E → TotalSpace E' (Trivial E E')` |
| 34 | +``` |
| 35 | +
|
| 36 | +-/ |
| 37 | + |
| 38 | +public meta section |
| 39 | + |
| 40 | +open scoped Bundle |
| 41 | + |
| 42 | +open Lean Meta Elab Tactic |
| 43 | +open Mathlib.Tactic |
| 44 | +open Qq |
| 45 | + |
| 46 | +namespace Bundle.Elab |
| 47 | + |
| 48 | +/- Note: these functions are convenient in this file, and may be convenient elsewhere, but their |
| 49 | +precise behavior should be considered before adding them to the meta API. -/ |
| 50 | + |
| 51 | +/-- Finds the first local instance of class `c` for which `p inst type` produces `some a`. |
| 52 | +Instantiates mvars in and runs `whnfR` on `type` before passing it to `p`. (Does not validate that |
| 53 | +`c` resolves to a class.) -/ |
| 54 | +private def findSomeLocalInstanceOf? (c : Name) {α} (p : Expr → Expr → MetaM (Option α)) : |
| 55 | + MetaM (Option α) := do |
| 56 | + (← getLocalInstances).findSomeM? fun inst ↦ do |
| 57 | + if inst.className == c then |
| 58 | + let type ← whnfR <| ← instantiateMVars <| ← inferType inst.fvar |
| 59 | + p inst.fvar type |
| 60 | + else return none |
| 61 | + |
| 62 | +/-- Finds the most recent local declaration for which `p fvar type` produces `some a`. |
| 63 | +Skips implementation details; instantiates mvars in and runs `whnfR` on `type` before providing it |
| 64 | +to `p`. -/ |
| 65 | +private def findSomeLocalHyp? {α} (p : Expr → Expr → MetaM (Option α)) : MetaM (Option α) := do |
| 66 | + (← getLCtx).findDeclRevM? fun decl ↦ do |
| 67 | + if decl.isImplementationDetail then return none |
| 68 | + let type ← whnfR <| ← instantiateMVars decl.type |
| 69 | + p decl.toExpr type |
| 70 | + |
| 71 | +/-- |
| 72 | +Utility for sections in a fibre bundle: if an expression `e` is a section |
| 73 | +`s : Π x : M, V x` as a dependent function, convert it to a non-dependent function into the total |
| 74 | +space. This handles the cases of |
| 75 | +- sections of a trivial bundle |
| 76 | +- vector fields on a manifold (i.e., sections of the tangent bundle) |
| 77 | +- sections of an explicit fibre bundle |
| 78 | +- turning a bare function `E → E'` into a section of the trivial bundle `Bundle.Trivial E E'` |
| 79 | +
|
| 80 | +This searches the local context for suitable hypotheses for the above cases by matching |
| 81 | +on the expression structure, avoiding `isDefEq`. Therefore, it should be fast enough to always run. |
| 82 | +This process can be traced with `set_option Elab.Bundle.TotalSpaceMk true`. |
| 83 | +
|
| 84 | +All applications of `e` in the resulting expression are beta-reduced. |
| 85 | +If none of the handled cases apply, we simply return `e` (after beta-reducing). |
| 86 | +
|
| 87 | +This function is used for implementing the `T%` elaborator. |
| 88 | +-/ |
| 89 | +-- TODO: document how this elaborator works, any gotchas, etc. |
| 90 | +def totalSpaceMk (e : Expr) : MetaM Expr := do |
| 91 | + let etype ← whnf <| ← instantiateMVars <| ← inferType e |
| 92 | + match etype with |
| 93 | + | .forallE x base tgt _ => withLocalDeclD x base fun x ↦ do |
| 94 | + let tgtHasLooseBVars := tgt.hasLooseBVars |
| 95 | + let tgt := tgt.instantiate1 x |
| 96 | + -- Note: we do not run `whnfR` on `tgt` because `Bundle.Trivial` is reducible. |
| 97 | + match_expr tgt with |
| 98 | + | Bundle.Trivial E E' _ => |
| 99 | + trace[Elab.Bundle.TotalSpaceMk] "`{e}` is a section of `Bundle.Trivial {E} {E'}`" |
| 100 | + -- Note: we allow `isDefEq` here because any mvar assignments should persist. |
| 101 | + if ← withReducible (isDefEq E base) then |
| 102 | + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, (e.app x).headBeta] |
| 103 | + mkLambdaFVars #[x] body |
| 104 | + else return e |
| 105 | + | TangentSpace _k _ E _ _ _H _ _I M _ _ _x => |
| 106 | + trace[Elab.Bundle.TotalSpaceMk] "`{e}` is a vector field on `{M}`" |
| 107 | + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, (e.app x).headBeta] |
| 108 | + mkLambdaFVars #[x] body |
| 109 | + | _ => match (← instantiateMVars tgt).cleanupAnnotations with |
| 110 | + | .app V _ => |
| 111 | + trace[Elab.Bundle.TotalSpaceMk] "Section of a bundle as a dependent function" |
| 112 | + let f? ← findSomeLocalInstanceOf? `FiberBundle fun _ declType ↦ |
| 113 | + /- Note: we do not use `match_expr` here since that would require importing |
| 114 | + `Mathlib.Topology.FiberBundle.Basic` to resolve `FiberBundle`. -/ |
| 115 | + match declType with |
| 116 | + | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => do |
| 117 | + if ← withReducible (pureIsDefEq E V) then |
| 118 | + let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, (e.app x).headBeta] |
| 119 | + some <$> mkLambdaFVars #[x] body |
| 120 | + else return none |
| 121 | + | _ => return none |
| 122 | + return f?.getD e.headBeta |
| 123 | + | tgt => |
| 124 | + trace[Elab.Bundle.TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" |
| 125 | + -- TODO: can `tgt` depend on `x` in a way that is not a function application? |
| 126 | + -- Check that `x` is not a bound variable in `tgt`! |
| 127 | + if tgtHasLooseBVars then |
| 128 | + throwError "Attempted to fall back to creating a section of the trivial bundle out of \ |
| 129 | + (`{e}` : `{etype}`) as a non-dependent function, but return type `{tgt}` depends on the |
| 130 | + bound variable (`{x}` : `{base}`).\n\ |
| 131 | + Hint: applying the `T%` elaborator twice makes no sense." |
| 132 | + let trivBundle ← mkAppOptM ``Bundle.Trivial #[base, tgt] |
| 133 | + let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[base, trivBundle, tgt, x, (e.app x).headBeta] |
| 134 | + mkLambdaFVars #[x] body |
| 135 | + | _ => return e.headBeta |
| 136 | + |
| 137 | +end Elab |
| 138 | + |
| 139 | +open Elab in |
| 140 | +/-- |
| 141 | +Elaborator for sections in a fibre bundle: converts a section `s : Π x : M, V x` as a dependent |
| 142 | +function to a non-dependent function into the total space. This handles the cases of |
| 143 | +- sections of a trivial bundle |
| 144 | +- vector fields on a manifold (i.e., sections of the tangent bundle) |
| 145 | +- sections of an explicit fibre bundle |
| 146 | +- turning a bare function `E → E'` into a section of the trivial bundle `Bundle.Trivial E E'` |
| 147 | +
|
| 148 | +This elaborator searches the local context for suitable hypotheses for the above cases by matching |
| 149 | +on the expression structure, avoiding `isDefEq`. Therefore, it should be fast enough to always run. |
| 150 | +The search can be traced with `set_option Elab.Bundle.TotalSpaceMk true`. |
| 151 | +-/ |
| 152 | +scoped elab:max "T% " t:term:arg : term => do |
| 153 | + totalSpaceMk (← Term.elabTerm t none) |
| 154 | + |
| 155 | +end Bundle |
| 156 | + |
| 157 | +section trace |
| 158 | + |
| 159 | +/-! |
| 160 | +### Trace classes |
| 161 | +
|
| 162 | +Note that the overall `Elab` trace class does not inherit the trace classes defined in this |
| 163 | +section, since they provide verbose information. |
| 164 | +-/ |
| 165 | + |
| 166 | +/-- |
| 167 | +Trace class for the `T%` elaborator, which converts a section of a vector bundle as a dependent |
| 168 | +function to a non-dependent function into the total space. |
| 169 | +-/ |
| 170 | +initialize registerTraceClass `Elab.Bundle.TotalSpaceMk |
| 171 | + |
| 172 | +end trace |
0 commit comments