public PatternMatcher(IStreamable <TKey, TPayload> source = default, Afa <TPayload, TRegister, TAccumulator> afa = default, TRegister defaultRegister = default, TAccumulator defaultAccumulator = default) { this.source = source; this.AFA = afa; this.defaultRegister = defaultRegister; this.defaultAccumulator = defaultAccumulator; }
public IPattern <TKey, TPayload, TRegister, TAccumulator> KleeneStar( Func <IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator>, IPattern <TKey, TPayload, TRegister, TAccumulator> > pattern) { var newConcreteRegex = pattern(new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>()); var result = new Afa <TPayload, TRegister, TAccumulator>(); var pattern_ = (Afa <TPayload, TRegister, TAccumulator>)newConcreteRegex.AFA; // Every final state maps back to the start state foreach (var kvp1 in pattern_.transitionInfo) { foreach (var kvp2 in kvp1.Value) { var to = kvp2.Key; if (pattern_.finalStates.Contains(to)) { to = pattern_.StartState; } result.AddArc(kvp1.Key, to, kvp2.Value); } } // Start state becomes the single final state result.finalStates.Add(pattern_.StartState); result.StartState = pattern_.StartState; return(Concat(x => new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>(this.source, result))); }
public IPattern <TKey, TPayload, TRegister, TAccumulator> Or( Func <IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator>, IPattern <TKey, TPayload, TRegister, TAccumulator> > pattern1, Func <IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator>, IPattern <TKey, TPayload, TRegister, TAccumulator> > pattern2, params Func <IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator>, IPattern <TKey, TPayload, TRegister, TAccumulator> >[] patterns) { var allPatterns = new Afa <TPayload, TRegister, TAccumulator> [patterns.Length + 2]; allPatterns[0] = pattern1(new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>()).AFA; allPatterns[1] = pattern2(new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>()).AFA; for (int i = 0; i < patterns.Length; i++) { allPatterns[i + 2] = patterns[i](new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>()).AFA; } var result = new Afa <TPayload, TRegister, TAccumulator>(this.defaultRegister, this.defaultAccumulator); int oldMax; for (int i = 0; i < allPatterns.Length; i++) { var nextPattern = allPatterns[i]; oldMax = result.MaxState + 1; result.AddArc(0, nextPattern.StartState + oldMax, new EpsilonArc <TPayload, TRegister>()); // If the next pattern start state is also a final state, add it directly, as it will not necessarily have a transition entry if (nextPattern.finalStates.Contains(nextPattern.StartState)) { if (!result.finalStates.Contains(nextPattern.StartState + oldMax)) { result.finalStates.Add(nextPattern.StartState + oldMax); } } foreach (var kvp1 in nextPattern.transitionInfo) { foreach (var kvp2 in kvp1.Value) { int from = kvp1.Key + oldMax; int to = kvp2.Key + oldMax; result.AddArc(from, to, kvp2.Value); if (nextPattern.finalStates.Contains(kvp2.Key)) { if (!result.finalStates.Contains(to)) { result.finalStates.Add(to); } } } } } result.StartState = 0; return(Concat(x => new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>(this.source, result))); }
/// <summary> /// Creates a new pattern with a register and adds an epsilon transition /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <returns>A pattern whose first transition is the one just created</returns> public static Afa <TInput, TRegister, bool> Epsilon <TInput, TRegister>() { var afa = Afa.Create <TInput, TRegister>(); afa.AddArc(0, 1, new EpsilonArc <TInput, TRegister> { }); afa.Seal(); return(afa); }
/// <summary> /// Creates a new pattern without a register and adds an epsilon transition /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <returns>A pattern whose first transition is the one just created</returns> public static Afa <TInput, Empty, bool> Epsilon <TInput>() { var afa = Afa.Create <TInput>(); afa.AddArc(0, 1, new EpsilonArc <TInput, Empty> { }); afa.Seal(); return(afa); }
public CompiledAfa(Afa <TPayload, TRegister, TAccumulator> afa) { if (!afa.IsSealed()) { throw new Exception("Cannot compile an unsealed AFA"); } this.uncompiledAfa = afa; CompileAfa(afa); }
/// <summary> /// Creates a new pattern with a register and adds a time-synchronous list transition that succeeds on event lists that match a condition /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <param name="condition">The time-sensitive, register-value sensitive condition that must be met to consider the transition satisfied</param> /// <param name="aggregator">A time-sensitive aggregator mutator that updates the value of the register</param> /// <returns>A pattern with an updatable register whose first transition is the one just created</returns> public static Afa <TInput, TRegister, bool> ListElement <TInput, TRegister>(Expression <Func <long, List <TInput>, TRegister, bool> > condition, Expression <Func <long, List <TInput>, TRegister, TRegister> > aggregator) { var afa = Afa.Create <TInput, TRegister>(); afa.AddArc(0, 1, new ListElementArc <TInput, TRegister> { Fence = condition, Transfer = aggregator }); afa.Seal(); return(afa); }
/// <summary> /// Creates a new pattern with a register and adds a single-element transition that succeeds on every stream element seen /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <returns>A pattern with an updatable register whose first transition is the one just created</returns> public static Afa <TInput, TRegister, bool> SingleElement <TInput, TRegister>() { var afa = Afa.Create <TInput, TRegister>(); afa.AddArc(0, 1, new SingleElementArc <TInput, TRegister> { Fence = (ts, ev, r) => true }); afa.Seal(); return(afa); }
/// <summary> /// Creates a new pattern without a register and adds a time-synchronous list transition that succeeds on every list of events seen /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <returns>A pattern whose first transition is the one just created</returns> public static Afa <TInput, Empty, bool> ListElement <TInput>() { var afa = Afa.Create <TInput>(); afa.AddArc(0, 1, new ListElementArc <TInput, Empty> { Fence = (ts, ev, r) => true }); afa.Seal(); return(afa); }
public IPattern <TKey, TPayload, TRegister, TAccumulator> Epsilon() { var afa = new Afa <TPayload, TRegister, TAccumulator>(); afa.AddArc(0, 1, new EpsilonArc <TPayload, TRegister> { }); afa.Seal(); return(Concat(x => new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>(this.source, afa))); }
/// <summary> /// Creates a new pattern with a register and adds a single-element transition that succeeds on stream elements that match a condition /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <param name="condition">The time-sensitive, register-value sensitive condition that must be met to consider the transition satisfied</param> /// <returns>A pattern with an updatable register whose first transition is the one just created</returns> public static Afa <TInput, TRegister, bool> SingleElement <TInput, TRegister>(Expression <Func <long, TInput, TRegister, bool> > condition) { var afa = Afa.Create <TInput, TRegister>(); afa.AddArc(0, 1, new SingleElementArc <TInput, TRegister> { Fence = condition }); afa.Seal(); return(afa); }
public CompiledAfa(Afa <TPayload, TRegister, TAccumulator> afa) { if (!afa.IsSealed()) { throw new InvalidOperationException("Cannot compile an unsealed AFA"); } this.uncompiledAfa = afa; this.defaultRegister = afa.DefaultRegister; this.defaultAccumulator = afa.DefaultAccumulator; CompileAfa(afa); }
/// <summary> /// Creates a new pattern without a register and adds a time-synchronous list transition that succeeds on event lists that match a condition /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <param name="condition">The condition that must be met to consider the transition satisfied</param> /// <returns>A pattern whose first transition is the one just created</returns> public static Afa <TInput, Empty, bool> ListElement <TInput>(Expression <Func <List <TInput>, bool> > condition) { var afa = Afa.Create <TInput>(); Expression <Func <long, List <TInput>, Empty, bool> > template = (ts, ev, r) => CallInliner.Call(condition, ev); afa.AddArc(0, 1, new ListElementArc <TInput, Empty> { Fence = template.InlineCalls() }); afa.Seal(); return(afa); }
/// <summary> /// Creates a new pattern with a register and adds a time-synchronous list transition that succeeds on event lists that match a condition /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <param name="condition">The time-sensitive, register-value sensitive condition that must be met to consider the transition satisfied</param> /// <param name="aggregator">An aggregator mutator that updates the value of the register</param> /// <returns>A pattern with an updatable register whose first transition is the one just created</returns> public static Afa <TInput, TRegister, bool> ListElement <TInput, TRegister>(Expression <Func <long, List <TInput>, TRegister, bool> > condition, Expression <Func <List <TInput>, TRegister, TRegister> > aggregator) { var afa = Afa.Create <TInput, TRegister>(); Expression <Func <long, List <TInput>, TRegister, TRegister> > aggregatorTemplate = (ts, ev, reg) => CallInliner.Call(aggregator, ev, reg); afa.AddArc(0, 1, new ListElementArc <TInput, TRegister> { Fence = condition, Transfer = aggregatorTemplate.InlineCalls(), }); afa.Seal(); return(afa); }
public AfaStreamable(IStreamable <TKey, TPayload> source, Afa <TPayload, TRegister, TAccumulator> afa, long maxDuration) : base(source, source.Properties.Afa <TKey, TPayload, TRegister>()) { Contract.Requires(source != null); afa.Seal(); this.afa = afa.Compile(); this.MaxDuration = maxDuration; Initialize(); }
public IPattern <TKey, TPayload, TRegister, TAccumulator> Or( Func <IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator>, IPattern <TKey, TPayload, TRegister, TAccumulator> > pattern1, Func <IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator>, IPattern <TKey, TPayload, TRegister, TAccumulator> > pattern2, params Func <IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator>, IPattern <TKey, TPayload, TRegister, TAccumulator> >[] patterns) { var allPatterns = new Afa <TPayload, TRegister, TAccumulator> [patterns.Length + 2]; allPatterns[0] = pattern1(new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>()).AFA; allPatterns[1] = pattern2(new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>()).AFA; for (int i = 0; i < patterns.Length; i++) { allPatterns[i + 2] = patterns[i](new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>()).AFA; } var result = new Afa <TPayload, TRegister, TAccumulator>(); int oldMax; for (int i = 0; i < allPatterns.Length; i++) { var nextPattern = allPatterns[i]; oldMax = result.MaxState + 1; result.AddArc(0, nextPattern.StartState + oldMax, new EpsilonArc <TPayload, TRegister>()); foreach (var kvp1 in nextPattern.transitionInfo) { foreach (var kvp2 in kvp1.Value) { int from = kvp1.Key; int to = kvp2.Key; from = from + oldMax; to = to + oldMax; result.AddArc(from, to, kvp2.Value); if (nextPattern.finalStates.Contains(kvp2.Key)) { if (!result.finalStates.Contains(to)) { result.finalStates.Add(to); } } } } } result.StartState = 0; return(Concat(x => new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>(this.source, result))); }
public IPattern <TKey, TPayload, TRegister, TAccumulator> SingleElement(Expression <Func <long, TPayload, TRegister, bool> > condition = null, Expression <Func <long, TPayload, TRegister, TRegister> > aggregator = null) { var afa = new Afa <TPayload, TRegister, TAccumulator>(); afa.AddArc(0, 1, new SingleElementArc <TPayload, TRegister> { Fence = condition, Transfer = aggregator }); afa.Seal(); return(Concat(x => new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>(this.source, afa))); }
/// <summary> /// Creates a new pattern with a register and adds a single-element transition that succeeds on stream elements that match a condition /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <param name="condition">The condition that must be met to consider the transition satisfied</param> /// <returns>A pattern with an updatable register whose first transition is the one just created</returns> public static Afa <TInput, TRegister, bool> SingleElement <TInput, TRegister>(Expression <Func <TInput, bool> > condition) { var afa = Afa.Create <TInput, TRegister>(); Expression <Func <long, TInput, TRegister, bool> > template = (ts, ev, r) => CallInliner.Call(condition, ev); afa.AddArc(0, 1, new SingleElementArc <TInput, TRegister> { Fence = template.InlineCalls() }); afa.Seal(); return(afa); }
/// <summary> /// Creates a new pattern resulting from the disjunction of other patterns /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <typeparam name="TAccumulator">The type of the accumulator in the underlying automaton</typeparam> /// <param name="pattern1">The first pattern in the disjunction</param> /// <param name="pattern2">The second pattern in the disjunction</param> /// <param name="patterns">Any remaining patterns to be disjunction, in order</param> /// <returns>A pattern whose first transition is the one just created</returns> public static Afa <TInput, TRegister, TAccumulator> Or <TInput, TRegister, TAccumulator>(Afa <TInput, TRegister, TAccumulator> pattern1, Afa <TInput, TRegister, TAccumulator> pattern2, params Afa <TInput, TRegister, TAccumulator>[] patterns) { var allPatterns = new Afa <TInput, TRegister, TAccumulator> [patterns.Length + 2]; allPatterns[0] = pattern1; allPatterns[1] = pattern2; patterns.CopyTo(allPatterns, 2); var result = new Afa <TInput, TRegister, TAccumulator>(); int oldMax; for (int i = 0; i < allPatterns.Length; i++) { var nextPattern = allPatterns[i]; oldMax = result.MaxState + 1; result.AddArc(0, nextPattern.StartState + oldMax, new EpsilonArc <TInput, TRegister>()); foreach (var kvp1 in nextPattern.transitionInfo) { foreach (var kvp2 in kvp1.Value) { int from = kvp1.Key; int to = kvp2.Key; from = from + oldMax; to = to + oldMax; result.AddArc(from, to, kvp2.Value); if (nextPattern.finalStates.Contains(kvp2.Key)) { if (!result.finalStates.Contains(to)) { result.finalStates.Add(to); } } } } } result.StartState = 0; return(result); }
public IPattern <TKey, TPayload, TRegister, TAccumulator> MultiElement(Expression <Func <long, TRegister, TAccumulator> > initialize, Expression <Func <long, TPayload, TRegister, TAccumulator, TAccumulator> > accumulate, Expression <Func <long, TPayload, TAccumulator, bool> > skipToEnd, Expression <Func <long, TAccumulator, TRegister, bool> > fence, Expression <Func <long, TAccumulator, TRegister, TRegister> > transfer, Expression <Action <TAccumulator> > dispose) { var afa = new Afa <TPayload, TRegister, TAccumulator>(); afa.AddArc(0, 1, new MultiElementArc <TPayload, TRegister, TAccumulator> { Initialize = initialize, Accumulate = accumulate, SkipToEnd = skipToEnd, Fence = fence, Transfer = transfer, Dispose = dispose }); afa.Seal(); return(Concat(x => new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>(this.source, afa))); }
public IPattern <TKey, TPayload, TRegister, TAccumulator> Concat( Func <IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator>, IPattern <TKey, TPayload, TRegister, TAccumulator> > pattern, params Func <IAbstractPatternRoot <TKey, TPayload, TRegister, TAccumulator>, IPattern <TKey, TPayload, TRegister, TAccumulator> >[] patterns) { var pattern1 = this.AFA; var pattern2 = pattern(new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>()).AFA; var afa = new Afa <TPayload, TRegister, TAccumulator> [patterns.Length]; for (int i = 0; i < patterns.Length; i++) { afa[i] = patterns[i](new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>()).AFA; } var result = ConcatWorker(false, pattern1, pattern2, afa); return(new PatternMatcher <TKey, TPayload, TRegister, TAccumulator>(this.source, result)); }
/// <summary> /// Detect a pattern over the incoming stream. Takes augmented finite automaton (AFA) as input. Create AFA using the Regex.* API or direct AFA specification. /// </summary> /// <typeparam name="TKey">Key type</typeparam> /// <typeparam name="TPayload">Payload type</typeparam> /// <typeparam name="TRegister">Result type (output of matcher is the register at an accepting state of the AFA)</typeparam> /// <typeparam name="TAccumulator">Accumulator type</typeparam> /// <param name="source">Source stream</param> /// <param name="afa">AFA specification</param> /// <param name="maxDuration">Maximum duration (window) for the pattern</param> /// <param name="allowOverlappingInstances">States whether to allow more than one state machine instance to be in effect at a time</param> /// <param name="isDeterministic">States whether to consider the AFA as deterministic</param> /// <returns>A stream of the matched results</returns> public static IStreamable <TKey, TRegister> Detect <TKey, TPayload, TRegister, TAccumulator>( this IStreamable <TKey, TPayload> source, Afa <TPayload, TRegister, TAccumulator> afa, long maxDuration = 0, bool allowOverlappingInstances = true, bool isDeterministic = false) { Invariant.IsNotNull(source, nameof(source)); if (maxDuration == 0) { if (!(source.Properties.IsConstantDuration && (source.Properties.ConstantDurationLength != null))) { throw new Exception("Either specify a MaxDuration parameter or use an input stream that is windowed by a constant"); } maxDuration = source.Properties.ConstantDurationLength.Value; } afa.AllowOverlappingInstances = allowOverlappingInstances; afa.IsDeterministic = isDeterministic; return(new AfaStreamable <TKey, TPayload, TRegister, TAccumulator>(source, afa, maxDuration)); }
/// <summary> /// Creates a new pattern resulting from zero to many iterations of the given pattern /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <typeparam name="TAccumulator">The type of the accumulator in the underlying automaton</typeparam> /// <param name="pattern">The pattern to iterate</param> /// <returns>A pattern whose first transition is the one just created</returns> public static Afa <TInput, TRegister, TAccumulator> KleeneStar <TInput, TRegister, TAccumulator>(Afa <TInput, TRegister, TAccumulator> pattern) { var result = new Afa <TInput, TRegister, TAccumulator>(); // Every final state maps back to the start state foreach (var kvp1 in pattern.transitionInfo) { foreach (var kvp2 in kvp1.Value) { var to = kvp2.Key; if (pattern.finalStates.Contains(to)) { to = pattern.StartState; } result.AddArc(kvp1.Key, to, kvp2.Value); } } // Start state becomes the single final state result.finalStates.Add(pattern.StartState); result.StartState = pattern.StartState; return(result); }
private void CompileAfa(Afa <TPayload, TRegister, TAccumulator> afa) { this.isFinal = new bool[afa.MaxState + 1]; this.hasOutgoingArcs = new bool[afa.MaxState + 1]; int nst = afa.StartState; var startStatesList = new List <int>(); var stack = new Stack <int>(); while (true) { startStatesList.Add(nst); if (afa.transitionInfo[nst] != null) { foreach (var kvp in afa.transitionInfo[nst]) { var to = kvp.Key; var arc = kvp.Value; if (arc.ArcType == ArcType.Epsilon) { stack.Push(to); } } } if (stack.Count == 0) { break; } nst = stack.Pop(); } this.startStates = startStatesList.ToArray(); this.numStartStates = startStatesList.Count; // Compile the automaton foreach (var x in afa.finalStates) { this.isFinal[x] = true; } bool knownDet = true; for (int from = 0; from <= afa.MaxState; from++) { this.hasOutgoingArcs[from] = false; int epsilonCount = 0; int singleEventCount = 0; int eventListCount = 0; int multiEventCount = 0; if (afa.transitionInfo.ContainsKey(from)) { this.hasOutgoingArcs[from] = true; foreach (var kvp in afa.transitionInfo[from]) { var to = kvp.Key; var arc = kvp.Value; switch (arc.ArcType) { case ArcType.Epsilon: if (from == to) { throw new InvalidOperationException("Self-looping epsilon states are not allowed"); } if (this.epsilonStateMap == null) { this.epsilonStateMap = new int[afa.MaxState + 1][]; } epsilonCount++; break; case ArcType.SingleElement: if (this.singleEventStateMap == null) { this.singleEventStateMap = new SingleEventArcInfo <TPayload, TRegister> [afa.MaxState + 1][]; } singleEventCount++; break; case ArcType.ListElement: if (this.eventListStateMap == null) { this.eventListStateMap = new EventListArcInfo <TPayload, TRegister> [afa.MaxState + 1][]; } eventListCount++; break; case ArcType.MultiElement: if (this.multiEventStateMap == null) { this.multiEventStateMap = new MultiEventArcInfo <TPayload, TRegister, TAccumulator> [afa.MaxState + 1][]; } multiEventCount++; break; default: throw new NotSupportedException(); } } } if (singleEventCount > 0) { this.singleEventStateMap[from] = new SingleEventArcInfo <TPayload, TRegister> [singleEventCount]; } if (eventListCount > 0) { this.eventListStateMap[from] = new EventListArcInfo <TPayload, TRegister> [eventListCount]; } if (multiEventCount > 0) { this.multiEventStateMap[from] = new MultiEventArcInfo <TPayload, TRegister, TAccumulator> [multiEventCount]; } if (epsilonCount > 0) { this.epsilonStateMap[from] = new int[epsilonCount]; } if (singleEventCount + eventListCount + multiEventCount + epsilonCount > 1) { knownDet = false; } singleEventCount = epsilonCount = eventListCount = multiEventCount = 0; ListElementArc <TPayload, TRegister> learc; MultiElementArc <TPayload, TRegister, TAccumulator> mearc; if (afa.transitionInfo.ContainsKey(from)) { foreach (var kvp in afa.transitionInfo[from]) { var to = kvp.Key; var arc = kvp.Value; switch (arc.ArcType) { case ArcType.Epsilon: this.epsilonStateMap[from][epsilonCount] = to; epsilonCount++; break; case ArcType.SingleElement: var searc = arc as SingleElementArc <TPayload, TRegister>; this.singleEventStateMap[from][singleEventCount] = new SingleEventArcInfo <TPayload, TRegister> { toState = to, Fence = searc.Fence.Compile(), Transfer = searc.Transfer?.Compile(), arcType = searc.ArcType }; singleEventCount++; break; case ArcType.MultiElement: mearc = arc as MultiElementArc <TPayload, TRegister, TAccumulator>; this.multiEventStateMap[from][multiEventCount] = new MultiEventArcInfo <TPayload, TRegister, TAccumulator> { toState = to, Initialize = mearc.Initialize != null ? mearc.Initialize.Compile() : (ts, reg) => this.defaultAccumulator, Accumulate = mearc.Accumulate != null?mearc.Accumulate.Compile() : (ts, ev, reg, acc) => acc, SkipToEnd = mearc.SkipToEnd?.Compile(), Dispose = mearc.Dispose?.Compile(), Fence = mearc.Fence.Compile(), Transfer = mearc.Transfer?.Compile(), arcType = mearc.ArcType }; for (int i = 0; i < this.numStartStates; i++) { if (from == this.startStates[i]) { this.multiEventStateMap[from][multiEventCount].fromStartState = true; } } multiEventCount++; break; case ArcType.ListElement: learc = arc as ListElementArc <TPayload, TRegister>; this.eventListStateMap[from][eventListCount] = new EventListArcInfo <TPayload, TRegister> { toState = to, Fence = learc.Fence.Compile(), Transfer = learc.Transfer?.Compile(), arcType = learc.ArcType }; eventListCount++; break; default: throw new NotSupportedException(); } } } } if (knownDet) { this.uncompiledAfa.IsDeterministic = true; } // Deterministic, but overlapping instances allowed => effectively non-deterministic if (this.uncompiledAfa.IsDeterministic && this.uncompiledAfa.AllowOverlappingInstances) { this.uncompiledAfa.IsDeterministic = false; } }
/// <summary> /// Creates a new pattern resulting from the concatenation of other patterns, but where each individual pattern may result in a final state /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <typeparam name="TAccumulator">The type of the accumulator in the underlying automaton</typeparam> /// <param name="pattern1">The first pattern in the concatenation</param> /// <param name="pattern2">The second pattern in the concatenation</param> /// <param name="patterns">Any remaining patterns to be concatenated, in order</param> /// <returns>A pattern whose first transition is the one just created</returns> public static Afa <TInput, TRegister, TAccumulator> OrConcat <TInput, TRegister, TAccumulator>(Afa <TInput, TRegister, TAccumulator> pattern1, Afa <TInput, TRegister, TAccumulator> pattern2, params Afa <TInput, TRegister, TAccumulator>[] patterns) => ConcatWorker(true, pattern1, pattern2, patterns);
private static Afa <TPayload, TRegister, TAccumulator> ConcatWorker(bool isOr, Afa <TPayload, TRegister, TAccumulator> pattern1, Afa <TPayload, TRegister, TAccumulator> pattern2, params Afa <TPayload, TRegister, TAccumulator>[] patterns) { int offset = 1; if (pattern1 != null) { offset++; } var allPatterns = new Afa <TPayload, TRegister, TAccumulator> [patterns.Length + offset]; int o = 0; if (pattern1 != null) { allPatterns[o++] = pattern1; } allPatterns[o++] = pattern2; patterns.CopyTo(allPatterns, offset); var extraFinalStates = new List <int>(); var result = allPatterns[0].Clone(); for (int i = 1; i < allPatterns.Length; i++) { var nextPattern = allPatterns[i]; var newFinal = result.MaxState + 1; var origFinalStates = new List <int>(); var epsilonArcAdded = false; foreach (var finalState in result.finalStates) { if (result.transitionInfo.TryGetValue(finalState, out Dictionary <int, Arc <TPayload, TRegister> > outgoingEdges)) { result.AddArc(finalState, newFinal, new EpsilonArc <TPayload, TRegister> { }); if (!epsilonArcAdded) { epsilonArcAdded = true; origFinalStates.Add(newFinal); } } else { origFinalStates.Add(finalState); } } result.finalStates.Clear(); foreach (var oldFinal in origFinalStates) { extraFinalStates.Add(oldFinal); int oldMax = result.MaxState; foreach (var kvp1 in nextPattern.transitionInfo) { foreach (var kvp2 in kvp1.Value) { int from = kvp1.Key; int to = kvp2.Key; if (from == nextPattern.StartState) { from = oldFinal; } else { from = from + oldMax; } if (to == nextPattern.StartState) { to = oldFinal; } else { to = to + oldMax; } result.AddArc(from, to, kvp2.Value); if (nextPattern.finalStates.Contains(kvp2.Key)) { if (!result.finalStates.Contains(to)) { result.finalStates.Add(to); } } } } } } if (isOr) { // Consider individual prefixes of the concat as final states foreach (var state in extraFinalStates) { if (!result.finalStates.Contains(state)) { result.finalStates.Add(state); } } } return(result); }
/// <summary> /// Creates a new pattern resulting from one to many iterations of the given pattern /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <typeparam name="TAccumulator">The type of the accumulator in the underlying automaton</typeparam> /// <param name="pattern">The pattern to iterate</param> /// <returns>A pattern whose first transition is the one just created</returns> public static Afa <TInput, TRegister, TAccumulator> KleenePlus <TInput, TRegister, TAccumulator>(Afa <TInput, TRegister, TAccumulator> pattern) => Concat(pattern, KleeneStar(pattern));
/// <summary> /// Creates a new pattern resulting from zero or one instances of the given pattern /// </summary> /// <typeparam name="TInput">The type of stream input data</typeparam> /// <typeparam name="TRegister">The type of the register to be mutated as transitions occur</typeparam> /// <typeparam name="TAccumulator">The type of the accumulator in the underlying automaton</typeparam> /// <param name="pattern">The pattern to identify</param> /// <returns>A pattern whose first transition is the one just created</returns> public static Afa <TInput, TRegister, TAccumulator> ZeroOrOne <TInput, TRegister, TAccumulator>(Afa <TInput, TRegister, TAccumulator> pattern) { var result = pattern.Clone(); if (!result.finalStates.Contains(result.StartState)) { result.finalStates.Add(result.StartState); } return(result); }
public PatternMatcher(IStreamable <TKey, TPayload> source, Afa <TPayload, TRegister, TAccumulator> afa) { this.source = source; this.AFA = afa; }