# 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.