Can any additional axiom make Coq Turing complete? - coq

Here I mean axiom as what we can define with the Axiom keyword in Coq Gallina, not with such command-line argument passing to Coq.
I know some axioms make Coq inconsistent. However, AFAIK they don't make Coq Turing complete. In my rough understanding, it's because they don't offer any additional computational behavior.
Is there one that makes Coq turning complete? If not, could you give a more concrete explanation of why it's impossible?

The answer to your question largely depends on where you want your functions defined in Coq to compute. In general, there is no problem to encode arbitrary partial functions in Coq using for instance step-indexing, see Mc Bride's "Turing completeness, totally free" for more details.
But you will only be able to evaluate these functions up to a specified finite bound in Coq.
If the goal is to write formally verified programs that could use arbitrary recursion and run them outside of Coq, then you don't need axioms, you can use the Extraction mechanism and its proof-erasure semantics as shown by the following example of an unbounded while loop:
Inductive Loop : Prop := Wrap : Loop -> Loop.
Notation next := (fun l => match l with Wrap l' => l' end).
Definition while {A : Type} (f : A -> A * bool) : Loop -> A -> A :=
fix aux (l : Loop) (a : A) {struct l} :=
let '(x, b) := f a in
if b then aux (next l) x else x.
Require Extraction.
Recursive Extraction while.
with extraction result:
type bool =
| True
| False
type ('a, 'b) prod =
| Pair of 'a * 'b
(** val while0 : ('a1 -> ('a1, bool) prod) -> 'a1 -> 'a1 **)
let rec while0 f x =
let Pair (x0, b) = f x in (match b with
| True -> while0 f x0
| False -> x0)
Note that the function while requires a proof of termination in Coq that is erased once it is turned to ocaml.
Finally, as you explain, you would need to extend Coq's computational reduction machinery if you wanted evaluation of partial functions to stay inside Coq. There is no general mechanism providing this feature at the moment (even though there is a coq enhancement proposal to add rewriting rules). It might be possible to abuse definitional UIP to evaluate partial functions. In all cases, adding the possibility to evaluate partial functions inside Coq, making it part of the conversion, automatically entails that the theory itself because undecidable (the proof assistant may fail to return a typechecking result).

Related

Classical axioms implies every proposition is decidable?

In the Lean manual 'Theorem proving in Lean' I read:
"With the classical axioms, we can prove that every proposition is decidable".
I would like to seek clarification about this statement and I am asking a Coq forum, as the question applies as much to Coq as it does to Lean (but feeling I am more likely to get an answer here).
When reading "With the classical axioms", I understand that we have something equivalent to the law of excluded middle:
Axiom LEM : forall (p:Prop), p \/ ~p.
When reading "every proposition is decidable", I understand that we can define a function (or at least we can prove the existence of such a function):
Definition decide (p:Prop) : Dec p.
where Dec is the inductive type family:
Inductive Dec (p:Prop) : Type :=
| isFalse : ~p -> Dec p
| isTrue : p -> Dec p
.
Yet, with what I know of Coq, I cannot implement decide as I cannot destruct (LEM p) (of sort Prop) to return something other than a Prop.
So my question is: assuming there is no mistake and the statement "With the classical axioms, we can prove that every proposition is decidable" is justified, I would like to know how I should understand it so I get out of the paradox I have highlighted. Is it maybe that we can prove the existence of the function decide (using LEM) but cannot actually provide a witness of this existence?
In the calculus of constructions without any axioms, there is meta-theoretical property that every proof of A \/ B is necessarily a proof that A holds (packaged using the constructor or_introl) or a proof that B holds (using the other constructor). So a proof of A \/ ~ A is either a proof that A holds or a proof that ~ A holds.
Following this meta-theoretical property, in Coq without any axioms, all proofs of propositions of the form forall x, P x \/ ~P x actually are proofs that P is decidable. In this paragraph, the meaning of decidable is the commonly accepted meaning, as used by computability books.
Some users started using the word decidable for any predicate P so that there exists a proof of forall x, P x \/ ~ P x. But they are actually talking about a different thing. To make it clearer, I will call this notion abuse-of-terminology-decidable.
Now, if you add an axiom like LEM in Coq, you basically state that every predicate P becomes abuse-of-terminology-decidable. Of course, you cannot change the meaning of conventionally-decidable by just adding an axiom in you Coq development, so there is no inclusion anymore.
I have been fighting against this abuse of terminology for years, but without success.
To be more precise, in Coq terminology, the term decidable is not used for propositions or predicates that enjoy LEM, but for propositions or predicates that enjoy the stronger following statement:
forall x, {P x}+{~P x}
Proofs of such propositions are often named with _dec suffix, where _dec directly refers to decidable. This abuse is less strong, but it is still an abuse of terminology.

apply rewrite tactic to sub-expression

How can I apply rewrite -> targetting only a sub-expression? For example, consider this theorem:
Parameter add : nat -> nat -> nat.
Axiom comm : forall a b, add a b = add b a.
Theorem t1 : forall a b : nat,
(add (add a b) (add a (add a b))) =
(add (add a b) (add a (add b a))).
Intuitively, it requires commuting only one (add a b) sub-expression, but if I do rewrite -> (comm a b), it rewrites all the occurrences. How can I target a particular sub-expression?
This is a case where the ssreflect matching facilities will usually be more convenient than "at" [I'd dare to say sub-term rewrites are often a cause of people switching to ssreflect's rewrite]. In particular:
rewrite {pos}[pat]lemma will select occurrences pos of pattern pat to rewrite,
pat can be a contextual pattern that may allow you improve the robustness of your scripts.
You can target a specific occurrence with the rewrite tactic using the suffix at N. Occurrences are numbered from 1 in left-to-right order. You can rewrite multiple occurrencess by separating their indices with spaces. You need Require Import Setoid. The at suffix is also available with some other tactics that target occurrences of a term, including many tactics that perform conversions (change, unfold, fold, etc.), set, destruct, etc.
intros.
rewrite -> (comm a b) at 2.
rewrite -> (comm _ _).
reflexivity.
There are other possible approaches, especially if all you need is to apply equalities. The congruence tactic can find what to rewrite and apply symmetry and transitivity on its own, but you need to prime it by adding all equivalences to the context (in the form of universally-quantified equalities), it won't query hint databases.
assert (Comm := comm).
congruence.
To get more automation, Hint Rewrite creates a database of theorems which the tactic autorewrite will try applying. For more advanced automation, look up generalized rewriting with setoids, which I'm not sufficiently familiar with to expound on.

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.

Why doesn't Coq's termination checker support the case where one argument gets structurally smaller and others remain the same

Coq's termination checker does not like functions like:
Fixpoint interleave (A : Type) (l1 l2 : list A) : list A :=
match l1 with
| cons h1 t1 => cons h1 (interleave l2 t1)
| nil => l2
end.
Some other languages with similar termination checkers, however, such as Lean, Idris and Isabelle, accept such functions. I'm wondering why Coq's termination checker will not accept such functions, where at least one argument gets structurally smaller each time, and no arguments get bigger. It seems to me that if at least one argument is always getting smaller and none are growing, the function must eventually terminate, or is there some case I'm missing?
Edit: Seems I've picked a terrible example here as apparently Idris and Lean cannot handle it either. A better example would be the fix-in-fix formulation given in How to deal with really large terms generated by Program Fixpoint in Coq?; I know I managed to implement that same function in Lean and Idris directly without requiring the fix-in-fix construction. Also, the original question still stands: why isn't that construction supported?
Like gallais suggests, you can use measure:
Require Import PeanoNat.
Require Import Coq.Program.Wf.
Program Fixpoint interleave (A : Type) (l1 l2 : list A) {measure (length l1 + length l2)} : list A :=
match l1 with
| nil => l2
| cons h1 t1 => cons h1 (interleave A l2 t1)
end.
Next Obligation.
simpl.
rewrite Nat.add_comm.
apply Nat.lt_succ_diag_r.
Defined.
Next Obligation.
Admitted.
After the definition you need to prove two things: first, that at each step the measure decreases; and second, that the measure is well founded. After completing the two proofs, your definition is done.

Tactics with variable arity

Say I want to have a tactic to clear multiple hypothesis at once, to do something like clear_multiple H1, H2, H3.. I tried to do that using pairs, like the following:
Ltac clear_multiple arg :=
match arg with
| (?f, ?s) => clear s; clear_multiple f
| ?f => clear f
end.
But then, the problem is that I have to place parenthesis to have a Prod:
Variable A: Prop.
Goal A -> A -> A -> True.
intros.
clear_multiple (H, H0, H1).
My question is, how to do that without using Prods ?
I checked this question, but it is not exactly what I want, since the number of arguments I want is not known.
You might like to know that the clear tactic can take multiple arguments, so you do not need to define a new tactic: you can just write clear H H0 H1.
Of course, you might want to define such n-ary tactics for other tasks. Coq has a tactic notation mechanism that supports such definitions. Unfortunately, they are not too powerful: you can only pass a list of arguments of a certain kind to a tactic that expects multiple arguments (like clear); I don't think it can give you a list that you can iterate on programmatically.