diff --git a/README.md b/README.md index c8107d947323c062121deef5853a7c5e44a56082..4d336d3e3f48f08fb963cef728779c1a3b3f0867 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,8 @@ Getting along with Iris in Coq: * Iris proof patterns and conventions are documented in the [proof guide](docs/proof_guide.md). +* Various notions of equality in Iris and their Coq interface are described in the [equality + docs](docs/equalities.md). * The Iris tactics are described in the [the Iris Proof Mode (IPM) / MoSeL documentation](docs/proof_mode.md) as well as the [HeapLang documentation](docs/heap_lang.md). diff --git a/docs/equalities.md b/docs/equalities.md new file mode 100644 index 0000000000000000000000000000000000000000..c24dc23249ab9de0a66eff58e7c52974ec6ec370 --- /dev/null +++ b/docs/equalities.md @@ -0,0 +1,151 @@ +# Equalities in Iris + +Using Iris involves dealing with a few subtly different equivalence and equality +relations, especially among propositions. +This document summarizes these relations and the subtle distinctions among them. +This is not a general introduction to Iris: instead, we discuss the different +Iris equalities and the interface to their Coq implementation. In particular, we +discuss: +- Equality from Iris metatheory vs Coq equality and setoid equivalence; +- N-equivalence on OFEs; +- Iris internal equality; +- Iris entailment and bi-entailment. + +## Leibniz equality and setoids + +First off, in the metalogic (Coq) we have both the usual propositional (or +Leibniz) equality `=`, and setoid equality `equiv` / `≡` (defined in `stdpp`). +Notations for metalogic connectives like `≡` are declared in Coq scope +`stdpp_scope`, which is "open" by default. + +Setoid equality for a type `A` is defined by the instance of `Equiv A`; this +allows defining quotient setoids. To deal with setoids, we use Coq's +[generalized +rewriting](https://coq.inria.fr/refman/addendum/generalized-rewriting.html) +facilities. + +Setoid equality can coincide with Leibniz equality: +- `equivL` defines a setoid equality coinciding with Leibniz equality. +- Some types enjoy `LeibnizEquiv`, which makes `equiv` be equivalent to `eq`. + +Given setoids `A` and `B` and a function `f : A → B`, an instance `Proper ((≡) +==> (≡)) f` declares that `f` respects setoid equality, as usual in Coq. Such +instances enable rewriting with setoid equalities. + +Here, stdpp adds the following facilities: +- `solve_proper` for automating proofs of `Proper` instances. +- `f_equiv` generalizes `f_equal` to other relations; it will for instance turn + goal `R (f a) (f b)` into `R a b` given an appropriate `Proper` instance + (here, `Proper (R ==> R) f`). + +## Equivalences on OFEs + +On paper, OFEs involve two relations, equality "=" and distance "=_n". In Coq, +equality "=" is formalized as setoid equality, written `≡` or `equiv`, as before; +distance "=_n" is formalized as relation `dist n`, also written `≡{n}≡`. +Tactics `solve_proper` and `f_equiv` also support distance. + +Some OFE constructors choose interesting equalities. +- `discreteO` constructs discrete OFEs (where distance coincides with setoid equality). +- `leibnizO` constructs discrete OFEs (like `discreteO`) but using `equivL`, so + that both distance and setoid equality coincide with Leibniz equality. + +Given OFEs `A` and `B`, non-expansive functions from `A` to `B` are functions +`f : A → B` with a proof of `NonExpansive f` (that is, `(∀ n, Proper (dist n +==> dist n) f)`). The two can be packaged together via `A -n> B`. + +Non-expansive functions from Leibniz OFEs can be given type `A -d> B` instead of +`leibnizO A -n> B`; this spares the need for bundled `NonExpansive` instances. +Moreover, `discreteO A -n> B` is isomorphic to `f : A -d> B` plus an instance +for `∀ n, Proper ((≡) ==> (≡{ n }≡)) f`. However, in the second case the +`Proper` instance can be omitted for proof convenience unless actively used. + +In both OFE function spaces (`A -n> B` and `A -d> B`), setoid equality is +defined to be pointwise equality, so that functional extensionality holds for `≡`. + +## Inside the Iris logic + +Next, we introduce notions internal to the Iris logic. Such notions often +overload symbols used for external notions; however, those overloaded notations +are declared in scope `bi_scope`; when writing `(P)%I`, notations in `P` are +resolved in `bi_scope` in preference over `stdpp_scope`. +We also use `bi_scope` for the arguments of all variants of Iris entailments. + +The Iris logic has an internal concept of equality. If `a` and `b` are Iris +terms of type `A`, then their internal equality is written (on paper) "a =_A b"; +in Coq, that's written `a ≡ b` (notation for `sbi_internal_eq` in scope `bi_scope`). + +As shown in the Iris appendix, an internal equality `a ≡ b` is interpreted using +OFE distance. Many types have `_equivI` lemmas characterizing internal +equality on them. For instance, if `f, g : A -d> B`, lemma +`discrete_fun_equivI` shows that `f ≡ g` is equivalent to `∀ x, f x ≡ g x`. +Typically, each `_equivI` lemma for type `T` lifts to internal equality on +`T` properties of the distance on `T`. + +## Relations among Iris propositions + +In this section, we discuss relations among internal propositions. +Even though some of these notes generalize to all internal logics (other +`sbi`s), we focus on Iris propositions (`iProp Σ`), to discuss both their proof +theory and their model. +As Iris propositions form a separation logic, we assume some familiarity with +separation logics, connectives such as `-∗`, `∗`, `emp` and `→`, and the idea +that propositions in separation logics are interpreted with predicates over +resources (see for instance Sec. 2.1 of the MoSEL paper). + +In the metalogic, Iris defines the entailment relation between uniform +predicates: intuitively, `P` entails `Q` (written `P ⊢ Q`) means that `P` implies +`Q` on _every_ resource (for details see Iris appendix [Sec. 6]). +Entailment `P ⊢ Q` is distinct from the magic wand, `(P -∗ Q)%I`, but +equivalent, as `P ⊢ Q` is equivalent to `emp ⊢ P -∗ Q` (per Iris lemmas +`entails_wand` and `wand_entails`). +Notation `P ⊢ Q` is declared in `stdpp_scope`, but takes arguments in +`bi_scope`, so that we can write conveniently `P ⊢ Q -∗ R` in `stdpp_scope`. +For additional convenience, `P ⊢ Q` can also be written `P -∗ Q` in +`stdpp_scope`, so that we can write `P -∗ Q -∗ R` instead of `P ⊢ Q -∗ R` or of +the equivalent `emp ⊢ P -∗ Q -∗ R`. +Using entailment, Iris defines an implicit coercion `bi_emp_valid`, mapping any +Iris propositions `P` into the Coq propositions `emp ⊢ P`. + +On paper, uniform predicates are defined by quotienting by an equivalence +relation ([Iris appendix, Sec. 3.3]); that relation is used in Coq as setoid +equivalence. That relation is also equivalent to bi-entailment (or entailment in +both directions), per lemma `equiv_spec`: +```coq +Lemma equiv_spec P Q : P ≡ Q ↔ (P ⊢ Q) ∧ (Q ⊢ P). +``` + +Hence, setoid equality `≡` on propositions is also written `⊣⊢`. For instance, +our earlier lemma `discrete_fun_equivI` is stated using `⊣⊢`: + +```coq +Lemma discrete_fun_equivI {A} {B : A → ofeT} (f g : discrete_fun B) : + f ≡ g ⊣⊢ ∀ x, f x ≡ g x. +``` + +Inside the logic, we can use internal equality `≡` (in `bi_scope`), which +translates to distance as usual. Here is a pitfall: internal equality `≡` is in +general strictly stronger than `∗-∗`, because `Q1 ≡ Q2` means that `Q1` and `Q2` +are equivalent _independently of the available resources_. +- When proving `P -∗ Q1 ∗-∗ Q2`, we can use `P` to show that `Q1` and `Q2` are + equivalent. +- Instead, to prove `P -∗ Q1 ≡ Q2`, we cannot use `P` unless it's a plain + proposition (so, one that holds on the empty resource). Crucially, pure + propositions `⌜ φ âŒ` are plain. + +We can explain internal equality using the Iris plainly modality: +```coq +Lemma prop_ext P Q : P ≡ Q ⊣⊢ â– (P ∗-∗ Q). +``` +Looking at the Iris semantics for the plainly modality, to prove internal equality +`P ≡ Q`, we must prove that `P` and `Q` are equivalent _without any resources +available_. + +Last, metalevel propositions `φ : Prop` can be embedded as pure Iris +propositions `⌜ φ âŒ`, and this allows embedding equalities from the metalogic. +For instance, `⌜ a1 = a2 âŒ` can be useful for making some proofs more +convenient, as Leibniz equality is the strongest equivalence available, is +respected by all Coq functions, and can be used for rewriting in the absence of +`Proper` instances. On the other hand, on-paper Iris does not allow writing +`⌜ a1 = a2 âŒ`, only `⌜ a1 ≡ a2 âŒ`, unless setoid equality and Leibniz equality +coincide.