private void CompileAfa()

in Sources/Core/Microsoft.StreamProcessing/Operators/Afa/CompiledAfa.cs [36:206]


        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?.Compile() ?? (Func<long, TRegister, TAccumulator>)((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;
        }