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