private static IEnumerable <Match> longLeftMatches(SymbolicString s1, SymbolicString s2) { var l1 = s1.root.wordLength(); var l2 = s2.root.wordLength(); var g = gcd(l1, l2); var v_beg = LinearIntegerExpression.FreshVariable(); var v_end = LinearIntegerExpression.FreshVariable(); // Split exactly at s2 root border yield return(Match.PartialSecond( LogicalExpression.And( // the beginning matches the s1 ComparisonExpression.Equal( LinearIntegerExpression.Times(l2, v_beg), LinearIntegerExpression.Times(l1, s1.repeat) ), // left over right bit is nonempty ComparisonExpression.GreaterThan( LinearIntegerExpression.Times(l2, v_end), 0 ), // beginning and end match s2 ComparisonExpression.Equal(v_beg + v_end, s2.repeat), ComparisonExpression.GreaterThanOrEqual(v_beg, 0), ComparisonExpression.GreaterThanOrEqual(v_end, 0) ), SymbolicString.Repeat(s2.root, v_end) )); // Split in the middle of s2 root if (l2 != 1) { for (int i = g; i < l2; i += g) { var suffix = SymbolicString.Concat(s2.root.sub_strings.Skip(i)); yield return(Match.PartialSecond( LogicalExpression.And( ComparisonExpression.Equal( LinearIntegerExpression.Times(l2, v_beg) + g, LinearIntegerExpression.Times(l1, s1.repeat) ), ComparisonExpression.GreaterThan( LinearIntegerExpression.Times(l2, v_beg) + suffix.length(), 0 ), ComparisonExpression.Equal(v_beg + v_end + 1, s2.repeat), ComparisonExpression.GreaterThanOrEqual(v_beg, 0), ComparisonExpression.GreaterThanOrEqual(v_end, 0) ), SymbolicString.Concat(suffix, SymbolicString.Repeat(s2.root, v_end)) )); } } }
// Generate TwoSplit's where either one may be empty // Generates the splits in order, i.e., by length of the prefix // So, for s being symbol and concat, first one will always be (\epsilon, s) and last one always (s, \epsilon) // So, for s being repeat (abc)^n, first will be ((abc)^i,(abc)^j) and last one always ((abc)^i ab, c(abc)^j) // Requires a flat symbolic string public IEnumerable <TwoSplit> TwoSplits() { SymbolicString prefix, suffix; // Contract.Requires(this.isFlat()); switch (this.expression_type) { case SymbolicStringType.Symbol: yield return(TwoSplit.MakeSplit(SymbolicString.Epsilon(), this, LogicalExpression.True())); yield return(TwoSplit.MakeSplit(this, SymbolicString.Epsilon(), LogicalExpression.True())); break; case SymbolicStringType.Concat: yield return(TwoSplit.MakeSplit(SymbolicString.Epsilon(), this, LogicalExpression.True())); for (int i = 0; i < this.sub_strings.Count; i++) { prefix = SymbolicString.Concat(this.sub_strings.Take(i).ToList()); suffix = SymbolicString.Concat(this.sub_strings.Skip(i + 1).ToList()); foreach (var split in this.sub_strings[i].TwoSplits()) { if (!split.start.isEpsilon()) { yield return(split.extend(prefix, suffix)); } } } break; case SymbolicStringType.Repeat: var v1 = LinearIntegerExpression.FreshVariable(); var v2 = LinearIntegerExpression.FreshVariable(); var sanityConstraint = LogicalExpression.And( ComparisonExpression.GreaterThanOrEqual(v1, 0), ComparisonExpression.GreaterThanOrEqual(v2, 0) ); prefix = SymbolicString.Repeat(this.root, v1); suffix = SymbolicString.Repeat(this.root, v2); yield return(TwoSplit.MakeSplit( prefix, suffix, LogicalExpression.And(sanityConstraint, ComparisonExpression.Equal(v1 + v2, this.repeat)) )); if (this.root.expression_type != SymbolicStringType.Concat) { break; } for (int i = 1; i < this.root.sub_strings.Count; i++) { var split = TwoSplit.MakeSplit( SymbolicString.Concat(this.root.sub_strings.Take(i)), SymbolicString.Concat(this.root.sub_strings.Skip(i)), LogicalExpression.And( ComparisonExpression.Equal(v1 + v2 + 1, this.repeat), sanityConstraint ) ); yield return(split.extend(prefix, suffix)); } break; default: throw new ArgumentOutOfRangeException(); } }
// Generates splits where all three parts may be empty public IEnumerable <Split> Splits() { // Contract.Requires<ArgumentException>(this.isFlat()); switch (this.expression_type) { case SymbolicStringType.Symbol: yield return(Split.MakeSplit(this, SymbolicString.Epsilon(), SymbolicString.Epsilon(), LogicalExpression.True())); yield return(Split.MakeSplit(SymbolicString.Epsilon(), this, SymbolicString.Epsilon(), LogicalExpression.True())); yield return(Split.MakeSplit(SymbolicString.Epsilon(), SymbolicString.Epsilon(), this, LogicalExpression.True())); break; case SymbolicStringType.Repeat: var v1 = LinearIntegerExpression.FreshVariable(); var v2 = LinearIntegerExpression.FreshVariable(); var v3 = LinearIntegerExpression.FreshVariable(); var sanityConstraint = LogicalExpression.And( ComparisonExpression.GreaterThanOrEqual(v1, 0), ComparisonExpression.GreaterThanOrEqual(v2, 0), ComparisonExpression.GreaterThanOrEqual(v3, 0) ); // Suppose the word w = a_0 a_1 \ldots a_{n-1} // All splits are of the form // BEG: (a_0 \ldots a_{n-1})^i (a_0 \ldots a_p) = w^i . w_1 // MID: (a_{p+1} \ldots a_{n-1} a_0 \ldots a_p)^j (a_{p+1} \ldots a_q) = (w_2 w_1)^j w_3 // END: (a_{q+1} \ldots a_{n-1}) (a_0 \ldots a_{n-1})^k = w_4 w^k var w = this.root.wordSymbols(); var ww = w.Concat(w); int n = w.Count(); for (int w1len = 0; w1len < n; w1len++) { var w_1 = w.Take(w1len); var w_2 = w.Skip(w1len); var beg = SymbolicString.Concat( SymbolicString.Repeat(this.root, v1), SymbolicString.Concat(w_1)); var mid_root = SymbolicString.Concat( SymbolicString.Concat(w_2), SymbolicString.Concat(w_1)); var mid_beg = SymbolicString.Repeat(mid_root, v2); for (int w3len = 0; w3len < n; w3len++) { var w_3 = ww.Skip(w1len).Take(w3len); var mid = SymbolicString.Concat(mid_beg, SymbolicString.Concat(w_3.ToList())); IEnumerable <SymbolicString> w_4; if (w1len + w3len == 0) { w_4 = new List <SymbolicString>(); } else if (w1len + w3len <= n) { w_4 = w.Skip(w1len).Skip(w3len); } else { w_4 = ww.Skip(w1len).Skip(w3len); } var end = SymbolicString.Concat( SymbolicString.Concat(w_4.ToList()), SymbolicString.Repeat(this.root, v3) ); var consumed = (w_1.Count() + w_3.Count() + w_4.Count()) / w.Count(); yield return(Split.MakeSplit( beg, mid, end, LogicalExpression.And( ComparisonExpression.Equal(v1 + v2 + v3 + consumed, this.repeat), sanityConstraint ) )); } } break; case SymbolicStringType.Concat: foreach (var beg_midend in this.TwoSplits()) { foreach (var mid_end in beg_midend.end.TwoSplits()) { yield return(Split.MakeSplit( beg_midend.start, mid_end.start, mid_end.end, LogicalExpression.And(beg_midend.constraints, mid_end.constraints))); } } break; default: throw new ArgumentOutOfRangeException(); } }