Library ATBR.Numbers


This file describes an interface NUM for abstract numbers and a functor that gives properties about them. One specificity of this interface is that we require an implemantation of both FSet and FMap on our numbers.
This interface is then instanciated with positive, and we are able to use positive maps in our development.
In NUMUTILS we define a tactic num_omega (and its couterparts num_omega_false), that reflects equalities and inequalities from num into nat and then calls omega. This tactic is implemented with autorewrite libraires.
In NUMUTILS, we also define tactics num_analyse and num_prop which respectively performs case analysis on function calls, and reflection from boolean functions into the underlying relations. (See BoolView.v for more details)

Require Import Common.
Require Import BoolView.
Require Import MyFSets MyFSetProperties MyFMapProperties FSetPositive FMapPositive.

Set Implicit Arguments.

The NUM interface

Module Type NUM.

  Parameter num : Type.

  Parameter nat_of_num : num nat.
  Parameter num_of_nat : nat num.

  Parameter leb : num num bool.
  Parameter ltb : num num bool.
  Parameter eqb : num num bool.
  Parameter compare : num num comparison.

  Parameter le : num num Prop.
  Parameter lt : num num Prop.

  Parameter S : num num.
  Parameter max: num num num.

  Parameter fold_num : A, (num A A) num A A.
  Parameter fold_num_sum : E T, (num T T + E) num T (T + E).

  Parameter pi0: num num.
  Parameter pi1: num num.
  Parameter pimatch: num num + num.

  Declare Module NumOTA: OrderedTypeAlt with Definition t := num.
  Declare Module NumSet: FSetInterface.S with Definition E.t := num.
  Declare Module NumMap: FMapInterface.S with Definition E.t := num.

  Parameter code: NumSet.t num.

  Notation "0" := (num_of_nat O).
  Notation "n < m" := (lt n m) (at level 70).
  Notation "n <= m" := (le n m) (at level 70).

  Axiom id_num : n, num_of_nat (nat_of_num n) = n.
  Axiom id_nat : n, nat_of_num (num_of_nat n) = n.

  Axiom le_spec : n m, reflect (le n m) (leb n m).
  Axiom lt_spec : n m, reflect (lt n m) (ltb n m).
  Axiom eq_spec : n m, reflect (n = m) (eqb n m).
  Axiom compare_spec : n m, compare_spec eq lt n m (compare n m).

  Axiom S_nat_spec : n, nat_of_num (S n) = Datatypes.S (nat_of_num n).
  Axiom max_spec : n m, nat_of_num (max n m) = Max.max (nat_of_num n) (nat_of_num m).
  Axiom le_nat_spec : n m, n m (nat_of_num n nat_of_num m)%nat.
  Axiom lt_nat_spec : n m, n < m (nat_of_num n < nat_of_num m)%nat.

  Axiom set_eq_spec : x y, NumSet.E.eq x y x = y.
  Axiom map_eq_spec : x y, NumMap.E.eq x y x = y.

  Axiom fold_num_O: A (a: A) f, fold_num f 0 a = a.
  Axiom fold_num_S: A (a: A) f n, fold_num f (S n) a = fold_num f n (f n a).

  Axiom fold_num_sum_O: E T a f, @fold_num_sum E T f 0 a = inl a.
  Axiom fold_num_sum_S: E T a f n, @fold_num_sum E T f (S n) a =
    match f n a with
      | inl afold_num_sum f n a
      | ee
    end.

  Axiom match_pi0: n, pimatch (pi0 n) = inl n.
  Axiom match_pi1: n, pimatch (pi1 n) = inr n.
  Axiom lt_pi0: n m, n < m pi0 n < pi0 m.
  Axiom lt_pi1: n m, n < m pi1 n < pi1 m.

End NUM.

Notations, lemmas and tactics derivable from the NUM interface

Module NumUtils (N : NUM).
  Export N.
  Module NumSetProps := MySetProps NumSet.
  Module NumMapProps := MyMapProps NumMap.

  Notation "0" := (num_of_nat O) : num_scope.
  Notation "1" := (num_of_nat 1) : num_scope.
  Notation "2" := (num_of_nat 2) : num_scope.
  Notation "3" := (num_of_nat 3) : num_scope.
  Notation "5" := (num_of_nat 5) : num_scope.
  Notation "7" := (num_of_nat 7) : num_scope.

  Notation "n < m" := (lt n m) (at level 70) : num_scope.
  Notation "n <= m" := (le n m) (at level 70) : num_scope.

  Open Scope num_scope.
  Bind Scope num_scope with num.

  Instance le_preorder: PreOrder le.
  Proof.
    constructor.
    intros x; unfold Ple. rewrite le_nat_spec. auto with arith.
    intros x y z Hxy Hyz. rewrite le_nat_spec in ×. apply (le_trans _ (nat_of_num y)); auto.
  Qed.

  Instance lt_transitive: Transitive lt.
  Proof.
    intros x y z Hxy Hyz. rewrite lt_nat_spec in ×. apply (lt_trans _ (nat_of_num y)); auto.
  Qed.

  Lemma num_peano_rec :
     (P : num Type), P (num_of_nat O) ( p, P p P (S p)) p, P p.
  Proof.
    intros P H IH p.
    rewrite <- id_num.
    generalize (nat_of_num p) as n. clear p.
    intros.
    induction n.
    apply H.
    rewrite <- (id_nat n). rewrite <- S_nat_spec. rewrite id_num. apply IH. auto.
  Qed.

  Lemma eq_nat_spec : n m, n = m nat_of_num n = nat_of_num m.
  Proof.
    intuition subst. reflexivity.
    setoid_rewrite <- id_num. rewrite H. reflexivity.
  Qed.

  Coercion num_of_nat : nat >-> num.
  Coercion nat_of_num : num >-> nat.

  Lemma pi0_inj: i j, pi0 i = pi0 j i = j.
  Proof.
    intros. cut (@inl num num i = @inl num num j). intro H'. injection H'. auto.
    rewrite <- match_pi0, H. apply match_pi0.
  Qed.

  Lemma pi1_inj: i j, pi1 i = pi1 j i = j.
  Proof.
    intros. cut (@inr num num i = @inr num num j). intro H'. injection H'. auto.
    rewrite <- match_pi1, H. apply match_pi1.
  Qed.

  Instance fold_num_compat' {A} {R} `{E: Equivalence A R}:
  Proper (pointwise_relation num (R ==> R) ==> pointwise_relation num (R ==> R)) (@fold_num A).
  Proof.
    intros f g H n. induction n using num_peano_rec; intros a b H'; simpl.
    rewrite 2fold_num_O. assumption.
    rewrite 2fold_num_S. apply IHn, H, H'.
  Qed.

  Instance fold_num_compat T: Proper
    (pointwise_relation num (pointwise_relation T (@eq T))
      ==>
     pointwise_relation num (pointwise_relation T (@eq T))) (@fold_num T).
  Proof.
    intros f g H n. induction n using num_peano_rec; intro a; simpl.
     rewrite 2fold_num_O. reflexivity.
     rewrite 2fold_num_S. rewrite IHn. rewrite H. reflexivity.
  Qed.

num_analyse : destroys the boolean expressions


  Instance eqb_view : Type_View eqb := { type_view := eq_spec }.
  Instance leb_view : Type_View leb := { type_view := le_spec }.
  Instance ltb_view : Type_View ltb := { type_view := lt_spec }.

  Ltac num_analyse :=
    repeat first [ type_view eqb | type_view leb | type_view ltb ].

num_prop : transforms atoms like leb x y = true into le x y

  Lemma leb_true : x y, leb x y = true le x y.
  Proof. intros. case le_spec; intuition discriminate. Qed.
  Lemma leb_false : x y, leb x y = false lt y x.
  Proof.
    intros. rewrite eq_not_negb. rewrite leb_true.
    rewrite le_nat_spec, lt_nat_spec. omega.
  Qed.
  Lemma ltb_true : x y, ltb x y = true lt x y.
  Proof. intros. case lt_spec; intuition discriminate. Qed.
  Lemma ltb_false : x y, ltb x y = false le y x.
  Proof.
    intros. rewrite eq_not_negb. rewrite ltb_true.
    rewrite le_nat_spec, lt_nat_spec. omega.
  Qed.
  Lemma eqb_true : x y, eqb x y = true x = y.
  Proof. intros. case eq_spec; intuition discriminate. Qed.
  Lemma eqb_false : x y, eqb x y = false x y.
  Proof. intros. case eq_spec; intuition. Qed.

  Lemma eq_num_dec: (n m: num), {n=m} + {nm}.
  Proof.
    intros n m. case_eq (eqb n m); intro H.
     rewrite eqb_true in H. auto.
     rewrite eqb_false in H. auto.
  Qed.

  Hint Rewrite
    leb_true leb_false
    ltb_true ltb_false
    eqb_true eqb_false : num_prop.

  Ltac num_prop := autorewrite with num_prop in ×.

  Lemma eqb_refl: x, eqb x x = true.
  Proof. intro. num_prop. reflexivity. Qed.
  Lemma leb_refl: x, leb x x = true.
  Proof. intro. num_prop. reflexivity. Qed.
  Hint Rewrite eqb_refl leb_refl id_nat id_num: bool_simpl.

num_omega : injects every prop about nums into equivalent props about nats, then call omega

  Lemma num_of_nat_comm : x y, x = num_of_nat y nat_of_num x = y.
  Proof.
    intros x y. split; [intros → | intros <-].
    rewrite id_nat. reflexivity.
    rewrite id_num. reflexivity.
  Qed.

  Lemma nat_of_num_comm : x y, num_of_nat y = x y = nat_of_num x .
  Proof.
    intros x y. split; [intros <- | intros ->].
    rewrite id_nat. reflexivity.
    rewrite id_num. reflexivity.
  Qed.

  Hint Rewrite eq_nat_spec le_nat_spec lt_nat_spec S_nat_spec max_spec : num_omega.
  Hint Rewrite nat_of_num_comm num_of_nat_comm : num_omega .
  Hint Rewrite id_nat id_num : num_omega.

  Ltac num_simpl := autorewrite with num_omega in ×.
  Ltac num_omega := num_simpl; intuition (subst; omega).
  Ltac num_omega_false := exfalso; num_omega.

  Lemma eqb_eq_nat_bool: i j,
    eqb i j = eq_nat_bool (nat_of_num i) (nat_of_num j).
  Proof.
    intros. num_analyse. subst. bool_simpl. reflexivity.
    symmetry. nat_prop. num_omega.
  Qed.

  Lemma numseteqb_eq_nat_bool: i j,
    NumSetProps.eqb i j = eq_nat_bool (nat_of_num i) (nat_of_num j).
  Proof.
    intros. rewrite <- eqb_eq_nat_bool. unfold NumSetProps.eqb. destruct (NumSetProps.P.Dec.F.eq_dec i j).
    rewrite set_eq_spec in e. subst. bool_simpl. reflexivity.
    rewrite set_eq_spec in n. symmetry. num_prop. auto.
  Qed.
  Hint Rewrite numseteqb_eq_nat_bool : bool_simpl.

  Lemma le_antisym: n m: num, n m m n n = m.
  Proof. intros. num_omega. Qed.

End NumUtils.

Instance of NUM with positive as base type

Module Positive <: NUM.
  Definition num := positive.
  Definition nat_of_num n := pred (nat_of_P n).
  Definition num_of_nat := P_of_succ_nat.
  Definition le := Ple.
  Definition lt := Plt.
  Definition compare := Pos.compare.

  Definition leb (n m: num) :=
    match Pos.compare n m with
      | Gtfalse
      | _true
    end.
  Definition ltb (n m: num) :=
    match Pos.compare n m with
      | Lttrue
      | _false
    end.
  Definition eqb := eq_pos_bool.

  Definition S := Psucc.
  Definition max := Pmax.
  Definition fold_num T (f: num T T) :=
    Prect (fun _T T) (fun accacc) (fun a aux accaux (f a acc)).

  Fixpoint PeanoView_sum_iter E T (f: positive T T + E) p (q: PeanoView p) a :=
    match q with
      | PeanoOneinl a
      | PeanoSucc p q
        match f p a with
          | inl aPeanoView_sum_iter f q a
          | ee
        end
    end.
  Definition fold_num_sum E T (f: num T T + E) p a := PeanoView_sum_iter f (peanoView p) a.

  Definition pi0 := xO.
  Definition pi1 := xI.
  Definition pimatch i := match i with xO iinl i | xI iinr i | xHinl xH end.

  Lemma id_num : n, num_of_nat (nat_of_num n) = n.
  Proof.
      intros n.
      unfold nat_of_num.
      pattern n.
      apply Pcase. simpl. reflexivity.
      clear n. intros n. replace (nat_of_P (Psucc n)) with (Datatypes.S (nat_of_P n)). simpl.
      apply P_of_succ_nat_o_nat_of_P_eq_succ.
      symmetry; apply nat_of_P_succ_morphism.
  Qed.

  Lemma id_nat : n, nat_of_num (num_of_nat n) = n.
  Proof.
    intros n.
    unfold nat_of_num.
    assert (Hn : 0 < nat_of_P (num_of_nat n) ). apply lt_O_nat_of_P.
    assert ( s n, 0 <s s = Datatypes.S n pred s = n). intros. omega.
    apply H. auto.
    apply nat_of_P_o_P_of_succ_nat_eq_succ.
  Qed.

  Lemma le_spec : n m, reflect (le n m) (leb n m).
  Proof.
    intros n m; unfold leb.
    case_eq (Pos.compare n m); intro H; try constructor.
    apply Pcompare_Eq_eq in H. subst. unfold le,Ple,Pos.compare. rewrite Pcompare_refl. intro; discriminate.
    unfold le. unfold Ple. rewrite H. intro; discriminate.
    apply ZC1 in H. unfold le, Ple. apply ZC2 in H. rewrite H. intro. tauto_false.
  Qed.
  Lemma lt_spec : n m, reflect (lt n m) (ltb n m).
  Proof.
    intros n m; unfold ltb.
    case_eq (Pos.compare n m); intro H; try constructor.
    intro H'. apply Pcompare_Eq_eq in H. subst. refine (Plt_irrefl _ H').
    auto.
    intro H'. apply ZC1 in H. assert (H'' := Plt_trans _ _ _ H H'). refine (Plt_irrefl _ H'').
  Qed.
  Definition eq_spec := eq_pos_spec.
  Lemma compare_spec : n m, compare_spec eq lt n m (compare n m).
  Proof.
   intros.
   case_eq (compare n m); intro H; constructor.
   apply Pcompare_Eq_eq. apply H.
   apply H.

   unfold compare in H.
   apply ZC1. auto.
  Qed.

  Lemma S_nat_spec : n, nat_of_num (S n) = Datatypes.S (nat_of_num n).
  Proof.
    intros n.
    unfold nat_of_num. rewrite nat_of_P_succ_morphism. simpl.
    assert (H := lt_O_nat_of_P n).
    omega.
  Qed.
  Lemma le_nat_spec : n m, le n m (nat_of_num n nat_of_num m)%nat.
  Proof.
    intros x y.
    assert (Hx := lt_O_nat_of_P x).
    assert (Hy := lt_O_nat_of_P y).

    split; intro H.
      assert (H' : ¬nat_of_P x > nat_of_P y). unfold Ple in H. intro H'.
      apply H.
      apply nat_of_P_gt_Gt_compare_complement_morphism. auto.
      unfold nat_of_num .
      omega.

      intro H'.
      apply nat_of_P_gt_Gt_compare_morphism in H'.
      unfold nat_of_num in H.
      omega.
  Qed.

  Lemma lt_nat_spec : n m, lt n m (nat_of_num n < nat_of_num m)%nat.
  Proof.
    intros x y.
    assert (Hx := lt_O_nat_of_P x).
    assert (Hy := lt_O_nat_of_P y).

    split; intro.
    assert (nat_of_P x < nat_of_P y).
    apply nat_of_P_lt_Lt_compare_morphism. apply H.
    unfold nat_of_num.
    omega.

    apply nat_of_P_lt_Lt_compare_complement_morphism.
    unfold nat_of_num in H.
    omega.
  Qed.

  Lemma max_spec : n m, nat_of_num (max n m) = Max.max (nat_of_num n) (nat_of_num m).
  Proof.
    intros n m. unfold max, Pmax. fold (compare n m). destruct (compare_spec n m).
     rewrite Max.max_r; trivial. apply lt_le_weak. rewrite <- lt_nat_spec. assumption.
     subst. rewrite Max.max_r; trivial.
     rewrite Max.max_l; trivial. apply lt_le_weak. rewrite <- lt_nat_spec. assumption.
  Qed.

  Lemma fold_num_O: A (a: A) f, fold_num f xH a = a.
  Proof. reflexivity. Qed.

  Lemma fold_num_S: A (a: A) f n, fold_num f (S n) a = fold_num f n (f n a).
  Proof.
    intros. unfold fold_num at 1. rewrite Prect_succ. reflexivity.
  Qed.

  Lemma fold_num_sum_O: E T a f, @fold_num_sum E T f (num_of_nat 0) a = inl a.
  Proof. intros. reflexivity. Qed.

  Lemma fold_num_sum_S: E T a f n, @fold_num_sum E T f (S n) a =
    match f n a with
      | inl afold_num_sum f n a
      | ee
    end.
  Proof.
    intros. unfold fold_num_sum.
    replace (peanoView (S n)) with (PeanoSucc n (peanoView n)). reflexivity.
    apply PeanoViewUnique.
  Qed.

  Lemma match_pi0: n, pimatch (pi0 n) = inl n. Proof. reflexivity. Qed.
  Lemma match_pi1: n, pimatch (pi1 n) = inr n. Proof. reflexivity. Qed.

  Lemma lt_pi0: n m, lt n m lt (pi0 n) (pi0 m).
  Proof. intros n m. setoid_rewrite lt_nat_spec. unfold pi0, nat_of_num. rewrite 2 nat_of_P_xO. omega. Qed.
  Lemma lt_pi1: n m, lt n m lt (pi1 n) (pi1 m).
  Proof. intros n m. setoid_rewrite lt_nat_spec. unfold pi1, nat_of_num. rewrite 2 nat_of_P_xI. omega. Qed.

  Module NumOTA := Pos_as_OTA.
  Module NumSet' := FSetPositive.PositiveSet. Module NumSet := FSetHide NumSet'.
  Module NumMap' := FMapPositive.PositiveMap. Module NumMap := FMapHide NumMap'.

  Local Open Scope positive_scope.
  Definition triangle k i :=
    match k with
      | 1 ⇒ i
      | k'~0k'×Pdouble_minus_one k'+i
      | k'~1k'×k+i
    end.
  Definition enc i j := triangle (Ppred (i+j)) i.
  Fixpoint code (x: NumSet.t): num :=
    match x with
      | NumSet'.Leaf ⇒ 1
      | NumSet'.Node l true renc (code l) (code r)~0
      | NumSet'.Node l false renc (code l) (code r)~1
    end.

  Ltac psubst :=
    (repeat match goal with
              | H: Pos_as_OTA.compare _ _ = Eq |- _apply Pos_as_OTA.reflect in H
            end); subst.

  Hint Extern 0 (Pos_as_OTA.compare _ _ = Eq) ⇒ apply Pos_as_OT.eq_refl.

  Lemma pcompare_prop: x y, Pos_as_OTA.compare x y = Eq x = y.
  Proof. intros. intuition; psubst; trivial. Qed.
  Hint Rewrite pcompare_prop : num_prop.

  Lemma set_eq_spec : x y, NumSet.E.eq x y x = y.
  Proof. intros. reflexivity. Qed.
  Lemma map_eq_spec : x y, NumMap.E.eq x y x = y.
  Proof. intros. reflexivity. Qed.

End Positive.

Module PositiveUtils := NumUtils Positive.