# Documentation des fonctions backend Ce document décrit l'ensemble des classes, attributs et méthodes implémentées. ## Classes Plusieurs classes d'objets sont disponibles. ### Solver.rb La classe Solver est la classe principale qui implémente les différentes méthodes du solveur. ```ruby= class Solver { attr_accessor :internships, :constraints, :reviewers, :message def read_files() def distribution() def write_csv() } ``` Elle possède 4 attributs : - ***internships*** qui est un tableau d'objet de type *internship* - ***reviewers*** qui est un tableau d'objet de type *reviewer* - ***constraints*** qui est un objet de type *constraint* - ***message*** qui vaut *nil* si aucune erreur n'est rencontrée durant l'exécution du solveur,et vaut le message d'erreur sinon Les méthodes de la classe sont : - ***read_files()*** qui lit les fichiers CSV et le fichier de contraintes et initialise les attributs *internships*, *constraints* et *reviewers* - ***distribution()*** qui exécute les méthodes de génération de répartitions *first_distribution* et *main_distribution*, si la répartition fournie en entrée est complète (ie. tous les stages ont un jury, un slot, et un relecteur) alors on exécute uniquement *main_distribution* - ***write_csv()*** qui écrit dans les fichiers CSV la nouvelle répartition générée ### Internship.rb La classe Internship permet de représenter un stage. ```ruby= class Internship { attr_accessor :id, :supervisor_email, :international, :login_reviewer, :jury, :slot, :company def initialize(identifiant,email,etranger,id_reviewer,nb_jury,nb_slot,company) } ``` - ***id*** : identifiant du stage - ***supervisor_email*** : email du tuteur de stage - ***international*** : vaut 1 si le stage s'est déroulé à l'étranger, 0 sinon - ***login_reviewer*** : identifiant du relecteur du stage - ***jury*** : jury auquel est assigné le stage - ***slot*** : créneau horaire auquel est assigné le stage - ***company*** : entreprise où le stage a eu lieu ### Reviewer.rb La classe Reviewer permet de représenter un relecteur. ```ruby= class Reviewer { attr_accessor :login, :max_reviews, :jury, :international, :examinator def initialize(login,max_reviews,jury,international,examinator) } ``` - ***login*** : identifiant du relecteur - ***max_reviews*** : nombre maximal de stages acceptés par le relecteur - ***jury*** : jury auquel est assigné le relecteur - ***international*** : vaut 1 si le relecteur peut être relecteur des stages à l'étranger, 0 sinon - ***examinator*** : vaut 1 si le relecteur peut être président de jury, 0 sinon ### Constraint.rb La classe Constraint permet de représenter les contraintes définies dans un fichier de contraintes. ```ruby= class Constraint { attr_accessor :nb_jury, :internship_internship, :internship_reviewer, :internship_slot, :slotname @@translation @@center def initialize() def constraint_build_matrix(len_internships,len_reviewers,nbslot) def constraint_fill(matrix_type,internships,reviewers,id_1,id_2,weight) def meta_constraint_international(internships,reviewers,weight) def meta_constraint_company(internships,weight) } ``` Les variables globales ***@@translation*** et ***@@center*** permettent de translater les poids des contraintes, définis dans le fichier de contraintes entre -10 et 10, sur un intervalle différent. La classe possède 5 attributs : - ***nb_jury*** qui indique le nombre de jurys - ***slotname*** qui est un tableau contenant les noms des créneaux horaires - ***internship_internship*** qui est une matrice de taille $n\times n$ avec $n$ le nombre de stages contenant le poids des contraintes "les stages $x$ et $y$ sont dans le même jury" - ***internship_reviewer*** qui est une matrice de taille $n\times m$ avec $n$ le nombre de stages et $m$ le nombre de relecteurs contenant le poids des contraintes "le stage $x$ est relu par le relecteur $y$" - ***internship_slot*** qui est une matrice de taille $n\times p$ avec $n$ le nombre de stages et $p$ le nombre de créneaux horaires contenant le poids des contraintes "le stage $x$ a lieu sur le créneau $y$" Les méthodes de la classe sont : - ***constraint_build_matrix*** qui initialise les attributs *internship_internship*, *internship_reviewer* et *internship_slot* - ***constraint_fill*** retourne *nil* si aucune erreur n'est rencontrée et le message d'erreur sinon. Cette méthode remplit l'attribut correspondant à *matrix_type* avec le poids *weight* liant les éléments identifiés par *id_1* et *id_2* - ***meta_constraint_international*** retourne *nil* si aucune erreur n'est rencontrée et le message d'erreur sinon. Modifie les matrices de contraintes selon le poids *weight* de la méta-contrainte *"les stages internationaux sont relus par des relecteurs internationaux"*. Si le poids de la méta-contrainte est plus fort que le poids initial alors le poids est modifié, sinon le poids initial est conservé - ***meta_constraint_company*** retourne *nil* si aucune erreur n'est rencontrée et le message d'erreur sinon. Modifie les matrices de contraintes selon le poids *weight* de la méta-contrainte *"les stages de la même entreprise sont dans le même jury"*. Si le poids de la méta-contrainte est plus fort que le poids initial alors le poids est modifié, sinon le poids initial est conservé ### Permutation.rb La classe Permutation permet de représenter une permutation. ```ruby= class Permutation { attr_accessor :jsr_1, :jsr_2, :dim, :not_acceptable_1, :not_acceptable_2 def initialize(jsr_1,jsr_2,dim) def new_index() def ==(perm) def inverse() } ``` La classe possède 5 attributs : - ***jsr_1*** et ***jsr_2*** qui sont des tableaux de taille 3 contenant les coordonnées des deux stages impliqués dans la permutation - ***dim*** qui est un tableau contenant les dimensions sur lesquels effectuer la permutation - ***not_acceptable_1***, respectivement ***not_acceptable_2***, qui vaut 0 si la permutation impliquant le stage de coordonnées ***jsr_1***, resp. ***jsr_2***, respect l'ensemble des contraintes appliquées à une permutation, 1 sinon. Les méthodes de la classe sont : - ***new_index*** qui retourne un tableau de dimension $2 \times 3$ contenant les nouvelles coordonnées des stages à partir de ***jsr_1***,***jsr_2*** et ***dim***. - ***inverse*** qui retourne la permutation inverse ### Jury.rb La classe Jury permet de représenter un jury. ```ruby= class Jury { attr_accessor :numero, :examinator def initialize(numero,examinator) def self.list_jury(reviewers,nb_jury,jurys) } ``` La classe possède 2 attributs : - ***numero*** qui correspond au numéro du jury - ***examinator*** qui correspond au nom du président de jury La classe possède une méthode de classe : - ***list_jury*** qui modifie la liste *jurys* en ajoutant *nb_jury* examinateurs à partir de la liste des relecteurs *reviewers* ## Modules Les algorithmes de répartition ont été implémentés en tant que modules. ### First_distribution.rb ```ruby= module FirstDistribution { def first_distribution(internships,constraints,reviewers) } ``` La méthode ***first_distribution*** permet de générer aléatoirement une première répartition à partir d'une distribution partielle. Elle modifie les paramètres afin d'y stocker la nouvelle répartition. Elle retourne *nil* si aucune erreur n'est rencontrée et le message d'erreur sinon. ### Main_distribution.rb ```ruby= module FirstDistribution { def main_distribution(internships,constraints,reviewers,stop,nb_iter_tabou,nb_neighborhood_sol) } ``` La méthode ***main_distribution***, basée sur l'algorithme de recherche taboue, permet d'optimiser la répartition initiale fournie en paramètre. Elle modifie les paramètres ***internships***, ***constraints*** et ***reviewers***, afin d'y stocker la nouvelle répartition. Elle retourne *nil* si aucune erreur n'est rencontrée et le message d'erreur sinon. Elle prend en paramètre : - ***internships*** : un tableau d'instances de type Internship - ***constraints*** : une instance de type Constraint représentant l'ensemble des contraintes du problème - ***reviewers*** : un tableau d'instances de type Reviewer - ***stop*** : le nombre d'itérations que réalise l'algorithme - ***nb_iter_tabou*** : le nombre d'itérations durant lequel un mouvement est tabou - ***nb_neighborhood_sol*** : le nombre de solutions voisines générées à chaque itération ### Main_distribution_recuit.rb Ce module est une amélioration de la méthode ***main_distribution*** en se basant sur la méthode du recuit. Cependant, ce code n'est pas fonctionnel, en effet de légers bugs persistent. ## Tests Afin d'exécuter l'ensemble des tests on peut taper la commande : ``` bin/rake ``` Si on ne souhaite exécuter qu'un seul fichier de tests il suffit de taper : ``` ruby -I test test/models/fichier_test.rb ``` ### Tests unitaires Nous avons 3 fichiers de tests unitaires présents dans le dossier ***test/models*** : - ***read_write_test.rb*** qui teste l'ensemble des méthodes du module ReadWriteFiles - ***first_distribution_test.rb*** qui teste l'ensemble des méthodes du module FirstDistribution - ***main_distribution_test.rb*** qui teste l'ensemble des méthodes du module MainDistribution ### Test fonctionnel Nous avons 1 fichier de test fonctionnel dans le dossier ***test/models*** : - ***functional.rb*** qui permet de tester l'exécution du solveur tel qu'il le serait depuis l'application, le test lit les fichiers présents dans le dossier **testapp/public/uploads**, génère une nouvelle répartition et écrit dans les fichiers *internship_defense.csv* et *internship_wishes.csv*. On vérifie avec ce test que : - le solveur ne rencontre pas d'erreurs non gérées - la répartition finale a assigné à chaque stage un jury, un relecteur et un créneau horaire - la répartition finale contient au maximum un stage par créneau horaire - la répartition finale n'assigne pas plus de stages que de relecture maximale pour chaque relecteur ### Tests de performance Les divers tests de performance du solveur sont définis dans le fichier ***performance_test.rb***. Ce fichier nous permet de tester : - la qualité de la solution et le temps d'exécution de ***first_distribution()*** - la qualité de la solution et le temps d'exécution de ***main_distribution()*** selon les paramètres fournis en entrée - la qualité de la solution et le temps d'exécution de ***distribution()*** qui exécute successivement ***first_distribution()*** et ***main_distribution()*** :warning: Attention pour exécuter les tests de performance, des dossiers ***testapp/test/models/graph/100_internships/*** et ***testapp/test/models/graph/25_internships/*** doivent exister.