Mefresa.Batteries

Batteries is a general purpose library for Coq development. It is essentially aimed at improving Coq Proof scripts' readability and maintainability.
As of now, it features the following:
  • An easy way to annotate/comment proof goals. This is achieved by using the Case command. For instance,
    • Case "Goal 1 of 5"
    will allow to seamlessly to include a text information in your proof script, but will also put the given string on top of your hypotheses. Of course, there is also 'SCase string' for subgoals, 'SSCase string' for subsubgoals, and so forth, until a depth of 8. Moreover, you can leverage this by indenting your code according to your use of Case.
  • A simple tactic(al) - thus - that fails if it doesn't solve the current goal. This is useful for maintaining your scripts. If you keep the rationale of always using this tactic to conclude your goals, whenever updating your Coq scripts, you will know exactly where it breaks.

Annotating your Proofs


Require Export String.

Open Scope string_scope.


The following definitions will allow us to annotate our proof scripts. These were taken from Software Foundations.
Ltac move_to_top x :=
  match reverse goal with
  | H : _ |- _ => try move x after H
  end.


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.


For instance, we can now annotate our proofs as the following:
Example annotation_example:
  forall A B, B /\ A -> (B /\ A).

Proof.

  intros A B Hab.

  split.

  Case "Let's prove the left side of the conjunction: B".

    apply Hab.

  Case "Let's prove the right side of the conjunction: A".

    apply Hab.

Qed.


The above example was trivial. Let's see now something more interesting. Consider the following definition:
We will now associate annotations to the goals generated by some given tactic. It is also possible to specify whether we are in 'Case's, 'SCase's, etc
Tactic Notation "awesome_cases" tactic(first) ident(c) :=
  first;
  [ Case_aux c "1st Constructor"
  | Case_aux c "2nd Constructor" ].


Generally speaking, this will serve the purpose of automatically associating the given strings foreach constructors of some given inductive definition.
With this tactical defined, we can use it as follows:

Example induction_example:
  forall a, a = Constructor1 \/ a = Constructor2.

Proof.

  intros.

  awesome_cases (induction a) Case.

And just like that, we get our goals already annotated at the top of our hypotheses. Moreover, the strings given on the '(S)Case's must be consistent with a possible annotation already present.
   Case "1st Constructor".
     left; auto.

   Case "2nd Constructor".

     right; auto.

Qed.


A Few Tactics

A Conclude-the-current-goal-or-Fail Tactic

The above increases proof scripts' readability. Here, we want to help the mantainability of always evolving proof scripts. The idea is simple, following the rationale of always concluding (sub)goals with the last tactic prefixed by the tactical 'thus', and making it fail if the (sub)goal is not discharged by this tactic.
This makes possible to exactly detect the point where the proof script breakes when updating something.
I've first seen this kind of approach in ssreflect.

Tactic Notation "thus" tactic(H) := solve [H; auto].


The above tactical fails if it doesn't solve the current goal. Here it is in action.

Lemma test: forall n : nat, n <= n.

Proof.

  intro.

  thus auto.

Qed.


Reflexivity-like Tactic

Our own reflexivity tactic. Nothing fancy here, just improving automation a tiny bit.

Tactic Notation "refl" := simpl; reflexivity.


Type-fast-Functional-induction Tactic

Well I do functional induction quite a lot, and I would rather write something that doesn't take that long to type :-) TODO: FIX the following: f needs to be a list
Ltac run f := functional induction f.

Assert-False-and-solve Tactic

A tactic to make proofs by being able to prove False faster
Ltac fromfalse := assert (False) as Hfalse; eauto; inversion Hfalse.

Some Functions and Facts on Lists

Coq standard library doesn't include a definition for Fold_left2. We shall use the following one whenever needed.
Require Export List.
Set Implicit Arguments.

Fixpoint fold_left2 (A:Type) (B:Type) (C:Type)
                    (f : A -> B -> C -> A)
                    (accu: A)
                    (l1: list B) (l2: list C) : option A :=
  match l1, l2 with
      nil, nil => Some accu
    | cons a1 l1, cons a2 l2 => fold_left2 f (f accu a1 a2) l1 l2
    | _, _ => None
  end.


For instance, we can use this definition for computations as follows:
Definition listAcc := (nil:list nat). Definition listB := 1::2::3::nil. Definition listC := 3::2::1::nil. Eval compute in fold_left2 (fun a b c => (b+c)::a) listAcc listB listC. Eval compute in fold_left2 (fun a b c => (b+c)::a) listAcc listB (0 :: listC).
A fact about list that may become handy. Got it from a thread in the Coq mailing list.

Lemma in_app_cons_fact : forall A x (a : A) bs cs,
  In x ((a :: bs) ++ cs) <-> In x (bs ++ (a :: cs)).

Proof.

intros A x a bs cs ; split ; intro H ; apply in_or_app ;
  assert (H2 := in_app_or _ _ _ H) ; destruct H2.

   destruct H0.

    right ; constructor ; assumption.

    left ; assumption.

    do 2 right ; assumption.

    left ; right ; assumption.

   destruct H0.

   left ; constructor ; assumption.

   right ; assumption.

Qed.


On Naturals and Strings!


Function beq_nat (x:nat) (y:nat) : bool :=
  match x, y with
    O, O => true
  | S n, S m => beq_nat n m
  | _, _ => false
  end.


implementation of: (n <= m) ? true : false
Function ble_nat n m : bool :=
 match n, m with
   O, _ => true
  | S n', S m' => ble_nat n' m'
  | _, _ => false
 end.


Let's make it reflect into Prop!

Require Import Coq.Arith.Le.

Lemma ble_nat_reflection:
  forall n m, ble_nat n m = true <-> n <= m.

Proof.

  induction n; induction m; split; simpl; intros;
  auto with arith;
  try congruence.

  Case "1/3".

    inversion H.

  Case "2/3".

    destruct IHn with (m:=m); auto.

    apply le_n_S; auto.

  Case "3/3".

    destruct IHn with (m:=m); auto.

    apply H1.

    apply le_S_n; auto.

Qed.


Hint Resolve ble_nat_reflection.


Require Import Coq.Strings.Ascii.

Require Import Coq.Strings.String.

Require Import NPeano.

Require Import Recdef.


Definition digit_of_nat n := ascii_of_nat (n + 48).


Function string_of_nat_aux n acc {measure (fun x => x) n} :=
  match n with
    | 0 => acc
    | _ => string_of_nat_aux (n / 10) (String (digit_of_nat (n mod 10)) acc)
  end.

Proof.

  intros.
apply Nat.div_lt; auto with arith.
Defined.


Definition string_of_nat n :=
  match n with
    | 0 => "0"%string
    | _ => string_of_nat_aux n EmptyString
  end.


Definition nat_to_string := string_of_nat.


Axiom nat_to_string_fact:
  forall n m, n <> m -> nat_to_string n <> nat_to_string m.


Lemma string_append_fact:
  forall s1 s2 s3: string, s2 = s3 -> append s1 s2 = append s1 s3.

Proof.

  intros.

  apply f_equal; auto.

Qed.


Lemma string_append_fact':
  forall s1 s2 s3: string, s2 <> s3 -> append s1 s2 <> append s1 s3.

Proof.

  induction s1; intros; simpl; auto.

  assert ((s1 ++ s2)%string <> (s1 ++ s3)%string); try apply IHs1; auto.

  intuition.

  apply H0.

  inversion H1.
auto.
Qed.


Function beq_bool b b' : bool :=
  match b, b' with
    true , true => true
  | false, false => true
  | _ , _ => false
  end.


Open Scope bool_scope.

Require Import Coq.Bool.Bool.

Function beq_ascii a a' : bool :=
  match a, a' with
    Ascii b1 b2 b3 b4 b5 b6 b7 b8,
    Ascii b1' b2' b3' b4' b5' b6' b7' b8' =>
       (beq_bool b1 b1') && (beq_bool b2 b2') && (beq_bool b3 b3') && (beq_bool b4 b4')
     && (beq_bool b5 b5') && (beq_bool b6 b6') && (beq_bool b7 b7') && (beq_bool b8 b8')
  end.


Lemma beq_bool_refl:
  forall b, beq_bool b b = true.

Proof.

  destruct b; simpl; refl.

Qed.


Lemma ascii_eq_reflection:
  forall a a', a=a' <-> beq_ascii a a'=true.

Proof.

  destruct a; destruct a'; split; intro.

  Case "Prop Entails Bool".

    inversion H; subst; auto.

    clear.

    simpl.

    repeat rewrite beq_bool_refl.

    simpl; auto.

  Case "Bool Entails Prop".

    simpl in H.

    repeat rewrite andb_true_iff in H.

    do 7 (destruct H).

    destruct b; destruct b7; simpl in H; try congruence; clear H;
    destruct b0; destruct b8; simpl in H6; try congruence; clear H6;
    destruct b1; destruct b9; simpl in H5; try congruence; clear H5;
    destruct b2; destruct b10; simpl in H4; try congruence; clear H4;
    destruct b3; destruct b11; simpl in H3; try congruence; clear H3;
    destruct b4; destruct b12; simpl in H2; try congruence; clear H2;
    destruct b5; destruct b13; simpl in H1; try congruence; clear H1;
    destruct b6; destruct b14; simpl in H0; try congruence; clear H0.

Qed.


Function beq_string str str' : bool :=
  match str, str' with
    String a r, String a' r' => beq_ascii a a' && beq_string r r'
  | EmptyString, EmptyString => true
  | _ , _ => false
  end.


Lemma beq_string_reflection_in_bool:
  forall str str', beq_string str str'= true -> str=str'.

Proof.

  induction str; induction str'; intros; simpl in *; try congruence.

  rewrite andb_true_iff in H.

  destruct H.

  destruct ascii_eq_reflection with (a:=a) (a':=a0).

  assert (a=a0); auto; subst.

  apply f_equal.

  apply IHstr; auto.

Qed.


Lemma beq_string_reflection_in_prop:
  forall str str', str=str' -> beq_string str str'= true.

Proof.

  induction str; induction str'; simpl; intros; try congruence.

  inversion H; subst.

  rewrite andb_true_iff.

  split; auto.

  destruct a0.

  simpl.

  repeat rewrite beq_bool_refl.

  simpl; auto.

Qed.


Lemma beq_string_reflection:
  forall str str', str=str' <-> beq_string str str'= true.

Proof.

  split;
  [ apply beq_string_reflection_in_prop
  | apply beq_string_reflection_in_bool
  ]; auto.

Qed.


A notion of Identifier

Let us start by defining a notion of identifier. It will be a simple constructor that takes a string.
Inductive ident : Type :=
  | Ident : string -> ident.


For instance, we can define some identifiers in the following manner:
Module IdentDefinitionExample.

Definition FooVariable : ident := Ident "foo".

Definition BarVariable : ident := Ident "bar".

Definition XyzVariable : ident := Ident "foo".


End IdentDefinitionExample.


We will a function to determine whether to identifiers are equal. Since our identifiers are simple constructions that take a string, we simply need to check whether the given identifiers have identical strings.
Function beq_ident (id1 id2: ident) : bool :=
  match id1, id2 with
    | Ident str1, Ident str2 => match string_dec str1 str2 with
                                      | left _ => true
                                      | right _ => false
                                   end
  end.



For the sake of readability, we define a notation to our comparison over identifiers operator close to what one would see in a standard programming language. We shall use it seamlessly in the remaining of this development.
Notation "s1 '==' s2" := (beq_ident s1 s2) (at level 80).



We can right now see our first proof. Let's start with something simple: decidability on identifiers.
Lemma ident_dec : forall id1 id2 : ident, {id1 = id2} + {id1 <> id2}.
Proof.

  repeat decide equality.

Qed.


Lemma str_symmetry:
  forall str1 str2, (if string_dec str1 str2 then true else false) =
                              (if string_dec str2 str1 then true else false).

Proof.

  intros.

  destruct string_dec with (s1:=str1) (s2:=str2);
  destruct string_dec with (s1:=str2) (s2:=str1); auto.

  congruence.

Qed.


Moreover, we shall prove an obvious, yet very useful lemma about our ident equality operator: it is symmetric.
Lemma beq_ident_symmetry:
  forall i i' X, (i == i') = X <-> (i' == i) = X.

Proof.

Admitted.


Lemma bool_conjunction_fact:
  forall id id' X,
    (id == id') && X = true ->
    (id == id') = true.

Proof.

  intros.

  functional induction beq_ident id id'; auto.

Qed.


Hint Resolve bool_conjunction_fact.


Lemma bool_conjunction_fact':
  forall id id' X,
    X && (id == id') = true ->
    (id == id') = true.

Proof.

  intros.

  assert (X && (id == id') = (id == id') && X).

    intuition.

  rewrite H0 in H.

  functional induction beq_ident id id'; auto.

Qed.


Hint Resolve bool_conjunction_fact'.


Lemma ident_equality_Prop2bool:
   forall id id',
   id = id' ->
   (id == id') = true.

Proof.

  intros.

  functional induction beq_ident id id'; auto.

  congruence.

Qed.


Lemma ident_equality_Prop2bool':
   forall id id',
   id <> id' ->
   (id == id') = false.

Proof.

  intros.

  functional induction beq_ident id id'; auto.

  congruence.

Qed.


Lemma ident_equality_bool2Prop:
   forall id id',
   (id == id') = false -> id <> id'.

Proof.

  intros.

  functional induction beq_ident id id'.

  congruence.

  intuition.

  apply _x; auto.

  inversion H0; auto.

Qed.


Lemma ident_equality_bool2Prop':
   forall id id',
   (id == id') = true -> id = id'.

Proof.

  intros.

  functional induction beq_ident id id'; auto.

  congruence.

Qed.


Hint Resolve ident_equality_Prop2bool ident_equality_Prop2bool'
             ident_equality_bool2Prop ident_equality_bool2Prop'.


Lemma ident_eq_reflection:
  forall id1 id2, (id1==id2)=true <-> id1=id2.

Proof.

  intros; split; auto.

Qed.


Lemma beq_ident_symmetry':
  forall i i', (i == i') = false <-> (i' == i) = false.

Proof.

  intros.

  destruct ident_dec with (id1:=i) (id2:=i').

  Case "Ids are equal".

    assert ((i == i') = true).

      eauto.

    subst.

    rewrite H.

    split; congruence.

  Case "Ids are not Equal".

    assert ((i == i') = false).

      eauto.

    assert ((i' == i) = false).

      eauto.

    rewrite H; rewrite H0; intuition.

Qed.


Hint Resolve beq_ident_symmetry'.


Another useful definition is the not-equal operator. Simply defined as follows:
Definition bneq_ident id1 id2 : bool :=
 match beq_ident id1 id2 with
   | true => false
   | false => true
 end.


Notation "s1 '!=' s2" := (bneq_ident s1 s2) (at level 80).


Lemma bneq_false_entails_beq_true:
  forall id id',
    (id != id') = false ->
    (id == id') = true.

Proof.

  intros.

  destruct ident_dec with (id1:=id) (id2:=id'); auto.

  assert ((id == id') = false).

    auto.

  unfold bneq_ident in H.

  rewrite H0 in H.

  discriminate.

Qed.


Lemma bneq_true_entails_beq_false:
  forall id id',
    (id != id') = true ->
    (id == id') = false.

Proof.

  intros.

  destruct ident_dec with (id1:=id) (id2:=id'); auto.

  assert ((id == id') = true).

    auto.

  unfold bneq_ident in H.

  rewrite H0 in H.

  discriminate.

Qed.


Hint Resolve bneq_false_entails_beq_true bneq_true_entails_beq_false.


As you can guess, comparison operators like beq_ident and bneq_ident will be useful for other types of structures that we will define at a more advanced stage. Of course, one would prefer to maintain the same notation for these other comparison operators.
Unfortunately for us, Coq will not be always able to infer to which actual definition the notation is referring to. As such, we will need to define scopes. This is the purpose of the following two lines. Their real significance will become clear with examples.
Bind Scope id_scope with ident.
Delimit Scope id_scope with id.


Warming up: Some Simple Proof Examples

So far, we just defined the notion of identifiers, let's see what can we prove about them.

Module IdentProofExamples.


Definition x : ident := Ident "x".

Definition y : ident := Ident "y".


Example warm_up_proof:
   x = y -> False.

Proof.

   intro.

   thus inversion H.

Qed.


Example warm_up_proof':
   (x == y) = false.

Proof.

   unfold beq_ident.

   thus auto.

Qed.


End IdentProofExamples.


Require Export Arith.EqNat.


Hint Resolve ident_dec beq_ident_symmetry.


Generic comparison function over lists.
Function beq_list_X (X:Type) (l l':list X) (beq_X:X->X->bool) : bool :=
  match l, l' with
    nil, nil => true
  | e::r, e'::r' => if beq_X e e' then beq_list_X r r' beq_X else false
  | _ , _ => false
  end.

Arguments beq_list_X [X] l l' beq_X.


Simple ArrayList type


Function generate_list (X:Type) (size:nat) (val:X): list X :=
  match size with
    0 => nil
  | S n => val :: generate_list n val
  end.

Implicit Arguments generate_list [X].


Record ArrayList : Type := mk_arraylist {
             element_type : Type;
             arraylist_length : nat;
             contents : list element_type
}.


Notation "'new' 'ArrayList<bool>' n" := (mk_arraylist n (generate_list n false)) (at level 80) .

Notation "'new' 'ArrayList<nat>' n" := (mk_arraylist n (generate_list n 0)) (at level 80) .


Function get_element_by_index X (l:list X) (i:nat) : option X :=
  match i, l with
    0 , e :: r => Some e
  | S n, e :: r => get_element_by_index r n
  | _, _ => None
  end.

Implicit Arguments get_element_by_index [X].


Function getArrayListElement a i :=
  get_element_by_index (@contents a) i.

Notation "a '[|' i '|]'" := (getArrayListElement a i) (at level 80).


Function set_element_by_index X (l:list X) i el : list X :=
  match i, l with
    0 , e :: r => el :: r
  | S n, e :: r => e :: set_element_by_index r n el
  | _, _ => nil
  end.

Implicit Arguments set_element_by_index [X].


Function setArrayListElement a i el :=
     let l := set_element_by_index (@contents a) i el in
     mk_arraylist (@arraylist_length a) l.


Notation "a '[|' i '|]' '<-' el" := (setArrayListElement a i el) (at level 80).