Why does Record forget which arguments are implicit? - coq

It seems that when Record converts to Variant, it drops the data about which arguments are implicit. Why? Here is a MWE:
> Variant example {n : nat} (e : n=n) :=
| a : nat -> example e.
> Check a.
a
: forall e : ?n = ?n, nat -> example e
where
?n : [ |- nat]
> Record example2 {n : nat} (e : n=n) := a2 { r: nat }.
> Check a2.
a2
: forall (n : nat) (e : n = n), nat -> example2 e

Related

Can I define an equivalent to this using the Axiom command?

mu can not be defined.
Definiton mu (A : Type) (f : A -> A) : A := f (mu A f).
However, the Axiom command can be used to pseudo-define mu.
Axiom mu : forall A : Type, (A -> A) -> A.
Axiom mu_beta : forall (A : Type) (f : A -> A), mu A f = f (mu A f).
Can I do the same for higher_path and higher_path_argument? Even after using several techniques, it still seems to be impossible.
Definition higher_path
: forall n : nat, higher_path_argument n -> Type
:= fun n : nat =>
match n with
| O => fun x : higher_path_argument 0 => x
| S n_p =>
fun x : higher_path_argument (S n_p) =>
match x with
| existT _ x_a x_b =>
match x_b with
| pair x_b_a x_b_b => x_b_a = x_b_b :> higher_path n_p x_a
end
end
end.
Definition higher_path_argument
: nat -> Type
:= fun n : nat =>
match n with
| O => Type
| S n_p =>
sigT
(A := higher_path_argument n_p)
(fun x_p => prod (higher_path n_p x_p) (higher_path n_p x_p))
end.
You will have to start with
Axiom higher_path_argument : nat -> Type.
Axiom higher_path : forall n : nat, higher_path_argument n -> Type.
then higher_path_argument_beta which you will have to use in the higher_path_beta to compute the type. You will however end up with something really verbose however.

How to use a theorem with a match pattern

Basically, I have a function, and a theorem about some properties of this function.
The function has the following signature :
Fixpoint compute_solution (s : list nat) : (option list nat) :=
...=> None
...=> Some l
The theorem is :
Theorem solution_is_correct:
forall (s : list nat), length s = 9 * 9 ->
match compute_solution s with
None => forall s1, length s1 = 9 *9 -> ~ nice_property s1
| Some s1 => nice_property s1
end.
Now, when I try to prove an additional theorem , I end up in the following situation :
s: list nat
Hs: length s = 9 * 9
prem: list nat
sol: compute_solution s = Some prem
...
================================
nice_property prem
How can I make use of solution_is_correct to prove the goal ?
Thank you for your help.
This should work
pose proof (solution_is_correct s Hs) as Tmp.
rewrite sol in Tmp.
But I'd rather rework the theorem to be more usable, eg
thm1 : forall s l, ... -> compute_solution s = Some l -> nice_property l
thm2 : forall s, ... -> compute_solution s = None -> ...

Proving coinductive theorems with coinductive assumptions

I have a simple lazy binary tree implementation:
CoInductive LTree (A : Set) : Set :=
| LLeaf : LTree A
| LBin : A -> (LTree A) -> (LTree A) -> LTree A.
And following properties:
(* Having some infinite branch *)
CoInductive SomeInfinite {A} : LTree A -> Prop :=
SomeInfinite_LBin :
forall (a : A) (l r : LTree A), (SomeInfinite l \/ SomeInfinite r) ->
SomeInfinite (LBin _ a l r).
(* Having only finite branches (i.e. being finite) *)
Inductive AllFinite {A} : LTree A -> Prop :=
| AllFinite_LLeaf : AllFinite (LLeaf A)
| AllFinite_LBin :
forall (a : A) (l r : LTree A), (AllFinite l /\ AllFinite r) ->
AllFinite (LBin _ a l r).
I would like to prove a theorem that states that a finite tree does not have any infinite branches:
Theorem allfinite_noinfinite : forall {A} (t : LTree A), AllFinite t -> not (SomeInfinite t).
...but I got lost after first few tactics. The hypothesis itself seems pretty trivial, but I cannot even start with it. What would proving of such a theorem look like?
The proof is actually not difficult (but you stumbled upon some annoying quirks): to start, the main idea of the proof is that you have an inductive witness that t is finite, so you can do an induction on that witness concluding with a contradiction when t is just a leaf and reusing the inductive hypothesis when it is a binary node.
Now the annoying problem is that Coq does not derive the right induction principle for AllFinite because of /\ : compare
Inductive AllFinite {A} : LTree A -> Prop :=
| AllFinite_LLeaf : AllFinite (LLeaf A)
| AllFinite_LBin :
forall (a : A) (l r : LTree A), AllFinite l /\ AllFinite r ->
AllFinite (LBin _ a l r).
Check AllFinite_ind.
(* AllFinite_ind *)
(* : forall (A : Set) (P : LTree A -> Prop), *)
(* P (LLeaf A) -> *)
(* (forall (a : A) (l r : LTree A), *)
(* AllFinite l /\ AllFinite r -> P (LBin A a l r)) -> *)
(* forall l : LTree A, AllFinite l -> P l *)
with
Inductive AllFinite' {A} : LTree A -> Prop :=
| AllFinite'_LLeaf : AllFinite' (LLeaf A)
| AllFinite'_LBin :
forall (a : A) (l r : LTree A), AllFinite' l -> AllFinite' r ->
AllFinite' (LBin _ a l r).
Check AllFinite'_ind.
(* AllFinite'_ind *)
(* : forall (A : Set) (P : LTree A -> Prop), *)
(* P (LLeaf A) -> *)
(* (forall (a : A) (l r : LTree A), *)
(* AllFinite' l -> P l -> AllFinite' r -> P r -> P (LBin A a l r)) -> *)
(* forall l : LTree A, AllFinite' l -> P l *)
In the inductive case, the first version does not give you the expected inductive hypothesis. So either you can change your AllFinite to AllFInite', or you need to reprove the induction principle by hand.

How can I construct terms in first-order logic using Coq?

I'm trying to define first-order logic in Coq and beginning at terms.
Supposing that c1 and c2 are two constant symbols, variables are nat and f1 and f2 are two function symbols whose arities are 1 and 2 respectively, I wrote the following code.
Definition var := nat.
Inductive const : Type :=
| c1
| c2.
Inductive term : Type :=
| Con : const -> term
| Var : var -> term
| F1 : term -> term
| F2 : term -> term -> term.
Then, I got a desired induction.
Check term_ind.
(* ==> term_ind
: forall P : term -> Prop,
(forall c : const, P (Con c)) ->
(forall v : var, P (Var v)) ->
(forall t : term, P t -> P (F1 t)) ->
(forall t : term, P t -> forall t0 : term, P t0 -> P (F2 t t0)) ->
forall t : term, P t *)
Then I wanted to separate functions from the definition of term, so I rewrote the above.
(*Idea A*)
Inductive funct {X : Type} : Type :=
| f1 : X -> funct
| f2 : X -> X -> funct.
Inductive term : Type :=
| Con : const -> term
| Var : var -> term
| Fun : #funct term -> term.
Check term_ind.
(* ==> term_ind
: forall P : term -> Prop,
(forall c : const, P (Con c)) ->
(forall v : var, P (Var v)) ->
(forall f1 : funct, P (Fun f1)) ->
forall t : term, P t *)
Check funct_ind term.
(* ==> funct_ind term
: forall P : funct -> Prop,
(forall x : term, P (f1 x)) ->
(forall x x0 : term, P (f2 x x0)) ->
forall f1 : funct, P f1 *)
(*Idea B*)
Inductive term : Type :=
| Con : const -> term
| Var : var -> term
| Fun : funct -> term
with funct : Type :=
| f1 : term -> funct
| f2 : term -> term -> funct.
Check term_ind.
(* ==> term_ind
: forall P : term -> Prop,
(forall c : const, P (Con c)) ->
(forall v : var, P (Var v)) ->
(forall f1 : funct, P (Fun f1)) ->
forall t : term, P t *)
Check funct_ind.
(* ==> funct_ind
: forall P : funct -> Prop,
(forall t : term, P (f1 t)) ->
(forall t t0 : term, P (f2 t t0)) ->
forall f1 : funct, P f1 *)
However, both ways seem not to generate the desired induction because they don't have induction hypotheses.
How can I construct term with functions separated from the definition of term without loss of proper induction?
Thanks.
This is a common issue with Coq: the induction principles generated for mutually inductive types and for types with complex recursive occurrences are too weak. Fortunately, this can be fixed by defining the induction principles by hand. In your case, the simplest approach is to use the mutually inductive definition, since Coq can lend us a hand for proving the principle.
First, let ask Coq not to generate its weak default induction principle:
Unset Elimination Schemes.
Inductive term : Type :=
| Con : const -> term
| Var : var -> term
| Fun : funct -> term
with funct : Type :=
| f1 : term -> funct
| f2 : term -> term -> funct.
Set Elimination Schemes.
(This is not strictly necessary, but it helps keeping the global namespace clean.)
Now, let us use the Scheme command to generate a mutual induction principle for these types:
Scheme term_ind' := Induction for term Sort Prop
with funct_ind' := Induction for funct Sort Prop.
(*
term_ind'
: forall (P : term -> Prop) (P0 : funct -> Prop),
(forall c : const, P (Con c)) ->
(forall v : var, P (Var v)) ->
(forall f1 : funct, P0 f1 -> P (Fun f1)) ->
(forall t : term, P t -> P0 (f1 t)) ->
(forall t : term, P t -> forall t0 : term, P t0 -> P0 (f2 t t0)) ->
forall t : term, P t
*)
This principle is already powerful enough for us to prove properties of term, but it is a bit awkward to use, since it requires us to specify a property that we want to prove about the funct type as well (the P0 predicate). We can simplify it a bit to avoid mentioning this auxiliary predicate: all we need to know is that the terms inside the function calls satisfy the predicate that we want to prove.
Definition lift_pred (P : term -> Prop) (f : funct) : Prop :=
match f with
| f1 t => P t
| f2 t1 t2 => P t1 /\ P t2
end.
Lemma term_ind (P : term -> Prop) :
(forall c, P (Con c)) ->
(forall v, P (Var v)) ->
(forall f, lift_pred P f -> P (Fun f)) ->
forall t, P t.
Proof.
intros HCon HVar HFun.
apply (term_ind' P (lift_pred P)); trivial.
now intros t1 IH1 t2 IH2; split.
Qed.
If you prefer, you can also rewrite this to look more like the original induction principle:
Reset term_ind.
Lemma term_ind (P : term -> Prop) :
(forall c, P (Con c)) ->
(forall v, P (Var v)) ->
(forall t, P t -> P (Fun (f1 t))) ->
(forall t1, P t1 -> forall t2, P t2 -> P (Fun (f2 t1 t2))) ->
forall t, P t.
Proof.
intros HCon HVar HFun_f1 HFun_f2.
apply (term_ind' P (lift_pred P)); trivial.
- now intros [t|t1 t2]; simpl; intuition.
- now simpl; intuition.
Qed.
Edit
To get an induction principle for your other approach, you have to write a proof term by hand:
Definition var := nat.
Inductive const : Type :=
| c1
| c2.
Inductive funct (X : Type) : Type :=
| f1 : X -> funct X
| f2 : X -> X -> funct X.
Arguments f1 {X} _.
Arguments f2 {X} _ _.
Unset Elimination Schemes.
Inductive term : Type :=
| Con : const -> term
| Var : var -> term
| Fun : funct term -> term.
Set Elimination Schemes.
Definition term_ind (P : term -> Type)
(HCon : forall c, P (Con c))
(HVar : forall v, P (Var v))
(HF1 : forall t, P t -> P (Fun (f1 t)))
(HF2 : forall t1, P t1 -> forall t2, P t2 -> P (Fun (f2 t1 t2))) :
forall t, P t :=
fix loop (t : term) : P t :=
match t with
| Con c => HCon c
| Var v => HVar v
| Fun (f1 t) => HF1 t (loop t)
| Fun (f2 t1 t2) => HF2 t1 (loop t1) t2 (loop t2)
end.

How to strengthen induction hypothesis in Coq proof?

I'm trying to formalize applicaion of context-free grammars in practice task. I have problems in proving one lemma. I tried to simplify my context to outline the problem, but it is still a bit cumbersome.
So I defined CFG in Chomsky normal form and derivability of list of terminals as follows:
Require Import List.
Import ListNotations.
Inductive ter : Type := T : nat -> ter.
Inductive var : Type := V : nat -> var.
Inductive eps : Type := E : eps.
Inductive rule : Type :=
| Rt : var -> ter -> rule
| Rv : var -> var -> var -> rule
| Re : var -> eps -> rule.
Definition grammar := list rule.
Inductive der_ter_list : grammar -> var -> list ter -> Prop :=
| Der_eps : forall (g : grammar) (v : var) (e : eps),
In (Re v e) g -> der_ter_list g v []
| Der_ter : forall (g : grammar) (v : var) (t : ter),
In (Rt v t) g -> der_ter_list g v [t]
| Der_var : forall (g : grammar) (v v1 v2 : var) (tl1 tl2 : list ter),
In (Rv v v1 v2) g -> der_ter_list g v1 tl1 -> der_ter_list g v2 tl2 ->
der_ter_list g v (tl1 ++ tl2).
I have objects that store terminal and some additional info, for example:
Inductive obj : Set := Get_obj : nat -> ter -> obj.
And I try to define all possible lists of objects, which are derivable from given nonterminal (with helper functions):
Fixpoint get_all_pairs (l1 l2 : list (list obj)) : list (list obj) := match l1 with
| [] => []
| l::t => (map (fun x => l ++ x) l2) ++ get_all_pairs t l2
end.
Fixpoint getLabels (objs : list obj) : list ter := match objs with
| [] => []
| (Get_obj yy ter)::t => ter::(getLabels t)
end.
Inductive paths : grammar -> var -> list (list obj) -> Prop :=
| Empty_paths : forall (g : grammar) (v : var) (e : eps),
In (Re v e) g -> paths g v [[]]
| One_obj_path : forall (g : grammar) (v : var) (n : nat) (t : ter) (objs : list obj),
In (Rt v t) g -> In (Get_obj n t) objs -> paths g v [[Get_obj n t]]
| Combine_paths : forall (g : grammar) (v v1 v2 : var) (l1 l2 : list (list obj)),
In (Rv v v1 v2) g -> paths g v1 l1 -> paths g v2 l2 -> paths g v (get_all_pairs l1 l2).
(Each constructor of paths actually corresponds to constructor of rule)
And now I'm trying to proof fact about paths by induction, that every element in paths can be derived from nonterminal:
Theorem derives_all_path : forall (g: grammar) (v : var)
(ll : list (list obj)) (pths : paths g v ll), forall (l : list obj),
In l ll -> der_ter_list g v (getLabels l).
Proof.
intros g v ll pt l contains.
induction pt.
This construction generates 3 subgoals, 1st and 2nd I've proved by applying Der_eps and Der_ter constructors respectively.
But context in 3rd subgoal is not relevant to prove my goal, it has:
contains : In l (get_all_pairs l1 l2)
IHpt1 : In l l1 -> der_ter_list g v1 (getLabels l)
IHpt2 : In l l2 -> der_ter_list g v2 (getLabels l)
So contains means that l is concatenation of some elements from l1 and l2, but premises in IHpt1 and IHpt2 are true iff l2 and l1 has empty lists, which is not true in general, so it is impossible to prove goal with this context.
The problem can be resolved if l in contains, IHpt1, IHpt2 will be different lists, but unfortunately I don't know how to explain it to Coq. Is it any way somehow change IHpt1 and IHpt2 to prove the goal, or any other way to prove the whole fact?
I tried to look on paths_ind, but it didn't make me happy.
It looks like your induction hypothesis is not strong enough. If you perform induction pt on a more polymorphic goal, you'll get more useful hypotheses not tied to the specific l you started with.
You should try:
intros g v ll pt; induction pt; intros l contains.