diff --git a/src/FiniteAutomaton.java b/src/FiniteAutomaton.java index 98326a8..73210af 100644 --- a/src/FiniteAutomaton.java +++ b/src/FiniteAutomaton.java @@ -1,44 +1,36 @@ import java.util.Map; import java.util.Set; -class FiniteAutomaton { - private Set Q; - private Set Sigma; - private Map> delta; - private char q0; - private Set F; +public class FiniteAutomaton { + private final Set ALPHABET; // Set of symbols in the alphabet + private final Map> P; // Transition function represented as a map of maps + private final String SS; // Starting state - public FiniteAutomaton(Set Q, Set Sigma, Map> delta, - char q0, Set 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 ALPHABET, Map> 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(); - } -} \ No newline at end of file +} diff --git a/src/Grammar.java b/src/Grammar.java index 58629d0..9ab205b 100644 --- a/src/Grammar.java +++ b/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 VN; - private Set VT; - private Map> P; - private char S; - private Random random; + // Instance variables to hold the grammar components + private final String SS; // Starting symbol + private final Set VN; // Set of non-terminal symbols + private final Map> P; // Production rules + private final FiniteAutomaton FA; // Finite Automaton representation of the grammar - public Grammar(Set VN, Set VT, Map> 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 VN, Set VT, Map> 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 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 Q = new HashSet<>(VN); - Q.addAll(VT); - Set Sigma = new HashSet<>(VT); - char q0 = S; - Set 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> buildTransitions(Map> productions) { + // Initialize a map to hold the transitions for each state (non-terminal symbol). + Map> transitions = new HashMap<>(); + // Iterate over each production rule. + for (Map.Entry> entry : productions.entrySet()) { + String state = entry.getKey(); // Get the non-terminal symbol as the state. + List productionList = entry.getValue(); // Get the list of productions for the state. + Map 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> 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; } + } diff --git a/src/Main.java b/src/Main.java index 648beca..137b42c 100644 --- a/src/Main.java +++ b/src/Main.java @@ -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 VN = Set.of("S", "B", "C"); // Non-terminal symbols + public static final Set VT = Set.of("a", "b", "c"); // Terminal symbols + public static final Map> 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 VN = new HashSet<>(Arrays.asList('S', 'A', 'B')); - Set VT = new HashSet<>(Arrays.asList('a', 'b', 'c', 'd')); - Map> 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)); } } - diff --git a/src/reports/lab_one.pdf b/src/reports/lab_one.pdf index e368390..ce784c4 100644 Binary files a/src/reports/lab_one.pdf and b/src/reports/lab_one.pdf differ