/********************************************/ /* Determinisation et Minimisation des NFAs */ /********************************************/ #include "nfa_determi.h" #include "nfa.h" /************************/ /* Procédure principale */ /************************/ // Fonction auxiliaire pour convertir une file d'états en une représentation // entière unique static uint dequeue_to_uint(dequeue *states) { uint result = 0; for (uint i = 0; i < size_dequeue(states); ++i) { result |= (1 << lefread_dequeue(states, i)); } return result; } // Fonction auxiliaire pour vérifier si un ensemble d'états est final static bool is_final_state(dequeue *states, dequeue *finals) { for (uint i = 0; i < size_dequeue(states); ++i) { if (mem_dequeue(lefread_dequeue(states, i), finals)) { return true; } } return false; } // Procédure de déterminisation. Le Booléen names indique si les noms des // nouveaux états (des ensembles d'états de l'ancien NFA) doivent être // sauvegardés dans le DFA. nfa *nfa_determinize(nfa *thenfa, bool recording) { printf("Déterminisation de l'automate1\n"); fflush(stdout); // Créer un nouvel automate pour représenter le DFA nfa *dfa = (nfa *)malloc(sizeof(nfa)); // Créer un graphe avec la taille de l'alphabet de l'automate initial dfa->trans = create_lgraph_noedges(0, thenfa->trans->size_alpha); dfa->initials = create_dequeue(); dfa->finals = create_dequeue(); // Copier les noms des lettres de l'alphabet; dfa->alpha_names = nfa_copy_alpha(thenfa); // Initialiser les noms des états si nécessaire if (recording) { dfa->state_names = (char **)malloc(sizeof(char *)); } else { dfa->state_names = NULL; } // Initialiser l'état initial du DFA // recopier les états initiaux de l'automate initial dequeue *initial_set = create_dequeue(); copy_dequeue_right(initial_set, thenfa->initials, 0); // on les transforme en binaires uint initial_state = dequeue_to_uint(initial_set); // On ajoute l'état initial du DFA en decimal à la file des états initiaux du // DFA lefins_dequeue(initial_state, dfa->initials); // Utiliser une file pour gérer les ensembles d'états à explorer dequeue *queue = create_dequeue(); // Ajouter l'état initial à la file lefins_dequeue(initial_state, queue); // tableau de booléens pour marquer les états visités de taille 2^size_graph barray *visited = create_barray(1 << thenfa->trans->size_graph); // Marquer l'état initial comme visité settrue_barray(visited, initial_state); // Carte pour stocker les ensembles d'états réels dequeue **state_sets = (dequeue **)malloc((1 << thenfa->trans->size_graph) * sizeof(dequeue *)); // on int state_sets[initial_state] = initial_set; // Traiter chaque ensemble d'états while (!isempty_dequeue(queue)) { uint current_state = lefpull_dequeue(queue); // stocke cet ensemble d'états initiaux dans le tableau `state_sets` à // l'indice `initial_state` dequeue *current_set = state_sets[current_state]; // Vérifier si l'état actuel est un état final if (is_final_state(current_set, thenfa->finals)) { lefins_dequeue(current_state, dfa->finals); } // Traiter chaque lettre de l'alphabet for (uint letter = 0; letter < thenfa->trans->size_alpha; ++letter) { dequeue *next_set = create_dequeue(); // Calculer l'ensemble des états atteignables par la lettre actuelle for (uint i = 0; i < size_dequeue(current_set); ++i) { uint state = lefread_dequeue(current_set, i); dequeue *transitions = thenfa->trans->edges[state][letter]; for (uint j = 0; j < size_dequeue(transitions); ++j) { uint next_state = lefread_dequeue(transitions, j); if (!mem_dequeue(next_state, next_set)) { lefins_dequeue(next_state, next_set); } } } // Convertir le prochain ensemble en une représentation entière unique uint next_state = dequeue_to_uint(next_set); // Si le prochain état n'a pas été visité, l'ajouter à la file et le // marquer comme visité if (!getval_barray(visited, next_state)) { settrue_barray(visited, next_state); lefins_dequeue(next_state, queue); state_sets[next_state] = next_set; } else { delete_dequeue(next_set); } // Ajouter la transition au DFA if (dfa->trans->size_graph <= current_state) { dfa->trans->size_graph = current_state + 1; dfa->trans->edges = (dequeue ***)realloc( dfa->trans->edges, dfa->trans->size_graph * sizeof(dequeue **)); for (uint k = 0; k < dfa->trans->size_graph; ++k) { dfa->trans->edges[k] = (dequeue **)malloc(dfa->trans->size_alpha * sizeof(dequeue *)); for (uint l = 0; l < dfa->trans->size_alpha; ++l) { dfa->trans->edges[k][l] = create_dequeue(); } } } lefins_dequeue(next_state, dfa->trans->edges[current_state][letter]); } // Enregistrer le nom de l'état si nécessaire if (recording) { char *state_name = (char *)malloc(256 * sizeof(char)); sprintf(state_name, "{"); for (uint i = 0; i < size_dequeue(current_set); ++i) { if (i > 0) { strcat(state_name, ","); } char buffer[10]; sprintf(buffer, "%u", lefread_dequeue(current_set, i)); strcat(state_name, buffer); } strcat(state_name, "}"); dfa->state_names[current_state] = state_name; } delete_dequeue(current_set); } // Nettoyage delete_dequeue(queue); delete_barray(visited); free(state_sets); printf("Fin de la déterminisation1\n"); fflush(stdout); return dfa; } // Complementation nfa *nfa_complement(nfa *thenfa) { printf("Complémentation de l'automate\n"); fflush(stdout); // Déterminiser l'automate nfa *det_nfa = nfa_determinize(thenfa, false); // Compléter l'automate déterminisé uint num_states = det_nfa->trans->size_graph; uint num_letters = det_nfa->trans->size_alpha; printf("Complémentation de l'automate1\n"); fflush(stdout); // Créer un nouvel état de puits uint sink_state = num_states; lgraph *new_trans = create_lgraph_noedges(num_states + 1, num_letters); printf("Complémentation de l'automate2\n"); fflush(stdout); // Copier les transitions existantes for (uint state = 0; state < num_states; state++) { for (uint letter = 0; letter < num_letters; letter++) { printf("Complémentation de l'automate3\n"); fflush(stdout); dequeue *transitions = det_nfa->trans->edges[state][letter]; if (transitions != NULL) { printf("Complémentation de l'automate4\n"); fflush(stdout); new_trans->edges[state][letter] = transitions; } else { printf("Complémentation de l'automate5\n"); fflush(stdout); new_trans->edges[state][letter] = create_dequeue(); printf("Complémentation de l'automate6\n"); fflush(stdout); rigins_dequeue(sink_state, new_trans->edges[state][letter]); printf("Complémentation de l'automate7\n"); fflush(stdout); } } } // Ajouter des transitions vers l'état de puits pour les transitions // manquantes for (uint letter = 0; letter < num_letters; letter++) { new_trans->edges[sink_state][letter] = create_dequeue(); rigins_dequeue(sink_state, new_trans->edges[sink_state][letter]); } printf("Complémentation de l'automate8\n"); fflush(stdout); // Créer le nouvel automate avec les transitions complétées nfa *comp_nfa = (nfa *)malloc(sizeof(nfa)); comp_nfa->trans = new_trans; comp_nfa->initials = det_nfa->initials; comp_nfa->alpha_names = nfa_copy_alpha(det_nfa); comp_nfa->state_names = nfa_copy_all_names(det_nfa); // Inverser les états finaux et non finaux barray *finals_barray = create_barray(num_states + 1); for (uint state = 0; state < num_states; state++) { if (!mem_dequeue(state, det_nfa->finals)) { settrue_barray(finals_barray, state); } } settrue_barray(finals_barray, sink_state); // Créer la liste des états finaux comp_nfa->finals = create_dequeue(); for (uint state = 0; state <= num_states; state++) { if (getval_barray(finals_barray, state)) { rigins_dequeue(state, comp_nfa->finals); } } printf("Complémentation de l'automate9\n"); fflush(stdout); // Libérer la mémoire delete_barray(finals_barray); nfa_delete(det_nfa); return comp_nfa; }