Skip to content
Snippets Groups Projects
Commit 199c984b authored by Robbert Krebbers's avatar Robbert Krebbers
Browse files

Merge branch 'msammler/rotate' into 'master'

Rotate everything

See merge request iris/stdpp!136
parents fb90d2d8 a613b693
No related branches found
No related tags found
No related merge requests found
......@@ -3,6 +3,9 @@ API-breaking change is listed.
## std++ master
- Added `rotate` and `rotate_take` functions for accessing a list with
wrap-around. Also added `rotate_nat_add` and `rotate_nat_sub` for
computing indicies into a rotated list.
- Added the `select` and `revert select` tactics for selecting and
reverting a hypothesis based on a pattern.
- Extracted `list_numbers.v` from `list.v` and `numbers.v` for
......
......@@ -143,6 +143,20 @@ Fixpoint replicate {A} (n : nat) (x : A) : list A :=
match n with 0 => [] | S n => x :: replicate n x end.
Instance: Params (@replicate) 2 := {}.
(** The function [rotate n l] rotates the list [l] by [n], e.g., [rotate 1
[x0; x1; ...; xm]] becomes [x1; ...; xm; x0]. Rotating by a multiple of
[length l] is the identity function. **)
Definition rotate {A} (n : nat) (l : list A) : list A :=
drop (Z.to_nat (n `mod` length l)%Z) l ++ take (Z.to_nat (n `mod` length l)%Z) l.
Instance: Params (@rotate) 2 := {}.
(** The function [rotate_take s e l] returns the range between the
indices [s] (inclusive) and [e] (exclusive) of [l]. If [e ≤ s], all
elements after [s] and before [e] are returned. *)
Definition rotate_take {A} (s e : nat) (l : list A) : list A :=
take (rotate_nat_sub s e (length l)) (rotate s l).
Instance: Params (@rotate_take) 3 := {}.
(** The function [reverse l] returns the elements of [l] in reverse order. *)
Definition reverse {A} (l : list A) : list A := rev_append l [].
Instance: Params (@reverse) 1 := {}.
......@@ -1354,6 +1368,97 @@ Lemma lookup_total_resize_old `{!Inhabited A} l n x i :
n i resize n x l !!! i = inhabitant.
Proof. intros. by rewrite !list_lookup_total_alt, lookup_resize_old. Qed.
(** ** Properties of the [rotate] function *)
Lemma rotate_replicate n1 n2 x:
rotate n1 (replicate n2 x) = replicate n2 x.
Proof.
unfold rotate. rewrite drop_replicate, take_replicate, <-replicate_plus.
f_equal. lia.
Qed.
Lemma rotate_length l n:
length (rotate n l) = length l.
Proof. unfold rotate. rewrite app_length, drop_length, take_length. lia. Qed.
Lemma lookup_rotate_r l n i:
i < length l
rotate n l !! i = l !! rotate_nat_add n i (length l).
Proof.
intros Hlen. destruct (Z_mod_lt n (length l)) as [??];[lia|].
assert (Z.to_nat (n `mod` length l) < length l) as Hr.
{ apply Nat2Z.inj_lt. rewrite Z2Nat.id; lia. }
unfold rotate. rewrite rotate_nat_add_add_mod, rotate_nat_add_alt by done.
remember (Z.to_nat (n `mod` length l)) as n'.
case_decide.
- by rewrite lookup_app_l, lookup_drop by (rewrite drop_length; lia).
- rewrite lookup_app_r, lookup_take, drop_length by (rewrite drop_length; lia).
f_equal. lia.
Qed.
Lemma lookup_rotate_r_Some l n i x:
rotate n l !! i = Some x
l !! rotate_nat_add n i (length l) = Some x i < length l.
Proof.
split.
- intros Hl. pose proof (lookup_lt_Some _ _ _ Hl) as Hlen.
rewrite rotate_length in Hlen. by rewrite <-lookup_rotate_r.
- intros [??]. by rewrite lookup_rotate_r.
Qed.
Lemma lookup_rotate_l l n i:
i < length l rotate n l !! rotate_nat_sub n i (length l) = l !! i.
Proof.
intros ?. rewrite lookup_rotate_r, rotate_nat_add_sub;[done..|].
apply rotate_nat_sub_lt. lia.
Qed.
Lemma elem_of_rotate l n x:
x rotate n l x l.
Proof.
unfold rotate. rewrite <-(take_drop (Z.to_nat (n `mod` length l)) l) at 5.
rewrite !elem_of_app. naive_solver.
Qed.
Lemma rotate_insert_l l n i x:
i < length l
rotate n (<[rotate_nat_add n i (length l):=x]> l) = <[i:=x]> (rotate n l).
Proof.
intros Hlen. destruct (Z_mod_lt n (length l)) as [Hn1 Hn2];[lia|].
assert (Z.to_nat (n `mod` length l) < length l) as Hr.
{ apply Nat2Z.inj_lt. rewrite Z2Nat.id; lia. } unfold rotate.
rewrite insert_length, rotate_nat_add_add_mod, rotate_nat_add_alt by done.
remember (Z.to_nat (n `mod` length l)) as n'.
case_decide.
- rewrite take_insert, drop_insert_le, insert_app_l
by (rewrite ?drop_length; lia). do 2 f_equal. lia.
- rewrite take_insert_lt, drop_insert_gt, insert_app_r_alt, drop_length
by (rewrite ?drop_length; lia). do 2 f_equal. lia.
Qed.
Lemma rotate_insert_r l n i x:
i < length l
rotate n (<[i:=x]> l) = <[rotate_nat_sub n i (length l):=x]> (rotate n l).
Proof.
intros ?. rewrite <-rotate_insert_l, rotate_nat_add_sub;[done..|].
apply rotate_nat_sub_lt. lia.
Qed.
(** ** Properties of the [rotate_take] function *)
Lemma rotate_take_insert l s e i x:
i < length l
rotate_take s e (<[i:=x]>l) =
if decide (rotate_nat_sub s i (length l) < rotate_nat_sub s e (length l)) then
<[rotate_nat_sub s i (length l):=x]> (rotate_take s e l) else rotate_take s e l.
Proof.
intros ?. unfold rotate_take. rewrite rotate_insert_r, insert_length by done.
case_decide; [rewrite take_insert_lt | rewrite take_insert]; naive_solver lia.
Qed.
Lemma rotate_take_add l b i :
i < length l
rotate_take b (rotate_nat_add b i (length l)) l = take i (rotate b l).
Proof. intros ?. unfold rotate_take. by rewrite rotate_nat_sub_add. Qed.
(** ** Properties of the [reshape] function *)
Lemma reshape_length szs l : length (reshape szs l) = length szs.
Proof. revert l. by induction szs; intros; f_equal/=. Qed.
......@@ -2793,6 +2898,19 @@ Section Forall2.
P x y Forall2 P (replicate n x) (replicate n y).
Proof. induction n; simpl; constructor; auto. Qed.
Lemma Forall2_rotate n l k :
Forall2 P l k Forall2 P (rotate n l) (rotate n k).
Proof.
intros HAll. unfold rotate. rewrite (Forall2_length _ _ HAll).
eauto using Forall2_app, Forall2_take, Forall2_drop.
Qed.
Lemma Forall2_rotate_take s e l k :
Forall2 P l k Forall2 P (rotate_take s e l) (rotate_take s e k).
Proof.
intros HAll. unfold rotate_take. rewrite (Forall2_length _ _ HAll).
eauto using Forall2_take, Forall2_rotate.
Qed.
Lemma Forall2_reverse l k : Forall2 P l k Forall2 P (reverse l) (reverse k).
Proof.
induction 1; rewrite ?reverse_nil, ?reverse_cons; eauto using Forall2_app.
......@@ -2943,6 +3061,10 @@ Section Forall2_proper.
Global Instance: Proper (R ==> Forall2 R) (replicate n).
Proof. repeat intro. eauto using Forall2_replicate. Qed.
Global Instance: Proper (Forall2 R ==> Forall2 R) (rotate n).
Proof. repeat intro. eauto using Forall2_rotate. Qed.
Global Instance: Proper (Forall2 R ==> Forall2 R) (rotate_take s e).
Proof. repeat intro. eauto using Forall2_rotate_take. Qed.
Global Instance: Proper (Forall2 R ==> Forall2 R) reverse.
Proof. repeat intro. eauto using Forall2_reverse. Qed.
Global Instance: Proper (Forall2 R ==> option_Forall2 R) last.
......@@ -3101,6 +3223,10 @@ Section setoid.
Proof. intros ???. rewrite !equiv_Forall2. by apply Forall2_filter. Qed.
Global Instance replicate_proper n : Proper ((≡@{A}) ==> ()) (replicate n).
Proof. induction n; constructor; auto. Qed.
Global Instance rotate_proper n : Proper ((≡@{list A}) ==> ()) (rotate n).
Proof. intros ??. rewrite !equiv_Forall2. by apply Forall2_rotate. Qed.
Global Instance rotate_take_proper s e : Proper ((≡@{list A}) ==> ()) (rotate_take s e).
Proof. intros ??. rewrite !equiv_Forall2. by apply Forall2_rotate_take. Qed.
Global Instance reverse_proper : Proper (() ==> (≡@{list A})) reverse.
Proof.
induction 1; rewrite ?reverse_cons; simpl; [constructor|].
......
......@@ -452,6 +452,22 @@ Proof.
apply Nat.mod_bound_pos; lia. }
by rewrite <-Nat2Z.inj_mul, <-Nat2Z.inj_add, <-Nat.div_mod.
Qed.
Lemma Nat2Z_inj_div x y :
0 x 0 y
Z.to_nat (x `div` y) = (Z.to_nat x `div` Z.to_nat y)%nat.
Proof.
intros. destruct (decide (y = 0%nat)); [by subst; destruct x|].
pose proof (Z.div_pos x y).
apply (inj Z.of_nat). by rewrite Z2Nat_inj_div, !Z2Nat.id by lia.
Qed.
Lemma Nat2Z_inj_mod x y :
0 x 0 y
Z.to_nat (x `mod` y) = (Z.to_nat x `mod` Z.to_nat y)%nat.
Proof.
intros. destruct (decide (y = 0%nat)); [by subst; destruct x|].
pose proof (Z_mod_pos x y).
apply (inj Z.of_nat). by rewrite Z2Nat_inj_mod, !Z2Nat.id by lia.
Qed.
Lemma Z_succ_pred_induction y (P : Z Prop) :
P y
( x, y x P x P (Z.succ x))
......@@ -808,3 +824,122 @@ Qed.
Lemma Qp_ge_0 (q: Qp): (0 q)%Qc.
Proof. apply Qclt_le_weak, Qp_prf. Qed.
(** * Helper for working with accessing lists with wrap-around
See also [rotate] and [rotate_take] in [list.v] *)
(** [rotate_nat_add base offset len] computes [(base + offset) `mod`
len]. This is useful in combination with the [rotate] function on
lists, since the index [i] of [rotate n l] corresponds to the index
[rotate_nat_add n i (length i)] of the original list. The definition
uses [Z] for consistency with [rotate_nat_sub]. **)
Definition rotate_nat_add (base offset len : nat) : nat :=
Z.to_nat ((base + offset) `mod` len)%Z.
(** [rotate_nat_sub base offset len] is the inverse of [rotate_nat_add
base offset len]. The definition needs to use modulo on [Z] instead of
on nat since otherwise we need the sidecondition [base < len] on
[rotate_nat_sub_add]. **)
Definition rotate_nat_sub (base offset len : nat) : nat :=
Z.to_nat ((len + offset - base) `mod` len)%Z.
Lemma rotate_nat_add_len_0 base offset:
rotate_nat_add base offset 0 = 0.
Proof. unfold rotate_nat_add. by rewrite Zmod_0_r. Qed.
Lemma rotate_nat_sub_len_0 base offset:
rotate_nat_sub base offset 0 = 0.
Proof. unfold rotate_nat_sub. by rewrite Zmod_0_r. Qed.
Lemma rotate_nat_add_add_mod base offset len:
rotate_nat_add base offset len =
rotate_nat_add (Z.to_nat (base `mod` len)%Z) offset len.
Proof.
destruct len as [|i];[ by rewrite !rotate_nat_add_len_0|].
pose proof (Z_mod_lt base (S i)) as Hlt. unfold rotate_nat_add.
rewrite !Z2Nat.id by lia. by rewrite Zplus_mod_idemp_l.
Qed.
Lemma rotate_nat_add_alt base offset len:
base < len offset < len
rotate_nat_add base offset len =
if decide (base + offset < len) then base + offset else base + offset - len.
Proof.
unfold rotate_nat_add. intros ??. case_decide.
- rewrite Z.mod_small by lia. by rewrite <-Nat2Z.inj_add, Nat2Z.id.
- rewrite (Zmod_in_range 1) by lia.
by rewrite Z.mul_1_l, <-Nat2Z.inj_add, <-Nat2Z.inj_sub,Nat2Z.id by lia.
Qed.
Lemma rotate_nat_sub_alt base offset len:
base < len offset < len
rotate_nat_sub base offset len =
if decide (offset < base) then len + offset - base else offset - base.
Proof.
unfold rotate_nat_sub. intros ??. case_decide.
- rewrite Z.mod_small by lia.
by rewrite <-Nat2Z.inj_add, <-Nat2Z.inj_sub, Nat2Z.id by lia.
- rewrite (Zmod_in_range 1) by lia.
rewrite Z.mul_1_l, <-Nat2Z.inj_add, <-!Nat2Z.inj_sub,Nat2Z.id; lia.
Qed.
Lemma rotate_nat_add_0 base len :
base < len rotate_nat_add base 0 len = base.
Proof.
intros ?. unfold rotate_nat_add.
rewrite Z.mod_small by lia. by rewrite Z.add_0_r, Nat2Z.id.
Qed.
Lemma rotate_nat_sub_0 base len :
base < len rotate_nat_sub base base len = 0.
Proof. intros ?. rewrite rotate_nat_sub_alt by done. case_decide; lia. Qed.
Lemma rotate_nat_add_lt base offset len :
0 < len rotate_nat_add base offset len < len.
Proof.
unfold rotate_nat_add. intros ?.
pose proof (Nat.mod_upper_bound (base + offset) len).
rewrite Nat2Z_inj_mod, Z2Nat.inj_add, !Nat2Z.id; lia.
Qed.
Lemma rotate_nat_sub_lt base offset len :
0 < len rotate_nat_sub base offset len < len.
Proof.
unfold rotate_nat_sub. intros ?.
pose proof (Z_mod_lt (len + offset - base) len).
apply Nat2Z.inj_lt. rewrite Z2Nat.id; lia.
Qed.
Lemma rotate_nat_add_sub base len offset:
offset < len
rotate_nat_add base (rotate_nat_sub base offset len) len = offset.
Proof.
intros ?. unfold rotate_nat_add, rotate_nat_sub.
rewrite Z2Nat.id by (apply Z_mod_pos; lia). rewrite Zplus_mod_idemp_r.
replace (base + (len + offset - base))%Z with (len + offset)%Z by lia.
rewrite (Zmod_in_range 1) by lia.
rewrite Z.mul_1_l, <-Nat2Z.inj_add, <-!Nat2Z.inj_sub,Nat2Z.id; lia.
Qed.
Lemma rotate_nat_sub_add base len offset:
offset < len
rotate_nat_sub base (rotate_nat_add base offset len) len = offset.
Proof.
intros ?. unfold rotate_nat_add, rotate_nat_sub.
rewrite Z2Nat.id by (apply Z_mod_pos; lia).
assert ( n, (len + n - base) = ((len - base) + n))%Z as -> by naive_solver lia.
rewrite Zplus_mod_idemp_r.
replace (len - base + (base + offset))%Z with (len + offset)%Z by lia.
rewrite (Zmod_in_range 1) by lia.
rewrite Z.mul_1_l, <-Nat2Z.inj_add, <-!Nat2Z.inj_sub,Nat2Z.id; lia.
Qed.
Lemma rotate_nat_add_add base offset len n:
0 < len
rotate_nat_add base (offset + n) len =
(rotate_nat_add base offset len + n) `mod` len.
Proof.
intros ?. unfold rotate_nat_add.
rewrite !Nat2Z_inj_mod, !Z2Nat.inj_add, !Nat2Z.id by lia.
by rewrite plus_assoc, Nat.add_mod_idemp_l by lia.
Qed.
Lemma rotate_nat_add_S base offset len:
0 < len
rotate_nat_add base (S offset) len =
S (rotate_nat_add base offset len) `mod` len.
Proof. intros ?. by rewrite <-Nat.add_1_r, rotate_nat_add_add, Nat.add_1_r. Qed.
......@@ -300,6 +300,10 @@ Section set_unfold_list.
constructor. rewrite elem_of_list_fmap. f_equiv; intros y.
by rewrite (set_unfold_elem_of y l (P y)).
Qed.
Global Instance set_unfold_rotate x l P n:
SetUnfoldElemOf x l P SetUnfoldElemOf x (rotate n l) P.
Proof. constructor. by rewrite elem_of_rotate, (set_unfold_elem_of x l P). Qed.
End set_unfold_list.
Tactic Notation "set_unfold" :=
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment