PQXDH in Lean

5.6. The PermDraws Tactic🔗

Definition5.1
L∃∀Nused by 0

A custom Lean 4 tactic for automatically proving distributional equivalences between probability computations that differ only in the order of independent uniform draws. Invoked as perm_draws in tactic mode.

Code for Definition5.11 definition
  • def PQXDHLean.Tactics.permDrawsImpl : Lean.Elab.Tactic.TacticMLean.Elab.Tactic.TacticM (α : Type) : TypeThe tactic monad, which extends the term elaboration monad `TermElabM` with state that contains the
    current goals (`Lean.Elab.Tactic.State`, accessible via `MonadStateOf`) and local information about
    the current tactic's name and whether error recovery is enabled (`Lean.Elab.Tactic.Context`,
    accessible via `MonadReaderOf`).
     UnitUnit : TypeThe canonical type with one element. This element is written `()`.
    
    `Unit` has a number of uses:
    * It can be used to model control flow that returns from a function call without providing other
      information.
    * Monadic actions that return `Unit` have side effects without computing values.
    * In polymorphic types, it can be used to indicate that no data is to be stored in a particular
      field.
    
    def PQXDHLean.Tactics.permDrawsImpl :
      Lean.Elab.Tactic.TacticMLean.Elab.Tactic.TacticM (α : Type) : TypeThe tactic monad, which extends the term elaboration monad `TermElabM` with state that contains the
    current goals (`Lean.Elab.Tactic.State`, accessible via `MonadStateOf`) and local information about
    the current tactic's name and whether error recovery is enabled (`Lean.Elab.Tactic.Context`,
    accessible via `MonadReaderOf`).
     UnitUnit : TypeThe canonical type with one element. This element is written `()`.
    
    `Unit` has a number of uses:
    * It can be used to model control flow that returns from a function call without providing other
      information.
    * Monadic actions that return `Unit` have side effects without computing values.
    * In polymorphic types, it can be used to indicate that no data is to be stored in a particular
      field.
    
    `perm_draws` automatically proves probability equality goals of the form
    `Pr[= z | LHS] = Pr[= z | RHS]` where both sides are sequences of
    independent uniform draws followed by the same body expression,
    possibly differing in draw order and unused draws.
    
    All rewrites target the LHS only (via `conv_lhs`). 
    complete

5.6.1. Motivation🔗

In game-based cryptographic proofs, security reductions often require showing that two probabilistic computations produce the same distribution. After unfolding definitions and simplifying oracle implementations, these goals reduce to: both sides sample the same uniform draws but in different order, possibly with extra unused draws on one side. Proving this by hand requires computing the permutation between draw orders and emitting a sequence of adjacent transpositions, which is tedious and error-prone. The perm_draws tactic automates this entirely.

5.6.2. Usage🔗

After normalizing both sides of a distributional equality to bind chains of uniform draws (typically via simp and simp_all), a single call to perm_draws closes the goal.

The tactic is used in the distributional equivalence proofs that underpin the passive secrecy theorem.

5.6.3. Design decision🔗

All rewrites target the LHS only via conv_lhs. This avoids the unpredictability of VCV-io's rewrite tactics, which use first | conv_lhs | conv_rhs and can modify either side of the equation when both sides have matching structure.

5.6.4. Scope🔗

The tactic handles goals where all draws are independent uniform samples, the bodies are identical modulo variable permutation, and the only structural difference is draw order and unused draws.

It does not handle dependent draws, conditional branches, different body structures, or computational indistinguishability arguments.

5.6.5. Implementation🔗

The tactic is implemented in six modules, each handling a distinct phase of the proof automation pipeline.

5.6.5.1. Expression utilities🔗

Definition5.2
L∃∀Nused by 0

Search for an application of a given constant anywhere inside an expression tree, used by the goal parser to locate probOutput and probEvent subexpressions.

Code for Definition5.21 definition
  • opaque PQXDHLean.Tactics.findApp? (nameLean.Name : Lean.NameLean.Name : TypeHierarchical names consist of a sequence of components, each of
    which is either a string or numeric, that are written separated by dots (`.`).
    
    Hierarchical names are used to name declarations and for creating
    unique identifiers for free variables and metavariables.
    
    You can create hierarchical names using a backtick:
    ```
    `Lean.Meta.whnf
    ```
    It is short for `.str (.str (.str .anonymous "Lean") "Meta") "whnf"`.
    
    You can use double backticks to request Lean to statically check whether the name
    corresponds to a Lean declaration in scope.
    ```
    ``Lean.Meta.whnf
    ```
    If the name is not in scope, Lean will report an error.
    
    There are two ways to convert a `String` to a `Name`:
    
     1. `Name.mkSimple` creates a name with a single string component.
    
     2. `String.toName` first splits the string into its dot-separated
        components, and then creates a hierarchical name.
    ) (eLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      OptionOption.{u} (α : Type u) : Type uOptional values, which are either `some` around a value from the underlying type or `none`.
    
    `Option` can represent nullable types or computations that might fail. In the codomain of a function
    type, it can also represent partiality.
     Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    
    opaque PQXDHLean.Tactics.findApp?
      (nameLean.Name : Lean.NameLean.Name : TypeHierarchical names consist of a sequence of components, each of
    which is either a string or numeric, that are written separated by dots (`.`).
    
    Hierarchical names are used to name declarations and for creating
    unique identifiers for free variables and metavariables.
    
    You can create hierarchical names using a backtick:
    ```
    `Lean.Meta.whnf
    ```
    It is short for `.str (.str (.str .anonymous "Lean") "Meta") "whnf"`.
    
    You can use double backticks to request Lean to statically check whether the name
    corresponds to a Lean declaration in scope.
    ```
    ``Lean.Meta.whnf
    ```
    If the name is not in scope, Lean will report an error.
    
    There are two ways to convert a `String` to a `Name`:
    
     1. `Name.mkSimple` creates a name with a single string component.
    
     2. `String.toName` first splits the string into its dot-separated
        components, and then creates a hierarchical name.
    ) (eLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      OptionOption.{u} (α : Type u) : Type uOptional values, which are either `some` around a value from the underlying type or `none`.
    
    `Option` can represent nullable types or computations that might fail. In the codomain of a function
    type, it can also represent partiality.
     Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    
    Find an application of `name` anywhere in `e`. 
    complete

5.6.5.2. Goal parsing🔗

Definition5.3
L∃∀Nused by 0

Extract the computation from a probOutput comp z expression.

Code for Definition5.31 definition
  • def PQXDHLean.Tactics.matchProbOutput? (eLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      OptionOption.{u} (α : Type u) : Type uOptional values, which are either `some` around a value from the underlying type or `none`.
    
    `Option` can represent nullable types or computations that might fail. In the codomain of a function
    type, it can also represent partiality.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.
    def PQXDHLean.Tactics.matchProbOutput?
      (eLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      OptionOption.{u} (α : Type u) : Type uOptional values, which are either `some` around a value from the underlying type or `none`.
    
    `Option` can represent nullable types or computations that might fail. In the codomain of a function
    type, it can also represent partiality.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.
    Extract the computation from a `probOutput comp z` expression.
    Returns `(comp, z)`. 
    complete
Definition5.4
L∃∀Nused by 0

Extract the computation from a probEvent comp p expression.

Code for Definition5.41 definition
  • def PQXDHLean.Tactics.matchProbEvent? (eLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      OptionOption.{u} (α : Type u) : Type uOptional values, which are either `some` around a value from the underlying type or `none`.
    
    `Option` can represent nullable types or computations that might fail. In the codomain of a function
    type, it can also represent partiality.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.
    def PQXDHLean.Tactics.matchProbEvent?
      (eLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      OptionOption.{u} (α : Type u) : Type uOptional values, which are either `some` around a value from the underlying type or `none`.
    
    `Option` can represent nullable types or computations that might fail. In the codomain of a function
    type, it can also represent partiality.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.
    Extract the computation from a `probEvent comp p` expression.
    Returns `(comp, p)`. 
    complete
Definition5.5
L∃∀Nused by 0

Parse the goal Pr[= z | LHS] = Pr[= z | RHS], supporting both probOutput and probEvent variants.

Code for Definition5.51 definition
  • def PQXDHLean.Tactics.parseProbEqSides (targetLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      Lean.MetaMLean.Meta.MetaM (α : Type) : TypeThe `MetaM` monad is a core component of Lean's metaprogramming framework, facilitating the
    construction and manipulation of expressions (`Lean.Expr`) within Lean.
    
    It builds on top of `CoreM` and additionally provides:
    - A `LocalContext` for managing free variables.
    - A `MetavarContext` for managing metavariables.
    - A `Cache` for caching results of the key `MetaM` operations.
    
    The key operations provided by `MetaM` are:
    - `inferType`, which attempts to automatically infer the type of a given expression.
    - `whnf`, which reduces an expression to the point where the outermost part is no longer reducible
      but the inside may still contain unreduced expression.
    - `isDefEq`, which determines whether two expressions are definitionally equal, possibly assigning
      meta variables in the process.
    - `forallTelescope` and `lambdaTelescope`, which make it possible to automatically move into
      (nested) binders while updating the local context.
    
    The following is a small example that demonstrates how to obtain and manipulate the type of a
    `Fin` expression:
    ```
    public import Lean
    
    open Lean Meta
    
    def getFinBound (e : Expr) : MetaM (Option Expr) := do
      let type ← whnf (← inferType e)
      let_expr Fin bound := type | return none
      return bound
    
    def a : Fin 100 := 42
    
    run_meta
      match ← getFinBound (.const ``a []) with
      | some limit => IO.println (← ppExpr limit)
      | none => IO.println "no limit found"
    ```
     (OptionOption.{u} (α : Type u) : Type uOptional values, which are either `some` around a value from the underlying type or `none`.
    
    `Option` can represent nullable types or computations that might fail. In the codomain of a function
    type, it can also represent partiality.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.)
    def PQXDHLean.Tactics.parseProbEqSides
      (targetLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      Lean.MetaMLean.Meta.MetaM (α : Type) : TypeThe `MetaM` monad is a core component of Lean's metaprogramming framework, facilitating the
    construction and manipulation of expressions (`Lean.Expr`) within Lean.
    
    It builds on top of `CoreM` and additionally provides:
    - A `LocalContext` for managing free variables.
    - A `MetavarContext` for managing metavariables.
    - A `Cache` for caching results of the key `MetaM` operations.
    
    The key operations provided by `MetaM` are:
    - `inferType`, which attempts to automatically infer the type of a given expression.
    - `whnf`, which reduces an expression to the point where the outermost part is no longer reducible
      but the inside may still contain unreduced expression.
    - `isDefEq`, which determines whether two expressions are definitionally equal, possibly assigning
      meta variables in the process.
    - `forallTelescope` and `lambdaTelescope`, which make it possible to automatically move into
      (nested) binders while updating the local context.
    
    The following is a small example that demonstrates how to obtain and manipulate the type of a
    `Fin` expression:
    ```
    public import Lean
    
    open Lean Meta
    
    def getFinBound (e : Expr) : MetaM (Option Expr) := do
      let type ← whnf (← inferType e)
      let_expr Fin bound := type | return none
      return bound
    
    def a : Fin 100 := 42
    
    run_meta
      match ← getFinBound (.const ``a []) with
      | some limit => IO.println (← ppExpr limit)
      | none => IO.println "no limit found"
    ```
    
        (OptionOption.{u} (α : Type u) : Type uOptional values, which are either `some` around a value from the underlying type or `none`.
    
    `Option` can represent nullable types or computations that might fail. In the codomain of a function
    type, it can also represent partiality.
    
          (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.)
    Parse goal `Pr[= z | lhs] = Pr[= z | rhs]`.
    Returns `(lhsComp, rhsComp, z)`. 
    complete

5.6.5.3. Bind chain extraction🔗

Definition5.6
L∃∀Nused by 0

Walk a computation's right-associated bind chain, collecting the sequence of draw computations and the residual body expression. The body has loose bound variable references where bvar 0 is the innermost (last) draw and bvar (n-1) is the outermost (first) draw.

Code for Definition5.61 definition
  • opaque PQXDHLean.Tactics.extractBindChain (eLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      Lean.MetaMLean.Meta.MetaM (α : Type) : TypeThe `MetaM` monad is a core component of Lean's metaprogramming framework, facilitating the
    construction and manipulation of expressions (`Lean.Expr`) within Lean.
    
    It builds on top of `CoreM` and additionally provides:
    - A `LocalContext` for managing free variables.
    - A `MetavarContext` for managing metavariables.
    - A `Cache` for caching results of the key `MetaM` operations.
    
    The key operations provided by `MetaM` are:
    - `inferType`, which attempts to automatically infer the type of a given expression.
    - `whnf`, which reduces an expression to the point where the outermost part is no longer reducible
      but the inside may still contain unreduced expression.
    - `isDefEq`, which determines whether two expressions are definitionally equal, possibly assigning
      meta variables in the process.
    - `forallTelescope` and `lambdaTelescope`, which make it possible to automatically move into
      (nested) binders while updating the local context.
    
    The following is a small example that demonstrates how to obtain and manipulate the type of a
    `Fin` expression:
    ```
    public import Lean
    
    open Lean Meta
    
    def getFinBound (e : Expr) : MetaM (Option Expr) := do
      let type ← whnf (← inferType e)
      let_expr Fin bound := type | return none
      return bound
    
    def a : Fin 100 := 42
    
    run_meta
      match ← getFinBound (.const ``a []) with
      | some limit => IO.println (← ppExpr limit)
      | none => IO.println "no limit found"
    ```
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.
    opaque PQXDHLean.Tactics.extractBindChain
      (eLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      Lean.MetaMLean.Meta.MetaM (α : Type) : TypeThe `MetaM` monad is a core component of Lean's metaprogramming framework, facilitating the
    construction and manipulation of expressions (`Lean.Expr`) within Lean.
    
    It builds on top of `CoreM` and additionally provides:
    - A `LocalContext` for managing free variables.
    - A `MetavarContext` for managing metavariables.
    - A `Cache` for caching results of the key `MetaM` operations.
    
    The key operations provided by `MetaM` are:
    - `inferType`, which attempts to automatically infer the type of a given expression.
    - `whnf`, which reduces an expression to the point where the outermost part is no longer reducible
      but the inside may still contain unreduced expression.
    - `isDefEq`, which determines whether two expressions are definitionally equal, possibly assigning
      meta variables in the process.
    - `forallTelescope` and `lambdaTelescope`, which make it possible to automatically move into
      (nested) binders while updating the local context.
    
    The following is a small example that demonstrates how to obtain and manipulate the type of a
    `Fin` expression:
    ```
    public import Lean
    
    open Lean Meta
    
    def getFinBound (e : Expr) : MetaM (Option Expr) := do
      let type ← whnf (← inferType e)
      let_expr Fin bound := type | return none
      return bound
    
    def a : Fin 100 := 42
    
    run_meta
      match ← getFinBound (.const ``a []) with
      | some limit => IO.println (← ppExpr limit)
      | none => IO.println "no limit found"
    ```
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.
    Extract a right-associated bind chain from a computation expression.
    Returns `(draws, body)` where `draws[0]` is the outermost draw.
    The body has loose bvar references:
      bvar 0 = innermost (last) draw,
      bvar (n-1) = outermost (first) draw. 
    complete

5.6.5.4. De Bruijn analysis🔗

Definition5.7
L∃∀Nused by 0

Traverse the LHS and RHS bodies in parallel, collecting pairs of de Bruijn indices at corresponding positions. Each pair (i, j) means LHS draw i fills the same role as RHS draw j. Draws that appear in one body but not the other are classified as unused.

Code for Definition5.71 definition
  • opaque PQXDHLean.Tactics.collectBVarPairs :
      Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
      Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
      ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.  ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.
    opaque PQXDHLean.Tactics.collectBVarPairs :
      Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     
        Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
     
          ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.  ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.
    Parallel traversal of two expressions to collect `(bvar_L, bvar_R)` pairs
    at corresponding positions. Both expressions should be structurally
    identical except for bvar indices. 
    complete

5.6.5.5. Permutation computation and bubble sort🔗

Definition5.8
L∃∀Nused by 0

Given bvar pairs and draw counts, compute the permutation mapping each LHS draw position to the corresponding RHS position. Unused LHS draws (newly inserted) are mapped to unused RHS positions.

Code for Definition5.81 definition
  • def PQXDHLean.Tactics.computePermutation (pairsArray (ℕ × ℕ) : ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.)
      (nL nR : Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    ) : Lean.MetaMLean.Meta.MetaM (α : Type) : TypeThe `MetaM` monad is a core component of Lean's metaprogramming framework, facilitating the
    construction and manipulation of expressions (`Lean.Expr`) within Lean.
    
    It builds on top of `CoreM` and additionally provides:
    - A `LocalContext` for managing free variables.
    - A `MetavarContext` for managing metavariables.
    - A `Cache` for caching results of the key `MetaM` operations.
    
    The key operations provided by `MetaM` are:
    - `inferType`, which attempts to automatically infer the type of a given expression.
    - `whnf`, which reduces an expression to the point where the outermost part is no longer reducible
      but the inside may still contain unreduced expression.
    - `isDefEq`, which determines whether two expressions are definitionally equal, possibly assigning
      meta variables in the process.
    - `forallTelescope` and `lambdaTelescope`, which make it possible to automatically move into
      (nested) binders while updating the local context.
    
    The following is a small example that demonstrates how to obtain and manipulate the type of a
    `Fin` expression:
    ```
    public import Lean
    
    open Lean Meta
    
    def getFinBound (e : Expr) : MetaM (Option Expr) := do
      let type ← whnf (← inferType e)
      let_expr Fin bound := type | return none
      return bound
    
    def a : Fin 100 := 42
    
    run_meta
      match ← getFinBound (.const ``a []) with
      | some limit => IO.println (← ppExpr limit)
      | none => IO.println "no limit found"
    ```
     (ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    )
    def PQXDHLean.Tactics.computePermutation
      (pairsArray (ℕ × ℕ) : ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     (Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
     ×Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`. Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    )Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v)The product type, usually written `α × β`. Product types are also called pair or tuple types.
    Elements of this type are pairs in which the first element is an `α` and the second element is a
    `β`.
    
    Products nest to the right, so `(x, y, z) : α × β × γ` is equivalent to `(x, (y, z)) : α × (β × γ)`.
    
    
    Conventions for notations in identifiers:
    
     * The recommended spelling of `×` in identifiers is `Prod`.) (nL nR : Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    ) :
      Lean.MetaMLean.Meta.MetaM (α : Type) : TypeThe `MetaM` monad is a core component of Lean's metaprogramming framework, facilitating the
    construction and manipulation of expressions (`Lean.Expr`) within Lean.
    
    It builds on top of `CoreM` and additionally provides:
    - A `LocalContext` for managing free variables.
    - A `MetavarContext` for managing metavariables.
    - A `Cache` for caching results of the key `MetaM` operations.
    
    The key operations provided by `MetaM` are:
    - `inferType`, which attempts to automatically infer the type of a given expression.
    - `whnf`, which reduces an expression to the point where the outermost part is no longer reducible
      but the inside may still contain unreduced expression.
    - `isDefEq`, which determines whether two expressions are definitionally equal, possibly assigning
      meta variables in the process.
    - `forallTelescope` and `lambdaTelescope`, which make it possible to automatically move into
      (nested) binders while updating the local context.
    
    The following is a small example that demonstrates how to obtain and manipulate the type of a
    `Fin` expression:
    ```
    public import Lean
    
    open Lean Meta
    
    def getFinBound (e : Expr) : MetaM (Option Expr) := do
      let type ← whnf (← inferType e)
      let_expr Fin bound := type | return none
      return bound
    
    def a : Fin 100 := 42
    
    run_meta
      match ← getFinBound (.const ``a []) with
      | some limit => IO.println (← ppExpr limit)
      | none => IO.println "no limit found"
    ```
     (ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    )
    Given bvar pairs and draw counts, compute the permutation.
    `perm[lhsPos] = rhsPos` for each LHS draw position.
    Unused LHS draws (newly inserted) are mapped to unused RHS positions. 
    complete
Definition5.9
L∃∀Nused by 0

Decompose a permutation into adjacent transpositions via bubble sort, producing a minimal swap sequence.

Code for Definition5.91 definition
  • def PQXDHLean.Tactics.bubbleSortSwaps (targetIndicesArray ℕ : ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    ) : ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    
    def PQXDHLean.Tactics.bubbleSortSwaps
      (targetIndicesArray ℕ : ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    ) : ArrayArray.{u} (α : Type u) : Type u`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
    from `α`. This type has special support in the runtime.
    
    Arrays perform best when unshared. As long as there is never more than one reference to an array,
    all updates will be performed _destructively_. This results in performance comparable to mutable
    arrays in imperative programming languages.
    
    An array has a size and a capacity. The size is the number of elements present in the array, while
    the capacity is the amount of memory currently allocated for elements. The size is accessible via
    `Array.size`, but the capacity is not observable from Lean code. `Array.emptyWithCapacity n` creates
    an array which is equal to `#[]`, but internally allocates an array of capacity `n`. When the size
    exceeds the capacity, allocation is required to grow the array.
    
    From the point of view of proofs, `Array α` is just a wrapper around `List α`.
     Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    
    Decompose a permutation into adjacent transpositions via bubble sort.
    Input: `targetIndices[i]` = where element at position `i` should go.
    Output: sequence of depths (swap positions `depth` and `depth+1`). 
    complete

5.6.5.6. Tactic emission🔗

Definition5.10
L∃∀Nused by 0

Build proof term for swapping adjacent draws at given depth. Depth 0 uses probEvent_bind_bind_swap, depth n+1 wraps in probEvent_bind_congr.

Code for Definition5.101 definition
  • def PQXDHLean.Tactics.mkSwapProofTerm (depth : Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    ) :
      Lean.Elab.Tactic.TacticMLean.Elab.Tactic.TacticM (α : Type) : TypeThe tactic monad, which extends the term elaboration monad `TermElabM` with state that contains the
    current goals (`Lean.Elab.Tactic.State`, accessible via `MonadStateOf`) and local information about
    the current tactic's name and whether error recovery is enabled (`Lean.Elab.Tactic.Context`,
    accessible via `MonadReaderOf`).
     (Lean.TSyntax (ks : Lean.SyntaxNodeKinds) : TypeTyped syntax, which tracks the potential kinds of the `Syntax` it contains.
    
    While syntax quotations produce or expect `TSyntax` values of the correct kinds, this is not
    otherwise enforced; it can easily be circumvented by direct use of the constructor.
    Lean.TSyntaxLean.TSyntax (ks : Lean.SyntaxNodeKinds) : TypeTyped syntax, which tracks the potential kinds of the `Syntax` it contains.
    
    While syntax quotations produce or expect `TSyntax` values of the correct kinds, this is not
    otherwise enforced; it can easily be circumvented by direct use of the constructor.
     `term)Lean.TSyntax (ks : Lean.SyntaxNodeKinds) : TypeTyped syntax, which tracks the potential kinds of the `Syntax` it contains.
    
    While syntax quotations produce or expect `TSyntax` values of the correct kinds, this is not
    otherwise enforced; it can easily be circumvented by direct use of the constructor.
    
    def PQXDHLean.Tactics.mkSwapProofTerm
      (depth : Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    ) :
      Lean.Elab.Tactic.TacticMLean.Elab.Tactic.TacticM (α : Type) : TypeThe tactic monad, which extends the term elaboration monad `TermElabM` with state that contains the
    current goals (`Lean.Elab.Tactic.State`, accessible via `MonadStateOf`) and local information about
    the current tactic's name and whether error recovery is enabled (`Lean.Elab.Tactic.Context`,
    accessible via `MonadReaderOf`).
    
        (Lean.TSyntax (ks : Lean.SyntaxNodeKinds) : TypeTyped syntax, which tracks the potential kinds of the `Syntax` it contains.
    
    While syntax quotations produce or expect `TSyntax` values of the correct kinds, this is not
    otherwise enforced; it can easily be circumvented by direct use of the constructor.
    Lean.TSyntaxLean.TSyntax (ks : Lean.SyntaxNodeKinds) : TypeTyped syntax, which tracks the potential kinds of the `Syntax` it contains.
    
    While syntax quotations produce or expect `TSyntax` values of the correct kinds, this is not
    otherwise enforced; it can easily be circumvented by direct use of the constructor.
     `term)Lean.TSyntax (ks : Lean.SyntaxNodeKinds) : TypeTyped syntax, which tracks the potential kinds of the `Syntax` it contains.
    
    While syntax quotations produce or expect `TSyntax` values of the correct kinds, this is not
    otherwise enforced; it can easily be circumvented by direct use of the constructor.
    
    Build proof term for swapping adjacent draws at given depth.
    Depth 0: `probEvent_bind_bind_swap _ _ _ _`
    Depth n+1: `probEvent_bind_congr fun _ _ => (inner)` 
    complete
Definition5.11
L∃∀Nused by 0

Emit a single adjacent transposition at a given depth, targeting LHS only. Handles the probOutput to probEvent conversion.

Code for Definition5.111 definition
  • def PQXDHLean.Tactics.emitLhsSwap (depth : Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    ) :
      Lean.Elab.Tactic.TacticMLean.Elab.Tactic.TacticM (α : Type) : TypeThe tactic monad, which extends the term elaboration monad `TermElabM` with state that contains the
    current goals (`Lean.Elab.Tactic.State`, accessible via `MonadStateOf`) and local information about
    the current tactic's name and whether error recovery is enabled (`Lean.Elab.Tactic.Context`,
    accessible via `MonadReaderOf`).
     UnitUnit : TypeThe canonical type with one element. This element is written `()`.
    
    `Unit` has a number of uses:
    * It can be used to model control flow that returns from a function call without providing other
      information.
    * Monadic actions that return `Unit` have side effects without computing values.
    * In polymorphic types, it can be used to indicate that no data is to be stored in a particular
      field.
    
    def PQXDHLean.Tactics.emitLhsSwap
      (depth : Nat : TypeThe natural numbers, starting at zero.
    
    This type is special-cased by both the kernel and the compiler, and overridden with an efficient
    implementation. Both use a fast arbitrary-precision arithmetic library (usually
    [GMP](https://gmplib.org/)); at runtime, `Nat` values that are sufficiently small are unboxed.
    ) :
      Lean.Elab.Tactic.TacticMLean.Elab.Tactic.TacticM (α : Type) : TypeThe tactic monad, which extends the term elaboration monad `TermElabM` with state that contains the
    current goals (`Lean.Elab.Tactic.State`, accessible via `MonadStateOf`) and local information about
    the current tactic's name and whether error recovery is enabled (`Lean.Elab.Tactic.Context`,
    accessible via `MonadReaderOf`).
     UnitUnit : TypeThe canonical type with one element. This element is written `()`.
    
    `Unit` has a number of uses:
    * It can be used to model control flow that returns from a function call without providing other
      information.
    * Monadic actions that return `Unit` have side effects without computing values.
    * In polymorphic types, it can be used to indicate that no data is to be stored in a particular
      field.
    
    Emit a single adjacent transposition at `depth`, targeting LHS only.
    Handles the `probOutput`↔`probEvent` conversion. 
    complete
Definition5.12
L∃∀Nused by 0

Insert one unused draw at position 0 in LHS via probOutput_bind_const.

Code for Definition5.121 definition
  • def PQXDHLean.Tactics.emitInsertUnusedDraw (sampleExprLean.Expr zLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      Lean.Elab.Tactic.TacticMLean.Elab.Tactic.TacticM (α : Type) : TypeThe tactic monad, which extends the term elaboration monad `TermElabM` with state that contains the
    current goals (`Lean.Elab.Tactic.State`, accessible via `MonadStateOf`) and local information about
    the current tactic's name and whether error recovery is enabled (`Lean.Elab.Tactic.Context`,
    accessible via `MonadReaderOf`).
     UnitUnit : TypeThe canonical type with one element. This element is written `()`.
    
    `Unit` has a number of uses:
    * It can be used to model control flow that returns from a function call without providing other
      information.
    * Monadic actions that return `Unit` have side effects without computing values.
    * In polymorphic types, it can be used to indicate that no data is to be stored in a particular
      field.
    
    def PQXDHLean.Tactics.emitInsertUnusedDraw
      (sampleExprLean.Expr zLean.Expr : Lean.ExprLean.Expr : TypeLean expressions. This data structure is used in the kernel and
    elaborator. However, expressions sent to the kernel should not
    contain metavariables.
    
    Remark: we use the `E` suffix (short for `Expr`) to avoid collision with keywords.
    We considered using «...», but it is too inconvenient to use.
    ) :
      Lean.Elab.Tactic.TacticMLean.Elab.Tactic.TacticM (α : Type) : TypeThe tactic monad, which extends the term elaboration monad `TermElabM` with state that contains the
    current goals (`Lean.Elab.Tactic.State`, accessible via `MonadStateOf`) and local information about
    the current tactic's name and whether error recovery is enabled (`Lean.Elab.Tactic.Context`,
    accessible via `MonadReaderOf`).
     UnitUnit : TypeThe canonical type with one element. This element is written `()`.
    
    `Unit` has a number of uses:
    * It can be used to model control flow that returns from a function call without providing other
      information.
    * Monadic actions that return `Unit` have side effects without computing values.
    * In polymorphic types, it can be used to indicate that no data is to be stored in a particular
      field.
    
    Insert one unused draw at position 0 in LHS.
    `sampleExpr` is the draw computation to prepend (e.g., `$ᵗ F`).
    `z` is the output value from the `Pr[= z | ...]` goal. 
    complete