Documentation

VCVio.OracleComp.SimSemantics.QueryImpl.Constructions

Basic Constructions of Simulation Oracles #

This file defines a number of basic simulation oracles, as well as operations to combine them.

preInsert and postInsert #

The two main building blocks for instrumented QueryImpl values are preInsert and postInsert. Both take a base QueryImpl spec m and a per-query side effect, and produce a new QueryImpl spec n that wraps the base with that side effect:

Both come with a complete generic theory, parametric in a projection proj : ∀ {γ}, n γ → m γ that strips the instrumentation: proj_simulateQ_preInsert, probFailure_proj_simulateQ_preInsert, NeverFail_proj_simulateQ_preInsert_iff, evalDist_proj_simulateQ_preInsert, probOutput_proj_simulateQ_preInsert, support_proj_simulateQ_preInsert, finSupport_proj_simulateQ_preInsert, and the induction principle simulateQ_preInsert.induct (with postInsert analogues). Query-bound transfer through these wrappers lives in QueryTracking/QueryBound.lean.

Most of the wrappers in QueryTracking/ (withTraceBefore, withTrace, withTraceAppendBefore, withTraceAppend, withCost, withCounting, withAddCost, withUnitCost, withLogging, appendInputLog) bottom out at these combinators. New instrumentation should follow the same pattern when its shape is "for each query, run a side effect and delegate" — wrappers whose control flow is conditional on external state or the would-be response (cache-on-hit, seed fallback, budget gating) genuinely need a custom QueryImpl and stay outside this hierarchy.

def QueryImpl.compose {m : Type u → Type v} [Monad m] {ι : Type u_1} {ι' : Type u_2} {spec : OracleSpec ι} {spec' : OracleSpec ι'} (so' : QueryImpl spec' m) (so : QueryImpl spec (OracleComp spec')) :
QueryImpl spec m

Given an implementation of spec in terms of a new set of oracles spec', and an implementation of spec' in terms of arbitrary m, implement spec in terms of m.

Instances For
    @[simp]
    theorem QueryImpl.apply_compose {m : Type u → Type v} [Monad m] {ι : Type u_1} {ι' : Type u_2} {spec : OracleSpec ι} {spec' : OracleSpec ι'} (so' : QueryImpl spec' m) (so : QueryImpl spec (OracleComp spec')) (t : spec.Domain) :
    (so' ∘ₛ so) t = simulateQ so' (so t)
    @[simp]
    theorem QueryImpl.simulateQ_compose {m : Type u → Type v} [Monad m] {ι : Type u_1} {ι' : Type u_2} {spec : OracleSpec ι} {spec' : OracleSpec ι'} {α : Type u} [LawfulMonad m] (so' : QueryImpl spec' m) (so : QueryImpl spec (OracleComp spec')) (oa : OracleComp spec α) :
    simulateQ (so' ∘ₛ so) oa = simulateQ so' (simulateQ so oa)
    @[simp]
    theorem QueryImpl.compose_id' {m : Type u → Type v} [Monad m] {ι : Type u_1} {spec : OracleSpec ι} [LawfulMonad m] (so : QueryImpl spec m) :
    def QueryImpl.preInsert {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α : Type u} (so : QueryImpl spec m) (nx : spec.Domainn α) :
    QueryImpl spec n

    Given monads m and n with MonadLiftT m n, an implementation of spec in m, and a computation nx in n for each query input, construct a new implementation QueryImpl.preInsert so nx that calls nx on every query before the actual substitution so. Note that nx is expected to have some side-effects, it's actual result is discarded.

    Instances For
      @[simp]
      theorem QueryImpl.preInsert_apply {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α : Type u} [LawfulMonad n] (so : QueryImpl spec m) (nx : spec.Domainn α) (t : spec.Domain) :
      so.preInsert nx t = do let __discrnx t have x : α := __discr liftM (so t)
      theorem QueryImpl.simulateQ_preInsert_query {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α : Type u} [LawfulMonad n] (so : QueryImpl spec m) (nx : spec.Domainn α) (t : spec.Domain) :
      simulateQ (so.preInsert nx) (query t) = do let __discrnx t have x : α := __discr liftM (so t)

      One-step characterisation of simulateQ (preInsert so nx) on a single query.

      theorem QueryImpl.simulateQ_preInsert.induct {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [Monad m] [LawfulMonad m] [LawfulMonad n] (so : QueryImpl spec m) (nx : spec.Domainn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.preInsert nx t) = so t) {motive : OracleComp spec βm βProp} (h_pure : ∀ (x : β), motive (pure x) (pure x)) (h_query_bind : ∀ (t : spec.Domain) (k : spec.Range tOracleComp spec β) (k' : spec.Range tm β), (∀ (u : spec.Range t), motive (k u) (k' u))motive (query t >>= k) (so t >>= k')) (oa : OracleComp spec β) :
      motive oa (proj (simulateQ (so.preInsert nx) oa))

      Induction principle for proj (simulateQ (so.preInsert nx) oa) parametric in a motive OracleComp spec β → m β → Prop. The recursion structure of proj_simulateQ_preInsert is exposed as two cases mirroring OracleComp.inductionOn: in pure x the projected term reduces to pure x, and in query t >>= k it reduces to so t >>= k' for some continuation k' u = proj (simulateQ (so.preInsert nx) (k u)). Tagged @[elab_as_elim] so it is usable as induction oa using simulateQ_preInsert.induct.

      theorem QueryImpl.proj_simulateQ_preInsert {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [Monad m] [LawfulMonad m] [LawfulMonad n] (so : QueryImpl spec m) (nx : spec.Domainn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.preInsert nx t) = so t) (oa : OracleComp spec β) :
      proj (simulateQ (so.preInsert nx) oa) = simulateQ so oa

      Generic strip lemma: given a monad-morphism-style projection proj : ∀ {γ}, n γ → m γ that preserves pure and bind and discards the inserted side effect on each query, simulating with preInsert so nx and projecting back recovers simulateQ so. The proof is the canonical use of simulateQ_preInsert.induct: the parametric motive is instantiated to the equality with simulateQ so oa, leaving trivial cases.

      theorem QueryImpl.probFailure_proj_simulateQ_preInsert {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [Monad m] [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SPMF] [LawfulMonadLiftT m SPMF] (so : QueryImpl spec m) (nx : spec.Domainn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.preInsert nx t) = so t) (oa : OracleComp spec β) :
      Pr[⊥ | proj (simulateQ (so.preInsert nx) oa)] = Pr[⊥ | simulateQ so oa]

      A preInsert instrumentation preserves failure probability for any base monad with [MonadLiftT m SPMF], given the projection bundle and its compatibility with failure probabilities.

      theorem QueryImpl.neverFail_proj_simulateQ_preInsert_iff {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [Monad m] [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SPMF] [LawfulMonadLiftT m SPMF] (so : QueryImpl spec m) (nx : spec.Domainn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.preInsert nx t) = so t) (oa : OracleComp spec β) :
      NeverFail (proj (simulateQ (so.preInsert nx) oa)) NeverFail (simulateQ so oa)

      NeverFail biconditional companion of probFailure_proj_simulateQ_preInsert.

      theorem QueryImpl.simulateQ_preInsert_const_pure {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [Monad m] [LawfulMonad m] [LawfulMonad n] [LawfulMonadLiftT m n] (so : QueryImpl spec m) (x : α) (oa : OracleComp spec β) :
      simulateQ (so.preInsert fun (x_1 : spec.Domain) => pure x) oa = liftM (simulateQ so oa)

      When nx is constantly pure x, preInsert so nx is the lift of so and the resulting simulation equals the lifted underlying simulation. Generic analogue of the run_simulateQ_withTraceBefore_const_one no-op identity.

      evalDist / probOutput / support bridges for preInsert #

      theorem QueryImpl.evalDist_proj_simulateQ_preInsert {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [Monad m] [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SPMF] [LawfulMonadLiftT m SPMF] (so : QueryImpl spec m) (nx : spec.Domainn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.preInsert nx t) = so t) (oa : OracleComp spec β) :
      𝒟[proj (simulateQ (so.preInsert nx) oa)] = 𝒟[simulateQ so oa]
      theorem QueryImpl.probOutput_proj_simulateQ_preInsert {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [Monad m] [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SPMF] [LawfulMonadLiftT m SPMF] (so : QueryImpl spec m) (nx : spec.Domainn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.preInsert nx t) = so t) (oa : OracleComp spec β) (x : β) :
      Pr[= x | proj (simulateQ (so.preInsert nx) oa)] = Pr[= x | simulateQ so oa]
      theorem QueryImpl.support_proj_simulateQ_preInsert {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [Monad m] [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SetM] (so : QueryImpl spec m) (nx : spec.Domainn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.preInsert nx t) = so t) (oa : OracleComp spec β) :
      support (proj (simulateQ (so.preInsert nx) oa)) = support (simulateQ so oa)
      theorem QueryImpl.finSupport_proj_simulateQ_preInsert {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [Monad m] [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SetM] [HasEvalFinset m] [DecidableEq β] (so : QueryImpl spec m) (nx : spec.Domainn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.preInsert nx t) = so t) (oa : OracleComp spec β) :
      finSupport (proj (simulateQ (so.preInsert nx) oa)) = finSupport (simulateQ so oa)
      def QueryImpl.postInsert {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} (so : QueryImpl spec m) {α : Type u} (nx : (t : spec.Domain) → spec.Range tn α) :
      QueryImpl spec n

      Given monads m and n with MonadLiftT m n, an implementation of spec in m, and a computation nx in n for each query output, construct a new implementation QueryImpl.postInsert so nx that calls nx on on the result of each substitution. Note that nx is expected to have some side-effects, it's actual result is discarded.

      Instances For
        @[simp]
        theorem QueryImpl.postInsert_apply {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α : Type u} (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (t : spec.Domain) :
        so.postInsert nx t = do let uliftM (so t) let __discrnx t u have x : α := __discr pure u
        theorem QueryImpl.simulateQ_postInsert_query {m : Type u → Type v} {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α : Type u} [LawfulMonad n] (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (t : spec.Domain) :
        simulateQ (so.postInsert nx) (query t) = do let uliftM (so t) let __discrnx t u have x : α := __discr pure u

        One-step characterisation of simulateQ (postInsert so nx) on a single query.

        theorem QueryImpl.simulateQ_postInsert.induct {m : Type u → Type v} [Monad m] {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [LawfulMonad m] [LawfulMonad n] (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.postInsert nx t) = so t) {motive : OracleComp spec βm βProp} (h_pure : ∀ (x : β), motive (pure x) (pure x)) (h_query_bind : ∀ (t : spec.Domain) (k : spec.Range tOracleComp spec β) (k' : spec.Range tm β), (∀ (u : spec.Range t), motive (k u) (k' u))motive (query t >>= k) (so t >>= k')) (oa : OracleComp spec β) :
        motive oa (proj (simulateQ (so.postInsert nx) oa))

        Induction principle for proj (simulateQ (so.postInsert nx) oa) parametric in a motive OracleComp spec β → m β → Prop. The recursion structure of proj_simulateQ_postInsert is exposed as two cases mirroring OracleComp.inductionOn: in pure x the projected term reduces to pure x, and in query t >>= k it reduces to so t >>= k' for some continuation k' u = proj (simulateQ (so.postInsert nx) (k u)). Tagged @[elab_as_elim] so it is usable as induction oa using simulateQ_postInsert.induct.

        theorem QueryImpl.proj_simulateQ_postInsert {m : Type u → Type v} [Monad m] {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [LawfulMonad m] [LawfulMonad n] (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.postInsert nx t) = so t) (oa : OracleComp spec β) :
        proj (simulateQ (so.postInsert nx) oa) = simulateQ so oa

        Generic strip lemma: given a monad-morphism-style projection proj : ∀ {γ}, n γ → m γ that preserves pure and bind and discards the inserted side effect on each query, simulating with postInsert so nx and projecting back recovers simulateQ so. The proof is the canonical use of simulateQ_postInsert.induct: the parametric motive is instantiated to the equality with simulateQ so oa, leaving trivial cases.

        theorem QueryImpl.probFailure_proj_simulateQ_postInsert {m : Type u → Type v} [Monad m] {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SPMF] [LawfulMonadLiftT m SPMF] (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.postInsert nx t) = so t) (oa : OracleComp spec β) :
        Pr[⊥ | proj (simulateQ (so.postInsert nx) oa)] = Pr[⊥ | simulateQ so oa]

        A postInsert instrumentation preserves failure probability for any base monad with [MonadLiftT m SPMF], given the projection bundle and its compatibility with failure probabilities.

        theorem QueryImpl.neverFail_proj_simulateQ_postInsert_iff {m : Type u → Type v} [Monad m] {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SPMF] [LawfulMonadLiftT m SPMF] (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.postInsert nx t) = so t) (oa : OracleComp spec β) :
        NeverFail (proj (simulateQ (so.postInsert nx) oa)) NeverFail (simulateQ so oa)

        NeverFail biconditional companion of probFailure_proj_simulateQ_postInsert.

        theorem QueryImpl.simulateQ_postInsert_const_pure {m : Type u → Type v} [Monad m] {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [LawfulMonad m] [LawfulMonad n] [LawfulMonadLiftT m n] (so : QueryImpl spec m) (x : α) (oa : OracleComp spec β) :
        simulateQ (so.postInsert fun (x_1 : spec.Domain) (x_2 : spec.Range x_1) => pure x) oa = liftM (simulateQ so oa)

        When nx is constantly pure x, postInsert so nx is the lift of so and the resulting simulation equals the lifted underlying simulation. Generic analogue of the run_simulateQ_withTrace_const_one no-op identity.

        evalDist / probOutput / support bridges for postInsert #

        theorem QueryImpl.evalDist_proj_simulateQ_postInsert {m : Type u → Type v} [Monad m] {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SPMF] [LawfulMonadLiftT m SPMF] (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.postInsert nx t) = so t) (oa : OracleComp spec β) :
        theorem QueryImpl.probOutput_proj_simulateQ_postInsert {m : Type u → Type v} [Monad m] {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SPMF] [LawfulMonadLiftT m SPMF] (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.postInsert nx t) = so t) (oa : OracleComp spec β) (x : β) :
        Pr[= x | proj (simulateQ (so.postInsert nx) oa)] = Pr[= x | simulateQ so oa]
        theorem QueryImpl.support_proj_simulateQ_postInsert {m : Type u → Type v} [Monad m] {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SetM] (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.postInsert nx t) = so t) (oa : OracleComp spec β) :
        support (proj (simulateQ (so.postInsert nx) oa)) = support (simulateQ so oa)
        theorem QueryImpl.finSupport_proj_simulateQ_postInsert {m : Type u → Type v} [Monad m] {n : Type u → Type w} [Monad n] [MonadLiftT m n] {ι : Type u_1} {spec : OracleSpec ι} {α β : Type u} [LawfulMonad m] [LawfulMonad n] [MonadLiftT m SetM] [HasEvalFinset m] [DecidableEq β] (so : QueryImpl spec m) (nx : (t : spec.Domain) → spec.Range tn α) (proj : {γ : Type u} → n γm γ) (hproj_pure : ∀ {γ : Type u} (x : γ), proj (pure x) = pure x) (hproj_bind : ∀ {γ δ : Type u} (b : n γ) (f : γn δ), proj (b >>= f) = do let xproj b proj (f x)) (hproj_apply : ∀ (t : spec.Domain), proj (so.postInsert nx t) = so t) (oa : OracleComp spec β) :
        finSupport (proj (simulateQ (so.postInsert nx) oa)) = finSupport (simulateQ so oa)