Priqueue: Priority Queues
- Discrete-event simulations: The highest-priority event is the one whose scheduled time is the earliest. Simulating one event causes new events to be scheduled in the future.
- Sorting: heap sort puts all the elements in a priority queue, then removes them one at a time.
- Computational geometry: algorithms such as convex hull use priority queues.
- Graph algorithms: Dijkstra's algorithm for finding the shortest path uses a priority queue.
- empty takes constant time
- insert takes constant time
- delete_max takes linear time
- merge takes linear time
Module Signature
This is the "signature" of a correct implementation of priority queues where the keys are natural numbers. Using nat for the key type is a bit silly, since the comparison function Nat.ltb takes linear time in the value of the numbers! But you have already seen in the Extract chapter how to define these kinds of algorithms on key types that have efficient comparisons, so in this chapter (and the Binom chapter) we simply won't worry about the time per comparison.From VFA Require Import Perm.
Module Type PRIQUEUE.
Parameter priqueue: Type.
Definition key := nat.
Parameter empty: priqueue.
Parameter insert: key -> priqueue -> priqueue.
Parameter delete_max: priqueue -> option (key * priqueue).
Parameter merge: priqueue -> priqueue -> priqueue.
Parameter priq: priqueue -> Prop.
Parameter Abs: priqueue -> list key -> Prop.
Axiom can_relate: forall p, priq p -> exists al, Abs p al.
Axiom abs_perm: forall p al bl,
priq p -> Abs p al -> Abs p bl -> Permutation al bl.
Axiom empty_priq: priq empty.
Axiom empty_relate: Abs empty nil.
Axiom insert_priq: forall k p, priq p -> priq (insert k p).
Axiom insert_relate:
forall p al k, priq p -> Abs p al -> Abs (insert k p) (k::al).
Axiom delete_max_None_relate:
forall p, priq p -> (Abs p nil <-> delete_max p = None).
Axiom delete_max_Some_priq:
forall p q k, priq p -> delete_max p = Some(k,q) -> priq q.
Axiom delete_max_Some_relate:
forall (p q: priqueue) k (pl ql: list key), priq p ->
Abs p pl ->
delete_max p = Some (k,q) ->
Abs q ql ->
Permutation pl (k::ql) /\ Forall (ge k) ql.
Axiom merge_priq: forall p q, priq p -> priq q -> priq (merge p q).
Axiom merge_relate:
forall p q pl ql al,
priq p -> priq q ->
Abs p pl -> Abs q ql -> Abs (merge p q) al ->
Permutation al (pl++ql).
End PRIQUEUE.
Take some time to consider whether this is the right specification!
As always, if we get the specification wrong, then proofs of
"correctness" are not so useful.
Now we are responsible for providing Definitions of all
those Parameters, and proving Theorems for all those Axioms,
so that the values in the Module match the types in
the Module Type. If we try to End List_Priqueue before
everything is provided, we'll get an error. Uncomment the next
line and try it!
Some Preliminaries
Fixpoint select (i: nat) (l: list nat) : nat * list nat :=
match l with
| nil => (i, nil)
| h::t => if i >=? h
then let (j, l') := select i t in (j, h::l')
else let (j,l') := select h t in (j, i::l')
end.
Lemma select_perm: forall i l,
let (j,r) := select i l in
Permutation (i::l) (j::r).
Proof. intros i l; revert i.
induction l; intros; simpl in *.
Admitted.
Lemma select_biggest_aux:
forall i al j bl,
Forall (fun x => j >= x) bl ->
select i al = (j,bl) ->
j >= i.
Proof. Admitted.
Theorem select_biggest:
forall i al j bl, select i al = (j,bl) ->
Forall (fun x => j >= x) bl.
Proof. intros i al; revert i; induction al; intros; simpl in *.
admit.
bdestruct (i >=? a).
*
destruct (select i al) eqn:?H.
Admitted.
☐
Definition key := nat.
Definition priqueue := list key.
Definition empty : priqueue := nil.
Definition insert (k: key)(p: priqueue) := k::p.
Definition delete_max (p: priqueue) :=
match p with
| i::p' => Some (select i p')
| nil => None
end.
Definition merge (p q: priqueue) : priqueue := p++q.
The Representation Invariant
The abstraction relation is trivial too.
Inductive Abs': priqueue -> list key -> Prop :=
Abs_intro: forall p, Abs' p p.
Definition Abs := Abs'.
Lemma can_relate : forall p, priq p -> exists al, Abs p al.
Proof.
intros. exists p; constructor.
Qed.
When the Abs relation says, "priority queue p contains elements al",
it is free to report the elements in any order. It could even relate p
to two different lists al and bl, as long as one is a permutation of
the other.
Lemma abs_perm: forall p al bl,
priq p -> Abs p al -> Abs p bl -> Permutation al bl.
Proof.
intros.
inv H0. inv H1. apply Permutation_refl.
Qed.
Lemma empty_priq: priq empty.
Proof. constructor. Qed.
Lemma empty_relate: Abs empty nil.
Proof. constructor. Qed.
Lemma insert_priq: forall k p, priq p -> priq (insert k p).
Proof. intros; constructor. Qed.
Lemma insert_relate:
forall p al k, priq p -> Abs p al -> Abs (insert k p) (k::al).
Proof. intros. unfold insert. inv H0. constructor. Qed.
Lemma delete_max_Some_priq:
forall p q k, priq p -> delete_max p = Some(k,q) -> priq q.
Proof. constructor. Qed.
Lemma delete_max_None_relate:
forall p, priq p ->
(Abs p nil <-> delete_max p = None).
Proof.
Admitted.
Lemma delete_max_Some_relate:
forall (p q: priqueue) k (pl ql: list key), priq p ->
Abs p pl ->
delete_max p = Some (k,q) ->
Abs q ql ->
Permutation pl (k::ql) /\ Forall (ge k) ql.
Proof.
Admitted.
Lemma merge_priq:
forall p q, priq p -> priq q -> priq (merge p q).
Proof. intros. constructor. Qed.
Lemma merge_relate:
forall p q pl ql al,
priq p -> priq q ->
Abs p pl -> Abs q ql -> Abs (merge p q) al ->
Permutation al (pl++ql).
Proof.
Admitted.
☐