How to compile Logic.v in Coq - coq

I'm using Coq 8.4pl6, and want to compile Logic.v (of Coq standard library) in Coq and to see its output as an example of module compiling and printing, but failed.
More specifically, tauto at line 107 of Logic.v was failed:
104 Theorem and_cancel_l : forall A B C : Prop,
105 (B -> A) -> (C -> A) -> ((A /\ B <-> A /\ C) <-> (B <-> C)).
106 Proof.
107 intros; tauto.
108 Qed.
The process I tried is as follows:
I tried coqc Logic.v from console, which produces Error: tauto failed in line 107. I thought this is because Coq initial environment already imported Logic.vo, so loading the same module twice made the error.
Next, I tried to compile with the empty initial state by running coqc -nois Logic.v, which produces the following error. I didn't understand the meaning of this error...
File ".../Logic.v", line 107, characters 10-15:
Anomaly: Incorrect tactic expression. Received exception is:
Anomaly: Uncaught exception Nametab.GlobalizationError(_). Please report..
Please report.
Is there any way to compile Logic.v without errors?

The problem with compiling Logic.v seems to be due to the fact that it redefines the inductive types True, False, and, or, ex, ex2, eq and the constants not, iff, IF_then_else, all, eq_ind_r, eq_rec_r, eq_rect_r, subrelation, unique, uniqueness.
The automated tactics must consider (and treat) these "new" types and constant different from the ones that were loaded first, when Coq starts up.
Once these Definition and Inductive statements were removed from Logic.v, I was able to compile the file.
Hope this helps. (A more complete answer would explain exactly where in the startup process this happens.)

Related

Show theorem definition in Coq

I'd like to view the definition of a Standard Library theorem which I found through Search. I think seeing the definition will help me complete a similar theorem.
Doing Print Rdiv_lt_0_compat. yields:
Rdiv_lt_0_compat =
fun (a b : R) (H : (0 < a)%R) (H0 : (0 < b)%R) =>
Rmult_lt_0_compat a (/ b) H (Rinv_0_lt_compat b H0)
: forall a b : R, (0 < a)%R -> (0 < b)%R -> (0 < a / b)%R
Argument scopes are [R_scope R_scope _ _]
Setting Set Printing All. doesn't help. There's nothing extra available in the docs page.
The whole Coq system is based on the idea Proofs are programs, logical formulas are types. When you consider a theorem, it is a proof (a program) and its statement is a logical formula (the type of a program). In the very
first years of Coq, there was no tactic language, every proof was defined using the same keywords as when defining a program.
After a few years, it was recognized that writing the programs entirely by hand was long and tiresome, so a tactic language was invented to explain how to construct the proof-programs in a shorter and less difficult way. But what is recorded and eventually checked are still the programs that you see using Print.
When building a proof-program, the tactic intros constructs anonymous function expressions (also known as lambdas, usually written with the keyword fun, and apply constructs an application of a function to a certain number arguments, which apply infers or leaves to the user as goals. The tactics induction and rewrite are similar, but they apply theorems that are not
given by the user. The tactic destruct essentially produces a piece of programs that is a pattern-matching construct.
With Rdiv_lt_0_compat, you are lucky that the proof built by the tactic is quite short. Often, proofs written using tactics produce programs that are much longer.
If instead of the program, you want to see the sequence of tactics that generated it, you need to find it in the sources of the system, because this
is not kept in the memory of the proof assistant. Here are the clues.
Require Import Reals.
Locate Rdiv_lt_0_compat.
the answer is Constant Coq.Reals.RIneq.Rdiv_lt_0_compat
This sequence of names indicates the hierarchy of modules in which the theorem is kept. The first name Coq expresses that this theorem is in the Coq sources, essentially in directory ...theories/, the second name Reals, indicates that you should look in tge sub directory ...theories/Reals.
The fourth name should not be used as a directory name, but as file name. So you should look in the file RIneq.v
So go an look in https://github.com/coq/coq/tree/v8.12/theories/Reals/RIneq.v and you will probably find the script fragment that was used to generate your theorem (for the 8.12 version of Coq). I just checked, the theorem appears at line https://github.com/coq/coq/blob/c95bd4cf015a3084a8bddf6d3640458c9c25b455/theories/Reals/RIneq.v#L2106
The sequence of names provided by Locate is not a sure way to find the file where the script for a theorem is stored. The correspondence between the long name and the file path is broken when the theorem is defined using modules and functor instantiation. In that case, you have to rely on stronger knowledge of how the Coq system works.

Why does Coq.Init.Logic define the notation "A -> B"?

The Coq Standard Library file Coq.Init.Logic, which can be found here, contains the statement
Notation "A -> B" := (forall (_ : A), B) : type_scope.
I don't understand how this is possible, given that the symbol -> already has a built-in meaning. Is -> overwritten by this?
If I type in A -> B, how does Coq know if I mean A -> B or forall (x : A), B?
Yes, I know the two propositions are logically equivalent, but shouldn't this be a theorem instead of a notation?
As you can tell, I've not had much experience with Coq, but I want to understand the details.
The -> symbol is actually defined by the notation you found in Coq.Init.Logic! While forall is built-in, -> is defined using the notation system. The Coq.Init.Logic module is loaded automatically into Coq because it's exported by Coq.Init.Prelude, which is why you immediately have access to it.
When you write A -> B it's interpreted using the notation, which is forall (_:A), B; this is syntactically similar to forall (x:A), B, except that the expression B isn't allowed to depend on x. There's no ambiguity - this is the only definition for A -> B, and indeed if you load Coq without the prelude (eg, by passing the -noinit flag) A -> B will not parse.
One aspect of Coq that makes -> seem built-in is that the notation is bidirectional - it applies to both parsing and to printing. This is why you see -> in your goals and when you use Check and Search. Here there is real ambiguity; in this case, if a forall (x:A), B has a B that does not depend on x, Coq prefers to print it using the notation rather than the built-in syntax. If you turn off printing of notations (Unset Printing Notation.) you'll see forall (_:A), B everywhere you used to see A -> B. Of course, if you have a function type with a real dependency, then Coq needs to use forall (x:A), B since B needs to refer to the variable x.

Coq: viewing proof term during proof script writing

So, I've got a proof that looks like this:
induction t; intros; inversion H ; crush.
It solves all my goals, but when I do Qed, I get the following error:
Cannot guess decreasing argument of fix.
So somewhere in the generated proof term, there's non-well-founded recursion. The problem is, I have no idea where.
Is there a way to debug this kind of error, or to see the (possibly non halting) proof term that the tactics script generates?
You can use Show Proof. to view the proof term so far.
Another command that can help with seeing where the recursion went wrong is Guarded., which runs the termination checker on the proof term so far. You'll need to break apart the tactic script into independent sentences to use it, though. Here's an example:
Fixpoint f (n:nat) : nat.
Proof.
apply plus.
exact (f n).
Guarded.
(* fails with:
Error:
Recursive definition of f is ill-formed.
...
*)
Defined.
You can use the Show Proof. command inside proof mode to print the proof term produced so far.
In addition to the other excellent answers, I also want to point out that using induction inside an interactive-mode Fixpoint is usually a mistake, because you're recursing twice. Writing fixpoints in interactive mode is often tricky because most automation tools will happily make a recursive call at every possible opportunity, even when it would be ill-founded.
I would advise to use Definition instead of Fixpoint and use induction in the proof script. This invokes the explicit recursor, which allows for much better control of automation. The disadvantage is decreased flexibility since fixpoints have fewer restrictions than recursors - but as we've seen, that is both a blessing and a curse.

not_iff_compat not found in the current environment

I'm quite new to Coq, and I have an error when I try to use not_iff_compat theorem in a proof. For instance, given the following mwe:
Require Import Coq.Init.Logic.
Lemma dummy: forall A B, (A <-> B) -> (~A <-> ~B).
Proof.
apply not_iff_compat.
Qed.
Coq tells me: "Error: The reference not_iff_compat was not found in the current environment."
(As far as I now, Coq.Init.Logic is automatically loaded so not necessary here, but the problem is the same without).
Remarks: I use CoqIde 8.6, if that matters.
Your link starts with https://coq.inria.fr/distrib/current/, but the current version is 8.7.0 as of now and Coq v8.6 does not have the lemma in that module.
You can browse the standard libraries of different Coq versions by replacing 'current' with the version of your choice, e.g. like so: https://coq.inria.fr/distrib/8.6.1/stdlib/Coq.Init.Logic.html.
Just a tip: usually you can append #lemma to the file path to get a more precise link: https://coq.inria.fr/distrib/current/stdlib/Coq.Init.Logic.html#not_iff_compat.

Can't automate a lemma that works manually in Coq

(It seems that my previous question had too much irrelevant information, so I tried to abstract away the details. I'm not sure it's still the same problem, but I'll delete the other question if the same solution works for both.)
I'm trying to reason about some custom-defined lists and predicates :
Inductive alphabet := A.
Definition sentence : Type := list alphabet.
Variable pred1 : sentence -> Prop.
Variable pred2 : sentence -> Prop.
Variable conclusion : Prop.
Now, with the following hypotheses,
Hypothesis H1 : forall (X : sentence),
pred1 X -> pred2 (X ++ X).
Hypothesis H2 : forall X,
pred2 X -> conclusion.
I want to prove
Example manual : pred1 [A] -> conclusion.
Which is obviously true, since conclusion follows whenever some sentence has pred2, and pred1 for any sentence implies that the repetition of that sentence has pred2. A hand-written proof would be
intro. eapply H2. apply H1. exact H. Qed.
Notice that the proof uses nothing but intro, apply, eapply, and exact. This means that the proof should allow a straightforward automation, as long as H1 and H2 are available in the context. For instance, a semi-automatic version
Example semiauto : pred1 [A] -> conclusion.
pose proof H1. pose proof H2. eauto. Qed.
works exactly as you would expect. Now, let's try a fully automated version with hints :
Hint Resolve H1 H2.
Example auto : pred1 [A] -> conclusion.
eauto.
intro.
eauto.
eapply H2.
eauto.
apply H1.
eauto. Qed.
This is strange. eauto fails not only in the beginning, but for every step except the last. Why does this happen?
Some guesses : the consequent of H1 includes the form X ++ X, which might be causing problems with unification. Perhaps Coq performs some implicit cleanup with H1 when it is explicitly introduced to context, but not when it's just in hint DB.
Any ideas?
The issue is transparency of sentence.
Building on Anton Trunov's answer, if you look very closely, you'll notice that a difference between Print HintDb core and Create HintDb foo. Print HintDb foo. is that Print HintDb core says
Unfoldable variable definitions: none
Unfoldable constant definitions: none
while Create HintDb foo. Print HintDb foo. says
Unfoldable variable definitions: all
Unfoldable constant definitions: all
I constructed the following simplified version of your example:
Require Import Coq.Lists.List.
Import ListNotations.
Definition sentence := list nat.
Variable pred1 : sentence -> Prop.
Variable pred2 : sentence -> Prop.
Hypothesis H1 : forall (X : sentence),
pred1 X -> pred2 (X ++ X).
Create HintDb foo.
Hint Resolve H1 : foo.
Hint Resolve H1 : bar.
Hint Resolve H1.
Example ex1 : pred1 [0] -> exists X, pred2 X.
eexists.
debug eauto.
Here, we have that eauto and eauto with bar (and eauto with bar nocore, which removes the core database from eauto's consideration) both fail, but eauto with foo (and eauto with foo nocore) succeeds. This suggests that the issue is transparency. A bit of playing around resulted in me discovering that eauto will work if we write
Hint Transparent sentence.
Additionally, even without this, eauto works fine if we explicitly give the X variable the unfolded type:
Example ex2 : pred1 [0] -> exists X : list nat, pred2 X.
I am not entirely sure why Coq behaves this way... perhaps it is refusing to unify evars with terms which are of different types (if ?X has type sentence when X ++ X has type list), or perhaps it is a holdover of meta-based unification... I've opened an issue on the bugtracker about this lack of documentation / bad behavior.
A possible workaround here is to add the hints to a new user-defined database:
Create HintDb my_hints.
Hint Resolve H1 H2 : my_hints.
Now we can finish the proof:
Example auto : pred1 [A] -> conclusion.
eauto with my_hints. Qed.
One more thing: Coq's reference manual tells (ยง8.9.1) us that
One can optionally declare a hint database using the command Create HintDb. If a hint is added to an unknown database, it will be automatically created.
But if we omit the Create HintDb my_hints. part, the eauto tactic won't work. It looks like the same thing is going on when the hints are being added to the default core hint database.