Documentation

GaudisCrypt.Language.Variables

Variables #

The memory model of programs and procedures:

Variable names #

A VariableName is a program variable's name together with its type. Besides the name it carries a natural-number key, the name's encoding VariableName.encode name, stored as a literal. The key exists for instance search: two names with different literal keys are told apart by VariableName.NameNe in a single unification step, whatever their length, which is what lets disjointness of two variables be found automatically. (Instance search cannot compare strings in one step: a string literal is opened into a list of characters, and every character then costs a step and a level of recursion. Nat literals are the one kind of data the unifier has built-in arithmetic for.)

key and its correctness proof keyCorrect are filled in automatically: key is an implicit argument of the constructor, and the variable_name_key tactic behind keyCorrect evaluates encode name when name is a string literal and assigns key the resulting literal. So one writes ⟨"x", Int⟩ or { name := "x", type := Int } and gets @VariableName.mk "x" Int 121 ⋯.

Argument tuples #

Defined here rather than in Programs.lean, which builds on this file.

@[reducible]

Reducible on purpose: at a concrete parameter list the tuple type has to be visible to unification at reducible transparency, or everything stated about _ × _ gets stuck on it — typeclass resolution (OfNat (typeListToTuple [Nat]) 5 for a numeral argument of a call, Lens.Disjoint of two projection lenses) is where it shows.

Equations
Instances For

    Variable names #

    Bijective base-0x110000 numeration of a character list, least significant digit first: character c is the digit c.toNat + 1 (in 1 … 0x110000, since a code point is below 0x110000), and the empty list is 0. Reduces by rfl in the kernel on literals (the corresponding encoding of the UTF-8 bytes does not: String.toUTF8 gets stuck).

    Equations
    Instances For

      The key of a variable name: an injective, computable encoding of strings as naturals (encode_injective). Quadratic in the length of the string — each step multiplies the accumulated number, about 21 bits per character, by a constant — which is microseconds at any plausible name length. (An O(n log n) version is possible: with base 2 ^ 21, merge neighbouring blocks with a ||| (b <<< w) in log n passes, each pass recursing on the list and the passes on a counter. Both recursions are structural, so it still reduces by rfl, which variable_name_key relies on. Splitting at the midpoint instead would need well-founded recursion, which does not reduce.)

      Equations
      Instances For

        Close ?key = VariableName.encode name. If name is a string literal, compute the encoding and assign ?key the resulting Nat literal, so that instance search can compare keys. Otherwise ?key becomes VariableName.encode name itself: the name is still a valid variable name, but VariableName.NameNe will not be found for it by instance search.

        Equations
        Instances For

          VariableName.encode "x" ↦ the literal variable_name_key assigns for "x". A slot built from a name that is a variable (as in setParams) carries the key encode n, and once n is instantiated to "x" it is still encode "x", while the slot localVarLens "x" T written in a program carries the literal. The two are defeq but not syntactically equal, so without this simp treats them as different slots (Function.update_self does not fire). The rewrite is by rfl: encode reduces on literals. A dsimproc, not a simproc: the key is an argument other arguments depend on (keyCorrect, and the value written in a Function.update), and simp rewrites such positions only with definitional steps.

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

            A program variable's name and type. key is encode name as a literal and is filled in automatically, together with its proof (see the module docstring). Two VariableNames are equal iff their names and types are (nonempty is a proposition, and key/keyCorrect are determined by the name).

            The type has to be nonempty, so that an assignment of values to all variable names exists at all (VariableAssignment.init). The instance is found by instance search.

            Instances For

              The variable name n : T as a term, the way localVarLens "n" T elaborates it: the Nonempty T instance synthesized (unless given), the key the literal variable_name_key computes. For meta code that makes up variables (hoare_proc_to_stmt, flattening).

              Equations
              • One or more equations did not get rendered due to their size.
              Instances For
                class GaudisCrypt.NatLt (a b : ℕ) :

                a < b, for natural-number literals, found by instance search in one step: unifying ?k + a + 1 =?= b is solved by the unifier's literal-offset rule as ?k := b - a - 1, at any size of the literals. (The unknown has to be the leftmost summand for that rule to apply.)

                • lt : a < b
                Instances
                  class GaudisCrypt.NatNe (a b : ℕ) :

                  a ≠ b, for natural-number literals, found by instance search via NatLt.

                  Instances
                    instance GaudisCrypt.instNatNeOfNatLt (a b : ℕ) [h : NatLt a b] :
                    NatNe a b
                    instance GaudisCrypt.instNatNeOfNatLt_1 (a b : ℕ) [h : NatLt b a] :
                    NatNe a b

                    Two variable names whose names differ. Found by instance search from the literal keys, for names given as constructor applications (as ⟨"x", Int⟩ elaborates); since encode is injective, it is found exactly when the names differ.

                    Instances
                      instance GaudisCrypt.instNameNeMkOfNatNe (n₁ n₂ : String) (T₁ T₂ : Type) (i₁ : Nonempty T₁) (i₂ : Nonempty T₂) (k₁ k₂ : ℕ) (h₁ : k₁ = VariableName.encode n₁) (h₂ : k₂ = VariableName.encode n₂) [h : NatNe k₁ k₂] :
                      { name := n₁, type := T₁, nonempty := i₁, key := k₁, keyCorrect := h₁ }.NameNe { name := n₂, type := T₂, nonempty := i₂, key := k₂, keyCorrect := h₂ }
                      theorem GaudisCrypt.VariableName.ext' {v w : VariableName} (hn : v.name = w.name) (ht : v.type = w.type) :
                      v = w

                      A variable name is determined by its name and type.

                      The variable name n : v.type: v with its name replaced (and the key recomputed, as a non-literal encode n). (v.withName n).type is v.type by definition, which is what lets embed move values between slots without casts.

                      Equations
                      Instances For

                        Variable assignments #

                        @[reducible, inline]

                        A value for every variable name. Inhabited (init) because every VariableName has a nonempty type. Reducible, so that m v typechecks at every transparency (rewriting needs this).

                        Equations
                        Instances For

                          The initial assignment: an unspecified value in every slot.

                          Equations
                          Instances For

                            Reading a slot under a renamed variable name, when the new name is the old one.

                            The lens onto the slot of variable v. Writing uses Function.update, with classical decidable equality of variable names (their types are arbitrary, so there is no other).

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

                              Slots of different variable names are disjoint.

                              instance GaudisCrypt.varLens.instDisjoint (n₁ n₂ : String) (T₁ T₂ : Type) (i₁ : Nonempty T₁) (i₂ : Nonempty T₂) (k₁ k₂ : ℕ) (h₁ : k₁ = VariableName.encode n₁) (h₂ : k₂ = VariableName.encode n₂) [{ name := n₁, type := T₁, nonempty := i₁, key := k₁, keyCorrect := h₁ }.NameNe { name := n₂, type := T₂, nonempty := i₂, key := k₂, keyCorrect := h₂ }] :
                              (varLens { name := n₁, type := T₁, nonempty := i₁, key := k₁, keyCorrect := h₁ }).Disjoint (varLens { name := n₂, type := T₂, nonempty := i₂, key := k₂, keyCorrect := h₂ })

                              Slots of differently named variables are disjoint, found by instance search when both names are literals (VariableName.NameNe). Stated for constructor applications: for a variable v, the slot type v.type is a projection the instance index cannot match against a concrete type, while (VariableName.mk n T).type reduces to T.

                              Writing arguments into parameter slots #

                              Write an argument tuple typeListToTuple tys into the slots names.zip tys, first parameter first (so on a duplicate name the later parameter wins). The Nonempty instance each slot's VariableName needs comes from the argument itself. Lists of different lengths (excluded by the length hypothesis) leave the assignment unchanged.

                              Equations
                              Instances For
                                theorem GaudisCrypt.VariableAssignment.setParams_apply_of_notMem (names : List String) (tys : List Type) (h : names.length = tys.length) (args : typeListToTuple tys) (m : VariableAssignment) (v : VariableName) :
                                v.name ∉ names → setParams names tys h args m v = m v

                                setParams leaves every slot outside the parameter names alone.

                                Renaming #

                                View an assignment through an injective name map ι: slot n : T of the view is slot ι n : T of the assignment. Writing a view back overwrites exactly the slots in the range of ι. Types are kept, so no casts are needed.

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

                                  Cleaning lemma: a slot seen through embed ι is the slot of the renamed variable.

                                  Renaming along a permutation of names: an isomorphism of assignments, slot n : T of rename π m being slot π n : T of m.

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

                                    embed along a permutation is the isomorphism lens of rename.

                                    Program states #

                                    The state a statement runs in: the program's globals and the running procedure's locals. Both are variable assignments, the globals named by full declaration names (see global_var).

                                    Instances For

                                      Lens onto the globals of a ProgramState.

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

                                        Lens onto the locals of a ProgramState.

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

                                          A lens into the locals, as a lens into the program state.

                                          Equations
                                          Instances For

                                            A lens into the globals, as a lens into the program state.

                                            Equations
                                            Instances For
                                              @[reducible, inline]
                                              noncomputable abbrev GaudisCrypt.localVarLens (n : String) (T : Type) [Nonempty T] {key : ℕ} (keyCorrect : key = VariableName.encode n := by variable_name_key) :

                                              The local variable n : T: its slot in the locals, as a lens into the program state. This is what a parameter or var of a proc stands for. The key of the variable name is filled in at the use site by variable_name_key, so for a literal n it is a literal, and two local variables with different literal names are found disjoint by instance search (through Lens.disjoint_intoLocal and varLens.instDisjoint; an abbrev, so that instance search sees the slot).

                                              Equations
                                              Instances For

                                                Global variables #

                                                global_var x : T declares the global variable x: the slot of the variable name ⟨"N.x", T⟩ in the globals, where N.x is the full name of the declaration, so two globals declared in different places never share a slot. It is a plain def (simp does not see through it), and Lens.IsGlobalVar records which slot it is, which is what instance search uses to find two globals disjoint (Lens.IsGlobalVar.instDisjoint).

                                                x is the slot of the variable name v (as the instance global_var emits says). v is an outParam, found from x.

                                                Instances
                                                  theorem GaudisCrypt.Lens.IsGlobalVar.disjoint {T U : Type} {x : Lens T VariableAssignment} {y : Lens U VariableAssignment} {v w : VariableName} (hx : x.IsGlobalVar v) (hy : y.IsGlobalVar w) (h : v ≠ w) :

                                                  Two slots of differently named variables are disjoint.

                                                  Globals with different (literal) names are disjoint.

                                                  global_var x : T declares the global variable x : Lens T VariableAssignment, the slot of ⟨"N.x", T⟩ with N.x the full name of the declaration (T must be nonempty), together with its Lens.IsGlobalVar instance, so that globals are found disjoint by instance search.

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