File: fin_map_dom.v

package info (click to toggle)
coq-stdpp 1.11.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,696 kB
  • sloc: makefile: 52; sh: 35; sed: 1
file content (463 lines) | stat: -rw-r--r-- 19,772 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
(** This file provides an axiomatization of the domain function of finite
maps. We provide such an axiomatization, instead of implementing the domain
function in a generic way, to allow more efficient implementations. *)
From stdpp Require Export sets fin_maps.
From stdpp Require Import options.

(* Pick up extra assumptions from section parameters. *)
Set Default Proof Using "Type*".

Class FinMapDom K M D `{∀ A, Dom (M A) D, FMap M,
    ∀ A, Lookup K A (M A), ∀ A, Empty (M A), ∀ A, PartialAlter K A (M A),
    OMap M, Merge M, ∀ A, MapFold K A (M A), EqDecision K,
    ElemOf K D, Empty D, Singleton K D,
    Union D, Intersection D, Difference D} := {
  finmap_dom_map :: FinMap K M;
  finmap_dom_set :: Set_ K D;
  elem_of_dom {A} (m : M A) i : i ∈ dom m ↔ is_Some (m !! i)
}.

Section fin_map_dom.
Context `{FinMapDom K M D}.

Lemma lookup_lookup_total_dom `{!Inhabited A} (m : M A) i :
  i ∈ dom m → m !! i = Some (m !!! i).
Proof. rewrite elem_of_dom. apply lookup_lookup_total. Qed.

Lemma dom_imap_subseteq {A B} (f: K → A → option B) (m: M A) :
  dom (map_imap f m) ⊆ dom m.
Proof.
  intros k. rewrite 2!elem_of_dom, map_lookup_imap.
  destruct 1 as [?[?[Eq _]]%bind_Some]. by eexists.
Qed.
Lemma dom_imap {A B} (f : K → A → option B) (m : M A) (X : D) :
  (∀ i, i ∈ X ↔ ∃ x, m !! i = Some x ∧ is_Some (f i x)) →
  dom (map_imap f m) ≡ X.
Proof.
  intros HX k. rewrite elem_of_dom, HX, map_lookup_imap.
  unfold is_Some. setoid_rewrite bind_Some. naive_solver.
Qed.

Lemma elem_of_dom_2 {A} (m : M A) i x : m !! i = Some x → i ∈ dom m.
Proof. rewrite elem_of_dom; eauto. Qed.
Lemma not_elem_of_dom {A} (m : M A) i : i ∉ dom m ↔ m !! i = None.
Proof. by rewrite elem_of_dom, eq_None_not_Some. Qed.
Lemma not_elem_of_dom_1 {A} (m : M A) i : i ∉ dom m → m !! i = None.
Proof. apply not_elem_of_dom. Qed.
Lemma not_elem_of_dom_2 {A} (m : M A) i : m !! i = None → i ∉ dom m.
Proof. apply not_elem_of_dom. Qed.
Lemma subseteq_dom {A} (m1 m2 : M A) : m1 ⊆ m2 → dom m1 ⊆ dom m2.
Proof.
  rewrite map_subseteq_spec.
  intros ??. rewrite !elem_of_dom. inv 1; eauto.
Qed.
Lemma subset_dom {A} (m1 m2 : M A) : m1 ⊂ m2 → dom m1 ⊂ dom m2.
Proof.
  intros [Hss1 Hss2]; split; [by apply subseteq_dom |].
  contradict Hss2. rewrite map_subseteq_spec. intros i x Hi.
  specialize (Hss2 i). rewrite !elem_of_dom in Hss2.
  destruct Hss2; eauto. by simplify_map_eq.
Qed.

Lemma dom_filter {A} (P : K * A → Prop) `{!∀ x, Decision (P x)} (m : M A) (X : D) :
  (∀ i, i ∈ X ↔ ∃ x, m !! i = Some x ∧ P (i, x)) →
  dom (filter P m) ≡ X.
Proof.
  intros HX i. rewrite elem_of_dom, HX.
  unfold is_Some. by setoid_rewrite map_lookup_filter_Some.
Qed.
Lemma dom_filter_subseteq {A} (P : K * A → Prop) `{!∀ x, Decision (P x)} (m : M A):
  dom (filter P m) ⊆ dom m.
Proof. apply subseteq_dom, map_filter_subseteq. Qed.

Lemma filter_dom {A} `{!Elements K D, !FinSet K D}
    (P : K → Prop) `{!∀ x, Decision (P x)} (m : M A) :
  filter P (dom m) ≡ dom (filter (λ kv, P kv.1) m).
Proof.
  intros i. rewrite elem_of_filter, !elem_of_dom. unfold is_Some.
  setoid_rewrite map_lookup_filter_Some. naive_solver.
Qed.

Lemma dom_empty {A} : dom (@empty (M A) _) ≡ ∅.
Proof.
  intros x. rewrite elem_of_dom, lookup_empty, <-not_eq_None_Some. set_solver.
Qed.
Lemma dom_empty_iff {A} (m : M A) : dom m ≡ ∅ ↔ m = ∅.
Proof.
  split; [|intros ->; by rewrite dom_empty].
  intros E. apply map_empty. intros. apply not_elem_of_dom.
  rewrite E. set_solver.
Qed.
Lemma dom_empty_inv {A} (m : M A) : dom m ≡ ∅ → m = ∅.
Proof. apply dom_empty_iff. Qed.
Lemma dom_alter {A} f (m : M A) i : dom (alter f i m) ≡ dom m.
Proof.
  apply set_equiv; intros j; rewrite !elem_of_dom; unfold is_Some.
  destruct (decide (i = j)); simplify_map_eq/=; eauto.
  destruct (m !! j); naive_solver.
Qed.
Lemma dom_insert {A} (m : M A) i x : dom (<[i:=x]>m) ≡ {[ i ]} ∪ dom m.
Proof.
  apply set_equiv. intros j. rewrite elem_of_union, !elem_of_dom.
  unfold is_Some. setoid_rewrite lookup_insert_Some.
  destruct (decide (i = j)); set_solver.
Qed.
Lemma dom_insert_lookup {A} (m : M A) i x :
  is_Some (m !! i) → dom (<[i:=x]>m) ≡ dom m.
Proof.
  intros Hindom. assert (i ∈ dom m) by by apply elem_of_dom.
  rewrite dom_insert. set_solver.
Qed.
Lemma dom_insert_subseteq {A} (m : M A) i x : dom m ⊆ dom (<[i:=x]>m).
Proof. rewrite (dom_insert _). set_solver. Qed.
Lemma dom_insert_subseteq_compat_l {A} (m : M A) i x X :
  X ⊆ dom m → X ⊆ dom (<[i:=x]>m).
Proof. intros. trans (dom m); eauto using dom_insert_subseteq. Qed.
Lemma dom_singleton {A} (i : K) (x : A) : dom ({[i := x]} : M A) ≡ {[ i ]}.
Proof. rewrite <-insert_empty, dom_insert, dom_empty; set_solver. Qed.
Lemma dom_delete {A} (m : M A) i : dom (delete i m) ≡ dom m ∖ {[ i ]}.
Proof.
  apply set_equiv. intros j. rewrite elem_of_difference, !elem_of_dom.
  unfold is_Some. setoid_rewrite lookup_delete_Some. set_solver.
Qed.
Lemma delete_partial_alter_dom {A} (m : M A) i f :
  i ∉ dom m → delete i (partial_alter f i m) = m.
Proof. rewrite not_elem_of_dom. apply delete_partial_alter. Qed.
Lemma delete_insert_dom {A} (m : M A) i x :
  i ∉ dom m → delete i (<[i:=x]>m) = m.
Proof. rewrite not_elem_of_dom. apply delete_insert. Qed.
Lemma map_disjoint_dom {A} (m1 m2 : M A) : m1 ##ₘ m2 ↔ dom m1 ## dom m2.
Proof.
  rewrite map_disjoint_spec, elem_of_disjoint.
  setoid_rewrite elem_of_dom. unfold is_Some. naive_solver.
Qed.
Lemma map_disjoint_dom_1 {A} (m1 m2 : M A) : m1 ##ₘ m2 → dom m1 ## dom m2.
Proof. apply map_disjoint_dom. Qed.
Lemma map_disjoint_dom_2 {A} (m1 m2 : M A) : dom m1 ## dom m2 → m1 ##ₘ m2.
Proof. apply map_disjoint_dom. Qed.
Lemma dom_union {A} (m1 m2 : M A) : dom (m1 ∪ m2) ≡ dom m1 ∪ dom m2.
Proof.
  apply set_equiv. intros i. rewrite elem_of_union, !elem_of_dom.
  unfold is_Some. setoid_rewrite lookup_union_Some_raw.
  destruct (m1 !! i); naive_solver.
Qed.
Lemma dom_intersection {A} (m1 m2: M A) : dom (m1 ∩ m2) ≡ dom m1 ∩ dom m2.
Proof.
  apply set_equiv. intros i. rewrite elem_of_intersection, !elem_of_dom.
  unfold is_Some. setoid_rewrite lookup_intersection_Some. naive_solver.
Qed.
Lemma dom_difference {A} (m1 m2 : M A) : dom (m1 ∖ m2) ≡ dom m1 ∖ dom m2.
Proof.
  apply set_equiv. intros i. rewrite elem_of_difference, !elem_of_dom.
  unfold is_Some. setoid_rewrite lookup_difference_Some.
  destruct (m2 !! i); naive_solver.
Qed.
Lemma dom_fmap {A B} (f : A → B) (m : M A) : dom (f <$> m) ≡ dom m.
Proof.
  apply set_equiv. intros i.
  rewrite !elem_of_dom, lookup_fmap, <-!not_eq_None_Some.
  destruct (m !! i); naive_solver.
Qed.
Lemma dom_finite {A} (m : M A) : set_finite (dom m).
Proof.
  induction m using map_ind; rewrite ?dom_empty, ?dom_insert.
  - by apply empty_finite.
  - apply union_finite; [apply singleton_finite|done].
Qed.
Global Instance dom_proper `{!Equiv A} : Proper ((≡@{M A}) ==> (≡)) dom.
Proof.
  intros m1 m2 EQm. apply set_equiv. intros i.
  rewrite !elem_of_dom, EQm. done.
Qed.
Lemma dom_list_to_map {A} (l : list (K * A)) :
  dom (list_to_map l : M A) ≡ list_to_set l.*1.
Proof.
  induction l as [|?? IH].
  - by rewrite dom_empty.
  - simpl. by rewrite dom_insert, IH.
Qed.

Lemma map_first_key_dom {A B} (m1 : M A) (m2 : M B) i :
  dom m1 ≡ dom m2 → map_first_key m1 i ↔ map_first_key m2 i.
Proof.
  intros Hm. apply map_first_key_dom'. intros j.
  by rewrite <-!elem_of_dom, Hm.
Qed.
Lemma map_first_key_dom_L {A B} (m1 : M A) (m2 : M B) i :
  dom m1 = dom m2 → map_first_key m1 i ↔ map_first_key m2 i.
Proof. intros Hm. apply map_first_key_dom. by rewrite Hm. Qed.

Lemma map_Forall2_dom {A B} (P : K → A → B → Prop) (m1 : M A) (m2 : M B) :
  map_Forall2 P m1 m2 → dom m1 ≡ dom m2.
Proof.
  revert m2. induction m1 as [|i x1 m1 ? IH] using map_ind; intros m2.
  { intros ->%map_Forall2_empty_inv_l. by rewrite !dom_empty. }
  intros (x2 & m2' & -> & ? & ? & ?)%map_Forall2_insert_inv_l; last done.
  by rewrite !dom_insert, IH by done.
Qed.

(** Alternative definition of [dom] in terms of [map_to_list]. *)
Lemma dom_alt {A} (m : M A) :
  dom m ≡ list_to_set (map_to_list m).*1.
Proof.
  rewrite <-(list_to_map_to_list m) at 1.
  rewrite dom_list_to_map.
  done.
Qed.

Lemma size_dom `{!Elements K D, !FinSet K D} {A} (m : M A) :
  size (dom m) = size m.
Proof.
  induction m as [|i x m ? IH] using map_ind.
  { by rewrite dom_empty, map_size_empty, size_empty. }
  assert ({[i]} ## dom m).
  { intros j. rewrite elem_of_dom. unfold is_Some. set_solver. }
  by rewrite dom_insert, size_union, size_singleton, map_size_insert_None, IH.
Qed.

Lemma dom_subseteq_size {A} (m1 m2 : M A) : 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 dom_subset_size {A} (m1 m2 : M A) : dom m2 ⊂ dom m1 → size m2 < size m1.
Proof.
  revert m1. induction m2 as [|i x m2 ? IH] using map_ind; intros m1 Hdom.
  { destruct m1 as [|i x m1 ? _] using map_ind.
    - rewrite !dom_empty in Hdom. set_solver.
    - rewrite map_size_empty, map_size_insert_None by done. 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_lt_mono by (by rewrite ?lookup_delete).
  apply IH. rewrite dom_delete. split; [set_solver|].
  intros ?. destruct Hdom as [? []].
  intros j. destruct (decide (i = j)); set_solver.
Qed.

Lemma subseteq_dom_eq {A} (m1 m2 : M A) :
  m1 ⊆ m2 → dom m2 ⊆ dom m1 → m1 = m2.
Proof. intros. apply map_subseteq_size_eq; auto using dom_subseteq_size. Qed.

Lemma dom_singleton_inv {A} (m : M A) i :
  dom m ≡ {[i]} → ∃ x, m = {[i := x]}.
Proof.
  intros Hdom. assert (is_Some (m !! i)) as [x ?].
  { apply (elem_of_dom (D:=D)); set_solver. }
  exists x. apply map_eq; intros j.
  destruct (decide (i = j)); simplify_map_eq; [done|].
  apply not_elem_of_dom. set_solver.
Qed.

Lemma dom_map_zip_with {A B C} (f : A → B → C) (ma : M A) (mb : M B) :
  dom (map_zip_with f ma mb) ≡ dom ma ∩ dom mb.
Proof.
  rewrite set_equiv. intros x.
  rewrite elem_of_intersection, !elem_of_dom, map_lookup_zip_with.
  destruct (ma !! x), (mb !! x); rewrite !is_Some_alt; naive_solver.
Qed.

Lemma dom_union_inv `{!RelDecision (∈@{D})} {A} (m : M A) (X1 X2 : D) :
  X1 ## X2 →
  dom m ≡ X1 ∪ X2 →
  ∃ m1 m2, m = m1 ∪ m2 ∧ m1 ##ₘ m2 ∧ dom m1 ≡ X1 ∧ dom m2 ≡ X2.
Proof.
  intros.
  exists (filter (λ '(k,x), k ∈ X1) m), (filter (λ '(k,x), k ∉ X1) m).
  assert (filter (λ '(k, _), k ∈ X1) m ##ₘ filter (λ '(k, _), k ∉ X1) m).
  { apply map_disjoint_filter_complement. }
  split_and!; [|done| |].
  - apply map_eq; intros i. apply option_eq; intros x.
    rewrite lookup_union_Some, !map_lookup_filter_Some by done.
    destruct (decide (i ∈ X1)); naive_solver.
  - apply dom_filter; intros i; split; [|naive_solver].
    intros. assert (is_Some (m !! i)) as [x ?] by (apply elem_of_dom; set_solver).
    naive_solver.
  - apply dom_filter; intros i; split.
    + intros. assert (is_Some (m !! i)) as [x ?] by (apply elem_of_dom; set_solver).
      naive_solver.
    + intros (x&?&?). apply dec_stable; intros ?.
      assert (m !! i = None) by (apply not_elem_of_dom; set_solver).
      naive_solver.
Qed.

Lemma dom_kmap `{!Elements K D, !FinSet K D, FinMapDom K2 M2 D2}
    {A} (f : K → K2) `{!Inj (=) (=) f} (m : M A) :
  dom (kmap (M2:=M2) f m) ≡@{D2} set_map f (dom m).
Proof.
  apply set_equiv. intros i.
  rewrite !elem_of_dom, (lookup_kmap_is_Some _), elem_of_map.
  by setoid_rewrite elem_of_dom.
Qed.

Lemma dom_omap_subseteq {A B} (f : A → option B) (m : M A) :
  dom (omap f m) ⊆ dom m.
Proof.
  intros a. rewrite !elem_of_dom. intros [c Hm].
  apply lookup_omap_Some in Hm. naive_solver.
Qed.

Lemma map_compose_dom_subseteq {C} `{FinMap K' M'} (m: M' C) (n : M K') :
  dom (m ∘ₘ n : M C) ⊆@{D} dom n.
Proof. apply dom_omap_subseteq. Qed.
Lemma map_compose_min_r_dom {C} `{FinMap K' M', !RelDecision (∈@{D})}
    (m : M C) (n : M' K) :
  m ∘ₘ n = m ∘ₘ filter (λ '(_,b), b ∈ dom m) n.
Proof.
  rewrite map_compose_min_r. f_equal.
  apply map_filter_ext. intros. by rewrite elem_of_dom.
Qed.

Lemma map_compose_empty_iff_dom_img {C} `{FinMap K' M', !RelDecision (∈@{D})}
    (m : M C) (n : M' K) :
  m ∘ₘ n = ∅ ↔ dom m ## map_img n.
Proof.
  rewrite map_compose_empty_iff, elem_of_disjoint.
  setoid_rewrite elem_of_dom. setoid_rewrite eq_None_not_Some.
  setoid_rewrite elem_of_map_img. naive_solver.
Qed.

(** If [D] has Leibniz equality, we can show an even stronger result.  This is a
common case e.g. when having a [gmap K A] where the key [K] has Leibniz equality
(and thus also [gset K], the usual domain) but the value type [A] does not. *)
Global Instance dom_proper_L `{!Equiv A, !LeibnizEquiv D} :
  Proper ((≡@{M A}) ==> (=)) (dom) | 0.
Proof. intros ???. unfold_leibniz. by apply dom_proper. Qed.

Section leibniz.
  Context `{!LeibnizEquiv D}.

  Lemma dom_filter_L {A} (P : K * A → Prop) `{!∀ x, Decision (P x)} (m : M A) X :
    (∀ i, i ∈ X ↔ ∃ x, m !! i = Some x ∧ P (i, x)) →
    dom (filter P m) = X.
  Proof. unfold_leibniz. apply dom_filter. Qed.
  Lemma filter_dom_L {A} `{!Elements K D, !FinSet K D}
      (P : K → Prop) `{!∀ x, Decision (P x)} (m : M A) :
    filter P (dom m) = dom (filter (λ kv, P kv.1) m).
  Proof. unfold_leibniz. apply filter_dom. Qed.
  Lemma dom_empty_L {A} : dom (@empty (M A) _) = ∅.
  Proof. unfold_leibniz; apply dom_empty. Qed.
  Lemma dom_empty_iff_L {A} (m : M A) : dom m = ∅ ↔ m = ∅.
  Proof. unfold_leibniz. apply dom_empty_iff. Qed.
  Lemma dom_empty_inv_L {A} (m : M A) : dom m = ∅ → m = ∅.
  Proof. by intros; apply dom_empty_inv; unfold_leibniz. Qed.
  Lemma dom_alter_L {A} f (m : M A) i : dom (alter f i m) = dom m.
  Proof. unfold_leibniz; apply dom_alter. Qed.
  Lemma dom_insert_L {A} (m : M A) i x : dom (<[i:=x]>m) = {[ i ]} ∪ dom m.
  Proof. unfold_leibniz; apply dom_insert. Qed.
  Lemma dom_insert_lookup_L {A} (m : M A) i x :
    is_Some (m !! i) → dom (<[i:=x]>m) = dom m.
  Proof. unfold_leibniz; apply dom_insert_lookup. Qed.
  Lemma dom_singleton_L {A} (i : K) (x : A) : dom ({[i := x]} : M A) = {[ i ]}.
  Proof. unfold_leibniz; apply dom_singleton. Qed.
  Lemma dom_delete_L {A} (m : M A) i : dom (delete i m) = dom m ∖ {[ i ]}.
  Proof. unfold_leibniz; apply dom_delete. Qed.
  Lemma dom_union_L {A} (m1 m2 : M A) : dom (m1 ∪ m2) = dom m1 ∪ dom m2.
  Proof. unfold_leibniz; apply dom_union. Qed.
  Lemma dom_intersection_L {A} (m1 m2 : M A) :
    dom (m1 ∩ m2) = dom m1 ∩ dom m2.
  Proof. unfold_leibniz; apply dom_intersection. Qed.
  Lemma dom_difference_L {A} (m1 m2 : M A) : dom (m1 ∖ m2) = dom m1 ∖ dom m2.
  Proof. unfold_leibniz; apply dom_difference. Qed.
  Lemma dom_fmap_L {A B} (f : A → B) (m : M A) : dom (f <$> m) = dom m.
  Proof. unfold_leibniz; apply dom_fmap. Qed.
  Lemma map_Forall2_dom_L {A B} (P : K → A → B → Prop) (m1 : M A) (m2 : M B) :
    map_Forall2 P m1 m2 → dom m1 = dom m2.
  Proof. unfold_leibniz. apply map_Forall2_dom. Qed.
  Lemma dom_imap_L {A B} (f: K → A → option B) (m: M A) X :
    (∀ i, i ∈ X ↔ ∃ x, m !! i = Some x ∧ is_Some (f i x)) →
    dom (map_imap f m) = X.
  Proof. unfold_leibniz; apply dom_imap. Qed.
  Lemma dom_list_to_map_L {A} (l : list (K * A)) :
    dom (list_to_map l : M A) = list_to_set l.*1.
  Proof. unfold_leibniz. apply dom_list_to_map. Qed.
  Lemma dom_singleton_inv_L {A} (m : M A) i :
    dom m = {[i]} → ∃ x, m = {[i := x]}.
  Proof. unfold_leibniz. apply dom_singleton_inv. Qed.
  Lemma dom_map_zip_with_L {A B C} (f : A → B → C) (ma : M A) (mb : M B) :
    dom (map_zip_with f ma mb) = dom ma ∩ dom mb.
  Proof. unfold_leibniz. apply dom_map_zip_with. Qed.
  Lemma dom_union_inv_L `{!RelDecision (∈@{D})} {A} (m : M A) (X1 X2 : D) :
    X1 ## X2 →
    dom m = X1 ∪ X2 →
    ∃ m1 m2, m = m1 ∪ m2 ∧ m1 ##ₘ m2 ∧ dom m1 = X1 ∧ dom m2 = X2.
  Proof. unfold_leibniz. apply dom_union_inv. Qed.
End leibniz.

Lemma dom_kmap_L `{!Elements K D, !FinSet K D, FinMapDom K2 M2 D2}
    `{!LeibnizEquiv D2} {A} (f : K → K2) `{!Inj (=) (=) f} (m : M A) :
  dom (kmap (M2:=M2) f m) = set_map f (dom m).
Proof. unfold_leibniz. by apply dom_kmap. Qed.

(** * Set solver instances *)
Global Instance set_unfold_dom_empty {A} i : SetUnfoldElemOf i (dom (∅:M A)) False.
Proof. constructor. by rewrite dom_empty, elem_of_empty. Qed.
Global Instance set_unfold_dom_alter {A} f i j (m : M A) Q :
  SetUnfoldElemOf i (dom m) Q →
  SetUnfoldElemOf i (dom (alter f j m)) Q.
Proof. constructor. by rewrite dom_alter, (set_unfold_elem_of _ (dom _) _). Qed.
Global Instance set_unfold_dom_insert {A} i j x (m : M A) Q :
  SetUnfoldElemOf i (dom m) Q →
  SetUnfoldElemOf i (dom (<[j:=x]> m)) (i = j ∨ Q).
Proof.
  constructor. by rewrite dom_insert, elem_of_union,
    (set_unfold_elem_of _ (dom _) _), elem_of_singleton.
Qed.
Global Instance set_unfold_dom_delete {A} i j (m : M A) Q :
  SetUnfoldElemOf i (dom m) Q →
  SetUnfoldElemOf i (dom (delete j m)) (Q ∧ i ≠ j).
Proof.
  constructor. by rewrite dom_delete, elem_of_difference,
    (set_unfold_elem_of _ (dom _) _), elem_of_singleton.
Qed.
Global Instance set_unfold_dom_singleton {A} i j x :
  SetUnfoldElemOf i (dom ({[ j := x ]} : M A)) (i = j).
Proof. constructor. by rewrite dom_singleton, elem_of_singleton. Qed.
Global Instance set_unfold_dom_union {A} i (m1 m2 : M A) Q1 Q2 :
  SetUnfoldElemOf i (dom m1) Q1 → SetUnfoldElemOf i (dom m2) Q2 →
  SetUnfoldElemOf i (dom (m1 ∪ m2)) (Q1 ∨ Q2).
Proof.
  constructor. by rewrite dom_union, elem_of_union,
    !(set_unfold_elem_of _ (dom _) _).
Qed.
Global Instance set_unfold_dom_intersection {A} i (m1 m2 : M A) Q1 Q2 :
  SetUnfoldElemOf i (dom m1) Q1 → SetUnfoldElemOf i (dom m2) Q2 →
  SetUnfoldElemOf i (dom (m1 ∩ m2)) (Q1 ∧ Q2).
Proof.
  constructor. by rewrite dom_intersection, elem_of_intersection,
    !(set_unfold_elem_of _ (dom _) _).
Qed.
Global Instance set_unfold_dom_difference {A} i (m1 m2 : M A) Q1 Q2 :
  SetUnfoldElemOf i (dom m1) Q1 → SetUnfoldElemOf i (dom m2) Q2 →
  SetUnfoldElemOf i (dom (m1 ∖ m2)) (Q1 ∧ ¬Q2).
Proof.
  constructor. by rewrite dom_difference, elem_of_difference,
    !(set_unfold_elem_of _ (dom _) _).
Qed.
Global Instance set_unfold_dom_fmap {A B} (f : A → B) i (m : M A) Q :
  SetUnfoldElemOf i (dom m) Q →
  SetUnfoldElemOf i (dom (f <$> m)) Q.
Proof. constructor. by rewrite dom_fmap, (set_unfold_elem_of _ (dom _) _). Qed.
End fin_map_dom.

Lemma dom_seq `{FinMapDom nat M D} {A} start (xs : list A) :
  dom (map_seq start (M:=M A) xs) ≡ set_seq start (length xs).
Proof.
  revert start. induction xs as [|x xs IH]; intros start; simpl.
  - by rewrite dom_empty.
  - by rewrite dom_insert, IH.
Qed.
Lemma dom_seq_L `{FinMapDom nat M D, !LeibnizEquiv D} {A} start (xs : list A) :
  dom (map_seq (M:=M A) start xs) = set_seq start (length xs).
Proof. unfold_leibniz. apply dom_seq. Qed.

Global Instance set_unfold_dom_seq `{FinMapDom nat M D} {A} start (xs : list A) i :
  SetUnfoldElemOf i (dom (map_seq start (M:=M A) xs)) (start ≤ i < start + length xs).
Proof. constructor. by rewrite dom_seq, elem_of_set_seq. Qed.