LAProof.C.distinct
Require Import VST.floyd.functional_base.
Require Import Coq.Relations.Relations.
Require Import Coq.Classes.RelationClasses.
Import ListNotations.
Inductive sorted {A} (le: relation A): list A → Prop :=
| sorted_nil:
sorted le nil
| sorted_1: ∀ x,
sorted le (x::nil)
| sorted_cons: ∀ x y l,
le x y → sorted le (y::l) → sorted le (x::y::l).
Lemma sorted_e: ∀ {A} `{d: Inhabitant A} {le: A → A → Prop}
{TR: Transitive le}
(al: list A),
sorted le al → ∀ i j, 0 ≤ i < j → j < Zlength al →
(le (Znth i al) (Znth j al)).
Lemma sorted_i: ∀ {A} `{d: Inhabitant A} (le: A → A → Prop) {TR: Transitive le}
(al: list A),
(∀ i j, 0 ≤ i < j → j < Zlength al → le (Znth i al) (Znth j al)) →
sorted le al.
Lemma le1_sorted: ∀ {A} {le: A → A → Prop}
{TR: Transitive le}
(a b: A) (al: list A),
(le a b) → sorted le (b::al) → sorted le (a::al).
Lemma sorted_app:
∀ {A} {le: A→A→Prop} {TRANS: Transitive le}
pivot al bl,
sorted le al → sorted le bl →
Forall (fun x ⇒ le x pivot) al →
Forall (le pivot) bl →
sorted le (al++bl).
Lemma sorted_app_e3:
∀ {A} {le: relation A} {TRANS: Transitive le}
pivot al bl,
sorted le (al++[pivot]++bl) →
sorted le al ∧ sorted le bl ∧
Forall (fun x ⇒ le x pivot) al ∧
Forall (le pivot) bl.
Lemma sorted_e1: ∀ {t} {Inh: Inhabitant t} {le: relation t} (al: list t), sorted le al →
∀ i,
0 ≤ i < Zlength al-1 → le (Znth i al) (Znth (i+1) al).
Lemma sorted_sublist:
∀ (i j: Z) {A} {InhA: Inhabitant A} le (al: list A),
0 ≤ i ≤ j → j ≤ Zlength al → sorted le al → sorted le (sublist i j al).
Class BoolOrder {A: Type} (R: relation A): Type := {
test : A → A → bool;
test_spec: ∀ x y, reflect (R x y) (test x y)
}.
Arguments test {A} R {BoolOrder}.
Module BPO.
Local Lemma mkteststrictspec {A} {R: relation A} {B: BoolOrder R}{P: PreOrder R}:
let strict x y := R x y ∧ ¬R y x in
let teststrict x y := andb (test R x y) (negb (test R y x)) in
∀ x y : A, reflect (strict x y) (teststrict x y).
Local Lemma StrictOrderstrict {A}{R: relation A}{P: PreOrder R}:
let strict x y := R x y ∧ ¬ R y x in
StrictOrder strict.
Local Lemma mktesteqvspec {A} {R: relation A}{BO: BoolOrder R}:
let eqv x y := R x y ∧ R y x in
let testeqv x y := andb (test R x y) (test R y x) in
∀ x y : A, reflect (eqv x y) (testeqv x y).
Local Lemma mkEqv {A}{R: relation A}{PO: PreOrder R}:
let eqv x y := R x y ∧ R y x in
Equivalence eqv.
Class BoolPreOrder {A: Type} (R: relation A) : Type := {
#[export] BO :: BoolOrder R ;
#[export] PO :: PreOrder R ;
lt : relation A := fun x y ⇒ R x y ∧ ¬R y x;
ltb: A → A → bool := fun x y ⇒ andb (test R x y) (negb (test R y x));
ltb_spec: ∀ x y, reflect (lt x y) (ltb x y) :=
mkteststrictspec;
#[export] Strict :: StrictOrder lt := StrictOrderstrict;
eqv: relation A := fun x y ⇒ R x y ∧ R y x;
eqvb: A → A → bool := fun x y ⇒ andb (test R x y) (test R y x);
eqvbspec: ∀ x y, reflect (eqv x y) (eqvb x y) :=
mktesteqvspec;
Eqv :: Equivalence eqv := mkEqv
}.
Arguments lt [A] [R] {_}.
Arguments ltb [A] [R] {_}.
Arguments eqv [A] [R] {_}.
Arguments eqvb [A] [R] {_}.
End BPO.
Import BPO.
Section SBO.
Context {A: Type} {le: relation A} {SBO: BoolPreOrder le}.
Context {InhA: Inhabitant A}.
Definition count_distinct_aux u v :=
let '(k,x) := u in (if ltb x v then k+1 else k, v).
Definition count_distinct (al: list A) : Z :=
match al with
| nil ⇒ 0
| a::rest ⇒ fst (fold_left count_distinct_aux rest (1,a))
end.
Lemma count_distinct_bound: ∀ el: list A,
0 ≤ count_distinct el ≤ Zlength el.
Lemma count_distinct_bound': ∀ el,
0 < Zlength el →
0 < @count_distinct el.
Lemma count_distinct_mono:
∀ (bl: list A) i,
count_distinct (sublist 0 i bl) ≤ count_distinct bl.
Lemma count_distinct_incr:
∀ (bl: list A) i,
lt (Znth (i-1) bl) (Znth i bl) →
0 < i < Zlength bl →
count_distinct (sublist 0 i bl) + 1 = count_distinct (sublist 0 (i+1) bl).
Lemma count_distinct_incr':
∀ (bl: list A) i,
lt (Znth (i - 1) bl) (Znth i bl) →
0 ≤ i - 1 < Zlength bl - 1 →
count_distinct (sublist 0 i bl) < count_distinct bl.
Lemma count_distinct_noincr:
∀ (al: list A) i,
0 < i < Zlength al →
¬lt (Znth (i-1) al) (Znth i al) →
count_distinct (sublist 0 i al) = count_distinct (sublist 0 (i+1) al).
Lemma count_distinct_aux_mono:
∀ al y u,
fst (fold_left count_distinct_aux al (u, y)) ≥ u.
Lemma eqv_cda: ∀ a x u al,
eqv x a →
fst (fold_left count_distinct_aux al (u, x)) =
fst (fold_left count_distinct_aux al (u, a)).
Lemma count_distinct_aux_lemma:
∀ al y (SOR: sorted le (y::al)) u,
fst (fold_left count_distinct_aux al (u, y)) ≤ u →
Forall (Basics.compose not (lt y)) al.
Lemma count_distinct_1:
∀ al
(SOR: sorted le al),
count_distinct al = 1 →
∀ x y, In x al → In y al → eqv x y.
Lemma count_distinct_range_same:
∀ al g h,
sorted le al → 0 ≤ g < h-1 → h ≤ Zlength al →
BPO.eqv (Znth g al) (Znth (h-1) al) ↔
count_distinct (sublist 0 (g+1) al) = count_distinct (sublist 0 h al).
End SBO.
Require Import Coq.Relations.Relations.
Require Import Coq.Classes.RelationClasses.
Import ListNotations.
Inductive sorted {A} (le: relation A): list A → Prop :=
| sorted_nil:
sorted le nil
| sorted_1: ∀ x,
sorted le (x::nil)
| sorted_cons: ∀ x y l,
le x y → sorted le (y::l) → sorted le (x::y::l).
Lemma sorted_e: ∀ {A} `{d: Inhabitant A} {le: A → A → Prop}
{TR: Transitive le}
(al: list A),
sorted le al → ∀ i j, 0 ≤ i < j → j < Zlength al →
(le (Znth i al) (Znth j al)).
Lemma sorted_i: ∀ {A} `{d: Inhabitant A} (le: A → A → Prop) {TR: Transitive le}
(al: list A),
(∀ i j, 0 ≤ i < j → j < Zlength al → le (Znth i al) (Znth j al)) →
sorted le al.
Lemma le1_sorted: ∀ {A} {le: A → A → Prop}
{TR: Transitive le}
(a b: A) (al: list A),
(le a b) → sorted le (b::al) → sorted le (a::al).
Lemma sorted_app:
∀ {A} {le: A→A→Prop} {TRANS: Transitive le}
pivot al bl,
sorted le al → sorted le bl →
Forall (fun x ⇒ le x pivot) al →
Forall (le pivot) bl →
sorted le (al++bl).
Lemma sorted_app_e3:
∀ {A} {le: relation A} {TRANS: Transitive le}
pivot al bl,
sorted le (al++[pivot]++bl) →
sorted le al ∧ sorted le bl ∧
Forall (fun x ⇒ le x pivot) al ∧
Forall (le pivot) bl.
Lemma sorted_e1: ∀ {t} {Inh: Inhabitant t} {le: relation t} (al: list t), sorted le al →
∀ i,
0 ≤ i < Zlength al-1 → le (Znth i al) (Znth (i+1) al).
Lemma sorted_sublist:
∀ (i j: Z) {A} {InhA: Inhabitant A} le (al: list A),
0 ≤ i ≤ j → j ≤ Zlength al → sorted le al → sorted le (sublist i j al).
Class BoolOrder {A: Type} (R: relation A): Type := {
test : A → A → bool;
test_spec: ∀ x y, reflect (R x y) (test x y)
}.
Arguments test {A} R {BoolOrder}.
Module BPO.
Local Lemma mkteststrictspec {A} {R: relation A} {B: BoolOrder R}{P: PreOrder R}:
let strict x y := R x y ∧ ¬R y x in
let teststrict x y := andb (test R x y) (negb (test R y x)) in
∀ x y : A, reflect (strict x y) (teststrict x y).
Local Lemma StrictOrderstrict {A}{R: relation A}{P: PreOrder R}:
let strict x y := R x y ∧ ¬ R y x in
StrictOrder strict.
Local Lemma mktesteqvspec {A} {R: relation A}{BO: BoolOrder R}:
let eqv x y := R x y ∧ R y x in
let testeqv x y := andb (test R x y) (test R y x) in
∀ x y : A, reflect (eqv x y) (testeqv x y).
Local Lemma mkEqv {A}{R: relation A}{PO: PreOrder R}:
let eqv x y := R x y ∧ R y x in
Equivalence eqv.
Class BoolPreOrder {A: Type} (R: relation A) : Type := {
#[export] BO :: BoolOrder R ;
#[export] PO :: PreOrder R ;
lt : relation A := fun x y ⇒ R x y ∧ ¬R y x;
ltb: A → A → bool := fun x y ⇒ andb (test R x y) (negb (test R y x));
ltb_spec: ∀ x y, reflect (lt x y) (ltb x y) :=
mkteststrictspec;
#[export] Strict :: StrictOrder lt := StrictOrderstrict;
eqv: relation A := fun x y ⇒ R x y ∧ R y x;
eqvb: A → A → bool := fun x y ⇒ andb (test R x y) (test R y x);
eqvbspec: ∀ x y, reflect (eqv x y) (eqvb x y) :=
mktesteqvspec;
Eqv :: Equivalence eqv := mkEqv
}.
Arguments lt [A] [R] {_}.
Arguments ltb [A] [R] {_}.
Arguments eqv [A] [R] {_}.
Arguments eqvb [A] [R] {_}.
End BPO.
Import BPO.
Section SBO.
Context {A: Type} {le: relation A} {SBO: BoolPreOrder le}.
Context {InhA: Inhabitant A}.
Definition count_distinct_aux u v :=
let '(k,x) := u in (if ltb x v then k+1 else k, v).
Definition count_distinct (al: list A) : Z :=
match al with
| nil ⇒ 0
| a::rest ⇒ fst (fold_left count_distinct_aux rest (1,a))
end.
Lemma count_distinct_bound: ∀ el: list A,
0 ≤ count_distinct el ≤ Zlength el.
Lemma count_distinct_bound': ∀ el,
0 < Zlength el →
0 < @count_distinct el.
Lemma count_distinct_mono:
∀ (bl: list A) i,
count_distinct (sublist 0 i bl) ≤ count_distinct bl.
Lemma count_distinct_incr:
∀ (bl: list A) i,
lt (Znth (i-1) bl) (Znth i bl) →
0 < i < Zlength bl →
count_distinct (sublist 0 i bl) + 1 = count_distinct (sublist 0 (i+1) bl).
Lemma count_distinct_incr':
∀ (bl: list A) i,
lt (Znth (i - 1) bl) (Znth i bl) →
0 ≤ i - 1 < Zlength bl - 1 →
count_distinct (sublist 0 i bl) < count_distinct bl.
Lemma count_distinct_noincr:
∀ (al: list A) i,
0 < i < Zlength al →
¬lt (Znth (i-1) al) (Znth i al) →
count_distinct (sublist 0 i al) = count_distinct (sublist 0 (i+1) al).
Lemma count_distinct_aux_mono:
∀ al y u,
fst (fold_left count_distinct_aux al (u, y)) ≥ u.
Lemma eqv_cda: ∀ a x u al,
eqv x a →
fst (fold_left count_distinct_aux al (u, x)) =
fst (fold_left count_distinct_aux al (u, a)).
Lemma count_distinct_aux_lemma:
∀ al y (SOR: sorted le (y::al)) u,
fst (fold_left count_distinct_aux al (u, y)) ≤ u →
Forall (Basics.compose not (lt y)) al.
Lemma count_distinct_1:
∀ al
(SOR: sorted le al),
count_distinct al = 1 →
∀ x y, In x al → In y al → eqv x y.
Lemma count_distinct_range_same:
∀ al g h,
sorted le al → 0 ≤ g < h-1 → h ≤ Zlength al →
BPO.eqv (Znth g al) (Znth (h-1) al) ↔
count_distinct (sublist 0 (g+1) al) = count_distinct (sublist 0 h al).
End SBO.