René Beckmann 7 роки тому
батько
коміт
361b3bbc03

+ 24 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/IStringShortener.java

@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2018 committers of YAKINDU and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * Contributors:
+ * 	rbeckmann - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.model.sexec.naming;
+
+import java.util.List;
+
+/**
+ * @author rbeckmann
+ *
+ */
+public interface IStringShortener {
+	public void setMaxLength(int length);
+	public StorageToken addString(List<String> s);
+	
+	public String getString(StorageToken token);
+}

+ 4 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/ShortString.xtend

@@ -71,6 +71,10 @@ class ShortString {
 			cutArray.set(i, previous_cutArray.get(i));
 		}
 	}
+	
+	override toString() {
+		shortenedString
+	}
 
 	def public String getShortenedString() {
 		// return the current version of the shortened string according to cutArray

+ 28 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/StorageToken.java

@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2018 committers of YAKINDU and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * Contributors:
+ * 	rbeckmann - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.model.sexec.naming;
+
+/**
+ * @author rbeckmann
+ *
+ * Objects that are created when a string is inserted into the StringShortener, so that whoever
+ * put the (long) string into it can get the (short) string back later - like a wardrobe.
+ */
+public class StorageToken {
+	protected static long tokenID = 0;
+	
+	protected long myID;
+	
+	public StorageToken() {
+		myID = tokenID;
+		tokenID += 1;
+	}
+}

+ 0 - 103
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/TreeNamingService.xtend

@@ -275,109 +275,6 @@ class TreeNamingService implements INamingService {
 		return name;
 	}
 
-	def protected Map<StringTreeNode, ArrayList<StringTreeNode>> constructIndividualNames() {
-		/*
-		 * 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 now have exactly length 1, which is the abortion criterion.
-		 * 
-		 * 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.
-		 * 
-		 */
-		 
-		// get all end-nodes, that is "ends of strings" added to the tree.
-		val nodes = tree.getEndNodes().sortWith(stringTreeNodeDepthComparator);
-		var doublets = new HashMap<String, ArrayList<ArrayList<StringTreeNode>>>();
-		val mapping = new HashMap<StringTreeNode, ArrayList<StringTreeNode>>();
-
-		// Initialization
-		for (node : nodes) {
-			if (!doublets.containsKey(node.data)) {
-				doublets.put(node.data, new ArrayList<ArrayList<StringTreeNode>>());
-			}
-			val list = new ArrayList<StringTreeNode>();
-			// add new inner list that will hold the nodes going to the end node forming the individual name
-			doublets.get(node.data).add(list);
-			// map this list to the end node. We'll return this map later, but we need to fill the lists first
-			mapping.put(node, list);
-			list.add(node);
-		}
-
-		var abort = false;
-		// Iteration
-		while (!abort) {
-			// Phase 1
-			for (name : doublets.keySet) {
-				// check outer list. If it contains more than one list, there is more than one element with the same name.
-				if (doublets.get(name).length > 1) {
-					// if that is the case, add one parent node to all inner node lists.
-					for (nodelist : doublets.get(name)) {
-						nodelist.add(0, nodelist.get(0).parent);
-					}
-				}
-			}
-
-			// Phase 2
-			val newDoublets = new HashMap<String, ArrayList<ArrayList<StringTreeNode>>>();
-
-			for (name : doublets.keySet) // for all keys
-			{
-				for (nodelist : doublets.get(name)) // for inner lists in outer lists - returned by doublets.get(name)
-				{
-					// construct names formed by inner lists, now possibly extended by one node
-					val sb = new StringBuilder();
-
-					for (var i = 0; i < nodelist.length; i++) {
-						if (i != 0) {
-							sb.append(separator)
-						}
-						sb.append(nodelist.get(i).getData())
-					}
-					// add string to new map if it doesn't exist already
-					if (!newDoublets.containsKey(sb.toString)) {
-						newDoublets.put(sb.toString, new ArrayList<ArrayList<StringTreeNode>>());
-					}
-
-					newDoublets.get(sb.toString).add(nodelist);
-				}
-			}
-
-			doublets = newDoublets;
-
-			// Abort criterion. If there is any name with more than one element, repeat.
-			abort = true;
-			for (name : doublets.keySet) {
-				if(doublets.get(name).length > 1) abort = false;
-			}
-		}
-
-		return mapping;
-	}
-
 	def protected shortenNames() {
 		if (individualMap === null || individualMap.isEmpty()) {
 			constructIndividualNames();

+ 264 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/TreeStringShortener.xtend

@@ -0,0 +1,264 @@
+/**
+ * Copyright (c) 2018 committers of YAKINDU and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * Contributors:
+ * 	rbeckmann - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.model.sexec.naming
+
+import java.util.ArrayList
+import java.util.HashMap
+import java.util.List
+import java.util.Map
+import org.eclipse.xtend.lib.annotations.Accessors
+
+/**
+ * @author rbeckmann
+ *
+ */
+class TreeStringShortener implements IStringShortener {
+	@Accessors(PUBLIC_SETTER) protected int maxLength = 0
+	
+	protected StringTreeNode tree
+	
+	protected boolean validState = false
+	
+	protected Map<StorageToken, String> result
+	protected Map<StorageToken, StringTreeNode> storage
+	protected Map<StorageToken, List<String>> originalStrings = newHashMap
+
+	override addString(List<String> s) {
+		validState = false
+		val token = new StorageToken()
+		originalStrings.put(token, s)
+		return token
+	}
+	
+	override getString(StorageToken token) {
+		if(!originalStrings.containsKey(token)) {
+			return null
+		}
+		
+		assertValidState()
+		
+		return result.get(token)
+	}
+	
+	def protected void assertValidState() {
+		if(!validState) {
+			if(maxLength == 0) {
+				result = newHashMap
+				originalStrings.keySet.forEach[token |
+					result.put(token, originalStrings.get(token).join)
+				]
+			} else {
+				buildTree()
+				shortenNames()
+			}
+			validState = true
+		}
+	}
+	
+	def protected buildTree() {
+		tree = new StringTreeNode
+		storage = newHashMap
+		
+		originalStrings.keySet.forEach [ token |
+			storage.put(token, tree.addStringList(originalStrings.get(token)))
+		]
+		
+		tree.compress()
+	}
+	
+	def protected shortenNames() {
+		val List<List<StringTreeNode>> nodes = newArrayList
+		val Map<StringTreeNode, List<StringTreeNode>> map = newHashMap
+		
+		for(node : tree.endNodes) {
+			val List<StringTreeNode> list = newArrayList
+			list.add(node)
+			nodes.add(list)
+			map.put(node, list)
+		}
+		
+		buildIndividualNames(nodes)
+		
+		val Map<StringTreeNode, List<ShortString>> shortStrings = newHashMap
+		
+		map.keySet.forEach[node |
+			shortStrings.put(node, newArrayList(map.get(node).map[new ShortString(it.data)]))
+		]
+		
+		val List<List<ShortString>> shortStringLists = newArrayList(shortStrings.values)
+		calculateShortNames(shortStringLists)
+		
+		storage.keySet.forEach[token |
+			result.put(
+				token,
+				shortStrings.get(storage.get(token)).map[it.shortenedString].join
+			)
+		]
+		
+	}
+	
+	def calculateShortNames(List<List<ShortString>> lists) {
+		while(getMaxLength(lists) > this.maxLength) {
+			
+		}
+	}
+	
+	def int getMaxLength(List<List<ShortString>> names) {
+		return names.map[innerList | innerList.map[getShortenedSize].reduce[a, b | a + b]].max
+	}
+	
+	def protected void buildIndividualNames(List<List<StringTreeNode>> nodes) {
+		val Map<String, List<List<StringTreeNode>>> map = newHashMap
+		
+		for(list : nodes) {
+			val name = toString(list)
+			
+			if(!map.containsKey(name)) {
+				map.put(name, newArrayList)
+			}
+			
+			map.get(name).add(list)
+		}
+		
+		var abort = true
+		for(list : map.values) {
+			if(list.size > 1) {
+				abort = false
+				for(nodeList : list) {
+					val parent = nodeList.get(0).parent
+					if(parent !== null) {
+						nodeList.add(0, parent)
+					}
+				}
+			}
+		}
+		
+		if(abort) {
+			return
+		}
+		
+		buildIndividualNames(nodes)
+		
+	}
+	
+	def protected String toString(List<StringTreeNode> list) {
+		val sb = new StringBuilder
+		
+		for(node : list) {
+			sb.append(node.data)
+		}
+		
+		sb.toString
+	}
+	
+	def protected Map<StringTreeNode, ArrayList<StringTreeNode>> constructIndividualNames() {
+		/*
+		 * 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 now have exactly length 1, which is the abortion criterion.
+		 * 
+		 * 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.
+		 * 
+		 */
+		 
+		// get all end-nodes, that is "ends of strings" added to the tree.
+		val nodes = tree.getEndNodes().sortWith(new StringTreeNodeDepthComparator);
+		var Map<String, ArrayList<ArrayList<StringTreeNode>>> doublets = newHashMap
+		val Map<StringTreeNode, ArrayList<StringTreeNode>> mapping = newHashMap
+
+		// Initialization
+		for (node : nodes) {
+			if (!doublets.containsKey(node.data)) {
+				doublets.put(node.data, new ArrayList<ArrayList<StringTreeNode>>());
+			}
+			val list = new ArrayList<StringTreeNode>();
+			// add new inner list that will hold the nodes going to the end node forming the individual name
+			doublets.get(node.data).add(list);
+			// map this list to the end node. We'll return this map later, but we need to fill the lists first
+			mapping.put(node, list);
+			list.add(node);
+		}
+
+		var abort = false;
+		// Iteration
+		while (!abort) {
+			// Phase 1
+			for (name : doublets.keySet) {
+				// check outer list. If it contains more than one list, there is more than one element with the same name.
+				if (doublets.get(name).length > 1) {
+					// if that is the case, add one parent node to all inner node lists.
+					for (nodelist : doublets.get(name)) {
+						nodelist.add(0, nodelist.get(0).parent);
+					}
+				}
+			}
+
+			// Phase 2
+			val newDoublets = new HashMap<String, ArrayList<ArrayList<StringTreeNode>>>();
+
+			for (name : doublets.keySet) // for all keys
+			{
+				for (nodelist : doublets.get(name)) // for inner lists in outer lists - returned by doublets.get(name)
+				{
+					// construct names formed by inner lists, now possibly extended by one node
+					val sb = new StringBuilder();
+
+					for (var i = 0; i < nodelist.length; i++) {
+						if (i != 0) {
+							sb.append(separator)
+						}
+						sb.append(nodelist.get(i).getData())
+					}
+					// add string to new map if it doesn't exist already
+					if (!newDoublets.containsKey(sb.toString)) {
+						newDoublets.put(sb.toString, new ArrayList<ArrayList<StringTreeNode>>());
+					}
+
+					newDoublets.get(sb.toString).add(nodelist);
+				}
+			}
+
+			doublets = newDoublets;
+
+			// Abort criterion. If there is any name with more than one element, repeat.
+			abort = true;
+			for (name : doublets.keySet) {
+				if(doublets.get(name).length > 1) abort = false;
+			}
+		}
+
+		return mapping;
+	}
+}