source: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/utils/TaskTraversalMyersDiff.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: 6.3 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 de.ugoe.cs.autoquest.tasktrees.temporalrelation.TaskInstanceComparator;
18import difflib.ChangeDelta;
19import difflib.Chunk;
20import difflib.DeleteDelta;
21import difflib.Delta;
22import difflib.InsertDelta;
23import difflib.Patch;
24import difflib.myers.DiffNode;
25import difflib.myers.MyersDiff;
26import difflib.myers.PathNode;
27import difflib.myers.Snake;
28
29/**
30 *
31 */
32public class TaskTraversalMyersDiff extends MyersDiff {
33   
34    /**  */
35    private final TaskInstanceComparator comparator;
36
37    /**
38     *
39     */
40    public TaskTraversalMyersDiff(TaskInstanceComparator comparator) {
41        this.comparator = comparator;
42    }
43
44    /**
45     *
46     */
47    public Patch getDiff(TaskTraversal variant1, TaskTraversal variant2) {
48        PathNode path = buildPath(variant1, variant2);
49        return buildRevision(path, variant1, variant2);
50    }
51   
52    /**
53     * overwrites the default implementation just to change the tree task comparison.
54     * This is an extended version of the original implementation respecting the appropriate
55     * copyrights. Please see the copyrights of the implementers of the base class for more
56     * information
57     */
58    private PathNode buildPath(TaskTraversal variant1, TaskTraversal variant2) {
59        if (variant1 == null) {
60            throw new IllegalArgumentException("variant1 is null");
61        }
62       
63        if (variant2 == null) {
64            throw new IllegalArgumentException("variant2 is null");
65        }
66       
67        // these are local constants
68        final int N = variant1.size();
69        final int M = variant2.size();
70       
71        final int MAX = N + M + 1;
72        final int size = 1 + 2 * MAX;
73        final int middle = size / 2;
74        final PathNode diagonal[] = new PathNode[size];
75       
76        diagonal[middle + 1] = new Snake(0, -1, null);
77       
78        for (int d = 0; d < MAX; d++) {
79            for (int k = -d; k <= d; k += 2) {
80                final int kmiddle = middle + k;
81                final int kplus = kmiddle + 1;
82                final int kminus = kmiddle - 1;
83                PathNode prev = null;
84               
85                int i;
86                if ((k == -d) || ((k != d) && (diagonal[kminus].i < diagonal[kplus].i))) {
87                    i = diagonal[kplus].i;
88                    prev = diagonal[kplus];
89                }
90                else {
91                    i = diagonal[kminus].i + 1;
92                    prev = diagonal[kminus];
93                }
94               
95                diagonal[kminus] = null; // no longer used
96               
97                int j = i - k;
98               
99                PathNode task = new DiffNode(i, j, prev);
100               
101                // orig and rev are zero-based
102                // but the algorithm is one-based
103                // that's why there's no +1 when indexing the sequences
104                synchronized (comparator) {
105                    while ((i < N) && (j < M) && comparator.equals(variant1.get(i), variant2.get(j)))
106                    {
107                        i++;
108                        j++;
109                    }
110                }
111               
112                if (i > task.i) {
113                    task = new Snake(i, j, task);
114                }
115               
116                diagonal[kmiddle] = task;
117               
118                if ((i >= N) && (j >= M)) {
119                    return diagonal[kmiddle];
120                }
121            }
122            diagonal[middle + d - 1] = null;
123           
124        }
125       
126        // According to Myers, this cannot happen
127        throw new RuntimeException("could not find a diff path");
128    }
129
130    /**
131     * overwrites the default implementation just to change the tree task comparison.
132     * This is an extended version of the original implementation respecting the appropriate
133     * copyrights. Please see the copyrights of the implementers of the base class for more
134     * information
135     */
136    private Patch buildRevision(PathNode      path,
137                                TaskTraversal variant1,
138                                TaskTraversal variant2)
139    {
140        if (path == null) {
141            throw new IllegalArgumentException("path is null");
142        }
143       
144        if (variant1 == null) {
145            throw new IllegalArgumentException("variant1 is null");
146        }
147       
148        if (variant2 == null) {
149            throw new IllegalArgumentException("variant2 is null");
150        }
151       
152        Patch patch = new Patch();
153        if (path.isSnake()) {
154            path = path.prev;
155        }
156       
157        while ((path != null) && (path.prev != null) && (path.prev.j >= 0)) {
158            if (path.isSnake()) {
159                throw new IllegalStateException
160                    ("bad diffpath: found snake when looking for diff");
161            }
162           
163            int i = path.i;
164            int j = path.j;
165           
166            path = path.prev;
167            int ianchor = path.i;
168            int janchor = path.j;
169           
170            Chunk original = new Chunk(ianchor, variant1.subList(ianchor, i));
171            Chunk revised = new Chunk(janchor, variant2.subList(janchor, j));
172            Delta delta = null;
173           
174            if ((original.size() == 0) && (revised.size() != 0)) {
175                delta = new InsertDelta(original, revised);
176            }
177            else if ((original.size() > 0) && (revised.size() == 0)) {
178                delta = new DeleteDelta(original, revised);
179            }
180            else {
181                delta = new ChangeDelta(original, revised);
182            }
183           
184            patch.addDelta(delta);
185           
186            if (path.isSnake()) {
187                path = path.prev;
188            }
189        }
190        return patch;
191    }
192   
193}
Note: See TracBrowser for help on using the repository browser.