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))
120 boolean allgood=true;
121 for(Iterator edgeit=gn.edges();edgeit.hasNext();) {
122 GraphNode gn2=((GraphNode.Edge)edgeit.next()).getTarget();
123 TermNode tn2=(TermNode)gn2.getOwner();
124 assert tn2.getType()==TermNode.ABSTRACT;
125 boolean foundupdate=false;
126 for(Iterator edgeit2=gn2.edges();edgeit2.hasNext();) {
127 GraphNode gn3=((GraphNode.Edge)edgeit2.next()).getTarget();
128 if (!couldremove.contains(gn3)&&!mustremove.contains(gn3)) {
129 TermNode tn3=(TermNode)gn3.getOwner();
130 if (tn3.getType()==TermNode.UPDATE)
138 couldremove.remove(gn);
142 /* Look for constraints which can only be satisfied one way */
144 Vector constraints=termination.state.vConstraints;
145 for(int i=0;i<constraints.size();i++) {
146 Constraint c=(Constraint)constraints.get(i);
147 Set conjunctionset=(Set)termination.conjunctionmap.get(c);
148 HashSet tmpset=new HashSet();
149 tmpset.addAll(conjunctionset);
150 tmpset.removeAll(mustremove);
151 if (tmpset.size()==1) {
152 int oldsize=cantremove.size();
153 cantremove.addAll(tmpset);
154 if (cantremove.size()!=oldsize)
160 /* Search through conjunction which must be satisfied, and attempt
161 to generate appropriate repair actions.
163 HashSet newset=new HashSet();
164 for(Iterator cit=cantremove.iterator();cit.hasNext();) {
165 GraphNode gn=(GraphNode)cit.next();
166 boolean nomodify=true;
167 HashSet toremove=new HashSet();
168 if (termination.conjunctions.contains(gn)) {
169 for(Iterator edgeit=gn.edges();edgeit.hasNext();) {
170 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
171 GraphNode gn2=e.getTarget();
172 TermNode tn2=(TermNode)gn2.getOwner();
173 if (nodes.contains(gn2)&&
174 tn2.getType()==TermNode.ABSTRACT) {
176 HashSet updateset=new HashSet();
177 for(Iterator upit=gn2.edges();upit.hasNext();) {
178 GraphNode.Edge e2=(GraphNode.Edge)upit.next();
179 GraphNode gn3=e2.getTarget();
180 TermNode tn3=(TermNode)gn3.getOwner();
181 if (tn3.getType()==TermNode.UPDATE)
184 updateset.removeAll(mustremove);
185 if (updateset.size()==1)
186 toremove.addAll(updateset);
189 newset.addAll(toremove);
194 int oldsize=cantremove.size();
195 cantremove.addAll(newset);
196 if (cantremove.size()!=oldsize)
200 /* Look for required actions for scope nodes */
201 for(Iterator scopeit=termination.scopenodes.iterator();scopeit.hasNext();) {
202 GraphNode gn=(GraphNode)scopeit.next();
203 HashSet tmpset=new HashSet();
204 for(Iterator edgeit=gn.edges();edgeit.hasNext();) {
205 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
206 tmpset.add(e.getTarget());
208 tmpset.removeAll(mustremove);
209 if (tmpset.size()==1) {
210 int oldsize=cantremove.size();
211 cantremove.addAll(tmpset);
212 if (cantremove.size()!=oldsize)
217 if (Compiler.AGGRESSIVESEARCH) {
218 /* Aggressively remove compensation nodes */
219 for(Iterator scopeit=termination.scopenodes.iterator();scopeit.hasNext();) {
220 GraphNode gn=(GraphNode)scopeit.next();
221 HashSet tmpset=new HashSet();
222 boolean doremove=false;
223 for(Iterator edgeit=gn.edges();edgeit.hasNext();) {
224 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
225 GraphNode gn2=e.getTarget();
226 if (termination.consequencenodes.contains(gn2)) {
227 if (((!couldremove.contains(gn2))||cantremove.contains(gn2))&&
228 !mustremove.contains(gn2)) {
232 } else tmpset.add(gn2);
235 mustremove.addAll(tmpset);
239 Set cycles2=GraphNode.findcycles(cantremove);
240 for(Iterator it=cycles2.iterator();it.hasNext();) {
241 GraphNode gn=(GraphNode)it.next();
242 if (termination.conjunctions.contains(gn)) {
244 GraphNode.DOTVisitor.visit(new FileOutputStream("graphdebug.dot"),cantremove);
245 } catch (Exception e) {
250 System.out.println("Cycle through conjunction "+gn.getTextLabel() +" which can't be removed.");
251 return null; // Out of luck
255 /* Search through abstract repair actions & correspond data structure updates */
256 for(Iterator it=termination.abstractrepairadd.iterator();it.hasNext();) {
257 GraphNode gn=(GraphNode)it.next();
258 TermNode tn=(TermNode)gn.getOwner();
260 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
261 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
262 GraphNode gn2=e.getTarget();
263 TermNode tn2=(TermNode)gn2.getOwner();
264 if (tn2.getType()!=TermNode.UPDATE)
267 boolean containsgn=cantremove.contains(gn);
268 boolean containsgn2=cantremove.contains(gn2);
273 Set cycle=GraphNode.findcycles(cantremove);
274 if (cycle.contains(gn2)) {
275 if (!mustremove.contains(gn2)) {
281 cantremove.remove(gn);
283 cantremove.remove(gn2);
287 /* Searches individual conjunctions + abstract action +updates for cycles */
288 for(Iterator it=termination.conjunctions.iterator();it.hasNext();) {
289 GraphNode gn=(GraphNode)it.next();
290 boolean foundnocycle=false;
292 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
293 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
294 GraphNode gn2=e.getTarget();
295 TermNode tn2=(TermNode)gn2.getOwner();
296 if (tn2.getType()!=TermNode.ABSTRACT)
298 AbstractRepair ar=tn2.getAbstract();
299 boolean ismodify=ar.getType()==AbstractRepair.MODIFYRELATION;
300 int numadd=0;int numremove=0;
302 for (Iterator edgeit2=gn2.edges();edgeit2.hasNext();) {
303 GraphNode.Edge e2=(GraphNode.Edge)edgeit2.next();
304 GraphNode gn3=e2.getTarget();
305 TermNode tn3=(TermNode)gn3.getOwner();
306 if (tn3.getType()!=TermNode.UPDATE)
309 boolean containsgn=cantremove.contains(gn);
310 boolean containsgn2=cantremove.contains(gn2);
311 boolean containsgn3=cantremove.contains(gn3);
315 Set cycle=GraphNode.findcycles(cantremove);
316 if (cycle.contains(gn3)) {
317 if (!mustremove.contains(gn3)) {
322 if (!mustremove.contains(gn3)&&!cycle.contains(gn)) {
325 MultUpdateNode mun=tn3.getUpdate();
326 if (mun.getType()==MultUpdateNode.ADD)
328 if (mun.getType()==MultUpdateNode.REMOVE)
333 cantremove.remove(gn);
335 cantremove.remove(gn2);
337 cantremove.remove(gn3);
339 if (ismodify&&((numadd==0)||(numremove==0))) {
340 for (Iterator edgeit2=gn2.edges();edgeit2.hasNext();) {
341 GraphNode.Edge e2=(GraphNode.Edge)edgeit2.next();
342 GraphNode gn3=e2.getTarget();
343 TermNode tn3=(TermNode)gn3.getOwner();
344 if (tn3.getType()!=TermNode.UPDATE)
346 MultUpdateNode mun=tn3.getUpdate();
347 if (((mun.getType()==MultUpdateNode.ADD)||
348 (mun.getType()==MultUpdateNode.REMOVE))&&
349 (!mustremove.contains(gn3)))
356 if (!mustremove.contains(gn)) {
363 /* Searches scope nodes + compensation nodes */
364 for(Iterator it=termination.scopenodes.iterator();it.hasNext();) {
365 GraphNode gn=(GraphNode)it.next();
367 if (nodes.contains(gn)) {
368 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
369 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
370 GraphNode gn2=e.getTarget();
371 TermNode tn2=(TermNode)gn2.getOwner();
373 if ((tn2.getType()==TermNode.CONSEQUENCE)&&
374 !mustremove.contains(gn2))
378 if (tn2.getType()!=TermNode.UPDATE)
380 /* We have a compensation node */
381 boolean containsgn=cantremove.contains(gn);
382 boolean containsgn2=cantremove.contains(gn2);
386 Set cycle=GraphNode.findcycles(cantremove);
387 if (cycle.contains(gn2)) {
388 if (!mustremove.contains(gn2)) {
393 if (!mustremove.contains(gn2))
397 cantremove.remove(gn);
399 cantremove.remove(gn2);
403 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
404 GraphNode.Edge e=(GraphNode.Edge)edgeit.next();
405 GraphNode gn2=e.getTarget();
406 TermNode tn2=(TermNode)gn2.getOwner();
407 if ((tn2.getType()==TermNode.UPDATE||tn2.getType()==TermNode.CONSEQUENCE)&&
408 !mustremove.contains(gn2)) {
409 if (!cantremove.contains(gn2)) {
418 couldremove.removeAll(mustremove);
419 couldremove.removeAll(cantremove);
421 Vector couldremovevector=new Vector();
422 couldremovevector.addAll(couldremove);
423 Vector combination=new Vector();
425 continue; //recalculate
428 GraphNode.DOTVisitor.visit(new FileOutputStream("graphsearch.dot"),nodes,couldremove);
429 } catch (Exception e) {
435 GraphNode.DOTVisitor.visit(new FileOutputStream("graphcycle.dot"),GraphNode.findcycles(nodes),couldremove);
436 } catch (Exception e) {
441 System.out.println("Searching set of "+couldremove.size()+" nodes.");
442 System.out.println("Eliminated must "+mustremove.size()+" nodes");
443 System.out.println("Eliminated cant "+cantremove.size()+" nodes");
444 System.out.println("Searching following set:");
445 for(Iterator it=couldremove.iterator();it.hasNext();) {
446 GraphNode gn=(GraphNode)it.next();
447 System.out.println(gn.getTextLabel());
449 System.out.println("Must remove set:");
450 for(Iterator it=mustremove.iterator();it.hasNext();) {
451 GraphNode gn=(GraphNode)it.next();
452 System.out.println(gn.getTextLabel());
454 System.out.println("Cant remove set:");
455 for(Iterator it=cantremove.iterator();it.hasNext();) {
456 GraphNode gn=(GraphNode)it.next();
457 System.out.println(gn.getTextLabel());
462 if (illegal(combination,couldremovevector))
464 Set combinationset=buildset(combination,couldremovevector);
465 checkmodify(combinationset);
466 combinationset.addAll(mustremove);
467 if (combinationset!=null) {
468 System.out.println("Checkabstract="+checkAbstract(combinationset));
469 System.out.println("Checkrepairs="+checkRepairs(combinationset));
470 System.out.println("Checkall="+checkAll(combinationset));
472 if (checkAbstract(combinationset)==0&&
473 checkRepairs(combinationset)==0&&
474 checkAll(combinationset)==0) {
475 return combinationset;
478 increment(combination,couldremovevector);
480 System.out.println("Search failed!");
485 private void checkmodify(Set removednodes) {
486 for (Iterator it=termination.abstractrepair.iterator();it.hasNext();) {
487 GraphNode gn=(GraphNode)it.next();
488 TermNode tn=(TermNode)gn.getOwner();
489 AbstractRepair ar=tn.getAbstract();
491 /* Has MODIFYRELATION */
492 if (ar.getType()==AbstractRepair.MODIFYRELATION) {
495 for(Iterator it2=gn.edges();it2.hasNext();) {
496 GraphNode.Edge edge=(GraphNode.Edge)it2.next();
497 GraphNode gn2=edge.getTarget();
498 TermNode tn2=(TermNode)gn2.getOwner();
499 if (!removednodes.contains(gn2)&&
500 tn2.getType()==TermNode.UPDATE) {
501 MultUpdateNode mun=tn2.getUpdate();
503 if (mun.getType()==MultUpdateNode.ADD)
505 if (mun.getType()==MultUpdateNode.REMOVE)
509 if ((numadd==0)||(numremove==0)) {
510 for(Iterator it2=gn.edges();it2.hasNext();) {
511 GraphNode.Edge edge=(GraphNode.Edge)it2.next();
512 GraphNode gn2=edge.getTarget();
513 TermNode tn2=(TermNode)gn2.getOwner();
514 if (!removednodes.contains(gn2)&&
515 tn2.getType()==TermNode.UPDATE) {
516 MultUpdateNode mun=tn2.getUpdate();
517 if ((mun.getType()==MultUpdateNode.ADD)
518 ||(mun.getType()==MultUpdateNode.REMOVE)) {
519 removednodes.add(gn2);
528 private static Set buildset(Vector combination, Vector couldremove) {
530 for(int i=0;i<combination.size();i++) {
531 int index=((Integer)combination.get(i)).intValue();
532 Object o=couldremove.get(index);
541 private static boolean illegal(Vector combination, Vector couldremove) {
542 if (combination.size()>couldremove.size())
546 private static void increment(Vector combination, Vector couldremove) {
547 boolean incremented=false;
548 boolean forcereset=false;
549 for(int i=0;i<combination.size();i++) {
550 int newindex=((Integer)combination.get(i)).intValue()+1;
551 if (newindex==couldremove.size()||forcereset) {
553 if ((i+1)==combination.size()) {
556 newindex=((Integer)combination.get(i+1)).intValue()+2;
557 for(int j=i;j>=0;j--) {
558 combination.set(j,new Integer(newindex));
561 if (newindex>couldremove.size())
565 combination.set(i,new Integer(newindex));
569 if (incremented==false) /* Increase length */ {
570 combination.add(new Integer(0));
571 System.out.println("Expanding to: "+combination.size());
575 /* This function checks the graph as a whole for bad cycles */
576 public int checkAll(Collection removed) {
577 Set nodes=new HashSet();
578 nodes.addAll(termination.conjunctions);
579 nodes.removeAll(removed);
580 GraphNode.computeclosure(nodes,removed);
581 Set cycles=GraphNode.findcycles(nodes);
582 for(Iterator it=cycles.iterator();it.hasNext();) {
583 GraphNode gn=(GraphNode)it.next();
584 TermNode tn=(TermNode)gn.getOwner();
585 switch(tn.getType()) {
586 case TermNode.UPDATE:
587 case TermNode.CONJUNCTION:
589 case TermNode.ABSTRACT:
590 case TermNode.RULESCOPE:
591 case TermNode.CONSEQUENCE:
599 /* This function checks that
600 1) All abstract repairs have a corresponding data structure update
602 2) All scope nodes have either a consequence node or a compensation
603 node that isn't removed.
605 public int checkRepairs(Collection removed) {
606 Set nodes=new HashSet();
607 nodes.addAll(termination.conjunctions);
608 nodes.removeAll(removed);
609 GraphNode.computeclosure(nodes,removed);
610 Set toretain=new HashSet();
611 toretain.addAll(termination.abstractrepair);
612 toretain.addAll(termination.scopenodes);
613 nodes.retainAll(toretain);
614 /* Nodes is now the reachable set of abstractrepairs */
615 /* Check to see that each has an implementation */
616 for(Iterator it=nodes.iterator();it.hasNext();) {
617 GraphNode gn=(GraphNode)it.next();
618 TermNode tn=(TermNode)gn.getOwner();
619 if (tn.getType()==TermNode.RULESCOPE) {
620 boolean foundnode=false;
621 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
622 GraphNode.Edge edge=(GraphNode.Edge)edgeit.next();
623 GraphNode gn2=edge.getTarget();
624 if (!removed.contains(gn2)) {
625 TermNode tn2=(TermNode)gn2.getOwner();
626 if ((tn2.getType()==TermNode.CONSEQUENCE)||
627 (tn2.getType()==TermNode.UPDATE)) {
634 System.out.println(gn.getTextLabel());
637 } else if (tn.getType()==TermNode.ABSTRACT) {
638 boolean foundnode=false;
639 for (Iterator edgeit=gn.edges();edgeit.hasNext();) {
640 GraphNode.Edge edge=(GraphNode.Edge)edgeit.next();
641 GraphNode gn2=edge.getTarget();
642 if (!removed.contains(gn2)) {
643 TermNode tn2=(TermNode)gn2.getOwner();
644 if (tn2.getType()==TermNode.UPDATE) {
652 } else throw new Error("Unanticipated Node");
656 /* This method checks that all constraints have conjunction nodes
657 and that there are no bad cycles in the abstract portion of the graph.
659 public int checkAbstract(Collection removed) {
660 Vector constraints=termination.state.vConstraints;
661 for(int i=0;i<constraints.size();i++) {
662 Constraint c=(Constraint)constraints.get(i);
663 Set conjunctionset=(Set)termination.conjunctionmap.get(c);
665 boolean foundrepair=false;
666 for(Iterator it=conjunctionset.iterator();it.hasNext();) {
667 GraphNode gn=(GraphNode)it.next();
668 if (!removed.contains(gn)) {
677 Set abstractnodes=new HashSet();
678 abstractnodes.addAll(termination.conjunctions);
679 abstractnodes.removeAll(removed);
680 GraphNode.computeclosure(abstractnodes,removed);
682 Set tset=new HashSet();
683 tset.addAll(termination.conjunctions);
684 tset.addAll(termination.abstractrepair);
685 tset.addAll(termination.scopenodes);
686 tset.addAll(termination.consequencenodes);
687 abstractnodes.retainAll(tset);
688 Set cycles=GraphNode.findcycles(abstractnodes);
690 for(Iterator it=cycles.iterator();it.hasNext();) {
691 GraphNode gn=(GraphNode)it.next();
692 System.out.println("NODE: "+gn.getTextLabel());
693 TermNode tn=(TermNode)gn.getOwner();
694 switch(tn.getType()) {
695 case TermNode.CONJUNCTION:
696 case TermNode.ABSTRACT:
698 case TermNode.UPDATE:
699 throw new Error("No Update Nodes should be here");