Raw File
require import Option.
require import Pair.
require import NewFSet.

(*** Finite maps are defined fully extensionally *)
type ('a,'b) map.

op "_.[_]"   : ('a,'b) map -> 'a -> 'b option.

pred (==) (m1 m2:('a,'b) map) = forall x,
  m1.[x] = m2.[x].

lemma eq_refl (m:('a,'b) map): m == m
by [].

lemma eq_trans (m1 m2 m3:('a,'b) map):
  m1 == m2 => m2 == m3 => m1 == m3
by (move=> eq_m1_m2 eq_m2_m3 x; rewrite eq_m1_m2 eq_m2_m3).

lemma eq_symm (m1 m2:('a,'b) map):
  m1 == m2 => m2 == m1
by (move=> eq_m1_m2 x; rewrite eq_m1_m2).

axiom mapP (m1 m2:('a,'b) map):
  m1 = m2 <=> m1 == m2.

(*** "Less-defined-than" partial order *)
pred (<=) (m1 m2:('a,'b) map) = forall x,
  m1.[x] <> None => m1.[x] = m2.[x].

lemma leq_refl (m:('a,'b) map): m <= m
by [].

lemma leq_trans (m1 m2 m3:('a,'b) map):
  m1 <= m2 => m2 <= m3 => m1 <= m3.
proof.
  move=> leq_m1_m2 leq_m2_m3 x; rewrite -neqF=> x_in_m1.
  cut eq_m1_m2:= leq_m1_m2 x _; first by rewrite x_in_m1.
  cut eq_m2_m3:= leq_m2_m3 x _;
    first by apply (absurd true)=> //; rewrite -eq_m1_m2 x_in_m1.
  by rewrite eq_m1_m2 eq_m2_m3.
qed.

lemma leq_asym (m1 m2:('a,'b) map):
  m1 <= m2 => m2 <= m1 => m1 = m2.
proof.
  move=> leq_m1_m2 leq_m2_m1; apply mapP=> x.
  case (m1.[x] <> None)=> [x_nin_m1 | //= x_in_m1].
    by rewrite leq_m1_m2.
    case (m2.[x] <> None)=> [x_nin_m2 | //= -> //].
    by rewrite leq_m2_m1.
qed.

(*** Operators *)
(** map0 *)
op map0:('a,'b) map.

axiom map0E x: map0<:'a,'b>.[x] = None.

(** domain *)
op dom: ('a,'b) map -> 'a fset.

axiom in_dom (m:('a,'b) map) x:
  mem (dom m) x <=> m.[x] <> None.

lemma in_dom_map0 x: mem (dom map0<:'a,'b>) x <=> false.
proof. by rewrite in_dom map0E. qed.

lemma dom_map0: dom map0<:'a,'b> = set0.
proof. by rewrite setP=> x; rewrite in_set0 in_dom_map0. qed.

(** range *)
op rng: ('a,'b) map -> 'b fset.

axiom in_rng (m:('a,'b) map) y:
  mem (rng m) y <=> (exists x, m.[x] = Some y).

lemma in_rng_map0 y: mem (rng map0<:'a,'b>) y <=> false.
proof. by rewrite in_rng; split=> //; case => x; rewrite map0E. qed.

lemma rng_map0: rng map0<:'a,'b> = set0.
proof. by rewrite setP=> x; rewrite in_rng_map0 in_set0. qed.

(** union of maps with disjoint domains *)
op mapU: ('a,'b) map -> ('a,'b) map -> ('a,'b) map.

axiom get_mapU (m1 m2:('a,'b) map) x:
  setI (dom m1) (dom m2) = set0 =>
  (mapU m1 m2).[x] =
    if (mem (dom m1) x) then m1.[x]
                        else m2.[x].

lemma in_dom_mapU (m1 m2:('a,'b) map) x:
  setI (dom m1) (dom m2) = set0 =>
  mem (dom (mapU m1 m2)) x <=> mem (setU (dom m1) (dom m2)) x.
proof.
  intros=> disj_dom; rewrite in_setU !in_dom get_mapU //.
  by case (mem (dom m1) x); rewrite in_dom /= => ->.
qed.

lemma dom_mapU (m1 m2:('a,'b) map):
  setI (dom m1) (dom m2) = set0 =>
  dom (mapU m1 m2) = setU (dom m1) (dom m2).
proof. by intros=> disj_dom; rewrite setP=> x; apply in_dom_mapU. qed.

(** splitting of maps according to a predicate *)
op mapS: ('a,'b) map -> ('a -> 'b -> bool) -> ('a,'b) map * ('a,'b) map.

axiom get_mapSl (m:('a,'b) map) P x:
  (fst (mapS m P)).[x] =
    if omap (P x) m.[x] = Some true then m.[x] else None.

axiom get_mapSr (m:('a,'b) map) P x:
  (snd (mapS m P)).[x] =
    if omap (P x) m.[x] = Some false then m.[x] else None.

lemma get_mapSl_nin (m:('a,'b) map) P x:
  !mem (dom m) x =>
  (fst (mapS m P)).[x] = None.
proof. by rewrite in_dom get_mapSl /= => ->. qed.

lemma get_mapSr_nin (m:('a,'b) map) P x:
  !mem (dom m) x =>
  (snd (mapS m P)).[x] = None.
proof. by rewrite in_dom get_mapSr /= => ->. qed.

lemma get_mapSl_in (m:('a,'b) map) P x:
  mem (dom m) x =>
  (fst (mapS m P)).[x] = if P x (oget m.[x]) = true then m.[x] else None.
proof.
  rewrite in_dom get_mapSl; case (m.[x])=> //= x'; rewrite /oget //=.
  by cut ->: (Some (P x x') = Some true) <=> (P x x' = true) by smt.
qed.

lemma get_mapSr_in (m:('a,'b) map) P x:
  mem (dom m) x =>
  (snd (mapS m P)).[x] = if P x (oget m.[x]) = false then m.[x] else None.
proof.
  rewrite in_dom get_mapSr; case (m.[x])=> //= x'; rewrite /oget //=.
  by cut ->: (Some (P x x') = Some false) <=> (P x x' = false) by smt.
qed.

lemma in_dom_mapSl (m:('a,'b) map) P x:
  mem (dom (fst (mapS m P))) x <=> omap (P x) m.[x] = Some true.
proof. by rewrite in_dom get_mapSl; case (omap (P x) m.[x] = Some true); case (m.[x]). qed.

lemma in_dom_mapSr (m:('a,'b) map) P x:
  mem (dom (snd (mapS m P))) x <=> omap (P x) m.[x] = Some false.
proof. by rewrite in_dom get_mapSr; case (omap (P x) m.[x] = Some false); case (m.[x]). qed.

(* note: we cannot express set-equality versions of these, since P may define an infinite set *)

lemma mapU_mapS (m:('a,'b) map) P:
  mapU (fst (mapS m P)) (snd (mapS m P)) = m.
proof.
  cut disj_dom: setI (dom (fst (mapS m P))) (dom (snd (mapS m P))) = set0
    by (rewrite setP=> x'; rewrite in_setI in_dom_mapSl in_dom_mapSr in_set0;
        case (omap (P x') m.[x'])=> //=; smt).
  rewrite mapP=> x; rewrite get_mapU //.
  rewrite in_dom_mapSl get_mapSl get_mapSr //; case (m.[x])=> //= y.
  by case (P x y)=> //=; cut ->: (Some false = Some true) = false by smt.
qed.

(** set *)
op "_.[_<-_]": ('a,'b) map -> 'a -> 'b -> ('a,'b) map.

axiom get_set (m:('a,'b) map) x y x':
  m.[x <- y].[x'] = if x = x' then Some y else m.[x'].

lemma get_set_eq (m:('a,'b) map) x y:
  m.[x <- y].[x] = Some y
by rewrite get_set.

lemma get_set_neq (m:('a,'b) map) x y x':
  x <> x' =>
  m.[x <- y].[x'] = m.[x']
by rewrite get_set -neqF=> ->.

lemma set_set (m:('a,'b) map) x y x' y':
  m.[x <- y].[x' <- y'] =
    if x = x' then m.[x' <- y']
              else m.[x' <- y'].[x <- y].
proof.
case (x = x')=> [<- | ].
  rewrite mapP=> x0; rewrite (get_set m.[x <- y]) (get_set m x y').
  by case (x = x0)=> //= neq_x_x0; rewrite get_set_neq.
  rewrite -neqF mapP=> neq_x_x' x0; rewrite !get_set.
  by case (x = x0)=> //= <-; rewrite (eq_sym x' x) neq_x_x'.
qed.

lemma set_set_eq y (m:('a,'b) map) x y':
  m.[x <- y].[x <- y'] = m.[x <- y']
by rewrite set_set.

lemma set_set_neq (m:('a,'b) map) x y x' y':
  x <> x' =>
  m.[x <- y].[x' <- y'] = m.[x' <- y'].[x <- y]
by rewrite -neqF set_set=> ->.

lemma in_dom_set (m:('a,'b) map) x y x0:
  mem (dom m.[x <- y]) x0 <=> (x = x0 \/ mem (dom m) x0).
proof. by rewrite !in_dom get_set; case (x = x0). qed.

lemma in_dom_set_eq (m:('a,'b) map) x y: mem (dom m.[x <- y]) x.
proof. by rewrite in_dom_set. qed.

lemma in_dom_set_neq (m:('a,'b) map) x y x0:
  x <> x0 =>
  mem (dom m.[x <- y]) x0 = mem (dom m) x0.
proof. by rewrite -neqF in_dom_set=> ->. qed.

lemma dom_set (m:('a,'b) map) x y: dom m.[x <- y] = setU (set1 x) (dom m).
proof. by rewrite setP=> x0; rewrite in_dom_set in_setU in_set1 (eq_sym x0 x). qed.

lemma rng_set_nin (m:('a,'b) map) x y:
  !mem (dom m) x =>
  rng (m.[x <- y]) = setU (set1 y) (rng m).
proof.
  rewrite in_dom setP /= => x_nin_m y0.
  rewrite in_rng in_setU in_set1 (eq_sym y0 y).
  split=> [[x'] | [y_y0 | ]].
    case (x = x')=> [<- | neq_x_x'].
      by rewrite get_set_eq=> eq_some; left; apply someI.
      by rewrite get_set_neq // in_rng=> mx_y0; right; exists x'.
    by exists x; rewrite get_set_eq y_y0.
    rewrite in_rng=> [x0 mx0_y0]; exists x0.
    rewrite get_set; case (x = x0)=> //=; apply (absurd (x = x0))=> _.
    by rewrite -not_def=> x_x0; generalize x_nin_m; rewrite x_x0 mx0_y0.
qed.

(* todo: interaction of set with splitting and joining *)

(** remove *)
op rm: 'a -> ('a,'b) map -> ('a,'b) map.

axiom get_rm (m:('a,'b) map) x x':
  (rm x m).[x'] = if (x = x') then None else m.[x'].

lemma get_rm_eq (m:('a,'b) map) x:
  (rm x m).[x] = None
by rewrite get_rm.

lemma get_rm_neq (m:('a,'b) map) x x':
  x <> x' =>
  (rm x m).[x'] = m.[x']
by rewrite -neqF get_rm=> ->.

lemma in_dom_rm (m:('a,'b) map) x x':
  mem (dom (rm x m)) x' =
    if (x = x') then false
                else mem (dom m) x'.
proof. by rewrite in_dom get_rm in_dom; case (x = x'). qed.

lemma in_dom_rm_eq (m:('a,'b) map) x:
  mem (dom (rm x m)) x <=> false
by rewrite in_dom_rm.

lemma in_dom_rm_neq (m:('a,'b) map) x x':
  x <> x' =>
  mem (dom (rm x m)) x' = mem (dom m) x'.
proof. by rewrite -neqF in_dom_rm=> ->. qed.

lemma dom_rm (m:('a,'b) map) x:
  dom (rm x m) = setD (dom m) (set1 x).
proof. by rewrite setP=> x0; rewrite in_dom_rm in_setD in_set1 (eq_sym x0 x); case (x = x0). qed.

lemma set_rm (m:('a,'b) map) x y x':
  (rm x' m).[x <- y] =
    if (x = x') then m.[x <- y]
                else rm x' m.[x <- y].
proof.
rewrite mapP=> x0; rewrite fun_if2 !get_set !get_rm; case (x = x').
  by case (x = x0)=> //=; rewrite -neqF=> neq_x_x0 <-; rewrite neq_x_x0.
  case (x = x0)=> //=; rewrite -!neqF (eq_sym x' x0).
    by move=> <- ->; rewrite get_set_eq.
    by rewrite get_set=> ->.
qed.

(* todo: interaction of removal with splitting, joining and setting *)
back to top