1 /*-----------------------------------------------------------------------
2
3 File: cto_kbolin.c
4
5 Author: Stephan Schulz
6
7 Contents:
8 Implementation of a Knuth_Bendix ordering (KBO) on CLIB
9 terms. This is based on CTKBO4-6 from [Loechner:JAR-2006].
10
11
12 Copyright 2010 by the author.
13 This code is released under the GNU General Public Licence and
14 the GNU Lesser General Public License.
15 See the file COPYING in the main E directory for details..
16 Run "eprover -h" for contact information.
17
18 Changes
19
20 <1> New
21 <2> Tue Jun 23 08:36:23 MET DST 1998
22 Changed
23 <3> Fri Aug 17 00:26:53 CEST 2001
24 Removed old code
25
26
27 -----------------------------------------------------------------------*/
28
29 #include "cto_kbolin.h"
30 #include "clb_plocalstacks.h"
31
32
33 /*---------------------------------------------------------------------*/
34 /* Global Variables */
35 /*---------------------------------------------------------------------*/
36
37
38 /*---------------------------------------------------------------------*/
39 /* Forward Declarations */
40 /*---------------------------------------------------------------------*/
41
42 static CompareResult kbolincmp(OCB_p ocb, Term_p s, Term_p t,
43 DerefType deref_s, DerefType deref_t);
44
45 static CompareResult kbo6cmp(OCB_p ocb, Term_p s, Term_p t,
46 DerefType deref_s, DerefType deref_t);
47
48 static CompareResult kbo6cmplex(OCB_p ocb, Term_p s, Term_p t,
49 DerefType deref_s, DerefType deref_t);
50
51 /*---------------------------------------------------------------------*/
52 /* Internal Functions */
53 /*---------------------------------------------------------------------*/
54
55 /*-----------------------------------------------------------------------
56 //
57 // Function: resize_vb()
58 //
59 // Enlarge ocb->vb array enough to accomodate index.
60 //
61 // Global Variables: -
62 //
63 // Side Effects : -
64 //
65 /----------------------------------------------------------------------*/
66
resize_vb(OCB_p ocb,size_t index)67 static void __attribute__ ((noinline)) resize_vb(OCB_p ocb, size_t index)
68 {
69 unsigned long old_size = ocb->vb_size;
70 int *tmp = ocb->vb;
71
72 while(ocb->vb_size <= index)
73 {
74 ocb->vb_size *= 2;
75 }
76 ocb->vb = SizeMalloc(ocb->vb_size * sizeof(int));
77 memcpy(ocb->vb, tmp, old_size * sizeof(int));
78 SizeFree(tmp, old_size * sizeof(int));
79 for(size_t i = old_size; i<ocb->vb_size; i++)
80 {
81 ocb->vb[i] = 0;
82 }
83 }
84
85
86 /*-----------------------------------------------------------------------
87 //
88 // Function: inc_vb()
89 //
90 // Update all values in ocb when processing var on the
91 // LHS of a comparison.
92 //
93 // Global Variables: -
94 //
95 // Side Effects : -
96 //
97 /----------------------------------------------------------------------*/
98
inc_vb(OCB_p ocb,Term_p var)99 static void inc_vb(OCB_p ocb, Term_p var)
100 {
101 const size_t index = -var->f_code;
102
103 if(UNLIKELY(index > ocb->max_var))
104 {
105 if(UNLIKELY(index >= ocb->vb_size))
106 {
107 resize_vb(ocb, index);
108 }
109 ocb->max_var = index;
110 ocb->vb[index] = 1;
111 ocb->pos_bal++;
112 ocb->wb += ocb->var_weight;
113 }
114 else
115 {
116 const long tmpbal = ocb->vb[index]++;
117 ocb->pos_bal += (tmpbal == 0);
118 ocb->neg_bal -= (tmpbal == -1);
119 ocb->wb += ocb->var_weight;
120 }
121 }
122
123
124 /*-----------------------------------------------------------------------
125 //
126 // Function: dec_vb()
127 //
128 // Update all values in ocb when processing var on the
129 // RHS of a comparison.
130 //
131 // Global Variables: -
132 //
133 // Side Effects : -
134 //
135 /----------------------------------------------------------------------*/
136
dec_vb(OCB_p ocb,Term_p var)137 static void dec_vb(OCB_p ocb, Term_p var)
138 {
139 const size_t index = -var->f_code;
140
141 if(UNLIKELY(index > ocb->max_var))
142 {
143 if(UNLIKELY(index >= ocb->vb_size))
144 {
145 resize_vb(ocb, index);
146 }
147 ocb->max_var = index;
148 ocb->vb[index] = -1;
149 ocb->neg_bal++;
150 ocb->wb -= ocb->var_weight;
151 }
152 else
153 {
154 const long tmpbal = ocb->vb[index]--;
155 ocb->neg_bal += (tmpbal == 0);
156 ocb->pos_bal -= (tmpbal == 1);
157 ocb->wb -= ocb->var_weight;
158 }
159 }
160
161
162 /*-----------------------------------------------------------------------
163 //
164 // Function: local_vb_update()
165 //
166 // Perform a local update of ocb according to t (which is not derefed).
167 //
168 // Global Variables: -
169 //
170 // Side Effects : -
171 //
172 /----------------------------------------------------------------------*/
173
local_vb_update(OCB_p ocb,Term_p t,bool lhs)174 static void local_vb_update(OCB_p ocb, Term_p t, bool lhs)
175 {
176 if(lhs)
177 {
178 if(TermIsVar(t))
179 {
180 inc_vb(ocb, t);
181 }
182 else
183 {
184 ocb->wb += OCBFunWeight(ocb, t->f_code);
185 }
186 }
187 else
188 {
189 if(TermIsVar(t))
190 {
191 dec_vb(ocb, t);
192 }
193 else
194 {
195 ocb->wb -= OCBFunWeight(ocb, t->f_code);
196 }
197 }
198 }
199
200
201
202 /*-----------------------------------------------------------------------
203 //
204 // Function: mfyvwbc()
205 //
206 // Update ocb according to t and lhs while checking if var occurs in t.
207 //
208 // Global Variables: -
209 //
210 // Side Effects : -
211 //
212 /----------------------------------------------------------------------*/
213
mfyvwbc(OCB_p ocb,Term_p t,DerefType deref_t,Term_p var,bool lhs)214 static bool mfyvwbc(OCB_p ocb, Term_p t, DerefType deref_t, Term_p var, bool lhs)
215 {
216 t = TermDeref(t, &deref_t);
217 local_vb_update(ocb, t, lhs);
218
219 if(var->f_code == t->f_code)
220 {
221 return true;
222 }
223
224 bool res = false;
225 for(size_t i=0; i<t->arity; i++)
226 {
227 res |= mfyvwbc(ocb, t->args[i], deref_t, var, lhs);
228 }
229 return res;
230 }
231
232
233 /*-----------------------------------------------------------------------
234 //
235 // Function: mfyvwb()
236 //
237 // Update ocb according to t and lhs.
238 //
239 // Global Variables: -
240 //
241 // Side Effects : -
242 //
243 /----------------------------------------------------------------------*/
244
mfyvwb(OCB_p ocb,Term_p t,DerefType deref_t,bool lhs)245 static void mfyvwb(OCB_p ocb, Term_p t, DerefType deref_t, bool lhs)
246 {
247 t = TermDeref(t, &deref_t);
248 local_vb_update(ocb, t, lhs);
249
250 // Note that arity == 0 for variables.
251 for(size_t i=0; i<t->arity; i++)
252 {
253 mfyvwb(ocb, t->args[i], deref_t, lhs);
254 }
255 }
256
257
258 /*-----------------------------------------------------------------------
259 //
260 // Function: kbo6cmplex()
261 //
262 // Perform a lexicographical comparison of the argument lists of s
263 // and t, updating the variable/weight balances accordingly.
264 //
265 // Global Variables: -
266 //
267 // Side Effects : -
268 //
269 /----------------------------------------------------------------------*/
270
kbo6cmplex(OCB_p ocb,Term_p s,Term_p t,DerefType deref_s,DerefType deref_t)271 static CompareResult kbo6cmplex(OCB_p ocb, Term_p s, Term_p t,
272 DerefType deref_s, DerefType deref_t)
273 {
274 CompareResult res = to_equal;
275
276 assert(s->arity == t->arity);
277 assert(s->f_code == t->f_code);
278
279 for(size_t i=0; i<s->arity; i++)
280 {
281 if(res == to_equal)
282 {
283 res = kbo6cmp(ocb, s->args[i], t->args[i], deref_s, deref_t);
284 }
285 else
286 {
287 mfyvwb(ocb, s->args[i], deref_s, true);
288 mfyvwb(ocb, t->args[i], deref_t, false);
289 }
290 }
291 return res;
292 }
293
294
295 /*-----------------------------------------------------------------------
296 //
297 // Function: kbo6cmp()
298 //
299 // Perform a KBO comparison between s and t.
300 //
301 // Global Variables: -
302 //
303 // Side Effects : -
304 //
305 /----------------------------------------------------------------------*/
306
kbo6cmp(OCB_p ocb,Term_p s,Term_p t,DerefType deref_s,DerefType deref_t)307 static CompareResult kbo6cmp(OCB_p ocb, Term_p s, Term_p t,
308 DerefType deref_s, DerefType deref_t)
309 {
310 CompareResult res, tmp;
311
312 s = TermDeref(s, &deref_s);
313 t = TermDeref(t, &deref_t);
314
315 /* Pacman lemma ;-) */
316 while((s->arity==1) && (s->f_code == t->f_code))
317 {
318 s = s->args[0];
319 t = t->args[0];
320 s = TermDeref(s, &deref_s);
321 t = TermDeref(t, &deref_t);
322 }
323 if(TermIsVar(s))
324 {
325 if(TermIsVar(t))
326 { /* X, Y */
327 inc_vb(ocb, s);
328 dec_vb(ocb, t);
329 res = s==t?to_equal:to_uncomparable;
330 }
331 else
332 { /* X, t */
333 bool ctn = mfyvwbc(ocb, t, deref_t, s, false);
334 inc_vb(ocb, s);
335 res = ctn?to_lesser:to_uncomparable;
336 }
337 }
338 else if(TermIsVar(t))
339 { /* s, Y */
340 bool ctn = mfyvwbc(ocb, s, deref_s, t, true);
341 dec_vb(ocb, t);
342 res = ctn?to_greater:to_uncomparable;
343 }
344 else
345 { /* s, t */
346 CompareResult lex;
347 if(s->f_code == t->f_code)
348 {
349 lex = kbo6cmplex(ocb, s, t, deref_s, deref_t);
350 }
351 else
352 {
353 lex = to_uncomparable;
354 mfyvwb(ocb, s, deref_s, true);
355 mfyvwb(ocb, t, deref_t, false);
356 }
357 CompareResult g_or_n = ocb->neg_bal?to_uncomparable:to_greater;
358 CompareResult l_or_n = ocb->pos_bal?to_uncomparable:to_lesser;
359 if(ocb->wb>0)
360 {
361 res = g_or_n;
362 }
363 else if(ocb->wb<0)
364 {
365 res = l_or_n;
366 }
367 else if((tmp = OCBFunCompare(ocb, s->f_code, t->f_code))==to_greater)
368 {
369 res = g_or_n;
370 }
371 else if(tmp==to_lesser)
372 {
373 res = l_or_n;
374 }
375 else if(s->f_code != t->f_code)
376 {
377 res = to_uncomparable;
378 }
379 else if(lex == to_equal)
380 {
381 res = to_equal;
382 }
383 else if(lex == to_greater)
384 {
385 res = g_or_n;
386 }
387 else if(lex == to_lesser)
388 {
389 res = l_or_n;
390 }
391 else
392 {
393 res = to_uncomparable;
394 }
395 }
396 return res;
397 }
398
399
400 /*-----------------------------------------------------------------------
401 //
402 // Function: mfyvwblhs()
403 //
404 // Update ocb according to term on the LHS of a comparison.
405 //
406 // Global Variables: -
407 //
408 // Side Effects : -
409 //
410 /----------------------------------------------------------------------*/
411
mfyvwblhs(OCB_p ocb,Term_p term,DerefType deref_t)412 static void mfyvwblhs(OCB_p ocb, Term_p term, DerefType deref_t)
413 {
414 PLocalTaggedStackInit(stack);
415
416 PLocalTaggedStackPush(stack, term, deref_t);
417
418 while(!PLocalTaggedStackEmpty(stack))
419 {
420 PLocalTaggedStackPop(stack, term, deref_t);
421 term = TermDeref(term, &deref_t);
422
423 if(TermIsVar(term))
424 {
425 inc_vb(ocb, term);
426 }
427 else
428 {
429 ocb->wb += OCBFunWeight(ocb, term->f_code);
430 PLocalTaggedStackPushTermArgs(stack, term, deref_t);
431 }
432 }
433
434 PLocalTaggedStackFree(stack);
435 }
436
437
438 /*-----------------------------------------------------------------------
439 //
440 // Function: mfyvwbrhs()
441 //
442 // Update ocb according to term on the RHS of a comparison.
443 //
444 // Global Variables: -
445 //
446 // Side Effects : -
447 //
448 /----------------------------------------------------------------------*/
449
mfyvwbrhs(OCB_p ocb,Term_p term,DerefType deref_t)450 static void mfyvwbrhs(OCB_p ocb, Term_p term, DerefType deref_t)
451 {
452 PLocalTaggedStackInit(stack);
453
454 PLocalTaggedStackPush(stack, term, deref_t);
455
456 while(!PLocalTaggedStackEmpty(stack))
457 {
458 PLocalTaggedStackPop(stack, term, deref_t);
459 term = TermDeref(term, &deref_t);
460
461 if(TermIsVar(term))
462 {
463 dec_vb(ocb, term);
464 }
465 else
466 {
467 ocb->wb -= OCBFunWeight(ocb, term->f_code);
468 PLocalTaggedStackPushTermArgs(stack, term, deref_t);
469 }
470 }
471
472 PLocalTaggedStackFree(stack);
473 }
474
475 /*-----------------------------------------------------------------------
476 //
477 // Function: kbolincmp()
478 //
479 // Perform a KBO comparison between s and t.
480 //
481 // Global Variables: -
482 //
483 // Side Effects : -
484 //
485 /----------------------------------------------------------------------*/
486
487
kbolincmp(OCB_p ocb,Term_p s,Term_p t,DerefType deref_s,DerefType deref_t)488 static CompareResult kbolincmp(OCB_p ocb, Term_p s, Term_p t,
489 DerefType deref_s, DerefType deref_t)
490 {
491 CompareResult res = to_equal;
492
493 s = TermDeref(s, &deref_s);
494 t = TermDeref(t, &deref_t);
495
496 if(s->f_code == t->f_code)
497 {
498 for(int i=0; i<s->arity; i++)
499 {
500 res = kbolincmp(ocb, s->args[i], t->args[i], deref_s, deref_t);
501 if(res!=to_equal)
502 {
503 i++;
504 if(i < s->arity)
505 {
506 for(;i<s->arity; i++)
507 {
508 mfyvwblhs(ocb, s->args[i], deref_s);
509 mfyvwbrhs(ocb, t->args[i], deref_t);
510 }
511
512 CompareResult g_or_n = ocb->neg_bal?to_uncomparable:to_greater;
513 CompareResult l_or_n = ocb->pos_bal?to_uncomparable:to_lesser;
514
515 if(ocb->wb>0)
516 {
517 res = g_or_n;
518 }
519 else if(ocb->wb<0)
520 {
521 res = l_or_n;
522 }
523 else if(res == to_greater)
524 {
525 res = g_or_n;
526 }
527 else if(res == to_lesser)
528 {
529 res = l_or_n;
530 }
531 }
532 }
533 }
534 }
535 else if(TermIsVar(s))
536 {
537 if(TermIsVar(t))
538 { /* X, Y */
539 inc_vb(ocb, s);
540 dec_vb(ocb, t);
541 res = to_uncomparable;
542 }
543 else
544 { /* X, t */
545 inc_vb(ocb, s);
546 mfyvwbrhs(ocb, t, deref_t);
547 res = ocb->pos_bal?to_uncomparable:to_lesser;
548 }
549 }
550 else if(TermIsVar(t))
551 { /* s, Y */
552 dec_vb(ocb, t);
553 mfyvwblhs(ocb, s, deref_s);
554 res = ocb->neg_bal?to_uncomparable:to_greater;
555 }
556 else
557 { /* s, t */
558 mfyvwblhs(ocb, s, deref_s);
559 mfyvwbrhs(ocb, t, deref_t);
560 CompareResult g_or_n = ocb->neg_bal?to_uncomparable:to_greater;
561 CompareResult l_or_n = ocb->pos_bal?to_uncomparable:to_lesser;
562 if(ocb->wb>0)
563 {
564 res = g_or_n;
565 }
566 else if(ocb->wb<0)
567 {
568 res = l_or_n;
569 }
570 else
571 {
572 CompareResult tmp = OCBFunCompare(ocb, s->f_code, t->f_code);
573 if(tmp == to_greater)
574 {
575 res = g_or_n;
576 }
577 else if(tmp == to_lesser)
578 {
579 res = l_or_n;
580 }
581 }
582 }
583 return res;
584 }
585
586
587 /*-----------------------------------------------------------------------
588 //
589 // Function: kbo6reset()
590 //
591 // Reset data in ocb changed when determining KBO6 comparison of terms.
592 //
593 // Global Variables: -
594 //
595 // Side Effects : -
596 //
597 /----------------------------------------------------------------------*/
598
kbo6reset(OCB_p ocb)599 static void __inline__ kbo6reset(OCB_p ocb)
600 {
601 for(size_t i=0; i<=ocb->max_var; i++)
602 {
603 ocb->vb[i] = 0;
604 }
605 ocb->wb = 0;
606 ocb->pos_bal = 0;
607 ocb->neg_bal = 0;
608 ocb->max_var = 0;
609 }
610
611
612 /*---------------------------------------------------------------------*/
613 /* Exported Functions */
614 /*---------------------------------------------------------------------*/
615
616
617 /*-----------------------------------------------------------------------
618 //
619 // Function: KBO6Compare(ocb, s, t)
620 //
621 // Compare two terms s,t in the Knuth-Bendix Ordering,
622 // return the result
623 // to_greater if s >KBO t
624 // to_equal if s =KBO t
625 // to_lesser if t >KBO s
626 // to_uncomparable otherwise
627 //
628 // Its a variant of KBOCompare where the variable condition is
629 // tested in the end.
630 //
631 // Global Variables: -
632 //
633 // Side Effects : -
634 //
635 -----------------------------------------------------------------------*/
636
KBO6Compare(OCB_p ocb,Term_p s,Term_p t,DerefType deref_s,DerefType deref_t)637 CompareResult KBO6Compare(OCB_p ocb, Term_p s, Term_p t,
638 DerefType deref_s, DerefType deref_t)
639 {
640 CompareResult res;
641
642 kbo6reset(ocb);
643 res = kbolincmp(ocb, s, t, deref_s, deref_t);
644 assert((kbo6reset(ocb), res == kbo6cmp(ocb, s, t, deref_s, deref_t)));
645 return res;
646 }
647
648
649
650 /*-----------------------------------------------------------------------
651 //
652 // Function: KBO6Greater(ocb, s, t)
653 //
654 // Checks whether the term s is greater than the term t in the
655 // Knuth-Bendix Ordering (KBO), i.e. returns
656 //
657 // true if s >KBO t,
658 // false otherwise.
659 //
660 // For a description of the KBO see the header of this file.
661 //
662 // Its a variant of KBOGreater where the variable condition is
663 // tested in the end.
664 //
665 // Global Variables: -
666 //
667 // Side Effects : -
668 //
669 -----------------------------------------------------------------------*/
670
KBO6Greater(OCB_p ocb,Term_p s,Term_p t,DerefType deref_s,DerefType deref_t)671 bool KBO6Greater(OCB_p ocb, Term_p s, Term_p t,
672 DerefType deref_s, DerefType deref_t)
673 {
674 CompareResult res;
675
676 kbo6reset(ocb);
677 res = kbolincmp(ocb, s, t, deref_s, deref_t);
678 assert((kbo6reset(ocb), res == kbo6cmp(ocb, s, t, deref_s, deref_t)));
679 return res == to_greater;
680 }
681
682 /*---------------------------------------------------------------------*/
683 /* End of File */
684 /*---------------------------------------------------------------------*/
685