(** Formal Reasoning About Programs * Chapter 15: Connecting to Real-World Programming Languages and Platforms * Author: Adam Chlipala * License: https://creativecommons.org/licenses/by-nc-nd/4.0/ *) Require Import FrapWithoutSets SepCancel. Require Import Arith.Div2. (** * Some odds and ends from past chapters *) Notation "m $! k" := (match m $? k with Some n => n | None => O end) (at level 30). Ltac simp := repeat (simplify; subst; propositional; try match goal with | [ H : ex _ |- _ ] => invert H end); try linear_arithmetic. (** * Bitvectors of known length *) Inductive word : nat -> Set := | WO : word O | WS : bool -> forall {n}, word n -> word (S n). Fixpoint wordToNat {sz} (w : word sz) : nat := match w with | WO => O | WS false w => 2 * wordToNat w | WS true w => S (2 * wordToNat w) end. Fixpoint mod2 (n : nat) : bool := match n with | 0 => false | 1 => true | S (S n') => mod2 n' end. Fixpoint natToWord (sz n : nat) : word sz := match sz with | O => WO | S sz' => WS (mod2 n) (natToWord sz' (div2 n)) end. Definition wzero {sz} := natToWord sz 0. Definition wone {sz} := natToWord sz 1. Notation "^" := (natToWord _) (at level 0). Definition wplus {sz} (w1 w2 : word sz) : word sz := natToWord sz (wordToNat w1 + wordToNat w2). Infix "^+" := wplus (at level 50, left associativity). Definition whd {sz} (w : word (S sz)) : bool := match w in word sz' return match sz' with | O => unit | S _ => bool end with | WO => tt | WS b _ => b end. Definition wtl {sz} (w : word (S sz)) : word sz := match w in word sz' return match sz' with | O => unit | S sz'' => word sz'' end with | WO => tt | WS _ w' => w' end. Lemma shatter_word : forall {n} (a : word n), match n return word n -> Prop with | O => fun a => a = WO | S _ => fun a => a = WS (whd a) (wtl a) end a. Proof. destruct a; eauto. Qed. Lemma shatter_word_S : forall {n} (a : word (S n)), exists b, exists c, a = WS b c. Proof. intros; repeat eexists; apply (shatter_word a). Qed. Lemma shatter_word_0 : forall a : word 0, a = WO. Proof. intros; apply (shatter_word a). Qed. Hint Resolve shatter_word_0. Require Import Coq.Logic.Eqdep_dec. Definition weq : forall {sz} (x y : word sz), {x = y} + {x <> y}. refine (fix weq sz (x : word sz) : forall y : word sz, {x = y} + {x <> y} := match x in word sz return forall y : word sz, {x = y} + {x <> y} with | WO => fun _ => left _ _ | WS b x' => fun y => if bool_dec b (whd y) then if weq _ x' (wtl y) then left _ _ else right _ _ else right _ _ end); clear weq. symmetry; apply shatter_word_0. subst; symmetry; apply (shatter_word y). rewrite (shatter_word y); simpl; intro; injection H; intros; apply n0; apply inj_pair2_eq_dec in H0; [ auto | apply eq_nat_dec ]. abstract (rewrite (shatter_word y); simpl; intro; apply n0; injection H; auto). Defined. (** * A simple C-like language with just two data types *) Module Type BIT_WIDTH. Parameter bit_width : nat. End BIT_WIDTH. Module DeeplyEmbedded(Import BW : BIT_WIDTH). Definition wrd := word bit_width. Inductive exp := | Var (x : var) | Const (n : wrd) | Add (x : var) (n : wrd) | Head (x : var) | Tail (x : var) | NotNull (x : var). Inductive stmt := | Skip | Assign (x : var) (e : exp) | WriteHead (x : var) (e : exp) | WriteTail (x : var) (e : exp) | Seq (s1 s2 : stmt) | IfThenElse (e : exp) (s1 s2 : stmt) | WhileLoop (e : exp) (s1 : stmt). Inductive type := | Scalar | ListPointer (t : type). Definition type_eq : forall t1 t2 : type, {t1 = t2} + {t1 <> t2}. decide equality. Defined. Record function := { Params : list (var * type); Locals : list (var * type); Return : type; Body : stmt }. Section fn. Variable fn : function. Definition vars := Params fn ++ Locals fn ++ [("result", Return fn)]. Fixpoint varType (x : var) (vs : list (var * type)) : option type := match vs with | nil => None | (y, t) :: vs' => if y ==v x then Some t else varType x vs' end. Fixpoint expType (e : exp) : option type := match e with | Var x => varType x vars | Const _ => Some Scalar | Add x _ => match varType x vars with | Some Scalar => Some Scalar | _ => None end | Head x => match varType x vars with | Some (ListPointer t) => Some t | _ => None end | Tail x => match varType x vars with | Some (ListPointer t) => Some (ListPointer t) | _ => None end | NotNull x => match varType x vars with | Some (ListPointer _) => Some Scalar | _ => None end end. Fixpoint stmtWf (s : stmt) : bool := match s with | Skip => true | Assign x e => match varType x vars, expType e with | Some t1, Some t2 => if type_eq t1 t2 then true else false | _, _ => false end | WriteHead x e => match varType x vars, expType e with | Some (ListPointer t1), Some t2 => if type_eq t1 t2 then true else false | _, _ => false end | WriteTail x e => match varType x vars, expType e with | Some (ListPointer t1), Some (ListPointer t2) => if type_eq t1 t2 then true else false | _, _ => false end | Seq s1 s2 => stmtWf s1 && stmtWf s2 | IfThenElse e s1 s2 => match expType e with | Some Scalar => stmtWf s1 && stmtWf s2 | _ => false end | WhileLoop e s1 => match expType e with | Some Scalar => stmtWf s1 | _ => false end end. Record functionWf : Prop := { VarsOk : NoDup (map fst (Params fn ++ Locals fn)); BodyOk : stmtWf (Body fn) = true }. End fn. Inductive value := | VScalar (n : wrd) | VList (p : wrd). Definition heap := fmap (wrd) (value * value). Definition valuation := fmap var value. Inductive eval : heap -> valuation -> exp -> value -> Prop := | VVar : forall H V x v, V $? x = Some v -> eval H V (Var x) v | VConst : forall H V n, eval H V (Const n) (VScalar n) | VAdd : forall H V x n xn, V $? x = Some (VScalar xn) -> eval H V (Add x n) (VScalar (xn ^+ n)) | VHead : forall H V x p ph pt, V $? x = Some (VList p) -> H $? p = Some (ph, pt) -> eval H V (Head x) ph | VTail : forall H V x p ph pt, V $? x = Some (VList p) -> H $? p = Some (ph, pt) -> eval H V (Tail x) pt | VNotNull : forall H V x p, V $? x = Some (VList p) -> eval H V (NotNull x) (VScalar (if weq p (^0) then ^1 else ^0)). Inductive step : heap * valuation * stmt -> heap * valuation * stmt -> Prop := | StAssign : forall H V x e v, eval H V e v -> step (H, V, Assign x e) (H, V $+ (x, v), Skip) | StWriteHead : forall H V x e a v hv tv, V $? x = Some (VList a) -> eval H V e v -> H $? a = Some (hv, tv) -> step (H, V, WriteHead x e) (H $+ (a, (v, tv)), V, Skip) | StWriteTail : forall H V x e a v hv tv, V $? x = Some (VList a) -> eval H V e v -> H $? a = Some (hv, tv) -> step (H, V, WriteTail x e) (H $+ (a, (hv, v)), V, Skip) | StSeq1 : forall H V s2, step (H, V, Seq Skip s2) (H, V, s2) | StSeq2 : forall H V s1 s2 H' V' s1', step (H, V, s1) (H', V', s1') -> step (H, V, Seq s1 s2) (H', V', Seq s1' s2) | StIfThen : forall H V e s1 s2 n, eval H V e (VScalar n) -> n <> ^0 -> step (H, V, IfThenElse e s1 s2) (H, V, s1) | StIfElse : forall H V e s1 s2, eval H V e (VScalar (^0)) -> step (H, V, IfThenElse e s1 s2) (H, V, s2) | StWhileTrue : forall H V e s1 n, eval H V e (VScalar n) -> n <> ^0 -> step (H, V, WhileLoop e s1) (H, V, Seq s1 (WhileLoop e s1)) | StWhileFalse : forall H V e s1, eval H V e (VScalar (^0)) -> step (H, V, WhileLoop e s1) (H, V, Skip). (** * Separation logic for our language *) Module Import S <: SEP. Definition hprop := heap -> Prop. Definition himp (p q : hprop) := forall h, p h -> q h. Definition heq (p q : hprop) := forall h, p h <-> q h. Definition lift (P : Prop) : hprop := fun h => P /\ h = $0. Definition star (p q : hprop) : hprop := fun h => exists h1 h2, split h h1 h2 /\ disjoint h1 h2 /\ p h1 /\ q h2. Definition exis {A} (p : A -> hprop) : hprop := fun h => exists x, p x h. Notation "[| P |]" := (lift P) : sep_scope. Infix "*" := star : sep_scope. Notation "'exists' x .. y , p" := (exis (fun x => .. (exis (fun y => p)) ..)) : sep_scope. Delimit Scope sep_scope with sep. Notation "p === q" := (heq p%sep q%sep) (no associativity, at level 70). Notation "p ===> q" := (himp p%sep q%sep) (no associativity, at level 70). Local Open Scope sep_scope. Lemma iff_two : forall A (P Q : A -> Prop), (forall x, P x <-> Q x) -> (forall x, P x -> Q x) /\ (forall x, Q x -> P x). Proof. firstorder. Qed. Local Ltac t := (unfold himp, heq, lift, star, exis; propositional; subst); repeat (match goal with | [ H : forall x, _ <-> _ |- _ ] => apply iff_two in H | [ H : ex _ |- _ ] => cases H | [ H : split _ _ $0 |- _ ] => apply split_empty_fwd in H end; propositional; subst); eauto 15. Theorem himp_heq : forall p q, p === q <-> (p ===> q /\ q ===> p). Proof. t. Qed. Theorem himp_refl : forall p, p ===> p. Proof. t. Qed. Theorem himp_trans : forall p q r, p ===> q -> q ===> r -> p ===> r. Proof. t. Qed. Theorem lift_left : forall p (Q : Prop) r, (Q -> p ===> r) -> p * [| Q |] ===> r. Proof. t. Qed. Theorem lift_right : forall p q (R : Prop), p ===> q -> R -> p ===> q * [| R |]. Proof. t. Qed. Hint Resolve split_empty_bwd'. Theorem extra_lift : forall (P : Prop) p, P -> p === [| P |] * p. Proof. t. apply split_empty_fwd' in H1; subst; auto. Qed. Theorem star_comm : forall p q, p * q === q * p. Proof. t. Qed. Theorem star_assoc : forall p q r, p * (q * r) === (p * q) * r. Proof. t. Qed. Theorem star_cancel : forall p1 p2 q1 q2, p1 ===> p2 -> q1 ===> q2 -> p1 * q1 ===> p2 * q2. Proof. t. Qed. Theorem exis_gulp : forall A p (q : A -> _), p * exis q === exis (fun x => p * q x). Proof. t. Qed. Theorem exis_left : forall A (p : A -> _) q, (forall x, p x ===> q) -> exis p ===> q. Proof. t. Qed. Theorem exis_right : forall A p (q : A -> _) x, p ===> q x -> p ===> exis q. Proof. t. Qed. End S. Export S. Module Import Se := SepCancel.Make(S). Definition heap1 (a : wrd) (p : value * value) : heap := $0 $+ (a, p). Definition ptsto (a : wrd) (p : value * value) : hprop := fun h => h = heap1 a p. (* Helpful notations, some the same as above *) Notation "[| P |]" := (lift P) : sep_scope. Notation emp := (lift True). Infix "*" := star : sep_scope. Notation "'exists' x .. y , p" := (exis (fun x => .. (exis (fun y => p)) ..)) : sep_scope. Delimit Scope sep_scope with sep. Notation "p === q" := (heq p%sep q%sep) (no associativity, at level 70). Notation "p ===> q" := (himp p%sep q%sep) (no associativity, at level 70). Infix "|->" := ptsto (at level 30) : sep_scope. (** * Finally, the Hoare logic *) Definition hassert := valuation -> hprop. Inductive hoare_triple_exp : hassert -> exp -> (value -> hassert) -> Prop := | HtVar : forall x, hoare_triple_exp (fun V => exists v, [| V $? x = Some v |])%sep (Var x) (fun r V => [| V $? x = Some r |])%sep | HtConst : forall n, hoare_triple_exp (fun _ => emp)%sep (Const n) (fun r _ => [| r = VScalar n |])%sep | HtAdd : forall x n, hoare_triple_exp (fun V => exists xn, [| V $? x = Some (VScalar xn) |])%sep (Add x n) (fun r V => exists xn, [| V $? x = Some (VScalar xn) |] * [| r = VScalar (xn ^+ n) |])%sep | HtHead : forall R x, hoare_triple_exp (fun V => exists a, [| V $? x = Some (VList a) |] * exists p, a |-> p * R p)%sep (Head x) (fun r V => exists a, [| V $? x = Some (VList a) |] * exists vt, a |-> (r, vt) * R (r, vt))%sep | HtTail : forall R x, hoare_triple_exp (fun V => exists a, [| V $? x = Some (VList a) |] * exists p, a |-> p * R p)%sep (Tail x) (fun r V => exists a, [| V $? x = Some (VList a) |] * exists vh, a |-> (vh, r) * R (vh, r))%sep | HtNotNull : forall x, hoare_triple_exp (fun V => exists a, [| V $? x = Some (VList a) |])%sep (NotNull x) (fun r V => exists a, [| V $? x = Some (VList a) |] * [| r = VScalar (if weq a (^0) then ^1 else ^0) |])%sep | HtExpConsequence : forall P e Q P' Q', hoare_triple_exp P e Q -> (forall V, P' V ===> P V) -> (forall r V, Q r V ===> Q' r V) -> hoare_triple_exp P' e Q' | HtExpFrame : forall P e Q R, hoare_triple_exp P e Q -> hoare_triple_exp (fun V => P V * R V)%sep e (fun r V => Q r V * R V)%sep. Fixpoint couldChange (s : stmt) (x : var) : bool := match s with | Skip => false | Assign y _ => if y ==v x then true else false | WriteHead _ _ | WriteTail _ _ => false | Seq s1 s2 => couldChange s1 x || couldChange s2 x | IfThenElse _ s1 s2 => couldChange s1 x || couldChange s2 x | WhileLoop _ s1 => couldChange s1 x end. Inductive hoare_triple : hassert -> stmt -> hassert -> Prop := | HtSkip : forall P, hoare_triple P Skip P | HtAssign : forall P x e Q, hoare_triple_exp P e Q -> hoare_triple P (Assign x e) (fun V => exists V' r, Q r V' * [| V = V' $+ (x, r) |])%sep | HtWriteHead : forall P x e R, hoare_triple_exp P e (fun r V => exists a, [| V $? x = Some (VList a) |] * exists vhd vtl, a |-> (vhd, vtl) * R r vhd vtl V)%sep -> hoare_triple P (WriteHead x e) (fun V => exists a, [| V $? x = Some (VList a) |] * exists r vhd vtl, a |-> (r, vtl) * R r vhd vtl V)%sep | HtWriteTail : forall P x e R, hoare_triple_exp P e (fun r V => exists a, [| V $? x = Some (VList a) |] * exists vhd vtl, a |-> (vhd, vtl) * R r vhd vtl V)%sep -> hoare_triple P (WriteTail x e) (fun V => exists a, [| V $? x = Some (VList a) |] * exists r vhd vtl, a |-> (vhd, r) * R r vhd vtl V)%sep | HtSeq : forall P s1 Q s2 R, hoare_triple P s1 Q -> hoare_triple Q s2 R -> hoare_triple P (Seq s1 s2) R | HtIfThenElse : forall P e s1 s2 Q R, hoare_triple_exp P e (fun r V => Q r V * exists n, [| r = VScalar n |])%sep -> hoare_triple (fun V => exists n, Q (VScalar n) V * [| n <> ^0 |])%sep s1 R -> hoare_triple (fun V => Q (VScalar (^0)) V)%sep s2 R -> hoare_triple P (IfThenElse e s1 s2) R | HtWhileLoop : forall I e s1 Q, hoare_triple_exp I e (fun r V => Q r V * exists n, [| r = VScalar n |])%sep -> hoare_triple (fun V => exists n, Q (VScalar n) V * [| n <> ^0 |])%sep s1 I -> hoare_triple I (WhileLoop e s1) (Q (VScalar (^0))) | HtConsequence : forall P s Q P' Q', hoare_triple P s Q -> (forall V, P' V ===> P V) -> (forall V, Q V ===> Q' V) -> hoare_triple P' s Q' | HtFrame : forall P s Q R, hoare_triple P s Q -> (forall V1 V2, (forall x, couldChange s x = false -> V1 $? x = V2 $? x) -> R V1 = R V2) -> hoare_triple (fun V => P V * R V)%sep s (fun V => Q V * R V)%sep. Notation "{{ V1 ~> P }} c {{ V2 ~> Q }}" := (hoare_triple (fun V1 => P%sep) c (fun V2 => Q%sep)) (at level 90, c at next level). Lemma HtStrengthen : forall P s Q Q', hoare_triple P s Q -> (forall V, Q V ===> Q' V) -> hoare_triple P s Q'. Proof. simplify. eapply HtConsequence; eauto. reflexivity. Qed. Lemma HtWeaken : forall P s Q P', hoare_triple P s Q -> (forall V, P' V ===> P V) -> hoare_triple P' s Q. Proof. simplify. eapply HtConsequence; eauto. reflexivity. Qed. Definition trsys_of (H : heap) (V : valuation) (s : stmt) := {| Initial := constant [(H, V, s)]; Step := step |}. Hint Constructors hoare_triple_exp hoare_triple eval step. Lemma eval_subheap : forall H V e r, eval H V e r -> forall H', (forall a v, H $? a = Some v -> H' $? a = Some v) -> eval H' V e r. Proof. invert 1; simplify; eauto. Qed. Lemma drop_cells : forall P e Q, hoare_triple_exp P e Q -> forall V H r, eval H V e r -> forall H', P V H' -> (forall a v, H' $? a = Some v -> H $? a = Some v) -> eval H' V e r. Proof. induct 1; simplify. invert H0; auto. invert H0; auto. invert H0; auto. invert H0. invert H1. invert H0; simp. invert H3. apply split_empty_fwd' in H1; subst. invert H6. invert H1; simp. econstructor. eassumption. cases (x2 $? x0). apply H2 in Heq. replace p0 with (r, pt) by equality. eauto. unfold split in H3; subst. unfold ptsto in H6; subst. unfold heap1 in Heq. rewrite lookup_join1 in Heq by (simplify; sets). simplify; equality. invert H0. invert H1. invert H0; simp. invert H3. apply split_empty_fwd' in H1; subst. invert H6. invert H1; simp. econstructor. eassumption. cases (x2 $? x0). apply H2 in Heq. replace p0 with (ph, r) by equality. eauto. unfold split in H3; subst. unfold ptsto in H6; subst. unfold heap1 in Heq. rewrite lookup_join1 in Heq by (simplify; sets). simplify; equality. invert H0; auto. eapply IHhoare_triple_exp; eauto. apply H0; auto. invert H2; simp. eapply IHhoare_triple_exp in H1. 2: eauto. eapply eval_subheap; eauto. simplify. unfold split in H4; subst. rewrite lookup_join1 by eauto using lookup_Some_dom. auto. simplify. unfold split in H4; subst. apply H3. rewrite lookup_join1 by eauto using lookup_Some_dom. auto. Qed. Lemma preservation_exp : forall P e Q, hoare_triple_exp P e Q -> forall V H r, P V H -> eval H V e r -> Q r V H. Proof. induct 1; simplify. invert H1. cases H0. cases H0. constructor; assumption. invert H1. invert H0. constructor; reflexivity. invert H1. invert H0. invert H1. eexists. exists $0, $0; propositional; eauto. constructor; eauto. constructor; equality. invert H1. invert H0. invert H1. simp. invert H2. invert H5. cases x1. replace r with v. exists x0. exists $0, H; propositional; eauto. constructor; auto. exists v0. apply split_empty_fwd' in H0; equality. invert H2; simp. unfold split in H5; subst. unfold ptsto in H6; subst. apply split_empty_fwd' in H0; subst. replace x0 with p in * by equality. unfold heap1 in H7. simplify. rewrite lookup_join1 in H7. simplify; equality. simplify; sets. invert H1. invert H0. invert H1. simp. invert H2. invert H5. cases x1. replace r with v0. exists x0. exists $0, H; propositional; eauto. constructor; auto. exists v. apply split_empty_fwd' in H0; equality. invert H2; simp. unfold split in H5; subst. unfold ptsto in H6; subst. apply split_empty_fwd' in H0; subst. replace x0 with p in * by equality. unfold heap1 in H7. simplify. rewrite lookup_join1 in H7. simplify; equality. simplify; sets. invert H1. invert H0. invert H1. exists p, $0, $0; propositional; eauto. constructor; auto. constructor; auto. unfold himp in *; eauto. invert H1; simp. exists x, x0; propositional; eauto. eapply IHhoare_triple_exp; eauto. eapply drop_cells; eauto. simplify. unfold split in H3; subst. rewrite lookup_join1 by eauto using lookup_Some_dom. auto. Qed. Opaque heq himp lift star exis ptsto. Lemma invert_Assign : forall P x e Q, hoare_triple P (Assign x e) Q -> exists Q', hoare_triple_exp P e Q' /\ forall V r, Q' r V ===> Q (V $+ (x, r)). Proof. induct 1; propositional; eauto. do 2 eexists. eassumption. simplify. do 2 eapply exis_right. cancel. first_order. do 2 eexists. eapply HtExpConsequence. eassumption. assumption. reflexivity. etransitivity; eauto. first_order. do 2 eexists. eapply HtExpFrame. eassumption. simplify. rewrite H0 with (V1 := V) (V2 := V $+ (x, r)). rewrite H2. reflexivity. simplify. cases (x ==v x1); simplify; equality. Qed. Lemma invert_WriteHead : forall P x e Q, hoare_triple P (WriteHead x e) Q -> exists R, hoare_triple_exp P e (fun r V => exists a, [| V $? x = Some (VList a) |] * exists vhd vtl, a |-> (vhd, vtl) * R r vhd vtl V)%sep /\ (forall V, (exists a, [| V $? x = Some (VList a) |] * exists r vhd vtl, a |-> (r, vtl) * R r vhd vtl V) ===> Q V). Proof. induct 1; first_order; eauto. do 2 eexists. eassumption. reflexivity. do 2 eexists. eapply HtExpConsequence. eassumption. assumption. simplify. reflexivity. etransitivity; eauto. exists (fun r vhd vtl V => x0 r vhd vtl V * R V)%sep. propositional. eapply HtExpConsequence with (Q := fun r V => ((exists a, [|V $? x = Some (VList a)|] * exists vhd vtl, a |-> (vhd, vtl) * x0 r vhd vtl V) * R V)%sep). eapply HtExpFrame. eassumption. reflexivity. cancel. rewrite <- H2. cancel. Qed. Lemma invert_WriteTail : forall P x e Q, hoare_triple P (WriteTail x e) Q -> exists R, hoare_triple_exp P e (fun r V => exists a, [| V $? x = Some (VList a) |] * exists vhd vtl, a |-> (vhd, vtl) * R r vhd vtl V)%sep /\ (forall V, (exists a, [| V $? x = Some (VList a) |] * exists r vhd vtl, a |-> (vhd, r) * R r vhd vtl V) ===> Q V). Proof. induct 1; first_order; eauto. do 2 eexists. eassumption. reflexivity. do 2 eexists. eapply HtExpConsequence. eassumption. assumption. simplify. reflexivity. etransitivity; eauto. exists (fun r vhd vtl V => x0 r vhd vtl V * R V)%sep. propositional. eapply HtExpConsequence with (Q := fun r V => ((exists a, [|V $? x = Some (VList a)|] * exists vhd vtl, a |-> (vhd, vtl) * x0 r vhd vtl V) * R V)%sep). eapply HtExpFrame. eassumption. reflexivity. cancel. rewrite <- H2. cancel. Qed. Lemma invert_Skip : forall P Q, hoare_triple P Skip Q -> forall V, P V ===> Q V. Proof. induct 1; simplify. reflexivity. do 2 (etransitivity; eauto). rewrite IHhoare_triple. reflexivity. Qed. Lemma invert_Seq : forall P s1 s2 Q, hoare_triple P (Seq s1 s2) Q -> exists R, hoare_triple P s1 R /\ hoare_triple R s2 Q. Proof. induct 1; simplify; first_order. do 2 eexists. eapply HtConsequence; eauto; reflexivity. eapply HtConsequence; eauto; reflexivity. do 2 eexists. eapply HtFrame; eauto. simplify. apply H0. simplify. apply orb_false_elim in H4; propositional; eauto. eapply HtFrame; eauto. simplify. apply H0. simplify. apply orb_false_elim in H4; propositional; eauto. Qed. Lemma invert_IfThenElse : forall P e s1 s2 Q, hoare_triple P (IfThenElse e s1 s2) Q -> exists R, hoare_triple_exp P e (fun r V => R r V * exists n, [| r = VScalar n |])%sep /\ hoare_triple (fun V => exists n, R (VScalar n) V * [| n <> ^0 |])%sep s1 Q /\ hoare_triple (fun V => R (VScalar (^0)) V)%sep s2 Q. Proof. induct 1; simplify; first_order. eexists; propositional. eapply HtExpConsequence. eassumption. assumption. simplify. reflexivity. eapply HtStrengthen. eassumption. assumption. eapply HtStrengthen. eassumption. assumption. exists (fun r V => x r V * R V)%sep; propositional. eapply HtExpConsequence. eapply HtExpFrame. eauto. simplify. reflexivity. simplify. cancel. eauto. eapply HtWeaken. eapply HtFrame. eassumption. simplify. apply H0. simplify. apply orb_false_elim in H5; propositional; eauto. simplify. cancel. eapply HtFrame. assumption. simplify. apply H0. simplify. apply orb_false_elim in H5; propositional; eauto. Qed. Lemma invert_WhileLoop : forall P e s1 Q, hoare_triple P (WhileLoop e s1) Q -> exists I R, (forall V, P V ===> I V) /\ hoare_triple_exp I e (fun r V => R r V * exists n, [| r = VScalar n |])%sep /\ hoare_triple (fun V => exists n, R (VScalar n) V * [| n <> ^0 |])%sep s1 I /\ (forall V, R (VScalar (^0)) V ===> Q V). Proof. induct 1; simplify; first_order. do 2 eexists; propositional; eauto; reflexivity. exists x, x0; propositional. etransitivity; eauto. etransitivity; eauto. exists (fun V => x V * R V)%sep, (fun r V => x0 r V * R V)%sep; propositional. rewrite H1; reflexivity. eapply HtExpConsequence. eapply HtExpFrame. eauto. simplify. reflexivity. simplify. cancel. eauto. eapply HtWeaken. eauto. simplify. cancel. rewrite H4. reflexivity. Qed. Transparent heq himp lift star exis ptsto. Lemma preservation : forall s H V s' V' H', step (H, V, s) (H', V', s') -> forall Q, hoare_triple (fun V' H' => H' = H /\ V' = V) s Q -> hoare_triple (fun V'' H'' => H'' = H' /\ V'' = V') s' Q. Proof. induct 1; simplify. apply invert_Assign in H; simp. eapply preservation_exp in H0; eauto. eapply HtWeaken. auto. unfold himp; simplify. propositional; subst. apply H2; assumption. simplify; auto. apply invert_WriteHead in H3; simp. eapply preservation_exp in H1; eauto. simplify. eapply HtWeaken. auto. unfold himp; simplify. propositional; subst. apply H5. invert H1. invert H4; simp. invert H6. invert H8. invert H6. invert H8; simp. invert H9. exists x1. apply split_empty_fwd' in H1; subst. exists $0, (x3 $+ (a, (v, tv))); propositional; eauto. constructor; auto. exists v, x2, tv. exists (heap1 x1 (v, tv)), x6; propositional; eauto. unfold split, heap1. unfold split, heap1 in H6. subst. apply fmap_ext; simplify. cases (weq k x1); subst. replace x1 with a by equality. repeat (rewrite lookup_join1 by (simplify; sets); simplify). auto. simplify. repeat (rewrite lookup_join2 by (simplify; sets); simplify). auto. unfold disjoint, heap1 in *. intros. apply H8 with a0. cases (weq x1 a0); subst; simplify. equality. assumption. assumption. constructor. unfold split in H6; subst. replace x1 with a in * by equality. unfold heap1 in H2. rewrite lookup_join1 in H2 by (simplify; sets). simplify. equality. simplify; auto. apply invert_WriteTail in H3; simp. eapply preservation_exp in H1; eauto. simplify. eapply HtWeaken. auto. unfold himp; simplify. propositional; subst. apply H5. invert H1. invert H4; simp. invert H6. invert H8. invert H6. invert H8; simp. invert H9. exists x1. apply split_empty_fwd' in H1; subst. exists $0, (x3 $+ (a, (hv, v))); propositional; eauto. constructor; auto. exists v, hv, x4. exists (heap1 x1 (hv, v)), x6; propositional; eauto. unfold split, heap1. unfold split, heap1 in H6. subst. apply fmap_ext; simplify. cases (weq k x1); subst. replace x1 with a by equality. repeat (rewrite lookup_join1 by (simplify; sets); simplify). auto. simplify. repeat (rewrite lookup_join2 by (simplify; sets); simplify). auto. unfold disjoint, heap1 in *. intros. apply H8 with a0. cases (weq x1 a0); subst; simplify. equality. assumption. assumption. constructor. unfold split in H6; subst. replace x1 with a in * by equality. unfold heap1 in H2. rewrite lookup_join1 in H2 by (simplify; sets). simplify. equality. simplify; auto. apply invert_Seq in H; first_order. eapply HtWeaken. eauto. simplify. eapply invert_Skip in H; eassumption. apply invert_Seq in H1; first_order. eauto. apply invert_IfThenElse in H; first_order. eapply HtWeaken; eauto. simplify. unfold himp; propositional; subst. eapply preservation_exp in H0; eauto. exists n, H', $0; propositional; eauto. invert H0; simp. invert H7. invert H6. apply split_empty_fwd in H4; subst. auto. constructor; auto. simplify; auto. apply invert_IfThenElse in H; first_order. eapply HtWeaken; eauto. simplify. unfold himp; propositional; subst. eapply preservation_exp in H0; eauto. eapply HtExpConsequence. eauto. simplify. instantiate (1 := fun V H'0 => H'0 = H' /\ V = V'). simplify. reflexivity. simplify. unfold himp; simplify. invert H3; simp. invert H7. invert H6. apply split_empty_fwd in H4; subst. auto. simplify; auto. apply invert_WhileLoop in H; first_order. eapply HtSeq. eapply HtWeaken; eauto. simplify. unfold himp; propositional; subst. eapply preservation_exp in H0; eauto. exists n, H', $0; propositional; eauto. invert H0; simp. invert H8. invert H7. apply split_empty_fwd in H5; subst. auto. constructor; auto. apply H; simplify; auto. eapply HtStrengthen. eauto. eauto. apply invert_WhileLoop in H; first_order. eapply HtWeaken; eauto. simplify. unfold himp; propositional; subst. eapply preservation_exp in H0; eauto. apply H3; auto. simplify. invert H0; simp. invert H7. invert H6. apply split_empty_fwd in H4; subst. auto. apply H; simplify; auto. Qed. Lemma hoare_triple_sound' : forall P s Q, hoare_triple P s Q -> forall H V, P V H -> invariantFor (trsys_of H V s) (fun p => hoare_triple (fun V' H' => H' = fst (fst p) /\ V' = snd (fst p)) (snd p) Q). Proof. simplify. apply invariant_induction; simplify. propositional; subst; simplify. eapply HtWeaken. eauto. unfold himp; simplify; equality. cases s0. cases p. cases s'. cases p. simplify. eapply preservation; eauto. Qed. Lemma progress_exp : forall P e Q, hoare_triple_exp P e Q -> forall V H H1 H2, split H H1 H2 -> disjoint H1 H2 -> P V H1 -> exists v, eval H V e v. Proof. induct 1; simplify; eauto. invert H4. invert H5. eauto. invert H4. invert H5. eexists. econstructor. eauto. invert H4. invert H5; simp. invert H6. apply split_empty_fwd' in H4; subst. invert H8. invert H1; simp. invert H6. cases x1. eexists. econstructor. eauto. unfold heap1, split in *; subst. rewrite lookup_join1. rewrite lookup_join1. simplify. eauto. eapply lookup_Some_dom; simplify; sets. eapply lookup_Some_dom; simplify. rewrite lookup_join1. simplify; eauto. eapply lookup_Some_dom; simplify; sets. invert H4. invert H5; simp. invert H6. apply split_empty_fwd' in H4; subst. invert H8. invert H1; simp. invert H6. cases x1. eexists. econstructor. eauto. unfold heap1, split in *; subst. rewrite lookup_join1. rewrite lookup_join1. simplify. eauto. eapply lookup_Some_dom; simplify; sets. eapply lookup_Some_dom; simplify. rewrite lookup_join1. simplify; eauto. eapply lookup_Some_dom; simplify; sets. invert H4. invert H5. eauto. eapply IHhoare_triple_exp; eauto. apply H0; auto. invert H5; simp. eapply IHhoare_triple_exp in H7; eauto. Qed. Lemma progress : forall P s Q, hoare_triple P s Q -> forall V H H1 H2, split H H1 H2 -> disjoint H1 H2 -> P V H1 -> s = Skip \/ (exists H' V' s', step (H, V, s) (H', V', s')). Proof. induct 1; simplify; eauto. eapply (progress_exp _ _ _ H) in H5; eauto. simp. right; do 3 eexists. econstructor. eauto. pose proof (progress_exp _ _ _ H _ _ _ _ H3 H4 H5) as Hprog. invert Hprog. assert (Hdropped : eval H1 V e x0). eapply drop_cells; eauto. unfold split in H3; subst. simplify. rewrite lookup_join1; auto. eapply lookup_Some_dom; eauto. pose proof (preservation_exp _ _ _ H _ _ _ H5 Hdropped) as Hpres. simplify. invert Hpres. invert H7; simp. invert H9. apply split_empty_fwd' in H8; subst. invert H11. invert H1. invert H8; simp. invert H9. right; do 3 eexists. econstructor. eauto. eauto. unfold heap1, split in *; subst. rewrite lookup_join1. rewrite lookup_join1. simplify. eauto. eapply lookup_Some_dom; simplify; sets. eapply lookup_Some_dom; simplify. rewrite lookup_join1. simplify; eauto. eapply lookup_Some_dom; simplify; sets. pose proof (progress_exp _ _ _ H _ _ _ _ H3 H4 H5) as Hprog. invert Hprog. assert (Hdropped : eval H1 V e x0). eapply drop_cells; eauto. unfold split in H3; subst. simplify. rewrite lookup_join1; auto. eapply lookup_Some_dom; eauto. pose proof (preservation_exp _ _ _ H _ _ _ H5 Hdropped) as Hpres. simplify. invert Hpres. invert H7; simp. invert H9. apply split_empty_fwd' in H8; subst. invert H11. invert H1. invert H8; simp. invert H9. right; do 3 eexists. econstructor. eauto. eauto. unfold heap1, split in *; subst. rewrite lookup_join1. rewrite lookup_join1. simplify. eauto. eapply lookup_Some_dom; simplify; sets. eapply lookup_Some_dom; simplify. rewrite lookup_join1. simplify; eauto. eapply lookup_Some_dom; simplify; sets. specialize (IHhoare_triple1 _ _ _ _ H4 H5 H6); simp; eauto 6. pose proof (progress_exp _ _ _ H _ _ _ _ H5 H6 H7) as Hprog. invert Hprog. assert (Hdropped : eval H3 V e x). eapply drop_cells; eauto. unfold split in H5; subst. simplify. rewrite lookup_join1; auto. eapply lookup_Some_dom; eauto. pose proof (preservation_exp _ _ _ H _ _ _ H7 Hdropped) as Hpres. simplify. invert Hpres; simp. invert H13. invert H12. cases (weq x2 (^0)); subst; eauto 10. pose proof (progress_exp _ _ _ H _ _ _ _ H4 H5 H6) as Hprog. invert Hprog. assert (Hdropped : eval H2 V e x). eapply drop_cells; eauto. unfold split in H4; subst. simplify. rewrite lookup_join1; auto. eapply lookup_Some_dom; eauto. pose proof (preservation_exp _ _ _ H _ _ _ H6 Hdropped) as Hpres. simplify. invert Hpres; simp. invert H12. invert H11. cases (weq x2 (^0)); subst; eauto 10. apply H0 in H7. eapply IHhoare_triple in H7; eauto. invert H6; simp. eapply IHhoare_triple in H8; eauto. Qed. Theorem hoare_triple_sound : forall P s Q, hoare_triple P s Q -> forall H V, P V H -> invariantFor (trsys_of H V s) (fun p => (snd p = Skip /\ Q (snd (fst p)) (fst (fst p))) \/ exists p', step p p'). Proof. simplify. eapply invariant_weaken. eapply hoare_triple_sound'; eauto. simplify. cases s0. cases p. simplify. pose proof (progress _ _ _ H2 v h h $0) as Hprog; simplify. cases Hprog; eauto. subst. eapply invert_Skip in H2. left; propositional. apply H2; auto. first_order. Qed. End DeeplyEmbedded.