diff --git a/barrier/barrier.v b/barrier/barrier.v index 25930884e6ef1f95d06dc7f5fd3f9cd1a82b9c19..d4b3021dc968d37f721443fdbbf5c7fa053ddb08 100644 --- a/barrier/barrier.v +++ b/barrier/barrier.v @@ -1,3 +1,4 @@ +From prelude Require Export functions. From algebra Require Export upred_big_op. From program_logic Require Export sts saved_prop. From program_logic Require Import hoare. @@ -144,6 +145,46 @@ Section proof. move=>? ? EQ. rewrite /send. do 4 apply exist_ne=>?. by rewrite EQ. Qed. + Lemma waiting_split i i1 i2 Q R1 R2 P I : + i ∈ I → i1 ∉ I → i2 ∉ I → i1 ≠i2 → + (saved_prop_own i2 R2 ★ saved_prop_own i1 R1 ★ saved_prop_own i Q ★ + (Q -★ R1 ★ R2) ★ waiting P I) + ⊑ waiting P ({[i1]} ∪ ({[i2]} ∪ (I ∖ {[i]}))). + Proof. + intros. rewrite /waiting !sep_exist_l. apply exist_elim=>Ψ. + rewrite -(exist_intro (<[i1:=R1]> (<[i2:=R2]> Ψ))). + rewrite [(Π★{set _} (λ _, saved_prop_own _ _))%I](big_sepS_delete _ I i) //. + rewrite !assoc [(_ ★ (_ -★ _))%I]comm !assoc [(_ ★ ▷ _)%I]comm. + rewrite !assoc [(_ ★ saved_prop_own i _)%I]comm !assoc [(_ ★ saved_prop_own i _)%I]comm -!assoc. + rewrite 3!assoc. apply sep_mono. + - rewrite saved_prop_agree. u_strip_later. + apply wand_intro_l. rewrite [(_ ★ (_ -★ Π★{set _} _))%I]comm !assoc wand_elim_r. + rewrite (big_sepS_delete _ I i) //. + rewrite big_sepS_insert; last set_solver. + rewrite big_sepS_insert; last set_solver. + rewrite [(_ ★ Π★{set _} _)%I]comm !assoc [(_ ★ Π★{set _} _)%I]comm -!assoc. + apply sep_mono. + + apply big_sepS_mono; first done. intros j. + rewrite elem_of_difference not_elem_of_singleton. intros. + rewrite fn_lookup_insert_ne; last naive_solver. + rewrite fn_lookup_insert_ne; last naive_solver. + done. + + rewrite !fn_lookup_insert fn_lookup_insert_ne // !fn_lookup_insert !assoc. + eapply wand_apply_r'; first done. + apply: (eq_rewrite (Ψ i) Q (λ x, x)%I); last by eauto with I. + rewrite eq_sym. eauto with I. + - rewrite big_sepS_insert; last set_solver. + rewrite big_sepS_insert; last set_solver. + rewrite !assoc. apply sep_mono. + + rewrite !fn_lookup_insert fn_lookup_insert_ne // !fn_lookup_insert comm. + done. + + apply big_sepS_mono; first done. intros j. + rewrite elem_of_difference not_elem_of_singleton. intros. + rewrite fn_lookup_insert_ne; last naive_solver. + rewrite fn_lookup_insert_ne; last naive_solver. + done. + Qed. + Lemma newchan_spec (P : iProp) (Φ : val → iProp) : (heap_ctx heapN ★ ∀ l, recv l P ★ send l P -★ Φ (LocV l)) ⊑ || newchan '() {{ Φ }}. @@ -297,30 +338,80 @@ Section proof. rewrite {1}/recv /barrier_ctx. rewrite sep_exist_r. apply exist_elim=>γ. rewrite sep_exist_r. apply exist_elim=>P. rewrite sep_exist_r. apply exist_elim=>Q. rewrite sep_exist_r. - apply exist_elim=>i. + apply exist_elim=>i. rewrite -wp_pvs. (* I think some evars here are better than repeating *everything* *) eapply (sts_fsaS _ (wp_fsa _)) with (N0:=N) (γ0:=γ); simpl; eauto with I ndisj. - rewrite [(_ ★ sts_ownS _ _ _)%I]comm -!assoc. apply sep_mono_r. + rewrite !assoc [(_ ★ sts_ownS _ _ _)%I]comm -!assoc. apply sep_mono_r. apply forall_intro=>-[p I]. apply wand_intro_l. rewrite -!assoc. - apply const_elim_sep_l=>Hs. destruct p; last done. - rewrite {1}/barrier_inv =>/={Hs}. rewrite later_sep. - eapply wp_store; eauto with I ndisj. - rewrite -!assoc. apply sep_mono_r. u_strip_later. - apply wand_intro_l. rewrite -(exist_intro (State High I)). - rewrite -(exist_intro ∅). rewrite const_equiv /=; last first. - { apply rtc_once. constructor; first constructor; - rewrite /= /tok /=; set_solver. } - rewrite left_id -later_intro {2}/barrier_inv -!assoc. apply sep_mono_r. - rewrite !assoc [(_ ★ P)%I]comm !assoc -2!assoc. - apply sep_mono; last first. - { apply wand_intro_l. eauto with I. } - (* Now we come to the core of the proof: Updating from waiting to ress. *) - rewrite /waiting /ress sep_exist_l. apply exist_elim=>{Φ} Φ. - rewrite later_wand {1}(later_intro P) !assoc wand_elim_r. - rewrite big_sepS_later -big_sepS_sepS. apply big_sepS_mono'=>i. - rewrite -(exist_intro (Φ i)) comm. done. - + apply const_elim_sep_l=>Hs. rewrite -wp_pvs. wp_seq. + eapply sep_elim_True_l. + { eapply saved_prop_alloc_strong with (P0 := R1) (G := I). } + rewrite pvs_frame_r. apply pvs_strip_pvs. rewrite sep_exist_r. + apply exist_elim=>i1. rewrite always_and_sep_l. rewrite -assoc. + apply const_elim_sep_l=>Hi1. eapply sep_elim_True_l. + { eapply saved_prop_alloc_strong with (P0 := R2) (G := I ∪ {[ i1 ]}). } + rewrite pvs_frame_r. apply pvs_mono. rewrite sep_exist_r. + apply exist_elim=>i2. rewrite always_and_sep_l. rewrite -assoc. + apply const_elim_sep_l=>Hi2. + rewrite ->not_elem_of_union, elem_of_singleton in Hi2. + destruct Hi2 as [Hi2 Hi12]. change (i ∈ I) in Hs. destruct p. + (* Case I: Low state. *) + - rewrite -(exist_intro (State Low ({[i1]} ∪ ({[i2]} ∪ (I ∖ {[i]}))))). + rewrite -(exist_intro ({[Change i1 ]} ∪ {[ Change i2 ]})). + rewrite const_equiv; last first. + { apply rtc_once. constructor; first constructor; rewrite /= /tok /=; first set_solver. + (* This gets annoying... and I think I can see a pattern with all these proofs. Automatable? *) + - apply elem_of_equiv=>t. destruct t; last set_solver. + rewrite !mkSet_elem_of /change_tokens /=. + rewrite !elem_of_union !elem_of_difference !elem_of_singleton. + naive_solver. + - apply elem_of_equiv=>t. destruct t as [j|]; last set_solver. + rewrite !mkSet_elem_of /change_tokens /=. + rewrite !elem_of_union !elem_of_difference !elem_of_singleton. + destruct (decide (i1 = j)); first naive_solver. + destruct (decide (i2 = j)); first naive_solver. + destruct (decide (i = j)); naive_solver. } + rewrite left_id -later_intro {1 3}/barrier_inv. + (* FIXME ssreflect rewrite fails if there are evars around. Also, this is very slow because we don't have a proof mode. *) + rewrite -(waiting_split _ _ _ Q R1 R2); [|done..]. + match goal with | |- _ ⊑ ?G => rewrite [G]lock end. + rewrite {1}[saved_prop_own i1 _]always_sep_dup. + rewrite {1}[saved_prop_own i2 _]always_sep_dup. + rewrite !assoc [(_ ★ saved_prop_own i1 _)%I]comm. + rewrite !assoc [(_ ★ saved_prop_own i _)%I]comm. + rewrite !assoc [(_ ★ (l ↦ _))%I]comm. + rewrite !assoc [(_ ★ (waiting _ _))%I]comm. + rewrite !assoc [(_ ★ (Q -★ _))%I]comm -!assoc 5!assoc. + unlock. apply sep_mono. + + (* This should really all be handled automatically. *) + rewrite !assoc [(_ ★ (l ↦ _))%I]comm -!assoc. apply sep_mono_r. + rewrite !assoc [(_ ★ saved_prop_own i2 _)%I]comm -!assoc. apply sep_mono_r. + rewrite !assoc [(_ ★ saved_prop_own i1 _)%I]comm -!assoc. apply sep_mono_r. + rewrite !assoc [(_ ★ saved_prop_own i _)%I]comm -!assoc. apply sep_mono_r. + done. + + apply wand_intro_l. rewrite !assoc. eapply pvs_wand_r. rewrite /recv. + rewrite -(exist_intro γ) -(exist_intro P) -(exist_intro R1) -(exist_intro i1). + rewrite -(exist_intro γ) -(exist_intro P) -(exist_intro R2) -(exist_intro i2). + do 2 rewrite !(assoc (★)%I) [(_ ★ sts_ownS _ _ _)%I]comm. + rewrite -!assoc. rewrite [(sts_ownS _ _ _ ★ _ ★ _)%I]assoc -pvs_frame_r. + apply sep_mono. + * rewrite -sts_ownS_op; [|set_solver|by eauto..]. + apply sts_own_weaken; first done. + { rewrite !mkSet_elem_of /=. set_solver+. } + apply sts.closed_op; [by eauto..|set_solver|]. + apply (non_empty_inhabited (State Low ({[i1]} ∪ ({[i2]} ∪ (I ∖ {[i]}))))). + rewrite !mkSet_elem_of /=. set_solver+. + * rewrite {1}[heap_ctx _]always_sep_dup !assoc [(_ ★ heap_ctx _)%I]comm -!assoc. apply sep_mono_r. + rewrite !assoc ![(_ ★ heap_ctx _)%I]comm -!assoc. apply sep_mono_r. + rewrite {1}[sts_ctx _ _ _]always_sep_dup !assoc [(_ ★ sts_ctx _ _ _)%I]comm -!assoc. apply sep_mono_r. + rewrite !assoc ![(_ ★ sts_ctx _ _ _)%I]comm -!assoc. apply sep_mono_r. + rewrite comm. apply sep_mono_r. apply sep_intro_True_l. + { rewrite -later_intro. apply wand_intro_l. by rewrite right_id. } + apply sep_intro_True_r; first done. + { rewrite -later_intro. apply wand_intro_l. by rewrite right_id. } +(* Case II: High state *) + - Abort. Lemma recv_strengthen l P1 P2 : diff --git a/program_logic/sts.v b/program_logic/sts.v index 74010c7092e14a24ea7cb53a31b6cdb4f15dd114..e0e6c2ad11e64df9de2249217599c3d0051cb269 100644 --- a/program_logic/sts.v +++ b/program_logic/sts.v @@ -53,6 +53,14 @@ Section sts. (* The same rule as implication does *not* hold, as could be shown using sts_frag_included. *) + (* TODO: sts.closed forces the user to prove that S2 is inhabited. This is + silly, we know that S1 is inhabited since we own it, and hence S2 is + inhabited, too. Probably, sts.closed should really just be about closedness. + I think keeping disjointnes of the token stuff in there is fine, since it + does not incur any unnecessary side-conditions. + Then we additionally demand for validity that S is nonempty, rather than + making that part of "closed". + *) Lemma sts_ownS_weaken E γ S1 S2 T1 T2 : T1 ≡ T2 → S1 ⊆ S2 → sts.closed S2 T2 → sts_ownS γ S1 T1 ⊑ (|={E}=> sts_ownS γ S2 T2).