Documentation

Complexitylib.Models.RoseTreeMachine.Prog

Programs in a rose tree machine (RTM) #

This file contains the main definition of the rose tree machine, its programs including semantics and time and space resource consumption.

Main definitions and notations #

Prog is the syntax representation of a functional language that has a resource consumption model which is compatible to that of a Turing machine. The data structure it operates on is a rose tree (Data). The advantage of this data structure is that the majority of lean data types have a direct encoding.

  • var (id : ) : Prog

    Variable reference at de Bruijn level id.

  • empty : Prog

    The empty constructor of Data.

  • cons (h t : Prog) : Prog

    The cons constructor of Data: prepend the value of h to the list value of t.

  • elim (v emp cs : Prog) : Prog

    Destructor of Data: evaluate v; if it is empty, run emp; otherwise destructure into head and tail and apply the function cs to head and then to tail.

  • ifEq (x y then_ else_ : Prog) : Prog

    Equality comparison: If x evaluates to the same data as y, run then_, else run else_. This can be simulated using while_ below, but it is useful to have.

  • while_ (init body : Prog) : Prog

    While loop: evaluate init to the starting accumulator; body must evaluate to a one-argument function which is applied to the current accumulator on each iteration. Return the accumulator if its head is empty.

  • fn (body : Prog) : Prog

    Abstraction / closure in one variable.

  • app (fn arg : Prog) : Prog

    Function application.

Instances For
    Equations
    • One or more equations did not get rendered due to their size.
    Instances For

      Runtime values for the semantics predicate ProgSem.

      Instances For
        @[irreducible]

        The size of a closure's environment, restricted to variables that body actually references.

        Equations
        Instances For
          @[irreducible]
          Equations
          Instances For
            @[irreducible]

            The size of a Value. The size of data is the length of its encoding and the size of a closure is the sum of the sizes of the referenced variables.

            Equations
            Instances For
              @[simp]
              theorem Complexity.RoseTreeMachine.closureSize_of_noVar {body : Prog} {env : List Value} (h : ∀ (i : ), ¬Prog.hasVar i body = true) :
              closureSize body env = 0
              @[simp]
              theorem Complexity.RoseTreeMachine.closureSize.go_append (body : Prog) (depth : ) (l1 l2 : List Value) :
              go body depth (l1 ++ l2) = go body depth l1 + go body (depth + l1.length) l2

              Splitting the environment of a closure size computation across an append.

              theorem Complexity.RoseTreeMachine.closureSize_append (body : Prog) (l1 l2 : List Value) :
              closureSize body (l1 ++ l2) = closureSize body l1 + closureSize.go body l1.length l2

              The closure size over an appended environment splits into the size over the prefix plus the contribution of the suffix (counted starting at depth l1.length).

              theorem Complexity.RoseTreeMachine.closureSize.go_mono {body1 body2 : Prog} (env : List Value) (h : ∀ (i : ), Prog.hasVar i body1 = trueProg.hasVar i body2 = true) (depth : ) :
              go body1 depth env go body2 depth env

              closureSize.go is monotone in the set of accessed variables.

              theorem Complexity.RoseTreeMachine.closureSize_mono {body1 body2 : Prog} (env : List Value) (h : ∀ (i : ), Prog.hasVar i body1 = trueProg.hasVar i body2 = true) :
              closureSize body1 env closureSize body2 env

              If every variable accessed by body1 is also accessed by body2, then body1 has a smaller closure size over any environment.

              theorem Complexity.RoseTreeMachine.closureSize.go_le_sum (body : Prog) (depth : ) (env : List Value) :
              go body depth env (List.map Value.size env).sum

              The closure size is bounded by the total size of the environment.

              Semantics of Prog including time and space resource bounds. ProgSem σ p x t s means that on environment σ, the program p evaluates to the value x and uses t time and s space.

              Instances For

                Application of a value to an argument value. AppSem f v r t s means that applying the closure f to the argument v yields r using t time and s space. Only closures can be applied; applying a first-order value has no derivation (the program is stuck).

                Instances For

                  Iterates the closure bodyVal of a while_ loop, threading the accumulator. WhileSem bodyVal acc r t s means that, starting from accumulator acc, repeatedly applying bodyVal to the current accumulator eventually yields result r using t time and s space. Before each iteration the halting condition is checked on the current accumulator: iteration terminates (with the accumulator as result) when acc is empty or its head is empty. Otherwise bodyVal is applied and its result becomes the new accumulator. Non-terminating loops simply have no derivation.

                  Instances For
                    theorem Complexity.RoseTreeMachine.ProgSem.size_le {σ : List Value} {p : Prog} {v : Value} {t s : } (h : ProgSem σ p v t s) :
                    v.size t v.size s

                    Producing a value costs at least its size, in both time and space. This holds because every ProgSem derivation either reads/builds the value directly (charging its size) or returns a value produced by a sub-derivation whose cost it includes. Provable by mutual induction over ProgSem/AppSem/WhileSem.

                    theorem Complexity.RoseTreeMachine.ProgSem.value_det {σ : List Value} {p : Prog} {v₁ : Value} {t₁ s₁ : } (h₁ : ProgSem σ p v₁ t₁ s₁) (v₂ : Value) (t₂ s₂ : ) :
                    ProgSem σ p v₂ t₂ s₂v₁ = v₂

                    Value-determinism of the relational semantics: a program evaluates to at most one value in a given environment. The mutually-defined AppSem/WhileSem relations are value-deterministic too. The potential branch overlaps (elim_nil/elim_cons, ifEq_then/ifEq_else) are ruled out by value-determinism of the scrutinee / compared values, supplied by the induction hypotheses.

                    The program p computes the value y from the value x in time t and space s.

                    Equations
                    Instances For

                      The program p computes the function f (on binary strings) in time t and space s. This is the main definition that defines complexity for this computation model.

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For

                        The function f is computable in time t in the RTM model, up to constant factors

                        Equations
                        Instances For

                          The function f is computable in space s in the RTM model, up to constant factors

                          Equations
                          Instances For

                            The in-place (first-order) fragment of the functional language.

                            InPlace p holds when every fn in p occurs in an immediately-consumed position — as the operator of an app, or as the (curried) branch of an elim/while_. Consequently no closure ever escapes: every abstraction is created and used on the spot, so all values that flow through the environment are first-order Data. This is exactly the fragment a defunctionalising compiler targets, and it is closed under the operational semantics.

                            A Turing machine can directly implement this fragment without the need for closures: One tape is used for each "node" in the syntax tree.

                            Instances For