Example #1
0
        public Dfa EquivalenceMinimization(Dfa dfa)
        {
            // Initialize with two groups from terminals and everything else
            var counter = 0;
            var groups  = new Dictionary <Group <State>, int>
            {
                { dfa.Final, counter++ },
                { dfa.States.Where(s => !dfa.Final.Contains(s)).ToGroup(), counter++ }
            };

            var marked   = new Group <Group <State> >();
            var unmarked = new Queue <Group <State> >(groups.Keys);

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

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

                var table =
                    from state in current
                    let transitions = (
                        from input in dfa.Inputs
                        let target = dfa.TransitionMap.TryGetValue((state, input), out var transition) ? transition : -1
                                     let targetGroup = target != -1 ? groups.Keys.Single(g => g.Contains(target)) : null
                                                       let targetGroupId = !(targetGroup is null) ? groups[targetGroup] : -1
                                                                           select targetGroupId
                        ).ToArray()
                                      select new {
                    State       = state,
                    Transitions = transitions,
                    Hash        = transitions.Aggregate(0, (p, c) => (p, c).GetHashCode())
                };

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

                var newGroups = partitions
                                .Select(hashGroup => new Group <State>(hashGroup.Select(g => g.State)))
                                .ToList();

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

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

                // Group is getting partitioned, so remove it
                groups.Remove(current);

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

            // Return the original dfa if nothing has been minimized
            if (!groups.Any(g => g.Key.Count > 1))
            {
                return(dfa);
            }

            // Rebuild the dfa from groups
            var id = 0;
            var statesFromGroups = groups.Keys
                                   .OrderBy(g => g.Min())
                                   .Select(g => (Group: g, Id: id++))
                                   .ToDictionary(kvp => kvp.Group, kvp => kvp.Id);

            var newStart = statesFromGroups[groups.Keys.Single(g => g.Contains(dfa.Start))];

            var newTransitions = (
                from sourceGroup in groups.Keys
                let source = sourceGroup.First()
                             from input in dfa.Inputs
                             where dfa.TransitionMap.ContainsKey((source, input))
                             let target = dfa.TransitionMap[(source, input)]
Example #2
0
 public Dfa MinimalDfaFromDfa(Dfa dfa) =>
 RemoveDeadStates(EquivalenceMinimization(dfa));