7 public class GraphAnalysis {
8 Termination termination;
9 static final int WORKS=0;
10 static final int ERR_NOREPAIR=1;
11 static final int ERR_CYCLE=2;
12 static final int ERR_RULE=3;
13 static final int ERR_ABSTRACT=4;
15 public GraphAnalysis(Termination t) {
19 private boolean safetransclosure(GraphNode gn, Set removed, Set cantremove, Set couldremove) {
20 Stack workset=new Stack();
21 HashSet closureset=new HashSet();
22 boolean needcyclecheck=false;
23 HashSet cantremovetrans=new HashSet();
25 while(!workset.empty()) {
26 GraphNode gn2=(GraphNode)workset.pop();
27 if (!closureset.contains(gn2)) {
29 boolean goodoption=false;
30 for(Iterator edgeit=gn2.edges();edgeit.hasNext();) {
31 GraphNode gn3=((GraphNode.Edge)edgeit.next()).getTarget();
32 if (removed.contains(gn3))
34 if (((cantremove.contains(gn2)||!couldremove.contains(gn2))
35 &&termination.conjunctions.contains(gn2))||
36 cantremovetrans.contains(gn2))
37 cantremovetrans.add(gn3);
39 if (termination.abstractrepair.contains(gn3)||
40 termination.conjunctions.contains(gn3)||
41 termination.updatenodes.contains(gn3)) {
42 /** Check for cycles if the graphnode can't
43 * be removed (we know we aren't introducing
44 * new things to repair). */
45 if ((!termination.abstractrepair.contains(gn3)&&
46 cantremove.contains(gn3))||
47 cantremovetrans.contains(gn3)) {
51 if ((!couldremove.contains(gn3))||cantremove.contains(gn3))
56 if (termination.scopenodes.contains(gn2))
62 Set cycles=GraphNode.findcycles(closureset);
63 for(Iterator it=cycles.iterator();it.hasNext();) {
64 GraphNode gn2=(GraphNode)it.next();
65 if (termination.abstractrepair.contains(gn2)||
66 termination.conjunctions.contains(gn2)||
67 termination.updatenodes.contains(gn2))
74 public Set doAnalysis() {
75 HashSet cantremove=new HashSet();
76 HashSet mustremove=new HashSet();
78 cantremove.addAll(termination.scopenodes);
79 cantremove.addAll(termination.abstractrepair);
83 HashSet nodes=new HashSet();
84 nodes.addAll(termination.conjunctions);
85 nodes.removeAll(mustremove);
86 GraphNode.computeclosure(nodes,mustremove);
87 Set cycles=GraphNode.findcycles(nodes);
88 Set couldremove=new HashSet();
89 couldremove.addAll(termination.conjunctions);
90 couldremove.addAll(termination.updatenodes);
91 couldremove.addAll(termination.consequencenodes);
92 couldremove.retainAll(nodes);
95 /* Check for consequence nodes which are fine */
97 for(Iterator it=termination.consequencenodes.iterator();it.hasNext();) {
98 GraphNode gn=(GraphNode) it.next();
99 if (safetransclosure(gn, mustremove,cantremove, couldremove)) {
100 couldremove.remove(gn);
104 /* Check for update nodes which are fine */
106 for(Iterator it=termination.updatenodes.iterator();it.hasNext();) {
107 GraphNode gn=(GraphNode) it.next();
108 if (safetransclosure(gn, mustremove,cantremove, cantremove)) {
109 couldremove.remove(gn);
113 /* Check for conjunction nodes which are fine */
115 for(Iterator it=termination.conjunctions.iterator();it.hasNext();) {
116 GraphNode gn=(GraphNode) it.next();
117 if (mustremove.contains(gn)||cantremove.contains(gn))
119 if (!safetransclosure(gn, mustremove,cantremove, cantremove))
122 boolean allgood=true;
123 for(Iterator edgeit=gn.edges();edgeit.hasNext();) {
124 GraphNode gn2=((GraphNode.Edge)edgeit.next()).getTarget();
125 TermNode tn2=(TermNode)gn2.getOwner();
126 assert tn2.getType()==TermNode.ABSTRACT;
127 boolean foundupdate=false;
128 for(Iterator edgeit2=gn2.edges();edgeit2.hasNext();) {
129 GraphNode gn3=((GraphNode.Edge)edgeit2.next()).getTarget();
130 if (!couldremove.contains(gn3)&&!mustremove.contains(gn3)) {
131 TermNode tn3=(TermNode)gn3.getOwner();
132 if (tn3.getType()==TermNode.UPDATE)
140 couldremove.remove(gn);
141 if (Compiler.PRUNEQUANTIFIERS) {
142 TermNode tn=(TermNode)gn.getOwner();
143 Constraint constr=tn.getConstraint();
144 for(Iterator consit=((Set)termination.conjunctionmap.get(constr)).iterator();consit.hasNext();) {
145 GraphNode gn4=(GraphNode)consit.next();
146 TermNode tn4=(TermNode)gn4.getOwner();
147 if (tn4.getquantifiernode()) {
148 mustremove.add(gn4); /* This node is history */
149 System.out.println("Eliminating: "+gn4.getTextLabel());
157 /* Look for constraints which can only be satisfied one way */
159 Vector constraints=termination.state.vConstraints;
160 for(int i=0;i<constraints.size();i++) {
161 Constraint c=(Constraint)constraints.get(i);
162 Set conjunctionset=(Set)termination.conjunctionmap.get(c);
163 HashSet tmpset=new HashSet();
164 tmpset.addAll(conjunctionset);
165 tmpset.removeAll(mustremove);
166 if (tmpset.size()==1) {
167 int oldsize=cantremove.size();
168 cantremove.addAll(tmpset);
169 if (cantremove.size()!=oldsize)
175 /* Search through conjunction which must be satisfied, and attempt
176 to generate appropriate repair actions.
178 HashSet newset=new HashSet();
179 for(Iterator cit=cantremove.iterator();cit.hasNext();) {
180 GraphNode gn=(GraphNode)cit.next();
181 boolean nomodify=true;
182 HashSet toremove=new HashSet();
183 if (termination.conjunctions.contains(gn)) {
184 for(Iterator edgeit=gn.edges();edgeit.hasNext();) {
185 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
186 GraphNode gn2=e.getTarget();
187 TermNode tn2=(TermNode)gn2.getOwner();
188 if (nodes.contains(gn2)&&
189 tn2.getType()==TermNode.ABSTRACT) {
191 HashSet updateset=new HashSet();
192 for(Iterator upit=gn2.edges();upit.hasNext();) {
193 GraphNode.Edge e2=(GraphNode.Edge)upit.next();
194 GraphNode gn3=e2.getTarget();
195 TermNode tn3=(TermNode)gn3.getOwner();
196 if (tn3.getType()==TermNode.UPDATE)
199 updateset.removeAll(mustremove);
200 if (updateset.size()==1)
201 toremove.addAll(updateset);
204 newset.addAll(toremove);
209 int oldsize=cantremove.size();
210 cantremove.addAll(newset);
211 if (cantremove.size()!=oldsize)
215 /* Look for required actions for scope nodes */
216 for(Iterator scopeit=termination.scopenodes.iterator();scopeit.hasNext();) {
217 GraphNode gn=(GraphNode)scopeit.next();
218 HashSet tmpset=new HashSet();
219 for(Iterator edgeit=gn.edges();edgeit.hasNext();) {
220 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
221 tmpset.add(e.getTarget());
223 tmpset.removeAll(mustremove);
224 if (tmpset.size()==1) {
225 int oldsize=cantremove.size();
226 cantremove.addAll(tmpset);
227 if (cantremove.size()!=oldsize)
232 if (Compiler.AGGRESSIVESEARCH) {
233 /* Aggressively remove compensation nodes */
234 for(Iterator scopeit=termination.scopenodes.iterator();scopeit.hasNext();) {
235 GraphNode gn=(GraphNode)scopeit.next();
236 HashSet tmpset=new HashSet();
237 boolean doremove=false;
238 for(Iterator edgeit=gn.edges();edgeit.hasNext();) {
239 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
240 GraphNode gn2=e.getTarget();
241 if (termination.consequencenodes.contains(gn2)) {
242 if (((!couldremove.contains(gn2))||cantremove.contains(gn2))&&
243 !mustremove.contains(gn2)) {
247 } else tmpset.add(gn2);
250 mustremove.addAll(tmpset);
254 Set cycles2=GraphNode.findcycles(cantremove);
255 for(Iterator it=cycles2.iterator();it.hasNext();) {
256 GraphNode gn=(GraphNode)it.next();
257 if (termination.conjunctions.contains(gn)) {
259 GraphNode.DOTVisitor.visit(new FileOutputStream("graphdebug.dot"),cantremove);
260 } catch (Exception e) {
265 System.out.println("Cycle through conjunction "+gn.getTextLabel() +" which can't be removed.");
266 System.out.println("CANTREMOVE");
267 for(Iterator it2=cantremove.iterator();it2.hasNext();) {
268 GraphNode gn2=(GraphNode)it2.next();
269 System.out.println(gn2.getTextLabel());
271 System.out.println("MUSTREMOVE");
272 for(Iterator it2=mustremove.iterator();it2.hasNext();) {
273 GraphNode gn2=(GraphNode)it2.next();
274 System.out.println(gn2.getTextLabel());
276 return null; // Out of luck
280 /* Search through abstract repair actions & correspond data structure updates */
281 for(Iterator it=termination.abstractrepairadd.iterator();it.hasNext();) {
282 GraphNode gn=(GraphNode)it.next();
283 TermNode tn=(TermNode)gn.getOwner();
285 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
286 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
287 GraphNode gn2=e.getTarget();
288 TermNode tn2=(TermNode)gn2.getOwner();
289 if (tn2.getType()!=TermNode.UPDATE)
292 boolean containsgn=cantremove.contains(gn);
293 boolean containsgn2=cantremove.contains(gn2);
298 Set cycle=GraphNode.findcycles(cantremove);
299 if (cycle.contains(gn2)) {
300 if (!mustremove.contains(gn2)) {
306 cantremove.remove(gn);
308 cantremove.remove(gn2);
312 /* Searches individual conjunctions + abstract action +updates for cycles */
313 for(Iterator it=termination.conjunctions.iterator();it.hasNext();) {
314 GraphNode gn=(GraphNode)it.next();
315 boolean foundnocycle=false;
317 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
318 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
319 GraphNode gn2=e.getTarget();
320 TermNode tn2=(TermNode)gn2.getOwner();
321 if (tn2.getType()!=TermNode.ABSTRACT)
323 AbstractRepair ar=tn2.getAbstract();
324 boolean ismodify=ar.getType()==AbstractRepair.MODIFYRELATION;
325 int numadd=0;int numremove=0;
327 for (Iterator edgeit2=gn2.edges();edgeit2.hasNext();) {
328 GraphNode.Edge e2=(GraphNode.Edge)edgeit2.next();
329 GraphNode gn3=e2.getTarget();
330 TermNode tn3=(TermNode)gn3.getOwner();
331 if (tn3.getType()!=TermNode.UPDATE)
334 boolean containsgn=cantremove.contains(gn);
335 boolean containsgn2=cantremove.contains(gn2);
336 boolean containsgn3=cantremove.contains(gn3);
340 Set cycle=GraphNode.findcycles(cantremove);
341 if (cycle.contains(gn3)) {
342 if (!mustremove.contains(gn3)) {
347 if (!mustremove.contains(gn3)&&!cycle.contains(gn)) {
350 MultUpdateNode mun=tn3.getUpdate();
351 if (mun.getType()==MultUpdateNode.ADD)
353 if (mun.getType()==MultUpdateNode.REMOVE)
358 cantremove.remove(gn);
360 cantremove.remove(gn2);
362 cantremove.remove(gn3);
364 if (ismodify&&((numadd==0)||(numremove==0&&ar.needsRemoves(termination.state)))) {
365 for (Iterator edgeit2=gn2.edges();edgeit2.hasNext();) {
366 GraphNode.Edge e2=(GraphNode.Edge)edgeit2.next();
367 GraphNode gn3=e2.getTarget();
368 TermNode tn3=(TermNode)gn3.getOwner();
369 if (tn3.getType()!=TermNode.UPDATE)
371 MultUpdateNode mun=tn3.getUpdate();
372 if (((mun.getType()==MultUpdateNode.ADD)||
373 (mun.getType()==MultUpdateNode.REMOVE))&&
374 (!mustremove.contains(gn3)))
381 if (!mustremove.contains(gn)) {
388 /* Searches scope nodes + compensation nodes */
389 for(Iterator it=termination.scopenodes.iterator();it.hasNext();) {
390 GraphNode gn=(GraphNode)it.next();
392 if (nodes.contains(gn)) {
393 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
394 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
395 GraphNode gn2=e.getTarget();
396 TermNode tn2=(TermNode)gn2.getOwner();
398 if ((tn2.getType()==TermNode.CONSEQUENCE)&&
399 !mustremove.contains(gn2))
403 if (tn2.getType()!=TermNode.UPDATE)
405 /* We have a compensation node */
406 boolean containsgn=cantremove.contains(gn);
407 boolean containsgn2=cantremove.contains(gn2);
411 Set cycle=GraphNode.findcycles(cantremove);
412 if (cycle.contains(gn2)) {
413 if (!mustremove.contains(gn2)) {
418 if (!mustremove.contains(gn2))
422 cantremove.remove(gn);
424 cantremove.remove(gn2);
428 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
429 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
430 GraphNode gn2=e.getTarget();
431 TermNode tn2=(TermNode)gn2.getOwner();
432 if ((tn2.getType()==TermNode.UPDATE||tn2.getType()==TermNode.CONSEQUENCE)&&
433 !mustremove.contains(gn2)) {
434 if (!cantremove.contains(gn2)) {
443 couldremove.removeAll(mustremove);
444 couldremove.removeAll(cantremove);
446 Vector couldremovevector=new Vector();
447 couldremovevector.addAll(couldremove);
448 Vector combination=new Vector();
450 continue; //recalculate
453 GraphNode.DOTVisitor.visit(new FileOutputStream("graphsearch.dot"),nodes,couldremove);
454 } catch (Exception e) {
460 GraphNode.DOTVisitor.visit(new FileOutputStream("graphcycle.dot"),GraphNode.findcycles(nodes),couldremove);
461 } catch (Exception e) {
466 System.out.println("Searching set of "+couldremove.size()+" nodes.");
467 System.out.println("Eliminated must "+mustremove.size()+" nodes");
468 System.out.println("Eliminated cant "+cantremove.size()+" nodes");
469 System.out.println("Searching following set:");
470 for(Iterator it=couldremove.iterator();it.hasNext();) {
471 GraphNode gn=(GraphNode)it.next();
472 System.out.println(gn.getTextLabel());
474 System.out.println("Must remove set:");
475 for(Iterator it=mustremove.iterator();it.hasNext();) {
476 GraphNode gn=(GraphNode)it.next();
477 System.out.println(gn.getTextLabel());
479 System.out.println("Cant remove set:");
480 for(Iterator it=cantremove.iterator();it.hasNext();) {
481 GraphNode gn=(GraphNode)it.next();
482 System.out.println(gn.getTextLabel());
485 System.out.println("==================================================");
487 if (illegal(combination,couldremovevector))
489 Set combinationset=buildset(combination,couldremovevector);
490 System.out.println("---------------------------");
491 for(Iterator it=combinationset.iterator();it.hasNext();) {
492 System.out.println(((GraphNode)it.next()).getTextLabel());
494 System.out.println("---------------------------");
495 checkmodify(combinationset);
496 combinationset.addAll(mustremove);
497 if (combinationset!=null) {
498 int checkabstract=checkAbstract(combinationset);
499 int checkrep=checkRepairs(combinationset);
500 int checkall=checkAll(combinationset);
502 System.out.println("Checkabstract="+checkabstract);
503 System.out.println("Checkrepairs="+checkrep);
504 System.out.println("Checkall="+checkall);
506 if (checkabstract==0&&
509 return combinationset;
512 increment(combination,couldremovevector);
514 System.out.println("Search failed!");
519 private void checkmodify(Set removednodes) {
520 for (Iterator it=termination.abstractrepair.iterator();it.hasNext();) {
521 GraphNode gn=(GraphNode)it.next();
522 TermNode tn=(TermNode)gn.getOwner();
523 AbstractRepair ar=tn.getAbstract();
525 /* Has MODIFYRELATION */
526 if (ar.getType()==AbstractRepair.MODIFYRELATION) {
529 for(Iterator it2=gn.edges();it2.hasNext();) {
530 GraphNode.Edge edge=(GraphNode.Edge)it2.next();
531 GraphNode gn2=edge.getTarget();
532 TermNode tn2=(TermNode)gn2.getOwner();
533 if (!removednodes.contains(gn2)&&
534 tn2.getType()==TermNode.UPDATE) {
535 MultUpdateNode mun=tn2.getUpdate();
537 if (mun.getType()==MultUpdateNode.ADD)
539 if (mun.getType()==MultUpdateNode.REMOVE)
543 if ((numadd==0)||(numremove==0&&ar.needsRemoves(termination.state))) {
544 for(Iterator it2=gn.edges();it2.hasNext();) {
545 GraphNode.Edge edge=(GraphNode.Edge)it2.next();
546 GraphNode gn2=edge.getTarget();
547 TermNode tn2=(TermNode)gn2.getOwner();
548 if (!removednodes.contains(gn2)&&
549 tn2.getType()==TermNode.UPDATE) {
550 MultUpdateNode mun=tn2.getUpdate();
551 if ((mun.getType()==MultUpdateNode.ADD)
552 ||(mun.getType()==MultUpdateNode.REMOVE)) {
553 removednodes.add(gn2);
562 private static Set buildset(Vector combination, Vector couldremove) {
564 for(int i=0;i<combination.size();i++) {
565 int index=((Integer)combination.get(i)).intValue();
566 Object o=couldremove.get(index);
575 private static boolean illegal(Vector combination, Vector couldremove) {
576 if (combination.size()>couldremove.size())
580 private static void increment(Vector combination, Vector couldremove) {
581 boolean incremented=false;
582 boolean forcereset=false;
583 for(int i=0;i<combination.size();i++) {
584 int newindex=((Integer)combination.get(i)).intValue()+1;
585 if (newindex==couldremove.size()||forcereset) {
587 if ((i+1)==combination.size()) {
590 newindex=((Integer)combination.get(i+1)).intValue()+2;
591 for(int j=i;j>=0;j--) {
592 combination.set(j,new Integer(newindex));
595 if (newindex>couldremove.size())
599 combination.set(i,new Integer(newindex));
603 if (incremented==false) /* Increase length */ {
604 combination.add(new Integer(0));
605 System.out.println("Expanding to: "+combination.size());
609 /* This function checks the graph as a whole for bad cycles */
610 public int checkAll(Collection removed) {
611 Set nodes=new HashSet();
612 nodes.addAll(termination.conjunctions);
613 nodes.removeAll(removed);
614 GraphNode.computeclosure(nodes,removed);
615 Set cycles=GraphNode.findcycles(nodes);
616 for(Iterator it=cycles.iterator();it.hasNext();) {
617 GraphNode gn=(GraphNode)it.next();
618 TermNode tn=(TermNode)gn.getOwner();
619 switch(tn.getType()) {
620 case TermNode.UPDATE:
621 case TermNode.CONJUNCTION:
623 case TermNode.ABSTRACT:
624 case TermNode.RULESCOPE:
625 case TermNode.CONSEQUENCE:
633 /* This function checks that
634 1) All abstract repairs have a corresponding data structure update
636 2) All scope nodes have either a consequence node or a compensation
637 node that isn't removed.
639 public int checkRepairs(Collection removed) {
640 Set nodes=new HashSet();
641 nodes.addAll(termination.conjunctions);
642 nodes.removeAll(removed);
643 GraphNode.computeclosure(nodes,removed);
644 Set toretain=new HashSet();
645 toretain.addAll(termination.abstractrepair);
646 toretain.addAll(termination.scopenodes);
647 nodes.retainAll(toretain);
648 /* Nodes is now the reachable set of abstractrepairs */
649 /* Check to see that each has an implementation */
650 for(Iterator it=nodes.iterator();it.hasNext();) {
651 GraphNode gn=(GraphNode)it.next();
652 TermNode tn=(TermNode)gn.getOwner();
653 if (tn.getType()==TermNode.RULESCOPE) {
654 boolean foundnode=false;
655 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
656 GraphNode.Edge edge=(GraphNode.Edge)edgeit.next();
657 GraphNode gn2=edge.getTarget();
658 if (!removed.contains(gn2)) {
659 TermNode tn2=(TermNode)gn2.getOwner();
660 if ((tn2.getType()==TermNode.CONSEQUENCE)||
661 (tn2.getType()==TermNode.UPDATE)) {
668 System.out.println(gn.getTextLabel());
671 } else if (tn.getType()==TermNode.ABSTRACT) {
672 boolean foundnode=false;
673 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
674 GraphNode.Edge edge=(GraphNode.Edge)edgeit.next();
675 GraphNode gn2=edge.getTarget();
676 if (!removed.contains(gn2)) {
677 TermNode tn2=(TermNode)gn2.getOwner();
678 if (tn2.getType()==TermNode.UPDATE) {
686 } else throw new Error("Unanticipated Node");
690 /* This method checks that all constraints have conjunction nodes
691 and that there are no bad cycles in the abstract portion of the graph.
693 public int checkAbstract(Collection removed) {
694 Vector constraints=termination.state.vConstraints;
695 for(int i=0;i<constraints.size();i++) {
696 Constraint c=(Constraint)constraints.get(i);
697 Set conjunctionset=(Set)termination.conjunctionmap.get(c);
699 boolean foundrepair=false;
700 for(Iterator it=conjunctionset.iterator();it.hasNext();) {
701 GraphNode gn=(GraphNode)it.next();
702 if (!removed.contains(gn)) {
711 Set abstractnodes=new HashSet();
712 abstractnodes.addAll(termination.conjunctions);
713 abstractnodes.removeAll(removed);
714 GraphNode.computeclosure(abstractnodes,removed);
716 Set tset=new HashSet();
717 tset.addAll(termination.conjunctions);
718 tset.addAll(termination.abstractrepair);
719 tset.addAll(termination.scopenodes);
720 tset.addAll(termination.consequencenodes);
721 abstractnodes.retainAll(tset);
722 Set cycles=GraphNode.findcycles(abstractnodes);
724 for(Iterator it=cycles.iterator();it.hasNext();) {
725 GraphNode gn=(GraphNode)it.next();
726 System.out.println("NODE: "+gn.getTextLabel());
727 TermNode tn=(TermNode)gn.getOwner();
728 switch(tn.getType()) {
729 case TermNode.CONJUNCTION:
730 case TermNode.ABSTRACT:
732 case TermNode.UPDATE:
733 throw new Error("No Update Nodes should be here");