1
1
struct node {
2
2
int value ;
3
- struct node * next ;
3
+ struct node * next ;
4
4
};
5
5
6
6
/*@
@@ -25,7 +25,7 @@ function [rec] ({list fst, list snd}) cn_split(list xs) {
25
25
{fst: Nil {}, snd: Nil {}}
26
26
}
27
27
Cons {head: h1, tail: Nil {}} => {
28
- {fst: Nil {} , snd: xs }
28
+ {fst: xs , snd: Nil {} }
29
29
}
30
30
Cons {head: h1, tail: Cons {head : h2, tail : tl2 }} => {
31
31
let P = cn_split(tl2);
@@ -37,22 +37,23 @@ function [rec] ({list fst, list snd}) cn_split(list xs) {
37
37
38
38
function [rec] (list) cn_merge(list xs, list ys) {
39
39
match xs {
40
- Nil {} => {
41
- ys
42
- }
43
- Cons {head: x, tail: xs1} => {
44
- match ys {
45
- Nil {} => {
46
- xs
40
+ Nil {} => {
41
+ ys
42
+ }
43
+ Cons {head: x, tail: xs_} => {
44
+ match ys {
45
+ Nil {} => {
46
+ xs
47
+ }
48
+ Cons {head: y, tail: ys_} => {
49
+ if (x <= y) {
50
+ Cons {head: x, tail: cn_merge(xs_, ys)}
51
+ } else {
52
+ Cons {head: y, tail: cn_merge(xs, ys_)}
47
53
}
48
- Cons { head: y, tail: ys1} => {
49
- let tail = cn_merge(xs1, ys1);
50
- (x < y) ?
51
- (Cons { head: x, tail: Cons {head: y, tail: tail}})
52
- : (Cons { head: y, tail: Cons {head: x, tail: tail}})
53
- }
54
- }
54
+ }
55
55
}
56
+ }
56
57
}
57
58
}
58
59
@@ -72,11 +73,44 @@ function [rec] (list) cn_mergesort(list xs) {
72
73
}
73
74
}
74
75
}
76
+
77
+ function (boolean) smaller (i32 head, list xs) {
78
+ match xs {
79
+ Nil {} => {
80
+ true
81
+ }
82
+ Cons {head : x, tail : _} => {
83
+ head <= x
84
+ }
85
+ }
86
+ }
87
+
88
+ function [rec] (boolean) is_sorted(list xs) {
89
+ match xs {
90
+ Nil {} => {
91
+ true
92
+ }
93
+ Cons {head: head, tail: tail} => {
94
+ smaller (head, tail) && is_sorted(tail)
95
+ }
96
+ }
97
+ }
98
+
99
+ function (list) tl (list xs) {
100
+ match xs {
101
+ Nil {} => {
102
+ Nil {}
103
+ }
104
+ Cons {head : _, tail : tail} => {
105
+ tail
106
+ }
107
+ }
108
+ }
75
109
@*/
76
110
77
111
struct node_pair {
78
- struct node * fst ;
79
- struct node * snd ;
112
+ struct node * fst ;
113
+ struct node * snd ;
80
114
};
81
115
82
116
struct node_pair split (struct node * xs )
@@ -92,7 +126,7 @@ struct node_pair split(struct node *xs)
92
126
} else {
93
127
struct node * cdr = xs -> next ;
94
128
if (cdr == 0 ) {
95
- struct node_pair r = {.fst = 0 , .snd = xs };
129
+ struct node_pair r = {.fst = xs , .snd = 0 };
96
130
return r ;
97
131
} else {
98
132
struct node_pair p = split (cdr -> next );
@@ -104,7 +138,7 @@ struct node_pair split(struct node *xs)
104
138
}
105
139
}
106
140
107
- struct node * merge (struct node * xs , struct node * ys )
141
+ struct node * merge (struct node * xs , struct node * ys )
108
142
/*@ requires take Xs = List(xs); @*/
109
143
/*@ requires take Ys = List(ys); @*/
110
144
/*@ ensures take Zs = List(return); @*/
@@ -113,25 +147,18 @@ struct node* merge(struct node *xs, struct node *ys)
113
147
/*@ unfold cn_merge(Xs, Ys); @*/
114
148
if (xs == 0 ) {
115
149
return ys ;
150
+ } else if (ys == 0 ) {
151
+ return xs ;
152
+ } else if (xs -> value <= ys -> value ) {
153
+ xs -> next = merge (xs -> next , ys );
154
+ return xs ;
116
155
} else {
117
- if (ys == 0 ) {
118
- return xs ;
119
- } else {
120
- struct node * zs = merge (xs -> next , ys -> next );
121
- if (xs -> value < ys -> value ) {
122
- xs -> next = ys ;
123
- ys -> next = zs ;
124
- return xs ;
125
- } else {
126
- ys -> next = xs ;
127
- xs -> next = zs ;
128
- return ys ;
129
- }
130
- }
156
+ ys -> next = merge (xs , ys -> next );
157
+ return ys ;
131
158
}
132
159
}
133
160
134
- struct node * naive_mergesort (struct node * xs )
161
+ struct node * naive_mergesort (struct node * xs )
135
162
/*@ requires take Xs = List(xs); @*/
136
163
/*@ ensures take Ys = List(return); @*/
137
164
/*@ ensures Ys == cn_mergesort(Xs); @*/
@@ -149,6 +176,9 @@ struct node* naive_mergesort(struct node *xs)
149
176
}
150
177
}
151
178
179
+
180
+
181
+
152
182
int main (void )
153
183
/*@ trusted; @*/
154
184
{
@@ -158,3 +188,57 @@ int main(void)
158
188
159
189
struct node * sorted_i1 = naive_mergesort (& i1 );
160
190
}
191
+
192
+
193
+
194
+
195
+
196
+ void prove_merge_sorted (struct node * p , struct node * q )
197
+ /*@ requires take xs_in = List(p);
198
+ take ys_in = List(q);
199
+ is_sorted(xs_in);
200
+ is_sorted(ys_in);
201
+ let merged = cn_merge(xs_in, ys_in);
202
+ ensures take xs_out = List(p);
203
+ take ys_out = List(q);
204
+ xs_out == xs_in && ys_out == ys_in;
205
+ is_sorted(merged);
206
+ @*/
207
+ {
208
+ /* Unfold the definition of `merged`. */
209
+ /*@ unfold cn_merge(xs_in, ys_in); @*/
210
+
211
+ /* If either list is empty, cn_merge just picks the other, which is
212
+ sorted by assumption, so nothing left to do. */
213
+ if (p == 0 || q == 0 ) {
214
+ return ;
215
+ }
216
+ /* For non-empty lists, cn_merge picks the smaller head and merges
217
+ the rest. */
218
+ else {
219
+ /* If `xs_in` has the smaller head, it merges `tl(xs_in)` with
220
+ `ys_in`. */
221
+ if (p -> value <= q -> value ) {
222
+ /* By induction hypothesis (IH) `cn_merge(tl(xs_in), ys_in))` is
223
+ sorted. To "apply" IH, expand the definition of
224
+ `is_sorted(xs_in)` to prove `is_sorted(tl(xs_in))`. */
225
+ /*@ unfold is_sorted(xs_in); @*/
226
+ prove_merge_sorted (p -> next , q );
227
+ /* By definition of `cn_merge(tl(xs_in), ys_in)`, that merged
228
+ list starts with the minimum of either head, ... */
229
+ /*@ unfold cn_merge(tl(xs_in), ys_in); @*/
230
+ /* ... so that list with `hd(xs_in)` cons'ed on is also
231
+ sorted. @*/
232
+ /*@ unfold is_sorted(merged); @*/
233
+ return ;
234
+ }
235
+ else {
236
+ /* This is symmetric to the proof above. */
237
+ /*@ unfold is_sorted(ys_in); @*/
238
+ prove_merge_sorted (p , q -> next );
239
+ /*@ unfold cn_merge(xs_in, tl(ys_in)); @*/
240
+ /*@ unfold is_sorted(merged); @*/
241
+ return ;
242
+ }
243
+ }
244
+ }
0 commit comments