1 package Analysis.SSJava;
3 import java.io.BufferedWriter;
4 import java.io.FileWriter;
5 import java.io.IOException;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.Iterator;
13 import IR.FieldDescriptor;
14 import IR.VarDescriptor;
16 public class HierarchyGraph {
23 Map<HNode, Set<HNode>> mapHNodeToIncomingSet;
24 Map<HNode, Set<HNode>> mapHNodeToOutgoingSet;
26 Map<Descriptor, HNode> mapDescToHNode;
27 Map<HNode, Set<Descriptor>> mapHNodeToDescSet;
28 Map<HNode, HNode> mapHNodeToCurrentHNode; // tracking which node corresponds to the initial node
29 Map<HNode, Set<HNode>> mapMergeNodetoMergingSet;
31 // data structures for a combination node
32 Map<Set<HNode>, HNode> mapSkeletonNodeSetToCombinationNode;
33 Map<HNode, Set<HNode>> mapCombinationNodeToCombineNodeSet;
34 Map<Set<HNode>, HNode> mapCombineNodeSetToCombinationNode;
35 Map<Set<HNode>, Set<HNode>> mapCombineNodeSetToOutgoingNodeSet;
39 public static int seed = 0;
41 // for the lattice generation
42 Map<HNode, Integer> mapHNodeToUniqueIndex;
43 Map<HNode, Set<Integer>> mapHNodeToBasis;
44 Set<Integer> BASISTOPELEMENT;
46 public HierarchyGraph() {
47 mapHNodeToIncomingSet = new HashMap<HNode, Set<HNode>>();
48 mapHNodeToOutgoingSet = new HashMap<HNode, Set<HNode>>();
49 mapHNodeToDescSet = new HashMap<HNode, Set<Descriptor>>();
50 mapDescToHNode = new HashMap<Descriptor, HNode>();
51 mapSkeletonNodeSetToCombinationNode = new HashMap<Set<HNode>, HNode>();
52 mapCombinationNodeToCombineNodeSet = new HashMap<HNode, Set<HNode>>();
53 mapCombineNodeSetToOutgoingNodeSet = new HashMap<Set<HNode>, Set<HNode>>();
54 mapCombineNodeSetToCombinationNode = new HashMap<Set<HNode>, HNode>();
55 nodeSet = new HashSet<HNode>();
57 mapHNodeToUniqueIndex = new HashMap<HNode, Integer>();
58 mapHNodeToBasis = new HashMap<HNode, Set<Integer>>();
60 mapMergeNodetoMergingSet = new HashMap<HNode, Set<HNode>>();
62 mapHNodeToCurrentHNode = new HashMap<HNode, HNode>();
66 public Descriptor getDesc() {
70 public void setDesc(Descriptor desc) {
74 public String getName() {
78 public void setName(String name) {
82 public HierarchyGraph(Descriptor d) {
88 public Map<HNode, Set<Descriptor>> getMapHNodeToDescSet() {
89 return mapHNodeToDescSet;
92 public void setMapHNodeToDescSet(Map<HNode, Set<Descriptor>> map) {
93 mapHNodeToDescSet.putAll(map);
96 public Map<HNode, HNode> getMapHNodeToCurrentHNode() {
97 return mapHNodeToCurrentHNode;
100 public void setMapHNodeToCurrentHNode(Map<HNode, HNode> mapHNodeToCurrentHNode) {
101 this.mapHNodeToCurrentHNode = mapHNodeToCurrentHNode;
104 public Map<Descriptor, HNode> getMapDescToHNode() {
105 return mapDescToHNode;
108 public void setMapDescToHNode(Map<Descriptor, HNode> map) {
109 mapDescToHNode.putAll(map);
112 public Set<HNode> getNodeSet() {
116 public void addEdge(HNode srcHNode, HNode dstHNode) {
118 if (!nodeSet.contains(srcHNode)) {
119 nodeSet.add(srcHNode);
122 if (!nodeSet.contains(dstHNode)) {
123 nodeSet.add(dstHNode);
126 Set<HNode> possibleCycleSet = getPossibleCycleNodes(srcHNode, dstHNode);
128 if (possibleCycleSet.size() > 0) {
130 if (possibleCycleSet.size() == 1) {
131 if (dstHNode.isSharedNode()) {
132 // it has already been assigned shared node.
134 dstHNode.setSharedNode(true);
139 HNode newMergeNode = mergeNodes(possibleCycleSet, false);
140 newMergeNode.setSharedNode(true);
141 System.out.println("### INTRODUCE A NEW MERGE NODE: " + newMergeNode);
142 System.out.println("### CYCLIC VALUE FLOW: " + srcHNode + " -> " + dstHNode);
144 getIncomingNodeSet(dstHNode).add(srcHNode);
145 getOutgoingNodeSet(srcHNode).add(dstHNode);
146 System.out.println("add an edge " + srcHNode + " -> " + dstHNode);
151 public void addNode(HNode node) {
155 public void addEdge(Descriptor src, Descriptor dst) {
156 HNode srcHNode = getHNode(src);
157 HNode dstHNode = getHNode(dst);
159 addEdge(srcHNode, dstHNode);
163 public void setParamHNode(Descriptor d) {
164 getHNode(d).setSkeleton(true);
167 public HNode getHNode(Descriptor d) {
168 if (!mapDescToHNode.containsKey(d)) {
169 HNode newNode = new HNode(d);
170 if (d instanceof FieldDescriptor) {
171 newNode.setSkeleton(true);
173 mappingDescriptorToHNode(d, newNode);
174 nodeSet.add(newNode);
176 return mapDescToHNode.get(d);
179 public HNode getHNode(String name) {
180 for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
181 HNode node = (HNode) iterator.next();
182 if (node.getName().equals(name)) {
189 private void mappingDescriptorToHNode(Descriptor desc, HNode node) {
190 mapDescToHNode.put(desc, node);
191 if (!mapHNodeToDescSet.containsKey(node)) {
192 mapHNodeToDescSet.put(node, new HashSet<Descriptor>());
194 mapHNodeToDescSet.get(node).add(desc);
197 public HierarchyGraph generateSkeletonGraph() {
199 // compose a skeleton graph that only consists of fields or parameters
200 HierarchyGraph skeletonGraph = new HierarchyGraph(desc);
201 skeletonGraph.setName(desc + "_SKELETON");
203 for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
204 HNode src = (HNode) iterator.next();
205 if (src.isSkeleton()) {
206 Set<HNode> reachSet = getDirectlyReachSkeletonSet(src);
207 if (reachSet.size() > 0) {
208 for (Iterator iterator2 = reachSet.iterator(); iterator2.hasNext();) {
209 HNode dst = (HNode) iterator2.next();
210 skeletonGraph.addEdge(src, dst);
213 skeletonGraph.addNode(src);
218 skeletonGraph.setMapDescToHNode(getMapDescToHNode());
219 skeletonGraph.setMapHNodeToDescSet(getMapHNodeToDescSet());
220 skeletonGraph.setMapHNodetoMergeSet(getMapHNodetoMergeSet());
221 skeletonGraph.setMapHNodeToCurrentHNode(getMapHNodeToCurrentHNode());
223 return skeletonGraph;
227 private Set<HNode> getDirectlyReachSkeletonSet(HNode node) {
229 Set<HNode> visited = new HashSet<HNode>();
230 Set<HNode> connected = new HashSet<HNode>();
231 recurReachSkeletonSet(node, connected, visited);
236 public void removeRedundantEdges() {
238 for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
239 HNode src = (HNode) iterator.next();
240 Set<HNode> connectedSet = getOutgoingNodeSet(src);
241 Set<HNode> toberemovedSet = new HashSet<HNode>();
242 for (Iterator iterator2 = connectedSet.iterator(); iterator2.hasNext();) {
243 HNode dst = (HNode) iterator2.next();
244 Set<HNode> otherNeighborSet = new HashSet<HNode>();
245 otherNeighborSet.addAll(connectedSet);
246 otherNeighborSet.remove(dst);
247 for (Iterator iterator3 = otherNeighborSet.iterator(); iterator3.hasNext();) {
248 HNode neighbor = (HNode) iterator3.next();
249 if (reachTo(neighbor, dst, new HashSet<HNode>())) {
250 toberemovedSet.add(dst);
254 if (toberemovedSet.size() > 0) {
255 connectedSet.removeAll(toberemovedSet);
257 for (Iterator iterator2 = toberemovedSet.iterator(); iterator2.hasNext();) {
258 HNode node = (HNode) iterator2.next();
259 getIncomingNodeSet(node).remove(src);
267 public void simplifyHierarchyGraph() {
268 removeRedundantEdges();
269 combineRedundantNodes(false);
272 public void simplifySkeletonCombinationHierarchyGraph() {
273 removeRedundantEdges();
274 combineRedundantNodes(true);
277 public void combineRedundantNodes(boolean onlyCombinationNodes) {
278 // Combine field/parameter nodes who have the same set of incoming/outgoing edges.
279 boolean isUpdated = false;
281 isUpdated = combineTwoRedundatnNodes(onlyCombinationNodes);
285 public Set<HNode> getIncomingNodeSet(HNode node) {
286 if (!mapHNodeToIncomingSet.containsKey(node)) {
287 mapHNodeToIncomingSet.put(node, new HashSet<HNode>());
289 return mapHNodeToIncomingSet.get(node);
292 public Set<HNode> getOutgoingNodeSet(HNode node) {
293 if (!mapHNodeToOutgoingSet.containsKey(node)) {
294 mapHNodeToOutgoingSet.put(node, new HashSet<HNode>());
296 return mapHNodeToOutgoingSet.get(node);
299 private boolean combineTwoRedundatnNodes(boolean onlyCombinationNodes) {
300 for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
301 HNode node1 = (HNode) iterator.next();
303 if ((onlyCombinationNodes && (!node1.isCombinationNode()))
304 || (!onlyCombinationNodes && (!node1.isSkeleton()))) {
308 Set<HNode> incomingNodeSet1 = getIncomingNodeSet(node1);
309 Set<HNode> outgoingNodeSet1 = getOutgoingNodeSet(node1);
311 for (Iterator iterator2 = nodeSet.iterator(); iterator2.hasNext();) {
312 HNode node2 = (HNode) iterator2.next();
314 if ((onlyCombinationNodes && (!node2.isCombinationNode()))
315 || (!onlyCombinationNodes && (!node2.isSkeleton()))) {
319 if (!isEligibleForMerging(node1, node2)) {
323 if (!node1.equals(node2)) {
325 Set<HNode> incomingNodeSet2 = getIncomingNodeSet(node2);
326 Set<HNode> outgoingNodeSet2 = getOutgoingNodeSet(node2);
328 if (incomingNodeSet1.equals(incomingNodeSet2)
329 && outgoingNodeSet1.equals(outgoingNodeSet2)) {
330 // need to merge node1 and node2
332 Set<HNode> mergeSet = new HashSet<HNode>();
335 mergeNodes(mergeSet, onlyCombinationNodes);
346 private boolean isEligibleForMerging(HNode node1, HNode node2) {
348 System.out.println("********isEligibleForMerging=" + node1 + " " + node2);
350 if (node1.isSharedNode() || node2.isSharedNode()) {
352 // if either of nodes is a shared node,
353 // all descriptors of node1 & node2 should have a primitive type
355 Set<Descriptor> descSet = new HashSet<Descriptor>();
356 descSet.addAll(getDescSetOfNode(node1));
357 descSet.addAll(getDescSetOfNode(node2));
359 for (Iterator iterator = descSet.iterator(); iterator.hasNext();) {
360 Descriptor desc = (Descriptor) iterator.next();
361 if (!isPrimitive(desc)) {
365 System.out.println("******** true");
371 private boolean isPrimitive(Descriptor desc) {
373 if (desc instanceof FieldDescriptor) {
374 return ((FieldDescriptor) desc).getType().isPrimitive();
375 } else if (desc instanceof VarDescriptor) {
376 return ((VarDescriptor) desc).getType().isPrimitive();
377 } else if (desc instanceof InterDescriptor) {
384 private void addEdgeWithNoCycleCheck(HNode srcHNode, HNode dstHNode) {
385 getIncomingNodeSet(dstHNode).add(srcHNode);
386 getOutgoingNodeSet(srcHNode).add(dstHNode);
387 System.out.println("addEdgeWithNoCycleCheck src=" + srcHNode + " -> " + dstHNode);
390 private HNode mergeNodes(Set<HNode> set, boolean onlyCombinationNodes) {
392 Set<HNode> incomingNodeSet = new HashSet<HNode>();
393 Set<HNode> outgoingNodeSet = new HashSet<HNode>();
395 for (Iterator iterator = set.iterator(); iterator.hasNext();) {
396 HNode node = (HNode) iterator.next();
397 incomingNodeSet.addAll(getIncomingNodeSet(node));
398 outgoingNodeSet.addAll(getOutgoingNodeSet(node));
402 boolean isMergeNode = false;
403 if (onlyCombinationNodes) {
404 nodeName = "Comb" + (seed++);
406 nodeName = "Node" + (seed++);
409 HNode newMergeNode = new HNode(nodeName);
410 newMergeNode.setMergeNode(isMergeNode);
412 nodeSet.add(newMergeNode);
413 nodeSet.removeAll(set);
415 // if the input set contains a skeleton node, need to set a new merge node as skeleton also
416 boolean hasSkeleton = false;
417 for (Iterator iterator = set.iterator(); iterator.hasNext();) {
418 HNode inNode = (HNode) iterator.next();
419 if (inNode.isSkeleton()) {
424 System.out.println("--Set merging node=" + newMergeNode + " as a skeleton=" + set
425 + " hasSkeleton=" + hasSkeleton);
426 newMergeNode.setSkeleton(hasSkeleton);
428 for (Iterator iterator = set.iterator(); iterator.hasNext();) {
429 HNode node = (HNode) iterator.next();
430 Set<Descriptor> descSetOfNode = getDescSetOfNode(node);
431 for (Iterator iterator2 = descSetOfNode.iterator(); iterator2.hasNext();) {
432 Descriptor desc = (Descriptor) iterator2.next();
433 mappingDescriptorToHNode(desc, newMergeNode);
437 for (Iterator iterator = incomingNodeSet.iterator(); iterator.hasNext();) {
438 HNode inNode = (HNode) iterator.next();
439 Set<HNode> outSet = getOutgoingNodeSet(inNode);
440 outSet.removeAll(set);
441 if (!set.contains(inNode)) {
442 addEdgeWithNoCycleCheck(inNode, newMergeNode);
446 for (Iterator iterator = outgoingNodeSet.iterator(); iterator.hasNext();) {
447 HNode outNode = (HNode) iterator.next();
448 Set<HNode> inSet = getIncomingNodeSet(outNode);
449 inSet.removeAll(set);
450 if (!set.contains(outNode)) {
451 addEdgeWithNoCycleCheck(newMergeNode, outNode);
455 Set<HNode> mergedSkeletonNode = new HashSet<HNode>();
456 for (Iterator<HNode> iter = set.iterator(); iter.hasNext();) {
457 HNode merged = iter.next();
458 if (merged.isSkeleton()) {
459 mergedSkeletonNode.add(merged);
462 mapMergeNodetoMergingSet.put(newMergeNode, mergedSkeletonNode);
463 for (Iterator iterator = mergedSkeletonNode.iterator(); iterator.hasNext();) {
464 HNode mergedNode = (HNode) iterator.next();
465 addMapHNodeToCurrentHNode(mergedNode, newMergeNode);
467 System.out.println("\n###mergedSkeletonNode=" + mergedSkeletonNode);
468 System.out.println("###MERGING NODE=" + set + " new node=" + newMergeNode);
470 for (Iterator iterator = set.iterator(); iterator.hasNext();) {
471 HNode hNode = (HNode) iterator.next();
472 System.out.println("old=" + hNode + "----->newNode=" + getCurrentHNode(hNode));
478 private void addMapHNodeToCurrentHNode(HNode curNode, HNode newNode) {
479 if (curNode.isMergeNode()) {
480 Set<HNode> mergingSet = getMergingSet(curNode);
481 mergingSet.add(curNode);
482 System.out.println("addMapHNodeToCurrentHNode curNode=" + curNode + " meringSet="
484 for (Iterator iterator = mergingSet.iterator(); iterator.hasNext();) {
485 HNode mergingNode = (HNode) iterator.next();
486 mapHNodeToCurrentHNode.put(mergingNode, newNode);
489 mapHNodeToCurrentHNode.put(curNode, newNode);
493 public HNode getCurrentHNode(HNode node) {
494 if (!mapHNodeToCurrentHNode.containsKey(node)) {
495 mapHNodeToCurrentHNode.put(node, node);
497 return mapHNodeToCurrentHNode.get(node);
500 private Set<HNode> getMergingSet(HNode mergeNode) {
501 Set<HNode> mergingSet = new HashSet<HNode>();
502 Set<HNode> mergedNode = mapMergeNodetoMergingSet.get(mergeNode);
503 for (Iterator iterator = mergedNode.iterator(); iterator.hasNext();) {
504 HNode node = (HNode) iterator.next();
505 if (node.isMergeNode()) {
506 mergingSet.add(node);
507 mergingSet.addAll(getMergingSet(node));
509 mergingSet.add(node);
515 public Set<Descriptor> getDescSetOfNode(HNode node) {
516 if (!mapHNodeToDescSet.containsKey(node)) {
517 mapHNodeToDescSet.put(node, new HashSet<Descriptor>());
519 return mapHNodeToDescSet.get(node);
522 private boolean reachTo(HNode src, HNode dst, Set<HNode> visited) {
523 Set<HNode> connectedSet = getOutgoingNodeSet(src);
524 for (Iterator<HNode> iterator = connectedSet.iterator(); iterator.hasNext();) {
525 HNode n = iterator.next();
529 if (!visited.contains(n)) {
531 if (reachTo(n, dst, visited)) {
539 private void recurReachSkeletonSet(HNode node, Set<HNode> connected, Set<HNode> visited) {
541 Set<HNode> outSet = getOutgoingNodeSet(node);
542 for (Iterator iterator = outSet.iterator(); iterator.hasNext();) {
543 HNode outNode = (HNode) iterator.next();
545 if (outNode.isSkeleton()) {
546 connected.add(outNode);
547 } else if (!visited.contains(outNode)) {
548 visited.add(outNode);
549 recurReachSkeletonSet(outNode, connected, visited);
555 public Set<HNode> getDirectlyReachableSkeletonCombinationNodeFrom(HNode node,
556 Set<HNode> combinationNodeSet) {
557 Set<HNode> reachable = new HashSet<HNode>();
558 Set<HNode> visited = new HashSet<HNode>();
560 recurDirectlyReachableSkeletonCombinationNodeFrom(node, visited, reachable, combinationNodeSet);
564 public void recurDirectlyReachableSkeletonCombinationNodeFrom(HNode node, Set<HNode> visited,
565 Set<HNode> reachable, Set<HNode> combinationNodeSet) {
567 Set<HNode> outSet = getOutgoingNodeSet(node);
568 for (Iterator iterator = outSet.iterator(); iterator.hasNext();) {
569 HNode out = (HNode) iterator.next();
571 if (!visited.contains(out)) {
573 if (out.isSkeleton()) {
575 } else if (out.isCombinationNode()) {
576 if (combinationNodeSet == null) {
578 } else if (!combinationNodeSet.contains(out)) {
581 recurDirectlyReachableSkeletonCombinationNodeFrom(out, visited, reachable,
585 recurDirectlyReachableSkeletonCombinationNodeFrom(out, visited, reachable,
595 public HNode getDirectlyReachableSkeletonCombinationNodeFrom(HNode node) {
596 Set<HNode> visited = new HashSet<HNode>();
597 return recurDirectlyReachableSkeletonCombinationNodeFrom(node, visited);
600 public HNode recurDirectlyReachableSkeletonCombinationNodeFrom(HNode node, Set<HNode> visited) {
602 Set<HNode> outSet = getOutgoingNodeSet(node);
603 for (Iterator iterator = outSet.iterator(); iterator.hasNext();) {
604 HNode out = (HNode) iterator.next();
605 // if (!visited.contains(out)) {
606 if (out.isCombinationNode() || out.isSkeleton()) {
610 return getDirectlyReachableSkeletonCombinationNodeFrom(out);
618 public Set<HNode> getPossibleCycleNodes(HNode src, HNode dst) {
619 // if an edge from src to dst introduces a new cycle flow,
620 // the method returns the set of elements consisting of the cycle
621 Set<HNode> cycleNodeSet = new HashSet<HNode>();
622 // if the dst node reaches to the src node, the new relation
623 // introduces a cycle to the lattice
624 if (dst.equals(src)) {
625 cycleNodeSet.add(dst);
626 cycleNodeSet.add(src);
627 } else if (reachTo(dst, src)) {
628 cycleNodeSet.add(dst);
629 cycleNodeSet.add(src);
630 getInBetweenElements(dst, src, cycleNodeSet);
635 private void getInBetweenElements(HNode start, HNode end, Set<HNode> nodeSet) {
636 Set<HNode> connectedSet = getOutgoingNodeSet(start);
637 for (Iterator iterator = connectedSet.iterator(); iterator.hasNext();) {
638 HNode cur = (HNode) iterator.next();
639 if ((!start.equals(cur)) && (!cur.equals(end)) && reachTo(cur, end)) {
641 getInBetweenElements(cur, end, nodeSet);
646 public boolean reachTo(HNode node1, HNode node2) {
647 return reachTo(node1, node2, new HashSet<HNode>());
650 public Set<HNode> getCombineSetByCombinationNode(HNode node) {
651 if (!mapCombinationNodeToCombineNodeSet.containsKey(node)) {
652 mapCombinationNodeToCombineNodeSet.put(node, new HashSet<HNode>());
654 return mapCombinationNodeToCombineNodeSet.get(node);
657 public HNode getCombinationNode(Set<HNode> combineSet) {
658 if (!mapCombineNodeSetToCombinationNode.containsKey(combineSet)) {
659 String name = "COMB" + (seed++);
660 HNode node = new HNode(name);
661 node.setCombinationNode(true);
663 mapCombineNodeSetToCombinationNode.put(combineSet, node);
664 mapCombinationNodeToCombineNodeSet.put(node, combineSet);
667 return mapCombineNodeSetToCombinationNode.get(combineSet);
670 public Map<Set<HNode>, HNode> getMapCombineNodeSetToCombinationNode() {
671 return mapCombineNodeSetToCombinationNode;
674 public Set<Set<HNode>> getCombineNodeSet() {
675 return mapCombineNodeSetToOutgoingNodeSet.keySet();
678 public void insertCombinationNodesToGraph(HierarchyGraph simpleHierarchyGraph) {
679 // add a new combination node where parameter/field flows are actually combined.
681 simpleHierarchyGraph.identifyCombinationNodes();
683 Set<Set<HNode>> keySet = simpleHierarchyGraph.getCombineNodeSet();
684 for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
685 Set<HNode> combineSet = (Set<HNode>) iterator.next();
686 System.out.println("--combineSet=" + combineSet);
687 HNode combinationNode = getCombinationNode(combineSet);
688 System.out.println("--combinationNode=" + combinationNode);
689 // add an edge from a skeleton node to a combination node
690 for (Iterator iterator2 = combineSet.iterator(); iterator2.hasNext();) {
691 HNode inSkeletonNode = (HNode) iterator2.next();
692 // System.out.println("--inSkeletonNode=" + inSkeletonNode + " desc="
693 // + inSkeletonNode.getDescriptor());
695 if (inSkeletonNode.getDescriptor() == null) {
696 // the node is merging one...
697 srcNode = inSkeletonNode;
699 srcNode = getHNode(inSkeletonNode.getDescriptor());
701 // System.out.println("--srcNode=" + srcNode);
702 addEdgeWithNoCycleCheck(srcNode, combinationNode);
705 // add an edge from the combination node to outgoing nodes
706 Set<HNode> outSet = simpleHierarchyGraph.getOutgoingNodeSetByCombineSet(combineSet);
707 for (Iterator iterator2 = outSet.iterator(); iterator2.hasNext();) {
708 HNode curNode = (HNode) iterator2.next();
709 if (curNode.isCombinationNode()) {
710 Set<HNode> combineNode = simpleHierarchyGraph.getCombineSetByCombinationNode(curNode);
711 HNode outNode = getCombinationNode(combineNode);
712 addEdgeWithNoCycleCheck(combinationNode, outNode);
713 } else if (curNode.isSkeleton()) {
714 // HNode dstNode2 = getHNode(curNode.getDescriptor());
715 HNode dstNode = getCurrentHNode(curNode);
716 // System.out.println("-----curNode=" + curNode + "------->" + dstNode + " dstNode2="
718 addEdgeWithNoCycleCheck(combinationNode, dstNode);
722 System.out.println("--");
728 private void addCombinationNode(HNode curNode, Set<HNode> reachToSet, Set<HNode> reachableSet) {
729 if (!mapSkeletonNodeSetToCombinationNode.containsKey(reachToSet)) {
730 // need to create a new combination node
731 String nodeName = "Comb" + (seed++);
732 HNode newCombinationNode = new HNode(nodeName);
733 newCombinationNode.setCombinationNode(true);
735 nodeSet.add(newCombinationNode);
736 mapSkeletonNodeSetToCombinationNode.put(reachToSet, newCombinationNode);
738 for (Iterator iterator = reachToSet.iterator(); iterator.hasNext();) {
739 HNode reachToNode = (HNode) iterator.next();
740 addEdge(reachToNode, newCombinationNode);
745 HNode combinationNode = mapSkeletonNodeSetToCombinationNode.get(reachToSet);
746 for (Iterator iterator = reachableSet.iterator(); iterator.hasNext();) {
747 HNode reachableNode = (HNode) iterator.next();
748 addEdge(combinationNode, reachableNode);
753 private Set<HNode> getSkeleteNodeSetReachTo(HNode node) {
755 Set<HNode> reachToSet = new HashSet<HNode>();
756 Set<HNode> visited = new HashSet<HNode>();
757 recurSkeletonReachTo(node, reachToSet, visited);
759 // if a node reaches to one of elements in the reachToSet, we do not need to keep it
760 // because the node is not directly connected to the combination node
762 removeRedundantReachToNodes(reachToSet);
767 private void removeRedundantReachToNodes(Set<HNode> reachToSet) {
769 Set<HNode> toberemoved = new HashSet<HNode>();
770 for (Iterator iterator = reachToSet.iterator(); iterator.hasNext();) {
771 HNode cur = (HNode) iterator.next();
773 for (Iterator iterator2 = reachToSet.iterator(); iterator2.hasNext();) {
774 HNode dst = (HNode) iterator2.next();
775 if (!cur.equals(dst) && reachTo(cur, dst)) {
777 toberemoved.add(cur);
781 reachToSet.removeAll(toberemoved);
784 private void recurSkeletonReachTo(HNode node, Set<HNode> reachToSet, Set<HNode> visited) {
786 Set<HNode> inSet = getIncomingNodeSet(node);
787 for (Iterator iterator = inSet.iterator(); iterator.hasNext();) {
788 HNode inNode = (HNode) iterator.next();
790 if (inNode.isSkeleton()) {
791 reachToSet.add(inNode);
792 } else if (!visited.contains(inNode)) {
794 recurSkeletonReachTo(inNode, reachToSet, visited);
800 public Map<HNode, Set<HNode>> getMapHNodeToOutgoingSet() {
801 return mapHNodeToOutgoingSet;
804 public Map<HNode, Set<HNode>> getMapHNodeToIncomingSet() {
805 return mapHNodeToIncomingSet;
808 public void setMapHNodeToOutgoingSet(Map<HNode, Set<HNode>> in) {
809 mapHNodeToOutgoingSet.clear();
810 Set<HNode> keySet = in.keySet();
811 for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
812 HNode key = (HNode) iterator.next();
813 Set<HNode> inSet = in.get(key);
814 Set<HNode> newSet = new HashSet<HNode>();
815 newSet.addAll(inSet);
816 mapHNodeToOutgoingSet.put(key, newSet);
820 public void setMapHNodeToIncomingSet(Map<HNode, Set<HNode>> in) {
821 mapHNodeToIncomingSet.clear();
822 Set<HNode> keySet = in.keySet();
823 for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
824 HNode key = (HNode) iterator.next();
825 Set<HNode> inSet = in.get(key);
826 Set<HNode> newSet = new HashSet<HNode>();
827 newSet.addAll(inSet);
828 mapHNodeToIncomingSet.put(key, newSet);
832 public void setNodeSet(Set<HNode> inSet) {
834 nodeSet.addAll(inSet);
837 public HierarchyGraph clone() {
838 HierarchyGraph clone = new HierarchyGraph();
839 clone.setDesc(getDesc());
840 clone.setName(getName());
841 clone.setNodeSet(getNodeSet());
842 clone.setMapHNodeToIncomingSet(getMapHNodeToIncomingSet());
843 clone.setMapHNodeToOutgoingSet(getMapHNodeToOutgoingSet());
844 clone.setMapDescToHNode(getMapDescToHNode());
845 clone.setMapHNodeToDescSet(getMapHNodeToDescSet());
846 clone.setMapHNodetoMergeSet(getMapHNodetoMergeSet());
847 clone.setMapHNodeToCurrentHNode(getMapHNodeToCurrentHNode());
851 public Map<HNode, Set<HNode>> getMapHNodetoMergeSet() {
852 return mapMergeNodetoMergingSet;
855 public void setMapHNodetoMergeSet(Map<HNode, Set<HNode>> mapHNodetoMergeSet) {
856 this.mapMergeNodetoMergingSet = mapHNodetoMergeSet;
859 public Set<HNode> getOutgoingNodeSetByCombineSet(Set<HNode> combineSet) {
861 if (!mapCombineNodeSetToOutgoingNodeSet.containsKey(combineSet)) {
862 mapCombineNodeSetToOutgoingNodeSet.put(combineSet, new HashSet<HNode>());
864 return mapCombineNodeSetToOutgoingNodeSet.get(combineSet);
867 public void identifyCombinationNodes() {
869 // 1) set combination node flag if a node combines more than one skeleton node.
870 for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
871 HNode node = (HNode) iterator.next();
872 if (!node.isSkeleton()) {
873 Set<HNode> reachToSet = getSkeleteNodeSetReachTo(node);
874 if (reachToSet.size() > 1) {
875 // if (countSkeletonNodes(reachToSet) > 1) {
876 System.out.println("-node=" + node + " reachToSet=" + reachToSet);
877 System.out.println("-set combinationnode=" + node);
878 node.setCombinationNode(true);
879 mapCombinationNodeToCombineNodeSet.put(node, reachToSet);
884 // 2) compute the outgoing set that needs to be directly connected from the combination node
885 for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
886 HNode node = (HNode) iterator.next();
887 if (node.isCombinationNode()) {
888 Set<HNode> combineSet = mapCombinationNodeToCombineNodeSet.get(node);
889 Set<HNode> outSet = getDirectlyReachableNodeSetFromCombinationNode(node);
890 addMapCombineSetToOutgoingSet(combineSet, outSet);
896 public Map<HNode, Set<HNode>> getMapCombinationNodeToCombineNodeSet() {
897 return mapCombinationNodeToCombineNodeSet;
900 public int countSkeletonNodes(Set<HNode> set) {
903 for (Iterator iterator = set.iterator(); iterator.hasNext();) {
904 HNode node = (HNode) iterator.next();
905 Set<Descriptor> descSet = getDescSetOfNode(node);
906 count += descSet.size();
912 private void addMapCombineSetToOutgoingSet(Set<HNode> combineSet, Set<HNode> outSet) {
913 if (!mapCombineNodeSetToOutgoingNodeSet.containsKey(combineSet)) {
914 mapCombineNodeSetToOutgoingNodeSet.put(combineSet, new HashSet<HNode>());
916 mapCombineNodeSetToOutgoingNodeSet.get(combineSet).addAll(outSet);
919 private Set<HNode> getDirectlyReachableNodeSetFromCombinationNode(HNode node) {
920 // the method returns the set of nodes that are reachable from the current node
921 // and do not combine the same set of skeleton nodes...
923 Set<HNode> visited = new HashSet<HNode>();
924 Set<HNode> reachableSet = new HashSet<HNode>();
925 Set<HNode> combineSet = mapCombinationNodeToCombineNodeSet.get(node);
927 recurDirectlyReachableNodeSetFromCombinationNode(node, combineSet, reachableSet, visited);
932 private void recurDirectlyReachableNodeSetFromCombinationNode(HNode node, Set<HNode> combineSet,
933 Set<HNode> reachableSet, Set<HNode> visited) {
935 Set<HNode> outSet = getOutgoingNodeSet(node);
936 for (Iterator iterator = outSet.iterator(); iterator.hasNext();) {
937 HNode outNode = (HNode) iterator.next();
939 if (outNode.isCombinationNode()) {
940 Set<HNode> combineSetOfOutNode = mapCombinationNodeToCombineNodeSet.get(outNode);
941 if (combineSetOfOutNode.equals(combineSet)) {
942 recurDirectlyReachableNodeSetFromCombinationNode(outNode, combineSet, reachableSet,
945 reachableSet.add(outNode);
947 } else if (outNode.isSkeleton()) {
948 reachableSet.add(outNode);
955 private Set<HNode> getReachableNodeSetFrom(HNode node) {
957 Set<HNode> reachableSet = new HashSet<HNode>();
958 Set<HNode> visited = new HashSet<HNode>();
960 recurReachableNodeSetFrom(node, reachableSet, visited);
965 private void recurReachableNodeSetFrom(HNode node, Set<HNode> reachableSet, Set<HNode> visited) {
967 Set<HNode> outgoingNodeSet = getOutgoingNodeSet(node);
968 for (Iterator iterator = outgoingNodeSet.iterator(); iterator.hasNext();) {
969 HNode outNode = (HNode) iterator.next();
970 reachableSet.add(outNode);
971 if (!visited.contains(outNode)) {
972 visited.add(outNode);
973 recurReachableNodeSetFrom(outNode, reachableSet, visited);
979 public void assignUniqueIndexToNode() {
981 System.out.println("nodeSet=" + nodeSet);
982 for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
983 HNode node = (HNode) iterator.next();
984 mapHNodeToUniqueIndex.put(node, idx);
988 BASISTOPELEMENT = new HashSet<Integer>();
989 for (int i = 1; i < idx + 1; i++) {
990 BASISTOPELEMENT.add(i);
994 public BasisSet computeBasisSet() {
996 // assign a unique index to a node
997 assignUniqueIndexToNode();
999 // compute basis for each node
1000 for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
1001 HNode node = (HNode) iterator.next();
1003 Set<Integer> basis = new HashSet<Integer>();
1004 basis.addAll(BASISTOPELEMENT);
1006 Set<HNode> reachableNodeSet = getReachableNodeSetFrom(node);
1007 System.out.println("node=" + node + " reachableNodeSet=" + reachableNodeSet);
1008 System.out.println("mapHNodeToUniqueIndex.get(node)=" + mapHNodeToUniqueIndex.get(node));
1009 // if a node is reachable from the current node
1010 // need to remove the index of the reachable node from the basis
1012 basis.remove(getHNodeIndex(node));
1013 for (Iterator iterator2 = reachableNodeSet.iterator(); iterator2.hasNext();) {
1014 HNode reachableNode = (HNode) iterator2.next();
1015 System.out.println("reachableNode=" + reachableNode);
1016 System.out.println("getHNodeIndex(reachableNode))="
1017 + mapHNodeToUniqueIndex.get(reachableNode));
1018 int idx = getHNodeIndex(reachableNode);
1022 mapHNodeToBasis.put(node, basis);
1025 // construct the basis set
1027 BasisSet basisSet = new BasisSet();
1029 Set<HNode> keySet = mapHNodeToBasis.keySet();
1030 for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
1031 HNode node = (HNode) iterator.next();
1032 Set<Integer> basis = mapHNodeToBasis.get(node);
1033 basisSet.addElement(basis, node);
1040 public int getHNodeIndex(HNode node) {
1041 return mapHNodeToUniqueIndex.get(node).intValue();
1044 public Map<HNode, Integer> getMapHNodeToUniqueIndex() {
1045 return mapHNodeToUniqueIndex;
1048 public Map<HNode, Set<Integer>> getMapHNodeToBasis() {
1049 return mapHNodeToBasis;
1052 public Set<HNode> getCombinationNodeSetByCombineNodeSet(Set<HNode> combineSkeletonNodeSet) {
1054 Set<HNode> combinationNodeSet = new HashSet<HNode>();
1055 Set<HNode> keySet = mapCombinationNodeToCombineNodeSet.keySet();
1056 for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
1057 HNode key = (HNode) iterator.next();
1059 if (mapCombinationNodeToCombineNodeSet.get(key).equals(combineSkeletonNodeSet)) {
1060 combinationNodeSet.add(key);
1064 return combinationNodeSet;
1067 public void writeGraph() {
1069 String graphName = "hierarchy" + name;
1070 graphName = graphName.replaceAll("[\\W]", "");
1073 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName + ".dot"));
1075 bw.write("digraph " + graphName + " {\n");
1077 Iterator<HNode> iter = nodeSet.iterator();
1079 Set<HNode> addedNodeSet = new HashSet<HNode>();
1081 while (iter.hasNext()) {
1082 HNode u = iter.next();
1084 Set<HNode> outSet = getOutgoingNodeSet(u);
1086 if (outSet.size() == 0) {
1087 if (!addedNodeSet.contains(u)) {
1089 addedNodeSet.add(u);
1092 for (Iterator iterator = outSet.iterator(); iterator.hasNext();) {
1093 HNode v = (HNode) iterator.next();
1094 if (!addedNodeSet.contains(u)) {
1096 addedNodeSet.add(u);
1098 if (!addedNodeSet.contains(v)) {
1100 addedNodeSet.add(v);
1102 bw.write("" + u.getName() + " -> " + v.getName() + ";\n");
1111 } catch (IOException e) {
1112 e.printStackTrace();
1116 public boolean contains(HNode node) {
1117 return nodeSet.contains(node);
1120 public boolean isDirectlyConnectedTo(HNode src, HNode dst) {
1121 return getOutgoingNodeSet(src).contains(dst);
1124 private String convertMergeSetToString(Set<HNode> mergeSet) {
1126 for (Iterator iterator = mergeSet.iterator(); iterator.hasNext();) {
1127 HNode merged = (HNode) iterator.next();
1128 if (merged.isMergeNode()) {
1129 str += " " + convertMergeSetToString(mapMergeNodetoMergingSet.get(merged));
1131 str += " " + merged.getName();
1137 private void drawNode(BufferedWriter bw, HNode node) throws IOException {
1139 if (node.isMergeNode()) {
1140 nodeName = node.getNamePropertyString();
1141 Set<HNode> mergeSet = mapMergeNodetoMergingSet.get(node);
1142 nodeName += ":" + convertMergeSetToString(mergeSet);
1144 nodeName = node.getNamePropertyString();
1146 bw.write(node.getName() + " [label=\"" + nodeName + "\"]" + ";\n");
1149 public int countHopFromTopLocation(HNode node) {
1151 Set<HNode> inNodeSet = getIncomingNodeSet(node);
1153 if (inNodeSet.size() > 0) {
1154 count = recurCountHopFromTopLocation(inNodeSet, 1);
1160 private int recurCountHopFromTopLocation(Set<HNode> nodeSet, int curCount) {
1163 for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
1164 HNode node = (HNode) iterator.next();
1165 Set<HNode> inNodeSet = getIncomingNodeSet(node);
1166 if (inNodeSet.size() > 0) {
1167 int recurCount = recurCountHopFromTopLocation(inNodeSet, curCount + 1);
1168 if (max < recurCount) {