Theorem plus_n_n_injective, exercise - coq

Help needed with an exercise from Software Foundations. This is the theorem:
Theorem plus_n_n_injective : ∀n m,
n + n = m + m →
n = m.
Proof.
I end up with n = 0 as goal and n + n = 0 as hypothesis. How to move on?

n + n cannot be simplified further because n is a variable, not a type constructor.
You can expose all the construction cases of n by destructing it as Ptival said. However using inversion in this context seems to me a bit extreme and not what this Sf exercise is about.
When replaced by the O constructor, O + O will reduce (using simpl for example) to O and reflexivity should do the trick.
When replaced by the S constructor, S foo + bar will always reduce to the shape S something, which can't be equal to O (the easiest way to assert that is by using discriminate) because they are two constructors of the same type.
Best,
V.

If you inspect n (destruct it), it's either going to be 0 in which case the goal is provable by reflexivity, or S n' in which case the hypothesis is contradictory by congruence/inversion.

The trick to solving this problem can be garnered from the Theorem for length_snoc' previously shown in the same chapter.
As this was the first time so far in the book that introducing some of the variable/hypothesis after doing an induction on n, this may come off as unusual to newcomers (like me). This allows you to get a more general hypotheses in your context after proving for the base case.
As mentioned before, you will be able to prove some goals simply by reflexivity. Some of them can be proven by inversion on a false hypotheses in your context(those should become straightforward once you spot them, the idea that 2 + 2 = 5 -> anything is true can go a long way).
Finally, you will have to rework one of your hypotheses using the previously defined lemmas plus_n_Sm and eq_add_S as well as symmetry to be able to apply the more general hypotheses we discussed earlier.

Related

How does one access the dependent type unification algorithm from Coq's internals -- especially the one from apply and the substitution solution?

TLDR: I want to be able to compare two terms -- one with a hole and the other without the hole -- and extract the actual lambda term that complete the term. Either in Coq or in OCaml or a Coq plugin or in anyway really.
For example, as a toy example say I have the theorem:
Theorem add_easy_0'':
forall n:nat,
0 + n = n.
Proof.
The (lambda term) proof for this is:
fun n : nat => eq_refl : 0 + n = n
if you had a partial proof script say:
Theorem add_easy_0'':
forall n:nat,
0 + n = n.
Proof.
Show Proof.
intros.
Show Proof.
Inspected the proof you would get as your partial lambda proof as:
(fun n : nat => ?Goal)
but in fact you can close the proof and therefore implicitly complete the term with the ddt unification algorithm using apply:
Theorem add_easy_0'':
forall n:nat,
0 + n = n.
Proof.
Show Proof.
intros.
Show Proof.
apply (fun n : nat => eq_refl : 0 + n = n).
Show Proof.
Qed.
This closes the proof but goes not give you the solution for ?Goal -- though obviously Coq must have solved the CIC/ddt/Coq unification problem implicitly and closes the goals. I want to get the substitution solution from apply.
How does one do this from Coq's internals? Ideally while remaining in Coq but OCaml internals or coq plugin solutions or in fact any solution I am happy with.
Appendix 1: how did I realize apply must use some sort of "coq unification"
I knew that apply must be doing this because in the description of the apply tactic I know apply must be using unification due to it saying this:
This tactic applies to any goal. The argument term is a term well-formed in the local context. The tactic apply tries to match the current goal against the conclusion of the type of term. If it succeeds, then the tactic returns as many subgoals as the number of non-dependent premises of the type of term.
This is very very similar to what I once saw in a lecture for unification in Isabelle:
with some notes on what that means:
- You have/know rule [[A1; … ;An]] => A (*)
- that says: that given A1; …; An facts then you can conclude A
- or in backwards reasoning, if you want to conclude A, then you must give a proof of A1; …;An (or know Ai's are true)
- you want to close the proof of [[B1; …; Bm]] => C (**) (since thats your subgoal)
- so you already have the assumptions B1; …; Bm lying around for you, but you wish to be able to conclude C
- Say you want to transform subgoal (**) using rule (*). Then this is what’s going on:
- first you need to see if your subgoal (**) is a "special case" of your rule (*). You commence by checking if the conclusion (targets) of the rules are "equivalent". If the conclusions match then instead of showing C you can now show A instead. But for you to have (or show) A, you now need to show A1; … ;An using the substitution that made C and A match. The reason you need to show A1;...;An is because if you show them you get A automatically according to rule (*) -- which by the "match" (unification) shows the original goal you were after. The main catch is that you need to do this by using the substitution that made A and C match. So:
- first see if you can “match” A and C. The conclusions from both side must match. This matching is called unification and returns a substitution sig that makes the terms equal
- sig = Unify(A,C) s.t. sig(A) = sig(C)
- then because we transformed the subgoal (**) using rule (*), we must then proceed to prove the obligations from the rule (*) we used to match to conclusion of the subgoal (**). from the assumptions of the original subgoal in (**) (since those are still true) but using the substitution sig that makes the rules match.
- so the new subgoals if we match the current subgoal (*) with rule (**) is:
- [[sig(B1); … ; sig(Bm) ]] => sigm(A1)
- ...
- [[sig(B1); … ; sig(Bm) ]] => sigm(An)
- Completing/closing the proof above (i.e. proving it) shows/proves:
- [[sig(B1); …;sig(Bm) ]] => sig(C)
- Command: apply (rule <(*)>) where (*) stands for the rule names
Appendix2: why not exact?
Note that initially I thought exact was the Coq tactic I wanted to intercept but I was wrong I believe. My notes on exact:
- exact p. (assuming p has type U).
- closes a proof if the goal term T (i.e. a Type) matches the type of the given term p.
- succeeds iff T and U are convertible (basically, intuitively if they unify https://coq.inria.fr/refman/language/core/conversion.html#conversion-rules since are saying if T is convertible to U)
conversion seems to be equality check not really unification i.e. it doesn't try to solve a system of symbolic equations.
Appendix 3: Recall unification
brief notes:
- unification https://en.wikipedia.org/wiki/Unification_(computer_science)
- an algorithm that solves a system of equations between symbolic expressions/terms
- i.e. you want
- cons2( cons1( x, y, ...,) ..., cons3(a, b, c), ... ) = cons1(x, nil)
- x = y
- basically a bunch of term LHS term RHS and want to know if you can make them all equal given the terms/values and variables in them...
- term1 = term2, term3 = term4 ? with some variables perhaps.
- the solution is the substitution of the variables that satisfies all the equations
bounty
I'm genuinely curious about intercepting the apply tactic or call its unification algorithm.
apply indeed solve a unification, according to the document.
The tactic apply relies on first-order unification with dependent types unless the conclusion of the type of term is of the form P (t1 ... tn) with P to be instantiated.
Note that generally, the apply will turn one "hole" to several "hole"s that each cooresponds to a subgoal generated by it.
I have no idea how to access the internal progress of apply and get the substitution it uses.
However, You can call unify t u to do unification maully. you can refer to the official document. As far as I am concerned, the unicoq plugin provides another unification algorithm, and you can use munify t u to find unification between two items, see the Unicoq official repo.
An example of using unify and mutify:
From Unicoq Require Import Unicoq.
Theorem add_easy_0'':
forall n:nat,
0 + n = n.
Proof.
Show Proof.
intros.
Show Proof.
refine ?[my_goal].
Show my_goal.
munify (fun t : nat => eq_refl : 0 + t = t) (fun n : nat => ?my_goal).
(* unify (fun t : nat => eq_refl : 0 + t = t) (fun n : nat => ?my_goal). *)
Qed.
However, I wonder whether I have understand your question correctly.
Do you want to name the goal?
If you want to "extract the actual lambda term that complete the (parial) term". The so-called "lamda term" is the goal at that time, isn't it? If so, why to you want to "extract" it? It is just over there! Do you want to store the current subgoal and name it? If so, the abstract tactic perhaps helps, as mentioned in How to save the current goal / subgoal as an `assert` lemma
For example:
Theorem add_easy_0'':
forall n:nat,
0 + n = n.
Proof.
Show Proof.
intros.
Show Proof.
abstract apply eq_refl using my_name.
Check my_name.
(*my_name : forall n : nat, 0 + n = n*)
Show Proof.
(*(fun n : nat => my_name n)*)
Qed.
Do you want to get the substituion?
Are you asking a substituion that make the goal term and the conclusion of the theorem applied match? For example:
Require Import Arith.
Lemma example4 : 3 <= 3.
Proof.
Show Proof.
Check le_n.
(* le_n : forall n : nat, n <= n *)
apply le_n.
Are you looking forward to get something like n=3? If you want to get such a "substitution", I am afraid the two tactics mentioned above will not help. Writing OCaml codes should be needed.
Do you want store the prove of current goal?
Or are you looking forward to store the proof of the current goal? Perhaps you can try assert, as mentioned in Using a proven subgoal in another subgoal in Coq.

Searching for a counterexample to a decidable predicate

It feels like the following Coq statement should be true constructively:
Require Import Decidable.
Lemma dec_search_nat_counterexample (P : nat -> Prop) (decH : forall i, decidable (P i))
: (~ (forall i, P i)) -> exists i, ~ P i.
If there were an upper bound, I'd expect to be able to show something of the form "suppose that not every i < N satisfies P i. Then there is an i < N where ~ P i". Indeed, you could actually write a function to find a minimal example by searching from zero.
Of course, there's not an upper bound for the original claim, but I feel like there should be an inductive argument to get there from the bounded version above. But I'm not clever enough to figure out how! Am I missing a clever trick? Or is there a fundamental reason that this cann't work, despite the well-orderedness of the natural numbers?
Reworked answer after Meven Lennon-Bertrand's comment
This statement is equivalent to Markov's principle with P and ~P exchanged. Since P is decidable we have P <-> (~ ~ P), so that one can do this replacement.
This paper (http://pauillac.inria.fr/~herbelin/articles/lics-Her10-markov.pdf) suggest that Markov's principle is not provable in Coq, since the author (one of the authors of Coq) suggests a new logic in this paper which allows to prove Markov's principle.
Old answer:
This is morally the "Limited Principle of Omniscience" - LPO (see https://en.wikipedia.org/wiki/Limited_principle_of_omniscience). It requires classical axioms to prove it in Coq - or you assert itself as an axiom.
See e.g.:
Require Import Coquelicot.Markov.
Check LPO.
Print Assumptions LPO.
Afair there is no standard library version of it.

proof Lemma which based on Fixpoint definitions

Trying to prove following Lemma:
I have tried unfold nth_error and nth in the goal but I cannot figure out a way to tell Coq to break the Fixpoint definition of these two functions. I have also tried to induction on n and the lists but none of them was able to solve the problem since the items in list are irrelevant with each other. But this is obviously a correct Lemma, right now I feel it is un-provable, anyone can help me solve this problem? Much appreciated!
Lemma nth_error_nth :
forall nodes1 (node : node) n,
n < length nodes1 ->
nth_error nodes1 n = Some (nth n nodes1 node).
Your question should really be edited to include a Minimal, Reproducible Example so we don't need to guess what definitions you're using. I'm assuming you're using the standard library's List module and that node is simply some type. Without any more information, I'll just assume it's something like Variable node: Type.
To prove this lemma, induction on the list itself should work. You'll probably also need to do case analysis on n (try destruct n) since n_th and a few other things depend on whether n is 0 or not. If something seems like it might be impossible to prove, try strengthening the inductive hypothesis. This involves having more hypotheses in the goal when you use induction. You can accomplish this with revert or simply never intro the hypothesis in question.
You'll likely get some absurd hypotheses, like n < 0. You can use some the lemmas in PeanoNat.Nat to derive a contradiction from this. It might be helpful to use the Search vernacular. For example, Search (?n < 0). finds the lemma I referred to. There's also one step where you'll need to conclude m < n from S m < S n, which can be done with Lt.lt_S_n.
Just to get you started, here's the beginning of a proof.
Lemma nth_error_nth :
forall nodes1 (node : node) n,
n < (length nodes1) ->
nth_error nodes1 n = Some (nth n nodes1 node).
Proof.
(* we don't intro n since we'll need to apply
the inductive hypothesis to two different values of n *)
intros nodes1 node.
induction nodes1 as [ | a nodes1 IH].

Is it possible to prove 'implies_to_or -> de_morgan_not_and_not' without resorting to other classical laws?

Theorem implies_to_or_to_de_morgan_not_and_not :
implies_to_or -> de_morgan_not_and_not.
Proof.
unfold implies_to_or, de_morgan_not_and_not, not.
intros.
Admitted.
1 subgoal
H : forall P Q : Prop, (P -> Q) -> (P -> False) \/ Q
P, Q : Prop
H0 : (P -> False) /\ (Q -> False) -> False
______________________________________(1/1)
P \/ Q
This is from the 5 star exercise near the end of SF Logic chapter.
I've bashed my head against this particular problem for too many hours now, so I really have to ask at this point. I've already proven excluded_middle <-> peirce, peirce <-> double_negation_elimination, double_negation_elimination <-> de_morgan_not_and_not, implies_to_or <-> excluded_middle, de_morgan_not_and_not -> implies_to_or so I already have more than all the paths covered. To me that only makes this problem that much more confusing and I do not understand why I can't even get this proof off the ground.
Somehow there just is not that much to work with here.
One option would be to do exfalso and try to do something from there, but that would throw away the P \/ Q goal and I suspect that would be too much of a loss of information even if I could make some kind of headway.
Another option would be to try and destruct H, but in that case there is a problem of trying to prove P -> Q without anything usable being in the premise.
I've had trouble with exercises in the past week and managed to surmount them with effort, but I am not experienced enough to just let this thing lie without asking for advice. What exactly am I not seeing here?
Obviously, I do not want to convert de_morgan_not_and_not to some other
easier to solve classical law (like the excluded middle) as that would be besides the point.
Since the Software Foundations book explicitly asks not to publish solutions, let me give a hint.
Notice that the hypothesis H is universally quantified wrt both propositions it talks about.
This means you can supply any propositions for P and Q, even same ones. Basically, this observation lets you reason classically, which is enough to solve this problem.
Is there a particular reason you don't want to use your other proofs to prove this? It's fairly artificial to avoid using a result that you know is unconditionally true.
You can avoid manipulating de_morgan_not_and_not by using implies_to_or to perform case analysis on P and Q (refer to your proof of implies_to_or -> excluded_middle). Then you have four cases to look at, and all four resulting goals are simple 1-3 line proofs.

How to perform induction over two inductive predicates?

I am starting with Coq and trying to formalize Automated Amortised Analysis. I am at lemma 4.13:
Lemma preservation : forall (Sigma : prog_sig) (Gamma : context) (p : program)
(s : stack) (h h' : heap) (e : expr) (c : type0) (v : val),
(* 4.1 *) has_type Sigma Gamma e c ->
(* 4.2 *) eval p s h e v h' ->
(* 4.3 *) mem_consistant_stack h s Gamma ->
(* 4.a *) mem_consistant h' v c /\ (* 4.b *) mem_consistant_stack h' s Gamma.
Proof.
intros Sigma Gamma p s h h' e c v WELL_TYPED EVAL.
The manual proof uses a double induction:
Proof. Note that claim (4.b) follows directly by Lemma 4.8 and Lemma
4.12. Each location l ∈ dom( H ) is either left unaltered or is overwritten by the value Bad and hence does not invalidate memory
consistency.
However, the first claim (4.a) requires a proof by
induction on the lengths of the derivations of (4.2) and (4.1) ordered
lexicographically with the derivation of the evaluation taking
priority over the typing derivation. This is required since an in-
duction on the length of the typing derivation alone would fail for
the case of function application: in order to allow recursive
functions, the type rule for application is a terminal rule relying on
the type given for the function in the program’s signature. However,
proving this case requires induction on the statement that the body of
the function is well-typed, which is most certainly a type derivation
of a longer length (i.e. longer than one step), prohibiting us from
using the induction hypothesis. Note in this particular case that the
length of the derivation for the evaluation statement does decrease.
An induction over the length of the derivation for premise (4.2) alone
fails similarly. Consider the last step in the derivation of premise
(4.1) being derived by the application of a structural rule, then the
length of the derivation for (4.2) remains exactly the same, while the
length of the derivation for premise (4.1) does decrease by one step.
Using induction on the lexicographically ordered lengths of the type
and evaluation derivations allows us to use the induction hypothesis
if either the length of the deriva- tion for premise (4.2) is
shortened or if the length of the derivation for premise (4.2) remains
unchanged while the length of the typing derivation is reduced. We
first treat the cases where the last step in the typing derivation was
obtained by application of a structural rule, which are all the cases
which leave the length of the derivation for the evaluation unchanged.
We then continue to consider the remaining cases based
604.3 Operational Semantics on the evaluation rule that had been applied last to derive premise (4.2), since the remaining type rules
are all syntax directed and thus unambiguously determined by the
applied evaluation rule.
How can such a "double induction" be performed in Coq?
I tried induction EVAL; induction WELL_TYPED, but got 418 subgoals, most of wich are unprovable.
I also tried to start with induction EVAL and use induction WELL_TYPED later, but go stucked in a similar situation.
I agree with #jbapple that a minimal example is better. That said, it may be that you are simply missing a concept of length of derivation. Note that the usual concept of proof by induction over a predicate actually implements something that is close to induction over the height of derivations, but not quite.
I propose that you exhibit two new predicates eval_n and
has_type_n that each express the same as eval
and has_type, but with an extra argument with meaning "... and derivation has size n". There are several ways in which size might be defined but I suspect that height will be enough for you.
Then you can prove
eval a1 .. ak <-> exists n, eval_n a1 .. ak n
and
has_type a1 .. ak <-> exists n, has_type a1 .. ak n
You should then be able to prove
forall p : nat * nat, forall a1 ... ak, eval_n a1 .. ak (fst p) ->
has_type_n a1 .. ak (snd p) -> YOUR GOAL
by well founded induction on pairs of natural numbers, using the lexical order construction of library Wellfounded (I suggest library Lexicographic_Product.v, it is a bit of an overkill for just pairs of natural numbers, but you only need to find the right instantiation).
This will be unwieldy because induction hypotheses will only refer to pairs
of numbers that are comparable for the lexical order, and you will have to perform inversions on the hypotheses concerning eval_n and has_type_n, but that should go through.
There probably exists a simpler solution, but for lack of more information from your side, I can only propose the big gun.