...
 
Commits (186)
# Enable syntax highlighting.
*.v gitlab-language=coq *.v gitlab-language=coq
# Convert to native line endings on checkout.
*.ref text
*.vo *.vo
*.vos
*.vok
*.vio *.vio
*.v.d *.v.d
.coqdeps.d .coqdeps.d
.Makefile.coq.d
*.glob *.glob
*.cache *.cache
*.aux *.aux
......
...@@ -18,61 +18,46 @@ variables: ...@@ -18,61 +18,46 @@ variables:
paths: paths:
- opamroot/ - opamroot/
only: only:
- master - master@iris/stdpp
- /^ci/ - /^ci/@iris/stdpp
except: except:
- triggers - triggers
- schedules - schedules
- api
## Build jobs ## Build jobs
build-coq.dev: build-coq.8.11.dev:
<<: *template <<: *template
variables: variables:
OCAML: "ocaml-base-compiler.4.07.0" OPAM_PINS: "coq version 8.11.dev"
OPAM_PINS: "coq version dev"
CI_COQCHK: "1" CI_COQCHK: "1"
build-coq.8.9.0: build-coq.8.11.0:
<<: *template <<: *template
variables: variables:
OPAM_PINS: "coq version 8.9.0" OPAM_PINS: "coq version 8.11.0"
OPAM_PKG: "coq-stdpp" OPAM_PKG: "coq-stdpp"
DOC_DIR: "coqdoc@center.mpi-sws.org:stdpp" DOC_DIR: "coqdoc@center.mpi-sws.org:stdpp"
TIMING_CONF: "coq-8.9.0"
tags: tags:
- fp-timing - fp-timing
build-coq.8.8.2: build-coq.8.10.2:
<<: *template <<: *template
variables: variables:
OPAM_PINS: "coq version 8.8.2" OPAM_PINS: "coq version 8.10.2"
build-coq.8.8.1: build-coq.8.9.1:
<<: *template <<: *template
variables: variables:
OPAM_PINS: "coq version 8.8.1" OPAM_PINS: "coq version 8.9.1"
build-coq.8.8.0: build-coq.8.8.2:
<<: *template <<: *template
variables: variables:
OPAM_PINS: "coq version 8.8.0" OPAM_PINS: "coq version 8.8.2"
TIMING_CONF: "coq-8.8.0"
tags:
- fp-timing
build-coq.8.7.2: build-coq.8.7.2:
<<: *template <<: *template
variables: variables:
OPAM_PINS: "coq version 8.7.2" OPAM_PINS: "coq version 8.7.2"
build-coq.8.7.1:
<<: *template
variables:
OPAM_PINS: "coq version 8.7.1"
build-coq.8.7.0:
<<: *template
variables:
OPAM_PINS: "coq version 8.7.0"
...@@ -3,20 +3,103 @@ API-breaking change is listed. ...@@ -3,20 +3,103 @@ API-breaking change is listed.
## std++ master ## std++ master
Numerous functions and theorems have been renamed. - Rename `dom_map_filter` into `dom_map_filter_subseteq` and repurpose
`dom_map_filter` for the version with the equality. This follows the naming
- Consistently use `set` instead of `collection`. convention for similar lemmas.
- Rename the `Collection` type class into `Set_`. Likewise, `SimpleCollection` - Generalize `list_find_Some` and `list_find_None` to become bi-implications.
is called `SemiSet`, and `FinCollection` is called `FinSet`, and - Disambiguate Haskell-style notations for partially applied operators. For
`CollectionMonad` is called `MonadSet`. example, change `(!! i)` into `(.!! x)` so that `!!` can also be used as a
- Rename `collections.v` and `fin_collections.v` into `sets.v` and `fin_sets.v`, prefix, as done in VST. A sed script to perform the renaming can be found at:
respectively. https://gitlab.mpi-sws.org/iris/stdpp/merge_requests/93
- Rename `set A := A → Prop` (`theories/set.v`) into `propset`, and likewise - Add type class `TopSet` for sets with a `⊤` element. Provide instances for
`bset` into `boolset`. `boolset`, `propset`, and `coPset`.
- Consistently prefer `X_to_Y` for conversion functions, e.g. `list_to_map`
instead of the former `map_of_list`. ## std++ 1.2.1 (released 2019-08-29)
The following `sed` script should get you a long way: This release of std++ received contributions by Dan Frumin, Michael Sammler,
Paolo G. Giarrusso, Paulo Emílio de Vilhena, Ralf Jung, Robbert Krebbers,
Rodolphe Lepigre, and Simon Spies.
Noteworthy additions and changes:
- Introduce `max` and `min` infix notations for `N` and `Z` like we have for `nat`.
- Make `solve_ndisj` tactic more powerful.
- Add type class `Involutive`.
- Improve `naive_solver` performance in case the goal is trivially solvable.
- Add a bunch of new lemmas for list, set, and map operations.
- Rename `lookup_imap` into `map_lookup_imap`.
## std++ 1.2.0 (released 2019-04-26)
Coq 8.9 is supported by this release, but Coq 8.6 is no longer supported. Use
std++ 1.1 if you have to use Coq 8.6. The repository moved to a new location at
https://gitlab.mpi-sws.org/iris/stdpp and automatically generated Coq-doc of
master is available at https://plv.mpi-sws.org/coqdoc/stdpp/.
This release of std++ received contributions by Dan Frumin, Hai Dang, Jan-Oliver
Kaiser, Mackie Loeffel, Maxime Dénès, Ralf Jung, Robbert Krebbers, and Tej
Chajed.
New features:
- New notations `=@{A}`, `≡@{A}`, `∈@{A}`, `∉@{A}`, `##@{A}`, `⊆@{A}`, `⊂@{A}`,
`⊑@{A}`, `≡ₚ@{A}` for being explicit about the type.
- A definition of basic telescopes `tele` and some theory about them.
- A simple type class based canceler `NatCancel` for natural numbers.
- A type `binder` for anonymous and named binders to be used in program language
definitions with string-based binders.
- More results about `set_fold` on sets and multisets.
- Notions of infinite and finite predicates/sets and basic theory about them.
- New operation `map_seq`.
- The symmetric and reflexive/transitive/symmetric closure of a relation (`sc`
and `rtsc`, respectively).
- Different notions of confluence (diamond property, confluence, local
confluence) and the relations between these.
- A `size` function for finite maps and prove some properties.
- More results about `Qp` fractions.
- More miscellaneous results about sets, maps, lists, multisets.
- Various type class utilities, e.g. `TCEq`, `TCIf`, `TCDiag`, `TCNoBackTrack`,
and `tc_to_bool`.
- Generalize `gset_to_propset` to `set_to_propset` for any `SemiSet`.
Changes:
- Consistently use `lia` instead of `omega` everywhere.
- Consistently block `simpl` on all `Z` operations.
- The `Infinite` class is now defined using a function `fresh : list A → A`
that given a list `xs`, gives an element `fresh xs ∉ xs`.
- Make `default` an abbreviation for `from_option id` (instead of just swapping
the argument order of `from_option`).
- More efficient `Countable` instance for `list` that is linear instead of
exponential.
- Improve performance of `set_solver` significantly by introducing specialized
type class `SetUnfoldElemOf` for propositions involving `∈`.
- Make `gset` a `Definition` instead of a `Notation` to improve performance.
- Use `disj_union` (notation `⊎`) for disjoint union on multisets (that adds the
multiplicities). Repurpose `∪` on multisets for the actual union (that takes
the max of the multiplicities).
Naming:
- Consistently use the `set` prefix instead of the `collection` prefix for
definitions and lemmas.
- Renaming of classes:
+ `Collection` into `Set_` (`_` since `Set` is a reserved keyword)
+ `SimpleCollection` into `SemiSet`
+ `FinCollection` into `FinSet`
+ `CollectionMonad` into `MonadSet`
- Types:
+ `set A := A → Prop` into `propset`
+ `bset := A → bool` into `boolset`.
- Files:
+ `collections.v` into `sets.v`
+ `fin_collections.v` into `fin_sets.v`
+ `bset` into `boolset`
+ `set` into `propset`
- Consistently use the naming scheme `X_to_Y` for conversion functions, e.g.
`list_to_map` instead of the former `map_of_list`.
The following `sed` script should perform most of the renaming:
``` ```
sed ' sed '
......
...@@ -9,7 +9,7 @@ all: Makefile.coq ...@@ -9,7 +9,7 @@ all: Makefile.coq
clean: Makefile.coq clean: Makefile.coq
+@make -f Makefile.coq clean +@make -f Makefile.coq clean
find theories tests \( -name "*.d" -o -name "*.vo" -o -name "*.aux" -o -name "*.cache" -o -name "*.glob" -o -name "*.vio" \) -print -delete || true find theories tests \( -name "*.d" -o -name "*.vo" -o -name "*.aux" -o -name "*.cache" -o -name "*.glob" -o -name "*.vio" \) -print -delete || true
rm -f Makefile.coq rm -f Makefile.coq .lia.cache
.PHONY: clean .PHONY: clean
# Create Coq Makefile. # Create Coq Makefile.
...@@ -29,14 +29,8 @@ build-dep: build-dep/opam phony ...@@ -29,14 +29,8 @@ build-dep: build-dep/opam phony
@# that are incompatible with our build requirements. @# that are incompatible with our build requirements.
@# To achieve this, we create a fake opam package that has our build-dependencies as @# To achieve this, we create a fake opam package that has our build-dependencies as
@# dependencies, but does not actually install anything itself. @# dependencies, but does not actually install anything itself.
@echo "# Pinning build-dep package." && \ @echo "# Installing build-dep package."
if opam --version | grep "^1\." -q; then \ @opam install $(OPAMFLAGS) build-dep/
BUILD_DEP_PACKAGE="$$(egrep "^name:" build-dep/opam | sed 's/^name: *"\(.*\)" */\1/')" && \
opam pin add -k path $(OPAMFLAGS) "$$BUILD_DEP_PACKAGE".dev build-dep && \
opam reinstall $(OPAMFLAGS) "$$BUILD_DEP_PACKAGE"; \
else \
opam install $(OPAMFLAGS) build-dep/; \
fi
# Some files that do *not* need to be forwarded to Makefile.coq # Some files that do *not* need to be forwarded to Makefile.coq
Makefile: ; Makefile: ;
......
...@@ -45,11 +45,11 @@ Notably: ...@@ -45,11 +45,11 @@ Notably:
This version is known to compile with: This version is known to compile with:
- Coq version 8.7.0 / 8.7.1 / 8.7.2 / 8.8.0 / 8.8.1 / 8.8.2 / 8.9.0 - Coq version 8.7.2 / 8.8.2 / 8.9.1 / 8.10.2 / 8.11.0
## Installing via opam ## Installing via opam
To obtain the latest stable release via opam (1.2.2 or newer), you have to add To obtain the latest stable release via opam (2.0.0 or newer), you have to add
the Coq opam repository: the Coq opam repository:
opam repo add coq-released https://coq.inria.fr/opam/released opam repo add coq-released https://coq.inria.fr/opam/released
...@@ -79,3 +79,9 @@ your account. Then you can fork the ...@@ -79,3 +79,9 @@ your account. Then you can fork the
[Coq-std++ git repository](https://gitlab.mpi-sws.org/iris/stdpp), make your [Coq-std++ git repository](https://gitlab.mpi-sws.org/iris/stdpp), make your
changes in your fork, and create a merge request. changes in your fork, and create a merge request.
## Common problems
On Windows, differences in line endings may cause tests to fail. This can be
fixed by setting Git's autocrlf option to true:
git config --global core.autocrlf true
-Q theories stdpp -Q theories stdpp
# "Declare Scope" does not exist yet in 8.9 # "Declare Scope" does not exist yet in 8.9.
-arg -w -arg -undeclared-scope -arg -w -arg -undeclared-scope
theories/base.v theories/base.v
theories/tactics.v theories/tactics.v
theories/option.v theories/option.v
...@@ -33,6 +34,7 @@ theories/numbers.v ...@@ -33,6 +34,7 @@ theories/numbers.v
theories/nmap.v theories/nmap.v
theories/zmap.v theories/zmap.v
theories/coPset.v theories/coPset.v
theories/coGset.v
theories/lexico.v theories/lexico.v
theories/propset.v theories/propset.v
theories/decidable.v theories/decidable.v
...@@ -44,3 +46,4 @@ theories/infinite.v ...@@ -44,3 +46,4 @@ theories/infinite.v
theories/nat_cancel.v theories/nat_cancel.v
theories/namespaces.v theories/namespaces.v
theories/telescopes.v theories/telescopes.v
theories/binders.v
This project contains an extended "Standard Library" for Coq called coq-std++.
The key features of this library are as follows:
- It provides a great number of definitions and lemmas for common data
structures such as lists, finite maps, finite sets, and finite multisets.
- It uses type classes for common notations (like `∅`, `∪`, and Haskell-style
monad notations) so that these can be overloaded for different data structures.
- It uses type classes to keep track of common properties of types, like it
having decidable equality or being countable or finite.
- Most data structures are represented in canonical ways so that Leibniz
equality can be used as much as possible (for example, for maps we have
`m1 = m2` iff `∀ i, m1 !! i = m2 !! i`). On top of that, the library provides
setoid instances for most types and operations.
- It provides various tactics for common tasks, like an ssreflect inspired
`done` tactic for finishing trivial goals, a simple breadth-first solver
`naive_solver`, an equality simplifier `simplify_eq`, a solver `solve_proper`
for proving compatibility of functions with respect to relations, and a solver
`set_solver` for goals involving set operations.
- It is entirely dependency- and axiom-free.
opam-version: "1.2" opam-version: "2.0"
name: "coq-stdpp" name: "coq-stdpp"
maintainer: "Ralf Jung <jung@mpi-sws.org>" maintainer: "Ralf Jung <jung@mpi-sws.org>"
homepage: "https://gitlab.mpi-sws.org/iris/stdpp"
authors: "Robbert Krebbers, Jacques-Henri Jourdan, Ralf Jung" authors: "Robbert Krebbers, Jacques-Henri Jourdan, Ralf Jung"
bug-reports: "https://gitlab.mpi-sws.org/iris/stdpp/issues"
license: "BSD" license: "BSD"
dev-repo: "https://gitlab.mpi-sws.org/iris/stdpp.git" homepage: "https://gitlab.mpi-sws.org/iris/stdpp"
build: [make "-j%{jobs}%"] bug-reports: "https://gitlab.mpi-sws.org/iris/stdpp/issues"
install: [make "install"] dev-repo: "git+https://gitlab.mpi-sws.org/iris/stdpp.git"
remove: ["rm" "-rf" "%{lib}%/coq/user-contrib/stdpp"]
synopsis: "This project contains an extended \"Standard Library\" for Coq called coq-std++"
description: """
This project contains an extended "Standard Library" for Coq called coq-std++.
The key features of this library are as follows:
- It provides a great number of definitions and lemmas for common data
structures such as lists, finite maps, finite sets, and finite multisets.
- It uses type classes for common notations (like `∅`, `∪`, and Haskell-style
monad notations) so that these can be overloaded for different data structures.
- It uses type classes to keep track of common properties of types, like it
having decidable equality or being countable or finite.
- Most data structures are represented in canonical ways so that Leibniz
equality can be used as much as possible (for example, for maps we have
`m1 = m2` iff `∀ i, m1 !! i = m2 !! i`). On top of that, the library provides
setoid instances for most types and operations.
- It provides various tactics for common tasks, like an ssreflect inspired
`done` tactic for finishing trivial goals, a simple breadth-first solver
`naive_solver`, an equality simplifier `simplify_eq`, a solver `solve_proper`
for proving compatibility of functions with respect to relations, and a solver
`set_solver` for goals involving set operations.
- It is entirely dependency- and axiom-free.
"""
depends: [ depends: [
"coq" { (>= "8.7" & < "8.10~") | (= "dev") } "coq" { (= "8.7.2") | (= "8.8.2") | (>= "8.9.1" & < "8.12~") | (= "dev") }
] ]
build: [make "-j%{jobs}%"]
install: [make "install"]
From stdpp Require Import namespaces strings.
Lemma test1 (N1 N2 : namespace) :
N1 ## N2 N1 @{coPset} N2.
Proof. solve_ndisj. Qed.
Lemma test2 (N1 N2 : namespace) :
N1 ## N2 N1.@"x" @{coPset} N1.@"y" N2.
Proof. solve_ndisj. Qed.
Lemma test3 (N : namespace) :
N @{coPset} N.@"x".
Proof. solve_ndisj. Qed.
Lemma test4 (N : namespace) :
N @{coPset} N.@"x" N.@"y".
Proof. solve_ndisj. Qed.
Lemma test5 (N1 N2 : namespace) :
N1 N2 @{coPset} N1.@"x" N2 N1.@"y".
Proof. solve_ndisj. Qed.
This diff is collapsed.
(* Copyright (c) 2012-2019, Coq-std++ developers. *)
(* This file is distributed under the terms of the BSD license. *)
(** This file implements a type [binder] with elements [BAnon] for the
anonymous binder, and [BNamed] for named binders. This type is isomorphic to
[option string], but we use a special type so that we can define [BNamed] as
a coercion.
This library is used in various Iris developments, like heap-lang, LambdaRust,
Iron, Fairis. *)
From stdpp Require Export strings.
From stdpp Require Import sets countable finite fin_maps.
Inductive binder := BAnon | BNamed :> string binder.
Bind Scope binder_scope with binder.
Delimit Scope binder_scope with binder.
Notation "<>" := BAnon : binder_scope.
Instance binder_dec_eq : EqDecision binder.
Proof. solve_decision. Defined.
Instance binder_inhabited : Inhabited binder := populate BAnon.
Instance binder_countable : Countable binder.
Proof.
refine (inj_countable'
(λ b, match b with BAnon => None | BNamed s => Some s end)
(λ b, match b with None => BAnon | Some s => BNamed s end) _); by intros [].
Qed.
(** The functions [cons_binder b ss] and [app_binder bs ss] are typically used
to collect the free variables of an expression. Here [ss] is the current list of
free variables, and [b], respectively [bs], are the binders that are being
added. *)
Definition cons_binder (b : binder) (ss : list string) : list string :=
match b with BAnon => ss | BNamed s => s :: ss end.
Infix ":b:" := cons_binder (at level 60, right associativity).
Fixpoint app_binder (bs : list binder) (ss : list string) : list string :=
match bs with [] => ss | b :: bs => b :b: app_binder bs ss end.
Infix "+b+" := app_binder (at level 60, right associativity).
Instance set_unfold_cons_binder s b ss P :
SetUnfoldElemOf s ss P SetUnfoldElemOf s (b :b: ss) (BNamed s = b P).
Proof.
constructor. rewrite <-(set_unfold (s ss) P).
destruct b; simpl; rewrite ?elem_of_cons; naive_solver.
Qed.
Instance set_unfold_app_binder s bs ss P Q :
SetUnfoldElemOf (BNamed s) bs P SetUnfoldElemOf s ss Q
SetUnfoldElemOf s (bs +b+ ss) (P Q).
Proof.
intros HinP HinQ.
constructor. rewrite <-(set_unfold (s ss) Q), <-(set_unfold (BNamed s bs) P).
clear HinP HinQ.
induction bs; set_solver.
Qed.
Lemma app_binder_named ss1 ss2 : (BNamed <$> ss1) +b+ ss2 = ss1 ++ ss2.
Proof. induction ss1; by f_equal/=. Qed.
Lemma app_binder_snoc bs s ss : bs +b+ (s :: ss) = (bs ++ [BNamed s]) +b+ ss.
Proof. induction bs; by f_equal/=. Qed.
Instance cons_binder_Permutation b : Proper (() ==> ()) (cons_binder b).
Proof. intros ss1 ss2 Hss. destruct b; csimpl; by rewrite Hss. Qed.
Instance app_binder_Permutation : Proper (() ==> () ==> ()) app_binder.
Proof.
assert ( bs, Proper (() ==> ()) (app_binder bs)).
{ induction bs as [|[]]; intros ss1 ss2; simpl; by intros ->. }
induction 1 as [|[]|[] []|]; intros ss1 ss2 Hss; simpl;
first [by eauto using perm_trans|by rewrite 1?perm_swap, Hss].
Qed.
Definition binder_delete `{Delete string M} (b : binder) (m : M) : M :=
match b with BAnon => m | BNamed s => delete s m end.
Definition binder_insert `{Insert string A M} (b : binder) (x : A) (m : M) : M :=
match b with BAnon => m | BNamed s => <[s:=x]> m end.
Instance: Params (@binder_insert) 4 := {}.
Section binder_delete_insert.
Context `{FinMap string M}.
Global Instance binder_insert_proper `{Equiv A} b :
Proper (() ==> () ==> (@{M A})) (binder_insert b).
Proof. destruct b; solve_proper. Qed.
Lemma binder_delete_empty {A} b : binder_delete b =@{M A} .
Proof. destruct b; simpl; auto using delete_empty. Qed.
Lemma lookup_binder_delete_None {A} (m : M A) b s :
binder_delete b m !! s = None b = BNamed s m !! s = None.
Proof. destruct b; simpl; by rewrite ?lookup_delete_None; naive_solver. Qed.
Lemma binder_insert_fmap {A B} (f : A B) (x : A) b (m : M A) :
f <$> binder_insert b x m = binder_insert b (f x) (f <$> m).
Proof. destruct b; simpl; by rewrite ?fmap_insert. Qed.
Lemma binder_delete_insert {A} b s x (m : M A) :
b BNamed s binder_delete b (<[s:=x]> m) = <[s:=x]> (binder_delete b m).
Proof. intros. destruct b; simpl; by rewrite ?delete_insert_ne by congruence. Qed.
Lemma binder_delete_delete {A} b s (m : M A) :
binder_delete b (delete s m) = delete s (binder_delete b m).
Proof. destruct b; simpl; by rewrite 1?delete_commute. Qed.
End binder_delete_insert.
...@@ -19,15 +19,16 @@ Instance boolset_intersection {A} : Intersection (boolset A) := λ X1 X2, ...@@ -19,15 +19,16 @@ Instance boolset_intersection {A} : Intersection (boolset A) := λ X1 X2,
BoolSet (λ x, boolset_car X1 x && boolset_car X2 x). BoolSet (λ x, boolset_car X1 x && boolset_car X2 x).
Instance boolset_difference {A} : Difference (boolset A) := λ X1 X2, Instance boolset_difference {A} : Difference (boolset A) := λ X1 X2,
BoolSet (λ x, boolset_car X1 x && negb (boolset_car X2 x)). BoolSet (λ x, boolset_car X1 x && negb (boolset_car X2 x)).
Instance boolset_set `{EqDecision A} : Set_ A (boolset A). Instance boolset_top_set `{EqDecision A} : TopSet A (boolset A).
Proof. Proof.
split; [split| |]. split; [split; [split| |]|].
- by intros x ?. - by intros x ?.
- by intros x y; rewrite <-(bool_decide_spec (x = y)). - by intros x y; rewrite <-(bool_decide_spec (x = y)).
- split. apply orb_prop_elim. apply orb_prop_intro. - split. apply orb_prop_elim. apply orb_prop_intro.
- split. apply andb_prop_elim. apply andb_prop_intro. - split. apply andb_prop_elim. apply andb_prop_intro.
- intros X Y x; unfold elem_of, boolset_elem_of; simpl. - intros X Y x; unfold elem_of, boolset_elem_of; simpl.
destruct (boolset_car X x), (boolset_car Y x); simpl; tauto. destruct (boolset_car X x), (boolset_car Y x); simpl; tauto.
- done.
Qed. Qed.
Instance boolset_elem_of_dec {A} : RelDecision (@{boolset A}). Instance boolset_elem_of_dec {A} : RelDecision (@{boolset A}).
Proof. refine (λ x X, cast_if (decide (boolset_car X x))); done. Defined. Proof. refine (λ x X, cast_if (decide (boolset_car X x))); done. Defined.
......
(* Copyright (c) 2020, Coq-std++ developers. *)
(* This file is distributed under the terms of the BSD license. *)
(** This file implements the type [coGset A] of finite/cofinite sets
of elements of any countable type [A].
Note that [coGset positive] cannot represent all elements of [coPset]
(e.g., [coPset_suffixes], [coPset_l], and [coPset_r] construct
infinite sets that cannot be represented). *)
From stdpp Require Export sets countable.
From stdpp Require Import decidable finite gmap coPset.
(* Set Default Proof Using "Type". *)
Inductive coGset `{Countable A} :=
| FinGSet (X : gset A)
| CoFinGset (X : gset A).
Arguments coGset _ {_ _} : assert.
Instance coGset_eq_dec `{Countable A} : EqDecision (coGset A).
Proof. solve_decision. Defined.
Instance coGset_countable `{Countable A} : Countable (coGset A).
Proof.
apply (inj_countable'
(λ X, match X with FinGSet X => inl X | CoFinGset X => inr X end)
(λ s, match s with inl X => FinGSet X | inr X => CoFinGset X end)).
by intros [].
Qed.
Section coGset.
Context `{Countable A}.
Global Instance coGset_elem_of : ElemOf A (coGset A) := λ x X,
match X with FinGSet X => x X | CoFinGset X => x X end.
Global Instance coGset_empty : Empty (coGset A) := FinGSet .
Global Instance coGset_top : Top (coGset A) := CoFinGset .
Global Instance coGset_singleton : Singleton A (coGset A) := λ x,
FinGSet {[x]}.
Global Instance coGset_union : Union (coGset A) := λ X Y,
match X, Y with
| FinGSet X, FinGSet Y => FinGSet (X Y)
| CoFinGset X, CoFinGset Y => CoFinGset (X Y)
| FinGSet X, CoFinGset Y => CoFinGset (Y X)
| CoFinGset X, FinGSet Y => CoFinGset (X Y)
end.
Global Instance coGset_intersection : Intersection (coGset A) := λ X Y,
match X, Y with
| FinGSet X, FinGSet Y => FinGSet (X Y)
| CoFinGset X, CoFinGset Y => CoFinGset (X Y)
| FinGSet X, CoFinGset Y => FinGSet (X Y)
| CoFinGset X, FinGSet Y => FinGSet (Y X)
end.
Global Instance coGset_difference : Difference (coGset A) := λ X Y,
match X, Y with
| FinGSet X, FinGSet Y => FinGSet (X Y)
| CoFinGset X, CoFinGset Y => FinGSet (Y X)
| FinGSet X, CoFinGset Y => FinGSet (X Y)
| CoFinGset X, FinGSet Y => CoFinGset (X Y)
end.
Global Instance coGset_set : TopSet A (coGset A).
Proof.
split; [split; [split| |]|].
- by intros ??.
- intros x y. unfold elem_of, coGset_elem_of; simpl.
by rewrite elem_of_singleton.
- intros [X|X] [Y|Y] x; unfold elem_of, coGset_elem_of, coGset_union; simpl.
+ set_solver.
+ by rewrite not_elem_of_difference, (comm ()).
+ by rewrite not_elem_of_difference.
+ by rewrite not_elem_of_intersection.
- intros [] [];
unfold elem_of, coGset_elem_of, coGset_intersection; set_solver.
- intros [X|X] [Y|Y] x;
unfold elem_of, coGset_elem_of, coGset_difference; simpl.
+ set_solver.
+ rewrite elem_of_intersection. destruct (decide (x Y)); tauto.
+ set_solver.
+ rewrite elem_of_difference. destruct (decide (x Y)); tauto.
- done.
Qed.
End coGset.
Instance coGset_elem_of_dec `{Countable A} : RelDecision (@{coGset A}) :=
λ x X,
match X with
| FinGSet X => decide_rel elem_of x X
| CoFinGset X => not_dec (decide_rel elem_of x X)
end.
Section infinite.
Context `{Countable A, Infinite A}.
Global Instance coGset_leibniz : LeibnizEquiv (coGset A).
Proof.
intros [X|X] [Y|Y]; rewrite elem_of_equiv;
unfold elem_of, coGset_elem_of; simpl; intros HXY.
- f_equal. by apply leibniz_equiv.
- by destruct (exist_fresh (X Y)) as [? [? ?%HXY]%not_elem_of_union].
- by destruct (exist_fresh (X Y)) as [? [?%HXY ?]%not_elem_of_union].
- f_equal. apply leibniz_equiv; intros x. by apply not_elem_of_iff.
Qed.
Global Instance coGset_equiv_dec : RelDecision (@{coGset A}).
Proof.
refine (λ X Y, cast_if (decide (X = Y))); abstract (by fold_leibniz).
Defined.
Global Instance coGset_disjoint_dec : RelDecision (##@{coGset A}).
Proof.
refine (λ X Y, cast_if (decide (X Y = )));
abstract (by rewrite disjoint_intersection_L).
Defined.
Global Instance coGset_subseteq_dec : RelDecision (@{coGset A}).
Proof.
refine (λ X Y, cast_if (decide (X Y = Y)));
abstract (by rewrite subseteq_union_L).
Defined.
Definition coGset_finite (X : coGset A) : bool :=
match X with FinGSet _ => true | CoFinGset _ => false end.
Lemma coGset_finite_spec X : set_finite X coGset_finite X.
Proof.
destruct X as [X|X];
unfold set_finite, elem_of at 1, coGset_elem_of; simpl.
- split; [done|intros _]. exists (elements X). set_solver.
- split; [intros [Y HXY]%(pred_finite_set(C:=gset A))|done].
by destruct (exist_fresh (X Y)) as [? [?%HXY ?]%not_elem_of_union].
Qed.
Global Instance coGset_finite_dec (X : coGset A) : Decision (set_finite X).
Proof.
refine (cast_if (decide (coGset_finite X)));
abstract (by rewrite coGset_finite_spec).
Defined.
End infinite.
(** * Pick elements from infinite sets *)
Definition cogpick `{Countable A, Infinite A} (X : coGset A) : A :=
fresh (match X with FinGSet _ => | CoFinGset X => X end).
Lemma cogpick_elem_of `{Countable A, Infinite A} X :
¬set_finite X cogpick X X.
Proof.
unfold cogpick. destruct X as [X|X]; rewrite coGset_finite_spec; simpl.
done. by intros _; apply is_fresh.
Qed.
(** * Conversion to and from gset *)
Definition coGset_to_gset `{Countable A} (X : coGset A) : gset A :=
match X with FinGSet X => X | CoFinGset _ => end.
Definition gset_to_coGset `{Countable A} : gset A coGset A := FinGSet.
Section to_gset.
Context `{Countable A, Infinite A}.
Lemma elem_of_coGset_to_gset (X : coGset A) x :
set_finite X x coGset_to_gset X x X.
Proof. rewrite coGset_finite_spec. by destruct X. Qed.
Lemma elem_of_gset_to_coGset (X : gset A) x : x gset_to_coGset X x X.
Proof. done. Qed.
Lemma gset_to_coGset_finite (X : gset A) : set_finite (gset_to_coGset X).
Proof. by rewrite coGset_finite_spec. Qed.
End to_gset.
(** * Conversion to coPset *)
Definition coGset_to_coPset (X : coGset positive) : coPset :=
match X with
| FinGSet X => gset_to_coPset X
| CoFinGset X => gset_to_coPset X
end.
Lemma elem_of_coGset_to_coPset X x : x coGset_to_coPset X x X.
Proof.
destruct X as [X|X]; simpl.
by rewrite elem_of_gset_to_coPset.
by rewrite elem_of_difference, elem_of_gset_to_coPset, (left_id True ()).
Qed.
(** * Inefficient conversion to arbitrary sets with a top element *)
(** This shows that, when [A] is countable, [coGset A] is initial
among sets with [∪], [∩], [∖], [∅], [{[_]}], and [⊤]. *)
Definition coGset_to_top_set `{Countable A, Empty C, Singleton A C, Union C,
Top C, Difference C} (X : coGset A) : C :=
match X with
| FinGSet X => list_to_set (elements X)
| CoFinGset X => list_to_set (elements X)
end.
Lemma elem_of_coGset_to_top_set `{Countable A, TopSet A C} X x :
x @{C} coGset_to_top_set X x X.
Proof. destruct X; set_solver. Qed.
(** * Domain of finite maps *)
Instance coGset_dom `{Countable K} {A} : Dom (gmap K A) (coGset K) := λ m,
gset_to_coGset (dom _ m).
Instance coGset_dom_spec `{Countable K} : FinMapDom K (gmap K) (coGset K).
Proof.
split; try apply _. intros B m i. unfold dom, coGset_dom.
by rewrite elem_of_gset_to_coGset, elem_of_dom.
Qed.
Typeclasses Opaque coGset_elem_of coGset_empty coGset_top coGset_singleton.
Typeclasses Opaque coGset_union coGset_intersection coGset_difference.
Typeclasses Opaque coGset_dom.
...@@ -169,9 +169,9 @@ Instance coPset_difference : Difference coPset := λ X Y, ...@@ -169,9 +169,9 @@ Instance coPset_difference : Difference coPset := λ X Y,
let (t1,Ht1) := X in let (t2,Ht2) := Y in let (t1,Ht1) := X in let (t2,Ht2) := Y in
(t1 coPset_opp_raw t2) coPset_intersection_wf _ _ Ht1 (coPset_opp_wf _). (t1 coPset_opp_raw t2) coPset_intersection_wf _ _ Ht1 (coPset_opp_wf _).
Instance coPset_set : Set_ positive coPset. Instance coPset_top_set : TopSet positive coPset.
Proof. Proof.
split; [split| |]. split; [split; [split| |]|].
- by intros ??. - by intros ??.
- intros p q. apply coPset_elem_of_singleton. - intros p q. apply coPset_elem_of_singleton.
- intros [t] [t'] p; unfold elem_of, coPset_elem_of, coPset_union; simpl. - intros [t] [t'] p; unfold elem_of, coPset_elem_of, coPset_union; simpl.
...@@ -181,8 +181,12 @@ Proof. ...@@ -181,8 +181,12 @@ Proof.
- intros [t] [t'] p; unfold elem_of, coPset_elem_of, coPset_difference; simpl. - intros [t] [t'] p; unfold elem_of, coPset_elem_of, coPset_difference; simpl.
by rewrite coPset_elem_of_intersection, by rewrite coPset_elem_of_intersection,
coPset_elem_of_opp, andb_True, negb_True. coPset_elem_of_opp, andb_True, negb_True.
- done.
Qed. Qed.
(** Iris and specifically [solve_ndisj] heavily rely on this hint. *)
Hint Resolve (top_subseteq (A:=positive) (C:=coPset)) : core.
Instance coPset_leibniz : LeibnizEquiv coPset. Instance coPset_leibniz : LeibnizEquiv coPset.
Proof. Proof.
intros X Y; rewrite elem_of_equiv; intros HXY. intros X Y; rewrite elem_of_equiv; intros HXY.
...@@ -204,11 +208,6 @@ Proof. ...@@ -204,11 +208,6 @@ Proof.
refine (λ X Y, cast_if (decide (X Y = Y))); abstract (by rewrite subseteq_union_L). refine (λ X Y, cast_if (decide (X Y = Y))); abstract (by rewrite subseteq_union_L).
Defined. Defined.
(** * Top *)
Lemma coPset_top_subseteq (X : coPset) : X .
Proof. done. Qed.
Hint Resolve coPset_top_subseteq : core.
(** * Finite sets *) (** * Finite sets *)
Fixpoint coPset_finite (t : coPset_raw) : bool := Fixpoint coPset_finite (t : coPset_raw) : bool :=
match t with match t with
...@@ -318,11 +317,11 @@ Proof. ...@@ -318,11 +317,11 @@ Proof.
Qed. Qed.
(** * Conversion to and from gsets of positives *) (** * Conversion to and from gsets of positives *)
Lemma coPset_to_gset_wf (m : Pmap ()) : gmap_wf (K:=positive) m. Lemma coPset_to_gset_wf (m : Pmap ()) : gmap_wf positive m.
Proof. done. Qed. Proof. unfold gmap_wf. by rewrite bool_decide_spec. Qed.
Definition coPset_to_gset (X : coPset) : gset positive := Definition coPset_to_gset (X : coPset) : gset positive :=
let 'Mapset m := coPset_to_Pset X in let 'Mapset m := coPset_to_Pset X in
Mapset (GMap m (bool_decide_pack _ (coPset_to_gset_wf m))). Mapset (GMap m (coPset_to_gset_wf m)).
Definition gset_to_coPset (X : gset positive) : coPset := Definition gset_to_coPset (X : gset positive) : coPset :=
let 'Mapset (GMap (PMap t Ht) _) := X in Pset_to_coPset_raw t Pset_to_coPset_wf _ Ht. let 'Mapset (GMap (PMap t Ht) _) := X in Pset_to_coPset_raw t Pset_to_coPset_wf _ Ht.
......
...@@ -18,14 +18,14 @@ Definition encode_nat `{Countable A} (x : A) : nat := ...@@ -18,14 +18,14 @@ Definition encode_nat `{Countable A} (x : A) : nat :=
pred (Pos.to_nat (encode x)). pred (Pos.to_nat (encode x)).
Definition decode_nat `{Countable A} (i : nat) : option A := Definition decode_nat `{Countable A} (i : nat) : option A :=
decode (Pos.of_nat (S i)). decode (Pos.of_nat (S i)).
Instance encode_inj `{Countable A} : Inj (=) (=) encode. Instance encode_inj `{Countable A} : Inj (=) (=) (encode (A:=A)).
Proof. Proof.
intros x y Hxy; apply (inj Some). intros x y Hxy; apply (inj Some).
by rewrite <-(decode_encode x), Hxy, decode_encode. by rewrite <-(decode_encode x), Hxy, decode_encode.
Qed. Qed.
Instance encode_nat_inj `{Countable A} : Inj (=) (=) encode_nat. Instance encode_nat_inj `{Countable A} : Inj (=) (=) (encode_nat (A:=A)).
Proof. unfold encode_nat; intros x y Hxy; apply (inj encode); lia. Qed. Proof. unfold encode_nat; intros x y Hxy; apply (inj encode); lia. Qed.
Lemma decode_encode_nat `{Countable A} x : decode_nat (encode_nat x) = Some x. Lemma decode_encode_nat `{Countable A} (x : A) : decode_nat (encode_nat x) = Some x.
Proof. Proof.
pose proof (Pos2Nat.is_pos (encode x)). pose proof (Pos2Nat.is_pos (encode x)).
unfold decode_nat, encode_nat. rewrite Nat.succ_pred by lia. unfold decode_nat, encode_nat. rewrite Nat.succ_pred by lia.
...@@ -102,6 +102,11 @@ Section inj_countable'. ...@@ -102,6 +102,11 @@ Section inj_countable'.
Next Obligation. intros x. by f_equal/=. Qed. Next Obligation. intros x. by f_equal/=. Qed.
End inj_countable'. End inj_countable'.
(** ** Empty *)
Program Instance Empty_set_countable : Countable Empty_set :=
{| encode u := 1; decode p := None |}.
Next Obligation. by intros []. Qed.
(** ** Unit *) (** ** Unit *)
Program Instance unit_countable : Countable unit := Program Instance unit_countable : Countable unit :=
{| encode u := 1; decode p := Some () |}. {| encode u := 1; decode p := Some () |}.
...@@ -264,7 +269,7 @@ Next Obligation. ...@@ -264,7 +269,7 @@ Next Obligation.
Qed. Qed.
(** ** Generic trees *) (** ** Generic trees *)
Close Scope positive. Local Close Scope positive.
Inductive gen_tree (T : Type) : Type := Inductive gen_tree (T : Type) : Type :=
| GenLeaf : T gen_tree T | GenLeaf : T gen_tree T
......
...@@ -91,6 +91,13 @@ Definition bool_decide (P : Prop) {dec : Decision P} : bool := ...@@ -91,6 +91,13 @@ Definition bool_decide (P : Prop) {dec : Decision P} : bool :=
Lemma bool_decide_reflect P `{dec : Decision P} : reflect P (bool_decide P). Lemma bool_decide_reflect P `{dec : Decision P} : reflect P (bool_decide P).
Proof. unfold bool_decide. destruct dec; [left|right]; assumption. Qed. Proof. unfold bool_decide. destruct dec; [left|right]; assumption. Qed.
Lemma bool_decide_decide P `{!Decision P} :
bool_decide P = if decide P then true else false.
Proof. reflexivity. Qed.
Lemma decide_bool_decide P {Hdec: Decision P} {X : Type} (x1 x2 : X):
(if decide P then x1 else x2) = (if bool_decide P then x1 else x2).
Proof. unfold bool_decide, decide. destruct Hdec; reflexivity. Qed.
Tactic Notation "case_bool_decide" "as" ident (Hd) := Tactic Notation "case_bool_decide" "as" ident (Hd) :=
match goal with match goal with
| H : context [@bool_decide ?P ?dec] |- _ => | H : context [@bool_decide ?P ?dec] |- _ =>
...@@ -108,14 +115,29 @@ Proof. rewrite bool_decide_spec; trivial. Qed. ...@@ -108,14 +115,29 @@ Proof. rewrite bool_decide_spec; trivial. Qed.
Lemma bool_decide_pack (P : Prop) {dec : Decision P} : P bool_decide P. Lemma bool_decide_pack (P : Prop) {dec : Decision P} : P bool_decide P.
Proof. rewrite bool_decide_spec; trivial. Qed. Proof. rewrite bool_decide_spec; trivial. Qed.
Hint Resolve bool_decide_pack : core. Hint Resolve bool_decide_pack : core.
Lemma bool_decide_true (P : Prop) `{Decision P} : P bool_decide P = true.
Proof. case_bool_decide; tauto. Qed. Lemma bool_decide_eq_true (P : Prop) `{Decision P} : bool_decide P = true P.
Lemma bool_decide_false (P : Prop) `{Decision P} : ¬P bool_decide P = false. Proof. case_bool_decide; intuition discriminate. Qed.
Proof. case_bool_decide; tauto. Qed. Lemma bool_decide_eq_false (P : Prop) `{Decision P} : bool_decide P = false ¬P.
Proof. case_bool_decide; intuition discriminate. Qed.
Lemma bool_decide_iff (P Q : Prop) `{Decision P, Decision Q} : Lemma bool_decide_iff (P Q : Prop) `{Decision P, Decision Q} :
(P Q) bool_decide P = bool_decide Q. (P Q) bool_decide P = bool_decide Q.
Proof. repeat case_bool_decide; tauto. Qed. Proof. repeat case_bool_decide; tauto. Qed.
Lemma bool_decide_eq_true_1 P `{!Decision P}: bool_decide P = true P.
Proof. apply bool_decide_eq_true. Qed.
Lemma bool_decide_eq_true_2 P `{!Decision P}: P bool_decide P = true.
Proof. apply bool_decide_eq_true. Qed.
Lemma bool_decide_eq_false_1 P `{!Decision P}: bool_decide P = false ¬P.
Proof. apply bool_decide_eq_false. Qed.
Lemma bool_decide_eq_false_2 P `{!Decision P}: ¬P bool_decide P = false.
Proof. apply bool_decide_eq_false. Qed.
(** Backwards compatibility notations. *)
Notation bool_decide_true := bool_decide_eq_true_2.
Notation bool_decide_false := bool_decide_eq_false_2.
(** * Decidable Sigma types *) (** * Decidable Sigma types *)
(** Leibniz equality on Sigma types requires the equipped proofs to be (** Leibniz equality on Sigma types requires the equipped proofs to be
equal as Coq does not support proof irrelevance. For decidable we equal as Coq does not support proof irrelevance. For decidable we
...@@ -135,7 +157,7 @@ Lemma dexists_proj1 `(P : A → Prop) `{∀ x, Decision (P x)} (x : dsig P) p : ...@@ -135,7 +157,7 @@ Lemma dexists_proj1 `(P : A → Prop) `{∀ x, Decision (P x)} (x : dsig P) p :
dexist (`x) p = x. dexist (`x) p = x.
Proof. apply dsig_eq; reflexivity. Qed. Proof. apply dsig_eq; reflexivity. Qed.
(** * Instances of Decision *) (** * Instances of [Decision] *)
(** Instances of [Decision] for operators of propositional logic. *) (** Instances of [Decision] for operators of propositional logic. *)
Instance True_dec: Decision True := left I. Instance True_dec: Decision True := left I.
Instance False_dec: Decision False := right (False_rect False). Instance False_dec: Decision False := right (False_rect False).
...@@ -162,6 +184,8 @@ Instance bool_eq_dec : EqDecision bool. ...@@ -162,6 +184,8 @@ Instance bool_eq_dec : EqDecision bool.
Proof. solve_decision. Defined. Proof. solve_decision. Defined.
Instance unit_eq_dec : EqDecision unit. Instance unit_eq_dec : EqDecision unit.
Proof. solve_decision. Defined. Proof. solve_decision. Defined.
Instance Empty_set_eq_dec : EqDecision Empty_set.
Proof. solve_decision. Defined.
Instance prod_eq_dec `{EqDecision A, EqDecision B} : EqDecision (A * B). Instance prod_eq_dec `{EqDecision A, EqDecision B} : EqDecision (A * B).
Proof. solve_decision. Defined. Proof. solve_decision. Defined.
Instance sum_eq_dec `{EqDecision A, EqDecision B} : EqDecision (A + B). Instance sum_eq_dec `{EqDecision A, EqDecision B} : EqDecision (A + B).
...@@ -192,3 +216,11 @@ Proof. destruct (decide Q); tauto. Qed. ...@@ -192,3 +216,11 @@ Proof. destruct (decide Q); tauto. Qed.
Program Definition inj_eq_dec `{EqDecision A} {B} (f : B A) Program Definition inj_eq_dec `{EqDecision A} {B} (f : B A)
`{!Inj (=) (=) f} : EqDecision B := λ x y, cast_if (decide (f x = f y)). `{!Inj (=) (=) f} : EqDecision B := λ x y, cast_if (decide (f x = f y)).
Solve Obligations with firstorder congruence. Solve Obligations with firstorder congruence.
(** * Instances of [RelDecision] *)
Definition flip_dec {A} (R : relation A) `{!RelDecision R} :
RelDecision (flip R) := λ x y, decide_rel R y x.
(** We do not declare this as an actual instance since Coq can unify [flip ?R]
with any relation. Coq's standard library is carrying out the same approach for
the [Reflexive], [Transitive], etc, instance of [flip]. *)
Hint Extern 3 (RelDecision (flip _)) => apply flip_dec : typeclass_instances.
...@@ -11,15 +11,26 @@ Class FinMapDom K M D `{∀ A, Dom (M A) D, FMap M, ...@@ -11,15 +11,26 @@ Class FinMapDom K M D `{∀ A, Dom (M A) D, FMap M,
OMap M, Merge M, A, FinMapToList K A (M A), EqDecision K, OMap M, Merge M, A, FinMapToList K A (M A), EqDecision K,
ElemOf K D, Empty D, Singleton K D, ElemOf K D, Empty D, Singleton K D,
Union D, Intersection D, Difference D} := { Union D, Intersection D, Difference D} := {
finmap_dom_map :>> FinMap K M; finmap_dom_map :> FinMap K M;
finmap_dom_set :>> Set_ K D; finmap_dom_set :> Set_ K D;
elem_of_dom {A} (m : M A) i : i dom D m is_Some (m !! i) elem_of_dom {A} (m : M A) i : i dom D m is_Some (m !! i)
}. }.
Section fin_map_dom. Section fin_map_dom.
Context `{FinMapDom K M D}. Context `{FinMapDom K M D}.
Lemma dom_map_filter {A} (P : K * A Prop) `{! x, Decision (P x)} (m : M A): Lemma lookup_lookup_total_dom `{!Inhabited A} (m : M A) i :
i dom D m m !! i = Some (m !!! i).
Proof. rewrite elem_of_dom. apply lookup_lookup_total. Qed.
Lemma dom_map_filter {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 D (filter P m) X.
Proof.
intros HX i. rewrite elem_of_dom, HX.
unfold is_Some. by setoid_rewrite map_filter_lookup_Some.
Qed.
Lemma dom_map_filter_subseteq {A} (P : K * A Prop) `{! x, Decision (P x)} (m : M A):
dom D (filter P m) dom D m. dom D (filter P m) dom D m.
Proof. Proof.
intros ?. rewrite 2!elem_of_dom. intros ?. rewrite 2!elem_of_dom.
...@@ -119,8 +130,23 @@ Proof. ...@@ -119,8 +130,23 @@ Proof.
eauto using (empty_finite (C:=D)), (union_finite (C:=D)), eauto using (empty_finite (C:=D)), (union_finite (C:=D)),
(singleton_finite (C:=D)). (singleton_finite (C:=D)).
Qed. Qed.
Global Instance dom_proper `{!Equiv A} : Proper ((@{M A}) ==> ()) (dom D).
Proof.
intros m1 m2 EQm. apply elem_of_equiv. intros i.
rewrite !elem_of_dom, EQm. done.
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 D) | 0.
Proof. intros ???. unfold_leibniz. by apply dom_proper. Qed.
Context `{!LeibnizEquiv D}. Context `{!LeibnizEquiv D}.
Lemma dom_map_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 D (filter P m) = X.
Proof. unfold_leibniz. apply dom_map_filter. Qed.
Lemma dom_empty_L {A} : dom D (@empty (M A) _) = . Lemma dom_empty_L {A} : dom D (@empty (M A) _) = .
Proof. unfold_leibniz; apply dom_empty. Qed. Proof. unfold_leibniz; apply dom_empty. Qed.
Lemma dom_empty_inv_L {A} (m : M A) : dom D m = m = . Lemma dom_empty_inv_L {A} (m : M A) : dom D m = m = .
...@@ -145,12 +171,12 @@ Proof. unfold_leibniz; apply dom_fmap. Qed. ...@@ -145,12 +171,12 @@ Proof. unfold_leibniz; apply dom_fmap. Qed.
End fin_map_dom. End fin_map_dom.
Lemma dom_seq `{FinMapDom nat M D} {A} start (xs : list A) : Lemma dom_seq `{FinMapDom nat M D} {A} start (xs : list A) :
dom D (map_seq start xs) set_seq start (length xs). dom D (map_seq start (M:=M A) xs) set_seq start (length xs).
Proof. Proof.
revert start. induction xs as [|x xs IH]; intros start; simpl. revert start. induction xs as [|x xs IH]; intros start; simpl.
- by rewrite dom_empty. - by rewrite dom_empty.
- by rewrite dom_insert, IH. - by rewrite dom_insert, IH.
Qed. Qed.
Lemma dom_seq_L `{FinMapDom nat M D, !LeibnizEquiv D} {A} start (xs : list A) : Lemma dom_seq_L `{FinMapDom nat M D, !LeibnizEquiv D} {A} start (xs : list A) :
dom D (map_seq start xs) = set_seq start (length xs). dom D (map_seq (M:=M A) start xs) = set_seq start (length xs).
Proof. unfold_leibniz. apply dom_seq. Qed. Proof. unfold_leibniz. apply dom_seq. Qed.
This diff is collapsed.
...@@ -60,8 +60,8 @@ Defined. ...@@ -60,8 +60,8 @@ Defined.
(** * The [elements] operation *) (** * The [elements] operation *)
Global Instance set_unfold_elements X x P : Global Instance set_unfold_elements X x P :
SetUnfold (x X) P SetUnfold (x elements X) P. SetUnfoldElemOf x X P SetUnfoldElemOf x (elements X) P.
Proof. constructor. by rewrite elem_of_elements, (set_unfold (x X) P). Qed. Proof. constructor. by rewrite elem_of_elements, (set_unfold_elem_of x X P). Qed.
Global Instance elements_proper: Proper (() ==> ()) (elements (C:=C)). Global Instance elements_proper: Proper (() ==> ()) (elements (C:=C)).
Proof. Proof.
...@@ -224,6 +224,11 @@ Proof. ...@@ -224,6 +224,11 @@ Proof.
rewrite (union_difference {[ x ]} X) by set_solver. rewrite (union_difference {[ x ]} X) by set_solver.
apply Hadd. set_solver. apply IH. set_solver. apply Hadd. set_solver. apply IH. set_solver.
Qed. Qed.
Lemma set_fold_ind_L `{!LeibnizEquiv C}
{B} (P : B C Prop) (f : A B B) (b : B) :
P b ( x X r, x X P r X P (f x r) ({[ x ]} X))
X, P (set_fold f b X) X.
Proof. apply set_fold_ind. by intros ?? -> ?? ->%leibniz_equiv. Qed.
Lemma set_fold_proper {B} (R : relation B) `{!Equivalence R} Lemma set_fold_proper {B} (R : relation B) `{!Equivalence R}
(f : A B B) (b : B) `{!Proper ((=) ==> R ==> R) f} (f : A B B) (b : B) `{!Proper ((=) ==> R ==> R) f}
(Hf : a1 a2 b, R (f a1 (f a2 b)) (f a2 (f a1 b))) : (Hf : a1 a2 b, R (f a1 (f a2 b)) (f a2 (f a1 b))) :
...@@ -278,9 +283,9 @@ Section filter. ...@@ -278,9 +283,9 @@ Section filter.
by rewrite elem_of_list_to_set, elem_of_list_filter, elem_of_elements. by rewrite elem_of_list_to_set, elem_of_list_filter, elem_of_elements.
Qed. Qed.
Global Instance set_unfold_filter X Q : Global Instance set_unfold_filter X Q :
SetUnfold (x X) Q SetUnfold (x filter P X) (P x Q). SetUnfoldElemOf x X Q SetUnfoldElemOf x (filter P X) (P x Q).
Proof. Proof.
intros ??; constructor. by rewrite elem_of_filter, (set_unfold (x X) Q). intros ??; constructor. by rewrite elem_of_filter, (set_unfold_elem_of x X Q).
Qed. Qed.
Lemma filter_empty : filter P (:C) . Lemma filter_empty : filter P (:C) .
...@@ -316,8 +321,8 @@ Section map. ...@@ -316,8 +321,8 @@ Section map.
by setoid_rewrite elem_of_elements. by setoid_rewrite elem_of_elements.
Qed. Qed.
Global Instance set_unfold_map (f : A B) (X : C) (P : A Prop) : Global Instance set_unfold_map (f : A B) (X : C) (P : A Prop) :
( y, SetUnfold (y X) (P y)) ( y, SetUnfoldElemOf y X (P y))
SetUnfold (x set_map (D:=D) f X) ( y, x = f y P y). SetUnfoldElemOf x (set_map (D:=D) f X) ( y, x = f y P y).
Proof. constructor. rewrite elem_of_map; naive_solver. Qed. Proof. constructor. rewrite elem_of_map; naive_solver. Qed.
Global Instance set_map_proper : Global Instance set_map_proper :
...@@ -396,7 +401,7 @@ Section infinite. ...@@ -396,7 +401,7 @@ Section infinite.
(** Properties about the [fresh] operation on finite sets *) (** Properties about the [fresh] operation on finite sets *)
Global Instance fresh_proper: Proper ((@{C}) ==> (=)) fresh. Global Instance fresh_proper: Proper ((@{C}) ==> (=)) fresh.
Proof. unfold fresh, set_fresh. solve_proper. Qed. Proof. unfold fresh, set_fresh. by intros X1 X2 ->. Qed.
Lemma is_fresh X : fresh X X. Lemma is_fresh X : fresh X X.
Proof. Proof.
......
...@@ -18,41 +18,41 @@ Definition card A `{Finite A} := length (enum A). ...@@ -18,41 +18,41 @@ Definition card A `{Finite A} := length (enum A).
Program Definition finite_countable `{Finite A} : Countable A := {| Program Definition finite_countable `{Finite A} : Countable A := {|
encode := λ x, encode := λ x,
Pos.of_nat $ S $ default 0 $ fst <$> list_find (x =) (enum A); Pos.of_nat $ S $ default 0 $ fst <$> list_find (x =.) (enum A);
decode := λ p, enum A !! pred (Pos.to_nat p) decode := λ p, enum A !! pred (Pos.to_nat p)
|}. |}.
Arguments Pos.of_nat : simpl never. Arguments Pos.of_nat : simpl never.
Next Obligation. Next Obligation.
intros ?? [xs Hxs HA] x; unfold encode, decode; simpl. intros ?? [xs Hxs HA] x; unfold encode, decode; simpl.
destruct (list_find_elem_of (x =) xs x) as [[i y] Hi]; auto. destruct (list_find_elem_of (x =.) xs x) as [[i y] Hi]; auto.
rewrite Nat2Pos.id by done; simpl; rewrite Hi; simpl. rewrite Nat2Pos.id by done; simpl; rewrite Hi; simpl.
destruct (list_find_Some (x =) xs i y); naive_solver. destruct (list_find_Some (x =.) xs i y); naive_solver.
Qed. Qed.
Hint Immediate finite_countable : typeclass_instances. Hint Immediate finite_countable : typeclass_instances.
Definition find `{Finite A} P `{ x, Decision (P x)} : option A := Definition find `{Finite A} P `{ x, Decision (P x)} : option A :=
list_find P (enum A) = decode_nat fst. list_find P (enum A) = decode_nat fst.
Lemma encode_lt_card `{finA: Finite A} x : encode_nat x < card A. Lemma encode_lt_card `{finA: Finite A} (x : A) : encode_nat x < card A.
Proof. Proof.
destruct finA as [xs Hxs HA]; unfold encode_nat, encode, card; simpl. destruct finA as [xs Hxs HA]; unfold encode_nat, encode, card; simpl.
rewrite Nat2Pos.id by done; simpl. rewrite Nat2Pos.id by done; simpl.
destruct (list_find _ xs) as [[i y]|] eqn:?; simpl. destruct (list_find _ xs) as [[i y]|] eqn:HE; simpl.
- destruct (list_find_Some (x =) xs i y); eauto using lookup_lt_Some. - apply list_find_Some in HE as (?&?&?); eauto using lookup_lt_Some.
- destruct xs; simpl. exfalso; eapply not_elem_of_nil, (HA x). lia. - destruct xs; simpl. exfalso; eapply not_elem_of_nil, (HA x). lia.
Qed. Qed.
Lemma encode_decode A `{finA: Finite A} i : Lemma encode_decode A `{finA: Finite A} i :
i < card A x, decode_nat i = Some x encode_nat x = i. i < card A x : A, decode_nat i = Some x encode_nat x = i.
Proof. Proof.
destruct finA as [xs Hxs HA]. destruct finA as [xs Hxs HA].
unfold encode_nat, decode_nat, encode, decode, card; simpl. unfold encode_nat, decode_nat, encode, decode, card; simpl.
intros Hi. apply lookup_lt_is_Some in Hi. destruct Hi as [x Hx]. intros Hi. apply lookup_lt_is_Some in Hi. destruct Hi as [x Hx].
exists x. rewrite !Nat2Pos.id by done; simpl. exists x. rewrite !Nat2Pos.id by done; simpl.
destruct (list_find_elem_of (x =) xs x) as [[j y] Hj]; auto. destruct (list_find_elem_of (x =.) xs x) as [[j y] Hj]; auto.
destruct (list_find_Some (x =) xs j y) as [? ->]; auto. split; [done|]; rewrite Hj; simpl.
rewrite Hj; csimpl; eauto using NoDup_lookup. apply list_find_Some in Hj as (?&->&?). eauto using NoDup_lookup.
Qed. Qed.
Lemma find_Some `{finA: Finite A} P `{ x, Decision (P x)} x : Lemma find_Some `{finA: Finite A} P `{ x, Decision (P x)} (x : A) :
find P = Some x P x. find P = Some x P x.
Proof. Proof.
destruct finA as [xs Hxs HA]; unfold find, decode_nat, decode; simpl. destruct finA as [xs Hxs HA]; unfold find, decode_nat, decode; simpl.
...@@ -60,13 +60,13 @@ Proof. ...@@ -60,13 +60,13 @@ Proof.
rewrite !Nat2Pos.id in Hx by done. rewrite !Nat2Pos.id in Hx by done.
destruct (list_find_Some P xs i y); naive_solver. destruct (list_find_Some P xs i y); naive_solver.
Qed. Qed.
Lemma find_is_Some