public ConditionalDerivative <S> Compose(ConditionalDerivative <S> that)
        {
            var f       = this.Condition;
            var g       = that.Condition;
            var builder = this.PartialDerivative.builder;
            var f_o_g   = ComposeCounterUpdates(f, g);
            var pd      = builder.MkConcat(this.PartialDerivative, that.PartialDerivative);
            var cd      = new ConditionalDerivative <S>(f_o_g, pd);

            return(cd);
        }
Beispiel #2
0
        internal IEnumerable <ConditionalDerivative <S> > EnumerateConditionalDerivatives(S elem, SymbolicRegexNode <S> node)
        {
            if (node == this.dotStar)
            {
                yield return(new ConditionalDerivative <S>(this.dotStar));
            }
            else if (node == this.nothing)
            {
                yield break;
            }
            else
            {
                switch (node.kind)
                {
                case SymbolicRegexKind.StartAnchor:
                case SymbolicRegexKind.EndAnchor:
                case SymbolicRegexKind.Epsilon:
                {
                    yield break;
                }

                case SymbolicRegexKind.Singleton:
                {
                    #region d(a,R) = epsilon if (a in R) else nothing
                    if (this.solver.IsSatisfiable(this.solver.MkAnd(elem, node.set)))
                    {
                        yield return(new ConditionalDerivative <S>(this.epsilon));
                    }
                    yield break;
                    #endregion
                }

                case SymbolicRegexKind.Or:
                {
                    #region d(a,A|B) = d(a,A) U d(a,B)
                    //the hashset is used to eliminate duplicates
                    //for two different members the derivatives may be the same
                    var derivs = new HashSet <ConditionalDerivative <S> >();
                    foreach (var member in node.alts)
                    {
                        foreach (var deriv in this.EnumerateConditionalDerivatives(elem, member))
                        {
                            if (derivs.Add(deriv))
                            {
                                yield return(deriv);
                            }
                        }
                    }
                    yield break;
                    #endregion
                }

                case SymbolicRegexKind.Concat:
                {
                    #region d(a, AB) = d(a,A)B U (if A nullable then d(a,B))
                    //rearrange the concat into left-associative form
                    //knowing that the representation initially is in
                    //right-associative form where none of the elements is itself a sequence
                    //this is crucial for correctness of nullability condition generation
                    var left  = node.left;
                    var right = node.right;
                    while (right.kind == SymbolicRegexKind.Concat)
                    {
                        left  = left.ConcatWithoutNormalizing(right.left);
                        right = right.right;
                    }

                    var derivs = new HashSet <ConditionalDerivative <S> >();
                    //observe that left will be already in the left-assoc form so the above loop will
                    //not be used again to normalize left to left-assoc form in the recursive call
                    foreach (var deriv in this.EnumerateConditionalDerivatives(elem, left))
                    {
                        var deriv1 = new ConditionalDerivative <S>(deriv.Condition,
                                                                   this.MkConcat(deriv.PartialDerivative, right));
                        if (derivs.Add(deriv1))
                        {
                            yield return(deriv1);
                        }
                    }

                    var reset = GetNullabilityCondition_of_left_assoc(left);
                    if (reset != null)
                    {
                        var cd_reset = new ConditionalDerivative <S>(reset, this.epsilon);
                        foreach (var deriv in this.EnumerateConditionalDerivatives(elem, right))
                        {
                            var deriv1 = cd_reset.Compose(deriv);
                            if (derivs.Add(deriv1))
                            {
                                yield return(deriv1);
                            }
                        }
                    }
                    yield break;
                    #endregion
                }

                case SymbolicRegexKind.Loop:
                {
                    #region d(a, R*) = d(a,R)R*
                    if (node.IsStar)
                    {
                        foreach (var step in this.EnumerateConditionalDerivatives(elem, node.left))
                        {
                            var deriv = this.MkConcat(step.PartialDerivative, node);
                            var cd    = new ConditionalDerivative <S>(step.Condition, deriv);
                            yield return(cd);
                        }
                    }
                    //--- already normalized, this should be dead code
                    //else if (node.IsPlus)
                    //{
                    //    var star = this.MkLoop(node.left);
                    //    var expandedloop = this.MkConcat(node.left, star);
                    //    foreach (var deriv in this.EnumerateConditionalDerivatives(elem, expandedloop))
                    //        yield return deriv;
                    //}
                    //else if (node.IsMaybe)
                    //{
                    //    foreach (var step in this.EnumerateConditionalDerivatives(elem, node.left))
                    //        yield return step;
                    //}
                    //else if (node.UpperBound == int.MaxValue)
                    //{
                    //    //normalize A{k,*} loop into A{k}A*
                    //    var Ak = this.MkLoop(node.left, node.lower, node.lower);
                    //    var Astar = this.MkLoop(node.left, 0, int.MaxValue);
                    //    var expandedloop = this.MkConcat(Ak, Astar);
                    //    foreach (var step in this.EnumerateConditionalDerivatives(elem, expandedloop))
                    //        yield return step;
                    //}
                    else
                    {
                        CounterUpdate ca = new CounterUpdate(node, CounterOp.INCREMENT);
                        foreach (var step in this.EnumerateConditionalDerivatives(elem, node.left))
                        {
                            var deriv = this.MkConcat(step.PartialDerivative, node);
                            var cond  = step.Condition.Append(ca);
                            var cd    = new ConditionalDerivative <S>(cond, deriv);
                            yield return(cd);
                        }
                    }
                    yield break;
                    #endregion
                }

                default:
                {
                    throw new NotSupportedException("Conditional derivatives not supported for " + node.kind);
                }
                }
            }
        }