Library prosa.classic.util.sorting
Require Import prosa.classic.util.tactics prosa.classic.util.induction prosa.classic.util.list.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop path.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop path.
Section Sorting.
Section SortedImplLeIdx.
Variable T: eqType.
Variable leT: rel T.
Notation "x ≺ y" := (leT x y) (at level 30).
Let sorted xs := sorted leT xs.
Variable xs: seq T.
Variable default: T.
Let nth := nth default.
Notation "xs [| n |]" := (nth xs n) (at level 10).
Lemma sort_ordered:
∀ (idx: nat),
sorted xs →
idx < (size xs).-1 →
xs[|idx|] ≺ xs[|idx.+1|].
Proof.
intros idx SORT LT.
induction xs; first by rewrite /= ltn0 in LT.
simpl in SORT, LT; move: SORT ⇒ /pathP SORT.
by simpl; apply SORT.
Qed.
Lemma sorted_rcons_prefix:
∀ x,
sorted (rcons xs x) →
sorted xs.
Proof.
intros x SORT; destruct xs; simpl; first by ins.
rewrite rcons_cons /= rcons_path in SORT.
by move: SORT ⇒ /andP [PATH _].
Qed.
Hypothesis H_leT_is_transitive: transitive leT.
Lemma order_sorted_rcons:
∀ (x lst: T),
sorted (rcons xs lst) →
x \in xs →
x ≺ lst.
Proof.
intros x last SORT IN.
induction xs as [ | a xs']; [ | clear xs; rename xs' into xs]; first by rewrite in_nil in IN.
simpl in SORT; move: IN; rewrite in_cons; move ⇒ /orP IN.
destruct IN as [HEAD | TAIL];
last by apply IHxs'; [by apply path_sorted in SORT| by ins].
move: HEAD ⇒ /eqP HEAD; subst a.
apply order_path_min in SORT; last by ins.
move: SORT ⇒ /allP SORT.
by apply SORT; rewrite mem_rcons in_cons; apply/orP; left.
Qed.
Lemma sorted_lt_idx_implies_rel:
∀ i1 i2,
sorted xs →
i1 < i2 →
i2 < size xs →
xs[|i1|] ≺ xs [|i2|].
Proof.
intros i1 i2 SORT LE LEsize.
generalize dependent i2; rewrite leq_as_delta.
intros delta LT.
destruct xs as [ | a xs']; [ | clear xs; rename xs' into xs]; first by rewrite ltn0 in LT.
simpl in SORT.
induction delta;
first by rewrite /= addn0 ltnS in LT; rewrite /= -addnE addn0; apply/pathP.
{
rewrite /transitive (H_leT_is_transitive (nth (a :: xs) (i1.+1 + delta))) //;
first by apply IHdelta, leq_ltn_trans with (n := i1.+1 + delta.+1); [rewrite leq_add2l| ].
rewrite -[delta.+1]addn1 addnA addn1.
move: SORT ⇒ /pathP SORT; apply SORT.
by rewrite /= -[delta.+1]addn1 addnA addn1 ltnS in LT.
}
Qed.
Lemma sorted_rel_implies_le_idx:
∀ i1 i2,
uniq xs →
antisymmetric_over_list leT xs →
sorted xs →
xs[|i1|] ≺ xs[|i2|] →
i1 < size xs →
i2 < size xs →
i1 ≤ i2.
Proof.
intros i1 i2 UNIQ ANTI SORT REL SIZE1 SIZE2.
generalize dependent i2.
induction i1; first by done.
{
intros i2 REL SIZE2.
feed IHi1; first by apply ltn_trans with (n := i1.+1).
apply leq_trans with (n := i1.+1); first by done.
rewrite ltn_neqAle; apply/andP; split.
{
apply/eqP; red; intro BUG; subst.
assert (REL': leT (nth xs i2) (nth xs i2.+1)).
by apply sorted_lt_idx_implies_rel; rewrite // ltnSn.
rewrite /antisymmetric_over_list in ANTI.
exploit (ANTI (nth xs i2) (nth xs i2.+1)); rewrite ?mem_nth //.
move ⇒ /eqP EQ; rewrite nth_uniq in EQ; try (by done).
by rewrite -[_ == _]negbK in EQ; move: EQ ⇒ /negP EQ; apply EQ; apply/eqP.
}
{
apply IHi1; last by done.
rewrite /transitive (H_leT_is_transitive (nth xs i1.+1)) //.
by apply sorted_lt_idx_implies_rel; try (by done); apply ltnSn.
}
}
Qed.
End SortedImplLeIdx.
Lemma prev_le_next:
∀ {T: Type} (F: T → nat) (xs: seq T) (def: T) (i k: nat),
(∀ i, i < (size xs).-1 → F (nth def xs i) ≤ F (nth def xs i.+1)) →
(i + k ≤ (size xs).-1) →
F (nth def xs i) ≤ F (nth def xs (i+k)).
Proof.
intros T F r x i k ALL SIZE.
generalize dependent i. generalize dependent k.
induction k; intros; first by rewrite addn0 leqnn.
specialize (IHk i.+1); exploit IHk; [by rewrite addSnnS | intro LE].
apply leq_trans with (n := F (nth x r (i.+1)));
last by rewrite -addSnnS.
apply ALL, leq_trans with (n := i + k.+1); last by ins.
by rewrite addnS ltnS leq_addr.
Qed.
End Sorting.
Section SortedImplLeIdx.
Variable T: eqType.
Variable leT: rel T.
Notation "x ≺ y" := (leT x y) (at level 30).
Let sorted xs := sorted leT xs.
Variable xs: seq T.
Variable default: T.
Let nth := nth default.
Notation "xs [| n |]" := (nth xs n) (at level 10).
Lemma sort_ordered:
∀ (idx: nat),
sorted xs →
idx < (size xs).-1 →
xs[|idx|] ≺ xs[|idx.+1|].
Proof.
intros idx SORT LT.
induction xs; first by rewrite /= ltn0 in LT.
simpl in SORT, LT; move: SORT ⇒ /pathP SORT.
by simpl; apply SORT.
Qed.
Lemma sorted_rcons_prefix:
∀ x,
sorted (rcons xs x) →
sorted xs.
Proof.
intros x SORT; destruct xs; simpl; first by ins.
rewrite rcons_cons /= rcons_path in SORT.
by move: SORT ⇒ /andP [PATH _].
Qed.
Hypothesis H_leT_is_transitive: transitive leT.
Lemma order_sorted_rcons:
∀ (x lst: T),
sorted (rcons xs lst) →
x \in xs →
x ≺ lst.
Proof.
intros x last SORT IN.
induction xs as [ | a xs']; [ | clear xs; rename xs' into xs]; first by rewrite in_nil in IN.
simpl in SORT; move: IN; rewrite in_cons; move ⇒ /orP IN.
destruct IN as [HEAD | TAIL];
last by apply IHxs'; [by apply path_sorted in SORT| by ins].
move: HEAD ⇒ /eqP HEAD; subst a.
apply order_path_min in SORT; last by ins.
move: SORT ⇒ /allP SORT.
by apply SORT; rewrite mem_rcons in_cons; apply/orP; left.
Qed.
Lemma sorted_lt_idx_implies_rel:
∀ i1 i2,
sorted xs →
i1 < i2 →
i2 < size xs →
xs[|i1|] ≺ xs [|i2|].
Proof.
intros i1 i2 SORT LE LEsize.
generalize dependent i2; rewrite leq_as_delta.
intros delta LT.
destruct xs as [ | a xs']; [ | clear xs; rename xs' into xs]; first by rewrite ltn0 in LT.
simpl in SORT.
induction delta;
first by rewrite /= addn0 ltnS in LT; rewrite /= -addnE addn0; apply/pathP.
{
rewrite /transitive (H_leT_is_transitive (nth (a :: xs) (i1.+1 + delta))) //;
first by apply IHdelta, leq_ltn_trans with (n := i1.+1 + delta.+1); [rewrite leq_add2l| ].
rewrite -[delta.+1]addn1 addnA addn1.
move: SORT ⇒ /pathP SORT; apply SORT.
by rewrite /= -[delta.+1]addn1 addnA addn1 ltnS in LT.
}
Qed.
Lemma sorted_rel_implies_le_idx:
∀ i1 i2,
uniq xs →
antisymmetric_over_list leT xs →
sorted xs →
xs[|i1|] ≺ xs[|i2|] →
i1 < size xs →
i2 < size xs →
i1 ≤ i2.
Proof.
intros i1 i2 UNIQ ANTI SORT REL SIZE1 SIZE2.
generalize dependent i2.
induction i1; first by done.
{
intros i2 REL SIZE2.
feed IHi1; first by apply ltn_trans with (n := i1.+1).
apply leq_trans with (n := i1.+1); first by done.
rewrite ltn_neqAle; apply/andP; split.
{
apply/eqP; red; intro BUG; subst.
assert (REL': leT (nth xs i2) (nth xs i2.+1)).
by apply sorted_lt_idx_implies_rel; rewrite // ltnSn.
rewrite /antisymmetric_over_list in ANTI.
exploit (ANTI (nth xs i2) (nth xs i2.+1)); rewrite ?mem_nth //.
move ⇒ /eqP EQ; rewrite nth_uniq in EQ; try (by done).
by rewrite -[_ == _]negbK in EQ; move: EQ ⇒ /negP EQ; apply EQ; apply/eqP.
}
{
apply IHi1; last by done.
rewrite /transitive (H_leT_is_transitive (nth xs i1.+1)) //.
by apply sorted_lt_idx_implies_rel; try (by done); apply ltnSn.
}
}
Qed.
End SortedImplLeIdx.
Lemma prev_le_next:
∀ {T: Type} (F: T → nat) (xs: seq T) (def: T) (i k: nat),
(∀ i, i < (size xs).-1 → F (nth def xs i) ≤ F (nth def xs i.+1)) →
(i + k ≤ (size xs).-1) →
F (nth def xs i) ≤ F (nth def xs (i+k)).
Proof.
intros T F r x i k ALL SIZE.
generalize dependent i. generalize dependent k.
induction k; intros; first by rewrite addn0 leqnn.
specialize (IHk i.+1); exploit IHk; [by rewrite addSnnS | intro LE].
apply leq_trans with (n := F (nth x r (i.+1)));
last by rewrite -addSnnS.
apply ALL, leq_trans with (n := i + k.+1); last by ins.
by rewrite addnS ltnS leq_addr.
Qed.
End Sorting.