source: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/utils/SimilarTasks.java @ 1767

Last change on this file since 1767 was 1767, checked in by pharms, 10 years ago
  • first version of merging similar task trees
File size: 40.5 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.tasktrees.temporalrelation.utils;
16
17import java.io.PrintStream;
18import java.util.HashSet;
19import java.util.LinkedList;
20import java.util.List;
21import java.util.Set;
22
23import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
24import de.ugoe.cs.autoquest.tasktrees.temporalrelation.TaskInstanceComparator;
25import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskTraversingVisitor;
26import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
27import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
28import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
29import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
30import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
31import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship;
32import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
33import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
34import de.ugoe.cs.autoquest.tasktrees.treeifc.ITemporalRelationship;
35import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskPath;
36import difflib.Chunk;
37import difflib.Delta;
38import difflib.Patch;
39
40/**
41 * <p>
42 * This class represents a pair of tasks and their corresponding similarity level, respectively,
43 * their diff level. In addition, it contains the task traversal, i.e., the flattened variants
44 * of the compared tasks. It provides static methods to compare two tasks and get an object of this
45 * class as result. Furthermore, it allows to adapt the contained traversals so that unmergable
46 * subtasks are not traversed.
47 * </p>
48 *
49 * @author Patrick Harms
50 */
51public class SimilarTasks {
52   
53    /**
54     * result of the string like comparison of both task traversals
55     */
56    private Patch patch;
57   
58    /**
59     * the diff level resulting from the comparison
60     */
61    private int diffLevel;
62   
63    /**
64     * the first compared task
65     */
66    private ITask leftHandSide;
67   
68    /**
69     * the second compare task
70     */
71    private ITask rightHandSide;
72   
73    /**
74     * the traversal of the first task
75     */
76    private TaskTraversal leftHandSideTraversal;
77   
78    /**
79     * the traversal of the second task
80     */
81    private TaskTraversal rightHandSideTraversal;
82   
83    /**
84     * initialized a pair of tasks and calculates its diff level
85     */
86    public SimilarTasks(Patch         patch,
87                        ITask         task1,
88                        TaskTraversal traversal1,
89                        ITask         task2,
90                        TaskTraversal traversal2)
91    {
92        this.leftHandSide = task1;
93        this.leftHandSideTraversal = traversal1;
94        this.rightHandSide = task2;
95        this.rightHandSideTraversal = traversal2;
96       
97        if (patch != null) {
98            this.patch = patch;
99            this.diffLevel = getDiffLevel(patch, traversal1, traversal2);
100        }
101        else {
102            this.diffLevel = 100;
103        }
104    }
105
106    /**
107     * static convenience method to compare two tasks
108     */
109    public static SimilarTasks compareTasks(ITask                  task1,
110                                            ITask                  task2,
111                                            TaskInstanceComparator comparator)
112    {
113        return compareTasks(task1, task2, comparator, null, true /* never set to false as a common
114                                                                 path may occur several times
115                                                                 at distinct places in a traversal
116                                                                 and once it may be part of a delta
117                                                                 and once not */);
118    }
119
120    /**
121     * static convenience method to compare two tasks but ignoring a given set of subtasks when
122     * creating the traversals. Furhtermore, it can be defined, if subtasks occurring in both
123     * similar tasks are traversed or not.
124     */
125    public static SimilarTasks compareTasks(ITask                  task1,
126                                            ITask                  task2,
127                                            TaskInstanceComparator comparator,
128                                            List<TaskPath>         pathsNotToTraverse,
129                                            boolean                traverseCommonPaths)
130    {
131        Set<ITask> commonInvolvedTasks;
132
133        if (traverseCommonPaths) {
134            commonInvolvedTasks = new HashSet<ITask>();
135        }
136        else {
137            commonInvolvedTasks = getCommonInvolvedTasks(task1, task2);
138        }
139
140        TaskTraversal traversal1 =
141             TaskTraversal.getTraversal(task1, commonInvolvedTasks, pathsNotToTraverse);
142       
143        TaskTraversal traversal2 =
144             TaskTraversal.getTraversal(task2, commonInvolvedTasks, pathsNotToTraverse);
145
146        if ((traversal1.size() <= 0) || (traversal2.size() <= 0)) {
147            return null;
148        }
149
150        Patch patch = new TaskTraversalMyersDiff(comparator).getDiff(traversal1, traversal2);
151
152        SimilarTasks result = new SimilarTasks(patch, task1, traversal1, task2, traversal2);
153
154        return result;
155    }
156
157
158    /**
159     * This method checks for mergability of the provided similar tasks and if this is not given,
160     * it reduces the traversals by ignoring interleaving iterations and other situations until
161     * the remaining traversals can be the basis of a merge.
162     */
163    public static SimilarTasks getMergableLevelOfSimilarity(SimilarTasks           source,
164                                                            TaskInstanceComparator comparator)
165    {
166        SimilarTasks similarTasks = source;
167       
168        List<TaskPath> pathsToIgnore = similarTasks.getPathsToIgnore();
169       
170        int prevPathsToIgnoreCount = 0;
171       
172        do {
173            prevPathsToIgnoreCount = pathsToIgnore.size();
174           
175            similarTasks = compareTasks
176                (similarTasks.getLeftHandSide(), similarTasks.getRightHandSide(),
177                 comparator, pathsToIgnore, true);
178
179            similarTasks.dump(System.out);
180           
181            List<TaskPath> furtherPathsToIgnore = similarTasks.getPathsToIgnore();
182           
183            for (TaskPath path : furtherPathsToIgnore) {
184                System.out.println(path);
185            }
186           
187            for (TaskPath pathToAdd : furtherPathsToIgnore) {
188                boolean found = false;
189                for (TaskPath pathToIgnore : pathsToIgnore) {
190                    if (pathToAdd.equals(pathToIgnore)) {
191                        found = true;
192                        break;
193                    }
194                }
195               
196                if (!found) {
197                    pathsToIgnore.add(pathToAdd);
198                }
199            }
200        }
201        while (pathsToIgnore.size() > prevPathsToIgnoreCount);
202       
203        return similarTasks;
204    }
205
206    /**
207     * checks if the delta between the two traversals is at their border or not
208     */
209    public boolean isInBetweenDifference() {
210        List<Delta> deltas = patch.getDeltas();
211       
212        for (Delta delta : deltas) {
213            int origPos = delta.getOriginal().getPosition();
214            int origSize = delta.getOriginal().size();
215            int revPos = delta.getRevised().getPosition();
216            int revSize = delta.getRevised().size();
217           
218            if ((origPos <= 0) || (revPos <= 0)) {
219                // optional must not be the beginning of the task
220                return false;
221            }
222            else if ((delta.getType() == Delta.TYPE.INSERT) &&
223                     ((revPos + revSize) >= rightHandSideTraversal.size()))
224            {
225                // optional must not be the end of the right hand side task
226                return false;
227            }
228            else if ((delta.getType() == Delta.TYPE.DELETE) &&
229                     ((origPos + origSize) >= leftHandSideTraversal.size()))
230            {
231                // optional must not be the end of the left hand side task
232                return false;
233            }
234            else if ((delta.getType() == Delta.TYPE.CHANGE) &&
235                     (((revPos + revSize) >= rightHandSideTraversal.size()) ||
236                      ((origPos + origSize) >= leftHandSideTraversal.size())))
237           {
238               // selection must not be the end of the left hand or right hand side task
239               return false;
240           }
241        }
242       
243        return deltas.size() > 0;
244    }
245   
246    /**
247     * @return the patch
248     */
249    public Patch getPatch() {
250        return patch;
251    }
252
253    /**
254     * @return the diff level
255     */
256    public int getDiffLevel() {
257        return diffLevel;
258    }
259
260    /**
261     * @return the first task of the comparison
262     */
263    public ITask getLeftHandSide() {
264        return leftHandSide;
265    }
266
267    /**
268     * @return the second task of the comparison
269     */
270    public ITask getRightHandSide() {
271        return rightHandSide;
272    }
273
274    /**
275     * @return the traversal of the first task of the comparison
276     */
277    public TaskTraversal getLeftHandSideTraversal() {
278        return leftHandSideTraversal;
279    }
280
281    /**
282     * @return the traversal of the second task of the comparison
283     */
284    public TaskTraversal getRightHandSideTraversal() {
285        return rightHandSideTraversal;
286    }
287
288    /**
289     * returns paths to subtasks, that can not be merged.
290     */
291    public List<TaskPath> getPathsToIgnore() {
292        List<TaskPath> result = new LinkedList<TaskPath>();
293        Delta singleChangeDelta = null;
294       
295        if ((patch.getDeltas().size() == 1) &&
296            (patch.getDeltas().get(0).getType() == Delta.TYPE.CHANGE))
297        {
298            singleChangeDelta = patch.getDeltas().get(0);
299        }
300       
301        // if it is a full change, then the parent of either side must be fully ignored
302        if (singleChangeDelta != null) {
303            if ((singleChangeDelta.getOriginal().getPosition() == 0) &&
304                (singleChangeDelta.getOriginal().size() == leftHandSideTraversal.size()))
305            {
306                TaskPath path = new TaskPath();
307                path.add(leftHandSide, 0);
308                result.add(path);
309            }
310       
311            if ((singleChangeDelta.getRevised().getPosition() == 0) &&
312                (singleChangeDelta.getRevised().size() == rightHandSideTraversal.size()))
313            {
314                TaskPath path = new TaskPath();
315                path.add(rightHandSide, 0);
316                result.add(path);
317            }
318        }
319       
320        if (result.size() < 2) {
321            // if we do not already ignore both root tasks, check for selections and interleaving
322            // iterations that have to be ignored if they belong to a delta
323            for (Delta delta : patch.getDeltas()) {
324                //getSelections(delta, result);
325                getPathsToRealIntersectingIterations(delta, result);
326                getNotFullyInterleavingIteration(delta, result);
327                getPathsToParentTasksFullyInsideDelta(delta, result);
328            }
329           
330            // check if there are common subtasks on both sides that lie outside any delta and
331            // that hence should be ignored (especially when performing flattening of task
332            // instances later with the goal to preserve as many subtasks and respective instances
333            int deltaIndex = 0;
334            int leftTraversalIndex = 0;
335            int rightTraversalIndex = 0;
336            Set<ITask> commonInvolvedTasks = getCommonInvolvedTasks(leftHandSide, rightHandSide);
337           
338            do {
339                Delta delta = deltaIndex < patch.getDeltas().size()
340                    ? patch.getDeltas().get(deltaIndex++) : null;
341               
342                int nextLeftTraversalIndex = leftHandSideTraversal.size();
343                int nextRightTraversalIndex = rightHandSideTraversal.size();
344               
345                if (delta != null) {
346                    nextLeftTraversalIndex = delta.getOriginal().getPosition() + 1;
347                    nextRightTraversalIndex = delta.getRevised().getPosition() + 1;
348                   
349                    if (delta.getType() == Delta.TYPE.INSERT) {
350                        nextLeftTraversalIndex--;
351                    }
352                    else if (delta.getType() == Delta.TYPE.DELETE) {
353                        nextRightTraversalIndex--;
354                    }
355                }
356               
357                TaskPath[] leftSubTraversal =
358                    leftHandSideTraversal.subList(leftTraversalIndex, nextLeftTraversalIndex);
359               
360                for (TaskPath path : leftSubTraversal) {
361                    for (int i = 0; i < path.size(); i++) {
362                        if (commonInvolvedTasks.contains(path.getTask(i))) {
363                            // found a candidate. Check if the candidate does not span more than
364                            // the sub traversal
365                            TaskPath parentPath = path.subPath(0, i + 1);
366                            int[] indexes = leftHandSideTraversal.getIndexesRootedBy(parentPath);
367                           
368                            if ((indexes[0] >= leftTraversalIndex) &&
369                                (indexes[1] < nextLeftTraversalIndex))
370                            {
371                                result.add(parentPath);
372                                break; // breaks only the path but the rest of the traversal is
373                                       // checked too
374                            }
375                        }
376                    }
377                }
378               
379                TaskPath[] rightSubTraversal =
380                    rightHandSideTraversal.subList(rightTraversalIndex, nextRightTraversalIndex);
381               
382                for (TaskPath path : rightSubTraversal) {
383                    for (int i = 0; i < path.size(); i++) {
384                        if (commonInvolvedTasks.contains(path.getTask(i))) {
385                            // found a candidate. Check if the candidate does not span more than
386                            // the sub traversal
387                            TaskPath parentPath = path.subPath(0, i + 1);
388                            int[] indexes = rightHandSideTraversal.getIndexesRootedBy(parentPath);
389                           
390                            if ((indexes[0] >= rightTraversalIndex) &&
391                                (indexes[1] < nextRightTraversalIndex))
392                            {
393                                result.add(parentPath);
394                                break; // breaks only the path but the rest of the traversal is
395                                       // checked too
396                            }
397                        }
398                    }
399                }
400               
401                leftTraversalIndex = nextLeftTraversalIndex;
402                rightTraversalIndex = nextRightTraversalIndex;
403            }
404            while (leftTraversalIndex < leftHandSideTraversal.size());
405           
406         }
407       
408        return result;
409    }
410
411    /**
412     *
413     */
414    public void dump(PrintStream out) {
415        out.println();
416        out.print("similar tasks: left ");
417        out.print(leftHandSide);
418        out.print(" (");
419        out.print(leftHandSide.getInstances().size());
420        out.print(" instances), right ");
421        out.print(rightHandSide);
422        out.print(" (");
423        out.print(rightHandSide.getInstances().size());
424        out.print(" instances), diff level ");
425        out.println(diffLevel);
426       
427        out.println("left traversal");
428        for (TaskPath path : leftHandSideTraversal.getTraversalPaths()) {
429            out.println(path);
430        }
431       
432        out.println("right traversal");
433        for (TaskPath path : rightHandSideTraversal.getTraversalPaths()) {
434            out.println(path);
435        }
436       
437        if (patch != null) {
438            out.println("deltas:");
439            for (Delta delta : patch.getDeltas()) {
440                out.println(delta);
441            }
442        }
443       
444        List<String> linesLeft = new LinkedList<String>();
445        TaskPath path = new TaskPath();
446        path.add(leftHandSide, 0);
447        dumpToLineList(path, leftHandSideTraversal, linesLeft);
448        path.removeLast();
449       
450        List<String> linesRight = new LinkedList<String>();
451        path.add(rightHandSide, 0);
452        dumpToLineList(path, rightHandSideTraversal, linesRight);
453
454       
455        /*System.out.println("\n#################################################");
456        for (int j = 0; ((j < linesLeft.size()) || (j < linesRight.size())); j++) {
457            String left = j < linesLeft.size() ? linesLeft.get(j) : "";
458            String right = j < linesRight.size() ? linesRight.get(j) : "";
459           
460            StringBuffer line = new StringBuffer();
461            line.append(j);
462            line.append(":\t");
463            line.append(left);
464           
465            for (int k = line.length(); k < 60; k++) {
466                line.append(' ');
467            }
468           
469            line.append(right);
470            System.out.println(line);
471        }*/
472
473        // change lists to have the same length depending on the changes
474        int lineIndexLeft = 0;
475        int lineIndexRight = 0;
476        int leftHandTraversalIndex = 0;
477        while (leftHandTraversalIndex < leftHandSideTraversal.size()) {
478           
479            //System.out.println("\n" + lineIndexLeft + "   " + lineIndexRight);
480           
481            Delta delta = null;
482           
483            for (Delta candidate : patch.getDeltas()) {
484                if (candidate.getOriginal().getPosition() == leftHandTraversalIndex) {
485                    delta = candidate;
486                    break;
487                }
488            }
489           
490            if ((delta != null) && (delta.getType() == Delta.TYPE.DELETE)) {
491                for (int j = 0; j < delta.getOriginal().size(); j++) {
492                    while (linesLeft.get(lineIndexLeft) != null) {
493                        lineIndexLeft++;
494                    }
495                   
496                    linesLeft.remove(lineIndexLeft);
497                   
498                    while (lineIndexRight < lineIndexLeft) {
499                        linesRight.add(lineIndexRight++, null);
500                    }
501                   
502                    leftHandTraversalIndex++;
503                }
504               
505                linesLeft.add(lineIndexLeft++, "-------------------------------------");
506                linesRight.add(lineIndexRight++, "-------------------------------------");
507            }
508            else if ((delta != null) && (delta.getType() == Delta.TYPE.INSERT)) {
509                for (int j = 0; j < delta.getRevised().size(); j++) {
510                    while (linesRight.get(lineIndexRight) != null) {
511                        lineIndexRight++;
512                    }
513                   
514                    linesRight.remove(lineIndexRight);
515                   
516                    while (lineIndexLeft < lineIndexRight) {
517                        linesLeft.add(lineIndexLeft++, null);
518                    }
519                }
520               
521                // ensure that what is equal is harmonized too (because after an insert always
522                // comes something equal). The traversal index will be updated automatically,
523                // too.
524                delta = null;
525               
526                linesLeft.add(lineIndexLeft++, "-------------------------------------");
527                linesRight.add(lineIndexRight++, "-------------------------------------");
528            }
529           
530            if ((delta == null) || (delta.getType() == Delta.TYPE.CHANGE)) {
531                int chunkSizeLeft = delta != null ? delta.getOriginal().size() : 1;
532                int chunkSizeRight = delta != null ? delta.getRevised().size() : 1;
533               
534                int chunksHandledLeft = 0;
535                int chunksHandledRight = 0;
536                   
537                for (int j = 0; j < Math.max(chunkSizeLeft, chunkSizeRight); j++) {
538                    if (chunksHandledLeft < chunkSizeLeft) {
539                        while (linesLeft.get(lineIndexLeft) != null) {
540                            lineIndexLeft++;
541                        }
542                       
543                        linesLeft.remove(lineIndexLeft);
544                        chunksHandledLeft++;
545                    }
546                       
547                    if (chunksHandledRight < chunkSizeRight) {
548                        while (linesRight.get(lineIndexRight) != null) {
549                            lineIndexRight++;
550                        }
551                   
552                        linesRight.remove(lineIndexRight);
553                        chunksHandledRight++;
554                    }
555                   
556                    while (lineIndexLeft < lineIndexRight) {
557                        linesLeft.add(lineIndexLeft++, null);
558                    }
559                    while (lineIndexRight < lineIndexLeft) {
560                        linesRight.add(lineIndexRight++, null);
561                    }
562                }
563               
564                linesLeft.add(lineIndexLeft++, "-------------------------------------");
565                linesRight.add(lineIndexRight++, "-------------------------------------");
566
567                leftHandTraversalIndex += delta != null ? delta.getOriginal().size() : 1;
568            }
569           
570            /*System.out.println(delta + "  " + leftHandTraversalIndex);
571            System.out.println("\n#################################################");
572            for (int j = 0; ((j < linesLeft.size()) || (j < linesRight.size())); j++) {
573                String left = j < linesLeft.size() ? linesLeft.get(j) : "";
574                String right = j < linesRight.size() ? linesRight.get(j) : "";
575               
576                StringBuffer line = new StringBuffer();
577                line.append(j);
578                line.append(":\t");
579                line.append(left);
580               
581                for (int k = line.length(); k < 60; k++) {
582                    line.append(' ');
583                }
584               
585                line.append(right);
586                System.out.println(line);
587            }*/
588        }
589       
590        int indentLeft = 0;
591        int indentRight = 0;
592       
593        for (int i = 0; i < linesLeft.size(); i++) {
594            StringBuffer line = new StringBuffer();
595            String left = linesLeft.get(i);
596            String right = linesRight.get(i);
597           
598            if (left != null) {
599                if (left.indexOf('}') >= 0) {
600                    indentLeft -= 2;
601                }
602
603                for (int j = 0; j < indentLeft; j++) {
604                    line.append(' ');
605                }
606                       
607                if (left.indexOf('{') >= 0) {
608                    indentLeft += 2;
609                }
610
611                line.append(left);
612            }
613
614            if (right != null) {
615                for (int j = line.length(); j < 100; j++) {
616                    line.append(' ');
617                }
618                if (right.indexOf('}') >= 0) {
619                    indentRight -= 2;
620                }
621
622                for (int j = 0; j < indentRight; j++) {
623                    line.append(' ');
624                }
625
626                if (right.indexOf('{') >= 0) {
627                    indentRight += 2;
628                }
629
630                line.append(right);
631            }
632
633            out.println(line);
634        }
635    }
636
637    /**
638     *
639     */
640    private static Set<ITask> getCommonInvolvedTasks(ITask task1, ITask task2) {
641        Set<ITask> result = getAllInvolvedTasks(task1);
642        result.retainAll(getAllInvolvedTasks(task2));
643        return result;
644    }
645
646    /**
647     *
648     */
649    private static Set<ITask> getAllInvolvedTasks(ITask task) {
650        final Set<ITask> result = new HashSet<ITask>();
651
652        task.accept(new DefaultTaskTraversingVisitor() {
653            @Override
654            public void visit(IEventTask eventTask) {
655                result.add(eventTask);
656            }
657
658            @Override
659            public void visit(IStructuringTemporalRelationship relationship) {
660                result.add(relationship);
661                super.visit(relationship);
662            }
663
664            @Override
665            public void visit(IMarkingTemporalRelationship relationship) {
666                result.add(relationship);
667                super.visit(relationship);
668            }
669        });
670
671        return result;
672    }
673
674    /**
675     *
676     */
677    private void dumpToLineList(TaskPath      path,
678                                TaskTraversal traversal,
679                                List<String>  lines)
680    {
681        boolean isTraversalElement = false;
682       
683        for (TaskPath candidate : traversal.getTraversalPaths()) {
684            if (path.equals(candidate)) {
685                isTraversalElement = true;
686                break;
687            }
688        }
689       
690        if (isTraversalElement) {
691            lines.add(path.getLast().toString());
692            lines.add(null);
693            /*ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
694            PrintStream out = new PrintStream(byteStream);
695
696            new TaskTreeEncoder().encode(path.getLast(), out);
697           
698            out.close();
699           
700            BufferedReader reader = new BufferedReader
701                (new InputStreamReader(new ByteArrayInputStream(byteStream.toByteArray())));
702           
703            String line = null;
704            do {
705                try {
706                    line = reader.readLine();
707                }
708                catch (IOException e) {
709                    // should not happen so dump hard
710                    e.printStackTrace();
711                }
712                lines.add(line != null ? line.trim() : null);
713            }
714            while (line != null);*/
715           
716        }
717        else {
718            ITask task = path.getLast();
719            if (task instanceof ITemporalRelationship) {
720                lines.add(task + " {");
721
722                if (task instanceof IStructuringTemporalRelationship) {
723                    List<ITask> children =
724                        ((IStructuringTemporalRelationship) task).getChildren();
725                   
726                    for (int i = 0; i < children.size(); i++) {
727                        path.add(children.get(i), i);
728                        dumpToLineList(path, traversal, lines);
729                        path.removeLast();
730                    }
731                }
732                else if (task instanceof IMarkingTemporalRelationship) {
733                    IMarkingTemporalRelationship relationship =
734                            (IMarkingTemporalRelationship) task;
735
736                    path.add(relationship.getMarkedTask(), 0);
737                    dumpToLineList(path, traversal, lines);
738                    path.removeLast();
739                }
740
741                if (lines.get(lines.size() - 1) != null) {
742                    lines.add("}");
743                }
744                else {
745                    lines.add(lines.size() - 1, "}");
746                }
747            }
748            else {
749                lines.add(task + " {}");
750            }
751        }
752    }
753
754    /**
755     *
756     */
757    /*@SuppressWarnings("unchecked")
758    private void getSelections(Delta delta, List<TaskPath> result) {
759        TaskPath path1 = getCommonPath((List<TaskPath>) delta.getOriginal().getLines());
760        TaskPath path2 = getCommonPath((List<TaskPath>) delta.getRevised().getLines());
761       
762        for (int i = 0; i < path1.size(); i++) {
763            if (path1.getTask(i) instanceof ISelection) {
764                System.out.println("found selection to ignore");
765                System.out.println(path1.subPath(0, i + 1));
766                result.add(path1.subPath(0, i + 1));
767                break;
768            }
769        }
770       
771        for (int i = 0; i < path2.size(); i++) {
772            if (path2.getTask(i) instanceof ISelection) {
773                System.out.println("found selection to ignore");
774                System.out.println(path2.subPath(0, i + 1));
775                result.add(path2.subPath(0, i + 1));
776                break;
777            }
778        }
779    }*/
780
781    /**
782     *
783     */
784    @SuppressWarnings("unchecked")
785    private void getPathsToRealIntersectingIterations(Delta delta, List<TaskPath> paths) {
786        TaskPath path1 = getCommonPath((List<TaskPath>) delta.getOriginal().getLines());
787        TaskPath path2 = getCommonPath((List<TaskPath>) delta.getRevised().getLines());
788       
789        // both paths denote those parent tasks that contain the delta.
790        // But there may be parent tasks still contained in the path that are iterations and
791        // that are disjoint with a parent in the other path. Those iterations need to be
792        // considered, as otherwise a created selection would be against the associative law of
793        // iterations. Hence, we search for the topmost iteration on both paths that is disjoint
794        // with a parent node in the respective other path.
795       
796        for (int i = 0; i < path1.size(); i++) {
797            TaskPath path1Prefix = path1.subPath(0, i + 1);
798            int[] idxsPath1 = leftHandSideTraversal.getIndexesRootedBy(path1Prefix);
799           
800            // normalize the indexes to be 0 the index of the delta. Everything left of it
801            // is smaller 0, everything right of it, larger.
802            idxsPath1[0] -= delta.getOriginal().getPosition();
803            idxsPath1[1] -= delta.getOriginal().getPosition() + delta.getOriginal().size() - 1;
804           
805            for (int j = 0; j < path2.size(); j++) {
806                TaskPath path2Prefix = path2.subPath(0, j + 1);
807                int[] idxsPath2 = rightHandSideTraversal.getIndexesRootedBy(path2Prefix);
808               
809                // normalize the indexes to be 0 the index of the delta. Everything left of it
810                // is smaller 0, everything right of it, larger.
811                idxsPath2[0] -= delta.getRevised().getPosition();
812                idxsPath2[1] -=
813                    delta.getRevised().getPosition() + delta.getRevised().size() - 1;
814               
815                // now compare the indexes and check, if the sublists are real subsets of each
816                // other. If not, they only have a real common subset but there is at least one
817                // non shared element on both sides. If so, and one is an iteration, we
818                // have to use it as elements to be selected
819                if (((idxsPath1[0] < idxsPath2[0]) && (idxsPath1[1] < idxsPath2[1])) ||
820                    ((idxsPath1[0] > idxsPath2[0]) && (idxsPath1[1] > idxsPath2[1])))
821                {
822                    if ((path1.get(i).getTask() instanceof IIteration) &&
823                        (path2.get(j).getTask() instanceof IIteration))
824                    {
825                        System.out.println("found paths to real intersecting parents");
826                        int[] indexBuf = leftHandSideTraversal.getIndexesRootedBy(path1Prefix);
827                        System.out.println(idxsPath1[0] + "(" + indexBuf[0] + ")  " + idxsPath1[1] +
828                                           "(" + indexBuf[1] + ")  " + path1Prefix);
829                        indexBuf = rightHandSideTraversal.getIndexesRootedBy(path2Prefix);
830                        System.out.println(idxsPath2[0] + "(" + indexBuf[0] + ")  " + idxsPath2[1] +
831                                           "(" + indexBuf[1] + ")  " + path2Prefix);
832                       
833                        paths.add(path1Prefix);
834                        paths.add(path2Prefix);
835                        return;
836                    }
837                }
838            }
839        }
840    }
841
842    /**
843     *
844     */
845    private TaskPath getCommonPath(List<TaskPath> paths) {
846        TaskPath commonPath;
847       
848        if (paths.size() > 0) {
849            commonPath = new TaskPath(paths.get(0));
850           
851            for (int i = 1; i < paths.size(); i++) {
852                TaskPath comparePath = paths.get(i);
853                for (int j = 0; (j < commonPath.size()) && (j < comparePath.size()); j++) {
854                    if (!commonPath.get(j).equals(comparePath.get(j))) {
855                        while (commonPath.size() > j) {
856                            commonPath.remove(j);
857                        }
858                        break;
859                    }
860                }
861            }
862        }
863        else {
864            commonPath = new TaskPath();
865        }
866       
867        return commonPath;
868    }
869
870    /**
871     *
872     */
873    private void getNotFullyInterleavingIteration(Delta delta, List<TaskPath> result) {
874        getNotFullyInterleavingIterations(delta.getOriginal(), leftHandSideTraversal, result);
875        getNotFullyInterleavingIterations(delta.getRevised(), rightHandSideTraversal, result);
876    }
877   
878    /**
879     * If a chunk has a minimum number of 2 entries and at least one of them belongs to an iteration
880     * the does not cover the other and also expands to preceding or succeeding paths in the
881     * traversal, we can no merge the situation.
882     */
883    private void getNotFullyInterleavingIterations(Chunk          chunk,
884                                                   TaskTraversal  traversal,
885                                                   List<TaskPath> result)
886    {
887        @SuppressWarnings("unchecked")
888        List<TaskPath> paths = (List<TaskPath>) chunk.getLines();
889       
890        TaskPath commonPath = getCommonPath(paths);
891
892        if (paths.size() > 1) {
893            TaskPath firstPath = paths.get(0);
894            TaskPath lastPath = paths.get(paths.size() - 1);
895           
896            for (int i = commonPath.size(); i < firstPath.size(); i++) {
897                if (firstPath.get(i).getTask() instanceof IIteration) {
898                    // check, if the iteration covers things preceding the delta but not the whole
899                    // delta
900                    int[] indexes = traversal.getIndexesRootedBy(firstPath.subPath(0, i + 1));
901                   
902                    if ((indexes[0] < chunk.getPosition()) && // starts before the delta
903                        (indexes[1] < (chunk.getPosition() + chunk.size() - 1))) // does not cover delta
904                    {
905                        result.add(firstPath.subPath(0, i + 1));
906                        break;
907                    }
908                }
909            }
910
911            for (int i = commonPath.size(); i < lastPath.size(); i++) {
912                if (lastPath.get(i).getTask() instanceof IIteration) {
913                    // check, if the iteration covers things preceding the delta but not the whole
914                    // delta
915                    int[] indexes = traversal.getIndexesRootedBy(lastPath.subPath(0, i + 1));
916                   
917                    if ((indexes[0] > chunk.getPosition()) && // starts in between the delta
918                        (indexes[1] >= (chunk.getPosition() + chunk.size()))) // ends after the delta
919                    {
920                        result.add(lastPath.subPath(0, i + 1));
921                        break;
922                    }
923                }
924            }
925        }
926    }
927
928    /**
929     *
930     */
931    private void getPathsToParentTasksFullyInsideDelta(Delta delta, List<TaskPath> result) {
932        getPathsToParentTasksFullyInsideChunk(delta.getOriginal(), leftHandSideTraversal, result);
933        getPathsToParentTasksFullyInsideChunk(delta.getRevised(), rightHandSideTraversal, result);
934    }
935   
936    /**
937     * If a chunk has a minimum number of 2 entries and at least one of them belongs to an iteration
938     * the does not cover the other and also expands to preceding or succeeding paths in the
939     * traversal, we can no merge the situation.
940     */
941    private void getPathsToParentTasksFullyInsideChunk(Chunk          chunk,
942                                                       TaskTraversal  traversal,
943                                                       List<TaskPath> result)
944    {
945        @SuppressWarnings("unchecked")
946        List<TaskPath> paths = (List<TaskPath>) chunk.getLines();
947       
948        TaskPath commonPath = getCommonPath(paths);
949
950        for (TaskPath path : paths) {
951            for (int i = commonPath.size(); i < path.size(); i++) {
952                if (!(path.getLast() instanceof IEventTask)) {
953                    // check, if the parent task covers things fully inside the delta
954                    int[] indexes = traversal.getIndexesRootedBy(path.subPath(0, i + 1));
955                   
956                    if ((chunk.getPosition() <= indexes[0]) && // starts in the delta
957                        (indexes[1] < (chunk.getPosition() + chunk.size()))) // ends in the delta
958                    {
959                        System.out.println("found path to parent task lieing completely in the " +
960                                           "delta: " + path.subPath(0, i + 1));
961                        result.add(path.subPath(0, i + 1));
962                        break;
963                    }
964                }
965            }
966        }
967    }
968
969    /**
970     *
971     */
972    @SuppressWarnings("unchecked")
973    private int getDiffLevel(Patch         patch,
974                             TaskTraversal traversal1,
975                             TaskTraversal traversal2)
976    {
977        int diffCount = 0;
978        int allCount = 0;
979       
980        for (Delta delta : patch.getDeltas()) {
981            for (TaskPath path : (List<TaskPath>) delta.getOriginal().getLines()) {
982                // inefficient actions are counted later.
983                if (!isInefficientAction(path.getLast())) {
984                    diffCount += getDiffPenalty(path.getLast());
985                }
986            }
987            for (TaskPath path : (List<TaskPath>) delta.getRevised().getLines()) {
988                // inefficient actions are counted later.
989                if (!isInefficientAction(path.getLast())) {
990                    diffCount += getDiffPenalty(path.getLast());
991                }
992            }
993        }
994       
995        //if (getPathsToRealIntersectingIterations().size() > 0) {
996            // add a penalty if intersecting iterations are present
997            //count += 10;
998        //}
999       
1000        // add a penalty for inefficient actions which are equal as they have to be treated
1001        // unequal, too. Otherwise, many scrolls, e.g., would pretend a high equality of tasks
1002        // which contain only some non inefficient actions
1003        for (TaskPath path : traversal1.getTraversalPaths()) {
1004            if (isInefficientAction(path.getLast())) {
1005                diffCount++;
1006            }
1007            else {
1008                allCount += getDiffPenalty(path.getLast());
1009            }
1010        }
1011       
1012        for (TaskPath path : traversal2.getTraversalPaths()) {
1013            if (isInefficientAction(path.getLast())) {
1014                diffCount++;
1015            }
1016            else {
1017                allCount += getDiffPenalty(path.getLast());
1018            }
1019        }
1020       
1021        return (100 * diffCount) / allCount;
1022    }
1023
1024    /**
1025     *
1026     */
1027    private boolean isInefficientAction(ITask task) {
1028        ITaskInstance inst = task.getInstances().iterator().next();
1029       
1030        if ((inst instanceof IEventTaskInstance) &&
1031            (((IEventTaskInstance) inst).getEvent().getType() instanceof Scroll))
1032        {
1033            return true;
1034        }
1035        else if (task instanceof IMarkingTemporalRelationship) {
1036            return isInefficientAction(((IMarkingTemporalRelationship) task).getMarkedTask());
1037        }
1038        else {
1039            return false;
1040        }
1041    }
1042
1043
1044    /**
1045     *
1046     */
1047    private int getDiffPenalty(ITask task) {
1048        if (task instanceof IEventTask) {
1049            return 1;
1050        }
1051        else if (task instanceof IMarkingTemporalRelationship) {
1052            return getDiffPenalty(((IMarkingTemporalRelationship) task).getMarkedTask());
1053        }
1054        else if (task instanceof IStructuringTemporalRelationship) {
1055            int result = 0;
1056           
1057            for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
1058                result += getDiffPenalty(child);
1059            }
1060           
1061            if (task instanceof ISelection) {
1062                result /= ((IStructuringTemporalRelationship) task).getChildren().size();
1063            }
1064           
1065            return result;
1066        }
1067       
1068        throw new IllegalArgumentException("unknown type of task: " + task);
1069    }
1070}
Note: See TracBrowser for help on using the repository browser.