Skip to content
Snippets Groups Projects
Commit 5ffb7e02 authored by Robin VAN DE MERGHEL's avatar Robin VAN DE MERGHEL :computer:
Browse files

New MRP course

parent fb4d2a19
No related branches found
No related tags found
No related merge requests found
......@@ -19,3 +19,12 @@
[submodule "POO/Projet"]
path = POO/Projet
url = git@gitlab.isima.fr:rovandemer/demineur.git
[submodule "POO/ProjetV2"]
path = POO/ProjetV2
url = git@gitlab.isima.fr:rovandemer/minesweeper.git
[submodule "Web-Serveur/Projet"]
path = Web-Serveur/Projet
url = git@gitlab.isima.fr:rovandemer/le-konbah.git
[submodule "Related Personal Projects/productivity"]
path = Related Personal Projects/productivity
url = git@gitlab.isima.fr:rovandemer/productivity.git
File added
import random
import Special_Graphs
import os
import graphviz as gv
"""A vertex is a string.
A graph is a dictionary; its keys are vertices and the value associated to a
key/vertex u is the set of neighbors of u in G.
"""
def extract_graph_from_file(file):
"""Takes a file name as input and extracts the graph inside it.
The file is composed of n lines, where n is the total number of vertices.
Each line is of the form u:v1:v2:...:vk where u is a vertex and the
vi's are its neighbors. If u has no neighbor, the corresponding line is u:
This function returns a dictionary representing the graph:
Its keys are vertices and its values are the sets of neighbors
of each vertex. """
with open(file, "r") as f:
d = {}
for line in f:
line = line.strip()
line = line.split(":")
if (len(line) == 1):
d[line[0]] = set()
else:
d[line[0]] = set(line[1:])
return d
def set_of_vertices(graph):
"""Returns the set of vertices of the graph."""
return set(graph.keys())
def set_of_neighbors(graph, u):
"""Returns the set of neighbors of vertex u in the graph."""
return set(graph[u])
def degree_of(graph, u):
"""Returns the numbers of neighbors of vertex u in the graph."""
return len(graph[u])
def are_neighbors(graph, u, v):
"""Boolean function returning True if u and v are neighbors in the graph.
Returns False otherwise."""
return v in graph[u]
def number_of_vertices(graph):
"""Returns the number of vertices of the graph."""
return len(graph)
def number_of_edges(graph):
"""Returns the number of edges of the graph.
We suppose that it is NON directed."""
return sum([len(graph[u]) for u in graph]) // 2
def is_symmetric(graph):
"""Boolean function returning True if the dictionary representing the graph
is symmetric: u is a neighbor of v iff v is a neighbor of u.
Returns False otherwise and print a non symmetric couple."""
for u in graph:
for v in graph[u]:
if u not in graph[v]:
print(f"Non symmetric couple: {u}, {v}")
return False
return True
def bfs(graph, r):
"""Makes the BFS of the graph from vertex r. Returns a tuple
(parent, d, color)."""
parent = {r: None}
d = {r: 0}
color = {r: "gray"}
queue = [r]
while queue:
u = queue.pop(0)
for v in graph[u]:
if v not in color:
color[v] = "gray"
d[v] = d[u] + 1
parent[v] = u
queue.append(v)
color[u] = "black"
return parent, d, color
def color_graph_by_list(graph, list_of_vertices):
"""Takes as input a graph and a list of its vertices. This function colors
the graph with this list and returns a tuple (c, color) where:
+ color is the constructed coloration (a dictionary whose keys are the
vertices and values are colors (integers > 0)) and
+ c is the number of colors used by the coloration color."""
color = {}
c = 0
for u in list_of_vertices:
color[u] = c
c += 1
return c, color
def color_graph_by_random_lists(graph, number_of_iterations=1):
"""Takes as input a graph, and an integer number_of_iterations.
Runs number_of_iterations times the coloring function of the graph on
random lists of vertices of the graph and returns the best coloring found
(the one using the lowest number of colors)."""
best_coloring = {}
best_c = float("inf")
for i in range(number_of_iterations):
list_of_vertices = list(graph.keys())
random.shuffle(list_of_vertices)
c, color = color_graph_by_list(graph, list_of_vertices)
if c < best_c:
best_c = c
best_coloring = color
return best_coloring
def is_stable(graph, set_s):
"""Boolean function taking as input a graph and a set of vertices.
It returns True if this set is a stable of the graph (there is no edge
between vertices of this set in the graph).
Returns False otherwise."""
for u in set_s:
for v in set_s:
if are_neighbors(graph, u, v):
return False
return True
def is_proper_coloring(graph, color):
"""Takes as input a graph and a coloring (a dictionary having the set of
vertices as keys and colors (integers > 0) as values).
Returns True if color is a proper coloring of the graph.
Returns False otherwise and print a message to indicate the error."""
for u in graph:
for v in graph[u]:
if color[u] == color[v]:
print(f"Error: {u} and {v} have the same color.")
return False
return True
def render_graph(graph, color=None, filename="graph"):
with open(filename + ".dot", "w") as f:
f.write("digraph G {\n")
for u in graph:
for v in graph[u]:
if color is None:
f.write(f"{u} -> {v};\n")
else:
f.write(f"{u} -> {v} [color={color[u]}];\n")
f.write("}\n")
os.system(f"dot -Tpng {filename}.dot -o {filename}.png")
# Special_Graphs.hypercube_graph(3) # To construct a hypercube(d)
global_graph = extract_graph_from_file("hypercube.txt")
print("------ BFS from 000:", bfs(global_graph, "000"))
print(f"------ Is the graph symmetric? {is_symmetric(global_graph)}")
global_coloring_of_the_graph = color_graph_by_random_lists(global_graph, 4)
print(global_coloring_of_the_graph)
# resultG["000"] = resultG["010"] # To force an error in H3 graph.
print(f"-- Is it a valid coloring? "
f"{is_proper_coloring(global_graph, global_coloring_of_the_graph)}")
render_graph(global_graph)
# This file must be renamed Special_Graphs.py
# ------ Hypercube graphs -------
def hypercube_graph(d):
"""Constructs the hypercube graph of dimension d and write it in file Hd.
Each vertex is associated to a binary word of length d.
For example '001101' is a vertex of hypercube of dimension 6.
Two vertices are neighbors iff they differ on exactly one bit.
For example, 01001 and 01101 are neighbors in hypercube(5)."""
with open("H" + str(d), "w") as f:
for i in range(2 ** d):
f.write("{0:b}".format(i).zfill(d) + ":")
for j in range(d):
f.write("{0:b}".format(i ^ (1 << j)).zfill(d) + ":")
f.write("\n")
# ------ Complete graphs -------
def complete_graph(n):
"""Constructs a complete graph of n vertices and write it in file Kn."""
pass
# ------ Grid graphs -------
def grid_graph(p, q):
"""Constructs a grid pXq and write it in file GridpXq."""
pass
# ------ Torus graphs -------
def torus_graph(p, q):
"""Constructs a torus pXq and write it in file ToruspXq."""
pass
File added
"""Automates finis deterministes (AFD).
Un état est une chaine de caractères.
Un caractère est une chaine de longueur 1.
Un alphabet est un ensemble de catactères.
Une fonction de transition delta est un dictionnaire dont les clés sont des
tuples (q,c), avec q un état et c un caractère, et donc les valeurs sont
des états.
Un automate est un tuple :
(alphabet, ens. des états, état initial, ens. de états accepteurs, delta)
Rappels :
Déterministe = pour tout état p et tout caractère c de l'alphabet, il
existe exactement un état q tel que : delta(p,c)=q.
L'automate a exactement un état initial.
Un mot est accepté ssi en partant de l'état initial l'automate est dans un
état accepteur après avoir traité l'intégralité du mot.
"""
def alphabet(automate):
"""Retourne l'alphabet de l'automate."""
return automate[0]
def ens_etats(automate):
"""Retourne l'ens. des états de l'automate."""
return automate[1]
def etat_initial(automate):
"""Retourne l'état initial de l'automate."""
return automate[2]
def ens_etats_accepteurs(automate):
"""Retourne l'ens. des états accepteurs de l'automate."""
return automate[3]
def delta(automate):
"""Retourne la fonction de transition de l'automate."""
return automate[4]
def construit_alphabet_a_partir_de_delta(dico_delta):
"""Extrait et retourne l'ens. alphabet de l'automate dont la fonction
delta est donnée sous forme de dictionnaire."""
return {el for _, el in dico_delta.keys()}
def construit_ens_etats_a_partir_de_delta(dico_delta):
"""Extrait et retourne l'ens. des états de l'automate dont la fonction
delta est donnée sous forme de dictionnaire."""
return {el for el, _ in dico_delta.keys()}
def est_mot_compatible(automate, mot_w):
"""Fonction Booléenne retournant True ssi les caractères du mot sont tous
dans l'alphabet de l'automate."""
return {x for x in mot_w}.issubset(alphabet(automate))
def delta_etoile(automate, etat_q, mot_w):
"""Retourne l'état de l'automate après le traitement du mot à partir de
l'état etat_q de l'automate."""
etat_courant = etat_q
delta_automate = delta(automate)
for caractere in mot_w:
etat_courant = delta_automate[(etat_courant, caractere)]
return etat_courant
def est_accepte(automate, mot_w):
"""Fonction Booléenne retournant True ssi mot_w est accepté par l'automate
déterministe."""
q_0 = etat_initial(automate)
# On récupère l'état final après le traitement du mot
etat_final = delta_etoile(automate, q_0, mot_w)
# On vérifie que l'état final est un état accepteur
if etat_final in ens_etats_accepteurs(automate):
return True
return False
# Cette fonction sera utilisée dans affiche_facteur_dans_mot
def affiche_facteur(mot, indice_deb, indice_fin):
"""Affiche le facteur du mot entre des deux indices donnés,
encadré par [...]"""
print(f"{mot[:indice_deb]}[{mot[indice_deb:indice_fin]}]{mot[indice_fin:]}")
# Cette fonction sera utilisée dans affiche_tous_les_facteurs
def affiche_facteur_dans_mot(automate, mot_m, indice_i):
"""Affiche tous les facteurs f du mot mot_m, à partir de l'indice indice_i
de celui-ci, avec la propriété que f est un mot (non vide) accepté par
l'automate."""
p = etat_initial(automate)
delt = delta(automate)
long = 0
for x in mot_m[indice_i:]:
p = delt.get((p, x))
long += 1
if p != None and p in ens_etats_accepteurs(automate):
affiche_facteur(mot_m, indice_i, indice_i + long)
elif p == None:
return None
def affiche_tous_les_facteurs(automate, mot_w):
"""Affiche tous les facteurs f du mot mot_w tels que f est un mot (non
vide) accepté par l'automate. L'affichage est de la forme ...[...]...
Le mot mot_w peut contenir des caractères qui ne sont pas dans l'alphabet
de l'automate."""
for indice in range(len(mot_w)):
affiche_facteur_dans_mot(automate, mot_w, indice)
def est_automate_deterministe(automate):
"""Fonction Booléenne retournant True ssi l'automate est déterministe."""
for etat in ens_etats(automate):
for caractere in alphabet(automate):
# On récupère les états suivants pour chaque couple (état,
# caractère)
etats_suivants = [delta(automate)[(etat, caractere)]]
# On vérifie que tous les états suivants sont différents
if len(etats_suivants) != len(set(etats_suivants)):
return False
return True
# ---- Construction de l'automate 1
etat_initial_1 = 'q1'
ensemble_etats_accepteurs_1 = {'q3'}
delta_1 = {('q1', 'a'): 'q3', ('q1', 'b'): 'q1',
('q2', 'a'): 'q2', ('q2', 'b'): 'q1',
('q3', 'a'): 'q2', ('q3', 'b'): 'q3'}
automate_1 = (construit_alphabet_a_partir_de_delta(delta_1),
construit_ens_etats_a_partir_de_delta(delta_1),
etat_initial_1, ensemble_etats_accepteurs_1, delta_1)
# ---- Construction de l'automate 2 : mots contenant un nombre pair de a dans
# ---- ceux composés de a et de b uniquement.
etat_initial_2 = 'q1'
ensemble_etats_accepteurs_2 = {'q1'}
delta_2 = {('q1', 'a'): 'q2', ('q1', 'b'): 'q1',
('q2', 'a'): 'q1', ('q2', 'b'): 'q2'}
automate_2 = (construit_alphabet_a_partir_de_delta(delta_2),
construit_ens_etats_a_partir_de_delta(delta_2),
etat_initial_2, ensemble_etats_accepteurs_2, delta_2)
# ---- Tests de diverses fonctions.
w = "abbaabbXYba"
if est_mot_compatible(automate_1, w):
print(f'Le mot "{w}" est ' + 'accepté' if est_accepte(automate_1, w) else
'refusé')
else:
print(f'Le mot "{w}" contient des caractères qui ne sont pas '
'dans l\'alphabet')
print("--"*10 + f'Facteurs de "{w}" de l\'Automate 1 :')
affiche_tous_les_facteurs(automate_1, w)
print("--"*10 + f'Facteurs de "{w}" de l\'Automate 2 :')
affiche_tous_les_facteurs(automate_2, w)
# --- Pour vous aider, voici ce que doit afficher cette dernière ligne :
# --------------------Facteurs de "abbaabbXYba" de l'Automate 2 :
# [abba]abbXYba
# a[b]baabbXYba
# a[bb]aabbXYba
# a[bbaa]bbXYba
# a[bbaab]bXYba
# a[bbaabb]XYba
# ab[b]aabbXYba
# ab[baa]bbXYba
# ab[baab]bXYba
# ab[baabb]XYba
# abb[aa]bbXYba
# abb[aab]bXYba
# abb[aabb]XYba
# abbaa[b]bXYba
# abbaa[bb]XYba
# abbaab[b]XYba
# abbaabbXY[b]a
digraph G {
000 -> 010;
000 -> 100;
000 -> 001;
001 -> 011;
001 -> 000;
001 -> 101;
010 -> 110;
010 -> 011;
010 -> 000;
011 -> 010;
011 -> 111;
011 -> 001;
100 -> 110;
100 -> 000;
100 -> 101;
101 -> 111;
101 -> 100;
101 -> 001;
110 -> 010;
110 -> 111;
110 -> 100;
111 -> 110;
111 -> 011;
111 -> 101;
}
Modeliser Resolution/graph.png

63.3 KiB

000:100:010:001
001:101:011:000
010:110:000:011
011:111:001:010
100:000:110:101
101:001:111:100
110:010:100:111
111:011:101:110
Subproject commit 91724c4b3eda66d87a5cad5faccac7a91242c45b
Subproject commit 135d82b35a158bddc3645f245d009983181ba7bb
Subproject commit 5d9a0fd9779637bbb91d412cf888e3533f3ab6cf
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment