Library Parray
Axiomatisation of persistent arrays
Require Import Vbase Veq MyInt31.
Set Implicit Arguments.
Unset Strict Implicit.
Local Open Scope int31.
Type of arrays
Return the length of an array.
Construct a properly initialized array; array length must be positive.
Parameter unsafe_init :
forall A (length: int31) (POS: 0 <? length)
(f: forall (i : int31) (BND: i <? length), A), t A.
forall A (length: int31) (POS: 0 <? length)
(f: forall (i : int31) (BND: i <? length), A), t A.
Read the value store at a particular array index (within bounds).
Update the value store at a particular array index (within bounds).
Parameter unsafe_set :
forall A (a: t A) (i: int31) (v : A) (BND: i <? length a), t A.
Arguments unsafe_init [A] length POS f.
Arguments unsafe_get [A] a i BND.
Arguments unsafe_set [A] a i v BND.
forall A (a: t A) (i: int31) (v : A) (BND: i <? length a), t A.
Arguments unsafe_init [A] length POS f.
Arguments unsafe_get [A] a i BND.
Arguments unsafe_set [A] a i v BND.
Axiomatization of the length function
Axiom length_pos :
forall A (a: t A), 0 <? length a.
Axiom length_unsafe_init :
forall A n POS f, length (unsafe_init (A:=A) n POS f) = n.
Axiom length_unsafe_set :
forall A (a: t A) x v PF, length (unsafe_set a x v PF) = length a.
Fact ltu_length_unsafe_initD A n POS f i :
i <? (length (unsafe_init (A:=A) n POS f)) -> i <? n.
Proof. by rewrite length_unsafe_init. Qed.
Fact ltu_length_unsafe_setD A (a : t A) x v PF i :
i <? length (unsafe_set a x v PF) -> i <? length a.
Proof. by rewrite length_unsafe_set. Qed.
Axiomatization of reading from initial and updated arrays.
Axiom uginit : forall A n POS f x PF,
unsafe_get (A:=A) (unsafe_init n POS f) x PF
= f x (ltu_length_unsafe_initD PF).
Axiom uguss : forall A a x v PF PF',
unsafe_get (A:=A) (unsafe_set a x v PF) x PF' = v.
Axiom uguso : forall A a x v y PF PF' (NEQ: x <> y),
unsafe_get (A:=A) (unsafe_set a x v PF) y PF'
= unsafe_get a y (ltu_length_unsafe_setD PF').
Two arrays are equal iff they have the same length and store the
same values
Axiom eqI : forall A (a b: t A)
(LEQ: length a = length b)
(REQ: forall x POS POS', unsafe_get a x POS = unsafe_get b x POS'),
a = b.
Below, we provide more convenient init, get and set methods
that do not require an "inside bounds" precondition.
Definition init A (length : int31) (f: int31 -> A) : t A :=
match 0 <? length as x with
| true => fun pf => unsafe_init length (sym_eq pf) (fun x pf => f x)
| false => fun _ => unsafe_init 1 eq_refl (fun x _ => f x)
end eq_refl.
Definition get A (a: t A) (i: int31) : A :=
match i <? length a as x with
| true => fun pf => unsafe_get a i (eq_sym pf)
| false => fun _ => unsafe_get a 0 (length_pos a)
end eq_refl.
Definition set A (a: t A) (i: int31) (v : A) : t A :=
match i <? length a as x with
| true => fun pf => unsafe_set a i v (eq_sym pf)
| false => fun _ => a
end eq_refl.
Lemma length_init A n (f : int31 -> A) :
length (init n f) = if 0 <? n then n else 1.
Proof.
by unfold init; des_eqrefl; rewrite length_unsafe_init; desf.
Qed.
Lemma length_set A a x (v : A) : length (set a x v) = length a.
Proof.
unfold set; des_eqrefl; try rewrite length_unsafe_set; desf.
Qed.
Lemma unsafe_getE A (a : t A) x PF :
unsafe_get a x PF = get a x.
Proof.
unfold get; des_eqrefl; [f_equal; apply proof_irrelevance|congruence].
Qed.
Lemma unsafe_setE A (a : t A) x v PF :
unsafe_set a x v PF = set a x v.
Proof.
unfold set; des_eqrefl; [f_equal; apply proof_irrelevance|congruence].
Qed.
Lemma ginit : forall A n f x (PF : x <? n), get (A:=A) (init n f) x = f x.
Proof.
ins; unfold init; des_eqrefl; unfold get; des_eqrefl;
rewrite ?length_unsafe_init in *; try congruence;
try by rewrite uginit; f_equal; apply proof_irrelevance.
rewrite uginit; f_equal; unfold int31_ltu in *.
change (phi 0) with 0%Z in *.
destruct (Z.ltb_spec 0 (phi n)); try done.
destruct (Z.ltb_spec (phi x) (phi n)); try done.
pose proof (phi_bounded x).
assert (X: 0%Z = phi x) by omega.
by apply (f_equal phi_inv) in X; rewrite phi_inv_phi in X.
Qed.
Lemma gss : forall A a x (LT: x <? length a) v, get (A:=A) (set a x v) x = v.
Proof.
unfold set; ins; des_eqrefl; simpl;
[unfold get; des_eqrefl; auto using uguss; rewrite length_unsafe_set in *|];
congruence.
Qed.
Lemma gso : forall A a x y (NEQ: x <> y) (LT: y <? length a) v,
get (A:=A) (set a x v) y = get a y.
Proof.
unfold set; ins; des_eqrefl; ins.
unfold get; des_eqrefl; auto using uguso; try rewrite length_unsafe_set in *.
des_eqrefl.
by rewrite uguso; ins; f_equal; apply proof_irrelevance.
exfalso; rewrite length_unsafe_set in *; congruence.
des_eqrefl; try (exfalso; congruence).
Qed.
Lemma gu A (a : t A) x :
get a x = get a (if x <? length a then x else 0).
Proof.
case_eq (x <? length a); ins; unfold get; do 2 des_eqrefl; try congruence.
f_equal; apply proof_irrelevance.
Qed.
Lemma gs :
forall A (a: t A) x v y (LT: y <? length a),
get (set a x v) y = if x == y then v else get a y.
Proof.
intros; desf; clarify; auto using gss, gso.
Qed.
Lemma gs2 A a x (v : A) y :
get (set a x v) y
= if y <? length a then
if x == y then v else get a y
else if x == 0 then v else get a y.
Proof.
rewrite gu, length_set; desf; subst;
auto using gss, gso, length_pos.
rewrite gso; auto using length_pos.
rewrite (gu _ y); desf.
Qed.
A simpler initializer
Definition create A (length: int31) (v: A) := init length (fun _ => v).
Lemma gcreate A n (v: A) x : get (create n v) x = v.
Proof.
by unfold create, init; des_eqrefl; unfold get; des_eqrefl; apply uginit.
Qed.
Lemma length_create A n (v: A) :
length (create n v) = if 0 <? n then n else 1.
Proof. apply length_init. Qed.
Create a copy of the array
Definition copy A (a : t A) : t A :=
unsafe_init (length a) (length_pos a) (unsafe_get a).
Lemma length_copy A (a : t A) : length (copy a) = length a.
Proof. apply length_unsafe_init. Qed.
Lemma gcopy : forall A (a: t A) x,
get (copy a) x = get a x.
Proof.
ins; unfold get, copy; rewrite uginit; try done.
do 2 des_eqrefl; try rewrite uginit;
try (exfalso; rewrite length_unsafe_init in *; congruence);
f_equal; apply proof_irrelevance.
Qed.
Lemma copyE A (a:t A) : copy a = a.
Proof. apply eqI; ins; rewrite ?unsafe_getE; auto using length_copy, gcopy. Qed.
Create a copy of the array, but with double the size (if possible)
Lemma double_helper x :
0 <? x ->
true = (x <? v30) ->
0 <? 2 * x.
Proof.
ins; apply Z.ltb_lt; apply Z.ltb_lt in H;
symmetry in H0; apply Z.ltb_lt in H0.
rewrite spec_mul; change (phi 0) with 0%Z in *.
change (2 ^ Z.of_nat size)%Z with (2 * phi v30)%Z.
rewrite Zmult_mod_distr_l, Zmod_small; omega.
Qed.
Definition double A (a : t A) : t A :=
let n := 2 * length a in
match length a <? v30 as x with
| true => fun pf =>
unsafe_init n (double_helper (length_pos a) pf) (fun i PF => get a i)
| false => fun _ => copy a
end eq_refl.
Lemma length_double A (a : t A) :
length (double a) = if length a <? v30 then 2 * length a else length a.
Proof.
unfold double; des_eqrefl;
[rewrite <- EQ at 1 | rewrite <- EQ]; apply length_unsafe_init.
Qed.
Lemma gdouble A (a : t A) x :
get (double a) x = get a x.
Proof.
unfold double; des_eqrefl; auto using gcopy.
unfold get; do 2 des_eqrefl; simpls; try rewrite uginit;
unfold get; des_eqrefl; try (f_equal; apply proof_irrelevance);
try solve [exfalso; rewrite length_unsafe_init, ?length_pos in *; congruence].
exfalso; rewrite length_unsafe_init in *.
symmetry in EQ; apply Z.ltb_lt in EQ.
symmetry in EQ0; apply Z.ltb_ge in EQ0.
symmetry in EQ1; apply Z.ltb_lt in EQ1.
symmetry in EQ2; apply Z.ltb_lt in EQ2.
revert EQ0; rewrite spec_mul; change (phi 0) with 0%Z in *.
change (2 ^ Z.of_nat size)%Z with (2 * phi v30)%Z.
rewrite Zmult_mod_distr_l, Zmod_small; intros; omega.
Qed.
Extraction
Extract Constant t "'a" => "'a Perarray.t".
Extract Inlined Constant create => "Perarray.create".
Extract Inlined Constant init => "Perarray.init".
Extract Inlined Constant length => "Perarray.length".
Extract Inlined Constant unsafe_get => "Perarray.get".
Extract Inlined Constant unsafe_set => "Perarray.set".