src/HOL/Library/Finite_Map.thy
author Lars Hupel <lars.hupel@mytum.de>
Fri Aug 17 21:34:56 2018 +0200 (11 months ago)
changeset 68757 e7e3776385ba
parent 68463 410818a69ee3
child 68810 db97c1ed115e
permissions -rw-r--r--
Finite_Map: monotonicity
lars@63885
     1
(*  Title:      HOL/Library/Finite_Map.thy
lars@63885
     2
    Author:     Lars Hupel, TU M√ľnchen
lars@63885
     3
*)
lars@63885
     4
lars@63885
     5
section \<open>Type of finite maps defined as a subtype of maps\<close>
lars@63885
     6
lars@63885
     7
theory Finite_Map
lars@68462
     8
  imports FSet AList Conditional_Parametricity
wenzelm@67780
     9
  abbrevs "(=" = "\<subseteq>\<^sub>f"
lars@63885
    10
begin
lars@63885
    11
lars@63885
    12
subsection \<open>Auxiliary constants and lemmas over @{type map}\<close>
lars@63885
    13
lars@68462
    14
parametric_constant map_add_transfer[transfer_rule]: map_add_def
lars@68462
    15
parametric_constant map_of_transfer[transfer_rule]: map_of_def
lars@68462
    16
lars@63885
    17
context includes lifting_syntax begin
lars@63885
    18
lars@63885
    19
abbreviation rel_map :: "('b \<Rightarrow> 'c \<Rightarrow> bool) \<Rightarrow> ('a \<rightharpoonup> 'b) \<Rightarrow> ('a \<rightharpoonup> 'c) \<Rightarrow> bool" where
nipkow@67399
    20
"rel_map f \<equiv> (=) ===> rel_option f"
lars@63885
    21
lars@63885
    22
lemma ran_transfer[transfer_rule]: "(rel_map A ===> rel_set A) ran ran"
lars@63885
    23
proof
lars@63885
    24
  fix m n
lars@63885
    25
  assume "rel_map A m n"
lars@63885
    26
  show "rel_set A (ran m) (ran n)"
lars@63885
    27
    proof (rule rel_setI)
lars@63885
    28
      fix x
lars@63885
    29
      assume "x \<in> ran m"
lars@63885
    30
      then obtain a where "m a = Some x"
lars@63885
    31
        unfolding ran_def by auto
lars@63885
    32
lars@63885
    33
      have "rel_option A (m a) (n a)"
lars@63885
    34
        using \<open>rel_map A m n\<close>
lars@63885
    35
        by (auto dest: rel_funD)
lars@63885
    36
      then obtain y where "n a = Some y" "A x y"
lars@63885
    37
        unfolding \<open>m a = _\<close>
lars@63885
    38
        by cases auto
lars@64180
    39
      then show "\<exists>y \<in> ran n. A x y"
lars@63885
    40
        unfolding ran_def by blast
lars@63885
    41
    next
lars@63885
    42
      fix y
lars@63885
    43
      assume "y \<in> ran n"
lars@63885
    44
      then obtain a where "n a = Some y"
lars@63885
    45
        unfolding ran_def by auto
lars@63885
    46
lars@63885
    47
      have "rel_option A (m a) (n a)"
lars@63885
    48
        using \<open>rel_map A m n\<close>
lars@63885
    49
        by (auto dest: rel_funD)
lars@63885
    50
      then obtain x where "m a = Some x" "A x y"
lars@63885
    51
        unfolding \<open>n a = _\<close>
lars@63885
    52
        by cases auto
lars@64180
    53
      then show "\<exists>x \<in> ran m. A x y"
lars@63885
    54
        unfolding ran_def by blast
lars@63885
    55
    qed
lars@63885
    56
qed
lars@63885
    57
lars@63885
    58
lemma ran_alt_def: "ran m = (the \<circ> m) ` dom m"
lars@63885
    59
unfolding ran_def dom_def by force
lars@63885
    60
lars@68462
    61
parametric_constant dom_transfer[transfer_rule]: dom_def
lars@63885
    62
lars@63885
    63
definition map_upd :: "'a \<Rightarrow> 'b \<Rightarrow> ('a \<rightharpoonup> 'b) \<Rightarrow> ('a \<rightharpoonup> 'b)" where
lars@63885
    64
"map_upd k v m = m(k \<mapsto> v)"
lars@63885
    65
lars@68462
    66
parametric_constant map_upd_transfer[transfer_rule]: map_upd_def
lars@63885
    67
lars@63885
    68
definition map_filter :: "('a \<Rightarrow> bool) \<Rightarrow> ('a \<rightharpoonup> 'b) \<Rightarrow> ('a \<rightharpoonup> 'b)" where
lars@63885
    69
"map_filter P m = (\<lambda>x. if P x then m x else None)"
lars@63885
    70
lars@68462
    71
parametric_constant map_filter_transfer[transfer_rule]: map_filter_def
lars@68462
    72
nipkow@68386
    73
lemma map_filter_map_of[simp]: "map_filter P (map_of m) = map_of [(k, _) \<leftarrow> m. P k]"
lars@63885
    74
proof
lars@63885
    75
  fix x
nipkow@68386
    76
  show "map_filter P (map_of m) x = map_of [(k, _) \<leftarrow> m. P k] x"
lars@63885
    77
    by (induct m) (auto simp: map_filter_def)
lars@63885
    78
qed
lars@63885
    79
lars@63885
    80
lemma map_filter_finite[intro]:
lars@63885
    81
  assumes "finite (dom m)"
lars@63885
    82
  shows "finite (dom (map_filter P m))"
lars@63885
    83
proof -
lars@63885
    84
  have "dom (map_filter P m) = Set.filter P (dom m)"
lars@63885
    85
    unfolding map_filter_def Set.filter_def dom_def
lars@63885
    86
    by auto
lars@64180
    87
  then show ?thesis
lars@63885
    88
    using assms
lars@63885
    89
    by (simp add: Set.filter_def)
lars@63885
    90
qed
lars@63885
    91
lars@63885
    92
definition map_drop :: "'a \<Rightarrow> ('a \<rightharpoonup> 'b) \<Rightarrow> ('a \<rightharpoonup> 'b)" where
lars@63885
    93
"map_drop a = map_filter (\<lambda>a'. a' \<noteq> a)"
lars@63885
    94
lars@68462
    95
parametric_constant map_drop_transfer[transfer_rule]: map_drop_def
lars@63885
    96
lars@63885
    97
definition map_drop_set :: "'a set \<Rightarrow> ('a \<rightharpoonup> 'b) \<Rightarrow> ('a \<rightharpoonup> 'b)" where
lars@63885
    98
"map_drop_set A = map_filter (\<lambda>a. a \<notin> A)"
lars@63885
    99
lars@68462
   100
parametric_constant map_drop_set_transfer[transfer_rule]: map_drop_set_def
lars@63885
   101
lars@63885
   102
definition map_restrict_set :: "'a set \<Rightarrow> ('a \<rightharpoonup> 'b) \<Rightarrow> ('a \<rightharpoonup> 'b)" where
lars@63885
   103
"map_restrict_set A = map_filter (\<lambda>a. a \<in> A)"
lars@63885
   104
lars@68462
   105
parametric_constant map_restrict_set_transfer[transfer_rule]: map_restrict_set_def
lars@63885
   106
lars@63885
   107
definition map_pred :: "('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow> ('a \<rightharpoonup> 'b) \<Rightarrow> bool" where
lars@63885
   108
"map_pred P m \<longleftrightarrow> (\<forall>x. case m x of None \<Rightarrow> True | Some y \<Rightarrow> P x y)"
lars@63885
   109
lars@68462
   110
parametric_constant map_pred_transfer[transfer_rule]: map_pred_def
lars@63885
   111
lars@63885
   112
definition rel_map_on_set :: "'a set \<Rightarrow> ('b \<Rightarrow> 'c \<Rightarrow> bool) \<Rightarrow> ('a \<rightharpoonup> 'b) \<Rightarrow> ('a \<rightharpoonup> 'c) \<Rightarrow> bool" where
lars@63885
   113
"rel_map_on_set S P = eq_onp (\<lambda>x. x \<in> S) ===> rel_option P"
lars@66267
   114
lars@66282
   115
definition set_of_map :: "('a \<rightharpoonup> 'b) \<Rightarrow> ('a \<times> 'b) set" where
lars@66282
   116
"set_of_map m = {(k, v)|k v. m k = Some v}"
lars@66282
   117
lars@66282
   118
lemma set_of_map_alt_def: "set_of_map m = (\<lambda>k. (k, the (m k))) ` dom m"
lars@66282
   119
unfolding set_of_map_def dom_def
lars@66282
   120
by auto
lars@66282
   121
lars@66282
   122
lemma set_of_map_finite: "finite (dom m) \<Longrightarrow> finite (set_of_map m)"
lars@66282
   123
unfolding set_of_map_alt_def
lars@66282
   124
by auto
lars@66282
   125
lars@66282
   126
lemma set_of_map_inj: "inj set_of_map"
lars@66282
   127
proof
lars@66282
   128
  fix x y
lars@66282
   129
  assume "set_of_map x = set_of_map y"
lars@66282
   130
  hence "(x a = Some b) = (y a = Some b)" for a b
lars@66282
   131
    unfolding set_of_map_def by auto
lars@66282
   132
  hence "x k = y k" for k
lars@66282
   133
    by (metis not_None_eq)
lars@66282
   134
  thus "x = y" ..
lars@66282
   135
qed
lars@66282
   136
lars@63885
   137
end
lars@63885
   138
lars@63885
   139
lars@63885
   140
subsection \<open>Abstract characterisation\<close>
lars@63885
   141
lars@63885
   142
typedef ('a, 'b) fmap = "{m. finite (dom m)} :: ('a \<rightharpoonup> 'b) set"
lars@63885
   143
  morphisms fmlookup Abs_fmap
lars@63885
   144
proof
lars@63885
   145
  show "Map.empty \<in> {m. finite (dom m)}"
lars@63885
   146
    by auto
lars@63885
   147
qed
lars@63885
   148
lars@63885
   149
setup_lifting type_definition_fmap
lars@63885
   150
lars@63885
   151
lemma fmlookup_finite[intro, simp]: "finite (dom (fmlookup m))"
lars@63885
   152
using fmap.fmlookup by auto
lars@63885
   153
lars@63885
   154
lemma fmap_ext:
lars@63885
   155
  assumes "\<And>x. fmlookup m x = fmlookup n x"
lars@63885
   156
  shows "m = n"
lars@63885
   157
using assms
lars@63885
   158
by transfer' auto
lars@63885
   159
lars@63885
   160
lars@63885
   161
subsection \<open>Operations\<close>
lars@63885
   162
lars@63885
   163
context
lars@63885
   164
  includes fset.lifting
lars@63885
   165
begin
lars@63885
   166
lars@63885
   167
lift_definition fmran :: "('a, 'b) fmap \<Rightarrow> 'b fset"
lars@63885
   168
  is ran
lars@63885
   169
  parametric ran_transfer
lars@68462
   170
by (rule finite_ran)
lars@63885
   171
lars@66268
   172
lemma fmlookup_ran_iff: "y |\<in>| fmran m \<longleftrightarrow> (\<exists>x. fmlookup m x = Some y)"
lars@66268
   173
by transfer' (auto simp: ran_def)
lars@66268
   174
lars@66268
   175
lemma fmranI: "fmlookup m x = Some y \<Longrightarrow> y |\<in>| fmran m" by (auto simp: fmlookup_ran_iff)
lars@66268
   176
lars@66268
   177
lemma fmranE[elim]:
lars@66268
   178
  assumes "y |\<in>| fmran m"
lars@66268
   179
  obtains x where "fmlookup m x = Some y"
lars@66268
   180
using assms by (auto simp: fmlookup_ran_iff)
lars@63885
   181
lars@63885
   182
lift_definition fmdom :: "('a, 'b) fmap \<Rightarrow> 'a fset"
lars@63885
   183
  is dom
lars@63885
   184
  parametric dom_transfer
lars@63885
   185
.
lars@63885
   186
lars@66268
   187
lemma fmlookup_dom_iff: "x |\<in>| fmdom m \<longleftrightarrow> (\<exists>a. fmlookup m x = Some a)"
lars@66268
   188
by transfer' auto
lars@66268
   189
lars@66268
   190
lemma fmdom_notI: "fmlookup m x = None \<Longrightarrow> x |\<notin>| fmdom m" by (simp add: fmlookup_dom_iff)
lars@66268
   191
lemma fmdomI: "fmlookup m x = Some y \<Longrightarrow> x |\<in>| fmdom m" by (simp add: fmlookup_dom_iff)
lars@66268
   192
lemma fmdom_notD[dest]: "x |\<notin>| fmdom m \<Longrightarrow> fmlookup m x = None" by (simp add: fmlookup_dom_iff)
lars@66268
   193
lars@66268
   194
lemma fmdomE[elim]:
lars@66268
   195
  assumes "x |\<in>| fmdom m"
lars@66268
   196
  obtains y where "fmlookup m x = Some y"
lars@66268
   197
using assms by (auto simp: fmlookup_dom_iff)
lars@63885
   198
lars@63885
   199
lift_definition fmdom' :: "('a, 'b) fmap \<Rightarrow> 'a set"
lars@63885
   200
  is dom
lars@63885
   201
  parametric dom_transfer
lars@63885
   202
.
lars@63885
   203
lars@66268
   204
lemma fmlookup_dom'_iff: "x \<in> fmdom' m \<longleftrightarrow> (\<exists>a. fmlookup m x = Some a)"
lars@66268
   205
by transfer' auto
lars@66268
   206
lars@66268
   207
lemma fmdom'_notI: "fmlookup m x = None \<Longrightarrow> x \<notin> fmdom' m" by (simp add: fmlookup_dom'_iff)
lars@66268
   208
lemma fmdom'I: "fmlookup m x = Some y \<Longrightarrow> x \<in> fmdom' m" by (simp add: fmlookup_dom'_iff)
lars@66268
   209
lemma fmdom'_notD[dest]: "x \<notin> fmdom' m \<Longrightarrow> fmlookup m x = None" by (simp add: fmlookup_dom'_iff)
lars@63885
   210
lars@66268
   211
lemma fmdom'E[elim]:
lars@66268
   212
  assumes "x \<in> fmdom' m"
lars@66268
   213
  obtains x y where "fmlookup m x = Some y"
lars@66268
   214
using assms by (auto simp: fmlookup_dom'_iff)
lars@63885
   215
lars@66268
   216
lemma fmdom'_alt_def: "fmdom' m = fset (fmdom m)"
lars@66268
   217
by transfer' force
lars@63885
   218
lars@63885
   219
lift_definition fmempty :: "('a, 'b) fmap"
lars@63885
   220
  is Map.empty
lars@63885
   221
by simp
lars@63885
   222
lars@63885
   223
lemma fmempty_lookup[simp]: "fmlookup fmempty x = None"
lars@63885
   224
by transfer' simp
lars@63885
   225
lars@63885
   226
lemma fmdom_empty[simp]: "fmdom fmempty = {||}" by transfer' simp
lars@63885
   227
lemma fmdom'_empty[simp]: "fmdom' fmempty = {}" by transfer' simp
lars@66269
   228
lemma fmran_empty[simp]: "fmran fmempty = fempty" by transfer' (auto simp: ran_def map_filter_def)
lars@63885
   229
lars@63885
   230
lift_definition fmupd :: "'a \<Rightarrow> 'b \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap"
lars@63885
   231
  is map_upd
lars@63885
   232
  parametric map_upd_transfer
lars@63885
   233
unfolding map_upd_def[abs_def]
lars@63885
   234
by simp
lars@63885
   235
lars@63885
   236
lemma fmupd_lookup[simp]: "fmlookup (fmupd a b m) a' = (if a = a' then Some b else fmlookup m a')"
lars@63885
   237
by transfer' (auto simp: map_upd_def)
lars@63885
   238
lars@63885
   239
lemma fmdom_fmupd[simp]: "fmdom (fmupd a b m) = finsert a (fmdom m)" by transfer (simp add: map_upd_def)
lars@63885
   240
lemma fmdom'_fmupd[simp]: "fmdom' (fmupd a b m) = insert a (fmdom' m)" by transfer (simp add: map_upd_def)
lars@63885
   241
lars@63885
   242
lift_definition fmfilter :: "('a \<Rightarrow> bool) \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap"
lars@63885
   243
  is map_filter
lars@63885
   244
  parametric map_filter_transfer
lars@63885
   245
by auto
lars@63885
   246
lars@63885
   247
lemma fmdom_filter[simp]: "fmdom (fmfilter P m) = ffilter P (fmdom m)"
lars@63885
   248
by transfer' (auto simp: map_filter_def Set.filter_def split: if_splits)
lars@63885
   249
lars@63885
   250
lemma fmdom'_filter[simp]: "fmdom' (fmfilter P m) = Set.filter P (fmdom' m)"
lars@63885
   251
by transfer' (auto simp: map_filter_def Set.filter_def split: if_splits)
lars@63885
   252
lars@63885
   253
lemma fmlookup_filter[simp]: "fmlookup (fmfilter P m) x = (if P x then fmlookup m x else None)"
lars@63885
   254
by transfer' (auto simp: map_filter_def)
lars@63885
   255
lars@63885
   256
lemma fmfilter_empty[simp]: "fmfilter P fmempty = fmempty"
lars@63885
   257
by transfer' (auto simp: map_filter_def)
lars@63885
   258
lars@63900
   259
lemma fmfilter_true[simp]:
lars@66268
   260
  assumes "\<And>x y. fmlookup m x = Some y \<Longrightarrow> P x"
lars@63900
   261
  shows "fmfilter P m = m"
lars@63900
   262
proof (rule fmap_ext)
lars@63900
   263
  fix x
lars@63900
   264
  have "fmlookup m x = None" if "\<not> P x"
lars@66268
   265
    using that assms by fastforce
lars@64180
   266
  then show "fmlookup (fmfilter P m) x = fmlookup m x"
lars@63900
   267
    by simp
lars@63900
   268
qed
lars@63885
   269
lars@66268
   270
lemma fmfilter_false[simp]:
lars@66268
   271
  assumes "\<And>x y. fmlookup m x = Some y \<Longrightarrow> \<not> P x"
lars@66268
   272
  shows "fmfilter P m = fmempty"
lars@66268
   273
using assms by transfer' (fastforce simp: map_filter_def)
lars@63885
   274
lars@63885
   275
lemma fmfilter_comp[simp]: "fmfilter P (fmfilter Q m) = fmfilter (\<lambda>x. P x \<and> Q x) m"
lars@63885
   276
by transfer' (auto simp: map_filter_def)
lars@63885
   277
lars@63885
   278
lemma fmfilter_comm: "fmfilter P (fmfilter Q m) = fmfilter Q (fmfilter P m)"
lars@63885
   279
unfolding fmfilter_comp by meson
lars@63885
   280
lars@63885
   281
lemma fmfilter_cong[cong]:
lars@66268
   282
  assumes "\<And>x y. fmlookup m x = Some y \<Longrightarrow> P x = Q x"
lars@63885
   283
  shows "fmfilter P m = fmfilter Q m"
lars@63900
   284
proof (rule fmap_ext)
lars@63900
   285
  fix x
lars@63900
   286
  have "fmlookup m x = None" if "P x \<noteq> Q x"
lars@66268
   287
    using that assms by fastforce
lars@64180
   288
  then show "fmlookup (fmfilter P m) x = fmlookup (fmfilter Q m) x"
lars@63900
   289
    by auto
lars@63900
   290
qed
lars@63885
   291
lars@63885
   292
lemma fmfilter_cong'[fundef_cong]:
lars@67485
   293
  assumes "m = n" "\<And>x. x \<in> fmdom' m \<Longrightarrow> P x = Q x"
lars@67485
   294
  shows "fmfilter P m = fmfilter Q n"
lars@67485
   295
using assms(2) unfolding assms(1)
lars@66268
   296
by (rule fmfilter_cong) (metis fmdom'I)
lars@63885
   297
lars@63900
   298
lemma fmfilter_upd[simp]:
lars@63900
   299
  "fmfilter P (fmupd x y m) = (if P x then fmupd x y (fmfilter P m) else fmfilter P m)"
lars@63885
   300
by transfer' (auto simp: map_upd_def map_filter_def)
lars@63885
   301
lars@63885
   302
lift_definition fmdrop :: "'a \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap"
lars@63885
   303
  is map_drop
lars@63885
   304
  parametric map_drop_transfer
lars@63885
   305
unfolding map_drop_def by auto
lars@63885
   306
lars@63885
   307
lemma fmdrop_lookup[simp]: "fmlookup (fmdrop a m) a = None"
lars@63885
   308
by transfer' (auto simp: map_drop_def map_filter_def)
lars@63885
   309
lars@63885
   310
lift_definition fmdrop_set :: "'a set \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap"
lars@63885
   311
  is map_drop_set
lars@63885
   312
  parametric map_drop_set_transfer
lars@63885
   313
unfolding map_drop_set_def by auto
lars@63885
   314
lars@63885
   315
lift_definition fmdrop_fset :: "'a fset \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap"
lars@63885
   316
  is map_drop_set
lars@63885
   317
  parametric map_drop_set_transfer
lars@63885
   318
unfolding map_drop_set_def by auto
lars@63885
   319
lars@63885
   320
lift_definition fmrestrict_set :: "'a set \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap"
lars@63885
   321
  is map_restrict_set
lars@63885
   322
  parametric map_restrict_set_transfer
lars@63885
   323
unfolding map_restrict_set_def by auto
lars@63885
   324
lars@63885
   325
lift_definition fmrestrict_fset :: "'a fset \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap"
lars@63885
   326
  is map_restrict_set
lars@63885
   327
  parametric map_restrict_set_transfer
lars@63885
   328
unfolding map_restrict_set_def by auto
lars@63885
   329
lars@63885
   330
lemma fmfilter_alt_defs:
lars@63885
   331
  "fmdrop a = fmfilter (\<lambda>a'. a' \<noteq> a)"
lars@63885
   332
  "fmdrop_set A = fmfilter (\<lambda>a. a \<notin> A)"
lars@63885
   333
  "fmdrop_fset B = fmfilter (\<lambda>a. a |\<notin>| B)"
lars@63885
   334
  "fmrestrict_set A = fmfilter (\<lambda>a. a \<in> A)"
lars@63885
   335
  "fmrestrict_fset B = fmfilter (\<lambda>a. a |\<in>| B)"
lars@63885
   336
by (transfer'; simp add: map_drop_def map_drop_set_def map_restrict_set_def)+
lars@63885
   337
lars@63885
   338
lemma fmdom_drop[simp]: "fmdom (fmdrop a m) = fmdom m - {|a|}" unfolding fmfilter_alt_defs by auto
lars@63885
   339
lemma fmdom'_drop[simp]: "fmdom' (fmdrop a m) = fmdom' m - {a}" unfolding fmfilter_alt_defs by auto
lars@63885
   340
lemma fmdom'_drop_set[simp]: "fmdom' (fmdrop_set A m) = fmdom' m - A" unfolding fmfilter_alt_defs by auto
lars@63885
   341
lemma fmdom_drop_fset[simp]: "fmdom (fmdrop_fset A m) = fmdom m - A" unfolding fmfilter_alt_defs by auto
lars@63885
   342
lemma fmdom'_restrict_set: "fmdom' (fmrestrict_set A m) \<subseteq> A" unfolding fmfilter_alt_defs by auto
lars@63885
   343
lemma fmdom_restrict_fset: "fmdom (fmrestrict_fset A m) |\<subseteq>| A" unfolding fmfilter_alt_defs by auto
lars@63885
   344
lars@63885
   345
lemma fmdom'_drop_fset[simp]: "fmdom' (fmdrop_fset A m) = fmdom' m - fset A"
lars@63885
   346
unfolding fmfilter_alt_defs by transfer' (auto simp: map_filter_def split: if_splits)
lars@63885
   347
lars@63885
   348
lemma fmdom'_restrict_fset: "fmdom' (fmrestrict_fset A m) \<subseteq> fset A"
lars@63885
   349
unfolding fmfilter_alt_defs by transfer' (auto simp: map_filter_def)
lars@63885
   350
lars@63885
   351
lemma fmlookup_drop[simp]:
lars@63885
   352
  "fmlookup (fmdrop a m) x = (if x \<noteq> a then fmlookup m x else None)"
lars@63885
   353
unfolding fmfilter_alt_defs by simp
lars@63885
   354
lars@63885
   355
lemma fmlookup_drop_set[simp]:
lars@63885
   356
  "fmlookup (fmdrop_set A m) x = (if x \<notin> A then fmlookup m x else None)"
lars@63885
   357
unfolding fmfilter_alt_defs by simp
lars@63885
   358
lars@63885
   359
lemma fmlookup_drop_fset[simp]:
lars@63885
   360
  "fmlookup (fmdrop_fset A m) x = (if x |\<notin>| A then fmlookup m x else None)"
lars@63885
   361
unfolding fmfilter_alt_defs by simp
lars@63885
   362
lars@63885
   363
lemma fmlookup_restrict_set[simp]:
lars@63885
   364
  "fmlookup (fmrestrict_set A m) x = (if x \<in> A then fmlookup m x else None)"
lars@63885
   365
unfolding fmfilter_alt_defs by simp
lars@63885
   366
lars@63885
   367
lemma fmlookup_restrict_fset[simp]:
lars@63885
   368
  "fmlookup (fmrestrict_fset A m) x = (if x |\<in>| A then fmlookup m x else None)"
lars@63885
   369
unfolding fmfilter_alt_defs by simp
lars@63885
   370
lars@63900
   371
lemma fmrestrict_set_dom[simp]: "fmrestrict_set (fmdom' m) m = m"
lars@66268
   372
  by (rule fmap_ext) auto
lars@63900
   373
lars@63900
   374
lemma fmrestrict_fset_dom[simp]: "fmrestrict_fset (fmdom m) m = m"
lars@66268
   375
  by (rule fmap_ext) auto
lars@63900
   376
lars@63885
   377
lemma fmdrop_empty[simp]: "fmdrop a fmempty = fmempty"
lars@63885
   378
  unfolding fmfilter_alt_defs by simp
lars@63885
   379
lars@63885
   380
lemma fmdrop_set_empty[simp]: "fmdrop_set A fmempty = fmempty"
lars@63885
   381
  unfolding fmfilter_alt_defs by simp
lars@63885
   382
lars@63885
   383
lemma fmdrop_fset_empty[simp]: "fmdrop_fset A fmempty = fmempty"
lars@63885
   384
  unfolding fmfilter_alt_defs by simp
lars@63885
   385
lars@63885
   386
lemma fmrestrict_set_empty[simp]: "fmrestrict_set A fmempty = fmempty"
lars@63885
   387
  unfolding fmfilter_alt_defs by simp
lars@63885
   388
lars@63885
   389
lemma fmrestrict_fset_empty[simp]: "fmrestrict_fset A fmempty = fmempty"
lars@63885
   390
  unfolding fmfilter_alt_defs by simp
lars@63885
   391
lars@66269
   392
lemma fmdrop_set_null[simp]: "fmdrop_set {} m = m"
lars@66269
   393
  by (rule fmap_ext) auto
lars@66269
   394
lars@66269
   395
lemma fmdrop_fset_null[simp]: "fmdrop_fset {||} m = m"
lars@66269
   396
  by (rule fmap_ext) auto
lars@66269
   397
lars@63885
   398
lemma fmdrop_set_single[simp]: "fmdrop_set {a} m = fmdrop a m"
lars@63885
   399
  unfolding fmfilter_alt_defs by simp
lars@63885
   400
lars@63885
   401
lemma fmdrop_fset_single[simp]: "fmdrop_fset {|a|} m = fmdrop a m"
lars@63885
   402
  unfolding fmfilter_alt_defs by simp
lars@63885
   403
lars@63885
   404
lemma fmrestrict_set_null[simp]: "fmrestrict_set {} m = fmempty"
lars@63885
   405
  unfolding fmfilter_alt_defs by simp
lars@63885
   406
lars@63885
   407
lemma fmrestrict_fset_null[simp]: "fmrestrict_fset {||} m = fmempty"
lars@63885
   408
  unfolding fmfilter_alt_defs by simp
lars@63885
   409
lars@63885
   410
lemma fmdrop_comm: "fmdrop a (fmdrop b m) = fmdrop b (fmdrop a m)"
lars@63885
   411
unfolding fmfilter_alt_defs by (rule fmfilter_comm)
lars@63885
   412
lars@66269
   413
lemma fmdrop_set_insert[simp]: "fmdrop_set (insert x S) m = fmdrop x (fmdrop_set S m)"
lars@66269
   414
by (rule fmap_ext) auto
lars@66269
   415
lars@66269
   416
lemma fmdrop_fset_insert[simp]: "fmdrop_fset (finsert x S) m = fmdrop x (fmdrop_fset S m)"
lars@66269
   417
by (rule fmap_ext) auto
lars@66269
   418
lars@63885
   419
lift_definition fmadd :: "('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap" (infixl "++\<^sub>f" 100)
lars@63885
   420
  is map_add
lars@63885
   421
  parametric map_add_transfer
lars@63885
   422
by simp
lars@63885
   423
lars@63900
   424
lemma fmlookup_add[simp]:
lars@63900
   425
  "fmlookup (m ++\<^sub>f n) x = (if x |\<in>| fmdom n then fmlookup n x else fmlookup m x)"
lars@63900
   426
  by transfer' (auto simp: map_add_def split: option.splits)
lars@63900
   427
lars@63885
   428
lemma fmdom_add[simp]: "fmdom (m ++\<^sub>f n) = fmdom m |\<union>| fmdom n" by transfer' auto
lars@63885
   429
lemma fmdom'_add[simp]: "fmdom' (m ++\<^sub>f n) = fmdom' m \<union> fmdom' n" by transfer' auto
lars@63885
   430
lars@63885
   431
lemma fmadd_drop_left_dom: "fmdrop_fset (fmdom n) m ++\<^sub>f n = m ++\<^sub>f n"
lars@63900
   432
  by (rule fmap_ext) auto
lars@63885
   433
lars@63885
   434
lemma fmadd_restrict_right_dom: "fmrestrict_fset (fmdom n) (m ++\<^sub>f n) = n"
lars@66268
   435
  by (rule fmap_ext) auto
lars@63885
   436
lars@63885
   437
lemma fmfilter_add_distrib[simp]: "fmfilter P (m ++\<^sub>f n) = fmfilter P m ++\<^sub>f fmfilter P n"
lars@63885
   438
by transfer' (auto simp: map_filter_def map_add_def)
lars@63885
   439
lars@63885
   440
lemma fmdrop_add_distrib[simp]: "fmdrop a (m ++\<^sub>f n) = fmdrop a m ++\<^sub>f fmdrop a n"
lars@63885
   441
  unfolding fmfilter_alt_defs by simp
lars@63885
   442
lars@63885
   443
lemma fmdrop_set_add_distrib[simp]: "fmdrop_set A (m ++\<^sub>f n) = fmdrop_set A m ++\<^sub>f fmdrop_set A n"
lars@63885
   444
  unfolding fmfilter_alt_defs by simp
lars@63885
   445
lars@63885
   446
lemma fmdrop_fset_add_distrib[simp]: "fmdrop_fset A (m ++\<^sub>f n) = fmdrop_fset A m ++\<^sub>f fmdrop_fset A n"
lars@63885
   447
  unfolding fmfilter_alt_defs by simp
lars@63885
   448
lars@63885
   449
lemma fmrestrict_set_add_distrib[simp]:
lars@63885
   450
  "fmrestrict_set A (m ++\<^sub>f n) = fmrestrict_set A m ++\<^sub>f fmrestrict_set A n"
lars@63885
   451
  unfolding fmfilter_alt_defs by simp
lars@63885
   452
lars@63885
   453
lemma fmrestrict_fset_add_distrib[simp]:
lars@63885
   454
  "fmrestrict_fset A (m ++\<^sub>f n) = fmrestrict_fset A m ++\<^sub>f fmrestrict_fset A n"
lars@63885
   455
  unfolding fmfilter_alt_defs by simp
lars@63885
   456
lars@63885
   457
lemma fmadd_empty[simp]: "fmempty ++\<^sub>f m = m" "m ++\<^sub>f fmempty = m"
lars@63885
   458
by (transfer'; auto)+
lars@63885
   459
lars@63885
   460
lemma fmadd_idempotent[simp]: "m ++\<^sub>f m = m"
lars@63885
   461
by transfer' (auto simp: map_add_def split: option.splits)
lars@63885
   462
lars@63885
   463
lemma fmadd_assoc[simp]: "m ++\<^sub>f (n ++\<^sub>f p) = m ++\<^sub>f n ++\<^sub>f p"
lars@63885
   464
by transfer' simp
lars@63885
   465
lars@66269
   466
lemma fmadd_fmupd[simp]: "m ++\<^sub>f fmupd a b n = fmupd a b (m ++\<^sub>f n)"
lars@66269
   467
by (rule fmap_ext) simp
lars@66269
   468
lars@63885
   469
lift_definition fmpred :: "('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow> ('a, 'b) fmap \<Rightarrow> bool"
lars@63885
   470
  is map_pred
lars@63885
   471
  parametric map_pred_transfer
lars@63885
   472
.
lars@63885
   473
lars@63885
   474
lemma fmpredI[intro]:
lars@63885
   475
  assumes "\<And>x y. fmlookup m x = Some y \<Longrightarrow> P x y"
lars@63885
   476
  shows "fmpred P m"
lars@63885
   477
using assms
lars@63885
   478
by transfer' (auto simp: map_pred_def split: option.splits)
lars@63885
   479
lars@66267
   480
lemma fmpredD[dest]: "fmpred P m \<Longrightarrow> fmlookup m x = Some y \<Longrightarrow> P x y"
lars@63885
   481
by transfer' (auto simp: map_pred_def split: option.split_asm)
lars@63885
   482
lars@63885
   483
lemma fmpred_iff: "fmpred P m \<longleftrightarrow> (\<forall>x y. fmlookup m x = Some y \<longrightarrow> P x y)"
lars@63885
   484
by auto
lars@63885
   485
lars@63885
   486
lemma fmpred_alt_def: "fmpred P m \<longleftrightarrow> fBall (fmdom m) (\<lambda>x. P x (the (fmlookup m x)))"
lars@63885
   487
unfolding fmpred_iff
lars@63885
   488
apply auto
lars@63900
   489
apply (rename_tac x y)
lars@63885
   490
apply (erule_tac x = x in fBallE)
lars@63885
   491
apply simp
lars@63885
   492
by (simp add: fmlookup_dom_iff)
lars@63885
   493
lars@68757
   494
lemma fmpred_mono_strong:
lars@68757
   495
  assumes "\<And>x y. fmlookup m x = Some y \<Longrightarrow> P x y \<Longrightarrow> Q x y"
lars@68757
   496
  shows "fmpred P m \<Longrightarrow> fmpred Q m"
lars@68757
   497
using assms unfolding fmpred_iff by auto
lars@68757
   498
lars@68757
   499
lemma fmpred_mono[mono]: "P \<le> Q \<Longrightarrow> fmpred P \<le> fmpred Q"
lars@68757
   500
apply rule
lars@68757
   501
apply (rule fmpred_mono_strong[where P = P and Q = Q])
lars@68757
   502
apply auto
lars@68757
   503
done
lars@68757
   504
lars@63885
   505
lemma fmpred_empty[intro!, simp]: "fmpred P fmempty"
lars@63885
   506
by auto
lars@63885
   507
lars@63885
   508
lemma fmpred_upd[intro]: "fmpred P m \<Longrightarrow> P x y \<Longrightarrow> fmpred P (fmupd x y m)"
lars@63885
   509
by transfer' (auto simp: map_pred_def map_upd_def)
lars@63885
   510
lars@63885
   511
lemma fmpred_updD[dest]: "fmpred P (fmupd x y m) \<Longrightarrow> P x y"
lars@63885
   512
by auto
lars@63885
   513
lars@63885
   514
lemma fmpred_add[intro]: "fmpred P m \<Longrightarrow> fmpred P n \<Longrightarrow> fmpred P (m ++\<^sub>f n)"
lars@63885
   515
by transfer' (auto simp: map_pred_def map_add_def split: option.splits)
lars@63885
   516
lars@63885
   517
lemma fmpred_filter[intro]: "fmpred P m \<Longrightarrow> fmpred P (fmfilter Q m)"
lars@63885
   518
by transfer' (auto simp: map_pred_def map_filter_def)
lars@63885
   519
lars@63885
   520
lemma fmpred_drop[intro]: "fmpred P m \<Longrightarrow> fmpred P (fmdrop a m)"
lars@63885
   521
  by (auto simp: fmfilter_alt_defs)
lars@63885
   522
lars@63885
   523
lemma fmpred_drop_set[intro]: "fmpred P m \<Longrightarrow> fmpred P (fmdrop_set A m)"
lars@63885
   524
  by (auto simp: fmfilter_alt_defs)
lars@63885
   525
lars@63885
   526
lemma fmpred_drop_fset[intro]: "fmpred P m \<Longrightarrow> fmpred P (fmdrop_fset A m)"
lars@63885
   527
  by (auto simp: fmfilter_alt_defs)
lars@63885
   528
lars@63885
   529
lemma fmpred_restrict_set[intro]: "fmpred P m \<Longrightarrow> fmpred P (fmrestrict_set A m)"
lars@63885
   530
  by (auto simp: fmfilter_alt_defs)
lars@63885
   531
lars@63885
   532
lemma fmpred_restrict_fset[intro]: "fmpred P m \<Longrightarrow> fmpred P (fmrestrict_fset A m)"
lars@63885
   533
  by (auto simp: fmfilter_alt_defs)
lars@63885
   534
lars@63885
   535
lemma fmpred_cases[consumes 1]:
lars@63885
   536
  assumes "fmpred P m"
lars@63885
   537
  obtains (none) "fmlookup m x = None" | (some) y where "fmlookup m x = Some y" "P x y"
lars@63885
   538
using assms by auto
lars@63885
   539
lars@63885
   540
lift_definition fmsubset :: "('a, 'b) fmap \<Rightarrow> ('a, 'b) fmap \<Rightarrow> bool" (infix "\<subseteq>\<^sub>f" 50)
lars@63885
   541
  is map_le
lars@63885
   542
.
lars@63885
   543
lars@63885
   544
lemma fmsubset_alt_def: "m \<subseteq>\<^sub>f n \<longleftrightarrow> fmpred (\<lambda>k v. fmlookup n k = Some v) m"
lars@63885
   545
by transfer' (auto simp: map_pred_def map_le_def dom_def split: option.splits)
lars@63885
   546
lars@63885
   547
lemma fmsubset_pred: "fmpred P m \<Longrightarrow> n \<subseteq>\<^sub>f m \<Longrightarrow> fmpred P n"
lars@63885
   548
unfolding fmsubset_alt_def fmpred_iff
lars@63885
   549
by auto
lars@63885
   550
lars@63885
   551
lemma fmsubset_filter_mono: "m \<subseteq>\<^sub>f n \<Longrightarrow> fmfilter P m \<subseteq>\<^sub>f fmfilter P n"
lars@63885
   552
unfolding fmsubset_alt_def fmpred_iff
lars@63885
   553
by auto
lars@63885
   554
lars@63885
   555
lemma fmsubset_drop_mono: "m \<subseteq>\<^sub>f n \<Longrightarrow> fmdrop a m \<subseteq>\<^sub>f fmdrop a n"
lars@63885
   556
unfolding fmfilter_alt_defs by (rule fmsubset_filter_mono)
lars@63885
   557
lars@63885
   558
lemma fmsubset_drop_set_mono: "m \<subseteq>\<^sub>f n \<Longrightarrow> fmdrop_set A m \<subseteq>\<^sub>f fmdrop_set A n"
lars@63885
   559
unfolding fmfilter_alt_defs by (rule fmsubset_filter_mono)
lars@63885
   560
lars@63885
   561
lemma fmsubset_drop_fset_mono: "m \<subseteq>\<^sub>f n \<Longrightarrow> fmdrop_fset A m \<subseteq>\<^sub>f fmdrop_fset A n"
lars@63885
   562
unfolding fmfilter_alt_defs by (rule fmsubset_filter_mono)
lars@63885
   563
lars@63885
   564
lemma fmsubset_restrict_set_mono: "m \<subseteq>\<^sub>f n \<Longrightarrow> fmrestrict_set A m \<subseteq>\<^sub>f fmrestrict_set A n"
lars@63885
   565
unfolding fmfilter_alt_defs by (rule fmsubset_filter_mono)
lars@63885
   566
lars@63885
   567
lemma fmsubset_restrict_fset_mono: "m \<subseteq>\<^sub>f n \<Longrightarrow> fmrestrict_fset A m \<subseteq>\<^sub>f fmrestrict_fset A n"
lars@63885
   568
unfolding fmfilter_alt_defs by (rule fmsubset_filter_mono)
lars@63885
   569
lars@66282
   570
lift_definition fset_of_fmap :: "('a, 'b) fmap \<Rightarrow> ('a \<times> 'b) fset" is set_of_map
lars@66282
   571
by (rule set_of_map_finite)
lars@66282
   572
lars@66282
   573
lemma fset_of_fmap_inj[intro, simp]: "inj fset_of_fmap"
lars@66282
   574
apply rule
lars@66282
   575
apply transfer'
lars@66282
   576
using set_of_map_inj unfolding inj_def by auto
lars@66282
   577
lars@66398
   578
lemma fset_of_fmap_iff[simp]: "(a, b) |\<in>| fset_of_fmap m \<longleftrightarrow> fmlookup m a = Some b"
lars@66398
   579
by transfer' (auto simp: set_of_map_def)
lars@66398
   580
lars@66398
   581
lemma fset_of_fmap_iff'[simp]: "(a, b) \<in> fset (fset_of_fmap m) \<longleftrightarrow> fmlookup m a = Some b"
lars@66398
   582
by transfer' (auto simp: set_of_map_def)
lars@66398
   583
lars@66398
   584
lars@63885
   585
lift_definition fmap_of_list :: "('a \<times> 'b) list \<Rightarrow> ('a, 'b) fmap"
lars@63885
   586
  is map_of
lars@63885
   587
  parametric map_of_transfer
lars@63885
   588
by (rule finite_dom_map_of)
lars@63885
   589
lars@63885
   590
lemma fmap_of_list_simps[simp]:
lars@63885
   591
  "fmap_of_list [] = fmempty"
lars@63885
   592
  "fmap_of_list ((k, v) # kvs) = fmupd k v (fmap_of_list kvs)"
lars@63885
   593
by (transfer, simp add: map_upd_def)+
lars@63885
   594
lars@63885
   595
lemma fmap_of_list_app[simp]: "fmap_of_list (xs @ ys) = fmap_of_list ys ++\<^sub>f fmap_of_list xs"
lars@63885
   596
by transfer' simp
lars@63885
   597
lars@63885
   598
lemma fmupd_alt_def: "fmupd k v m = m ++\<^sub>f fmap_of_list [(k, v)]"
lars@63885
   599
by transfer' (auto simp: map_upd_def)
lars@63885
   600
lars@63885
   601
lemma fmpred_of_list[intro]:
lars@63885
   602
  assumes "\<And>k v. (k, v) \<in> set xs \<Longrightarrow> P k v"
lars@63885
   603
  shows "fmpred P (fmap_of_list xs)"
lars@63885
   604
using assms
lars@63885
   605
by (induction xs) (transfer'; auto simp: map_pred_def)+
lars@63885
   606
lars@63885
   607
lemma fmap_of_list_SomeD: "fmlookup (fmap_of_list xs) k = Some v \<Longrightarrow> (k, v) \<in> set xs"
lars@63885
   608
by transfer' (auto dest: map_of_SomeD)
lars@63885
   609
lars@66269
   610
lemma fmdom_fmap_of_list[simp]: "fmdom (fmap_of_list xs) = fset_of_list (map fst xs)"
lars@66269
   611
apply transfer'
lars@66269
   612
apply (subst dom_map_of_conv_image_fst)
lars@66269
   613
apply auto
lars@66269
   614
done
lars@66269
   615
lars@63885
   616
lift_definition fmrel_on_fset :: "'a fset \<Rightarrow> ('b \<Rightarrow> 'c \<Rightarrow> bool) \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'c) fmap \<Rightarrow> bool"
lars@63885
   617
  is rel_map_on_set
lars@63885
   618
.
lars@63885
   619
lars@63885
   620
lemma fmrel_on_fset_alt_def: "fmrel_on_fset S P m n \<longleftrightarrow> fBall S (\<lambda>x. rel_option P (fmlookup m x) (fmlookup n x))"
lars@63885
   621
by transfer' (auto simp: rel_map_on_set_def eq_onp_def rel_fun_def)
lars@63885
   622
lars@64181
   623
lemma fmrel_on_fsetI[intro]:
lars@63885
   624
  assumes "\<And>x. x |\<in>| S \<Longrightarrow> rel_option P (fmlookup m x) (fmlookup n x)"
lars@63885
   625
  shows "fmrel_on_fset S P m n"
lars@63885
   626
using assms
lars@63885
   627
unfolding fmrel_on_fset_alt_def by auto
lars@63885
   628
lars@63885
   629
lemma fmrel_on_fset_mono[mono]: "R \<le> Q \<Longrightarrow> fmrel_on_fset S R \<le> fmrel_on_fset S Q"
lars@63885
   630
unfolding fmrel_on_fset_alt_def[abs_def]
lars@63885
   631
apply (intro le_funI fBall_mono)
lars@63885
   632
using option.rel_mono by auto
lars@63885
   633
lars@63885
   634
lemma fmrel_on_fsetD: "x |\<in>| S \<Longrightarrow> fmrel_on_fset S P m n \<Longrightarrow> rel_option P (fmlookup m x) (fmlookup n x)"
lars@63885
   635
unfolding fmrel_on_fset_alt_def
lars@63885
   636
by auto
lars@63885
   637
lars@63885
   638
lemma fmrel_on_fsubset: "fmrel_on_fset S R m n \<Longrightarrow> T |\<subseteq>| S \<Longrightarrow> fmrel_on_fset T R m n"
lars@63885
   639
unfolding fmrel_on_fset_alt_def
lars@63885
   640
by auto
lars@63885
   641
lars@66274
   642
lemma fmrel_on_fset_unionI:
lars@66274
   643
  "fmrel_on_fset A R m n \<Longrightarrow> fmrel_on_fset B R m n \<Longrightarrow> fmrel_on_fset (A |\<union>| B) R m n"
lars@66274
   644
unfolding fmrel_on_fset_alt_def
lars@66274
   645
by auto
lars@66274
   646
lars@66274
   647
lemma fmrel_on_fset_updateI:
lars@66274
   648
  assumes "fmrel_on_fset S P m n" "P v\<^sub>1 v\<^sub>2"
lars@66274
   649
  shows "fmrel_on_fset (finsert k S) P (fmupd k v\<^sub>1 m) (fmupd k v\<^sub>2 n)"
lars@66274
   650
using assms
lars@66274
   651
unfolding fmrel_on_fset_alt_def
lars@66274
   652
by auto
lars@66274
   653
lars@63885
   654
end
lars@63885
   655
lars@63885
   656
lars@63885
   657
subsection \<open>BNF setup\<close>
lars@63885
   658
lars@63885
   659
lift_bnf ('a, fmran': 'b) fmap [wits: Map.empty]
lars@63885
   660
  for map: fmmap
lars@63885
   661
      rel: fmrel
lars@63885
   662
  by auto
lars@63885
   663
lars@66269
   664
declare fmap.pred_mono[mono]
lars@66268
   665
lars@63885
   666
context includes lifting_syntax begin
lars@63885
   667
lars@63885
   668
lemma fmmap_transfer[transfer_rule]:
nipkow@67399
   669
  "((=) ===> pcr_fmap (=) (=) ===> pcr_fmap (=) (=)) (\<lambda>f. (\<circ>) (map_option f)) fmmap"
lars@64180
   670
  unfolding fmmap_def
lars@64180
   671
  by (rule rel_funI ext)+ (auto simp: fmap.Abs_fmap_inverse fmap.pcr_cr_eq cr_fmap_def)
lars@63885
   672
lars@63885
   673
lemma fmran'_transfer[transfer_rule]:
nipkow@67399
   674
  "(pcr_fmap (=) (=) ===> (=)) (\<lambda>x. UNION (range x) set_option) fmran'"
lars@64180
   675
  unfolding fmran'_def fmap.pcr_cr_eq cr_fmap_def by fastforce
lars@63885
   676
lars@63885
   677
lemma fmrel_transfer[transfer_rule]:
nipkow@67399
   678
  "((=) ===> pcr_fmap (=) (=) ===> pcr_fmap (=) (=) ===> (=)) rel_map fmrel"
lars@64180
   679
  unfolding fmrel_def fmap.pcr_cr_eq cr_fmap_def vimage2p_def by fastforce
lars@63885
   680
lars@63885
   681
end
lars@63885
   682
lars@63885
   683
lars@66268
   684
lemma fmran'_alt_def: "fmran' m = fset (fmran m)"
lars@63885
   685
including fset.lifting
lars@63885
   686
by transfer' (auto simp: ran_def fun_eq_iff)
lars@63885
   687
lars@66268
   688
lemma fmlookup_ran'_iff: "y \<in> fmran' m \<longleftrightarrow> (\<exists>x. fmlookup m x = Some y)"
lars@66268
   689
by transfer' (auto simp: ran_def)
lars@66268
   690
lars@66268
   691
lemma fmran'I: "fmlookup m x = Some y \<Longrightarrow> y \<in> fmran' m" by (auto simp: fmlookup_ran'_iff)
lars@66268
   692
lars@66268
   693
lemma fmran'E[elim]:
lars@66268
   694
  assumes "y \<in> fmran' m"
lars@66268
   695
  obtains x where "fmlookup m x = Some y"
lars@66268
   696
using assms by (auto simp: fmlookup_ran'_iff)
lars@63885
   697
lars@63885
   698
lemma fmrel_iff: "fmrel R m n \<longleftrightarrow> (\<forall>x. rel_option R (fmlookup m x) (fmlookup n x))"
lars@63885
   699
by transfer' (auto simp: rel_fun_def)
lars@63885
   700
lars@63885
   701
lemma fmrelI[intro]:
lars@63885
   702
  assumes "\<And>x. rel_option R (fmlookup m x) (fmlookup n x)"
lars@63885
   703
  shows "fmrel R m n"
lars@63885
   704
using assms
lars@63885
   705
by transfer' auto
lars@63885
   706
lars@63885
   707
lemma fmrel_upd[intro]: "fmrel P m n \<Longrightarrow> P x y \<Longrightarrow> fmrel P (fmupd k x m) (fmupd k y n)"
lars@63885
   708
by transfer' (auto simp: map_upd_def rel_fun_def)
lars@63885
   709
lars@63885
   710
lemma fmrelD[dest]: "fmrel P m n \<Longrightarrow> rel_option P (fmlookup m x) (fmlookup n x)"
lars@63885
   711
by transfer' (auto simp: rel_fun_def)
lars@63885
   712
lars@63885
   713
lemma fmrel_addI[intro]:
lars@63885
   714
  assumes "fmrel P m n" "fmrel P a b"
lars@63885
   715
  shows "fmrel P (m ++\<^sub>f a) (n ++\<^sub>f b)"
lars@63885
   716
using assms
lars@63885
   717
apply transfer'
lars@63885
   718
apply (auto simp: rel_fun_def map_add_def)
lars@63885
   719
by (metis option.case_eq_if option.collapse option.rel_sel)
lars@63885
   720
lars@63885
   721
lemma fmrel_cases[consumes 1]:
lars@63885
   722
  assumes "fmrel P m n"
lars@63885
   723
  obtains (none) "fmlookup m x = None" "fmlookup n x = None"
lars@63885
   724
        | (some) a b where "fmlookup m x = Some a" "fmlookup n x = Some b" "P a b"
lars@63885
   725
proof -
lars@63885
   726
  from assms have "rel_option P (fmlookup m x) (fmlookup n x)"
lars@63885
   727
    by auto
lars@64180
   728
  then show thesis
lars@63885
   729
    using none some
lars@63885
   730
    by (cases rule: option.rel_cases) auto
lars@63885
   731
qed
lars@63885
   732
lars@63885
   733
lemma fmrel_filter[intro]: "fmrel P m n \<Longrightarrow> fmrel P (fmfilter Q m) (fmfilter Q n)"
lars@63885
   734
unfolding fmrel_iff by auto
lars@63885
   735
lars@63885
   736
lemma fmrel_drop[intro]: "fmrel P m n \<Longrightarrow> fmrel P (fmdrop a m) (fmdrop a n)"
lars@63885
   737
  unfolding fmfilter_alt_defs by blast
lars@63885
   738
lars@63885
   739
lemma fmrel_drop_set[intro]: "fmrel P m n \<Longrightarrow> fmrel P (fmdrop_set A m) (fmdrop_set A n)"
lars@63885
   740
  unfolding fmfilter_alt_defs by blast
lars@63885
   741
lars@63885
   742
lemma fmrel_drop_fset[intro]: "fmrel P m n \<Longrightarrow> fmrel P (fmdrop_fset A m) (fmdrop_fset A n)"
lars@63885
   743
  unfolding fmfilter_alt_defs by blast
lars@63885
   744
lars@63885
   745
lemma fmrel_restrict_set[intro]: "fmrel P m n \<Longrightarrow> fmrel P (fmrestrict_set A m) (fmrestrict_set A n)"
lars@63885
   746
  unfolding fmfilter_alt_defs by blast
lars@63885
   747
lars@63885
   748
lemma fmrel_restrict_fset[intro]: "fmrel P m n \<Longrightarrow> fmrel P (fmrestrict_fset A m) (fmrestrict_fset A n)"
lars@63885
   749
  unfolding fmfilter_alt_defs by blast
lars@63885
   750
lars@66274
   751
lemma fmrel_on_fset_fmrel_restrict:
lars@66274
   752
  "fmrel_on_fset S P m n \<longleftrightarrow> fmrel P (fmrestrict_fset S m) (fmrestrict_fset S n)"
lars@66274
   753
unfolding fmrel_on_fset_alt_def fmrel_iff
lars@66274
   754
by auto
lars@66274
   755
lars@66274
   756
lemma fmrel_on_fset_refl_strong:
lars@66274
   757
  assumes "\<And>x y. x |\<in>| S \<Longrightarrow> fmlookup m x = Some y \<Longrightarrow> P y y"
lars@66274
   758
  shows "fmrel_on_fset S P m m"
lars@66274
   759
unfolding fmrel_on_fset_fmrel_restrict fmrel_iff
lars@66274
   760
using assms
lars@66274
   761
by (simp add: option.rel_sel)
lars@66274
   762
lars@66274
   763
lemma fmrel_on_fset_addI:
lars@66274
   764
  assumes "fmrel_on_fset S P m n" "fmrel_on_fset S P a b"
lars@66274
   765
  shows "fmrel_on_fset S P (m ++\<^sub>f a) (n ++\<^sub>f b)"
lars@66274
   766
using assms
lars@66274
   767
unfolding fmrel_on_fset_fmrel_restrict
lars@66274
   768
by auto
lars@66274
   769
lars@66274
   770
lemma fmrel_fmdom_eq:
lars@66274
   771
  assumes "fmrel P x y"
lars@66274
   772
  shows "fmdom x = fmdom y"
lars@66274
   773
proof -
lars@66274
   774
  have "a |\<in>| fmdom x \<longleftrightarrow> a |\<in>| fmdom y" for a
lars@66274
   775
    proof -
lars@66274
   776
      have "rel_option P (fmlookup x a) (fmlookup y a)"
lars@66274
   777
        using assms by (simp add: fmrel_iff)
lars@66274
   778
      thus ?thesis
lars@66274
   779
        by cases (auto intro: fmdomI)
lars@66274
   780
    qed
lars@66274
   781
  thus ?thesis
lars@66274
   782
    by auto
lars@66274
   783
qed
lars@66274
   784
lars@66274
   785
lemma fmrel_fmdom'_eq: "fmrel P x y \<Longrightarrow> fmdom' x = fmdom' y"
lars@66274
   786
unfolding fmdom'_alt_def
lars@66274
   787
by (metis fmrel_fmdom_eq)
lars@66274
   788
lars@66274
   789
lemma fmrel_rel_fmran:
lars@66274
   790
  assumes "fmrel P x y"
lars@66274
   791
  shows "rel_fset P (fmran x) (fmran y)"
lars@66274
   792
proof -
lars@66274
   793
  {
lars@66274
   794
    fix b
lars@66274
   795
    assume "b |\<in>| fmran x"
lars@66274
   796
    then obtain a where "fmlookup x a = Some b"
lars@66274
   797
      by auto
lars@66274
   798
    moreover have "rel_option P (fmlookup x a) (fmlookup y a)"
lars@66274
   799
      using assms by auto
lars@66274
   800
    ultimately have "\<exists>b'. b' |\<in>| fmran y \<and> P b b'"
lars@66274
   801
      by (metis option_rel_Some1 fmranI)
lars@66274
   802
  }
lars@66274
   803
  moreover
lars@66274
   804
  {
lars@66274
   805
    fix b
lars@66274
   806
    assume "b |\<in>| fmran y"
lars@66274
   807
    then obtain a where "fmlookup y a = Some b"
lars@66274
   808
      by auto
lars@66274
   809
    moreover have "rel_option P (fmlookup x a) (fmlookup y a)"
lars@66274
   810
      using assms by auto
lars@66274
   811
    ultimately have "\<exists>b'. b' |\<in>| fmran x \<and> P b' b"
lars@66274
   812
      by (metis option_rel_Some2 fmranI)
lars@66274
   813
  }
lars@66274
   814
  ultimately show ?thesis
lars@66274
   815
    unfolding rel_fset_alt_def
lars@66274
   816
    by auto
lars@66274
   817
qed
lars@66274
   818
lars@66274
   819
lemma fmrel_rel_fmran': "fmrel P x y \<Longrightarrow> rel_set P (fmran' x) (fmran' y)"
lars@66274
   820
unfolding fmran'_alt_def
lars@66274
   821
by (metis fmrel_rel_fmran rel_fset_fset)
lars@66274
   822
lars@63885
   823
lemma pred_fmap_fmpred[simp]: "pred_fmap P = fmpred (\<lambda>_. P)"
lars@63885
   824
unfolding fmap.pred_set fmran'_alt_def
lars@63885
   825
including fset.lifting
lars@63885
   826
apply transfer'
lars@63885
   827
apply (rule ext)
lars@63885
   828
apply (auto simp: map_pred_def ran_def split: option.splits dest: )
lars@63885
   829
done
lars@63885
   830
lars@63885
   831
lemma pred_fmap_id[simp]: "pred_fmap id (fmmap f m) \<longleftrightarrow> pred_fmap f m"
lars@63885
   832
unfolding fmap.pred_set fmap.set_map
lars@63885
   833
by simp
lars@63885
   834
lars@66274
   835
lemma pred_fmapD: "pred_fmap P m \<Longrightarrow> x |\<in>| fmran m \<Longrightarrow> P x"
lars@66274
   836
by auto
lars@66274
   837
lars@63885
   838
lemma fmlookup_map[simp]: "fmlookup (fmmap f m) x = map_option f (fmlookup m x)"
lars@64180
   839
by transfer' auto
lars@63885
   840
lars@63885
   841
lemma fmpred_map[simp]: "fmpred P (fmmap f m) \<longleftrightarrow> fmpred (\<lambda>k v. P k (f v)) m"
lars@63885
   842
unfolding fmpred_iff pred_fmap_def fmap.set_map
lars@63885
   843
by auto
lars@63885
   844
lars@63885
   845
lemma fmpred_id[simp]: "fmpred (\<lambda>_. id) (fmmap f m) \<longleftrightarrow> fmpred (\<lambda>_. f) m"
lars@63885
   846
by simp
lars@63885
   847
lars@63885
   848
lemma fmmap_add[simp]: "fmmap f (m ++\<^sub>f n) = fmmap f m ++\<^sub>f fmmap f n"
lars@63885
   849
by transfer' (auto simp: map_add_def fun_eq_iff split: option.splits)
lars@63885
   850
lars@63885
   851
lemma fmmap_empty[simp]: "fmmap f fmempty = fmempty"
lars@63885
   852
by transfer auto
lars@63885
   853
lars@63885
   854
lemma fmdom_map[simp]: "fmdom (fmmap f m) = fmdom m"
lars@63885
   855
including fset.lifting
lars@63885
   856
by transfer' simp
lars@63885
   857
lars@63885
   858
lemma fmdom'_map[simp]: "fmdom' (fmmap f m) = fmdom' m"
lars@63885
   859
by transfer' simp
lars@63885
   860
lars@66269
   861
lemma fmran_fmmap[simp]: "fmran (fmmap f m) = f |`| fmran m"
lars@66269
   862
including fset.lifting
lars@66269
   863
by transfer' (auto simp: ran_def)
lars@66269
   864
lars@66269
   865
lemma fmran'_fmmap[simp]: "fmran' (fmmap f m) = f ` fmran' m"
lars@66269
   866
by transfer' (auto simp: ran_def)
lars@66269
   867
lars@63885
   868
lemma fmfilter_fmmap[simp]: "fmfilter P (fmmap f m) = fmmap f (fmfilter P m)"
lars@63885
   869
by transfer' (auto simp: map_filter_def)
lars@63885
   870
lars@63885
   871
lemma fmdrop_fmmap[simp]: "fmdrop a (fmmap f m) = fmmap f (fmdrop a m)" unfolding fmfilter_alt_defs by simp
lars@63885
   872
lemma fmdrop_set_fmmap[simp]: "fmdrop_set A (fmmap f m) = fmmap f (fmdrop_set A m)" unfolding fmfilter_alt_defs by simp
lars@63885
   873
lemma fmdrop_fset_fmmap[simp]: "fmdrop_fset A (fmmap f m) = fmmap f (fmdrop_fset A m)" unfolding fmfilter_alt_defs by simp
lars@63885
   874
lemma fmrestrict_set_fmmap[simp]: "fmrestrict_set A (fmmap f m) = fmmap f (fmrestrict_set A m)" unfolding fmfilter_alt_defs by simp
lars@63885
   875
lemma fmrestrict_fset_fmmap[simp]: "fmrestrict_fset A (fmmap f m) = fmmap f (fmrestrict_fset A m)" unfolding fmfilter_alt_defs by simp
lars@63885
   876
lars@63885
   877
lemma fmmap_subset[intro]: "m \<subseteq>\<^sub>f n \<Longrightarrow> fmmap f m \<subseteq>\<^sub>f fmmap f n"
lars@63885
   878
by transfer' (auto simp: map_le_def)
lars@63885
   879
lars@66398
   880
lemma fmmap_fset_of_fmap: "fset_of_fmap (fmmap f m) = (\<lambda>(k, v). (k, f v)) |`| fset_of_fmap m"
lars@66398
   881
including fset.lifting
lars@66398
   882
by transfer' (auto simp: set_of_map_def)
lars@66398
   883
lars@66398
   884
lars@66398
   885
subsection \<open>@{const size} setup\<close>
lars@66398
   886
lars@66398
   887
definition size_fmap :: "('a \<Rightarrow> nat) \<Rightarrow> ('b \<Rightarrow> nat) \<Rightarrow> ('a, 'b) fmap \<Rightarrow> nat" where
lars@66398
   888
[simp]: "size_fmap f g m = size_fset (\<lambda>(a, b). f a + g b) (fset_of_fmap m)"
lars@66398
   889
lars@66398
   890
instantiation fmap :: (type, type) size begin
lars@66398
   891
lars@66398
   892
definition size_fmap where
lars@66398
   893
size_fmap_overloaded_def: "size_fmap = Finite_Map.size_fmap (\<lambda>_. 0) (\<lambda>_. 0)"
lars@66398
   894
lars@66398
   895
instance ..
lars@66398
   896
lars@66398
   897
end
lars@66398
   898
lars@66398
   899
lemma size_fmap_overloaded_simps[simp]: "size x = size (fset_of_fmap x)"
lars@66398
   900
unfolding size_fmap_overloaded_def
lars@66398
   901
by simp
lars@66398
   902
lars@66398
   903
lemma fmap_size_o_map: "inj h \<Longrightarrow> size_fmap f g \<circ> fmmap h = size_fmap f (g \<circ> h)"
lars@66398
   904
  unfolding size_fmap_def
lars@66398
   905
  apply (auto simp: fun_eq_iff fmmap_fset_of_fmap)
lars@66398
   906
  apply (subst sum.reindex)
lars@66398
   907
  subgoal for m
lars@66398
   908
    using prod.inj_map[unfolded map_prod_def, of "\<lambda>x. x" h]
lars@66398
   909
    unfolding inj_on_def
lars@66398
   910
    by auto
lars@66398
   911
  subgoal
lars@66398
   912
    by (rule sum.cong) (auto split: prod.splits)
lars@66398
   913
  done
lars@66398
   914
lars@66398
   915
setup \<open>
lars@66398
   916
BNF_LFP_Size.register_size_global @{type_name fmap} @{const_name size_fmap}
lars@66398
   917
  @{thm size_fmap_overloaded_def} @{thms size_fmap_def size_fmap_overloaded_simps}
lars@66398
   918
  @{thms fmap_size_o_map}
lars@66398
   919
\<close>
lars@66398
   920
lars@63885
   921
lars@66269
   922
subsection \<open>Additional operations\<close>
lars@66269
   923
lars@66269
   924
lift_definition fmmap_keys :: "('a \<Rightarrow> 'b \<Rightarrow> 'c) \<Rightarrow> ('a, 'b) fmap \<Rightarrow> ('a, 'c) fmap" is
lars@66269
   925
  "\<lambda>f m a. map_option (f a) (m a)"
lars@66269
   926
unfolding dom_def
lars@66269
   927
by simp
lars@66269
   928
lars@66269
   929
lemma fmpred_fmmap_keys[simp]: "fmpred P (fmmap_keys f m) = fmpred (\<lambda>a b. P a (f a b)) m"
lars@66269
   930
by transfer' (auto simp: map_pred_def split: option.splits)
lars@66269
   931
lars@66269
   932
lemma fmdom_fmmap_keys[simp]: "fmdom (fmmap_keys f m) = fmdom m"
lars@66269
   933
including fset.lifting
lars@66269
   934
by transfer' auto
lars@66269
   935
lars@66269
   936
lemma fmlookup_fmmap_keys[simp]: "fmlookup (fmmap_keys f m) x = map_option (f x) (fmlookup m x)"
lars@66269
   937
by transfer' simp
lars@66269
   938
lars@66269
   939
lemma fmfilter_fmmap_keys[simp]: "fmfilter P (fmmap_keys f m) = fmmap_keys f (fmfilter P m)"
lars@66269
   940
by transfer' (auto simp: map_filter_def)
lars@66269
   941
lars@66269
   942
lemma fmdrop_fmmap_keys[simp]: "fmdrop a (fmmap_keys f m) = fmmap_keys f (fmdrop a m)"
lars@66269
   943
unfolding fmfilter_alt_defs by simp
lars@66269
   944
lars@66269
   945
lemma fmdrop_set_fmmap_keys[simp]: "fmdrop_set A (fmmap_keys f m) = fmmap_keys f (fmdrop_set A m)"
lars@66269
   946
unfolding fmfilter_alt_defs by simp
lars@66269
   947
lars@66269
   948
lemma fmdrop_fset_fmmap_keys[simp]: "fmdrop_fset A (fmmap_keys f m) = fmmap_keys f (fmdrop_fset A m)"
lars@66269
   949
unfolding fmfilter_alt_defs by simp
lars@66269
   950
lars@66269
   951
lemma fmrestrict_set_fmmap_keys[simp]: "fmrestrict_set A (fmmap_keys f m) = fmmap_keys f (fmrestrict_set A m)"
lars@66269
   952
unfolding fmfilter_alt_defs by simp
lars@66269
   953
lars@66269
   954
lemma fmrestrict_fset_fmmap_keys[simp]: "fmrestrict_fset A (fmmap_keys f m) = fmmap_keys f (fmrestrict_fset A m)"
lars@66269
   955
unfolding fmfilter_alt_defs by simp
lars@66269
   956
lars@66269
   957
lemma fmmap_keys_subset[intro]: "m \<subseteq>\<^sub>f n \<Longrightarrow> fmmap_keys f m \<subseteq>\<^sub>f fmmap_keys f n"
lars@66269
   958
by transfer' (auto simp: map_le_def dom_def)
lars@66269
   959
lars@68463
   960
definition sorted_list_of_fmap :: "('a::linorder, 'b) fmap \<Rightarrow> ('a \<times> 'b) list" where
lars@68463
   961
"sorted_list_of_fmap m = map (\<lambda>k. (k, the (fmlookup m k))) (sorted_list_of_fset (fmdom m))"
lars@68463
   962
lars@68463
   963
lemma list_all_sorted_list[simp]: "list_all P (sorted_list_of_fmap m) = fmpred (curry P) m"
lars@68463
   964
unfolding sorted_list_of_fmap_def curry_def list.pred_map
lars@68463
   965
apply (auto simp: list_all_iff)
lars@68463
   966
including fmap.lifting fset.lifting
lars@68463
   967
by (transfer; auto simp: dom_def map_pred_def split: option.splits)+
lars@68463
   968
lars@68463
   969
lemma map_of_sorted_list[simp]: "map_of (sorted_list_of_fmap m) = fmlookup m"
lars@68463
   970
unfolding sorted_list_of_fmap_def
lars@68463
   971
including fmap.lifting fset.lifting
lars@68463
   972
by transfer (simp add: map_of_map_keys)
lars@68463
   973
lars@66269
   974
lars@66269
   975
subsection \<open>Lifting/transfer setup\<close>
lars@66269
   976
lars@66269
   977
context includes lifting_syntax begin
lars@66269
   978
lars@66269
   979
lemma fmempty_transfer[simp, intro, transfer_rule]: "fmrel P fmempty fmempty"
lars@66269
   980
by transfer auto
lars@66269
   981
lars@66269
   982
lemma fmadd_transfer[transfer_rule]:
lars@66269
   983
  "(fmrel P ===> fmrel P ===> fmrel P) fmadd fmadd"
lars@66269
   984
  by (intro fmrel_addI rel_funI)
lars@66269
   985
lars@66269
   986
lemma fmupd_transfer[transfer_rule]:
nipkow@67399
   987
  "((=) ===> P ===> fmrel P ===> fmrel P) fmupd fmupd"
lars@66269
   988
  by auto
lars@66269
   989
lars@66269
   990
end
lars@66269
   991
lars@66274
   992
lars@66274
   993
subsection \<open>View as datatype\<close>
lars@66274
   994
lars@66274
   995
lemma fmap_distinct[simp]:
lars@66274
   996
  "fmempty \<noteq> fmupd k v m"
lars@66274
   997
  "fmupd k v m \<noteq> fmempty"
lars@66274
   998
by (transfer'; auto simp: map_upd_def fun_eq_iff)+
lars@66274
   999
lars@66274
  1000
lifting_update fmap.lifting
lars@66274
  1001
lars@66274
  1002
lemma fmap_exhaust[case_names fmempty fmupd, cases type: fmap]:
lars@66274
  1003
  assumes fmempty: "m = fmempty \<Longrightarrow> P"
lars@66274
  1004
  assumes fmupd: "\<And>x y m'. m = fmupd x y m' \<Longrightarrow> x |\<notin>| fmdom m' \<Longrightarrow> P"
lars@66274
  1005
  shows "P"
lars@66274
  1006
using assms including fmap.lifting fset.lifting
lars@66274
  1007
proof transfer
lars@66274
  1008
  fix m P
lars@66274
  1009
  assume "finite (dom m)"
lars@66274
  1010
  assume empty: P if "m = Map.empty"
lars@66274
  1011
  assume map_upd: P if "finite (dom m')" "m = map_upd x y m'" "x \<notin> dom m'" for x y m'
lars@66274
  1012
lars@66274
  1013
  show P
lars@66274
  1014
    proof (cases "m = Map.empty")
lars@66274
  1015
      case True thus ?thesis using empty by simp
lars@66274
  1016
    next
lars@66274
  1017
      case False
lars@66274
  1018
      hence "dom m \<noteq> {}" by simp
lars@66274
  1019
      then obtain x where "x \<in> dom m" by blast
lars@66274
  1020
lars@66274
  1021
      let ?m' = "map_drop x m"
lars@66274
  1022
lars@66274
  1023
      show ?thesis
lars@66274
  1024
        proof (rule map_upd)
lars@66274
  1025
          show "finite (dom ?m')"
lars@66274
  1026
            using \<open>finite (dom m)\<close>
lars@66274
  1027
            unfolding map_drop_def
lars@66274
  1028
            by auto
lars@66274
  1029
        next
lars@66274
  1030
          show "m = map_upd x (the (m x)) ?m'"
lars@66274
  1031
            using \<open>x \<in> dom m\<close> unfolding map_drop_def map_filter_def map_upd_def
lars@66274
  1032
            by auto
lars@66274
  1033
        next
lars@66274
  1034
          show "x \<notin> dom ?m'"
lars@66274
  1035
            unfolding map_drop_def map_filter_def
lars@66274
  1036
            by auto
lars@66274
  1037
        qed
lars@66274
  1038
    qed
lars@66274
  1039
qed
lars@66274
  1040
lars@66274
  1041
lemma fmap_induct[case_names fmempty fmupd, induct type: fmap]:
lars@66274
  1042
  assumes "P fmempty"
lars@66274
  1043
  assumes "(\<And>x y m. P m \<Longrightarrow> fmlookup m x = None \<Longrightarrow> P (fmupd x y m))"
lars@66274
  1044
  shows "P m"
lars@66274
  1045
proof (induction "fmdom m" arbitrary: m rule: fset_induct_stronger)
lars@66274
  1046
  case empty
lars@66274
  1047
  hence "m = fmempty"
lars@66274
  1048
    by (metis fmrestrict_fset_dom fmrestrict_fset_null)
lars@66274
  1049
  with assms show ?case
lars@66274
  1050
    by simp
lars@66274
  1051
next
lars@66274
  1052
  case (insert x S)
lars@66274
  1053
  hence "S = fmdom (fmdrop x m)"
lars@66274
  1054
    by auto
lars@66274
  1055
  with insert have "P (fmdrop x m)"
lars@66274
  1056
    by auto
lars@66274
  1057
lars@66274
  1058
  have "x |\<in>| fmdom m"
lars@66274
  1059
    using insert by auto
lars@66274
  1060
  then obtain y where "fmlookup m x = Some y"
lars@66274
  1061
    by auto
lars@66274
  1062
  hence "m = fmupd x y (fmdrop x m)"
lars@66274
  1063
    by (auto intro: fmap_ext)
lars@66274
  1064
lars@66274
  1065
  show ?case
lars@66274
  1066
    apply (subst \<open>m = _\<close>)
lars@66274
  1067
    apply (rule assms)
lars@66274
  1068
    apply fact
lars@66274
  1069
    apply simp
lars@66274
  1070
    done
lars@66274
  1071
qed
lars@66274
  1072
lars@66274
  1073
lars@63885
  1074
subsection \<open>Code setup\<close>
lars@63885
  1075
lars@63885
  1076
instantiation fmap :: (type, equal) equal begin
lars@63885
  1077
lars@63885
  1078
definition "equal_fmap \<equiv> fmrel HOL.equal"
lars@63885
  1079
lars@63885
  1080
instance proof
lars@63885
  1081
  fix m n :: "('a, 'b) fmap"
nipkow@67399
  1082
  have "fmrel (=) m n \<longleftrightarrow> (m = n)"
lars@63885
  1083
    by transfer' (simp add: option.rel_eq rel_fun_eq)
lars@64180
  1084
  then show "equal_class.equal m n \<longleftrightarrow> (m = n)"
lars@63885
  1085
    unfolding equal_fmap_def
lars@63885
  1086
    by (simp add: equal_eq[abs_def])
lars@63885
  1087
qed
lars@63885
  1088
lars@63885
  1089
end
lars@63885
  1090
lars@63885
  1091
lemma fBall_alt_def: "fBall S P \<longleftrightarrow> (\<forall>x. x |\<in>| S \<longrightarrow> P x)"
lars@63885
  1092
by force
lars@63885
  1093
lars@63885
  1094
lemma fmrel_code:
lars@63885
  1095
  "fmrel R m n \<longleftrightarrow>
lars@63885
  1096
    fBall (fmdom m) (\<lambda>x. rel_option R (fmlookup m x) (fmlookup n x)) \<and>
lars@63885
  1097
    fBall (fmdom n) (\<lambda>x. rel_option R (fmlookup m x) (fmlookup n x))"
lars@63885
  1098
unfolding fmrel_iff fmlookup_dom_iff fBall_alt_def
lars@63885
  1099
by (metis option.collapse option.rel_sel)
lars@63885
  1100
lars@66291
  1101
lemmas [code] =
lars@63885
  1102
  fmrel_code
lars@63885
  1103
  fmran'_alt_def
lars@63885
  1104
  fmdom'_alt_def
lars@63885
  1105
  fmfilter_alt_defs
lars@63885
  1106
  pred_fmap_fmpred
lars@63885
  1107
  fmsubset_alt_def
lars@63885
  1108
  fmupd_alt_def
lars@63885
  1109
  fmrel_on_fset_alt_def
lars@63885
  1110
  fmpred_alt_def
lars@63885
  1111
lars@63885
  1112
lars@63885
  1113
code_datatype fmap_of_list
lars@63885
  1114
quickcheck_generator fmap constructors: fmap_of_list
lars@63885
  1115
lars@63885
  1116
context includes fset.lifting begin
lars@63885
  1117
lars@66269
  1118
lemma fmlookup_of_list[code]: "fmlookup (fmap_of_list m) = map_of m"
lars@63885
  1119
by transfer simp
lars@63885
  1120
lars@66269
  1121
lemma fmempty_of_list[code]: "fmempty = fmap_of_list []"
lars@63885
  1122
by transfer simp
lars@63885
  1123
lars@66269
  1124
lemma fmran_of_list[code]: "fmran (fmap_of_list m) = snd |`| fset_of_list (AList.clearjunk m)"
lars@63885
  1125
by transfer (auto simp: ran_map_of)
lars@63885
  1126
lars@66269
  1127
lemma fmdom_of_list[code]: "fmdom (fmap_of_list m) = fst |`| fset_of_list m"
lars@63885
  1128
by transfer (auto simp: dom_map_of_conv_image_fst)
lars@63885
  1129
lars@66269
  1130
lemma fmfilter_of_list[code]: "fmfilter P (fmap_of_list m) = fmap_of_list (filter (\<lambda>(k, _). P k) m)"
lars@63885
  1131
by transfer' auto
lars@63885
  1132
lars@66269
  1133
lemma fmadd_of_list[code]: "fmap_of_list m ++\<^sub>f fmap_of_list n = fmap_of_list (AList.merge m n)"
lars@63885
  1134
by transfer (simp add: merge_conv')
lars@63885
  1135
lars@66269
  1136
lemma fmmap_of_list[code]: "fmmap f (fmap_of_list m) = fmap_of_list (map (apsnd f) m)"
lars@63885
  1137
apply transfer
lars@63885
  1138
apply (subst map_of_map[symmetric])
lars@63885
  1139
apply (auto simp: apsnd_def map_prod_def)
lars@63885
  1140
done
lars@63885
  1141
lars@66269
  1142
lemma fmmap_keys_of_list[code]: "fmmap_keys f (fmap_of_list m) = fmap_of_list (map (\<lambda>(a, b). (a, f a b)) m)"
lars@66269
  1143
apply transfer
lars@66269
  1144
subgoal for f m by (induction m) (auto simp: apsnd_def map_prod_def fun_eq_iff)
lars@66269
  1145
done
lars@66269
  1146
lars@63885
  1147
end
lars@63885
  1148
lars@66267
  1149
lars@66267
  1150
subsection \<open>Instances\<close>
lars@66267
  1151
lars@66267
  1152
lemma exists_map_of:
lars@66267
  1153
  assumes "finite (dom m)" shows "\<exists>xs. map_of xs = m"
lars@66267
  1154
  using assms
lars@66267
  1155
proof (induction "dom m" arbitrary: m)
lars@66267
  1156
  case empty
lars@66267
  1157
  hence "m = Map.empty"
lars@66267
  1158
    by auto
lars@66267
  1159
  moreover have "map_of [] = Map.empty"
lars@66267
  1160
    by simp
lars@66267
  1161
  ultimately show ?case
lars@66267
  1162
    by blast
lars@66267
  1163
next
lars@66267
  1164
  case (insert x F)
lars@66267
  1165
  hence "F = dom (map_drop x m)"
lars@66267
  1166
    unfolding map_drop_def map_filter_def dom_def by auto
lars@66267
  1167
  with insert have "\<exists>xs'. map_of xs' = map_drop x m"
lars@66267
  1168
    by auto
lars@66267
  1169
  then obtain xs' where "map_of xs' = map_drop x m"
lars@66267
  1170
    ..
lars@66267
  1171
  moreover obtain y where "m x = Some y"
lars@66267
  1172
    using insert unfolding dom_def by blast
lars@66267
  1173
  ultimately have "map_of ((x, y) # xs') = m"
lars@66267
  1174
    using \<open>insert x F = dom m\<close>
lars@66267
  1175
    unfolding map_drop_def map_filter_def
lars@66267
  1176
    by auto
lars@66267
  1177
  thus ?case
lars@66267
  1178
    ..
lars@66267
  1179
qed
lars@66267
  1180
lars@66267
  1181
lemma exists_fmap_of_list: "\<exists>xs. fmap_of_list xs = m"
lars@66267
  1182
by transfer (rule exists_map_of)
lars@66267
  1183
lars@66267
  1184
lemma fmap_of_list_surj[simp, intro]: "surj fmap_of_list"
lars@66267
  1185
proof -
lars@66267
  1186
  have "x \<in> range fmap_of_list" for x :: "('a, 'b) fmap"
lars@66267
  1187
    unfolding image_iff
lars@66267
  1188
    using exists_fmap_of_list by (metis UNIV_I)
lars@66267
  1189
  thus ?thesis by auto
lars@66267
  1190
qed
lars@66267
  1191
lars@66267
  1192
instance fmap :: (countable, countable) countable
lars@66267
  1193
proof
lars@66267
  1194
  obtain to_nat :: "('a \<times> 'b) list \<Rightarrow> nat" where "inj to_nat"
lars@66267
  1195
    by (metis ex_inj)
lars@66267
  1196
  moreover have "inj (inv fmap_of_list)"
lars@66267
  1197
    using fmap_of_list_surj by (rule surj_imp_inj_inv)
lars@66267
  1198
  ultimately have "inj (to_nat \<circ> inv fmap_of_list)"
lars@66267
  1199
    by (rule inj_comp)
lars@66267
  1200
  thus "\<exists>to_nat::('a, 'b) fmap \<Rightarrow> nat. inj to_nat"
lars@66267
  1201
    by auto
lars@66267
  1202
qed
lars@66267
  1203
lars@66282
  1204
instance fmap :: (finite, finite) finite
lars@66282
  1205
proof
lars@66282
  1206
  show "finite (UNIV :: ('a, 'b) fmap set)"
lars@66282
  1207
    by (rule finite_imageD) auto
lars@66282
  1208
qed
lars@66282
  1209
lars@63885
  1210
lifting_update fmap.lifting
lars@63885
  1211
lifting_forget fmap.lifting
lars@63885
  1212
lars@67485
  1213
end