Example #1
0
        /// <summary>
        /// Removes states that do not have an possible input transitions to a
        /// terminating state
        /// </summary>
        /// <param name="partial"></param>
        /// <returns></returns>
        public PartialDFA RemoveDeadStates(
            PartialDFA partial)
        {
            var terminable = partial.Terminals.ToSet(Comparer);
            var unknown    = partial.States.Where(s => !terminable.Contains(s)).ToSet(Comparer);

            var queue = new Queue <TState>(terminable);

            while (queue.Any())
            {
                var current = queue.Dequeue();

                var sourceStates = partial.Transitions
                                   .Where(t => terminable.Contains(t.Target))
                                   .Where(t => unknown.Contains(t.Source))
                                   .Select(t => t.Source);

                foreach (var state in sourceStates)
                {
                    terminable.Add(state);
                    unknown.Remove(state);
                    queue.Enqueue(state);
                }
            }

            if (!unknown.Any())
            {
                return(partial);
            }

            var transitions =
                from transition in partial.Transitions
                where !unknown.Contains(transition.Source)
                where !unknown.Contains(transition.Target)
                select transition;

            return(new PartialDFA(
                       partial.Initial,
                       partial.Terminals.ToList(),
                       transitions.ToList()));
        }
Example #2
0
        /// <summary>
        /// Uses the equivalence minimization algorithm to reduce duplicate states
        /// </summary>
        /// <param name="partial"></param>
        /// <returns></returns>
        public PartialDFA EquivalenceMinimization(
            PartialDFA partial)
        {
            // Initialize with two groups from terminals and everything else
            var counter = 0;
            var groups  = new Dictionary <Set <TState>, int> {
                { partial.Terminals.ToSet(Comparer), counter++ },
                { partial.States.Where(s => !partial.Terminals.Contains(s)).ToSet(Comparer), counter++ }
            };

            var marked   = new Set <Set <TState> >();
            var unmarked = new Queue <Set <TState> >(groups.Keys);

            // Continue until all sets are marked
            while (unmarked.Any())
            {
                var current = unmarked.Dequeue();

                if (current.Count == 1)
                {
                    // Can't reduce a set of one
                    marked.Add(current);
                    continue;
                }

                var table =
                    from state in current
                    let transitons = (
                        from input in partial.Inputs
                        let targets = partial.Transitions.Where(t => t.Source.Equals(state) && t.Input.Equals(input)).ToList()
                                      let targetGroup = targets.Any() ? groups.Keys.Single(g => g.Contains(targets.Single().Target)) : null
                                                        let targetGroupId = !(targetGroup is null) ? groups[targetGroup] : -1
                                                                            select targetGroupId
                        ).ToSet()
                                     select(
                        State: state,
                        Transitions: transitons,
                        Hash: transitons.GetSequentialHashCode()
                        );

                var partitions =
                    from row in table
                    group row by row.Hash into rowsByHash
                    select rowsByHash;

                var newGroups = partitions
                                .Select(grp => new Set <TState>(grp.Select(g => g.State), Comparer))
                                .ToList();

                if (newGroups.Count == 1)
                {
                    marked.Add(current);
                    continue;
                }

                // Move all marked groups back to unmarked
                foreach (var markedGroup in marked)
                {
                    unmarked.Enqueue(markedGroup);
                }
                marked.Clear();

                // Current group is getting partitioned, to remove it
                groups.Remove(current);

                foreach (var newGroup in newGroups)
                {
                    groups.Add(newGroup, counter++);
                    unmarked.Enqueue(newGroup);
                }
            }

            var terminals =
                from terminal in partial.Terminals
                select groups.Keys.Single(g => g.Contains(terminal));

            var transitions =
                from sourceGroup in groups.Keys
                from input in partial.Inputs
                let source = sourceGroup.First()
                             where partial.Transitions.Any(t => t.Source.Equals(source) && t.Input.Equals(input))
                             let target = partial.Transitions.Single(t => t.Source.Equals(source) && t.Input.Equals(input)).Target
                                          let targetGroup = groups.Keys.Single(g => g.Contains(target))
                                                            select GroupTransition(sourceGroup, input, targetGroup);

            return(Reduce(
                       groups.Keys.Single(g => g.Contains(partial.Initial)),
                       terminals,
                       transitions
                       ));
        }