// 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))); } } }
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)) )); } } }
// 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 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> 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); } } }
// Generates splits (x, y, z) such that |y| > 0 and |xy| < p public IEnumerable <Split> ValidSplits( LinearIntegerExpression pumpingLengthVariable, BooleanExpression additionalConstraints) { foreach (var split in this.Splits()) { if (split.mid.isEpsilon()) { continue; } var cond1 = ComparisonExpression.GreaterThan(split.mid.length(), LinearIntegerExpression.Constant(0)); var cond2 = ComparisonExpression.LessThan(split.start.length() + split.mid.length(), pumpingLengthVariable); var condition = LogicalExpression.And(additionalConstraints, cond1, cond2); if (condition.isMaybeSatisfiable()) { split.AddConstraint(condition); yield return(split); } } }
public Dictionary <VariableType, UnaryComparison> getReducedUnaryConstraints() { if (!getComparisonExpressions(constraint).All(expr => expr.isUnary())) { throw new PumpingLemmaException("The Language doesn't contain only unary constraints."); } if (!constraint.isSatisfiable()) { throw new PumpingLemmaException("The Language constraint is not satisfiable."); } Dictionary <VariableType, UnaryComparison> comparisonsToReturn = new Dictionary <VariableType, UnaryComparison>(); IEnumerable <ComparisonExpression> allExpr = getComparisonExpressions(constraint); //delete non-constraints allExpr = allExpr.Except(allExpr.Where(e => e.arithmetic_operand1.isConstant() && e.arithmetic_operand2.isConstant())); //put variable on left side //divide, so that coefficient = 1 HashSet <ComparisonExpression> ToDelete = new HashSet <ComparisonExpression>(); var exprToAdd = new HashSet <ComparisonExpression>(); foreach (ComparisonExpression expr in allExpr) { if (expr.arithmetic_operand1.isConstant()) { switch (expr.comparison_operator) { case ComparisonExpression.ComparisonOperator.GEQ: exprToAdd.Add(ComparisonExpression.LessThanOrEqual(expr.arithmetic_operand2, expr.arithmetic_operand1)); break; case ComparisonExpression.ComparisonOperator.GT: exprToAdd.Add(ComparisonExpression.LessThan(expr.arithmetic_operand2, expr.arithmetic_operand1)); break; case ComparisonExpression.ComparisonOperator.LEQ: exprToAdd.Add(ComparisonExpression.GreaterThanOrEqual(expr.arithmetic_operand2, expr.arithmetic_operand1)); break; case ComparisonExpression.ComparisonOperator.LT: exprToAdd.Add(ComparisonExpression.GreaterThan(expr.arithmetic_operand2, expr.arithmetic_operand1)); break; default: break; } } } ToDelete = new HashSet <ComparisonExpression>(allExpr.Where(e => e.arithmetic_operand1.isConstant())); allExpr = allExpr.Except(ToDelete); allExpr = allExpr.Union(exprToAdd); ToDelete = new HashSet <ComparisonExpression>(); exprToAdd = new HashSet <ComparisonExpression>(); foreach (var expr in allExpr) { foreach (VariableType variable in expr.GetVariables()) { int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; double divided = (double)constant / (double)coefficient; switch (expr.comparison_operator) { case ComparisonExpression.ComparisonOperator.EQ: case ComparisonExpression.ComparisonOperator.NEQ: if (!isInt(divided)) { ToDelete.Add(expr); } else { expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(divided)); } break; case ComparisonExpression.ComparisonOperator.GEQ: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Ceiling(divided))); break; case ComparisonExpression.ComparisonOperator.GT: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Floor(divided))); break; case ComparisonExpression.ComparisonOperator.LEQ: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Floor(divided))); break; case ComparisonExpression.ComparisonOperator.LT: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Ceiling(divided))); break; default: throw new ArgumentException(); } } } allExpr = allExpr.Except(ToDelete); allExpr = allExpr.Union(exprToAdd); ToDelete = new HashSet <ComparisonExpression>(); exprToAdd = new HashSet <ComparisonExpression>(); //reduce if equal constraint is found HashSet <string> varsToDelete = new HashSet <string>(); foreach (ComparisonExpression expr in allExpr) { if (expr.comparison_operator == ComparisonExpression.ComparisonOperator.EQ) { VariableType variable = expr.arithmetic_operand1.GetVariables().First(); int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; int divided = divideConstant(constant, coefficient); comparisonsToReturn.Add(variable, UnaryComparison.equal(variable, divided)); varsToDelete.Add(variable.ToString()); } } IEnumerable <ComparisonExpression> exprToDelete = allExpr.Where(e => varsToDelete.Contains(e.arithmetic_operand1.GetVariables().First().ToString())); allExpr = allExpr.Except(exprToDelete); //GEQ -> GT, LEQ -> LT exprToDelete = new HashSet <ComparisonExpression>(); exprToAdd = new HashSet <ComparisonExpression>(); foreach (ComparisonExpression expr in allExpr) { if (expr.comparison_operator == ComparisonExpression.ComparisonOperator.GEQ) { ComparisonExpression newExpr = ComparisonExpression.GreaterThan(expr.arithmetic_operand1, expr.arithmetic_operand2.constant - 1); exprToAdd.Add(newExpr); } if (expr.comparison_operator == ComparisonExpression.ComparisonOperator.LEQ) { ComparisonExpression newExpr = ComparisonExpression.LessThan(expr.arithmetic_operand1, expr.arithmetic_operand2.constant + 1); exprToAdd.Add(newExpr); } } exprToDelete = allExpr.Where(e => e.comparison_operator == ComparisonExpression.ComparisonOperator.LEQ || e.comparison_operator == ComparisonExpression.ComparisonOperator.GEQ); allExpr = allExpr.Except(exprToDelete); allExpr = allExpr.Union(exprToAdd); HashSet <VariableType> allVars = new HashSet <VariableType>(); foreach (ComparisonExpression expr in allExpr) { allVars.Add(expr.arithmetic_operand1.GetVariables().First()); } foreach (VariableType variable in allVars) { IEnumerable <ComparisonExpression> varExpr = allExpr.Where(e => variable.ToString().Equals(e.GetVariables().First().ToString())); //reduce to single constraints IEnumerable <ComparisonExpression> gtExpr = varExpr.Where(e => e.comparison_operator == ComparisonExpression.ComparisonOperator.GT); int gthan = -1; foreach (ComparisonExpression expr in gtExpr) { int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; //floor int divided = constant / coefficient; if (constant > gthan) { gthan = constant; } } IEnumerable <ComparisonExpression> ltExpr = varExpr.Where(e => e.comparison_operator == ComparisonExpression.ComparisonOperator.LT); int lthan = Int32.MaxValue; foreach (ComparisonExpression expr in ltExpr) { int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; if (constant < lthan) { lthan = constant; } } varExpr = varExpr.Except(gtExpr); varExpr = varExpr.Except(ltExpr); //rest should be NEQ HashSet <int> neqInts = new HashSet <int>(); foreach (ComparisonExpression expr in varExpr) { if (expr.comparison_operator != ComparisonExpression.ComparisonOperator.NEQ) { throw new PumpingLemmaException("The programmer is stupid."); } int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; double divided = (double)constant / coefficient; //if not int, discard if (Math.Abs(divided % 1) <= (Double.Epsilon * 100)) { int divided_int = (int)divided; neqInts.Add(divided_int); } } if (gthan > -1 && lthan < Int32.MaxValue) { comparisonsToReturn.Add(variable, UnaryComparison.between(variable, gthan, lthan, neqInts)); } else if (gthan > -1 && lthan == Int32.MaxValue) { comparisonsToReturn.Add(variable, UnaryComparison.greater(variable, gthan, neqInts)); } else if (gthan == -1 && lthan < Int32.MaxValue) { comparisonsToReturn.Add(variable, UnaryComparison.between(variable, -1, lthan, neqInts)); } else { comparisonsToReturn.Add(variable, UnaryComparison.greater(variable, -1, neqInts)); } } return(comparisonsToReturn); }