// Strategy:
        // a) Match the prefix and suffix of the language with the x and z
        // b) See if y can be pumped against the middle part
        // The horrifying part is the quantifiers
        public static bool splitGood(Split split, ArithmeticLanguage language, BooleanExpression additionalConstraint)
        {
            // We just need to find a k such that (x y^k z) \not\in L
            // If we cannot find such a k for some p, it is a bad split

            // Say i, j are the variables in the language constraint and
            // v_1, v_2 are variables in split constraints
            // Therefore, if for all p, v_1, \ldots, v_n that satisfies split constraints
            // and additional constraints and exists k such that for all i, j language
            // constraint does not hold, then split is bad
            Console.WriteLine("\t\tSplit is good if none of the following mids can be pumped: ");

            // We will definitely go through the loop at least once as match is working
            var beginningMatches = Matcher
                                   .match(split.start, language.symbolic_string)
                                   .Where(x => !x.FirstRemaining)
                                   .Select(x => x.withAdditionalConstraint(language.constraint))
                                   .Select(x => x.withAdditionalConstraint(additionalConstraint))
                                   .Where(x => x.isFeasible());

            foreach (var beginMatch in beginningMatches)
            {
                var remainingLanguage = beginMatch.remaining2;
                var endMatches        = Matcher
                                        .match(split.end.reverse(), remainingLanguage.reverse())
                                        .Where(x => !x.FirstRemaining)
                                        .Select(x => x.withAdditionalConstraint(language.constraint))
                                        .Select(x => x.withAdditionalConstraint(additionalConstraint))
                                        .Where(x => x.isFeasible());

                foreach (var endMatch in endMatches)
                {
                    var fullConstraint = LogicalExpression.And(beginMatch.constraint, endMatch.constraint);
                    if (!fullConstraint.isSatisfiable())
                    {
                        continue;
                    }
                    var midLanguage = endMatch.remaining2.reverse();
                    var midSplit    = split.mid;
                    var ctx         = new Context();
                    // Console.WriteLine("\t\t" + midLanguage + " ===== " + midSplit + " when " + fullConstraint);
                    // var z3exp = fullConstraint.toZ3(ctx).Simplify();
                    // Console.WriteLine("\t\t" + midLanguage + " ===== " + midSplit + " when " + z3exp);
                    if (!canMismatchOne(midLanguage, midSplit, fullConstraint))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
예제 #2
0
        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);
        }
예제 #4
0
        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);
                }
            }
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
                }
            }
        }
예제 #7
0
        // 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))
                                 ));
            }
        }
예제 #8
0
        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)
                                                                )));
                }
            }
        }
예제 #9
0
        public Match forceFinish()
        {
            BooleanExpression additionalConstraint = LogicalExpression.True();

            if (FirstRemaining)
            {
                additionalConstraint = LogicalExpression.And(
                    additionalConstraint,
                    ComparisonExpression.Equal(remaining1.length(), 0)
                    );
            }
            if (SecondRemaining)
            {
                additionalConstraint = LogicalExpression.And(
                    additionalConstraint,
                    ComparisonExpression.Equal(remaining2.length(), 0)
                    );
            }
            return(FullMatch(LogicalExpression.And(this.constraint, additionalConstraint)));
        }
예제 #10
0
        // 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);
                }
            }
        }
예제 #11
0
        public static int NonRegularGetI(ArithmeticLanguage language, string start, string mid, string end)
        {
            SymbolicString matchingString = splitToSymbStr(language.alphabet.ToList(), start, mid, end);

            if (ProofChecker.checkContainment(matchingString, language, LogicalExpression.True()))
            {
                return(1); // AI surrenders
            }
            else
            {
                int i = 0;
                do
                {
                    string         word = pumpMid(start, mid, end, i);
                    SymbolicString ss   = SymbolicString.FromTextDescription(language.alphabet.ToList(), word);
                    if (!ProofChecker.checkContainment(ss, language, LogicalExpression.True()))
                    {
                        return(i);
                    }
                    i++;
                } while (i < 99); //for debugging purposes
                return(-1);
            }
        }
 public void AddConstraint(BooleanExpression c)
 {
     this.constraints = LogicalExpression.And(this.constraints, c);
 }
 public static BooleanExpression And(IEnumerable <BooleanExpression> ops)
 {
     return(ops.Aggregate(LogicalExpression.True() as BooleanExpression, (x, y) => And(x, y)));
 }
예제 #14
0
        // 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();
            }
        }
예제 #15
0
        // 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();
            }
        }
예제 #16
0
        // Generates XML for the
        public XElement SplitDisplayXML(
            VariableType pumpingLength,
            BooleanExpression additionalConstraints)
        {
            Contract.Assert(additionalConstraints.GetVariables().Count() <= 1);
            if (additionalConstraints.GetVariables().Count == 1)
            {
                Contract.Assert(additionalConstraints.GetVariables().First().Equals(pumpingLength));
            }
            var pumpingLengthVariable = LinearIntegerExpression.SingleTerm(1, pumpingLength);

            var repeatLengths = repeats();

            // For great and inexplicable reasons. Trust me, it looks better this way.
            var displayConstraints = LogicalExpression.And(repeatLengths.Select(x =>
                                                                                ComparisonExpression.GreaterThanOrEqual(x, LinearIntegerExpression.Constant(5))
                                                                                ));

            XElement symbstrings = new XElement("symbstrings");

            foreach (var split in this.ValidSplits(pumpingLengthVariable, additionalConstraints))
            {
                var splitRepeatLengths = split.start.repeats();
                splitRepeatLengths.AddRange(split.mid.repeats());
                splitRepeatLengths.AddRange(split.end.repeats());

                // Get models that don't look terrible
                var splitDisplayConstraints = LogicalExpression.And(splitRepeatLengths.Select(x =>
                                                                                              ComparisonExpression.GreaterThanOrEqual(x, LinearIntegerExpression.Constant(1))
                                                                                              ));
                var constraint = LogicalExpression.And(displayConstraints, split.constraints, splitDisplayConstraints);

                if (!constraint.isSatisfiable())
                {
                    continue;
                }
                var splitModel = constraint.getModel();

                var symbstr = new XElement("symbstr");
                var strings = new XElement("strings");
                var splits  = new XElement("splits");
                var constrs = new XElement("constraints");

                Func <string, Tuple <int, int, SymbolicString>, XElement> handleSegment = (parentTagName, segment) => {
                    var parent = new XElement(parentTagName);
                    var from   = new XElement("from"); from.Value = segment.Item1.ToString();
                    var to     = new XElement("to"); to.Value = segment.Item2.ToString();
                    var label  = new XElement("label"); label.Add(segment.Item3.ToDisplayXML());
                    parent.Add(from);
                    parent.Add(to);
                    parent.Add(label);
                    return(parent);
                };

                int strIndex = 0;
                foreach (var segment in getSegments(splitModel, ref strIndex))
                {
                    strings.Add(handleSegment("string", segment));
                }

                int splitIndex = 0;
                foreach (var segment in new[] { split.start, split.mid, split.end })
                {
                    splits.Add(handleSegment("split", segment.makeSegment(splitModel, ref splitIndex)));
                }

                var constr = new XElement("constraint");
                constr.Add(split.constraints.ToDisplayXML());
                constrs.Add(constr);

                symbstr.Add(strings);
                symbstr.Add(splits);
                symbstr.Add(constrs);
                symbstrings.Add(symbstr);
            }

            return(symbstrings);
        }
 public static BooleanExpression Implies(BooleanExpression op1, BooleanExpression op2)
 {
     return(LogicalExpression.Or(LogicalExpression.Not(op1), op2));
 }
        public static ArithmeticLanguage FromTextDescriptions(List <String> alphabet, string symbolicStringText, string constraintText)
        {
            var symbolPattern  = new Regex(@"^[a-zA-Z0-9]$");
            var illegalSymbols = alphabet.FindAll(s => !symbolPattern.IsMatch(s));

            if (illegalSymbols.Count > 0)
            {
                var message = string.Format(
                    "Found illegal symbols {0} in alphabet. Symbols should match [a-zA-Z0-9]",
                    string.Join(", ", illegalSymbols)
                    );
                throw new PumpingLemmaException(message);
            }

            // Parse the language
            var ss = PumpingLemma.Parser.parseSymbolicString(symbolicStringText, alphabet);

            if (ss == null)
            {
                throw new PumpingLemmaException("Unable to parse language");
            }

            // Parse the constraintDesc
            var constraint = PumpingLemma.Parser.parseCondition(constraintText);

            if (constraint == null)
            {
                throw new PumpingLemmaException("Unable to parse constraint");
            }

            // Make sure all the variables are bound
            var boundVariables      = ss.GetIntegerVariables();
            var constraintVariables = constraint.GetVariables();

            // Console.WriteLine("Bound variables: " + String.Join(", ", boundVariables));
            // Console.WriteLine("Constriant variables: " + String.Join(", ", constraintVariables));
            foreach (var consVar in constraintVariables)
            {
                if (!boundVariables.Contains(consVar))
                {
                    throw new PumpingLemmaException(
                              string.Format("Constraint variable {0} not bound", consVar));
                }
            }

            // Add constraints saying that all variables are >= 0
            BooleanExpression defaultConstraint = LogicalExpression.True();

            foreach (var consVar in constraintVariables)
            {
                defaultConstraint = LogicalExpression.And(
                    defaultConstraint,
                    ComparisonExpression.GreaterThanOrEqual(
                        LinearIntegerExpression.SingleTerm(1, consVar),
                        LinearIntegerExpression.Constant(0)
                        )
                    );
            }

            return(new ArithmeticLanguage(alphabet, ss, constraint));
        }
 public static BooleanExpression And(params BooleanExpression[] ops)
 {
     return(ops.Aggregate(LogicalExpression.True() as BooleanExpression, (x, y) => And(x, y)));
 }