@@ -277,17 +277,17 @@ private class Trace extends TTrace {
277277 result = "Step(" + s1 + ", " + s2 + ", " + t + ")"
278278 )
279279 }
280- }
281280
282- /**
283- * Gets a string corresponding to the trace `t`.
284- */
285- private string concretise ( Trace t ) {
286- t = Nil ( ) and result = ""
287- or
288- exists ( InputSymbol s1 , InputSymbol s2 , Trace rest | t = Step ( s1 , s2 , rest ) |
289- result = concretise ( rest ) + intersect ( s1 , s2 )
290- )
281+ /** Holds if the `i`th pair of this trace is `(s1, s2)`. */
282+ predicate hasPair ( int i , InputSymbol s1 , InputSymbol s2 ) {
283+ this = Step ( s1 , s2 , _) and
284+ i = 0
285+ or
286+ exists ( Trace t |
287+ this = Step ( _, _, t ) and
288+ t .hasPair ( i - 1 , s1 , s2 )
289+ )
290+ }
291291}
292292
293293/**
@@ -321,14 +321,36 @@ private StatePair getAForkPair(State fork) {
321321 result = MkStatePair ( epsilonPred * ( fork ) , epsilonPred * ( fork ) )
322322}
323323
324+ private class RelevantTrace extends Trace {
325+ RelevantTrace ( ) {
326+ exists ( State fork , StatePair q |
327+ isReachableFromFork ( fork , q , this , _) and
328+ q = getAForkPair ( fork )
329+ )
330+ }
331+
332+ /** Gets a string corresponding to this trace. */
333+ // the pragma is needed for the case where `intersect(s1, s2)` has multiple values,
334+ // not for recursion
335+ language [ monotonicAggregates]
336+ string concretise ( ) {
337+ result =
338+ concat ( int i , InputSymbol s1 , InputSymbol s2 |
339+ this .hasPair ( i , s1 , s2 )
340+ |
341+ intersect ( s1 , s2 ) order by i desc
342+ )
343+ }
344+ }
345+
324346/**
325347 * Holds if `fork` is a pumpable fork with word `w`.
326348 */
327349private predicate isPumpable ( State fork , string w ) {
328- exists ( StatePair q , Trace t |
350+ exists ( StatePair q , RelevantTrace t |
329351 isReachableFromFork ( fork , q , t , _) and
330352 q = getAForkPair ( fork ) and
331- w = concretise ( t )
353+ w = t . concretise ( )
332354 )
333355}
334356
0 commit comments