Пример #1
0
 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;
 }
Пример #2
0
        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)));
        }
Пример #3
0
        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)));
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
 public CompiledAfa(Afa <TPayload, TRegister, TAccumulator> afa)
 {
     if (!afa.IsSealed())
     {
         throw new Exception("Cannot compile an unsealed AFA");
     }
     this.uncompiledAfa = afa;
     CompileAfa(afa);
 }
Пример #7
0
        /// <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);
        }
Пример #8
0
        /// <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);
        }
Пример #9
0
        /// <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);
        }
Пример #10
0
        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)));
        }
Пример #11
0
        /// <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);
        }
Пример #12
0
 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);
 }
Пример #13
0
        /// <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);
        }
Пример #14
0
        /// <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);
        }
Пример #15
0
        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();
        }
Пример #16
0
        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)));
        }
Пример #17
0
        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)));
        }
Пример #18
0
        /// <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);
        }
Пример #19
0
        /// <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);
        }
Пример #20
0
        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)));
        }
Пример #21
0
        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));
        }
Пример #22
0
        /// <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));
        }
Пример #23
0
        /// <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);
        }
Пример #24
0
        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;
            }
        }
Пример #25
0
 /// <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);
Пример #26
0
        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);
        }
Пример #27
0
 /// <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));
Пример #28
0
        /// <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);
        }
Пример #29
0
 public PatternMatcher(IStreamable <TKey, TPayload> source, Afa <TPayload, TRegister, TAccumulator> afa)
 {
     this.source = source;
     this.AFA    = afa;
 }