1 /*
2 * Tableau.cpp
3 *
4 * Created on: May 28, 2014
5 * Author: nicola
6 */
7
8 #include "Tableau.h"
9
10 namespace ctl_sat {
11
sign(Formula * f)12 int sign(Formula * f){
13 if(f->getType()==NEGATION)
14 return -1;
15
16 return 1;
17 }
18
~Tableau()19 Tableau::~Tableau() {}
20
Tableau(Formula * f)21 Tableau::Tableau(Formula * f){//builds the tableau for formula f
22
23 //firstly, positive closure set is computed. Here there are only positive formulas (i.e. not negations). formulas must be sorted and copies must be removed.
24 positive_closure = f->positiveClosure();
25
26 //sort positive closure set
27 std::sort (positive_closure->begin(), positive_closure->end(), formulaLessThan);
28
29 //remove duplicates and resize
30 positive_closure->resize( std::distance(positive_closure->begin(),
31 std::unique (positive_closure->begin(), positive_closure->end(), formulaEqual)) );
32
33 cout << "Positive closure set (only non-negated formulas in the closure set):\n";
34
35 for(uint i=0;i<positive_closure->size();i++)
36 cout << (i+1) << ". " << positive_closure->at(i)->toString()<<endl;
37
38 cout << "\nClosure set has size " << positive_closure->size()*2<< ". \n\nBuilding initial feasible states of the tableau ... "<< endl;
39
40 computeSubFormulas();
41
42 formula_index orig_position = indexOf(f);//position of the original formula f in positive form in the positive closure
43
44 if(f->getType()==NEGATION)
45 initial_formula = indexToNegativeFormula(orig_position);
46 else
47 initial_formula = indexToPositiveFormula(orig_position);
48
49 states = vector<state>();
50 buildFeasibleStates();
51
52 number_of_states = states.size();
53
54 //these vectors mark formulas that are globally valid in a state (i.e. they have been previously checked and we don't need to check them again)
55 globally_satisfied_formulas_positive = vector<state>(number_of_states);
56 globally_satisfied_formulas_negative = vector<state>(number_of_states);
57
58 //visited_during_mark_removal = vector<bool>(number_of_states,false);
59
60 for(uint i=0;i<number_of_states;++i){
61
62 globally_satisfied_formulas_positive[i] = newState();
63 globally_satisfied_formulas_negative[i] = newState();
64
65 }
66
67
68 cout << "done. Initial model has " << number_of_states << " states"<<endl<<endl;
69
70 isRemoved = vector<bool>(states.size());//tracks removed states
71
72 for(ulint i=0;i<states.size();i++)
73 isRemoved.at(i)=false;
74
75 status = new state_status[states.size()];
76 mark_timestamps.assign(states.size(),0);
77
78 //now build edges
79
80 cout << "Building initial feasible edges of the tableau ... "<< endl;
81
82 edges = vector<set<uint> >(states.size());
83 back_edges = vector<set<uint> >(states.size());
84
85 buildEdges();
86 cout << "done. Initial model has " << number_of_edges << " edges"<<endl<<endl;
87
88 //count how many states have the original formula
89
90 number_of_states_with_original_formula=0;
91 for(uint i=0;i<states.size();i++)//for all states
92 if(belongsTo(states.at(i),initial_formula))//if the original formula is in the state
93 number_of_states_with_original_formula++;
94
95 //Now apply repeated cull.
96 //culls are divided in 3 categories: easy, medium, hard:
97 //easy: EXT, EX, ENX
98 //medium: EU, ENU
99 //hard: AU, ANU
100 //heuristic:
101 //1) firstly, apply only easy culls until it is no more possible to apply them
102 //2) then, apply medium culls together with easy culls until is no more possible to apply medium/easy culls
103 //3) at this point, try with the hard culls. Once a hard cull has been executed, restart from 1)
104 //repeat until no more culls are possible.
105 //when a state is removed, its predecessors are checked (and so on, recursively)
106
107 cout << "Applying repeated cull ..."<< endl;
108 timestamp=time(0);
109 last_time_printed=(ulint)timestamp+1;
110 cull();
111 cout << "\ndone. Number of states left : " << number_of_states <<endl<<endl;
112
113 /*cout << endl;
114 for(uint i=0;i<states.size();i++){
115
116 cout << "State nr " << i << "\nedges : ";
117
118 for(uint j=0;j<edges.at(i).size();j++)
119 cout << j << " ";
120
121 cout << "\nREMOVED? " << isRemoved.at(i) << endl;
122
123 printState(states.at(i));
124 cout << endl;
125 }
126 cout << endl;*/
127
128 }
129
clearMarked()130 void Tableau::clearMarked(){
131
132 current_timestamp=0;
133
134 for(ulint i=0;i<states.size();i++){
135 status[i] = NOT_VISITED;
136 mark_timestamps[i]=0;
137 }
138 }
139
computeSubFormulas()140 void Tableau::computeSubFormulas(){
141
142 leftSubformula = new vector<int>(positive_closure->size());
143 rightSubformula = new vector<int>(positive_closure->size());
144
145 for(uint i=0;i<positive_closure->size();i++){
146
147 switch(positive_closure->at(i)->getType()){
148
149 case ATOMIC: /*no subformulas*/ break;
150
151 case NEGATION:
152 leftSubformula->at(i) = sign(positive_closure->at(i)->getSubFormula())*(indexOf(positive_closure->at(i)->getSubFormula())+1); break;
153
154 case CONJUNCTION:
155 leftSubformula->at(i) = sign(positive_closure->at(i)->getLeftSubFormula())*(indexOf(positive_closure->at(i)->getLeftSubFormula())+1);
156 rightSubformula->at(i) = sign(positive_closure->at(i)->getRightSubFormula())*(indexOf(positive_closure->at(i)->getRightSubFormula())+1); break;
157
158 case ALL_TOMORROW:
159 leftSubformula->at(i) = sign(positive_closure->at(i)->getSubFormula())*(indexOf(positive_closure->at(i)->getSubFormula())+1); break;
160
161 case EXISTS_TOMORROW:
162 leftSubformula->at(i) = sign(positive_closure->at(i)->getSubFormula())*(indexOf(positive_closure->at(i)->getSubFormula())+1); break;
163
164 case ALL_UNTIL:
165 leftSubformula->at(i) = sign(positive_closure->at(i)->getLeftSubFormula())*(indexOf(positive_closure->at(i)->getLeftSubFormula())+1);
166 rightSubformula->at(i) = sign(positive_closure->at(i)->getRightSubFormula())*(indexOf(positive_closure->at(i)->getRightSubFormula())+1); break;
167
168 case EXISTS_UNTIL:
169 leftSubformula->at(i) = sign(positive_closure->at(i)->getLeftSubFormula())*(indexOf(positive_closure->at(i)->getLeftSubFormula())+1);
170 rightSubformula->at(i) = sign(positive_closure->at(i)->getRightSubFormula())*(indexOf(positive_closure->at(i)->getRightSubFormula())+1); break;
171
172 }
173
174 }
175
176 }
177
newState()178 state Tableau::newState(){
179
180 //each state is a vector of bools with one bit for every formula in positive_closure_set. if the bit is 1, the formula appears
181 //in positive form; otherwise, it appears in negative form (negated)
182
183 state x = vector<bool>(positive_closure->size(),false);
184
185 return x;
186
187 }
188
indexOf(Formula * f)189 uint Tableau::indexOf(Formula * f){//returns index of the formula f in closure_set. Linear-time, but used only at the beginning while constructing closure set
190
191 //assumption: f in positive form is in positive_closure
192
193 Formula * f1 = f;
194
195 if(f->getType()==NEGATION)
196 f1 = f->getSubFormula();
197
198 uint idx=0;
199 while(idx < positive_closure->size() and *(positive_closure->at(idx))!=(*f1))
200 idx++;
201
202 return idx;
203
204 }
205
printState(state B)206 void Tableau::printState(state B){
207
208 for(uint i=0;i<B.size();i++){
209 cout << (B.at(i)==0?"NOT ":" ") << positive_closure->at(i)->toString() <<endl;
210 }
211
212 }
213
buildFeasibleStates()214 void Tableau::buildFeasibleStates(){
215
216 state inserted = newState();//tracks if the formula number i has been inserted (1) or not (0)
217 state polarity = newState();//tracks if the formula number i has been inserted in positive (1) or negative (0) form
218
219 buildFeasibleStatesRecursive(inserted,polarity,0);
220
221 }
222
handleConjunction(state inserted,state polarity,formula_index formula_nr)223 void Tableau::handleConjunction(state inserted, state polarity, formula_index formula_nr){
224
225 formula a = leftSubformula->at(formula_nr);
226 formula b = rightSubformula->at(formula_nr);
227
228 if( not (
229 belongsTo(inserted,polarity,indexToNegativeFormula(formula_nr)) or
230 belongsTo(inserted,polarity,negateFormula(a)) or
231 belongsTo(inserted,polarity,negateFormula(b)) or
232 a == negateFormula(b) /*otherwise a and b cannot be both inserted*/
233 )
234 ){
235
236 //insert {a^b,a,b} and call recursively
237 state inserted2 = inserted;
238 state polarity2 = polarity;
239
240 inserted2.at(formula_nr) = true;
241 inserted2.at(formulaToIndex(a)) = true;
242 inserted2.at(formulaToIndex(b)) = true;
243
244 polarity2 = insert(polarity2,indexToPositiveFormula(formula_nr));
245 polarity2 = insert(polarity2,a);
246 polarity2 = insert(polarity2,b);
247
248 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
249
250 }
251
252 if( not (
253 belongsTo(inserted,polarity,indexToPositiveFormula(formula_nr)) or
254 belongsTo(inserted,polarity,a) or
255 belongsTo(inserted,polarity,negateFormula(b)) or
256 a == b
257 )
258 ){
259
260 //insert {~(a^b),~a,b} and call recursively
261 state inserted2 = inserted;
262 state polarity2 = polarity;
263
264 inserted2.at(formula_nr) = true;
265 inserted2.at(formulaToIndex(a)) = true;
266 inserted2.at(formulaToIndex(b)) = true;
267
268 polarity2 = insert(polarity2,indexToNegativeFormula(formula_nr));
269 polarity2 = insert(polarity2,negateFormula(a));
270 polarity2 = insert(polarity2,b);
271
272 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
273
274 }
275
276 if( not (
277 belongsTo(inserted,polarity,indexToPositiveFormula(formula_nr)) or
278 belongsTo(inserted,polarity,a) or
279 belongsTo(inserted,polarity,b) or
280 a == negateFormula(b)
281 )
282 ){
283
284 //insert {~(a^b),~a,~b} and call recursively
285 state inserted2 = inserted;
286 state polarity2 = polarity;
287
288 inserted2.at(formula_nr) = true;
289 inserted2.at(formulaToIndex(a)) = true;
290 inserted2.at(formulaToIndex(b)) = true;
291
292 polarity2 = insert(polarity2,indexToNegativeFormula(formula_nr));
293 polarity2 = insert(polarity2,negateFormula(a));
294 polarity2 = insert(polarity2,negateFormula(b));
295
296 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
297
298 }
299
300 if( not (
301 belongsTo(inserted,polarity,indexToPositiveFormula(formula_nr)) or
302 belongsTo(inserted,polarity,negateFormula(a)) or
303 belongsTo(inserted,polarity,b) or
304 a == b
305 )
306 ){
307
308 //insert {~(a^b),a,~b} and call recursively
309 state inserted2 = inserted;
310 state polarity2 = polarity;
311
312 inserted2.at(formula_nr) = true;
313 inserted2.at(formulaToIndex(a)) = true;
314 inserted2.at(formulaToIndex(b)) = true;
315
316 polarity2 = insert(polarity2,indexToNegativeFormula(formula_nr));
317 polarity2 = insert(polarity2,a);
318 polarity2 = insert(polarity2,negateFormula(b));
319
320 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
321
322 }
323
324 }
325
handleUntil(state inserted,state polarity,formula_index formula_nr)326 void Tableau::handleUntil(state inserted, state polarity, formula_index formula_nr){
327
328 formula a = leftSubformula->at(formula_nr);
329 formula b = rightSubformula->at(formula_nr);
330
331 if( not (
332 belongsTo(inserted,polarity,indexToNegativeFormula(formula_nr)) or
333 belongsTo(inserted,polarity,negateFormula(a)) or
334 belongsTo(inserted,polarity,negateFormula(b)) or
335 a == negateFormula(b) /*otherwise a and b cannot be both inserted*/
336 )
337 ){
338
339 //insert {Y(aUb),a,b} (Y = A or E) and call recursively
340 state inserted2 = inserted;
341 state polarity2 = polarity;
342
343 inserted2.at(formula_nr) = true;
344 inserted2.at(formulaToIndex(a)) = true;
345 inserted2.at(formulaToIndex(b)) = true;
346
347 polarity2 = insert(polarity2,indexToPositiveFormula(formula_nr));
348 polarity2 = insert(polarity2,a);
349 polarity2 = insert(polarity2,b);
350
351 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
352
353 }
354
355 if( not (
356 belongsTo(inserted,polarity,indexToNegativeFormula(formula_nr)) or
357 belongsTo(inserted,polarity,a) or
358 belongsTo(inserted,polarity,negateFormula(b)) or
359 a == b /*otherwise ~a and b cannot be both inserted*/
360 )
361 ){
362
363 //insert {Y(aUb),~a,b} (Y = A or E) and call recursively
364 state inserted2 = inserted;
365 state polarity2 = polarity;
366
367 inserted2.at(formula_nr) = true;
368 inserted2.at(formulaToIndex(a)) = true;
369 inserted2.at(formulaToIndex(b)) = true;
370
371 polarity2 = insert(polarity2,indexToPositiveFormula(formula_nr));
372 polarity2 = insert(polarity2,negateFormula(a));
373 polarity2 = insert(polarity2,b);
374
375 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
376
377 }
378
379 if( not (
380 belongsTo(inserted,polarity,indexToNegativeFormula(formula_nr)) or
381 belongsTo(inserted,polarity,negateFormula(a)) or
382 belongsTo(inserted,polarity,b) or
383 a == b /*otherwise a and ~b cannot be both inserted*/
384 )
385 ){
386
387 //insert {Y(aUb),a,~b} (Y = A or E) and call recursively
388 state inserted2 = inserted;
389 state polarity2 = polarity;
390
391 inserted2.at(formula_nr) = true;
392 inserted2.at(formulaToIndex(a)) = true;
393 inserted2.at(formulaToIndex(b)) = true;
394
395 polarity2 = insert(polarity2,indexToPositiveFormula(formula_nr));
396 polarity2 = insert(polarity2,a);
397 polarity2 = insert(polarity2,negateFormula(b));
398
399 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
400
401 }
402
403 if( not (
404 belongsTo(inserted,polarity,indexToPositiveFormula(formula_nr)) or
405 belongsTo(inserted,polarity,a) or
406 belongsTo(inserted,polarity,b) or
407 a == negateFormula(b) /*otherwise ~a and ~b cannot be both inserted*/
408 )
409 ){
410
411 //insert {~Y(aUb),~a,~b} (Y = A or E) and call recursively
412 state inserted2 = inserted;
413 state polarity2 = polarity;
414
415 inserted2.at(formula_nr) = true;
416 inserted2.at(formulaToIndex(a)) = true;
417 inserted2.at(formulaToIndex(b)) = true;
418
419 polarity2 = insert(polarity2,indexToNegativeFormula(formula_nr));
420 polarity2 = insert(polarity2,negateFormula(a));
421 polarity2 = insert(polarity2,negateFormula(b));
422
423 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
424
425 }
426
427 if( not (
428 belongsTo(inserted,polarity,indexToPositiveFormula(formula_nr)) or
429 belongsTo(inserted,polarity,negateFormula(a)) or
430 belongsTo(inserted,polarity,b) or
431 a == b
432 )
433 ){
434
435 //insert {~Y(aUb),a,~b} (Y = A or E) and call recursively
436 state inserted2 = inserted;
437 state polarity2 = polarity;
438
439 inserted2.at(formula_nr) = true;
440 inserted2.at(formulaToIndex(a)) = true;
441 inserted2.at(formulaToIndex(b)) = true;
442
443 polarity2 = insert(polarity2,indexToNegativeFormula(formula_nr));
444 polarity2 = insert(polarity2,a);
445 polarity2 = insert(polarity2,negateFormula(b));
446
447 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
448
449 }
450
451 }
452
handleOtherCases(state inserted,state polarity,formula_index formula_nr)453 void Tableau::handleOtherCases(state inserted, state polarity, formula_index formula_nr){
454
455 if( not (
456 belongsTo(inserted,polarity,indexToPositiveFormula(formula_nr))
457 )
458 ){
459
460 //insert ~a and call recursively
461 state inserted2 = inserted;
462 state polarity2 = polarity;
463
464 inserted2.at(formula_nr) = true;
465
466 polarity2 = insert(polarity2,indexToNegativeFormula(formula_nr));
467
468 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
469
470 }
471
472 if( not (
473 belongsTo(inserted,polarity,indexToNegativeFormula(formula_nr))
474 )
475 ){
476
477 //insert a and call recursively
478 state inserted2 = inserted;
479 state polarity2 = polarity;
480
481 inserted2.at(formula_nr) = true;
482
483 polarity2 = insert(polarity2,indexToPositiveFormula(formula_nr));
484
485 buildFeasibleStatesRecursive(inserted2, polarity2, formula_nr+1);
486
487 }
488 }
489
buildFeasibleStatesRecursive(state inserted,state polarity,formula_index formula_nr)490 void Tableau::buildFeasibleStatesRecursive(state inserted, state polarity, formula_index formula_nr){
491
492 if(formula_nr>=positive_closure->size()){
493 states.push_back(polarity);
494
495 if(states.size()%1000==0){
496 cout << " " << states.size() << " feasible states created until now\n";
497 }
498
499 return;
500 }
501
502 switch(positive_closure->at(formula_nr)->getType()){
503
504 case CONJUNCTION: //a^b. create new states inserting the combinations: {a^b,a,b},{~(a^b),~a,b},{~(a^b),~a,~b},{~(a^b),a,~b}
505 handleConjunction(inserted, polarity, formula_nr); break;
506
507 case ALL_UNTIL://A(aUb). create new states inserting the combinations: {A(aUb),a,b},{A(aUb),~a,b},{A(aUb),a,~b},{~A(aUb),~a,~b},{~A(aUb),a,~b}
508 handleUntil(inserted, polarity, formula_nr); break;
509
510 case EXISTS_UNTIL://E(aUb). create new states inserting the combinations: {E(aUb),a,b},{E(aUb),~a,b},{E(aUb),a,~b},{~E(aUb),~a,~b},{~E(aUb),a,~b}
511 handleUntil(inserted, polarity, formula_nr); break;
512
513 default://other cases: insert the combinations {a} and {~a}
514 handleOtherCases(inserted, polarity, formula_nr); break;
515
516 }
517
518 }
519
checkEdgeConditionsType1(ulint i,ulint j,formula_index k)520 bool Tableau::checkEdgeConditionsType1(ulint i, ulint j, formula_index k){
521
522 // 1.1) i(k) = AXa -> a must be in j
523 // 1.2) i(k) = A~Xa = ~EXa -> ~a must be in j
524 // 1.3) i(k) = A(aUb) AND ~b in i -> A(aUb) must be in j
525 // 1.4) i(k) = A~(aUb) = ~E(aUb) AND a in i -> A~(aUb) = ~E(aUb) must be in j
526
527 switch(positive_closure->at(k)->getType()){
528
529 case ALL_TOMORROW: /*case 1.1*/
530
531 if(states.at(i).at(k)){//AXa is present in positive form inside i
532
533 formula a = leftSubformula->at(k);//extract subformula a of AXa
534
535 if( not belongsTo(states.at(j),a) )//a must be in j
536 return false;
537
538 }
539
540 break;
541
542 case EXISTS_TOMORROW: /*case 1.2*/
543
544 if(not states.at(i).at(k)){//~EXa is present inside i (at position k). i(k)=~EXa
545
546 formula a = leftSubformula->at(k);//extract subformula a of ~EXa
547
548 if( not belongsTo(states.at(j),negateFormula(a) ) )//~a must be in j
549 return false;
550
551 }
552
553 break;
554
555 case ALL_UNTIL: /*case 1.3*/
556
557 if(states.at(i).at(k)){//A(aUb) is present in positive form inside i
558
559 formula b = rightSubformula->at(k);//extract subformula b of A(aUb)
560
561 if( belongsTo(states.at(i),negateFormula(b)) ){//~b is in i
562
563 if( not belongsTo(states.at(j),indexToPositiveFormula(k)) )//A(aUb) must be in j
564 return false;
565
566 }
567
568 }
569
570 break;
571
572 case EXISTS_UNTIL: /*case 1.4*/
573
574 if(not states.at(i).at(k)){//~E(aUb) is present inside i (at position k). i(k)=~E(aUb)
575
576 formula a = leftSubformula->at(k);//extract left subformula a of ~E(aUb)
577
578 if( belongsTo(states.at(i),a) ){//a is inside i
579
580 if( not belongsTo(states.at(j),indexToNegativeFormula(k) ) )//~E(aUb) must be in j
581 return false;
582
583 }
584
585 }
586
587 break;
588
589 default: return true; break;
590
591 }
592
593
594 return true;
595
596 }
597
checkEdgeConditionsType2(ulint i,ulint j,formula_index k)598 bool Tableau::checkEdgeConditionsType2(ulint i, ulint j, formula_index k){
599
600 //2) formula present in j -> check i
601 // 2.1) j(k) = E(aUb) AND a in i -> E(aUb) must be in i
602 // 2.2) j(k) = E~(aUb) = ~A(aUb) AND ~b in i -> E~(aUb) = ~A(aUb) must be in i
603
604 switch(positive_closure->at(k)->getType()){
605
606 case EXISTS_UNTIL:/*case 2.1*/
607
608 if(states.at(j).at(k)){//E(aUb) is present in positive form inside j. j(k)=E(aUb)
609
610 formula a = leftSubformula->at(k);//extract left subformula a of E(aUb)
611
612 if( belongsTo(states.at(i),a) ){//a is in i
613
614 if(not belongsTo(states.at(i),indexToPositiveFormula(k)) )//E(aUb) must be in i
615 return false;
616
617 }
618
619 }
620
621 break;
622
623 case ALL_UNTIL:/*case 2.2*/
624
625 if(not states.at(j).at(k)){//~A(aUb) is present inside j. j(k)=~A(aUb)
626
627 formula b = rightSubformula->at(k);//extract right subformula b of ~A(aUb)
628
629 if( belongsTo(states.at(i), negateFormula(b)) ){//~b is inside i
630
631 if( not belongsTo(states.at(i),indexToNegativeFormula(k) ) )//~A(aUb) must be in i
632 return false;
633
634 }
635
636 }
637
638 break;
639
640 default: return true; break;
641
642 }
643
644 return true;
645
646 }
647
buildEdges()648 void Tableau::buildEdges(){
649
650 number_of_edges = 0;
651
652 for(ulint i=0;i<states.size();i++){
653
654 for(ulint j=0;j<states.size();j++){//for each pair (i,j) of states
655
656 //2 types of conditions:
657 //1) formula present in i -> check j
658 // 1.1) AXa in i -> a must be in j
659 // 1.2) A~Xa = ~EXa in i -> ~a must be in j
660 // 1.3) { A(aUb), ~b } in i -> A(aUb) must be in D
661 // 1.4) { A~(aUb) = ~E(aUb), a } in i -> A~(aUb) = ~E(aUb) must be in D
662 //2) formula present in j -> check i
663 // 2.1) E(aUb) in j AND a in i -> E(aUb) must be in i
664 // 2.2) E~(aUb) = ~A(aUb) in j AND ~b in i -> E~(aUb) = ~A(aUb) must be in i
665
666 bool conditions_passed=true;
667
668 //check conditions of type 1
669 for(formula_index k=0;conditions_passed and k<positive_closure->size();k++)//for each formula in i
670 conditions_passed &= checkEdgeConditionsType1(i,j,k);
671
672 //check conditions of type 2
673 if(conditions_passed)
674 for(formula_index k=0;conditions_passed and k<positive_closure->size();k++)//for each formula in j
675 conditions_passed &= checkEdgeConditionsType2(i,j,k);
676
677 if(conditions_passed){//add edge i->j and back_edge j->i
678
679 edges.at(i).insert(j);
680 back_edges.at(j).insert(i);
681 number_of_edges++;
682
683 if(number_of_edges%50000==0)
684 cout << " " << number_of_edges << " feasible edges created until now\n";
685
686 }
687
688 }
689
690 }
691
692 }
693
cull()694 void Tableau::cull(){
695
696 bool verbose = false;
697 uint states_removed = 1;//to enter in the while loop
698
699 while(isSatisfiable() and states_removed>0){//repeat cull until there exists a state where the original formula is satisfiable
700
701 if(verbose) cout << " Checking EX, EXT, ENX conditions ... ";
702 states_removed = cullEasy();
703 if(verbose) cout << states_removed << " states removed.\n";
704
705 if(states_removed==0){
706
707 if(verbose) cout << " All states satisfy EX, EXT, ENX conditions. Checking EU and ENU conditions ... ";
708 states_removed = cullMedium();
709 if(verbose) cout << states_removed << " states removed.\n";
710
711 if(states_removed==0){
712 if(verbose) cout << " All states satisfy EX, EXT, ENX, EU, and ENU conditions. Checking AU and ANU conditions ... ";
713 states_removed = cullHard();
714 if(verbose) cout << states_removed << " states removed.\n";
715 }
716 }
717
718
719 }
720
721 }
722
cullEasy()723 uint Tableau::cullEasy(){
724
725 uint initial_nr_of_states = number_of_states;
726
727 //1) check iteratively easy conditions: EXT, EX, ENX
728
729 //search a state that falsifies at least one easy condition and cull it recursively backtracking its back edges
730 for(uint i=0;i<states.size();i++)//for all states
731 if(not isRemoved.at(i)){//if state is present in the model
732
733 if(not checkEasy(i))
734 cullEasyRecursive(i);
735
736 }
737
738 return initial_nr_of_states-number_of_states;//return number of states removed
739
740 }
741
cullMedium()742 uint Tableau::cullMedium(){
743
744 uint initial_nr_of_states = number_of_states;
745
746 for(uint i=0; i<states.size();i++)//for all states
747 if(not isRemoved.at(i)){//if state is present in the model
748
749 if(not checkMedium(i))
750 cullEasyRecursive(i);
751
752 }
753
754 return initial_nr_of_states-number_of_states;//return number of states removed
755
756 }
757
cullHard()758 uint Tableau::cullHard(){
759
760 uint initial_nr_of_states = number_of_states;
761
762 for(uint i=0; i<states.size();i++)//for all states
763 if(not isRemoved.at(i)){//if state is present in the model
764
765 if(not checkHard(i))
766 cullEasyRecursive(i);
767
768 }
769
770 return initial_nr_of_states-number_of_states;//return number of states removed
771
772 }
773
cullEasyRecursive(uint i)774 void Tableau::cullEasyRecursive(uint i){
775
776 removeState(i);//remove state, all its forward edges (not back edges) and remove the state i from the adj lists of all its neighbors
777
778 for(std::set<uint>::iterator it = back_edges.at(i).begin(); it != back_edges.at(i).end();++it){//for each predecessor of i
779
780 if(not checkEasy(*it) and not isRemoved.at(*it))
781 cullEasyRecursive(*it);
782
783 }
784
785 }
786
removeGlobalMarks(uint i)787 void Tableau::removeGlobalMarks(uint i){
788
789 for(uint j=0;j<visited_during_mark_removal.size();++j)
790 visited_during_mark_removal[j]=false;
791
792 removeGlobalMarksRecursive(i);
793
794 }
795
removeGlobalMarksRecursive(uint i)796 void Tableau::removeGlobalMarksRecursive(uint i){
797
798 globally_satisfied_formulas_positive[i] = newState();
799 globally_satisfied_formulas_negative[i] = newState();
800
801 visited_during_mark_removal[i] = true;
802
803 std::set<uint>::iterator it;
804
805 //loop through states that have an edge towards i and clear their global marks
806 for(it = back_edges.at(i).begin(); it != back_edges.at(i).end();++it)
807 if(not visited_during_mark_removal[*it])
808 removeGlobalMarksRecursive(*it);
809
810 }
811
removeState(uint i)812 void Tableau::removeState(uint i){//removes state i and all entering and exiting edges
813
814 if(isRemoved.at(i)){//already removed
815
816 cout << "WARNING: removing state already removed ("<<i<<")\n";
817 return;
818
819 }
820
821 //if initial formula is in this state, decrease counter of states having the original formula.
822 if(belongsTo(states.at(i),initial_formula)){
823
824 if(number_of_states_with_original_formula==0)
825 cout << "WARNING: trying to decrease counter with zero value (number of states with original formula). Debug needed!\n";
826 else
827 number_of_states_with_original_formula--;
828
829 }
830
831 number_of_states--;
832
833 if(number_of_states%100==0)
834 cout << " " << number_of_states << " states left\n";
835
836 /*if((ulint)difftime( time(0), timestamp)%5==0 and (ulint)difftime( time(0), timestamp) != last_time_printed){
837 last_time_printed = (ulint)difftime( time(0), timestamp);
838 cout << " " << number_of_states << " states left\n";
839 }*/
840
841
842 isRemoved.at(i) = true;//mark as removed
843
844 //removeGlobalMarks(i);//backtrack on predecessors and erase their global marks
845
846 std::set<uint>::iterator it;
847
848 //loop through states that have an edge towards i and remove i from their adjacency list
849 for(it = back_edges.at(i).begin(); it != back_edges.at(i).end();++it)
850 edges.at(*it).erase(i);
851
852 //loop through states in the adj list of i and remove i from their back adj list
853 for(it = edges.at(i).begin(); it != edges.at(i).end();++it)
854 back_edges.at(*it).erase(i);
855
856 //free memory of state i
857 edges.at(i).clear();
858 //back_edges.at(i).clear();//back_edges are not removed because they have to be used to backtrack cull effects
859
860 }
861
checkEasy(ulint i)862 bool Tableau::checkEasy(ulint i){
863
864 return checkEXT(i) and checkEX(i) and checkENX(i);
865
866 }
867
checkMedium(ulint i)868 bool Tableau::checkMedium(ulint i){
869
870 return checkEU(i) and checkENU(i);
871
872 }
873
checkHard(ulint i)874 bool Tableau::checkHard(ulint i){
875
876 return checkAU(i) and checkANU(i);
877
878 }
879
checkEXT(ulint i)880 bool Tableau::checkEXT(ulint i){
881
882 //state i must have at least one successor
883 return edges.at(i).size()>0;
884
885 }
886
checkEX(ulint i)887 bool Tableau::checkEX(ulint i){
888
889 //if EXa is in i, then at least one successor of i must have a
890
891 bool all_exists_have_successor=true;
892
893 for(formula_index k = 0; all_exists_have_successor and k<positive_closure->size();k++){//for each formula in i
894
895 //if k is inside i in positive form AND k is a EXa (i.e. for all EXa inside i)
896 if( belongsTo(states.at(i),indexToPositiveFormula(k)) and positive_closure->at(k)->getType()==EXISTS_TOMORROW){
897
898 formula a = leftSubformula->at(k);//get subformula of EXa
899
900 std::set<uint>::iterator it;
901 bool exists_successor=false;
902
903 //loop through states in the adj list of i.
904 for(it = edges.at(i).begin(); (not exists_successor) and it != edges.at(i).end();++it)
905 exists_successor |= belongsTo(states.at(*it),a);//a must be in at least one successor of i
906
907 all_exists_have_successor &= exists_successor;
908
909 }
910
911 }
912
913 return all_exists_have_successor;
914
915 }
916
checkENX(ulint i)917 bool Tableau::checkENX(ulint i){
918
919 //if EX~a = E~Xa = ~AXa is in i, then at least one successor of i must have ~a
920
921 bool all_neg_exists_have_successor=true;
922
923 for(formula_index k = 0; all_neg_exists_have_successor and k<positive_closure->size();k++){//for each formula in i
924
925 //if k is inside i in negative form AND k is a AXa (i.e. for all ~AXa inside i)
926 if( belongsTo(states.at(i),indexToNegativeFormula(k)) and positive_closure->at(k)->getType()==ALL_TOMORROW){
927
928 formula not_a = negateFormula(leftSubformula->at(k));//get subformula a of AXa and negate it, obtaining ~a
929
930 bool exists_successor=false;
931
932 //loop through states in the adj list of i.
933 for(std::set<uint>::iterator it = edges.at(i).begin(); (not exists_successor) and it != edges.at(i).end();++it)
934 exists_successor |= belongsTo(states.at(*it),not_a);//~a must be in at least one successor of i
935
936 all_neg_exists_have_successor &= exists_successor;
937
938 }
939
940 }
941
942 return all_neg_exists_have_successor;
943
944 }
945
checkEU(ulint i)946 bool Tableau::checkEU(ulint i){
947
948 //for each E(aUb): find a path starting from i that has always a until finally b is found
949 //no loops back: mark states
950
951 bool all_EU_satisfied = true;
952
953 for(formula_index k = 0; all_EU_satisfied and k<positive_closure->size();k++){//for each formula in i
954
955 //if k is inside i in positive form AND k is a E(aUb) (i.e. for all E(aUb) inside i)
956 if( belongsTo(states.at(i),indexToPositiveFormula(k)) and positive_closure->at(k)->getType()==EXISTS_UNTIL){
957
958 formula a = leftSubformula->at(k);
959 formula b = rightSubformula->at(k);
960
961 clearMarked();//unmark all states
962 all_EU_satisfied &= checkEUrecursive(i,k,a,b);//start visit (DFS)
963
964 }
965
966 }
967
968 return all_EU_satisfied;
969
970 }
971
checkAU(ulint i)972 bool Tableau::checkAU(ulint i){
973
974 //for each A(aUb): find a tree substructure having always a and the leafs contain b and consistent with EX, E~X, EU, E~U
975 //no loops back: mark states
976
977 bool all_AU_satisfied = true;
978
979 for(formula_index k = 0; all_AU_satisfied and k<positive_closure->size();k++){//for each formula in i
980
981 //if k is inside i in positive form AND k is a A(aUb) (i.e. for all A(aUb) inside i)
982 if( belongsTo(states.at(i),indexToPositiveFormula(k)) and positive_closure->at(k)->getType()==ALL_UNTIL){
983
984 formula a = leftSubformula->at(k);
985 formula b = rightSubformula->at(k);
986
987 clearMarked();//unmark all states
988 all_AU_satisfied &= checkAUrecursive(i,a,b);//start visit (DFS)
989
990 }
991
992 }
993
994 return all_AU_satisfied;
995
996 }
997
checkAUrecursive(ulint i,formula a,formula b)998 bool Tableau::checkAUrecursive(ulint i,formula a, formula b){
999
1000 //b is in this state: return true
1001 if(belongsTo(states.at(i),b)){
1002 status[i] = SATISFIED;
1003 return true;
1004 }
1005
1006 //here we know that b is not in i
1007
1008 if(not belongsTo(states.at(i),a)){//a and b are not in i: return false
1009 status[i] = NOT_SATISFIED;
1010 return false;
1011 }
1012
1013 status[i] = VISITED;//mark status as visited to prevent loops
1014
1015 //here we are sure that the state contains a AND does not contain b: check AU rule
1016
1017 //1) visit recursively successors and check the A(aUb) rule
1018
1019 uint sat_successors=0;//number of satisfied successors
1020
1021 for(std::set<uint>::iterator it = edges.at(i).begin(); it != edges.at(i).end();++it){//for all non-visited successors of i
1022
1023 if(status[*it]==NOT_VISITED)
1024 checkAUrecursive(*it,a, b);
1025
1026 if(status[*it]==SATISFIED)
1027 sat_successors++;
1028
1029 }
1030
1031 //now each successor is marked as SATISFIED (A(aUb) satisfied), NOT_SATISFIED (A(aUb) not satisfied) or
1032 //VISITED (loop: A(aUb) not satisfied because there exists a loop where a is always valid, but b never)
1033
1034 //extract all EX, E~X, EU, E~U rules present in state i
1035
1036 vector<formula> existential_formulas;//existential formulas inside state i
1037
1038 for(formula_index k = 0; k<positive_closure->size();k++){//for each formula in i
1039
1040 if( belongsTo(states.at(i),indexToPositiveFormula(k)) and positive_closure->at(k)->getType()==EXISTS_TOMORROW)//EX
1041 existential_formulas.push_back(indexToPositiveFormula(k));
1042
1043 if( belongsTo(states.at(i),indexToNegativeFormula(k)) and positive_closure->at(k)->getType()==ALL_TOMORROW)//~AX = E~X
1044 existential_formulas.push_back(indexToNegativeFormula(k));
1045
1046 if( belongsTo(states.at(i),indexToPositiveFormula(k)) and positive_closure->at(k)->getType()==EXISTS_UNTIL)//EU
1047 existential_formulas.push_back(indexToPositiveFormula(k));
1048
1049 if( belongsTo(states.at(i),indexToNegativeFormula(k)) and positive_closure->at(k)->getType()==ALL_UNTIL)//~AU = E~U
1050 existential_formulas.push_back(indexToNegativeFormula(k));
1051
1052 }
1053
1054 //now, 2 cases:
1055 //1) if existential_formulas not empty: for each E formula in existential_formulas, check that there exist a successor marked SATISFIED that satisfies the E formula
1056 //1) if existential_formulas is empty: there must be at least one successor marked SATISFIED
1057
1058 bool E_satisfied = true;
1059
1060 for(uint k=0;E_satisfied and k<existential_formulas.size();k++){//for each E formula
1061
1062 bool exist_good_successor = false;//exists a successor marked SATISFIED that satisfies the E formula
1063
1064 for(std::set<uint>::iterator it = edges.at(i).begin(); (not exist_good_successor) and it != edges.at(i).end();++it){//for all successors of i
1065
1066 if(status[*it]==SATISFIED)//only for successors marked SATISFIED
1067 exist_good_successor |= checkEformula(existential_formulas.at(k),i,*it);//check that the E formula is sat in i->*it
1068
1069 }
1070
1071 E_satisfied &= exist_good_successor;
1072
1073 }
1074
1075 if(E_satisfied and sat_successors>0)
1076 status[i] = SATISFIED;
1077 else
1078 status[i] = NOT_SATISFIED;
1079
1080 return status[i] == SATISFIED;
1081
1082 }
1083
checkANU(ulint i)1084 bool Tableau::checkANU(ulint i){
1085
1086 bool all_ANU_satisfied = true;
1087
1088 for(formula_index k = 0; all_ANU_satisfied and k<positive_closure->size();k++){//for each formula in i
1089
1090 //if k is inside i in negative form AND k is a E(aUb) (i.e. for all A~(aUb) inside i)
1091 if( belongsTo(states.at(i),indexToNegativeFormula(k)) and positive_closure->at(k)->getType()==EXISTS_UNTIL){
1092
1093 formula a = leftSubformula->at(k);
1094 formula b = rightSubformula->at(k);
1095
1096 clearMarked();//unmark all states
1097 all_ANU_satisfied &= checkANUrecursive(i,a,b);//start visit (DFS)
1098
1099 }
1100
1101 }
1102
1103 return all_ANU_satisfied;
1104
1105 }
1106
checkANUrecursive(ulint i,formula a,formula b)1107 bool Tableau::checkANUrecursive(ulint i,formula a, formula b){
1108
1109 current_timestamp++;
1110 mark_timestamps[i] = current_timestamp;
1111
1112 //b is in this state: return false
1113 if(belongsTo(states.at(i),b)){
1114 status[i] = NOT_SATISFIED;
1115 return false;
1116 }
1117
1118 //here we know that b is not in i
1119
1120 if(not belongsTo(states.at(i),a)){//a and b are not in i: return true (A~(aUb) satisfied in this state)
1121 status[i] = SATISFIED;
1122 return true;
1123 }
1124
1125 //here we know that b is NOT in i and a is in i
1126
1127 status[i] = VISITED;//mark status as visited
1128
1129 //1) visit recursively successors and check the A~(aUb) rule
1130
1131 for(std::set<uint>::iterator it = edges.at(i).begin(); it != edges.at(i).end();++it){//for all non-visited successors of i
1132
1133 if(status[*it]==NOT_VISITED)
1134 checkANUrecursive(*it,a, b);
1135
1136 }
1137
1138 //now each successor is marked as SATISFIED (A~(aUb) satisfied), NOT_SATISFIED (A~(aUb) not satisfied) or
1139 //VISITED (loop)
1140
1141 //extract all EX, E~X, EU, E~U rules present in state i: sub-structure must be consistent
1142
1143 vector<formula> existential_formulas;//existential formulas inside state i
1144
1145 for(formula_index k = 0; k<positive_closure->size();k++){//for each formula in i
1146
1147 if( belongsTo(states.at(i),indexToPositiveFormula(k)) and positive_closure->at(k)->getType()==EXISTS_TOMORROW)//EX
1148 existential_formulas.push_back(indexToPositiveFormula(k));
1149
1150 if( belongsTo(states.at(i),indexToNegativeFormula(k)) and positive_closure->at(k)->getType()==ALL_TOMORROW)//~AX = E~X
1151 existential_formulas.push_back(indexToNegativeFormula(k));
1152
1153 if( belongsTo(states.at(i),indexToPositiveFormula(k)) and positive_closure->at(k)->getType()==EXISTS_UNTIL)//EU
1154 existential_formulas.push_back(indexToPositiveFormula(k));
1155
1156 if( belongsTo(states.at(i),indexToNegativeFormula(k)) and positive_closure->at(k)->getType()==ALL_UNTIL)//~AU = E~U
1157 existential_formulas.push_back(indexToNegativeFormula(k));
1158
1159 }
1160
1161 bool E_satisfied = true;//all existential formulas satisfied
1162
1163 for(uint k=0;E_satisfied and k<existential_formulas.size();k++){//for each E formula
1164
1165 bool exist_good_successor = false;//exists a successor marked SATISFIED or VISITED (loop) that satisfies the E formula
1166
1167 for(std::set<uint>::iterator it = edges.at(i).begin(); (not exist_good_successor) and it != edges.at(i).end();++it){//for all successors of i
1168
1169 if(status[*it]==SATISFIED or status[*it]==VISITED)//only for successors marked SATISFIED or VISITED
1170 exist_good_successor |= checkEformula(existential_formulas.at(k),i,*it);//check that the E formula is sat in i->*it
1171
1172 }
1173
1174 E_satisfied &= exist_good_successor;
1175
1176 }
1177
1178 if(E_satisfied)
1179 status[i] = SATISFIED;
1180 else{
1181
1182 status[i] = NOT_SATISFIED;
1183
1184 //in this case, erase all marks made after the timestamp of this state because some assumptions made while
1185 //accepting loops may no more be valid (e.g. if a loop turned back to this state, now this state is not satisfied so the loop should not
1186 //have been accepted)
1187
1188 for(ulint s=0;s<states.size();s++){
1189
1190 if(mark_timestamps[s]>mark_timestamps[i]){//this status has been computed after the current node: erase it
1191 mark_timestamps[s]=0;
1192 status[s] = NOT_VISITED;
1193 }
1194
1195 }
1196
1197 }
1198
1199 return status[i] == SATISFIED;
1200
1201 }
1202
1203
checkEformula(formula f,ulint s1,ulint s2)1204 bool Tableau::checkEformula(formula f, ulint s1, ulint s2){//check if existential formula f is valid in the states s1->s2
1205
1206 //assumption: f is either EX, ~AX, EU or ~AU
1207
1208 formula_index k = formulaToIndex(f);
1209 formula a,b;
1210
1211 switch(positive_closure->at(k)->getType()){
1212
1213 case EXISTS_TOMORROW: /*f is EXa: s2 must contain a*/
1214
1215 a = leftSubformula->at(k);
1216 return belongsTo(states.at(s2),a);
1217
1218 break;
1219
1220 case ALL_TOMORROW: /*f is E~Xa: s2 must contain ~a*/
1221
1222 a = leftSubformula->at(k);
1223 return belongsTo(states.at(s2),negateFormula(a));
1224
1225 break;
1226
1227 case EXISTS_UNTIL: /*f is E(aUb): either b must be in s1 or E(aUb) must be in s2*/
1228
1229 b = rightSubformula->at(k);
1230
1231 if(belongsTo(states.at(s1),b))
1232 return true;
1233
1234 //b is not in s1: check that E(aUb) is in s2
1235
1236 return belongsTo(states.at(s2),f);
1237
1238 break;
1239
1240 case ALL_UNTIL: /* f is E~(aUb): by construction, ~b is in s1. either ~a must be in s1 or E~(aUb) must be in s2*/
1241
1242 a = leftSubformula->at(k);
1243
1244 if(belongsTo(states.at(s1),negateFormula(a)))
1245 return true;
1246
1247 //s1 contains a and ~b. E~(aUb) must be in s2
1248
1249 return belongsTo(states.at(s2),f);
1250
1251 break;
1252
1253 default: cout << "WARNING: unexpected formula in function checkEformula\n. Debug needed!\n"; return false; break;
1254
1255 }
1256
1257 return false;
1258
1259 }
1260
1261 //parameters: state, index of the EU formula, left and right subformulas
checkEUrecursive(ulint i,formula_index k,formula a,formula b)1262 bool Tableau::checkEUrecursive(ulint i,formula_index k, formula a, formula b){
1263
1264 //check if the state had already been checked in the past for this formula
1265 //if(globally_satisfied_formulas_positive[i][k])
1266 // return true;
1267
1268 //find a path starting from i that has always a until finally b is found (DFS visit)
1269 //no loops back: mark states
1270
1271 status[i] = VISITED;
1272 //marked->at(i) = true;//mark this state
1273
1274 if(belongsTo(states.at(i),b)){//b is in this state: mark globally and return success
1275 //globally_satisfied_formulas_positive[i][k] = true;
1276 return true;
1277 }
1278
1279 if(not belongsTo(states.at(i),a))//a is not in this state (and neither b): return false
1280 return false;
1281
1282 //b is not in this state and a is in this state. return success iif at least one non-visited successor returns success
1283
1284 bool path_found = false;
1285
1286 //first of all, check if there are successors marked globally (avoid recursion if possible)
1287
1288 /*for(std::set<uint>::iterator it = edges.at(i).begin(); (not path_found) and it != edges.at(i).end();++it){//for all successors of i
1289
1290 if(status[*it] == NOT_VISITED){//if the successor is not marked
1291
1292 path_found |= globally_satisfied_formulas_positive[*it][k];
1293
1294 }
1295
1296 }*/
1297
1298 //then, recurse only if no successors were already marked globally
1299
1300 for(std::set<uint>::iterator it = edges.at(i).begin(); (not path_found) and it != edges.at(i).end();++it){//for all successors of i
1301
1302 if(status[*it] == NOT_VISITED){//if the successor is not marked
1303
1304 path_found |= checkEUrecursive(*it,k,a,b);
1305
1306 }
1307
1308 }
1309
1310 //if(path_found)
1311 //globally_satisfied_formulas_positive[i][k] = true;
1312
1313 return path_found;
1314
1315 }
1316
checkENU(ulint i)1317 bool Tableau::checkENU(ulint i){
1318
1319 //for each E~(aUb) = ~A(aUb): find a path starting from i that has always ~b until finally ~b and ~a is found, OR
1320 //the path has always ~b and at some point it loops
1321
1322 clearMarked();//unmark all states
1323
1324 bool all_ENU_satisfied = true;
1325
1326 for(formula_index k = 0; all_ENU_satisfied and k<positive_closure->size();k++){//for each formula in i
1327
1328 //if k is inside i in negative form AND k is a A(aUb) (i.e. for all E~(aUb) inside i)
1329 if( belongsTo(states.at(i),indexToNegativeFormula(k)) and positive_closure->at(k)->getType()==ALL_UNTIL){
1330
1331 formula a = leftSubformula->at(k);
1332 formula b = rightSubformula->at(k);
1333
1334 all_ENU_satisfied &= checkENUrecursive(i,a,b);//start visit (DFS). note that states are all unmarked after call is finished (no need to call clearMarked())
1335
1336 }
1337
1338 }
1339
1340 return all_ENU_satisfied;
1341
1342 }
1343
checkENUrecursive(ulint i,formula a,formula b)1344 bool Tableau::checkENUrecursive(ulint i,formula a, formula b){
1345
1346 if(belongsTo(states.at(i),b))//b is in this state: return false
1347 return false;
1348
1349 //here we are sure that ~b is in this state
1350
1351 if(belongsTo(states.at(i),negateFormula(a)))//~a is in this state return true
1352 return true;
1353
1354 status[i] = VISITED;
1355 //marked->at(i) = true;//mark this state
1356
1357 //here we know that the state contains ~b and a
1358
1359 bool path_found = false;
1360
1361 for(std::set<uint>::iterator it = edges.at(i).begin(); (not path_found) and it != edges.at(i).end();++it){//for all successors of i
1362
1363 if(status[*it] == NOT_VISITED){//if the successor is not marked: call recursive DFS
1364
1365 path_found |= checkENUrecursive(*it,a,b);
1366
1367 }else{//the successor is marked: since we are unmarking states returning from recursion, this means that we found a loop
1368
1369 return true;
1370
1371 }
1372
1373 }
1374
1375 status[i] = NOT_VISITED;
1376 //marked->at(i) = false;//unmark this state
1377
1378 return path_found;
1379
1380 }
1381
isSatisfiable()1382 bool Tableau::isSatisfiable(){//true iif f admits a model
1383
1384 return number_of_states_with_original_formula>0;
1385
1386 }
1387
1388
1389 } /* namespace ctl_sat */
1390
1391
1392
1393