public static BooleanExpression containmentCondition(SymbolicString s, ArithmeticLanguage l, BooleanExpression additionalConstraints) { // Console.WriteLine("Checking containment of " + s + " in " + l); var goodMatches = Matcher .match(s, l.symbolic_string) .Select(x => x.forceFinish()) .Select(x => x.withAdditionalConstraint(l.constraint)) .Where(x => x.isFeasible()) ; if (goodMatches.Count() == 0) return LogicalExpression.False(); var matchCondition = LogicalExpression.False(); foreach (var match in goodMatches) { // Console.WriteLine("Got good match: " + match); matchCondition = LogicalExpression.Or(matchCondition, match.constraint); } var condition = LogicalExpression.Implies(additionalConstraints, matchCondition); var variables = condition.GetVariables(); var pVariables = s.GetIntegerVariables(); // Most of the times, should be 1 var nonPVariables = variables.Where(x => !pVariables.Contains(x)); var eCondition = QuantifiedExpression.Exists(nonPVariables, condition); var aCondition = QuantifiedExpression.Forall(pVariables, eCondition); return aCondition; }
private static string pumpedWord(SymbolicString symbStr, Dictionary <VariableType, int> assignment) { StringBuilder sb = new StringBuilder(); switch (symbStr.expression_type) { case SymbolicString.SymbolicStringType.Symbol: return(symbStr.atomic_symbol); case SymbolicString.SymbolicStringType.Concat: foreach (SymbolicString s in symbStr.sub_strings) { sb.Append(pumpedWord(s, assignment)); } return(sb.ToString()); case SymbolicString.SymbolicStringType.Repeat: for (int i = 0; i < symbStr.repeat.constant; i++) { sb.Append(pumpedWord(symbStr.root, assignment)); } foreach (var v in symbStr.repeat.coefficients) { for (int i = 0; i < v.Value * assignment[v.Key]; i++) { sb.Append(pumpedWord(symbStr.root, assignment)); } } return(sb.ToString()); default: throw new ArgumentException(); } }
private bool checkVariableOnce(SymbolicString symbString) { switch (symbString.expression_type) { case SymbolicString.SymbolicStringType.Symbol: return(true); case SymbolicString.SymbolicStringType.Concat: foreach (SymbolicString s in symbString.sub_strings) { if (!checkVariableOnce(s)) { return(false); } } return(true); case SymbolicString.SymbolicStringType.Repeat: HashSet <VariableType> vars = symbString.repeat.GetVariables(); if (varsSeen.Intersect(vars).Any()) { return(false); } varsSeen.UnionWith(vars); return(checkVariableOnce(symbString.root)); default: throw new ArgumentException(); } }
public static BooleanExpression containmentCondition(SymbolicString s, ArithmeticLanguage l, BooleanExpression additionalConstraints) { // Console.WriteLine("Checking containment of " + s + " in " + l); var goodMatches = Matcher .match(s, l.symbolic_string) .Select(x => x.forceFinish()) .Select(x => x.withAdditionalConstraint(l.constraint)) .Where(x => x.isFeasible()) ; if (goodMatches.Count() == 0) { return(LogicalExpression.False()); } var matchCondition = LogicalExpression.False(); foreach (var match in goodMatches) { System.Diagnostics.Debug.WriteLine("Got good match: " + match); matchCondition = LogicalExpression.Or(matchCondition, match.constraint); } var condition = LogicalExpression.Implies(additionalConstraints, matchCondition); var variables = condition.GetVariables(); var pVariables = s.GetIntegerVariables(); // Most of the times, should be 1 var nonPVariables = variables.Where(x => !pVariables.Contains(x)); var eCondition = QuantifiedExpression.Exists(nonPVariables, condition); var aCondition = QuantifiedExpression.Forall(pVariables, eCondition); return(aCondition); }
public static SymbolicString Concat(IEnumerable <SymbolicString> sub_strings) { var ans = new SymbolicString(sub_strings.ToList()); ans.flatten(); return(ans); }
public static SymbolicString repeatLast(SymbolicString s, LinearIntegerExpression e) { if (s == null || e == null) { return(null); } switch (s.expression_type) { case SymbolicString.SymbolicStringType.Symbol: return(SymbolicString.Repeat(s, e)); case SymbolicString.SymbolicStringType.Repeat: return(SymbolicString.Repeat(s, e)); case SymbolicString.SymbolicStringType.Concat: List <SymbolicString> sub_strings = new List <SymbolicString>(); sub_strings.AddRange(s.sub_strings.Take(s.sub_strings.Count - 1)); var last = s.sub_strings[s.sub_strings.Count - 1]; sub_strings.Add(SymbolicString.Repeat(last, e)); return(SymbolicString.Concat(sub_strings)); default: throw new ArgumentOutOfRangeException(); } }
// Match only if both symbols are same private static IEnumerable <Match> matchSymbolSymbol(SymbolicString s1, SymbolicString s2) { if (s2.atomic_symbol == s1.atomic_symbol) { yield return(Match.FullMatch(LogicalExpression.True())); } }
public static bool checkNonContainment(SymbolicString s, ArithmeticLanguage l, BooleanExpression additionalConstraints) { var condition = containmentCondition(s, l, additionalConstraints); // Check if the containment condition is unsatisfiable return(!condition.isSatisfiable()); }
// Returns only those matches where s1 is consumed fully private static IEnumerable <Match> allLeftMatches(SymbolicString s1, SymbolicString s2) { // First empty yield return(Match.PartialSecond( LogicalExpression.And( ComparisonExpression.Equal(s1.length(), 0), ComparisonExpression.GreaterThan(s2.length(), 0) ), s2 )); // First non-empty if (!omegaEqual(s1.root, s2.root)) { // They will mismatch at some point. So, just get small matches up to that point int firstMismatch = getFirstMismatch(s1.root, s2.root); foreach (var m in shortLeftMatches(s1, s2, firstMismatch)) { yield return(m.withAdditionalConstraint(ComparisonExpression.GreaterThan(s1.length(), 0))); } } else { // They will never mismatch. So, split s2 into two parts where s1 = first part foreach (var m in longLeftMatches(s1, s2)) { yield return(m.withAdditionalConstraint(ComparisonExpression.GreaterThan(s1.length(), 0))); } } }
public static string NonRegularCheckWord(ArithmeticLanguage lang, int n, string word) { if (word.Length < n) { return("<false>Word is too short.</false>"); } foreach (char c in word) { if (!lang.alphabet.Contains(c + "")) { return("<false>Word contains illegal letters.</false>"); } } if (lang.symbolic_string.isFlat()) { SymbolicString wordSS = Parser.parseSymbolicString(word, lang.alphabet.ToList()); if (ProofChecker.checkContainment(wordSS, lang, LogicalExpression.True())) { return("<true></true>"); } else { return("<false>Word is not in the language.</false>"); } } else { throw new PumpingLemmaException("Arithmetic Language must be flat!"); } }
public static SymbolicString join(SymbolicString a, SymbolicString b) { if (a == null || b == null) { return(null); } if (a.expression_type == SymbolicString.SymbolicStringType.Concat && b.expression_type == SymbolicString.SymbolicStringType.Concat) { return(SymbolicString.Concat(a.sub_strings.Concat(b.sub_strings))); } List <SymbolicString> sub_strings = new List <SymbolicString>(); if (a.expression_type == SymbolicString.SymbolicStringType.Concat) { sub_strings.AddRange(a.sub_strings); } else { sub_strings.Add(a); } if (b.expression_type == SymbolicString.SymbolicStringType.Concat) { sub_strings.AddRange(b.sub_strings); } else { sub_strings.Add(b); } return(SymbolicString.Concat(sub_strings)); }
public static bool checkContainment(SymbolicString s, ArithmeticLanguage l, BooleanExpression additionalConstraints) { var condition = containmentCondition(s, l, additionalConstraints); // Check if the containment condition is valid return(!LogicalExpression.Not(condition).isSatisfiable()); }
private static IEnumerable <Match> matchRepeatRepeat(SymbolicString s1, SymbolicString s2) { Debug.Assert(s1.root.isWord()); Debug.Assert(s2.root.isWord()); // Assume s1 is fully consumed foreach (var m in allLeftMatches(s1, s2)) { yield return(m); } // Assume s2 is fully consumed foreach (var m in allLeftMatches(s2, s1)) { yield return(m.reverse()); } // Assume both are fully consumed if (omegaEqual(s1.root, s2.root)) { yield return(Match.FullMatch(ComparisonExpression.Equal( LinearIntegerExpression.Times(s1.root.wordLength(), s1.repeat), LinearIntegerExpression.Times(s2.root.wordLength(), s2.repeat) ))); } else { yield return(Match.FullMatch(LogicalExpression.And( ComparisonExpression.Equal(s2.length(), 0), ComparisonExpression.Equal(s1.length(), 0) ))); } }
private static int wordLength(SymbolicString symbStr, Dictionary <VariableType, int> assignment) { int sum; switch (symbStr.expression_type) { case SymbolicString.SymbolicStringType.Symbol: return(1); case SymbolicString.SymbolicStringType.Concat: sum = 0; foreach (SymbolicString s in symbStr.sub_strings) { sum += wordLength(s, assignment); } return(sum); case SymbolicString.SymbolicStringType.Repeat: if (symbStr.repeat.isConstant()) { return(wordLength(symbStr.root, assignment) * symbStr.repeat.constant); } sum = 0; foreach (var v in symbStr.repeat.coefficients) { sum += v.Value * assignment[v.Key] * wordLength(symbStr.root, assignment); } return(sum); default: throw new ArgumentException(); } }
public static Match PartialFirst(BooleanExpression _c, SymbolicString remaining1) { return new Match( _c, remaining1, SymbolicString.Epsilon() ); }
public static Match PartialFirst(BooleanExpression _c, SymbolicString remaining1) { return(new Match( _c, remaining1, SymbolicString.Epsilon() )); }
public static Match PartialSecond(BooleanExpression _c, SymbolicString remaining2) { return(new Match( _c, SymbolicString.Epsilon(), remaining2 )); }
private void Copy(SymbolicString that) { this.expression_type = that.expression_type; this.atomic_symbol = that.atomic_symbol; this.root = that.root; this.repeat = that.repeat; this.sub_strings = that.sub_strings; }
public static Match PartialSecond(BooleanExpression _c, SymbolicString remaining2) { return new Match( _c, SymbolicString.Epsilon(), remaining2 ); }
public static Match FullMatch(BooleanExpression _c) { return(new Match( _c, SymbolicString.Epsilon(), SymbolicString.Epsilon() )); }
public static SymbolicString repeat(SymbolicString s, LinearIntegerExpression e) { if (s == null || e == null) { return(null); } return(SymbolicString.Repeat(s, e)); }
public static bool canMismatchWitness( SymbolicString midLanguage, SymbolicString midSplit, BooleanExpression fullConstraint, LinearIntegerExpression pumpingWitness ) { throw new NotImplementedException(); }
public TwoSplit extend(SymbolicString prefix, SymbolicString suffix) { var new_start = SymbolicString.Concat(prefix, start); var new_end = SymbolicString.Concat(end, suffix); new_start.flatten(); new_end.flatten(); return(MakeSplit(new_start, new_end, constraints)); }
internal IEnumerable<Match> continueMatch(SymbolicString rest1, SymbolicString rest2) { var cont1 = SymbolicString.Concat(this.remaining1, rest1); var cont2 = SymbolicString.Concat(this.remaining2, rest2); foreach (var mp in Matcher.match(cont1, cont2)) { yield return mp.withAdditionalConstraint(this.constraint); } }
/* * // If symbols are allowed to be more than one character * public static List<String> splitIntoAlphabetSymbols(string text, List<String> alphabet) * { * List<String> return_tokens = null; * if (text.Length == 0) * { * return_tokens = new List<string>(); * return return_tokens; * } * foreach (string symbol in alphabet) * { * if (text.StartsWith(symbol)) * { * List<String> sub = splitIntoAlphabetSymbols(text.Substring(symbol.Length), alphabet); * if (sub != null) * { * sub.Insert(0, symbol); * if (return_tokens != null) * { * // Multiple parses * return_tokens = null; * break; * } * else * { * return_tokens = sub; * } * } * } * } * return return_tokens; * } */ public static SymbolicString wordToSymbolicString(List <String> symbols) { if (symbols.Count == 1) { return(SymbolicString.Symbol(symbols[0])); } return(SymbolicString.Concat( symbols.Select(x => SymbolicString.Symbol(x)).ToList() )); }
private Split(SymbolicString s, SymbolicString m, SymbolicString e, BooleanExpression c) { start = s; mid = m; end = e; start.flatten(); mid.flatten(); end.flatten(); constraints = c; }
internal IEnumerable <Match> continueMatch(SymbolicString rest1, SymbolicString rest2) { var cont1 = SymbolicString.Concat(this.remaining1, rest1); var cont2 = SymbolicString.Concat(this.remaining2, rest2); foreach (var mp in Matcher.match(cont1, cont2)) { yield return(mp.withAdditionalConstraint(this.constraint)); } }
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)) )); } } }
int getNumberOfMatches(SymbolicString s1, SymbolicString s2) { Console.WriteLine("Matching " + s1 + " with " + s2); int count = 0; foreach (var m in Matcher.match(s1, s2)) { Console.WriteLine("\t" + m); count++; } return count; }
public static Tuple <string, string, string> NonRegularGetPumpableSplit(ArithmeticLanguage language, string word, int n) { foreach (var split in possibleSplits(word, n)) { SymbolicString str = splitToSymbStr(language.alphabet.ToList(), split.Item1, split.Item2, split.Item3); if (ProofChecker.checkContainment(str, language, LogicalExpression.True())) { return(split); } } return(null); }
public static bool NonRegularCheckI(ArithmeticLanguage language, string start, string mid, string end, int i) { string fullWord = pumpMid(start, mid, end, i); if (language.symbolic_string.isFlat()) { SymbolicString wordSS = Parser.parseSymbolicString(fullWord.ToString(), language.alphabet.ToList()); return(ProofChecker.checkContainment(wordSS, language, LogicalExpression.True())); } else { throw new PumpingLemmaException("Arithmetic Language must be flat!"); } }
public static bool check(ArithmeticLanguage language, SymbolicString pumpingString) { if (pumpingString.GetIntegerVariables().Count() != 1) { return(false); } var pumpingLength = pumpingString.GetIntegerVariables().First(); var pumpingLengthVariable = PumpingLemma.LinearIntegerExpression .SingleTerm(1, pumpingLength); var additionalConstraint = LogicalExpression.And( PumpingLemma.ComparisonExpression.GreaterThan(pumpingLengthVariable, 0), LogicalExpression.And(pumpingString.repeats().Select(x => ComparisonExpression.GreaterThanOrEqual(x, 0))) ); // 0. Need to check if pumping string grows unboundedly with p var pumpingStringLength = pumpingString.length(); if (pumpingStringLength.isConstant() || pumpingStringLength.coefficients[pumpingLength] < 0) { return(false); } foreach (var r in pumpingString.repeats()) { if (r.coefficients[pumpingLength] < 0) { return(false); } } // 1. Check that the pumping string is in the language for all p if (!checkContainment(pumpingString, language, additionalConstraint)) { return(false); } Console.WriteLine("Language is non-regular if all the following splits are good:"); int i = 0; // 2. Check that each split of the pumping string has an valid pumping length foreach (var split in pumpingString.ValidSplits(pumpingLengthVariable, additionalConstraint)) { Console.WriteLine("\t" + (i++) + ": " + split + " when " + additionalConstraint); if (!splitGood(split, language, additionalConstraint)) { return(false); } } return(true); }
public static bool canMismatchOne(SymbolicString language, SymbolicString midSplit, BooleanExpression fullConstraint) { /* * var matches = Matcher * .matchRepeatedFull(language, midSplit) * .Select(x => x.finishMatch()); * foreach (var match in matches) * { * var x = LogicalExpression.And(match.constraint, fullConstraint); * // Do something here * } */ throw new NotImplementedException(); }
private static IEnumerable <Match> matchConcatConcat(SymbolicString s1, SymbolicString s2) { if (s1.isEpsilon() || s2.isEpsilon()) { yield return(Match.MakeMatch(LogicalExpression.True(), s1, s2)); yield break; } // Quick match prefix symbols int i; for (i = 0; i < s1.sub_strings.Count && i < s2.sub_strings.Count; i++) { if (s1.sub_strings[i].expression_type != SymbolicString.SymbolicStringType.Symbol || s2.sub_strings[i].expression_type != SymbolicString.SymbolicStringType.Symbol) { break; } if (s1.sub_strings[i].atomic_symbol != s2.sub_strings[i].atomic_symbol) { yield break; } } var sub1 = s1.sub_strings.Skip(i); var sub2 = s2.sub_strings.Skip(i); // If we have consumed something fully, just return the remaining bits if (i == s1.sub_strings.Count || i == s2.sub_strings.Count) { yield return(Match.MakeMatch( LogicalExpression.True(), SymbolicString.Concat(sub1), SymbolicString.Concat(sub2))); yield break; } var rest1 = SymbolicString.Concat(sub1.Skip(1)); var rest2 = SymbolicString.Concat(sub2.Skip(1)); foreach (var m in match(sub1.First(), sub2.First())) { foreach (var mp in m.continueMatch(rest1, rest2)) { yield return(mp); } } }
public static string NonRegularGetUnpumpableWord(ArithmeticLanguage language, SymbolicString unpumpableWord, int n) { Dictionary <VariableType, int> assignment = new Dictionary <VariableType, int>(); assignment.Add(VariableType.Variable("n"), n); string word = pumpedWord(unpumpableWord, assignment); SymbolicString ss = SymbolicString.FromTextDescription(language.alphabet.ToList(), word); while (!ProofChecker.checkContainment(ss, language, LogicalExpression.True())) { assignment[VariableType.Variable("n")]++; word = pumpedWord(unpumpableWord, assignment); ss = SymbolicString.FromTextDescription(language.alphabet.ToList(), word); } return(word); }
public static bool checkPumping( ArithmeticLanguage language, SymbolicString pumpingString, Split split, LinearIntegerExpression pump) { if (pump.isConstant()) { var k = pump.constant; var pumpedMid = SymbolicString.Concat(Enumerable.Repeat(split.mid, k)); var pumpedString = SymbolicString.Concat(split.start, pumpedMid, split.end); return checkNonContainment(pumpedString, language, split.constraints); } else { throw new NotImplementedException(); } }
public static bool check(ArithmeticLanguage language, SymbolicString pumpingString) { if (pumpingString.GetIntegerVariables().Count() != 1) return false; var pumpingLength = pumpingString.GetIntegerVariables().First(); var pumpingLengthVariable = PumpingLemma.LinearIntegerExpression .SingleTerm(1, pumpingLength); var additionalConstraint = LogicalExpression.And( PumpingLemma.ComparisonExpression.GreaterThan(pumpingLengthVariable, 0), LogicalExpression.And(pumpingString.repeats().Select(x => ComparisonExpression.GreaterThanOrEqual(x, 0))) ); // 0. Need to check if pumping string grows unboundedly with p var pumpingStringLength = pumpingString.length(); if (pumpingStringLength.isConstant() || pumpingStringLength.coefficients[pumpingLength] < 0) return false; foreach (var r in pumpingString.repeats()) if (r.coefficients[pumpingLength] < 0) return false; // 1. Check that the pumping string is in the language for all p if (!checkContainment(pumpingString, language, additionalConstraint)) return false; Console.WriteLine("Language is non-regular if all the following splits are good:"); int i = 0; // 2. Check that each split of the pumping string has an valid pumping length foreach (var split in pumpingString.ValidSplits(pumpingLengthVariable, additionalConstraint)) { Console.WriteLine("\t" + (i++) + ": " + split + " when " + additionalConstraint); if (!splitGood(split, language, additionalConstraint)) return false; } return true; }
private Match(BooleanExpression _c, SymbolicString _s1, SymbolicString _s2) { this.constraint = _c; this.remaining1 = _s1; this.remaining2 = _s2; }
// Match only if both symbols are same private static IEnumerable<Match> matchSymbolSymbol(SymbolicString s1, SymbolicString s2) { if (s2.atomic_symbol == s1.atomic_symbol) yield return Match.FullMatch(LogicalExpression.True()); }
// Either consume symbol with first symbol of repeat and say repeat is positive // Or don't consume symbol and say repeat is zero private static IEnumerable<Match> matchSymbolRepeat(SymbolicString s1, SymbolicString s2) { Debug.Assert(s2.isFlat()); // When repeat is 0 yield return Match.PartialFirst(ComparisonExpression.Equal(s2.repeat, 0), s1); // When repeat is non-zero foreach (var m in match(s1, s2.root)) { // Because the root is a word, we immediately know if the symbol matches or not // and get an m if and only if the symbol matches Debug.Assert(!m.FirstRemaining); yield return Match.PartialSecond( LogicalExpression.And(m.constraint, ComparisonExpression.GreaterThan(s2.repeat, 0)), SymbolicString.Concat(m.remaining2, SymbolicString.Repeat(s2.root, s2.repeat - 1)) ); } }
private SymbolicString(SymbolicString root, LinearIntegerExpression repeat) { this.expression_type = SymbolicStringType.Repeat; this.root = root; this.repeat = repeat; }
public static SymbolicString repeatLast(SymbolicString s, LinearIntegerExpression e) { if (s == null || e == null) return null; switch(s.expression_type) { case SymbolicString.SymbolicStringType.Symbol: return SymbolicString.Repeat(s, e); case SymbolicString.SymbolicStringType.Repeat: return SymbolicString.Repeat(s, e); case SymbolicString.SymbolicStringType.Concat: List<SymbolicString> sub_strings = new List<SymbolicString>(); sub_strings.AddRange(s.sub_strings.Take(s.sub_strings.Count - 1)); var last = s.sub_strings[s.sub_strings.Count - 1]; sub_strings.Add(SymbolicString.Repeat(last, e)); return SymbolicString.Concat(sub_strings); default: throw new ArgumentOutOfRangeException(); } }
public static SymbolicString join(SymbolicString a, SymbolicString b) { if (a == null || b == null) return null; if (a.expression_type == SymbolicString.SymbolicStringType.Concat && b.expression_type == SymbolicString.SymbolicStringType.Concat) { return SymbolicString.Concat(a.sub_strings.Concat(b.sub_strings)); } List<SymbolicString> sub_strings = new List<SymbolicString>(); if (a.expression_type == SymbolicString.SymbolicStringType.Concat) sub_strings.AddRange(a.sub_strings); else sub_strings.Add(a); if (b.expression_type == SymbolicString.SymbolicStringType.Concat) sub_strings.AddRange(b.sub_strings); else sub_strings.Add(b); return SymbolicString.Concat(sub_strings); }
public static SymbolicString Concat(IEnumerable<SymbolicString> sub_strings) { var ans = new SymbolicString(sub_strings.ToList()); ans.flatten(); return ans; }
internal static Match MakeMatch(BooleanExpression _c, SymbolicString remaining1, SymbolicString remaining2) { return new Match(_c, remaining1, remaining2); }
// s1 and s2 are omega equal if s1^\omega = s2^\omega // Theorem: s1 and s2 are omega equal if and only if there // exists a w such that s1 = w^(l1/g) and s2 = w^(l2/g) // where l1, l2 are lengths of s1 and s2, and g = gcd(l1, l2) private static bool omegaEqual(SymbolicString s1, SymbolicString s2) { Debug.Assert(s1.isWord() && s2.isWord()); var l1 = s1.wordLength(); var l2 = s2.wordLength(); var g = gcd(l1, l2); var w1 = s1.word().ToArray(); for (int i = 0; i < l1; i++) if (w1[i] != w1[i % g]) return false; var w2 = s2.word().ToArray(); for (int i = 0; i < l2; i++) if (w2[i] != w2[i % g]) return false; for (int i = 0; i < g; i++) if (w1[i] != w2[i]) return false; return true; }
// Call only when omegaEqual(s1, s2) holds // TODO: There is definitely a more optimal implementation of this private static int getFirstMismatch(SymbolicString s1, SymbolicString s2) { Debug.Assert(s1.isWord() && s2.isWord()); var l1 = s1.wordLength(); var l2 = s2.wordLength(); var w1 = s1.word().ToArray(); var w2 = s2.word().ToArray(); for (int i = 0; true; i++) { if (w1[i % l1] != w2[i % l2]) return i; } }
private static IEnumerable<Match> shortLeftMatches(SymbolicString s1, SymbolicString s2, int firstMismatch) { int l1 = s1.root.wordLength(); for (int i = 1; l1 * i <= firstMismatch; i++) { var s1r = SymbolicString.Concat(Enumerable.Repeat(s1.root, i)); foreach (var m in match(s1r, s2)) { if (m.FirstRemaining) continue; yield return m.withAdditionalConstraint(LogicalExpression.And( ComparisonExpression.Equal(s1.length(), s1r.length()), ComparisonExpression.GreaterThan(m.remaining2.length(), 0) )); } } }
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)) ); } } }
// Returns only those matches where s1 is consumed fully private static IEnumerable<Match> allLeftMatches(SymbolicString s1, SymbolicString s2) { // First empty yield return Match.PartialSecond( LogicalExpression.And( ComparisonExpression.Equal(s1.length(), 0), ComparisonExpression.GreaterThan(s2.length(), 0) ), s2 ); // First non-empty if (!omegaEqual(s1.root, s2.root)) { // They will mismatch at some point. So, just get small matches up to that point int firstMismatch = getFirstMismatch(s1.root, s2.root); foreach (var m in shortLeftMatches(s1, s2, firstMismatch)) yield return m.withAdditionalConstraint(ComparisonExpression.GreaterThan(s1.length(), 0)); } else { // They will never mismatch. So, split s2 into two parts where s1 = first part foreach (var m in longLeftMatches(s1, s2)) yield return m.withAdditionalConstraint(ComparisonExpression.GreaterThan(s1.length(), 0)); } }
// Just dispatches to the appropriate helper method public static IEnumerable<Match> match(SymbolicString s1, SymbolicString s2) { Debug.Assert(s1.isFlat() && s2.isFlat()); Func<SymbolicString.SymbolicStringType, string> toSignature = (ss_type) => { switch(ss_type) { case SymbolicString.SymbolicStringType.Symbol: return "S"; case SymbolicString.SymbolicStringType.Repeat: return "R"; case SymbolicString.SymbolicStringType.Concat: return "C"; default: throw new ArgumentException(); } }; switch (toSignature(s1.expression_type) + toSignature(s2.expression_type)) { case "RS": case "CS": case "CR": return match(s2, s1).Select(x => x.reverse()); case "SS": return matchSymbolSymbol(s1, s2); case "SR": return matchSymbolRepeat(s1, s2); case "SC": return matchSymbolConcat(s1, s2); case "RR": return matchRepeatRepeat(s1, s2); case "RC": return matchRepeatConcat(s1, s2); case "CC": return matchConcatConcat(s1, s2); default: throw new ArgumentException(); } }
private static IEnumerable<Match> matchRepeatRepeat(SymbolicString s1, SymbolicString s2) { Debug.Assert(s1.root.isWord()); Debug.Assert(s2.root.isWord()); // Assume s1 is fully consumed foreach (var m in allLeftMatches(s1, s2)) yield return m; // Assume s2 is fully consumed foreach (var m in allLeftMatches(s2, s1)) yield return m.reverse(); // Assume both are fully consumed if (omegaEqual(s1.root, s2.root)) { yield return Match.FullMatch(ComparisonExpression.Equal( LinearIntegerExpression.Times(s1.root.wordLength(), s1.repeat), LinearIntegerExpression.Times(s2.root.wordLength(), s2.repeat) )); } else { yield return Match.FullMatch(LogicalExpression.And( ComparisonExpression.Equal(s2.length(), 0), ComparisonExpression.Equal(s1.length(), 0) )); } }
public static SymbolicString Repeat(SymbolicString root, LinearIntegerExpression repeat) { return new SymbolicString(root, repeat); }
private static IEnumerable<Match> matchRepeatConcat(SymbolicString s1, SymbolicString s2) { if (s2.isEpsilon()) { yield return Match.FullMatch(ComparisonExpression.Equal(s1.length(), 0)); yield return Match.PartialFirst(ComparisonExpression.GreaterThan(s1.length(), 0), s1); yield break; } var first = s2.sub_strings.First(); var rest = SymbolicString.Concat(s2.sub_strings.Skip(1)); foreach (var m in match(s1, first)) foreach (var mp in m.continueMatch(SymbolicString.Epsilon(), rest)) yield return mp; }
private static IEnumerable<Match> matchConcatConcat(SymbolicString s1, SymbolicString s2) { if (s1.isEpsilon() || s2.isEpsilon()) { yield return Match.MakeMatch(LogicalExpression.True(), s1, s2); yield break; } // Quick match prefix symbols int i; for (i = 0; i < s1.sub_strings.Count && i < s2.sub_strings.Count; i++) { if (s1.sub_strings[i].expression_type != SymbolicString.SymbolicStringType.Symbol || s2.sub_strings[i].expression_type != SymbolicString.SymbolicStringType.Symbol) break; if (s1.sub_strings[i].atomic_symbol != s2.sub_strings[i].atomic_symbol) yield break; } var sub1 = s1.sub_strings.Skip(i); var sub2 = s2.sub_strings.Skip(i); // If we have consumed something fully, just return the remaining bits if (i == s1.sub_strings.Count || i == s2.sub_strings.Count) { yield return Match.MakeMatch( LogicalExpression.True(), SymbolicString.Concat(sub1), SymbolicString.Concat(sub2)); yield break; } var rest1 = SymbolicString.Concat(sub1.Skip(1)); var rest2 = SymbolicString.Concat(sub2.Skip(1)); foreach (var m in match(sub1.First(), sub2.First())) foreach (var mp in m.continueMatch(rest1, rest2)) yield return mp; }
public static SymbolicString repeat(SymbolicString s, LinearIntegerExpression e) { if (s == null || e == null) return null; return SymbolicString.Repeat(s, e); }
private static IEnumerable<Match> matchSymbolConcat(SymbolicString s1, SymbolicString s2) { if (s2.isEpsilon()) { yield return Match.PartialFirst(LogicalExpression.True(), s1); yield break; } var rest = SymbolicString.Concat(s2.sub_strings.Skip(1)); foreach (var m in match(s1, s2.sub_strings.First())) foreach (var mp in m.continueMatch(SymbolicString.Epsilon(), rest)) yield return mp; }
public static bool checkContainment(SymbolicString s, ArithmeticLanguage l, BooleanExpression additionalConstraints) { var condition = containmentCondition(s, l, additionalConstraints); // Check if the containment condition is valid return !LogicalExpression.Not(condition).isSatisfiable(); }
private ArithmeticLanguage(IEnumerable<String> _alphabet, SymbolicString _symbolic_string, BooleanExpression _constraint) { this.alphabet = _alphabet; this.symbolic_string = _symbolic_string; this.constraint = _constraint; }