Преглед на файлове

Implemented new algorithm for individual names that are suffix-free #194

Rene Beckmann преди 9 години
родител
ревизия
dfdb9c1e01
променени са 1 файла, в които са добавени 89 реда и са изтрити 40 реда
  1. 89 40
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/TreeNamingService.xtend

+ 89 - 40
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/TreeNamingService.xtend

@@ -320,61 +320,110 @@ class TreeNamingService implements INamingService {
 	
 	def private Map<StringTreeNode, ArrayList<StringTreeNode>> constructIndividualNames()
 	{
-		val HashMap<StringTreeNode, ArrayList<StringTreeNode>> mapping = newHashMap;
-		
 		val nodes = tree.getEndNodes().sortWith(stringTreeNodeDepthComparator);
 		
 		val names = new ArrayList<String>();
+		
+		/*
+		 * The map doublets is a three dimensional construct.
+		 * For each end-node-name in the tree, it holds a list of lists describing that name.
+		 * The outer list contains instances representing the same name, and the inner lists hold 
+		 * the current set of nodes that is needed to make the name individual.
+		 * 
+		 * Consider the following simple tree:
+		 * main_region-StateA
+		 * main_region-StateB
+		 * second_region-StateA
+		 * 
+		 * After the initial phase, the map then contains the following:
+		 * {"StateA": [[node(StateA)], [node(StateA)]], "StateB": [[node(StateB)]]}
+		 * 
+		 * The iteration consists of two phases then.
+		 * In Phase 1, all inner lists are extended with the first element's parent - as long as there is more than one list.
+		 * This leads to the following:
+		 * {"StateA": [[node(main_region), node(StateA)], [node(second_region), node(StateA)]], "StateB": [[node(StateB)]]}
+		 * in Phase 2, the map is then resorted with the new names:
+		 * {
+		 * 	"main_region_StateA": [[node(main_region), node(StateA)]],
+		 * 	"second_region_StateA": [[node(second_region), node(StateA)]],
+		 * 	"StateB": [[node(StateB)]] 
+		 * }
+		 * 
+		 * As we can see, all outer lists have exactly length 1, which is the abortion criteria.
+		 * 
+		 * In the finalization phase, we check if there are any weird things happening like randomly created double names.
+		 * For example, someone could create a state named "region_StateA" and two other elements named "region" and "StateA" could
+		 * be clumped together to form an individual name.
+		 * 
+		 */
+		var doublets = new HashMap<String, ArrayList<ArrayList<StringTreeNode>>>();
+		
+		val mapping = new HashMap<StringTreeNode, ArrayList<StringTreeNode>>();
+		
+		// Initialization
 		for(node : nodes)
 		{
-			var individualNameFound = false;
-			
-			var currentNode = node.getParent(); // actual end node only contains empty string
-			var name = currentNode.getData();
-			
-			val nodelist = new ArrayList<StringTreeNode>();
-			
-			mapping.put(node, nodelist); // 'nodelist' is filled further down
-			
-			nodelist.add(currentNode);
-			nodelist.add(node);
+			if(!doublets.containsKey(node.data)) {
+				doublets.put(node.data, new ArrayList<ArrayList<StringTreeNode>>());
+			}
+			val list = new ArrayList<StringTreeNode>();
+			doublets.get(node.data).add(list);
+			mapping.put(node, list);
+			list.add(node);
+		}
+		
+		var abort = false;
+		// Iteration
+		while(!abort)
+		{
+			// Phase 1
+			for(name : doublets.keySet)
+			{
+				if(doublets.get(name).length > 1)
+				{
+					for(nodelist : doublets.get(name))
+					{
+						nodelist.add(0, nodelist.get(0).parent);
+					}
+				}
+			}
 			
-			/*
-			 * elements that point to this node, because we need to check if
-			 * it's a step. In that case, we want to prepend one more node,
-			 * so that - for example - "lr0" becomes "StateA_lr0".
-			 */
-			val loop_nodeElements = getNodeElements(node);
+			// Phase 2
+			val newDoublets = new HashMap<String, ArrayList<ArrayList<StringTreeNode>>>();
 			
-			var isStep = false;
-			for(elem : loop_nodeElements)
+			for(name : doublets.keySet) // for all keys
 			{
-				if(elem instanceof Step) {
-					isStep = true;
+				for(nodelist : doublets.get(name)) // for inner lists
+				{
+					val sb = new StringBuilder();
+					
+					for(var i=0; i<nodelist.length;i++)
+					{
+						if(i != 0) {
+							sb.append(separator)
+						}
+						sb.append(nodelist.get(i).getData())
+					}
+					
+					if(!newDoublets.containsKey(sb.toString)) {
+						newDoublets.put(sb.toString, new ArrayList<ArrayList<StringTreeNode>>());
+					}
+					
+					newDoublets.get(sb.toString).add(nodelist);
 				}
 			}
-			if(isStep) {
-				// if this NamedElement is a step, it has a name like "tr0" or "lr0". That's not very descriptive,
-				// so it's prepended with the name of the parent element, like for example "StateA".
-				currentNode = currentNode.getParent();
-				name = currentNode.getData() + separator + name;
-				nodelist.add(0, currentNode);
-			}
 			
-			while(!individualNameFound)
+			doublets = newDoublets;
+			
+			// Abort criterion
+			abort = true;
+			for(name : doublets.keySet)
 			{
-				// prepend further parent elements (walk tree upwards) until an individual name is found.
-				if(!names.contains(name)) {
-					individualNameFound = true;
-					names.add(name);
-				} else {
-					currentNode = currentNode.getParent();
-					name = currentNode.getData() + separator + name;
-					nodelist.add(0, currentNode);
-				}
+				if(doublets.get(name).length > 1) abort = false;
 			}
 		}
 		
+		
 		return mapping;
 	}