G2z: Struktury cykliczne [TODO]
Require Import List.
Import ListNotations.
From Typonomikon Require Import F4.
Module CyclicList.
Inductive CList (A V : Type) : Type :=
| Var : V -> CList A V
| Nil : CList A V
| RCons : A -> CList A (option V) -> CList A V.
Arguments Var {A V} _.
Arguments Nil {A V}.
Arguments RCons {A V} _ _.
Technically, this is realized using a nested inductive type. The type
family CList has two type parameters, A and V. A is the type of
elements held in the list, while V represents pointers that can be used
to close a cycle. Our intention is that when V is nonempty, CList A V
represents cyclic lists "with free variables", whereas for empty V,
CList A V represents "closed" cyclic lists.
Fixpoint map {A B V : Type} (f : A -> B) (l : CList A V) : CList B V :=
match l with
| Var v => Var v
| Nil => Nil
| RCons h t => RCons (f h) (map f t)
end.
map is easy.
Fixpoint shift {A V : Type} (l : CList A V) : CList A (option V) :=
match l with
| Var v => Var (Some v)
| Nil => Nil
| RCons h t => RCons h (shift t)
end.
shift is a very important auxiliary function which shifts all pointers
one place to the right, i.e. a pointer that referred to the list's zeroth
element now refers to the first one and so on.
Lemma map_shift :
forall {A B V : Type} (f : A -> B) (l : CList A V),
map f (shift l) = shift (map f l).
Proof.
induction l as [| | h t]; cbn.
1-2: reflexivity.
f_equal. exact IHl.
Qed.
Lemma map_map :
forall {A B C V : Type} (f : A -> B) (g : B -> C) (l : CList A V),
map g (map f l) = map (fun x => g (f x)) l.
Proof.
induction l as [| | h t]; cbn; intros.
1-2: reflexivity.
rewrite IHl. reflexivity.
Qed.
Lemma map_id :
forall {A V : Type} (l : CList A V),
map (fun x => x) l = l.
Proof.
induction l as [| | h t]; cbn; intros.
1-2: reflexivity.
rewrite IHl. reflexivity.
Qed.
Fixpoint app {A V : Type} (l1 l2 : CList A V) : CList A V :=
match l1 with
| Var v => Var v
| Nil => l2
| RCons h t => RCons h (app t (shift l2))
end.
app is also easy, but we need to shift the pointers when appending l2
to the tail of l1. When we hit a variable we drop l2, because it means
that we have arrived in a location where a pointer to an earlier location
in the list is used, i.e. the first list is cyclic and thus "infinite".
Lemma map_app :
forall {A B V : Type} (f : A -> B) (l1 l2 : CList A V),
map f (app l1 l2) = app (map f l1) (map f l2).
Proof.
induction l1 as [| | h t]; cbn; intros.
1-2: reflexivity.
rewrite IHl1, map_shift. reflexivity.
Qed.
Lemma app_shift :
forall {A V : Type} (l1 l2 : CList A V),
app (shift l1) (shift l2) = shift (app l1 l2).
Proof.
induction l1 as [| | h t]; cbn; intros.
1-2: reflexivity.
rewrite IHl1. reflexivity.
Qed.
Lemma app_assoc :
forall {A V : Type} (l1 l2 l3 : CList A V),
app (app l1 l2) l3 = app l1 (app l2 l3).
Proof.
induction l1 as [| | h t]; cbn; intros.
1-2: reflexivity.
rewrite IHl1, app_shift. reflexivity.
Qed.
Fixpoint snoc {A V : Type} (x : A) (l : CList A V) : CList A V :=
match l with
| Var v => Var v
| Nil => RCons x Nil
| RCons h t => RCons h (snoc x t)
end.
Lemma snoc_shift :
forall {A V : Type} (x : A) (l : CList A V),
snoc x (shift l) = shift (snoc x l).
Proof.
induction l as [| | h t]; cbn.
1-2: reflexivity.
rewrite IHl. reflexivity.
Qed.
Lemma snoc_app :
forall {A V : Type} (x : A) (l1 l2 : CList A V),
snoc x (app l1 l2) = app l1 (snoc x l2).
Proof.
induction l1 as [| | h t]; cbn; intros.
1-2: reflexivity.
rewrite IHl1, snoc_shift. reflexivity.
Qed.
Fixpoint replicate {A V : Type} (n : nat) (x : A) : CList A V :=
match n with
| 0 => Nil
| S n' => RCons x (replicate n' x)
end.
Definition repeat {A V : Type} (x : A) : CList A V :=
RCons x (Var None).
Inductive Finite {A V : Type} : CList A V -> Type :=
| FNil : Finite Nil
| FRCons : forall (h : A) (t : CList A (option V)),
Finite t -> Finite (RCons h t).
Lemma shift_replicate :
forall (n : nat) {A V : Type} (x : A),
@shift A V (replicate n x) = replicate n x.
Proof.
induction n as [| n']; cbn; intros.
reflexivity.
rewrite IHn'. reflexivity.
Qed.
Lemma Finite_replicate :
forall (n : nat) {A V : Type} (x : A),
@Finite A V (@replicate A V n x).
Proof.
induction n as [| n']; cbn; intros.
constructor.
constructor. apply IHn'.
Qed.
Lemma not_Finite_repeat :
forall {A V : Type} (x : A),
@Finite A V (repeat x) -> False.
Proof.
inversion 1. subst. inversion X0.
Qed.
Definition CList' (A : Type) : Type := CList A False.
Definition cons {A V : Type} (h : A) (t : CList' A) : CList' A :=
RCons h (shift t).
Fixpoint recycle {A V : Type} (x : A) (l : CList A (option V)) : CList A V :=
match l with
| Var None => RCons x (Var None)
| Var (Some v) => Var v
| Nil => Nil
| RCons h t => RCons h (recycle x t)
end.
Definition cuncons {A : Type} (l : CList' A) : option (A * CList' A) :=
match l with
| Var v => match v with end
| Nil => None
| RCons h t => Some (h, recycle h t)
end.
CoFixpoint unwind {A : Type} (l : CList' A) : CoList A :=
{|
uncons :=
match cuncons l with
| None => NilF
| Some (h, t) => ConsF h (unwind t)
end
|}.
Fixpoint ctake (n : nat) {A : Type} (l : CoList A) : list A :=
match n with
| 0 => []
| S n' =>
match uncons l with
| NilF => []
| ConsF h t => h :: ctake n' t
end
end.
Definition example : CList' nat :=
RCons 1 (RCons 2 (Var None)).
Definition take (n : nat) {A : Type} (l : CList' A) : list A :=
ctake n (unwind l).
Definition example' : CList' nat :=
RCons 1 (RCons 2 Nil).
Compute take 10 example'.
Definition example'' : CList' nat :=
RCons 1 (RCons 2 (RCons 3 (RCons 4 (Var (Some (Some None)))))).
Compute take 10 example''.
Fixpoint drop (n : nat) {A : Type} (l : CList' A) : CList' A :=
match n with
| 0 => l
| S n' =>
match cuncons l with
| None => Nil
| Some (_, t) => drop n' t
end
end.
Compute drop 11 example.
Fixpoint take' (n : nat) {A : Type} (l : CList' A) : list A :=
match n with
| 0 => []
| S n' =>
match cuncons l with
| None => []
| Some (h, t) => h :: take' n' t
end
end.
Compute take' 10 example.
Fail Fixpoint bind {A B V : Type} (l : CList A V) (f : A -> CList B V) : CList B V :=
match l with
| Var v => Var v
| Nil => Nil
| RCons h t => app (f h) (bind t (fun l => shift (f l)))
end.
Fixpoint rev {A V : Type} (l : CList A V) : CList A V :=
match l with
| Var v => Var v
| Nil => Nil
| RCons h t => recycle h (rev t)
end.
Definition from1to5 : CList' nat :=
RCons 1 (RCons 2 (RCons 3 (RCons 4 (RCons 5 (Var None))))).
Compute rev from1to5.
Fixpoint nth (n : nat) {A : Type} (l : CList' A) : option A :=
match n, cuncons l with
| _ , None => None
| 0 , Some (h, t) => Some h
| S n', Some (h, t) => nth n' t
end.
Compute List.map (fun n => nth n from1to5) [0; 1; 2; 3; 4; 5; 6; 7].
Fixpoint cycle (n : nat) {A : Type} (l : CList' A) : CList' A :=
match n, cuncons l with
| 0 , _ => l
| _ , None => l
| S n', Some (h, t) => cycle n' t
end.
Compute List.map (fun n => cycle n from1to5) [0; 1; 2; 3; 4; 5; 6; 7].
Fixpoint any {A V : Type} (p : A -> bool) (l : CList A V) : bool :=
match l with
| Var v => false
| Nil => false
| RCons h t => p h || any p t
end.
Fixpoint wut {A V : Type} (l : CList A (option V)) : CList A V :=
match l with
| Var None => Nil
| Var (Some v) => Var v
| Nil => Nil
| RCons h t => RCons h (wut t)
end.
Fixpoint filter {A V : Type} (p : A -> bool) (l : CList A V) : CList A V :=
match l with
| Var v => Var v
| Nil => Nil
| RCons h t => if p h then RCons h (filter p t) else wut (filter p t)
end.
Compute from1to5.
Compute filter Nat.even from1to5.
Compute filter Nat.even (RCons 1 (RCons 2 (Var None))).
Fixpoint shift' {A V : Type} (l : CList A V) : CList A (option (option V)) :=
match l with
| Var v => Var (Some (Some v))
| Nil => Nil
| RCons h t => RCons h (shift' t)
end.
Fail Fixpoint intersperse {A V : Type} (x : A) (l : CList A V) : CList A V :=
match l with
| Var v => Var v
| Nil => Nil
| RCons h t => RCons h (shift' (RCons x (intersperse x t)))
end.
Fail Compute take 20 (intersperse 0 from1to5).
Inductive Elem {A V : Type} (x : A) : CList A V -> Type :=
| Zero :
forall l : CList A (option V), Elem x (RCons x l)
| Succ :
forall (h : A) (t : CList A (option V)),
Elem x t -> Elem x (RCons h t).
Inductive Dup {A V : Type} : CList A V -> Type :=
| DupVar :
forall v : V, Dup (Var v)
| DupHere :
forall (h : A) (t : CList A (option V)),
Elem h t -> Dup (RCons h t)
| DupThere :
forall (h : A) (t : CList A (option V)),
Dup t -> Dup (RCons h t).
Lemma NoDup_Finite :
forall {A V : Type} (l : CList A V),
(Dup l -> False) -> Finite l.
Proof.
induction l as [| | h t]; cbn; intros.
contradiction H. constructor.
constructor.
constructor. apply IHl. intro. apply H. constructor 3. assumption.
Qed.
Lemma NoFinite_Dup :
forall {A V : Type} (l : CList A V),
(Finite l -> False) -> Dup l.
Proof.
induction l as [| | h t]; intros.
constructor.
contradict H. constructor.
constructor 3. apply IHl. intro. apply H. constructor. assumption.
Qed.
Inductive Ex {A V : Type} (P : A -> Type) : CList A V -> Type :=
| ExHere :
forall (x : A) (l : CList A (option V)),
P x -> Ex P (RCons x l)
| ExThere :
forall (h : A) (t : CList A (option V)),
Ex P t -> Ex P (RCons h t).
Fixpoint takeWhile {A V : Type} (p : A -> bool) (l : CList A V) : CList A V :=
match l with
| Var v => Var v
| Nil => Nil
| RCons h t => if p h then RCons h (takeWhile p t) else Nil
end.
Compute takeWhile (fun n => Nat.leb n 6) from1to5.
Fail Fixpoint dropWhile {A V : Type} (p : A -> bool) (l : CList A V) : CList A V :=
match l with
| Var v => Var v
| Nil => Nil
| RCons h t => if p h then dropWhile p t else Nil
end.
End CyclicList.
Listy cykliczne bez udziwnień (TODO)
Module SimpleCyclicList.
From Typonomikon Require Import D5a D5b.
Inductive Cyclic (A : Type) : Type :=
| C : forall (start : list A) (cycle : list A), Cyclic A.
Arguments C {A} _ _.
Definition cmap {A B : Type} (f : A -> B) (l : Cyclic A) : Cyclic B :=
match l with
| C start cycle => C (map f start) (map f cycle)
end.
Lemma cmap_cmap :
forall {A B C : Type} (f : A -> B) (g : B -> C) (l : Cyclic A),
cmap g (cmap f l) = cmap (fun x => g (f x)) l.
Proof.
destruct l; cbn.
f_equal; apply map_map.
Qed.
Lemma cmap_id :
forall {A : Type} (l : Cyclic A),
cmap (fun x => x) l = l.
Proof.
destruct l; cbn.
f_equal; apply map_id.
Qed.
Definition capp {A : Type} (l1 l2 : Cyclic A) : Cyclic A :=
match l1, l2 with
| C s1 [], C s2 c2 => C (s1 ++ s2) c2
| C s1 c1, C s2 c2 => l1
end.
Lemma map_app :
forall {A B : Type} (f : A -> B) (l1 l2 : Cyclic A),
cmap f (capp l1 l2) = capp (cmap f l1) (cmap f l2).
Proof.
destruct l1 as [s1 []], l2 as [s2 c2]; cbn.
f_equal. apply map_app.
reflexivity.
Qed.
Lemma capp_assoc :
forall {A : Type} (l1 l2 l3 : Cyclic A),
capp (capp l1 l2) l3 = capp l1 (capp l2 l3).
Proof.
destruct l1 as [s1 []], l2 as [s2 []], l3 as [s3 c3]; cbn.
2-4: reflexivity.
f_equal. rewrite app_assoc. reflexivity.
Qed.
Definition csnoc {A : Type} (x : A) (l : Cyclic A) : Cyclic A :=
match l with
| C s [] => C (snoc x s) []
| C s c => C s c
end.
Lemma csnoc_capp :
forall {A : Type} (x : A) (l1 l2 : Cyclic A),
csnoc x (capp l1 l2) = capp l1 (csnoc x l2).
Proof.
destruct l1 as [s1 []], l2 as [s2 []]; cbn.
2-4: try reflexivity.
f_equal. apply snoc_app.
Qed.
Definition creplicate {A : Type} (n : nat) (x : A) : Cyclic A :=
C (replicate n x) [].
Definition crepeat {A : Type} (x : A) : Cyclic A :=
C [] [x].
Inductive Finite {A : Type} : Cyclic A -> Type :=
| Finite' : forall l : list A, Finite (C l []).
Lemma Finite_creplicate :
forall (n : nat) {A : Type} (x : A),
Finite (creplicate n x).
Proof.
constructor.
Qed.
Lemma not_Finite_crepeat :
forall {A : Type} (x : A),
Finite (crepeat x) -> False.
Proof.
inversion 1.
Qed.
Definition ccons {A : Type} (h : A) (t : Cyclic A) : Cyclic A :=
match t with
| C s c => C (h :: s) c
end.
Definition cuncons {A : Type} (l : Cyclic A) : option (A * Cyclic A) :=
match l with
| C [] [] => None
| C [] (h :: t) => Some (h, C [] (snoc h t))
| C (h :: t) c => Some (h, C t c)
end.
Definition example : Cyclic nat :=
C [] [1; 2; 3; 4; 5].
Fixpoint ctake (n : nat) {A : Type} (l : Cyclic A) : list A :=
match n, l with
| 0 , _ => []
| S n', C [] [] => []
| S n', C (h :: t) c => h :: ctake n' (C t c)
| S n', C [] (h :: t) => h :: ctake n' (C [] (snoc h t))
end.
Compute ctake 10 example.
Fixpoint cdrop (n : nat) {A : Type} (l : Cyclic A) : Cyclic A :=
match n, l with
| 0 , _ => l
| S n', C [] [] => C [] []
| S n', C (h :: t) c => cdrop n' (C t c)
| S n', C [] (h :: t) => cdrop n' (C [] (snoc h t))
end.
Compute cdrop 23 example.
Fixpoint cbind_aux {A B : Type} (l : list A) (f : A -> Cyclic B) : Cyclic B :=
match l with
| [] => C [] []
| h :: t => capp (f h) (cbind_aux t f)
end.
Definition cbind {A B : Type} (l : Cyclic A) (f : A -> Cyclic B) : Cyclic B :=
match l with
| C s c => capp (cbind_aux s f) (cbind_aux c f)
end.
Definition crev {A : Type} (l : Cyclic A) : Cyclic A :=
match l with
| C s [] => C (rev s) []
| C _ c => C [] (rev c)
end.
Compute ctake 10 (crev (C [1; 2] [3; 4; 5])).
Compute crev example.
Fixpoint nth (n : nat) {A : Type} (l : Cyclic A) : option A :=
match n, l with
| _ , C [] [] => None
| 0 , C (h :: _) _ => Some h
| 0 , C [] (h :: _) => Some h
| S n', C (_ :: t) c => nth n' (C t c)
| S n', C [] (h :: t) => nth n' (C [] (snoc h t))
end.
Compute map (fun n => nth n example) [0; 1; 2; 3; 4; 5; 6; 7].
Definition cany {A : Type} (p : A -> bool) (l : Cyclic A) : bool :=
match l with
| C s c => any p s || any p c
end.
Definition cfilter {A : Type} (p : A -> bool) (l : Cyclic A) : Cyclic A :=
match l with
| C s c => C (filter p s) (filter p c)
end.
Compute example.
Compute cfilter Nat.even example.
Compute ctake 10 (cfilter Nat.even example).
Definition cintersperse {A : Type} (x : A) (l : Cyclic A) : Cyclic A :=
match l with
| C s [] => C (intersperse x s) []
| C s c => C (intersperse x s) (x :: intersperse x c)
end.
Compute example.
Compute cintersperse 0 example.
Compute ctake 20 (cintersperse 0 example).
Definition ctakeWhile {A : Type} (p : A -> bool) (l : Cyclic A) : Cyclic A :=
match l with
| C s c =>
if length s =? length (takeWhile p s)
then C (takeWhile p s) (takeWhile p c)
else C (takeWhile p s) []
end.
Compute ctakeWhile (fun n => n <? 3) example.
Definition cdropWhile {A : Type} (p : A -> bool) (l : Cyclic A) : Cyclic A :=
match l with
| C s c =>
match dropWhile p s with
| [] => C [] (dropWhile p c)
| s' => C s' c
end
end.
Compute cdropWhile (fun n => n <? 3) example.
End SimpleCyclicList.
Cykliczne drzewa binarne (TODO)
Sadly, this wonderful technique doesn't work with binary trees. This is
because cyclic lists have only one cycle, which is easy to represent with
a single ordinary
list, but trees can have as many cycles as they have
leaves.
Module CyclicBinaryTree.
Inductive CBin (A V : Type) : Type :=
| Var : V -> CBin A V
| E : CBin A V
| N : A -> CBin A (option V) -> CBin A (option V) -> CBin A V.
Arguments Var {A V} _.
Arguments E {A V}.
Arguments N {A V} _ _ _.
Definition CBin' (A : Type) : Type :=
CBin A False.
Definition example : CBin' nat :=
N 1
(N 2
(N 3 (Var None) E)
E)
(N 4
(N 5 E E)
(N 6 E E)).
Fixpoint recycle {A V : Type} (x : A) (t : CBin A (option V)) : CBin A V :=
match t with
| Var None => N x (Var None) (Var None)
| Var (Some v) => Var v
| E => E
| N y l r => N y (recycle x l) (recycle x r)
end.
Definition unN {A : Type} (t : CBin' A) : option (A * CBin' A * CBin' A) :=
match t with
| Var v => match v with end
| E => None
| N x l r => Some (x, recycle x l, recycle x r)
end.
Fixpoint map {A B V : Type} (f : A -> B) (t : CBin A V) : CBin B V :=
match t with
| Var v => Var v
| E => E
| N x l r => N (f x) (map f l) (map f r)
end.
Fixpoint mirror {A V : Type} (t : CBin A V) : CBin A V :=
match t with
| Var v => Var v
| E => E
| N x l r => N x (mirror r) (mirror l)
end.
Definition complete {A : Type} (x : A) : CBin' A :=
N x (Var None) (Var None).
Fixpoint index {A : Type} (l : list bool) (t : CBin' A) : option A :=
match l, unN t with
| _, None => None
| [] , Some (x, _ , _ ) => Some x
| false :: l', Some (_, t', _ ) => index l' t'
| true :: l', Some (_, _ , t') => index l' t'
end.
Compute example.
Compute index [false; false; false; false] example.
Fixpoint shift {A V : Type} (t : CBin A V) : CBin A (option V) :=
match t with
| Var v => Var (Some v)
| E => E
| N x l r => N x (shift l) (shift r)
end.
Fixpoint take (n : nat) {A : Type} (t : CBin' A) : CBin' A :=
match n, unN t with
| _ , None => E
| 0 , _ => E
| S n', Some (x, l, r) => N x (shift (take n' l)) (shift (take n' r))
end.
Compute take 5 example.
Fixpoint any {A V : Type} (p : A -> bool) (t : CBin A V) : bool :=
match t with
| Var v => false
| E => false
| N x l r => p x || any p l || any p r
end.
Fixpoint all {A V : Type} (p : A -> bool) (t : CBin A V) : bool :=
match t with
| Var v => false
| E => false
| N x l r => p x && all p l && all p r
end.
Fixpoint takeWhile {A V : Type} (p : A -> bool) (t : CBin A V) : CBin A V :=
match t with
| Var v => Var v
| E => E
| N x l r => if p x then N x (takeWhile p l) (takeWhile p r) else E
end.
Compute takeWhile (fun x => Nat.leb x 3) example.
End CyclicBinaryTree.
Module GeneralCyclicStructures.
The above approach can be generalized even more, to a Fixpoint-with-Cycles
inductive type like. But for this to work in Coq, we need to turn off the
positivity checker and then the termination checker each time we want to
implement a recursive function, so we're not going to pursue the generalized
approach here.
Anyway, for more details see
Representing Cyclic Structures as Nested Data Types, section 4.
End GeneralCyclicStructures.