YAP 7.1.0
sort.c
1/*************************************************************************
2* *
3* YAP Prolog *
4* *
5* Yap Prolog was developed at NCCUP - Universidade do Porto *
6* *
7* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8* *
9**************************************************************************
10* *
11* File: sort.c *
12* Last rev: *
13* mods: *
14* comments: sorting in Prolog *
15* *
16*************************************************************************/
17
18/* for the moment, follow Prolog's traditional mergesort */
19
20#include "Yap.h"
21#include "YapError.h"
22#include "Yatom.h"
23#include "YapHeap.h"
24#include "amiops.h"
25
26/* fill in the even or the odd elements */
27#define M_EVEN 0
28#define M_ODD 1
29
30static void simple_mergesort(CELL *, Int, int);
31static Int compact_mergesort(CELL *, Int, int);
32static int key_mergesort(CELL *, Int, int, Functor);
33static void adjust_vector(CELL *, Int);
34static Int p_sort( USES_REGS1 );
35static Int p_msort( USES_REGS1 );
36static Int p_ksort( USES_REGS1 );
37
38
39/* copy to a new list of terms */
40static
41void simple_mergesort(CELL *pt, Int size, int my_p)
42{
43
44 if (size > 2) {
45 Int half_size = size / 2;
46 CELL *pt_left, *pt_right, *end_pt, *end_pt_left;
47 int left_p, right_p;
48
49 pt_right = pt + half_size*2;
50 left_p = my_p^1;
51 right_p = my_p;
52 simple_mergesort(pt, half_size, left_p);
53 simple_mergesort(pt_right, size-half_size, right_p);
54 /* now implement a simple merge routine */
55
56 /* pointer to after the end of the list */
57 end_pt = pt + 2*size;
58 /* pointer to the element after the last element to the left */
59 end_pt_left = pt+half_size*2;
60 /* where is left list */
61 pt_left = pt+left_p;
62 /* where is right list */
63 pt_right += right_p;
64 /* where is new list */
65 pt += my_p;
66 /* while there are elements in the left or right vector do compares */
67 while (pt_left < end_pt_left && pt_right < end_pt) {
68 /* if the element to the left is larger than the one to the right */
69 if (Yap_compare_terms(pt_left[0], pt_right[0]) <= 0) {
70 /* copy the one to the left */
71 pt[0] = pt_left[0];
72 /* and avance the two pointers */
73 pt += 2;
74 pt_left += 2;
75 } else {
76 /* otherwise, copy the one to the right */
77 pt[0] = pt_right[0];
78 pt += 2;
79 pt_right += 2;
80 }
81 }
82 /* if any elements were left in the left vector just copy them */
83 while (pt_left < end_pt_left) {
84 pt[0] = pt_left[0];
85 pt += 2;
86 pt_left += 2;
87 }
88 /* if any elements were left in the right vector
89 and they are in the wrong place, just copy them */
90 if (my_p != right_p) {
91 while(pt_right < end_pt) {
92 pt[0] = pt_right[0];
93 pt += 2;
94 pt_right += 2;
95 }
96 }
97 } else {
98 if (size > 1 && (Yap_compare_terms(pt[0],pt[2]) > 0)) {
99 CELL t = pt[2];
100 pt[2+my_p] = pt[0];
101 pt[my_p] = t;
102 } else if (my_p) {
103 pt[1] = pt[0];
104 if (size > 1)
105 pt[3] = pt[2];
106 }
107 }
108}
109
110/* copy to a new list of terms */
111static
112int key_mergesort(CELL *pt, Int size, int my_p, Functor FuncDMinus)
113{
114
115 if (size > 2) {
116 Int half_size = size / 2;
117 CELL *pt_left, *pt_right, *end_pt, *end_pt_left;
118 int left_p, right_p;
119
120 pt_right = pt + half_size*2;
121 left_p = my_p^1;
122 right_p = my_p;
123 if (!key_mergesort(pt, half_size, left_p, FuncDMinus))
124 return(FALSE);
125 if (!key_mergesort(pt_right, size-half_size, right_p, FuncDMinus))
126 return(FALSE);
127 /* now implement a simple merge routine */
128
129 /* pointer to after the end of the list */
130 end_pt = pt + 2*size;
131 /* pointer to the element after the last element to the left */
132 end_pt_left = pt+half_size*2;
133 /* where is left list */
134 pt_left = pt+left_p;
135 /* where is right list */
136 pt_right += right_p;
137 /* where is new list */
138 pt += my_p;
139 /* while there are elements in the left or right vector do compares */
140 while (pt_left < end_pt_left && pt_right < end_pt) {
141 /* if the element to the left is larger than the one to the right */
142 Term t0 = pt_left[0] , t1 = pt_right[0];
143 if (IsVarTerm(t0) || !IsApplTerm(t0) || FunctorOfTerm(t0) != FuncDMinus)
144 return(FALSE);
145 t0 = ArgOfTerm(1,t0);
146 if (IsVarTerm(t1) || !IsApplTerm(t1) || FunctorOfTerm(t1) != FuncDMinus)
147 return(FALSE);
148 t1 = ArgOfTerm(1,t1);
149 if (Yap_compare_terms(t0, t1) <= 0) {
150 /* copy the one to the left */
151 pt[0] = pt_left[0];
152 /* and avance the two pointers */
153 pt += 2;
154 pt_left += 2;
155 } else {
156 /* otherwise, copy the one to the right */
157 pt[0] = pt_right[0];
158 pt += 2;
159 pt_right += 2;
160 }
161 }
162 /* if any elements were left in the left vector just copy them */
163 while (pt_left < end_pt_left) {
164 pt[0] = pt_left[0];
165 pt += 2;
166 pt_left += 2;
167 }
168 /* if any elements were left in the right vector
169 and they are in the wrong place, just copy them */
170 if (my_p != right_p) {
171 while(pt_right < end_pt) {
172 pt[0] = pt_right[0];
173 pt += 2;
174 pt_right += 2;
175 }
176 }
177 } else {
178 if (size > 1) {
179 Term t0 = pt[0], t1 = pt[2];
180 if (IsVarTerm(t0) || !IsApplTerm(t0) || FunctorOfTerm(t0) != FuncDMinus)
181 return(FALSE);
182 t0 = ArgOfTerm(1,t0);
183 if (IsVarTerm(t1) || !IsApplTerm(t1) || FunctorOfTerm(t1) != FuncDMinus)
184 return(FALSE);
185 t1 = ArgOfTerm(1,t1);
186 if (Yap_compare_terms(t0,t1) > 0) {
187 CELL t = pt[2];
188 pt[2+my_p] = pt[0];
189 pt[my_p] = t;
190 } else if (my_p) {
191 pt[1] = pt[0];
192 pt[3] = pt[2];
193 }
194 } else {
195 if (my_p)
196 pt[1] = pt[0];
197 }
198 }
199 return(TRUE);
200}
201
202/* copy to a new list of terms and compress duplicates */
203static
204Int compact_mergesort(CELL *pt, Int size, int my_p)
205{
206
207 if (size > 2) {
208 Int half_size = size / 2;
209 CELL *pt_left, *pt_right, *end_pt_right, *end_pt_left;
210 int left_p, right_p;
211 Int lsize, rsize;
212
213 pt_right = pt + half_size*2;
214 left_p = my_p^1;
215 right_p = my_p;
216 lsize = compact_mergesort(pt, half_size, left_p);
217 rsize = compact_mergesort(pt_right, size-half_size, right_p);
218 /* now implement a simple merge routine */
219
220 /* where is left list */
221 pt_left = pt+left_p;
222 /* pointer to the element after the last element to the left */
223 end_pt_left = pt+2*lsize;
224 /* where is right list */
225 pt_right += right_p;
226 /* pointer to after the end of the list */
227 end_pt_right = pt_right + 2*rsize;
228 /* where is new list */
229 pt += my_p;
230 size = 0;
231 /* while there are elements in the left or right vector do compares */
232 while (pt_left < end_pt_left && pt_right < end_pt_right) {
233 /* if the element to the left is larger than the one to the right */
234 Int cmp = Yap_compare_terms(pt_left[0], pt_right[0]);
235 if (cmp < (Int)0) {
236 /* copy the one to the left */
237 pt[0] = pt_left[0];
238 /* and avance the two pointers */
239 pt += 2;
240 size ++;
241 pt_left += 2;
242 } else if (cmp == (Int)0) {
243 /* otherwise, just skip one of them, anyone */
244 pt_left += 2;
245 } else {
246 /* otherwise, copy the one to the right */
247 pt[0] = pt_right[0];
248 pt += 2;
249 pt_right += 2;
250 size++;
251 }
252 }
253 /* if any elements were left in the left vector just copy them */
254 while (pt_left < end_pt_left) {
255 pt[0] = pt_left[0];
256 pt += 2;
257 pt_left += 2;
258 size++;
259 }
260 /* if any elements were left in the right vector
261 and they are in the wrong place, just copy them */
262 while(pt_right < end_pt_right) {
263 pt[0] = pt_right[0];
264 pt += 2;
265 pt_right += 2;
266 size++;
267 }
268 return(size);
269 } else if (size == 2) {
270 Int cmp = Yap_compare_terms(pt[0],pt[2]);
271 if (cmp > 0) {
272 /* swap */
273 CELL t = pt[2];
274 pt[2+my_p] = pt[0];
275 pt[my_p] = t;
276 return(2);
277 } else if (cmp == 0) {
278 if (my_p)
279 pt[1] = pt[0];
280 return(1);
281 } else {
282 if (my_p) {
283 pt[1] = pt[0];
284 pt[3] = pt[2];
285 }
286 return(2);
287 }
288 } else {
289 /* size = 1 */
290 if (my_p)
291 pt[1] = pt[0];
292 return(1);
293 }
294}
295
296static void
297adjust_vector(CELL *pt, Int size)
298{ /* the elements are where they should be */
299 CELL *ptf = pt + 2*(size-1);
300 pt ++;
301 while (pt < ptf) {
302 pt[0] = AbsPair(pt+1);
303 pt += 2;
304 }
305 /* close the list */
306 pt[0] = TermNil;
307}
308
309
310
311static ssize_t prepare(Term t)
312{
313 /* use the heap to build a new list */
314 Term r0[1], *r = r0;
315 r0[0]=TermNil;
316 /* list size */
317 if (IsVarTerm(t)) {
318 Yap_ThrowError( INSTANTIATION_ERROR, t, "sort");
319 return -1;
320 }
321 Term t0 = t;
322 ssize_t size = Yap_SkipList(&t,&r);
323 if (size < 0 || r[0] != TermNil) {
324 if (IsVarTerm(r[0])) {
325 Yap_ThrowError( INSTANTIATION_ERROR, r[0], "sort");
326 return -1;
327 }
328 if (r[0] != TermNil) {
329 Yap_ThrowError( TYPE_ERROR_LIST, t0, "sort");
330 return -1;
331 }
332 }
333 while (ASP-HR < 2*size+4096) {
334 yhandle_t yt = Yap_InitHandle(t);
335 if (!Yap_dogcl(3*size*sizeof(CELL))) {
336 Yap_ThrowError(RESOURCE_ERROR_STACK, TermNil, NULL);
337 return(FALSE);
338 }
339 t = Yap_GetFromHandle(yt);
340 }
341 /* make sure no one writes on our temp data structure */
342 ssize_t i;
343 for (i=0;i<size;i++) {
344 *HR++ = HeadOfTerm(t);
345 *HR = 0;
346 t = TailOfTerm(t);
347 HR++;
348 }
349 return size;
350}
351
352Term Yap_MergeSort(Term l USES_REGS)
353{
354 CELL *pt;
355 ssize_t size = prepare(l);
356 if (size < 2) {
357 return l;
358 }
359
360 pt = HR-2*size;
361 if (pt > ASP-1024)
362 return 0;
363 simple_mergesort(pt, size, M_EVEN);
364 adjust_vector(pt, size);
365 /* reajust space */
366 HR = pt+size*2;
367 return AbsPair(pt);
368}
369
370Term Yap_SortList(Term l USES_REGS)
371{
372 CELL *pt;
373 ssize_t size = prepare(l);
374 if (size < 2) {
375 return l;
376 }
377
378 pt = HR-2*size;
379 if (pt > ASP-1024)
380 return 0;
381size=
382 compact_mergesort(pt, size, M_EVEN);
383 adjust_vector(pt, size);
384 /* reajust space */
385 HR = pt+size*2;
386 return AbsPair(pt);
387}
388
389static Int
390p_sort( USES_REGS1 )
391{
392
393 ssize_t size = prepare(Deref(ARG1));
394 if (size < 2) {
395 HR -= 2*size;
396 return(Yap_unify(ARG1, ARG2));
397 }
398 CELL *pt = HR-2*size;
399 /* use the heap to build a new list */
400 Term out;
401 size = compact_mergesort(pt, size, M_EVEN);
402 adjust_vector(pt, size);
403 out = AbsPair(pt);
404 return(Yap_unify(out, ARG2));
405}
406
407static Int
408p_msort( USES_REGS1 )
409{
410
411 ssize_t size = prepare(Deref(ARG1));
412 if (size < 2) {
413 HR -= 2*size;
414 return(Yap_unify(ARG1, ARG2));
415 }
416 CELL *pt = HR-2*size;
417 /* use the heap to build a new list */
418 Term out;
419 simple_mergesort(pt, size, M_EVEN);
420 adjust_vector(pt, size);
421 out = AbsPair(pt);
422 return(Yap_unify(out, ARG2));
423}
424
425static Int
426p_ksort( USES_REGS1 )
427{
428 /* use the heap to build a new list */
429 Term out;
430 ssize_t size = prepare(Deref(ARG1));
431 if (size < 2) {
432 HR -= 2*size;
433 return(Yap_unify(ARG1, ARG2));
434 }
435 CELL *pt = HR-2*size;
436 if (!key_mergesort(pt, size, M_EVEN, FunctorMinus))
437 return(FALSE);
438 adjust_vector(pt, size);
439 out = AbsPair(pt);
440 return(Yap_unify(out, ARG2));
441}
442
443void
444Yap_InitSortPreds(void)
445{
446 Yap_InitCPred("$sort", 2, p_sort, 0);
447 Yap_InitCPred("$msort", 2, p_msort, 0);
448 Yap_InitCPred("$keysort", 2, p_ksort, 0);
449}
Main definitions.