Skip to content

Commit 21c7fd5

Browse files
committed
Merge branch 'dev'
Conflicts: AppendOnlyLinkedList.v
2 parents fe4c83b + 3f8f1c5 commit 21c7fd5

File tree

9 files changed

+184
-17
lines changed

9 files changed

+184
-17
lines changed

AppendOnlyLinkedList.v

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ Obligation Tactic :=
2727
Require Import Coq.Program.Tactics.
2828

2929
Global Instance appList_fold : rel_fold appList :=
30-
{ rgfold := fun R G => appList }. (* TODO: This is technically unsound - need to recursively rewrite tail pointer relations... *)
30+
{ rgfold := fun R G => appList ; (* TODO: This is technically unsound - need to recursively rewrite tail pointer relations... *)
31+
fold := fun R G x => x
32+
}.
3133

3234
Global Instance appList_contains : Containment appList. Admitted.
3335
(* want something like { contains := fun RR => RR = (optset ...) }. but need to handle cons/option shifting *)
@@ -48,7 +50,15 @@ Program Definition alist_append {Γ}(n:nat)(l:alist) : rgref Γ unit Γ :=
4850
| rcons n' tl' => rec tl'
4951
end)
5052
end _))) l.
51-
Next Obligation. compute in *. rewrite H. constructor. Qed.
53+
Next Obligation.
54+
(* This proof is by no means ideal. It only works because we can assume
55+
that appList_fold's identity behavior matches meta_fold, which is useful
56+
but very specific, and won't be true in many cases we care about. *)
57+
erewrite deref_conversion with (f' := @meta_fold (option appList)) in *.
58+
rewrite H.
59+
constructor.
60+
Grab Existential Variables. eauto. eauto.
61+
Qed.
5262

5363
Program Example test1 {Γ} : rgref Γ unit Γ :=
5464
l <- Alloc None;

KnownUnsoundnessExamples.v

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,19 @@ Program Definition BAD_alist_append {Γ}(n:nat)(l:alist) : rgref Γ unit Γ :=
2828
| rcons n' tl' => rec tl'
2929
end)
3030
end))) l.
31-
Next Obligation. compute in Heq_anonymous. compute. rewrite <- Heq_anonymous. constructor. Qed.
32-
Next Obligation. compute in *. rewrite <- Heq_anonymous. constructor. Qed.
31+
Next Obligation.
32+
erewrite deref_conversion with (f' := @meta_fold (option appList)) in *.
33+
rewrite <- Heq_anonymous.
34+
constructor.
35+
Grab Existential Variables. eauto. eauto.
36+
Qed.
37+
Next Obligation.
38+
erewrite deref_conversion with (f' := @meta_fold (option appList)) in *.
39+
rewrite <- Heq_anonymous.
40+
constructor.
41+
Grab Existential Variables. eauto. eauto.
42+
Qed.
43+
3344
(** The specific issue with this example is that using a match inside a Program Definition
3445
adds an equality proof to the context for goals inside the match clauses. In this case,
3546
in the None branch of the match, the assumption << !tl=None >> is added to the context.

LinkedList.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ Hint Resolve precise_prepend.
233233
(* Folding anything into this list container is a no-op: the head already points to a rgrList' with guarantee list_imm,
234234
so no further restriction is necessary / possible. *)
235235
Instance lst_cont_fold {P Q}: rel_fold (@list_container P Q) := {
236-
rgfold := (fun R => fun G => @list_container P Q)
236+
rgfold := (fun R => fun G => @list_container P Q) ;
237+
fold := fun _ _ x => x
237238
}.
238239

239240
Require Import Coq.Program.Tactics.

MonotonicCounter.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ Program Definition mkCounter { Γ } (u:unit) : rgref Γ monotonic_counter Γ :=
2424

2525
Program Example test_counter { Γ } (u:unit) : rgref Γ unit Γ :=
2626
x <- mkCounter tt;
27-
inc_monotonic x.
27+
inc_monotonic x.

PosMonotonicCounter.v

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Require Import Coq.Arith.Arith.
2+
Require Import RGref.DSL.DSL.
3+
4+
(** * A Strictly Positive Monotonic Counter
5+
A monotonically increasing non-zero counter.
6+
A slightly better basic example than the plain monotonic counter since this one has a nontrivial refinement. *)
7+
8+
Definition increasing : hrel nat := (fun n n' _ _ => n <= n').
9+
Hint Unfold increasing.
10+
11+
Definition pos : hpred nat := (fun n _ => n > 0).
12+
13+
(** We'll give the Program extension some hints for this module *)
14+
Local Obligation Tactic := intros; eauto with arith; compute; eauto with arith.
15+
16+
(** Now the definition of a verified monotonically increasing counter is
17+
barely more work than a completely unchecked counter. *)
18+
Program Definition posmonotonic_counter := ref{nat|pos}[increasing,increasing].
19+
20+
Program Definition read_counter (c:posmonotonic_counter) : nat := !c.
21+
22+
Program Definition inc_monotonic { Γ } (p:posmonotonic_counter) : rgref Γ unit Γ :=
23+
[p]:= !p + 1.
24+
25+
Program Definition mkCounter { Γ } (u:unit) : rgref Γ posmonotonic_counter Γ :=
26+
Alloc 1.
27+
28+
Program Example test_counter { Γ } (u:unit) : rgref Γ unit Γ :=
29+
x <- mkCounter tt;
30+
inc_monotonic x.

RGref/DSL/Core.v

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ Definition precise_rel {A:Set}{AR:ImmediateReachability A} (R:hrel A) :=
117117
is essentially a no-op. The guarantee, however, still needs to be
118118
projected and intersected component-wise in any structure. *)
119119
Class rel_fold (A:Set) :=
120-
{ rgfold : forall (R G:hrel A), Set }.
120+
{ rgfold : forall (R G:hrel A), Set ;
121+
fold : forall {R G}, A -> rgfold R G
122+
}.
121123
(** In meta-proofs, of things like satisfying a guarantee, we use this
122124
identity fold instead of the appropriate developer instance so
123125
G and P don't have to have polymorphic arities and relation arguments
@@ -126,7 +128,9 @@ Class rel_fold (A:Set) :=
126128
*)
127129
Section HideMetaFold.
128130
Local Instance meta_fold {A:Set} : rel_fold A :=
129-
{ rgfold := fun R G => A }.
131+
{ rgfold := fun R G => A ;
132+
fold := fun _ _ x => x
133+
}.
130134
End HideMetaFold.
131135
Notation "{{{ e }}}" := (let mfold : forall A, rel_fold A := @meta_fold in e) (at level 50).
132136

@@ -153,6 +157,16 @@ Axiom deref : forall {A:Set}{B:Set}`{rel_fold A}{P:hpred A}{R G:hrel A}, hreflex
153157
(*Axiom deref : forall {A:Set}{P:hpred A}{R G:hrel A}, ref A P R G -> A.*)
154158
Notation "! e" := (deref _ _ e) (at level 30). (* with reflexivity, add an _ in there *)
155159

160+
(* This axiom asserts that all folds that produce the same result type operate equally on
161+
the underlying values. This is fragile if a developer specifies multiple instances for
162+
folding the same type. This is a weaker version of a more general axiom that
163+
the relationship between the results of folds of different result types depends on the
164+
relationship between results of the fold members of the instances when applied to the
165+
same value. This version is really only useful for equating identity folds with
166+
the identity meta_fold instance results. *)
167+
Axiom deref_conversion : forall (A B:Set)(f f':rel_fold A) P R G rf1 rf2 fe1 fe2,
168+
@deref A B f P R G rf1 fe1 = @deref A B f' P R G rf2 fe2.
169+
156170
Axiom ptr_eq_deref : forall A P P' R R' G G' h (p:ref{A|P}[R,G]) (r:ref{A|P'}[G',R']), p≡r -> h[p]=h[r].
157171
Hint Resolve ptr_eq_deref.
158172
Axiom ptr_eq_update : forall A P P' R R' G G' (p:ref{A|P}[R,G]) (r:ref{A|P'}[G',R']),
@@ -215,16 +229,24 @@ Global Instance ref_contains {A:Set}{P:hpred A}{R G:hrel A} : Containment (ref{A
215229

216230
(** ** Relation Folding *)
217231
Definition const_rel_fold (A:Set) (R G:hrel A) : Set := A.
218-
Global Instance nat_fold : rel_fold nat := {rgfold := const_rel_fold nat}.
219-
Global Instance bool_fold : rel_fold bool := {rgfold := const_rel_fold bool}.
220-
Global Instance unit_fold : rel_fold unit := {rgfold := const_rel_fold unit}.
232+
Definition const_id_fold {A:Set}(R G:hrel A)(x:A) := x.
233+
Global Instance nat_fold : rel_fold nat := {rgfold := const_rel_fold nat; fold := const_id_fold}.
234+
Global Instance bool_fold : rel_fold bool := {rgfold := const_rel_fold bool; fold := const_id_fold}.
235+
Global Instance unit_fold : rel_fold unit := {rgfold := const_rel_fold unit; fold := const_id_fold}.
221236
Global Instance pair_fold `{A:Set,B:Set,FA:rel_fold A,FB:rel_fold B}: rel_fold (A*B) :=
222237
{ rgfold := fun R G =>
223238
prod (rgfold (fun _ _ _ _ => True) (fun a a' h h' => forall b, G (a,b) (a',b) h h'))
224-
(rgfold (fun _ _ _ _ => True) (fun b b' h h' => forall a, G (a,b) (a,b') h h')) }.
239+
(rgfold (fun _ _ _ _ => True) (fun b b' h h' => forall a, G (a,b) (a,b') h h')) ;
240+
fold := fun R G xy => match xy with (x,y) => (fold x, fold y) end
241+
}.
225242
Global Instance ref_fold `{A:Set,P:hpred A,R:hrel A,G:hrel A} : rel_fold (ref{A|P}[R,G]) :=
226243
{ rgfold := fun R' G' => ref{A|P}[R,G ⋂ (fun a a' h h' =>
227-
forall (r:ref{A|P}[R,G]), h[r]=a -> h'[r]=a' -> G' r r h h')] }.
244+
forall (r:ref{A|P}[R,G]), h[r]=a -> h'[r]=a' -> G' r r h h')]
245+
}.
246+
(* We'll admit the runtime fold for references; the semantics for proofs will need an extensional treatment
247+
as an axiom. *)
248+
Admitted.
249+
228250
(** TODO: polymorphic lists *)
229251

230252
(** ** Reachability, containment, and folding for pure types *)
@@ -237,7 +259,7 @@ Global Instance pure_reachable `{A:Set,PA:pure_type A} : ImmediateReachability A
237259
Global Instance pure_contains `{A:Set,PA:pure_type A} : Containment A :=
238260
{ contains := fun _ => True }.
239261
Global Instance pure_fold `{A:Set,PA:pure_type A} : rel_fold A :=
240-
{ rgfold := fun _ _ => A }.
262+
{ rgfold := fun _ _ => A ; fold := const_id_fold }.
241263
Global Instance nat_pure : pure_type nat.
242264
Global Instance bool_pure : pure_type bool.
243265
Global Instance unit_pure : pure_type unit.
@@ -247,4 +269,24 @@ Global Instance list_pure `{A:Set,PA:pure_type A} : pure_type (list A).
247269
Things like heap dereference being the same between converted and unconverted references, etc. *)
248270
(** For now we need an explicit subtyping operator *)
249271
Axiom convert_P : forall {A:Set}{P P':hpred A}{R G}`{ImmediateReachability A},(forall v h, P v h -> P' v h) -> precise_pred P' -> stable P' R -> ref{A|P}[R,G] -> ref{A|P'}[R,G].
250-
Axiom conversion_P_refeq : forall h A (P P':hpred A) (R G:hrel A)`{ImmediateReachability A} pf1 pf2 pf3 x, h[(@convert_P A P P' R G _ pf1 pf2 pf3 x)]=h[x].
272+
Axiom conversion_P_refeq : forall h A (P P':hpred A) (R G:hrel A)`{ImmediateReachability A} pf1 pf2 pf3 x, h[(@convert_P A P P' R G _ pf1 pf2 pf3 x)]=h[x].
273+
Axiom convert : forall {A:Set}{P P':hpred A}{R R' G G':hrel A}`{ImmediateReachability A},
274+
ref{A|P}[R,G] ->
275+
(forall v h, P v h -> P' v h) ->
276+
(G' ⊆ G) -> (R ⊆ R') -> stable P' R' ->
277+
(G' ⊆ R') -> (* <-- self-splitting, this is a pure conversion *)
278+
ref{A|P'}[R',G'].
279+
Axiom convert_equiv : forall {A}{P P':hpred A}{R R' G G':hrel A}`{ImmediateReachability A}
280+
(r:ref{A|P}[R,G]) pfP pfG pfR stab splt,
281+
forall h, h[r]=h[@convert A P P' R R' G G' _ r pfP pfG pfR stab splt].
282+
283+
Axiom refine_ref : forall {A:Set}{P P' R G}{fld : rel_fold A}{rfl : hreflexive G}
284+
(r : ref{A|P}[R,G])
285+
(x : rgfold R G),
286+
stable P' R ->
287+
((@deref _ _ fld _ _ _ rfl (eq_refl) r) = x) -> (* <-- This is only available in special match statements, and flow is restricted! *)
288+
(forall h, (fold (h[r]))=(deref rfl (eq_refl) r) -> (deref rfl eq_refl r) = x -> P (h[r]) h -> P' (h[r]) h) ->
289+
ref{A|P'}[R,G].
290+
Axiom refinement_equiv : forall {A P P' R G}{fld : rel_fold A}{rfl : hreflexive G}
291+
(r:ref{A|P}[R,G]) x stab pf refpf,
292+
forall h, h[r] = h[@refine_ref A P P' R G fld rfl r x stab pf refpf].

RGref/DSL/Fields.v

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
Require Import RGref.DSL.DSL.
2+
Require Import Coq.Vectors.Fin.
3+
Require Import Coq.Arith.Arith.
4+
5+
(* Field Typing is a tagging mechanism, that fields of T are indexed by F *)
6+
Class FieldTyping (T : Set) (F : Set) : Set := {}.
7+
8+
Class FieldType (T : Set) (F : Set) `{FieldTyping T F} (f:F) (FT : Set) := {
9+
getF : T -> FT;
10+
setF : T -> FT -> T
11+
(* In theory we could also require a proof that it satisfies the theory
12+
of arrays, e.g. forall x v, getF (setF x v) = v. *)
13+
}.
14+
15+
(* Field-aware heap access primitives *)
16+
Axiom field_read : forall {T B F Res:Set}{P R G}`{rel_fold T}
17+
`{rgfold R G = B}
18+
`{hreflexive G}
19+
(r:ref{T|P}[R,G]) (f:F)
20+
`{FieldType B F f Res},
21+
Res.
22+
Check @getF. Check @fold. Check @setF.
23+
Axiom field_write : forall {Γ}{T F Res:Set}{P R G}{folder:rel_fold T}
24+
(r:ref{T|P}[R,G]) (f:F) (e : Res)
25+
`{FieldTyping T F}
26+
{ft:FieldType T F f Res}
27+
`{forall h v,
28+
P v h ->
29+
(forall Post ft' fte' (pf1:rgfold R G = Post) pf2 x y,
30+
@field_read T Post F Res P R G folder pf1 pf2 r f x y =
31+
@getF (@rgfold T folder R G) F ft' f Res fte' (@fold T folder R G v)) ->
32+
G v (@setF T F _ f Res ft v e) h (heap_write r (@setF T F _ f Res ft v e) h)},
33+
rgref Γ unit Γ.
34+
35+
Section FieldDemo.
36+
37+
Inductive D : Set :=
38+
mkD : nat -> bool -> D.
39+
Inductive deltaD : hrel D :=
40+
incCount : forall n n' b h h', n <= n' -> deltaD (mkD n b) (mkD n' b) h h'
41+
| setFlag : forall n h h', deltaD (mkD n false) (mkD n true) h h'.
42+
Lemma refl_deltaD : hreflexive deltaD. Proof. red. intros. destruct x. apply incCount. eauto with arith. Qed.
43+
Hint Resolve refl_deltaD.
44+
45+
(* I feel like this is reinventing lenses... *)
46+
Inductive Dfield : Set := Count | Flag.
47+
Instance dfields : FieldTyping D Dfield.
48+
Instance dfield_count : FieldType D Dfield Count nat := {
49+
getF := fun v => match v with (mkD n b) => n end;
50+
setF := fun v fv => match v with (mkD n b) => (mkD fv b) end
51+
}.
52+
Instance dfield_flag : FieldType D Dfield Flag bool := {
53+
getF := fun v => match v with (mkD n b) => b end;
54+
setF := fun v fv => match v with (mkD n b) => (mkD n fv) end
55+
}.
56+
57+
Instance pureD : pure_type D.
58+
Program Example demo {Γ} (r : ref{D|any}[deltaD,deltaD]) : rgref Γ unit Γ :=
59+
@field_write Γ D Dfield nat _ _ _ _ r Count ((@field_read _ D Dfield _ _ _ _ _ _ _ r Count _ _)+1) _ _ _.
60+
Next Obligation.
61+
unfold demo_obligation_1. unfold demo_obligation_2.
62+
(* Check @getF.
63+
cut (forall T B (v:B) F Res P R G folder pf1 pf2 r f fs fi ft ftb,
64+
@field_read T B F Res P R G folder pf1 pf2 r f fs fi =
65+
@getF B F ft f Res ftb v).
66+
intros Hfieldstuff.*)
67+
destruct v.
68+
(* rewrite Hfieldstuff.*) erewrite H0.
69+
compute. fold plus. constructor. eauto with arith.
70+
Qed.
71+
End FieldDemo.

RGref/DSL/Theories.v

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ Proof. compute. intros. inversion H2; subst; constructor. Qed.
6767
Hint Resolve optset_precise.
6868
(* TODO: Contains instance for options *)
6969
Instance option_fold {A:Set}`{rel_fold A} : rel_fold (option A) :=
70-
{ rgfold := fun R G => option (rgfold havoc (fun a a' h h' => G (Some a) (Some a') h h')) }.
70+
{ rgfold := fun R G => option (rgfold havoc (fun a a' h h' => G (Some a) (Some a') h h')) ;
71+
fold := fun R G o => match o with None => None | Some o' => Some (fold o') end
72+
}.
7173
Lemma optset_refl : forall (A:Set), hreflexive (optset A).
7274
Proof. compute; intuition; constructor. Qed.
7375
Hint Resolve optset_refl.

compile.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22
export CORE="RGref/DSL/LinearEnv.v RGref/DSL/DSL.v RGref/DSL/Theories.v RGref/DSL/Core.v RGref/DSL/Monad.v"
3-
export EXAMPLES="AppendOnlyLinkedList.v MonotonicCounter.v PrependOnlyPureList.v CounterModule.v RCC.v ReferenceImmutability.v LinkedList.v"
3+
export EXAMPLES="PosMonotonicCounter.v AppendOnlyLinkedList.v MonotonicCounter.v PrependOnlyPureList.v CounterModule.v RCC.v ReferenceImmutability.v LinkedList.v"
44
export BUGS="KnownUnsoundnessExamples.v"
55
coq_makefile -arg -impredicative-set -R RGref RGref $CORE $EXAMPLES $BUGS > Makefile
66
touch .depend

0 commit comments

Comments
 (0)