changes.
[IRC.git] / Robust / src / Analysis / SSJava / HierarchyGraph.java
index 02625d92ed469c44987e28f3292834835985a1de..852206af43b0a4377b7f3a40e10666dd82b6c05a 100644 (file)
@@ -17,19 +17,33 @@ public class HierarchyGraph {
   Descriptor desc;
 
   String name;
-  Map<Descriptor, HNode> mapDescToHNode;
-  Map<HNode, Set<Descriptor>> mapHNodeToDescSet;
+
+  // graph structure
   Map<HNode, Set<HNode>> mapHNodeToIncomingSet;
   Map<HNode, Set<HNode>> mapHNodeToOutgoingSet;
+
+  Map<Descriptor, HNode> mapDescToHNode;
+  Map<HNode, Set<Descriptor>> mapHNodeToDescSet;
+  Map<HNode, HNode> mapHNodeToCurrentHNode; // tracking which node corresponds to the initial node
+  Map<HNode, Set<HNode>> mapMergeNodetoMergingSet;
+
+  // data structures for a combination node
   Map<Set<HNode>, HNode> mapSkeletonNodeSetToCombinationNode;
   Map<HNode, Set<HNode>> mapCombinationNodeToCombineNodeSet;
   Map<Set<HNode>, HNode> mapCombineNodeSetToCombinationNode;
   Map<Set<HNode>, Set<HNode>> mapCombineNodeSetToOutgoingNodeSet;
 
+  Map<HNode, String> mapHNodeToLocationName;
+
   Set<HNode> nodeSet;
 
   public static int seed = 0;
 
+  // for the lattice generation
+  Map<HNode, Integer> mapHNodeToUniqueIndex;
+  Map<HNode, Set<Integer>> mapHNodeToBasis;
+  Set<Integer> BASISTOPELEMENT;
+
   public HierarchyGraph() {
     mapHNodeToIncomingSet = new HashMap<HNode, Set<HNode>>();
     mapHNodeToOutgoingSet = new HashMap<HNode, Set<HNode>>();
@@ -40,6 +54,15 @@ public class HierarchyGraph {
     mapCombineNodeSetToOutgoingNodeSet = new HashMap<Set<HNode>, Set<HNode>>();
     mapCombineNodeSetToCombinationNode = new HashMap<Set<HNode>, HNode>();
     nodeSet = new HashSet<HNode>();
+
+    mapHNodeToUniqueIndex = new HashMap<HNode, Integer>();
+    mapHNodeToBasis = new HashMap<HNode, Set<Integer>>();
+
+    mapHNodeToLocationName = new HashMap<HNode, String>();
+    mapMergeNodetoMergingSet = new HashMap<HNode, Set<HNode>>();
+
+    mapHNodeToCurrentHNode = new HashMap<HNode, HNode>();
+
   }
 
   public Descriptor getDesc() {
@@ -50,6 +73,14 @@ public class HierarchyGraph {
     this.desc = desc;
   }
 
+  public void addMapHNodeToLocationName(HNode node, String locName) {
+    mapHNodeToLocationName.put(node, locName);
+  }
+
+  public String getLocationName(HNode node) {
+    return mapHNodeToLocationName.get(node);
+  }
+
   public String getName() {
     return name;
   }
@@ -72,6 +103,14 @@ public class HierarchyGraph {
     mapHNodeToDescSet.putAll(map);
   }
 
+  public Map<HNode, HNode> getMapHNodeToCurrentHNode() {
+    return mapHNodeToCurrentHNode;
+  }
+
+  public void setMapHNodeToCurrentHNode(Map<HNode, HNode> mapHNodeToCurrentHNode) {
+    this.mapHNodeToCurrentHNode = mapHNodeToCurrentHNode;
+  }
+
   public Map<Descriptor, HNode> getMapDescToHNode() {
     return mapDescToHNode;
   }
@@ -96,14 +135,21 @@ public class HierarchyGraph {
 
     Set<HNode> possibleCycleSet = getPossibleCycleNodes(srcHNode, dstHNode);
 
-    System.out.println("src=" + srcHNode + " dstHNode=" + dstHNode + " possibleCycleSet="
-        + possibleCycleSet);
-
     if (possibleCycleSet.size() > 0) {
+
+      if (possibleCycleSet.size() == 1) {
+        if (dstHNode.isSharedNode()) {
+          // it has already been assigned shared node.
+        } else {
+          dstHNode.setSharedNode(true);
+        }
+        return;
+      }
+
       HNode newMergeNode = mergeNodes(possibleCycleSet, false);
       newMergeNode.setSharedNode(true);
-      System.out.println("### CYCLIC VALUE FLOW: " + srcHNode + " -> " + dstHNode);
       System.out.println("### INTRODUCE A NEW MERGE NODE: " + newMergeNode);
+      System.out.println("### CYCLIC VALUE FLOW: " + srcHNode + " -> " + dstHNode);
     } else {
       getIncomingNodeSet(dstHNode).add(srcHNode);
       getOutgoingNodeSet(srcHNode).add(dstHNode);
@@ -140,6 +186,16 @@ public class HierarchyGraph {
     return mapDescToHNode.get(d);
   }
 
+  public HNode getHNode(String name) {
+    for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
+      HNode node = (HNode) iterator.next();
+      if (node.getName().equals(name)) {
+        return node;
+      }
+    }
+    return null;
+  }
+
   private void mappingDescriptorToHNode(Descriptor desc, HNode node) {
     mapDescToHNode.put(desc, node);
     if (!mapHNodeToDescSet.containsKey(node)) {
@@ -171,6 +227,8 @@ public class HierarchyGraph {
 
     skeletonGraph.setMapDescToHNode(getMapDescToHNode());
     skeletonGraph.setMapHNodeToDescSet(getMapHNodeToDescSet());
+    skeletonGraph.setMapHNodetoMergeSet(getMapHNodetoMergeSet());
+    skeletonGraph.setMapHNodeToCurrentHNode(getMapHNodeToCurrentHNode());
 
     return skeletonGraph;
 
@@ -185,7 +243,7 @@ public class HierarchyGraph {
     return connected;
   }
 
-  private void removeRedundantEdges() {
+  public void removeRedundantEdges() {
 
     for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
       HNode src = (HNode) iterator.next();
@@ -226,7 +284,7 @@ public class HierarchyGraph {
     combineRedundantNodes(true);
   }
 
-  private void combineRedundantNodes(boolean onlyCombinationNodes) {
+  public void combineRedundantNodes(boolean onlyCombinationNodes) {
     // Combine field/parameter nodes who have the same set of incoming/outgoing edges.
     boolean isUpdated = false;
     do {
@@ -234,14 +292,14 @@ public class HierarchyGraph {
     } while (isUpdated);
   }
 
-  private Set<HNode> getIncomingNodeSet(HNode node) {
+  public Set<HNode> getIncomingNodeSet(HNode node) {
     if (!mapHNodeToIncomingSet.containsKey(node)) {
       mapHNodeToIncomingSet.put(node, new HashSet<HNode>());
     }
     return mapHNodeToIncomingSet.get(node);
   }
 
-  private Set<HNode> getOutgoingNodeSet(HNode node) {
+  public Set<HNode> getOutgoingNodeSet(HNode node) {
     if (!mapHNodeToOutgoingSet.containsKey(node)) {
       mapHNodeToOutgoingSet.put(node, new HashSet<HNode>());
     }
@@ -309,12 +367,15 @@ public class HierarchyGraph {
     }
 
     String nodeName;
+    boolean isMergeNode = false;
     if (onlyCombinationNodes) {
       nodeName = "Comb" + (seed++);
     } else {
       nodeName = "Node" + (seed++);
+      isMergeNode = true;
     }
     HNode newMergeNode = new HNode(nodeName);
+    newMergeNode.setMergeNode(isMergeNode);
 
     nodeSet.add(newMergeNode);
     nodeSet.removeAll(set);
@@ -328,6 +389,8 @@ public class HierarchyGraph {
         break;
       }
     }
+    System.out.println("--Set merging node=" + newMergeNode + " as a skeleton=" + set
+        + " hasSkeleton=" + hasSkeleton);
     newMergeNode.setSkeleton(hasSkeleton);
 
     for (Iterator iterator = set.iterator(); iterator.hasNext();) {
@@ -357,10 +420,56 @@ public class HierarchyGraph {
       }
     }
 
-    System.out.println("#MERGING NODE=" + set + " new node=" + newMergeNode);
+    Set<HNode> mergedSkeletonNode = new HashSet<HNode>();
+    for (Iterator<HNode> iter = set.iterator(); iter.hasNext();) {
+      HNode merged = iter.next();
+      if (merged.isSkeleton()) {
+        mergedSkeletonNode.add(merged);
+      }
+    }
+    mapMergeNodetoMergingSet.put(newMergeNode, mergedSkeletonNode);
+    for (Iterator iterator = mergedSkeletonNode.iterator(); iterator.hasNext();) {
+      HNode mergedNode = (HNode) iterator.next();
+      addMapHNodeToCurrentHNode(mergedNode, newMergeNode);
+    }
+
+    System.out.println("###MERGING NODE=" + set + " new node=" + newMergeNode);
     return newMergeNode;
   }
 
+  private void addMapHNodeToCurrentHNode(HNode curNode, HNode newNode) {
+    if (curNode.isMergeNode()) {
+      Set<HNode> mergingSet = getMergingSet(curNode);
+      for (Iterator iterator = mergingSet.iterator(); iterator.hasNext();) {
+        HNode mergingNode = (HNode) iterator.next();
+        mapHNodeToCurrentHNode.put(mergingNode, newNode);
+      }
+    } else {
+      mapHNodeToCurrentHNode.put(curNode, newNode);
+    }
+  }
+
+  public HNode getCurrentHNode(HNode node) {
+    if (!mapHNodeToCurrentHNode.containsKey(node)) {
+      mapHNodeToCurrentHNode.put(node, node);
+    }
+    return mapHNodeToCurrentHNode.get(node);
+  }
+
+  private Set<HNode> getMergingSet(HNode mergeNode) {
+    Set<HNode> mergingSet = new HashSet<HNode>();
+    Set<HNode> mergedNode = mapMergeNodetoMergingSet.get(mergeNode);
+    for (Iterator iterator = mergedNode.iterator(); iterator.hasNext();) {
+      HNode node = (HNode) iterator.next();
+      if (node.isMergeNode()) {
+        mergingSet.addAll(getMergingSet(node));
+      } else {
+        mergingSet.add(node);
+      }
+    }
+    return mergingSet;
+  }
+
   private Set<Descriptor> getDescSetOfNode(HNode node) {
     if (!mapHNodeToDescSet.containsKey(node)) {
       mapHNodeToDescSet.put(node, new HashSet<Descriptor>());
@@ -401,6 +510,69 @@ public class HierarchyGraph {
 
   }
 
+  public Set<HNode> getDirectlyReachableSkeletonCombinationNodeFrom(HNode node,
+      Set<HNode> combinationNodeSet) {
+    Set<HNode> reachable = new HashSet<HNode>();
+    Set<HNode> visited = new HashSet<HNode>();
+    visited.add(node);
+    recurDirectlyReachableSkeletonCombinationNodeFrom(node, visited, reachable, combinationNodeSet);
+    return reachable;
+  }
+
+  public void recurDirectlyReachableSkeletonCombinationNodeFrom(HNode node, Set<HNode> visited,
+      Set<HNode> reachable, Set<HNode> combinationNodeSet) {
+
+    Set<HNode> outSet = getOutgoingNodeSet(node);
+    for (Iterator iterator = outSet.iterator(); iterator.hasNext();) {
+      HNode out = (HNode) iterator.next();
+
+      if (!visited.contains(out)) {
+        visited.add(out);
+        if (out.isSkeleton()) {
+          reachable.add(out);
+        } else if (out.isCombinationNode()) {
+          if (combinationNodeSet == null) {
+            reachable.add(out);
+          } else if (!combinationNodeSet.contains(out)) {
+            reachable.add(out);
+          } else {
+            recurDirectlyReachableSkeletonCombinationNodeFrom(out, visited, reachable,
+                combinationNodeSet);
+          }
+        } else {
+          recurDirectlyReachableSkeletonCombinationNodeFrom(out, visited, reachable,
+              combinationNodeSet);
+        }
+
+      }
+
+    }
+
+  }
+
+  public HNode getDirectlyReachableSkeletonCombinationNodeFrom(HNode node) {
+    Set<HNode> visited = new HashSet<HNode>();
+    return recurDirectlyReachableSkeletonCombinationNodeFrom(node, visited);
+  }
+
+  public HNode recurDirectlyReachableSkeletonCombinationNodeFrom(HNode node, Set<HNode> visited) {
+
+    Set<HNode> outSet = getOutgoingNodeSet(node);
+    for (Iterator iterator = outSet.iterator(); iterator.hasNext();) {
+      HNode out = (HNode) iterator.next();
+      // if (!visited.contains(out)) {
+      if (out.isCombinationNode() || out.isSkeleton()) {
+        return out;
+      } else {
+        // visited.add(out);
+        return getDirectlyReachableSkeletonCombinationNodeFrom(out);
+      }
+    }
+    // }
+
+    return null;
+  }
+
   public Set<HNode> getPossibleCycleNodes(HNode src, HNode dst) {
     // if an edge from src to dst introduces a new cycle flow,
     // the method returns the set of elements consisting of the cycle
@@ -440,7 +612,7 @@ public class HierarchyGraph {
     return mapCombinationNodeToCombineNodeSet.get(node);
   }
 
-  private HNode getCombinationNode(Set<HNode> combineSet) {
+  public HNode getCombinationNode(Set<HNode> combineSet) {
     if (!mapCombineNodeSetToCombinationNode.containsKey(combineSet)) {
       String name = "COMB" + (seed++);
       HNode node = new HNode(name);
@@ -453,42 +625,58 @@ public class HierarchyGraph {
     return mapCombineNodeSetToCombinationNode.get(combineSet);
   }
 
+  public Map<Set<HNode>, HNode> getMapCombineNodeSetToCombinationNode() {
+    return mapCombineNodeSetToCombinationNode;
+  }
+
   public Set<Set<HNode>> getCombineNodeSet() {
     return mapCombineNodeSetToOutgoingNodeSet.keySet();
   }
 
-  public void insertCombinationNodesToGraph(HierarchyGraph hierarchyGraph) {
+  public void insertCombinationNodesToGraph(HierarchyGraph simpleHierarchyGraph) {
     // add a new combination node where parameter/field flows are actually combined.
 
-    hierarchyGraph.identifyCombinationNodes();
+    simpleHierarchyGraph.identifyCombinationNodes();
 
-    Set<Set<HNode>> keySet = hierarchyGraph.getCombineNodeSet();
+    Set<Set<HNode>> keySet = simpleHierarchyGraph.getCombineNodeSet();
     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
       Set<HNode> combineSet = (Set<HNode>) iterator.next();
-      System.out.println("combineSet=" + combineSet);
+      System.out.println("--combineSet=" + combineSet);
       HNode combinationNode = getCombinationNode(combineSet);
-
+      System.out.println("--combinationNode=" + combinationNode);
       // add an edge from a skeleton node to a combination node
       for (Iterator iterator2 = combineSet.iterator(); iterator2.hasNext();) {
         HNode inSkeletonNode = (HNode) iterator2.next();
-        HNode srcNode = getHNode(inSkeletonNode.getDescriptor());
-        System.out.println("inSkeletonNode=" + inSkeletonNode + "   srcNode=" + srcNode);
+        // System.out.println("--inSkeletonNode=" + inSkeletonNode + "  desc="
+        // + inSkeletonNode.getDescriptor());
+        HNode srcNode;
+        if (inSkeletonNode.getDescriptor() == null) {
+          // the node is merging one...
+          srcNode = inSkeletonNode;
+        } else {
+          srcNode = getHNode(inSkeletonNode.getDescriptor());
+        }
+        // System.out.println("--srcNode=" + srcNode);
         addEdgeWithNoCycleCheck(srcNode, combinationNode);
       }
 
       // add an edge from the combination node to outgoing nodes
-      Set<HNode> outSet = hierarchyGraph.getOutgoingNodeSetByCombineSet(combineSet);
+      Set<HNode> outSet = simpleHierarchyGraph.getOutgoingNodeSetByCombineSet(combineSet);
       for (Iterator iterator2 = outSet.iterator(); iterator2.hasNext();) {
         HNode curNode = (HNode) iterator2.next();
         if (curNode.isCombinationNode()) {
-          Set<HNode> combineNode = hierarchyGraph.getCombineSetByCombinationNode(curNode);
+          Set<HNode> combineNode = simpleHierarchyGraph.getCombineSetByCombinationNode(curNode);
           HNode outNode = getCombinationNode(combineNode);
           addEdgeWithNoCycleCheck(combinationNode, outNode);
         } else if (curNode.isSkeleton()) {
-          addEdgeWithNoCycleCheck(combinationNode, curNode);
+          // HNode dstNode = getHNode(curNode.getDescriptor());
+          HNode dstNode = getCurrentHNode(curNode);
+          addEdgeWithNoCycleCheck(combinationNode, dstNode);
         }
       }
 
+      System.out.println("--");
+
     }
 
   }
@@ -522,12 +710,33 @@ public class HierarchyGraph {
 
     Set<HNode> reachToSet = new HashSet<HNode>();
     Set<HNode> visited = new HashSet<HNode>();
-
     recurSkeletonReachTo(node, reachToSet, visited);
 
+    // if a node reaches to one of elements in the reachToSet, we do not need to keep it
+    // because the node is not directly connected to the combination node
+
+    removeRedundantReachToNodes(reachToSet);
+
     return reachToSet;
   }
 
+  private void removeRedundantReachToNodes(Set<HNode> reachToSet) {
+
+    Set<HNode> toberemoved = new HashSet<HNode>();
+    for (Iterator iterator = reachToSet.iterator(); iterator.hasNext();) {
+      HNode cur = (HNode) iterator.next();
+
+      for (Iterator iterator2 = reachToSet.iterator(); iterator2.hasNext();) {
+        HNode dst = (HNode) iterator2.next();
+        if (!cur.equals(dst) && reachTo(cur, dst)) {
+          // it is redundant
+          toberemoved.add(cur);
+        }
+      }
+    }
+    reachToSet.removeAll(toberemoved);
+  }
+
   private void recurSkeletonReachTo(HNode node, Set<HNode> reachToSet, Set<HNode> visited) {
 
     Set<HNode> inSet = getIncomingNodeSet(node);
@@ -590,10 +799,19 @@ public class HierarchyGraph {
     clone.setMapHNodeToOutgoingSet(getMapHNodeToOutgoingSet());
     clone.setMapDescToHNode(getMapDescToHNode());
     clone.setMapHNodeToDescSet(getMapHNodeToDescSet());
-
+    clone.setMapHNodetoMergeSet(getMapHNodetoMergeSet());
+    clone.setMapHNodeToCurrentHNode(getMapHNodeToCurrentHNode());
     return clone;
   }
 
+  public Map<HNode, Set<HNode>> getMapHNodetoMergeSet() {
+    return mapMergeNodetoMergingSet;
+  }
+
+  public void setMapHNodetoMergeSet(Map<HNode, Set<HNode>> mapHNodetoMergeSet) {
+    this.mapMergeNodetoMergingSet = mapHNodetoMergeSet;
+  }
+
   public Set<HNode> getOutgoingNodeSetByCombineSet(Set<HNode> combineSet) {
 
     if (!mapCombineNodeSetToOutgoingNodeSet.containsKey(combineSet)) {
@@ -610,6 +828,9 @@ public class HierarchyGraph {
       if (!node.isSkeleton()) {
         Set<HNode> reachToSet = getSkeleteNodeSetReachTo(node);
         if (reachToSet.size() > 1) {
+          // if (countSkeletonNodes(reachToSet) > 1) {
+          System.out.println("-node=" + node + "  reachToSet=" + reachToSet);
+          System.out.println("-set combinationnode=" + node);
           node.setCombinationNode(true);
           mapCombinationNodeToCombineNodeSet.put(node, reachToSet);
         }
@@ -628,6 +849,22 @@ public class HierarchyGraph {
 
   }
 
+  public Map<HNode, Set<HNode>> getMapCombinationNodeToCombineNodeSet() {
+    return mapCombinationNodeToCombineNodeSet;
+  }
+
+  public int countSkeletonNodes(Set<HNode> set) {
+    int count = 0;
+
+    for (Iterator iterator = set.iterator(); iterator.hasNext();) {
+      HNode node = (HNode) iterator.next();
+      Set<Descriptor> descSet = getDescSetOfNode(node);
+      count += descSet.size();
+    }
+
+    return count;
+  }
+
   private void addMapCombineSetToOutgoingSet(Set<HNode> combineSet, Set<HNode> outSet) {
     if (!mapCombineNodeSetToOutgoingNodeSet.containsKey(combineSet)) {
       mapCombineNodeSetToOutgoingNodeSet.put(combineSet, new HashSet<HNode>());
@@ -671,6 +908,115 @@ public class HierarchyGraph {
 
   }
 
+  private Set<HNode> getReachableNodeSetFrom(HNode node) {
+
+    Set<HNode> reachableSet = new HashSet<HNode>();
+    Set<HNode> visited = new HashSet<HNode>();
+
+    recurReachableNodeSetFrom(node, reachableSet, visited);
+
+    return reachableSet;
+  }
+
+  private void recurReachableNodeSetFrom(HNode node, Set<HNode> reachableSet, Set<HNode> visited) {
+
+    Set<HNode> outgoingNodeSet = getOutgoingNodeSet(node);
+    for (Iterator iterator = outgoingNodeSet.iterator(); iterator.hasNext();) {
+      HNode outNode = (HNode) iterator.next();
+      reachableSet.add(outNode);
+      if (!visited.contains(outNode)) {
+        visited.add(outNode);
+        recurReachableNodeSetFrom(outNode, reachableSet, visited);
+      }
+    }
+
+  }
+
+  public void assignUniqueIndexToNode() {
+    int idx = 1;
+    for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
+      HNode node = (HNode) iterator.next();
+      mapHNodeToUniqueIndex.put(node, idx);
+      idx++;
+    }
+
+    BASISTOPELEMENT = new HashSet<Integer>();
+    for (int i = 1; i < idx + 1; i++) {
+      BASISTOPELEMENT.add(i);
+    }
+  }
+
+  public BasisSet computeBasisSet() {
+
+    // assign a unique index to a node
+    assignUniqueIndexToNode();
+
+    // compute basis for each node
+    for (Iterator iterator = nodeSet.iterator(); iterator.hasNext();) {
+      HNode node = (HNode) iterator.next();
+
+      Set<Integer> basis = new HashSet<Integer>();
+      basis.addAll(BASISTOPELEMENT);
+
+      Set<HNode> reachableNodeSet = getReachableNodeSetFrom(node);
+      System.out.println("node=" + node + "    reachableNodeSet=" + reachableNodeSet);
+
+      // if a node is reachable from the current node
+      // need to remove the index of the reachable node from the basis
+
+      basis.remove(getHNodeIndex(node));
+      for (Iterator iterator2 = reachableNodeSet.iterator(); iterator2.hasNext();) {
+        HNode reachableNode = (HNode) iterator2.next();
+        System.out.println("reachableNode=" + reachableNode);
+        int idx = getHNodeIndex(reachableNode);
+        basis.remove(idx);
+      }
+
+      mapHNodeToBasis.put(node, basis);
+    }
+
+    // construct the basis set
+
+    BasisSet basisSet = new BasisSet();
+
+    Set<HNode> keySet = mapHNodeToBasis.keySet();
+    for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
+      HNode node = (HNode) iterator.next();
+      Set<Integer> basis = mapHNodeToBasis.get(node);
+      basisSet.addElement(basis, node);
+    }
+
+    return basisSet;
+
+  }
+
+  public int getHNodeIndex(HNode node) {
+    return mapHNodeToUniqueIndex.get(node).intValue();
+  }
+
+  public Map<HNode, Integer> getMapHNodeToUniqueIndex() {
+    return mapHNodeToUniqueIndex;
+  }
+
+  public Map<HNode, Set<Integer>> getMapHNodeToBasis() {
+    return mapHNodeToBasis;
+  }
+
+  public Set<HNode> getCombinationNodeSetByCombineNodeSet(Set<HNode> combineSkeletonNodeSet) {
+
+    Set<HNode> combinationNodeSet = new HashSet<HNode>();
+    Set<HNode> keySet = mapCombinationNodeToCombineNodeSet.keySet();
+    for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
+      HNode key = (HNode) iterator.next();
+
+      if (mapCombinationNodeToCombineNodeSet.get(key).equals(combineSkeletonNodeSet)) {
+        combinationNodeSet.add(key);
+      }
+    }
+
+    return combinationNodeSet;
+  }
+
   public void writeGraph() {
 
     String graphName = "hierarchy" + name;
@@ -720,12 +1066,36 @@ public class HierarchyGraph {
     }
   }
 
-  private void drawNode(BufferedWriter bw, HNode node) throws IOException {
-    String shared = "";
-    if (node.isSharedNode()) {
-      shared = "*";
+  public boolean contains(HNode node) {
+    return nodeSet.contains(node);
+  }
+
+  public boolean isDirectlyConnectedTo(HNode src, HNode dst) {
+    return getOutgoingNodeSet(src).contains(dst);
+  }
+
+  private String convertMergeSetToString(Set<HNode> mergeSet) {
+    String str = "";
+    for (Iterator iterator = mergeSet.iterator(); iterator.hasNext();) {
+      HNode merged = (HNode) iterator.next();
+      if (merged.isMergeNode()) {
+        str += " " + convertMergeSetToString(mapMergeNodetoMergingSet.get(merged));
+      } else {
+        str += " " + merged.getName();
+      }
     }
-    bw.write(node.getName() + " [label=\"" + node.getName() + shared + "\"]" + ";\n");
+    return str;
   }
 
+  private void drawNode(BufferedWriter bw, HNode node) throws IOException {
+    String nodeName;
+    if (node.isMergeNode()) {
+      nodeName = node.getNamePropertyString();
+      Set<HNode> mergeSet = mapMergeNodetoMergingSet.get(node);
+      nodeName += ":" + convertMergeSetToString(mergeSet);
+    } else {
+      nodeName = node.getNamePropertyString();
+    }
+    bw.write(node.getName() + " [label=\"" + nodeName + "\"]" + ";\n");
+  }
 }