public DFSM(FSM <T> fsm) : this()
        {
            List <BuildSet> marked = new List <BuildSet>();

            marked.Add(new BuildSet(new int[] { 0 }));

            for (int j = 0; j < marked.Count; j++)
            {
                foreach (T s in fsm.Symbols)
                {
                    List <int> acumulator = new List <int>();
                    foreach (int i in marked[j].Items)
                    {
                        acumulator.AddRange(fsm.StatesFrom(i, s));
                    }

                    if (acumulator.Count > 0)
                    {
                        BuildSet set = new BuildSet(acumulator);
                        if (!marked.Contains(set))
                        {
                            marked.Add(set);
                        }

                        int k = marked.IndexOf(set);
                        if (!this._transitions.ContainsKey(j))
                        {
                            this._transitions[j] = new Dictionary <T, List <int> >();
                        }

                        if (!this._transitions[j].ContainsKey(s))
                        {
                            this._transitions[j][s] = new List <int>();
                        }

                        if (!this._transitions[j][s].Contains(k))
                        {
                            this._transitions[j][s].Add(k);
                        }

                        foreach (int fs in set.Items)
                        {
                            if (fsm.AcceptingStates.ContainsKey(fs))
                            {
                                if (!this.AcceptingStates.ContainsKey(k))
                                {
                                    this.AcceptingStates[k] = new List <string>();
                                }

                                this.AcceptingStates[k].AddRange(fsm.AcceptingStates[fs].Except(this.AcceptingStates[k]));
                            }
                        }
                    }
                }
            }
        }
        public DFSM <T> Minimize()
        {
            DFSM <T> result = new DFSM <T>();

            //make clone
            result._transitions = new Dictionary <int, Dictionary <T, List <int> > >();
            foreach (int i in this._transitions.Keys)
            {
                result._transitions[i] = new Dictionary <T, List <int> >();
                foreach (T s in this._transitions[i].Keys)
                {
                    result._transitions[i][s] = new List <int>(this._transitions[i][s]);
                }
            }

            foreach (KeyValuePair <int, List <string> > kv in this.AcceptingStates)
            {
                result.AcceptingStates[kv.Key] = new List <string>(kv.Value);
            }

            //remove unreachable and looped states
            result.Trim();

            List <int>      states       = result.States;
            List <int>      acc          = result.AcceptingStates.Keys.ToList();
            List <int>      nonacc       = result.States.Except(acc).ToList();
            List <T>        symbols      = result.Symbols;
            List <BuildSet> distinctsets = new List <BuildSet>();
            List <BuildSet> sets         = new List <BuildSet>();
            Dictionary <BuildSet, List <BuildSet> > deltasets = new Dictionary <BuildSet, List <BuildSet> >();

            //populate all sets
            for (int i = 0; i < states.Count; i++)
            {
                for (int j = i + 1; j < states.Count; j++)
                {
                    BuildSet newset = new BuildSet(new int[] { states[i], states[j] });
                    sets.Add(newset);
                    if ((acc.Contains(states[i]) && nonacc.Contains(states[j])) || (acc.Contains(states[j]) && nonacc.Contains(states[i])))
                    {
                        distinctsets.Add(newset);
                    }
                    else
                    {
                        if (!deltasets.ContainsKey(newset))
                        {
                            deltasets[newset] = new List <BuildSet>();
                        }

                        foreach (T s in symbols)
                        {
                            foreach (int x in result.StatesFrom(states[i], s))
                            {
                                foreach (int y in result.StatesFrom(states[j], s))
                                {
                                    if (x != y)
                                    {
                                        deltasets[newset].Add(new BuildSet(new int[] { x, y }));
                                    }
                                }
                            }
                        }

                        deltasets[newset] = deltasets[newset].Distinct().ToList();
                    }
                }
            }

            //mark all distinct states
            int distcounter = 0;

            while (distinctsets.Count != distcounter)
            {
                distcounter = distinctsets.Count;
                foreach (BuildSet bs in deltasets.Keys)
                {
                    if (deltasets[bs].Intersect(distinctsets).Any())
                    {
                        distinctsets.Add(bs);
                    }

                    if (deltasets[bs].Count == 0)
                    {
                        distinctsets.Add(bs);
                    }
                }

                distinctsets = distinctsets.Distinct().ToList();
                foreach (BuildSet bs in distinctsets)
                {
                    deltasets.Remove(bs);
                }
            }

            //join mergeble sets
            List <BuildSet> identicsets = sets.Except(distinctsets).ToList();

            for (int i = 0; i < identicsets.Count; i++)
            {
                for (int j = i + 1; j < identicsets.Count; j++)
                {
                    if (identicsets[i].Items.Intersect(identicsets[j].Items).Any())
                    {
                        List <int> newset = identicsets[i].Items.Union(identicsets[j].Items).ToList();
                        identicsets.RemoveAt(j);
                        identicsets.RemoveAt(i);
                        identicsets.Insert(i, new BuildSet(newset));
                        j = i;
                    }
                }
            }

            foreach (BuildSet b in identicsets)
            {
                List <int> items = new List <int>(b.Items);
                while (items.Count > 1)
                {
                    result.RenumberState(items[1], items[0]);
                    items.RemoveAt(1);
                }
            }

            return(result);
        }