Fixed grammar and transitions, + chose wrong variant
This commit is contained in:
@@ -1,44 +1,36 @@
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
class FiniteAutomaton {
|
||||
private Set<Character> Q;
|
||||
private Set<Character> Sigma;
|
||||
private Map<Character, Map<Character, Character>> delta;
|
||||
private char q0;
|
||||
private Set<Character> F;
|
||||
public class FiniteAutomaton {
|
||||
private final Set<String> ALPHABET; // Set of symbols in the alphabet
|
||||
private final Map<String, Map<String, String>> P; // Transition function represented as a map of maps
|
||||
private final String SS; // Starting state
|
||||
|
||||
public FiniteAutomaton(Set<Character> Q, Set<Character> Sigma, Map<Character, Map<Character, Character>> delta,
|
||||
char q0, Set<Character> F) {
|
||||
this.Q = Q;
|
||||
this.Sigma = Sigma;
|
||||
this.delta = delta;
|
||||
this.q0 = q0;
|
||||
this.F = F;
|
||||
// Constructor to initialize the FiniteAutomaton with the alphabet, transition function, and starting state
|
||||
public FiniteAutomaton(Set<String> ALPHABET, Map<String, Map<String, String>> P, String SS) {
|
||||
this.ALPHABET = ALPHABET; // Initialize the alphabet
|
||||
this.P = P; // Initialize the transition function
|
||||
this.SS = SS; // Initialize the starting state
|
||||
}
|
||||
|
||||
public boolean stringBelongToLanguage(final String inputString) {
|
||||
char currentState = q0;
|
||||
for (char c : inputString.toCharArray()) {
|
||||
if (!Sigma.contains(c)) {
|
||||
return false;
|
||||
}
|
||||
if (!delta.get(currentState).containsKey(c)) {
|
||||
return false;
|
||||
}
|
||||
currentState = delta.get(currentState).get(c);
|
||||
// Method to validate an input string against the finite automaton
|
||||
public boolean isValid(String input) {
|
||||
String currentState = SS; // Start from the initial state
|
||||
|
||||
// Iterate over each symbol in the input string
|
||||
for (char symbol : input.toCharArray()) {
|
||||
String symbolStr = String.valueOf(symbol); // Convert the symbol to a string
|
||||
|
||||
// Check if the symbol is in the alphabet
|
||||
if (!ALPHABET.contains(symbolStr)) return false; // If not, the input is invalid
|
||||
|
||||
// Check if there is a transition defined for the current state and symbol
|
||||
if (P.containsKey(currentState) && P.get(currentState).containsKey(symbolStr))
|
||||
currentState = P.get(currentState).get(symbolStr); // Move to the next state
|
||||
else
|
||||
return false; // If no transition is defined, the input is invalid
|
||||
}
|
||||
return F.contains(currentState);
|
||||
// Check if the final state is the "OK" state, indicating the input is valid
|
||||
return currentState.equals("OK");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("States (Q): ").append(Q).append("\n");
|
||||
sb.append("Alphabet (Sigma): ").append(Sigma).append("\n");
|
||||
sb.append("Transition Function (delta): ").append(delta).append("\n");
|
||||
sb.append("Initial State (q0): ").append(q0).append("\n");
|
||||
sb.append("Accepting States (F): ").append(F);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
129
src/Grammar.java
129
src/Grammar.java
@@ -1,66 +1,91 @@
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class Grammar {
|
||||
private Set<Character> VN;
|
||||
private Set<Character> VT;
|
||||
private Map<Character, List<String>> P;
|
||||
private char S;
|
||||
private Random random;
|
||||
// Instance variables to hold the grammar components
|
||||
private final String SS; // Starting symbol
|
||||
private final Set<String> VN; // Set of non-terminal symbols
|
||||
private final Map<String, List<String>> P; // Production rules
|
||||
private final FiniteAutomaton FA; // Finite Automaton representation of the grammar
|
||||
|
||||
public Grammar(Set<Character> VN, Set<Character> VT, Map<Character, List<String>> P, char S) {
|
||||
this.VN = VN;
|
||||
this.VT = VT;
|
||||
this.P = P;
|
||||
this.S = S;
|
||||
this.random = new Random(System.currentTimeMillis());
|
||||
// Constructor to initialize the Grammar object with the provided grammar components.
|
||||
public Grammar(String SS, Set<String> VN, Set<String> VT, Map<String, List<String>> P) {
|
||||
this.SS = SS; // Initialize the starting symbol
|
||||
this.VN = VN; // Initialize the set of non-terminal symbols
|
||||
this.P = P; // Initialize the production rules
|
||||
// Convert the grammar to a Finite Automaton for validation.
|
||||
// The Finite Automaton will use the terminal symbols and transitions built from the production rules.
|
||||
this.FA = new FiniteAutomaton(VT, buildTransitions(P), SS);
|
||||
}
|
||||
|
||||
// Method to generate and print a specified number of strings and their validity.
|
||||
public void generateNeededStrings(int num) {
|
||||
System.out.println("Strings + Validity:");
|
||||
// Loop to generate and check validity for each string
|
||||
for (int i = 0; i < num; i++) {
|
||||
// Generate a random string according to the grammar.
|
||||
String generatedString = generateString();
|
||||
// Check if the generated string is valid and print its validity.
|
||||
System.out.println((i + 1) + ": " + generatedString + " " + (isValid(generatedString) ? "is valid" : "is not valid"));
|
||||
}
|
||||
}
|
||||
|
||||
// Method to check if a given word is valid according to the grammar.
|
||||
public boolean isValid(String word) {
|
||||
// Delegate the validation to the Finite Automaton representation of the grammar.
|
||||
return FA.isValid(word);
|
||||
}
|
||||
|
||||
// Method to generate a random string according to the grammar.
|
||||
public String generateString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
generateStringHelper(S, sb);
|
||||
return sb.toString();
|
||||
// Start with the starting symbol.
|
||||
String result = getRandomProduction(SS);
|
||||
boolean containsNonTerminal = true;
|
||||
|
||||
// Continue replacing non-terminals with their productions until no more non-terminals remain.
|
||||
while (containsNonTerminal) {
|
||||
containsNonTerminal = false;
|
||||
// Iterate over each character in the current string.
|
||||
for (char entry : result.toCharArray()) {
|
||||
String entryString = String.valueOf(entry);
|
||||
// If the character is a non-terminal, replace it with a random production.
|
||||
if (VN.contains(entryString)) {
|
||||
result = result.replaceFirst(entryString, getRandomProduction(entryString));
|
||||
containsNonTerminal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void generateStringHelper(char symbol, StringBuilder sb) {
|
||||
if (VT.contains(symbol)) {
|
||||
sb.append(symbol);
|
||||
} else {
|
||||
List<String> productions = P.get(symbol);
|
||||
String chosenProduction = productions.get(random.nextInt(productions.size()));
|
||||
for (char c : chosenProduction.toCharArray()) {
|
||||
generateStringHelper(c, sb);
|
||||
}
|
||||
}
|
||||
// Method to get a random production for a given non-terminal symbol.
|
||||
private String getRandomProduction(String nonTerminal) {
|
||||
// Get the list of productions for the given non-terminal and select one randomly.
|
||||
return P.get(nonTerminal).get(ThreadLocalRandom.current().nextInt(P.get(nonTerminal).size()));
|
||||
}
|
||||
|
||||
public FiniteAutomaton toFiniteAutomaton() {
|
||||
Set<Character> Q = new HashSet<>(VN);
|
||||
Q.addAll(VT);
|
||||
Set<Character> Sigma = new HashSet<>(VT);
|
||||
char q0 = S;
|
||||
Set<Character> F = new HashSet<>();
|
||||
for (char vn : VN) {
|
||||
if (P.get(vn).contains("ε")) {
|
||||
F.add(vn);
|
||||
// Method to build transitions for the Finite Automaton representation of the grammar.
|
||||
private Map<String, Map<String, String>> buildTransitions(Map<String, List<String>> productions) {
|
||||
// Initialize a map to hold the transitions for each state (non-terminal symbol).
|
||||
Map<String, Map<String, String>> transitions = new HashMap<>();
|
||||
// Iterate over each production rule.
|
||||
for (Map.Entry<String, List<String>> entry : productions.entrySet()) {
|
||||
String state = entry.getKey(); // Get the non-terminal symbol as the state.
|
||||
List<String> productionList = entry.getValue(); // Get the list of productions for the state.
|
||||
Map<String, String> stateTransitions = new HashMap<>();
|
||||
// Iterate over each production.
|
||||
for (String production : productionList) {
|
||||
String symbol = production.substring(0, 1); // Get the first character as the symbol.
|
||||
// Get the next state as the rest of the production, or "OK" if it's empty.
|
||||
String nextState = production.length() > 1 ? production.substring(1) : "OK";
|
||||
stateTransitions.put(symbol, nextState); // Add the transition to the state's transitions.
|
||||
}
|
||||
transitions.put(state, stateTransitions); // Add the state and its transitions to the overall transitions map.
|
||||
}
|
||||
Map<Character, Map<Character, Character>> delta = new HashMap<>();
|
||||
for (char q : Q) {
|
||||
delta.put(q, new HashMap<>());
|
||||
for (char c : Sigma) {
|
||||
delta.get(q).put(c, ' ');
|
||||
}
|
||||
}
|
||||
for (char vn : VN) {
|
||||
if (!P.containsKey(vn)) {
|
||||
P.put(vn, Collections.emptyList());
|
||||
}
|
||||
for (String production : P.get(vn)) {
|
||||
char nextState = production.charAt(0);
|
||||
char inputSymbol = production.length() > 1 ? production.charAt(1) : ' ';
|
||||
delta.get(vn).put(inputSymbol, nextState);
|
||||
}
|
||||
}
|
||||
return new FiniteAutomaton(Q, Sigma, delta, q0, F);
|
||||
return transitions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
// Define the starting symbol, non-terminal symbols, terminal symbols, and production rules
|
||||
public static final String SS = "S"; // Starting symbol
|
||||
public static final Set<String> VN = Set.of("S", "B", "C"); // Non-terminal symbols
|
||||
public static final Set<String> VT = Set.of("a", "b", "c"); // Terminal symbols
|
||||
public static final Map<String, List<String>> P = Map.of( // Production rules
|
||||
"S", List.of("aB"), // Production rule for S
|
||||
"B", List.of("aC", "bB"), // Production rule for B
|
||||
"C", List.of("bB", "c", "aS")); // Production rule for C
|
||||
|
||||
public static void main(String[] args) {
|
||||
Set<Character> VN = new HashSet<>(Arrays.asList('S', 'A', 'B'));
|
||||
Set<Character> VT = new HashSet<>(Arrays.asList('a', 'b', 'c', 'd'));
|
||||
Map<Character, List<String>> P = new HashMap<>();
|
||||
P.put('S', Arrays.asList("bS", "dA"));
|
||||
P.put('A', Arrays.asList("aA", "dB", "b"));
|
||||
P.put('B', Arrays.asList("cB", "a"));
|
||||
char S = 'S';
|
||||
|
||||
Grammar grammar = new Grammar(VN, VT, P, S);
|
||||
|
||||
FiniteAutomaton finiteAutomaton = grammar.toFiniteAutomaton();
|
||||
|
||||
System.out.println("Generated Strings: ");
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
String generated = grammar.generateString();
|
||||
System.out.println(i + " " + generated);
|
||||
// System.out.println("Accepted by automaton? " + finiteAutomaton.stringBelongToLanguage(generated));
|
||||
}
|
||||
String toCheck = "aac"; // Word to check
|
||||
|
||||
// Create a Grammar object with the defined grammar
|
||||
Grammar grammar = new Grammar(SS, VN, VT, P);
|
||||
|
||||
// Generate strings needed for the validation process
|
||||
grammar.generateNeededStrings(5);
|
||||
|
||||
// Check if the given word is valid according to the grammar
|
||||
System.out.println("Is " + toCheck + " valid? " + grammar.isValid(toCheck));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user