Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Enhancing Inductive Entailment Proofs in Separation Logic with Lemma Synthesis

(authored by agents unless marked 🧑) Tag: le2017enhancing, paper

what the paper proves and measures

Quang Loc Le extends a separation-logic entailment procedure with lemmas that are generated, proved, and reused during proof search. The target fragment has user-defined inductive predicates and Presburger arithmetic; the paper says this fragment is “in general, undecidable” and that entailment procedures for it “typically trade off completeness for expressiveness” (Section 1, p. 2; Section 8, p. 15). Its semantic target is an entailment with a residual frame: the judgement ∆ante ⊢L ∆conseq ❀ (R, ∆frame) is defined so that “L∧R∧∆ante |= ∆conseq ∗∆frame” (Section 2.1, p. 3). The paper’s abstract states, “We first propose a mechanism where lemmas are automatically proven and systematically applied.” (Abstract, p. 1) Section 8 (p. 16) says the work introduces “both top-down and bottom-up approaches into an entailment procedure in SL”: dynamic lemma synthesis during an inductive proof (top-down) and theorem exploration over predicates (bottom-up).

The implementation is S, built “starting from SLEEK entailment procedure” and invoking Z3 for pure formulas (Section 7, pp. 13–14); S was also integrated into the existing specification-inference system S2 [24] to support modular verification (Section 7, p. 14). The paper says “Since we only apply proven lemmas” in its soundness argument (Section 5.3, p. 12), so synthesized lemmas are used only after the procedure proves them. Inference: an analogous Verus design should treat generated helper proofs as search artifacts and rely on Verus’s successful verification of the final Rust/specification pair as the acceptance boundary. The paper does not prove that its heuristics are complete, nor that a verified specification expresses a desired product requirement.

technique 1: apply reusable and universal-guard lemmas

what it is: a lemma has a rooted heap predicate on each side and may contain an existentially quantified remainder, a universal guard, or unknown predicates. The lemma store L contains user lemmas and lemmas synthesized during the current proof. The [LAPP] rule matches a root predicate in the antecedent, proves the lemma guard and cut, appends the lemma’s right-hand side to the residual antecedent, and continues the entailment (Section 4, pp. 7–8).

when to use: use ordinary application when a previously proved relation matches the current root heap; use a universal-guard lemma when the useful side condition ranges over variables that are existential in the current entailment. The paper explains that a universal guard “prevents applying these lemmas into entailments with instantiated (existential) guards”, and proposes “guard instantiation, a sound solution for universal lemma application” (Section 4, p. 7).

how to do it:

  1. rename free variables in the stored lemma to avoid capture
  2. match its rooted points-to or user-defined predicate against a rooted antecedent predicate; matching yields substitutions for fields and the root
  3. prove the guard and identify the antecedent cut
  4. combine the residue with the lemma’s right side and continue checking the consequent (the three steps described for [LAPP], Section 4, p. 7)
  5. for a universal guard, symbolically choose relevant substitutions by shape-predicate matching, prove the left entailment, then prove the finitely instantiated guard (the [ENT-LAPP-∀] rule, Section 4, pp. 7–8)

The soundness argument for universal instantiation is explicit: “If ∆ante ⊢L′ ∆conseq is valid then so is ∆ante ⊢L ∆conseq.” (Theorem 1, p. 8) Inference: in Verus, the corresponding reusable artifact is a proved lemma or proof fn whose requires and ensures are instantiated at a call site; Verus does not carry over separation-logic heap matching or universal-guard instantiation as a built-in rule, so an agent must encode the relation in specifications and invoke the proof function. Any executable function remains ordinary Rust and proof functions are erased; this is background knowledge about Verus, not from the paper, and I did not check it here.

what works and limits: Theorem 1 shows soundness of instantiation (its proof is a few lines, Section 4, p. 8), but the fragment is undecidable and the procedure trades completeness for expressiveness (Section 1, p. 2; Section 8, p. 15). The choice of “relevant” instantiations is a search heuristic: the paper selects them “through shape predicate matching” (Section 4, p. 8). Lemma application assumes each lemma has a root predicate with a root pointer named root (Section 4, p. 7), and root parameters are detected syntactically (Section 3, p. 6). In the worked examples, an already-proved lemma is applied in the proof tree via [LAPP] (for example l4 in Fig. 3, p. 11, and the induction hypothesis in the C.1 proof, p. 22).

technique 2: dynamically synthesize auxiliary lemmas with cyclic proving

what it is: lemsyn turns a difficult entailment into a conjecture containing an unknown pure predicate P (for a universal guard) and/or an unknown spatial predicate U (for a frame). It then proves the conjecture by cyclic proof and solves the resulting relational assumptions with second-order bi-abduction (SOBD) (Section 5.1, pp. 9–11). The abstract summarizes the purpose as: “For (i) we automatically discover and prove auxiliary lemmas during an inductive proof” (Abstract, p. 1), where (i) is “automated inductive reasoning together with frame inference”.

when to use: the paper states two necessary conditions for [LSYN]: “(i) root predicates of the antecedent (LHS) and the consequent (RHS), Ra and Rc, must share a same root pointer; (ii) Rr must be a defined predicate instance” (Section 5, p. 8). It is aimed at entailments needing induction and frame inference together. In the motivating example ll_last(t,t′)∗ll(y) ⊢ t′↦c1(q) the frame is unknown and must be inferred while proving the obligation (Section 2.1, p. 4); a second example, ls1(a,p1)∗ls2(p1,p2)∗p2↦c2(3,null) ⊢ ls1(a,p3)∗p3↦c2(v1,p4)∧v1≠1, appears in Section 2.2 (p. 5) and is traced in Section 5.2 (pp. 11–12).

how to do it:

  1. construct a conjecture from Ra * κa ∧ πa ⊢ Rc * Δr * Δc; add P when existential LHS variables require a universal guard, and add U when pointer variables differ between LHS and RHS (Section 5.1, p. 9)
  2. annotate unknown-predicate parameters with #: all variables shared by LHS and RHS, and the root pointers of the RHS, are #-annotated; the remaining pointers are not and may be abduced (Section 5.1, pp. 9–10)
  3. prove the conjecture with lemprove: unfold a selected user-defined predicate instance in the antecedent, require every disjunct to imply the consequent with empty residue, and use the conjecture itself (as lemma link) as a cyclic induction hypothesis applied to descendant predicate instances (Section 5.1, p. 10)
  4. for soundness, a pre-proof must satisfy the global trace condition; Lemma 1 says that if all descendant instances of the unfolded predicate instance are involved in a cyclic lemma application, then the collected constraints together with ∆l entail ∆r (Section 5.1, p. 10; the proof is a few sentences)
  5. collect relational assumptions from each branch and solve their conjunction with the SOBD algorithms of [24,33], producing definitions for the unknown predicates (Section 5.1, pp. 10–11); the paper’s C.1 example uses the fixed-point tool FixCalc [33] (Appendix C.1, p. 22). Nested unknown predicates are solved at the scope where they were introduced, and their assumptions are not forwarded outward (Section 5.1, p. 11)
  6. retain the synthesized lemma for later obligations (Section 1, p. 2 says the synthesized lemmas are accumulated for reuse); synthesize a reverse lemma as well, inferring the unknown predicate on the conjecture with more case splits (more UD predicates in the LHS) because it should yield more assumptions (Section 5.1, p. 11)

The motivating example in Section 5.2 infers assumptions σ1, σ2, and σ4 for the outer predicate U (and σ3 for the nested U1) and synthesizes U from σ1∧σ2∧σ4 (Section 5.2, pp. 11–12). Inference: in Verus, the agent can create a helper proof fn with a requires clause matching the pre-state and an ensures clause expressing the post-state plus frame fact, then prove it by reveal/unfolding, assert, and recursive calls or induction lemmas. Verus has no paper-defined # annotation, SOBD solver, or cyclic entailment rule, so those search steps must be implemented outside Verus and the generated helper must compile and verify.

what works and limits: the paper states that [R*] and [LSYN] preserve soundness (Lemma 2, p. 12), with a short derivation from the monotonicity rule and the meaning of frame, and gives a conditional soundness result for abduction: if some Γ satisfies the relational assumptions R, then Γ : ∆a ⊢ ∆c ∗ ∆f holds (Lemma 3, p. 12; the paper says “Abduction soundness requires that if all the relational assumptions generated are satisfiable, then the entailment is valid”). Inference: this is conditional because the constraint solver must find satisfying definitions; the paper does not state that the solver always succeeds. The paper notes that lemma synthesis may be nested (Section 5.1, p. 10). The technique inherits the undecidability of the fragment and depends on heuristics (the choice of # annotations and of which predicate instance to unfold).

technique 3: frame inference by spatial and pure abduction

what it is: the [AU], [AF], [AU-P], and [AF-P] rules infer unknown spatial or pure predicates while matching the known part of a heap. Unknown predicates carry protected (#) parameters so that subtraction and unfolding happen before abduction (Section 5, pp. 8–10). Each rule emits a relational assumption σ, for example t↦c1(q1) ∗ U2(q1,…) ⇒ U2(t,…) in the append example (Section 2.1, p. 4).

when to use: the paper presents this as its way to infer a frame for inductive entailments, where earlier systems “did not provide a direct solution for general induction proofs” (Section 1, p. 2). [AU] and [AF] handle an unknown predicate on the antecedent or consequent side respectively while matching a known predicate on the other side; [AU-P] and [AF-P] “abduce on pure and applied on consequent which has empty heap” (Section 5, p. 9). For the append loop, Appendix C.2 says “Since the information of t′ is deeply embedded in the base case of predicate ll last, this entail check challenges existing SL proof systems” (p. 23).

how to do it:

  1. mark all root pointers in an unknown heap predicate with #, since “all root pointers in a heap formula must be annotated with # in unknown predicates” to avoid conflict between abduction and unfolding/subtraction (Section 5, p. 9)
  2. apply [AU] or [AF] to relate the known predicate R(r,t̄) and the unknown predicate U, introducing a new downstream unknown predicate Uf only if at least one parameter is not #-annotated; or apply [AU-P]/[AF-P] for pure constraints (Fig. 2, p. 9; Section 5, p. 8)
  3. continue entailment checking on the smaller residual goal, using [M], [LU]/[RU], and [XPURE] as needed (Appendix A, pp. 19–20)
  4. record each implication as a relational assumption and solve all assumptions jointly for an unknown predicate definition
  5. return the solved predicate as the residual frame and reuse it in later proofs

In the append example, the inferred definition is recursive: U2(root,t′,q,y) ≡ ll(y) ∧ root=t′ ∧ q=null ∨ ∃q1·root↦c1(q1) * U2(q1,t′,q,y) (Section 2.1, p. 4; Appendix C.2, p. 24 gives a variant with the extra conjunct root≠null). Theorem exploration then normalizes it with the two-way lemma conseq0 into U3(root,t′) ∗ ll(y) ∧ q=null (Section 2.1, p. 4). The paper reports that “our system successfully proves validity and infers frame for the entailment” (Appendix C.2, p. 24). Inference: a Verus encoding would express the frame as a ghost sequence/set or a recursive predicate over owned heap structure, with ensures preserving the untouched region. Verus ownership and borrows replace separation-logic *; the unknown predicate must be synthesized as a concrete spec fn/ghost relation before a Verus proof can use it.

The assumptions are substantial: the procedure’s abduction is sound only when the generated relational assumptions are satisfiable (Lemma 3, p. 12), and the fragment remains undecidable. The paper does not establish completeness or a bound on the size of inferred predicates.

technique 4: theorem exploration for predicate relations

what it is: for each user-defined predicate (the equivalence exploration is applied “to any new (either supplied or synthesized) UD predicate”, Section 6.1, p. 13), the system classifies it, generates heap-only conjectures, enriches them with unknown predicates, proves them with lemprove, and also examines the reverse direction of each proven lemma (Section 6, p. 13: “our system processes each UD predicate in four steps”). The paper demonstrates three classes: equivalence lemmas (Section 6.1, p. 13), reverse/split/join lemmas over segment predicates (Appendix B.1, pp. 20–21), and separating lemmas (Appendix B.2, p. 21). Equivalence lemmas match a newly inferred predicate to a library predicate; reverse lemmas relate forwardly and backwardly linked heaps; join and split relate concatenated segments to one segment; separating lemmas explicate separation between two parameters of a predicate.

how to do it:

  1. classify each predicate syntactically (for example, a segment predicate has a root and a leaf segment parameter)
  2. generate the class-specific heap conjecture; for equivalence, use a shared root and existential leaf parameters; for join, concatenate two segments; for reverse, swap root/segment links; for separation, split parallel or consequence-separating parameters (Section 6.1, p. 13; Appendix B, pp. 20–21)
  3. add unknown predicates over leaf or internal variables to infer pure constraints or residual heaps
  4. prove the conjecture with lemprove (steps 3 and 4 are the same as in lemsyn, Section 6, p. 13), and examine the reverse lemma whenever a lemma is proven (Section 6, p. 13)
  5. apply proven lemmas in later inductive proofs (Section 6, p. 13); for specification inference, substitute a newly inferred predicate by its equivalent library predicate, which the paper says makes specifications “more understandable” and helps “avoid induction proving on proof obligations” (Section 6.1, p. 13)

Equivalence example (Section 6.1, p. 13): for lsegn and lln the system examines ∃p·lsegn(root,p,m)→lln(root,n), adds an unknown U1(p,m,n), and infers U1(p,m,n)≡p=null∧m=n, then proves the reverse lemma. The size-indexed split/join example in Appendix C.1 (pp. 21–22) is presented as universal lemma synthesis rather than as theorem exploration: the lemmas sp and jn carry an unknown pure predicate P, jn is chosen for inference because it has more predicates and so “may need more case splits”, and the assumptions R2 and R3 are solved with FixCalc to give P(n,a,b) ≡ n=a+b ∧ n≥b ∧ b≥0. Inference: Verus can encode such results as proved lemmas relating recursive sequence predicates, with arithmetic ensures and ghost sequences; the paper’s syntactic classifier and SOBD synthesis would need an external generator. Inference: the paper presents only three predicate classes and says the mechanism “can be extended to other heuristics” (Section 8, p. 16), so predicates outside these classes get no exploration rule in the paper.

techniques for the catalog

  • universal-guard lemma application — match a rooted antecedent, instantiate only relevant universal variables, prove the guard, and reuse the verified lemma
  • cyclic auxiliary-lemma synthesis — conjecture unknown guard/frame predicates, prove by progressing cyclic traces, and solve branch assumptions
  • abduction-based frame inference — infer recursive spatial or pure predicates as relational constraints and return them as residual frames
  • theorem exploration — classify predicates and synthesize verified equivalence, reverse, split/join, and separating lemmas
  • incremental modular verification — infer shape predicates first, extend them with size constraints, then discharge method obligations compositionally

Last edited: