Commit 0d70f23e authored by Jacques-Henri Jourdan's avatar Jacques-Henri Jourdan

Include the math directory of the union find proof.

parent eca1d3c9
CoqMakefile.conf
Makefile.coq.conf
Makefile.coq
*.v.d
*.aux
......
-Q theories iris_time
-arg -w -arg -notation-overridden
theories/Auth_mnat.v
theories/Auth_nat.v
theories/ClockIntegers.v
......@@ -13,3 +14,37 @@ theories/TimeCredits.v
theories/TimeCreditsAltProofs.v
theories/TimeReceipts.v
theories/Translation.v
theories/union_find/math/Ackermann.v
theories/union_find/math/FilterTowardsInfinity.v
theories/union_find/math/Filter.v
theories/union_find/math/InverseAckermann.v
theories/union_find/math/InverseNatNat.v
theories/union_find/math/LibFunOrd.v
theories/union_find/math/LibIter.v
theories/union_find/math/LibNatExtra.v
theories/union_find/math/LibRewrite.v
theories/union_find/math/MiscArith.v
theories/union_find/math/TLCBuffer.v
theories/union_find/math/UnionFind01Data.v
theories/union_find/math/UnionFind02EmptyCreate.v
theories/union_find/math/UnionFind03Link.v
theories/union_find/math/UnionFind04Compress.v
theories/union_find/math/UnionFind05IteratedCompression.v
theories/union_find/math/UnionFind06Join.v
theories/union_find/math/UnionFind11Rank.v
theories/union_find/math/UnionFind12RankEmptyCreate.v
theories/union_find/math/UnionFind13RankLink.v
theories/union_find/math/UnionFind14RankCompress.v
theories/union_find/math/UnionFind15RankJoin.v
theories/union_find/math/UnionFind21Parent.v
theories/union_find/math/UnionFind22ParentEvolution.v
theories/union_find/math/UnionFind23Evolution.v
theories/union_find/math/UnionFind24Pleasant.v
theories/union_find/math/UnionFind31Potential.v
theories/union_find/math/UnionFind32PotentialCompress.v
theories/union_find/math/UnionFind33PotentialAnalysis.v
theories/union_find/math/UnionFind41Potential.v
theories/union_find/math/UnionFind42PotentialCompress.v
theories/union_find/math/UnionFind43PotentialAnalysis.v
theories/union_find/math/UnionFind44PotentialJoin.v
(* This module defines Tarjan's variant of Ackermann's function,
and establishes some of its properties. *)
From iris_time.union_find.math Require Import LibNatExtra LibFunOrd
LibIter LibRewrite.
(* -------------------------------------------------------------------------- *)
(* Tarjan's definition, formulated in terms of [iter]. *)
Definition Abase :=
fun x => 1 + x.
Definition Astep :=
fun Ak x => iter (1 + x) Ak x.
Definition A k :=
iter k Astep Abase.
(* -------------------------------------------------------------------------- *)
(* Tarjan's characteristic equations are satisfied. *)
Lemma Abase_eq:
forall x,
A 0 x = 1 + x.
Proof using.
reflexivity.
Qed.
Lemma Astep_eq:
forall k x,
A (1 + k) x = iter (1 + x) (A k) x.
Proof using.
reflexivity.
Qed.
(* -------------------------------------------------------------------------- *)
(* Closed forms for [A 1] and [A 2], from Cormen et al. *)
Lemma A_1_eq:
forall x,
A 1 x = 2 * x + 1.
Proof using.
assert (fact: forall x y, iter x (A 0) y = x + y).
induction x; intros; simpl.
auto.
rewrite IHx. auto.
intro x.
rewrite Astep_eq.
rewrite fact.
omega.
Qed.
Lemma iter_A_1_eq:
forall i x,
iter i (A 1) x =
2^i * (1 + x) - 1.
Proof using.
Opaque plus. (* TEMPORARY ugly *)
induction i; simpl; intros.
omega.
rewrite A_1_eq. rewrite IHi.
(* Now for some pain... *)
assert (0 < 2^i). { eauto using power_positive. }
assert (0 < 1+x). { omega. }
generalize dependent (2^i); intro n; intros.
generalize dependent (1+x); intro y; intros.
assert (0 < n * y). { eauto using mult_positive. }
rewrite <- mult_assoc.
generalize dependent (n * y); intros ny; intros.
omega. (* phew! *)
Transparent plus.
Qed.
Lemma A_2_eq:
forall x,
A 2 x = 2^(1 + x) * (1 + x) - 1.
Proof using.
intros. rewrite Astep_eq. eapply iter_A_1_eq.
Qed.
(* -------------------------------------------------------------------------- *)
(* Every [A k] is inflationary. That is, [x <= A k x] holds. *)
Local Notation everywhere :=
(fun _ => True).
Local Notation inflationary_ :=
(inflationary everywhere le).
Lemma inflationary_Abase:
inflationary_ Abase.
Proof using.
unfold inflationary, Abase. intros. omega.
Qed.
Lemma preserves_inflationary_Astep:
preserves inflationary_ Astep.
Proof using.
unfold preserves, within, inflationary, Astep. intros.
eapply iter_inflationary with (okA := everywhere);
unfold preserves, within;
eauto using le_trans.
Qed.
Lemma Ak_inflationary:
forall k,
inflationary_ (A k).
Proof using.
intro. unfold A.
eapply iter_invariant.
eapply inflationary_Abase.
eapply preserves_inflationary_Astep.
Qed.
Lemma iter_Ak_inflationary:
forall n k x,
x <= iter n (A k) x.
Proof using.
intros.
(* Kind of reproving the same thing again... *)
eapply iter_inflationary with (okA := everywhere);
unfold preserves, within;
eauto using le_trans, Ak_inflationary.
Qed.
(* -------------------------------------------------------------------------- *)
(* [Astep] is inflationary. That is, for every inflationary function [Ak],
[Ak <= Astep Ak] holds -- this is a pointwise inequality. *)
Lemma inflationary_Astep:
inflationary inflationary_ (pointwise everywhere le) Astep.
Proof using.
unfold inflationary, pointwise, Astep. intros.
simpl. rewrite iter_iter_1.
eapply iter_inflationary with (okA := everywhere);
unfold preserves, within; eauto using le_trans.
Qed.
(* -------------------------------------------------------------------------- *)
(* The function [A] is monotonic. (That is, it is monotonic in its first
argument [k], and the results, which are functions, are compared using
pointwise inequality.) *)
Lemma A_monotonic:
monotonic le (pointwise everywhere le) A.
Proof using.
unfold A.
(* We must prove that [iter k Astep Abase] is monotonic with respect to [k].
Because the lemma [inflationary_Astep] has an inflation hypothesis, we
must carry the information that [A k] is inflationary. This is done by
picking an appropriate [okA]. *)
eapply iter_monotonic_in_n_specialized with (okA := inflationary_);
unfold pointwise; eauto using le_trans, inflationary_Abase,
preserves_inflationary_Astep, inflationary_Astep.
Qed.
(* As a corollary, the function [fun k => A k x] is monotonic. In other
words, Ackermann's function is monotonic in its first argument. *)
Lemma Akx_monotonic_in_k:
forall x,
monotonic le le (fun k => A k x).
Proof using.
(* Forgetting [x], it suffices to argue that [A] is monotonic. *)
intro.
eapply monotonic_pointwise_specialize with (okB := everywhere);
eauto using A_monotonic.
Qed.
Hint Resolve Akx_monotonic_in_k : monotonic typeclass_instances.
(* Example. *)
Goal
forall k1 k2 x, k1 <= k2 -> A k1 x <= A k2 x.
Proof using.
eauto with monotonic. (* cool *)
Qed.
(* -------------------------------------------------------------------------- *)
(* The function [fun x => A k x] is monotonic. In other words, Ackermann's
function is monotonic in its second argument. *)
Lemma monotonic_Abase:
monotonic le le Abase.
Proof using.
unfold monotonic, Abase. intros. omega.
Qed.
Lemma preserves_monotonic_Astep:
forall f,
inflationary_ f ->
monotonic le le f ->
monotonic le le (Astep f).
Proof using.
intros. intros x1 x2 ?. unfold Astep.
eapply le_trans; [ | eapply iter_monotonic_in_x; eauto ].
eapply iter_monotonic_in_n with (okA := everywhere);
unfold preserves, within; eauto using le_trans.
omega.
Qed.
Lemma Akx_monotonic_in_x:
forall k,
monotonic le le (A k).
Proof using.
(* Because the lemma [preserves_monotonic_Astep] has an inflation
hypothesis, we argue simultaneously that [A k] is inflationary
and monotonic. This is a little redundant, but seems acceptable. *)
cut (forall k, inflationary_ (A k) /\ monotonic le le (A k)).
{ intro h. eapply h. }
intro. unfold A.
eapply iter_invariant; split; simpl in *;
intuition eauto using inflationary_Abase, monotonic_Abase,
preserves_inflationary_Astep, preserves_monotonic_Astep.
Qed.
Hint Resolve Akx_monotonic_in_x Akx_monotonic_in_k : monotonic typeclass_instances.
(* Example. *)
Goal
forall k x1 x2, x1 <= x2 -> A k x1 <= A k x2.
Proof using.
eauto with monotonic. (* cool *)
Qed.
(* -------------------------------------------------------------------------- *)
(* The power function [pow] can be defined in terms of [iter]. *)
Lemma pow_iter:
forall x y,
x ^ y = iter y (fun a => x * a) 1.
Proof using.
induction y; simpl; eauto.
Qed.
(* [2 ^ x <= A 2 x]. *)
Lemma A_2_lower_bound:
forall x,
2 ^ x <= A 2 x.
Proof using.
(* Tarjan's course notes claim a strict inequality, but in fact there
is equality when [x] is zero. *)
intro.
rewrite pow_iter.
rewrite Astep_eq.
rewrite iter_iter_1p.
rewrite A_1_eq.
(* We are now comparing two applications of [iter]. It suffices to
exploit the fact that [iter n f x] is monotonic in [f] and [x]. *)
eapply le_trans; [ eapply iter_monotonic_in_f | eapply iter_monotonic_in_x ].
(* from [iter_monotonic_in_f] *)
eauto.
eauto using le_trans.
split.
eauto with monotonic.
unfold pointwise. intros. rewrite A_1_eq. omega.
(* from [iter_monotonic_in_x] *)
eauto with monotonic.
omega.
Qed.
(* A slightly more powerful version of the previous lemma. It is not a
direct consequence of the previous lemma, because [2 ^ (log2 n)] is
in general less than or equal to [n]. *)
Lemma A_2_log2_lower_bound:
forall n,
n <= A 2 (log2 n).
Proof using.
(* It is somewhat miraculous that this auxiliary assertion holds. *)
assert (forall b n, n <= 2 * iter (log2 n) (A 1) b + 1).
{ intros. eapply (log2_induction (fun k n => n <= 2 * iter k (A 1) b + 1)). omega. omega.
intros. simpl. rewrite A_1_eq. eauto with div2. }
intros. rewrite Astep_eq. simpl. rewrite A_1_eq. eauto.
(* An alternative proof would consist in using [A_2_eq] together
with the fact that [2^(1 + log2 n)] is at least [n + 1]. *)
Qed.
(* [2 ^ (2 ^ ( ... 2)) { x + 1 times } <= A 3 x]. *)
Lemma A_3_lower_bound:
forall x,
iter (1 + x) (fun a => 2 ^ a) 0 <= A 3 x.
Proof using.
intro.
rewrite Astep_eq.
(* We are now comparing two applications of [iter]. It suffices to
exploit the fact that [iter n f x] is monotonic in [f] and [x]. *)
eapply le_trans; [ eapply iter_monotonic_in_f | eapply iter_monotonic_in_x ].
(* from [iter_monotonic_in_f] *)
eauto.
eauto using le_trans.
split.
eauto with monotonic.
unfold pointwise. eauto using A_2_lower_bound.
(* from [iter_monotonic_in_x] *)
eauto with monotonic.
omega.
Qed.
(* -------------------------------------------------------------------------- *)
From iris_time.union_find.math Require Import Filter.
From iris_time.union_find.math Require Import FilterTowardsInfinity.
(* For every [k], the function [fun x => A k x] tends towards infinity. *)
Lemma Akx_tends_to_infinity_along_x:
forall k,
limit towards_infinity towards_infinity (fun x => A k x).
Proof using.
intro.
eapply prove_tends_towards_infinity.
(* It suffices to exploit the fact that [A k] is inflationary,
i.e. [x <= A k x] holds. *)
intros. exists y. intros ? h.
rewrite h. eapply Ak_inflationary; eauto.
Qed.
(* For every [x] greater than zero, the function [fun k => A k x] tends
towards infinity. We prove this via a very weak lower bound, namely
[k <= A k x]. *)
Lemma Ax_inflationary:
forall x,
x > 0 ->
inflationary_ (fun k => A k x).
Proof using.
unfold inflationary.
intros x ? k _.
induction k; intros; simpl.
(* Base. *)
omega.
(* Step. *)
rewrite Astep_eq.
(* [1 + x] is at least 2, and [iter] is monotonic in [n]. *)
transitivity (iter 2 (A k) x).
2: eapply iter_monotonic_in_n_specialized with (okA := everywhere);
unfold preserves, within;
eauto using le_trans, Ak_inflationary
with omega.
(* Unfold [iter], and exploit the induction hypothesis (which is
possible because [A k] is monotonic). *)
simpl.
transitivity (A k k).
2: eauto with monotonic.
(* Now, [A k k] is at least [A 0 k]. *)
transitivity (A 0 k).
2: eauto with monotonic omega.
(* And [A 0 k] is precisely [1 + k]. *)
rewrite Abase_eq at 1.
omega.
Qed.
Lemma Akx_tends_to_infinity_along_k:
forall x,
x > 0 ->
limit towards_infinity towards_infinity (fun k => A k x).
Proof using.
intros.
eapply prove_tends_towards_infinity.
intros. exists y. intros.
rewrite Ax_inflationary by eauto.
eauto with monotonic.
Qed.
Hint Resolve Akx_tends_to_infinity_along_k : monotonic typeclass_instances.
(* exploited in [InverseAckermann.v] *)
(* -------------------------------------------------------------------------- *)
(* Every [A k] is strictly inflationary. That is, [x < A k x] holds. *)
Lemma Ak_strictly_inflationary:
forall k x,
x < A k x.
Proof using.
(* [A 0] is strictly inflationary already, and [A k] is no less than
[A 0]. The result follows by transitivity. *)
intros.
assert (x < A 0 x).
{ rewrite Abase_eq. omega. }
assert (A 0 x <= A k x).
{ eauto with monotonic omega. }
omega.
Qed.
(* For every [n] other than zero, [iter n (A k)] is strictly inflationary. *)
Lemma iter_Ak_strictly_inflationary:
forall n k x,
n > 0 ->
x < iter n (A k) x.
Proof using.
intros. destruct n; [ omega | ]. simpl.
assert (x < A k x).
{ eapply Ak_strictly_inflationary. }
assert (A k x <= A k (iter n (A k) x)).
{ eauto using iter_Ak_inflationary with monotonic. }
omega.
Qed.
(* -------------------------------------------------------------------------- *)
(* The function [fun k => A k x] is strictly monotonic in [k]. *)
Lemma Akx_strictly_monotonic_in_k_step:
forall k x,
x > 0 ->
A k x < A (1 + k) x.
Proof using.
intros. rewrite Astep_eq. simpl. rewrite iter_iter_1.
eauto using iter_Ak_strictly_inflationary.
Qed.
Lemma Akx_strictly_monotonic_in_k:
forall x,
x > 0 ->
monotonic lt lt (fun k => A k x).
Proof using.
intros. intros k1 k2 ?.
assert (A k1 x < A (1 + k1) x).
{ eauto using Akx_strictly_monotonic_in_k_step. }
assert (A (1 + k1) x <= A k2 x).
{ eauto with monotonic omega. }
omega.
Qed.
Hint Resolve Akx_strictly_monotonic_in_k : monotonic typeclass_instances.
(* -------------------------------------------------------------------------- *)
(* The orbit of a strictly inflationary function goes to infinity. *)
Lemma iter_strictly_inflationary_tends_to_infinity:
forall f x,
(forall x, x < f x) ->
limit towards_infinity towards_infinity (fun i => iter i f x).
Proof using.
(* This lemma has nothing to do with Ackermann's function and could
be placed in a separate file. *)
(* A strictly inflationary function grows by at least one at each
iteration, so we can give a linear lower bound for it. This
implies that iterating over and over takes us to infinity. *)
intros f x hinfl.
assert (bound: forall i, x + i <= iter i f x).
{ intro. eapply iter_indexed_invariant; [ | omega ]. intros j y ?.
generalize (hinfl y). omega. }
(* Manual proof. *)
eapply prove_tends_towards_infinity.
intro y. exists y. intros z ?.
generalize (bound z). omega.
Qed.
(* The orbit of [A k] out of [x] goes to infinity. *)
Lemma iter_i_Akx_tends_to_infinity_along_i:
forall k x,
limit towards_infinity towards_infinity (fun i => iter i (A k) x).
Proof using.
eauto using iter_strictly_inflationary_tends_to_infinity, Ak_strictly_inflationary.
Qed.
(* Iterating [i] times an inflationary function [f] yields a monotonic function
of [i]. *)
Lemma iter_inflationary_monotonic:
forall f x,
(forall x, x <= f x) ->
monotonic le le (fun i => iter i f x).
Proof using.
intros f x hinfl i j ?.
replace j with ((j - i) + i) by omega.
rewrite iter_iter.
generalize (iter i f x). intro y.
eapply iter_inflationary with (okA := everywhere);
unfold preserves, within, inflationary; eauto using le_trans.
Qed.
(* [fun i => iter i (A k) x] is monotonic. *)
Lemma iter_Ak_monotonic_in_i:
forall k x,
monotonic le le (fun i => iter i (A k) x).
Proof using.
intros.
eapply iter_inflationary_monotonic.
intro. eapply Ak_inflationary. tauto.
Qed.
From TLC Require Import LibTactics.
From TLC Require Import LibLogic. (* defines [pred_incl] *)
From TLC Require Import LibSet. (* defines [set] *)
(* ---------------------------------------------------------------------------- *)
(* Technically, a filter is a nonempty set of nonempty subsets of A, which is
closed under inclusion and intersection. *)
Definition filter A := set (set A).
(* Intuitively, a filter is a modality. Let us write [ultimately] for a filter.
If [P] is a predicate, then [ultimately P] is a proposition. Technically,
this proposition asserts that [P] is an element of the filter; intuitively,
it means that [P] holds ``in the limit''. *)
Class Filter {A : Type} (ultimately : filter A) := {
(* A filter must be nonempty. *)
filter_nonempty:
exists P, ultimately P;
(* A filter does not have the empty set as a member. *)
filter_member_nonempty:
forall P, ultimately P ->
exists a, P a;
(* A filter is closed by inclusion and by intersection. *)
filter_closed_under_intersection:
forall P1 P2 P : set A,
ultimately P1 ->
ultimately P2 ->
(forall a, P1 a -> P2 a -> P a) ->
ultimately P
}.
(* ---------------------------------------------------------------------------- *)
(* Basic properties of filters. *)
Section Properties.
Context {A : Type} {ultimately : filter A} `{@Filter A ultimately}.
(* A filter is closed by subset inclusion. In other words, if [ultimately]
is a filter, then it is covariant. *)
Lemma filter_closed_under_inclusion:
forall P1 P2 : set A,
ultimately P1 ->
(forall a, P1 a -> P2 a) ->
ultimately P2.
Proof.
intros. eapply filter_closed_under_intersection; eauto.
Qed.
(* A filter is compatible with extensional equality: if [P1] and [P2] are
extensionally equal, then [ultimately P1] is equivalent to [ultimately
P2]. *)
Lemma filter_extensional:
forall P1 P2 : set A,
(forall a, P1 a <-> P2 a) ->
(ultimately P1 <-> ultimately P2).
Proof.
introv h. split; intros; eapply filter_closed_under_inclusion; eauto;
intros; eapply h; eauto.
Qed.
(* A filter always contains the universe as a member. In other words, if
[P] holds everywhere, then [ultimately P] holds. *)
Lemma filter_universe:
forall P : set A,
(forall a, P a) ->
ultimately P.
Proof.
(* A filter is nonempty, so it has one inhabitant. *)
destruct filter_nonempty.
(* A filter is closed by inclusion, so the universe is also
an inhabitant of the filter. *)
eauto using @filter_closed_under_inclusion.
Qed.
(* If [P] holds ultimately and is independent of its argument, then [P]
holds, period. *)
Lemma filter_const:
forall P : Prop,
ultimately (fun _ => P) ->
P.
Proof.
intros.
forwards [ a ? ]: filter_member_nonempty. eauto.
eauto.
Qed.
End Properties.
(* ---------------------------------------------------------------------------- *)
(* Inclusion of filters. *)
Notation finer ultimately1 ultimately2 :=
(pred_incl ultimately2 ultimately1).
Notation coarser ultimately1 ultimately2 :=
(pred_incl ultimately1 ultimately2).
(* These relations are reflexive and transitive; see [pred_incl_refl] and
[pred_incl_trans] in [LibLogic]. *)
(* ---------------------------------------------------------------------------- *)
(* Applying a function [f] to a filter [ultimately] produces another filter,
known as the image of [ultimately] under [f]. *)
Definition image {A} (ultimately : filter A) {B} (f : A -> B) : set (set B) :=
fun P => ultimately (fun x => P (f x)).
(* Make this a definition, not an instance, because we do not wish it to be
used during the automated search for instances. *)
Definition filter_image {A} ultimately `{Filter A ultimately} {B} (f : A -> B) :
Filter (image ultimately f).
Proof.
econstructor; unfold image.
(* There exists an element in this filter, namely the universe. *)
exists (fun (_ : B) => True). eauto using filter_universe.
(* No element of this filter is empty. *)
intros.
forwards [ a ? ]: filter_member_nonempty; eauto. simpl in *.
eauto.
(* This filter is stable under intersection. *)
introv h1 h2 ?.
eapply (filter_closed_under_intersection _ _ _ h1 h2).
eauto.