// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.commands.usability; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import de.ugoe.cs.autoquest.CommandHelpers; import de.ugoe.cs.autoquest.eventcore.IEventTarget; import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality; import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEqualityRuleManager; import de.ugoe.cs.autoquest.tasktrees.temporalrelation.TaskComparator; import de.ugoe.cs.autoquest.tasktrees.temporalrelation.utils.SimilarTasks; import de.ugoe.cs.autoquest.tasktrees.temporalrelation.utils.TaskTraversal; import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskTraversingVisitor; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration; import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric; import de.ugoe.cs.util.StopWatch; import de.ugoe.cs.util.console.Command; import de.ugoe.cs.util.console.Console; import de.ugoe.cs.util.console.GlobalDataContainer; /** *

* compares a set of task models with each other and drops their similarity as results *

* * @author Patrick Harms * @version 1.0 */ public class CMDgetTaskModelSimilarity implements Command { /* * (non-Javadoc) * * @see de.ugoe.cs.util.console.Command#help() */ @Override public String help() { return "getTaskModelSimilarity ..."; } /* * (non-Javadoc) * * @see de.ugoe.cs.util.console.Command#run(java.util.List) */ @Override public void run(List parameters) { List inputTaskTreeNames = new LinkedList<>(); try { for (Object param : parameters) { inputTaskTreeNames.add((String) param); } } catch (Exception e) { throw new IllegalArgumentException("must provide valid input task tree names"); } Map> inputTaskModels = new IdentityHashMap<>(); ITaskModel firstModel = null; for (String inputTaskTreeName : inputTaskTreeNames) { Object dataObject = GlobalDataContainer.getInstance().getData(inputTaskTreeName); if (dataObject == null) { CommandHelpers.objectNotFoundMessage(inputTaskTreeName); return; } if (!(dataObject instanceof ITaskModel)) { CommandHelpers.objectNotType(inputTaskTreeName, "ITaskModel"); return; } List tasksToCompare = new LinkedList<>(); for (ITask task : ((ITaskModel) dataObject).getTasks()) { if (task instanceof ISequence) { tasksToCompare.add((ISequence) task); } } inputTaskModels.put((ITaskModel) dataObject, tasksToCompare); if (firstModel == null) { firstModel = (ITaskModel) dataObject; } } getTaskModelSimilarity(firstModel, inputTaskModels); } /** * */ private void getTaskModelSimilarity(ITaskModel modelToCompare, Map> inputTaskModels) { // create the indexes to not do too many comparisons Map>>> index1 = new IdentityHashMap<>(); Map lengthIndex = new HashMap<>(); Map firstTargetIndex = new HashMap<>(); Map taskTraversalIndex = new HashMap<>(); final List terminalNodes = new ArrayList<>(); final List selections = new ArrayList<>(); for (Map.Entry> entry : inputTaskModels.entrySet()) { for (ISequence sequence : entry.getValue()) { terminalNodes.clear(); selections.clear(); sequence.accept(new DefaultTaskTraversingVisitor() { @Override public void visit(IEventTask eventTask) { terminalNodes.add(eventTask); } @Override public void visit(ISelection selection) { selections.add(selection); // no need to traverse children as a sequences containing a selection // will be handled differently } }); int length = terminalNodes.size(); IEventTarget firstTarget = ((IEventTaskInstance) terminalNodes.get(0).getInstances() .iterator().next()).getEvent().getTarget(); if (selections.size() > 0) { length = -1; firstTarget = null; } Map>> lengthMap = index1.get(entry.getKey()); if (lengthMap == null) { lengthMap = new HashMap<>(); index1.put(entry.getKey(), lengthMap); } Map> firstTaskMap = lengthMap.get(length); if (firstTaskMap == null) { firstTaskMap = new HashMap<>(); lengthMap.put(length, firstTaskMap); } List compareList = firstTaskMap.get(firstTarget); if (compareList == null) { compareList = new LinkedList(); firstTaskMap.put(firstTarget, compareList); } compareList.add(sequence); lengthIndex.put(sequence, length); firstTargetIndex.put(sequence, firstTarget); taskTraversalIndex.put(sequence, TaskTraversal.getTraversal(sequence, null)); } } // create the comparison runnables List runnables = new LinkedList<>(); for (Map.Entry> model2 : inputTaskModels.entrySet()) { if (modelToCompare != model2.getKey()) { runnables.add(new ComparisonRunnable(modelToCompare, inputTaskModels.get(modelToCompare), model2.getKey(), model2.getValue(), Collections.unmodifiableMap (index1.get(model2.getKey())), Collections.unmodifiableMap(lengthIndex), Collections.unmodifiableMap(firstTargetIndex), Collections.unmodifiableMap(taskTraversalIndex), runnables)); } } // execute the threads Console.traceln(Level.FINE, "scheduling " + runnables.size() + " comparison threads"); synchronized (runnables) { int startedRunnables = 0; for (ComparisonRunnable runnable : runnables) { while (startedRunnables >= Math.max(1, Runtime.getRuntime().availableProcessors())) { try { Console.traceln(Level.FINER, "waiting for next thread to finish"); runnables.wait(); startedRunnables--; Console.traceln(Level.FINER, "thread finished"); } catch (InterruptedException e) { // should not happen Console.logException(e); } } Console.traceln(Level.FINER, "starting next thread"); startedRunnables++; Console.traceln(Level.FINE, "comparing " + runnable.tasks1.size() + " tasks of model " + runnable.model1 + " with " + runnable.tasks2.size() + " tasks of model " + runnable.model2); new Thread(runnable).start(); Console.traceln(Level.FINER, "started next thread " + runnable); } while (startedRunnables > 0) { try { Console.traceln(Level.FINER, "waiting for next thread to finish"); runnables.wait(); startedRunnables--; Console.traceln(Level.FINER, "thread finished"); } catch (InterruptedException e) { // should not happen Console.logException(e); } } } // merge the results Console.traceln(Level.FINER, "all threads finished, mergin results"); for (ComparisonRunnable runnable : runnables) { Console.println("\nsimilarity statistics of comparison between " + runnable.model1 + " (" + runnable.tasks1.size() + " tasks) and " + runnable.model2 + " (" + runnable.tasks2.size() + " tasks)"); runnable.getStatistics().dump(); } } /** * */ private static class SimilarityStatistics { /** */ private int taskCounter1 = 0; /** */ private int maxCoverage1 = 0; /** */ private ITaskModel model1 = null; /** */ private Map coverageCounters1 = new HashMap<>(); /** */ private int taskCounter2 = 0; /** */ private int maxCoverage2 = 0; /** */ private ITaskModel model2 = null; /** */ private Map coverageCounters2 = new HashMap<>(); /** */ private Map>> equalityCounters = new HashMap<>(); /** * */ private void addCoverageCounter(ITask task, ITaskModel model) { if (model1 == null) { model1 = model; } else if (model2 == null) { model2 = model; } int coverageRatio = model.getTaskInfo(task).getMeasureValue(TaskMetric.EVENT_COVERAGE); if (model == model1) { addToMaps(coverageCounters1, coverageRatio, 1); taskCounter1++; maxCoverage1 = Math.max(maxCoverage1, coverageRatio); } else { addToMaps(coverageCounters2, coverageRatio, 1); taskCounter2++; maxCoverage2 = Math.max(maxCoverage2, coverageRatio); } } /** * */ private void store(ITask task, ITaskModel model, ITask other, ITaskModel otherModel, TaskEquality equality) { int coverageRatio1 = model.getTaskInfo(task).getMeasureValue(TaskMetric.EVENT_COVERAGE); int coverageRatio2 = otherModel.getTaskInfo(other).getMeasureValue(TaskMetric.EVENT_COVERAGE); addToMaps(coverageRatio1, coverageRatio2, equality, 1); } /** * */ private void store(ITask task, ITaskModel model) { int coverageRatio1 = model.getTaskInfo(task).getMeasureValue(TaskMetric.EVENT_COVERAGE); addToMaps(coverageRatio1, 0, TaskEquality.UNEQUAL, 1); } /** * */ private void addToMaps(Map coverageCounters, int ratio, int increment) { Integer counter = coverageCounters.get(ratio); if (counter == null) { coverageCounters.put(ratio, increment); } else { coverageCounters.put(ratio, counter + increment); } } /** * */ private void addToMaps(Integer ratio1, Integer ratio2, TaskEquality equality, int value) { Map> counters1 = equalityCounters.get(ratio1); if (counters1 == null) { counters1 = new HashMap<>(); equalityCounters.put(ratio1, counters1); } Map counters2 = counters1.get(ratio2); if (counters2 == null) { counters2 = new HashMap<>(); counters1.put(ratio2, counters2); } Integer counter = counters2.get(equality); if (counter == null) { counters2.put(equality, value); } else { counters2.put(equality, counter + value); } } /** * */ private void dump() { Console.println("Statistics of Similarity"); Console.println("========================"); int[][] bins1 = getBinsOfAlmostEqualSize(coverageCounters1, taskCounter1, maxCoverage1); int[][] bins2 = getBinsOfAlmostEqualSize(coverageCounters2, taskCounter2, maxCoverage2); int lowerBorder1; int higherBorder1; int lowerBorder2; int higherBorder2; int identicalEqualitiesOfBin = 0; int lexicalEqualitiesOfBin = 0; int syntacticalEqualitiesOfBin = 0; int semanticalEqualitiesOfBin = 0; int similaritiesOfBin = 0; int allEqualities = 0; String[][] outputs = new String[(bins1.length * (bins2.length + 3)) + 1][]; int outputIndex = 0; DecimalFormat percentFormat = new DecimalFormat("##0.0%"); StringBuffer csvData = new StringBuffer(); csvData.append(taskCounter1); csvData.append(';'); csvData.append(taskCounter2); for (int i = 0; i < bins1.length; i++) { if (i == 0) { higherBorder1 = maxCoverage1; } else { higherBorder1 = bins1[i - 1][0] - 1; } lowerBorder1 = bins1[i][0]; int allInBin1 = bins1[i][1]; csvData.append(';'); csvData.append(allInBin1); identicalEqualitiesOfBin = 0; lexicalEqualitiesOfBin = 0; syntacticalEqualitiesOfBin = 0; semanticalEqualitiesOfBin = 0; similaritiesOfBin = 0; outputs[outputIndex++] = new String[] { "similarities of " + bins1[i][1] + " tasks with " + lowerBorder1 + " to " + higherBorder1 + " covered events", "IDENT", "LEX", "SYN", "SEM", "ALL EQUAL", "SIM", "ALL" }; for (int j = 0; j < bins2.length; j++) { if (j == 0) { higherBorder2 = maxCoverage2; } else { higherBorder2 = bins2[j - 1][0] - 1; } lowerBorder2 = bins2[j][0]; int allInBin2 = bins2[j][1]; csvData.append(';'); csvData.append(allInBin2); int count1 = countEqualities(lowerBorder1, higherBorder1, lowerBorder2, higherBorder2, TaskEquality.IDENTICAL); int count2 = countEqualities(lowerBorder1, higherBorder1, lowerBorder2, higherBorder2, TaskEquality.LEXICALLY_EQUAL); int count3 = countEqualities(lowerBorder1, higherBorder1, lowerBorder2, higherBorder2, TaskEquality.SYNTACTICALLY_EQUAL); int count4 = countEqualities(lowerBorder1, higherBorder1, lowerBorder2, higherBorder2, TaskEquality.SEMANTICALLY_EQUAL); int count5 = countEqualities(lowerBorder1, higherBorder1, lowerBorder2, higherBorder2, null); outputs[outputIndex++] = new String[] { "--> to " + allInBin2 + " tasks with " + lowerBorder2 + " to " + higherBorder2 + " covered events", format(count1, allInBin1), format(count2, allInBin1), format(count3, allInBin1), format(count4, allInBin1), format(count1 + count2 + count3 + count4, allInBin1), format(count5, allInBin1), format(count1 + count2 + count3 + count4 + count5, allInBin1) }; identicalEqualitiesOfBin += count1; lexicalEqualitiesOfBin += count2; syntacticalEqualitiesOfBin += count3; semanticalEqualitiesOfBin += count4; similaritiesOfBin += count5; csvData.append(';'); csvData.append(percentFormat.format((double) count1 / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format((double) count2 / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format((double) count3 / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format((double) count4 / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format ((double) (count1 + count2 + count3 + count4) / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format((double) count5 / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format ((double) (count1 + count2 + count3 + count4 + count5) / allInBin1)); } outputs[outputIndex++] = new String[] { "--> all recalls", format(identicalEqualitiesOfBin, allInBin1), format(lexicalEqualitiesOfBin, allInBin1), format(syntacticalEqualitiesOfBin, allInBin1), format(semanticalEqualitiesOfBin, allInBin1), format(identicalEqualitiesOfBin + lexicalEqualitiesOfBin + syntacticalEqualitiesOfBin + semanticalEqualitiesOfBin, allInBin1), format(similaritiesOfBin, allInBin1), format(identicalEqualitiesOfBin + lexicalEqualitiesOfBin + syntacticalEqualitiesOfBin + semanticalEqualitiesOfBin + similaritiesOfBin, allInBin1) }; csvData.append(';'); csvData.append(percentFormat.format((double) identicalEqualitiesOfBin / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format((double) lexicalEqualitiesOfBin / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format((double) syntacticalEqualitiesOfBin / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format((double) semanticalEqualitiesOfBin / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format ((double) (identicalEqualitiesOfBin + lexicalEqualitiesOfBin + syntacticalEqualitiesOfBin + semanticalEqualitiesOfBin) / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format((double) similaritiesOfBin / allInBin1)); csvData.append(';'); csvData.append(percentFormat.format ((double) (identicalEqualitiesOfBin + lexicalEqualitiesOfBin + syntacticalEqualitiesOfBin + semanticalEqualitiesOfBin + similaritiesOfBin) / allInBin1)); allEqualities += identicalEqualitiesOfBin + lexicalEqualitiesOfBin + syntacticalEqualitiesOfBin + semanticalEqualitiesOfBin + similaritiesOfBin; outputIndex++; } outputs[outputIndex++] = new String[] { "complete recall is", null, null, null, null, null, format(allEqualities, taskCounter1) }; csvData.append(';'); csvData.append(percentFormat.format((double) allEqualities / taskCounter1)); dump(outputs); Console.println("\nCSV: " + csvData); } /** * */ private void dump(String[][] outputs) { int[] lengths = new int[outputs[0].length]; for (String[] line : outputs) { if (line != null) { for (int i = 0; i < line.length; i++) { if (line[i] != null) { lengths[i] = Math.max(lengths[i], line[i].length()); } } } } for (String[] line : outputs) { StringBuffer toWrite = new StringBuffer(); if (line != null) { for (int i = 0; i < line.length; i++) { if (i > 0) { toWrite.append(" | "); } String text = line[i]; if (text == null) { text = ""; } for (int j = 0; j < (lengths[i] - text.length()); j++) { toWrite.append(' '); } toWrite.append(text); } } Console.println(toWrite.toString()); } } /** * */ private int[][] getBinsOfAlmostEqualSize(Map coverageCounters, int taskCounter, int maxCoverage) { int[][] result = new int[5][]; for (int i = 0; i < result.length; i++) { result[i] = new int[2]; } int averageBinSize = taskCounter / result.length; int aimedBinSize = averageBinSize; int index = 0; int allCoverageCounterSum = 0; for (int i = maxCoverage; i > 0; i--) { if (result[index][1] > aimedBinSize) { if ((index + 2) < result.length) { // try to compensate, if the previous bin was a little too large aimedBinSize = averageBinSize + averageBinSize - result[index][1]; } else { // put all remaining in the last bin aimedBinSize = Integer.MAX_VALUE; } index++; } Integer value = coverageCounters.get(i); if (value != null) { result[index][0] = i; result[index][1] += value; allCoverageCounterSum += value; } } if (taskCounter != allCoverageCounterSum) { throw new RuntimeException("bins do not cover all tasks"); } return result; } /** * */ private String format(int noOfEqualTasks, int noOfAllTasks) { StringBuffer result = new StringBuffer(); if (noOfAllTasks > 0) { double value = ((double) (noOfEqualTasks * 100)) / noOfAllTasks; result.append(noOfEqualTasks); result.append(" ("); result.append(new DecimalFormat("##0.0").format(value)); result.append("%)"); } else { result.append("n.a."); } return result.toString(); } /** * */ private int countEqualities(int lowerBorder1, int higherBorder1, int lowerBorder2, int higherBorder2, TaskEquality equality) { int counter = 0; for (int i = lowerBorder1; i <= higherBorder1; i++) { Map> counters1 = equalityCounters.get(i); if (counters1 != null) { for (int j = lowerBorder2; j <= higherBorder2; j++) { Map counters2 = counters1.get(j); if (counters2 != null) { Integer counterObj = counters2.get(equality); if (counterObj != null) { counter += counterObj; } } } } } return counter; } } /** * */ private static class ComparisonRunnable implements Runnable { /** */ private ITaskModel model1; /** */ private ITaskModel model2; /** */ private List tasks1; /** */ private List tasks2; /** */ private Map>> lengthIndex1; /** */ private Map lengthIndex2; /** */ private Map firstTargetIndex; /** */ private Map traversalIndex; /** */ private Object semaphore; /** */ private SimilarityStatistics statistics = new SimilarityStatistics(); /** */ private TaskEqualityRuleManager equalityRuleManager = TaskEqualityRuleManager.getInstance(); /** * */ private ComparisonRunnable(ITaskModel model1, List tasks1, ITaskModel model2, List tasks2, Map>> lengthIndex1, Map lengthIndex2, Map firstTargetIndex, Map traversalIndex, Object semaphore) { this.model1 = model1; this.tasks1 = tasks1; this.model2 = model2; this.tasks2 = tasks2; this.lengthIndex1 = lengthIndex1; this.lengthIndex2 = lengthIndex2; this.firstTargetIndex = firstTargetIndex; this.traversalIndex = traversalIndex; this.semaphore = semaphore; } /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { TaskComparator comparator = new TaskComparator(TaskEquality.SEMANTICALLY_EQUAL); TaskEquality mostCommonEquality; ISequence mostSimilarTask; TaskEquality equality; SimilarTasks similarity; // store coverage infos for models for (ISequence task : tasks1) { statistics.addCoverageCounter(task, model1); } for (ISequence task : tasks2) { statistics.addCoverageCounter(task, model2); } List tasksToCompareWith = new ArrayList(); StopWatch watch = new StopWatch(); watch.start("all comparisons "); int count = 0; int taskNo = 0; int nextPercent = 10; for (ISequence task : tasks1) { int length = lengthIndex2.get(task); IEventTarget firstTarget = firstTargetIndex.get(task); tasksToCompareWith.clear(); // add tasks with same length Map> eventTaskMap = lengthIndex1.get(length); List toCompare; if (eventTaskMap != null) { toCompare = eventTaskMap.get(firstTarget); if (toCompare != null) { tasksToCompareWith.addAll(toCompare); } } // add tasks containing selections eventTaskMap = lengthIndex1.get(-1); if (eventTaskMap != null) { toCompare = eventTaskMap.get(firstTarget); if (toCompare != null) { tasksToCompareWith.addAll(toCompare); } } mostCommonEquality = null; mostSimilarTask = null; for (ISequence taskToCompare : tasksToCompareWith) { count++; watch.start("normal comparison"); equality = equalityRuleManager.compare(task, taskToCompare); watch.stop("normal comparison"); if ((equality != TaskEquality.UNEQUAL) && ((mostCommonEquality == null) || (equality.isAtLeast(mostCommonEquality)))) { // >>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>> // synchronized (System.out) { // System.out.println("found equal tasks: " + equality); // new TaskTreeEncoder().encode(task, System.out); // new TaskTreeEncoder().encode(taskToCompare, System.out); // } // <<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<< mostCommonEquality = equality; mostSimilarTask = taskToCompare; if (mostCommonEquality.isAtLeast(TaskEquality.LEXICALLY_EQUAL)) { // we found a lexically equal match, the most concrete that // we can find. We can break up here break; } } } if (mostCommonEquality != null) { // check, if both tasks are identical if (!identicalTasks(task, mostSimilarTask)) { statistics.store(task, model1, mostSimilarTask, model2, mostCommonEquality); } else { statistics.store (task, model1, mostSimilarTask, model2, TaskEquality.IDENTICAL); } } else { int lowestDiffLevel = Integer.MAX_VALUE; TaskTraversal traversal1 = traversalIndex.get(task); for (ISequence taskToCompare : tasksToCompareWith) { count++; watch.start("similarity comparison"); TaskTraversal traversal2 = traversalIndex.get(taskToCompare); similarity = SimilarTasks.compareTraversals(traversal1, traversal2, comparator); watch.stop("similarity comparison"); if (similarity.getDiffLevel() < lowestDiffLevel) { lowestDiffLevel = similarity.getDiffLevel(); mostSimilarTask = taskToCompare; if (lowestDiffLevel <= 0) { // >>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>> // synchronized (System.out) { // System.out.println("found similar tasks"); // similarity.dump(System.out); // } // <<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<< // we found a fully similar task. We will not find any more // similar, hence we break break; } } } if (lowestDiffLevel <= 0) { statistics.store(task, model1, mostSimilarTask, model2, null); } else { statistics.store(task, model1); } } taskNo++; if (((taskNo * 100) / tasks1.size()) > nextPercent) { System.out.println("compared " + nextPercent + "% (" + taskNo + " tasks) of " + model1 + " with " + tasks2.size() + " tasks of " + model2); nextPercent += 10; } } System.out.println("performed " + count + " comparisons for comparing " + model1 + " with " + model2); watch.stop("all comparisons "); watch.dumpStatistics(System.out); synchronized (semaphore) { semaphore.notify(); } } /** * */ private boolean identicalTasks(ISequence sequence1, ISequence sequence2) { if (sequence1.getChildren().size() != sequence2.getChildren().size()) { return false; } for (int i = 0; i < sequence1.getChildren().size(); i++) { if (!identicalTasks(sequence1.getChildren().get(i), sequence2.getChildren().get(i))) { return false; } } return true; } /** * */ private boolean identicalTasks(IIteration iteration1, IIteration iteration2) { return identicalTasks(iteration1.getMarkedTask(), iteration2.getMarkedTask()); } /** * */ private boolean identicalTasks(IOptional optional1, IOptional optional2) { return identicalTasks(optional1.getMarkedTask(), optional2.getMarkedTask()); } /** * */ private boolean identicalTasks(ISelection selection1, ISelection selection2) { if (selection1.getChildren().size() != selection2.getChildren().size()) { return false; } FIRST_SELECTION_CHILDREN: for (ITask child1 : selection1.getChildren()) { for (ITask child2 : selection2.getChildren()) { if (identicalTasks(child1, child2)) { continue FIRST_SELECTION_CHILDREN; } } return false; } return true; } /** * */ private boolean identicalTasks(IEventTask eventTask1, IEventTask eventTask2) { return equalityRuleManager.compare(eventTask1, eventTask2).isAtLeast (TaskEquality.SEMANTICALLY_EQUAL); } /** * */ private boolean identicalTasks(ITask task1, ITask task2) { if ((task1 instanceof ISequence) && (task2 instanceof ISequence)) { return identicalTasks((ISequence) task1, (ISequence) task2); } else if ((task1 instanceof IIteration) && (task2 instanceof IIteration)) { return identicalTasks((IIteration) task1, (IIteration) task2); } else if ((task1 instanceof IOptional) && (task2 instanceof IOptional)) { return identicalTasks((IOptional) task1, (IOptional) task2); } else if ((task1 instanceof ISelection) && (task2 instanceof ISelection)) { return identicalTasks((ISelection) task1, (ISelection) task2); } else if ((task1 instanceof IEventTask) && (task2 instanceof IEventTask)) { return identicalTasks((IEventTask) task1, (IEventTask) task2); } else { return false; } } /** * @return the statistics */ private SimilarityStatistics getStatistics() { return statistics; } } }