Qcert.Basic.Util.RUtil





Section RUtil.

  Section bools.

    Lemma andb_true_inversion:
       b1 b2 : bool,
        andb b1 b2 = true b1 = true b2 = true.

    Lemma four_cases {A:Type} :
       (p1 p2: A bool) (a:A),
        ((((p1 a) = true) ((p2 a) = true))
         (((p1 a) = true) ((p2 a) = false)))
        ((((p1 a) = false) ((p2 a) = true))
         (((p1 a) = false) ((p2 a) = false))).

    Lemma two_cases {A:Type} :
       (p: A bool) (a:A),
        ((p a) = true) ((p a) = false).

    Lemma notand p q:
      ~(p q) ¬p ¬q.

    Lemma eq_implies_pred {A:Type} :
       (p:A bool), (x1 x2:A),
          x1 = x2 (p x1) = (p x2).

    Lemma not_pred_implies_neq {A:Type}:
       (p:A bool), (x1 x2:A),
          (p x1) (p x2) x1 x2.

  End bools.

  Section In.
    Context {A:Type}.

    Lemma In_app (x:A) (l1 l2:list A):
      In x (l1 ++ l2) In x l1 In x l2.

    Lemma In_app_comm (v:A) (l1 l2:list A) :
      In v (l1++l2) In v (l2++l1).

    Lemma In_app_iff (v:A) (l1 l2:list A) :
      In v (l1++l2) In v (l2++l1).

    Lemma find_In {f l} {b:A} : find f l = Some b In b l.

    Lemma find_correct {f l} {b:A} : find f l = Some b f b = true.

    Lemma app_or_in (x:A) (l1 l2: list A) :
      In x (l1 ++ l2) In x l1 In x l2.

    Lemma app_or_in_iff (x:A) (l1 l2: list A) :
      In x (l1 ++ l2) In x l1 In x l2.

    Lemma in_or_not (eqd: a a':A, {a=a'} + {aa'}) (l:list A) a:
      (In a l) ~(In a l).

    Lemma nin_app_or (x:A) a b :
      (¬ In x (a ++ b)) (¬ In x a ¬ In x b).

    Lemma in_in_app_false {l l1 l2} :
      ( x:A,
          In x l
          In x (l1 ++ l2) False)
      (( x,
           In x l
           In x l1 False)
       ( x,
           In x l
           In x l2 False)).

    Lemma in_in_cons_app_false {v l l1 l2} :
      ( x:A,
          In x l
          v = x In x (l1 ++ l2) False)
      (( x,
           In x l
           In x (l1) False)
       ( x,
           In x l
           In x (l2) False)
       ¬ (In v l)).

    Lemma in_in_cons_cons_app_app_false {v v0 l l1 l2 l3} :
      ( x:A,
          In x l
          v = x v0 = x In x (l1 ++ l2 ++ l3) False)
      (( x,
           In x l
           In x l1 False)
       ( x,
           In x l
           In x l2 False)
       ( x,
           In x l
           In x l3 False)
       ¬ (In v l)
       ¬ (In v0 l)).

  End In.

  Section forallt.
    Inductive Forallt {A : Type} (P : A Type) : list A Type :=
      Forallt_nil : Forallt P nil
    | Forallt_cons : (x : A) (l : list A),
        P x Forallt P l Forallt P (x :: l).

    Lemma list_Forallt_eq_dec {A:Type}:
       (c l: list A),
        Forallt (fun x : A y : A, {x = y} + {x y}) c {c = l} + {c l}.

    Lemma forallt_impl {A} {P1 P2:AType} {l:list A} :
      Forallt P1 l Forallt (fun xP1 x P2 x) l Forallt P2 l.

    Lemma forallt_weaken {A} P : ( x:A, P x) l, Forallt P l.

    Lemma Forallt_inv: A P (a:A) l, Forallt P (a :: l) P a.

    Lemma Forallt_inv2: A P (a:A) l, Forallt P (a :: l) Forallt P l.


    Lemma Forallt_In {A:Type} {P:AType} {r} {eq:EqDec A eq}:
      Forallt P r a, In a r P a.

    Lemma Forall_app {A} (P:AProp) (l1 l2:list A):
      Forall P l1 Forall P l2
      Forall P (l1 ++ l2).

    Lemma Forall_app_inv {A : Type} {P : A Prop} (l1 l2 : list A) :
      Forall P (l1 ++ l2) Forall P l1 Forall P l2.

    Lemma Forall_map {A B} P (f:AB) l:
      Forall P (map f l)
      Forall (fun xP (f x)) l.

    Lemma Forall_impl_in {A} {P Q : A Prop} {l} :
      ( a, In a l P a Q a)
      Forall P l Forall Q l.

    Lemma Forallt_Forall {A:Prop} (P:AProp) (l:list A) :
      Forallt P l Forall P l.

  End forallt.

  Section forallb.

    Lemma forallb_ext {A} f1 f2 (l:list A) :
      ( x, In x l f1 x = f2 x)
      forallb f1 l = forallb f2 l.

    Lemma forallb_incl {A} f (l1 l2 : list A) :
      incl l1 l2
      forallb f l2 = true
      forallb f l1 = true.

    Lemma forallb_app {A} (f:Abool) l1 l2 :
      forallb f (l1 ++ l2) = true
      (forallb f l1 = true forallb f l2 = true).

    Lemma forallb_map {A B} f (mf:AB) m : forallb f (map mf m) = forallb ((fun xf (mf x))) m.

    Lemma existsb_not_forallb {A} f (l:list A)
      : existsb f l = negb (forallb (fun xnegb (f x)) l).

    Lemma forallb_not_existb {A} f (l:list A)
      : forallb f l = negb (existsb (fun xnegb (f x)) l).

    Lemma map_eq {A B} {f g:AB} {l} :
      Forall (fun xf x = g x) l
      map f l = map g l.

    Lemma map_cons {A B:Type} (f:AB) (l:list A) (a:A) :
      map f (a::l) = (f a)::map f l.

    Lemma map_eq_cons {A B} (f : A B) (l:list A) b l' :
      map f l = b::l'
      {a : A & {ls:list A | l = a::ls f a = b map f ls = l'}}.

  End forallb.

  Section pairs.

    Lemma pair_eq_dec {A B:Type} (a1:A) (b1:B) (a2:A) (b2:B) :
      {a1 = a2} + {a1 a2}
      {b1 = b2} + {b1 b2}
      {(a1, b1) = (a2, b2)} + {(a1, b1) (a2, b2)}.


    Global Instance string_eqdec : EqDec String.string eq := String.string_dec.
    Global Instance pair_eqdec {A B} `{EqDec A eq} `{EqDec B eq} : EqDec (prod A B) eq.

    Global Instance option_eqdec {A:Type} `{EqDec A eq}: EqDec (option A) eq.

  End pairs.


  Section arith.

    Lemma min_zero:
       (n1 n2:nat), min n1 (S n2) = 0 n1 = 0.

    Lemma min_against_one:
       (n:nat), min n 1 = 0 min n 1 = 1.

    Lemma compare_either (n1 n2:nat):
      (n1 n2) (n2 n1).

    Lemma min_one_yields_one:
       n:nat, min n 1 = 1 1 n.

    Lemma fold_left_arith_dist1 {A} (x0:nat) (l:list A) (f:A nat):
      fold_left (fun (x:nat) (y:A) ⇒ (f y) + x) l x0 =
      (fold_left (fun (x:nat) (y:A) ⇒ (f y) + x) l 0) + x0.

    Lemma fold_left_arith_dist2 {A} (x0 n0:nat) (l:list A) (f:A nat):
      fold_left (fun (x:nat) (y:A) ⇒ n0 × (f y) + x) l x0 =
      n0 × (fold_left (fun (x:nat) (y:A) ⇒ (f y) + x) l 0) + x0.

    Lemma fold_left_arith_dist3 {A} (x0 n0:nat) (l:list A) (f:A nat):
      n0 × (fold_left (fun (x:nat) (y:A) ⇒ (f y) + x) l 0) + x0 =
      n0 × (fold_left (fun (x:nat) (y:A) ⇒ x + (f y)) l 0) + x0.

    Lemma fold_left_arith_dist4 {A} (x0 n0:nat) (l:list A) (f:A nat):
      fold_left (fun (x:nat) (y:A) ⇒ n0 × (f y) + x) l x0 =
      n0 × (fold_left (fun (x:nat) (y:A) ⇒ x + (f y)) l 0) + x0.

  End arith.

  Section Zutil.

    Definition ZToSignedNat (z:Z) : (bool×nat) :=
      match (Z.sgn z) with
      | -1 ⇒ (false,(Z.to_nat z))
      | _(true, (Z.to_nat z))
      end.

    Lemma pos_succ_inv (n1 n2:positive):
      (Pos.succ n1 = Pos.succ n2 n1 = n2).

    Lemma Pos_of_nat_inv (n1 n2:nat) :
      Pos.of_nat (S n1) = Pos.of_nat (S n2) n1 = n2.

    Lemma of_nat_inv (n1 n2:nat) :
      Z.of_nat n1 = Z.of_nat n2 n1 = n2.

    Lemma pos_succ_nat_inv (n1 n2:nat) :
      Pos.of_succ_nat n1 = Pos.of_succ_nat n2 n1 = n2.

    Global Instance Z_eqdec : EqDec Z eq.

  End Zutil.

  Section iter.
    Lemma repeat_plus {A} (x:A) (n1 n2:nat) :
      repeat x (n1+n2) = repeat x n1 ++ repeat x n2.

    Fixpoint iter {A} (f:AA) (iterations:nat) (a:A)
      := match iterations with
         | 0 ⇒ a
         | S niter f n (f a)
         end.

    Lemma iter_fold_left_list {A B} (f:AA) (l:list B) (a:A)
      : iter f (length l) a = fold_left (fun x yf x) l a.

    Lemma iter_fold_left_repeat {A} (f:AA) (iterations:nat) (a:A)
      : iter f iterations a = fold_left (fun x yf x) (repeat 0 iterations) a.

    Lemma iter_fold_right_list {A B} (f:AA) (l:list B) (a:A)
      : iter f (length l) a = fold_right (fun x yf y) a l.

    Lemma iter_plus {A} (f:AA) (iterations1 iterations2:nat) (a:A) :
      iter f (iterations1+iterations2) a = iter f iterations2 (iter f iterations1 a).

    Lemma iter_trans {A} (R:relation A) {pre:PreOrder R} f
          (pf: x, R x (f x)) (iterations:nat) a :
      R a (iter f iterations a).

  End iter.

  Section cost.

    Context {A:Type}.
    Function iter_cost (optim: A A) (cost: A nat) (p: A) { measure cost p } :=
      let p' := optim p in
      if lt_dec (cost p') (cost p)
      then iter_cost optim cost p'
      else p.

    Lemma iter_cost_trans (R:relation A) {pre:PreOrder R} f
          (pf: x, R x (f x)) (cost:Anat) a :
      R a (iter_cost f cost a).

  End cost.

  Section vm.
    Definition is_true {A B} (x:{A}+{B}) : bool :=
      Eval vm_compute in (if x then true else false).

    Definition holds {A B} (x:{A}+{B}) : Prop :=
      is_true x = true.
  End vm.

End RUtil.



Tactic Notation "assert_eq" ident(x) constr(v) :=
  let H := fresh in
  assert (x = v) as H by reflexivity;
  clear H.

Tactic Notation "Case_aux" ident(x) constr(name) :=
  first [
    set (x := name); move_to_top x
  | assert_eq x name; move_to_top x
  | fail 1 "because we are working on a different case" ].

Tactic Notation "Case" constr(name) := Case_aux Case name.
Tactic Notation "SCase" constr(name) := Case_aux SCase name.
Tactic Notation "SSCase" constr(name) := Case_aux SSCase name.
Tactic Notation "SSSCase" constr(name) := Case_aux SSSCase name.
Tactic Notation "SSSSCase" constr(name) := Case_aux SSSSCase name.
Tactic Notation "SSSSSCase" constr(name) := Case_aux SSSSSCase name.
Tactic Notation "SSSSSSCase" constr(name) := Case_aux SSSSSSCase name.
Tactic Notation "SSSSSSSCase" constr(name) := Case_aux SSSSSSSCase name.










Definition brand := string.

Class ToString (A:Type)
  := {
      toString (a:A) : string
      }.