Skip to content

Commit 9027174

Browse files
vzalivaolympichekcp526
authored
Finished proof automation of PredicateRequest for struct with folding (using hints). (#58)
* Simplify folding hints * Implement struct folding automation * Ensure use of the right context in hints simplification * bump up Coq version. fixes #63 --------- Co-authored-by: Valerii Huhnin <33845529+olympichek@users.noreply.github.com> Co-authored-by: Christopher Pulte <cp526@cam.ac.uk>
1 parent bd7a483 commit 9027174

File tree

4 files changed

+215
-47
lines changed

4 files changed

+215
-47
lines changed

coq/Cn/BaseTypes.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ Lemma option_eq_dec {A : Type}
152152
forall (o1 o2 : option A), {o1 = o2} + {o1 <> o2}.
153153
Proof.
154154
decide equality.
155-
Qed.
155+
Defined.
156156

157157
Module BasetTypes_t_as_MiniDecidableType <: MiniDecidableType.
158158
Definition t := t.

coq/Reasoning/ProofAutomation.v

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Qed.
9393

9494

9595
(* [struct_resource_inference_step] constructor pre-condition proof *)
96-
Ltac2 prove_struct_resource_inference_step () :=
96+
Ltac2 prove_struct_resource_inference_step (log_entry:constr) :=
9797
match! goal with
9898
| [ |- exists field_res,
9999
unfold_all _ _ field_res /\
@@ -113,7 +113,12 @@ Qed.
113113
Std.split false NoBindings;
114114
Control.focus 1 1 (fun () =>
115115
(* Proof using computational reflection: *)
116-
Control.shelve ()
116+
ltac1:(apply unfold_all_singleton_eq);
117+
ltac1:(log_entry |- apply unfold_all_explicit_eq with (unfold_changed := (get_hints_from_log_entry log_entry)))
118+
(Ltac1.of_constr log_entry);
119+
ltac1:(apply unfold_all_explicit_fun_eq);
120+
ltac1:(vm_compute);
121+
ltac1:(reflexivity)
117122
); (* unfold predicate *)
118123
Control.focus 1 1 (fun () =>
119124
pairwise_decidability (constr:(Resource_as_MiniDecidableType.eq_dec)) in_res_list ;
@@ -160,34 +165,38 @@ Ltac2 prove_unfold_step (hints:constr) :=
160165
Predicate.pointer := _; Predicate.iargs := _
161166
|}
162167
_ ?hints _) ] =>
163-
verbose_msg (smsg "Checking PredicateRequest for Struct");
164-
verbose_print_constr " Situation: " s;
165-
verbose_print_constr " Predicate symbol name: " isym;
166-
let lhints := destruct_list (constr:(log_entry)) hints in
167-
verbose_msg (Message.concat (Message.of_string " Number of hints: ") (Message.of_int (List.length lhints)));
168-
Std.constructor_n false 3 NoBindings; (* apply struct_resource_inference_step *)
169-
Control.focus 1 1 (fun () => Std.reflexivity ());
170-
Control.focus 1 1 (fun () => Std.reflexivity ());
171-
Control.focus 1 1 (fun () => Std.reflexivity ());
172-
Control.focus 1 1 (fun () => Std.reflexivity ());
173-
Control.focus 1 1 (fun () => Std.reflexivity ());
174-
Control.focus 1 1 (fun () => Std.reflexivity ());
175-
Control.focus 1 1 (fun () => Std.reflexivity ());
176-
Control.focus 1 1 (fun () =>
177-
let clause := { on_hyps := None; on_concl := AllOccurrences } in
178-
Std.unfold [(const_to_const_reference constr:(@ctx_resources_set), AllOccurrences)] clause;
179-
Std.cbn
180-
{ rStrength := Std.Norm;
181-
rBeta := true;
182-
rMatch := true;
183-
rFix := true;
184-
rCofix := true;
185-
rZeta := true;
186-
rDelta := true;
187-
rConst := [const_to_const_reference constr:(@set_from_list); const_to_const_reference constr:(@Sym.map_from_list)]
188-
} clause ;
189-
prove_struct_resource_inference_step ()
190-
)
168+
match! goal with
169+
| [ |- log_entry_valid ?log_entry ] =>
170+
verbose_msg (smsg "Checking PredicateRequest for Struct");
171+
verbose_print_constr " Situation: " s;
172+
verbose_print_constr " Predicate symbol name: " isym;
173+
let lhints := destruct_list (constr:(log_entry)) hints in
174+
verbose_msg (Message.concat (Message.of_string " Number of hints: ") (Message.of_int (List.length lhints)));
175+
Std.constructor_n false 3 NoBindings; (* apply struct_resource_inference_step *)
176+
Control.focus 1 1 (fun () => Std.reflexivity ());
177+
Control.focus 1 1 (fun () => Std.reflexivity ());
178+
Control.focus 1 1 (fun () => Std.reflexivity ());
179+
Control.focus 1 1 (fun () => Std.reflexivity ());
180+
Control.focus 1 1 (fun () => Std.reflexivity ());
181+
Control.focus 1 1 (fun () => Std.reflexivity ());
182+
Control.focus 1 1 (fun () => Std.reflexivity ());
183+
Control.focus 1 1 (fun () =>
184+
let clause := { on_hyps := None; on_concl := AllOccurrences } in
185+
Std.unfold [(const_to_const_reference constr:(@ctx_resources_set), AllOccurrences)] clause;
186+
Std.cbn
187+
{ rStrength := Std.Norm;
188+
rBeta := true;
189+
rMatch := true;
190+
rFix := true;
191+
rCofix := true;
192+
rZeta := true;
193+
rDelta := true;
194+
rConst := [const_to_const_reference constr:(@set_from_list); const_to_const_reference constr:(@Sym.map_from_list)]
195+
} clause ;
196+
prove_struct_resource_inference_step log_entry
197+
)
198+
end
199+
191200
(* PredicateRequest for non-Struct *)
192201
| [ |- log_entry_valid (PredicateRequest _ ?s ?p _ _ _)] =>
193202
(* PredicateRequest case *)

coq/Reasoning/ResourceInference.v

Lines changed: 157 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ Import ListNotations.
1515
Inductive provable (g:Global.t): LCSet.t -> LogicalConstraints.t -> Prop :=
1616
| solvable_SMT: forall lc it, provable g lc it.
1717

18+
(* Helper function to get a list of resources from the contex *)
19+
Definition ctx_resources_list (l: (list (Resource.t * Z)) * Z) : list Resource.t :=
20+
List.map fst (fst l).
21+
1822
(* Helper function to get a set of resources from the contex *)
19-
Definition ctx_resources_set (l:((list (Resource.t * Z)) * Z)) : ResSet.t
20-
:=
21-
Resource.set_from_list (List.map fst (fst l)).
23+
Definition ctx_resources_set (l: (list (Resource.t * Z)) * Z) : ResSet.t :=
24+
Resource.set_from_list (ctx_resources_list l).
2225

2326
Inductive term_is_struct: Terms.term BaseTypes.t -> Prop :=
2427
| term_is_struct_intro: forall tag fields,
@@ -521,6 +524,34 @@ Inductive unfold_one (globals:Global.t): Resource.t -> ResSet.t -> Prop :=
521524
iout)
522525
out_res.
523526

527+
Definition apply_for_subsumed (iinit: init) (f : init -> bool) : bool :=
528+
match iinit with
529+
| Init => f Init
530+
| Uninit => f Uninit || f Init
531+
end.
532+
533+
Lemma apply_for_subsumed_spec:
534+
forall iinit f t, apply_for_subsumed iinit f = true ->
535+
exists iinit', subsumed (Owned t iinit) (Owned t iinit') /\ f iinit' = true.
536+
Proof.
537+
intros iinit f t H.
538+
unfold apply_for_subsumed in H.
539+
destruct iinit.
540+
- exists Init; split.
541+
+ apply Subsumed_equal.
542+
reflexivity.
543+
+ apply H.
544+
- apply orb_true_iff in H as [H | H].
545+
+ exists Uninit; split.
546+
* apply Subsumed_equal.
547+
reflexivity.
548+
* apply H.
549+
+ exists Init; split.
550+
* apply Subsumed_owned.
551+
reflexivity.
552+
* apply H.
553+
Qed.
554+
524555
(* Computable version of unfold_one predicate *)
525556
Definition unfold_one_fun (globals:Global.t) (r : Resource.t) (out_res: list Resource.t) : bool :=
526557
match r with
@@ -532,9 +563,10 @@ Definition unfold_one_fun (globals:Global.t) (r : Resource.t) (out_res: list Res
532563
match SymMap.find isym globals.(Global.struct_decls) with
533564
| Some sdecl =>
534565
(List.length sdecl =? List.length out_res) &&
535-
List.forallb
536-
(fun '(piece, r) => struct_piece_to_resource_fun piece iinit ipointer iargs isym iout r)
537-
(List.combine sdecl out_res)
566+
apply_for_subsumed iinit (fun iinit' =>
567+
List.forallb
568+
(fun '(piece, r) => struct_piece_to_resource_fun piece iinit' ipointer iargs isym iout r)
569+
(List.combine sdecl out_res))
538570
| None => false
539571
end
540572
| _ => false
@@ -559,9 +591,10 @@ Proof.
559591
apply SymMap.find_2 in Hf.
560592
assert (piece_def : Memory.struct_piece) by (repeat constructor).
561593
assert (res_def : Resource.t) by (repeat constructor).
562-
eapply unfold_one_struct with (iinit' := i).
563-
{ apply Subsumed_equal.
564-
reflexivity. }
594+
apply apply_for_subsumed_spec with (t := Struct s) in H.
595+
destruct H as [i' [Hi H]].
596+
eapply unfold_one_struct with (iinit' := i').
597+
{ apply Hi. }
565598
{ apply Hf. }
566599
intros r; split.
567600
- intros Hr.
@@ -616,6 +649,87 @@ Inductive unfold_all (globals:Global.t): ResSet.t -> ResSet.t -> Prop :=
616649
ResSet.Equal input output ->
617650
unfold_all globals input output.
618651

652+
Lemma unfold_one_Proper : Proper (eq ==> eq ==> ResSet.Equal ==> iff) unfold_one.
653+
Proof.
654+
intros globals globals' Hglobals r r' Hr rs rs' Hrs.
655+
subst r' globals'.
656+
enough (forall r rs rs', ResSet.Equal rs rs' -> unfold_one globals r rs -> unfold_one globals r rs') as H.
657+
{ split; intros H1.
658+
- eapply H.
659+
+ apply Hrs.
660+
+ apply H1.
661+
- eapply H.
662+
+ symmetry; apply Hrs.
663+
+ apply H1. }
664+
clear.
665+
intros r rs rs' Hrs H.
666+
inversion H; subst; clear H.
667+
econstructor; eauto.
668+
intros r; split; intros Hr.
669+
- apply H2.
670+
eapply ResSetDecide.F.In_m.
671+
+ reflexivity.
672+
+ apply Hrs.
673+
+ apply Hr.
674+
- eapply ResSetDecide.F.In_m.
675+
+ reflexivity.
676+
+ symmetry.
677+
apply Hrs.
678+
+ apply H2, Hr.
679+
Qed.
680+
681+
Lemma unfold_all_Proper : Proper (eq ==> ResSet.Equal ==> ResSet.Equal ==> iff) unfold_all.
682+
Proof.
683+
intros globals globals' Hglobals r1 r1' Hr1 r2 r2' Hr2.
684+
subst globals'.
685+
enough (forall r1 r1' r2 r2', ResSet.Equal r1 r1' -> ResSet.Equal r2 r2' ->
686+
unfold_all globals r1 r2 -> unfold_all globals r1' r2') as H.
687+
{ split; intros H1.
688+
- eapply H.
689+
+ apply Hr1.
690+
+ apply Hr2.
691+
+ apply H1.
692+
- eapply H.
693+
+ symmetry; apply Hr1.
694+
+ symmetry; apply Hr2.
695+
+ apply H1. }
696+
clear.
697+
intros r1 r1' r2 r2' Hr1 Hr2 H.
698+
revert r1' r2' Hr1 Hr2.
699+
induction H; intros r1' r2' Hr1 Hr2.
700+
- eapply unfold_all_step with (input' := input').
701+
+ apply Hr1, H.
702+
+ apply H0.
703+
+ ResSetDecide.fsetdec.
704+
+ apply IHunfold_all.
705+
* reflexivity.
706+
* apply Hr2.
707+
- apply unfold_all_fixpoint.
708+
+ intros H1.
709+
apply H.
710+
destruct H1 as [r [Hr H1]].
711+
exists r; split; try assumption.
712+
apply Hr1, Hr.
713+
+ transitivity input.
714+
{ apply Equivalence_Symmetric, Hr1. }
715+
transitivity output.
716+
{ apply H0. }
717+
apply Hr2.
718+
Qed.
719+
720+
Lemma unfold_all_singleton_eq:
721+
forall globals r output,
722+
unfold_all globals (Resource.set_from_list [r]) output <->
723+
unfold_all globals (ResSet.singleton r) output.
724+
Proof.
725+
intros globals r output.
726+
eapply unfold_all_Proper.
727+
- reflexivity.
728+
- cbn.
729+
ResSetDecide.fsetdec.
730+
- reflexivity.
731+
Qed.
732+
619733
(* A version of `unfold_all`, using hints *)
620734
Inductive unfold_all_explicit (globals:Global.t):
621735
list (Resource.t * unpack_result) -> ResSet.t -> ResSet.t -> Prop :=
@@ -746,6 +860,40 @@ Qed.
746860
Definition unfold_step_flatten (l : list unfold_step): unfold_changed :=
747861
List.concat (List.map fst l).
748862

863+
Definition get_resources_from_log (log_entries : log) : list Resource.t :=
864+
List.fold_right (fun log_entry rs =>
865+
match log_entry with
866+
| PredicateRequest _ _ _ (p, o) _ _ => (Request.P p, o) :: rs
867+
| UnfoldResources _ _ _ _ => rs (* probably shouldn't happen *)
868+
end) [] log_entries.
869+
870+
Definition resource_set_init (r : Resource.t) : Resource.t :=
871+
match r with
872+
| (Request.P {| Predicate.name := Request.Owned t _;
873+
Predicate.pointer := p;
874+
Predicate.iargs := args |}, out) =>
875+
(Request.P {| Predicate.name := Request.Owned t Init;
876+
Predicate.pointer := p;
877+
Predicate.iargs := args |}, out)
878+
| r => r
879+
end.
880+
881+
Definition resource_set_correct_init_status (c : Context.t) (r : Resource.t) : Resource.t :=
882+
if List.existsb (fun r' => bool_of_sum (Resource_as_DecidableType.eq_dec r r')) (ctx_resources_list c.(resources))
883+
then r
884+
else resource_set_init r.
885+
886+
Fixpoint get_hints_from_log_entry (log_entry : log_entry) : unfold_changed :=
887+
match log_entry with
888+
| PredicateRequest _ _ _ _ [] _ => []
889+
| PredicateRequest ic _ _ (p, o) log_entries _ =>
890+
let r := (Request.P p, o) in
891+
let unfolded_r := List.map (resource_set_correct_init_status ic) (get_resources_from_log log_entries) in
892+
let hints_inner := List.concat (List.map get_hints_from_log_entry log_entries) in
893+
(r, UnpackRES unfolded_r) :: hints_inner
894+
| UnfoldResources _ _ _ _ => [] (* probably shouldn't happen *)
895+
end.
896+
749897
(** Inductive predicate which defines correctness of resource unfolding step *)
750898
Inductive unfold_step : Context.t -> Context.t -> Prop :=
751899
| simple_unfold_step:

lib/resourceInference.ml

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ module General = struct
399399
| _ ->
400400
let@ ftyp, rw_time, l' =
401401
parametric_ftyp_args_request_step
402-
resource_request
402+
(resource_request ~simplify_prooflog:true)
403403
IT.subst
404404
loc
405405
uiinfo
@@ -412,24 +412,35 @@ module General = struct
412412
loop ftyp [] []
413413

414414

415-
and resource_request loc uiinfo (request : Req.t)
415+
and resource_request ?(simplify_prooflog = false) loc uiinfo (request : Req.t)
416416
: (Resource.t * int list * Prooflog.log) option m
417417
=
418418
match request with
419419
| P request ->
420420
let@ c = get_typing_context () in
421421
let@ result = predicate_request loc uiinfo request in
422422
let@ c' = get_typing_context () in
423+
let@ simp_ctxt = simp_ctxt () in
423424
return
424425
(Option.map
425-
(fun ((p, o), changed_or_deleted, l) ->
426+
(fun ((p, Resource.O o), changed_or_deleted, l) ->
426427
let hints =
427-
if Prooflog.is_enabled () then
428-
[ Prooflog.PredicateRequest (c, fst uiinfo, request, (p, o), l, c') ]
428+
if Prooflog.is_enabled () then (
429+
let p, o =
430+
if not simplify_prooflog then
431+
(p, o)
432+
else (
433+
let p = Simplify.Request.Predicate.simp simp_ctxt p in
434+
let o = Simplify.IndexTerms.simp simp_ctxt o in
435+
(p, o))
436+
in
437+
[ Prooflog.PredicateRequest
438+
(c, fst uiinfo, request, (p, Resource.O o), l, c')
439+
])
429440
else
430441
[]
431442
in
432-
((Req.P p, o), changed_or_deleted, hints))
443+
((Req.P p, Resource.O o), changed_or_deleted, hints))
433444
result)
434445
| Q request ->
435446
let@ result = qpredicate_request loc uiinfo request in
@@ -447,7 +458,7 @@ module General = struct
447458
let ftyp_args_request_step rt_subst loc situation original_resources ftyp =
448459
let@ rt, _rw_time, l =
449460
parametric_ftyp_args_request_step
450-
resource_request
461+
(resource_request ~simplify_prooflog:false)
451462
rt_subst
452463
loc
453464
situation

0 commit comments

Comments
 (0)