Binary tree inversion in Coq - binary-tree

I'm trying to prove that inverting a binary tree twice produces the same binary tree.
So I have written the following inductive type:
Inductive tree : Type :=
| Leaf (x : Type)
| Node (t1 : tree) (t2 : tree).
And here's the inversion function:
Fixpoint invertTree (t : tree) :=
match t with
| Leaf x => Leaf x
| Node l r => Node (invertTree r) (invertTree l)
end.
The theorem is pretty simple:
Theorem involution_of_invert : forall t : tree,
(invertTree (invertTree t)) = t.
The base case is pretty easy to prove, we start with a proof by induction and just compute -> reflexivity. I'm having a hard time understanding the induction step. Here's as far as I got:
Proof.
induction t.
compute.
reflexivity.
induction t1, t2.
compute.
reflexivity.
And my remaining goals:
3 subgoals (ID 57)
x : Type
t2_1, t2_2 : tree
IHt1 : invertTree (invertTree (Leaf x)) = Leaf x
IHt2 : invertTree (invertTree (Node t2_1 t2_2)) = Node t2_1 t2_2
============================
invertTree (invertTree (Node (Leaf x) (Node t2_1 t2_2))) =
Node (Leaf x) (Node t2_1 t2_2)
subgoal 2 (ID 74) is:
invertTree (invertTree (Node (Node t1_1 t1_2) (Leaf x))) =
Node (Node t1_1 t1_2) (Leaf x)
subgoal 3 (ID 81) is:
invertTree (invertTree (Node (Node t1_1 t1_2) (Node t2_1 t2_2))) =
Node (Node t1_1 t1_2) (Node t2_1 t2_2)
Would be glad if any hint could be provided. I'm pretty new to Coq (as should be pretty clear from the question heh).
Thanks

Found a solution to this, here it is:
Inductive tree : Type :=
| Leaf (x : Type)
| Node (t1 : tree) (t2 : tree).
Fixpoint invertTree (t : tree) :=
match t with
| Leaf x => Leaf x
| Node l r => Node (invertTree r) (invertTree l)
end.
Theorem involution_of_invert : forall t : tree,
(invertTree (invertTree t)) = t.
Proof.
induction t.
compute.
reflexivity.
simpl.
rewrite -> IHt1.
rewrite -> IHt2.
reflexivity.
Qed.

Related

How to prove insert_BST in Coq

I want to prove that when receiving a binary search tree as an argument, the [insert] function generates another binary search tree.
Insert Function:
Fixpoint insert {V : Type} (x : key) (v : V) (t : tree V) : tree V :=
match t with
| E => T E x v E
| T l y v' r => if x <? y then T (insert x v l) y v' r
else if x >? y then T l y v' (insert x v r)
else T l x v r
end.
I have written the following proof. However I am stuck in the middle of the proof.
I can see what I have to proove BST (T t1 k v t2), but I am unable to proceed by applying the hypothesis H : BST (T t1 k0 v0 t2)...
What can I do next in order to proove that
Theorem insert_BST : forall (V : Type) (k : key) (v : V) (t : tree V),
BST t -> BST (insert k v t).
Proof.
intros V k v t.
induction t; intros H.
- simpl. apply BST_T.
+ simpl. constructor.
+ simpl. constructor.
+ constructor.
+ constructor.
- inversion H; subst.
simpl in *.
bdestruct (k0 >? k).
+ apply BST_T.
* apply ForallT_insert.
apply H4.
apply H0.
* apply H5.
* apply IHt1.
apply H6.
* apply H7.
+ bdall.
** constructor. apply H4.
* apply ForallT_insert.
assumption.
assumption.
*apply H6.
* apply IHt2 in H7.
apply H7.
** constructor; apply H.
The whole code is here down below:
From Coq Require Import String.
From Coq Require Export Arith.
From Coq Require Export Lia.
Notation "a >=? b" := (Nat.leb b a) (at level 70) : nat_scope.
Notation "a >? b" := (Nat.ltb b a) (at level 70) : nat_scope.
Definition key := nat.
Inductive tree (V : Type) : Type :=
| E
| T (l : tree V) (k : key) (v : V) (r : tree V).
Arguments E {V}.
Arguments T {V}.
Definition empty_tree {V : Type} : tree V := E.
Fixpoint bound {V : Type} (x : key) (t : tree V) :=
match t with
| E => false
| T l y v r => if x <? y then bound x l
else if x >? y then bound x r
else true
end.
Fixpoint lookup {V : Type} (d : V) (x : key) (t : tree V) : V :=
match t with
| E => d
| T l y v r => if x <? y then lookup d x l
else if x >? y then lookup d x r
else v
end.
Fixpoint insert {V : Type} (x : key) (v : V) (t : tree V) : tree V :=
match t with
| E => T E x v E
| T l y v' r => if x <? y then T (insert x v l) y v' r
else if x >? y then T l y v' (insert x v r)
else T l x v r
end.
(** Nossa primeira tarefa será mostrar que a função [insert] de fato preserva esta invariante. Vamos então formalizar a invariante de uma árvore binária de busca. Faremos isto com a ajuda da função [ForallT]: *)
Fixpoint ForallT {V : Type} (P: key -> V -> Prop) (t: tree V) : Prop :=
match t with
| E => True
| T l k v r => P k v /\ ForallT P l /\ ForallT P r
end.
Inductive BST {V : Type} : tree V -> Prop :=
| BST_E : BST E
| BST_T : forall l x v r,
ForallT (fun y _ => y < x) l ->
ForallT (fun y _ => y > x) r ->
BST l ->
BST r ->
BST (T l x v r).
Hint Constructors BST.
Ltac inv H := inversion H; clear H; subst.
Inductive reflect (P : Prop) : bool -> Set :=
| ReflectT : P -> reflect P true
| ReflectF : ~ P -> reflect P false.
Theorem iff_reflect : forall P b, (P <-> b = true) -> reflect P b.
Proof.
intros P b H. destruct b.
- apply ReflectT. rewrite H. reflexivity.
- apply ReflectF. rewrite H. intros H'. inversion H'.
Qed.
Theorem reflect_iff : forall P b, reflect P b -> (P <-> b = true).
Proof.
intros P b H; split.
- intro H'.
inv H.
+ reflexivity.
+ contradiction.
- intro H'; subst.
inv H; assumption.
Qed.
Lemma eqb_reflect : forall x y, reflect (x = y) (x =? y).
Proof.
intros x y. apply iff_reflect. symmetry.
apply Nat.eqb_eq.
Qed.
Lemma ltb_reflect : forall x y, reflect (x < y) (x <? y).
Proof.
intros x y. apply iff_reflect. symmetry.
apply Nat.ltb_lt.
Qed.
Lemma leb_reflect : forall x y, reflect (x <= y) (x <=? y).
Proof.
intros x y. apply iff_reflect. symmetry.
apply Nat.leb_le.
Qed.
Hint Resolve ltb_reflect leb_reflect eqb_reflect : bdestruct.
Ltac bdestruct X :=
let H := fresh in let e := fresh "e" in
evar (e: Prop);
assert (H: reflect e X); subst e;
[eauto with bdestruct
| destruct H as [H|H];
[ | try first [apply not_lt in H | apply not_le in H]]].
Theorem empty_tree_BST : forall (V : Type),
BST (#empty_tree V).
Proof.
unfold empty_tree.
constructor;try lia.
Qed.
Lemma ForallT_insert : forall (V : Type) (P : key -> V -> Prop) (t : tree V),
ForallT P t -> forall (k : key) (v : V),
P k v -> ForallT P (insert k v t).
Proof.
intros V P t.
induction t; intros H k' v' Pkv.
- simpl. auto.
- simpl in *.
destruct H as [H1 [H2 H3]].
bdestruct (k >? k').
+ simpl. repeat split.
* assumption.
* apply (IHt1 H2 k' v' Pkv).
* assumption.
+ bdestruct (k' >? k).
++ simpl. repeat split.
* assumption.
* assumption.
* apply (IHt2 H3 k' v' Pkv).
++ simpl. repeat split.
* assumption.
* assumption.
* assumption.
Qed.
Ltac bdestruct_guard :=
match goal with
| |- context [ if ?X =? ?Y then _ else _ ] => bdestruct (X =? Y)
| |- context [ if ?X <=? ?Y then _ else _ ] => bdestruct (X <=? Y)
| |- context [ if ?X <? ?Y then _ else _ ] => bdestruct (X <? Y)
end.
Ltac bdall :=
repeat (simpl; bdestruct_guard; try lia; auto).
Theorem insert_BST : forall (V : Type) (k : key) (v : V) (t : tree V),
BST t -> BST (insert k v t).
Proof.
intros V k v t.
induction t; intros H.
- simpl. apply BST_T.
+ simpl. constructor.
+ simpl. constructor.
+ constructor.
+ constructor.
- inversion H; subst.
simpl in *.
bdestruct (k0 >? k).
+ apply BST_T.
* apply ForallT_insert.
apply H4.
apply H0.
* apply H5.
* apply IHt1.
apply H6.
* apply H7.
+ bdall.
** constructor. apply H4.
* apply ForallT_insert.
assumption.
assumption.
*apply H6.
* apply IHt2 in H7.
apply H7.
**
The shortest way to complete your proof may be (just at your last **):
** assert (k = k0) by auto with arith; subst.
inversion_clear H; now constructor.
Qed.
(the second line replaces the lemma BST_irrel of my previous post)
Indeed, you were very close to the Qed! Quite often, if some conclusion looks difficult to prove, it may be useful to look at the context. If you are lucky, you may find a contradiction and it's done. Otherwise, you can try to do a few forward-reasoning steps (like infering k=k0 in your example, and replace k with k0in appropriate occurrences).
Pierre
In your last goal, you have k0 = k (by H0and H1), and you know T t1 k0 v0 t2 is a search tree.
H : BST (T t1 k0 v0 t2)
H0 : k >= k0
H1 : k0 >= k
============================
BST (T t1 k v t2)
So, you may replace kwith k0 in the conclusion. If you prove
that the value v is irrelevant for T l k v r's searchness (a small lemma to prove), your proof is almost completed.
Lemma BST_irrel {V: Type} : forall l r k (v w:V),
BST (T l k v r) -> BST (T l k w r).
Proof. inversion 1; now constructor. Qed.

How to delete min element in splay tree

I made a splay tree, but I don't understand how to delete min element from it, can someone help please?
data Splay a = Empty | Node a (Splay a) (Splay a) deriving Show
data Direction = L | R deriving Eq
rotate :: Direction -> Splay a -> Splay a
rotate L (Node x a (Node y b c)) = (Node y (Node x a b) c)
rotate R (Node y (Node x a b) c) = (Node x a (Node y b c))
insert :: Ord a => a -> Splay a -> Splay a
insert x t = let (path, t') = pathToInserted x t in splay t' path
where pathToInserted :: Ord a => a -> Splay a -> ([Direction], Splay a)
pathToInserted x Empty = ([], Node x Empty Empty)
pathToInserted x t#(Node val l r)
| x == val = ([], t)
| x < val = let (path,l') = pathToInserted x l in (L:path, Node val l' r)
| x > val = let (path,r') = pathToInserted x r in (R:path, Node val l r')
splay :: Splay a -> [Direction] -> Splay a
splay t [] = t
-- Zig
splay t [L] = rotate R t
splay t [R] = rotate L t
-- Zig-zig
splay (Node q (Node p x c) d) (L:L:path) =
rotate R $ rotate R (Node q (Node p (splay x path) c) d)
splay (Node p a (Node q b x)) (R:R:path) =
rotate L $ rotate L (Node p a (Node q b (splay x path)))
-- Zig-zag
splay (Node q (Node p a x) d) (L:R:path) =
rotate R (Node q (rotate L $ Node p a (splay x path)) d)
splay (Node p a (Node q x d)) (R:L:path) =
rotate L (Node p a (rotate R $ Node q (splay x path) d))
fromList :: Ord a => [a] -> Splay a
fromList = foldr insert Empty
insert' :: Ord a => a -> Splay a -> Splay a
insert' x Empty = Node x Empty Empty
insert' x t#(Node val l r)
| x == val = t
| x < val = rotate R (Node val (insert' x l) r)
| x > val = rotate L (Node val l (insert' x r))
main :: IO()
main = putStrLn . show $ fromList [8,3,10,1,6,4,7,14,13]
Splay the leftmost element and return its right child. You'll need a helper like pathToInserted to return a list of Ls of the proper length.

Understanding and working with nested inductive definitons in coq

I'm trying to prove insert_SearchTree, a theorem about the preservation of a binary search tree after an insertion relation, below. I'm not sure how to use the induction hypothesis which relies on the nested Inductive definitions, namely SearchTree's single constructor calls on SearchTree'. Once I instantiate and invert the IH, though, we are given an arguement hi0 which is incomparable to k?
....
H1 : SearchTree' 0 (insert k0 v0 l) hi0
H2 : k0 < k
============================
SearchTree' 0 (insert k0 v0 l) k
Is my approach to this proof flawed, or is there a trick to make them comparable? I had thought to try to prove something like
Theorem insert_SearchTree'':
forall k v t hi,
SearchTree' 0 t hi -> SearchTree' 0 (insert k v t) hi .
Proof.
but after attempting I realized this is not equivalent (and I think unproveable, although I'm not sure)... Any advice is welcome. Most of the code is auxiliary, and I included it based on the advice that questions be stand-alone.
Require Export Coq.Arith.Arith.
Require Export Coq.Arith.EqNat.
Require Export Coq.omega.Omega.
Notation "a >=? b" := (Nat.leb b a)
(at level 70, only parsing) : nat_scope.
Notation "a >? b" := (Nat.ltb b a)
(at level 70, only parsing) : nat_scope.
Notation " a =? b" := (beq_nat a b)
(at level 70) : nat_scope.
Print reflect.
Lemma beq_reflect : forall x y, reflect (x = y) (x =? y).
Proof.
intros x y.
apply iff_reflect. symmetry. apply beq_nat_true_iff.
Qed.
Lemma blt_reflect : forall x y, reflect (x < y) (x <? y).
Proof.
intros x y.
apply iff_reflect. symmetry. apply Nat.ltb_lt.
Qed.
Lemma ble_reflect : forall x y, reflect (x <= y) (x <=? y).
Proof.
intros x y.
apply iff_reflect. symmetry. apply Nat.leb_le.
Qed.
Hint Resolve blt_reflect ble_reflect beq_reflect : bdestruct.
Ltac bdestruct X :=
let H := fresh in let e := fresh "e" in
evar (e: Prop);
assert (H: reflect e X); subst e;
[eauto with bdestruct
| destruct H as [H|H];
[ | try first [apply not_lt in H | apply not_le in H]]].
Section TREES.
Variable V : Type.
Variable default: V.
Definition key := nat.
Inductive tree : Type :=
| E : tree
| T: tree -> key -> V -> tree -> tree.
Inductive SearchTree' : key -> tree -> key -> Prop :=
| ST_E : forall lo hi, lo <= hi -> SearchTree' lo E hi
| ST_T: forall lo l k v r hi,
SearchTree' lo l k ->
SearchTree' (S k) r hi ->
SearchTree' lo (T l k v r) hi.
Inductive SearchTree: tree -> Prop :=
| ST_intro: forall t hi, SearchTree' 0 t hi -> SearchTree t.
Fixpoint insert (x: key) (v: V) (s: tree) : tree :=
match s with
| E => T E x v E
| T a y v' b => if x <? y then T (insert x v a) y v' b
else if y <? x then T a y v' (insert x v b)
else T a x v b
end.
Theorem insert_SearchTree:
forall k v t,
SearchTree t -> SearchTree (insert k v t).
Proof.
clear default.
intros.
generalize dependent v.
generalize dependent k.
induction H.
induction H.
- admit.
- intros.
specialize (IHSearchTree'1 k0 v0).
inversion IHSearchTree'1.
subst.
simpl.
bdestruct (k0 <? k).
apply (ST_intro _ hi0 ).
constructor.
admit.
End TREES.
The goal is currently too weak when you start induction. At the beginning of the second case, the goal looks like this:
H : SearchTree' lo l k
H0 : SearchTree' (S k) r hi
IHSearchTree'1 : forall (k : key) (v : V), SearchTree (insert k v l)
IHSearchTree'2 : forall (k : key) (v : V), SearchTree (insert k v r)
============================
forall (k0 : key) (v0 : V), SearchTree (insert k0 v0 (T l k v r))
and the high-level idea to go on is to combine H and IHSearchTree'2, or H0 and IHSearchTree'1, depending on which side the insertion goes. But this is impossible because the SearchTree predicate in the two IH assumptions is not compositional: knowing only that insert k0 v0 l is a search tree does not help to know whether a tree containing it, T (insert k0 v0 l) k v r, is also a search tree. So the proof doesn't go through.
When putting search trees together, we don't just want to know that something is a search tree. We also want to know some bounds on the keys (here in particular, they must be bounded by k). This is what the auxiliary predicate SearchTree' provides. This matter of compositionality is precisely why SearchTree is defined using an auxiliary inductive predicate SearchTree', which is compositional (it can be, and is, defined in terms of itself).
Properties about recursive functions on trees mentioning SearchTree should first be generalized as more informative properties using SearchTree' so induction can go through. It will look like this:
Lemma insert_SearchTree' :
forall t k0 v0 ??? ,
SearchTree' ??? t ??? -> SearchTree' ??? (insert k0 v0 t) ???.
There are multiple valid ways of filling these "???" blanks. Coming up with new ones is a good exercise for the reader. One way that should work well here and many other situations is to put variables for all the missing arguments of predicates, and then figure out some suitable relation between them:
Lemma insert_SearchTree' :
forall t k0 v0 lo hi lo' hi',
??? (* find a suitable assumption *) ->
SearchTree' lo t hi -> SearchTree' lo' (insert k0 v0 t) hi'.
The relation should reflect the behavior of insert. What insert does, as far as those bounds are concerned, is to add the key k0 to the tree, so the bounds must bound that, in addition to the rest of the tree:
Lemma insert_SearchTree' :
forall t k0 v0 lo hi lo' hi',
lo' <= lo -> hi <= hi' ->
lo' <= k0 -> k0 < hi' ->
SearchTree' lo t hi -> SearchTree' lo' (insert k0 v0 t) hi'.
Finally, since we're going to use induction on the SearchTree' lo t hi assumption, it's desirable to move most variables and hypotheses that it does not mention to the right, to strengthen the induction hypothesis further (as far as I can tell, this is always safe to do):
Lemma insert_SearchTree' :
forall t k0 v0 lo hi, (* k0 and v0 remain constant throughout the recursive applications of (insert k0 v0), so they can stay here (it would still be fine if they are moved with the rest). *)
SearchTree' lo t hi ->
forall lo' hi', (* The bounds are going to change at every step, so they move to the right of the inductive predicate. *)
lo' <= lo -> hi <= hi' ->
lo' <= k0 -> k0 < hi' ->
SearchTree' lo' (insert k0 v0 t) hi'.
Proving this lemma and using it to prove insert_SearchTree is left as an exercise for the reader.

Binarysearch in sml

datatype 'a tree= Leaf of 'a | Node of 'a tree * 'a * 'a tree
fun binSearch (Node(left,n,right)) x =
if x > n then false
else if x=n then true
else binSearch (Node(left,n,right)) x = binSearch (right) x andalso binSearch (left) x;
I'm helpless. What's wrong with that code?
BTW it works for:
binSearch (Node (Node (Leaf 1, 2, Leaf 3), 4, Leaf 7)) 7;
and doesn't work for:
binSearch (Node (Node (Leaf 1, 2, Leaf 3), 4, Leaf 7)) 2;
Your definition of a binary tree isn't ideal, since (for example) you can't construct a tree with two elements. A more flexible and generally simpler definition is
datatype 'a tree = Leaf | Node of 'a tree * 'a * 'a tree
where Leaf is a tree with no elements. This lets you write very simple base cases:
fun binSearch t x =
case t of
Leaf => false
| Node (left, n, right) => ...
For the Node case, you might find it helpful to structure your code according to the three possibilities of comparing the the desired value x to the current value n.
fun binSearch t x =
case t of
Leaf => false
| Node (left, n, right) =>
case Int.compare (x, n) of
LESS => ...
| EQUAL => true
| GREATER => ...
I'll leave the rest to you.
In the first condition, you're saying that no elements smaller than x exist in any tree.
You forgot to write a case for the empty tree, which is the only case where you know whether a value definitely isn't found:
binSearch (Leaf n) x = n = x
Also, your last else,
binSearch (Node(left,n,right)) x = binSearch (right) x andalso binSearch (left) x
is a comparison of whether binSearch (Node(left,n,right)) x gives the same result as binSearch right x andalso binSearch left x.
That is, it says that x is found in the tree if it's either in the entire tree and both its subtrees, or not found anywhere at all.
The recursion should go
If x is the value n in the node, we've found it.
Otherwise,
If x < n, recurse into the left subtree,
If x > n, recurse into the right subtree
Implementation left as an exercise.

Lazy Evaluation Correctness and Totality (Coq)

As the title suggests, my question concerns proving the correctness and totality of lazy evaluation of arithmetic expressions in Coq. The theorems that I would like to prove are three in total:
Computations only give canonical
expressions as results
Theorem Only_canonical_results:
(forall x y: Aexp, Comp x y -> Canonical y).
Correctness: the computation relation
preserves denotation of expressions
Theorem correct_wrt_semantics:
(forall x y: Aexp, Comp x y ->
I N (denotation x) (denotation y)).
Every input leads to some result.
Theorem Comp_is_total: (forall x:Aexp,
(Sigma Aexp (fun y =>
prod (Comp x y) (Canonical y)))).
The necessary definitions are to be found in the code attached below. I should make it clear I am a novice when it comes to Coq; which more experienced users will probably notice right away. It is most certainly the case that the majority, or perhaps even all of the background material I have written can be found in the standard library. But, then again, if I knew exactly what to import from the standard library in order to prove the desired results, I would most probably not be here bothering you. That is why I submit to you the material I have so far, in the hope that some kind spirited person/s may help me. Thanks!
(* Sigma types *)
Inductive Sigma (A:Set)(B:A -> Set) :Set :=
Spair: forall a:A, forall b : B a,Sigma A B.
Definition E (A:Set)(B:A -> Set)
(C: Sigma A B -> Set)
(c: Sigma A B)
(d: (forall x:A, forall y:B x,
C (Spair A B x y))): C c :=
match c as c0 return (C c0) with
| Spair a b => d a b
end.
Definition project1 (A:Set)(B:A -> Set)(c: Sigma A B):=
E A B (fun z => A) c (fun x y => x).
(* Binary sum type *)
Inductive sum' (A B:Set):Set :=
inl': A -> sum' A B | inr': B -> sum' A B.
Print sum'_rect.
Definition D (A B : Set)(C: sum' A B -> Set)
(c: sum' A B)
(d: (forall x:A, C (inl' A B x)))
(e: (forall y:B, C (inr' A B y))): C c :=
match c as c0 return C c0 with
| inl' x => d x
| inr' y => e y
end.
(* Three useful finite sets *)
Inductive N_0: Set :=.
Definition R_0
(C:N_0 -> Set)
(c: N_0): C c :=
match c as c0 return (C c0) with
end.
Inductive N_1: Set := zero_1:N_1.
Definition R_1
(C:N_1 -> Set)
(c: N_1)
(d_zero: C zero_1): C c :=
match c as c0 return (C c0) with
| zero_1 => d_zero
end.
Inductive N_2: Set := zero_2:N_2 | one_2:N_2.
Definition R_2
(C:N_2 -> Set)
(c: N_2)
(d_zero: C zero_2)
(d_one: C one_2): C c :=
match c as c0 return (C c0) with
| zero_2 => d_zero
| one_2 => d_one
end.
(* Natural numbers *)
Inductive N:Set :=
zero: N | succ : N -> N.
Print N.
Print N_rect.
Definition R
(C:N -> Set)
(d: C zero)
(e: (forall x:N, C x -> C (succ x))):
(forall n:N, C n) :=
fix F (n: N): C n :=
match n as n0 return (C n0) with
| zero => d
| succ n0 => e n0 (F n0)
end.
(* Boolean to truth-value converter *)
Definition Tr (c:N_2) : Set :=
match c as c0 with
| zero_2 => N_0
| one_2 => N_1
end.
(* Identity type *)
Inductive I (A: Set)(x: A) : A -> Set :=
r : I A x x.
Print I_rect.
Theorem J
(A:Set)
(C: (forall x y:A,
forall z: I A x y, Set))
(d: (forall x:A, C x x (r A x)))
(a:A)(b:A)(c:I A a b): C a b c.
induction c.
apply d.
Defined.
(* functions are extensional wrt
identity types *)
Theorem I_I_extensionality (A B: Set)(f: A -> B):
(forall x y:A, I A x y -> I B (f x) (f y)).
Proof.
intros x y P.
induction P.
apply r.
Defined.
(* addition *)
Definition add (m n:N) : N
:= R (fun z=> N) m (fun x y => succ y) n.
(* multiplication *)
Definition mul (m n:N) : N
:= R (fun z=> N) zero (fun x y => add y m) n.
(* Axioms of Peano verified *)
Theorem P1a: (forall x: N, I N (add x zero) x).
intro x.
(* force use of definitional equality
by applying reflexivity *)
apply r.
Defined.
Theorem P1b: (forall x y: N,
I N (add x (succ y)) (succ (add x y))).
intros.
apply r.
Defined.
Theorem P2a: (forall x: N, I N (mul x zero) zero).
intros.
apply r.
Defined.
Theorem P2b: (forall x y: N,
I N (mul x (succ y)) (add (mul x y) x)).
intros.
apply r.
Defined.
Definition pd (n: N): N :=
R (fun _=> N) zero (fun x y=> x) n.
(* alternatively
Definition pd (x: N): N :=
match x as x0 with
| zero => zero
| succ n0 => n0
end.
*)
Theorem P3: (forall x y:N,
I N (succ x) (succ y) -> I N x y).
intros x y p.
apply (I_I_extensionality N N pd (succ x) (succ y)).
apply p.
Defined.
Definition not (A:Set): Set:= (A -> N_0).
Definition isnonzero (n: N): N_2:=
R (fun _ => N_2) zero_2 (fun x y => one_2) n.
Theorem P4 : (forall x:N,
not (I N (succ x) zero)).
intro x.
intro p.
apply (J N (fun x y z =>
Tr (isnonzero x) -> Tr (isnonzero y))
(fun x => (fun t => t)) (succ x) zero)
.
apply p.
simpl.
apply zero_1.
Defined.
Theorem P5 (P:N -> Set):
P zero -> (forall x:N, P x -> P (succ x))
-> (forall x:N, P x).
intros base step n.
apply R.
apply base.
apply step.
Defined.
(* I(A,-,-) is an equivalence relation *)
Lemma Ireflexive (A:Set): (forall x:A, I A x x).
intro x.
apply r.
Defined.
Lemma Isymmetric (A:Set): (forall x y:A, I A x y -> I A y x).
intros x y P.
induction P.
apply r.
Defined.
Lemma Itransitive (A:Set):
(forall x y z:A, I A x y -> I A y z -> I A x z).
intros x y z P Q.
induction P.
assumption.
Defined.
Definition or (A B : Set):= sum' A B.
(* arithmetical expressions *)
Inductive Aexp :Set :=
zer: Aexp
| suc: Aexp -> Aexp
| pls: Aexp -> Aexp -> Aexp.
(* denotation of an expression *)
Definition denotation: Aexp->N:=
fix F (a: Aexp): N :=
match a as a0 with
| zer => zero
| suc a1 => succ (F a1)
| pls a1 a2 => add (F a1) (F a2)
end.
(* predicate for distinguishing
canonical expressions *)
Definition Canonical (x:Aexp):Set :=
or (I Aexp x zer)
(Sigma Aexp (fun y =>
I Aexp x (suc y))).
(* the computation relation is
an inductively defined relation *)
Inductive Comp : Aexp -> Aexp -> Set
:=
refrule: forall a: Aexp,
forall p: Canonical a, Comp a a
| zerrule: forall a b c:Aexp,
forall p: Comp b zer,
forall q: Comp a c,
Comp (pls a b) c
| sucrule: forall a b c:Aexp,
forall p: Comp b (suc c),
Comp (pls a b) (suc (pls a c)).
(* Computations only give canonical
expressions as results *)
Theorem Only_canonical_results:
(forall x y: Aexp, Comp x y -> Canonical y).
admit.
Defined.
(* Here is where help is needed *)
(* Correctness: the computation relation
preserves denotation of expressions *)
Theorem correct_wrt_semantics:
(forall x y: Aexp, Comp x y ->
I N (denotation x) (denotation y)).
admit.
(* Here is where help is need*)
Defined.
(* every input leads to some result *)
Theorem Comp_is_total: (forall x:Aexp,
(Sigma Aexp (fun y =>
prod (Comp x y) (Canonical y)))).
admit.
(* Proof required *)
Defined.
The first two theorems can be proved almost blindly. They follow by induction on the definition of Comp. The third one requires some thinking and some auxiliary theorems though. But you should be following a tutorial if you want to learn Coq.
About the tactics I used:
induction 1 does induction on the first unnamed hypothesis.
info_eauto tries to finish a goal by blindly applying theorems.
Hint Constructors adds the constructors of an inductive definition to the database of theorems info_eauto can use.
unfold, simpl, and rewrite should be self-explanatory.
.
Hint Constructors sum' prod Sigma I Comp.
Theorem Only_canonical_results:
(forall x y: Aexp, Comp x y -> Canonical y).
unfold Canonical, or.
induction 1.
info_eauto.
info_eauto.
info_eauto.
Defined.
Theorem correct_wrt_semantics:
(forall x y: Aexp, Comp x y ->
I N (denotation x) (denotation y)).
induction 1.
info_eauto.
simpl. rewrite IHComp1. rewrite IHComp2. simpl. info_eauto.
simpl. rewrite IHComp. simpl. info_eauto.
Defined.
Theorem Comp_is_total: (forall x:Aexp,
(Sigma Aexp (fun y =>
prod (Comp x y) (Canonical y)))).
unfold Canonical, or.
induction x.
eapply Spair. eapply pair.
eapply refrule. unfold Canonical, or. info_eauto.
info_eauto.
Admitted.

Resources