Module memory_injections

Require Export references memory_basics.

Inductive meminj (K : Set) :=
  | meminj_id : meminj K
  | meminj_map : indexmap (index * ref K) → meminj K.
Arguments meminj_id {_}.
Arguments meminj_map {_} _.
Instance meminj_dec {K : Set} `{∀ k1 k2 : K, Decision (k1 = k2)}
  (f g : meminj K) : Decision (f = g).
Proof. solve_decision. Defined.
Instance meminj_lookup {K} : Lookup index (index * ref K) (meminj K) :=
  λ o f, match f with meminj_id => Some (o, []) | meminj_map m => m !! o end.
Definition meminj_compose {K} (f g : meminj K) : meminj K :=
  match f, g with
  | meminj_id, meminj_id => meminj_id
  | meminj_map m, meminj_id => meminj_map m
  | meminj_id, meminj_map m => meminj_map m
  | meminj_map m1, meminj_map m2 => meminj_map $
     mergeyr _ : option (index * ref K),
       '(y1,r1) ← yr; '(y2,r2) ← m1 !! y1; Some (y2, r1 ++ r2)) m2
  end.
Arguments meminj_compose _ !_ !_ /.
Infix "◎" := meminj_compose (at level 40, left associativity) : C_scope.
Notation "(◎)" := meminj_compose (only parsing) : C_scope.

Definition meminj_injective {K} (f : meminj K) : Prop := ∀ o1 o2 o r1 r2,
  f !! o1 = Some (o,r1) → f !! o2 = Some (o,r2) → o1 = o2r1r2.
Instance meminj_subseteq {K} : SubsetEq (meminj K) := λ f1 f2,
  ∀ o o' r', f1 !! o = Some (o',r') → f2 !! o = Some (o',r').

Section meminj.
Context {K : Set}.
Implicit Types f g : meminj K.
Implicit Types o : index.
Implicit Types r : ref K.

Lemma meminj_eq f g : (∀ o, f !! o = g !! o) → f = g.
Proof.
  intros Hfg. destruct f as [|m1], g as [|m2].
  * done.
  * generalize (Hfg (fresh (dom _ m2))); unfold lookup; simpl.
    by rewrite (proj1 (not_elem_of_dom _ _)) by (apply is_fresh).
  * generalize (Hfg (fresh (dom _ m1))); unfold lookup; simpl.
    by rewrite (proj1 (not_elem_of_dom _ _)) by (apply is_fresh).
  * f_equal. apply map_eq, Hfg.
Qed.


Lemma lookup_meminj_id o : @meminj_id K !! o = Some (o, []).
Proof. done. Qed.
Lemma lookup_meminj_id_Some o1 o2 r :
  meminj_id !! o1 = Some (o2,r) ↔ o2 = o1r = [].
Proof. rewrite lookup_meminj_id; naive_solver. Qed.
Lemma lookup_meminj_compose f g o :
  (fg) !! o = '(y1,r1) ← g !! o; '(y2,r2) ← f !! y1; Some (y2,r1 ++ r2).
Proof.
  unfold lookup; destruct f as [|m1], g as [|m2]; csimpl.
  * done.
  * by destruct (_ !! o) as [[??]|]; csimpl; rewrite ?(right_id_L [] (++)).
  * by destruct (_ !! o) as [[??]|].
  * by rewrite lookup_merge by done.
Qed.

Lemma lookup_meminj_compose_Some f g o1 o3 r :
  (fg) !! o1 = Some (o3,r) ↔
  ∃ o2 r2 r3, g !! o1 = Some (o2,r2) ∧ f !! o2 = Some (o3,r3) ∧ r = r2 ++ r3.
Proof.
  rewrite lookup_meminj_compose. split.
  * intros. destruct (g !! o1) as [[o2 r2]|] eqn:?; simplify_equality'.
    destruct (f !! o2) as [[??]|] eqn:?; naive_solver.
  * by intros (?&?&?&?&?&?); simplify_option_equality.
Qed.


Global Instance: LeftId (@eq (meminj K)) meminj_id (◎).
Proof. by intros []. Qed.
Global Instance: RightId (@eq (meminj K)) meminj_id (◎).
Proof. by intros []. Qed.
Global Instance: Associative (@eq (meminj K)) (◎).
Proof.
  intros f g h. apply meminj_eq. intros o1. rewrite !lookup_meminj_compose.
  destruct (h !! o1) as [[o2 r2]|]; csimpl; [|done].
  rewrite !lookup_meminj_compose.
  destruct (g !! o2) as [[o3 r3]|]; csimpl; [|done].
  by destruct (f !! o3) as [[??]|]; csimpl; rewrite ?(associative_L (++)).
Qed.

Lemma meminj_positive_l f g : fg = meminj_idf = meminj_id.
Proof. by destruct f, g. Qed.
Lemma meminj_positive_r f g : fg = meminj_idg = meminj_id.
Proof. by destruct f, g. Qed.

Lemma meminj_id_injective : meminj_injective (@meminj_id K).
Proof. intros x1 x2 y r1 r2; rewrite !lookup_meminj_id; naive_solver. Qed.
Lemma meminj_compose_injective f g :
  meminj_injective fmeminj_injective gmeminj_injective (fg).
Proof.
  intros Hf Hg o1 o2 o r1 r2; rewrite !lookup_meminj_compose_Some.
  intros (o1'&r1'&r1''&?&?&->) (o2'&r2'&r2''&?&?&->).
  destruct (decide (o1 = o2)); [by left|].
  destruct (Hf o1' o2' o r1'' r2'') as [->|?]; simplify_equality'; auto.
  { destruct (Hg o1 o2 o2' r1' r2') as [->|?]; auto.
    right. by apply ref_disjoint_here_app_1. }
  right. by apply ref_disjoint_app_l, ref_disjoint_app_r.
Qed.

Lemma meminj_injective_alt f o1 o2 o r1 r2 :
  meminj_injective ff !! o1 = Some (o,r1) → f !! o2 = Some (o,r2) →
  o1 = o2o1o2r1r2.
Proof.
  intros Hf ??. destruct (decide (o1 = o2)); [by left|].
  destruct (Hf o1 o2 o r1 r2); auto.
Qed.

Lemma meminj_injective_ne f o1 o2 o3 o4 r2 r4 :
  meminj_injective ff !! o1 = Some (o2,r2) → f !! o3 = Some (o4,r4) →
  o1o3o2o4o2 = o4r2r4.
Proof.
  intros Hf ???. destruct (decide (o2 = o4)) as [->|]; auto.
  destruct (Hf o1 o3 o4 r2 r4); auto.
Qed.

Global Instance: PartialOrder ((⊆) : relation (meminj K)).
Proof.
  repeat split.
  * by intros f o o' r'.
  * intros f1 f2 f3. unfold subseteq, meminj_subseteq. naive_solver.
  * intros f1 f2; unfold subseteq, meminj_subseteq; intros.
    apply meminj_eq. intros o. apply option_eq. intros [o' r']; naive_solver.
Qed.

End meminj.