Docker-in-Docker (DinD) capabilities of public runners deactivated. More info

Commit 46ef7760 authored by Cyril L'Orphelin's avatar Cyril L'Orphelin
Browse files

Finalisation du repo

parent 735e5c6b
......@@ -13,24 +13,24 @@
- Mise en place des pratiques de qualité logicielle
# Documentation, tests et analyse
# Documentation, tests et analyse de la qualité
- Gestion de la documentation [(PDF)](présentations/documentation.pdf) - *Julien Peloton*
- Méthodologie : Retour d'expérience sur la gestion de la documentation [(PDF)](présentations/Rex-docs_MXT.pdf) - *Antoine Pérus*
- Outils de test [(PDF)](présentations/outils_test.pdf) - *Cyril L'Orphelin*
- Outils d’analyse et de mesure de la qualité du code [(PDF)](présentations/outils_analyse.pdf) - *Cyril L'Orphelin*
- Outils de construction du code final, d'intégration et de déploiement continus [(PDF)](présentations/outils_cicd.pdf) - *Cyril L'Orphelin*
# Outils de partage de code, outils collaboratifs, intégration continue
- Partage de code et plateformes collaboratives [(PDF)](présentations/outils_collaboratifs.pdf) - *Cyril L'Orphelin*
- Processus de traitement de la qualité logicielle: outils et notion d'usine logicielle [(PDF)](présentations/usine_logicielle.pdf) [(PPT)](présentations/usine_logicielle.ppt) - *Alexis Chatillon*
- Processus de traitement de la qualité logicielle: outils et notion d'usine logicielle [(PDF)](présentations/usine_logicielle.pdf) [(PPT)](présentations/usine_logicielle.pptx) - *Alexis Chatillon*
- Outils de construction du code final, d'intégration et de déploiement continus [(PDF)](présentations/outils_cicd.pdf) - *Cyril L'Orphelin*
# Retours d'expériences
- Exemple d'application aux projets IN2P3: LSST et les pipelines de données [(Google Drive)](https://docs.google.com/presentation/d/1uKlPSIXn-yEX7raPGadSvSbmO15373wd3Ip1XH6e68A/edit#slide=id.ga2f7fb1a1f_0_70) - *Jim Bosch*
- Retour d’expérience INSU sur la qualité logicielle appliquée au sein du projet logiciel vol PLATO [(PDF)](présentations/rex_plato.pdf) - *Philippe Plasson*
- Retour d'expérience IN2P3 : plateforme d'intégration continue pour le développement du pipeline de données EUCLID [(PDF)](présentations/rex_euclid.pdf) - *Antoine Boizard*
- Retour d'expérience INSU : environnement de développement, d’integration et de test développé pour le segment sol de l’instrument RPW de la mission Solar Orbiter [(PDF)](présentations/rex_INSU_RPW.pdf) - *Xavier Bonnin, Sonny Lion*
- Retour d'expérience INSU : environnement de développement, d’integration et de test développé pour le segment sol de l’instrument RPW de la mission Solar Orbiter [(PDF)](présentations/rex_INSU_RPW.pdf) [(PPT)](présentations/rex_INSU_RPW.pptx)- *Xavier Bonnin, Sonny Lion*
- Cas du spatial et de l’embarqué : spécificités et impacts sur le processus de qualité logicielle, exemple avec le logiciel de vol du spectro-imageur MAJIS de la mission JUICE [(PPT)](présentations/rex_majis.pptx) *Karin Dassas, Benoit Garçon*
......@@ -40,6 +40,9 @@ En clonant ce repository vous aurez toutes les ressources nécessaires pour les
Les identifiants nécessaires pour l'accès aux différents outils (Notebook Jupyter, SonarQube) sont disponibles dans :
<br/><code>Gitlab > Settings > CI-CD > Variables</code>
Les TPs ont été conçus pour fonctionner sur la plateforme de Notebook.
Cependant vous pouvez très bien réaliser ces TPs sur votre machine .
Il faudra installer un environnement Pyhton, l'outil Pylint et coverage.py
<hr/>
......
......@@ -4,7 +4,7 @@
- Ouvrez un terminal dans le <a href="https://notebook.cc.in2p3.fr/" title="Notebook">notebook Jupyter </a>
- Placez vous dans le répertoire TP4 de votre repository Gitlab pour le TP
- Vous devez visualiser 2 fichiers
- Vous devez visualiser 2 fichiers et un répertoire qui comprend les solutions du TP
- le fichier [tri.py](tri.py) qui comprend un certain nombre de méthodes de tri de tableaux
- le fichier [tri_test.py](tri_test.py) qui contient les tests de ces de méthodes de tri
......@@ -22,7 +22,7 @@
<details>
<summary>Solution Pylint</summary>
<pre><code>$ pylint tri.py
# Supprimez les imports inutiles
# Corrigez les espaces mal positionnés
# Supprimez les sauts de lignes inutiles
# Renommez qq variables
</code></pre>
......@@ -32,12 +32,13 @@
<summary>Solution tests unitaires et rapport</summary>
<pre><code>$ coverage run -m unittest tri_test.py
$ coverage report -m --omit=tri_test.py
# les lignes 197-219 ne sont pas couvertes => le tri rapide n'est pas testé
# les lignes 202-224 ne sont pas couvertes => le tri rapide n'est pas testé
</code></pre>
</details>
<details>
<summary>Solution Coverage 80%</summary>
Rajouter la portion de code suivante dans les tests
<pre><code>def test_tri_rapide(self):
print("tri_rapide")
for i in range(len(longueur)):
......@@ -53,7 +54,7 @@ $ coverage report -m --omit=tri_test.py
- Evaluez les performances des méthodes de tri pour différentes tailles de tableau 10, 1000 , 10000 de façon naïve en mesurant les temps d'exécution
- La fonction de tri récursif va bloquer à cause du limite de python, il va falloir utiliser la méthode <code>sys.setrecursionlimit()</code>
- Quelle est la méthode la plus performante à chacune des tailles ?
- Quelle est la méthode la plus performante à chacune des tailles ?
<details>
<summary>Solution</summary>
......@@ -77,6 +78,9 @@ $ coverage report -m --omit=tri_test.py
print("{:20} => {:.02E}".format(TAB_METHODS[idx].__name__ , execution_time))
</details>
**Remarque:** Vous avez les solutions des scripts complets dans le répertoire solutions
----
### Etape 3 : Sonarqube
......
# -*- coding: utf-8 -*-
"""
Comparaison des performances de plusieurs algorithmes de tri écrit en Python
\n tri par selection
\n tri par selection récursif
\n tri par insertion
\n tri fusion
\n tri bulle
\n tri rapide
:author: cyril
:copyright: cnrs
Comparaison des performances de plusieurs algorithmes de tri écrit en Python :
- tri par selection
- tri par selection récursif
- tri par insertion
- tri fusion
- tri bulle
- tri rapide
"""
import random
import timeit
def tri_selection(tab, longueur):
import sys
sys.setrecursionlimit(10005)
def tri_selection(t, n):
"""
Tri par sélection \n
Tri par sélection
On détermine la position du plus petit élément, on le met en première
position et on itère le procédé sur le tableau restant. \n
Complexité en 0(lgn2) dans tous les cas.
:param tab: tableau à trier
:type tab: array
:param longueur: taille du tableau
position et on itère le procédé sur le tableau restant.
Complexité en 0(n2) dans tous les cas.
:param t: tableau à trier
:param n: taille du tableau
:return: tableau trié
:rtype: array
"""
if longueur < 2:
if n < 2:
# Moins de 2 éléments : pas besoin de trier
return tab
for index in range(longueur - 1):
return t
for i in range(n-1):
# On suppose que le min est en premier
mini = tab[index]
imin = index
for j in range(index + 1, longueur):
if tab[j] < mini:
# On met à jour le mini
mini = tab[j]
min = t[i]
imin = i
for j in range(i+1, n):
if t[j] < min:
# On met à jour le min
min = t[j]
imin = j
if imin != index:
if imin != i:
# On pertmute pour mettre le min en premier
tab[imin] = tab[index]
tab[index] = mini
return tab
t[imin] = t[i]
t[i] = min
return t
def tri_recursif(tab, longueur):
def tri_recursif(t, n):
"""
Tri par sélection récursif\n
Tri par sélection récursif
On détermine la position du plus grand élément et on le met en dernière
position. On réappelle alors la fonction tri_recursif sur le sous tableau
composé des n-1 premiers éléments de t.\n
composé des n-1 premiers éléments de t.
Complexité en O(n**2) dans tous les cas.
:param tab: tableau à trier
:type tab: array
:param longueur: taille du tableau
:return: tableau trié
:rtype: array
:param t:
:param n:
:return:
"""
if longueur < 2:
if n < 2:
# Moins de 2 éléments : pas besoin de trier
return tab
return t
# On suppose que le max est en dernier
maxi = tab[longueur - 1]
imax = longueur - 1
for index in range(longueur - 2):
if tab[index] > maxi:
max = t[n-1]
imax = n-1
for i in range(n-2):
if t[i] > max:
# On met à jour le max
maxi = tab[index]
imax = index
if imax != longueur - 1:
max = t[i]
imax = i
if imax != n-1:
# On permute pour mettre le max en dernier
tab[imax] = tab[longueur - 1]
tab[longueur - 1] = maxi
t[imax] = t[n-1]
t[n-1] = max
# Appel de tri_recursif sur t de taille n-1 pour trier le reste du tableau
tab = tri_recursif(tab, longueur - 1)
return tab
t = tri_recursif(t, n-1)
return t
def tri_insertion(tab, longueur):
def tri_insertion(t, n):
"""
Tri par insertion\n
On ordonne les deux premiers éléments.\n
On insère le 3ème de manière à ce que les 3 soient ordonnés.\n
On insère le i-ème de manière à ce que les i éléments soient ordonnées.\n
La complèxité est en O(n**2) dans le pire des cas.\n
:param tab: tableau à trier
:type tab: array
:param longueur: taille du tableau
:return: tableau trié
:rtype: array
Tri par insertion
On ordonne les deux premiers éléments.
On insère le 3ème de manière à ce que les 3 soient ordonnés.
On insère le i-ème de manière à ce que les i éléments soient ordonnées.
La complèxité est en O(n**2) dans le pire des cas.
:param t:
:param n:
:return:
"""
if longueur < 2:
if n < 2:
# Moins de 2 éléments : pas besoin de trier
return tab
for index in range(2, longueur):
item = tab[index] # un élément de la t
j = index
# tant qu'on n'a pas atteint le début ou un élément plus petit
while j > 0 and tab[j - 1] > item:
tab[j] = tab[j - 1] # on décale l'élément trouvé vers la droite
j = j - 1
tab[j] = item # on insere item a sa place
return tab
return t
for index in range(1, n):
item = t[index] #un élément de la t
j = index-1
while j>=0 and item < t[j] : #tant qu'on n'a pas atteint le début ou un élément plus petit
t[j+1] = t[j] #on décale l'élément trouvé vers la droite
j=j-1
t[j+1]=item #on insere item a sa place
return t
def tri_fusion(tab, longueur):
def tri_fusion(t, n):
"""
Tri fusion\n
Tri fusion
On découpe le tableau à trier en deux sous-tableaux de taille n/2.
On trie alors les deux sous-tableaux récursivement, ou on ne fait rien
s'ils sont de taille 1.\n
s'ils sont de taille 1.
On reconstitue le tableau trié initial en fusionnant les deux sous-tableaux
triés.\n
La complexité est en O(n*log(n)) dans le pire des cas.\n
:param tab: tableau à trier
:type tab: array
:param longueur: taille du tableau
:return: tableau trié
:rtype: array
triés.
La complexité est en O(n*log(n)) dans le pire des cas.
:param t:
:param n:
:return:
"""
def vidage(ta, pa, na, tab, pos):
def vidage(ta, pa, na, t, p):
"""
Copie ta de taille na à partir de la position pa dans t à partir de p
Copie tableau ta de taille na à partir de la position pa dans t à partir de p
:param ta: tableau à copier
:param pa: position à partir de laquelle copier
:param na: taille de ta
:param tab: tableau de destination
:param t: tableau de destination
:param p: position à partir de laquelle coller
:return:
"""
for index in range(pa, na):
tab[pos] = ta[index]
pos += 1
return tab
for i in range(pa, na):
t[p] = ta[i]
p += 1
return t
if longueur < 2:
if n < 2:
# Moins de 2 éléments : pas besoin de trier
return tab
return t
# Cas général : on découpe le tableau en 2 partie que l'on trie
pos = longueur // 2
tab1 = tab[:pos]
lgn1 = len(tab1)
tab1 = tri_fusion(tab1, lgn1)
tab2 = tab[pos:]
lgn2 = len(tab2)
tab2 = tri_fusion(tab2, lgn2)
p = n // 2
t1 = t[:p]
n1 = len(t1)
t1 = tri_fusion(t1, n1)
t2 = t[p:]
n2 = len(t2)
t2 = tri_fusion(t2, n2)
# Fusion des deux parties
pos1, pos2, pos = 0, 0, 0 # position dans tab1, tab2 et t
while pos1 < lgn1 and pos2 < lgn2:
if tab1[pos1] < tab2[pos2]:
# On met tab1[pos1] dans t
tab[pos] = tab1[pos1]
pos1 += 1
p1, p2, p = 0, 0, 0 # position dans t1, t2 et t
while p1 < n1 and p2 < n2:
if t1[p1] < t2[p2]:
# On met t1[p1] dans t
t[p] = t1[p1]
p1 += 1
else:
# On met tab2[pos2] dans t
tab[pos] = tab2[pos2]
pos2 += 1
pos += 1
if pos1 == len(tab1):
vidage(tab2, pos2, len(tab2), tab, pos)
# On met t2[p2] dans t
t[p] = t2[p2]
p2 += 1
p += 1
if p1 == len(t1):
vidage(t2, p2, len(t2), t, p)
else:
vidage(tab1, pos1, len(tab1), tab, pos)
return tab
vidage(t1, p1, len(t1), t, p)
return t
def tri_bulle(tab, longueur):
def tri_bulle(t, n):
"""
Tri bulle\n
Tri bulle
On compare les couples d'éléments successifs pour placer systématiquement
le plus grand après le plus petit. Un parcours complet du tableau selon
ce processus nous assure que le plus grand élément est en dernière
position. \nOn réitère alors le processus sur le sous tableau restant.\n
position. On réitère alors le processus sur le sous tableau restant.
Complexité en O(n**2).
:param tab: tableau à trier
:type tab: array
:param longueur: taille du tableau
:return: tableau trié
:rtype: array
:param t:
:param n:
:return:
"""
if longueur < 2:
if n < 2:
# Moins de 2 éléments : pas besoin de trier
return tab
for index in range(longueur - 1):
for j in range(longueur - 1 - index):
if tab[j] > tab[j + 1]:
return t
for i in range(n-1):
for j in range(n-1-i):
if t[j] > t[j+1]:
# On permute
temp = tab[j]
tab[j] = tab[j + 1]
tab[j + 1] = temp
return tab
temp = t[j]
t[j] = t[j+1]
t[j+1] = temp
return t
def tri_rapide(tab, longueur):
def tri_rapide(t, n):
"""
Tri rapide\n
Tri rapide
On choisit un élément du tableau au hasard qui sera 'pivot' et on permute
tous les éléments de manière à placer à gauche du pivot les éléments qui
lui sont inférieurs, et à droite ceux qui lui sont supérieurs.\n
lui sont inférieurs, et à droite ceux qui lui sont supérieurs.
On trie alors de la meme manière les deux moitiés de part et d'autre du
pivot.\n
pivot.
Complexité en O(nlog(n)).
:param tab: tableau à trier
:type tab: array
:param longueur: taille du tableau
:return: tableau trié
:rtype: array
:param t:
:param n:
:return:
"""
def tri_rapide_rec(tab, i, j):
def tri_rapide(t, i, j):
if i >= j:
# Pas besoin de trier
return tab
pos = i
# On place les éléments plus petits que le pivot (tab[j-1]) au début
for k in range(i, j - 1):
if tab[k] <= tab[j - 1]:
tab[k], tab[pos] = tab[pos], tab[k]
pos += 1
return t
p = i
# On place les éléments plus petits que le pivot (t[j-1]) au début
for k in range(i, j-1):
if t[k] <= t[j-1]:
t[k], t[p] = t[p], t[k]
p += 1
# On remet le pivot après les éléments plus petits
tab[j - 1], tab[pos] = tab[pos], tab[j - 1]
t[j-1], t[p] = t[p], t[j-1]
# On trie les deux parties
tri_rapide_rec(tab, i, pos - 1)
tri_rapide_rec(tab, pos + 1, j - 1)
return tab
tri_rapide(t, i, p-1)
tri_rapide(t, p+1, j-1)
return t
if longueur < 2:
if n < 2:
# Moins de 2 éléments : pas besoin de trier
return tab
return t
tab = tri_rapide_rec(tab, 0, longueur)
return tab
t = tri_rapide(t, 0, n)
return t
if __name__ == '__main__':
import sys
sys.setrecursionlimit(100000)
TAB_LONGUEURS = [10, 1000, 10000]
TAB_METHODS = {0: tri_selection, 1: tri_recursif, 2: tri_insertion, 3: tri_fusion, 4: tri_bulle, 5: tri_rapide}
for longueurT in TAB_LONGUEURS:
t0 = random.sample(range(1, 100000), longueurT)
print("############# LONGUEUR :" + str(longueurT) + " ###########")
for idx in range(6):
start = timeit.default_timer()
TAB_METHODS[idx](t0, longueurT)
stop = timeit.default_timer()
execution_time = stop - start
print(TAB_METHODS[idx].__name__ + " => " + str(execution_time))
\ No newline at end of file
longueur=100
t0 = random.sample(range(1,10000), longueur)
t2 = tri_selection(t0,longueur)
t3 = tri_recursif(t0,longueur)
t4 = tri_insertion(t0,longueur)
t5 = tri_fusion(t0,longueur)
t6 = tri_bulle(t0,longueur)
t7 = tri_rapide(t0,longueur)
......@@ -5,44 +5,53 @@ import sys
from tri import *
n=100
tableau_n= random.sample(range(1,n+1), n)
tableau_n_sorted = tableau_n
tableau_n_sorted.sort()
tableau=[[0],[1,2,3],[3,1,0],[1,1,1],[-1,0,1],[1,0,-1],[0.3,0.2,0.1],tableau_n]
longueur=[1,3,3,3,3,3,3,n]
tableau_res=[[0],[1,2,3],[0,1,3],[1,1,1],[-1,0,1],[-1,0,1],[0.1,0.2,0.3],tableau_n_sorted]
class TestTri(unittest.TestCase):
"""
Classe de test permettant de valider le bon fonctionnement des fonctions de tri
"""
def setUp(self):
"""
Initialisation d'un tableau random de taille n pour le dernier cas de test
Comparaison possible avec le tableau trié gràce à la fonction sort
"""
n=100
tableau_n= random.sample(range(1,n+1), n)
tableau_n_sorted = tableau_n
tableau_n_sorted.sort()
self.tableau=[[0],[1,2,3],[3,1,0],[1,1,1],[-1,0,1],[1,0,-1],[0.3,0.2,0.1],tableau_n]
self.longueur=[1,3,3,3,3,3,3,n]
self.tableau_res=[[0],[1,2,3],[0,1,3],[1,1,1],[-1,0,1],[-1,0,1],[0.1,0.2,0.3],tableau_n_sorted]
def test_tri_selection(self):
print("tri_selection")
for i in range(len(longueur)):
self.assertEqual(tri_selection(tableau[i],longueur[i]),tableau_res[i])
for i in range(len(self.longueur)):
self.assertEqual(tri_selection(self.tableau[i],self.longueur[i]),self.tableau_res[i])
def test_tri_recursif(self):
print("tri_recursif")
for i in range(len(longueur)):
self.assertEqual(tri_recursif(tableau[i],longueur[i]),tableau_res[i])
for i in range(len(self.longueur)):
self.assertEqual(tri_recursif(self.tableau[i],self.longueur[i]),self.tableau_res[i])
def test_tri_insertion(self):
print("tri_insertion")
for i in range(len(longueur)):
self.assertEqual(tri_insertion(tableau[i],longueur[i]),tableau_res[i])
for i in range(len(self.longueur)):
self.assertEqual(tri_insertion(self.tableau[i],self.longueur[i]),self.tableau_res[i])
def test_tri_fusion(self):
print("tri_fusion")
for i in range(len(longueur)):
self.assertEqual(tri_fusion(tableau[i],longueur[i]),tableau_res[i])
for i in range(len(self.longueur)):
self.assertEqual(tri_fusion(self.tableau[i],self.longueur[i]),self.tableau_res[i])
def test_tri_bulle(self):
print("tri_bulle")
for i in range(len(longueur)):
self.assertEqual(tri_bulle(tableau[i],longueur[i]),tableau_res[i])
for i in range(len(self.longueur)):
self.assertEqual(tri_bulle(self.tableau[i],self.longueur[i]),self.tableau_res[i])
if __name__ == '__main__':
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment