1 /*-----------------------------------------------------------------------
2 
3 File  : ccl_splitting.c
4 
5 Author: Stephan Schulz
6 
7 Contents
8 
9   Implements functions for destructive splitting of clauses with at
10   least two non-propositional variable disjoint subsets of literals.
11 
12   Copyright 1998, 1999 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> Wed Apr 18 18:24:18 MET DST 2001
21     New
22 
23 -----------------------------------------------------------------------*/
24 
25 #include "ccl_splitting.h"
26 
27 
28 
29 /*---------------------------------------------------------------------*/
30 /*                        Global Variables                             */
31 /*---------------------------------------------------------------------*/
32 
33 
34 /*---------------------------------------------------------------------*/
35 /*                      Forward Declarations                           */
36 /*---------------------------------------------------------------------*/
37 
38 
39 /*---------------------------------------------------------------------*/
40 /*                         Internal Functions                          */
41 /*---------------------------------------------------------------------*/
42 
43 
44 /*-----------------------------------------------------------------------
45 //
46 // Function: initialize_lit_table()
47 //
48 //   Initialize the literal table. For each literal, mark them as
49 //   unassigned to any art and collect the variables that are marked
50 //   by var_filter. If ground literals are not split off individually,
51 //   assign them to partition 1.
52 //
53 // Global Variables:
54 //
55 // Side Effects    :
56 //
57 /----------------------------------------------------------------------*/
58 
initialize_lit_table(LitSplitDesc_p lit_table,Clause_p clause,SplitType how,TermProperties var_filter)59 static void initialize_lit_table(LitSplitDesc_p lit_table,Clause_p
60              clause, SplitType how, TermProperties
61              var_filter)
62 {
63    int i, lit_no = ClauseLiteralNumber(clause);
64    Eqn_p handle = clause->literals;
65 
66    for(i=0; i<lit_no; i++)
67    {
68       assert(handle);
69       lit_table[i].literal = handle;
70       lit_table[i].part    = 0;
71       lit_table[i].varset  = NULL;
72       (void)EqnCollectPropVariables(handle, &(lit_table[i].varset),
73               var_filter);
74       /* We are only calling EqnCollectVariables for the side
75     effect here */
76       if(how == SplitGroundOne || how == SplitGroundNone)
77       {
78     if(!lit_table[i].varset)
79     {
80        lit_table[i].part = 1;
81     }
82       }
83       handle = handle->next;
84    }
85 }
86 
87 
88 /*-----------------------------------------------------------------------
89 //
90 // Function: cond_init_lit_table()
91 //
92 //   Initialize the literal table. For each literal, mark them as
93 //   unassigned to any art and collect the variables that are marked
94 //   by var_filter. If ground literals are not split off individually,
95 //   assign them to partition 1.
96 //
97 // Global Variables:
98 //
99 // Side Effects    :
100 //
101 /----------------------------------------------------------------------*/
102 
cond_init_lit_table(LitSplitDesc_p lit_table,Clause_p clause,SplitType how,PStack_p split_vars)103 static int cond_init_lit_table(LitSplitDesc_p lit_table,
104                                 Clause_p clause, SplitType how,
105                                 PStack_p split_vars)
106 {
107    int split_var_no;
108 
109    split_var_no = PStackGetSP(split_vars);
110 
111    if(!split_var_no)
112    {
113       initialize_lit_table(lit_table, clause, how, TPIgnoreProps);
114    }
115    else
116    {
117       PStackPointer sp;
118       Term_p var;
119 
120       ClauseTermSetProp(clause, TPCheckFlag);
121       for(sp=0; sp<split_var_no; sp++)
122       {
123     var = PStackElementP(split_vars,sp);
124     assert(TermCellQueryProp(var, TPCheckFlag));
125     TermCellDelProp(var,TPCheckFlag);
126       }
127       initialize_lit_table(lit_table, clause, how, TPCheckFlag);
128    }
129    return split_var_no;
130 }
131 
132 
133 
134 
135 
136 /*-----------------------------------------------------------------------
137 //
138 // Function: find_free_literal()
139 //
140 //   Find the first entry in lit_table that corresponds to a literal
141 //   not yet assigned to any clause part and return its index. If none
142 //   exists, return -1.
143 //
144 // Global Variables: -
145 //
146 // Side Effects    : -
147 //
148 /----------------------------------------------------------------------*/
149 
find_free_literal(LitSplitDesc_p lit_table,int lit_no)150 static int find_free_literal(LitSplitDesc_p lit_table, int lit_no)
151 {
152    int res = -1,i;
153 
154    for(i=0; i<lit_no; i++)
155    {
156       if(!lit_table[i].part)
157       {
158     res = i;
159     break;
160       }
161    }
162    return res;
163 }
164 
165 
166 /*-----------------------------------------------------------------------
167 //
168 // Function: build_part()
169 //
170 //   Given the index of the first unassigned literal in lit_table and
171 //   a part number, assign this number to all literals that are
172 //   transitively variable-linked to this first literal.
173 //
174 // Global Variables: -
175 //
176 // Side Effects    : Accumulates all part variables in
177 //                   lit_table[lit_index].varset
178 //
179 /----------------------------------------------------------------------*/
180 
build_part(LitSplitDesc_p lit_table,int lit_no,int lit_index,int part)181 static void build_part(LitSplitDesc_p lit_table, int lit_no, int
182              lit_index, int part)
183 {
184    bool new_vars = true;
185    int  i;
186 
187    lit_table[lit_index].part = part;
188    while(new_vars)
189    {
190       new_vars = false;
191       for(i=lit_index+1; i< lit_no; i++)
192       {
193     if(!lit_table[i].part)
194     {
195        if(PTreeSharedElement(&(lit_table[lit_index].varset),
196               lit_table[i].varset))
197        {
198           lit_table[i].part = part;
199           new_vars = PTreeMerge(&(lit_table[lit_index].varset),
200                  lit_table[i].varset)||new_vars;
201           lit_table[i].varset = NULL;
202        }
203     }
204       }
205    }
206 }
207 
208 
209 /*-----------------------------------------------------------------------
210 //
211 // Function: assemble_part_literals()
212 //
213 //   Given a partition number, assemble and return all literals
214 //   belonging to that partition.
215 //
216 // Global Variables: -
217 //
218 // Side Effects    : -
219 //
220 /----------------------------------------------------------------------*/
221 
assemble_part_literals(LitSplitDesc_p lit_table,int lit_no,int part)222 Eqn_p assemble_part_literals(LitSplitDesc_p lit_table, int lit_no, int part)
223 {
224    Eqn_p handle = NULL, tmp;
225    int j;
226 
227    for(j=0; j<lit_no; j++)
228    {
229       if(lit_table[j].part == part)
230       {
231          tmp = lit_table[j].literal;
232          tmp->next = handle;
233          handle = tmp;
234       }
235    }
236    return handle;
237 }
238 
239 
240 /*-----------------------------------------------------------------------
241 //
242 // Function: clause_split_general()
243 //
244 //   Try to split clause into different clauses according to the
245 //   inference rule below. If successful,
246 //   deposit split clauses into set and return number of clauses
247 //   created. Otherwise return 0.
248 //
249 //   L1(X) v L2(X) v L3(X) ...
250 //   ----------------------------------------------------
251 //   T1(X) v T2(X) v T3(X) ....,
252 //   ~T1(X) v L1(X), ~T2(X) v L2(X), ~T3(X) v L3(X), ...
253 //
254 //   if the Li are subsets of the clause that do not share any
255 //   variables but those in the set X and the Ti
256 //   are _new_ predicate symbols. X is a parameter to the function!
257 //
258 //   If fresh_defs is false (and split_vars is empty), try if an
259 //   existing definition already covers any of the parts and reuse it,
260 //   otherwise always use fresh definitions.
261 //
262 // Global Variables: -
263 //
264 // Side Effects    : Memory allocation, if successful, destroys
265 //                   clause!
266 //
267 /----------------------------------------------------------------------*/
268 
clause_split_general(DefStore_p store,Clause_p clause,ClauseSet_p set,SplitType how,bool fresh_defs,PStack_p split_vars)269 int clause_split_general(DefStore_p store, Clause_p clause,
270                          ClauseSet_p set, SplitType how,
271                          bool fresh_defs, PStack_p split_vars)
272 {
273    int               res = 0, part = 0,i,size, lit_no, split_var_no;
274    LitSplitDesc_p    lit_table;
275    Eqn_p             handle,tmp, join;
276    FunCode           new_pred;
277    long              def_id;
278    TB_p              bank;
279    Clause_p          new_clause;
280    FormulaProperties props;
281 
282    assert(clause);
283    assert(!clause->children);
284    assert(!clause->set);
285    assert(set);
286 
287    props = ClauseGiveProps(clause, CPTypeMask|CPIsSOS);
288    lit_no = ClauseLiteralNumber(clause);
289 
290    if(lit_no<=1 || ClauseHasSplitLiteral(clause))
291    {
292       return 0;
293    }
294    bank = clause->literals->bank;
295    size = lit_no*sizeof(LitSplitDescCell);
296    lit_table = SizeMalloc(size);
297 
298    split_var_no = cond_init_lit_table(lit_table, clause, how, split_vars);
299 
300    if((how == SplitGroundOne) && find_free_literal(lit_table, lit_no))
301    {
302       part++;
303    }
304    /* Find the variable disjoint parts of the clause */
305    while((i=find_free_literal(lit_table, lit_no))!=-1)
306    {
307       part++;
308       build_part(lit_table, lit_no, i, part);
309    }
310    if(part>1)
311    {
312       Clause_p parent1 = clause->parent1;
313       Clause_p parent2 = clause->parent2;
314       PStack_p def_stack = PStackAlloc();
315 
316       /* Build split clauses from original literals */
317       join = NULL;
318       clause->literals = NULL; /* Literals are stored in lit_table and
319               are recycled in new clauses, clause
320               skeleton is refilled below. */
321       for(i=1; i<=part; i++)
322       {
323          if(split_var_no)
324          {
325             /* Get new predicate code */
326             new_pred = SigGetNewPredicateCode(bank->sig,
327                                               split_var_no);
328             SigSetFuncProp(bank->sig, new_pred, FPClSplitDef);
329 
330             /* Create definition clause (for maintaining completeness) */
331             handle = GenDefLit(bank, new_pred, true, split_vars);
332             assert(!handle->next);
333 
334             handle->next = assemble_part_literals(lit_table, lit_no, i);
335 
336             new_clause = ClauseAlloc(handle);
337             assert(new_clause);
338 
339             def_id = new_clause->ident;
340             assert(def_id);
341             assert(new_pred);
342          }
343          else
344          {
345             WFormula_p new_form;
346             /* Create definition clause (for maintaining completeness) */
347             handle = assemble_part_literals(lit_table, lit_no, i);
348 
349             new_pred = GetDefinitions(store, handle,
350                                       &new_form, &new_clause, fresh_defs);
351             def_id = 0;
352             if(new_form)
353             {
354                def_id = new_form->ident;
355                ClausePushDerivation(clause, DCApplyDef, new_form, NULL);
356             }
357          }
358          PStackPushInt(def_stack, def_id);
359 
360          if(new_clause)
361          {
362             /* Fix clause properties */
363 
364             new_clause->properties = props;
365             /* Note: Potentially recycled definitions have no real
366                parents, as they are conceptually introduced ad-hoc and
367                can be reused for many other clauses. */
368             if(parent1 && fresh_defs)
369             {
370                new_clause->parent1 = parent1;
371                ClauseRegisterChild(parent1, new_clause);
372             }
373             if(parent2 && fresh_defs)
374             {
375                new_clause->parent2 = parent2;
376                ClauseRegisterChild(parent2, new_clause);
377             }
378 
379             /* Insert result clause */
380             ClauseSetInsert(set, new_clause);
381 
382             /* Document creation -> Now done in ccl_def_handling.c*/
383             /* DocClauseCreationDefault(new_clause, inf_split, clause,
384                NULL); */
385          }
386          /* Extend remainder clause (after application of definition) */
387     tmp       = GenDefLit(bank, new_pred, false, split_vars);
388     tmp->next = join;
389     join = tmp;
390       }
391       clause->literals = join;
392       ClauseRecomputeLitCounts(clause);
393 
394       ClauseSetInsert(set, clause);
395       DocClauseApplyDefsDefault(clause, clause->ident, def_stack);
396 
397       res = part+1;
398       PStackFree(def_stack);
399    }
400    for(i=0; i<lit_no; i++)
401    {
402       PTreeFree(lit_table[i].varset);
403    }
404    SizeFree(lit_table, size);
405 
406    return res;
407 }
408 
409 
410 /*-----------------------------------------------------------------------
411 //
412 // Function: initialize_permute_stack()
413 //
414 //   We want to generate unordered n-tuples from k elements. This
415 //   initializes a stack to contain the first valid sample (1, 2,
416 //   ...n) of size n.
417 //
418 // Global Variables: -
419 //
420 // Side Effects    : -
421 //
422 /----------------------------------------------------------------------*/
423 
initialize_permute_stack(PStack_p stack,int size)424 static void initialize_permute_stack(PStack_p stack, int size)
425 {
426    int i;
427 
428    PStackReset(stack);
429    for(i=0; i<size; i++)
430    {
431       PStackPushInt(stack, i);
432    }
433 }
434 
435 /*-----------------------------------------------------------------------
436 //
437 // Function: permute_stack_next()
438 //
439 //   Generate the next valid permutation and return true if it exists,
440 //   otherwise return false.
441 //
442 // Global Variables: -
443 //
444 // Side Effects    : -
445 //
446 /----------------------------------------------------------------------*/
447 
permute_stack_next(PStack_p permute_stack,int var_no)448 static bool permute_stack_next(PStack_p permute_stack, int var_no)
449 {
450    PStackPointer limit = PStackGetSP(permute_stack), i;
451    long tmp;
452 
453    i = 0;
454    while(i < limit)
455    {
456       tmp = PStackPopInt(permute_stack);
457       tmp++;
458       if((tmp) < (var_no-i))
459       {
460     while(i>=0)
461     {
462        PStackPushInt(permute_stack, tmp);
463        tmp++;
464        i--;
465     }
466     return true;
467       }
468       i++;
469    }
470    return false;
471 }
472 
473 /*---------------------------------------------------------------------*/
474 /*                         Exported Functions                          */
475 /*---------------------------------------------------------------------*/
476 
477 
478 /*-----------------------------------------------------------------------
479 //
480 // Function: ClauseHasSplitLiteral()
481 //
482 //   Return true if a literal in the clause is a split literal.
483 //
484 // Global Variables: -
485 //
486 // Side Effects    : -
487 //
488 /----------------------------------------------------------------------*/
489 
ClauseHasSplitLiteral(Clause_p clause)490 bool ClauseHasSplitLiteral(Clause_p clause)
491 {
492    Eqn_p handle;
493 
494    for(handle = clause->literals; handle; handle = handle->next)
495    {
496       if(EqnQueryProp(handle, EPIsSplitLit))
497       {
498     return true;
499       }
500    }
501    return false;
502 }
503 
504 
505 
506 /*-----------------------------------------------------------------------
507 //
508 // Function: ClauseSplit()
509 //
510 //   Try to split clause into different clauses according to the
511 //   inference rule below. If successful,
512 //   deposit split clauses into set and return number of clauses
513 //   created. Otherwise return 0.
514 //
515 //   L1 v L2 v L3 ...
516 //   ----------------------------------------------------
517 //   T1 v T2 v T3 ...., ~T1 v L1, ~T2 v L2, ~T3 v L3, ...
518 //
519 //   if the Li are variable-disjoint subsets of the clause and the Ti
520 //   are _new_ propositional variables.
521 //
522 // Global Variables: -
523 //
524 // Side Effects    : Memory allocation, if successful, destroys
525 //                   clause!
526 //
527 /----------------------------------------------------------------------*/
528 
ClauseSplit(DefStore_p store,Clause_p clause,ClauseSet_p set,SplitType how,bool fresh_defs)529 int ClauseSplit(DefStore_p store, Clause_p clause, ClauseSet_p set,
530                 SplitType how, bool fresh_defs)
531 {
532    int res ;
533    PStack_p dummy = PStackAlloc();
534 
535    res = clause_split_general(store, clause, set, how, fresh_defs, dummy);
536    PStackFree(dummy);
537    return res;
538 }
539 
540 
541 /*-----------------------------------------------------------------------
542 //
543 // Function: ClauseSplitGeneral()
544 //
545 //   Wrapper for clause_split_general(). Tries tries different
546 //   variable subsets (partially ordered by cardinality) to find a
547 //   subset that splits the clause. Only used for eground, so I skimp
548 //   on options.
549 //
550 // Global Variables: -
551 //
552 // Side Effects    : Memory allocation, if successful, destroys
553 //                   clause!
554 //
555 /----------------------------------------------------------------------*/
556 
ClauseSplitGeneral(DefStore_p store,bool fresh_defs,Clause_p clause,ClauseSet_p set,long tries)557 int ClauseSplitGeneral(DefStore_p store, bool fresh_defs,
558                        Clause_p clause, ClauseSet_p set, long tries)
559 {
560    int res, var_no, set_size;
561    PStackPointer i;
562    PStack_p vars, split_vars, permute_stack;
563    PTree_p  vars_tree = NULL;
564 
565    res =  ClauseSplit(store, clause, set, SplitGroundOne, fresh_defs);
566    if(res)
567    {
568       return res;
569    }
570 
571    var_no = ClauseCollectVariables(clause, &vars_tree);
572    if(var_no<=2) /* Non-ground splitting is useless here */
573    {
574       PTreeFree(vars_tree);
575       return 0;
576    }
577    vars = PStackAlloc();
578    split_vars = PStackAlloc();
579    permute_stack = PStackAlloc();
580 
581    PTreeToPStack(vars, vars_tree);
582    PTreeFree(vars_tree);
583 
584    set_size = 1;
585 
586    initialize_permute_stack(permute_stack, set_size);
587 
588    while(tries)
589    {
590       PStackReset(split_vars);
591       for(i=0; i<set_size; i++)
592       {
593     PStackPushP(split_vars,
594            PStackElementP(vars,
595                 PStackElementInt(permute_stack, i)));
596       }
597       res = clause_split_general(store, clause, set, SplitGroundNone,
598                                  fresh_defs, split_vars);
599       if(res)
600       {
601     break;
602       }
603       if(!permute_stack_next(permute_stack, var_no))
604       {
605     if(set_size == var_no-2)
606     {
607        break;
608     }
609     set_size++;
610     initialize_permute_stack(permute_stack, set_size);
611       }
612       tries--;
613    }
614    PStackFree(permute_stack);
615    PStackFree(split_vars);
616    PStackFree(vars);
617    return res;
618 }
619 
620 
621 /*-----------------------------------------------------------------------
622 //
623 // Function: ClauseSetSplitClauses()
624 //
625 //   Split all clauses in from_set and put the result into to_set.
626 //
627 // Global Variables: -
628 //
629 // Side Effects    : -
630 //
631 /----------------------------------------------------------------------*/
632 
ClauseSetSplitClauses(DefStore_p store,ClauseSet_p from_set,ClauseSet_p to_set,SplitType how,bool fresh_defs)633 long ClauseSetSplitClauses(DefStore_p store, ClauseSet_p from_set,
634                            ClauseSet_p to_set, SplitType how, bool fresh_defs)
635 {
636    long res=0, tmp;
637    Clause_p handle;
638 
639    assert(from_set&&to_set);
640 
641    while(!ClauseSetEmpty(from_set))
642    {
643       handle = ClauseSetExtractFirst(from_set);
644       tmp = ClauseSplit(store, handle, to_set, how, fresh_defs);
645       if(!tmp)
646       {
647     ClauseSetInsert(to_set, handle);
648       }
649       res += tmp;
650    }
651    return res;
652 }
653 
654 
655 
656 /*-----------------------------------------------------------------------
657 //
658 // Function: ClauseSetSplitClausesGeneral()
659 //
660 //   Split all clauses in from_set and put the result into to_set.
661 //
662 // Global Variables: -
663 //
664 // Side Effects    : -
665 //
666 /----------------------------------------------------------------------*/
667 
ClauseSetSplitClausesGeneral(DefStore_p store,bool fresh_defs,ClauseSet_p from_set,ClauseSet_p to_set,long tries)668 long ClauseSetSplitClausesGeneral(DefStore_p store, bool fresh_defs,
669                                   ClauseSet_p from_set,
670                                   ClauseSet_p to_set, long tries)
671 {
672    long res=0, tmp;
673    Clause_p handle;
674 
675    assert(from_set&&to_set);
676 
677    while(!ClauseSetEmpty(from_set))
678    {
679       handle = ClauseSetExtractFirst(from_set);
680       tmp = ClauseSplitGeneral(store, fresh_defs, handle, to_set, tries);
681       if(!tmp)
682       {
683     ClauseSetInsert(to_set, handle);
684       }
685       res += tmp;
686    }
687    return res;
688 }
689 
690 
691 
692 
693 /*---------------------------------------------------------------------*/
694 /*                        End of File                                  */
695 /*---------------------------------------------------------------------*/
696