@@ -119,7 +119,7 @@ func (r Result) Similar() bool {
119
119
return r .NumSame + 1 >= r .NumDiff
120
120
}
121
121
122
- var randInt = rand .New (rand .NewSource (time .Now ().Unix ())).Intn (2 )
122
+ var randBool = rand .New (rand .NewSource (time .Now ().Unix ())).Intn (2 ) == 0
123
123
124
124
// Difference reports whether two lists of lengths nx and ny are equal
125
125
// given the definition of equality provided as f.
@@ -168,17 +168,6 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
168
168
// A vertical edge is equivalent to inserting a symbol from list Y.
169
169
// A diagonal edge is equivalent to a matching symbol between both X and Y.
170
170
171
- // To ensure flexibility in changing the algorithm in the future,
172
- // introduce some degree of deliberate instability.
173
- // This is achieved by fiddling the zigzag iterator to start searching
174
- // the graph starting from the bottom-right versus than the top-left.
175
- // The result may differ depending on the starting search location,
176
- // but still produces a valid edit script.
177
- zigzagInit := randInt // either 0 or 1
178
- if flags .Deterministic {
179
- zigzagInit = 0
180
- }
181
-
182
171
// Invariants:
183
172
// • 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx
184
173
// • 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny
@@ -197,6 +186,11 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
197
186
// approximately the square-root of the search budget.
198
187
searchBudget := 4 * (nx + ny ) // O(n)
199
188
189
+ // Running the tests with the "cmp_debug" build tag prints a visualization
190
+ // of the algorithm running in real-time. This is educational for
191
+ // understanding how the algorithm works. See debug_enable.go.
192
+ f = debug .Begin (nx , ny , f , & fwdPath .es , & revPath .es )
193
+
200
194
// The algorithm below is a greedy, meet-in-the-middle algorithm for
201
195
// computing sub-optimal edit-scripts between two lists.
202
196
//
@@ -214,22 +208,28 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
214
208
// frontier towards the opposite corner.
215
209
// • This algorithm terminates when either the X coordinates or the
216
210
// Y coordinates of the forward and reverse frontier points ever intersect.
217
- //
211
+
218
212
// This algorithm is correct even if searching only in the forward direction
219
213
// or in the reverse direction. We do both because it is commonly observed
220
214
// that two lists commonly differ because elements were added to the front
221
215
// or end of the other list.
222
216
//
223
- // Running the tests with the "cmp_debug" build tag prints a visualization
224
- // of the algorithm running in real-time. This is educational for
225
- // understanding how the algorithm works. See debug_enable.go.
226
- f = debug .Begin (nx , ny , f , & fwdPath .es , & revPath .es )
227
- for {
217
+ // Non-deterministically start with either the forward or reverse direction
218
+ // to introduce some deliberate instability so that we have the flexibility
219
+ // to change this algorithm in the future.
220
+ if flags .Deterministic || randBool {
221
+ goto forwardSearch
222
+ } else {
223
+ goto reverseSearch
224
+ }
225
+
226
+ forwardSearch:
227
+ {
228
228
// Forward search from the beginning.
229
229
if fwdFrontier .X >= revFrontier .X || fwdFrontier .Y >= revFrontier .Y || searchBudget == 0 {
230
- break
230
+ goto finishSearch
231
231
}
232
- for stop1 , stop2 , i := false , false , zigzagInit ; ! (stop1 && stop2 ) && searchBudget > 0 ; i ++ {
232
+ for stop1 , stop2 , i := false , false , 0 ; ! (stop1 && stop2 ) && searchBudget > 0 ; i ++ {
233
233
// Search in a diagonal pattern for a match.
234
234
z := zigzag (i )
235
235
p := point {fwdFrontier .X + z , fwdFrontier .Y - z }
@@ -262,10 +262,14 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
262
262
} else {
263
263
fwdFrontier .Y ++
264
264
}
265
+ goto reverseSearch
266
+ }
265
267
268
+ reverseSearch:
269
+ {
266
270
// Reverse search from the end.
267
271
if fwdFrontier .X >= revFrontier .X || fwdFrontier .Y >= revFrontier .Y || searchBudget == 0 {
268
- break
272
+ goto finishSearch
269
273
}
270
274
for stop1 , stop2 , i := false , false , 0 ; ! (stop1 && stop2 ) && searchBudget > 0 ; i ++ {
271
275
// Search in a diagonal pattern for a match.
@@ -300,8 +304,10 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
300
304
} else {
301
305
revFrontier .Y --
302
306
}
307
+ goto forwardSearch
303
308
}
304
309
310
+ finishSearch:
305
311
// Join the forward and reverse paths and then append the reverse path.
306
312
fwdPath .connect (revPath .point , f )
307
313
for i := len (revPath .es ) - 1 ; i >= 0 ; i -- {
0 commit comments