Documentation

VCVio.OracleComp.Constructions.SampleableType

Uniform Selection Over a Type #

This file defines a typeclass SampleableType β for types β with a canonical uniform selection operation, using the ProbComp monad.

As compared to HasUniformSelect this provides much more structure on the behavior, enforcing that every possible output has the same output probability never fails.

class SampleableType (β : Type) :

A SampleableType β instance means that β is a finite inhabited type, with a computation selectElem that selects uniformly at random from the type. This generally requires choosing some "canonical" ordering for the type, so we include this to get a computable version of selection. We also require that each element has the same probability of being chosen from by selectElem, see SampleableType.probOutput_uniformSample for the reduction when α has a fintype instance involving the explicit cardinality of the type.

Instances
    def uniformSample (β : Type) [h : SampleableType β] :

    Select uniformly from the type β using a type-class provided definition. NOTE: naming is somewhat strange now that Fintype isn't explicitly required.

    Instances For
      @[simp]
      theorem probOutput_uniformSample (α : Type) [ : SampleableType α] [Fintype α] (x : α) :
      Pr[= x | $ᵗ α] = (↑(Fintype.card α))⁻¹
      theorem probOutput_uniformSample_inj (α : Type) [ : SampleableType α] (x y : α) :
      Pr[= x | $ᵗ α] = Pr[= y | $ᵗ α]
      theorem probOutput_map_bijective_uniformSample (α : Type) [ : SampleableType α] {f : αα} (hf : Function.Bijective f) (x : α) :
      Pr[= x | f <$> ($ᵗ α)] = Pr[= x | $ᵗ α]
      theorem probOutput_map_bijective_uniform_cross (α : Type) [ : SampleableType α] {β : Type} [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) (y : β) :
      Pr[= y | f <$> ($ᵗ α)] = Pr[= y | $ᵗ β]

      Pushing forward uniform sampling along a bijection preserves output probabilities.

      theorem probOutput_bind_bijective_uniform_cross (α : Type) [ : SampleableType α] {β γ : Type} [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) (g : βProbComp γ) (z : γ) :
      Pr[= z | do let x$ᵗ α g (f x)] = Pr[= z | do let y$ᵗ β g y]

      Binding after pushing forward uniform sampling along a bijection preserves output probabilities.

      theorem probOutput_add_left_uniform (α : Type) [ : SampleableType α] [AddGroup α] (m x : α) :
      Pr[= x | (fun (x : α) => m + x) <$> ($ᵗ α)] = Pr[= x | $ᵗ α]
      theorem probOutput_bind_add_left_uniform (α : Type) [ : SampleableType α] [AddGroup α] {β : Type} (m : α) (f : αProbComp β) (z : β) :
      Pr[= z | do let y$ᵗ α f (m + y)] = Pr[= z | do let y$ᵗ α f y]
      theorem probOutput_add_right_uniform (α : Type) [ : SampleableType α] [AddGroup α] (m x : α) :
      Pr[= x | (fun (x : α) => x + m) <$> ($ᵗ α)] = Pr[= x | $ᵗ α]

      Right-translation analogue of probOutput_add_left_uniform: right-adding a constant to a uniform sample in AddGroup α preserves the output distribution, since (· + m) is a bijection on α with inverse (· + (-m)).

      theorem probOutput_bind_add_right_uniform (α : Type) [ : SampleableType α] [AddGroup α] {β : Type} (m : α) (f : αProbComp β) (z : β) :
      Pr[= z | do let y$ᵗ α f (y + m)] = Pr[= z | do let y$ᵗ α f y]
      @[simp]
      theorem evalDist_add_left_uniform (α : Type) [ : SampleableType α] [AddGroup α] (m : α) :
      evalDist ((fun (x : α) => m + x) <$> ($ᵗ α)) = evalDist ($ᵗ α)

      Translating a uniform additive sample preserves the full evaluation distribution.

      theorem evalDist_add_left_uniform_eq (α : Type) [ : SampleableType α] [AddGroup α] (m₁ m₂ : α) :
      evalDist ((fun (x : α) => m₁ + x) <$> ($ᵗ α)) = evalDist ((fun (x : α) => m₂ + x) <$> ($ᵗ α))

      Two additive translations of a uniform sample have the same evaluation distribution.

      @[simp]
      theorem evalDist_add_right_uniform (α : Type) [ : SampleableType α] [AddGroup α] (m : α) :
      evalDist ((fun (x : α) => x + m) <$> ($ᵗ α)) = evalDist ($ᵗ α)

      Right-translation analogue of evalDist_add_left_uniform: right-adding a constant to a uniform sample in AddGroup α preserves the full evaluation distribution.

      theorem evalDist_add_right_uniform_eq (α : Type) [ : SampleableType α] [AddGroup α] (m₁ m₂ : α) :
      evalDist ((fun (x : α) => x + m₁) <$> ($ᵗ α)) = evalDist ((fun (x : α) => x + m₂) <$> ($ᵗ α))

      Two right-translations of a uniform sample have the same evaluation distribution.

      theorem evalDist_map_bijective_uniform_cross (α : Type) [ : SampleableType α] {β : Type} [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) :
      evalDist (f <$> ($ᵗ α)) = evalDist ($ᵗ β)

      Pushing forward uniform sampling via a bijection preserves the full evaluation distribution.

      theorem evalDist_bind_bijective_add_right_uniform (α : Type) [ : SampleableType α] {β γ : Type} [AddGroup β] [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) (m : β) (cont : βProbComp γ) :
      (evalDist do let x$ᵗ α cont (f x + m)) = evalDist do let y$ᵗ β cont y

      Bijective uniform + right-translation gives uniform. Sampling x ← $ᵗ α, transporting through a bijection f : α → β, and right-adding any fixed m : β yields the same distribution as sampling y ← $ᵗ β directly, as observed by any continuation cont : β → ProbComp γ.

      This is the "one-time pad" fact underlying many cryptographic reductions: bijective transport makes f x uniform on β, and in any AddGroup β right-translation (· + m) is a bijection on the uniform measure, so the sum is again uniform.

      theorem evalDist_bind_bijective_add_right_eq (α : Type) [ : SampleableType α] {β γ : Type} [AddGroup β] [SampleableType β] [Finite α] (f : αβ) (hf : Function.Bijective f) (m₁ m₂ : β) (cont : βProbComp γ) :
      (evalDist do let x$ᵗ α cont (f x + m₁)) = evalDist do let x$ᵗ α cont (f x + m₂)

      Constant-irrelevance form of evalDist_bind_bijective_add_right_uniform: sampling through a bijection and right-adding a constant has a distribution independent of the constant. Any two offsets produce the same evaluation distribution.

      @[simp]
      theorem mem_support_uniformSample (α : Type) [ : SampleableType α] {x : α} :
      @[simp]
      theorem probEvent_uniformSample (α : Type) [ : SampleableType α] [Fintype α] (p : αProp) [DecidablePred p] :
      @[reducible]
      Instances For
        @[implicit_reducible]
        @[implicit_reducible]
        @[implicit_reducible]
        @[implicit_reducible]
        instance instSampleableTypeRangeSumHAddOracleSpec {ι : Type u_1} {ι' : Type u_2} {spec : OracleSpec ι} {spec' : OracleSpec ι'} [h : (t : ι) → SampleableType (spec.Range t)] [h' : (t : ι') → SampleableType (spec'.Range t)] (t : ι ι') :
        SampleableType ((spec + spec').Range t)

        A sum of oracle specs with sampleable ranges again has sampleable ranges.

        @[implicit_reducible]

        Select a uniform element from α × β by independently selecting from α and β.

        @[reducible]
        def SampleableType.ofEquiv {α β : Type} [SampleableType α] (e : α β) :

        A type equivalent to a SampleableType is also SampleableType.

        Instances For
          @[implicit_reducible]

          Any finitely enumerable type can be sampled uniformly using the underlying equivalence.

          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]
          @[implicit_reducible]

          Select a uniform element from Vector α n by independently selecting α at each index.

          @[implicit_reducible]
          instance instFintypeVector (α : Type u) (n : ) [Fintype α] :

          Vector α n is finite when α is finite, via the equivalence with Fin n → α.

          @[implicit_reducible]
          instance instSampleableTypeFinFunc {n : } {α : Type} [SampleableType α] :
          SampleableType (Fin nα)

          A function from Fin n to a SampleableType is also SampleableType.

          @[implicit_reducible]
          instance instSampleableTypeMatrixFin (α : Type) (n m : ) [SampleableType α] :

          Select a uniform element from Matrix α n by selecting each row independently.

          theorem probOutput_uniformBool_not_decide_eq_decide {ob : ProbComp Bool} :
          Pr[= true | do let b$ᵗ Bool let b'ob pure !decide (b = b')] = Pr[= true | do let b$ᵗ Bool let b'ob pure (decide (b = b'))]

          Given an independent probabilistic computation ob : ProbComp Bool, the probability that its output b' differs from a uniformly chosen boolean b is the same as the probability that they are equal. In other words, P(b ≠ b') = P(b = b') where b is uniform.

          theorem probOutput_bind_uniformBool {α : Type} (f : BoolProbComp α) (x : α) :
          Pr[= x | do let b$ᵗ Bool f b] = (Pr[= x | f true] + Pr[= x | f false]) / 2

          Conditioning on a uniform boolean averages the two branch probabilities.

          theorem probOutput_uniformBool_branch_toReal_sub_half (real rand : ProbComp Bool) :
          Pr[= true | do let b$ᵗ Bool have __do_jp : BoolProbComp Bool := fun (z : Bool) => pure (b == z) if b = true then do let yreal __do_jp y else do let yrand __do_jp y].toReal - 1 / 2 = (Pr[= true | real].toReal - Pr[= true | rand].toReal) / 2

          Guessing a uniformly random bit after branching between real and rand decomposes into the difference of the branch success probabilities.

          theorem probOutput_decide_eq_uniformBool_half (f : BoolProbComp Bool) (heq : evalDist (f true) = evalDist (f false)) :
          Pr[= true | do let b$ᵗ Bool let b'f b pure (decide (b = b'))] = 1 / 2

          If the distribution of f b is independent of b, then guessing a uniformly random bit by running f has success probability exactly 1/2. This is the core lemma behind "all-random hybrid has probability 1/2" arguments.