(* Stuff that should be upstreamed to std++ *) From stdpp Require Export gmap stringmap ssreflect. From stdpp Require Import sorting. From stdpp Require Import options. Set Default Proof Using "Type*". (* Succeeds if [t] is syntactically a constructor applied to some arguments. Note that Coq's [is_constructor] succeeds on [S], but fails on [S n]. *) Ltac is_app_constructor t := lazymatch t with | ?t _ => is_app_constructor t | _ => is_constructor t end. Lemma xorb_True b1 b2 : xorb b1 b2 ↔ ¬(b1 ↔ b2). Proof. destruct b1, b2; naive_solver. Qed. Definition option_to_eq_Some {A} (mx : option A) : option { x | mx = Some x } := match mx with | Some x => Some (x ↾ eq_refl) | None => None end. (* Premise can probably be weakened to something with [ProofIrrel]. *) Lemma option_to_eq_Some_Some `{!EqDecision A} (mx : option A) x (H : mx = Some x) : option_to_eq_Some mx = Some (x ↾ H). Proof. destruct mx as [x'|]; simplify_eq/=; f_equal/=. assert (x' = x) as Hx by congruence. destruct Hx. f_equal. apply (proof_irrel _). Qed. Definition from_sum {A B C} (f : A → C) (g : B → C) (xy : A + B) : C := match xy with inl x => f x | inr y => g y end. Global Instance maybe_String : Maybe2 String := λ s, if s is String a s then Some (a,s) else None. Global Instance String_inj a : Inj (=) (=) (String a). Proof. by injection 1. Qed. Global Instance full_relation_dec {A} : RelDecision (λ _ _ : A, True). Proof. unfold RelDecision. apply _. Defined. Global Instance prod_relation_dec `{RA : relation A, RB : relation B} : RelDecision RA → RelDecision RB → RelDecision (prod_relation RA RB). Proof. unfold RelDecision. apply _. Defined. Global Hint Extern 0 (from_option _ _ _) => progress simpl : core. Definition map_sum_with `{MapFold K A M} (f : A → nat) : M → nat := map_fold (λ _, plus ∘ f) 0. Lemma map_sum_with_lookup_le `{FinMap K M} {A} (f : A → nat) (m : M A) i x : m !! i = Some x → f x ≤ map_sum_with f m. Proof. intros. rewrite /map_sum_with (map_fold_delete_L _ _ i x m) /=; auto with lia. Qed. Lemma map_Forall2_dom `{FinMapDom K M C} {A B} (P : K → A → B → Prop) (m1 : M A) (m2 : M B) : map_Forall2 P m1 m2 → dom m1 ≡ dom m2. Proof. revert m2. induction m1 as [|i x1 m1 ? IH] using map_ind; intros m2. { intros ->%map_Forall2_empty_inv_l. by rewrite !dom_empty. } intros (x2 & m2' & -> & ? & ? & ?)%map_Forall2_insert_inv_l; last done. rewrite !dom_insert IH //. Qed. Lemma map_Forall2_dom_L `{FinMapDom K M C, !LeibnizEquiv C} {A B} (P : K → A → B → Prop) (m1 : M A) (m2 : M B) : map_Forall2 P m1 m2 → dom m1 = dom m2. Proof. unfold_leibniz. apply map_Forall2_dom. Qed. Definition map_mapM `{!∀ A, MapFold K A (M A), !∀ A, Empty (M A), !∀ A, Insert K A (M A)} `{MBind F, MRet F} {A B} (f : A → F B) (m : M A) : F (M B) := map_fold (λ i x mm, y ← f x; m ← mm; mret $ <[i:=y]> m) (mret ∅) m. Section fin_map. Context `{FinMap K M}. Lemma map_insert_inv_eq {A} {m1 m2 : M A} x v u : m1 !! x = None → m2 !! x = None → <[x:=v]> m1 = <[x:=u]> m2 → v = u ∧ m1 = m2. Proof. intros Hm1 Hm2 Heq. split. - assert (Huv : <[x:=v]> m1 !! x = Some v). { apply lookup_insert. } rewrite Heq lookup_insert in Huv. by injection Huv as ->. - apply map_eq. intros i. replace m1 with (delete x (<[x:=v]> m1)) by (apply delete_insert; done). replace m2 with (delete x (<[x:=u]> m2)) by (apply delete_insert; done). by rewrite Heq. Qed. Lemma map_insert_inv_ne {A} {m1 m2 : M A} x1 x2 v1 v2 : x1 ≠ x2 → m1 !! x1 = None → m2 !! x2 = None → <[x1:=v1]> m1 = <[x2:=v2]> m2 → m1 !! x2 = Some v2 ∧ m2 !! x1 = Some v1 ∧ delete x2 m1 = delete x1 m2. Proof. intros Hx1x2 Hm1 Hm2 Hm1m2. rewrite map_eq_iff in Hm1m2. split_and!. - rewrite -(lookup_insert_ne _ x1 _ v1) // Hm1m2 lookup_insert //. - rewrite -(lookup_insert_ne _ x2 _ v2) // -Hm1m2 lookup_insert //. - apply map_eq. intros y. destruct (decide (y = x1)) as [->|]; first rewrite lookup_delete_ne // lookup_delete //. destruct (decide (y = x2)) as [->|]; first rewrite lookup_delete lookup_delete_ne //. rewrite !lookup_delete_ne // -(lookup_insert_ne m2 x2 _ v2) // -(lookup_insert_ne m1 x1 _ v1) //. Qed. Lemma map_mapM_empty `{MBind F, MRet F} {A B} (f : A → F B) : map_mapM f (∅ : M A) =@{F (M B)} mret ∅. Proof. unfold map_mapM. by rewrite map_fold_empty. Qed. Lemma map_mapM_insert `{MBind F, MRet F} {A B} (f : A → F B) (m : M A) i x : m !! i = None → map_first_key (<[i:=x]> m) i → map_mapM f (<[i:=x]> m) = y ← f x; m ← map_mapM f m; mret $ <[i:=y]> m. Proof. intros. rewrite /map_mapM map_fold_insert_first_key //. Qed. Lemma map_mapM_insert_option {A B} (f : A → option B) (m : M A) i x : m !! i = None → map_mapM f (<[i:=x]> m) = y ← f x; m ← map_mapM f m; mret $ <[i:=y]> m. Proof. intros. apply: map_fold_insert; [|done]. intros ?? z1 z2 my ???. destruct (f z1), (f z2), my; f_equal/=. by apply insert_commute. Qed. End fin_map. Definition map_minimal_key `{MapFold K A M} (R : relation K) `{!RelDecision R} (m : M) : option K := map_fold (λ i _ mj, match mj with | Some j => if decide (R i j) then Some i else Some j | None => Some i end) None m. Section map_sorted. Context `{FinMap K M} (R : relation K) . Lemma map_minimal_key_None {A} `{!RelDecision R} (m : M A) : map_minimal_key R m = None ↔ m = ∅. Proof. split; [|intros ->; apply map_fold_empty]. induction m as [|j x m ?? _] using map_first_key_ind; intros Hm; [done|]. rewrite /map_minimal_key map_fold_insert_first_key // in Hm. repeat case_match; simplify_option_eq. Qed. Lemma map_minimal_key_Some_1 {A} `{!RelDecision R, !PreOrder R, !Total R} (m : M A) i : map_minimal_key R m = Some i → is_Some (m !! i) ∧ ∀ j, is_Some (m !! j) → R i j. Proof. revert i. induction m as [|j x m ?? IH] using map_first_key_ind; intros i Hm. { by rewrite /map_minimal_key map_fold_empty in Hm. } rewrite /map_minimal_key map_fold_insert_first_key // in Hm. destruct (map_fold _ _ m) as [i'|] eqn:Hfold; simplify_eq. - apply IH in Hfold as [??]. rewrite lookup_insert_is_Some. case_decide as HR; simplify_eq/=. + split; [by auto|]. intros j [->|[??]]%lookup_insert_is_Some; [done|]. trans i'; eauto. + split. { right; split; [|done]. intros ->. by destruct HR. } intros j' [->|[??]]%lookup_insert_is_Some; [|by eauto]. by destruct (total R i j'). - apply map_minimal_key_None in Hfold as ->. split; [rewrite lookup_insert; by eauto|]. intros j' [->|[? Hj']]%lookup_insert_is_Some; [done|]. rewrite lookup_empty in Hj'. by destruct Hj'. Qed. Lemma map_minimal_key_Some {A} `{!RelDecision R, !PartialOrder R, !Total R} (m : M A) i : map_minimal_key R m = Some i ↔ is_Some (m !! i) ∧ ∀ j, is_Some (m !! j) → R i j. Proof. split; [apply map_minimal_key_Some_1|]. intros [Hi ?]. destruct (map_minimal_key R m) as [i'|] eqn:Hmin. - f_equal. apply map_minimal_key_Some_1 in Hmin as [??]. apply (anti_symm R); eauto. - apply map_minimal_key_None in Hmin as ->. rewrite lookup_empty in Hi. by destruct Hi. Qed. Lemma map_sorted_ind {A} `{!PreOrder R, !Total R} (P : M A → Prop) : P ∅ → (∀ i x m, m !! i = None → (∀ j, is_Some (m !! j) → R i j) → P m → P (<[i:=x]> m)) → (∀ m, P m). Proof. intros Hemp Hins m. induction (Nat.lt_wf_0_projected size m) as [m _ IH]. cut (m = ∅ ∨ map_Exists (λ i _, ∀ j, is_Some (m !! j) → R i j) m). { intros [->|(i & x & Hi & ?)]; [done|]. rewrite -(insert_delete m i x) //. apply Hins; [by rewrite lookup_delete|..]. - intros j ?%lookup_delete_is_Some. naive_solver. - apply IH. rewrite -{2}(insert_delete m i x) // map_size_insert lookup_delete. lia. } clear P Hemp Hins IH. induction m as [|i x m ? IH] using map_ind; [by auto|]. right. destruct IH as [->|(i' & x' & ? & ?)]. { rewrite insert_empty map_Exists_singleton. by intros j [y [-> ->]%lookup_singleton_Some]. } apply map_Exists_insert; first done. destruct (total R i i'). - left. intros j [->|[??]]%lookup_insert_is_Some; [done|]. trans i'; eauto. - right. exists i', x'. split; [done|]. intros j [->|[??]]%lookup_insert_is_Some; eauto. Qed. End map_sorted. Definition map_fold_sorted `{!MapFold K A M} {B} (R : relation K) `{!RelDecision R} (f : K → A → B → B) (b : B) (m : M) : B := foldr (λ '(i,x), f i x) b $ merge_sort (prod_relation R (λ _ _, True)) (map_to_list m). Definition map_mapM_sorted `{!∀ A, MapFold K A (M A), !∀ A, Empty (M A), !∀ A, Insert K A (M A)} `{MBind F, MRet F} {A B} (R : relation K) `{!RelDecision R} (f : A → F B) (m : M A) : F (M B) := map_fold_sorted R (λ i x mm, y ← f x; m ← mm; mret $ <[i:=y]> m) (mret ∅) m. Section fin_map. Context `{FinMap K M}. Context (R : relation K) `{!RelDecision R, !PartialOrder R, !Total R}. Lemma map_fold_sorted_empty {A B} (f : K → A → B → B) b : map_fold_sorted R f b (∅ : M A) = b. Proof. by rewrite /map_fold_sorted map_to_list_empty. Qed. Lemma map_fold_sorted_insert {A B} (f : K → A → B → B) (m : M A) b i x : m !! i = None → (∀ j, is_Some (m !! j) → R i j) → map_fold_sorted R f b (<[i:=x]> m) = f i x (map_fold_sorted R f b m). Proof. intros Hi Hleast. unfold map_fold_sorted. set (R' := prod_relation R _). assert (PreOrder R'). { split; [done|]. intros [??] [??] [??] [??] [??]; split; [by etrans|done]. } assert (Total R'). { intros [i1 ?] [i2 ?]. destruct (total R i1 i2); [by left|by right]. } assert (merge_sort R' (map_to_list (<[i:=x]> m)) = (i,x) :: merge_sort R' (map_to_list m)) as ->; [|done]. eapply (Sorted_unique_strong R'). - intros [i1 y1] [i2 y2]. rewrite !merge_sort_Permutation elem_of_cons !elem_of_map_to_list. rewrite lookup_insert_Some. intros ?? [? _] [? _]. assert (i1 = i2) as -> by (by apply (anti_symm R)); naive_solver. - apply (Sorted_merge_sort _). - apply Sorted_cons; [apply (Sorted_merge_sort _)|]. destruct (merge_sort R' (map_to_list m)) as [|[i' x'] ixs] eqn:Hixs; repeat constructor; simpl. apply Hleast. exists x'. apply elem_of_map_to_list. rewrite -(merge_sort_Permutation R' (map_to_list m)) Hixs. left. - by rewrite !merge_sort_Permutation map_to_list_insert. Qed. Lemma map_mapM_sorted_empty `{MBind F, MRet F} {A B} (f : A → F B) : map_mapM_sorted R f (∅ : M A) =@{F (M B)} mret ∅. Proof. by rewrite /map_mapM_sorted map_fold_sorted_empty. Qed. Lemma map_mapM_sorted_insert `{MBind F, MRet F} {A B} (f : A → F B) (m : M A) i x : m !! i = None → (∀ j, is_Some (m !! j) → R i j) → map_mapM_sorted R f (<[i:=x]> m) = y ← f x; m ← map_mapM_sorted R f m; mret $ <[i:=y]> m. Proof. intros. by rewrite /map_mapM_sorted map_fold_sorted_insert. Qed. End fin_map.