Library prosa.util.nondecreasing

From mathcomp Require Import ssreflect ssrbool ssrfun eqtype ssrnat seq fintype bigop.
Require Export prosa.util.epsilon.
Require Export prosa.util.nat.
Require Export prosa.util.list.

Non-Decreasing Sequence and Distances

In this file we introduce the notion of a non-decreasing sequence.
First, let's introduce the notion of the nth element of a sequence.
  Notation "xs [| n |]" := (nth 0 xs n) (at level 30).

We say that a sequence xs is non-decreasing iff for any two indices n1 and n2 such that n1 ≤ n2 < size [xs] condition [xs][n1] ≤ [xs][n2] holds.
  Definition nondecreasing_sequence (xs : seq nat) :=
    ∀ n1 n2,
      n1 ≤ n2 < size xs →
      xs[|n1|] ≤ xs[|n2|].

Similarly, we define an increasing sequence.
  Definition increasing_sequence (xs : seq nat) :=
    ∀ n1 n2,
      n1 < n2 < size xs →
      xs[|n1|] < xs[|n2|].

For a non-decreasing sequence we define the notion of distances between neighboring elements of the sequence. Example: Consider the following sequence of natural numbers: xs = :: 1; 10; 10; 17; 20; 41. Then drop 1 xs is equal to :: 10; 10; 17; 20; 41. Then zip xs (drop 1 xs) is equal to :: (1,10); (10,10); (10,17); (17,20); (20,41) And after the mapping map (fun '(x1, x2) ⇒ x2 - x1) we end up with :: 9; 0; 7; 3; 21.
  Definition distances (xs : seq nat) :=
    map (fun '(x1, x2) ⇒ x2 - x1) (zip xs (drop 1 xs)).

Properties of Increasing Sequence

In this section we prove a few lemmas about increasing sequences.
Note that a filtered iota sequence is an increasing sequence.
  Lemma iota_is_increasing_sequence :
    ∀ a b P,
      increasing_sequence [seq x <- index_iota a b | P x].

We prove that any increasing sequence is also a non-decreasing sequence.
  Lemma increasing_implies_nondecreasing :
    ∀ xs,
      increasing_sequence xs →
      nondecreasing_sequence xs.

Properties of Non-Decreasing Sequence

In this section we prove a few lemmas about non-decreasing sequences.
First we prove that if 0 ∈ xs, then 0 is the first element of xs.
  Lemma nondec_seq_zero_first :
    ∀ xs,
      (0 \in xs) →
      nondecreasing_sequence xs →
      first0 xs = 0.

If x1::x2::xs is a non-decreasing sequence, then either x1 = x2 or x1 < x2.
  Lemma nondecreasing_sequence_2cons_leVeq :
    ∀ x1 x2 xs,
      nondecreasing_sequence (x1 :: x2 :: xs) →
      x1 = x2 ∨ x1 < x2.

We prove that if x::xs is a non-decreasing sequence, then xs also is a non-decreasing sequence.
  Lemma nondecreasing_sequence_cons :
    ∀ x xs,
      nondecreasing_sequence (x :: xs) →
      nondecreasing_sequence xs.

Let xs be a non-decreasing sequence, then for x s.t. ∀ y ∈ xs, x ≤ y x::xs is a non-decreasing sequence.
  Lemma nondecreasing_sequence_add_min :
    ∀ x xs,
      (∀ y, y \in xs → x ≤ y) →
      nondecreasing_sequence xs →
      nondecreasing_sequence (x :: xs).

We prove that if x::xs is a non-decreasing sequence, then x::x::xs also is a non-decreasing sequence.
  Lemma nondecreasing_sequence_cons_double :
    ∀ x xs,
      nondecreasing_sequence (x :: xs) →
      nondecreasing_sequence (x :: x :: xs).

We prove that if x::xs is a non-decreasing sequence, then x is a minimal element of xs.
  Lemma nondecreasing_sequence_cons_min :
    ∀ x xs,
      nondecreasing_sequence (x :: xs) →
      (∀ y, y \in xs → x ≤ y).

We also prove a similar lemma for strict minimum.
  Corollary nondecreasing_sequence_cons_smin :
    ∀ x1 x2 xs,
      x1 < x2 →
      nondecreasing_sequence (x1 :: x2 :: xs) →
      (∀ y, y \in x2 :: xs → x1 < y).

Next, we prove that no element can lie strictly between two neighboring elements and still belong to the list.
  Lemma antidensity_of_nondecreasing_seq :
    ∀ (xs : seq nat) (x : nat) (n : nat),
      nondecreasing_sequence xs →
      xs[|n|] < x < xs[|n.+1|] →
      ~~ (x \in xs).

Alternatively, consider an arbitrary natural number x that is bounded by the first and the last element of a sequence xs. Then there is an index n such that xs[n] ≤ x < x[n+1].
  Lemma belonging_to_segment_of_seq_is_total :
    ∀ (xs : seq nat) (x : nat),
      2 ≤ size xs →
      first0 xs ≤ x < last0 xs →
      ∃ n,
        n.+1 < size xs
        ∧ xs[|n|] ≤ x < xs[|n.+1|].

Note that the last element of a non-decreasing sequence is the max element.
  Lemma last_is_max_in_nondecreasing_seq :
    ∀ (xs : seq nat) (x : nat),
      nondecreasing_sequence xs →
      (x \in xs) →
      x ≤ last0 xs.

Properties of Undup of Non-Decreasing Sequence

In this section we prove a few lemmas about undup of non-decreasing sequences.
First we prove that undup x::x::xs is equal to undup x::xs.
  Remark nodup_sort_2cons_eq :
    ∀ {X : eqType} (x : X) (xs : seq X),
      undup (x::x::xs) = undup (x::xs).

For non-decreasing sequences we show that the fact that x1 < x2 implies that undup x1::x2::xs = x1::undup x2::xs.
  Lemma nodup_sort_2cons_lt :
    ∀ x1 x2 xs,
      x1 < x2 →
      nondecreasing_sequence (x1::x2::xs) →
      undup (x1::x2::xs) = x1 :: undup (x2::xs).

Next we show that function undup doesn't change the last element of a sequence.
  Lemma last0_undup :
    ∀ xs,
      nondecreasing_sequence xs →
      last0 (undup xs) = last0 xs.

Non-decreasing sequence remains non-decreasing after application of undup.
  Lemma nondecreasing_sequence_undup :
    ∀ xs,
      nondecreasing_sequence xs →
      nondecreasing_sequence (undup xs).

We also show that the penultimate element of a sequence undup xs is bounded by the penultimate element of sequence xs.
  Lemma undup_nth_le :
    ∀ xs,
      nondecreasing_sequence xs →
      undup xs [| (size (undup xs)).-2 |] ≤ xs [| (size xs).-2 |].
    Opaque undup.

Properties of Distances

In this section we prove a few lemmas about function distances.
We begin with a simple lemma that helps us unfold distances of lists with two consecutive cons x0::x1::xs.
  Lemma distances_unfold_2cons :
    ∀ x0 x1 xs,
      distances (x0::x1::xs) = (x1 - x0) :: distances (x1::xs).

Similarly, we prove a lemma stating that two consecutive appends to a sequence in distances function (distances(xs ++ [:: a; b])) can be rewritten as distances(xs ++ [:: a]) ++ [:: b - a].
  Lemma distances_unfold_2app_last :
    ∀ (a b : nat) (xs : seq nat),
      distances (xs ++ [:: a; b])
      = distances (xs ++ [:: a]) ++ [:: b - a].

We also prove a lemma stating that one append to a sequence in the distances function (i.e., distances(xs ++ [:: x])) can be rewritten as distances xs ++ [:: x - last0 xs].
  Lemma distances_unfold_1app_last :
    ∀ x xs,
      size xs ≥ 1 →
      distances (xs ++ [:: x]) = distances xs ++ [:: x - last0 xs].

We prove that the difference between any two neighboring elements is bounded by the max element of the distances-sequence.
Note that the distances-function has the expected behavior indeed. I.e. an element on the position n of the distance-sequence is equal to the difference between elements on positions n+1 and n.
  Lemma function_of_distances_is_correct :
    ∀ (xs : seq nat) (n : nat),
      (distances xs)[|n|] = xs[|n.+1|] - xs[|n|].

We show that the size of a distances-sequence is one less than the size of the original sequence.
  Lemma size_of_seq_of_distances :
    ∀ (xs : seq nat),
      2 ≤ size xs →
      size xs = size (distances xs) + 1.

We prove that index_iota 0 n produces a sequence of numbers which are always one unit apart from each other.
  Lemma distances_of_iota_ε :
    ∀ n x, x \in distances (index_iota 0 n) → x = ε.

Properties of Distances of Non-Decreasing Sequence

In this section, we prove a few basic lemmas about distances of non-decreasing sequences.
First we show that the max distance between elements of any nontrivial sequence (i.e., a sequence that contains at least two distinct elements) is positive.
  Lemma max_distance_in_nontrivial_seq_is_positive :
    ∀ (xs : seq nat),
      nondecreasing_sequence xs →
      (∃ x y, x \in xs ∧ y \in xs ∧ x ≠ y) →
      0 < max0 (distances xs).

Given a non-decreasing sequence xs with length n, we show that the difference between the last element of xs and the last element of the distances-sequence of xs is equal to xs[n-2].
  Lemma last_seq_minus_last_distance_seq :
    ∀ (xs : seq nat),
      nondecreasing_sequence xs →
      last0 xs - last0 (distances xs) = xs [| (size xs).-2 |].

The max element of the distances-sequence of a sequence xs is bounded by the last element of xs. Since all elements of xs are non-negative, they all lie within the interval 0, last xs.
  Lemma max_distance_in_seq_le_last_element_of_seq :
    ∀ (xs : seq nat),
      nondecreasing_sequence xs →
      max0 (distances xs) ≤ last0 xs.

Let xs be a non-decreasing sequence. We prove that distances of sequence [seq ρ <- index_iota 0 k.+1 | ρ \in xs] coincide with sequence [seq x <- distances xs | 0 < x]].
  Lemma distances_iota_filtered :
    ∀ xs k,
      (∀ x, x \in xs → x ≤ k) →
      nondecreasing_sequence xs →
      distances [seq ρ <- index_iota 0 k.+1 | ρ \in xs] = [seq x <- distances xs | 0 < x].

Let xs again be a non-decreasing sequence. We prove that distances of sequence undup xs coincide with sequence of positive distances of xs.
  Lemma distances_positive_undup :
    ∀ xs,
      nondecreasing_sequence xs →
      [seq d <- distances xs | 0 < d] = distances (undup xs).

Consider two non-decreasing sequences xs and ys and assume that (1) first element of xs is at most the first element of ys and (2) distances-sequences of xs is dominated by distances-sequence of ys. Then xs is dominated by ys.
  Lemma domination_of_distances_implies_domination_of_seq :
    ∀ (xs ys : seq nat),
      first0 xs ≤ first0 ys →
      2 ≤ size xs →
      2 ≤ size ys →
      size xs = size ys →
      nondecreasing_sequence xs →
      nondecreasing_sequence ys →
      (∀ n, (distances xs)[|n|] ≤ (distances ys)[|n|]) →
      (∀ n, xs[|n|] ≤ ys[|n|]).

End NondecreasingSequence.