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); }
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); } } } }