What does the "functional induction" tactic do in Coq? - coq

I have used functional induction in this proof that I have been trying. As far as I understand, it essentially allows one to perform induction on all parameters of a recursive function "at the same time".
The tactics page states that:
The tactic functional induction performs case analysis and induction following the definition of a function. It makes use of a principle generated by Function
I assume that principle is something technical whose definition I do not know. What does it mean?
In the future, how do I find out what this tactic is doing? (Is there some way to access the LTac?)
Is there a more canonical way of solving the theorem which I pose below?
Require Import FunInd.
Require Import Coq.Lists.List.
Require Import Coq.FSets.FMapInterface.
Require Import FMapFacts.
Require Import FunInd FMapInterface.
Require Import
Coq.FSets.FMapList
Coq.Structures.OrderedTypeEx.
Module Import MNat := FMapList.Make(Nat_as_OT).
Module Import MNatFacts := WFacts(MNat).
Module Import OTF_Nat := OrderedTypeFacts Nat_as_OT.
Module Import KOT_Nat := KeyOrderedType Nat_as_OT.
(* Consider using https://coq.inria.fr/library/Coq.FSets.FMapFacts.html *)
(* Consider using https://coq.inria.fr/library/Coq.FSets.FMapFacts.html *)
(* Consider using https://coq.inria.fr/library/Coq.FSets.FMapFacts.html *)
Definition NatToNat := MNat.t nat.
Definition NatToNatEmpty : NatToNat := MNat.empty nat.
(* We wish to show that map will have only positive values *)
Function insertNats (n: nat) (mm: NatToNat) {struct n}: NatToNat :=
match n with
| O => mm
| S (next) => insertNats next (MNat.add n n mm)
end.
Theorem insertNatsDoesNotDeleteKeys:
forall (n: nat) (k: nat) (mm: NatToNat),
MNat.In k mm -> MNat.In k (insertNats n mm).
intros n.
intros k mm.
intros kinmm.
functional induction insertNats n mm.
exact kinmm.
rewrite add_in_iff in IHn0.
assert(S next = k \/ MNat.In k mm).
auto.
apply IHn0.
exact H.
Qed.

The "principle" just means "an induction principle" - a complete set of cases that must be proved in order to prove some motive "inductively".
The difference between Function and Fixpoint in Coq is that the former creates an induction principle and recursion principle based on the given definition, and then each return value is passed in (as a lambda, if there are variables bound by case analysis or there is a recursive call's value involved). This generally computes slower. The principles generated are with respect to a generated Inductive type, each variant of which is a case of the function's call scheme. The latter Fixpoint uses Coq's limited termination analysis to justify the well-foundedness of a function's recursion*. Fixpoint is faster, because it uses OCaml's own pattern matching and direct recursion in computation.
How is the induction scheme created? First, all the function parameters are abstracted into a forall. Then, each branch of a match expression creates a new case to prove for the scheme (the number of cases multiplies for each nested match). All the "return" positions in a function are in scope of some number of match expressions' bindings; each binding is an argument to an induction case that must produce the motive on the reconstructed arguments (e.g., if in the case of a list A's cons, we have an a : A and a list_a : list A binding, so then we must produce a Motive (cons a list_a) result). If there is a recursive call with the list_a argument, then we get a further binding of an induction hypothesis of type Motive list_a.
An actual Coq implementer will probably correct me on the specifics of the above, but it's more or less how induction schemes are inferred from well-founded recursive functions.
This is all fairly rough, and better explained in the documentation on Function and Functional Scheme.
The termination analysis is maybe was too smart for its own good. It needed to be revised (by IIRC Maxime Dénès, good job) following a proof of False given (a consequence of) the univalence axiom.

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.

Is there any way to rewrite the function in "is_lim"?

I'm using Coq and Coquelicot Library, and I'd like to know a better way to handle limit easily.
When I want to prove \lim_{x \to 1} (x^2-1)/(x-1) = 2, I code as follows.
Require Import Reals Lra.
From mathcomp Require Import all_ssreflect.
From Coquelicot Require Import Coquelicot.
Lemma lim_1_2 : is_lim (fun x:R => (x^2 - 1)/(x - 1)) 1 2.
Proof.
apply (is_lim_ext_loc (fun x:R => x + 1)).
- rewrite /Rbar_locally' /locally' /within /locally.
exists (mkposreal 1 Rlt_0_1).
move => y Hyball Hyneq1.
field; lra.
- apply is_lim_plus'; [apply is_lim_id | apply is_lim_const].
Qed.
In this example, I explicitly write the goal term (fun x:R => x + 1). Is there any way to transform (fun x:R => (x^2 - 1)/(x - 1)) to (fun x:R => x + 1) like rewrite tactic? In other words, I'm looking for a similar tactic as under for eq_big_nat.
Coquelicot is optimized for ease of use and uses total functions rather than dependent restrictions wherever possible - e.g. you can write down an integral without having a prove that it exists, but as far as I know this does not extend to division by zero. To make your above equation work, one would need a definition of division, which somehow can handle the 0/0 you get for x=1. One can define a division for functions (polynomials) which can handle this in a reasonable way - and this is what you are using implicitly by stating that this makes sense, but one cannot define division for individual real numbers which can handle 0/0 in the way you would like. But the division operator you use above is a division on individual numbers and not on polynomials. In informal mathematics one is sometimes a bit sloppy about such things.
Besides the 0/0 issue, you also would have to use the axiom of functional extensionality, which states that two functions are equal in case they are equal for each point.
Here is a snippet of Coq which shows what one can be done and where the issues are :
Require Import Reals.
Require Import Lra.
Require Import FunctionalExtensionality.
Open Scope R.
Definition dom := {x : R | x<>1}.
Definition dom2R (x : dom) : R := proj1_sig x.
Coercion dom2R : dom >-> R.
Example Example:
(fun x : dom => (x^2 - 1)/(x - 1))
= (fun x : dom => x + 1).
Proof.
apply functional_extensionality.
intros [x xH].
cbv.
field.
lra.
Qed.
All in all it is not that bad with the implicit coercion from dom to Real, although the function is in reality more complicated than it looks since each x is an implicit coercion projecting from dom to R.
Also one could have an axiom of functional extensionality, which works if the domain of one function is a subset of the domain of the other function. I am not sure if this would be consistent, though and it would also require a non standard definition of equality because with the usual equality only things of the same type can be equal. This would allow you to equate the polynomial fraction with the polynomial on the full R.
I hope this explains why things are as they are. Coquelicot relies on the division operator from the standard library, for which you can't prove anything in case the denominator is zero. This is sometimes inconvenient, but to my knowledge (which is not very extensive - I am physicist not mathematician) up to now nobody came up with a definition of division which allows you to easily do what you want.

Equality of finite maps in coq (defined using map2)

Suppose I want to define a type of Monomials in Coq. These would be finite maps from some ordered set of variables to nat where, say, x²y³ is represented by the map that sends x to 2, y to 3 and where everything else gets the default value, zero.
The basic definitions don't seem so hard:
Require Import
Coq.FSets.FMapFacts
Coq.FSets.FMapList
Coq.Structures.OrderedType.
Module Monomial (K : OrderedType).
Module M := FMapList.Make(K).
Module P := WProperties_fun K M.
Module F := P.F.
Definition Var : Type := M.key.
Definition Monomial : Type := M.t nat.
Definition mon_one : Monomial := M.empty _.
Definition add_at (a : option nat) (b : option nat) : option nat :=
match a, b with
| Some aa, Some bb => Some (aa + bb)
| Some aa, None => Some aa
| None, Some bb => Some bb
| None, None => None
end.
Definition mon_times (M : Monomial) (M' : Monomial) : Monomial :=
M.map2 add_at M M'.
End Monomial.
At this point, I'd like to prove something like:
Lemma mon_times_comm : forall M M', mon_times M M' = mon_times M' M.
I can see how to prove that the two maps are Equal using the lemma Equal_mapsto_iff, but I'd really like to say that my type really represents monomials and that multiplication is genuinely commutative (and the maps are eq).
I'm pretty new to Coq: is this a reasonable thing to try to prove?
Also, I realise that this might depend on the finite map implementation: if FMapList was the wrong choice and another implementation makes this easier, please point me at that!
I can see how to prove that the two maps are Equal using the lemma Equal_mapsto_iff, but I'd really like to say that my type really represents monomials and that multiplication is genuinely commutative (and the maps are eq).
I'm pretty new to Coq: is this a reasonable thing to try to prove?
Also, I realise that this might depend on the finite map implementation: if FMapList was the wrong choice and another implementation makes this easier, please point me at that!
Indeed, you are on the right track. The set type you are using doesn't have the property that two sets with the same elements are definitionally equal in Coq. As such sets are implemented as binary trees you may have Node(A, Node(B,C)) <> Node(Node(A,B),C).
In particular, having a good "set type" is an extremely challenging task in Coq due to several issues, see the anwser How to define set in coq without defining set as a list of elements for a bit more of discussion.
Doing proper algebra does indeed require a lot of complex infrastructure, #ErikMD's pointer is the right one, you should have a look at math-comp and related papers to get an understanding on the state of the art. Of course, keep experimenting!
Regarding the formalization of monomials and multivariate polynomials in Coq, you could consider using the multinomials library. It is available on OPAM:
$ opam install coq-mathcomp-multinomials
and it naturally proves a similar result to your mon_times_comm lemma:
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
From mathcomp Require Import choice finfun tuple fintype ssralg bigop.
From SsrMultinomials Require Import freeg mpoly.
Lemma test1 (n : nat) (m1 m2 : 'X_{1..n}) : (m1 + m2 = m2 + m1)%MM.
Proof.
move=> *.
by rewrite addmC.
Qed.
Lemma test2 (n : nat) (R : comRingType) (p q : {mpoly R[n]}) :
(p * q = q * p)%R.
Proof.
move=> *.
by rewrite mpoly_mulC.
Qed.
Note that the multinomials library is built upon the MathComp library that is strongly related to the SSReflect extension of the Coq proof language.
Finally, note that this library is very convenient to develop Coq proofs involving multinomial polynomials, but doesn't directly allow computing with these Coq datatypes (Eval vm_compute in ...). If you are also interested in that aspect, you may also want to take a look at the CoqEAL library (and in particular its multipoly.v theory that relies on FMaps).

{assumption, apply, intro} is sufficient for min prop logic

I read that the set {assumption, apply, intro} of tactics from Ltac is sufficient to prove any tautology in the minimal constructive propositional logic.
I suppose that a pen-and-paper proof of this claim is done by induction on the syntax of a tautology by showing that the 3 tactics can build incrementally a term that represent the tautology.
I am interested to know if an alternative proof inside Coq using Ltac or other meta-language could be possible.
It would mean that Ltac or an alternative meta-language could reflect on what these tactics really do and could manipulate them as variables.
I am much interested in a positive answer in this direction even if it is a bit contrived.
Actually, just apply is sufficient. Just apply a proof term with the correct type. Or to be really lean, don't use any Ltac at all, just assign the proof term with
Definition name : < proposition > := < proof term >.
Example:
Lemma has_next : forall n, exists n', S n = n'.
Proof.
intro n.
exists (S n).
reflexivity.
Qed.
can be "proved" by giving the proof term directly.
Definition has_next : forall n, exists n', S n = n' := fun n => ex_intro _ (S n) eq_refl.
You know, there is nothing magical about the Ltac commands. They are just tools that make it easier to create the proof term little by little, but you can supply the whole proof term in one go, if you want to use as few tactics as possible.
The "proof" comes from the fact that you have shown that there really exists a proof term with the required type (the proposition). And Coq type-checks the term for you, to make sure that the term actually has that type.
Coq doesn't even care how the term was constructed - by divine insight or from a partially buggy program, as long as the term type checks.

Why Coq doesn't allow inversion, destruct, etc. when the goal is a Type?

When refineing a program, I tried to end proof by inversion on a False hypothesis when the goal was a Type. Here is a reduced version of the proof I tried to do.
Lemma strange1: forall T:Type, 0>0 -> T.
intros T H.
inversion H. (* Coq refuses inversion on 'H : 0 > 0' *)
Coq complained
Error: Inversion would require case analysis on sort
Type which is not allowed for inductive definition le
However, since I do nothing with T, it shouldn't matter, ... or ?
I got rid of the T like this, and the proof went through:
Lemma ex_falso: forall T:Type, False -> T.
inversion 1.
Qed.
Lemma strange2: forall T:Type, 0>0 -> T.
intros T H.
apply ex_falso. (* this changes the goal to 'False' *)
inversion H.
Qed.
What is the reason Coq complained? Is it just a deficiency in inversion, destruct, etc. ?
I had never seen this issue before, but it makes sense, although one could probably argue that it is a bug in inversion.
This problem is due to the fact that inversion is implemented by case analysis. In Coq's logic, one cannot in general perform case analysis on a logical hypothesis (i.e., something whose type is a Prop) if the result is something of computational nature (i.e., if the sort of the type of the thing being returned is a Type). One reason for this is that the designers of Coq wanted to make it possible to erase proof arguments from programs when extracting them into code in a sound way: thus, one is only allowed to do case analysis on a hypothesis to produce something computational if the thing being destructed cannot alter the result. This includes:
Propositions with no constructors, such as False.
Propositions with only one constructor, as long as that constructor takes no arguments of computational nature. This includes True, Acc (the accessibility predicated used for doing well-founded recursion), but excludes the existential quantifier ex.
As you noticed, however, it is possible to circumvent that rule by converting some proposition you want to use for producing your result to another one you can do case analysis on directly. Thus, if you have a contradictory assumption, like in your case, you can first use it to prove False (which is allowed, since False is a Prop), and then eliminating False to produce your result (which is allowed by the above rules).
In your example, inversion is being too conservative by giving up just because it cannot do case analysis on something of type 0 < 0 in that context. It is true that it can't do case analysis on it directly by the rules of the logic, as explained above; however, one could think of making a slightly smarter implementation of inversion that recognizes that we are eliminating a contradictory hypothesis and adds False as an intermediate step, just like you did. Unfortunately, it seems that we need to do this trick by hand to make it work.
In addition to Arthur's answer, there is a workaround using constructive_definite_description axiom. Using this axiom in a function would not allow to perform calculations and extract code from it, but it still could be used in other proofs:
From Coq Require Import Description.
Definition strange1: forall T:Type, 0>0 -> T.
intros T H.
assert (exists! t:T, True) as H0 by inversion H.
apply constructive_definite_description in H0.
destruct H0 as [x ?].
exact x.
Defined.
Or same function without proof editing mode:
Definition strange2 (T: Type) (H: 0 > 0): T :=
proj1_sig (constructive_definite_description (fun _ => True) ltac: (inversion H)).
Also there's a stronger axiom constructive_indefinite_description that converts a proposition exists x:T, P x (without uniqueness) into a corresponding sigma-type {x:T | P x}.