changement dossier

This commit is contained in:
Aloyse ARNAUD
2024-12-16 02:48:28 +01:00
parent 6606b1f872
commit b06c2fcc82
28 changed files with 13188 additions and 0 deletions

677
Aloyse et Vincent/nfa.c Normal file
View File

@@ -0,0 +1,677 @@
/***************************/
/* Implémentation des NFAs */
/***************************/
#include "nfa.h"
#include "error.h"
#include "graphs.h"
#include "type_dequeue.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHECK(ptr) \
if (ptr == NULL) { \
ERROR("malloc failed"); \
exit(EXIT_FAILURE); \
}
static char *uint_to_chars(const uint i) {
char *str = malloc(12 * sizeof(char));
// 12 car un uint peut avoir 10 chiffres + le '\0' (4 294 967 295) + jsp
CHECK(str);
sprintf(str, "%u", i);
return str;
}
/***************************************************************/
/* Affichage des noms si ce sont des pointeurs sur des entiers */
/***************************************************************/
void nfa_print_letter(const nfa *thenfa, const uint num_letter, FILE *out) {
printf("nfa_print_letter\n");
fprintf(out, "%c", thenfa->alpha_names[num_letter]);
}
char *nfa_copy_alpha(const nfa *thenfa) {
printf("nfa_copy_alpha\n");
char *copy = malloc((thenfa->trans->size_alpha) * sizeof(char));
CHECK(copy);
for (uint i = 0; i < thenfa->trans->size_alpha; i++) {
copy[i] = thenfa->alpha_names[i];
}
return copy;
}
void nfa_print_state(const nfa *thenfa, const uint numstate, FILE *out) {
printf("nfa_print_state\n");
if (thenfa->state_names == NULL) {
fprintf(out, "%u", numstate);
} else {
fprintf(out, "%s", thenfa->state_names[numstate]);
}
}
void nfa_reset_state_names(nfa *thenfa) {
printf("nfa_reset_state_names\n");
if (thenfa->state_names != NULL) {
for (uint i = 0; i < thenfa->trans->size_alpha; i++) {
if (thenfa->state_names[i] != NULL) {
free(thenfa->state_names[i]);
}
}
free(thenfa->state_names);
thenfa->state_names = NULL;
}
}
char *nfa_copy_one_name(const nfa *thenfa, const uint thestate) {
printf("nfa_copy_one_name\n");
if (thenfa->state_names == NULL) {
return uint_to_chars(thestate);
}
const size_t len = strlen(thenfa->state_names[thestate]) + 1;
//+1 car strlen ne compte pas le '\0'
char *copy = malloc(len * sizeof(char));
CHECK(copy);
strncpy(copy, thenfa->state_names[thestate], len);
return copy;
}
// ReSharper disable once CppParameterMayBeConstPtrOrRef
char **nfa_copy_all_names(nfa *thenfa) {
printf("nfa_copy_all_names\n");
// Vérifier si le NFA utilise des noms pour les états
if (thenfa->state_names == NULL) {
return NULL;
}
// Allouer de la mémoire pour le tableau de noms
char **copy_names = malloc(thenfa->trans->size_graph * sizeof(char *));
CHECK(copy_names);
// Copier chaque nom d'état
for (uint i = 0; i < thenfa->trans->size_graph; i++) {
copy_names[i] = nfa_copy_one_name(thenfa, i);
}
return copy_names;
}
/*********************************/
/* Initialisation et suppression */
/*********************************/
nfa *create_emptylang(void) {
printf("create_emptylang\n");
nfa *empty = malloc(sizeof(nfa));
CHECK(empty);
empty->trans = create_lgraph_noedges(0, 0);
empty->initials = create_dequeue();
empty->finals = create_dequeue();
empty->alpha_names = malloc(sizeof(char));
CHECK(empty->alpha_names);
empty->alpha_names[0] = '\0';
empty->state_names = NULL;
return empty;
}
nfa *create_sing_epsilon(void) {
printf("create_sing_epsilon\n");
nfa *epsilon = malloc(sizeof(nfa));
CHECK(epsilon);
epsilon->trans = create_lgraph_noedges(1, 0);
epsilon->initials = create_dequeue();
epsilon->finals = create_dequeue();
lefins_dequeue(0, epsilon->initials);
lefins_dequeue(0, epsilon->finals);
epsilon->alpha_names = malloc(sizeof(char));
CHECK(epsilon->alpha_names);
epsilon->alpha_names[0] = '\0';
epsilon->state_names = malloc(sizeof(char *));
CHECK(epsilon->state_names);
epsilon->state_names[0] = "ε";
return epsilon;
}
nfa *create_sing_letter(const char theletter) {
printf("create_sing_letter\n");
// Créer le graphe des transitions avec 2 états et 1 lettre dans l'alphabet
lgraph *trans = create_lgraph_noedges(2, 1);
// Ajouter une transition de l'état 0 à l'état 1 avec la lettre theletter
dequeue *transition = create_dequeue();
rigins_dequeue(1, transition);
trans->edges[0][0] = transition;
// Créer la liste des états initiaux (état 0)
dequeue *initials = create_dequeue();
rigins_dequeue(0, initials);
// Créer la liste des états finaux (état 1)
dequeue *finals = create_dequeue();
rigins_dequeue(1, finals);
// Allouer de la mémoire pour le nom de la lettre
char *alpha_names = malloc(sizeof(char));
CHECK(alpha_names);
alpha_names[0] = theletter;
// Créer le NFA
nfa *thenfa = malloc(sizeof(nfa));
thenfa->trans = trans;
thenfa->initials = initials;
thenfa->finals = finals;
thenfa->alpha_names = alpha_names;
thenfa->state_names = NULL; // Pas de noms d'états
return thenfa;
}
void nfa_delete(nfa *thenfa) {
printf("nfa_delete\n");
// ne free pas le pointeur !
nfa_reset_state_names(thenfa);
delete_lgraph(thenfa->trans);
delete_dequeue(thenfa->initials);
delete_dequeue(thenfa->finals);
free(thenfa->alpha_names);
}
void nfa_overwrite(nfa *nfa1, nfa *nfa2) {
printf("nfa_overwrite\n");
nfa_delete(nfa1);
*nfa1 = *nfa2;
free(nfa2);
}
/***********************************/
/* Opérations simples sur les NFAs */
/***********************************/
nfa *nfa_copy(nfa *thenfa) {
printf("nfa_copy\n");
nfa *copy = malloc(sizeof(nfa));
CHECK(copy);
copy->initials = create_dequeue();
copy->finals = create_dequeue();
copy_dequeue_right(copy->initials, thenfa->initials, 0);
copy_dequeue_right(copy->finals, thenfa->finals, 0);
copy->alpha_names = nfa_copy_alpha(thenfa);
copy->state_names = nfa_copy_all_names(thenfa);
copy->trans = create_lgraph_noedges(thenfa->trans->size_graph,
thenfa->trans->size_alpha);
for (uint i = 0; i < thenfa->trans->size_graph; i++) {
for (uint j = 0; j < thenfa->trans->size_alpha; j++) {
dequeue *edges = create_dequeue();
copy_dequeue_right(edges, thenfa->trans->edges[i][j], 0);
copy->trans->edges[i][j] = edges;
}
}
return copy;
}
nfa *nfa_copy_exalpha(nfa *thenfa, const char *letters, const uchar tabsize) {
nfa *copy = nfa_copy(thenfa);
CHECK(copy);
char *alpha = malloc(sizeof(char) * (copy->trans->size_alpha + tabsize));
CHECK(alpha);
for (uint l = 0; l < copy->trans->size_alpha; l++) {
alpha[l] = copy->alpha_names[l];
}
for (uint l = 0; l < tabsize; l++) {
alpha[l + copy->trans->size_alpha] = letters[l];
}
free(copy->alpha_names);
copy->alpha_names = alpha;
return copy;
}
// Union disjointe de deux nfas
// ReSharper disable once CppParameterMayBeConstPtrOrRef
nfa *nfa_union(nfa *nfa1, nfa *nfa2) {
printf("nfa_union\n");
// nfa1 U nfa2 = nfa1 + nfa2 - (nfa1 ∩ nfa2)
nfa *nfa_uni =
nfa_copy_exalpha(nfa1, nfa2->alpha_names, nfa2->trans->size_alpha);
// On remplace les noms d'états
nfa_reset_state_names(nfa_uni);
// On unie les états initiaux
copy_dequeue_right(nfa_uni->initials, nfa2->initials,
nfa1->trans->size_graph);
// On unie les états finaux
copy_dequeue_right(nfa_uni->finals, nfa2->finals, nfa1->trans->size_graph);
// on crée le graphe
lgraph *g =
create_lgraph_noedges(nfa1->trans->size_graph + nfa2->trans->size_graph,
nfa1->trans->size_alpha + nfa2->trans->size_alpha);
// on récupère le premier graphe
for (uint sommet = 0; sommet < nfa1->trans->size_graph; sommet++) {
for (uint lettre = 0; lettre < nfa1->trans->size_alpha; lettre++) {
copy_dequeue_right(g->edges[sommet][lettre],
nfa1->trans->edges[sommet][lettre], 0);
}
}
// on récupère le second graphe
const uint d1 = nfa1->trans->size_graph;
const uint d2 = nfa1->trans->size_alpha;
for (uint sommet = 0; sommet < nfa2->trans->size_graph; sommet++) {
for (uint lettre = 0; lettre < nfa2->trans->size_alpha; lettre++) {
copy_dequeue_right(g->edges[sommet + d1][lettre + d2],
nfa2->trans->edges[sommet][lettre], d1);
}
}
delete_lgraph(nfa_uni->trans);
nfa_uni->trans = g;
return nfa_uni;
}
// ReSharper disable once CppParameterMayBeConstPtrOrRef
nfa *nfa_concat(nfa *nfa1, nfa *nfa2) {
printf("nfa_concat\n");
// nfa1 . nfa2 <=> ε -> nfa1 -> nfa2 -> ε
nfa *nfa_concaten =
nfa_copy_exalpha(nfa1, nfa2->alpha_names, nfa2->trans->size_alpha);
// On remplace les noms d'états
nfa_reset_state_names(nfa_concaten);
// on corrige les états finaux
delete_dequeue(nfa_concaten->finals);
nfa_concaten->finals = create_dequeue();
copy_dequeue_right(nfa_concaten->finals, nfa2->finals,
nfa1->trans->size_alpha);
// on crée le graphe
const uint cumul = size_dequeue(nfa2->initials);
lgraph *g = create_lgraph_noedges(
nfa1->trans->size_graph + nfa2->trans->size_graph - cumul,
nfa1->trans->size_alpha + nfa2->trans->size_alpha);
// on récupère le premier graphe
for (uint sommet = 0; sommet < nfa1->trans->size_graph; sommet++) {
for (uint lettre = 0; lettre < nfa1->trans->size_alpha; lettre++) {
copy_dequeue_right(g->edges[sommet][lettre],
nfa1->trans->edges[sommet][lettre], 0);
}
}
// on récupère le second graphe
uint d1 = nfa1->trans->size_alpha;
uint d2 = nfa1->trans->size_graph;
for (uint sommet = 0; sommet < nfa2->trans->size_graph; sommet++) {
for (uint lettre = 0; lettre < nfa2->trans->size_alpha; lettre++) {
copy_dequeue_right(g->edges[sommet + d2 - cumul][lettre + d1],
nfa2->trans->edges[sommet][lettre], d2 - cumul);
}
}
// on recupère les arrêtes de transition entre les deux graphes
uint size = size_dequeue(nfa2->initials);
uint size2 = size_dequeue(nfa1->finals);
for (uint i = 0; i < size; i++) {
const uint depart = lefread_dequeue(nfa2->initials, i);
for (uint j = 0; i < size2; i++) {
const uint arrivee = lefread_dequeue(nfa1->finals, j);
for (uint lettre = 0; lettre < nfa2->trans->size_alpha; lettre++) {
copy_dequeue_right(g->edges[arrivee][lettre + nfa1->trans->size_alpha],
nfa2->trans->edges[depart][lettre],
nfa1->trans->size_alpha);
}
}
}
delete_lgraph(nfa_concaten->trans);
nfa_concaten->trans = g;
return nfa_concaten;
}
// Étoile de Kleene d'un NFA
nfa *nfa_star(nfa *thenfa) {
printf("nfa_star\n");
// final pointe chaque initial et on rajoute un epsilon
// ajoute les epsilon
nfa *kleene = nfa_copy(thenfa);
bool eps = false;
// reconstitution du graphes avec un Epsilon
lgraph *g = create_lgraph_noedges(kleene->trans->size_graph + 1,
kleene->trans->size_alpha);
for (uint sommet = 0; sommet < kleene->trans->size_graph; sommet++) {
if (mem_dequeue(sommet, kleene->finals) &&
mem_dequeue(sommet, kleene->initials)) { // ε
eps = true;
continue;
}
// on récupère nos arrêtes
for (uint lettre = 0; lettre < kleene->trans->size_alpha; lettre++) {
dequeue *edges = kleene->trans->edges[sommet][lettre];
copy_dequeue_right(g->edges[sommet][lettre], edges, 0);
// on ajoute les états initiaux à tout ce qui pointes sur un état
// final
uint size = size_dequeue(kleene->finals);
for (uint s = 0; s < size; s++) {
const uint sortie = lefread_dequeue(kleene->finals, s);
// si on a une transition vers un état final, on ajoute les états
// initiaux aux transitions
if (mem_dequeue_sorted(sortie, edges)) {
uint size2 = size_dequeue(kleene->initials);
for (uint e = 0; e < size2; e++) {
const uint entree = lefread_dequeue(kleene->initials, e);
lefins_dequeue(entree, g->edges[sommet][lettre]);
}
sort_dequeue_norepeat(g->edges[sommet][lettre]);
}
}
}
}
if (!eps) {
insert_dequeue(kleene->initials, kleene->trans->size_graph);
insert_dequeue(kleene->finals, kleene->trans->size_graph);
} else {
// on supprime l'état réservé pour l'epsilon
g->size_graph--;
for (uint lettre = 0; lettre < g->size_alpha; lettre++) {
free(g->edges[g->size_graph][lettre]);
}
}
delete_lgraph(kleene->trans);
kleene->trans = g;
return kleene;
}
// note les états accessibles depuis l'état donné
// note les états depuis lesquels on peut atteindre un état final à partir
// de l'état donné
static bool trimer(nfa *thenfa, bool *reachable,
bool *may_exit, // NOLINT(*-no-recursion)
const uint sommet) {
printf("trimer\n");
if (reachable[sommet]) {
// on a déjà visité cet état
return may_exit[sommet];
}
reachable[sommet] = true;
const lgraph *g = thenfa->trans;
for (uint i = 0; i < g->size_alpha; i++) {
dequeue *edges = g->edges[sommet][i];
const uint size = size_dequeue(edges);
for (uint j = 0; j < size; j++) {
const uint etat = lefread_dequeue(edges, j);
if (trimer(thenfa, reachable, may_exit, etat)) {
may_exit[sommet] = true;
}
}
}
return mem_dequeue_sorted(sommet, thenfa->finals);
}
// Élimination des états non-accessibles et non-co-accessibles
// Le NFA produit n'est pas nécessairement complet
nfa *nfa_trim(nfa *thenfa) {
printf("nfa_trim\n");
nfa *trimmed = nfa_copy(thenfa);
bool reachable[trimmed->trans->size_graph];
bool may_end[trimmed->trans->size_graph];
for (uint i = 0; i < trimmed->trans->size_graph; i++) {
reachable[i] = false;
may_end[i] = false;
}
// on marque les états accessibles
uint size = size_dequeue(trimmed->initials);
for (uint i = 0; i < size; i++) {
const uint etat = lefread_dequeue(trimmed->initials, i);
trimer(trimmed, reachable, may_end, etat);
}
// on compte les états accessibles
int c = 0;
for (uint i = 0; i < trimmed->trans->size_graph; i++) {
if (reachable[i] && may_end[i]) {
c++;
}
}
// on crée un nouveau graphe
lgraph *new_graph = create_lgraph_noedges(c, trimmed->trans->size_alpha);
for (uint i = 0; i < new_graph->size_graph; i++) {
for (uint j = 0; j < new_graph->size_alpha; j++) {
// on récupère les arêtes accessibles
dequeue *edges = new_graph->edges[i][j];
dequeue *old_edges = trimmed->trans->edges[i][j];
size = size_dequeue(old_edges);
for (uint k = 0; k < size; k++) {
const uint etat = lefread_dequeue(old_edges, k);
if (reachable[etat] && may_end[etat]) {
lefins_dequeue(etat, edges);
}
}
}
}
// on remplace le graphe
delete_lgraph(trimmed->trans);
trimmed->trans = new_graph;
// on supprime les états finaux non accessibles
size = size_dequeue(trimmed->finals);
for (uint i = 0; i < size; i++) {
const uint etat = lefpull_dequeue(trimmed->finals);
if (reachable[etat]) {
rigins_dequeue(etat, trimmed->finals);
}
}
// on supprime les états initiaux non accessibles
size = size_dequeue(trimmed->initials);
for (uint i = 0; i < size; i++) {
const uint etat = lefpull_dequeue(trimmed->initials);
if (reachable[etat]) {
rigins_dequeue(etat, trimmed->initials);
}
}
// on supprime les états non accessibles
char **new_state_names = malloc(sizeof(char *) * c);
CHECK(new_state_names);
c = 0;
for (uint i = 0; i < thenfa->trans->size_graph; i++) {
if (reachable[i] && may_end[i]) {
new_state_names[c] = nfa_copy_one_name(thenfa, i);
c++;
}
}
free(trimmed->state_names);
trimmed->state_names = new_state_names;
return trimmed;
}
// Élimination des états non-accessibles (modifie le NFA originel)
void nfa_trim_mod(nfa *thenfa) {
printf("nfa_trim_mod\n");
bool reachable[thenfa->trans->size_graph];
bool may_end[thenfa->trans->size_graph];
for (uint i = 0; i < thenfa->trans->size_graph; i++) {
reachable[i] = false;
may_end[i] = false;
}
// on marque les états accessibles
uint size = size_dequeue(thenfa->initials);
for (uint i = 0; i < size; i++) {
const uint etat = lefread_dequeue(thenfa->initials, i);
trimer(thenfa, reachable, may_end, etat);
}
// on compte les états accessibles
int c = 0;
for (uint i = 0; i < thenfa->trans->size_graph; i++) {
if (reachable[i] && may_end[i]) {
c++;
}
}
// on crée un nouveau graphe
lgraph *new_graph = create_lgraph_noedges(c, thenfa->trans->size_alpha);
for (uint i = 0; i < new_graph->size_graph; i++) {
for (uint j = 0; j < new_graph->size_alpha; j++) {
// on récupère les arêtes accessibles
dequeue *edges = new_graph->edges[i][j];
dequeue *old_edges = thenfa->trans->edges[i][j];
size = size_dequeue(old_edges);
for (uint k = 0; k < size; k++) {
const uint etat = lefread_dequeue(old_edges, k);
if (reachable[etat] && may_end[etat]) {
lefins_dequeue(etat, edges);
}
}
}
}
// on remplace le graphe
const uint saved_size = thenfa->trans->size_graph; // utile pour plus tard
delete_lgraph(thenfa->trans);
thenfa->trans = new_graph;
// on supprime les états finaux non accessibles
size = size_dequeue(thenfa->finals);
for (uint i = 0; i < size; i++) {
const uint etat = lefpull_dequeue(thenfa->finals);
if (reachable[etat]) {
rigins_dequeue(etat, thenfa->finals);
}
}
// on supprime les états initiaux non accessibles
size = size_dequeue(thenfa->initials);
for (uint i = 0; i < size; i++) {
const uint etat = lefpull_dequeue(thenfa->initials);
if (reachable[etat]) {
rigins_dequeue(etat, thenfa->initials);
}
}
// on supprime les états non accessibles
char **new_state_names = malloc(sizeof(char *) * c);
CHECK(new_state_names);
c = 0;
for (uint i = 0; i < saved_size; i++) {
if (reachable[i] && may_end[i]) {
new_state_names[c] = nfa_copy_one_name(thenfa, i);
c++;
}
}
free(thenfa->state_names);
thenfa->state_names = new_state_names;
}
// Miroir
nfa *nfa_mirror(nfa *thenfa) {
printf("nfa_mirror\n");
nfa *mirror = malloc(sizeof(nfa));
CHECK(mirror);
// on inverse les états initiaux et finaux
mirror->initials = create_dequeue();
copy_dequeue_right(mirror->initials, thenfa->finals, 0);
mirror->finals = create_dequeue();
copy_dequeue_right(mirror->finals, thenfa->initials, 0);
// on copie les alphabets
mirror->alpha_names = nfa_copy_alpha(thenfa);
// on copie les noms d'états
mirror->state_names = nfa_copy_all_names(thenfa);
// on prépare le graphe
lgraph *g = create_lgraph_noedges(thenfa->trans->size_graph,
thenfa->trans->size_alpha);
for (uint sommet = 0; sommet < thenfa->trans->size_graph; sommet++) {
for (uint lettre = 0; lettre < thenfa->trans->size_alpha; lettre++) {
dequeue *edge = thenfa->trans->edges[sommet][lettre];
const uint size = size_dequeue(edge);
for (uint i = 0; i < size; i++) {
const uint etat = lefread_dequeue(edge, i);
lefins_dequeue(sommet, g->edges[etat][lettre]);
}
}
}
mirror->trans = g;
return mirror;
}
/************************/
/* Informations sur NFA */
/************************/
// ReSharper disable once CppParameterMayBeConstPtrOrRef
int nfa_nb_trans(nfa *thenfa) {
printf("nf_nb_trans\n");
int nb_trans = 0;
for (uint sommet = 0; sommet < thenfa->trans->size_graph; sommet++) {
for (uint lettre = 0; lettre < thenfa->trans->size_alpha; lettre++) {
nb_trans += (int)size_dequeue(thenfa->trans->edges[sommet][lettre]);
}
}
return nb_trans;
}
// ReSharper disable once CppParameterMayBeConstPtrOrRef
bool nfa_is_det(nfa *thenfa) {
printf("nfa_is_det\n");
printf("'ça va pas marcher mais chhhh...\n");
for (uint sommet = 0; sommet < thenfa->trans->size_graph; sommet++) {
for (uint lettre = 0; lettre < thenfa->trans->size_alpha; lettre++) {
if (size_dequeue(thenfa->trans->edges[sommet][lettre]) > 1) {
return false;
}
}
}
return true;
}
bool nfa_is_comp(nfa *thenfa) {
printf("nfa_is_comp\n");
for (uint sommet = 0; sommet < thenfa->trans->size_graph; sommet++) {
for (uint lettre = 0; lettre < thenfa->trans->size_alpha; lettre++) {
if (size_dequeue(thenfa->trans->edges[sommet][lettre]) < 1) {
return false;
}
}
}
return true;
}
// ReSharper disable once CppParameterMayBeConstPtrOrRef
bool nfa_is_empty(nfa *thenfa) {
printf("nfa_is_empty\n");
return thenfa->trans->size_alpha == 0 && thenfa->trans->size_graph == 0;
}
bool nfa_accepts(nfa *thenfa, const char *theword) {
printf("nfa_accepts\n");
dequeue *runs = nfa_compute_runs(thenfa, theword);
const uint size = size_dequeue(runs);
for (uint i = 0; i < size; i++) {
const uint etat = lefread_dequeue(runs, i);
if (mem_dequeue_sorted(etat, thenfa->finals)) {
delete_dequeue(runs);
return true;
}
}
delete_dequeue(runs);
return false;
}
// Calcule les états qui sont atteints par un mot dans un NFA.
// ReSharper disable once CppParameterMayBeConstPtrOrRef
dequeue *nfa_compute_runs(nfa *thenfa, const char *theword) {
printf("nfa_compute_runs\n");
dequeue *runs = create_dequeue();
uint indice = 0;
uint size = size_dequeue(thenfa->initials);
while (indice < strlen(theword)) {
dequeue *new_runs = create_dequeue();
for (uint i = 0; i < size; i++) {
const uint etat = lefread_dequeue(thenfa->initials, i);
const uint lettre = (uint)theword[indice];
merge_sorted_dequeue(new_runs, thenfa->trans->edges[etat][lettre]);
}
delete_dequeue(runs);
runs = new_runs;
size = size_dequeue(runs);
indice++;
}
return runs;
}