text:
** * Induction: Proof by Induction *)

(** Before getting started, we need to import all of our
    definitions from the previous chapter: *)

(*Require Export Basics.*)

(** For the [Require Export] to work, you first need to use
    [coqc] to compile [Basics.v] into [Basics.vo].  This is like
    making a [.class] file from a [.java] file, or a [.o] file from a
    [.c] file.  There are two ways to do it:

     - In CoqIDE:

         Open [Basics.v].  In the "Compile" menu, click on "Compile
         Buffer".

     - From the command line: Either

         [make Basics.vo]

       (assuming you've downloaded the whole LF directory and have a
       working [make] command) or

         [coqc Basics.v]

       (which should work from any terminal window).

    If you have trouble (e.g., if you get complaints about missing
    identifiers later in the file), it may be because the "load path"
    for Coq is not set up correctly.  The [Print LoadPath.] command may
    be helpful in sorting out such issues.

    In particular, if you see a message like

        [Compiled library Foo makes inconsistent assumptions over
        library Coq.Init.Bar]

    you should check whether you have multiple installations of Coq on
    your machine.  If so, it may be that commands (like [coqc]) that
    you execute in a terminal window are getting a different version of
    Coq than commands executed by Proof General or CoqIDE.

    One more tip for CoqIDE users: If you see messages like [Error:
    Unable to locate library Basics], a likely reason is
    inconsistencies between compiling things _within CoqIDE_ vs _using
    coqc_ from the command line.  This typically happens when there are
    two incompatible versions of [coqc] installed on your system (one
    associated with CoqIDE, and one associated with [coqc] from the
    terminal).  The workaround for this situation is compiling using
    CoqIDE only (i.e. choosing "make" from the menu), and avoiding
    using [coqc] directly at all. *)

(* ################################################################# *)
(** * Proof by Induction *)

(** We proved in the last chapter that [0] is a neutral element
    for [+] on the left, using an easy argument based on
    simplification.  We also observed that proving the fact that it is
    also a neutral element on the _right_... *)

Theorem plus_n_O_firsttry : forall n:nat,
  n = n + 0.

(** ... can't be done in the same simple way.  Just applying
  [reflexivity] doesn't work, since the [n] in [n + 0] is an arbitrary
  unknown number, so the [match] in the definition of [+] can't be
  simplified.  *)

Proof.
  intros n.
  simpl. (* Does nothing! *)
Abort.

(** And reasoning by cases using [destruct n] doesn't get us much
    further: the branch of the case analysis where we assume [n = 0]
    goes through fine, but in the branch where [n = S n'] for some [n'] we
    get stuck in exactly the same way. *)

Theorem plus_n_O_secondtry : forall n:nat,
  n = n + 0.
Proof.
  intros n. destruct n as [| n'].
  - (* n = 0 *)
    reflexivity. (* so far so good... *)
  - (* n = S n' *)
    simpl.       (* ...but here we are stuck again *)
Abort.

(** We could use [destruct n'] to get one step further, but,
    since [n] can be arbitrarily large, if we just go on like this
    we'll never finish. *)

(** To prove interesting facts about numbers, lists, and other
    inductively defined sets, we usually need a more powerful
    reasoning principle: _induction_.

    Recall (from high school, a discrete math course, etc.) the
    _principle of induction over natural numbers_: If [P(n)] is some
    proposition involving a natural number [n] and we want to show
    that [P] holds for all numbers [n], we can reason like this:
         - show that [P(O)] holds;
         - show that, for any [n'], if [P(n')] holds, then so does
           [P(S n')];
         - conclude that [P(n)] holds for all [n].

    In Coq, the steps are the same: we begin with the goal of proving
    [P(n)] for all [n] and break it down (by applying the [induction]
    tactic) into two separate subgoals: one where we must show [P(O)]
    and another where we must show [P(n') -> P(S n')].  Here's how
    this works for the theorem at hand: *)

Theorem plus_n_O : forall n:nat, n = n + 0.
Proof.
  intros n. induction n as [| n' IHn'].
  - (* n = 0 *)    reflexivity.
  - (* n = S n' *) simpl. rewrite <- IHn'. reflexivity.  Qed.

(** Like [destruct], the [induction] tactic takes an [as...]
    clause that specifies the names of the variables to be introduced
    in the subgoals.  Since there are two subgoals, the [as...] clause
    has two parts, separated by [|].  (Strictly speaking, we can omit
    the [as...] clause and Coq will choose names for us.  In practice,
    this is a bad idea, as Coq's automatic choices tend to be
    confusing.)

    In the first subgoal, [n] is replaced by [0].  No new variables
    are introduced (so the first part of the [as...] is empty), and
    the goal becomes [0 = 0 + 0], which follows by simplification.

    In the second subgoal, [n] is replaced by [S n'], and the
    assumption [n' + 0 = n'] is added to the context with the name
    [IHn'] (i.e., the Induction Hypothesis for [n']).  These two names
    are specified in the second part of the [as...] clause.  The goal
    in this case becomes [S n' = (S n') + 0], which simplifies to
    [S n' = S (n' + 0)], which in turn follows from [IHn']. *)

Theorem minus_diag : forall n,
  minus n n = 0.
Proof.
  (* WORKED IN CLASS *)
  intros n. induction n as [| n' IHn'].
  - (* n = 0 *)
    simpl. reflexivity.
  - (* n = S n' *)
    simpl. rewrite -> IHn'. reflexivity.  Qed.

(** (The use of the [intros] tactic in these proofs is actually
    redundant.  When applied to a goal that contains quantified
    variables, the [induction] tactic will automatically move them
    into the context as needed.) *)

(** **** Exercise: 2 stars, recommended (basic_induction)  *)
(** Prove the following using induction. You might need previously
    proven results. *)

Theorem mult_0_r : forall n:nat,
  n * 0 = 0.
Proof.
  intros n. induction n as [| n' IHn'].
  - (* n = 0 *)
    simpl. reflexivity.
  - (* n = S n' *)
    simpl. rewrite -> IHn'. reflexivity.  Qed.
(* GRADE_THEOREM 0.5: mult_0_r *)

Theorem plus_n_Sm : forall n m : nat,
  S (n + m) = n + (S m).
Proof.
  intros n m. induction n as [| n' IHn'].
  - (* n = 0 *)
    simpl. reflexivity.
  - (* n = S n' *)
    simpl. rewrite -> IHn'. reflexivity.  Qed.
(* GRADE_THEOREM 0.5: plus_n_Sm *)

Theorem plus_comm : forall n m : nat,
  n + m = m + n.
Proof.
  intros n m. induction n as [| n' IHn'].
  - (* n = 0 *)
    simpl. rewrite <- plus_n_O. reflexivity.
  - (* n = S n' *)
    simpl. rewrite -> IHn'. rewrite -> plus_n_Sm. reflexivity.  Qed.
(* GRADE_THEOREM 0.5: plus_comm *)

Theorem plus_assoc : forall n m p : nat,
  n + (m + p) = (n + m) + p.
Proof.
  intros. induction n as [| n' IHn'].
  - (* n = 0 *)
    simpl. reflexivity.
  - (* n = S n' *)
    simpl. rewrite -> IHn'. reflexivity.  Qed.

(* GRADE_THEOREM 0.5: plus_assoc *)
(** [] *)

(** **** Exercise: 2 stars (double_plus)  *)
(** Consider the following function, which doubles its argument: *)

Fixpoint double (n:nat) :=
  match n with
  | O => O
  | S n' => S (S (double n'))
  end.

(** Use induction to prove this simple fact about [double]: *)

Lemma double_plus : forall n, double n = n + n .
Proof.
  intros n. induction n as [| n' IHn'].
  - (* n = 0 *)
    simpl. reflexivity.
  - (* n = S n' *)
    simpl. rewrite -> IHn'. rewrite -> plus_n_Sm. reflexivity.  Qed.
(** [] *)

(** **** Exercise: 2 stars, optional (evenb_S)  *)
(** One inconvenient aspect of our definition of [evenb n] is the
    recursive call on [n - 2]. This makes proofs about [evenb n]
    harder when done by induction on [n], since we may need an
    induction hypothesis about [n - 2]. The following lemma gives an
    alternative characterization of [evenb (S n)] that works better
    with induction: *)
(* remove*)
Fixpoint evenb (n:nat) : bool :=
  match n with
  | O        => true
  | S O      => false
  | S (S n') => evenb n'
  end.

Theorem negb_involutive : forall b : bool,
  negb (negb b) = b.
Proof.
  intros b. destruct b.
  - reflexivity.
  - reflexivity.  Qed.

Theorem evenb_S : forall n : nat,
  evenb (S n) = negb (evenb n).
Proof.
  intros n. induction n as [| n' IHn'].
  - (* n = 0 *)
    simpl. reflexivity.
  - (* n = S n' *)
    rewrite -> IHn'. rewrite -> negb_involutive. simpl. reflexivity. Qed.
(** [] *)

(** **** Exercise: 1 star (destruct_induction)  *)
(** Briefly explain the difference between the tactics [destruct]
    and [induction].

(* FILL IN HERE *)
*)
(** [] *)

(* ################################################################# *)
(** * Proofs Within Proofs *)

(** In Coq, as in informal mathematics, large proofs are often
    broken into a sequence of theorems, with later proofs referring to
    earlier theorems.  But sometimes a proof will require some
    miscellaneous fact that is too trivial and of too little general
    interest to bother giving it its own top-level name.  In such
    cases, it is convenient to be able to simply state and prove the
    needed "sub-theorem" right at the point where it is used.  The
    [assert] tactic allows us to do this.  For example, our earlier
    proof of the [mult_0_plus] theorem referred to a previous theorem
    named [plus_O_n].  We could instead use [assert] to state and
    prove [plus_O_n] in-line: *)

Theorem mult_0_plus' : forall n m : nat,
  (0 + n) * m = n * m.
Proof.
  intros n m.
  assert (H: 0 + n = n). { reflexivity. }
  rewrite -> H.
  reflexivity.  Qed.

(** The [assert] tactic introduces two sub-goals.  The first is
    the assertion itself; by prefixing it with [H:] we name the
    assertion [H].  (We can also name the assertion with [as] just as
    we did above with [destruct] and [induction], i.e., [assert (0 + n
    = n) as H].)  Note that we surround the proof of this assertion
    with curly braces [{ ... }], both for readability and so that,
    when using Coq interactively, we can see more easily when we have
    finished this sub-proof.  The second goal is the same as the one
    at the point where we invoke [assert] except that, in the context,
    we now have the assumption [H] that [0 + n = n].  That is,
    [assert] generates one subgoal where we must prove the asserted
    fact and a second subgoal where we can use the asserted fact to
    make progress on whatever we were trying to prove in the first
    place. *)

(** Another example of [assert]... *)

(** For example, suppose we want to prove that [(n + m) + (p + q)
    = (m + n) + (p + q)]. The only difference between the two sides of
    the [=] is that the arguments [m] and [n] to the first inner [+]
    are swapped, so it seems we should be able to use the
    commutativity of addition ([plus_comm]) to rewrite one into the
    other.  However, the [rewrite] tactic is not very smart about
    _where_ it applies the rewrite.  There are three uses of [+] here,
    and it turns out that doing [rewrite -> plus_comm] will affect
    only the _outer_ one... *)

Theorem plus_rearrange_firsttry : forall n m p q : nat,
  (n + m) + (p + q) = (m + n) + (p + q).
Proof.
  intros n m p q.
  (* We just need to swap (n + m) for (m + n)... seems
     like plus_comm should do the trick! *)
  rewrite -> plus_comm.
  (* Doesn't work...Coq rewrote the wrong plus! *)
Abort.

(** To use [plus_comm] at the point where we need it, we can introduce
    a local lemma stating that [n + m = m + n] (for the particular [m]
    and [n] that we are talking about here), prove this lemma using
    [plus_comm], and then use it to do the desired rewrite. *)

Theorem plus_rearrange : forall n m p q : nat,
  (n + m) + (p + q) = (m + n) + (p + q).
Proof.
  intros n m p q.
  assert (H: n + m = m + n).
  { rewrite -> plus_comm. reflexivity. }
  rewrite -> H. reflexivity.  Qed.

(* ################################################################# *)
(** * Formal vs. Informal Proof *)

(** "_Informal proofs are algorithms; formal proofs are code_." *)

(** What constitutes a successful proof of a mathematical claim?
    The question has challenged philosophers for millennia, but a
    rough and ready definition could be this: A proof of a
    mathematical proposition [P] is a written (or spoken) text that
    instills in the reader or hearer the certainty that [P] is true --
    an unassailable argument for the truth of [P].  That is, a proof
    is an act of communication.

    Acts of communication may involve different sorts of readers.  On
    one hand, the "reader" can be a program like Coq, in which case
    the "belief" that is instilled is that [P] can be mechanically
    derived from a certain set of formal logical rules, and the proof
    is a recipe that guides the program in checking this fact.  Such
    recipes are _formal_ proofs.

    Alternatively, the reader can be a human being, in which case the
    proof will be written in English or some other natural language,
    and will thus necessarily be _informal_.  Here, the criteria for
    success are less clearly specified.  A "valid" proof is one that
    makes the reader believe [P].  But the same proof may be read by
    many different readers, some of whom may be convinced by a
    particular way of phrasing the argument, while others may not be.
    Some readers may be particularly pedantic, inexperienced, or just
    plain thick-headed; the only way to convince them will be to make
    the argument in painstaking detail.  But other readers, more
    familiar in the area, may find all this detail so overwhelming
    that they lose the overall thread; all they want is to be told the
    main ideas, since it is easier for them to fill in the details for
    themselves than to wade through a written presentation of them.
    Ultimately, there is no universal standard, because there is no
    single way of writing an informal proof that is guaranteed to
    convince every conceivable reader.

    In practice, however, mathematicians have developed a rich set of
    conventions and idioms for writing about complex mathematical
    objects that -- at least within a certain community -- make
    communication fairly reliable.  The conventions of this stylized
    form of communication give a fairly clear standard for judging
    proofs good or bad.

    Because we are using Coq in this course, we will be working
    heavily with formal proofs.  But this doesn't mean we can
    completely forget about informal ones!  Formal proofs are useful
    in many ways, but they are _not_ very efficient ways of
    communicating ideas between human beings. *)

(** For example, here is a proof that addition is associative: *)

Theorem plus_assoc' : forall n m p : nat,
  n + (m + p) = (n + m) + p.
Proof. intros n m p. induction n as [| n' IHn']. reflexivity.
  simpl. rewrite -> IHn'. reflexivity.  Qed.

(** Coq is perfectly happy with this.  For a human, however, it
    is difficult to make much sense of it.  We can use comments and
    bullets to show the structure a little more clearly... *)

Theorem plus_assoc'' : forall n m p : nat,
  n + (m + p) = (n + m) + p.
Proof.
  intros n m p. induction n as [| n' IHn'].
  - (* n = 0 *)
    reflexivity.
  - (* n = S n' *)
    simpl. rewrite -> IHn'. reflexivity.   Qed.

(** ... and if you're used to Coq you may be able to step
    through the tactics one after the other in your mind and imagine
    the state of the context and goal stack at each point, but if the
    proof were even a little bit more complicated this would be next
    to impossible.

    A (pedantic) mathematician might write the proof something like
    this: *)

(** - _Theorem_: For any [n], [m] and [p],

      n + (m + p) = (n + m) + p.

    _Proof_: By induction on [n].

    - First, suppose [n = 0].  We must show

        0 + (m + p) = (0 + m) + p.

      This follows directly from the definition of [+].

    - Next, suppose [n = S n'], where

        n' + (m + p) = (n' + m) + p.

      We must show

        (S n') + (m + p) = ((S n') + m) + p.

      By the definition of [+], this follows from

        S (n' + (m + p)) = S ((n' + m) + p),

      which is immediate from the induction hypothesis.  _Qed_. *)

(** The overall form of the proof is basically similar, and of
    course this is no accident: Coq has been designed so that its
    [induction] tactic generates the same sub-goals, in the same
    order, as the bullet points that a mathematician would write.  But
    there are significant differences of detail: the formal proof is
    much more explicit in some ways (e.g., the use of [reflexivity])
    but much less explicit in others (in particular, the "proof state"
    at any given point in the Coq proof is completely implicit,
    whereas the informal proof reminds the reader several times where
    things stand). *)

(** **** Exercise: 2 stars, advanced, recommended (plus_comm_informal)  *)
(** Translate your solution for [plus_comm] into an informal proof:

    Theorem: Addition is commutative.

    Proof: (* FILL IN HERE *)
*)
(** [] *)

(** **** Exercise: 2 stars, optional (beq_nat_refl_informal)  *)
(** Write an informal proof of the following theorem, using the
    informal proof of [plus_assoc] as a model.  Don't just
    paraphrase the Coq tactics into English!

    Theorem: [true = beq_nat n n] for any [n].

    Proof: (* FILL IN HERE *)
*)
(** [] *)

(* ################################################################# *)
(** * More Exercises *)

(** **** Exercise: 3 stars, recommended (mult_comm)  *)
(** Use [assert] to help prove this theorem.  You shouldn't need to
    use induction on [plus_swap]. *)

Theorem plus_swap : forall n m p : nat,
  n + (m + p) = m + (n + p).
Proof.
  intros.
  rewrite plus_comm.
  rewrite <- plus_assoc.
  assert (p + n = n + p).
  { rewrite <- plus_comm. reflexivity. }
  rewrite <- H. simpl.  reflexivity. Qed.

(** Now prove commutativity of multiplication.  (You will probably
    need to define and prove a separate subsidiary theorem to be used
    in the proof of this one.  You may find that [plus_swap] comes in
    handy.) *)

Theorem mult_plus : forall m n : nat,
  n * S m = n + n * m.
Proof.
  intros. induction n as [| n'].
  - reflexivity.
  - simpl. rewrite IHn'. rewrite plus_swap. reflexivity.  Qed.

Theorem mult_comm : forall m n : nat,
  m * n = n * m.
Proof.
  intros. induction n as [| n'].
   - rewrite mult_0_r. reflexivity.
   - simpl. rewrite <- IHn'. rewrite mult_plus. reflexivity.
Qed.

(*
Theorem mult_comm : forall m n : nat,
  m * n = n * m.
Proof.
  intros m n.
  assert(H1: m * S n = m + (m * n) ).
  { intros. induction m as [| m' H2m'].
    - reflexivity.
    - simpl. rewrite -> H2m'. rewrite -> plus_swap. reflexivity. }
  induction n as [| n'].
    - rewrite -> mult_0_r. simpl. reflexivity.
    - simpl. rewrite <- IHn'. rewrite H1. reflexivity. Qed.
  (* FILL IN HERE *) Admitted.
(** [] *)
*)
(** **** Exercise: 3 stars, optional (more_exercises)  *)
(** Take a piece of paper.  For each of the following theorems, first
    _think_ about whether (a) it can be proved using only
    simplification and rewriting, (b) it also requires case
    analysis ([destruct]), or (c) it also requires induction.  Write
    down your prediction.  Then fill in the proof.  (There is no need
    to turn in your piece of paper; this is just to encourage you to
    reflect before you hack!) *)

Fixpoint leb (n m : nat) : bool :=
  match n with
  | O => true
  | S n' =>
      match m with
      | O => false
      | S m' => leb n' m'
      end
  end.

Check leb.

Theorem leb_refl : forall n:nat,
  true = leb n n.
Proof.
  intros. induction n as [| n'].
  - simpl. reflexivity.
  - simpl. rewrite IHn'. reflexivity.  Qed.

Fixpoint beq_nat (n m : nat) : bool :=
  match n with
  | O => match m with
         | O => true
         | S m' => false
         end
  | S n' => match m with
            | O => false
            | S m' => beq_nat n' m'
            end
  end.

Theorem zero_nbeq_S : forall n:nat,
  beq_nat 0 (S n) = false.
Proof.
 intros. induction n as [| n'].
  - simpl. reflexivity.
  - simpl. reflexivity.  Qed.

Definition andb (b1:bool) (b2:bool) : bool :=
  match b1 with
  | true => b2
  | false => false
  end.

Theorem andb_false_r : forall b : bool,
  andb b false = false.
Proof.
intros. destruct b.
  - simpl. reflexivity.
  - simpl. reflexivity.  Qed.

Theorem plus_ble_compat_l : forall n m p : nat,
  leb n m = true -> leb (p + n) (p + m) = true.
Proof.
intros. induction p as [| p'].
  - simpl. rewrite H. reflexivity.
  - simpl. rewrite IHp'. reflexivity.  Qed.

Theorem S_nbeq_0 : forall n:nat,
  beq_nat (S n) 0 = false.
Proof.
intros. induction n as [| n'].
  - simpl. reflexivity.
  - simpl.  reflexivity. Qed.

Theorem mult_1_l : forall n:nat, 1 * n = n.
Proof.
intros. induction n as [| n'].
  - simpl. reflexivity.
  - simpl. rewrite <- plus_n_O.  reflexivity. Qed.

Theorem all3_spec : forall b c : bool,
    orb
      (andb b c)
      (orb (negb b)
               (negb c))
  = true.
Proof.
intros. destruct b.
  - simpl. destruct c.
      + simpl. reflexivity.
      + simpl. reflexivity.
  - simpl. destruct c.
      + simpl. reflexivity.
      + simpl. reflexivity.
Qed.

Theorem mult_plus_distr_r : forall n m p : nat,
  (n + m) * p = (n * p) + (m * p).
Proof.
intros. induction n as [| n'].
  - simpl. reflexivity.
  - simpl. rewrite IHn'. rewrite plus_assoc. reflexivity.  Qed.

Theorem mult_assoc : forall n m p : nat,
  n * (m * p) = (n * m) * p.
Proof.
intros. induction n as [| n'].
  - simpl. reflexivity.
  - simpl. rewrite IHn'. rewrite mult_plus_distr_r. reflexivity.  Qed.
(** [] *)

(** **** Exercise: 2 stars, optional (beq_nat_refl)  *)
(** Prove the following theorem.  (Putting the [true] on the left-hand
    side of the equality may look odd, but this is how the theorem is
    stated in the Coq standard library, so we follow suit.  Rewriting
    works equally well in either direction, so we will have no problem
    using the theorem no matter which way we state it.) *)

Theorem beq_nat_refl : forall n : nat,
  true = beq_nat n n.
Proof.
intros. induction n as [| n'].
  - simpl. reflexivity.
  - simpl. rewrite IHn'. reflexivity.  Qed.
(** [] *)

(** **** Exercise: 2 stars, optional (plus_swap')  *)
(** The [replace] tactic allows you to specify a particular subterm to
   rewrite and what you want it rewritten to: [replace (t) with (u)]
   replaces (all copies of) expression [t] in the goal by expression
   [u], and generates [t = u] as an additional subgoal. This is often
   useful when a plain [rewrite] acts on the wrong part of the goal.

   Use the [replace] tactic to do a proof of [plus_swap'], just like
   [plus_swap] but without needing [assert (n + m = m + n)]. *)

Theorem plus_swap' : forall n m p : nat,
  n + (m + p) = m + (n + p).
Proof.
intros. induction n as [| n'].
  - simpl. reflexivity.
  - simpl. rewrite IHn'. rewrite plus_n_Sm. reflexivity.  Qed.
(** [] *)

(** **** Exercise: 3 stars, recommended (binary_commute)  *)
(** Recall the [incr] and [bin_to_nat] functions that you
    wrote for the [binary] exercise in the [Basics] chapter.  Prove
    that the following diagram commutes:

                            incr
              bin ----------------------> bin
               |                           |
    bin_to_nat |                           |  bin_to_nat
               |                           |
               v                           v
              nat ----------------------> nat
                             S

    That is, incrementing a binary number and then converting it to
    a (unary) natural number yields the same result as first converting
    it to a natural number and then incrementing.
    Name your theorem [bin_to_nat_pres_incr] ("pres" for "preserves").

    Before you start working on this exercise, copy the definitions
    from your solution to the [binary] exercise here so that this file
    can be graded on its own.  If you want to change your original
    definitions to make the property easier to prove, feel free to
    do so! *)

(* FILL IN HERE *)
(** [] *)

(** **** Exercise: 5 stars, advanced (binary_inverse)  *)
(** This exercise is a continuation of the previous exercise about
    binary numbers.  You will need your definitions and theorems from
    there to complete this one; please copy them to this file to make
    it self contained for grading.

    (a) First, write a function to convert natural numbers to binary
        numbers.  Then prove that starting with any natural number,
        converting to binary, then converting back yields the same
        natural number you started with.

    (b) You might naturally think that we should also prove the
        opposite direction: that starting with a binary number,
        converting to a natural, and then back to binary yields the
        same number we started with.  However, this is not true!
        Explain what the problem is.

    (c) Define a "direct" normalization function -- i.e., a function
        [normalize] from binary numbers to binary numbers such that,
        for any binary number b, converting to a natural and then back
        to binary yields [(normalize b)].  Prove it.  (Warning: This
        part is tricky!)

    Again, feel free to change your earlier definitions if this helps
    here. *)

(* FILL IN HERE *)
(** [] *)

author: dandougherty


text:
Require Import Setoid.

(* Natural Numbers *)

Reserved Notation "x =? y" (at level 70).

Fixpoint eqb (n m : nat) : bool :=
  match n, m with
  | O, O => true
  | S n', S m' => n' =? m'
  | _, _ => false
  end
where "n =? m" := (eqb n m) : nat_scope.

Lemma eq_S : forall n m, n = m <-> S n = S m.
Proof.
  split.
  - intros. rewrite H. reflexivity.
  - intros. injection H as H. apply H. Qed.

Lemma eqb_refl : forall n, n =? n = true.
Proof.
  induction n as [| n' IH].
  - reflexivity.
  - simpl. apply IH. Qed.

Theorem eqb_eq : forall n m, n =? m = true <-> n = m.
Proof.
  split.
  - generalize dependent m. induction n as [| n' IH].
    + intros m H. destruct m as [| m'].
      * reflexivity.
      * discriminate H.
    + intros m H. destruct m as [| m'].
      * discriminate H.
      * rewrite <- eq_S. simpl in H. apply (IH m' H).
  - intro H. rewrite H. apply eqb_refl. Qed.

Theorem eq_cancel : forall n x y, n + x = n + y <-> x = y.
Proof.
  split.
  - generalize dependent x. generalize dependent y.
    induction n as [| n' IH].
    + intros. apply H.
    + intros. inversion H. apply (IH _ _ H1).
  - intros. rewrite H. reflexivity. Qed.

Fixpoint double (n : nat) : nat :=
  match n with
  | O => 0
  | S n' => S (S (double n'))
  end.

Lemma n_plus_Sm_Sn_plus_m : forall n m, n + S m = S (n + m).
Proof.
  induction n as [| n' IH].
  - intro m. reflexivity.
  - intro m. simpl. rewrite IH. reflexivity. Qed.

Theorem double_destruct : forall n, double n = n + n.
Proof.
  induction n as [| n' IH].
  - reflexivity.
  - simpl. rewrite n_plus_Sm_Sn_plus_m.
    rewrite IH. reflexivity. Qed.

Theorem plus_assoc : forall n m o, n + (m + o) = n + m + o.
Proof.
  induction n as [| n' IH].
  - reflexivity.
  - intros. assert (H: S n' + (m + o) =  S (n' + (m + o))).
    { reflexivity. } rewrite H. rewrite IH. reflexivity. Qed.

Lemma plus_0 : forall n, n + 0 = n.
Proof.
  induction n as [| n' IH].
  - reflexivity.
  - replace (S n' + 0) with (S (n' + 0)).
    rewrite IH. reflexivity.
    + reflexivity. Qed.

Theorem plus_comm : forall n m, n + m = m + n.
Proof.
  induction n as [| n' IH].
  - intros. rewrite plus_0. reflexivity.
  - intros. rewrite n_plus_Sm_Sn_plus_m.
    rewrite <- IH. reflexivity. Qed.

(* Binary Trees and Lengths *)

Inductive btree (X : Type) : Type :=
| bt_nil
| bt_node (l : btree X) (x : X) (r : btree X).

Arguments bt_nil {X}.
Arguments bt_node {X}.

Notation "{ }" := bt_nil.
Notation "{ l , x , r }" := (bt_node l x r).

Fixpoint internal_length {X} (t : btree X) (h : nat) : nat :=
  match t with
  | {} => 0
  | {l,x,r} => h + (internal_length l (S h)) +
              (internal_length r (S h))
  end.

Fixpoint external_length {X} (t : btree X) (h : nat) : nat :=
  match t with
  | {} => h
  | {l,x,r} => (external_length l (S h)) +
              (external_length r (S h))
  end.

Fixpoint non_leaf_count {X} (t : btree X) : nat :=
  match t with
  | {} => 0
  | {l,x,r} => 1 + (non_leaf_count l) +
              (non_leaf_count r)
  end.

Example test_internal_length1 : internal_length {{},3,{}} 0 = 0.
Proof. reflexivity. Qed.

Example test_external_length1 : external_length {{},3,{}} 0 = 2.
Proof. reflexivity. Qed.

Example test_non_leaf_count1 : non_leaf_count {{},3,{}} = 1.
Proof. reflexivity. Qed.

Example test_internal_length2 :
  internal_length {{{},2,{}},1,{{{},4,{}},3,{}}} 0 = 4.
Proof. reflexivity. Qed.

Example test_external_length2 :
  external_length {{{},2,{}},1,{{{},4,{}},3,{}}} 0 = 12.
Proof. reflexivity. Qed.

Example test_non_leaf_count2 :
  non_leaf_count {{{},2,{}},1,{{{},4,{}},3,{}}} = 4.
Proof. reflexivity. Qed.

(* Lemmas and the Theorem *)

Lemma internal_length_S : forall n X (t : btree X),
    internal_length t n + non_leaf_count t =
    internal_length t (S n).
Proof.
  intros. generalize dependent n.
  induction t as [| l IHl x r IHr].
  - reflexivity.
  - simpl. intro n. rewrite <- plus_assoc. rewrite n_plus_Sm_Sn_plus_m.
    rewrite n_plus_Sm_Sn_plus_m. rewrite <- eq_S. rewrite <- plus_assoc.
    rewrite <- plus_assoc. rewrite eq_cancel. rewrite plus_assoc.
    rewrite plus_assoc.
    replace (internal_length l (S n) + internal_length r (S n) +
             non_leaf_count l + non_leaf_count r) with
        (internal_length l (S n) + non_leaf_count l +
         (internal_length r (S n) + non_leaf_count r)).
    rewrite IHl. rewrite IHr. reflexivity.
    + rewrite plus_assoc.
      replace (internal_length l (S n) + non_leaf_count l +
               internal_length r (S n) + non_leaf_count r) with
          (internal_length l (S n) +
           (non_leaf_count l + internal_length r (S n)) +
           non_leaf_count r).
      rewrite (plus_comm (non_leaf_count l) (internal_length r (S n))).
      rewrite plus_assoc. reflexivity.
      * rewrite plus_assoc. reflexivity. Qed.

Lemma external_length_S : forall n X (t : btree X),
    1 + external_length t n + non_leaf_count t =
    external_length t (S n).
Proof.
  intros. generalize dependent n.
  induction t as [| l IHl x r IHr].
  - intros. rewrite plus_0. reflexivity.
  - intros. simpl in *.
    replace (S (external_length l (S n) + external_length r (S n) +
                S (non_leaf_count l + non_leaf_count r))) with
        (S (external_length l (S n) + non_leaf_count l) +
         S (external_length r (S n) + non_leaf_count r)).
    rewrite IHl. rewrite IHr. reflexivity.
    + simpl. rewrite <- eq_S. rewrite n_plus_Sm_Sn_plus_m.
      rewrite n_plus_Sm_Sn_plus_m. rewrite <- eq_S.
      rewrite <- plus_assoc.
      rewrite (plus_assoc (non_leaf_count l)
                          (external_length r (S n))
                          (non_leaf_count r)).
      rewrite (plus_comm (non_leaf_count l)
                         (external_length r (S n))).
      rewrite plus_assoc. rewrite plus_assoc.
      rewrite plus_assoc. reflexivity. Qed.

(* Too many `rewrite`-s! Can't Coq resolve equalities automatically? *)
Theorem the_theorem : forall X (t : btree X),
    external_length t 0 = internal_length t 0 + double (non_leaf_count t).
Proof.
  induction t as [| l IHl x r IHr].
  - reflexivity.
  - simpl.
    rewrite double_destruct in IHl. rewrite plus_assoc in IHl.
    rewrite (internal_length_S 0) in IHl.
    rewrite double_destruct in IHr. rewrite plus_assoc in IHr.
    rewrite (internal_length_S 0) in IHr.
    replace (internal_length l 1 + internal_length r 1 +
             S (S (double (non_leaf_count l + non_leaf_count r)))) with
        (1 + (internal_length l 1 + non_leaf_count l) + non_leaf_count l +
         (1 + (internal_length r 1 + non_leaf_count r) + non_leaf_count r)).
    rewrite <- IHl. rewrite <- IHr. rewrite (external_length_S 0).
    rewrite (external_length_S 0). reflexivity.
    + simpl. rewrite n_plus_Sm_Sn_plus_m. rewrite n_plus_Sm_Sn_plus_m.
      rewrite n_plus_Sm_Sn_plus_m. rewrite <- eq_S. rewrite <- eq_S.
      rewrite double_destruct. rewrite plus_assoc. rewrite plus_assoc.
      rewrite plus_assoc. rewrite plus_assoc. rewrite plus_assoc.
      assert (H: non_leaf_count l + non_leaf_count l +
                 internal_length r 1 + non_leaf_count r =
                 internal_length r 1 + non_leaf_count l +
                 non_leaf_count r + non_leaf_count l).
      { rewrite <- (plus_assoc (non_leaf_count l)
                              (non_leaf_count l)
                              (internal_length r 1)).
        rewrite (plus_comm (non_leaf_count l) (internal_length r 1)).
        rewrite plus_assoc. rewrite (plus_comm (non_leaf_count l)
                                               (internal_length r 1)).
        rewrite <- (plus_assoc (internal_length r 1 + non_leaf_count l)
                              (non_leaf_count l)
                              (non_leaf_count r)).
        rewrite (plus_comm (non_leaf_count l) (non_leaf_count r)).
        rewrite plus_assoc. reflexivity. }
      assert (H1: internal_length l 1 + non_leaf_count l +
                  non_leaf_count l + internal_length r 1 +
                  non_leaf_count r + non_leaf_count r =
                  internal_length l 1 +
                  (non_leaf_count l +
                   non_leaf_count l + internal_length r 1 +
                   non_leaf_count r) + non_leaf_count r).
      { rewrite plus_assoc. rewrite plus_assoc.
        rewrite plus_assoc. reflexivity. }
      rewrite H1. rewrite H. rewrite plus_assoc. rewrite plus_assoc.
      rewrite plus_assoc. reflexivity. Qed.

Print Assumptions the_theorem.

(* UNUSED Definitions and Lemmas *)

Inductive list (X : Type) : Type :=
| nil
| cons (x : X) (l : list X).

Arguments nil {X}.
Arguments cons {X}.

Notation "[ ]" := nil.
Notation "x :: y" := (cons x y) (at level 60, right associativity).
Notation "[ x ; .. ; y ]" := (cons x .. (cons y []) ..).
Notation "x ++ y" := (app x y) (at level 60, right associativity).

Fixpoint length {X} (l : list X) : nat :=
  match l with
  | nil => O
  | _ :: l' => S (length l')
  end.

Inductive reflect (P : Prop) : bool -> Prop :=
| ReflectT : P -> reflect P true
| ReflectF : ~ P -> reflect P false.

Theorem iff_reflect : forall P b, (P <-> b = true) -> reflect P b.
Proof.
  intros P b H. destruct b eqn:Eb.
  - apply ReflectT. rewrite H. reflexivity.
  - apply ReflectF. rewrite H. discriminate. Qed.

Inductive dir : Type :=
| Left
| Right.

(* Say a list of directions "proper," if a leaf node
   is just reached by following the list. *)
Fixpoint ld_proper {X} (t : btree X) (ld : list dir) : bool :=
  match t, ld with
  | {}, [] => true
  | {l,x,r}, h :: ld' =>
    match h with
    | Left => ld_proper l ld'
    | Right => ld_proper r ld'
    end
  | _, _ => false
  end.

Fixpoint extend_leaf {X} (t : btree X) (ld : list dir) (x' : X) : btree X :=
  match t with
  | {} => {{},x',{}}
  | {l,x,r} =>
    match ld with
    | [] => {l,x,r}  (* avoid extending non-leaf nodes *)
    | h :: ld' =>
      match h with
      | Left => {extend_leaf l ld' x',x,r}
      | Right => {l,x,extend_leaf r ld' x'}
      end
    end
  end.

Example test_extend_leaf1 :
  extend_leaf {} [] 1 = {{},1,{}}.
Proof. reflexivity. Qed.

Example test_extend_leaf2 :
  extend_leaf {{{},2,{}},1,{{},3,{}}} [Right; Left] 4 =
  {{{},2,{}},1,{{{},4,{}},3,{}}}.
Proof. reflexivity. Qed.

Example test_extend_leaf3 :
  extend_leaf {{{},2,{}},1,{{},3,{}}} [Right; Left; Right] 4 =
  {{{},2,{}},1,{{{},4,{}},3,{}}}.
Proof. reflexivity. Qed.

Example test_extend_leaf4 :
  extend_leaf {{{},2,{}},1,{{},3,{}}} [Right] 4 =
  {{{},2,{}},1,{{},3,{}}}.
Proof. reflexivity. Qed.

Definition leaf_eqb {X} (t : btree X) : bool :=
  external_length t 0 =? 0.

Lemma leaf_eqb_eq : forall X (t : btree X),
    t = {} <-> leaf_eqb t = true.
Proof.
  split.
  - intro H. rewrite H. reflexivity.
  - unfold leaf_eqb. intro H. apply eqb_eq in H.
    induction t as [| l IHl x r IHr].
    + reflexivity.
    + simpl in H. rewrite <- external_length_S in H.
      discriminate H. Qed.

Theorem leaf_eqP : forall X (t : btree X),
    reflect (t = {}) (leaf_eqb t).
Proof.
  intros. apply iff_reflect. apply leaf_eqb_eq. Qed.

Lemma non_leaf_is_properly_extended : forall X (t : btree X),
    ~ (t = {}) ->
    exists t' ld x', ld_proper t' ld = true /\ t = extend_leaf t' ld x'.
Proof.
  induction t as [| l IHl x r IHr].
  - intros contra. exfalso. apply contra. reflexivity.
  - intros _. destruct (leaf_eqP _ l).
    + destruct (leaf_eqP _ r).
      * exists {}. exists []. exists x. simpl. rewrite H. rewrite H0.
        split; reflexivity.
      * apply IHr in H0. destruct H0 as [t' [ld [x' H0]]].
        exists {l,x,t'}. exists (Right :: ld). exists x'.
        simpl. destruct H0 as [H0 H1]. rewrite H0. rewrite H1.
        split; reflexivity.
    + apply IHl in H. destruct H as [t' [ld [x' H]]].
      exists {t',x,r}. exists (Left :: ld). exists x'.
      simpl. destruct H as [H0 H1]. rewrite H0. rewrite H1.
      split; reflexivity. Qed.

author: duinomaker

repo: LearningStuff


text:
(*
  Autor(s):
    Andrej Dudenhefner (1)
  Affiliation(s):
    (1) Saarland University, Saarbrücken, Germany
*)

(*
  Reduction from:
    Right-uniform Two-inequality Semi-unification (RU2SemiU)
  to:
    Left-uniform Two-inequality Semi-unification (LU2SemiU)
*)

Require Import List.

Require Import Undecidability.SemiUnification.SemiU.
From Undecidability.SemiUnification.Util Require Import Enumerable.

Require Import ssreflect ssrfun ssrbool.

Set Default Proof Using "Type".
Set Default Goal Selector "!".

Module Argument.
Definition embed_var (x: nat) := atom (to_nat (x, 0)).

(* two fresh variables *)
Definition z (b: bool) := atom (to_nat (0, if b then 2 else 1)).

Section RU2SemiU_LU2SemiU.
  Variables s0 s1 t: term. (* RU2SemiU instance *)

  (* LU2SemiU instance *)
  Definition s' := substitute embed_var (arr s0 s1).
  Definition t0' := arr (substitute embed_var t) (z false).
  Definition t1' := arr (z true) (substitute embed_var t).

  Section Transport.
    Variables φ ψ0 ψ1 : valuation.
    Variable Hψ0 : substitute ψ0 (substitute φ s0) = substitute φ t.
    Variable Hψ1 : substitute ψ1 (substitute φ s1) = substitute φ t.

    (* LU2SemiU valuation φ from RU2SemiU valuation φ' *)
    Definition φ' : valuation := fun x =>
      match of_nat x with
      | (x, 0) => substitute embed_var (φ x)
      | (0, 1) => substitute embed_var (substitute ψ0 (substitute φ s1))
      | (0, 2) => substitute embed_var (substitute ψ1 (substitute φ s0))
      | _ => atom x
      end.

    (* LU2SemiU valuations ψ from RU2SemiU valuations *)
    Definition ψ0' : valuation := fun x =>
      match of_nat x with
      | (x, 0) => substitute embed_var (ψ0 x)
      | _ => atom x
      end.

    Definition ψ1' : valuation := fun x =>
      match of_nat x with
      | (x, 0) => substitute embed_var (ψ1 x)
      | _ => atom x
      end.

    Lemma substitute_φ'P {r: term} :
      substitute φ' (substitute embed_var r) = substitute embed_var (substitute φ r).
    Proof. elim: r => [[| ?] | *] /=; [by rewrite /φ' ?enumP | by rewrite /φ' ?enumP | by f_equal]. Qed.

    Lemma substitute_ψ0'P {r: term} :
      substitute ψ0' (substitute embed_var r) = substitute embed_var (substitute ψ0 r).
    Proof. elim: r => [[| ?] | *] /=; [by rewrite /ψ0' ?enumP | by rewrite /ψ0' ?enumP | by f_equal]. Qed.

    Lemma substitute_ψ1'P {r: term} :
      substitute ψ1' (substitute embed_var r) = substitute embed_var (substitute ψ1 r).
    Proof. elim: r => [[| ?] | *] /=; [by rewrite /ψ1' ?enumP | by rewrite /ψ1' ?enumP | by f_equal]. Qed.

    (* if the given right-uniform semi-unification instance is solvable,
      then so is the constructed left-uniform semi-unification instance *)
    Lemma transport : LU2SemiU (s', t0', t1').
    Proof using φ ψ0 ψ1 Hψ0 Hψ1.
      exists φ', ψ0', ψ1'. constructor.
      - rewrite /s' /t0' /=. congr arr; rewrite ?substitute_φ'P substitute_ψ0'P ?/φ' ?enumP; by congruence.
      - rewrite /s' /t1' /=. congr arr; rewrite ?substitute_φ'P substitute_ψ1'P ?/φ' ?enumP; by congruence.
    Qed.
  End Transport.

  Section Reflection.
    Variables φ' ψ0' ψ1' : valuation.
    Variable Hψ0' : substitute ψ0' (substitute φ' s') = substitute φ' t0'.
    Variable Hψ1' : substitute ψ1' (substitute φ' s') = substitute φ' t1'.

    Lemma substitute_embed_var {ξ r} :
      substitute (fun x => ξ (to_nat (x, 0))) r = substitute ξ (substitute embed_var r).
    Proof.
      elim: r; [done | by move=> /=; congruence].
    Qed.

    (* if the constructed left-uniform semi-unification instance is solvable,
      then so is given right-uniform semi-unification instance *)
    Lemma reflection : RU2SemiU (s0, s1, t).
    Proof using φ' ψ0' ψ1' Hψ0' Hψ1'.
      exists (fun x => φ' (to_nat (x, 0))), ψ0', ψ1'. move: Hψ0' Hψ1'.
      rewrite ?(substitute_embed_var (ξ := φ')) /s' /t0' /t1' /=.
      move=> ? ?. constructor; by congruence.
    Qed.

  End Reflection.
End RU2SemiU_LU2SemiU.
End Argument.

Require Import Undecidability.Synthetic.Definitions.

(* many-one reduction from right-uniform two-inequality semi-unification
  to left-uniform two-inequality semi-unification *)
Theorem reduction : RU2SemiU ⪯ LU2SemiU.
Proof.
  exists (fun '(s0, s1, t) => (Argument.s' s0 s1, Argument.t0' t, Argument.t1' t)).
  move=> [[? ?] ?]. constructor.
  - move=> [?] [?] [?] [? ?]. apply: Argument.transport; by eassumption.
  - move=> [?] [?] [?] [? ?]. apply: Argument.reflection; by eassumption.
Qed.

author: uds-psl

repo: coq-synthetic-incompleteness


text:
From Test Require Import tactic.

Section FOFProblem.

Variable Universe : Set.
Variable UniverseElement : Universe.

Variable p_ : Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Universe -> Prop.
Variable goal_ : Prop.
Variable dom_ : Universe -> Prop.

Variable a9_ : Universe.
Variable a8_ : Universe.
Variable a7_ : Universe.
Variable a6_ : Universe.
Variable a5_ : Universe.
Variable a4_ : Universe.
Variable a34_ : Universe.
Variable a33_ : Universe.
Variable a32_ : Universe.
Variable a31_ : Universe.
Variable a30_ : Universe.
Variable a3_ : Universe.
Variable a29_ : Universe.
Variable a28_ : Universe.
Variable a27_ : Universe.
Variable a26_ : Universe.
Variable a25_ : Universe.
Variable a24_ : Universe.
Variable a23_ : Universe.
Variable a22_ : Universe.
Variable a21_ : Universe.
Variable a20_ : Universe.
Variable a2_ : Universe.
Variable a19_ : Universe.
Variable a18_ : Universe.
Variable a17_ : Universe.
Variable a16_ : Universe.
Variable a15_ : Universe.
Variable a14_ : Universe.
Variable a13_ : Universe.
Variable a12_ : Universe.
Variable a11_ : Universe.
Variable a10_ : Universe.
Variable a1_ : Universe.

Variable ax1_1 : (dom_ a1_ /\ (dom_ a2_ /\ (dom_ a3_ /\ (dom_ a4_ /\ (dom_ a5_ /\ (dom_ a6_ /\ (dom_ a7_ /\ (dom_ a8_ /\ (dom_ a9_ /\ (dom_ a10_ /\ (dom_ a11_ /\ (dom_ a12_ /\ (dom_ a13_ /\ (dom_ a14_ /\ (dom_ a15_ /\ (dom_ a16_ /\ (dom_ a17_ /\ (dom_ a18_ /\ (dom_ a19_ /\ (dom_ a20_ /\ (dom_ a21_ /\ (dom_ a22_ /\ (dom_ a23_ /\ (dom_ a24_ /\ (dom_ a25_ /\ (dom_ a26_ /\ (dom_ a27_ /\ (dom_ a28_ /\ (dom_ a29_ /\ (dom_ a30_ /\ (dom_ a31_ /\ (dom_ a32_ /\ (dom_ a33_ /\ dom_ a34_))))))))))))))))))))))))))))))))).
Variable ax2_2 : (forall A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 A16 A17 A18 A19 A20 A21 A22 A23 A24 A25 A26 A27 A28 A29 A30 A31 A32 A33 A34 : Universe, ((dom_ A1 /\ (dom_ A2 /\ (dom_ A3 /\ (dom_ A4 /\ (dom_ A5 /\ (dom_ A6 /\ (dom_ A7 /\ (dom_ A8 /\ (dom_ A9 /\ (dom_ A10 /\ (dom_ A11 /\ (dom_ A12 /\ (dom_ A13 /\ (dom_ A14 /\ (dom_ A15 /\ (dom_ A16 /\ (dom_ A17 /\ (dom_ A18 /\ (dom_ A19 /\ (dom_ A20 /\ (dom_ A21 /\ (dom_ A22 /\ (dom_ A23 /\ (dom_ A24 /\ (dom_ A25 /\ (dom_ A26 /\ (dom_ A27 /\ (dom_ A28 /\ (dom_ A29 /\ (dom_ A30 /\ (dom_ A31 /\ (dom_ A32 /\ (dom_ A33 /\ dom_ A34))))))))))))))))))))))))))))))))) -> p_ A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 A16 A17 A18 A19 A20 A21 A22 A23 A24 A25 A26 A27 A28 A29 A30 A31 A32 A33 A34)).
Variable ax3_3 : (p_ a34_ a33_ a32_ a31_ a30_ a29_ a28_ a27_ a26_ a25_ a24_ a23_ a22_ a21_ a20_ a19_ a18_ a17_ a16_ a15_ a14_ a13_ a12_ a11_ a10_ a9_ a8_ a7_ a6_ a5_ a4_ a3_ a2_ a1_ -> goal_).

Theorem lemma34_4 : goal_.
Proof.
  time tac.
Qed.

End FOFProblem.

author: janicicpredrag

repo: Larus

save_path: github-repos/coq/janicicpredrag-Larus


text:
Require Import Relation_Definitions.
Require Import Coq.Setoids.Setoid.

(**
  The only worthwhile instances of typeclasses are lawful ones. Therefore, this
  library packages the interfaces together with proofs that the laws hold.
  However, some laws include assertions of function equality (think `fmap id =
  id`), which is not a native concept to Coq. Therefore, we use a Setoid which
  encodes extensional equality and allows us to use the setoid rewriting tactics
  when proving it.
 *)

Section ExtensionalEquality.
  Variable A B : Type.

  Definition extensional_equality (f g : A -> B) : Prop := forall a : A, f a = g a.

  (* do we need a class? *)
  (* Class ExtensionallyEqual (f g : A -> B) : Prop := *)
  (*   { extensionally_equal : extensional_equality f g; }. *)

  (* This was the common component of all three proofs *)
  Ltac dnry x := unfold x; intros; unfold extensional_equality in *; intros.

  Lemma extensional_equality_refl : reflexive _ extensional_equality.
    dnry reflexive.
    trivial.
  Qed.

  Lemma extensional_equality_sym: symmetric _ extensional_equality.
    dnry symmetric.
    apply eq_sym.
    apply (H a).
  Qed.

  Lemma extensional_equality_trans: transitive _ extensional_equality.
    dnry transitive.
    rewrite (H a).
    apply (H0 a).
  Qed.

  Add Parametric Relation : (A -> B) extensional_equality
  reflexivity proved by extensional_equality_refl
  symmetry proved by extensional_equality_sym
  transitivity proved by extensional_equality_trans
  as extensional_equality_rel.

End ExtensionalEquality.

(**
 Since composition is the most common operation on functions, we also provide a
 proof that it is proper with respect to extensional equality as defined above
 as a Lemma.
 *)

Require Import MathClasses.interfaces.canonical_names.

Section Composition.
  Variable A B C : Type.
  Lemma composition_proper : Proper ((@extensional_equality B C) ==> (@extensional_equality A B) ==> (@extensional_equality A C)) (∘).
    compute.
    intros.
    rewrite (H0 a).
    now rewrite (H (y0 a)).
  Qed.
End Composition.

author: langston-barrett

repo: coq-typeclass-hierarchy


text:
Require Export A007logic.

Definition relation (X: Type) := X->X->Prop.

Definition partial_function {X: Type} (R: relation X) :=
  forall x y1 y2 : X, R x y1 -> R x y2 -> y1 = y2.

Inductive next_nat (n:nat) : nat -> Prop :=
  | nn : next_nat n (S n).

Theorem le_not_a_partial_function :
  ~ (partial_function le).
Proof.
  unfold partial_function.
  intro.
  assert (0 = 1) as nonsense.
  apply H with (x:=0).
  reflexivity.
  apply le_S. reflexivity.
  inversion nonsense.
Qed.

Inductive total_relation : nat -> nat -> Prop :=
  tot : forall n m : nat, total_relation n m.

Theorem total_relation_not_a_partial_function :
  ~ (partial_function total_relation).
Proof.
  unfold partial_function.
  intro.
  assert (0 = 1).
  apply H with (x := 0).
  apply tot.
  apply tot.
  inversion H0.
Qed.

Inductive empty_relation : nat -> nat -> Prop :=.

Theorem empty_relation_is_a_partial_function :
  partial_function empty_relation.
Proof.
  unfold partial_function.
  intros.
  inversion H.
Qed.

Definition reflexive {X: Type} (R: relation X) :=
  forall a : X, R a a.

Theorem le_reflexive :
  reflexive le.
Proof.
  unfold reflexive.
  intro.
  apply le_n.
Qed.

Definition transitive {X: Type} (R: relation X) :=
  forall a b c : X, (R a b) -> (R b c) -> (R a c).

Theorem le_trans :
  transitive le.
Proof.
  unfold transitive.
  intros.
  (*
   H: a <= b
   H0: b <= c
   -----------
   a <= c
   *)
  induction H0.
  (* Goal 1:
     H: a <= b
     -----------
     a <= b

     Goal 2:
     H: a <= b
     m: nat
     H0: b <= m
     IHle: a <= m
     ------------
     a <= S m
   *)

  assumption.
  apply le_S. assumption.
Qed.

(* NOTE: i have once confused on how induction works here.
   then i posed the question on irc #coq, soonly i got a clear explanation.

   IRC log (abridged):

(01:42:22 AM) shouya: first of all, the type of le is nat -> nat -> Prop, right?
(01:42:36 AM) Cypi: Yes
(01:42:42 AM) shouya: so 'le a b' should have type of Prop isn't it?
(01:42:44 AM) ianjneu: le is an inductive definition that carries more information about the ordering relationship of two natural numbers.
(01:42:56 AM) Cypi: Yes it does
(01:42:59 AM) shouya: that's why it's valid to be put as a hypo.
(01:43:01 AM) shouya: and...
(01:43:02 AM) ianjneu: You can eliminate Prop into Prop.
(01:43:20 AM) shouya: why can i perform an induction on a Prop.
(01:43:32 AM) ianjneu: relation's return type is Prop.
(01:43:34 AM) shouya: Prop isn't any inductive type basically.
(01:43:41 AM) Cypi: Because in this case, [le] is an inductive definition
(01:44:02 AM) shouya: Cypi: okay, that's how i interpret it. fine.
(01:44:15 AM) shouya: and second, i don't know if i'm understanding correctly.
(01:44:50 AM) shouya: induction basically means to seperate an inductive definition into each cases, just like what 'destruct' does.
01:45
(01:45:18 AM) shouya: so as the definition of le, showing here: http://lpaste.net/107061
(01:45:42 AM) Ptival: shouya: yes, but on top of what destruct does, it also gives you a proof for the recursive occurences of the same type
(01:45:57 AM) shouya: Ptival: yup that's no problem.
(01:46:19 AM) shouya: but i found no where the cases goes in splited subgoals after induction.
(01:47:32 AM) Ptival: shouya: what is your misunderstanding
(01:47:45 AM) Ptival: so after induction you now have two subgoals, one for each of the constructors of `le`
(01:48:36 AM) shouya: Ptival: yup i think in this way.
(01:48:47 AM) Ptival: in the first case, `b` and `c` have been unified (because le_n is indexed at the same value as its parameter)
(01:49:31 AM) shouya: okay. good so far :)
01:50
(01:50:10 AM) shouya: so it should yield a hypo: b = c right?
(01:50:25 AM) shouya: okay... i get it.
(01:50:31 AM) shouya: how about the second case?
(01:50:39 AM) Ptival: well, it does, but then it just substs it, so you never see that hypothesis
(01:50:52 AM) Ptival: I mean, it doesn't, but morally you could think it does
(01:51:13 AM) shouya: Ptival: i see it :)
(01:51:46 AM) shouya: btw, updated paste: the goals before and after the induction are shown. http://lpaste.net/107061
(01:51:52 AM) Ptival: in fact, if you do 'remember c.' before the induction, you will see it
(01:52:18 AM) shouya: Ptival: i think i can comprehend this case, no problem :)
(01:52:35 AM) Ptival: not the second one?
(01:53:27 AM) Ptival: so in the second one, we consider the case where the original `b <= c` we did induction has been built using the constructor `le_S`
(01:54:08 AM) Ptival: so it must be the case that `b <= c` unifies with `n <= S m`, therefore `b` unifies with `n` and `c` unifies with `S m`
(01:54:22 AM) shouya: hmm...
(01:54:48 AM) shouya: gotcha!
01:55
(01:55:09 AM) Ptival: so you get in your context the parameters given to le_S: m, `n <= m` (which after unification becomes `b <= m`)
(01:55:22 AM) shouya: Ptival: thank you i think i got the idea of how it works :P
(01:55:40 AM) Ptival: and your goal is still `a <= c`, but `c` has been unified with `S m`, so the goal is `a <= S m`
(01:55:47 AM) shouya: yes, yes..
(01:56:07 AM) shouya: it just a little bit convoluted :)

*)

(*
  annotation by ianjneu: http://lpaste.net/107061,
  elaborating the detailed works
*)
Theorem le_trans' :
  transitive le.
Proof.
  unfold transitive.
  intros; generalize dependent c.
  induction H.  (* why? *)
  intros; assumption.
  intros; inversion H0; subst; apply le_S.
  assumption.
  apply IHle.
  assert (R : forall m n, S m <= n -> m <= n).
  induction n; [intro bad; inversion bad
               |intros K; inversion K; subst; constructor;
                  [constructor|apply IHn; assumption]].
  apply R; assumption.
Qed.

Theorem lt_le :
  forall a b : nat, a < b -> a < S b.
Proof.
  unfold lt. intros.
  induction H.
  constructor; constructor.
  constructor; apply IHle.
Qed.

Theorem lt_trans:
  transitive lt.
Proof.
  unfold lt.
  unfold transitive.
  intros.
  apply le_S in H.
  apply le_trans with (a := (S a)) (b := (S b)) (c := c).
  assumption.
  assumption.
Qed.

Theorem lt_trans' :
  transitive lt.
Proof.
  (* Prove this by induction on evidence that m is less than o. *)
  unfold lt. unfold transitive.
  intros.
  induction H0.
  constructor; assumption.
  constructor; assumption.
Qed.

Theorem lt_trans'' :
  transitive lt.
Proof.
  unfold lt. unfold transitive.
  intros n m o Hnm Hmo.
  induction o as [| o'].
  inversion Hmo.
  induction Hmo; constructor; assumption.
Qed.

Theorem le_Sn_le : forall n m, S n <= m -> n <= m.
Proof.
  intros.
  induction H.
  constructor; constructor.
  constructor; assumption.
Qed.

(* One star ??! *)
Theorem le_S_n : forall n m,
  (S n <= S m) -> (n <= m).
Proof.
  intros.
  generalize dependent n.
  induction m.

  intros.
  induction n.
  constructor.

  inversion H.
  inversion H1.

  intros.
  induction n.
  assert (forall a, 0 <= a).
  induction a. constructor. constructor; assumption.
  apply H0.

  inversion H. constructor.

  apply le_trans with (S (S n)).
  constructor. constructor.

  assumption.
Qed.

Theorem le_Sn_n : forall n, ~(S n <= n).
Proof.
  intros. intro.
  induction n.
  inversion H.
  apply le_S_n in H. apply IHn in H. inversion H.
Qed.

Definition symmetric {X: Type} (R: relation X) :=
  forall a b : X, (R a b) -> (R b a).

(* prove by contradiction *)

Theorem le_not_symmetric :
  ~ (symmetric le).
Proof.
  unfold symmetric. intro.
  assert (1 <= 0).
  apply H. constructor. constructor.
  inversion H0.
Qed.

Definition antisymmetric {X: Type} (R: relation X) :=
  forall a b : X, (R a b) -> (R b a) -> a = b.

Lemma Sn_neq_n : forall n, ~(S n = n).
Proof.
  induction n.
  intro. inversion H.
  intro.
  inversion H. apply IHn in H1.
  assumption.
Qed.

Lemma Sn_nle_n : forall n, ~(S n <= n).
Proof.
  intros. intro.
  induction n.
  inversion H.
  apply le_S_n in H. apply IHn in H. inversion H.
Qed.

Theorem le_antisymmetric :
  antisymmetric le.
Proof.
  unfold antisymmetric.
  intros.
  induction H0.
  reflexivity.

  assert (S m <= m).
  apply le_trans with (b := b); assumption.
  apply le_Sn_n in H1. inversion H1.
Qed.

Theorem le_step : forall n m p,
  n < m ->
  m <= S p ->
  n <= p.
Proof.
  intros.
  unfold lt in H.
  assert (S n <= S p). apply le_trans with (b := m); assumption.
  apply le_S_n. assumption.
Qed.

Definition equivalence {X:Type} (R: relation X) :=
  (reflexive R) /\ (symmetric R) /\ (transitive R).

Definition order {X:Type} (R: relation X) :=
  (reflexive R) /\ (antisymmetric R) /\ (transitive R).

Definition preorder {X:Type} (R: relation X) :=
  (reflexive R) /\ (transitive R).

Theorem le_order :
  order le.
Proof.
  unfold order.
  split. apply le_reflexive.
  split. apply le_antisymmetric. apply le_trans.
Qed.

Inductive clos_refl_trans {A: Type} (R: relation A) : relation A :=
    | rt_step : forall x y, R x y -> clos_refl_trans R x y
    | rt_refl : forall x, clos_refl_trans R x x
    | rt_trans : forall x y z,
          clos_refl_trans R x y ->
          clos_refl_trans R y z ->
          clos_refl_trans R x z.

Theorem next_nat_closure_is_le : forall n m,
  (n <= m) <-> ((clos_refl_trans next_nat) n m).
Proof.
  intros. split.
  Case "->".
    intro.
    induction H.
    apply rt_refl.
    apply rt_trans with m. assumption.
    apply rt_step. apply nn.

  Case "<-".
    intro. induction H.
    induction H. apply le_S. apply le_n.
    apply le_n.
    apply le_trans with y. assumption. assumption.
Qed.

Inductive refl_step_closure {X:Type} (R: relation X) : relation X :=
  | rsc_refl : forall (x : X), refl_step_closure R x x
  | rsc_step : forall (x y z : X),
                    R x y ->
                    refl_step_closure R y z ->
                    refl_step_closure R x z.

Tactic Notation "rt_cases" tactic(first) ident(c) :=
  first;
  [ Case_aux c "rt_step" | Case_aux c "rt_refl"
  | Case_aux c "rt_trans" ].

Tactic Notation "rsc_cases" tactic(first) ident(c) :=
  first;
  [ Case_aux c "rsc_refl" | Case_aux c "rsc_step" ].

Theorem rsc_R : forall (X:Type) (R:relation X) (x y : X),
       R x y -> refl_step_closure R x y.
Proof.
  intros.
  apply rsc_step with y. assumption.
  apply rsc_refl.
Qed.

Theorem rsc_trans :
  forall (X:Type) (R: relation X) (x y z : X),
      refl_step_closure R x y ->
      refl_step_closure R y z ->
      refl_step_closure R x z.
Proof.
  intros.
  induction H. assumption.
  apply rsc_step with y. assumption.
  apply IHrefl_step_closure. assumption.
Qed.

Theorem rtc_rsc_coincide :
         forall (X:Type) (R: relation X) (x y : X),
  clos_refl_trans R x y <-> refl_step_closure R x y.
Proof.
  intros.
  split.
  Case "->".
    intro. induction H.
    SCase "R x y". apply rsc_R. assumption.
    SCase "refl". apply rsc_refl.
    SCase "trans". apply rsc_trans with y; assumption.
  Case "<-".
    intro.
    induction H.
    SCase "refl". apply rt_refl.
    SCase "R x y -> rsc y z -> rsc x z".
      apply rt_trans with y.
      SSCase "rt x y". apply rt_step. assumption.
      SSCase "rt y z". assumption.
Qed.

author: shouya

repo: thinking-dumps

save_path: github-repos/coq/shouya-thinking-dumps


text:
From Hammer Require Import Hammer.

Set Warnings "-notation-overridden,-parsing".
From Coq Require Import Bool.Bool.
From Coq Require Import Init.Nat.
From Coq Require Import Arith.Arith.
From Coq Require Import Arith.EqNat.
From Coq Require Import omega.Omega.
From Coq Require Import Lists.List.
From Coq Require Import Strings.String.
Import ListNotations.

From PLF Require Import Maps.

Module AExp.

Inductive aexp : Type :=
| ANum (n : nat)
| APlus (a1 a2 : aexp)
| AMinus (a1 a2 : aexp)
| AMult (a1 a2 : aexp).

Inductive bexp : Type :=
| BTrue
| BFalse
| BEq (a1 a2 : aexp)
| BLe (a1 a2 : aexp)
| BNot (b : bexp)
| BAnd (b1 b2 : bexp).

Fixpoint aeval (a : aexp) : nat :=
match a with
| ANum n => n
| APlus  a1 a2 => (aeval a1) + (aeval a2)
| AMinus a1 a2 => (aeval a1) - (aeval a2)
| AMult  a1 a2 => (aeval a1) * (aeval a2)
end.

Example test_aeval1:
aeval (APlus (ANum 2) (ANum 2)) = 4.
Proof. hammer_hook "Imp" "Imp.AExp.test_aeval1". reflexivity. Qed.

Fixpoint beval (b : bexp) : bool :=
match b with
| BTrue       => true
| BFalse      => false
| BEq a1 a2   => (aeval a1) =? (aeval a2)
| BLe a1 a2   => (aeval a1) <=? (aeval a2)
| BNot b1     => negb (beval b1)
| BAnd b1 b2  => andb (beval b1) (beval b2)
end.

Fixpoint optimize_0plus (a:aexp) : aexp :=
match a with
| ANum n => ANum n
| APlus (ANum 0) e2 => optimize_0plus e2
| APlus  e1 e2 => APlus  (optimize_0plus e1) (optimize_0plus e2)
| AMinus e1 e2 => AMinus (optimize_0plus e1) (optimize_0plus e2)
| AMult  e1 e2 => AMult  (optimize_0plus e1) (optimize_0plus e2)
end.

Example test_optimize_0plus:
optimize_0plus (APlus (ANum 2)
(APlus (ANum 0)
(APlus (ANum 0) (ANum 1))))
= APlus (ANum 2) (ANum 1).
Proof. hammer_hook "Imp" "Imp.AExp.test_optimize_0plus". reflexivity. Qed.

Theorem optimize_0plus_sound: forall a,
aeval (optimize_0plus a) = aeval a.
Proof. hammer_hook "Imp" "Imp.AExp.optimize_0plus_sound".
intros a. induction a.
-  reflexivity.
-  destruct a1 eqn:Ea1.
+  destruct n eqn:En.
*   simpl. apply IHa2.
*  simpl. rewrite IHa2. reflexivity.
+
simpl. simpl in IHa1. rewrite IHa1.
rewrite IHa2. reflexivity.
+
simpl. simpl in IHa1. rewrite IHa1.
rewrite IHa2. reflexivity.
+
simpl. simpl in IHa1. rewrite IHa1.
rewrite IHa2. reflexivity.
-
simpl. rewrite IHa1. rewrite IHa2. reflexivity.
-
simpl. rewrite IHa1. rewrite IHa2. reflexivity.  Qed.

Theorem silly1 : forall ae, aeval ae = aeval ae.
Proof. hammer_hook "Imp" "Imp.AExp.silly1". try reflexivity.  Qed.

Theorem silly2 : forall (P : Prop), P -> P.
Proof. hammer_hook "Imp" "Imp.AExp.silly2".
intros P HP.
try reflexivity.
apply HP.
Qed.

Lemma foo : forall n, 0 <=? n = true.
Proof. hammer_hook "Imp" "Imp.AExp.foo".
intros.
destruct n.

-  simpl. reflexivity.
-  simpl. reflexivity.
Qed.

Lemma foo' : forall n, 0 <=? n = true.
Proof. hammer_hook "Imp" "Imp.AExp.foo'".
intros.

destruct n;

simpl;

reflexivity.
Qed.

Theorem optimize_0plus_sound': forall a,
aeval (optimize_0plus a) = aeval a.
Proof. hammer_hook "Imp" "Imp.AExp.optimize_0plus_sound'".
intros a.
induction a;

try (simpl; rewrite IHa1; rewrite IHa2; reflexivity).

-  reflexivity.
-
destruct a1 eqn:Ea1;

try (simpl; simpl in IHa1; rewrite IHa1;
rewrite IHa2; reflexivity).

+  destruct n eqn:En;
simpl; rewrite IHa2; reflexivity.   Qed.

Theorem optimize_0plus_sound'': forall a,
aeval (optimize_0plus a) = aeval a.
Proof. hammer_hook "Imp" "Imp.AExp.optimize_0plus_sound''".
intros a.
induction a;

try (simpl; rewrite IHa1; rewrite IHa2; reflexivity);

try reflexivity.

-
destruct a1; try (simpl; simpl in IHa1; rewrite IHa1;
rewrite IHa2; reflexivity).
+  destruct n;
simpl; rewrite IHa2; reflexivity. Qed.

Theorem In10 : In 10 [1;2;3;4;5;6;7;8;9;10].
Proof. hammer_hook "Imp" "Imp.AExp.In10".
repeat (try (left; reflexivity); right).
Qed.

Theorem In10' : In 10 [1;2;3;4;5;6;7;8;9;10].
Proof. hammer_hook "Imp" "Imp.AExp.In10'".
repeat (left; reflexivity).
repeat (right; try (left; reflexivity)).
Qed.

Fixpoint optimize_0plus_b (b : bexp) : bexp
. Admitted.

Theorem optimize_0plus_b_sound : forall b,
beval (optimize_0plus_b b) = beval b.
Proof. hammer_hook "Imp" "Imp.AExp.optimize_0plus_b_sound".
Admitted.

Tactic Notation "simpl_and_try" tactic(c) :=
simpl;
try c.

Example silly_presburger_example : forall m n o p,
m + n <= n + o /\ o + 3 = p + 3 ->
m <= p.
Proof. hammer_hook "Imp" "Imp.AExp.silly_presburger_example".
intros. omega.
Qed.

Module aevalR_first_try.

Inductive aevalR : aexp -> nat -> Prop :=
| E_ANum n :
aevalR (ANum n) n
| E_APlus (e1 e2: aexp) (n1 n2: nat) :
aevalR e1 n1 ->
aevalR e2 n2 ->
aevalR (APlus e1 e2) (n1 + n2)
| E_AMinus (e1 e2: aexp) (n1 n2: nat) :
aevalR e1 n1 ->
aevalR e2 n2 ->
aevalR (AMinus e1 e2) (n1 - n2)
| E_AMult (e1 e2: aexp) (n1 n2: nat) :
aevalR e1 n1 ->
aevalR e2 n2 ->
aevalR (AMult e1 e2) (n1 * n2).

Module TooHardToRead.

Inductive aevalR : aexp -> nat -> Prop :=
| E_ANum n :
aevalR (ANum n) n
| E_APlus (e1 e2: aexp) (n1 n2: nat)
(H1 : aevalR e1 n1)
(H2 : aevalR e2 n2) :
aevalR (APlus e1 e2) (n1 + n2)
| E_AMinus (e1 e2: aexp) (n1 n2: nat)
(H1 : aevalR e1 n1)
(H2 : aevalR e2 n2) :
aevalR (AMinus e1 e2) (n1 - n2)
| E_AMult (e1 e2: aexp) (n1 n2: nat)
(H1 : aevalR e1 n1)
(H2 : aevalR e2 n2) :
aevalR (AMult e1 e2) (n1 * n2).

End TooHardToRead.

Notation "e '\\' n"
:= (aevalR e n)
(at level 50, left associativity)
: type_scope.

End aevalR_first_try.

Reserved Notation "e '\\' n" (at level 90, left associativity).

Inductive aevalR : aexp -> nat -> Prop :=
| E_ANum (n : nat) :
(ANum n) \\ n
| E_APlus (e1 e2 : aexp) (n1 n2 : nat) :
(e1 \\ n1) -> (e2 \\ n2) -> (APlus e1 e2) \\ (n1 + n2)
| E_AMinus (e1 e2 : aexp) (n1 n2 : nat) :
(e1 \\ n1) -> (e2 \\ n2) -> (AMinus e1 e2) \\ (n1 - n2)
| E_AMult (e1 e2 : aexp) (n1 n2 : nat) :
(e1 \\ n1) -> (e2 \\ n2) -> (AMult e1 e2) \\ (n1 * n2)

where "e '\\' n" := (aevalR e n) : type_scope.

Definition manual_grade_for_beval_rules : option (nat*string) := None.

Theorem aeval_iff_aevalR : forall a n,
(a \\ n) <-> aeval a = n.
Proof. hammer_hook "Imp" "Imp.AExp.aeval_iff_aevalR".
split.
-
intros H.
induction H; simpl.
+
reflexivity.
+
rewrite IHaevalR1.  rewrite IHaevalR2.  reflexivity.
+
rewrite IHaevalR1.  rewrite IHaevalR2.  reflexivity.
+
rewrite IHaevalR1.  rewrite IHaevalR2.  reflexivity.
-
generalize dependent n.
induction a;
simpl; intros; subst.
+
apply E_ANum.
+
apply E_APlus.
apply IHa1. reflexivity.
apply IHa2. reflexivity.
+
apply E_AMinus.
apply IHa1. reflexivity.
apply IHa2. reflexivity.
+
apply E_AMult.
apply IHa1. reflexivity.
apply IHa2. reflexivity.
Qed.

Theorem aeval_iff_aevalR' : forall a n,
(a \\ n) <-> aeval a = n.
Proof. hammer_hook "Imp" "Imp.AExp.aeval_iff_aevalR'".

split.
-
intros H; induction H; subst; reflexivity.
-
generalize dependent n.
induction a; simpl; intros; subst; constructor;
try apply IHa1; try apply IHa2; reflexivity.
Qed.

Inductive bevalR: bexp -> bool -> Prop :=

.

Lemma beval_iff_bevalR : forall b bv,
bevalR b bv <-> beval b = bv.
Proof. hammer_hook "Imp" "Imp.AExp.beval_iff_bevalR".
Admitted.

End AExp.

Module aevalR_division.

Inductive aexp : Type :=
| ANum (n : nat)
| APlus (a1 a2 : aexp)
| AMinus (a1 a2 : aexp)
| AMult (a1 a2 : aexp)
| ADiv (a1 a2 : aexp).

Reserved Notation "e '\\' n"
(at level 90, left associativity).

Inductive aevalR : aexp -> nat -> Prop :=
| E_ANum (n : nat) :
(ANum n) \\ n
| E_APlus (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) -> (a2 \\ n2) -> (APlus a1 a2) \\ (n1 + n2)
| E_AMinus (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) -> (a2 \\ n2) -> (AMinus a1 a2) \\ (n1 - n2)
| E_AMult (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) -> (a2 \\ n2) -> (AMult a1 a2) \\ (n1 * n2)
| E_ADiv (a1 a2 : aexp) (n1 n2 n3 : nat) :
(a1 \\ n1) -> (a2 \\ n2) -> (n2 > 0) ->
(mult n2 n3 = n1) -> (ADiv a1 a2) \\ n3

where "a '\\' n" := (aevalR a n) : type_scope.

End aevalR_division.

Module aevalR_extended.

Reserved Notation "e '\\' n" (at level 90, left associativity).

Inductive aexp : Type :=
| AAny
| ANum (n : nat)
| APlus (a1 a2 : aexp)
| AMinus (a1 a2 : aexp)
| AMult (a1 a2 : aexp).

Inductive aevalR : aexp -> nat -> Prop :=
| E_Any (n : nat) :
AAny \\ n
| E_ANum (n : nat) :
(ANum n) \\ n
| E_APlus (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) -> (a2 \\ n2) -> (APlus a1 a2) \\ (n1 + n2)
| E_AMinus (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) -> (a2 \\ n2) -> (AMinus a1 a2) \\ (n1 - n2)
| E_AMult (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) -> (a2 \\ n2) -> (AMult a1 a2) \\ (n1 * n2)

where "a '\\' n" := (aevalR a n) : type_scope.

End aevalR_extended.

Definition state := total_map nat.

Inductive aexp : Type :=
| ANum (n : nat)
| AId (x : string)
| APlus (a1 a2 : aexp)
| AMinus (a1 a2 : aexp)
| AMult (a1 a2 : aexp).

Definition W : string := "W".
Definition X : string := "X".
Definition Y : string := "Y".
Definition Z : string := "Z".

Inductive bexp : Type :=
| BTrue
| BFalse
| BEq (a1 a2 : aexp)
| BLe (a1 a2 : aexp)
| BNot (b : bexp)
| BAnd (b1 b2 : bexp).

Coercion AId : string >-> aexp.
Coercion ANum : nat >-> aexp.

Definition bool_to_bexp (b : bool) : bexp :=
if b then BTrue else BFalse.
Coercion bool_to_bexp : bool >-> bexp.

Bind Scope imp_scope with aexp.
Bind Scope imp_scope with bexp.
Delimit Scope imp_scope with imp.

Notation "x + y" := (APlus x y) (at level 50, left associativity) : imp_scope.
Notation "x - y" := (AMinus x y) (at level 50, left associativity) : imp_scope.
Notation "x * y" := (AMult x y) (at level 40, left associativity) : imp_scope.
Notation "x <= y" := (BLe x y) (at level 70, no associativity) : imp_scope.
Notation "x = y" := (BEq x y) (at level 70, no associativity) : imp_scope.
Notation "x && y" := (BAnd x y) (at level 40, left associativity) : imp_scope.
Notation "'~' b" := (BNot b) (at level 75, right associativity) : imp_scope.

Definition example_aexp := (3 + (X * 2))%imp : aexp.
Definition example_bexp := (true && ~(X <= 4))%imp : bexp.

Set Printing Coercions.

Print example_bexp.

Unset Printing Coercions.

Fixpoint aeval (st : state) (a : aexp) : nat :=
match a with
| ANum n => n
| AId x => st x
| APlus a1 a2 => (aeval st a1) + (aeval st a2)
| AMinus a1 a2  => (aeval st a1) - (aeval st a2)
| AMult a1 a2 => (aeval st a1) * (aeval st a2)
end.

Fixpoint beval (st : state) (b : bexp) : bool :=
match b with
| BTrue       => true
| BFalse      => false
| BEq a1 a2   => (aeval st a1) =? (aeval st a2)
| BLe a1 a2   => (aeval st a1) <=? (aeval st a2)
| BNot b1     => negb (beval st b1)
| BAnd b1 b2  => andb (beval st b1) (beval st b2)
end.

Definition empty_st := (_ !-> 0).

Notation "a '!->' x" := (t_update empty_st a x) (at level 100).

Example aexp1 :
aeval (X !-> 5) (3 + (X * 2))%imp
= 13.
Proof. hammer_hook "Imp" "Imp.aexp1". reflexivity. Qed.

Example bexp1 :
beval (X !-> 5) (true && ~(X <= 4))%imp
= true.
Proof. hammer_hook "Imp" "Imp.bexp1". reflexivity. Qed.

Inductive com : Type :=
| CSkip
| CAss (x : string) (a : aexp)
| CSeq (c1 c2 : com)
| CIf (b : bexp) (c1 c2 : com)
| CWhile (b : bexp) (c : com).

Bind Scope imp_scope with com.
Notation "'SKIP'" :=
CSkip : imp_scope.
Notation "x '::=' a" :=
(CAss x a) (at level 60) : imp_scope.
Notation "c1 ;; c2" :=
(CSeq c1 c2) (at level 80, right associativity) : imp_scope.
Notation "'WHILE' b 'DO' c 'END'" :=
(CWhile b c) (at level 80, right associativity) : imp_scope.
Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" :=
(CIf c1 c2 c3) (at level 80, right associativity) : imp_scope.

Definition fact_in_coq : com :=
(Z ::= X;;
Y ::= 1;;
WHILE ~(Z = 0) DO
Y ::= Y * Z;;
Z ::= Z - 1
END)%imp.

Unset Printing Notations.
Print fact_in_coq.

Set Printing Notations.

Set Printing Coercions.
Print fact_in_coq.

Unset Printing Coercions.

Locate "&&".

Locate ";;".

Locate "WHILE".

Locate aexp.

Definition plus2 : com :=
X ::= X + 2.

Definition XtimesYinZ : com :=
Z ::= X * Y.

Definition subtract_slowly_body : com :=
Z ::= Z - 1 ;;
X ::= X - 1.

Definition subtract_slowly : com :=
(WHILE ~(X = 0) DO
subtract_slowly_body
END)%imp.

Definition subtract_3_from_5_slowly : com :=
X ::= 3 ;;
Z ::= 5 ;;
subtract_slowly.

Definition loop : com :=
WHILE true DO
SKIP
END.

Open Scope imp_scope.
Fixpoint ceval_fun_no_while (st : state) (c : com)
: state :=
match c with
| SKIP =>
st
| x ::= a1 =>
(x !-> (aeval st a1) ; st)
| c1 ;; c2 =>
let st' := ceval_fun_no_while st c1 in
ceval_fun_no_while st' c2
| TEST b THEN c1 ELSE c2 FI =>
if (beval st b)
then ceval_fun_no_while st c1
else ceval_fun_no_while st c2
| WHILE b DO c END =>
st
end.
Close Scope imp_scope.

Reserved Notation "st '=[' c ']=>' st'"
(at level 40).

Inductive ceval : com -> state -> state -> Prop :=
| E_Skip : forall st,
st =[ SKIP ]=> st
| E_Ass  : forall st a1 n x,
aeval st a1 = n ->
st =[ x ::= a1 ]=> (x !-> n ; st)
| E_Seq : forall c1 c2 st st' st'',
st  =[ c1 ]=> st'  ->
st' =[ c2 ]=> st'' ->
st  =[ c1 ;; c2 ]=> st''
| E_IfTrue : forall st st' b c1 c2,
beval st b = true ->
st =[ c1 ]=> st' ->
st =[ TEST b THEN c1 ELSE c2 FI ]=> st'
| E_IfFalse : forall st st' b c1 c2,
beval st b = false ->
st =[ c2 ]=> st' ->
st =[ TEST b THEN c1 ELSE c2 FI ]=> st'
| E_WhileFalse : forall b st c,
beval st b = false ->
st =[ WHILE b DO c END ]=> st
| E_WhileTrue : forall st st' st'' b c,
beval st b = true ->
st  =[ c ]=> st' ->
st' =[ WHILE b DO c END ]=> st'' ->
st  =[ WHILE b DO c END ]=> st''

where "st =[ c ]=> st'" := (ceval c st st').

Example ceval_example1:
empty_st =[
X ::= 2;;
TEST X <= 1
THEN Y ::= 3
ELSE Z ::= 4
FI
]=> (Z !-> 4 ; X !-> 2).
Proof. hammer_hook "Imp" "Imp.ceval_example1".

apply E_Seq with (X !-> 2).
-
apply E_Ass. reflexivity.
-
apply E_IfFalse.
reflexivity.
apply E_Ass. reflexivity.
Qed.

Example ceval_example2:
empty_st =[
X ::= 0;; Y ::= 1;; Z ::= 2
]=> (Z !-> 2 ; Y !-> 1 ; X !-> 0).
Proof. hammer_hook "Imp" "Imp.ceval_example2".
Admitted.

Definition pup_to_n : com
. Admitted.

Theorem pup_to_2_ceval :
(X !-> 2) =[
pup_to_n
]=> (X !-> 0 ; Y !-> 3 ; X !-> 1 ; Y !-> 2 ; Y !-> 0 ; X !-> 2).
Proof. hammer_hook "Imp" "Imp.pup_to_2_ceval".
Admitted.

Theorem ceval_deterministic: forall c st st1 st2,
st =[ c ]=> st1  ->
st =[ c ]=> st2 ->
st1 = st2.
Proof. hammer_hook "Imp" "Imp.ceval_deterministic".
intros c st st1 st2 E1 E2.
generalize dependent st2.
induction E1;
intros st2 E2; inversion E2; subst.
-  reflexivity.
-  reflexivity.
-
assert (st' = st'0) as EQ1.
{  apply IHE1_1; assumption. }
subst st'0.
apply IHE1_2. assumption.
-
apply IHE1. assumption.
-
rewrite H in H5. discriminate H5.
-
rewrite H in H5. discriminate H5.
-
apply IHE1. assumption.
-
reflexivity.
-
rewrite H in H2. discriminate H2.
-
rewrite H in H4. discriminate H4.
-
assert (st' = st'0) as EQ1.
{  apply IHE1_1; assumption. }
subst st'0.
apply IHE1_2. assumption.  Qed.

Theorem plus2_spec : forall st n st',
st X = n ->
st =[ plus2 ]=> st' ->
st' X = n + 2.
Proof. hammer_hook "Imp" "Imp.plus2_spec".
intros st n st' HX Heval.

inversion Heval. subst. clear Heval. simpl.
apply t_update_eq.  Qed.

Definition manual_grade_for_XtimesYinZ_spec : option (nat*string) := None.

Theorem loop_never_stops : forall st st',
~(st =[ loop ]=> st').
Proof. hammer_hook "Imp" "Imp.loop_never_stops".
intros st st' contra. unfold loop in contra.
remember (WHILE true DO SKIP END)%imp as loopdef
eqn:Heqloopdef.

Admitted.

Open Scope imp_scope.
Fixpoint no_whiles (c : com) : bool :=
match c with
| SKIP =>
true
| _ ::= _ =>
true
| c1 ;; c2 =>
andb (no_whiles c1) (no_whiles c2)
| TEST _ THEN ct ELSE cf FI =>
andb (no_whiles ct) (no_whiles cf)
| WHILE _ DO _ END  =>
false
end.
Close Scope imp_scope.

Inductive no_whilesR: com -> Prop :=

.

Theorem no_whiles_eqv:
forall c, no_whiles c = true <-> no_whilesR c.
Proof. hammer_hook "Imp" "Imp.no_whiles_eqv".
Admitted.

Definition manual_grade_for_no_whiles_terminating : option (nat*string) := None.

Inductive sinstr : Type :=
| SPush (n : nat)
| SLoad (x : string)
| SPlus
| SMinus
| SMult.

Fixpoint s_execute (st : state) (stack : list nat)
(prog : list sinstr)
: list nat
. Admitted.

Example s_execute1 :
s_execute empty_st []
[SPush 5; SPush 3; SPush 1; SMinus]
= [2; 5].
Admitted.

Example s_execute2 :
s_execute (X !-> 3) [3;4]
[SPush 4; SLoad X; SMult; SPlus]
= [15; 4].
Admitted.

Fixpoint s_compile (e : aexp) : list sinstr
. Admitted.

Example s_compile1 :
s_compile (X - (2 * Y))%imp
= [SLoad X; SPush 2; SLoad Y; SMult; SMinus].
Admitted.

Theorem s_compile_correct : forall (st : state) (e : aexp),
s_execute st [] (s_compile e) = [ aeval st e ].
Proof. hammer_hook "Imp" "Imp.s_compile_correct".
Admitted.

Module BreakImp.

Inductive com : Type :=
| CSkip
| CBreak
| CAss (x : string) (a : aexp)
| CSeq (c1 c2 : com)
| CIf (b : bexp) (c1 c2 : com)
| CWhile (b : bexp) (c : com).

Notation "'SKIP'" :=
CSkip.
Notation "'BREAK'" :=
CBreak.
Notation "x '::=' a" :=
(CAss x a) (at level 60).
Notation "c1 ;; c2" :=
(CSeq c1 c2) (at level 80, right associativity).
Notation "'WHILE' b 'DO' c 'END'" :=
(CWhile b c) (at level 80, right associativity).
Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" :=
(CIf c1 c2 c3) (at level 80, right associativity).

Inductive result : Type :=
| SContinue
| SBreak.

Reserved Notation "st '=[' c ']=>' st' '/' s"
(at level 40, st' at next level).

Inductive ceval : com -> state -> result -> state -> Prop :=
| E_Skip : forall st,
st =[ CSkip ]=> st / SContinue

where "st '=[' c ']=>' st' '/' s" := (ceval c st s st').

Theorem break_ignore : forall c st st' s,
st =[ BREAK;; c ]=> st' / s ->
st = st'.
Proof. hammer_hook "Imp" "Imp.BreakImp.break_ignore".
Admitted.

Theorem while_continue : forall b c st st' s,
st =[ WHILE b DO c END ]=> st' / s ->
s = SContinue.
Proof. hammer_hook "Imp" "Imp.BreakImp.while_continue".
Admitted.

Theorem while_stops_on_break : forall b c st st',
beval st b = true ->
st =[ c ]=> st' / SBreak ->
st =[ WHILE b DO c END ]=> st' / SContinue.
Proof. hammer_hook "Imp" "Imp.BreakImp.while_stops_on_break".
Admitted.

Theorem while_break_true : forall b c st st',
st =[ WHILE b DO c END ]=> st' / SContinue ->
beval st' b = true ->
exists st'', st'' =[ c ]=> st' / SBreak.
Proof. hammer_hook "Imp" "Imp.BreakImp.while_break_true".
Admitted.

Theorem ceval_deterministic: forall (c:com) st st1 st2 s1 s2,
st =[ c ]=> st1 / s1 ->
st =[ c ]=> st2 / s2 ->
st1 = st2 /\ s1 = s2.
Proof. hammer_hook "Imp" "Imp.BreakImp.ceval_deterministic".
Admitted.

End BreakImp.

author: lukaszcz

repo: coqhammer-eval