/// <inheritdoc/> public string ToDot() { var writer = new DotWriter <TState>(this.StateComparer); writer.WriteStart("NFA"); // Accepting states writer.WriteAcceptingStates(this.AcceptingStates); // Non-accepting states writer.WriteStates(this.States.Except(this.AcceptingStates, this.StateComparer)); // Initial states writer.WriteInitialStates(this.InitialStates); // Transitions var tupleComparer = new TupleEqualityComparer <TState, TState>(this.StateComparer, this.StateComparer); var transitionsByState = this.Transitions.GroupBy(t => (t.Source, t.Destination), tupleComparer); var remainingEpsilon = this.epsilonTransitions.EpsilonTransitionMap .ToDictionary(kv => kv.Key, kv => kv.Value.ToHashSet(this.StateComparer), this.StateComparer); foreach (var group in transitionsByState) { var from = group.Key.Item1; var to = group.Key.Item2; var on = string.Join(" U ", group.Select(g => g.Symbol)); if (this.EpsilonTransitions.Contains(new(from, to))) { remainingEpsilon[from].Remove(to); on = $"{on}, ε"; } writer.WriteTransition(from, on, to); } // Epsilon-transitions foreach (var(from, toSet) in remainingEpsilon) { foreach (var to in toSet) { writer.WriteTransition(from, "ε", to); } } writer.WriteEnd(); return(writer.Code.ToString()); }