Files
c-automates-giiiiive/Aloyse et Vincent/nfa_determi.c
2024-12-16 02:48:28 +01:00

247 lines
8.4 KiB
C

/********************************************/
/* 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;
}