Ignore:
Timestamp:
05/31/15 19:22:54 (9 years ago)
Author:
pharms
Message:
  • fixed a bug in the detection of overlapping iterations before merging them.
  • now iterations are ignored, if they cause no repetitions in a task to be merged
  • the same applies for optionals making hopefully the merge more intuitive and cause less large selections
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/utils/SimilarTasks.java

    r1890 r1954  
    2727import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; 
    2828import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration; 
     29import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance; 
    2930import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship; 
    30 import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional; 
     31import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance; 
    3132import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection; 
    32 import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence; 
     33import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance; 
     34import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance; 
    3335import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship; 
    3436import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; 
     
    344346    public List<TaskPath> getPathsToIgnore() { 
    345347        List<TaskPath> result = new LinkedList<TaskPath>(); 
    346         Delta singleChangeDelta = null; 
    347348         
    348349        if ((patch.getDeltas().size() == 1) && 
    349350            (patch.getDeltas().get(0).getType() == Delta.TYPE.CHANGE)) 
    350351        { 
    351             singleChangeDelta = patch.getDeltas().get(0); 
    352         } 
    353          
    354         // if it is a full change, then the parent of either side must be fully ignored 
    355         if (singleChangeDelta != null) { 
     352            // if it is a full change, then the parent of either side must be fully ignored 
     353            Delta singleChangeDelta = patch.getDeltas().get(0); 
     354 
    356355            if ((singleChangeDelta.getOriginal().getPosition() == 0) && 
    357356                (singleChangeDelta.getOriginal().size() == leftHandSideTraversal.size())) 
     
    372371         
    373372        if (result.size() < 2) { 
    374             // if we do not already ignore both root tasks, check for selections and interleaving 
    375             // iterations that have to be ignored if they belong to a delta 
     373            // if we do not already ignore both root tasks, check for overlapping 
     374            // iterations that are executed multiple times for the tasks to be merged as they have 
     375            // to be ignored 
     376            result.addAll(getConflictingIterations()); 
     377             
     378            // then check for tasks fully inside delta, which can be preserved 
    376379            for (Delta delta : patch.getDeltas()) { 
    377                 //getSelections(delta, result); 
    378                 getPathsToRealIntersectingIterations(delta, result); 
    379380                getNotFullyInterleavingIteration(delta, result); 
    380381                getPathsToParentTasksFullyInsideDelta(delta, result); 
    381382            } 
    382383             
    383             // check for any parent optional that may be empty and can hence not be flattened 
    384             TaskPath tmppath = new TaskPath(); 
    385             tmppath.add(leftHandSide, 0); 
    386             getParentOptionals(tmppath, result); 
    387             tmppath = new TaskPath(); 
    388             tmppath.add(rightHandSide, 0); 
    389             getParentOptionals(tmppath, result); 
     384            // check for any parent optional that are at least once empty in instances of the 
     385            // tasks to be merged and that can, hence, not be flattened 
     386            getUnexecutedParentOptionals(leftHandSide, result); 
     387            getUnexecutedParentOptionals(rightHandSide, result); 
    390388             
    391389            // check if there are common subtasks on both sides that lie outside any delta and 
     
    839837        } 
    840838    }*/ 
    841  
    842     /** 
    843      * 
    844      */ 
    845     @SuppressWarnings("unchecked") 
    846     private void getPathsToRealIntersectingIterations(Delta delta, List<TaskPath> paths) { 
    847         TaskPath path1 = getCommonPath((List<TaskPath>) delta.getOriginal().getLines()); 
    848         TaskPath path2 = getCommonPath((List<TaskPath>) delta.getRevised().getLines()); 
    849          
    850         // both paths denote those parent tasks that contain the delta. 
    851         // But there may be parent tasks still contained in the path that are iterations and 
    852         // that are disjoint with a parent in the other path. Those iterations need to be 
    853         // considered, as otherwise a created selection would be against the associative law of 
    854         // iterations. Hence, we search for the topmost iteration on both paths that is disjoint 
    855         // with a parent node in the respective other path. 
    856          
    857         for (int i = 0; i < path1.size(); i++) { 
    858             TaskPath path1Prefix = path1.subPath(0, i + 1); 
    859             int[] idxsPath1 = leftHandSideTraversal.getIndexesRootedBy(path1Prefix); 
    860              
    861             // normalize the indexes to be 0 the index of the delta. Everything left of it 
    862             // is smaller 0, everything right of it, larger. 
    863             idxsPath1[0] -= delta.getOriginal().getPosition(); 
    864             idxsPath1[1] -= delta.getOriginal().getPosition() + delta.getOriginal().size() - 1; 
    865              
    866             for (int j = 0; j < path2.size(); j++) { 
    867                 TaskPath path2Prefix = path2.subPath(0, j + 1); 
    868                 int[] idxsPath2 = rightHandSideTraversal.getIndexesRootedBy(path2Prefix); 
    869                  
    870                 // normalize the indexes to be 0 the index of the delta. Everything left of it 
    871                 // is smaller 0, everything right of it, larger. 
    872                 idxsPath2[0] -= delta.getRevised().getPosition(); 
    873                 idxsPath2[1] -= 
    874                     delta.getRevised().getPosition() + delta.getRevised().size() - 1; 
    875                  
    876                 // now compare the indexes and check, if the sublists are real subsets of each 
    877                 // other. If not, they only have a real common subset but there is at least one 
    878                 // non shared element on both sides. If so, and one is an iteration, we 
    879                 // have to use it as elements to be selected 
    880                 if (((idxsPath1[0] < idxsPath2[0]) && (idxsPath1[1] < idxsPath2[1])) || 
    881                     ((idxsPath1[0] > idxsPath2[0]) && (idxsPath1[1] > idxsPath2[1]))) 
    882                 { 
    883                     if ((path1.get(i).getTask() instanceof IIteration) && 
    884                         (path2.get(j).getTask() instanceof IIteration)) 
    885                     { 
    886                         // System.out.println("found paths to real intersecting parents"); 
    887                         // int[] indexBuf = leftHandSideTraversal.getIndexesRootedBy(path1Prefix); 
    888                         // System.out.println(idxsPath1[0] + "(" + indexBuf[0] + ")  " + idxsPath1[1] + 
    889                         //                    "(" + indexBuf[1] + ")  " + path1Prefix); 
    890                         // indexBuf = rightHandSideTraversal.getIndexesRootedBy(path2Prefix); 
    891                         // System.out.println(idxsPath2[0] + "(" + indexBuf[0] + ")  " + idxsPath2[1] + 
    892                         //                    "(" + indexBuf[1] + ")  " + path2Prefix); 
     839     
     840    /** 
     841     * conflicting iterations are those that belong to either side of the sequence pair, that cover 
     842     * at least two actions, and that were executed multiple times in the context of the tasks 
     843     * to be merged. Iterations do only conflict, if there are at least two, one belonging to the 
     844     * left hand side, and the other to the right hand side. They conflict only, if they cover the 
     845     * same terminal nodes in the task traversals. 
     846     */ 
     847    private List<TaskPath> getConflictingIterations() { 
     848        List<TaskPath> iterationsWithMultipleExecutions = new LinkedList<>(); 
     849        getIterationsWithMultipleExecutions(leftHandSide, iterationsWithMultipleExecutions); 
     850         
     851        if (iterationsWithMultipleExecutions.size() > 0) { 
     852            // only, if iterations are executed in both side, they are of interest. Hence, 
     853            // check right hand side only, if left hand side contains repeated iterations. 
     854            int noOfLeftHandSideRepeatedIterations = iterationsWithMultipleExecutions.size(); 
     855            getIterationsWithMultipleExecutions(rightHandSide, iterationsWithMultipleExecutions); 
     856             
     857            if (iterationsWithMultipleExecutions.size() > noOfLeftHandSideRepeatedIterations) { 
     858                // also the right hand side contains problematic iterations. Check if they are 
     859                // overlapping and drop all which are not. 
     860                dropNonOverlappingIterations(iterationsWithMultipleExecutions); 
     861            } 
     862            else { 
     863                // no conflict, clear the list 
     864                iterationsWithMultipleExecutions.clear(); 
     865            } 
     866        } 
     867         
     868        return iterationsWithMultipleExecutions; 
     869    } 
     870 
     871    /** 
     872     * 
     873     */ 
     874    private void getIterationsWithMultipleExecutions(ITask          task, 
     875                                                     List<TaskPath> result) 
     876    { 
     877        for (ITaskInstance instance : task.getInstances()) { 
     878            TaskPath taskPath = new TaskPath(); 
     879            taskPath.add(task, 0); 
     880            getIterationsWithMultipleExecutions(instance, taskPath, result); 
     881        } 
     882    } 
     883 
     884    /** 
     885     * 
     886     */ 
     887    private void getIterationsWithMultipleExecutions(ITaskInstance  instance, 
     888                                                     TaskPath       currentPath, 
     889                                                     List<TaskPath> result) 
     890    { 
     891        if (instance instanceof IIterationInstance) { 
     892            if (((IIterationInstance) instance).size() > 1) { 
     893                // iteration executed multiple times --> store path 
     894                result.add(currentPath.subPath(0, currentPath.size())); // ensure to create a copy 
     895            } 
     896             
     897            currentPath.add(((IIteration) instance.getTask()).getMarkedTask(), 0); 
     898             
     899            for (ITaskInstance child : (IIterationInstance) instance) { 
     900                getIterationsWithMultipleExecutions(child, currentPath, result); 
     901            } 
     902             
     903            currentPath.removeLast(); 
     904        } 
     905        else if (instance instanceof ISequenceInstance) { 
     906            int index = 0; 
     907            for (ITaskInstance child : (ISequenceInstance) instance) { 
     908                currentPath.add(child.getTask(), index++); 
     909                getIterationsWithMultipleExecutions(child, currentPath, result); 
     910                currentPath.removeLast(); 
     911            } 
     912        } 
     913        else if (instance instanceof ISelectionInstance) { 
     914            ITaskInstance child = ((ISelectionInstance) instance).getChild(); 
     915            currentPath.add(child.getTask(), 0); 
     916            getIterationsWithMultipleExecutions(child, currentPath, result); 
     917            currentPath.removeLast(); 
     918        } 
     919        else if (instance instanceof IOptionalInstance) { 
     920            ITaskInstance child = ((IOptionalInstance) instance).getChild(); 
     921            if (child != null) { 
     922                currentPath.add(child.getTask(), 0); 
     923                getIterationsWithMultipleExecutions(child, currentPath, result); 
     924                currentPath.removeLast(); 
     925            } 
     926        } 
     927    } 
     928 
     929    /** 
     930     * 
     931     */ 
     932    private void dropNonOverlappingIterations(List<TaskPath> iterationsWithMultipleExecutions) { 
     933        // to check overlappings, iterate the iterations. Then check for each the indexes it covers 
     934        // in its respective traversal. Adapt the indexes depending on deltas that an iteration 
     935        // covers. Then check all other iterations. Consider also here the indexes in the traversal. 
     936        // also here, the indexes must be adapted in case of covered deltas. 
     937        List<TaskPath> overlappingIterations = new LinkedList<TaskPath>(); 
     938         
     939        for (TaskPath leftPath : iterationsWithMultipleExecutions) { 
     940            if (leftPath.getTask(0).equals(leftHandSide)) { 
     941                int[] leftIdxs = leftHandSideTraversal.getIndexesRootedBy(leftPath); 
     942                 
     943                for (TaskPath rightPath : iterationsWithMultipleExecutions) { 
     944                    if (rightPath.getTask(0).equals(rightHandSide)) { 
     945                        int[] rightIdxs = rightHandSideTraversal.getIndexesRootedBy(rightPath); 
    893946                         
    894                         paths.add(path1Prefix); 
    895                         paths.add(path2Prefix); 
    896                         return; 
    897                     } 
    898                 } 
    899             } 
    900         } 
     947                        adaptIndexesBasedOnDeltas(leftIdxs, rightIdxs, patch.getDeltas()); 
     948                         
     949                        if (((leftIdxs[0] < rightIdxs[0]) && (rightIdxs[0] <= leftIdxs[1])) || 
     950                            ((rightIdxs[0] < leftIdxs[0]) && (leftIdxs[0] <= rightIdxs[1]))) 
     951                        { 
     952                            overlappingIterations.add(leftPath); 
     953                            overlappingIterations.add(rightPath); 
     954                        } 
     955                    } 
     956                } 
     957            } 
     958        } 
     959         
     960        iterationsWithMultipleExecutions.retainAll(overlappingIterations); 
     961    } 
     962 
     963    /** 
     964     * 
     965     */ 
     966    private void adaptIndexesBasedOnDeltas(int[]       originalIndexes, 
     967                                           int[]       revisedIndexes, 
     968                                           List<Delta> deltas) 
     969    { 
     970        int originalStartUpdate = 0; 
     971        int originalEndUpdate = 0; 
     972        int revisedStartUpdate = 0; 
     973        int revisedEndUpdate = 0; 
     974         
     975        for (Delta delta : deltas) { 
     976            if (delta.getOriginal().getPosition() < originalIndexes[0]) { 
     977                originalStartUpdate += delta.getRevised().size(); 
     978            } 
     979            if (delta.getOriginal().getPosition() < originalIndexes[1]) { 
     980                originalEndUpdate += delta.getRevised().size(); 
     981            } 
     982            if (delta.getRevised().getPosition() < revisedIndexes[0]) { 
     983                revisedStartUpdate += delta.getOriginal().size(); 
     984            } 
     985            if (delta.getRevised().getPosition() < revisedIndexes[1]) { 
     986                revisedEndUpdate += delta.getOriginal().size(); 
     987            } 
     988        } 
     989         
     990        originalIndexes[0] += originalStartUpdate; 
     991        originalIndexes[1] += originalEndUpdate; 
     992        revisedIndexes[0] += revisedStartUpdate; 
     993        revisedIndexes[1] += revisedEndUpdate; 
    901994    } 
    902995 
     
    9391032    /** 
    9401033     * If a chunk has a minimum number of 2 entries and at least one of them belongs to an iteration 
    941      * the does not cover the other and also expands to preceding or succeeding paths in the 
    942      * traversal, we can no merge the situation. 
     1034     * that does not cover the other and also expands to preceding or succeeding paths in the 
     1035     * traversal, we can not merge the situation. 
    9431036     */ 
    9441037    private void getNotFullyInterleavingIterations(Chunk          chunk, 
     
    10311124     * 
    10321125     */ 
    1033     private void getParentOptionals(TaskPath taskPath, List<TaskPath> result) { 
    1034         ITask task = taskPath.getLast(); 
    1035          
    1036         if (task instanceof IOptional) { 
    1037             result.add(new TaskPath(taskPath)); 
    1038         } 
    1039         else if (task instanceof ISequence) { 
    1040             for (int i = 0; i < ((ISequence) task).getChildren().size(); i++) { 
    1041                 taskPath.add(((ISequence) task).getChildren().get(i), i); 
    1042                 getParentOptionals(taskPath, result); 
    1043                 taskPath.removeLast(); 
    1044             } 
    1045         } 
    1046         else if (task instanceof ISelection) { 
    1047             for (int i = 0; i < ((ISelection) task).getChildren().size(); i++) { 
    1048                 taskPath.add(((ISelection) task).getChildren().get(i), 0); 
    1049                 getParentOptionals(taskPath, result); 
    1050                 taskPath.removeLast(); 
    1051             } 
    1052         } 
    1053         else if (task instanceof IIteration) { 
    1054             taskPath.add(((IIteration) task).getMarkedTask(), 0); 
    1055             getParentOptionals(taskPath, result); 
    1056             taskPath.removeLast(); 
     1126    private void getUnexecutedParentOptionals(ITask          task, 
     1127                                              List<TaskPath> result) 
     1128    { 
     1129        for (ITaskInstance instance : task.getInstances()) { 
     1130            TaskPath taskPath = new TaskPath(); 
     1131            taskPath.add(task, 0); 
     1132            getUnexecutedParentOptionals(instance, taskPath, result); 
     1133        } 
     1134    } 
     1135     
     1136    /** 
     1137     * 
     1138     */ 
     1139    private void getUnexecutedParentOptionals(ITaskInstance  instance, 
     1140                                              TaskPath       currentPath, 
     1141                                              List<TaskPath> result) 
     1142    { 
     1143        if (instance instanceof IOptionalInstance) { 
     1144            ITaskInstance child = ((IOptionalInstance) instance).getChild(); 
     1145            if (child != null) { 
     1146                currentPath.add(child.getTask(), 0); 
     1147                getUnexecutedParentOptionals(child, currentPath, result); 
     1148                currentPath.removeLast(); 
     1149            } 
     1150            else { 
     1151                result.add(currentPath.subPath(0, currentPath.size())); // ensure to create a copy 
     1152            } 
     1153        } 
     1154        else if (instance instanceof IIterationInstance) { 
     1155            currentPath.add(((IIteration) instance.getTask()).getMarkedTask(), 0); 
     1156             
     1157            for (ITaskInstance child : (IIterationInstance) instance) { 
     1158                getUnexecutedParentOptionals(child, currentPath, result); 
     1159            } 
     1160             
     1161            currentPath.removeLast(); 
     1162        } 
     1163        else if (instance instanceof ISequenceInstance) { 
     1164            int index = 0; 
     1165            for (ITaskInstance child : (ISequenceInstance) instance) { 
     1166                currentPath.add(child.getTask(), index++); 
     1167                getUnexecutedParentOptionals(child, currentPath, result); 
     1168                currentPath.removeLast(); 
     1169            } 
     1170        } 
     1171        else if (instance instanceof ISelectionInstance) { 
     1172            ITaskInstance child = ((ISelectionInstance) instance).getChild(); 
     1173            currentPath.add(child.getTask(), 0); 
     1174            getUnexecutedParentOptionals(child, currentPath, result); 
     1175            currentPath.removeLast(); 
    10571176        } 
    10581177    } 
Note: See TracChangeset for help on using the changeset viewer.