Preliminaries


From Coq Require Import Lia List Init.Nat PeanoNat.
From PCF2.external Require Import SR.
From PCF2.external.Synthetic Require Import Definitions DecidabilityFacts.
Set Default Goal Selector "!".

Ltac inv H := inversion H; subst; clear H.

Lemma iter_succ_r (n: ) (A: Type) (f: A A) (x: A):
    iter (S n) f x = iter n f (f x).
Proof.
    now rewrite PeanoNat.Nat.iter_succ_r.
Qed.


Lemma iter_succ_l (n: ) (A: Type) (f: A A) (x: A):
    iter (S n) f x = f (iter n f x).
Proof.
    now rewrite PeanoNat.Nat.iter_succ.
Qed.


Lemma rev_nth_error1 {A: Type} (l: list A) n (a: A):
     n < length l nth_error l n = nth_error (rev l) (length l - S n).
Proof.
    intros H. rewrite (nth_error_nth' (rev l) a). 2: simpl_list; .
    rewrite rev_length.
    rewrite rev_nth. 2: simpl_list; .
    simpl_list. now rewrite nth_error_nth'.
Qed.


Lemma rev_nth_error2 {A: Type} (l: list A) n (a: A):
     n < length l nth_error l (length l - S n) = nth_error (rev l) n.
Proof.
    intros H. rewrite nth_error_nth' with (d := a). 2: .
    rewrite rev_nth. 2: easy. rewrite nth_error_nth'.
    1: easy. now simpl_list.
Qed.


Definition eq_dec X := decidable ( p: X * X fst p = snd p).

Lemma bool_eq_dec:
    eq_dec bool.
Proof.
    unfold eq_dec.
    rewrite decidable_iff.
    constructor. intros [ ].
    destruct , ; firstorder; right; easy.
Qed.


Lemma list_eq_dec {A: Type}:
    eq_dec A eq_dec (list A).
Proof.
    intros dec_A. unfold eq_dec in *.
    rewrite decidable_iff in dec_A. destruct dec_A as [dec_A].
    rewrite decidable_iff. constructor.
    intros [ ]. induction in |-*.
    - destruct ; firstorder. now right.
    - destruct . 1: now right.
    destruct ( ), (dec_A (a, )).
    {left. cbn in *. intuition congruence. }
    all: right; cbn in *; intuition congruence.
Qed.


Lemma pair_eq_dec {A B: Type}:
    eq_dec A eq_dec B eq_dec (prod A B).
Proof.
    intros dec_A dec_B. unfold eq_dec in *.
    rewrite decidable_iff in dec_A. destruct dec_A as [dec_A].
    rewrite decidable_iff in dec_B. destruct dec_B as [dec_B].
    rewrite decidable_iff. constructor.
    intros [[ ] [ ]]. destruct (dec_A (, )), (dec_B (, )).
    all: cbn in *.
    1: left; intuition congruence.
    all: right; intuition congruence.
Qed.


Lemma rules_eq_decidable:
    eq_dec (str * str).
Proof.
    apply pair_eq_dec.
    all: apply list_eq_dec, bool_eq_dec.
Qed.


Lemma list_eq {A: Type} (l l': list A):
    length l = length l' ( n a a', nth_error l n = Some a nth_error l' n = Some a' a = a') l = l'.
Proof.
    intros len H. induction l as [| a l] in l', len, H |-*.
    - now destruct l'.
    - destruct l' as [| a' l'].
    1: easy.
    enough (H': a = a' l = l').
    { destruct H' as [ ]. now subst. }
    split.
    1: now apply (H 0).
    apply IHl.
    1: now injection len.
    intros n s t H_s H_t. now apply (H (S n)).
Qed.


Lemma nat_ord_dec (n m: ):
    (n m) + (n > m).
Proof.
    induction n in m |-*.
    1: left; .
    destruct m.
    1: right; .
    destruct (IHn m).
    1: left; .
    right; .
Qed.


Lemma leb_le_true:
     n m, leb n m = true n m.
Proof.
    apply Nat.leb_le.
Qed.


Lemma leb_le_false:
     n m, leb n m = false n > m.
Proof.
    intros n m. split.
    - intros H. assert (: leb n m = true) by now destruct (leb n m).
        rewrite leb_le_true in . .
    - intros H. assert (: n m) by . rewrite leb_le_true in .
        now destruct (leb n m).
Qed.


Lemma ltb_lt_true:
     n m, ltb n m = true n < m.
Proof.
    apply Nat.ltb_lt.
Qed.


Lemma ltb_lt_false:
     n m, ltb n m = false n m.
Proof.
    intros n m. split.
    - intros H. assert (: ltb n m = true) by now destruct (ltb n m).
        rewrite ltb_lt_true in . .
    - intros H. assert (: n < m) by . rewrite ltb_lt_true in .
        now destruct (ltb n m).
Qed.


Lemma arith_technical m n o:
    n > m n m + o n', n' < o n = m + 1 + n'.
Proof.
intros . induction n in m, , |-*.
    - .
    - destruct m.
        + exists n. .
        + assert (: n > m) by . assert (: n m + o) by .
        destruct (IHn m ) as [n' Hn']. exists n'. .
Qed.


Lemma arith_technical' m n o:
    n m n < m + o n', n' < o n = m + n'.
Proof.
intros . induction m in n, , |-*.
    - exists n. .
    - destruct n.
        + exists m. .
        + assert (: n m) by . assert (: n < m + o) by .
        destruct (IHm n ) as [n' Hn']. exists n'. .
Qed.


Definition diff n m := (n - m) + (m - n).

Lemma diff1 n m:
  n m diff n m = n - m.
Proof.
  intros ?. unfold diff. .
Qed.


Lemma diff2 n m:
  n < m diff n m = m - n.
Proof.
  intros ?. unfold diff. .
Qed.