Documentation

MIPRE.Foundations.Cost.Fold

The closure library, part IV: folds over lists #

The generic iteration combinator of the library, PolyTimeFun.foldl: a fold of a polynomial-time body over a list is polynomial-time provided the accumulator grows by at most an additive polynomial in the element at each step (the Cobham condition esize (F (s, a)) ≤ esize s + B (esize a)), and from it cons, casesList, map, zip, append, replicate and reverse (planning/succinct-cook-levin.md, S3). Every combinator's toFun is the corresponding List function, so that a program assembled from them is defined by its mathematical meaning and only its time bound is inherited.

Lists of an arbitrary encodable type encode as cons-chains of the encodings (instSizedEncodingList, at low priority so that the existing instances for bit strings and gate lists are still found first; they agree definitionally).

Lists of encodable values #

@[instance_reducible, instance 100]

Lists encode elementwise, as cons-chains.

Equations
theorem MIPRE.Cost.encode_list_cons {α : Type u_1} [SizedEncoding α] (a : α) (l : List α) :
encode (a :: l) = (encode a).cons (encode l)
@[simp]
@[simp]
theorem MIPRE.Cost.esize_list_cons {α : Type u_1} [SizedEncoding α] (a : α) (l : List α) :
esize (a :: l) = esize a + esize l + 1
theorem MIPRE.Cost.esize_mem_le {α : Type u_1} [SizedEncoding α] {a : α} {l : List α} (h : a ∈ l) :
theorem MIPRE.Cost.esize_list_append {α : Type u_1} [SizedEncoding α] (l₁ l₂ : List α) :
esize (l₁ ++ l₂) + 1 = esize l₁ + esize l₂

Program layer: the fold loop #

The body of the fold loop of F: on the state cons xs acc, stop with acc if xs is empty; otherwise bind acc' := F (acc, head xs) and continue with cons (tail xs) acc'.

Equations
  • One or more equations did not get rendered due to their size.
Instances For
    theorem MIPRE.Cost.Prog.foldBody_step {F : Prog} (hF : WellScoped 1 F) (h rest acc acc' : Data) (t : ℕ) (hrun : Eval [acc.cons h] F acc' t) :
    Eval [(h.cons rest).cons acc] F.foldBody ((Data.nil.cons Data.nil).cons (rest.cons acc')) (acc.size + h.size + rest.size + acc'.size + t + 14)

    Function layer #

    @[reducible, inline]
    abbrev MIPRE.Cost.PolyTimeFun.step {α : Type u_1} {σ : Type u_4} [SizedEncoding α] [SizedEncoding σ] (F : PolyTimeFun (σ × α) σ) (s : σ) (a : α) :
    σ

    The step function of a fold, as a binary function.

    Equations
    Instances For
      theorem MIPRE.Cost.PolyTimeFun.foldl_esize_le {α : Type u_1} {σ : Type u_4} [SizedEncoding α] [SizedEncoding σ] (F : PolyTimeFun (σ × α) σ) (B : Polynomial ℕ) (hB : ∀ (s : σ) (a : α), esize (F.toFun (s, a)) ≤ esize s + Polynomial.eval (esize a) B) (l : List α) (s₀ : σ) (pre : List α) :
      pre ⊆ l → esize (List.foldl F.step s₀ pre) ≤ esize s₀ + pre.length * Polynomial.eval (esize l) B

      The size bound along a fold under the additive Cobham condition: after consuming pre, the accumulator has size at most esize s₀ + |pre| · B (esize l) whenever the elements of pre are elements of l.

      def MIPRE.Cost.PolyTimeFun.FoldBounded {α : Type u_1} {σ : Type u_4} [SizedEncoding α] [SizedEncoding σ] (F : PolyTimeFun (σ × α) σ) (B : Polynomial ℕ) :

      The Cobham condition for folding F over a list: along the fold of any list l from any s₀, the accumulator has size at most B (esize (l, s₀)).

      Equations
      Instances For
        theorem MIPRE.Cost.PolyTimeFun.foldBounded_of_additive {α : Type u_1} {σ : Type u_4} [SizedEncoding α] [SizedEncoding σ] (F : PolyTimeFun (σ × α) σ) (B : Polynomial ℕ) (hB : ∀ (s : σ) (a : α), esize (F.toFun (s, a)) ≤ esize s + Polynomial.eval (esize a) B) :

        The additive condition — each step grows the accumulator by at most B (esize a) — is a Cobham condition with the bound X + X · B.

        noncomputable def MIPRE.Cost.PolyTimeFun.foldStepBound {α : Type u_1} {σ : Type u_4} [SizedEncoding α] [SizedEncoding σ] (F : PolyTimeFun (σ × α) σ) (B : Polynomial ℕ) :

        The per-iteration cost bound of the fold loop, as a polynomial in esize (l, s₀).

        Equations
        Instances For
          noncomputable def MIPRE.Cost.PolyTimeFun.foldl {α : Type u_1} {σ : Type u_4} [SizedEncoding α] [SizedEncoding σ] (F : PolyTimeFun (σ × α) σ) (B : Polynomial ℕ) (hB : F.FoldBounded B) :
          PolyTimeFun (List α × σ) σ

          Folding a polynomial-time body over a list, under the Cobham condition FoldBounded F B: foldl F B hB (l, s₀) = l.foldl (fun s a => F (s, a)) s₀. The loop state is the input pair itself.

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            @[simp]
            theorem MIPRE.Cost.PolyTimeFun.foldl_apply {α : Type u_1} {σ : Type u_4} [SizedEncoding α] [SizedEncoding σ] (F : PolyTimeFun (σ × α) σ) (B : Polynomial ℕ) (hB : F.FoldBounded B) (l : List α) (s₀ : σ) :
            (F.foldl B hB).toFun (l, s₀) = List.foldl (fun (s : σ) (a : α) => F.toFun (s, a)) s₀ l
            noncomputable def MIPRE.Cost.PolyTimeFun.foldlAdd {α : Type u_1} {σ : Type u_4} [SizedEncoding α] [SizedEncoding σ] (F : PolyTimeFun (σ × α) σ) (B : Polynomial ℕ) (hB : ∀ (s : σ) (a : α), esize (F.toFun (s, a)) ≤ esize s + Polynomial.eval (esize a) B) :
            PolyTimeFun (List α × σ) σ

            Folding under the additive condition.

            Equations
            Instances For
              @[simp]
              theorem MIPRE.Cost.PolyTimeFun.foldlAdd_apply {α : Type u_1} {σ : Type u_4} [SizedEncoding α] [SizedEncoding σ] (F : PolyTimeFun (σ × α) σ) (B : Polynomial ℕ) (hB : ∀ (s : σ) (a : α), esize (F.toFun (s, a)) ≤ esize s + Polynomial.eval (esize a) B) (l : List α) (s₀ : σ) :
              (F.foldlAdd B hB).toFun (l, s₀) = List.foldl (fun (s : σ) (a : α) => F.toFun (s, a)) s₀ l

              Derived combinators #

              noncomputable def MIPRE.Cost.PolyTimeFun.congr {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (F : PolyTimeFun α β) (f : α → β) (h : ∀ (a : α), F.toFun a = f a) :

              Replacing the function of a PolyTimeFun by an extensionally equal one.

              Equations
              Instances For
                @[simp]
                theorem MIPRE.Cost.PolyTimeFun.congr_apply {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (F : PolyTimeFun α β) (f : α → β) (h : ∀ (a : α), F.toFun a = f a) (a : α) :
                (F.congr f h).toFun a = f a
                noncomputable def MIPRE.Cost.PolyTimeFun.ofEncodeEq {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (f : α → β) (h : ∀ (a : α), encode (f a) = encode a) :

                A function whose output encodes exactly as its input is computed by var 0.

                Equations
                Instances For
                  @[simp]
                  theorem MIPRE.Cost.PolyTimeFun.ofEncodeEq_apply {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (f : α → β) (h : ∀ (a : α), encode (f a) = encode a) (a : α) :
                  (ofEncodeEq f h).toFun a = f a
                  noncomputable def MIPRE.Cost.PolyTimeFun.cast {α : Type u_1} {β : Type u_2} {γ : Type u_3} [SizedEncoding α] [SizedEncoding β] [SizedEncoding γ] (F : PolyTimeFun α β) (f : α → γ) (h : ∀ (a : α), encode (f a) = encode (F.toFun a)) :

                  Retyping the output: a function whose values encode as the values of F is computed by the program of F.

                  Equations
                  • F.cast f h = { toFun := f, code := F.code, closed := ⋯, timeBound := F.timeBound, computes := ⋯ }
                  Instances For
                    @[simp]
                    theorem MIPRE.Cost.PolyTimeFun.cast_apply {α : Type u_1} {β : Type u_2} {γ : Type u_3} [SizedEncoding α] [SizedEncoding β] [SizedEncoding γ] (F : PolyTimeFun α β) (f : α → γ) (h : ∀ (a : α), encode (f a) = encode (F.toFun a)) (a : α) :
                    (F.cast f h).toFun a = f a
                    noncomputable def MIPRE.Cost.PolyTimeFun.cons {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (F : PolyTimeFun α β) (G : PolyTimeFun α (List β)) :

                    Consing.

                    Equations
                    Instances For
                      @[simp]
                      theorem MIPRE.Cost.PolyTimeFun.cons_apply {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (F : PolyTimeFun α β) (G : PolyTimeFun α (List β)) (a : α) :
                      (F.cons G).toFun a = F.toFun a :: G.toFun a
                      noncomputable def MIPRE.Cost.PolyTimeFun.reverse {α : Type u_1} [SizedEncoding α] :

                      Reversal.

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For
                        def MIPRE.Cost.PolyTimeFun.casesListFun {α : Type u_1} {β : Type u_2} {γ : Type u_3} (N : α → β) (K : α × γ × List γ → β) :
                        α × List γ → β

                        Case analysis on a list: the function of casesList.

                        Equations
                        Instances For
                          noncomputable def MIPRE.Cost.PolyTimeFun.casesList {α : Type u_1} {β : Type u_2} {γ : Type u_3} [SizedEncoding α] [SizedEncoding β] [SizedEncoding γ] (N : PolyTimeFun α β) (K : PolyTimeFun (α × γ × List γ) β) :
                          PolyTimeFun (α × List γ) β

                          Case analysis on a list component: casesList N K (a, []) is N a and casesList N K (a, h :: t) is K (a, (h, t)).

                          Equations
                          • One or more equations did not get rendered due to their size.
                          Instances For
                            @[simp]
                            theorem MIPRE.Cost.PolyTimeFun.casesList_nil {α : Type u_1} {β : Type u_2} {γ : Type u_3} [SizedEncoding α] [SizedEncoding β] [SizedEncoding γ] (N : PolyTimeFun α β) (K : PolyTimeFun (α × γ × List γ) β) (a : α) :
                            @[simp]
                            theorem MIPRE.Cost.PolyTimeFun.casesList_cons {α : Type u_1} {β : Type u_2} {γ : Type u_3} [SizedEncoding α] [SizedEncoding β] [SizedEncoding γ] (N : PolyTimeFun α β) (K : PolyTimeFun (α × γ × List γ) β) (a : α) (h : γ) (t : List γ) :
                            (N.casesList K).toFun (a, h :: t) = K.toFun (a, h, t)

                            The list functions underlying the combinators #

                            theorem MIPRE.Cost.foldl_cons_map {α : Type u_1} {β : Type u_2} (f : α → β) (l : List α) (init : List β) :
                            (List.foldl (fun (acc : List β) (a : α) => f a :: acc) init l).reverse = init.reverse ++ List.map f l

                            The fold underlying map.

                            theorem MIPRE.Cost.foldl_cons_reverse {α : Type u_1} (l₁ l₂ : List α) :
                            List.foldl (fun (acc : List α) (a : α) => a :: acc) l₂ l₁.reverse = l₁ ++ l₂

                            The fold underlying append.

                            def MIPRE.Cost.zipStep {α : Type u_1} {β : Type u_2} (s : List β × List (α × β)) (a : α) :
                            List β × List (α × β)

                            The step of the zip fold: on the state (l₂, acc) and the element a, consume the head of l₂.

                            Equations
                            Instances For
                              theorem MIPRE.Cost.foldl_zipStep_nil {α : Type u_1} {β : Type u_2} (l : List α) (acc : List (α × β)) :
                              theorem MIPRE.Cost.foldl_zipStep {α : Type u_1} {β : Type u_2} (l₁ : List α) (l₂ : List β) (acc : List (α × β)) :
                              (List.foldl zipStep (l₂, acc) l₁).2.reverse = acc.reverse ++ l₁.zip l₂
                              theorem MIPRE.Cost.foldl_replicate {β : Type u_2} (u : List Unit) (acc : List β) (b : β) :
                              List.foldl (fun (s : List β × β) (x : Unit) => (s.2 :: s.1, s.2)) (acc, b) u = (List.replicate u.length b ++ acc, b)

                              The fold underlying replicate: the state carries the value to replicate.

                              noncomputable def MIPRE.Cost.PolyTimeFun.map {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (F : PolyTimeFun α β) :

                              Mapping a polynomial-time function over a list.

                              Equations
                              • One or more equations did not get rendered due to their size.
                              Instances For
                                @[simp]
                                theorem MIPRE.Cost.PolyTimeFun.map_apply {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (F : PolyTimeFun α β) (l : List α) :
                                noncomputable def MIPRE.Cost.PolyTimeFun.append {α : Type u_1} [SizedEncoding α] :
                                PolyTimeFun (List α × List α) (List α)

                                Appending.

                                Equations
                                • One or more equations did not get rendered due to their size.
                                Instances For
                                  @[simp]
                                  theorem MIPRE.Cost.PolyTimeFun.append_apply {α : Type u_1} [SizedEncoding α] (p : List α × List α) :
                                  append.toFun p = p.1 ++ p.2
                                  noncomputable def MIPRE.Cost.PolyTimeFun.zipStepF {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] :
                                  PolyTimeFun ((List β × List (α × β)) × α) (List β × List (α × β))

                                  The zip step as a polynomial-time function.

                                  Equations
                                  • One or more equations did not get rendered due to their size.
                                  Instances For
                                    @[simp]
                                    theorem MIPRE.Cost.PolyTimeFun.zipStepF_apply {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (p : (List β × List (α × β)) × α) :
                                    noncomputable def MIPRE.Cost.PolyTimeFun.zip {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] :
                                    PolyTimeFun (List α × List β) (List (α × β))

                                    Zipping two lists.

                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    Instances For
                                      @[simp]
                                      theorem MIPRE.Cost.PolyTimeFun.zip_apply {α : Type u_1} {β : Type u_2} [SizedEncoding α] [SizedEncoding β] (p : List α × List β) :
                                      zip.toFun p = p.1.zip p.2

                                      Unary numerals as lists of units #

                                      @[instance_reducible]

                                      The unit encodes as the atom, so that a list of n units is the unary numeral Data.ofNat n.

                                      Equations
                                      • One or more equations did not get rendered due to their size.
                                      @[reducible, inline]

                                      Unary numerals: lists of units.

                                      Equations
                                      Instances For

                                        The unary numeral of n.

                                        Equations
                                        Instances For
                                          @[simp]
                                          @[simp]
                                          theorem MIPRE.Cost.esize_unary (n : ℕ) :
                                          esize (unary n) = 2 * n + 1
                                          theorem MIPRE.Cost.unary_add (a b : ℕ) :
                                          unary (a + b) = unary a ++ unary b
                                          noncomputable def MIPRE.Cost.PolyTimeFun.length {α : Type u_1} [SizedEncoding α] :

                                          The length of a list, in unary.

                                          Equations
                                          Instances For
                                            noncomputable def MIPRE.Cost.PolyTimeFun.replicate {β : Type u_2} [SizedEncoding β] :

                                            replicate (u, b) = List.replicate |u| b, by a fold over the unary numeral u whose state carries b.

                                            Equations
                                            • One or more equations did not get rendered due to their size.
                                            Instances For
                                              noncomputable def MIPRE.Cost.PolyTimeFun.mapWith {α : Type u_1} {β : Type u_2} {γ : Type u_3} [SizedEncoding α] [SizedEncoding β] [SizedEncoding γ] (F : PolyTimeFun (α × β) γ) :
                                              PolyTimeFun (List α × β) (List γ)

                                              Mapping with a parameter: mapWith F (l, c) = l.map (fun a => F (a, c)), by zipping l with copies of c.

                                              Equations
                                              • One or more equations did not get rendered due to their size.
                                              Instances For
                                                @[simp]
                                                theorem MIPRE.Cost.PolyTimeFun.mapWith_apply {α : Type u_1} {β : Type u_2} {γ : Type u_3} [SizedEncoding α] [SizedEncoding β] [SizedEncoding γ] (F : PolyTimeFun (α × β) γ) (p : List α × β) :
                                                F.mapWith.toFun p = List.map (fun (a : α) => F.toFun (a, p.2)) p.1