diff --git a/Makefile b/Makefile index 7d0da0d..54178f5 100644 --- a/Makefile +++ b/Makefile @@ -6,3 +6,5 @@ clean: cd build/ && \ gnat clean ../src/*.adb +test: + bash test_pagerank.bash \ No newline at end of file diff --git a/README.md b/README.md index 2ac2e30..872d912 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,19 @@ -% Utilisation du dépôt SVN pour le projet -% -% - - -**Remarque :** On peut engendrer une version pdf de ce fichier en faisant : - +# Building ~~~ -pandoc -N -o LISEZ-MOI.pdf LISEZ-MOI.txt +$ colormake ~~~ -# Recommandation +# Cleaning +~~~ +$ make clean +~~~ -## Ne pas encombrer le serveur SVN avec des fichiers inutiles +# Testing +~~~ +$ make test +~~~ -**Ne pas pousser sur SVN les gros exemples.** - -Vous pouvez les avoir dans votre copie locale mais il ne faut pas les mettre -sur SVN car vous n'avez pas à les modifier, qu'on peut les retrouver -facilement sur Moodle et qu'ils vont inutilement occuper beaucoup de place sur -le serveurs SVN. Il y a pas loin de 100 équipes !. - -De la même façon, on ne met pas les exécutables ni aucun fichier résultat de -la compilation. - -Si vous le faites, outre la place gaspillée sur le serveur, vous allez avoir -de nombreux conflits car SVN ne saura pas faire la fusion des fichiers objets -ou exécutables ! - - -## Pousser régulièrement vos modifications - -Vous devez pousser régulièrement vos modifications. Définissez de petits -objectifs (écrire un sous-programme, tester un sous-programme, améliorer un -algorithmique, etc.) et dès qu'il est atteint vous pousser vos modifications -sur le serveurs SVN. - -Faites aussi des `svn update` régulièrement pour limiter les conflits et -communiquez avec votre coéquipier ! - - -# Organisation du dépôt SVN +# Tree . \ ├── build \ @@ -48,15 +22,22 @@ communiquez avec votre coéquipier ! │ ├── raffinages.txt \ │ └── rapport.pdf \ ├── Makefile \ -├── README.md \ -└── src \ - ├── google_naive.adb \ - ├── google_naive.ads \ - ├── pagerank.adb \ - ├── vector.adb \ - └── vector.ads \ +├── README.md \ +├── src \ +│ ├── google_creux.adb \ +│ ├── google_creux.ads \ +│ ├── google_naive.adb \ +│ ├── google_naive.ads \ +│ ├── pagerank.adb \ +│ ├── vector.adb \ +│ └── vector.ads \ +└── test_pagerank.bash \ -# Autres informations +# TODO -Vous pouvez ajouter ici toute information utile pour comprendre -l'organisation de votre dépôt... \ No newline at end of file +- algo tri quicksort +- implémenter creux +- paufinner tests +- rédiger rapport +- rédiger présentation +- meilleur initialize(vec) \ No newline at end of file diff --git a/src/google_creux.adb b/src/google_creux.adb index 6676039..3914a7a 100644 --- a/src/google_creux.adb +++ b/src/google_creux.adb @@ -1,72 +1,70 @@ with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; +with Ada.Text_IO; use Ada.Text_IO; +with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; +with Ada.Command_Line; use Ada.Command_Line; +with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; +with Ada.Text_IO.Text_Streams; + + package body Google_Creux is - function "*"(left : T_Vecteur; right : T_Google) return T_Vecteur is - vec: T_Vecteur; - c: T_Element; + -- construction simple, de compléxité N^2 + -- on peut diminuer la compléxité en triant d'abord le réseau + -- on passerait à une complexité 2*N + N*Log(2, N) + procedure create_H(mat: in out T_Google; file: in out Ada.Text_IO.File_Type) is + row, col: Natural; + nb: Natural := 0; begin - initialize(vec); + mat.rows(0) := 0; for i in 0..N-1 loop - c := 0.0; - for j in 0..N-1 loop - c := c + left(j)*right(j,i); + reset(file, In_File); + skip_line(file); + for j in 0..N_links-1 loop + get(file, row); + get(file, col); + if row = i then + mat.cols(nb) := col; + nb := nb + 1; + end if; end loop; - vec(i) := c; - end loop; - return vec; - end "*"; - - procedure create_H(mat: in out T_Google; file: in Ada.Text_IO.File_Type) is - row, col: Integer; - begin - while not end_of_File(file) loop - get(file, row); - get(file, col); - mat(row, col) := 1.0; + mat.rows(i+1) := nb; end loop; end create_H; - procedure create_S(mat: in out T_Google) is - sum: T_Element; - begin - for i in 0..N-1 loop - sum := 0.0; - for j in 0..N-1 loop - sum := sum + mat(i,j); - end loop; - - if sum /= 0.0 then - for j in 0..N-1 loop - if mat(i,j) /= 0.0 then - mat(i,j) := 1.0/sum; - end if; - end loop; - else -- sum == 0 then - for j in 0..N-1 loop - mat(i,j) := 1.0/T_Element(N); - end loop; - end if; - end loop; - end create_S; - - procedure create_G(mat: in out T_Google; alpha: in T_Element) is - begin - for i in 0..N-1 loop - for j in 0..N-1 loop - mat(i,j) := alpha*mat(i,j) + (1.0-alpha)/T_Element(N); - end loop; - end loop; - end create_G; - procedure put(mat: in T_Google) is begin - for i in 0..N-1 loop - for j in 0..N-1 loop - put(mat(i,j)); - end loop; - new_line; + for i in 0..N_links-1 loop + put(mat.cols(i)); + end loop; + new_line; + for i in 0..N loop + put(mat.rows(i)); end loop; end put; + function calcul(vec: in T_Vecteur_Element; mat: in T_Google; alpha: in T_Element) return T_Vecteur_Element is + new_vec: T_Vecteur_Element; + nb_col: Natural := 0; + col_CRS: Natural := 0; + col_vec: Natural := 0; + begin + initialize(new_vec, sum(vec)*(1.0-alpha)/T_Element(N)); + for i in 0..N-1 loop + nb_col := mat.rows(i+1) - mat.rows(i); + if nb_col = 0 then + for j in 0..N-1 loop + new_vec(j) := new_vec(j) + alpha*vec(i)/T_Element(N); + end loop; + else + for j in 1..nb_col loop + col_vec := mat.cols(col_CRS); + new_vec(col_vec) := new_vec(col_vec) + alpha*vec(i)/T_Element(nb_col); + col_CRS := col_CRS + 1; + end loop; + end if; + end loop; + return new_vec; + end calcul; + end Google_Creux; diff --git a/src/google_creux.ads b/src/google_creux.ads index 7796889..3728ca5 100644 --- a/src/google_creux.ads +++ b/src/google_creux.ads @@ -5,6 +5,7 @@ generic type T_Element is digits <>; N: Positive; + N_links: Positive; with package Vector_T_Element is new Vector(T_Element => T_Element, N => N); package Google_Creux is @@ -17,13 +18,17 @@ package Google_Creux is -- on utilise le module Vector use Vector_T_Element; - type T_Google is array (0..N-1, 0..N-1) of T_Element; + type T_Rows is array (0..N) of Natural; + type T_Cols is array (0..N_links-1) of Natural; + type T_Google is record + cols: T_Cols; + rows: T_Rows; + offset: T_Element; + end record; - function "*"(left: T_Vecteur; right: T_Google) return T_Vecteur; + function calcul(vec : T_Vecteur_Element; mat : T_Google; alpha: in T_Element) return T_Vecteur_Element; - procedure create_H(mat: in out T_Google; file: in Ada.Text_IO.File_Type); - procedure create_S(mat: in out T_Google); - procedure create_G(mat: in out T_Google; alpha: in T_Element); + procedure create_H(mat: in out T_Google; file: in out Ada.Text_IO.File_Type); procedure put(mat: in T_Google); diff --git a/src/google_naive.adb b/src/google_naive.adb index 989b635..c248e74 100644 --- a/src/google_naive.adb +++ b/src/google_naive.adb @@ -2,11 +2,11 @@ with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; package body Google_Naive is - function "*"(left : T_Vecteur; right : T_Google) return T_Vecteur is - vec: T_Vecteur; + function "*"(left : T_Vecteur_Element; right : T_Google) return T_Vecteur_Element is + vec: T_Vecteur_Element; c: T_Element; begin - initialize(vec); + initialize(vec); -- garder ? for i in 0..N-1 loop c := 0.0; for j in 0..N-1 loop diff --git a/src/google_naive.ads b/src/google_naive.ads index 87df155..e826247 100644 --- a/src/google_naive.ads +++ b/src/google_naive.ads @@ -19,7 +19,7 @@ package Google_Naive is type T_Google is array (0..N-1, 0..N-1) of T_Element; - function "*"(left: T_Vecteur; right: T_Google) return T_Vecteur; + function "*"(left: T_Vecteur_Element; right: T_Google) return T_Vecteur_Element; procedure initialize(mat: in out T_Google); diff --git a/src/pagerank.adb b/src/pagerank.adb index 55e2245..40d9b43 100644 --- a/src/pagerank.adb +++ b/src/pagerank.adb @@ -2,6 +2,7 @@ with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; with Ada.Command_Line; use Ada.Command_Line; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; +with Ada.Text_IO.Text_Streams; with Vector; with Google_Naive; @@ -10,9 +11,13 @@ with Google_Creux; procedure pageRank is ERROR_args: Exception; + ERROR_alpha: Exception; + ERROR_ite: Exception; + ERROR_unexpected: Exception; + INFO_help: Exception; -- définition du type T_Double - Type T_Double is digits 11; + Type T_Double is digits 18; -- on utilise le module générique Float_IO pour pouvoir afficher T_Double directement package Text_T_Double is new Ada.Text_IO.Float_IO(Num => T_Double); @@ -21,7 +26,8 @@ procedure pageRank is - -- proédure pour récupérer les arguments de la ligne de commande + + -- procédure pour récupérer les arguments de la ligne de commande procedure get_args(filename: in out Unbounded_String; ite_max: in out Natural; alpha: in out T_Double; @@ -41,22 +47,32 @@ procedure pageRank is new_line; -- on vérifie d'abord que le nombre d'arguments est cohérent - if not(0 < Argument_Count and Argument_Count <= 6) then + if not(0 < Argument_Count and Argument_Count <= 7) then raise ERROR_args; else -- sinon on parse les arguments loop - if Argument(i) = "-P" then + if Argument(i) = "-h" or Argument(i) = "--help" then + put_line("parsed help"); + raise INFO_help; + + elsif Argument(i) = "-n" or Argument(i) = "--naif" then naif := True; i := i + 1; put_line("parsed naif"); - elsif Argument(i) = "-A" then + elsif Argument(i) = "-a" or Argument(i) = "--alpha" then alpha := T_Double'Value(Argument(i+1)); + if alpha < 0.0 or alpha > 1.0 then + raise ERROR_alpha; + end if; i := i + 2; put_line("parsed alpha"); - elsif Argument(i) = "-I" then + elsif Argument(i) = "-i" or Argument(i) = "--ite-max" then ite_max := Natural'Value(Argument(i+1)); + if ite_max > 150 then + raise ERROR_ite; + end if; i := i + 2; put_line("parsed ite_max"); @@ -66,8 +82,12 @@ procedure pageRank is put_line("parsed filename"); else - put_line("unexpected passing case"); - raise ERROR_args; + new_line; + put("Option: '"); + put(Argument(i)); + put("' non reconnu"); + new_line; + raise ERROR_unexpected; end if; exit when i > Argument_Count; @@ -75,38 +95,50 @@ procedure pageRank is end if; new_line; - put("alpha = "); put(alpha, 1); new_line; + put("alpha = "); put(alpha, Fore=>1, Aft=>10); new_line; put("naif = "); put(Boolean'Pos(naif), 1); new_line; put("ite_max = "); put(ite_max, 1); new_line; put("filename = "); put_line(To_String(filename)); new_line; exception - when others => raise ERROR_args; + + when CONSTRAINT_ERROR => + if Argument(i) = "-a" or Argument(i) = "--alpha" then + raise ERROR_alpha; + elsif Argument(i) = "-i" or Argument(i) = "--ite-max" then + raise ERROR_ite; + end if; + end get_args; + -- procédure pour choisir le type d'algo, une fois N et les arguments récupérés - procedure type_algo(N: Natural; + procedure type_algo(N: Positive; + N_links: Positive; filename: in Unbounded_String; file: in out Ada.Text_IO.File_Type; alpha: T_Double; ite_max: Natural; naif: Boolean) is - + -- on instancie le module générique Vecteur package Vector_T_Double is new Vector(T_Element => T_Double, N => N); use Vector_T_Double; + -- pour le retour chariot + stdout: constant Ada.Text_IO.File_Type := Ada.Text_IO.Standard_Output; + -- procédure qui effectue l'algorithme du pageRank avec Google_Naive procedure algorithm_naif(file: in out Ada.Text_IO.File_Type; alpha: in T_Double; ite_max: in Natural; - pi: out T_Vecteur) is + pi: out T_Vecteur_Element) is -- on instancie le module générique Naif de Google package Google is @@ -122,57 +154,75 @@ procedure pageRank is initialize(pi); put_line("initialized pi"); - --put(pi); new_line; + -- put(pi); new_line; initialize(G); put_line("initialized G"); - --put(G); new_line; + -- put(G); new_line; create_H(G, file); put_line("created H"); close(file); - --put(G); new_line; + -- put(G); new_line; create_S(G); put_line("created S"); - --put(G); new_line; + -- put(G); new_line; create_G(G, alpha); put_line("created G"); - --put(G); new_line; + -- put(G); new_line; -- on applique l'algorithme itératif - put("ite: "); for i in 1..ite_max loop pi := pi * G; - put(i, 1); put(" "); + String'Write(Ada.Text_IO.Text_Streams.Stream(stdout), + "ite:" & Integer'Image(i) & " /" & Integer'Image(ite_max) & ASCII.CR); end loop; new_line; - --new_line; - --put_line("final pi:"); - --put(pi); + new_line; + put_line("final pi:"); + put(pi); end algorithm_naif; -- procédure qui effectue l'algorithme du pageRank avec Google_Creux procedure algorithm_creux(file: in out Ada.Text_IO.File_Type; - alpha: in T_Double; - ite_max: in Natural; - pi: out T_Vecteur) is + alpha: in T_Double; + ite_max: in Natural; + pi: out T_Vecteur_Element) is -- on instancie le module générique Creux de Google package Google is new Google_Creux(T_Element => T_Double, N => N, + N_links => N_links, Vector_T_Element => Vector_T_Double); use Google; -- définition de la matrice Google - G: T_Google; + H: T_Google; begin - put("TODO"); + initialize(pi); + put_line("initialized pi:"); + -- put(pi); new_line; + + create_H(H, file); + put_line("created H:"); + -- put(H); new_line; new_line; + + -- on applique l'algorithme itératif + for i in 1..ite_max loop + pi := calcul(pi, H, alpha); + String'Write(Ada.Text_IO.Text_Streams.Stream(stdout), + ASCII.CR & "ite:" & Integer'Image(i) & " /" & Integer'Image(ite_max)); + end loop; new_line; + + new_line; + put_line("final pi:"); + put(pi); end algorithm_creux; @@ -182,21 +232,20 @@ procedure pageRank is -- procédure pour écrire les résultats dans les fichiers procedure write_to_files(filename: in Unbounded_String; - pi_sorted: in T_Vecteur; - pi_index: in T_Vecteur_Index) is + pi_sorted: in T_Vecteur_Element; + pi_index: in T_Vecteur_Natural) is file: Ada.Text_IO.File_Type; begin - create(file, Out_File, To_String(filename & ".p")); - put(file, N, 1); - put(file, alpha, 2); - put(file, ite_max, 2); - new_line(file); + create(file, Out_File, To_String(filename & "_GH05.p")); + put(file, N, 1); put(file, ' '); + put(file, alpha, Fore=>1, Aft=>10); put(file, ' '); + put(file, ite_max, 1); new_line(file); put(file, pi_sorted); close(file); - create(file, Out_File, To_String(filename & ".ord")); + create(file, Out_File, To_String(filename & "_GH05.ord")); put(file, pi_index); close(file); end write_to_files; @@ -206,8 +255,8 @@ procedure pageRank is -- définition des vecteurs - pi: T_Vecteur; - pi_index: T_Vecteur_Index; + pi: T_Vecteur_Element; + pi_index: T_Vecteur_Natural; begin @@ -221,9 +270,9 @@ procedure pageRank is initialize(pi_index); sort_with_index_desc(pi, pi_index); - new_line; - put_line("sorted pi:"); - put(pi); new_line; + -- new_line; + -- put_line("sorted pi:"); + -- put(pi); new_line; -- on écrit les resultats dans des fichiers write_to_files(filename, pi, pi_index); @@ -242,6 +291,7 @@ procedure pageRank is -- définition des variables pour créer les matices/vecteurs N: Positive; + N_links: Integer := -1; file: Ada.Text_IO.File_Type; begin @@ -254,18 +304,51 @@ begin open(file, In_File, To_String(filename & ".net")); put_line("file OK"); + -- on récupère le nombre de liens + while not End_Of_File(file) loop + Skip_Line(file); + N_links := N_links + 1; + end loop; + reset(file, In_File); + put("N_links = "); put(N_links, 1); new_line; + -- on récupère le nombre de pages get(file, N); put("N = "); put(N, 1); new_line; - + -- on peut maintenant choisir le type de matrice que l'on souhaite - type_algo(N, filename, file, alpha, ite_max, naif); + type_algo(N, N_links, filename, file, alpha, ite_max, naif); exception -- si il y a une erreur lors du parsing des arguments, on rappelle l'usage. when ERROR_args => - put_line("Erreur lors de la saisi de la commande"); - put_line("Usage: pagerank [-I max_iterations] [-A alpha] [-P] fichier_reseau.net"); + new_line; + put_line("Erreur lors de la saisi de la commande."); + put_line("Usage: pagerank [-P] [-i max_iterations] [-a alpha] [-h] fichier_reseau.net"); + + when ERROR_unexpected => + put_line("Essayez 'pagerank --help' pour plus d'informations."); + + when ERROR_alpha => + new_line; + put_line("Erreur lors de la saisi de alpha."); + put_line("alpha ∈ [0, 1]"); + + when ERROR_ite => + new_line; + put_line("Erreur lors de la saisi de ite_max."); + put_line("ite_max ∈ ⟦0, 150⟧"); + + when INFO_help => + new_line; + put_line("Usage: pagerank [OPTIONS] network.net"); + put_line("Calcule le pagerank d'un réseau à partir de son réseau.net"); + new_line; + put_line("Options:"); + put_line(" -P, --naif specifies which type of matrix to use"); + put_line(" -a, --alpha specifies the alpha constant (alpha ∈ [0, 1])"); + put_line(" -i, --ite-max specifies the maximum number of iterations (ite_max ∈ ⟦0, 150⟧)"); + put_line(" -h, --help display this help message and exit"); end pageRank; diff --git a/src/vector.adb b/src/vector.adb index 2fd83a5..0b82fde 100644 --- a/src/vector.adb +++ b/src/vector.adb @@ -2,28 +2,52 @@ with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; package body vector is - procedure initialize(vec: in out T_Vecteur) is + procedure initialize(vec: in out T_Vecteur_Element) is begin for i in 0..N-1 loop vec(i) := 1.0/T_Element(N); end loop; end initialize; - procedure initialize(vec: in out T_Vecteur_Index) is + procedure initialize(vec: in out T_Vecteur_Element; value: in T_Element) is + begin + for i in 0..N-1 loop + vec(i) := value; + end loop; + end initialize; + + procedure initialize(vec: in out T_Vecteur_Natural) is begin for i in 0..N-1 loop vec(i) := i; end loop; end initialize; - procedure put(vec: in T_Vecteur) is + function sum(vec: in T_Vecteur_Element) return T_Element is + s: T_Element := 0.0; + begin + for i in 0..N-1 loop + s := s + vec(i); + end loop; + return s; + end sum; + + procedure put(vec: in T_Vecteur_Element) is begin for i in 0..N-1 loop put(vec(i)); new_line; end loop; end put; - procedure put(file: in out Ada.Text_IO.File_Type; vec: in T_Vecteur) is + procedure put(file: in out Ada.Text_IO.File_Type; vec: in T_Vecteur_Element) is + begin + for i in 0..N-1 loop + put(file, vec(i), Fore=>1, Aft=>10); + new_line(file); + end loop; + end put; + + procedure put(file: in out Ada.Text_IO.File_Type; vec: in T_Vecteur_Natural) is begin for i in 0..N-1 loop put(file, vec(i), 1); @@ -31,15 +55,7 @@ package body vector is end loop; end put; - procedure put(file: in out Ada.Text_IO.File_Type; vec: in T_Vecteur_Index) is - begin - for i in 0..N-1 loop - put(file, vec(i), 1); - new_line(file); - end loop; - end put; - - procedure sort_with_index_desc(vec: in out T_Vecteur; vec_index: in out T_Vecteur_Index) is + procedure sort_with_index_desc(vec: in out T_Vecteur_Element; vec_index: in out T_Vecteur_Natural) is tmp_Element: T_Element; tmp_Natural: Natural; max: Natural; @@ -47,7 +63,7 @@ package body vector is for i in 0..N-2 loop max := i; for j in i+1..N-1 loop - if vec(max) < vec(j) then + if vec(max) <= vec(j) then max := j; end if; end loop; diff --git a/src/vector.ads b/src/vector.ads index 4a469f8..d79be42 100644 --- a/src/vector.ads +++ b/src/vector.ads @@ -7,21 +7,24 @@ generic package Vector is - type T_Vecteur is array (0..N-1) of T_Element; - type T_Vecteur_Index is array (0..N-1) of Natural; + type T_Vecteur_Element is array (0..N-1) of T_Element; + type T_Vecteur_Natural is array (0..N-1) of Natural; -- on permet l'affichage direct des T_Element package Text_T_Element is new Ada.Text_IO.Float_IO(Num => T_Element); use Text_T_Element; - procedure initialize(vec: in out T_Vecteur); - procedure initialize(vec: in out T_Vecteur_Index); + procedure initialize(vec: in out T_Vecteur_Element); + procedure initialize(vec: in out T_Vecteur_Element; value: in T_Element); + procedure initialize(vec: in out T_Vecteur_Natural); - procedure put(vec: in T_Vecteur); - procedure put(file: in out Ada.Text_IO.File_Type; vec: in T_Vecteur); - procedure put(file: in out Ada.Text_IO.File_Type; vec: in T_Vecteur_Index); + function sum(vec: in T_Vecteur_Element) return T_Element; - procedure sort_with_index_desc(vec: in out T_Vecteur; vec_index: in out T_Vecteur_Index); + procedure put(vec: in T_Vecteur_Element); + procedure put(file: in out Ada.Text_IO.File_Type; vec: in T_Vecteur_Element); + procedure put(file: in out Ada.Text_IO.File_Type; vec: in T_Vecteur_Natural); + + procedure sort_with_index_desc(vec: in out T_Vecteur_Element; vec_index: in out T_Vecteur_Natural); end Vector;