Added toDFSM method.
This commit is contained in:
parent
0741d9d62d
commit
d58c4d8d3b
|
@ -20,9 +20,13 @@ public class GrammarTool {
|
||||||
-> q0 : "" -> q1, "b" -> q2
|
-> q0 : "" -> q1, "b" -> q2
|
||||||
q1 : "c" -> q1, "a" -> q2,
|
q1 : "c" -> q1, "a" -> q2,
|
||||||
q2 : "d" -> q2, "d" -> q3,
|
q2 : "d" -> q2, "d" -> q3,
|
||||||
* q3 : "c" -> q1
|
* q3 : "c" -> q0
|
||||||
""");
|
""");
|
||||||
System.out.println(f1);
|
System.out.println(f1);
|
||||||
System.out.println("Deterministic? " + f1.isDeterministic());
|
System.out.println("Deterministic? " + f1.isDeterministic());
|
||||||
|
|
||||||
|
FiniteStateMachine d1 = f1.toDeterministic();
|
||||||
|
System.out.println(d1);
|
||||||
|
System.out.println("Deterministic? " + d1.isDeterministic());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,8 @@ import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class Symbol implements Comparable<Symbol> {
|
public class Symbol implements Comparable<Symbol> {
|
||||||
|
public static final Symbol EMPTY = Symbol.of("");
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final String identifier;
|
private final String identifier;
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,7 @@ package nl.andrewlalis.grammar_tool.machine;
|
||||||
|
|
||||||
import nl.andrewlalis.grammar_tool.grammar.Symbol;
|
import nl.andrewlalis.grammar_tool.grammar.Symbol;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -49,6 +46,90 @@ public class FiniteStateMachine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Transition> getTransitionsStartingAt(State state) {
|
||||||
|
Set<Transition> stateTransitions = new HashSet<>();
|
||||||
|
for (Transition t : this.transitions) {
|
||||||
|
if (t.getStartState().equals(state)) {
|
||||||
|
stateTransitions.add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stateTransitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<State> getNextStates(State currentState, Symbol acceptingSymbol) {
|
||||||
|
Set<State> nextStates = new HashSet<>();
|
||||||
|
for (Transition t : this.transitions) {
|
||||||
|
if (t.getStartState().equals(currentState) && t.getAcceptingSymbol().equals(acceptingSymbol)) {
|
||||||
|
nextStates.add(t.getEndState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nextStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<State> getNextStates(Set<State> states, Symbol acceptingSymbol) {
|
||||||
|
Set<State> nextStates = new HashSet<>();
|
||||||
|
for (State state : states) {
|
||||||
|
nextStates.addAll(this.getNextStates(state, acceptingSymbol));
|
||||||
|
}
|
||||||
|
return nextStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<State> getEpsilonClosure(State currentState) {
|
||||||
|
Set<State> nextStates = this.getNextStates(currentState, Symbol.EMPTY);
|
||||||
|
nextStates.add(currentState);
|
||||||
|
return nextStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<State> getEpsilonClosure(Set<State> states) {
|
||||||
|
Set<State> nextStates = this.getNextStates(states, Symbol.EMPTY);
|
||||||
|
nextStates.addAll(states);
|
||||||
|
return nextStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDeterministic() {
|
||||||
|
for (State state : this.states) {
|
||||||
|
for (Symbol symbol : this.alphabet) {
|
||||||
|
if (this.getNextStates(state, symbol).size() > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FiniteStateMachine toDeterministic() {
|
||||||
|
Set<State> finalStates = new HashSet<>();
|
||||||
|
Set<Transition> transitions = new HashSet<>();
|
||||||
|
Set<State> startClosure = this.getEpsilonClosure(this.startState);
|
||||||
|
State startState = State.of(startClosure);
|
||||||
|
Deque<Set<State>> stateQueue = new LinkedList<>();
|
||||||
|
Set<Set<State>> visitedClosures = new HashSet<>();
|
||||||
|
stateQueue.add(startClosure);
|
||||||
|
while (!stateQueue.isEmpty()) {
|
||||||
|
Set<State> currentClosure = stateQueue.pop();
|
||||||
|
visitedClosures.add(currentClosure);
|
||||||
|
State combinedState = State.of(currentClosure);
|
||||||
|
for (State state : currentClosure) {
|
||||||
|
if (this.finalStates.contains(state)) {
|
||||||
|
finalStates.add(combinedState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Symbol symbol : this.alphabet) {
|
||||||
|
if (symbol.isEmpty()) continue;
|
||||||
|
Set<State> nextStates = this.getNextStates(currentClosure, symbol);
|
||||||
|
Set<State> nextStateClosure = this.getEpsilonClosure(nextStates);
|
||||||
|
if (nextStateClosure.isEmpty()) continue;
|
||||||
|
State combinedNextState = State.of(nextStateClosure);
|
||||||
|
// System.out.println(combinedState + " : " + "\"" + symbol + "\" -> " + combinedNextState);
|
||||||
|
transitions.add(new Transition(combinedState, symbol, combinedNextState));
|
||||||
|
if (!visitedClosures.contains(nextStateClosure)) {
|
||||||
|
stateQueue.add(nextStateClosure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FiniteStateMachine.fromTransitions(startState, transitions, finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -93,37 +174,6 @@ public class FiniteStateMachine {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Transition> getTransitionsStartingAt(State state) {
|
|
||||||
Set<Transition> stateTransitions = new HashSet<>();
|
|
||||||
for (Transition t : this.transitions) {
|
|
||||||
if (t.getStartState().equals(state)) {
|
|
||||||
stateTransitions.add(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stateTransitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<State> getNextStates(State currentState, Symbol acceptingSymbol) {
|
|
||||||
Set<State> nextStates = new HashSet<>();
|
|
||||||
for (Transition t : this.transitions) {
|
|
||||||
if (t.getStartState().equals(currentState) && t.getAcceptingSymbol().equals(acceptingSymbol)) {
|
|
||||||
nextStates.add(t.getEndState());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nextStates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDeterministic() {
|
|
||||||
for (State state : this.states) {
|
|
||||||
for (Symbol symbol : this.alphabet) {
|
|
||||||
if (this.getNextStates(state, symbol).size() > 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FiniteStateMachine fromTransitions(State startState, Set<Transition> transitions, Set<State> finalStates) {
|
public static FiniteStateMachine fromTransitions(State startState, Set<Transition> transitions, Set<State> finalStates) {
|
||||||
Set<Symbol> alphabet = new HashSet<>();
|
Set<Symbol> alphabet = new HashSet<>();
|
||||||
Set<State> states = new HashSet<>();
|
Set<State> states = new HashSet<>();
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package nl.andrewlalis.grammar_tool.machine;
|
package nl.andrewlalis.grammar_tool.machine;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class State implements Comparable<State> {
|
public class State implements Comparable<State> {
|
||||||
private final String name;
|
private final String name;
|
||||||
|
@ -31,4 +33,11 @@ public class State implements Comparable<State> {
|
||||||
public int compareTo(State o) {
|
public int compareTo(State o) {
|
||||||
return this.name.compareTo(o.name);
|
return this.name.compareTo(o.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static State of(Set<State> states) {
|
||||||
|
if (states.isEmpty()) throw new IllegalArgumentException("Cannot construct state of empty states.");
|
||||||
|
if (states.size() == 1) return states.stream().findAny().get();
|
||||||
|
String name = states.stream().sorted().map(State::toString).collect(Collectors.joining(", "));
|
||||||
|
return new State("{" + name + "}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue