Documentation

VCVio.OracleComp.ProbComp

Computations with Uniform Selection Oracles #

This file defines a type ProbComp α for the case of OracleComp with access to a uniform selection oracle, specified by unifSpec, as well as common operations for this type.

We define $[0..n] as uniform selection starting from zero for any n : ℕ (uniformFin) as well as a version $[n⋯m] that tries to synthesize an instance of n < m (uniformRange). This allows us to avoid needing an OptionT wrapper to handle empty ranges.

We also define typeclasses HasUniformSelect β cont and HasUniformSelect! β cont to allow for $ xs and $! xs notation for uniform sampling from a container. These don't really enforce any semantics, so any new definition will need to prove lemmas about the behavior of the operation. TODO: we could introduce a mixin typeclass at least to handle this?

SampleableType α on the other hand allows for $ᵗ α notation for uniform type sampleing, and does enforce the uniformity of outputs. Encapsulating the thing you want to select in a SampleableType can therefore give more useful lemmas out of the box, in particular when using subtypes.

TODO: Some lemmas here don't exist at the PMF/SPMF levels.

theorem Fin.card_eq_countP_mem {n : } (s : Finset (Fin n)) :
s.card = Fin.countP fun (x : Fin n) => decide (x s)
@[reducible, inline]
abbrev ProbComp :

Simplified notation for computations with no oracles besides random inputs. This specific case can be used with #eval to run a random program, see OracleComp.runIO. NOTE: Need to decide if this should be more opaque than abbrev, seems like no as of now..

Equations
    Instances For
      def ProbComp.uniformFin (n : ) :
      ProbComp (Fin (n + 1))

      $[0..n] is the computation choosing a random value in the given range, inclusively. By making this range inclusive we avoid the case of choosing from the empty range.

      Equations
        Instances For
          theorem ProbComp.probOutput_uniformFin_eq_div (n : ) (m : Fin (n + 1)) :
          Pr[=m | $[0..n]] = 1 / (n + 1)
          @[simp]
          theorem ProbComp.probOutput_uniformFin (n : ) (m : Fin (n + 1)) :
          Pr[=m | $[0..n]] = (n + 1)⁻¹
          @[simp]
          theorem ProbComp.probEvent_uniformFin (n : ) (p : Fin (n + 1)Prop) [DecidablePred p] :
          Pr[p | $[0..n]] = (Fin.countP fun (i : Fin (n + 1)) => decide (p i)) / ↑(n + 1)
          def ProbComp.uniformRange (n m : ) (h : n < m) :
          ProbComp (Fin (m + 1))

          Select uniformly from a non-empty range. The notation attempts to derive h automatically.

          Equations
            Instances For

              Tactic to attempt to prove uniformRange decreasing bound, similar to array indexing.

              Equations
                Instances For

                  Select uniformly from a range of numbers. Attempts to use `get

                  Equations
                    Instances For
                      theorem ProbComp.uniformRange_def (n m : ) (h : n < m) :
                      @[simp]
                      theorem ProbComp.uniformRange_eq_uniformFin (n : ) (hn : 0 < n) :
                      @[simp]
                      theorem ProbComp.support_uniformRange (n m : ) (h : n < m) :
                      support (uniformRange n m h) = Set.Icc (Fin.ofNat (m + 1) n) (Fin.ofNat (m + 1) m)
                      @[simp]
                      theorem ProbComp.finSupport_uniformRange (n m : ) (h : n < m) :
                      @[simp]
                      theorem ProbComp.probOutput_uniformRange (n m : ) (k : Fin (m + 1)) (h : n < m) :
                      Pr[=k | uniformRange n m h] = if n k then (m - n + 1)⁻¹ else 0
                      @[simp]
                      theorem ProbComp.probEvent_uniformRange (n m : ) (p : Fin (m + 1)Prop) [DecidablePred p] (h : n < m) :
                      Pr[p | uniformRange n m h] = {x : Fin (m + 1) | n x p x}.card / (m - n + 1)
                      class ProbComp.HasUniformSelect (cont : Type u) (β : outParam Type) :

                      Typeclass to implement the notation $ xs for selecting an object uniformly from a collection. The container type is given by cont with the resulting type given by β. β is marked as an outParam so that Lean will first pick the output type before synthesizing. NOTE: This current implementation doesn't impose any "correctness" conditions, it purely exists to provide the notation, could revisit that in the future.

                      Instances
                        class ProbComp.HasUniformSelect! (cont : Type u) (β : outParam Type) :

                        Version of HasUniformSelect that doesn't allow for failure. Useful for things like Vector that can be shown nonempty at the type level.

                        Instances
                          Equations
                            Instances For
                              Equations
                                Instances For

                                  Given a non-failing uniform selection operation we also have a potentially failing one, using OptionT.lift

                                  Equations
                                    @[simp]
                                    theorem ProbComp.liftM_uniformSelect! {cont : Type u} {β : Type} [HasUniformSelect! cont β] (xs : cont) :
                                    liftM ($!xs) = $xs

                                    Compatibility of the $! xs operation with $ xs given the inferred instance. TODO: I think we probably want to simp in the other direction when possible?

                                    theorem ProbComp.uniformSelect_eq_liftM_uniformSelect! {cont : Type u} {β : Type} [HasUniformSelect! cont β] (xs : cont) :
                                    $xs = liftM ($!xs)

                                    Select a random element from a list by indexing into it with a uniform value. If the list is empty we instead just fail rather than choose a default value. This means selecting from a vector is often preferable, as we can prove at the type level that there is an element in the list, avoiding the defualt case of empty lists.

                                    Equations
                                      theorem ProbComp.uniformSelectList_def {α : Type} (xs : List α) :
                                      $xs = match xs with | [] => failure | x :: xs => (fun (x_1 : Fin (xs.length + 1)) => (x :: xs)[x_1]) <$> liftM $[0..xs.length]
                                      theorem ProbComp.uniformSelectList_cons {α : Type} (x : α) (xs : List α) :
                                      $(x :: xs) = liftM ((fun (x_1 : Fin (xs.length + 1)) => (x :: xs)[x_1]) <$> $[0..xs.length])
                                      @[simp]
                                      theorem ProbComp.support_uniformSelectList {α : Type} (xs : List α) :
                                      support ($xs) = {x : α | x xs}
                                      @[simp]
                                      theorem ProbComp.probOutput_uniformSelectList {α : Type} [DecidableEq α] (xs : List α) (x : α) :
                                      Pr[=x | $xs] = (List.count x xs) / xs.length
                                      @[simp]
                                      theorem ProbComp.probEvent_uniformSelectList {α : Type} (xs : List α) (p : αProp) [DecidablePred p] :
                                      Pr[p | $xs] = (List.countP (fun (b : α) => decide (p b)) xs) / xs.length
                                      instance ProbComp.hasUniformSelectVector (α : Type) (n : ) :
                                      HasUniformSelect! (Vector α (n + 1)) α

                                      Select a random element from a vector by indexing into it with a uniform value. TODO: different types of vectors in mathlib now

                                      Equations
                                        theorem ProbComp.uniformSelectVector_def {α : Type} {n : } (xs : Vector α (n + 1)) :
                                        $!xs = (fun (x : Fin (n + 1)) => xs[x]) <$> $[0..n]
                                        @[simp]
                                        theorem ProbComp.support_uniformSelectVector {α : Type} {n : } (xs : Vector α (n + 1)) :
                                        support ($!xs) = {x : α | x xs.toList}
                                        @[simp]
                                        theorem ProbComp.finSupport_uniformSelectVector {α : Type} {n : } (xs : Vector α (n + 1)) [DecidableEq α] :
                                        @[simp]
                                        theorem ProbComp.probOutput_uniformSelectVector {α : Type} {n : } (xs : Vector α (n + 1)) [DecidableEq α] (x : α) :
                                        Pr[=x | $!xs] = (Vector.count x xs) / (n + 1)
                                        @[simp]
                                        theorem ProbComp.probEvent_uniformSelectVector {α : Type} {n : } (xs : Vector α (n + 1)) (p : αProp) [DecidablePred p] :
                                        Pr[p | $xs] = (List.countP (fun (b : α) => decide (p b)) xs.toList) / (n + 1)
                                        theorem ProbComp.uniformSelectListVector_def {α : Type} {n : } (xs : List.Vector α (n + 1)) :
                                        $!xs = (fun (x : Fin (n + 1)) => xs[x]) <$> $[0..n]
                                        @[simp]
                                        theorem ProbComp.probOutput_uniformSelectListVector {α : Type} {n : } (xs : List.Vector α (n + 1)) [DecidableEq α] (x : α) :
                                        Pr[=x | $!xs] = (List.count x xs.toList) / (n + 1)
                                        @[simp]
                                        theorem ProbComp.probEvent_uniformSelectListVector {α : Type} {n : } (xs : List.Vector α (n + 1)) (p : αProp) [DecidablePred p] :
                                        Pr[p | $!xs] = (List.countP (fun (b : α) => decide (p b)) xs.toList) / (n + 1)
                                        noncomputable instance ProbComp.hasUniformSelectFinset (α : Type) :

                                        Choose a random element from a finite set, by converting to a list and choosing from that. This is noncomputable as we don't have a canoncial ordering for the resulting list, so generally this should be avoided when possible.

                                        Equations
                                          @[simp]
                                          theorem ProbComp.probOutput_uniformSelectFinset {α : Type} (s : Finset α) [DecidableEq α] (x : α) :
                                          Pr[=x | $s] = if x s then (↑s.card)⁻¹ else 0
                                          @[simp]
                                          theorem ProbComp.probEvent_uniformSelectFinset {α : Type} (s : Finset α) [DecidableEq α] (p : αProp) [DecidablePred p] :
                                          Pr[p | $s] = {xs | p x}.card / s.card