Skip to content

Commit 4e58e26

Browse files
committed
Add DFA/NFA state machine utility code.
1 parent 4bbd18a commit 4e58e26

File tree

6 files changed

+348
-0
lines changed

6 files changed

+348
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
3+
namespace CppSharp.Utils.FSM{
4+
public class ConsoleWriter{
5+
public static void Failure(string message){
6+
Console.ForegroundColor = ConsoleColor.DarkRed;
7+
Write(message);
8+
}
9+
10+
public static void Success(string message){
11+
Console.ForegroundColor = ConsoleColor.DarkGreen;
12+
Write(message);
13+
}
14+
15+
private static void Write(string message){
16+
Console.WriteLine(message);
17+
Console.ResetColor();
18+
}
19+
}
20+
}

src/Generator/Utils/FSM/DFSM.cs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Text;
4+
5+
namespace CppSharp.Utils.FSM
6+
{
7+
public class DFSM{
8+
public readonly List<string> Q = new List<string>();
9+
public readonly List<char> Sigma = new List<char>();
10+
public readonly List<Transition> Delta = new List<Transition>();
11+
public List<string> Q0 = new List<string>();
12+
public readonly List<string> F = new List<string>();
13+
14+
public DFSM(IEnumerable<string> q, IEnumerable<char> sigma, IEnumerable<Transition> delta,
15+
IEnumerable<string> q0, IEnumerable<string> f){
16+
Q = q.ToList();
17+
Sigma = sigma.ToList();
18+
AddTransitions(delta);
19+
AddInitialStates(q0);
20+
AddFinalStates(f);
21+
}
22+
23+
private void AddTransitions(IEnumerable<Transition> transitions){
24+
foreach (var transition in transitions.Where(ValidTransition)){
25+
Delta.Add(transition);
26+
}
27+
}
28+
29+
private bool ValidTransition(Transition transition){
30+
return Q.Contains(transition.StartState) &&
31+
Q.Contains(transition.EndState) &&
32+
Sigma.Contains(transition.Symbol) &&
33+
!TransitionAlreadyDefined(transition);
34+
}
35+
36+
private bool TransitionAlreadyDefined(Transition transition){
37+
return Delta.Any(t => t.StartState == transition.StartState &&
38+
t.Symbol == transition.Symbol);
39+
}
40+
41+
private void AddInitialStates(IEnumerable<string> q0){
42+
foreach (var startingState in q0.Where(q => q != null && Q.Contains(q))){
43+
Q0.Add(startingState);
44+
}
45+
}
46+
47+
private void AddFinalStates(IEnumerable<string> finalStates){
48+
foreach (var finalState in finalStates.Where(finalState => Q.Contains(finalState))){
49+
F.Add(finalState);
50+
}
51+
}
52+
53+
public void Accepts(string input){
54+
ConsoleWriter.Success("Trying to parse: " + input);
55+
if (InvalidInputOrFSM(input)){
56+
return;
57+
}
58+
foreach (var q0 in Q0){
59+
var currentState = q0;
60+
var steps = new StringBuilder();
61+
foreach (var symbol in input.ToCharArray()){
62+
var transition = Delta.Find(t => t.StartState == currentState &&
63+
t.Symbol == symbol);
64+
if (transition == null){
65+
ConsoleWriter.Failure("No transitions for current state and symbol");
66+
ConsoleWriter.Failure(steps.ToString());
67+
continue;
68+
}
69+
currentState = transition.EndState;
70+
steps.Append(transition + "\n");
71+
}
72+
if (F.Contains(currentState)){
73+
ConsoleWriter.Success("Accepted the input with steps:\n" + steps);
74+
return;
75+
}
76+
ConsoleWriter.Failure("Stopped in state " + currentState +
77+
" which is not a final state.");
78+
ConsoleWriter.Failure(steps.ToString());
79+
}
80+
}
81+
82+
private bool InvalidInputOrFSM(string input){
83+
if (InputContainsNotDefinedSymbols(input)){
84+
return true;
85+
}
86+
if (InitialStateNotSet()){
87+
ConsoleWriter.Failure("No initial state has been set");
88+
return true;
89+
}
90+
if (NoFinalStates()){
91+
ConsoleWriter.Failure("No final states have been set");
92+
return true;
93+
}
94+
return false;
95+
}
96+
97+
private bool InputContainsNotDefinedSymbols(string input){
98+
foreach (var symbol in input.ToCharArray().Where(symbol => !Sigma.Contains(symbol))){
99+
ConsoleWriter.Failure("Could not accept the input since the symbol " + symbol + " is not part of the alphabet");
100+
return true;
101+
}
102+
return false;
103+
}
104+
105+
private bool InitialStateNotSet(){
106+
return Q0.Count == 0;
107+
}
108+
109+
private bool NoFinalStates(){
110+
return F.Count == 0;
111+
}
112+
113+
public void RemoveUnreachableStates(){
114+
var reachableStates = new HashSet<string>(Q0);
115+
var newStates = new HashSet<string>(Q0);
116+
do{
117+
var temp = new HashSet<string>();
118+
foreach (var q in newStates){
119+
var reachableFromQ = Delta.FindAll(t => t.StartState == q).Select(t => t.EndState);
120+
temp.UnionWith(reachableFromQ);
121+
}
122+
temp.ExceptWith(reachableStates);
123+
newStates = temp;
124+
reachableStates.UnionWith(newStates);
125+
} while (newStates.Count > 0);
126+
var unreachableStates = Q.Where(q => !reachableStates.Contains(q));
127+
for (int i = Delta.Count - 1; i > 0; i--){
128+
var transition = Delta[i];
129+
if (unreachableStates.Contains(transition.EndState) ||
130+
unreachableStates.Contains(transition.StartState)){
131+
Delta.Remove(transition);
132+
}
133+
}
134+
foreach (var unrechableState in unreachableStates){
135+
Q.Remove(unrechableState);
136+
}
137+
}
138+
}
139+
}

src/Generator/Utils/FSM/Minimize.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
4+
namespace CppSharp.Utils.FSM{
5+
internal class Minimize{
6+
public static DFSM MinimizeDFSM(DFSM fsm){
7+
var reversedNDFSM = Reverse(fsm);
8+
var reversedDFSM = PowersetConstruction(reversedNDFSM);
9+
var NDFSM = Reverse(reversedDFSM);
10+
return PowersetConstruction(NDFSM);
11+
}
12+
13+
private static NDFSM Reverse(DFSM d){
14+
var delta = new List<Transition>();
15+
foreach (var transition in d.Delta){
16+
delta.Add(new Transition(transition.EndState, transition.Symbol, transition.StartState));
17+
}
18+
return new NDFSM(d.Q, d.Sigma, delta, d.F, d.Q0);
19+
}
20+
21+
public static DFSM PowersetConstruction(NDFSM ndfsm){
22+
var Q = new List<string>();
23+
var Sigma = ndfsm.Sigma.ToList();
24+
var Delta = new List<Transition>();
25+
var Q0 = new List<string> { string.Join(" ", ndfsm.Q0) };
26+
var F = new List<string>();
27+
28+
var processed = new List<string>();
29+
var queue = new Queue<string>();
30+
queue.Enqueue(string.Join(",", ndfsm.Q0));
31+
32+
while (queue.Count > 0){
33+
var setState = queue.Dequeue();
34+
processed.Add(setState);
35+
Q.Add(CleanupState(setState));
36+
37+
var statesInCurrentSetState = setState.Split(',').ToList();
38+
foreach (var state in statesInCurrentSetState){
39+
if (ndfsm.F.Contains(state)){
40+
F.Add(CleanupState(setState));
41+
break;
42+
}
43+
}
44+
var symbols = ndfsm.Delta
45+
.Where(t => statesInCurrentSetState.Contains(t.StartState))
46+
.Select(t => t.Symbol)
47+
.Distinct();
48+
foreach (var symbol in symbols){
49+
var reachableStates =
50+
ndfsm.Delta
51+
.Where(t => t.Symbol == symbol &&
52+
statesInCurrentSetState.Contains(t.StartState))
53+
.OrderBy(t => t.EndState).
54+
Select(t => t.EndState);
55+
var reachableSetState = string.Join(",", reachableStates);
56+
57+
Delta.Add(new Transition(CleanupState(setState), symbol, CleanupState(reachableSetState)));
58+
59+
if (!processed.Contains(reachableSetState)){
60+
queue.Enqueue(reachableSetState);
61+
}
62+
}
63+
}
64+
return new DFSM(Q, Sigma, Delta, Q0, F);
65+
}
66+
67+
private static string CleanupState(string state){
68+
return state.Replace(",", " ");
69+
}
70+
}
71+
}

src/Generator/Utils/FSM/NDFSM.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Text;
4+
5+
namespace CppSharp.Utils.FSM{
6+
public class NDFSM{
7+
private readonly List<string> Q = new List<string>();
8+
public readonly List<char> Sigma = new List<char>();
9+
public readonly List<Transition> Delta = new List<Transition>();
10+
public List<string> Q0 = new List<string>();
11+
public readonly List<string> F = new List<string>();
12+
13+
public NDFSM(IEnumerable<string> q, IEnumerable<char> sigma,
14+
IEnumerable<Transition> delta, IEnumerable<string> q0, IEnumerable<string> f){
15+
Q = q.ToList();
16+
Sigma = sigma.ToList();
17+
AddTransitions(delta);
18+
AddInitialStates(q0);
19+
AddFinalStates(f);
20+
}
21+
22+
private void AddTransitions(IEnumerable<Transition> transitions){
23+
foreach (var transition in transitions.Where(ValidTransition)){
24+
Delta.Add(transition);
25+
}
26+
}
27+
28+
private bool ValidTransition(Transition transition){
29+
return Q.Contains(transition.StartState) &&
30+
Q.Contains(transition.EndState) &&
31+
Sigma.Contains(transition.Symbol);
32+
}
33+
34+
private void AddInitialStates(IEnumerable<string> q0){
35+
foreach (var startingState in q0.Where(q => q != null && Q.Contains(q))){
36+
Q0.Add(startingState);
37+
}
38+
}
39+
40+
private void AddFinalStates(IEnumerable<string> finalStates){
41+
foreach (var finalState in finalStates.Where(finalState => Q.Contains(finalState))){
42+
F.Add(finalState);
43+
}
44+
}
45+
46+
public void Accepts(string input){
47+
ConsoleWriter.Success("Trying to accept: " + input);
48+
if (Q0.Any(q0 => Accepts(q0, input, new StringBuilder()))){
49+
return;
50+
}
51+
ConsoleWriter.Failure("Could not accept the input: " + input);
52+
}
53+
54+
private bool Accepts(string currentState, string input, StringBuilder steps){
55+
if (input.Length > 0){
56+
var transitions = GetAllTransitions(currentState, input[0]);
57+
foreach (var transition in transitions){
58+
var currentSteps = new StringBuilder(steps.ToString() + transition);
59+
if (Accepts(transition.EndState, input.Substring(1), currentSteps)){
60+
return true;
61+
}
62+
}
63+
return false;
64+
}
65+
if (F.Contains(currentState)){
66+
ConsoleWriter.Success("Successfully accepted the input " + input + " " +
67+
"in the final state " + currentState +
68+
" with steps:\n" + steps);
69+
return true;
70+
}
71+
return false;
72+
}
73+
74+
private IEnumerable<Transition> GetAllTransitions(string currentState, char symbol){
75+
return Delta.FindAll(t => t.StartState == currentState &&
76+
t.Symbol == symbol);
77+
}
78+
}
79+
}

src/Generator/Utils/FSM/Program.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System.Collections.Generic;
2+
3+
namespace CppSharp.Utils.FSM{
4+
internal class Program{
5+
private static void Main(string[] args){
6+
var Q = new List<string>{"q0", "q1"};
7+
var Sigma = new List<char>{'0', '1'};
8+
var Delta = new List<Transition>{
9+
new Transition("q0", '0', "q0"),
10+
new Transition("q0", '1', "q1"),
11+
new Transition("q1", '1', "q1"),
12+
new Transition("q1", '0', "q0")
13+
};
14+
var Q0 = new List<string>{"q0"};
15+
var F = new List<string>{"q0", "q1"};
16+
var DFSM = new DFSM(Q, Sigma, Delta, Q0, F);
17+
18+
var minimizedDFSM = Minimize.MinimizeDFSM(DFSM);
19+
}
20+
}
21+
}

src/Generator/Utils/FSM/Transition.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace CppSharp.Utils.FSM{
2+
public class Transition{
3+
public string StartState { get; private set; }
4+
public char Symbol { get; private set; }
5+
public string EndState { get; private set; }
6+
7+
public Transition(string startState, char symbol, string endState){
8+
StartState = startState;
9+
Symbol = symbol;
10+
EndState = endState;
11+
}
12+
13+
public override string ToString(){
14+
return string.Format("({0}, {1}) -> {2}\n", StartState, Symbol, EndState);
15+
}
16+
}
17+
}
18+

0 commit comments

Comments
 (0)