Lundi 30 octobre 2023
k-leafs-cover.c | sat-solver.c
Ce programme suit le même modèle que le programme pour le problème Couverture par sommets : il offre les mêmes fonctionnalités pour le problème Arbre à k feuilles.
wget https://sylvain-chiron.emi.u-bordeaux.fr/coca/k-leafs-cover.c https://sylvain-chiron.emi.u-bordeaux.fr/coca/sat-solver.c \ https://gitlab.com/Frigory33/handymacros/-/raw/master/src/handymacros.h https://gitlab.com/Frigory33/handymacros/-/raw/master/src/handymacros.c cc -o k-leafs-cover k-leafs-cover.c handymacros.c -I . -Wall -O2 ./k-leafs-cover $mode help
Rappel des quatre modes : rien (résoudre), verify
, reduce
et valuation
. Cette fois, la
réduction vers SAT ne donne pas une formule CNF.
Lorsque vous avez une réduction vers SAT, vous pouvez compiler et exécuter votre sat-solver
de cette façon :
cc -o sat-solver sat-solver.c handymacros.c -x c - -I . -Wall -O2 -D K_LEAFS_COVER ./sat-solver
Voir plus bas le format que doit avoir le fichier d’entrée.
Le problème Arbre à k feuilles a été le sujet du devoir surveillé du 23 octobre. On nous y a demandé de décrire le fonctionnement d’un vérificateur pour ce problème, et de compléter un algorithme de réduction de ce problème vers SAT.
Le problème correspond à la question suivante : « Pour un graphe donné et un entier k, existe-t-il un arbre couvrant ce graphe qui a exactement k feuilles ? » Par exemple, sur le graphe G₁ ci-dessous, les arêtes bleues correspondent à un arbre couvrant à 3 feuilles.
Les informations déjà présentes sur la page du programme pour le problème Couverture par sommets ne sont pas répétées ici.
Les exemples de la section suivante sont faits avec les deux graphes ci-dessous :
G₁ | 5 7 0 1 0 2 0 3 0 4 2 3 2 4 3 4 |
G₂ | 6 6 1 2 2 3 3 4 0 3 3 5 5 0 |
Résolutions pour le graphe G₁ :
$ ./k-leafs-cover help Instance : Graphe : Nb sommets et arêtes : 5 7 Arête : 0 1 Arête : 0 2 Arête : 0 3 Arête : 0 4 Arête : 2 3 Arête : 2 4 Arête : 3 4 Nb feuilles voulues : 4 Réponse : Oui Certificat : Arêtes : 0 1 2 3
$ ./k-leafs-cover Instance : 5 7 0 1 0 2 0 3 0 4 2 3 2 4 3 4 3 Réponse : Oui Certificat : Arêtes : 0 1 2 5
$ ./k-leafs-cover Instance : 5 7 0 1 0 2 0 3 0 4 2 3 2 4 3 4 2 Réponse : Oui Certificat : Arêtes : 0 1 4 6
Résolutions pour le graphe G₂ :
$ ./k-leafs-cover Instance : 6 6 1 2 2 3 3 4 0 3 3 5 5 0 4 Réponse : Oui Certificat : Arêtes : 0 1 2 3 4
$ ./k-leafs-cover Instance : 6 6 1 2 2 3 3 4 0 3 3 5 5 0 3 Réponse : Oui Certificat : Arêtes : 0 1 2 3 5
$ ./k-leafs-cover Instance : 6 6 1 2 2 3 3 4 0 3 3 5 5 0 2 Réponse : Non
Vérifications de la sélection (les arêtes bleues) sur le graphe G₁ :
$ ./k-leafs-cover verify help Instance : Graphe : Nb sommets et arêtes : 5 7 Arête : 0 1 Arête : 0 2 Arête : 0 3 Arête : 0 4 Arête : 2 3 Arête : 2 4 Arête : 3 4 Nb feuilles voulues : 3 Valeurs : Nb arêtes : 4 Arêtes (par n°) : 4 5 0 1 Ça passe
Instance : 5 7 0 1 0 2 0 3 0 4 2 3 2 4 3 4 4 Valeurs : 4 4 5 0 1 Ça ne passe pas
Réduction pour le petit graphe G du problème Couverture par sommets :
$ ./k-leafs-cover reduce Instance : 3 2 0 1 1 2 2 Réduction : ( // φ1 ( true && (false || y[0][0] || y[1][0] || y[2][0]) && (false || y[0][1] || y[1][1] || y[2][1]) ) && ( true && ( true && (!y[0][0] || !y[1][0]) && (!y[0][0] || !y[2][0]) && (!y[1][0] || !y[2][0]) ) && ( true && (!y[0][1] || !y[1][1]) && (!y[0][1] || !y[2][1]) && (!y[1][1] || !y[2][1]) ) ) && ( true && ( true && (!y[0][0] || !y[0][1]) ) && ( true && (!y[1][0] || !y[1][1]) ) && ( true && (!y[2][0] || !y[2][1]) ) ) ) && ( // φ2 true && ( z[1][0][0] == (false || y[0][0] || y[0][1]) && ( true && z[1][0][1] == (z[1][0][0] || (z[0][0][0] && z[1][0][0])) && z[1][0][2] == (z[1][0][1] || (z[0][1][1] && z[1][1][1])) && z[1][0][3] == (z[1][0][2] || (z[0][2][2] && z[1][2][2])) ) && z[1][0][3] ) && ( !z[2][0][0] && ( true && z[2][0][1] == (z[2][0][0] || (z[0][0][0] && z[2][0][0])) && z[2][0][2] == (z[2][0][1] || (z[0][1][1] && z[2][1][1])) && z[2][0][3] == (z[2][0][2] || (z[0][2][2] && z[2][2][2])) ) && z[2][0][3] ) && ( z[2][1][0] == (false || y[1][0] || y[1][1]) && ( true && z[2][1][1] == (z[2][1][0] || (z[1][0][0] && z[2][0][0])) && z[2][1][2] == (z[2][1][1] || (z[1][1][1] && z[2][1][1])) && z[2][1][3] == (z[2][1][2] || (z[1][2][2] && z[2][2][2])) ) && z[2][1][3] ) ) && ( // φ3 ( true && ( (false || x[0][0] || x[0][1]) == ( true && (!z[1][0][0] || !z[2][0][0]) ) ) && ( (false || x[1][0] || x[1][1]) == ( true && (!z[1][0][0] || !z[2][1][0]) ) ) && ( (false || x[2][0] || x[2][1]) == ( true && (!z[2][0][0] || !z[2][1][0]) ) ) ) && ( true && (false || x[0][0] || x[1][0] || x[2][0]) && (false || x[0][1] || x[1][1] || x[2][1]) ) && ( true && ( true && (!x[0][0] || !x[1][0]) && (!x[0][0] || !x[2][0]) && (!x[1][0] || !x[2][0]) ) && ( true && (!x[0][1] || !x[1][1]) && (!x[0][1] || !x[2][1]) && (!x[1][1] || !x[2][1]) ) ) && ( true && ( true && (!x[0][0] || !x[0][1]) ) && ( true && (!x[1][0] || !x[1][1]) ) && ( true && (!x[2][0] || !x[2][1]) ) ) )
Réduction pour le graphe G₂ :
$ ./k-leafs-cover reduce Instance : 6 6 1 2 2 3 3 4 0 3 3 5 5 0 3 Réduction : ( // φ1 ( true && (false || y[0][0] || y[1][0] || y[2][0] || y[3][0] || y[4][0] || y[5][0]) && (false || y[0][1] || y[1][1] || y[2][1] || y[3][1] || y[4][1] || y[5][1]) && (false || y[0][2] || y[1][2] || y[2][2] || y[3][2] || y[4][2] || y[5][2]) && (false || y[0][3] || y[1][3] || y[2][3] || y[3][3] || y[4][3] || y[5][3]) && (false || y[0][4] || y[1][4] || y[2][4] || y[3][4] || y[4][4] || y[5][4]) ) && ( true && ( true && (!y[0][0] || !y[1][0]) && (!y[0][0] || !y[2][0]) && (!y[0][0] || !y[3][0]) && (!y[0][0] || !y[4][0]) && (!y[0][0] || !y[5][0]) && (!y[1][0] || !y[2][0]) && (!y[1][0] || !y[3][0]) && (!y[1][0] || !y[4][0]) && (!y[1][0] || !y[5][0]) && (!y[2][0] || !y[3][0]) && (!y[2][0] || !y[4][0]) && (!y[2][0] || !y[5][0]) && (!y[3][0] || !y[4][0]) && (!y[3][0] || !y[5][0]) && (!y[4][0] || !y[5][0]) ) && ( true && (!y[0][1] || !y[1][1]) && (!y[0][1] || !y[2][1]) && (!y[0][1] || !y[3][1]) && (!y[0][1] || !y[4][1]) && (!y[0][1] || !y[5][1]) && (!y[1][1] || !y[2][1]) && (!y[1][1] || !y[3][1]) && (!y[1][1] || !y[4][1]) && (!y[1][1] || !y[5][1]) && (!y[2][1] || !y[3][1]) && (!y[2][1] || !y[4][1]) && (!y[2][1] || !y[5][1]) && (!y[3][1] || !y[4][1]) && (!y[3][1] || !y[5][1]) && (!y[4][1] || !y[5][1]) ) && ( true && (!y[0][2] || !y[1][2]) && (!y[0][2] || !y[2][2]) && (!y[0][2] || !y[3][2]) && (!y[0][2] || !y[4][2]) && (!y[0][2] || !y[5][2]) && (!y[1][2] || !y[2][2]) && (!y[1][2] || !y[3][2]) && (!y[1][2] || !y[4][2]) && (!y[1][2] || !y[5][2]) && (!y[2][2] || !y[3][2]) && (!y[2][2] || !y[4][2]) && (!y[2][2] || !y[5][2]) && (!y[3][2] || !y[4][2]) && (!y[3][2] || !y[5][2]) && (!y[4][2] || !y[5][2]) ) && ( true && (!y[0][3] || !y[1][3]) && (!y[0][3] || !y[2][3]) && (!y[0][3] || !y[3][3]) && (!y[0][3] || !y[4][3]) && (!y[0][3] || !y[5][3]) && (!y[1][3] || !y[2][3]) && (!y[1][3] || !y[3][3]) && (!y[1][3] || !y[4][3]) && (!y[1][3] || !y[5][3]) && (!y[2][3] || !y[3][3]) && (!y[2][3] || !y[4][3]) && (!y[2][3] || !y[5][3]) && (!y[3][3] || !y[4][3]) && (!y[3][3] || !y[5][3]) && (!y[4][3] || !y[5][3]) ) && ( true && (!y[0][4] || !y[1][4]) && (!y[0][4] || !y[2][4]) && (!y[0][4] || !y[3][4]) && (!y[0][4] || !y[4][4]) && (!y[0][4] || !y[5][4]) && (!y[1][4] || !y[2][4]) && (!y[1][4] || !y[3][4]) && (!y[1][4] || !y[4][4]) && (!y[1][4] || !y[5][4]) && (!y[2][4] || !y[3][4]) && (!y[2][4] || !y[4][4]) && (!y[2][4] || !y[5][4]) && (!y[3][4] || !y[4][4]) && (!y[3][4] || !y[5][4]) && (!y[4][4] || !y[5][4]) ) ) && ( true && ( true && (!y[0][0] || !y[0][1]) && (!y[0][0] || !y[0][2]) && (!y[0][0] || !y[0][3]) && (!y[0][0] || !y[0][4]) && (!y[0][1] || !y[0][2]) && (!y[0][1] || !y[0][3]) && (!y[0][1] || !y[0][4]) && (!y[0][2] || !y[0][3]) && (!y[0][2] || !y[0][4]) && (!y[0][3] || !y[0][4]) ) && ( true && (!y[1][0] || !y[1][1]) && (!y[1][0] || !y[1][2]) && (!y[1][0] || !y[1][3]) && (!y[1][0] || !y[1][4]) && (!y[1][1] || !y[1][2]) && (!y[1][1] || !y[1][3]) && (!y[1][1] || !y[1][4]) && (!y[1][2] || !y[1][3]) && (!y[1][2] || !y[1][4]) && (!y[1][3] || !y[1][4]) ) && ( true && (!y[2][0] || !y[2][1]) && (!y[2][0] || !y[2][2]) && (!y[2][0] || !y[2][3]) && (!y[2][0] || !y[2][4]) && (!y[2][1] || !y[2][2]) && (!y[2][1] || !y[2][3]) && (!y[2][1] || !y[2][4]) && (!y[2][2] || !y[2][3]) && (!y[2][2] || !y[2][4]) && (!y[2][3] || !y[2][4]) ) && ( true && (!y[3][0] || !y[3][1]) && (!y[3][0] || !y[3][2]) && (!y[3][0] || !y[3][3]) && (!y[3][0] || !y[3][4]) && (!y[3][1] || !y[3][2]) && (!y[3][1] || !y[3][3]) && (!y[3][1] || !y[3][4]) && (!y[3][2] || !y[3][3]) && (!y[3][2] || !y[3][4]) && (!y[3][3] || !y[3][4]) ) && ( true && (!y[4][0] || !y[4][1]) && (!y[4][0] || !y[4][2]) && (!y[4][0] || !y[4][3]) && (!y[4][0] || !y[4][4]) && (!y[4][1] || !y[4][2]) && (!y[4][1] || !y[4][3]) && (!y[4][1] || !y[4][4]) && (!y[4][2] || !y[4][3]) && (!y[4][2] || !y[4][4]) && (!y[4][3] || !y[4][4]) ) && ( true && (!y[5][0] || !y[5][1]) && (!y[5][0] || !y[5][2]) && (!y[5][0] || !y[5][3]) && (!y[5][0] || !y[5][4]) && (!y[5][1] || !y[5][2]) && (!y[5][1] || !y[5][3]) && (!y[5][1] || !y[5][4]) && (!y[5][2] || !y[5][3]) && (!y[5][2] || !y[5][4]) && (!y[5][3] || !y[5][4]) ) ) ) && ( // φ2 true && ( !z[1][0][0] && ( true && z[1][0][1] == (z[1][0][0] || (z[0][0][0] && z[1][0][0])) && z[1][0][2] == (z[1][0][1] || (z[0][1][1] && z[1][1][1])) && z[1][0][3] == (z[1][0][2] || (z[0][2][2] && z[1][2][2])) && z[1][0][4] == (z[1][0][3] || (z[0][3][3] && z[1][3][3])) && z[1][0][5] == (z[1][0][4] || (z[0][4][4] && z[1][4][4])) && z[1][0][6] == (z[1][0][5] || (z[0][5][5] && z[1][5][5])) ) && z[1][0][6] ) && ( !z[2][0][0] && ( true && z[2][0][1] == (z[2][0][0] || (z[0][0][0] && z[2][0][0])) && z[2][0][2] == (z[2][0][1] || (z[0][1][1] && z[2][1][1])) && z[2][0][3] == (z[2][0][2] || (z[0][2][2] && z[2][2][2])) && z[2][0][4] == (z[2][0][3] || (z[0][3][3] && z[2][3][3])) && z[2][0][5] == (z[2][0][4] || (z[0][4][4] && z[2][4][4])) && z[2][0][6] == (z[2][0][5] || (z[0][5][5] && z[2][5][5])) ) && z[2][0][6] ) && ( z[3][0][0] == (false || y[3][0] || y[3][1] || y[3][2] || y[3][3] || y[3][4]) && ( true && z[3][0][1] == (z[3][0][0] || (z[0][0][0] && z[3][0][0])) && z[3][0][2] == (z[3][0][1] || (z[0][1][1] && z[3][1][1])) && z[3][0][3] == (z[3][0][2] || (z[0][2][2] && z[3][2][2])) && z[3][0][4] == (z[3][0][3] || (z[0][3][3] && z[3][3][3])) && z[3][0][5] == (z[3][0][4] || (z[0][4][4] && z[3][4][4])) && z[3][0][6] == (z[3][0][5] || (z[0][5][5] && z[3][5][5])) ) && z[3][0][6] ) && ( !z[4][0][0] && ( true && z[4][0][1] == (z[4][0][0] || (z[0][0][0] && z[4][0][0])) && z[4][0][2] == (z[4][0][1] || (z[0][1][1] && z[4][1][1])) && z[4][0][3] == (z[4][0][2] || (z[0][2][2] && z[4][2][2])) && z[4][0][4] == (z[4][0][3] || (z[0][3][3] && z[4][3][3])) && z[4][0][5] == (z[4][0][4] || (z[0][4][4] && z[4][4][4])) && z[4][0][6] == (z[4][0][5] || (z[0][5][5] && z[4][5][5])) ) && z[4][0][6] ) && ( z[5][0][0] == (false || y[5][0] || y[5][1] || y[5][2] || y[5][3] || y[5][4]) && ( true && z[5][0][1] == (z[5][0][0] || (z[0][0][0] && z[5][0][0])) && z[5][0][2] == (z[5][0][1] || (z[0][1][1] && z[5][1][1])) && z[5][0][3] == (z[5][0][2] || (z[0][2][2] && z[5][2][2])) && z[5][0][4] == (z[5][0][3] || (z[0][3][3] && z[5][3][3])) && z[5][0][5] == (z[5][0][4] || (z[0][4][4] && z[5][4][4])) && z[5][0][6] == (z[5][0][5] || (z[0][5][5] && z[5][5][5])) ) && z[5][0][6] ) && ( z[2][1][0] == (false || y[0][0] || y[0][1] || y[0][2] || y[0][3] || y[0][4]) && ( true && z[2][1][1] == (z[2][1][0] || (z[1][0][0] && z[2][0][0])) && z[2][1][2] == (z[2][1][1] || (z[1][1][1] && z[2][1][1])) && z[2][1][3] == (z[2][1][2] || (z[1][2][2] && z[2][2][2])) && z[2][1][4] == (z[2][1][3] || (z[1][3][3] && z[2][3][3])) && z[2][1][5] == (z[2][1][4] || (z[1][4][4] && z[2][4][4])) && z[2][1][6] == (z[2][1][5] || (z[1][5][5] && z[2][5][5])) ) && z[2][1][6] ) && ( !z[3][1][0] && ( true && z[3][1][1] == (z[3][1][0] || (z[1][0][0] && z[3][0][0])) && z[3][1][2] == (z[3][1][1] || (z[1][1][1] && z[3][1][1])) && z[3][1][3] == (z[3][1][2] || (z[1][2][2] && z[3][2][2])) && z[3][1][4] == (z[3][1][3] || (z[1][3][3] && z[3][3][3])) && z[3][1][5] == (z[3][1][4] || (z[1][4][4] && z[3][4][4])) && z[3][1][6] == (z[3][1][5] || (z[1][5][5] && z[3][5][5])) ) && z[3][1][6] ) && ( !z[4][1][0] && ( true && z[4][1][1] == (z[4][1][0] || (z[1][0][0] && z[4][0][0])) && z[4][1][2] == (z[4][1][1] || (z[1][1][1] && z[4][1][1])) && z[4][1][3] == (z[4][1][2] || (z[1][2][2] && z[4][2][2])) && z[4][1][4] == (z[4][1][3] || (z[1][3][3] && z[4][3][3])) && z[4][1][5] == (z[4][1][4] || (z[1][4][4] && z[4][4][4])) && z[4][1][6] == (z[4][1][5] || (z[1][5][5] && z[4][5][5])) ) && z[4][1][6] ) && ( !z[5][1][0] && ( true && z[5][1][1] == (z[5][1][0] || (z[1][0][0] && z[5][0][0])) && z[5][1][2] == (z[5][1][1] || (z[1][1][1] && z[5][1][1])) && z[5][1][3] == (z[5][1][2] || (z[1][2][2] && z[5][2][2])) && z[5][1][4] == (z[5][1][3] || (z[1][3][3] && z[5][3][3])) && z[5][1][5] == (z[5][1][4] || (z[1][4][4] && z[5][4][4])) && z[5][1][6] == (z[5][1][5] || (z[1][5][5] && z[5][5][5])) ) && z[5][1][6] ) && ( z[3][2][0] == (false || y[1][0] || y[1][1] || y[1][2] || y[1][3] || y[1][4]) && ( true && z[3][2][1] == (z[3][2][0] || (z[2][0][0] && z[3][0][0])) && z[3][2][2] == (z[3][2][1] || (z[2][1][1] && z[3][1][1])) && z[3][2][3] == (z[3][2][2] || (z[2][2][2] && z[3][2][2])) && z[3][2][4] == (z[3][2][3] || (z[2][3][3] && z[3][3][3])) && z[3][2][5] == (z[3][2][4] || (z[2][4][4] && z[3][4][4])) && z[3][2][6] == (z[3][2][5] || (z[2][5][5] && z[3][5][5])) ) && z[3][2][6] ) && ( !z[4][2][0] && ( true && z[4][2][1] == (z[4][2][0] || (z[2][0][0] && z[4][0][0])) && z[4][2][2] == (z[4][2][1] || (z[2][1][1] && z[4][1][1])) && z[4][2][3] == (z[4][2][2] || (z[2][2][2] && z[4][2][2])) && z[4][2][4] == (z[4][2][3] || (z[2][3][3] && z[4][3][3])) && z[4][2][5] == (z[4][2][4] || (z[2][4][4] && z[4][4][4])) && z[4][2][6] == (z[4][2][5] || (z[2][5][5] && z[4][5][5])) ) && z[4][2][6] ) && ( !z[5][2][0] && ( true && z[5][2][1] == (z[5][2][0] || (z[2][0][0] && z[5][0][0])) && z[5][2][2] == (z[5][2][1] || (z[2][1][1] && z[5][1][1])) && z[5][2][3] == (z[5][2][2] || (z[2][2][2] && z[5][2][2])) && z[5][2][4] == (z[5][2][3] || (z[2][3][3] && z[5][3][3])) && z[5][2][5] == (z[5][2][4] || (z[2][4][4] && z[5][4][4])) && z[5][2][6] == (z[5][2][5] || (z[2][5][5] && z[5][5][5])) ) && z[5][2][6] ) && ( z[4][3][0] == (false || y[2][0] || y[2][1] || y[2][2] || y[2][3] || y[2][4]) && ( true && z[4][3][1] == (z[4][3][0] || (z[3][0][0] && z[4][0][0])) && z[4][3][2] == (z[4][3][1] || (z[3][1][1] && z[4][1][1])) && z[4][3][3] == (z[4][3][2] || (z[3][2][2] && z[4][2][2])) && z[4][3][4] == (z[4][3][3] || (z[3][3][3] && z[4][3][3])) && z[4][3][5] == (z[4][3][4] || (z[3][4][4] && z[4][4][4])) && z[4][3][6] == (z[4][3][5] || (z[3][5][5] && z[4][5][5])) ) && z[4][3][6] ) && ( z[5][3][0] == (false || y[4][0] || y[4][1] || y[4][2] || y[4][3] || y[4][4]) && ( true && z[5][3][1] == (z[5][3][0] || (z[3][0][0] && z[5][0][0])) && z[5][3][2] == (z[5][3][1] || (z[3][1][1] && z[5][1][1])) && z[5][3][3] == (z[5][3][2] || (z[3][2][2] && z[5][2][2])) && z[5][3][4] == (z[5][3][3] || (z[3][3][3] && z[5][3][3])) && z[5][3][5] == (z[5][3][4] || (z[3][4][4] && z[5][4][4])) && z[5][3][6] == (z[5][3][5] || (z[3][5][5] && z[5][5][5])) ) && z[5][3][6] ) && ( !z[5][4][0] && ( true && z[5][4][1] == (z[5][4][0] || (z[4][0][0] && z[5][0][0])) && z[5][4][2] == (z[5][4][1] || (z[4][1][1] && z[5][1][1])) && z[5][4][3] == (z[5][4][2] || (z[4][2][2] && z[5][2][2])) && z[5][4][4] == (z[5][4][3] || (z[4][3][3] && z[5][3][3])) && z[5][4][5] == (z[5][4][4] || (z[4][4][4] && z[5][4][4])) && z[5][4][6] == (z[5][4][5] || (z[4][5][5] && z[5][5][5])) ) && z[5][4][6] ) ) && ( // φ3 ( true && ( (false || x[0][0] || x[0][1] || x[0][2]) == ( true && (!z[1][0][0] || !z[2][0][0]) && (!z[1][0][0] || !z[3][0][0]) && (!z[1][0][0] || !z[4][0][0]) && (!z[1][0][0] || !z[5][0][0]) && (!z[2][0][0] || !z[3][0][0]) && (!z[2][0][0] || !z[4][0][0]) && (!z[2][0][0] || !z[5][0][0]) && (!z[3][0][0] || !z[4][0][0]) && (!z[3][0][0] || !z[5][0][0]) && (!z[4][0][0] || !z[5][0][0]) ) ) && ( (false || x[1][0] || x[1][1] || x[1][2]) == ( true && (!z[1][0][0] || !z[2][1][0]) && (!z[1][0][0] || !z[3][1][0]) && (!z[1][0][0] || !z[4][1][0]) && (!z[1][0][0] || !z[5][1][0]) && (!z[2][1][0] || !z[3][1][0]) && (!z[2][1][0] || !z[4][1][0]) && (!z[2][1][0] || !z[5][1][0]) && (!z[3][1][0] || !z[4][1][0]) && (!z[3][1][0] || !z[5][1][0]) && (!z[4][1][0] || !z[5][1][0]) ) ) && ( (false || x[2][0] || x[2][1] || x[2][2]) == ( true && (!z[2][0][0] || !z[2][1][0]) && (!z[2][0][0] || !z[3][2][0]) && (!z[2][0][0] || !z[4][2][0]) && (!z[2][0][0] || !z[5][2][0]) && (!z[2][1][0] || !z[3][2][0]) && (!z[2][1][0] || !z[4][2][0]) && (!z[2][1][0] || !z[5][2][0]) && (!z[3][2][0] || !z[4][2][0]) && (!z[3][2][0] || !z[5][2][0]) && (!z[4][2][0] || !z[5][2][0]) ) ) && ( (false || x[3][0] || x[3][1] || x[3][2]) == ( true && (!z[3][0][0] || !z[3][1][0]) && (!z[3][0][0] || !z[3][2][0]) && (!z[3][0][0] || !z[4][3][0]) && (!z[3][0][0] || !z[5][3][0]) && (!z[3][1][0] || !z[3][2][0]) && (!z[3][1][0] || !z[4][3][0]) && (!z[3][1][0] || !z[5][3][0]) && (!z[3][2][0] || !z[4][3][0]) && (!z[3][2][0] || !z[5][3][0]) && (!z[4][3][0] || !z[5][3][0]) ) ) && ( (false || x[4][0] || x[4][1] || x[4][2]) == ( true && (!z[4][0][0] || !z[4][1][0]) && (!z[4][0][0] || !z[4][2][0]) && (!z[4][0][0] || !z[4][3][0]) && (!z[4][0][0] || !z[5][4][0]) && (!z[4][1][0] || !z[4][2][0]) && (!z[4][1][0] || !z[4][3][0]) && (!z[4][1][0] || !z[5][4][0]) && (!z[4][2][0] || !z[4][3][0]) && (!z[4][2][0] || !z[5][4][0]) && (!z[4][3][0] || !z[5][4][0]) ) ) && ( (false || x[5][0] || x[5][1] || x[5][2]) == ( true && (!z[5][0][0] || !z[5][1][0]) && (!z[5][0][0] || !z[5][2][0]) && (!z[5][0][0] || !z[5][3][0]) && (!z[5][0][0] || !z[5][4][0]) && (!z[5][1][0] || !z[5][2][0]) && (!z[5][1][0] || !z[5][3][0]) && (!z[5][1][0] || !z[5][4][0]) && (!z[5][2][0] || !z[5][3][0]) && (!z[5][2][0] || !z[5][4][0]) && (!z[5][3][0] || !z[5][4][0]) ) ) ) && ( true && (false || x[0][0] || x[1][0] || x[2][0] || x[3][0] || x[4][0] || x[5][0]) && (false || x[0][1] || x[1][1] || x[2][1] || x[3][1] || x[4][1] || x[5][1]) && (false || x[0][2] || x[1][2] || x[2][2] || x[3][2] || x[4][2] || x[5][2]) ) && ( true && ( true && (!x[0][0] || !x[1][0]) && (!x[0][0] || !x[2][0]) && (!x[0][0] || !x[3][0]) && (!x[0][0] || !x[4][0]) && (!x[0][0] || !x[5][0]) && (!x[1][0] || !x[2][0]) && (!x[1][0] || !x[3][0]) && (!x[1][0] || !x[4][0]) && (!x[1][0] || !x[5][0]) && (!x[2][0] || !x[3][0]) && (!x[2][0] || !x[4][0]) && (!x[2][0] || !x[5][0]) && (!x[3][0] || !x[4][0]) && (!x[3][0] || !x[5][0]) && (!x[4][0] || !x[5][0]) ) && ( true && (!x[0][1] || !x[1][1]) && (!x[0][1] || !x[2][1]) && (!x[0][1] || !x[3][1]) && (!x[0][1] || !x[4][1]) && (!x[0][1] || !x[5][1]) && (!x[1][1] || !x[2][1]) && (!x[1][1] || !x[3][1]) && (!x[1][1] || !x[4][1]) && (!x[1][1] || !x[5][1]) && (!x[2][1] || !x[3][1]) && (!x[2][1] || !x[4][1]) && (!x[2][1] || !x[5][1]) && (!x[3][1] || !x[4][1]) && (!x[3][1] || !x[5][1]) && (!x[4][1] || !x[5][1]) ) && ( true && (!x[0][2] || !x[1][2]) && (!x[0][2] || !x[2][2]) && (!x[0][2] || !x[3][2]) && (!x[0][2] || !x[4][2]) && (!x[0][2] || !x[5][2]) && (!x[1][2] || !x[2][2]) && (!x[1][2] || !x[3][2]) && (!x[1][2] || !x[4][2]) && (!x[1][2] || !x[5][2]) && (!x[2][2] || !x[3][2]) && (!x[2][2] || !x[4][2]) && (!x[2][2] || !x[5][2]) && (!x[3][2] || !x[4][2]) && (!x[3][2] || !x[5][2]) && (!x[4][2] || !x[5][2]) ) ) && ( true && ( true && (!x[0][0] || !x[0][1]) && (!x[0][0] || !x[0][2]) && (!x[0][1] || !x[0][2]) ) && ( true && (!x[1][0] || !x[1][1]) && (!x[1][0] || !x[1][2]) && (!x[1][1] || !x[1][2]) ) && ( true && (!x[2][0] || !x[2][1]) && (!x[2][0] || !x[2][2]) && (!x[2][1] || !x[2][2]) ) && ( true && (!x[3][0] || !x[3][1]) && (!x[3][0] || !x[3][2]) && (!x[3][1] || !x[3][2]) ) && ( true && (!x[4][0] || !x[4][1]) && (!x[4][0] || !x[4][2]) && (!x[4][1] || !x[4][2]) ) && ( true && (!x[5][0] || !x[5][1]) && (!x[5][0] || !x[5][2]) && (!x[5][1] || !x[5][2]) ) ) )
Valuation pour le graphe G₂ et la solution pour 3 feuilles :
$ ./k-leafs-cover valuation Instance : 6 6 1 2 2 3 3 4 0 3 3 5 5 0 3 Valeurs : 5 0 1 2 3 5 Valuation : bool y[6][5] = { [0][0] = true, [1][1] = true, [2][2] = true, [3][3] = true, [5][4] = true, }, z[6][6][7] = { [1][2][0] = true, [2][1][0] = true, [2][3][0] = true, [3][2][0] = true, [3][4][0] = true, [4][3][0] = true, [0][3][0] = true, [3][0][0] = true, [5][0][0] = true, [0][5][0] = true, [0][3][1] = true, [3][0][1] = true, [0][5][1] = true, [5][0][1] = true, [1][2][1] = true, [2][1][1] = true, [2][3][1] = true, [3][2][1] = true, [3][4][1] = true, [4][3][1] = true, [3][5][1] = true, [5][3][1] = true, [0][3][2] = true, [3][0][2] = true, [0][5][2] = true, [5][0][2] = true, [1][2][2] = true, [2][1][2] = true, [2][3][2] = true, [3][2][2] = true, [3][4][2] = true, [4][3][2] = true, [3][5][2] = true, [5][3][2] = true, [0][3][3] = true, [3][0][3] = true, [0][5][3] = true, [5][0][3] = true, [1][2][3] = true, [2][1][3] = true, [1][3][3] = true, [3][1][3] = true, [2][3][3] = true, [3][2][3] = true, [3][4][3] = true, [4][3][3] = true, [3][5][3] = true, [5][3][3] = true, [0][1][4] = true, [1][0][4] = true, [0][2][4] = true, [2][0][4] = true, [0][3][4] = true, [3][0][4] = true, [0][4][4] = true, [4][0][4] = true, [0][5][4] = true, [5][0][4] = true, [1][2][4] = true, [2][1][4] = true, [1][3][4] = true, [3][1][4] = true, [1][4][4] = true, [4][1][4] = true, [1][5][4] = true, [5][1][4] = true, [2][3][4] = true, [3][2][4] = true, [2][4][4] = true, [4][2][4] = true, [2][5][4] = true, [5][2][4] = true, [3][4][4] = true, [4][3][4] = true, [3][5][4] = true, [5][3][4] = true, [4][5][4] = true, [5][4][4] = true, [0][1][5] = true, [1][0][5] = true, [0][2][5] = true, [2][0][5] = true, [0][3][5] = true, [3][0][5] = true, [0][4][5] = true, [4][0][5] = true, [0][5][5] = true, [5][0][5] = true, [1][2][5] = true, [2][1][5] = true, [1][3][5] = true, [3][1][5] = true, [1][4][5] = true, [4][1][5] = true, [1][5][5] = true, [5][1][5] = true, [2][3][5] = true, [3][2][5] = true, [2][4][5] = true, [4][2][5] = true, [2][5][5] = true, [5][2][5] = true, [3][4][5] = true, [4][3][5] = true, [3][5][5] = true, [5][3][5] = true, [4][5][5] = true, [5][4][5] = true, [0][1][6] = true, [1][0][6] = true, [0][2][6] = true, [2][0][6] = true, [0][3][6] = true, [3][0][6] = true, [0][4][6] = true, [4][0][6] = true, [0][5][6] = true, [5][0][6] = true, [1][2][6] = true, [2][1][6] = true, [1][3][6] = true, [3][1][6] = true, [1][4][6] = true, [4][1][6] = true, [1][5][6] = true, [5][1][6] = true, [2][3][6] = true, [3][2][6] = true, [2][4][6] = true, [4][2][6] = true, [2][5][6] = true, [5][2][6] = true, [3][4][6] = true, [4][3][6] = true, [3][5][6] = true, [5][3][6] = true, [4][5][6] = true, [5][4][6] = true, }, x[6][3] = { [1][0] = true, [4][1] = true, [5][2] = true, };
Les expressions générées par les fonctionnalités de réduction et de valuation peuvent être utilisées dans un programme de ce type :
#include <stdio.h> #include <handymacros.h> int main() { // Mettez la valuation ici bool ok = // Mettez l’expression ici ; if (ok) { printf("Valuation satisfaisante\nArêtes :"); for_range (int, edgeNum, 0, < array_len(y), ++) { for_array (bool, val, y[edgeNum]) { if (val) { printf(" %d", edgeNum); } } } printf("\n"); } else { printf("Valuation non satisfaisante\n"); } }
Votre fichier source pour le solveur SAT devrait avoir ce format :
#include <handymacros.h> size_t const nbVert = /* nombre de sommets */, nbEdges = /* nombre d’arêtes */, nbWantedLeafs = /* nombre de feuilles exigé */; bool kLeafsCoverTest(bool y[nbEdges][nbVert - 1], bool z[nbVert][nbVert][nbVert + 1], bool x[nbVert][nbWantedLeafs]) { return /* expression */; }
Cependant, le solveur SAT naïf que j’ai développé est bien trop inefficace pour traiter ce problème. En effet, même avec un graphe de seulement trois sommets et deux arêtes, le nombre de variables est de 46, ce qui correspond à des billions de valuations à tester.
Le troisième paramètre de la fonction verify(graph, nbWantedLeafs, selectedEdges)
est un sous-ensemble des
arêtes du graphe (incarné par un tableau de booléens). Pour vérifier que cela forme bien un arbre, cette fonction vérifie
que ce sous-graphe a bien n−1 arêtes (avec n le nombre de sommets), et construit sa liste d’adjacence
afin de le parcourir en largeur pour vérifier qu’il est connexe. L’exploration se fait à partir du sommet 0, et chaque sommet
est marqué afin de vérifier qu’ils sont tous atteints. Pour vérifier que l’arbre a exactement k arêtes, la
fonction compte le nombre de sommets de degré 1 dans la liste d’adjacence.
La fonction findSolution(graph, nbWantedLeafs)
utilise le vérificateur, en lui soumettant tous les
sous-ensembles de n−1 arêtes, jusqu’à en trouver un qui soit accepté.
L’algorithme à compléter au DS demandait d’utiliser les trois grands tableaux de booléens suivants :
Note : les conventions de mon algorithme diffèrent un peu de celles du DS. Dans le sujet du DS, les sommets et les positions étaient numérotés à partir de 1, et dans la notation zu,u’,v, le sommet v était inclus comme sommet intermédiaire possible. Mon algorithme considère que les numérotations commencent à zéro et que le sommet v n’est pas inclus, conventions un peu plus courantes en programmation.
Le sens de ces variables n’est bien sûr pas acquis d’avance, et l’objectif de la formule est de le contraindre, puis de s’en
servir pour assurer que les arêtes sélectionnées forment bien un arbre couvrant qui n’a pas plus de k feuilles. La
fonction reduceToSat(graph, nbWantedLeafs)
produit le code pour trois contraintes φ1, φ2
et φ3 (les mêmes que dans le sujet du DS) : une pour chaque grand tableau, en connectant ce dernier avec le
tableau précédent.
φ1 et φ3 utilisent la fonction constrainSatSet(name, superSize, size)
qui code les trois
contraintes assurant que le tableau name
est bien un sous-ensemble de taille size
d’un ensemble de
taille superSize
; il s’agit du même tryptique « au moins un par position, au plus un par position, au plus une
position pour un », déjà utilisé pour la réduction du
problème Couverture par sommets. φ1 ne contient d’ailleurs rien d’autre que ça.
S’agissant de zu,u’,v, il faut remarquer que :
φ2 est divisé en trois contraintes :
Le « si et seulement si » est codé par ==
en C.
Enfin, dans φ3, il faut vérifier que chaque sommet de l’ensemble des feuilles a bien un seul voisin, et
réciproquement. Pour vérifier si un sommet n’a qu’un seul voisin, on teste toute les paires {zu,u₁,0,
zu,u₂,0} : il ne doit pas y en avoir deux vrais à la fois. Encore une fois, l’opérateur C
==
est utilisé : un sommet est dans l’ensemble des feuilles si et seulement si il n’a pas plus d’un voisin.
Cette contrainte est la première grande parenthèse de φ3, suivie par les contraintes de
constrainSatSet
.
Ce mode ne prend en entrée que l’instance (graphe et nombre de feuilles voulu) et le certificat (sous-ensemble d’arêtes).
Pour générer le tableau zu,u’,v, l’algorithme de Warshall est employé, pour transformer progressivement la matrice d’adjacence du sous-graphe en matrice d’accessibilité.
Pour générer le tableau xv,i, les degrés sont calculés et les sommets de degré 1 sont ajoutés comme feuilles. Notez que s’il y a plus de k sommets de degré 1, alors certaines feuilles seront aux mêmes positions i afin que le code C demeure valide.