Search code examples
coq

Lexicographical comparison of tuples of nats


I'm working with tuples of nats (specifically triples, nat*nat*nat) and would like a way to lexicographically compare tuples. Something equivalent to this:

Inductive lt3 : nat*nat*nat -> nat*nat*nat -> Prop :=
| lt3_1 : forall n1 n2 n3 m1 m2 m3, n1 < m1 -> lt3 (n1,n2,n3) (m1,m2,m3)
| lt3_2 : forall n1 n2 n3    m2 m3, n2 < m2 -> lt3 (n1,n2,n3) (n1,m2,m3)
| lt3_3 : forall n1 n2 n3       m3, n3 < m3 -> lt3 (n1,n2,n3) (n1,n2,m3).

I would like to have proofs of basic properties such as transitivity and well-foundedness. Are there things in the standard library that do most of the work? If not, I'm most interested in well-foundedness. How would I go about proving it?


Solution

  • The standard library has its own definition of lexicographic product, along with a proof of well-foundedness. The problem with that definition, however, is that it is stated for dependent pairs:

    lexprod : forall (A : Type) (B : A -> Type), relation {x : A & B x}
    

    If you want, you can instantiate B with a constant type family of the form fun _ => B', because the types A * B' and {x : A & B'} are isomorphic. But if you want to work directly with the Coq type of regular pairs, you can simply replicate the proofs for a more restricted version of the lexicographic product. The proof is not very complicated, but it requires a nested induction on the accessibility predicate that defines well-foundedness.

    Require Import
      Coq.Relations.Relation_Definitions
      Coq.Relations.Relation_Operators.
    
    Set Implicit Arguments.
    Unset Strict Implicit.
    Unset Printing Implicit Defensive.
    
    Section Lexicographic.
    
    Variables (A B : Type) (leA : relation A) (leB : relation B).
    
    Inductive lexprod : A * B -> A * B -> Prop :=
    | left_lex  : forall x x' y y', leA x x' -> lexprod (x, y) (x', y')
    | right_lex : forall x y y',    leB y y' -> lexprod (x, y) (x, y').
    
    Theorem wf_trans :
      transitive _ leA ->
      transitive _ leB ->
      transitive _ lexprod.
    Proof.
    intros tA tB [x1 y1] [x2 y2] [x3 y3] H.
    inversion H; subst; clear H.
    - intros H.
      inversion H; subst; clear H; apply left_lex; now eauto.
    - intros H.
      inversion H; subst; clear H.
      + now apply left_lex.
      + now apply right_lex; eauto.
    Qed.
    
    Theorem wf_lexprod :
      well_founded leA ->
      well_founded leB ->
      well_founded lexprod.
    Proof.
    intros wfA wfB [x].
    induction (wfA x) as [x _ IHx]; clear wfA.
    intros y.
    induction (wfB y) as [y _ IHy]; clear wfB.
    constructor.
    intros [x' y'] H.
    now inversion H; subst; clear H; eauto.
    Qed.
    
    End Lexicographic.
    

    You can then instantiate this general version to recover, for instance, your definition of the lexicographic product for triples of natural numbers:

    Require Import Coq.Arith.Wf_nat.
    
    Definition myrel : relation (nat * nat * nat) :=
      lexprod (lexprod lt lt) lt.
    
    Lemma wf_myrel : well_founded myrel.
    Proof. repeat apply wf_lexprod; apply lt_wf. Qed.