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