/* This constructor creates a finite state machine execution from a finite state machine definition.
  * The created machine starts at the initial state (defined in the definition).
  */
 public FiniteStateMachineExecutionById(FiniteStateMachineDefinitionById machineDefinition)
 {
     definition = machineDefinition;
     state      = definition.InitialState;
 }
        /* This constructor creates a finite state machine definition. The arguments are:
         * - the alphabet (an array without duplicates)
         * - the states (an array without duplicates)
         * - an initial state id (must be a member of the sates)
         * - a transition matrix, with lines being states, columns beeing letter and content being the new states,
         *   ie newMachinesTransitions[s1_id,a_id] = s2_id means that when the machine is in state newMachineStates[s1_id]
         *   and reads letter newMachineAlphabet[a_id], it goes in state newMachineStates[s2].
         * - an vector of booleans, as many as states, which say if the state is final or not
         *
         * About FrozenVector and FrozenMatrix:
         * This object requires that you use FrozenVector and FrozenMatrix for
         * the transitions matrix and the vector of final states.
         * As FrozenVector and FrozenMatrix are read-only, they can safely be
         * shared accross machines definitions. For convenience, a overrided
         * constructor is provided, that takes usual arrays, and converts them
         * to FrozenMatrix/Vector.
         */
        // IDS OR CUSTOM TYPES?
        // States and letters have a double representation. They can bee seen as
        // integer ids (positions in the matrix, newMachineBlankSymbolId, newMachineInitialStateId)
        // or as TState and TAlphabet (types you choose). The mapping between this 2 representations
        // is acomplished using newMachineTapeAlphabet and newMachineStates. It is not mandatory
        // to use this 2 representations. You may be happy with just integers. In that case,
        // pass <int,int> as <TAlphabet,TState> and null as newMachineTapeAlphabet and newMachineStates.
        // The number of states and letters will then be computer using matrix lengths.
        // You can have a mix of the 2, for example state as ids only but letters as cutom type.
        public FiniteStateMachineDefinition(ICollection <TAlphabet> newMachineAlphabet,
                                            ICollection <TState> newMachineStates,
                                            int newMachineInitialStateId,
                                            FrozenMatrix <int> newMachineTransitions,
                                            FrozenVector <bool> newMachineFinalStates)
        {
            int alphabetSize;

            /* Store alphabet and check it is correct (ie no duplicates). */
            if (newMachineAlphabet != null)
            {
                alphabet = new TAlphabet[newMachineAlphabet.Count];
                newMachineAlphabet.CopyTo(alphabet, 0);
                alphabetIds = new Dictionary <TAlphabet, int>();
                int i = 0;
                foreach (TAlphabet a in newMachineAlphabet)
                {
                    if (alphabetIds.ContainsKey(a))
                    {
                        throw new FiniteStateMachineException("Duplicated letter in newMachineAlphabet : " + a);
                    }
                    alphabetIds.Add(a, i);
                    i++;
                }
                // newMachineAlphabet array has authority for giving the number of letters
                alphabetSize = alphabet.Length;
            }
            else
            {
                if (typeof(TAlphabet) != typeof(int))
                {
                    throw new FiniteStateMachineException("You passed null as newMachineAlphabet, so I deduce that you want to identify"
                                                          + " letters with ids instead of TAlphabet type, but did not choose int as TAlphabet"
                                                          + " so this is inconsistant.");
                }
                // the matrix has authority for giving the number of letters
                alphabetSize = newMachineTransitions.GetLength(1);
            }


            int numberOfStates;

            /* Store states and check it is correct (ie no duplicates). */
            if (newMachineStates != null)
            {
                states = new TState[newMachineStates.Count];
                newMachineStates.CopyTo(states, 0);
                stateIds = new Dictionary <TState, int>();
                int i = 0;
                foreach (TState s in newMachineStates)
                {
                    if (stateIds.ContainsKey(s))
                    {
                        throw new FiniteStateMachineException("Duplicated state in newMachineStates : " + s);
                    }
                    stateIds.Add(s, i);
                    i++;
                }
                // newMachineStates array has auothority for giving the number of letters
                numberOfStates = states.Length;
            }
            else
            {
                if (typeof(TState) != typeof(int))
                {
                    throw new FiniteStateMachineException("You passed null as newMachineStates, so I deduce that you want to identify"
                                                          + " states with ids instead of TState type, but did not choose int as TState"
                                                          + " so this is inconsistant.");
                }
                // the matrix has authority for giving the number of states
                numberOfStates = newMachineTransitions.GetLength(0);
            }


            /* Now build our internal FiniteStateMachineDefinitionById. */
            definitionById = new FiniteStateMachineDefinitionById(alphabetSize,
                                                                  numberOfStates,
                                                                  newMachineInitialStateId,
                                                                  newMachineTransitions,
                                                                  newMachineFinalStates);
        }