Utils

This module gathers auxiliary definitions and constructions of general utility across the RingLike development. It is meant to centralize reusable elements shared by multiple modules.

From Stdlib Require Import Utf8 Arith.
Import List.ListNotations.

Require Import Misc.

Iterators for aggregation operations

The functions iter_list and iter_seq define generic iteration schemes over lists and integer intervals, respectively. They are designed to support readable notations such as:
  • (i l), f i : list-based summation
  • (i = b, e), f i : summation over integer ranges
These iterators also apply to other aggregation operations: products (∏), maxima (Max), conjunctions (⋀).
The Rocq system renders iter_list and iter_seq symbolically (∑, ∏, Max, ⋀) according to their use context.
There are also various theorems for manipulating these iterators.
These definitions and theorems are used in the following modules:

Definition iter_list {A B} (l : list B) f (d : A) := List.fold_left f l d.

Definition iter_seq {T} b e f (d : T) := iter_list (List.seq b (S e - b)) f d.

Arguments iter_seq : simpl never.
Arguments iter_list : simpl never.

Theorem fold_iter_list : {A B} (f : A B A) l d,
  List.fold_left f l d = iter_list l f d.

Theorem fold_iter_seq' : A b len f (d : A),
  iter_list (List.seq b len) f d =
    if b + len =? 0 then d
    else iter_seq b (b + len - 1) f d.

Theorem fold_left_op_fun_from_d : {T A} d op a l (f : A _)
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  List.fold_left (λ (c : T) i, op c (f i)) l a =
  op a (List.fold_left (λ (c : T) i, op c (f i)) l d).

Theorem iter_list_op_fun_from_d : T A d op a l (f : A _)
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  iter_list l (λ (c : T) (i : A), op c (f i)) a =
  op a (iter_list l (λ (c : T) (i : A), op c (f i)) d).

Theorem iter_list_all_d : T A d op (l : list A) f
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  ( i, i l f i = d)
   iter_list l (λ (c : T) i, op c (f i)) d = d.

Theorem iter_seq_all_d : T d op b e f
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  ( i : nat, b i e f i = d)
   iter_seq b e (λ (c : T) (i : nat), op c (f i)) d = d.

Theorem iter_list_split_first : T A d op l z f
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  l []
   iter_list l (λ (c : T) (i : A), op c (f i)) d =
    op (f (List.hd z l))
      (iter_list (List.tl l) (λ (c : T) (i : A), op c (f i)) d).

Theorem iter_list_split_last : T A d (op : T T T) l (g : A T) z,
  l []
   iter_list l (λ c i, op c (g i)) d =
    op (iter_list (List.removelast l) (λ c i, op c (g i)) d)
      (g (List.last l z)).

Theorem iter_seq_split_first : T d op b k g
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  b k
   iter_seq b k (λ (c : T) (i : nat), op c (g i)) d =
    op (g b) (iter_seq (S b) k (λ (c : T) (i : nat), op c (g i)) d).
Theorem iter_seq_split_last : T d (op : T T T) b k g,
  b k
   iter_seq b k (λ (c : T) (i : nat), op c (g i)) d =
    op (iter_seq (S b) k (λ (c : T) (i : nat), op c (g (i - 1)%nat)) d) (g k).

Theorem iter_seq_split : T d op j g b k
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
   b S j S k
   iter_seq b k (λ (c : T) (i : nat), op c (g i)) d =
    op (iter_seq b j (λ (c : T) (i : nat), op c (g i)) d)
      (iter_seq (j + 1) k (λ (c : T) (i : nat), op c (g i)) d).

Theorem iter_seq_split3 : T d op j g b k
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  b j k
   iter_seq b k (λ (c : T) (i : nat), op c (g i)) d =
    op (op (iter_seq (S b) j (λ (c : T) (i : nat), op c (g (i - 1))) d) (g j))
      (iter_seq (j + 1) k (λ (c : T) (i : nat), op c (g i)) d).

Theorem iter_list_eq_compat : A B d (op : A A A) (l : list B) g h,
  ( i, i l g i = h i)
   iter_list l (λ c i, op c (g i)) d =
    iter_list l (λ c i, op c (h i)) d.

Theorem iter_seq_eq_compat : T d (op : T T T) b k g h,
  ( i, b i k g i = h i)
   iter_seq b k (λ c i, op c (g i)) d =
    iter_seq b k (λ c i, op c (h i)) d.

Theorem iter_seq_succ_succ : {T} (d : T) b k f,
  iter_seq (S b) (S k) f d =
  iter_seq b k (λ c i, f c (S i)) d.

Theorem iter_seq_succ_succ' : {T} (d : T) b k f,
  iter_seq (S b) (S k) (λ c i, f c (i - 1)) d =
  iter_seq b k (λ c i, f c i) d.

Theorem iter_list_empty : T A d (op : T T T) (l : list A) g,
  l = []
   iter_list l (λ c i, op c (g i)) d = d.

Theorem iter_seq_empty : T d (op : T T T) b k g,
  k < b
   iter_seq b k (λ (c : T) (i : nat), op c (g i)) d = d.

Theorem iter_list_distr : T A d op g h (l : list A)
  (op_d_l : x, op d x = x)
  (op_comm : a b, op a b = op b a)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  iter_list l (λ (c : T) (i : A), op c (op (g i) (h i))) d =
  op (iter_list l (λ (c : T) (i : A), op c (g i)) d)
    (iter_list l (λ (c : T) (i : A), op c (h i)) d).

Theorem iter_seq_distr : T d op g h b k
  (op_d_l : x, op d x = x)
  (op_comm : a b, op a b = op b a)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  iter_seq b k (λ (c : T) (i : nat), (op c (op (g i) (h i)))) d =
  op
    (iter_seq b k (λ (c : T) (i : nat), op c (g i)) d)
    (iter_seq b k (λ (c : T) (i : nat), op c (h i)) d).

Theorem iter_list_inv : T A d op inv (f : A T) l
  (inv_op_distr : a b, inv (op a b) = op (inv a) (inv b)),
  inv (iter_list l (λ (c : T) i, op c (f i)) d) =
  iter_list l (λ (c : T) i, op c (inv (f i))) (inv d).

Theorem iter_shift : {T} s b k f (d : T),
  s b k
   iter_seq b k f d =
    iter_seq (b - s) (k - s) (λ c i, f c (s + i)) d.

Theorem iter_rshift : {T} s b k f (d : T),
  iter_seq b k f d =
  iter_seq (s + b) (s + k) (λ c i, f c (i - s)) d.

Theorem iter_seq_inv : T d op inv b e f
  (inv_op_distr : a b, inv (op a b) = op (inv a) (inv b)),
  inv (iter_seq b e (λ (c : T) (i : nat), op c (f i)) d) =
  iter_seq b e (λ (c : T) (i : nat), op c (inv (f i))) (inv d).

Theorem iter_seq_rtl : T d op b k f
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_comm : a b, op a b = op b a)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  iter_seq b k (λ (c : T) (i : nat), op c (f i)) d =
  iter_seq b k (λ (c : T) (i : nat), op c (f (k + b - i))) d.

Theorem iter_list_only_one : T A d (op : T T T) (g : A T) a,
  op d (g a) = g a
   iter_list [a] (λ c i, op c (g i)) d = g a.

Theorem iter_seq_only_one : T d (op : T T T) g n,
  op d (g n) = g n
   iter_seq n n (λ c i, op c (g i)) d = g n.

Theorem iter_list_cons : A B d op (a : B) la f
  (op_d_l : x, op d x = x)
  (op_d_r : x, op x d = x)
  (op_assoc : a b c, op a (op b c) = op (op a b) c),
  iter_list (a :: la) (λ (c : A) i, op c (f i)) d =
  op (f a) (iter_list la (λ (c : A) i, op c (f i)) d).

Theorem iter_list_app : A B (d : A) (f : A B A) la lb,
  iter_list (la ++ lb) f d = iter_list lb f (iter_list la f d).

Theorem iter_list_seq : T d (op : T T T) b len f,
  len 0
   iter_list (List.seq b len) (λ c i, op c (f i)) d =
    iter_seq b (b + len - 1) (λ c i, op c (f i)) d.

Theorem List_flat_length_map : A B (f : A list B) l,
  length (List.flat_map f l) = iter_list l (fun c ac + length (f a)) 0.

List_cart_prod

Generalization of the standard List.list_prod to an arbitrary number of lists (not just two). It computes the Cartesian product of a list of lists.
For example:
      List.list_prod [1; 2] [3; 4; 5] =
        [(1,3); (1,4); (1,5); (2,3); (2,4); (2,5)]

      List_cart_prod [[1; 2]; [3; 4; 5]] =
        [[1;3]; [1;4]; [1;5]; [2;3]; [2;4]; [2;5]]
Instead of producing pairs (a, b), this function produces lists a; b. The number of input lists can be zero, one, two, or more.
  • List_cart_prod [] returns []
  • List_cart_prod [[1; 2]; [3; 4]] returns all pairs as 2-lists
  • List_cart_prod [[a1; a2]; [b1]; [c1; c2]] returns 4 3-lists: a1; b1; c1, a1; b1; c2, a2; b1; c1, a2; b1; c2

Fixpoint List_cart_prod {A} (ll : list (list A)) :=
  match ll with
  | [][[]]
| l :: ll'List.flat_map (λ a, List.map (cons a) (List_cart_prod ll')) l
  end.

Theorem List_cart_prod_length : A (ll : list (list A)),
  ll []
   length (List_cart_prod ll) = iter_list ll (fun c lc × length l) 1.

Theorem List_in_cart_prod_length : A (ll : list (list A)) l,
  l List_cart_prod ll length l = length ll.

Theorem List_in_nth_cart_prod : A (d : A) ll l i,
  i < length ll
   l List_cart_prod ll
   List.nth i l d List.nth i ll [].

Theorem List_in_cart_prod_iff : {A} (d : A) ll la,
  la List_cart_prod ll
   length la = length ll
     i, i < length la List.nth i la d List.nth i ll [].

List_extract

An enhanced version of List.find that returns an optional triple:
  • the list segment before the match
  • the matching element
  • the segment after the match
Fixpoint List_extract {A} (f : A bool) l :=
  match l with
  | []None
  | a :: la
      if f a then Some ([], a, la)
      else
        match List_extract f la with
        | NoneNone
        | Some (bef, b, aft)Some (a :: bef, b, aft)
        end
  end.

Theorem List_extract_Some_iff : A (f : A _) l a bef aft,
  List_extract f l = Some (bef, a, aft)
   ( x, x bef f x = false) f a = true l = bef ++ a :: aft.
Theorem List_extract_None_iff : {A} (f : A _) l,
  List_extract f l = None a, a l f a = false.

List_rank

Returns the index (rank) of the first element satisfying a predicate. Similar to List.find, but returns the position instead of the value, or length of the list if not found.
Fixpoint List_rank_loop i [A] (f : A bool) (l : list A) : nat :=
  match l with
  | []i
  | x :: tlif f x then i else List_rank_loop (S i) f tl
end.

Definition List_rank [A] := @List_rank_loop 0 A.

Theorem List_rank_loop_interv : {A} f (l : list A) i,
  i List_rank_loop i f l i + length l.

Theorem List_rank_loop_if : A d f (l : list A) i j,
  List_rank_loop i f l = j
   ( k, i k < j f (List.nth (k - i) l d) = false)
    (j < i + length l f (List.nth (j - i) l d) = true
     j = i + length l).

Theorem List_rank_if : {A} d f (l : list A) {i},
  List_rank f l = i
   ( j, j < i f (List.nth j l d) = false)
    (i < length l f (List.nth i l d) = true i = length l).

List_map2

List_map2 f la lb maps f over corresponding elements of la and lb. Stops at the shortest of the two lists.

Fixpoint List_map2 {A B C} (f : A B C) la lb :=
  match la with
  | [][]
  | a :: la'
      match lb with
      | [][]
      | b :: lb'f a b :: List_map2 f la' lb'
      end
  end.

Theorem List_map2_nil_l : A B C (f : A B C) la, List_map2 f [] la = [].

Theorem List_map2_nil_r : A B C (f : A B C) la, List_map2 f la [] = [].

Theorem List_map2_nth : {A B C} a b c (f : A B C) la lb n,
  n < length la
   n < length lb
   List.nth n (List_map2 f la lb) c = f (List.nth n la a) (List.nth n lb b).

Theorem List_map2_map_l :
   A B C D (f : C B D) g (la : list A) (lb : list B),
  List_map2 f (List.map g la) lb = List_map2 (λ a b, f (g a) b) la lb.

Theorem List_map2_map_r :
   A B C D (f : A C D) g (la : list A) (lb : list B),
  List_map2 f la (List.map g lb) = List_map2 (λ a b, f a (g b)) la lb.

Theorem List_map_map2 : A B C D (f : A B) (g : C D A) la lb,
  List.map f (List_map2 g la lb) = List_map2 (λ a b, f (g a b)) la lb.

Theorem List_fold_left_map2 :
   A B C D (f : A B A) (g : C D B) lc ld (a : A),
  List.fold_left f (List_map2 g lc ld) a =
  List.fold_left (λ b c, f b (g (fst c) (snd c))) (List.combine lc ld) a.

Theorem List_length_map2 : A B C (f : A B C) la lb,
  length (List_map2 f la lb) = min (length la) (length lb).

Theorem List_in_map2_iff : A B C (f : A B C) la lb c,
  c List_map2 f la lb
   i,
  i < min (length la) (length lb)
   a b, f (List.nth i la a) (List.nth i lb b) = c.
Theorem List_map2_ext_in : A B C (f g : A B C) la lb,
  ( ab, ab List.combine la lb f (fst ab) (snd ab) = g (fst ab) (snd ab))
   List_map2 f la lb = List_map2 g la lb.

Theorem List_map2_diag : A B (f : A A B) la,
  List_map2 f la la = List.map (λ i, f i i) la.

Theorem List_map2_map2_seq_l : {A B C} d (f : A B C) la lb,
  List_map2 f la lb =
    List_map2 (λ i b, f (List.nth i la d) b) (List.seq 0 (length la)) lb.

Theorem List_map2_map2_seq_r : {A B C} d (f : A B C) la lb,
  List_map2 f la lb =
    List_map2 (λ a i, f a (List.nth i lb d)) la (List.seq 0 (length lb)).

Theorem List_map2_app_l : A B C l1 l2 l (f : A B C),
  List_map2 f (l1 ++ l2) l =
    List_map2 f l1 (List.firstn (length l1) l) ++
    List_map2 f l2 (List.skipn (length l1) l).

Theorem List_map2_swap : A B C (f : A B C) la lb,
  List_map2 f la lb = List_map2 (λ a b, f b a) lb la.

Theorem List_map2_rev_seq_r : A B (f : A _ B) la sta len,
  List_map2 f la (List.rev (List.seq sta len)) =
  List_map2 (λ a i, f a (2 × sta + len - 1 - i)) la (List.seq sta len).

Theorem List_map2_map_min :
   {A B C} ad bd la lb (f : A B C),
  List_map2 f la lb =
    List.map (λ i, f (List.nth i la ad) (List.nth i lb bd))
      (List.seq 0 (min (length la) (length lb))).

Theorem List_map2_app_app :
   A B C la lb lc ld (f : A B C),
  length la = length lb
   List_map2 f (la ++ lc) (lb ++ ld) =
    List_map2 f la lb ++ List_map2 f lc ld.

Theorem List_rev_map2 : A B C (f : A B C) la lb,
  length la = length lb
   List.rev (List_map2 f la lb) = List_map2 f (List.rev la) (List.rev lb).

Theorem List_eq_map2_nil : A B C (f : A B C) la lb,
  List_map2 f la lb = [] la = [] lb = [].

binomial

binomial n k returns the binomial coefficient "n choose k", i.e., the number of k-element subsets of an n-element set.

Fixpoint binomial n k :=
  match k with
  | 0 ⇒ 1
  | S k'
      match n with
      | 0 ⇒ 0
      | S n'binomial n' k' + binomial n' k
     end
  end.

Theorem binomial_succ_succ : n k,
  binomial (S n) (S k) = binomial n k + binomial n (S k).

Theorem binomial_lt : n k, n < k binomial n k = 0.

Theorem binomial_succ_diag_r : n, binomial n (S n) = 0.

This page has been generated by coqdoc