184 | | == D.1. graph_t * parse_graph(char *filename) == |
185 | | |
186 | | Cette fonction prend pour argument un nom de fichier au format.dot |
187 | | représentant le graphe à partitionner, et construit en mémoire la structure |
188 | | graph_t correspondante, et renvoie un pointeur sur cette structure. Si aucune |
189 | | partition initiale n'est définie dans le fichier .dot, les noeuds d'index |
190 | | inférieur à NBNODE/2 sont arbitrairement rangés dans le sous-ensemble L, |
191 | | et les noeuds d'index supérieur à NBNODE/2 sont rangés dans le sous-ensemble R. |
192 | | |
193 | | Un exemple de fichier au format .dot est donné ci-dessous. Les noeuds du graphe |
194 | | sont identifiés par un index, il y a une ligne par arête, les deux sous-graphes |
195 | | cluster0 et cluster1 définissent la partition initiale et sont optionnels. |
| 179 | '''graph_t * parse_graph(char *filename)''':: |
| 180 | Cette fonction prend pour argument un nom de fichier au format.dot |
| 181 | représentant le graphe à partitionner, et construit en mémoire la structure |
| 182 | graph_t correspondante, et renvoie un pointeur sur cette structure. Si aucune |
| 183 | partition initiale n'est définie dans le fichier .dot, les noeuds d'index |
| 184 | inférieur à NBNODE/2 sont arbitrairement rangés dans le sous-ensemble L, |
| 185 | et les noeuds d'index supérieur à NBNODE/2 sont rangés dans le sous-ensemble R. |
| 186 | |
| 187 | Un exemple de fichier au format .dot est donné ci-dessous. Les noeuds du graphe |
| 188 | sont identifiés par un index, il y a une ligne par arête, les deux sous-graphes |
| 189 | cluster0 et cluster1 définissent la partition initiale et sont optionnels. |
213 | | == D.2. void drive_graph(graph_t *p, char *filename) == |
214 | | |
215 | | Cette fonction prend en paramètre un pointeur p sur une structure graph_t, |
216 | | ainsi que le nom du fichier de sortie, et écrit sur disque un fichier au |
217 | | format .dot, en conservant dans le fichier les informations de partition |
218 | | (sous-ensemble L et R). Ce format est affichable sous forme graphique et |
219 | | permet de visualiser la partition. |
220 | | |
221 | | == D.3. bichain_t * cons_bichain (bichain_t *prev, bichain_t *next, unsigned inode, int igain, unsigned part) == |
222 | | |
223 | | Cette fonction alloue la mémoire nécessaire pour créer un élément d'une liste |
224 | | doublement chaînée, elle initialise les différents champs de cette structure, |
225 | | et renvoie un pointeur sur cette structure. |
226 | | |
227 | | == D.4. void free_bichain (bichain_t *p) == |
228 | | |
229 | | Cette fonction libère la mémoire allouée lors de la construction de l'objet |
230 | | bichain_t par la donction cons_bichain(). |
231 | | |
232 | | == D.5. move_manager_t * cons_move_manager(graph_t *p) == |
233 | | |
234 | | Cette fonction pend pour argument un pointeur sur la structure représentant |
235 | | le graphe partitionné, et construit en mémoire la structure move_manager_t |
236 | | correspondant à cette partition. |
237 | | |
238 | | == D.6. void add_node (move_manager_t *mm, bichain_t *node) == |
239 | | |
240 | | Cette fonction prend pour arguments un pointeur sur la structure représentant |
241 | | les gestionnaire de mouvements, un pointeur sur un élément de liste doublement |
242 | | chaînée (représentant un noeud), contenant l'index du nSud dans le graphe, |
243 | | un entier représentant l'index dans le tableau GAIN_R ou GAIN_L, et un entier |
244 | | définissant le sous-ensemble d'appartenance (0 pour R, 1 pour L). Elle range |
245 | | ce noeud dans la liste doublement chaînée correspondante, elle met à jour |
246 | | le tableau NODES et les index LX ou LR. Les champs NEXT et PREV du nSud ne |
247 | | sont pas utilisés, ils sont initialisés par la fonction add_node elle-même. |
248 | | |
249 | | == D.7. bichain_t * del_node(move_manager_t *mm, bichain_t *node) == |
250 | | |
251 | | cette fonction prend pour arguments un pointeur sur la structure représentant |
252 | | les gestionnaire de mouvements, et un pointeur sur un élément de liste |
253 | | doublement chaînée (représentant un noeud). Elle retire cet élément de la |
254 | | liste doublement chaînée, et renvoie un pointeur sur la structure bichain_t |
255 | | pour une éventuelle libération de la mémoire. |
256 | | |
257 | | == D.8. int compute_gain (graph_t *g, unsigned index) == |
258 | | |
259 | | Cette fonction prend pour argument un pointeur sur la structure représentant le |
260 | | graphe, un index désignant un noeud particulier, et calcule le gain associé |
261 | | à ce noeud, pour la partition courante. |
262 | | |
263 | | == D.9. int global_cost (graph_t *g) == |
264 | | |
265 | | Cette fonction prend pour argument un pointeur sur la structure représentant |
266 | | le graphe, calcule la fonction de coût globale pour la partition courante, |
267 | | et renvoie la valeur calculée. |
| 207 | '''void drive_graph(graph_t *p, char *filename)''':: |
| 208 | Cette fonction prend en paramètre un pointeur p sur une structure graph_t, |
| 209 | ainsi que le nom du fichier de sortie, et écrit sur disque un fichier au |
| 210 | format .dot, en conservant dans le fichier les informations de partition |
| 211 | (sous-ensemble L et R). Ce format est affichable sous forme graphique et |
| 212 | permet de visualiser la partition. |
| 213 | |
| 214 | '''bichain_t * cons_bichain (bichain_t *prev, bichain_t *next, unsigned inode, int igain, unsigned part)''':: |
| 215 | Cette fonction alloue la mémoire nécessaire pour créer un élément d'une liste |
| 216 | doublement chaînée, elle initialise les différents champs de cette structure, |
| 217 | et renvoie un pointeur sur cette structure. |
| 218 | |
| 219 | '''void free_bichain (bichain_t *p)''':: |
| 220 | Cette fonction libère la mémoire allouée lors de la construction de l'objet |
| 221 | bichain_t par la donction cons_bichain(). |
| 222 | |
| 223 | '''move_manager_t * cons_move_manager(graph_t *p)''':: |
| 224 | Cette fonction pend pour argument un pointeur sur la structure représentant |
| 225 | le graphe partitionné, et construit en mémoire la structure move_manager_t |
| 226 | correspondant à cette partition. |
| 227 | |
| 228 | '''void add_node (move_manager_t *mm, bichain_t *node)''':: |
| 229 | Cette fonction prend pour arguments un pointeur sur la structure représentant |
| 230 | les gestionnaire de mouvements, un pointeur sur un élément de liste doublement |
| 231 | chaînée (représentant un noeud), contenant l'index du nSud dans le graphe, |
| 232 | un entier représentant l'index dans le tableau GAIN_R ou GAIN_L, et un entier |
| 233 | définissant le sous-ensemble d'appartenance (0 pour R, 1 pour L). Elle range |
| 234 | ce noeud dans la liste doublement chaînée correspondante, elle met à jour |
| 235 | le tableau NODES et les index LX ou LR. Les champs NEXT et PREV du nSud ne |
| 236 | sont pas utilisés, ils sont initialisés par la fonction add_node elle-même. |
| 237 | |
| 238 | '''bichain_t * del_node(move_manager_t *mm, bichain_t *node)''':: |
| 239 | cette fonction prend pour arguments un pointeur sur la structure représentant |
| 240 | les gestionnaire de mouvements, et un pointeur sur un élément de liste |
| 241 | doublement chaînée (représentant un noeud). Elle retire cet élément de la |
| 242 | liste doublement chaînée, et renvoie un pointeur sur la structure bichain_t |
| 243 | pour une éventuelle libération de la mémoire. |
| 244 | |
| 245 | '''int compute_gain (graph_t *g, unsigned index)''':: |
| 246 | Cette fonction prend pour argument un pointeur sur la structure représentant le |
| 247 | graphe, un index désignant un noeud particulier, et calcule le gain associé |
| 248 | à ce noeud, pour la partition courante. |
| 249 | |
| 250 | '''int global_cost (graph_t *g)''':: |
| 251 | Cette fonction prend pour argument un pointeur sur la structure représentant |
| 252 | le graphe, calcule la fonction de coût globale pour la partition courante, |
| 253 | et renvoie la valeur calculée. |
274 | | == E.1. Construction et initialisation du gestionnaire de mouvements == |
275 | | |
276 | | C'est un point important puisque que c'est la structure de base de |
277 | | l'algorithme. Vous disposez pour vous aidez d'une fonction dump_move_manager() |
278 | | qui affiche le contenu de la structure. |
279 | | |
280 | | == E.2. Ecriture de l'algorithme MinCut glouton == |
281 | | |
282 | | Ecrivez la boucle réalisant les transferts de cellules tant que le transfert |
283 | | d'une paire de cellules améliore la fonction de coût FC. |
284 | | |
285 | | == E.3. Exécution et évaluation == |
286 | | |
287 | | Exécutez cet algorithme sur différents graphes que vous définirez |
288 | | vous-mêmes. La partition résultante est-elle toujours la partition |
289 | | optimale? Pourquoi? Donnez un contre-exemple. |
290 | | |
291 | | == E.4. Ecriture des fonctions == |
292 | | |
293 | | Ecrire les différentes fonctions d'accès aux structures de données définies |
294 | | dans la partie D, et validez ces fonctions en les intégrant peu à peu dans |
295 | | votre programme. |
296 | | |
297 | | == E.5. construction du graphe en mémoire == |
298 | | |
299 | | L'objectif est ici d'écrire la fonction parse_graph(), en utilisant lex et |
300 | | yacc. Nous vous suggérons de supposer qu'il n'y a pas de clusters dans le |
301 | | fichier, puis de les introduire. Si vous n'avez pas le temps de construire |
302 | | le graphe, étudiez au moins la grammaire de ce petit langage. |
| 260 | '''1. Construction et initialisation du gestionnaire de mouvements''':: |
| 261 | C'est un point important puisque que c'est la structure de base de |
| 262 | l'algorithme. Vous disposez pour vous aidez d'une fonction dump_move_manager() |
| 263 | qui affiche le contenu de la structure. |
| 264 | |
| 265 | '''2. Ecriture de l'algorithme !MinCut glouton''':: |
| 266 | Ecrivez la boucle réalisant les transferts de cellules tant que le transfert |
| 267 | d'une paire de cellules améliore la fonction de coût FC. |
| 268 | |
| 269 | '''3. Exécution et évaluation''':: |
| 270 | Exécutez cet algorithme sur différents graphes que vous définirez |
| 271 | vous-mêmes. La partition résultante est-elle toujours la partition |
| 272 | optimale? Pourquoi? Donnez un contre-exemple. |
| 273 | |
| 274 | '''4. Ecriture des fonctions''':: |
| 275 | Ecrire les différentes fonctions d'accès aux structures de données définies |
| 276 | dans la partie D, et validez ces fonctions en les intégrant peu à peu dans |
| 277 | votre programme. |
| 278 | |
| 279 | '''5. construction du graphe en mémoire''':: |
| 280 | L'objectif est ici d'écrire la fonction parse_graph(), en utilisant lex et |
| 281 | yacc. Nous vous suggérons de supposer qu'il n'y a pas de clusters dans le |
| 282 | fichier, puis de les introduire. Si vous n'avez pas le temps de construire |
| 283 | le graphe, étudiez au moins la grammaire de ce petit langage. |