Documentation

VCVio.OracleComp.QueryTracking.Tracing

Generic Trace Instrumentation for Query Implementations #

Two primitive ways to attach a writer-valued trace to a QueryImpl. Each comes in two flavours, mirroring Mathlib's two Monad (WriterT ω M) instances:

The two flavours are mathematically the same (a free monoid view vs. an append-list view), but they correspond to different Monad (WriterT ω m) instances and Lean's resolver picks whichever one is unambiguously available. We expose both so neither of QueryCount/QueryLog has to switch its underlying writer interpretation.

For each flavour, "Before" emits traceFn t before running the handler (so a handler failure still records the trace), while the bare version emits traceFn t u after the handler returns response u (so a failure skips the trace).

Concretely:

The generic lemmas (output marginal, failure probability, NeverFail equivalence, evalDist / support / probOutput bridges) flow downstream automatically.

Connection to Control.Trace #

The trace function traceFn : (t : spec.Domain) → spec.Range t → ω is a curried form of Idx spec.toPFunctor → ω, which is precisely Control.Trace ω (Idx spec.toPFunctor). The Tracing API is therefore the oracle-level counterpart of the abstract Control.Trace / PFunctor.Trace infrastructure in ToMathlib.

withTraceBefore: response-independent trace, recorded before handler #

def QueryImpl.withTraceBefore {ι : Type u} {spec : OracleSpec ι} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] (so : QueryImpl spec m) (traceFn : spec.Domainω) :
QueryImpl spec (WriterT ω m)

Wrap an oracle implementation so that each query records traceFn t in the writer ω before running the handler. The trace value depends only on the query, so a failure inside the handler still leaves the trace recorded.

Instances For
    @[simp]
    theorem QueryImpl.withTraceBefore_apply {ι : Type u} {spec : OracleSpec ι} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] (so : QueryImpl spec m) (traceFn : spec.Domainω) (t : spec.Domain) :
    so.withTraceBefore traceFn t = do tell (traceFn t) liftM (so t)
    theorem QueryImpl.fst_map_run_withTraceBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :
    theorem QueryImpl.probFailure_run_simulateQ_withTraceBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :

    A "before"-style trace preserves failure probability for any base monad with HasEvalSPMF: instrumenting with withTraceBefore does not change the probability of failure.

    theorem QueryImpl.NeverFail_run_simulateQ_withTraceBefore_iff {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :
    @[simp]
    theorem QueryImpl.run_simulateQ_withTraceBefore_const_one {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] (so : QueryImpl spec m) (mx : OracleComp spec α) :
    (simulateQ (so.withTraceBefore fun (x : spec.Domain) => 1) mx).run = (fun (x : α) => (x, 1)) <$> simulateQ so mx

    When every query traces to the monoid identity 1, withTraceBefore is a no-op up to pairing with 1.

    evalDist / probOutput / support bridges for withTraceBefore #

    theorem QueryImpl.evalDist_fst_run_withTraceBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :
    theorem QueryImpl.probOutput_fst_run_withTraceBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) (x : α) :
    theorem QueryImpl.support_fst_run_withTraceBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :

    withTrace: response-dependent trace, recorded after handler #

    def QueryImpl.withTrace {ι : Type u} {spec : OracleSpec ι} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) :
    QueryImpl spec (WriterT ω m)

    Wrap an oracle implementation so that each query records traceFn t u in the writer ω after the handler returns response u. A handler failure skips the trace (the response never materialised).

    Instances For
      @[simp]
      theorem QueryImpl.withTrace_apply {ι : Type u} {spec : OracleSpec ι} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (t : spec.Domain) :
      so.withTrace traceFn t = do let uliftM (so t) tell (traceFn t u) pure u
      theorem QueryImpl.fst_map_run_withTrace {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :
      Prod.fst <$> (simulateQ (so.withTrace traceFn) mx).run = simulateQ so mx
      theorem QueryImpl.probFailure_run_simulateQ_withTrace {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :
      Pr[⊥ | (simulateQ (so.withTrace traceFn) mx).run] = Pr[⊥ | simulateQ so mx]

      An "after"-style trace preserves failure probability for any base monad with HasEvalSPMF: instrumenting with withTrace does not change the probability of failure. When m = OracleComp spec, both sides are 0 (trivially true); when m can genuinely fail (e.g. OptionT (OracleComp spec)), this is a non-trivial faithfulness property.

      theorem QueryImpl.NeverFail_run_simulateQ_withTrace_iff {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :
      @[simp]
      theorem QueryImpl.run_simulateQ_withTrace_const_one {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] (so : QueryImpl spec m) (mx : OracleComp spec α) :
      (simulateQ (so.withTrace fun (x : spec.Domain) (x_1 : spec.Range x) => 1) mx).run = (fun (x : α) => (x, 1)) <$> simulateQ so mx

      When every query/response pair traces to the monoid identity 1, withTrace is a no-op up to pairing with 1.

      evalDist / probOutput / support bridges for withTrace #

      theorem QueryImpl.evalDist_fst_run_withTrace {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :
      theorem QueryImpl.probOutput_fst_run_withTrace {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) (x : α) :
      Pr[= x | Prod.fst <$> (simulateQ (so.withTrace traceFn) mx).run] = Pr[= x | simulateQ so mx]
      theorem QueryImpl.support_fst_run_withTrace {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [Monoid ω] [LawfulMonad m] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :

      withTraceAppendBefore: response-independent trace, recorded before #

      handler, accumulating via / ++

      def QueryImpl.withTraceAppendBefore {ι : Type u} {spec : OracleSpec ι} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] (so : QueryImpl spec m) (traceFn : spec.Domainω) :
      QueryImpl spec (WriterT ω m)

      Append-flavoured analogue of withTraceBefore: each query records traceFn t in the writer ω before running the handler, and WriterT uses the [EmptyCollection ω] [Append ω] Monad instance (tell is a single push, bind concatenates with ++). The trace value depends only on the query, so a failure inside the handler still leaves the trace recorded.

      Instances For
        @[simp]
        theorem QueryImpl.withTraceAppendBefore_apply {ι : Type u} {spec : OracleSpec ι} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] (so : QueryImpl spec m) (traceFn : spec.Domainω) (t : spec.Domain) :
        so.withTraceAppendBefore traceFn t = do tell (traceFn t) liftM (so t)
        theorem QueryImpl.fst_map_run_withTraceAppendBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :
        theorem QueryImpl.probFailure_run_simulateQ_withTraceAppendBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :
        theorem QueryImpl.NeverFail_run_simulateQ_withTraceAppendBefore_iff {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :

        evalDist / probOutput / support bridges for withTraceAppendBefore #

        theorem QueryImpl.evalDist_fst_run_withTraceAppendBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :
        theorem QueryImpl.probOutput_fst_run_withTraceAppendBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) (x : α) :
        theorem QueryImpl.support_fst_run_withTraceAppendBefore {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : spec.Domainω) (mx : OracleComp spec α) :

        withTraceAppend: response-dependent trace, recorded after handler, #

        accumulating via / ++

        def QueryImpl.withTraceAppend {ι : Type u} {spec : OracleSpec ι} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) :
        QueryImpl spec (WriterT ω m)

        Append-flavoured analogue of withTrace: each query records traceFn t u in the writer ω after the handler returns response u, using the [EmptyCollection ω] [Append ω] Monad (WriterT ω m) instance. A handler failure skips the trace (the response never materialised).

        Instances For
          @[simp]
          theorem QueryImpl.withTraceAppend_apply {ι : Type u} {spec : OracleSpec ι} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (t : spec.Domain) :
          so.withTraceAppend traceFn t = do let uliftM (so t) tell (traceFn t u) pure u
          theorem QueryImpl.fst_map_run_withTraceAppend {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :
          theorem QueryImpl.probFailure_run_simulateQ_withTraceAppend {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :
          theorem QueryImpl.NeverFail_run_simulateQ_withTraceAppend_iff {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :

          evalDist / probOutput / support bridges for withTraceAppend #

          theorem QueryImpl.evalDist_fst_run_withTraceAppend {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :
          theorem QueryImpl.probOutput_fst_run_withTraceAppend {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) (x : α) :
          theorem QueryImpl.support_fst_run_withTraceAppend {ι : Type u} {spec : OracleSpec ι} {α : Type u} {m : Type u → Type v} [Monad m] {ω : Type u} [EmptyCollection ω] [Append ω] [LawfulMonad m] [LawfulAppend ω] [HasEvalSPMF m] (so : QueryImpl spec m) (traceFn : (t : spec.Domain) → spec.Range tω) (mx : OracleComp spec α) :