From 6ddf690f29f87e3cd5b7c69caf8b667d63d9f0cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrgen=20Walter?= <juergen.walter@uni-wuerzburg.de>
Date: Fri, 4 May 2018 19:36:59 +0200
Subject: [PATCH] Added permutations when resolving recurring DoFs

Calculate permutations matching recurring DoFs instead of full
permutation. Illustrative example:

'cpu cores'<8>,
'users'<50,75,100, 150>, 'Probability dropRequests'<0.0>,
'users'<300>, 'Probability dropRequests'<0.1>,
'users'<400>, 'Probability dropRequests'<0.3>,

Generates 6 permutations: <8, (((50|75|100|150),0.0) | (300,0.1) |
(400,0.2))>
---
 .../engine/util/DoFCrossProductHelper.java    | 109 +++++++++++++++---
 1 file changed, 91 insertions(+), 18 deletions(-)

diff --git a/core/tools.descartes.dql.core.engine/src/tools/descartes/dql/core/engine/util/DoFCrossProductHelper.java b/core/tools.descartes.dql.core.engine/src/tools/descartes/dql/core/engine/util/DoFCrossProductHelper.java
index 82cda653..f586f065 100644
--- a/core/tools.descartes.dql.core.engine/src/tools/descartes/dql/core/engine/util/DoFCrossProductHelper.java
+++ b/core/tools.descartes.dql.core.engine/src/tools/descartes/dql/core/engine/util/DoFCrossProductHelper.java
@@ -42,18 +42,84 @@ public class DoFCrossProductHelper {
 
 	Map<DoF, String[]> possibleDofValues;
 	List<HashMap<DoF, String>> result;
+	int distinctDoFs;
+	Map<String, List<Integer>> map;
+	EntityMapping request;
+	String[] dofss;
+	int maxOccurences;
+	int mostFrequentDoFIndex;
 
 	/**
-	 * calculates the X-Product for DoFs of the EntityMapping input
+	 * Calculates the permutations for DoFs of the EntityMapping
 	 * 
 	 * @param input
 	 * @return List of DoF-combination. Each list element contains one possible
 	 *         combination
 	 */
 	public static List<HashMap<DoF, String>> calculateCrossProduct(EntityMapping input) {
-		DoFCrossProductHelper helper = new DoFCrossProductHelper();
-		helper.possibleDofValues = helper.getPossibleDofValues(input);
-		List<HashMap<DoF, String>> result = helper.recursiveCrossProduct();
+		return (new DoFCrossProductHelper()).calculatePermutations(input);
+
+	}
+
+	private List<HashMap<DoF, String>> calculatePermutations(EntityMapping request) {
+		this.request = request;
+		map = new HashMap<String, List<Integer>>();
+		for (int i = 0; i < request.getDoF().size(); i++) {
+			DoF dof = request.getDoF().get(i);
+			String key = dof.getIdentifier();
+			if (!map.containsKey(key)) {
+				List<Integer> list = new LinkedList<Integer>();
+				list.add(i);
+				map.put(dof.getIdentifier(), list);
+			} else {
+				List<Integer> list = map.get(key);
+				list.add(i);
+				map.put(key, list);
+			}
+		}
+		int repeatedDoFs = 0;
+		maxOccurences = 1;
+		for (String key : map.keySet()) {
+			System.out.println("" + key + " " + map.get(key));
+			if (map.get(key).size() > 1) {
+				maxOccurences = Math.max(map.get(key).size(), maxOccurences);
+				mostFrequentDoFIndex = 1;
+				repeatedDoFs++;
+
+			}
+		}
+		distinctDoFs = map.keySet().size();
+
+		if (repeatedDoFs == 0) {
+			/** calculate cross product */
+			possibleDofValues = getPossibleDofValues(request);
+			this.result = new ArrayList<HashMap<DoF, String>>();
+			this.recursiveCrossProduct(0, new HashMap<DoF, String>());
+
+		} else {
+			/**
+			 * Calculate permutations matching recurring DoFs instead of full permutation
+			 * Illustrative example:
+			 * 
+			 * 'cpu cores'<8>,
+			 * 
+			 * 'users'<50,75,100, 150>, 'Probability dropRequests'<0.0>,
+			 * 
+			 * 'users'<300>, 'Probability dropRequests'<0.1>,
+			 * 
+			 * 'users'<400>, 'Probability dropRequests'<0.3>,
+			 * 
+			 * Generates 6 permutations: <8, (((50|75|100|150),0.0) | (300,0.1) | (400,0.2)>
+			 * 
+			 */
+			this.possibleDofValues = getPossibleDofValues(request);
+			this.dofss = (String[]) map.keySet().toArray(new String[map.keySet().size()]);
+
+			this.result = new ArrayList<HashMap<DoF, String>>();
+			for (int i = 0; i < maxOccurences; i++) {
+				generatePermutations(new HashMap<DoF, String>(), 0, i);
+			}
+		}
 		return result;
 	}
 
@@ -72,15 +138,6 @@ public class DoFCrossProductHelper {
 		return possibleDofValues;
 	}
 
-	/**
-	 * Starting point for recursion
-	 */
-	private List<HashMap<DoF, String>> recursiveCrossProduct() {
-		this.result = new ArrayList<HashMap<DoF, String>>();
-		recursiveCrossProduct(0, new HashMap<DoF, String>());
-		return result;
-	}
-
 	/**
 	 * recursive traversal of possible options
 	 */
@@ -89,7 +146,7 @@ public class DoFCrossProductHelper {
 		if (counter == possibleDofValues.size())
 			result.add((HashMap<DoF, String>) temporaryResult.clone());
 		else {
-			Entry<DoF, String[]> entry = getElementNumber(possibleDofValues, counter);
+			Entry<DoF, String[]> entry = getDoFPair(possibleDofValues, counter);
 			for (String string : entry.getValue()) {
 				temporaryResult.put(entry.getKey(), string);
 				recursiveCrossProduct(counter + 1, temporaryResult);
@@ -97,10 +154,27 @@ public class DoFCrossProductHelper {
 		}
 	}
 
+	private void generatePermutations(HashMap<DoF, String> temporaryResult, int dofNumber, int occurence) {
+
+		if (dofNumber >= distinctDoFs) {
+			result.add((HashMap<DoF, String>) temporaryResult.clone());
+		} else {
+			String key = dofss[dofNumber];
+			DoF dof = request.getDoF().get(map.get(key).get(Math.min(occurence, map.get(key).size() - 1)));
+			String[] values = possibleDofValues.get(dof);
+			dofNumber = dofNumber + 1;
+			for (String dofValue : values) {
+				temporaryResult.put(dof, dofValue);
+				generatePermutations((HashMap<DoF, String>) temporaryResult.clone(), dofNumber, occurence);
+			}
+		}
+
+	}
+
 	/**
 	 * returns element number i for a map, treating it like a map
 	 */
-	private Entry<DoF, String[]> getElementNumber(Map<DoF, String[]> map, int counter) {
+	private Entry<DoF, String[]> getDoFPair(Map<DoF, String[]> map, int counter) {
 		int i = 0;
 
 		for (Entry<DoF, String[]> entry : map.entrySet()) {
@@ -113,8 +187,8 @@ public class DoFCrossProductHelper {
 	}
 
 	/**
-	 * Creates an String[] with the values of the requested DoF. Calculation
-	 * depends on if it is an IntervalVariationClause or a ValueVariationClause
+	 * Creates an String[] with the values of the requested DoF. Calculation depends
+	 * on if it is an IntervalVariationClause or a ValueVariationClause
 	 * 
 	 * @param doFProperties
 	 * @return DoF values as String[]
@@ -140,7 +214,6 @@ public class DoFCrossProductHelper {
 			arrayString = arrayString.substring(0, arrayString.length() - 1);
 
 		} else if (doFProperties.get("function").equals("fixed")) {
-
 			arrayString = (String) doFProperties.get("value");
 			arrayString = arrayString.replace("]", "");
 			arrayString = arrayString.replace("[", "");
-- 
GitLab