How to rearrange newly defined associative terms in Coq? - coq

I wonder what is the most elegant way of rearranging associative terms in Coq. I think it is a well-defined problem for some existing operators, such as plus.
I have defined new associative operater and operands with corresponding types. In short, an associative lemma states that
Lemma assoc: forall A B C: sometype, A # (B # C) = A # B # C
Surely, all chains organized in the same order are equal no matter how to put the brackets. e.g.
A # B # C # D # E = (A # B) # (C # (D # E)) = (A # (B # (C # (D # E))))
I know one can use repeat rewrite assoc. or repeat rewrite <- assoc.to achieve LHS or RHS from the middle expression. Now I want to apply a lemma about (B # C). How can I quickly rewrite the expression to something like,
A # (B # C) # D # E
One solution is to use replace ... with ... by now rewrite assoc. However, it can be tedious when the expressions are getting longer. Is there any other effective way of rearranging terms/bracket? Is the aac-tactics library helpful for the problem? I cannot find a tutorial for using aac over the customized operators.

Yes AAC-Tactics is the recommended tactic for such problems. It provides an extensible tactic for associative and commutative rewriting. The tutorial is here (https://github.com/coq-community/aac-tactics/blob/master/theories/Tutorial.v).
AAC-Tactics is included in Coq Platform, so you can expect long term support for it.

Related

How to debug tactic failure in a match goal branch?

Let's say I have some complex tactics in the body of a match goal branch that can easily go wrong in a way I might need to debug. Is there a way to get the "real" error message from the branch if some tactic fails, rather than simply getting "Error: No matching clauses for match goal"?
Take as an example this fake tactic where apply A, B, C has several chances for something to go wrong. I've been fighting with a real tactic somewhat similar to this today.
Ltac three_applications :=
match goal with
| [
A : (* something reasonable *),
B : (* something reasonable *),
C : (* something reasonable *)
|- _ ] =>
idtac A B C;
assert (F: (* something reasonable *))
by apply A, B, C;
solve [discriminate F]
end.
Thank you in advance!
The easiest is to use lazymatch goal instead but it has different semantics, but as I see you match only on one shape, it might be ok for you.
The idea is that match goal might backtrack: if you have
match goal with
| n : nat |- _ => destruct n ; reflexivity
| |- nat => exact 0
end.
it will first try to find some n : nat in your hypotheses, starting from the most recent, and then try the tactic destruct n ; reflexivity. If it fails, it will try to find another natural number. If all of them fail, then it will look if the goal matches the second clause instead, and if so execute exact 0.
If that fails again, it will backtrack once again and conclude that No matching clauses for match goal.
On the other hand,
lazymatch goal with
| n : nat |- _ => destruct n ; reflexivity
| |- nat => exact 0
end.
will find the first branch that matches, and then apply the tactic, if it fails, no backtracking in the lazymatch, and it will give you the error of the tactic in the corresponding branch.
Note that I would always use lazymatch, not just for debugging purposes, when I don't find a use case for backtracking.
In case, lazymatch is not semantically equivalent to your match and backtracking needs to be involved then it will be harder, but indeed, using idtac A B C can help you see which branch it selected before launching the error.
Sometimes, writing
Fail three_applications.
instead of just
three_applications.
will help because Fail will usually keep the printing that you made in the command, even if it failed in the end.
Once you know the branch, just apply your tactic manually.

how to create conditionals in a Fixpoint definition Coq

I am working through the book "Software Foundations", and am on the last problem in Chapter two. The problem asks to convert a natural number into a binary number, where a binary number is defined in the following ways:
- [is] zero,
- [is] twice a binary number, or
- [is] one more than twice a binary number.
My thought process is that if a natural number is even, then it can be expressed as
double(nat_to_bin n)
However, in my Fixpoint definition, when I tried to write
(evenb n' = true) => double(nat_to_bin)
I got an error because evenb n' is not a constructor of nat. Is there any way for me to create a conditional such that the above line would be a valid function definition, without changing the definition of nat?
Nevermind, I figured out a solution. I can just write the term
match (evenb n') with
| true => ....
Took me a while, though.

How does one divide two Nats in Coq?

I wanted to divide two numbers in Coq because I was trying to implement my own custom Imp language and had a statement:
match (aeval st a1) with
| Some n0 => Some (NDiv n0 (S n))
| None => None
however / returns an error:
Unknown interpretation for notation "_ / _".
and so does NDiv, error:
The reference NDiv was not found in the current environment.
what can I do so that I don't get this error?
How does one do something like the python "integer division" but with nats?
You can use the command Require Import Arith. which will import, among other things, the function Nat.div and the notation _ / _ for it.
Seems like:
Require Import Coq.Init.Nat.
works, but I wonder how I could have searched this more efficiently without having to resort to put this trivial Q on SO.

Decreasing argument (and what is a Program Fixpoint)

Consider the following fixpoint:
Require Import Coq.Lists.List.
Import ListNotations.
Inductive my_type: Type:=
| Left: my_type
| Right: my_type
.
Fixpoint decrease (which: my_type) (left right: list my_type) : list my_type :=
match which with
| Left =>
match left with
| [] => []
| a::tl => decrease a tl right
end
| Right =>
match right with
| [] => []
| a::tl => decrease a left tl
end
end.
Coq rejects the following fixpoint because it can not guess the decreasing fixpoint (sometimes the left list looses its head, sometimes it is the right one).
This answer shows that one can solve this by using a Program Fixpoint and specifying a {measure ((length left)+(length right))}.
My questions are:
What is the difference between a regular Fixpoint and a Program Fixpoint ?
Is it possible to explicit the decreasing argument in a regular Fixpoint ?
What is the Next Obligation goal ?
The Fixpoint command in Coq constructs a recursive function using Coq's primitive fix, which checks for structural recursion to ensure termination. This is the only recursion in Coq, and all other techniques ultimately desugar to a fix of some sort.
Program Fixpoint is a feature of Program, which allows writing definitions in a slightly extended language that are then compiled into Coq definitions. Program Fixpoint accepts any recursive function, generates an appropriate proof obligation that shows the function terminates (by decreasing some measure of its arguments on each recursive subcall), and then packages up the definition and termination proof into a Coq definition that structurally decreases an argument. If that sounds magical it basically is, but CPDT gives a good explanation of how to do this kind of encoding.
Yes, you can add a {struct arg} annotation to explicitly specify which argument is structurally decreasing: Fixpoint decrease (which: my_type) (left right: list my_type) {struct right} : list my_type. This doesn't help for your example, since your function doesn't in general structurally decrease either argument. All primitive fix constructs have a struct annotation, but Coq can usually infer it automatically when you write a Fixpoint. For example, here's Nat.add:
Nat.add =
fix add (n m : nat) {struct n} : nat :=
match n with
| 0 => m
| S p => S (add p m)
end : nat -> nat -> nat
You get two types of goals from Next Obligation with Program Fixpoint: first that each subcall has a smaller argument (using measure, "smaller" is defined using < on nats), and second, that the "smaller" relation is well-founded; this is, it has no infinitely descending sequences of smaller and smaller objects. I'm not sure why Program Fixpoint doesn't do this automatically for Nat.lt, given that it should know the relevant theorem. Note that Program has more features than just more general recursion, so it can generate other goals related to those features as well, depending on the definition you write.

coq error when trying to use Case. Example from Software Foundations book

I am trying to learn Coq by working through the online Software Foundations book: http://www.cis.upenn.edu/~bcpierce/sf/
I'm using the interactive command line Coq interpreter coqtop.
In the induction chapter (http://www.cis.upenn.edu/~bcpierce/sf/Induction.html), I am following the instructions exactly. I compile Basics.v using coqc Basics.v. I then start coqtop and type exactly:
Require Export Basics.
Theorem andb_true_elim1 : forall b c : bool,
andb b c = true -> b = true.
Proof.
intros b c H.
destruct b.
Case "b = true".
Everything works until that last line, at which point I get the following error:
Toplevel input, characters 5-15:
> Case "b = true".
> ^^^^^^^^^^
Error: No interpretation for string "b = true".
I'm too new to Coq to start to unpack why this isn't working. I found something online suggesting I needed to do Require String. first, however, this didn't work either. Has anyone worked through this book or encountered this problem? How do I get the code to work properly?
This Case keyword (tactic?) seems to be dependent on something else that the SF book is not making clear is needed, but I can't figure out what.
What's missing is a string datatype which hooks into the "..." notation; the String module contains such a notation and datatype, but you have to tell Coq to use that notation via Open Scope string_scope. What's also missing, however, is an implementation of Case, which will only show up after you fix the string problem. All of this is provided for you in the Induction.v file inside the "Download" tarball, but it is not included in the output Induction.html, possibly due to a typo in the .v file. The relevant code, which would be the second paragraph of the "Naming Cases" section (right after "…but a better way is to use the Case tactic," and right before "Here's an example of how Case is used…") is:
(* [Case] is not built into Coq: we need to define it ourselves.
There is no need to understand how it works -- you can just skip
over the definition to the example that follows. It uses some
facilities of Coq that we have not discussed -- the string
library (just for the concrete syntax of quoted strings) and the
[Ltac] command, which allows us to declare custom tactics. Kudos
to Aaron Bohannon for this nice hack! *)
Require String. Open Scope string_scope.
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.
(A side note: When I worked through Software Foundations, I found using the provided .v files as my work material to be very helpful. You don't have to worry about elided code, you don't have to retype the definitions, and all the problems are right there. Your mileage may vary, of course.)