aboutsummaryrefslogtreecommitdiffstats
Require Import Coq.Strings.String.
From stdpp Require Import countable fin_maps fin_map_dom.

(** Generic lemmas for finite maps and their domains *)

Lemma map_insert_empty_lookup {A} `{FinMap K M}
  (i j : K) (x y : A) :
    <[i := x]> (∅ : M A) !! j = Some y → i = j ∧ y = x.
Proof.
  intros Hiel.
  destruct (decide (i = j)).
  - split; try done. simplify_eq/=.
    rewrite lookup_insert in Hiel. congruence.
  - rewrite lookup_insert_ne in Hiel; try done.
    exfalso. eapply lookup_empty_Some, Hiel.
Qed.

Lemma map_insert_ne_inv `{FinMap K M} {A}
  (m1 m2 : M A) i j x y :
    i ≠ j →
    <[i := x]>m1 = <[j := y]>m2 →
    m2 !! i = Some x ∧ m1 !! j = Some y ∧
    delete i (delete j m1) = delete i (delete j m2).
Proof.
  intros Hneq Heq.
  split; try split.
  - rewrite <-lookup_delete_ne with (i := j) by congruence.
    rewrite <-delete_insert_delete with (x := y).
    rewrite <-Heq.
    rewrite lookup_delete_ne by congruence.
    by rewrite lookup_insert.
  - rewrite <-lookup_delete_ne with (i := i) by congruence.
    rewrite <-delete_insert_delete with (x := x).
    rewrite Heq.
    rewrite lookup_delete_ne by congruence.
    by rewrite lookup_insert.
  - setoid_rewrite <-delete_insert_delete with (x := x) at 1.
    setoid_rewrite <-delete_insert_delete with (x := y) at 4.
    rewrite <-delete_insert_ne by congruence.
    by do 2 f_equal.
Qed.

Lemma map_insert_inv `{FinMap K M} {A}
  (m1 m2 : M A) i x y :
    <[i := x]>m1 = <[i := y]>m2 →
    x = y ∧ delete i m1 = delete i m2.
Proof.
  intros Heq.
  split; try split.
  - apply Some_inj.
    replace (Some x) with (<[i := x]>m1 !! i) by apply lookup_insert.
    replace (Some y) with (<[i := y]>m2 !! i) by apply lookup_insert.
    by rewrite Heq.
  - replace (delete i m1) with (delete i (<[i := x]>m1))
    by apply delete_insert_delete.
    replace (delete i m2) with (delete i (<[i := y]>m2))
    by apply delete_insert_delete.
    by rewrite Heq.
Qed.

Lemma fmap_insert_lookup `{FinMap K M} {A B}
  (f : A → B) (m1 : M A) (m2 : M B) i x :
    f <$> m1 = <[i := x]>m2 →
    f <$> m1 !! i = Some x.
Proof.
  intros Hmap.
  rewrite <-lookup_fmap.
  rewrite Hmap.
  apply lookup_insert.
Qed.

Lemma map_dom_delete_insert_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (m1 : M A) (m2 : M B) i x y :
    dom (delete i m1) = dom (delete i m2) →
    dom (<[i := x]>m1) = dom (<[i := y]> m2).
Proof.
  intros Hdel.
  setoid_rewrite <-insert_delete_insert at 1 2.
  rewrite 2 dom_insert_L.
  set_solver.
Qed.

Lemma map_dom_delete_insert_subseteq_L `{FinMapDom K M D} `{!LeibnizEquiv D}
  {A B} (m1 : M A) (m2 : M B) i x y :
    dom (delete i m1) ⊆ dom (delete i m2) →
    dom (<[i := x]>m1) ⊆ dom (<[i := y]> m2).
Proof.
  intros Hdel.
  setoid_rewrite <-insert_delete_insert at 1 2.
  rewrite 2 dom_insert_L.
  set_solver.
Qed.

Lemma map_dom_empty_eq_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A}
  (m : M A) : dom (∅ : M A) = dom m → m = ∅.
Proof.
  intros Hdom.
  rewrite dom_empty_L in Hdom.
  symmetry in Hdom.
  by apply dom_empty_inv_L.
Qed.

Lemma map_dom_insert_eq_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A}
  (i : K) (x : A) (m1 m2 : M A) :
    dom (<[i := x]>m1) = dom m2 →
    dom (delete i m1) = dom (delete i m2) ∧ i ∈ dom m2.
Proof. set_solver. Qed.

(* Copied from stdpp and changed so that the value types
   of m1 and m2 are decoupled *)
Lemma map_dom_subseteq_size `{FinMapDom K M D} {A B} (m1 : M A) (m2 : M B) :
  dom m2 ⊆ dom m1 → size m2 ≤ size m1.
Proof.
  revert m1. induction m2 as [|i x m2 ? IH] using map_ind; intros m1 Hdom.
  { rewrite map_size_empty. lia. }
  rewrite dom_insert in Hdom.
  assert (i ∉ dom m2) by (by apply not_elem_of_dom).
  assert (i ∈ dom m1) as [x' Hx'] % elem_of_dom by set_solver.
  rewrite <-(insert_delete m1 i x') by done.
  rewrite !map_size_insert_None, <-Nat.succ_le_mono
  by (by rewrite ?lookup_delete).
  apply IH. rewrite dom_delete. set_solver.
Qed.

Lemma map_dom_empty_subset `{Countable K} `{FinMapDom K M D} {A B} (m : M A) :
  dom m ⊆ dom (∅ : M B) → m = ∅.
Proof.
  intros Hdom.
  apply map_dom_subseteq_size in Hdom.
  rewrite map_size_empty in Hdom.
  inv Hdom.
  by apply map_size_empty_inv.
Qed.

(** map_mapM *)

Definition map_mapM {M : Type → Type} `{MBind F} `{MRet F} `{FinMap K M} {A B}
  (f : A → F B) (m : M A) : F (M B) :=
    map_fold (λ i x om', m' ← om'; x' ← f x; mret $ <[i := x']>m') (mret ∅) m.

Lemma map_mapM_dom_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (f : A → option B) (m1 : M A) (m2 : M B) :
    map_mapM f m1 = Some m2 → dom m1 = dom m2.
Proof.
  revert m2.
  induction m1 using map_ind; intros m2 HmapM.
  - unfold map_mapM in HmapM. rewrite map_fold_empty in HmapM.
    simplify_option_eq.
    by rewrite 2 dom_empty_L.
  - unfold map_mapM in HmapM.
    rewrite map_fold_insert_L in HmapM.
    + simplify_option_eq.
      apply IHm1 in Heqo.
      rewrite 2 dom_insert_L.
      by f_equal.
    + intros.
      destruct y; simplify_option_eq; try done.
      destruct (f z2); simplify_option_eq.
      * destruct (f z1); simplify_option_eq; try done.
        f_equal. by apply insert_commute.
      * destruct (f z1); by simplify_option_eq.
    + done.
Qed.

Lemma map_mapM_option_insert_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (f : A → option B) (m1 : M A) (m2 m2' : M B) (i : K) (x : A) :
    m1 !! i = None →
    map_mapM f (<[i := x]>m1) = Some m2 →
    ∃ x', f x = Some x' ∧ map_mapM f m1 = Some (delete i m2).
Proof.
  intros Helem HmapM.
  unfold map_mapM in HmapM.
  rewrite map_fold_insert_L in HmapM.
  - simplify_option_eq.
    exists H15.
    split; try done.
    rewrite delete_insert.
    apply Heqo.
    apply map_mapM_dom_L in Heqo.
    apply not_elem_of_dom in Helem.
    apply not_elem_of_dom.
    set_solver.
  - intros.
    destruct y; simplify_option_eq; try done.
    destruct (f z2); simplify_option_eq.
    + destruct (f z1); simplify_option_eq; try done.
      f_equal. by apply insert_commute.
    + destruct (f z1); by simplify_option_eq.
  - done.
Qed.

(** map_Forall2 *)

Definition map_Forall2 `{∀ A, Lookup K A (M A)} {A B}
  (R : A → B → Prop) :=
    map_relation (M := M) R (λ _, False) (λ _, False).

Global Instance map_Forall2_dec `{FinMap K M} {A B} (R : A → B → Prop)
  `{∀ a b, Decision (R a b)} : RelDecision (map_Forall2 (M := M) R).
Proof. apply map_relation_dec; intros; try done; apply False_dec. Qed.

Lemma map_Forall2_insert_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (m1 : M A) (m2 : M B) R i x y :
    m1 !! i = None →
    m2 !! i = None →
    R x y →
    map_Forall2 R m1 m2 →
    map_Forall2 R (<[i := x]>m1) (<[i := y]>m2).
Proof.
  unfold map_Forall2, map_relation, option_relation.
  intros Him1 Him2 HR HForall2 j.
  destruct (decide (i = j)).
  + simplify_option_eq. by rewrite 2 lookup_insert.
  + rewrite 2 lookup_insert_ne by done. apply HForall2.
Qed.

Lemma map_Forall2_insert_weak `{FinMap K M} {A B}
  (m1 : M A) (m2 : M B) R i x y :
    R x y →
    map_Forall2 R (delete i m1) (delete i m2) →
    map_Forall2 R (<[i := x]>m1) (<[i := y]>m2).
Proof.
  unfold map_Forall2, map_relation, option_relation.
  intros HR HForall2 j.
  destruct (decide (i = j)).
  - simplify_option_eq. by rewrite 2 lookup_insert.
  - rewrite 2 lookup_insert_ne by done.
    rewrite <-lookup_delete_ne with (i := i) by done.
    replace (m2 !! j) with (delete i m2 !! j); try by apply lookup_delete_ne.
    apply HForall2.
Qed.

Lemma map_Forall2_destruct `{FinMap K M} {A B}
  (m1 : M A) (m2 : M B) R i x :
    map_Forall2 R (<[i := x]>m1) m2 →
    ∃ y m2', m2' !! i = None ∧ m2 = <[i := y]>m2'.
Proof.
  intros HForall2.
  unfold map_Forall2, map_relation, option_relation in HForall2.
  pose proof (HForall2 i). clear HForall2.
  case_match.
  - case_match; try done.
    exists b, (delete i m2).
    split.
    * apply lookup_delete.
    * by rewrite insert_delete_insert, insert_id.
  - case_match; try done.
    by rewrite lookup_insert in H8.
Qed.

Lemma map_Forall2_insert_inv `{FinMap K M} {A B}
  (m1 : M A) (m2 : M B) R i x y :
    map_Forall2 R (<[i := x]>m1) (<[i := y]>m2) →
    R x y ∧ map_Forall2 R (delete i m1) (delete i m2).
Proof.
  intros HForall2.
  unfold map_Forall2, map_relation, option_relation in HForall2.
  pose proof (HForall2 i).
  case_match.
  - case_match; try done.
    rewrite lookup_insert in H8. rewrite lookup_insert in H9.
    simplify_eq/=. split; try done.
    unfold map_Forall2, map_relation, option_relation.
    intros j.
    destruct (decide (i = j)).
    + simplify_option_eq.
      case_match.
      * by rewrite lookup_delete in H8.
      * case_match; [|done].
        by rewrite lookup_delete in H9.
    + case_match; case_match;
        rewrite lookup_delete_ne in H8 by done;
        rewrite lookup_delete_ne in H9 by done;
        pose proof (HForall2 j);
        case_match; case_match; try done;
          rewrite lookup_insert_ne in H11 by done;
          rewrite lookup_insert_ne in H12 by done;
          by simplify_eq/=.
  - by rewrite lookup_insert in H8.
Qed.

Lemma map_Forall2_insert_inv_strict `{FinMap K M} {A B}
  (m1 : M A) (m2 : M B) R i x y :
    m1 !! i = None →
    m2 !! i = None →
    map_Forall2 R (<[i := x]>m1) (<[i := y]>m2) →
    R x y ∧ map_Forall2 R m1 m2.
Proof.
  intros Him1 Him2 HForall2.
  apply map_Forall2_insert_inv in HForall2 as [HPixy HForall2].
  split; try done.
  apply delete_notin in Him1, Him2.
  by rewrite Him1, Him2 in HForall2.
Qed.

Lemma map_Forall2_dom_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (R : A → B → Prop) (m1 : M A) (m2 : M B) :
    map_Forall2 R m1 m2 → dom m1 = dom m2.
Proof.
  revert m2.
  induction m1 using map_ind; intros m2.
  - intros HForall2.
    destruct m2 using map_ind; [set_solver|].
    unfold map_Forall2, map_relation, option_relation in HForall2.
    pose proof (HForall2 i). by rewrite lookup_empty, lookup_insert in H15.
  - intros HForall2.
    apply map_Forall2_destruct in HForall2 as Hm2.
    destruct Hm2 as [y [m2' [Hm21 Hm22]]]. simplify_eq/=.
    apply map_Forall2_insert_inv_strict in HForall2 as [_ HForall2]; try done.
    set_solver.
Qed.

Lemma map_Forall2_empty_l_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (R : A → B → Prop) (m2 : M B) :
    map_Forall2 R ∅ m2 → m2 = ∅.
Proof.
  intros HForall2.
  apply map_Forall2_dom_L in HForall2 as Hdom.
  rewrite dom_empty_L in Hdom.
  symmetry in Hdom.
  by apply dom_empty_inv_L in Hdom.
Qed.

Lemma map_Forall2_empty_r_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (R : A → B → Prop) (m1 : M A) :
    map_Forall2 R m1 ∅ → m1 = ∅.
Proof.
  intros HForall2.
  apply map_Forall2_dom_L in HForall2 as Hdom.
  rewrite dom_empty_L in Hdom.
  by apply dom_empty_inv_L in Hdom.
Qed.

Lemma map_Forall2_empty `{FinMap K M} {A B} (R : A → B → Prop):
  map_Forall2 R (∅ : M A) (∅ : M B).
Proof.
  unfold map_Forall2, map_relation.
  intros i. by rewrite 2 lookup_empty.
Qed.

Lemma map_Forall2_impl_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (R1 R2 : A → B → Prop) :
    (∀ x y, R1 x y → R2 x y) →
      ∀ (m1 : M A) (m2 : M B),
        map_Forall2 R1 m1 m2 → map_Forall2 R2 m1 m2.
Proof.
  intros HR1R2 ?? HForall2.
  unfold map_Forall2, map_relation, option_relation in *.
  intros j. pose proof (HForall2 j). clear HForall2.
  case_match; case_match; try done.
  by apply HR1R2.
Qed.

Lemma map_Forall2_fmap_r_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B C}
  (R : A → C → Prop) (m1 : M A) (m2 : M B) (f : B → C) :
    map_Forall2 R m1 (f <$> m2) → map_Forall2 (λ x y, R x (f y)) m1 m2.
Proof.
  intros HForall2.
  unfold map_Forall2, map_relation, option_relation in *.
  intros j. pose proof (HForall2 j). clear HForall2.
  case_match; case_match; try done; case_match;
    rewrite lookup_fmap in H16; rewrite H17 in H16; by simplify_eq/=.
Qed.

Lemma map_Forall2_eq_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A}
  (m1 m2 : M A) :
    m1 = m2 ↔ map_Forall2 (=) m1 m2.
Proof.
  split; revert m2.
  - induction m1 using map_ind; intros m2 Heq; inv Heq.
    + apply map_Forall2_empty.
    + apply map_Forall2_insert_L; try done. by apply IHm1.
  - induction m1 using map_ind; intros m2 HForall2.
    + by apply map_Forall2_empty_l_L in HForall2.
    + apply map_Forall2_destruct in HForall2 as Hm.
      destruct Hm as [y [m2' [Him2' Heqm2]]]. subst.
      apply map_Forall2_insert_inv in HForall2 as [Heqxy HForall2].
      rewrite 2 delete_notin in HForall2 by done.
      apply IHm1 in HForall2. by subst.
Qed.

Lemma map_insert_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A}
  (i : K) (x y : A) (m1 m2 : M A) :
    x = y →
    delete i m1 = delete i m2 →
    <[i := x]>m1 = <[i := y]>m2.
Proof.
  intros Heq Hdel.
  apply map_Forall2_eq_L.
  eapply map_Forall2_insert_weak; [done|].
  by apply map_Forall2_eq_L.
Qed.

Lemma map_insert_rev_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A}
  (m1 m2 : M A) (i : K) (x y : A) :
    <[i := x]>m1 = <[i := y]>m2 → x = y ∧ delete i m1 = delete i m2.
Proof.
  intros Heq. apply map_Forall2_eq_L in Heq.
  apply map_Forall2_insert_inv in Heq as [Heq1 Heq2].
  by apply map_Forall2_eq_L in Heq2.
Qed.

Lemma map_insert_rev_1_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A}
  (m1 m2 : M A) (i : K) (x y : A) :
    <[i := x]>m1 = <[i := y]>m2 → x = y.
Proof. apply map_insert_rev_L. Qed.

Lemma map_insert_rev_2_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A}
  (m1 m2 : M A) (i : K) (x y : A) :
    <[i := x]>m1 = <[i := y]>m2 → delete i m1 = delete i m2.
Proof. apply map_insert_rev_L. Qed.

Lemma map_Forall2_alt_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (R : A → B → Prop) (m1 : M A) (m2 : M B) :
    map_Forall2 R m1 m2 ↔
      dom m1 = dom m2 ∧ ∀ i x y, m1 !! i = Some x → m2 !! i = Some y → R x y.
Proof.
  split.
  - intros HForall2.
    split.
    + by apply map_Forall2_dom_L in HForall2.
    + intros i x y Him1 Him2.
      unfold map_Forall2, map_relation, option_relation in HForall2.
      pose proof (HForall2 i). clear HForall2.
      by simplify_option_eq.
  - intros [Hdom HForall2].
    unfold map_Forall2, map_relation, option_relation.
    intros j.
    case_match; case_match; try done.
    + by eapply HForall2.
    + apply mk_is_Some in H14.
      apply not_elem_of_dom in H15.
      apply elem_of_dom in H14.
      set_solver.
    + apply not_elem_of_dom in H14.
      apply mk_is_Some in H15.
      apply elem_of_dom in H15.
      set_solver.
Qed.

(** Relation between map_mapM and map_Forall2 *)

Lemma map_mapM_Some_1_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (f : A → option B) (m1 : M A) (m2 : M B) :
    map_mapM f m1 = Some m2 → map_Forall2 (λ x y, f x = Some y) m1 m2.
Proof.
  revert m1 m2 f.
  induction m1 using map_ind.
  - intros m2 f Hmap_mapM.
    unfold map_mapM in Hmap_mapM.
    rewrite map_fold_empty in Hmap_mapM.
    simplify_option_eq. apply map_Forall2_empty.
  - intros m2 f Hmap_mapM.
    csimpl in Hmap_mapM.
    unfold map_mapM in Hmap_mapM.
    csimpl in Hmap_mapM.
    rewrite map_fold_insert_L in Hmap_mapM.
    + simplify_option_eq.
      apply IHm1 in Heqo.
      apply map_Forall2_insert_L; try done.
      apply not_elem_of_dom in H14.
      apply not_elem_of_dom.
      apply map_Forall2_dom_L in Heqo.
      set_solver.
    + intros.
      destruct y; simplify_option_eq; try done.
      destruct (f z2); simplify_option_eq.
      * destruct (f z1); simplify_option_eq; try done.
        f_equal. by apply insert_commute.
      * destruct (f z1); by simplify_option_eq.
    + done.
Qed.

Lemma map_mapM_Some_2_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (f : A → option B) (m1 : M A) (m2 : M B) :
    map_Forall2 (λ x y, f x = Some y) m1 m2 → map_mapM f m1 = Some m2.
Proof.
  revert m2.
  induction m1 using map_ind; intros m2 HForall2.
  - unfold map_mapM. rewrite map_fold_empty.
    apply map_Forall2_empty_l_L in HForall2.
    by simplify_eq.
  - destruct (map_Forall2_destruct _ _ _ _ _ HForall2) as
      [y [m2' [HForall21 HForall22]]]. subst.
    destruct (map_Forall2_insert_inv_strict _ _ _ _ _ _ H14 HForall21 HForall2) as
      [Hfy HForall22].
    apply IHm1 in HForall22.
    unfold map_mapM.
    rewrite map_fold_insert_L; try by simplify_option_eq.
    intros.
    destruct y0; simplify_option_eq; try done.
    destruct (f z2); simplify_option_eq.
    * destruct (f z1); simplify_option_eq; try done.
      f_equal. by apply insert_commute.
    * destruct (f z1); by simplify_option_eq.
Qed.

Lemma map_mapM_Some_L `{FinMapDom K M D} `{!LeibnizEquiv D} {A B}
  (f : A → option B) (m1 : M A) (m2 : M B) :
    map_mapM f m1 = Some m2 ↔ map_Forall2 (λ x y, f x = Some y) m1 m2.
Proof. split; [apply map_mapM_Some_1_L | apply map_mapM_Some_2_L]. Qed.