Documentation

VCVio.OracleComp.Coercions.SubSpec

Coercions Between Computations With Additional Oracles #

This file defines the SubSpec relation between pairs of OracleSpecs. An instance spec ⊂ₒ superSpec packages the data of a polynomial-functor lens PFunctor.Lens spec.toPFunctor superSpec.toPFunctor between the underlying PFunctors, given by

By the Yoneda lemma this lens data is in bijection with natural transformations OracleQuery spec → OracleQuery superSpec. The class therefore extends MonadLift (OracleQuery spec) (OracleQuery superSpec). Concrete instances spell monadLift out alongside the lens data and discharge the propositional coherence liftM_eq_lift (typically rfl); see the class docstring for why the monadLift field is not defaulted.

We use the notation spec ⊂ₒ spec' to represent this inclusion. The non-inclusive subset symbol reflects that we avoid defining SubSpec reflexively, since MonadLiftT.refl already handles the identity case.

LawfulSubSpec refines SubSpec with the requirement that onResponse is bijective on every fiber, i.e. that the underlying lens is cartesian in the sense of PFunctor.Lens.IsCartesian. This is strictly weaker than PFunctor.Lens.Equiv (which would also require onQuery to be a bijection, ruling out the basic case spec ⊂ₒ (spec + spec') where onQuery = Sum.inl). Cartesianness is exactly the condition needed to preserve the uniform distribution under lifting (evalDist_liftComp); see LawfulSubSpec.toLens_isCartesian for the bridge to the lens-level predicate.

class OracleSpec.SubSpec {ι : Type u} {τ : Type v} (spec : OracleSpec ι) (superSpec : OracleSpec τ) extends MonadLift (OracleQuery spec) (OracleQuery superSpec) :
Type (max (max u v) (w + 1))

Inclusion of one set of oracles into another, packaged as a polynomial-functor lens between the underlying OracleSpecs. Carries the forward translation onQuery on query inputs and the fiberwise backward translation onResponse on query responses, plus the resulting MonadLift action.

We extends MonadLift (OracleQuery spec) (OracleQuery superSpec) so that typeclass synthesis can derive MonadLift (and therefore MonadLiftT) through the structure projection SubSpec.toMonadLift. The monadLift field is not defaulted: each concrete SubSpec instance must spell it out, alongside onQuery / onResponse, and discharge the propositional coherence liftM_eq_lift (typically by rfl).

Spelling monadLift out explicitly (rather than defaulting it from the lens data) is what makes the lifted query fully reduce during rw / simp pattern matching against lemmas like probEvent_liftComp. A defaulted monadLift field becomes opaque to isDefEq once it travels through the MonadLiftT instance chain, which silently breaks rewriting.

Informally, spec ⊂ₒ superSpec says that any query to an oracle of spec can be perfectly simulated by a query to an oracle of superSpec. We avoid the built-in Subset notation because we care about the actual data of the mapping (it is needed when defining type coercions), not just its existence.

Instances

    Inclusion of one set of oracles into another, packaged as a polynomial-functor lens between the underlying OracleSpecs. Carries the forward translation onQuery on query inputs and the fiberwise backward translation onResponse on query responses, plus the resulting MonadLift action.

    We extends MonadLift (OracleQuery spec) (OracleQuery superSpec) so that typeclass synthesis can derive MonadLift (and therefore MonadLiftT) through the structure projection SubSpec.toMonadLift. The monadLift field is not defaulted: each concrete SubSpec instance must spell it out, alongside onQuery / onResponse, and discharge the propositional coherence liftM_eq_lift (typically by rfl).

    Spelling monadLift out explicitly (rather than defaulting it from the lens data) is what makes the lifted query fully reduce during rw / simp pattern matching against lemmas like probEvent_liftComp. A defaulted monadLift field becomes opaque to isDefEq once it travels through the MonadLiftT instance chain, which silently breaks rewriting.

    Informally, spec ⊂ₒ superSpec says that any query to an oracle of spec can be perfectly simulated by a query to an oracle of superSpec. We avoid the built-in Subset notation because we care about the actual data of the mapping (it is needed when defining type coercions), not just its existence.

    Instances For
      @[reducible]
      def OracleSpec.SubSpec.liftQuery {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {α : Type w} [h : spec ⊂ₒ superSpec] (q : OracleQuery spec α) :
      OracleQuery superSpec α

      The lens action on a single query: forward on the input, post-compose the backward fiber on the continuation. Used as the canonical reduced form of liftM q for proofs that need to inspect the resulting query.

      Instances For
        def OracleSpec.SubSpec.toLens {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} (h : spec ⊂ₒ superSpec) :
        spec.toPFunctor.Lens superSpec.toPFunctor

        The polynomial-functor lens between the underlying PFunctors carried by a SubSpec instance. This is the lens-level view of the data; concrete properties (like cartesianness via LawfulSubSpec) are stated on this lens.

        The other half of the data, monadLift, is fixed by liftM_eq_lift to be the standard action of this lens on OracleQuery.

        Instances For
          @[simp]
          theorem OracleSpec.SubSpec.toLens_toFunA {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} (h : spec ⊂ₒ superSpec) :
          @[simp]
          theorem OracleSpec.SubSpec.toLens_toFunB {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} (h : spec ⊂ₒ superSpec) :
          @[reducible]
          def OracleSpec.SubSpec.trans {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {κ : Type w'} {spec₃ : OracleSpec κ} (h₁ : spec ⊂ₒ superSpec) (h₂ : superSpec ⊂ₒ spec₃) :
          spec ⊂ₒ spec₃

          Transitivity of SubSpec: lens composition.

          Instances For
            @[simp]
            theorem OracleSpec.SubSpec.trans_toLens {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {κ : Type w'} {spec₃ : OracleSpec κ} (h₁ : spec ⊂ₒ superSpec) (h₂ : superSpec ⊂ₒ spec₃) :
            (h₁.trans h₂).toLens = h₂.toLens ∘ₗ h₁.toLens
            class OracleSpec.LawfulSubSpec {ι : Type u} {τ : Type v} (spec : OracleSpec ι) (superSpec : OracleSpec τ) [h : spec ⊂ₒ superSpec] :

            LawfulSubSpec extends SubSpec with the requirement that the backward translation onResponse is bijective on every fiber. Equivalently: the underlying lens SubSpec.toLens is cartesian in the sense of PFunctor.Lens.IsCartesian, i.e. it is a fiberwise isomorphism over an arbitrary forward map on positions.

            This is strictly weaker than PFunctor.Lens.Equiv, which would also force onQuery to be a bijection. We intentionally only require fiberwise bijectivity because the canonical SubSpec instances embed a small spec into a larger one (e.g. spec₁ ⊂ₒ (spec₁ + spec₂) with onQuery = Sum.inl), and these embeddings are essential to the API.

            Cartesianness is exactly what is needed to preserve the uniform distribution under the lift: see evalDist_liftM_query and the bridge LawfulSubSpec.toLens_isCartesian.

            Instances

              Lawful oracle-spec inclusion: a SubSpec whose response translation is bijective on every fiber.

              Instances For
                theorem OracleSpec.LawfulSubSpec.toLens_isCartesian {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} [h : spec ⊂ₒ superSpec] [spec.LawfulSubSpec superSpec] :

                The lens-level statement of LawfulSubSpec: the underlying PFunctor.Lens is cartesian. This makes the dictionary between the oracle-spec layer and the polynomial-functor lens layer explicit.

                theorem OracleSpec.LawfulSubSpec.evalDist_liftM_query {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} [h : spec ⊂ₒ superSpec] [spec.LawfulSubSpec superSpec] [superSpec.Fintype] [superSpec.Inhabited] [spec.Fintype] [spec.Inhabited] (t : spec.Domain) :

                Pushing the uniform distribution on superSpec.Range through the lens's backward fiber recovers the uniform distribution on spec.Range. Load-bearing for evalDist_liftComp below.

                class OracleSpec.DisjointSubSpec {ι₁ : Type u} {ι₂ : Type v} {τ : Type w'} (spec₁ : OracleSpec ι₁) (spec₂ : OracleSpec ι₂) (superSpec : OracleSpec τ) [h₁ : spec₁ ⊂ₒ superSpec] [h₂ : spec₂ ⊂ₒ superSpec] :

                Two oracle-spec inclusions into the same ambient spec have disjoint query images.

                This is stronger than LawfulSubSpec: lawfulness preserves the distribution of responses under lifting, while disjointness says the two lifted query namespaces do not overlap inside the ambient interface.

                Instances

                  Oracle-spec inclusions with disjoint query images in an ambient interface.

                  Instances For
                    def OracleComp.liftComp {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {α : Type w} (mx : OracleComp spec α) (superSpec : OracleSpec τ) [h : MonadLiftT (OracleQuery spec) (OracleQuery superSpec)] :
                    OracleComp superSpec α

                    Lift a computation from spec to superSpec using a SubSpec instance on queries. Usually liftM should be preferred but this can allow more explicit annotation.

                    Instances For
                      theorem OracleComp.liftComp_def {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {α : Type w} (superSpec : OracleSpec τ) [h : MonadLiftT (OracleQuery spec) (OracleQuery superSpec)] (mx : OracleComp spec α) :
                      mx.liftComp superSpec = simulateQ (fun (t : spec.Domain) => liftM (OracleSpec.query t)) mx
                      @[simp]
                      theorem OracleComp.liftComp_pure {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {α : Type w} (superSpec : OracleSpec τ) [h : MonadLiftT (OracleQuery spec) (OracleQuery superSpec)] (x : α) :
                      (pure x).liftComp superSpec = pure x
                      @[simp]
                      theorem OracleComp.liftComp_query {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {α : Type w} (superSpec : OracleSpec τ) [h : MonadLiftT (OracleQuery spec) (OracleQuery superSpec)] (q : OracleQuery spec α) :
                      @[simp]
                      theorem OracleComp.liftComp_bind {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {α β : Type w} (superSpec : OracleSpec τ) [h : MonadLiftT (OracleQuery spec) (OracleQuery superSpec)] (mx : OracleComp spec α) (ob : αOracleComp spec β) :
                      (mx >>= ob).liftComp superSpec = do let xmx.liftComp superSpec (ob x).liftComp superSpec
                      @[simp]
                      theorem OracleComp.liftComp_self {ι : Type u} {spec : OracleSpec ι} {α : Type w} (mx : OracleComp spec α) :
                      mx.liftComp spec = mx
                      @[simp]
                      theorem OracleComp.liftComp_map {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {α β : Type w} (superSpec : OracleSpec τ) [h : MonadLiftT (OracleQuery spec) (OracleQuery superSpec)] (mx : OracleComp spec α) (f : αβ) :
                      (f <$> mx).liftComp superSpec = f <$> mx.liftComp superSpec
                      @[simp]
                      theorem OracleComp.liftComp_seq {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {α β : Type w} (superSpec : OracleSpec τ) [h : MonadLiftT (OracleQuery spec) (OracleQuery superSpec)] (og : OracleComp spec (αβ)) (mx : OracleComp spec α) :
                      (og <*> mx).liftComp superSpec = og.liftComp superSpec <*> mx.liftComp superSpec
                      @[simp]
                      theorem OracleComp.evalDist_liftComp {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {α : Type w} [spec.Fintype] [spec.Inhabited] [superSpec.Fintype] [superSpec.Inhabited] [h : spec ⊂ₒ superSpec] [spec.LawfulSubSpec superSpec] (mx : OracleComp spec α) :
                      𝒟[mx.liftComp superSpec] = 𝒟[mx]
                      @[simp]
                      theorem OracleComp.probOutput_liftComp {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {α : Type w} [spec.Fintype] [spec.Inhabited] [superSpec.Fintype] [superSpec.Inhabited] [h : spec ⊂ₒ superSpec] [spec.LawfulSubSpec superSpec] (mx : OracleComp spec α) (x : α) :
                      Pr[= x | mx.liftComp superSpec] = Pr[= x | mx]
                      @[simp]
                      theorem OracleComp.probEvent_liftComp {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {α : Type w} [spec.Fintype] [spec.Inhabited] [superSpec.Fintype] [superSpec.Inhabited] [h : spec ⊂ₒ superSpec] [spec.LawfulSubSpec superSpec] (mx : OracleComp spec α) (p : αProp) :
                      probEvent (mx.liftComp superSpec) p = probEvent mx p
                      @[implicit_reducible, instance 100]
                      instance OracleComp.instMonadLiftOfOracleQuery {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] :
                      MonadLift (OracleComp spec) (OracleComp superSpec)

                      Extend a lifting on OracleQuery to a lifting on OracleComp.

                      Registered as a low-priority MonadLift (not MonadLiftT) so that:

                      • For spec = superSpec, Lean's built-in MonadLiftT.refl (which is definitionally id) wins typeclass resolution. This is what Std.Do.Spec.UnfoldLift.monadLift_refl (a rfl-based lemma) needs in order to peel off spurious self-lifts inside mvcgen-elaborated terms.

                      • For MonadLiftT (OracleQuery spec) (OracleComp superSpec), the built-in high-priority MonadLift (OracleQuery superSpec) (OracleComp superSpec) is tried first by monadLiftTrans and succeeds via the SubSpec chain on OracleQuery, never reaching this instance. Single-query lifts therefore go through the standard "lift query then embed" path with no spurious walk through liftComp.

                      • For MonadLiftT (OracleComp spec) (OracleComp superSpec) with spec ≠ superSpec, the high-priority built-in fails (no MonadLiftT (OracleComp _) (OracleQuery _)), Lean backtracks to this low-priority instance, and the recursive subgoal collapses via MonadLiftT.refl. The result is a single liftComp mx superSpec.

                      @[simp]
                      theorem OracleComp.liftComp_eq_liftM {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {α : Type w} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] (mx : OracleComp spec α) :
                      mx.liftComp superSpec = liftM mx

                      We choose to actively rewrite liftComp as liftM to enable LawfulMonadLift lemmas.

                      instance OracleComp.instLawfulMonadLift {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] :
                      @[simp]
                      theorem OracleComp.monadLift_eq_self {ι : Type u} {spec : OracleSpec ι} {α : Type u_1} (mx : OracleComp spec α) :
                      monadLift mx = mx

                      Self-lift on OracleComp is definitionally id, supplied by Lean's built-in MonadLiftT.refl thanks to the low-priority MonadLift instance above (which causes the parametric path to lose typeclass resolution to MonadLiftT.refl when spec = superSpec).

                      Regression smoke-tests for the instance-priority invariants above. The rfl proofs are the load-bearing signal: if priority drifts so that the parametric MonadLift beats MonadLiftT.refl, the self-lift stops being definitionally id and the rfl below breaks. Similarly, the MonadLiftT synthesis check guards against future refactors that would remove the transitive lift chain.

                      @[implicit_reducible]
                      instance OracleComp.instMonadLiftOptionTOfOracleQuery {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] :
                      @[simp]
                      theorem OracleComp.liftM_OptionT_eq {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {α : Type w} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] (mx : OptionT (OracleComp spec) α) :
                      liftM mx = have impl := fun (t : spec.Domain) => liftM (OracleSpec.query t); simulateQ impl mx
                      @[simp]
                      theorem OracleComp.liftM_failure {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {α : Type w} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] :
                      instance OracleComp.instLawfulMonadLiftOptionT {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] :
                      @[simp]
                      theorem OracleComp.monadLift_liftM_OptionT {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {α : Type w} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] (mx : OracleComp spec α) :

                      Coherence: lifting an OracleComp to a superspec and then into OptionT via the standard MonadLift equals lifting directly through the transitive MonadLiftT chain (which goes through the simulateQ-based OptionT MonadLift instance).

                      @[implicit_reducible]
                      instance OracleComp.instMonadLiftStateTOfOracleQuery {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {σ : Type u_1} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] :
                      MonadLift (StateT σ (OracleComp spec)) (StateT σ (OracleComp superSpec))
                      @[simp]
                      theorem OracleComp.liftM_StateT_eq {ι : Type u} {τ : Type v} {spec : OracleSpec ι} {superSpec : OracleSpec τ} {α σ : Type w} [MonadLift (OracleQuery spec) (OracleQuery superSpec)] (mx : StateT σ (OracleComp spec) α) :
                      liftM mx = StateT.mk fun (s : σ) => liftM (mx.run s)