/** * Esercizio 4.2 dopo aver effettuato la minimizzazione dei dfa, se gli stati iniziali sono * indistinguibili, allora i due automi sono equivalenti * * @param target automa sul quale si vuole effettuare il test di equivalenza * @return <code>True</code> se l'automa passato come parametro è eqivalente all'automa utilizzato * <code>false</code> altrimenti */ public boolean equivalentTo(DFA target) { DFA a = this.minimize(); // l'automa minimp è equivalente all'automa di partenza DFA b = target.minimize(); return a.numberOfStates == b.numberOfStates && a.finalStates.equals(b.finalStates) && a.transitions.equals(b.transitions); }
/** * Esercizio 4.1 dato un automa deterministico ne crea uno che accetta lo stesso linguaggio, ma * con un numero di stati minimo. per fare ciò utilizza l'algoritmo denominato "riempi tabella", * ovvero trova gli stati distignuibili * * @return DFA il dfa con un numero di stati minimo */ public DFA minimize() { boolean bool = true; // variabile booleana per indicare se ci sono ancora delle transizioni da analizzare HashSet<Character> alfabeto = this.alphabet(); Iterator<Character> itAlfabeto; /** * 1 Allocare una matrice eq di elementi di tipo boolean e dimensioni n x n, dove n e il numero * di stati dell'automa */ boolean eq[][] = new boolean[numberOfStates][numberOfStates]; /** * 2 Inizializzare la matrice in modo tale che l’elemento eq[i][j] sia true se i e j sono * entrambi finali o entrambi non finali, false altrimenti. */ for (int i = 0; i < numberOfStates; i++) { for (int j = 0; j < numberOfStates; j++) { eq[i][j] = finalState(i) == finalState( j); // parto con la selezione degli stati finali, che di sicuro sono // indistinguibili } } /** * 3 Per ogni coppia di stati i e j ed ogni carattere ch tali che eq[i][j] è true ed * eq[move(i,ch)][move(j,ch)] è false, si pone l'elemento eq[i][j] a false. */ while (bool) { bool = false; for (int i = 0; i < numberOfStates; i++) { for (int j = 0; j < numberOfStates; j++) { if (eq[i][j] == true) { // abbiamo trovato uno stato inditinguibile itAlfabeto = alfabeto.iterator(); while (itAlfabeto.hasNext()) { // ciclo finchè non trovo un indistinguibile char ch = itAlfabeto.next(); if (eq[move(i, ch)][move(j, ch)] == false) { eq[i][j] = false; bool = true; } } } } } } /** * 4 Ripetere il passo precedente fintantoche vengono scoperte nuove ´ coppie di stati * distinguibili: A tal fine è stato aggiunto il while esterno */ /** * 5 Allocare un vettore m di elementi di tipo int e dimensione n e inizializzarlo in modo tale * che l'elemento i-esimo sia lo stato indistinguibile da i con indice piu piccolo. vado a * creare le classi di equivalenza */ int[] m = new int[numberOfStates]; int k = -1; for (int i = 0; i < numberOfStates; i++) { for (int j = 0; j < numberOfStates; j++) { // prende la prima j sulla colonna che, incrociato con i, ha valore true(indistinguibile) if (eq[i][j]) { m[i] = j; // nell'array di costruzione mettiamo j nella posizione i if (j > k) { k = j; // num. degli stati che mi servono per costruire l'automa minimo } break; } } } /** * 6 Sia k l'elemento piu grande del vettore m. Allocare e inizializzare un DFA B con k + 1 * stati e tale che per ogni transizione da i a j etichettata ch in A esiste una transizione da * m[i] a m[j] etichettata chin B. Fare in modo che, se i è finale in A, allora m[i] sia finale * in B. Ora siamo giunti alla fine e siamo pronti per costruire l'automa minimo */ DFA b = new DFA(k + 1); Move move; for (int i = 0; i < numberOfStates; i++) { // per ogni transazione da i itAlfabeto = alfabeto.iterator(); while (itAlfabeto.hasNext()) { char ch = itAlfabeto.next(); // etichettata ch move = new Move(i, ch); if (transitions.get(move) != null) { // (se esiste) b.setMove( m[i], ch, m[transitions.get(move)]); // aggiungo una transazione da m[i] a m[j] etichetata ch if (this.finalState(i)) { // se è finale b.addFinalState(m[i]); // lo imposto tale } } } } return b; }