Require Import Coq.Strings.String. From stdpp Require Import gmap option tactics. From mininix Require Import binop expr maptools matching relations sem. Lemma ctx_item_inj E uf_ext uf_int : is_ctx_item uf_ext uf_int E → Inj (=) (=) E. Proof. intros Hctx. destruct Hctx; intros e1' e2' Hinj; try congruence. injection Hinj as Hinj. by apply map_insert_rev_1_L in Hinj. Qed. Global Instance id_inj {A} : Inj (=) (=) (@id A). Proof. by unfold Inj. Qed. Lemma ctx_inj E uf_ext uf_int : is_ctx uf_ext uf_int E → Inj (=) (=) E. Proof. intros Hctx. induction Hctx. - apply id_inj. - apply ctx_item_inj in H. by apply compose_inj with (=). Qed. Lemma base_step_deterministic : deterministic base_step. Proof. unfold deterministic. intros e0 e1 e2 H1 H2. inv H1; inv H2; try done. - destruct ys, ys0. by simplify_eq/=. - destruct ys. by simplify_eq/=. - destruct ys. by simplify_eq/=. - apply map_insert_inv in H0. by destruct H0. - destruct ys. by simplify_eq/=. - destruct ys. by simplify_eq/=. - destruct ys, ys0. by simplify_eq/=. - exfalso. apply H3. by exists bs. - exfalso. apply H. by exists bs. - f_equal. by eapply matches_deterministic. - apply map_insert_inv in H0 as [H01 H02]. by simplify_eq/=. - f_equal. by eapply binop_deterministic. - rewrite H4 in H. by apply is_Some_None in H. - exfalso. apply H4. by exists bs. - rewrite H in H4. by apply is_Some_None in H4. - exfalso. apply H. by exists bs. Qed. Reserved Notation "e '-/' uf '/->' e'" (right associativity, at level 55). Inductive fstep : bool → expr → expr → Prop := | F_Ctx e1 e2 E uf_ext uf_int : is_ctx uf_ext uf_int E → e1 -->base e2 → E e1 -/uf_ext/-> E e2 where "e -/ uf /-> e'" := (fstep uf e e'). Hint Constructors fstep : core. Lemma ufstep e e' : e -/false/-> e' ↔ e --> e'. Proof. split; intros; inv H; by econstructor. Qed. Lemma fstep_strongly_confluent_aux x uf y1 y2 : x -/uf/-> y1 → x -/uf/-> y2 → y1 = y2 ∨ ∃ z, y1 -/uf/-> z ∧ y2 -/uf/-> z. Proof. intros Hstep1 Hstep2. inv Hstep1 as [b11 b12 E1 uf_int uf_int1 Hctx1 Hbase1]. inv Hstep2 as [b21 b22 E2 uf_int uf_int2 Hctx2 Hbase2]. revert b11 b12 b21 b22 E2 Hbase1 Hbase2 Hctx2 H0. induction Hctx1 as [|E1 E0]; intros b11 b12 b21 b22 E2 Hbase1 Hbase2 Hctx2 H2; inv Hctx2. - (* L: id, R: id *) left. by eapply base_step_deterministic. - (* L: id, R: ∘ *) simplify_eq/=. inv H; try inv select (_ -->base b12); (inv select (is_ctx _ _ _); [inv select (b21 -->base b22) |inv select (is_ctx_item _ _ _)]). simplify_option_eq. destruct sv; try discriminate. exfalso. clear uf. simplify_option_eq. apply fmap_insert_lookup in H1. simplify_option_eq. revert bs0 x H H1 Heqo. induction H2; intros bs0 x H' H1 Heqo; [inv Hbase2|]. simplify_option_eq. inv H. destruct H'; try discriminate. inv H1. apply fmap_insert_lookup in H0. simplify_option_eq. by eapply IHis_ctx. - (* L: ∘, R: id *) simplify_eq/=. inv H; try inv select (_ -->base b22); (inv select (is_ctx _ _ _); [inv select (b11 -->base b12) |inv select (is_ctx_item _ _ _)]). clear IHHctx1. simplify_option_eq. destruct sv; try discriminate. exfalso. simplify_option_eq. apply fmap_insert_lookup in H0. simplify_option_eq. revert bs0 x H H0 Heqo. induction H1; intros bs0 x H' H0 Heqo; [inv Hbase1|]. simplify_option_eq. inv H. destruct H'; try discriminate. inv H0. apply fmap_insert_lookup in H2. simplify_option_eq. by eapply IHis_ctx. - (* L: ∘, R: ∘ *) simplify_option_eq. inv H; inv H0. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H2) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_Select z xs). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e, X_Select e xs) ∘ E); try done; by eapply IsCtx_Compose. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H2) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_SelectOr z xs e2). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e1, X_SelectOr e1 xs e2) ∘ E); try done; by eapply IsCtx_Compose. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H2) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_Incl z e2). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e1, X_Incl e1 e2) ∘ E); try done; by eapply IsCtx_Compose. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H2) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_Apply z e2). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e1, X_Apply e1 e2) ∘ E); try done; by eapply IsCtx_Compose. + inv Hctx1; simplify_option_eq. * inv Hbase1. * inv H. + inv H1; simplify_option_eq. * inv Hbase2. * inv H. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H0) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_Apply (V_AttrsetFn m e1) z). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e2, X_Apply (V_AttrsetFn m e1) e2) ∘ E); try done; by eapply IsCtx_Compose. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H2) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_Cond z e2 e3). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e1, X_Cond e1 e2 e3) ∘ E); try done; by eapply IsCtx_Compose. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H2) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_Assert z e2). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e1, X_Assert e1 e2) ∘ E); try done; by eapply IsCtx_Compose. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_Op op z e2). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e1, X_Op op e1 e2) ∘ E); try done; by eapply IsCtx_Compose. + inv Hctx1; simplify_option_eq. * inv Hbase1. * inv H0. + inv H1; simplify_option_eq. * inv Hbase2. * inv H0. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H0) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_Op op v1 z). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e2, X_Op op v1 e2) ∘ E); try done; by eapply IsCtx_Compose. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H2) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_HasAttr z x). split; [inv IHz1 | inv IHz2]; eapply F_Ctx with (E := (λ e, X_HasAttr e x) ∘ E); try done; by eapply IsCtx_Compose. + destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H2) as [IH | [z [IHz1 IHz2]]]. * left. congruence. * right. exists (X_Force z). split. -- inv IHz1. (* apply is_ctx_uf_false_impl_true in H0 as []. *) eapply F_Ctx with (E := X_Force ∘ E); try done; by eapply IsCtx_Compose. -- inv IHz2. eapply F_Ctx with (E := X_Force ∘ E); try done; by eapply IsCtx_Compose. + destruct (decide (x0 = x)). * simplify_option_eq. apply map_insert_rev_L in H2 as [H21 H22]. destruct (IHHctx1 _ _ _ _ E4 Hbase1 Hbase2 H1 H21) as [IH | [z [IHz1 IHz2]]]. -- left. rewrite IH. do 2 f_equal. by apply map_insert_L. -- right. exists (V_Attrset (<[x := z]>bs)). split. ++ inv IHz1. eapply F_Ctx with (E := (λ e, X_V $ V_Attrset (<[x := e]>bs)) ∘ E); try done. by eapply IsCtx_Compose. ++ inv IHz2. rewrite (map_insert_L _ _ _ _ _ (eq_refl (E e1)) H22). eapply F_Ctx with (E := (λ e, X_V $ V_Attrset (<[x := e]>bs)) ∘ E); try done. by eapply IsCtx_Compose. * simplify_option_eq. right. exists (V_Attrset (<[x := E0 b12]>(<[x0 := E4 b22]>bs))). split. -- apply map_insert_ne_inv in H2 as H3; try done. destruct H3. replace bs with (<[x0 := E4 b21]>bs) at 1; try by rewrite insert_id. setoid_rewrite insert_commute; try by congruence. eapply F_Ctx with (E := (λ e, X_V $ V_Attrset (<[x0 := e]>(<[x := E0 b12]> bs))) ∘ E4). ++ by eapply IsCtx_Compose. ++ done. -- apply map_insert_ne_inv in H2 as H3; try done. destruct H3 as [H31 [H32 H33]]. replace bs0 with (<[x := E0 b11]>bs0) at 1; try by rewrite insert_id. rewrite insert_commute; try by congruence. replace (<[x:=E0 b11]> (<[x0:=E4 b22]> bs0)) with (<[x:=E0 b11]> (<[x0:=E4 b22]> bs)). 2: { rewrite <-insert_delete_insert. setoid_rewrite <-insert_delete_insert at 2. rewrite delete_insert_ne by congruence. rewrite delete_commute. rewrite <-H33. rewrite insert_delete_insert. rewrite <-delete_insert_ne by congruence. by rewrite insert_delete_insert. } eapply F_Ctx with (E := (λ e, X_V $ V_Attrset (<[x := e]>(<[x0 := E4 b22]>bs))) ∘ E0). ++ by eapply IsCtx_Compose. ++ done. Qed. Lemma step_strongly_confluent_aux x y1 y2 : x --> y1 → x --> y2 → y1 = y2 ∨ ∃ z, y1 --> z ∧ y2 --> z. Proof. intros Hstep1 Hstep2. apply ufstep in Hstep1, Hstep2. destruct (fstep_strongly_confluent_aux _ _ _ _ Hstep1 Hstep2) as [|[?[]]]. - by left. - right. exists x0. split; by apply ufstep. Qed. Theorem step_strongly_confluent : strongly_confluent step. Proof. intros x y1 y2 Hy1 Hy2. destruct (step_strongly_confluent_aux x y1 y2 Hy1 Hy2) as [|[z [Hz1 Hz2]]]. - exists y1. by subst. - exists z. split. + by apply rtc_once. + by apply rc_once. Qed. Lemma step_semi_confluent : semi_confluent step. Proof. apply strong__semi_confluence. apply step_strongly_confluent. Qed. Lemma step_cr : cr step. Proof. apply semi_confluence__cr. apply step_semi_confluent. Qed. Theorem step_confluent : confluent step. Proof. apply confluent_alt. apply step_cr. Qed.