static ExtendedAutomaton <S> MkEmpty()
        {
            var fsa = new ExtendedAutomaton <S>();

            fsa.initialState = 0;
            fsa.maxState     = 0;
            fsa.delta        = new Dictionary <int, List <ExtendedNormalMove <S> > >();
            fsa.deltaFinal   = new Dictionary <int, List <ExtendedFinalMove <S> > >();
            fsa.deltaInv     = new Dictionary <int, List <ExtendedNormalMove <S> > >();
            fsa.finalMoves   = new List <ExtendedFinalMove <S> >();


            fsa.delta[0]      = new List <ExtendedNormalMove <S> >();
            fsa.deltaInv[0]   = new List <ExtendedNormalMove <S> >();
            fsa.deltaFinal[0] = new List <ExtendedFinalMove <S> >();

            fsa.isDeterministic = true;
            return(fsa);
        }
        /// <summary>
        /// Create a symbolic automaton.
        /// </summary>
        /// <param name="initialState">initial state</param>
        /// <param name="finalStates">final states</param>
        /// <param name="moves">moves</param>
        /// <returns></returns>
        public static ExtendedAutomaton <S> Create(int initialState, IEnumerable <ExtendedMove <S> > moves, bool eliminateUnrreachableStates = false, bool eliminateDeadStates = false)
        {
            var delta      = new Dictionary <int, List <ExtendedNormalMove <S> > >();
            var deltaInv   = new Dictionary <int, List <ExtendedNormalMove <S> > >();
            var deltaFinal = new Dictionary <int, List <ExtendedFinalMove <S> > >();
            var finalMoves = new List <ExtendedFinalMove <S> >();

            delta[initialState]      = new List <ExtendedNormalMove <S> >();
            deltaInv[initialState]   = new List <ExtendedNormalMove <S> >();
            deltaFinal[initialState] = new List <ExtendedFinalMove <S> >();

            int  maxState        = initialState;
            bool isDeterministic = true;

            foreach (ExtendedMove <S> move in moves)
            {
                if (!delta.ContainsKey(move.SourceState))
                {
                    delta[move.SourceState] = new List <ExtendedNormalMove <S> >();
                }
                if (!deltaInv.ContainsKey(move.SourceState))
                {
                    deltaInv[move.SourceState] = new List <ExtendedNormalMove <S> >();
                }
                if (!deltaFinal.ContainsKey(move.SourceState))
                {
                    deltaFinal[move.SourceState] = new List <ExtendedFinalMove <S> >();
                }

                maxState = Math.Max(maxState, move.SourceState);

                if (move.isFinal)
                {
                    var mv = move as ExtendedFinalMove <S>;
                    deltaFinal[move.SourceState].Add(mv);
                    finalMoves.Add(mv);
                }
                else
                {
                    var mv = move as ExtendedNormalMove <S>;
                    delta[mv.SourceState].Add(mv);
                    deltaInv[mv.TargetState].Add(mv);
                    maxState = Math.Max(maxState, mv.TargetState);
                }
            }

            ExtendedAutomaton <S> fsa = new ExtendedAutomaton <S>();

            fsa.initialState    = initialState;
            fsa.maxState        = maxState;
            fsa.delta           = delta;
            fsa.deltaFinal      = deltaFinal;
            fsa.deltaInv        = deltaInv;
            fsa.finalMoves      = finalMoves;
            fsa.isDeterministic = isDeterministic;
            if (eliminateUnrreachableStates)
            {
                fsa.EliminateUnrreachableStates();
            }
            if (eliminateDeadStates)
            {
                fsa.EliminateDeadStates();
            }
            return(fsa);
        }