Skip to content
Snippets Groups Projects

docs.diff

  • Clone with SSH
  • Clone with HTTPS
  • Embed
  • Share
    The snippet can be accessed without any authentication.
    Authored by Ralf Jung
    Edited
    docs.diff 19.07 KiB
    diff --git a/docs/proof_guide.md b/docs/resource_algebras.md
    index 3195c63d..eaee3948 100644
    --- a/docs/proof_guide.md
    +++ b/docs/resource_algebras.md
    @@ -1,101 +1,17 @@
    -# Iris Proof Guide
    +## Global resource algebra management
     
    -This work-in-progress document serves to explain how Iris proofs are typically
    -carried out in Coq: what are the common patterns and conventions, what are the
    -common pitfalls.  This complements the tactic documentation for the
    -[proof mode](./proof_mode.md) and [HeapLang](./heap_lang.md).
    +The type of Iris propositions `iProp Σ` is parameterized by a *global* list `Σ:
    +gFunctors` of resource algebras that the proof may use.  (Actually this list
    +contains functors instead of resource algebras, but you only need to worry about
    +that when dealing with higher-order ghost state -- see "Camera functors" below.)
     
    -## Order of `Requires`
    +In our proofs, we always keep the `Σ` universally quantified to enable composition of proofs.
    +Each proof just assumes that some particular resource algebras are contained in that global list.
    +This is expressed via the `inG Σ R` typeclass, which roughly says that `R ∈ Σ`.
     
    -In Coq, declarations in modules imported later may override the
    -previous definition. Therefore, in order to make sure the most
    -relevant declarations and notations always take priority, we recommend
    -importing dependencies from the furthest to the closest.
    -
    -In particular, when importing Iris, Stdpp and Coq stdlib modules, we
    -recommend importing in the following order:
    -- Coq
    -- stdpp
    -- iris.bi
    -- iris.proofmode
    -- iris.algebra
    -- iris.base_logic
    -- iris.program_logic
    -- iris.heap_lang
    -
    -## Combinators for functors
    -
    -In Iris, the type of propositions [iProp] is described by the solution to the
    -recursive domain equation:
    -
    -```
    -iProp ≅ uPred (F (iProp))
    -```
    -
    -Here, `F` is a user-chosen locally contractive bifunctor from COFEs to unital
    -Cameras (a step-indexed generalization of unital resource algebras). To make it
    -convenient to construct such functors out of smaller pieces, we provide a number
    -of abstractions:
    -
    -- [`cFunctor`](theories/algebra/ofe.v): bifunctors from COFEs to OFEs.
    -- [`rFunctor`](theories/algebra/cmra.v): bifunctors from COFEs to cameras.
    -- [`urFunctor`](theories/algebra/cmra.v): bifunctors from COFEs to unital
    -  cameras.
    -
    -Besides, there are the classes `cFunctorContractive`, `rFunctorContractive`, and
    -`urFunctorContractive` which describe the subset of the above functors that
    -are contractive.
    -
    -To compose these functors, we provide a number of combinators, e.g.:
    -
    -- `constCF (A : ofeT) : cFunctor           := λ (B,B⁻), A `
    -- `idCF : cFunctor                         := λ (B,B⁻), B`
    -- `prodCF (F1 F2 : cFunctor) : cFunctor    := λ (B,B⁻), F1 (B,B⁻) * F2 (B,B⁻)`
    -- `ofe_morCF (F1 F2 : cFunctor) : cFunctor := λ (B,B⁻), F1 (B⁻,B) -n> F2 (B,B⁻)`
    -- `laterCF (F : cFunctor) : cFunctor       := λ (B,B⁻), later (F (B,B⁻))`
    -- `agreeRF (F : cFunctor) : rFunctor       := λ (B,B⁻), agree (F (B,B⁻))`
    -- `gmapURF K (F : rFunctor) : urFunctor    := λ (B,B⁻), gmap K (F (B,B⁻))`
    -
    -Using these combinators, one can easily construct bigger functors in point-free
    -style, e.g:
    -
    -```
    -F := gmapURF K (agreeRF (prodCF (constCF natC) (laterCF idCF)))
    -```
    -
    -which effectively defines `F := λ (B,B⁻), gmap K (agree (nat * later B))`.
    -
    -Furthermore, for functors written using these combinators like the functor `F`
    -above, Coq can automatically `urFunctorContractive F`.
    -
    -To make it a little bit more convenient to write down such functors, we make
    -the constant functors (`constCF`, `constRF`, and `constURF`) a coercion, and
    -provide the usual notation for products, etc. So the above functor can be
    -written as follows (which is similar to the effective definition of `F` above):
    -
    -```
    -F := gmapURF K (agreeRF (natC * ▶ ∙))
    -```
    -
    -## Resource algebra management
    -
    -When using ghost state in Iris, you have to make sure that the resource algebras
    -you need are actually available.  Every Iris proof is carried out using a
    -universally quantified list `Σ: gFunctors` defining which resource algebras are
    -available.  The `Σ` is the *global* list of resources that the entire proof can
    -use.  We keep the `Σ` universally quantified to enable composition of proofs.
    -
    -You can think of this as a list of resource algebras, though in reality it is a
    -list of locally contractive functors from COFEs to Cameras.  This list is used
    -to define the parameter `F` of Iris mentioned in the previous section. The
    -formal side of this is described in §7.4 of
    -[The Iris Documentation](http://plv.mpi-sws.org/iris/appendix-3.1.pdf); here we
    -describe the user-side Coq aspects of this approach.
    -
    -The assumptions that an Iris proof makes are collected in a type class called
    -`somethingG`.  The most common kind of assumptions is `inG`, which says that a
    -particular resource algebra is available for ghost state.  For example, in the
    -[one-shot example](tests/one_shot.v):
    +Libraries typically bundle the `inG` they need in a `libG` typeclass, so they do
    +not have to expose to clients what exactly their resource algebras are. For
    +example, in the [one-shot example](../tests/one_shot.v), we have:
     ```
     Class one_shotG Σ := { one_shot_inG :> inG Σ one_shotR }.
     ```
    @@ -107,10 +23,9 @@ add a field like `one_shot_other :> otherG Σ`.
     Having defined the type class, we need to provide a way to instantiate it.  This
     is an important step, as not every resource algebra can actually be used: if
     your resource algebra refers to `Σ`, the definition becomes recursive.  That is
    -actually legal under some conditions (which is why the global list `Σ` contains
    -functors and not just resource algebras), but for the purpose of this guide we
    -will ignore that case.  We have to define a list that contains all the resource
    -algebras we need:
    +actually legal under some conditions (see "Camera functors" below), but for now
    +we will ignore that case.  We have to define a list that contains all the
    +resource algebras we need:
     ```
     Definition one_shotΣ : gFunctors := #[GFunctor one_shotR].
     ```
    @@ -152,7 +67,24 @@ assuming.  This can easily lead to making more assumptions than you are aware
     of, and often it leads to duplicate assumptions which breaks type class
     resolutions.
     
    -### Obtaining a closed proof
    +## Resource algebra combinators
    +
    +Defining a new resource algebra `one_shotR` for each new proof and verifying all
    +the algebra laws would be quite cumbersome, so instead Iris provides a rich set
    +of resource algebra combinators that one can use to build up the desired
    +resource algebras. For example, `one_shotR` is defined as follows:
    +
    +```
    +Definition one_shotR := csumR (exclR unitO) (agreeR ZO).
    +```
    +
    +The suffixes `R` and `O` indicate that we are not working on the level of Coq
    +types here, but on the level of `R`esource algebras and `O`FEs,
    +respectively. Unfortunately this means we cannot use Coq's usual type notation
    +(such as `*` for products and `()` for the unit type); we have to spell out the
    +underlying OFE or resource algebra names instead.
    +
    +## Obtaining a closed proof
     
     To obtain a closed Iris proof, i.e., a proof that does not make assumptions like
     `inG`, you have to assemble a list of functors of all the involved modules,
    @@ -175,7 +107,7 @@ Lemma client_adequate σ : adequate NotStuck client σ (λ _ _, True).
     Proof. apply (heap_adequacy clientΣ)=> ?. apply client_safe. Qed.
     ```
     
    -### Advanced topic: Ghost state singletons
    +## Advanced topic: Ghost state singletons
     
     Some Iris modules involve a form of "global state".  For example, defining the
     `↦` for HeapLang involves a piece of ghost state that matches the current
    @@ -224,171 +156,128 @@ assumed explicitly everywhere.  Bundling `heapG` in a module type class like
     `one_shotG` would lose track of the fact that there exists just one `heapG`
     instance that is shared by everyone.
     
    -### Advanced topic: Additional module assumptions
    +## Advanced topic: Camera functors and higher-order ghost state
    +
    +As we already alluded to, `Σ` actually consists of functors, not resource
    +algebras. This enables you to use *higher-order ghost state*: ghost state that
    +recursively refers to `iProp`.
    +
    +**Background: Iris Model.** To understand how this works, we have to dig a bit
    +into the model of Iris. In Iris, the type of propositions `iProp` is described
    +by the solution to the recursive domain equation:
     
    -Some modules need additional assumptions.  For example, the STS module is
    -parameterized by an STS and assumes that the STS state space is inhabited:
     ```
    -Class stsG Σ (sts : stsT) := {
    -  sts_inG :> inG Σ (stsR sts);
    -  sts_inhabited :> Inhabited (sts.state sts);
    -}.
    +iProp ≅ uPred (F (iProp))
     ```
    -In this rather exceptional case, the `Instance` for this class has more than
    -just a `subG` assumption:
    -```
    -Instance subG_stsΣ Σ sts :
    -  subG (stsΣ sts) Σ → Inhabited (sts.state sts) → stsG Σ sts.
    -```
    -If users of this module follow the pattern described above, their own type class
    -instance will check these additional assumption.  But this is one more reason
    -why it is important for every module to have an instance for its `somethingG`:
    -to make sure that it does not accidentally make more assumptions than it intends
    -to.
    -
    -Another subtle detail here is that the `subG` assumption comes first in
    -`subG_stsΣ`, i.e., it appears before the `Inhabited`.  This is important because
    -otherwise, `sts_inhabited` and `subG_stsΣ` form an instance cycle that makes
    -type class search diverge.
    -
    -## Canonical structures and type classes
    -
    -In Iris, we use both canonical structures and type classes, and some careful
    -tweaking is necessary to make the two work together properly.  The details of
    -this still need to be written up properly, but here is some background material:
    -
    -* [Type Classes for Mathematics in Type Theory](http://www.eelis.net/research/math-classes/mscs.pdf)
    -* [Canonical Structures for the working Coq user](https://hal.inria.fr/hal-00816703v1/document)
    -
    -## Implicit generalization
    -
    -We often use the implicit generalization feature of Coq, triggered by a backtick:
    -`` `{!term A B}`` means that an implicit argument of type `term A B` is added,
    -and if any of the identifiers that are used here is not yet bound, it gets added
    -as well.  Usually, `term` will be some existing type class or similar, and we
    -use this syntax to also generalize over `A` and `B`; then the above is
    -equivalent to `{A B} {Hterm: term A B}`.  The `!` in front of the term disables
    -an even stronger form of generalization, where if `term` is a type class then
    -all missing arguments get implicitly generalized as well.  This is sometimes
    -useful, e.g. we can write `` `{Countable C}`` instead of `` `{!EqDecision C,
    -!Countable C}``.  However, generally it is more important to be aware of the
    -assumptions you are making, so implicit generalization without `!` should be
    -avoided.
    -
    -## Type class resolution control
    -
    -When you are writing a module that exports some Iris term for others to use
    -(e.g., `join_handle` in the [spawn module](theories/heap_lang/lib/spawn.v)), be
    -sure to mark these terms as opaque for type class search at the *end* of your
    -module (and outside any section):
    -```
    -Typeclasses Opaque join_handle.
    -```
    -This makes sure that the proof mode does not "look into" your definition when it
    -is used by clients.
    -
    -## Notations
    -
    -Notations starting with `(` or `{` should be left at their default level (`0`),
    -and inner subexpressions that are bracketed by delimiters should be left at
    -their default level (`200`).
    -
    -Moreover, correct parsing of notations sometimes relies on Coq's automatic
    -left-factoring, which can require coordinating levels of certain "conflicting"
    -notations and their subexpressions.  For instance, to disambiguate `(⊢@{ PROP
    -})` and `(⊢@{ PROP } P)`, Coq must factor out a nonterminal for `⊢@{ PROP }`,
    -but it can only do so if all occurrences of `⊢@{ PROP }` agree on the
    -precedences for all subexpressions. This also requires using the same
    -tokenization in all cases, i.e., the notation has to consistently be declared as
    -`(⊢@{` or `('⊢@{'`, but not a mixture of the two. The latter form of using
    -explicit tokenization with `'` is preferred to avoid relying on Coq's default.
    -
    -For details, consult [the Coq manual](https://coq.inria.fr/refman/user-extensions/syntax-extensions.html#simple-factorization-rules).
    -
    -## Naming conventions for variables/arguments/hypotheses
    -
    -### small letters
    -
    -* a : A = cmraT or ofeT
    -* b : B = cmraT or ofeT
    -* c
    -* d
    -* e : expr = expressions
    -* f = some generic function
    -* g = some generic function
    -* h : heap
    -* i
    -* j
    -* k
    -* l
    -* m : iGst = ghost state
    -* m* = prefix for option
    -* n
    -* o
    -* p
    -* q
    -* r : iRes = resources
    -* s = state (STSs)
    -* s = stuckness bits
    -* t
    -* u
    -* v : val = values of language
    -* w
    -* x
    -* y
    -* z 
    -
    -### capital letters
    -
    -* A : Type, cmraT or ofeT
    -* B : Type, cmraT or ofeT
    -* C
    -* D   
    -* E : coPset = Viewshift masks
    -* F = a functor
    -* G
    -* H = hypotheses
    -* I = indexing sets
    -* J
    -* K : ectx = evaluation contexts
    -* K = keys of a map
    -* L
    -* M = maps / global CMRA
    -* N : namespace
    -* O 
    -* P : uPred, iProp or Prop
    -* Q : uPred, iProp or Prop
    -* R : uPred, iProp or Prop
    -* S : set state = state sets in STSs
    -* T : set token = token sets in STSs
    -* U
    -* V : abstraction of value type in frame shift assertions
    -* W
    -* X : sets
    -* Y : sets
    -* Z : sets
    -
    -### small greek letters
    -
    -* γ : gname
    -* σ : state = state of language
    -* φ : interpretation of STS/Auth
    -
    -### capital greek letters
    -
    -* Φ : general predicate (over uPred, iProp or Prop)
    -* Ψ : general predicate (over uPred, iProp or Prop)
    -
    -## Naming conventions for algebraic classes
    -
    -### Suffixes
    -
    -* O: OFEs
    -* R: cameras
    -* UR: unital cameras or resources algebras
    -* F: functors (can be combined with all of the above, e.g. OF is an OFE functor)
    -* G: global camera functor management (typeclass; see [proof\_guide.md](./proof_guide.md))
    -* I: bunched implication logic (of type `bi`)
    -* SI: step-indexed bunched implication logic (of type `sbi`)
    -* T: canonical structures for algebraic classes (for example ofeT for OFEs, cmraT for cameras)
    -* Σ: global camera functor management (`gFunctors`; see [proof\_guide.md](./proof_guide.md))
    +
    +Here, `uPred M` describes "propositions with resources of type `M`".  The
    +peculiar aspect of this definition is that the notion of resources can itself
    +refer to the set propositions that we are just defining; that dependency is
    +expressed by `F`.  `F` is a user-chosen locally contractive bifunctor from COFEs
    +to unital Cameras (a step-indexed generalization of unital resource
    +algebras). Having just a single fixed `F` would however be rather inconvenient,
    +so instead we have a list `Σ`, and then we define the global functor `F_global`
    +roughly as follows:
    +
    +```
    +F_global X := Π_{F ∈ Σ} gmap nat (F X)
    +```
    +
    +In other words, each functor in `Σ` is applied to the recursive argument `X`,
    +wrapped in a finite partial function, and then we take a big product of all of
    +that.  The product ensures that all `F ∈ Σ` are available, and the `gmap` is
    +needed to provide the proof rule `own_alloc`, which lets you create new
    +instances of the given type of resource any time.
    +
    +However, this on its own would be too restrictive, as it requires all
    +occurrences of `X` to be in positive positions (otherwise the functor laws
    +would not hold for `F`).  To mitigate this, we instead work with "bifunctors":
    +functors that take two arguments, `X` and `X⁻`, where `X⁻` is used for
    +negative positions.  This leads us to the following domain equation:
    +
    +```
    +iProp ≅ uPred (F_global (iProp,iProp))
    +F_global (X,X⁻) := Π_{F ∈ Σ} gmap nat (F (X,X⁻))
    +```
    +
    +To make this equation well-defined, the bifunctors `F ∈ Σ` need to be "contractive".
    +For further details, see §7.4 of
    +[The Iris Documentation](http://plv.mpi-sws.org/iris/appendix-3.3.pdf); here we
    +describe the user-side Coq aspects of this approach.
    +
    +Below, when we say "functor", we implicitly mean "bifunctor".
    +
    +**Higher-order ghost state.** To use higher-order ghost state, you need to give
    +a functor whose "hole" will later be filled with `iProp` itself. For example,
    +let us say you would like to have ghost state of type `gmap K (agree (nat *
    +later iProp))`, using the "type-level" `later` operator which ensures
    +contractivity.  Then you will have to define a functor such as:
    +
    +```
    +F (X,X⁻) := gmap K (agree (nat * ▶ X))
    +```
    +
    +To make it convenient to construct such functors and prove their contractivity,
    +we provide a number of abstractions:
    +
    +- [`cFunctor`](theories/algebra/ofe.v): functors from COFEs to OFEs.
    +- [`rFunctor`](theories/algebra/cmra.v): functors from COFEs to cameras.
    +- [`urFunctor`](theories/algebra/cmra.v): functors from COFEs to unital
    +  cameras.
    +
    +Besides, there are the classes `cFunctorContractive`, `rFunctorContractive`, and
    +`urFunctorContractive` which describe the subset of the above functors that are
    +contractive.
    +
    +To compose these functors, we provide a number of combinators, e.g.:
    +
    +- `constOF (A : ofeT) : cFunctor           := λ (B,B⁻), A `
    +- `idOF : cFunctor                         := λ (B,B⁻), B`
    +- `prodOF (F1 F2 : cFunctor) : cFunctor    := λ (B,B⁻), F1 (B,B⁻) * F2 (B,B⁻)`
    +- `ofe_morOF (F1 F2 : cFunctor) : cFunctor := λ (B,B⁻), F1 (B⁻,B) -n> F2 (B,B⁻)`
    +- `laterOF (F : cFunctor) : cFunctor       := λ (B,B⁻), later (F (B,B⁻))`
    +- `agreeRF (F : cFunctor) : rFunctor       := λ (B,B⁻), agree (F (B,B⁻))`
    +- `gmapURF K (F : rFunctor) : urFunctor    := λ (B,B⁻), gmap K (F (B,B⁻))`
    +
    +Note in particular how the functor for the function space, `ofe_morOF`, swaps
    +`B` and `B⁻` for the functor `F1` describing the domain.  This reflects the fact
    +that that functor is used in a negative position.
    +
    +Using these combinators, one can easily construct bigger functors in point-free
    +style and automatically infer their contractivity, e.g:
    +
    +```
    +F := gmaURF K (agreeRF (prodOF (constOF natO) (laterOF idOF)))
    +```
    +
    +which effectively defines the desired example functor
    +`F := λ (B,B⁻), gmap K (agree (nat * later B))`.
    +
    +To make it a little bit more convenient to write down such functors, we make
    +the constant functors (`constOF`, `constRF`, and `constURF`) a coercion, and
    +provide the usual notation for products, etc. So the above functor can be
    +written as follows:
    +
    +```
    +F := gmapRF K (agreeRF (natO * ▶ ∙))
    +```
    +
    +Basically, the functor can be written "as if" you were writing a resource
    +algebra, except that there need to be extra "F" suffixes to indicate that we are
    +working with functors, and the desired recursive `iProp` is replaced by the
    +"hole" `∙`.
    +
    +Putting it all together, the `libG` typeclass and `libΣ` list of functors for
    +your example would look as follows:
    +
    +```
    +Class libG Σ := { lib_inG :> inG Σ (gmapR K (agreeR (prodO natO (laterO (iPropO Σ))))) }.
    +Definition libΣ : gFunctors := #[GFunctor (gmapRF K (agreeRF (natO * ▶ ∙)))].
    +Instance subG_libΣ {Σ} : subG libΣ Σ → libG Σ.
    +Proof. solve_inG. Qed.
    +```
    +
    +It is instructive to remove the `▶` and see what happens: the `libG` class still
    +works just fine, but `libΣ` complains that the functor is not contractive. This
    +demonstrates the importance of always defining a `libΣ` alongside the `libG` and
    +proving their relation.
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment