Simple syntax for terms of decidable subset types - coq

I have a type BoundedNat n, representing natural numbers smaller than n. My current implementation is as follows:
Definition BoundedNat n := {x : nat | x < n}.
Manipulating elements of type BoundedNat n is relatively heavyweight. I constantly need to wrap (using exist n ltac:(lia)) and unwrap (using proj1_sig) elements. How can I best piggyback off the underlying type's notations, equality, ordering, etc.?

Though you can definitely roll up your own implementation of bounded natural numbers, I strongly encourage you to reuse an existing one. My favorite library for that is ssreflect. It contains an ordinal n type family that corresponds to your BoundedNat, defined in fintype.v (doc here). There is a coercion from ordinal to nat so that you can readily reuse most operators on natural numbers transparently -- e.g. you can write i < j directly when i j : ordinal n.
Building terms of ordinal is more complicated, since it requires the proof argument. There is no best way of finding this proof, so the way to proceed depends on the application. For instance, adding a constant to a bounded nat is common enough to deserve a specialized operation in ssreflect:
rshift : forall m n, ordinal n -> ordinal (m + n)
One of the advantages of using ssreflect is that it comes with generic support for subset types like ordinal. For instance, there is a insub : nat -> option (ordinal n) function that succeeds if an only if its argument is bounded by n. This function works not only for nat and ordinal, but for any pair of types connected by the subtype interface: sT is a subtype of T if it is of the form {x : T | P x} for some boolean predicate P. Thus, you can manipulate subtypes with a consistent interface rather than rolling up your own each time.

Related

Equality between two propositions nat -> nat

I am currently working in a project in coq where I need to work with lists of nat -> nat. So basically I will have a definition that takes a list (nat -> nat) and a proposition f : nat -> nat as parameters and the goal is to retrieve the index of f in the given list.
What I did is that I implemented a fixpoint going through the list and comparing each elements to f with equality =. But I found out that this was not correct and equality at such types are undecidable.
Does anyone know an alternative to solve this ? Or an easier way to retrieve the index of f in the list ?
I am not sure why you would call f : nat -> nat a proposition and not a function but in any case, unless you have more hypotheses on the contents of l, I don't think there is a solution to your problem.
As you point out, equality of functions is not decidable in general. You can only perform a finite amount of observations on them (like calling f 0 and examining the result). If you know your functions to be different enough then it might be enough to check whether they agree on a few (carefully chosen) specific values but otherwise I do not see a way out.
Perhaps is it that you oversimplified your problem/task at hand and the real problem you have does have a solution. At the moment, the problem is not related to Coq.
For the record, it seems unlikely that you really want/need this, provided that the general problem is undecidable (as Théo explained). However, for the sake of answering the question:
If you know for sure that your input list has exactly one occurrence of the function f you are looking for (where functions are identified by their pointwise equality), then all other functions of the list disagree with f at some point. In other words, for each of the other functions, there exists a k : nat such that g k ≠ f k.
Since nat is enumerable, that integer comparison is decidable, and that the list is finite, there is a terminating algorithm to solve this problem. In imperative pseudo-code:
input: a function f : nat → nat
input: a list of functions [ g[0] ; g[1] ; … ; g[n−1] ] : list (nat → nat)
start:
candidates := { 0 ; 1 ; … ; n−1 } (set of cardinal n)
k := 0
while true do:
if card candidates < 2 then:
return the only candidate
for all i in candidates do:
if f k ≠ g[i] k then:
candidates := candidates \ { i }
k := k+1
end
If the list has several occurrences of f, then the algorithm never terminates (the occurrences remain candidates forever). If there is zero or one occurrence, the algorithm terminates but there is no way of deciding whether the remaining candidate is totally equal to f.
Hence the assumption stated above is necessary for termination and correction. That’s likely not easy to implement in Coq, especially since you have to convince Coq of the termination. Good luck if that’s really what you want. ;-)

Cardinality of Prop, Set and Type_i in Coq

Can we assign cardinals in Coq to Prop, Set and each Type_i ? I only see the definition of finite cardinals in Coq's library, so maybe we need that of big cardinals to begin with.
According to the proof-irrelevance semantics, for example exposed here, Set and the Type_i form an increasing sequence of inaccessible cardinals. Can this be proven in Coq ?
Prop seems more complex because of impredicativity. Proof-irrelevance means we identify all proofs of the same P : Prop, and interpret Prop itself as the pair {false, true}. So the cardinal of Prop would be 2. However, for any two proofs p1 p2 : P, Coq does not accept eq_refl p1 as a proof of p1 = p2. So Coq does not completely identify p1 and p2. And on the other hand, impredicativity means that for any A : Type and P : Prop, A -> P is of type Prop. That makes a lot more inhabitants than in Set.
If this is too hard, can Coq prove that Prop and Set are uncountable ? By Cantor's theorem, Coq easily proves that there is not surjection nat -> (nat -> Prop). This does not seem very far from proving there is not surjection nat -> Prop. But then we need the filter Prop -> (nat -> Prop), that isolates which Prop's have a free nat variable. Can we define this filter in Coq, since we cannot pattern-match on Prop ?
It is not possible to show that Prop is uncountable inside Coq. The ClassicalFacts module in the standard library shows that the axiom of propositional degeneracy, forall A : Prop, A = True \/ A = False, is equivalent to the presence of the excluded middle and propositional extensionality. Since Coq's set theoretic model validates these two axioms, Coq cannot refute degeneracy.
It is certainly possible to show that Set and Type are infinite, since they contain all types Fin n of natural numbers bounded by n, and these types are provably different from one another since they have different cardinality. I suspect that it is possible to show that they are uncountable by adapting the usual diagonalization argument -- that is, assume that some invertible count function e : nat -> Set, and try to encode something like the type of all natural numbers that "do not contain themselves". I do not know how you would go about proving that these types are inaccessible cardinals.

Definition by property in coq

I am having trouble with formalizing definitions of the following form: define an integer such that some property holds.
Let's say that I formalized the definition of the property:
Definition IsGood (x : Z) : Prop := ...
Now I need a definition of the form:
Definition Good : Z := ...
assuming that I proved that an integer with the property exists and is unique:
Lemma Lemma_GoodExistsUnique : exists! (x : Z), IsGood x.
Is there an easy way of defining Good using IsGood and Lemma_GoodExistsUnique?
Since, the property is defined on integer numbers, it seems that no additional axioms should be necessary. In any event, I don't see how adding something like the axiom of choice can help with the definition.
Also, I am having trouble with formalizing definitions of the following form (I suspect this is related to the problem I described above, but please indicate if that is not the case): for every x, there exists y, and these y are different for different x. Like, for example, how to define that there are N distinct good integer numbers using IsGood:
Definition ThereAreNGoodIntegers (N : Z) (IsGood : Z -> Prop) := ...?
In real-world mathematics, definitions like that occur every now and again, so this should not be difficult to formalize if Coq is intended to be suitable for practical mathematics.
The short answer to your first question is: in general, it is not possible, but in your particular case, yes.
In Coq's theory, propositions (i.e., Props) and their proofs have a very special status. In particular, it is in general not possible to write a choice operator that extracts the witness of an existence proof. This is done to make the theory compatible with certain axioms and principles, such as proof irrelevance, which says that all proofs of a given proposition are equal to each other. If you want to be able to do this, you need to add this choice operator as an additional axiom to your theory, as in the standard library.
However, in certain particular cases, it is possible to extract a witness out of an abstract existence proof without recurring to any additional axioms. In particular, it is possible to do this for countable types (such as Z) when the property in question is decidable. You can for instance use the choiceType interface in the Ssreflect library to get exactly what you want (look for the xchoose function).
That being said, I would usually advice against doing things in this style, because it leads to unnecessary complexity. It is probably easier to define Good directly, without resorting to the existence proof, and then prove separately that Good has the sought property.
Definition Good : Z := (* ... *)
Definition IsGood (z : Z) : Prop := (* ... *)
Lemma GoodIsGood : IsGood Good.
Proof. (* ... *) Qed.
Lemma GoodUnique : forall z : Z, IsGood z -> z = Good.
If you absolutely want to define Good with an existence proof, you can also change the proof of Lemma_GoodExistsUnique to use a connective in Type instead of Prop, since it allows you to extract the witness directly using the proj1_sig function:
Lemma Lemma_GoodExistsUnique : {z : Z | Good z /\ forall z', Good z' -> z' = z}.
Proof. (* ... *) Qed.
As for your second question, yes, it is a bit related to the first point. Once again, I would recommend that you write down a function y_from_x with type Z -> Z that will compute y given x, and then prove separately that this function relates inputs and outputs in a particular way. Then, you can say that the ys are different for different xs by proving that y_from_x is injective.
On the other hand, I'm not sure how your last example relates to this second question. If I understand what you want to do correctly, you can write something like
Definition ThereAreNGoodIntegers (N : Z) (IsGood : Z -> Prop) :=
exists zs : list Z,
Z.of_nat (length zs) = N
/\ NoDup zs
/\ Forall IsGood zs.
Here, Z.of_nat : nat -> Z is the canonical injection from naturals to integers, NoDup is a predicate asserting that a list doesn't contain repeated elements, and Forall is a higher-order predicate asserting that a given predicate (in this case, IsGood) holds of all elements of a list.
As a final note, I would advice against using Z for things that can only involve natural numbers. In your example, your using an integer to talk about the cardinality of a set, and this number is always a natural number.

What forms of goal in Coq are considered to be "true"?

When I prove some theorem, my goal evolves as I apply more and more tactics. Generally speaking the goal tends to split into sub goals, where the subgoals are more simple. At some final point Coq decides that the goal is proven. How this "proven" goal may look like? These goals seems to be fine:
a = a. (* Any object is identical to itself (?) *)
myFunc x y = myFunc x y. (* Result of the same function with the same params
is always the same (?) *)
What else can be here or can it be that examples are fundamentally wrong?
In other words, when I finally apply reflexivity, Coq just says ** Got it ** without any explanation. Is there any way to get more details on what it actually did or why it decided that the goal is proven?
You're actually facing a very general notion that seems not so general because Coq has some user-friendly facility for reasoning with equality in particular.
In general, Coq accepts a goal as solved as soon as it receives a term whose type is the type of the goal: it has been convinced the proposition is true because it has been convinced the type that this proposition describes is inhabited, and what convinced it is the actual witness you helped build along your proof.
For the particular case of inductive datatypes, the two ways you are going to be able to proved the proposition P a b c are:
by constructing a term of type P a b c, using the constructors of the inductive type P, and providing all the necessary arguments.
or by reusing an existing proof or an axiom in the environment whose type you can get to match P a b c.
For the even more particular case of equality proofs (equality is just an inductive datatype in Coq), the same two ways I list above degenerate to this:
the only constructor of equality is eq_refl, and to apply it you need to show that the two sides are judgementally equal. For most purposes, this corresponds to goals that look like T a b c = T a b c, but it is actually a slightly more broad notion of equality (see below). For these, all you have to do is apply the eq_refl constructor. In a nutshell, that is what reflexivity does!
the second case consists in proving that the equality holds because you have other equalities in your context, nothing special here.
Now one part of your question was: when does Coq accept that two sides of an equality are equal by reflexivity?
If I am not mistaken, the answer is when the two sides of the equality are αβδιζ-convertible.
What this grossly means is that there is a way to make them syntactically equal by repeated applications of:
α : sane renaming of non-free variables
β : computing reducible expressions
δ : unfolding definitions
ι : simplifying matches
ζ : expanding let-bound expressions
[someone please correct me if more rules apply or if I got one wrong]
For instance some of the things that are not captured by these rules are:
equality of functions that do more or less the same thing in different ways:
(fun x => 0 + x) = (fun x => x + 0)
quicksort = mergesort
equality of terms that are stuck reducing but would be equal:
forall n, 0 + n = n + 0

Subset parameter

I have a set as a parameter:
Parameter Q:Set.
Now I want to define another parameter that is a subset of Q. Something like:
Parameter F: subset Q.
How I can define that? I guess I can add the restriction later as an axiom, but seems more natural to express it directly in the type of F.
You can't express it directly.
It's misleading to think of objects in Set as mathematical sets. Set is the sort of datatypes, the same kinds of types that you find in programming languages (except that Coq's types are very powerful).
Coq doesn't have subtyping¹. If the two types F and Q are distinct, then they are disjoint, as far as the mathematical model is concerned.
The usual approach is to declare F as a completely related set, and declare a canonical injection from F to Q. You'll want to specify any interesting property of that injection, beyond the obvious.
Parameter Q : Set.
Parameter F : Set.
Parameter inj_F_Q : F -> Q.
Axiom inj_F_Q_inj : forall x y : F, inj_F_Q x = inj_F_Q y -> x = y.
Coercion inj_F_Q : F >-> Q.
That last line declares a coercion from F to Q. That lets you put an object of type F wherever the context requires the type Q. The type inference engine will insert a call to inj_F_Q. You will need to write the coercion explicitly occasionally, since the type inference engine, while very good, is not perfect (perfection would be mathematically impossible). There is a chapter on coercions in the Coq reference manual; you should at least skim through it.
Another approach is to define your subset with an extensional property, i.e. declare a predicate P on the set (the type) Q and define F from P.
Parameter Q : Set.
Parameter P : Q -> Prop.
Definition G := sig P.
Definition inj_G_Q : G -> Q := #proj1_sig Q P.
Coercion inj_G_Q : G >-> Q.
sig is a specification, i.e. a weak sum type, i.e. a pair consisting of an object and a proof that said object has a certain property. sig P is eta-equivalent to {x | P x} (which is syntactic sugar sig (fun x => P x)). You have to decide whether you prefer the short or the long form (you need to be consistent). The Program vernacular is often useful when working with weak sums.
¹
There is subtyping in the module language, but that's not relevant here. And coercions fake subtyping well enough for many uses, but they're not the real thing.