|
|
|
@ -0,0 +1,751 @@
|
|
|
|
|
From iris.prelude Require Import options.
|
|
|
|
|
From iris.proofmode Require Import tactics.
|
|
|
|
|
From iris.heap_lang Require Import lang notation.
|
|
|
|
|
From semantics.pl Require Export hoare_lib.
|
|
|
|
|
|
|
|
|
|
Import hoare.
|
|
|
|
|
Implicit Types
|
|
|
|
|
(P Q: iProp)
|
|
|
|
|
(φ ψ: Prop)
|
|
|
|
|
(e: expr)
|
|
|
|
|
(v: val).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** * Hoare logic *)
|
|
|
|
|
|
|
|
|
|
(** Entailment rules *)
|
|
|
|
|
Check ent_equiv.
|
|
|
|
|
Check ent_refl.
|
|
|
|
|
Check ent_trans.
|
|
|
|
|
(* NOTE: True = ⌜True⌝ *)
|
|
|
|
|
(* NOTE: False = ⌜False⌝ *)
|
|
|
|
|
Check ent_prove_pure.
|
|
|
|
|
Check ent_assume_pure.
|
|
|
|
|
Check ent_and_elim_r.
|
|
|
|
|
Check ent_and_elim_l.
|
|
|
|
|
Check ent_and_intro.
|
|
|
|
|
Check ent_or_introl.
|
|
|
|
|
Check ent_or_intror.
|
|
|
|
|
Check ent_or_elim.
|
|
|
|
|
Check ent_all_intro.
|
|
|
|
|
Check ent_all_elim.
|
|
|
|
|
Check ent_exist_intro.
|
|
|
|
|
Check ent_exist_elim.
|
|
|
|
|
|
|
|
|
|
(** Derived entailment rules *)
|
|
|
|
|
Lemma ent_weakening P Q R :
|
|
|
|
|
(P ⊢ R) →
|
|
|
|
|
P ∧ Q ⊢ R.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma ent_true P :
|
|
|
|
|
P ⊢ True.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma ent_false P :
|
|
|
|
|
False ⊢ P.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma ent_and_comm P Q :
|
|
|
|
|
P ∧ Q ⊢ Q ∧ P.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma ent_or_comm P Q :
|
|
|
|
|
P ∨ Q ⊢ Q ∨ P.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma ent_all_comm {X} (Φ : X → X → iProp) :
|
|
|
|
|
(∀ x y, Φ x y) ⊢ (∀ y x, Φ x y).
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma ent_exist_comm {X} (Φ : X → X → iProp) :
|
|
|
|
|
(∃ x y, Φ x y) ⊢ (∃ y x, Φ x y).
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** Derived Hoare rules *)
|
|
|
|
|
Lemma hoare_con_pre P Q Φ e:
|
|
|
|
|
(P ⊢ Q) →
|
|
|
|
|
{{ Q }} e {{ Φ }} →
|
|
|
|
|
{{ P }} e {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
intros ??. eapply hoare_con; eauto.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma hoare_con_post P Φ Ψ e:
|
|
|
|
|
(∀ v, Ψ v ⊢ Φ v) →
|
|
|
|
|
{{ P }} e {{ Ψ }} →
|
|
|
|
|
{{ P }} e {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
intros ??. eapply hoare_con; last done; eauto.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma hoare_value_con P Φ v :
|
|
|
|
|
(P ⊢ Φ v) →
|
|
|
|
|
{{ P }} v {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
intros H. eapply hoare_con; last apply hoare_value.
|
|
|
|
|
- apply H.
|
|
|
|
|
- eauto.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma hoare_value' P v :
|
|
|
|
|
{{ P }} v {{ w, P ∗ ⌜w = v⌝}}.
|
|
|
|
|
Proof.
|
|
|
|
|
eapply hoare_con; last apply hoare_value with (Φ := (λ v', P ∗ ⌜v' = v⌝)%I).
|
|
|
|
|
- etrans; first apply ent_sep_true. rewrite ent_sep_comm. apply ent_sep_split; first done.
|
|
|
|
|
by apply ent_prove_pure.
|
|
|
|
|
- done.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma hoare_rec P Φ f x e v:
|
|
|
|
|
({{ P }} subst' x v (subst' f (rec: f x := e) e) {{Φ}}) →
|
|
|
|
|
{{ P }} (rec: f x := e)%V v {{Φ}}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma hoare_let P Φ x e v:
|
|
|
|
|
({{ P }} subst' x v e {{Φ}}) →
|
|
|
|
|
{{ P }} let: x := v in e {{Φ}}.
|
|
|
|
|
Proof.
|
|
|
|
|
intros Ha. eapply hoare_pure_steps.
|
|
|
|
|
{ eapply (rtc_pure_step_fill [AppLCtx _]).
|
|
|
|
|
apply pure_step_val. done.
|
|
|
|
|
}
|
|
|
|
|
eapply hoare_pure_step; last done.
|
|
|
|
|
apply pure_step_beta.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma hoare_eq_num (n m: Z):
|
|
|
|
|
{{ ⌜n = m⌝ }} #n = #m {{ u, ⌜u = #true⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
eapply hoare_pure; first reflexivity.
|
|
|
|
|
intros ->. eapply hoare_pure_step.
|
|
|
|
|
{ apply pure_step_eq. done. }
|
|
|
|
|
apply hoare_value_con.
|
|
|
|
|
by apply ent_prove_pure.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma hoare_neq_num (n m: Z):
|
|
|
|
|
{{ ⌜n ≠ m⌝ }} #n = #m {{ u, ⌜u = #false⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma hoare_sub (z1 z2: Z):
|
|
|
|
|
{{ True }} #z1 - #z2 {{ v, ⌜v = #(z1 - z2)⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma hoare_add (z1 z2: Z):
|
|
|
|
|
{{ True }} #z1 + #z2 {{ v, ⌜v = #(z1 + z2)⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma hoare_if_false P e1 e2 Φ:
|
|
|
|
|
{{ P }} e2 {{ Φ }} →
|
|
|
|
|
({{ P }} if: #false then e1 else e2 {{ Φ }}).
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma hoare_if_true P e1 e2 Φ:
|
|
|
|
|
{{ P }} e1 {{ Φ }} →
|
|
|
|
|
({{ P }} if: #true then e1 else e2 {{ Φ }}).
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma hoare_pure_pre φ Φ e:
|
|
|
|
|
{{ ⌜φ⌝ }} e {{ Φ }} ↔ (φ → {{ True }} e {{ Φ }}).
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** Example: Fibonacci *)
|
|
|
|
|
Definition fib: val :=
|
|
|
|
|
rec: "fib" "n" :=
|
|
|
|
|
if: "n" = #0 then #0
|
|
|
|
|
else if: "n" = #1 then #1
|
|
|
|
|
else "fib" ("n" - #1) + "fib" ("n" - #2).
|
|
|
|
|
|
|
|
|
|
Lemma fib_zero:
|
|
|
|
|
{{ True }} fib #0 {{ v, ⌜v = #0⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma fib_one:
|
|
|
|
|
{{ True }} fib #1 {{ v, ⌜v = #1⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma fib_succ (z n m: Z):
|
|
|
|
|
{{ True }} fib #(z - 1)%Z {{ v, ⌜v = #n⌝ }} →
|
|
|
|
|
{{ True }} fib #(z - 2)%Z {{ v, ⌜v = #m⌝ }} →
|
|
|
|
|
{{ ⌜z > 1⌝%Z }} fib #z {{ v, ⌜v = #(n + m)⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
intros H1 H2. eapply hoare_pure_pre. intros Hgt.
|
|
|
|
|
unfold fib.
|
|
|
|
|
eapply hoare_pure_steps.
|
|
|
|
|
{ econstructor 2.
|
|
|
|
|
{ apply pure_step_beta. }
|
|
|
|
|
simpl. econstructor 2. { apply (pure_step_fill [IfCtx _ _]). apply pure_step_neq. lia. }
|
|
|
|
|
simpl. econstructor 2. { apply pure_step_if_false. }
|
|
|
|
|
econstructor 2. { apply (pure_step_fill [IfCtx _ _]). apply pure_step_neq. lia. }
|
|
|
|
|
simpl. econstructor 2. { apply pure_step_if_false. }
|
|
|
|
|
fold fib. reflexivity.
|
|
|
|
|
}
|
|
|
|
|
eapply (hoare_bind [BinOpRCtx _ _]).
|
|
|
|
|
{ eapply (hoare_bind [AppRCtx _]). { apply hoare_sub. }
|
|
|
|
|
intros v. eapply hoare_pure_pre. intros ->. apply H2.
|
|
|
|
|
}
|
|
|
|
|
intros v. apply hoare_pure_pre. intros ->. simpl.
|
|
|
|
|
eapply (hoare_bind [BinOpLCtx _ _]).
|
|
|
|
|
{ eapply (hoare_bind [AppRCtx _]). { apply hoare_sub. }
|
|
|
|
|
intros v. eapply hoare_pure_pre. intros ->. apply H1.
|
|
|
|
|
}
|
|
|
|
|
intros v. apply hoare_pure_pre. intros ->. simpl.
|
|
|
|
|
eapply hoare_pure_step. { apply pure_step_add. }
|
|
|
|
|
eapply hoare_value_con. by apply ent_prove_pure.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma fib_succ_oldschool (z n m: Z):
|
|
|
|
|
{{ True }} fib #(z - 1)%Z {{ v, ⌜v = #n⌝ }} →
|
|
|
|
|
{{ True }} fib #(z - 2)%Z {{ v, ⌜v = #m⌝ }} →
|
|
|
|
|
{{ ⌜z > 1⌝%Z }} fib #z {{ v, ⌜v = #(n + m)⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fixpoint Fib (n: nat) :=
|
|
|
|
|
match n with
|
|
|
|
|
| 0 => 0
|
|
|
|
|
| S n =>
|
|
|
|
|
match n with
|
|
|
|
|
| 0 => 1
|
|
|
|
|
| S m => Fib n + Fib m
|
|
|
|
|
end
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
Lemma fib_computes_Fib (n: nat):
|
|
|
|
|
{{ True }} fib #n {{ v, ⌜v = #(Fib n)⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
induction (lt_wf n) as [n _ IH].
|
|
|
|
|
destruct n as [|[|n]].
|
|
|
|
|
- simpl. eapply fib_zero.
|
|
|
|
|
- simpl. eapply fib_one.
|
|
|
|
|
- replace (Fib (S (S n)): Z) with (Fib (S n) + Fib n)%Z by (simpl; lia).
|
|
|
|
|
edestruct (hoare_pure_pre (S (S n) > 1))%Z as [H1 _]; eapply H1; last lia.
|
|
|
|
|
eapply fib_succ.
|
|
|
|
|
+ replace (S (S n) - 1)%Z with (S n: Z) by lia. eapply IH. lia.
|
|
|
|
|
+ replace (S (S n) - 2)%Z with (n: Z) by lia. eapply IH. lia.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
(** ** Example: gcd *)
|
|
|
|
|
Definition mod_val : val :=
|
|
|
|
|
λ: "a" "b", "a" - ("a" `quot` "b") * "b".
|
|
|
|
|
Definition euclid: val :=
|
|
|
|
|
rec: "euclid" "a" "b" :=
|
|
|
|
|
if: "b" = #0 then "a" else "euclid" "b" (mod_val "a" "b").
|
|
|
|
|
|
|
|
|
|
Lemma quot_diff a b :
|
|
|
|
|
(0 ≤ a)%Z → (0 < b)%Z → (0 ≤ a - a `quot` b * b < b)%Z.
|
|
|
|
|
Proof.
|
|
|
|
|
intros. split.
|
|
|
|
|
- rewrite Z.mul_comm -Z.rem_eq; last lia. apply Z.rem_nonneg; lia.
|
|
|
|
|
- rewrite Z.mul_comm -Z.rem_eq; last lia.
|
|
|
|
|
specialize (Z.rem_bound_pos_pos a b ltac:(lia) ltac:(lia)). lia.
|
|
|
|
|
Qed.
|
|
|
|
|
Lemma Z_nonneg_ind (P : Z → Prop) :
|
|
|
|
|
(∀ x, (0 ≤ x)%Z → (∀ y, (0 ≤ y < x)%Z → P y) → P x) →
|
|
|
|
|
∀ x, (0 ≤ x)%Z → P x.
|
|
|
|
|
Proof.
|
|
|
|
|
intros IH x Hle. generalize Hle.
|
|
|
|
|
revert x Hle. refine (Z_lt_induction (λ x, (0 ≤ x)%Z → P x) _).
|
|
|
|
|
naive_solver.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma mod_spec (a b : Z) :
|
|
|
|
|
{{ ⌜(b > 0)%Z⌝ ∧ ⌜(a >= 0)%Z⌝ }}
|
|
|
|
|
mod_val #a #b
|
|
|
|
|
{{ cv, ∃ (c k : Z), ⌜cv = #c ∧ (0 <= k)%Z ∧ (a = b * k + c)%Z ∧ (0 <= c < b)%Z⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
eapply (hoare_pure _ (b > 0 ∧ a >= 0)%Z).
|
|
|
|
|
{ eapply ent_assume_pure. { eapply ent_and_elim_l. }
|
|
|
|
|
intros ?. eapply ent_assume_pure. { eapply ent_and_elim_r. }
|
|
|
|
|
intros ?. eapply ent_assume_pure. { eapply ent_and_elim_l. }
|
|
|
|
|
intros ?. apply ent_prove_pure. done.
|
|
|
|
|
}
|
|
|
|
|
intros (? & ?).
|
|
|
|
|
unfold mod_val. eapply hoare_pure_step.
|
|
|
|
|
{ apply pure_step_fill with (K := [AppLCtx _]). apply pure_step_beta. }
|
|
|
|
|
fold mod_val. simpl.
|
|
|
|
|
apply hoare_let. simpl.
|
|
|
|
|
eapply hoare_pure_step.
|
|
|
|
|
{ apply pure_step_fill with (K := [BinOpLCtx _ _; BinOpRCtx _ _]).
|
|
|
|
|
apply pure_step_quot. lia.
|
|
|
|
|
}
|
|
|
|
|
simpl. eapply hoare_pure_step.
|
|
|
|
|
{ apply pure_step_fill with (K := [BinOpRCtx _ _]). apply pure_step_mul. }
|
|
|
|
|
simpl. eapply hoare_pure_step.
|
|
|
|
|
{ apply pure_step_sub. }
|
|
|
|
|
eapply hoare_value_con.
|
|
|
|
|
eapply ent_exist_intro. apply ent_exist_intro with (x := (a `quot` b)%Z).
|
|
|
|
|
(* MATH *)
|
|
|
|
|
apply ent_prove_pure. split; last split; last split.
|
|
|
|
|
- reflexivity.
|
|
|
|
|
- apply Z.quot_pos; lia.
|
|
|
|
|
- lia.
|
|
|
|
|
- apply quot_diff; lia.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma gcd_step (b c k : Z) :
|
|
|
|
|
Z.gcd b c = Z.gcd (b * k + c) b.
|
|
|
|
|
Proof.
|
|
|
|
|
rewrite Z.add_comm (Z.gcd_comm _ b) Z.mul_comm Z.gcd_add_mult_diag_r. done.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma euclid_step_gt0 (a b : Z) :
|
|
|
|
|
(∀ c : Z,
|
|
|
|
|
{{ ⌜(0 ≤ c < b)%Z⌝}}
|
|
|
|
|
euclid #b #c
|
|
|
|
|
{{ d, ⌜d = #(Z.gcd b c)⌝ }}) →
|
|
|
|
|
{{ ⌜(b > 0)%Z⌝ ∧ ⌜(a >= 0)%Z⌝}} euclid #a #b {{ c, ⌜c = #(Z.gcd a b)⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
intros Ha.
|
|
|
|
|
eapply (hoare_pure _ (a >= 0 ∧ b > 0)%Z).
|
|
|
|
|
{ eapply ent_assume_pure. { eapply ent_and_elim_l. }
|
|
|
|
|
intros ?. eapply ent_assume_pure. { eapply ent_and_elim_r. }
|
|
|
|
|
intros ?. eapply ent_assume_pure. { eapply ent_and_elim_l. }
|
|
|
|
|
intros ?. apply ent_prove_pure. done.
|
|
|
|
|
}
|
|
|
|
|
intros (? & ?).
|
|
|
|
|
unfold euclid. eapply hoare_pure_step.
|
|
|
|
|
{ apply (pure_step_fill [AppLCtx _]). apply pure_step_beta. }
|
|
|
|
|
fold euclid. simpl. apply hoare_let. simpl.
|
|
|
|
|
eapply hoare_pure_step.
|
|
|
|
|
{ apply (pure_step_fill [IfCtx _ _]). apply pure_step_neq. lia. }
|
|
|
|
|
simpl. apply hoare_if_false.
|
|
|
|
|
|
|
|
|
|
eapply hoare_bind with (K := [AppRCtx _]).
|
|
|
|
|
{ apply mod_spec. }
|
|
|
|
|
intros v. simpl.
|
|
|
|
|
apply hoare_exist_pre. intros d.
|
|
|
|
|
apply hoare_exist_pre. intros k.
|
|
|
|
|
apply hoare_pure_pre.
|
|
|
|
|
intros (-> & ? & -> & ?).
|
|
|
|
|
eapply hoare_con; last apply Ha.
|
|
|
|
|
{ apply ent_prove_pure. split_and!; lia. }
|
|
|
|
|
{ simpl. intros v. eapply ent_assume_pure; first done. intros ->.
|
|
|
|
|
apply ent_prove_pure. f_equiv. f_equiv. apply gcd_step.
|
|
|
|
|
}
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma euclid_step_0 (a : Z) :
|
|
|
|
|
{{ True }} euclid #a #0 {{ v, ⌜v = #a⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
unfold euclid. eapply hoare_pure_step.
|
|
|
|
|
{ apply (pure_step_fill [AppLCtx _]). apply pure_step_beta. }
|
|
|
|
|
fold euclid. simpl. apply hoare_let. simpl.
|
|
|
|
|
eapply hoare_pure_step.
|
|
|
|
|
{ apply (pure_step_fill [IfCtx _ _]). apply pure_step_eq. lia. }
|
|
|
|
|
simpl. apply hoare_if_true.
|
|
|
|
|
apply hoare_value_con. by apply ent_prove_pure.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Lemma euclid_proof (a b : Z) :
|
|
|
|
|
{{ ⌜(0 ≤ a ∧ 0 ≤ b)%Z⌝ }} euclid #a #b {{ c, ⌜c = #(Z.gcd a b)⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
eapply hoare_pure_pre. intros (Ha & Hb).
|
|
|
|
|
revert b Hb a Ha. refine (Z_nonneg_ind _ _).
|
|
|
|
|
intros b Hb IH a Ha.
|
|
|
|
|
destruct (decide (b = 0)) as [ -> | Hneq0].
|
|
|
|
|
- eapply hoare_con; last apply euclid_step_0.
|
|
|
|
|
{ done. }
|
|
|
|
|
{ intros v. simpl. eapply ent_assume_pure; first done. intros ->.
|
|
|
|
|
apply ent_prove_pure.
|
|
|
|
|
rewrite Z.gcd_0_r Z.abs_eq; first done. lia.
|
|
|
|
|
}
|
|
|
|
|
- (* use a mod b < b *)
|
|
|
|
|
eapply hoare_con; last apply euclid_step_gt0.
|
|
|
|
|
{ apply ent_and_intro; apply ent_prove_pure; lia. }
|
|
|
|
|
{ done. }
|
|
|
|
|
intros c. apply hoare_pure_pre. intros.
|
|
|
|
|
eapply hoare_con; last eapply IH; [ done | done | lia.. ].
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
(** Exercise: Factorial *)
|
|
|
|
|
Definition fac : val :=
|
|
|
|
|
rec: "fac" "n" :=
|
|
|
|
|
if: "n" = #0 then #1
|
|
|
|
|
else "n" * "fac" ("n" - #1).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fixpoint Fac (n : nat) :=
|
|
|
|
|
match n with
|
|
|
|
|
| 0 => 1
|
|
|
|
|
| S n => (S n) * Fac n
|
|
|
|
|
end.
|
|
|
|
|
Lemma fac_computes_Fac (n : nat) :
|
|
|
|
|
{{ True }} fac #n {{ v, ⌜v = #(Fac n)⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** * Separation Logic *)
|
|
|
|
|
(*Check ent_sep_weaken.*)
|
|
|
|
|
(*Check ent_sep_true.*)
|
|
|
|
|
(*Check ent_sep_comm.*)
|
|
|
|
|
(*Check ent_sep_split.*)
|
|
|
|
|
(*Check ent_sep_assoc.*)
|
|
|
|
|
(*Check ent_pointsto_sep.*)
|
|
|
|
|
(*Check ent_exists_sep.*)
|
|
|
|
|
|
|
|
|
|
(* Note: The separating conjunction can usually be typed with \ast or \sep *)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma ent_pointsto_disj l l' v w :
|
|
|
|
|
l ↦ v ∗ l' ↦ w ⊢ ⌜l ≠ l'⌝.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma ent_sep_exists {X} (Φ : X → iProp) P :
|
|
|
|
|
(∃ x : X, Φ x ∗ P) ⊣⊢ (∃ x : X, Φ x) ∗ P.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** ** Example: Chains *)
|
|
|
|
|
Fixpoint chain_pre n l r : iProp :=
|
|
|
|
|
match n with
|
|
|
|
|
| 0 => ⌜l = r⌝
|
|
|
|
|
| S n => ∃ t : loc, l ↦ #t ∗ chain_pre n t r
|
|
|
|
|
end.
|
|
|
|
|
Definition chain l r : iProp := ∃ n, ⌜n > 0⌝ ∗ chain_pre n l r.
|
|
|
|
|
|
|
|
|
|
Lemma chain_single (l r : loc) :
|
|
|
|
|
l ↦ #r ⊢ chain l r.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma chain_cons (l r t : loc) :
|
|
|
|
|
l ↦ #r ∗ chain r t ⊢ chain l t.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma chain_trans (l r t : loc) :
|
|
|
|
|
chain l r ∗ chain r t ⊢ chain l t.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma chain_sep_false (l r t : loc) :
|
|
|
|
|
chain l r ∗ chain l t ⊢ False.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Definition cycle l := chain l l.
|
|
|
|
|
Lemma chain_cycle l r :
|
|
|
|
|
chain l r ∗ chain r l ⊢ cycle l.
|
|
|
|
|
Proof.
|
|
|
|
|
apply chain_trans.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** New Hoare rules *)
|
|
|
|
|
(*Check hoare_frame.*)
|
|
|
|
|
(*Check hoare_new.*)
|
|
|
|
|
(*Check hoare_store.*)
|
|
|
|
|
(*Check hoare_load.*)
|
|
|
|
|
|
|
|
|
|
Lemma hoare_pure_pre_sep_l (ϕ : Prop) Q Φ e :
|
|
|
|
|
(ϕ → {{ Q }} e {{ Φ }}) →
|
|
|
|
|
{{ ⌜ϕ⌝ ∗ Q }} e {{ Φ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
intros He.
|
|
|
|
|
eapply hoare_pure.
|
|
|
|
|
{ apply ent_sep_weaken. }
|
|
|
|
|
intros ?.
|
|
|
|
|
eapply hoare_con; last by apply He.
|
|
|
|
|
- rewrite ent_sep_comm. apply ent_sep_weaken.
|
|
|
|
|
- done.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
(* Enables rewriting with equivalences ⊣⊢ in pre/post condition *)
|
|
|
|
|
#[export] Instance hoare_proper :
|
|
|
|
|
Proper (equiv ==> eq ==> (pointwise_relation val (⊢)) ==> impl) hoare.
|
|
|
|
|
Proof.
|
|
|
|
|
intros P1 P2 HP%ent_equiv e1 e2 <- Φ1 Φ2 HΦ Hp.
|
|
|
|
|
eapply hoare_con; last done.
|
|
|
|
|
- apply HP.
|
|
|
|
|
- done.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
Definition assert e := (if: e then #() else #0 #0)%E.
|
|
|
|
|
|
|
|
|
|
Lemma hoare_assert P e :
|
|
|
|
|
{{ P }} e {{ v, ⌜v = #true⌝ }} →
|
|
|
|
|
{{ P }} assert e {{ v, ⌜v = #()⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma frame_example (f : val) :
|
|
|
|
|
(∀ l l' : loc, {{ l ↦ #0 }} f #l #l' {{ _, l ↦ #42 }}) →
|
|
|
|
|
{{ True }}
|
|
|
|
|
let: "x" := ref #0 in
|
|
|
|
|
let: "y" := ref #42 in
|
|
|
|
|
(f "x" "y";;
|
|
|
|
|
assert (!"x" = !"y"))
|
|
|
|
|
{{ _, True }}.
|
|
|
|
|
Proof.
|
|
|
|
|
intros Hf.
|
|
|
|
|
eapply hoare_bind with (K := [AppRCtx _]).
|
|
|
|
|
{ apply hoare_new. }
|
|
|
|
|
intros v. simpl.
|
|
|
|
|
apply hoare_exist_pre. intros l.
|
|
|
|
|
apply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
eapply hoare_let. simpl.
|
|
|
|
|
|
|
|
|
|
eapply hoare_bind with (K := [AppRCtx _]).
|
|
|
|
|
{ eapply hoare_con_pre. { apply ent_sep_true. }
|
|
|
|
|
eapply hoare_frame. apply hoare_new. }
|
|
|
|
|
intros v. simpl.
|
|
|
|
|
|
|
|
|
|
rewrite -ent_sep_exists. apply hoare_exist_pre. intros l'.
|
|
|
|
|
rewrite -ent_sep_assoc. eapply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
eapply hoare_let. simpl.
|
|
|
|
|
eapply hoare_bind with (K := [AppRCtx _]).
|
|
|
|
|
{ rewrite ent_sep_comm. eapply hoare_frame. apply Hf. }
|
|
|
|
|
intros v. simpl.
|
|
|
|
|
|
|
|
|
|
apply hoare_let. simpl.
|
|
|
|
|
eapply hoare_con_post; first last.
|
|
|
|
|
{ apply hoare_assert.
|
|
|
|
|
eapply hoare_bind with (K := [BinOpRCtx _ _]).
|
|
|
|
|
{ rewrite ent_sep_comm. apply hoare_frame. apply hoare_load. }
|
|
|
|
|
intros v'. simpl. rewrite -ent_sep_assoc. apply hoare_pure_pre_sep_l.
|
|
|
|
|
intros ->.
|
|
|
|
|
|
|
|
|
|
eapply hoare_bind with (K := [BinOpLCtx _ _]).
|
|
|
|
|
{ rewrite ent_sep_comm. apply hoare_frame. apply hoare_load. }
|
|
|
|
|
intros v'. simpl. rewrite -ent_sep_assoc. apply hoare_pure_pre_sep_l.
|
|
|
|
|
intros ->.
|
|
|
|
|
|
|
|
|
|
eapply hoare_pure_step. { by apply pure_step_eq. }
|
|
|
|
|
eapply hoare_value_con. by apply ent_prove_pure.
|
|
|
|
|
}
|
|
|
|
|
intros. apply ent_true.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
(** Exercise: swap *)
|
|
|
|
|
Definition swap : val :=
|
|
|
|
|
λ: "l" "r", let: "t" := ! "r" in "r" <- !"l";; "l" <- "t".
|
|
|
|
|
|
|
|
|
|
Lemma swap_correct (l r: loc) (v w: val):
|
|
|
|
|
{{ l ↦ v ∗ r ↦ w }} swap #l #r {{ _, l ↦ w ∗ r ↦ v }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** ** Case study: lists *)
|
|
|
|
|
Fixpoint is_ll (xs : list val) (v : val) : iProp :=
|
|
|
|
|
match xs with
|
|
|
|
|
| [] => ⌜v = NONEV⌝
|
|
|
|
|
| x :: xs =>
|
|
|
|
|
∃ (l : loc) (w : val),
|
|
|
|
|
⌜v = SOMEV #l⌝ ∗ l ↦ (x, w) ∗ is_ll xs w
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
Definition new_ll : val :=
|
|
|
|
|
λ: <>, NONEV.
|
|
|
|
|
|
|
|
|
|
Definition cons_ll : val :=
|
|
|
|
|
λ: "h" "l", SOME (ref ("h", "l")).
|
|
|
|
|
|
|
|
|
|
Definition head_ll : val :=
|
|
|
|
|
λ: "x", match: "x" with NONE => #() | SOME "r" => Fst (!"r") end.
|
|
|
|
|
Definition tail_ll : val :=
|
|
|
|
|
λ: "x", match: "x" with NONE => #() | SOME "r" => Snd (!"r") end.
|
|
|
|
|
|
|
|
|
|
Definition len_ll : val :=
|
|
|
|
|
rec: "len" "x" := match: "x" with NONE => #0 | SOME "r" => #1 + "len" (Snd !"r") end.
|
|
|
|
|
|
|
|
|
|
Definition app_ll : val :=
|
|
|
|
|
rec: "app" "x" "y" :=
|
|
|
|
|
match: "x" with NONE => "y" | SOME "r" =>
|
|
|
|
|
let: "rs" := !"r" in
|
|
|
|
|
"r" <- (Fst "rs", "app" (Snd "rs") "y");;
|
|
|
|
|
SOME "r"
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma app_ll_correct xs ys v w :
|
|
|
|
|
{{ is_ll xs v ∗ is_ll ys w }} app_ll v w {{ u, is_ll (xs ++ ys) u }}.
|
|
|
|
|
Proof.
|
|
|
|
|
induction xs as [ | x xs IH] in v |-*.
|
|
|
|
|
- simpl. apply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
eapply hoare_bind with (K := [AppLCtx _]).
|
|
|
|
|
{ apply hoare_rec. simpl.
|
|
|
|
|
eapply hoare_pure_steps.
|
|
|
|
|
{ apply pure_step_val. done. }
|
|
|
|
|
eapply hoare_value'.
|
|
|
|
|
}
|
|
|
|
|
intros v'. simpl. rewrite ent_sep_comm. apply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
|
|
|
|
|
apply hoare_rec. simpl.
|
|
|
|
|
eapply hoare_pure_step. { apply pure_step_match_injl. }
|
|
|
|
|
apply hoare_let. simpl. apply hoare_value.
|
|
|
|
|
- simpl. rewrite -ent_sep_exists. apply hoare_exist_pre.
|
|
|
|
|
intros l. rewrite -ent_sep_exists. apply hoare_exist_pre.
|
|
|
|
|
intros w'. rewrite -ent_sep_assoc. apply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
|
|
|
|
|
eapply hoare_bind with (K := [AppLCtx _ ]).
|
|
|
|
|
{ apply hoare_rec. simpl.
|
|
|
|
|
eapply hoare_pure_steps. {apply pure_step_val. done. }
|
|
|
|
|
eapply hoare_value'.
|
|
|
|
|
}
|
|
|
|
|
intros v'. simpl. rewrite ent_sep_comm. apply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
|
|
|
|
|
apply hoare_rec. simpl.
|
|
|
|
|
eapply hoare_pure_step. {apply pure_step_match_injr. }
|
|
|
|
|
apply hoare_let. simpl.
|
|
|
|
|
eapply hoare_bind with (K := [AppRCtx _]).
|
|
|
|
|
{ apply hoare_frame. apply hoare_frame. apply hoare_load. }
|
|
|
|
|
intros v. simpl.
|
|
|
|
|
rewrite -!ent_sep_assoc. apply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
apply hoare_let. simpl.
|
|
|
|
|
|
|
|
|
|
eapply hoare_bind with (K := [PairRCtx _; StoreRCtx _; AppRCtx _]).
|
|
|
|
|
{ eapply hoare_bind with (K := [AppRCtx _; AppLCtx _]).
|
|
|
|
|
{ eapply hoare_pure_step. { apply pure_step_snd. }
|
|
|
|
|
apply hoare_value'.
|
|
|
|
|
}
|
|
|
|
|
intros v. simpl. fold app_ll.
|
|
|
|
|
rewrite ent_sep_comm. apply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
rewrite ent_sep_comm. eapply hoare_frame.
|
|
|
|
|
apply IH.
|
|
|
|
|
}
|
|
|
|
|
intros v. simpl.
|
|
|
|
|
eapply hoare_bind with (K := [PairLCtx _; StoreRCtx _; AppRCtx _]).
|
|
|
|
|
{ eapply hoare_pure_step. { apply pure_step_fst. }
|
|
|
|
|
apply hoare_value'.
|
|
|
|
|
}
|
|
|
|
|
intros v'. simpl. rewrite ent_sep_comm. apply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
eapply hoare_bind with (K := [AppRCtx _]).
|
|
|
|
|
{ rewrite ent_sep_comm. apply hoare_frame.
|
|
|
|
|
eapply hoare_bind with (K := [StoreRCtx _]).
|
|
|
|
|
{ eapply hoare_pure_steps.
|
|
|
|
|
{ eapply pure_step_val. eauto. }
|
|
|
|
|
eapply hoare_value'.
|
|
|
|
|
}
|
|
|
|
|
intros v'. simpl. rewrite ent_sep_comm. apply hoare_pure_pre_sep_l. intros ->.
|
|
|
|
|
apply hoare_store.
|
|
|
|
|
}
|
|
|
|
|
intros v'. simpl. apply hoare_let. simpl.
|
|
|
|
|
eapply hoare_pure_steps.
|
|
|
|
|
{ eapply pure_step_val. eauto. }
|
|
|
|
|
eapply hoare_value_con.
|
|
|
|
|
eapply ent_exist_intro. eapply ent_exist_intro.
|
|
|
|
|
etrans. { apply ent_sep_true. }
|
|
|
|
|
eapply ent_sep_split.
|
|
|
|
|
{ apply ent_prove_pure. done. }
|
|
|
|
|
apply ent_sep_split; reflexivity.
|
|
|
|
|
Qed.
|
|
|
|
|
|
|
|
|
|
(** Exercise: linked lists *)
|
|
|
|
|
Lemma new_ll_correct :
|
|
|
|
|
{{ True }} new_ll #() {{ v, is_ll [] v }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma cons_ll_correct (v x : val) xs :
|
|
|
|
|
{{ is_ll xs v }} cons_ll x v {{ u, is_ll (x :: xs) u }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma head_ll_correct (v x : val) xs :
|
|
|
|
|
{{ is_ll (x :: xs) v }} head_ll v {{ w, ⌜w = x⌝ }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma tail_ll_correct v x xs :
|
|
|
|
|
{{ is_ll (x :: xs) v }} tail_ll v {{ w, is_ll xs w }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Lemma len_ll_correct v xs :
|
|
|
|
|
{{ is_ll xs v }} len_ll v {{ w, ⌜w = #(length xs)⌝ ∗ is_ll xs v }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* TODO: exercise *)
|
|
|
|
|
Admitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** Exercise: State and prove a strengthened specification for [tail]. *)
|
|
|
|
|
Lemma tail_ll_strengthened v x xs :
|
|
|
|
|
{{ is_ll (x :: xs) v }} tail_ll v {{ w, False (* FIXME *) }}.
|
|
|
|
|
Proof.
|
|
|
|
|
(* FIXME: exercise *)
|
|
|
|
|
Abort.
|
|
|
|
|
|