-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathRoseTree.v
187 lines (152 loc) · 6.58 KB
/
RoseTree.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
(**********************************************************************)
(* Equations *)
(* Copyright (c) 2009-2021 Matthieu Sozeau <[email protected]> *)
(**********************************************************************)
(* This file is distributed under the terms of the *)
(* GNU Lesser General Public License Version 2.1 *)
(**********************************************************************)
From Stdlib Require Import Program.
From Equations.Prop Require Import Equations.
From Stdlib Require Import Utf8 Lia Arith.
From Stdlib Require Import List.
Import ListNotations.
Set Keyed Unification.
Equations map_In {A B : Type}
(l : list A) (f : forall (x : A), In x l -> B) : list B :=
| nil, _ := nil
| cons x xs, f := cons (f x _) (map_In xs (fun x H => f x _)).
Lemma map_In_spec {A B : Type} (f : A -> B) (l : list A) :
map_In l (fun (x : A) (_ : In x l) => f x) = List.map f l.
Proof.
funelim (map_In l _); rewrite ?H; trivial.
Qed.
Section list_size.
Context {A : Type} (f : A -> nat).
Equations list_size (l : list A) : nat :=
| nil := 0
| x :: xs := S (f x + list_size xs).
Lemma In_list_size:
forall x xs, In x xs -> f x < S (list_size xs).
Proof.
intros. funelim (list_size xs); simpl in *. destruct H.
destruct H0.
* subst; lia.
* specialize (H _ H0). intuition. lia.
Qed.
End list_size.
Transparent list_size.
Module RoseTree.
Section roserec.
Context {A : Set}.
Inductive t : Set :=
| leaf (a : A) : t
| node (l : list t) : t.
Derive NoConfusion for t.
Fixpoint size (r : t) :=
match r with
| leaf a => 0
| node l => S (list_size size l)
end.
Equations? elements (r : t) : list A by wf (size r) lt :=
elements (leaf a) := [a];
elements (node l) := concat (map_In l (fun x H => elements x)).
Proof. red. now apply In_list_size. Qed.
Equations elements_def (r : t) : list A :=
elements_def (leaf a) := [a];
elements_def (node l) := concat (List.map elements_def l).
Lemma elements_equation (r : t) : elements r = elements_def r.
Proof.
funelim (elements r); simp elements_def; trivial. f_equal.
rewrite map_In_spec. clear Heqcall.
induction l; simpl; auto. rewrite H. rewrite IHl; auto.
intros. apply H. now constructor 2. now constructor.
Qed.
(** To solve measure subgoals *)
Hint Extern 4 (_ < _) => simpl; lia : rec_decision.
Hint Extern 4 (MR _ _ _ _) => repeat red; simpl in *; lia : rec_decision.
Obligation Tactic := simpl in *; program_simpl; try typeclasses eauto with subterm_relation simp rec_decision.
(* Nested rec *)
Equations elements_acc (r : t) (acc : list A) : list A by wf (size r) lt :=
elements_acc (leaf a) acc := a :: acc;
elements_acc (node l) acc := aux l _
where aux (x : list t) (H : list_size size x < size (node l)) : list A by wf (list_size size x) lt :=
aux nil _ := acc;
aux (cons x xs) H := elements_acc x (aux xs _).
Definition elements2 (r : t) : list A := elements_acc r [].
Lemma elements2_equation r acc : elements_acc r acc = elements_def r ++ acc.
Proof.
revert r acc.
let t := constr:(fun_elim (f:=elements_acc)) in
apply (t (fun r acc res => res = elements_def r ++ acc)
(fun r acc x H res => res = concat (List.map elements_def x) ++ acc));
intros; simp elements; trivial.
rewrite H1. clear H1.
rewrite H0. simpl. now rewrite app_assoc.
Qed.
Equations elements' (r : t) : list A by wf r (MR lt size) :=
| leaf a := [a]
| node l := fn l hidebody
where fn (x : list t) (H : list_size size x < size (node l)) : list A
by wf x (MR lt (list_size size)) :=
| nil, _ := nil;
| cons x xs, _ := elements' x ++ fn xs hidebody.
Equations elements'_def (r : t) : list A :=
elements'_def (leaf a) := [a];
elements'_def (node l) := concat (List.map elements' l).
Lemma elements'_equation (r : t) : elements' r = elements'_def r.
Proof.
pose (fun_elim (f:=elements')).
apply (p (fun r f => f = elements'_def r) (fun l x H r => r = concat (List.map elements' x)));
clear p; intros; simp elements'_def; trivial.
simpl. f_equal. apply H1.
Qed.
End roserec.
Arguments t : clear implicits.
Section AltSize.
Context {A : Set}.
(** Let's use an alternative size criterion allowing to make recursive calls
on non-strict subterms of the initial list: we just count the maximal
depth of [node] constructors among all forests. *)
Equations alt_size (r : t A) : nat :=
{ alt_size (leaf _) => 0;
alt_size (node l) => S (max_size l) }
where max_size (l : list (t A)) : nat :=
{ max_size nil := 0;
max_size (cons a t) := Nat.max (alt_size a) (max_size t) }.
(** This has the property that the maximal size of two appended lists is the maximal
size of the separate lists. *)
Lemma max_size_app l l' : max_size (l ++ l') = Nat.max (max_size l) (max_size l').
Proof.
induction l; simp max_size. reflexivity.
simpl. rewrite <- Nat.max_assoc. f_equal.
apply IHl.
Qed.
Context {B : Set} (f : A -> B).
(** It hence becomes possible to recurse on an arbitrary list as long as the depth
decreases, for example by appending the subforest to itself in the [node] case.
The same is possible with sized types where node has type [j < i -> list^i (t^j) -> t^(S i)].
*)
Equations? map_t (r : t A) : t B by wf (alt_size r) lt :=
map_t (leaf a) := leaf (f a);
map_t (node l) := node (map_list (l ++ l) _)
where map_list (l' : list (t A)) (H : max_size l' ≤ max_size l) : list (t B) by struct l' :=
map_list nil _ := nil;
map_list (cons a t) Hl' := cons (map_t a) (map_list t _).
Proof. simp alt_size. apply Nat.lt_succ_r. now apply Nat.max_lub_l in Hl'.
now apply Nat.max_lub_r in Hl'.
clear map_list. rewrite max_size_app. now rewrite Nat.max_id.
Defined.
End AltSize.
Section fns.
Context {A B : Set} (f : A -> B) (g : B -> A -> B) (h : A -> B -> B).
Equations map (r : t A) : t B :=
| leaf a := leaf (f a)
| node l := node (List.map map l).
Equations fold (acc : B) (r : t A) : B :=
fold acc (leaf a) := g acc a;
fold acc (node l) := List.fold_left fold l acc.
Equations fold_right (r : t A) (acc : B) : B :=
fold_right (leaf a) acc := h a acc;
fold_right (node l) acc := List.fold_right fold_right acc l.
End fns.
End RoseTree.