diff --git a/Tp7/Tp_tris.py b/Tp7/Tp_tris.py new file mode 100644 index 0000000000000000000000000000000000000000..d7850c8a78c2212ad86474bf92675ce566e5bd04 --- /dev/null +++ b/Tp7/Tp_tris.py @@ -0,0 +1,80 @@ +# l'expression qui permet de construire une liste des entiers +#de 0 àn-1 est range(n) + + +from random import shuffle +from typing import Callable +from compare import compare +from ap_decorators import count +from tris import * +import matplotlib.pyplot as plt +from anlyse_tris import tri_select +import timeit +from math import sqrt + + +def liste_alea(n:int)->list[int]: + """construit une liste de longueur n contenant les entiers 0 à n-1 mélangés. + + Précondition : n>=0 + Exemple(s) : + $$$ liste_alea(5) + [3, 2, 0, 4, 1 ] + $$$ liste_alea(3) + [2, 1, 0] + $$$ liste_alea(2) + [0, 1] + + """ + + L=list(range(n)) + random.shuffle(L) + return L + +#Representation graphique evec Matpotlib: + +import matplotlib.pyplot as plt +abscisses = [1, 2, 4] +ordonnees = [2, 5, 0] +plt.plot(abscisses, ordonnees, color='blue') +plt.show() + +#Évaluation expérimentale de la complexité en temps +compare = count(compare) + +def analyser_tri(tri: Callable[[list[T], Callable[[T, T], int]], NoneType], + nbre_essais: int, + taille: int) -> float: + """ + renvoie: le nombre moyen de comparaisons effectuées par l'algo tri + pour trier des listes de taille t, la moyenne étant calculée + sur n listes aléatoires. + précondition: n > 0, t >= 0, la fonc + """ + res = 0 + for i in range(nbre_essais): + compare.counter = 0 + l = [k for k in range(taille)] + shuffle(l) + tri(l, compare) + res += compare.counter + return res / nbre_essais + + + + +#calcul de nombres moyens de compraisons pour des listes + +TAILLE_MAX = 100 +L=[] +t=[] + + +for t in range(TAILLE_MAX+1): + + + + + + + diff --git a/Tp7/analyse-tris.zip b/Tp7/analyse-tris.zip new file mode 100644 index 0000000000000000000000000000000000000000..93aed14f5508d1cbd03c4263483fdc9826249941 Binary files /dev/null and b/Tp7/analyse-tris.zip differ diff --git a/Tp7/analyse-tris/analyse_tris.py b/Tp7/analyse-tris/analyse_tris.py new file mode 100644 index 0000000000000000000000000000000000000000..9d12c3495eb527f26efa2ed40a25f584acada2ae --- /dev/null +++ b/Tp7/analyse-tris/analyse_tris.py @@ -0,0 +1,79 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`analyse_tris` module +:author: FIL - Faculté des Sciences et Technologies - Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: janvier 2017 +:dernières révisions: février 2018, février 2019 + +Analyse empirique des tris + +""" +from random import shuffle +from typing import Callable +from compare import compare +from ap_decorators import count +from tris import * + +################################################ +# ANALYSE EMPIRIQUE DES TRIS # +################################################ + +# ajout d'un compteur à la fonction compare +compare = count(compare) + +def analyser_tri(tri: Callable[[list[T], Callable[[T, T], int]], NoneType], + nbre_essais: int, + taille: int) -> float: + """ + renvoie: le nombre moyen de comparaisons effectuées par l'algo tri + pour trier des listes de taille t, la moyenne étant calculée + sur n listes aléatoires. + précondition: n > 0, t >= 0, la fonc + """ + res = 0 + for i in range(nbre_essais): + compare.counter = 0 + l = [k for k in range(taille)] + shuffle(l) + tri(l, compare) + res += compare.counter + return res / nbre_essais + + +if (__name__ == '__main__'): + from matplotlib import pyplot as plt + + # Calcul de nombres moyens de comparaison pour des listes + # de tailles comprises entre 0 et TAILLE_MAX + NB_ESSAIS = 50 + TAILLE_MAX = 100 + c_select = [0.0] * (TAILLE_MAX + 1) + c_insert = [0.0] * (TAILLE_MAX + 1) + + for t in range(TAILLE_MAX + 1): + c_select[t] = analyser_tri(tri_select, 1, t) + # inutile de moyenner pour le tri par sélection + c_insert[t] = analyser_tri(tri_insert, NB_ESSAIS, t) + + # Sauvegarde des données calculées dans un fichier au format CSV + prem_ligne = 'taille;"tri séléction";"tri insertion"\n' + ligne = '{:3d};{:8.2f};{:8.2f}\n' + with open('analyse_tris.csv', 'wt', encoding='utf8') as sortie: + sortie.write(prem_ligne) + for t in range(TAILLE_MAX + 1): + sortie.write(ligne.format(t, + c_select[t], + c_insert[t])) + + # Représentation graphique + plt.plot(list(range(TAILLE_MAX + 1)), c_select, 'b.', label='Tri sélection') + plt.plot(list(range(TAILLE_MAX + 1)), c_insert, 'r.', label='Tri insertion') + plt.title('Tris : nbre de comparaisons') + plt.legend() + plt.xlabel('n = taille des listes') + plt.ylabel('c(n) = nbre de comparaisons') + plt.savefig('tris_nbcomp.png') + plt.show() + diff --git a/Tp7/analyse-tris/ap_decorators.py b/Tp7/analyse-tris/ap_decorators.py new file mode 100644 index 0000000000000000000000000000000000000000..5f4adc9129d3d7ffef9d7dc68b59e4d6643d419d --- /dev/null +++ b/Tp7/analyse-tris/ap_decorators.py @@ -0,0 +1,135 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:module: ap_decorators +:author: FIL - Faculté des Sciences et Technologies - Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2018, september + +""" + +from functools import wraps + + +def trace(fct): + ''' + Decorator for tracing every call to fct. + Recursive calls are indented. + + :Example: + + >>> @trace + ... def fact(n): + ... if n == 0: + ... return 1 + ... else: + ... return n * fact(n - 1) + + >>> fact(5) + -> fact((5,), {}) + ... -> fact((4,), {}) + ...... -> fact((3,), {}) + ......... -> fact((2,), {}) + ............ -> fact((1,), {}) + ............... -> fact((0,), {}) + ............... <- 1 + ............ <- 1 + ......... <- 2 + ...... <- 6 + ... <- 24 + <- 120 + 120 + ''' + @wraps(fct) + def wrapper(*args, **kwargs): + dots = '...' * wrapper.__depth + print('{:s} -> {:s}{:s}'.format(dots, wrapper.__name__, repr((args, kwargs)))) + wrapper.__depth += 1 + y = fct(*args, **kwargs) + wrapper.__depth -= 1 + print('{:s} <- {:s}'.format(dots, repr(y))) + return y + wrapper.__depth = 0 + return wrapper + +def count(fct): + ''' + decorator for counting calls to function fct + + :Example: + + >>> @count + ... def fact(n): + ... if n == 0: + ... return 1 + ... else: + ... return n * fact(n - 1) + + >>> fact.counter + 0 + >>> fact(5) + 120 + >>> fact.counter + 6 + ''' + @wraps(fct) + def wrapper(*args, **kwargs): + y = fct(*args, **kwargs) + wrapper.counter += 1 + return y + wrapper.counter = 0 + return wrapper + + +def memoize(fct): + ''' + decorator for memoizing computed values of function fct + + :Example: + + >>> @count + ... @memoize + ... def fact(n): + ... if n == 0: + ... return 1 + ... else: + ... return n * fact(n - 1) + + >>> fact.counter + 0 + >>> fact(5) + 120 + >>> fact.counter + 6 + >>> fact.counter = 0 + >>> fact(5) + 120 + >>> fact.counter + 1 + ''' + cache = dict() + @wraps(fct) + def wrapper(*args, **kwargs): + key = repr((args, kwargs)) + if key in cache: + return cache[key] + else: + y = fct(*args, **kwargs) + cache[key] = y + return y + return wrapper + + + +if __name__ == '__main__': + import doctest + doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS, verbose=False) + + + + + + + + + diff --git a/Tp7/analyse-tris/apl1test.py b/Tp7/analyse-tris/apl1test.py new file mode 100644 index 0000000000000000000000000000000000000000..8533ccaca5d99e7cfb83d6d86aa9334bb6a73a40 --- /dev/null +++ b/Tp7/analyse-tris/apl1test.py @@ -0,0 +1,89 @@ +import thonnycontrib +from thonnycontrib.backend.evaluator import Evaluator +import thonnycontrib.backend.l1test_backend +from thonny.plugins.cpython_backend.cp_back import MainCPythonBackend +import thonnycontrib.backend.doctest_parser +from thonnycontrib.backend.doctest_parser import ExampleWithExpected, ExampleWithoutExpected +import thonnycontrib.backend.ast_parser +from thonnycontrib.backend.ast_parser import L1DocTest +import thonnycontrib.backend.verdicts +from thonnycontrib.backend.verdicts.ExceptionVerdict import ExceptionVerdict + +import inspect +import tempfile +import os +import sys + +class MockBackend(MainCPythonBackend): + """ + Fake backend. + """ + def __init__(self): + ... + + def send_message(self, msg) -> None: + ... + +# register backend +thonnycontrib.backend.l1test_backend.BACKEND = MockBackend() + +def l1test_to_org(filename: str, source: str=""): + """ + Return an org abstract of the tests presents in `filename` file. + """ + abstract = {'total': 0, + 'success': 0, + 'failures': 0, + 'errors': 0, + 'empty': 0} + + if source == "": + with open(filename, 'rt') as fin: + source = fin.read() + evaluator = Evaluator(filename=filename, + source=source) + tests = evaluator.evaluate() + n = len(tests) + abstract['total'] = n + res = "" + for test in tests: + examples = test.get_examples() + res_examples = "" + nb_test, nb_test_ok = 0, 0 + empty = True + for example in examples: + verdict = test.get_verdict_from_example(example) + if isinstance(example, ExampleWithExpected): + nb_test += 1 + if verdict.isSuccess(): + nb_test_ok += 1 + abstract['success'] += 1 + else: + abstract['failures'] += 1 + empty = False + if isinstance(verdict, ExceptionVerdict): + abstract['errors'] += 1 + empty = False + res_examples += f"** {verdict}\n\n" + if not verdict.isSuccess(): + res_examples += f" {verdict.get_details()}\n\n" + if not empty: + res += f"* {test.get_name()} ~ {nb_test_ok}/{nb_test} réussis\n\n" + else: + abstract['empty'] += 1 + res += f"* {test.get_name()}\n\n Aucun test trouvé !\n\n" + res += res_examples + res = f"Tests exécutés : {abstract['total']}\nSuccès: {abstract['success']}, \ +Echecs: {abstract['failures']}, Erreurs: {abstract['errors']}, \ +Vide: {abstract['empty']}\n\n" + res + return res + + +def testmod(modulename: str): + """ + mimic the doctest.testmod function + for `modulename` module + """ + print(l1test_to_org(modulename)) + + diff --git a/Tp7/analyse-tris/compare.py b/Tp7/analyse-tris/compare.py new file mode 100644 index 0000000000000000000000000000000000000000..abad0a4c2af8427e32cf9f56cc7868fe742be0e1 --- /dev/null +++ b/Tp7/analyse-tris/compare.py @@ -0,0 +1,44 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`compare` module +:author: FIL - FST - Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2016, january +:dernière révision: février 2018 + +Fonction de comparaison +pour l'analyse des algos de recherche et de tri + +""" +from typing import TypeVar + + +T = TypeVar('T') +def compare(x: T, y: T) -> int: + """ + renvoie: + - -1 si x < y + - 0 si x == y + - 1 si x > y + précondition: x et y doivent être d'un type pour lequel les opérateurs de comparaison <, <=, == + peuvent s'appliquer + exemples: + + $$$ compare(1, 3) + -1 + $$$ compare(3, 1) + 1 + $$$ compare(3, 3) + 0 + """ + if x == y: + return 0 + elif x > y: + return 1 + else: + return -1 + +if (__name__ == '__main__'): + import apl1test + apl1test.testmod('compare.py') diff --git a/Tp7/analyse-tris/tris.py b/Tp7/analyse-tris/tris.py new file mode 100644 index 0000000000000000000000000000000000000000..18df74065a465ff7025f8fc807a4bd08958869a5 --- /dev/null +++ b/Tp7/analyse-tris/tris.py @@ -0,0 +1,193 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`tris` module +:author: FIL - Faculté des Sciences et Technologies - + Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2015, january +:dernière révision: février 2018 + + +Tris de listes + +- tri par sélection +- tri par insertion + +""" + +from types import NoneType +from typing import Callable, TypeVar +from compare import compare +T = TypeVar('T') + +def est_trie(liste: list[T], comp: Callable[[T, T], int] = compare) -> bool: + """ + renvoir True si et seulement si liste est triée selon l'ordre défini par comp + + précondition: les éléments de liste doivent être comparables selon comp + + exemples: + + $$$ est_trie([1, 2, 3, 4]) + True + $$$ est_trie([1, 2, 4, 3]) + False + $$$ est_trie([]) + True + """ + i = 0 + res = True + while res and i < len(liste) - 1: + res = comp(liste[i], liste[i+1]) <= 0 + i += 1 + return res + # ou plus simplement + # return all(comp(liste[i], liste[i+1]) <= 0 for i in range(len(liste)-1)) + + +################################################ +# TRI PAR SELECTION # +################################################ + +def echanger(liste: list[T], i: int, j: int) -> NoneType: + """ + échange les éléments d'indice i et j de liste. + + précondition: 0 <= i,j < len(liste) + + exemples: + + $$$ l1 = [3, 1, 4, 9, 5, 1, 2] + $$$ l2 = l1.copy() + $$$ echanger(l2, 3, 5) + $$$ (l1[3], l1[5]) == (l2[5], l2[3]) + True + """ + liste[i], liste[j] = liste[j], liste[i] + + +def select_min(liste: list[T], a: int, b: int, comp: Callable[[T, T], int]=compare) -> int: + """ + renvoie l'indice du minimum dans la tranche liste[a:b] + précondition: 0 <= a < b <= long(liste), + éléments de liste comparables avec comp + exemples: + + $$$ select_min([1, 2, 3, 4, 5, 6, 7, 0], 0, 8) + 7 + $$$ select_min([1, 2, 3, 4, 5, 6, 7, 0], 1, 7) + 1 + """ + ind_min = a + # l'indice du plus petit élément de la tranche liste[a:a+1] est ind_min + for i in range(a + 1, b): + # supposons que l'indice du plus petit élément de la + # tranche liste[a:i] est ind_min + if comp(liste[i], liste[ind_min]) == -1: + ind_min = i + # alors l'indice du plus petit élément de la tranche liste[a:i+1] + # est ind_min + # à l'issue de l'itération l'indice du plus petit élément de la tranche + # liste[a:b] est ind_min + return ind_min + + +def tri_select(liste: list[T], comp: Callable[[T, T], int] = compare) -> NoneType: + """ + modifie la liste liste en triant ses éléments selon l'ordre défini par comp + Algorithme du tri par sélection du minimum + précondition: liste liste homogène d'éléments comparables selon comp + exemples: + + $$$ liste = [3, 1, 4, 1, 5, 9, 2] + $$$ tri_select(liste) + $$$ liste == [1, 1, 2, 3, 4, 5, 9] + True + $$$ from random import randrange + $$$ l1 = [randrange(1000) for k in range(randrange(100))] + $$$ l2 = l1.copy() + $$$ tri_select(l2) + $$$ est_trie(l2) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l1) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l2) + True + """ + n = len(liste) + # la tranche liste[0:1] est triée + for i in range(n - 1): + # supposons la tranche liste[0:i+1] triée + ind_min = select_min(liste, i, n, comp=comp) + echanger(liste, i, ind_min) + # alors la tranche liste[0:i+1] est triée + # à l'issue de l'itération la tranche liste[0:n] est triée + + +################################################ +# TRI PAR INSERTION # +################################################ + +def inserer(liste: list[T], i: int, comp: Callable[[T, T], int] = compare) -> NoneType: + """ + insère l'élément liste[i] à sa place dans la tranche + liste[0:i+1] de sorte que cette tranche soit triée + si liste[0:i] l'est auparavant + + précondition: 0 <= i < long(liste) + éléments de liste comparables par comp + exemples: + + $$$ liste = [1, 2, 4, 5, 3, 7, 6] + $$$ inserer(liste, 4) + $$$ liste == [1, 2, 3, 4, 5, 7, 6] + True + $$$ inserer(liste, 5) + $$$ liste == [1, 2, 3, 4, 5, 7, 6] + True + $$$ inserer(liste, 6) + $$$ liste == [1, 2, 3, 4, 5, 6, 7] + True + """ + aux = liste[i] + k = i + while k >= 1 and comp(aux, liste[k - 1]) == -1: + liste[k] = liste[k - 1] + k = k - 1 + liste[k] = aux + + +def tri_insert(liste: list[T], comp: Callable[[T, T], int] = compare) -> NoneType: + """ + modifie la liste liste en triant ses éléments selon l'ordre défini par comp Algorithme du tri par insertion + précondition: liste liste homogène d'éléments comparables selon comp + exemples: + + $$$ liste = [3, 1, 4, 1, 5, 9, 2] + $$$ tri_insert(liste) + $$$ liste == [1, 1, 2, 3, 4, 5, 9] + True + $$$ from random import randrange + $$$ l1 = [randrange(1000) for k in range(randrange(100))] + $$$ l2 = l1.copy() + $$$ tri_insert(l2) + $$$ est_trie(l2) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l1) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l2) + True + """ + n = len(liste) + # la tranche liste[0:1] est triée + for i in range(1, n): + # supposons la tranche liste[0:i] triée + inserer(liste, i, comp=comp) + # alors la tranche liste[0:i+1] est triée + # à l'issue de l'itération la tranche liste[0:n] est triée + + +if (__name__ == '__main__'): + import apl1test + apl1test.testmod('tris.py') diff --git a/Tp7/analyse_tris2.py b/Tp7/analyse_tris2.py new file mode 100755 index 0000000000000000000000000000000000000000..126de5b02a916977064221e4295c479d8e693dc2 --- /dev/null +++ b/Tp7/analyse_tris2.py @@ -0,0 +1,94 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`analyse_tris` module +:author: FIL - Faculté des Sciences et Technologies - Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: janvier 2017 +:dernières révisions: février 2018, février 2019 + +Analyse empirique des tris + +""" +from random import shuffle +from typing import Callable +from compare import compare +from ap_decorators import count +from tris import * + +################################################ +# ANALYSE EMPIRIQUE DES TRIS # +################################################ + +# ajout d'un compteur à la fonction compare +compare = count(compare) + +def analyser_tri(tri: Callable[[list[T], Callable[[T, T], int]], NoneType], + nbre_essais: int, + taille: int) -> float: + """ + renvoie: le nombre moyen de comparaisons effectuées par l'algo tri + pour trier des listes de taille t, la moyenne étant calculée + sur n listes aléatoires. + précondition: n > 0, t >= 0, la fonc + """ + res = 0 + for i in range(nbre_essais): + compare.counter = 0 + l = [k for k in range(taille)] + shuffle(l) + tri(l, compare) + res += compare.counter + return res / nbre_essais + +def tris_sort(l:list[T], comp:callable[T, T], int= compare): + """à_remplacer_par_ce_que_fait_la_fonction + + Précondition : + Exemple(s) : + $$$ + + """ + sorted (l,key= lambda x:comp(x,x)) + + +if (__name__ == '__main__'): + from matplotlib import pyplot as plt + + # Calcul de nombres moyens de comparaison pour des listes + # de tailles comprises entre 0 et TAILLE_MAX + NB_ESSAIS = 50 + TAILLE_MAX = 100 + c_select = [0.0] * (TAILLE_MAX + 1) + c_insert = [0.0] * (TAILLE_MAX + 1) + c_sort = [0.0] * (TAILLE_MAX + 1) + + + + + for t in range(TAILLE_MAX + 1): + c_select[t] = analyser_tri(tri_select, 1, t) + # inutile de moyenner pour le tri par sélection + c_insert[t] = analyser_tri(tri_insert, NB_ESSAIS, t) + c_insert[t] = analyser_tri(tri_sort, NB_ESSAIS, t) + + # Sauvegarde des données calculées dans un fichier au format CSV + prem_ligne = 'taille;"tri séléction";"tri insertion"\n' + ligne = '{:3d};{:8.2f};{:8.2f}\n' + with open('analyse_tris.csv', 'wt', encoding='utf8') as sortie: + sortie.write(prem_ligne) + for t in range(TAILLE_MAX + 1): + sortie.write(ligne.format(t, + c_select[t], + c_insert[t])) + + # Représentation graphique + plt.plot(list(range(TAILLE_MAX + 1)), c_select, 'b.', label='Tri sélection') + plt.plot(list(range(TAILLE_MAX + 1)), c_insert, 'r.', label='Tri insertion') + plt.plot(list(range(TAILLE_MAX + 1)), c_insert, 'green.', label='Tri sort') + plt.title('Tris : nbre de comparaisons') + plt.legend() + plt.xlabel('n = taille des listes') + plt.ylabel('c(n) = nbre de comparaisons') + plt.savefig('tris_nbcomp.png') + plt.show() diff --git a/Tp7/ap_decorators.py b/Tp7/ap_decorators.py new file mode 100644 index 0000000000000000000000000000000000000000..5f4adc9129d3d7ffef9d7dc68b59e4d6643d419d --- /dev/null +++ b/Tp7/ap_decorators.py @@ -0,0 +1,135 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:module: ap_decorators +:author: FIL - Faculté des Sciences et Technologies - Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2018, september + +""" + +from functools import wraps + + +def trace(fct): + ''' + Decorator for tracing every call to fct. + Recursive calls are indented. + + :Example: + + >>> @trace + ... def fact(n): + ... if n == 0: + ... return 1 + ... else: + ... return n * fact(n - 1) + + >>> fact(5) + -> fact((5,), {}) + ... -> fact((4,), {}) + ...... -> fact((3,), {}) + ......... -> fact((2,), {}) + ............ -> fact((1,), {}) + ............... -> fact((0,), {}) + ............... <- 1 + ............ <- 1 + ......... <- 2 + ...... <- 6 + ... <- 24 + <- 120 + 120 + ''' + @wraps(fct) + def wrapper(*args, **kwargs): + dots = '...' * wrapper.__depth + print('{:s} -> {:s}{:s}'.format(dots, wrapper.__name__, repr((args, kwargs)))) + wrapper.__depth += 1 + y = fct(*args, **kwargs) + wrapper.__depth -= 1 + print('{:s} <- {:s}'.format(dots, repr(y))) + return y + wrapper.__depth = 0 + return wrapper + +def count(fct): + ''' + decorator for counting calls to function fct + + :Example: + + >>> @count + ... def fact(n): + ... if n == 0: + ... return 1 + ... else: + ... return n * fact(n - 1) + + >>> fact.counter + 0 + >>> fact(5) + 120 + >>> fact.counter + 6 + ''' + @wraps(fct) + def wrapper(*args, **kwargs): + y = fct(*args, **kwargs) + wrapper.counter += 1 + return y + wrapper.counter = 0 + return wrapper + + +def memoize(fct): + ''' + decorator for memoizing computed values of function fct + + :Example: + + >>> @count + ... @memoize + ... def fact(n): + ... if n == 0: + ... return 1 + ... else: + ... return n * fact(n - 1) + + >>> fact.counter + 0 + >>> fact(5) + 120 + >>> fact.counter + 6 + >>> fact.counter = 0 + >>> fact(5) + 120 + >>> fact.counter + 1 + ''' + cache = dict() + @wraps(fct) + def wrapper(*args, **kwargs): + key = repr((args, kwargs)) + if key in cache: + return cache[key] + else: + y = fct(*args, **kwargs) + cache[key] = y + return y + return wrapper + + + +if __name__ == '__main__': + import doctest + doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS, verbose=False) + + + + + + + + + diff --git a/Tp7/compare.py b/Tp7/compare.py new file mode 100644 index 0000000000000000000000000000000000000000..abad0a4c2af8427e32cf9f56cc7868fe742be0e1 --- /dev/null +++ b/Tp7/compare.py @@ -0,0 +1,44 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`compare` module +:author: FIL - FST - Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2016, january +:dernière révision: février 2018 + +Fonction de comparaison +pour l'analyse des algos de recherche et de tri + +""" +from typing import TypeVar + + +T = TypeVar('T') +def compare(x: T, y: T) -> int: + """ + renvoie: + - -1 si x < y + - 0 si x == y + - 1 si x > y + précondition: x et y doivent être d'un type pour lequel les opérateurs de comparaison <, <=, == + peuvent s'appliquer + exemples: + + $$$ compare(1, 3) + -1 + $$$ compare(3, 1) + 1 + $$$ compare(3, 3) + 0 + """ + if x == y: + return 0 + elif x > y: + return 1 + else: + return -1 + +if (__name__ == '__main__'): + import apl1test + apl1test.testmod('compare.py') diff --git a/Tp7/tris.py b/Tp7/tris.py new file mode 100644 index 0000000000000000000000000000000000000000..18df74065a465ff7025f8fc807a4bd08958869a5 --- /dev/null +++ b/Tp7/tris.py @@ -0,0 +1,193 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`tris` module +:author: FIL - Faculté des Sciences et Technologies - + Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2015, january +:dernière révision: février 2018 + + +Tris de listes + +- tri par sélection +- tri par insertion + +""" + +from types import NoneType +from typing import Callable, TypeVar +from compare import compare +T = TypeVar('T') + +def est_trie(liste: list[T], comp: Callable[[T, T], int] = compare) -> bool: + """ + renvoir True si et seulement si liste est triée selon l'ordre défini par comp + + précondition: les éléments de liste doivent être comparables selon comp + + exemples: + + $$$ est_trie([1, 2, 3, 4]) + True + $$$ est_trie([1, 2, 4, 3]) + False + $$$ est_trie([]) + True + """ + i = 0 + res = True + while res and i < len(liste) - 1: + res = comp(liste[i], liste[i+1]) <= 0 + i += 1 + return res + # ou plus simplement + # return all(comp(liste[i], liste[i+1]) <= 0 for i in range(len(liste)-1)) + + +################################################ +# TRI PAR SELECTION # +################################################ + +def echanger(liste: list[T], i: int, j: int) -> NoneType: + """ + échange les éléments d'indice i et j de liste. + + précondition: 0 <= i,j < len(liste) + + exemples: + + $$$ l1 = [3, 1, 4, 9, 5, 1, 2] + $$$ l2 = l1.copy() + $$$ echanger(l2, 3, 5) + $$$ (l1[3], l1[5]) == (l2[5], l2[3]) + True + """ + liste[i], liste[j] = liste[j], liste[i] + + +def select_min(liste: list[T], a: int, b: int, comp: Callable[[T, T], int]=compare) -> int: + """ + renvoie l'indice du minimum dans la tranche liste[a:b] + précondition: 0 <= a < b <= long(liste), + éléments de liste comparables avec comp + exemples: + + $$$ select_min([1, 2, 3, 4, 5, 6, 7, 0], 0, 8) + 7 + $$$ select_min([1, 2, 3, 4, 5, 6, 7, 0], 1, 7) + 1 + """ + ind_min = a + # l'indice du plus petit élément de la tranche liste[a:a+1] est ind_min + for i in range(a + 1, b): + # supposons que l'indice du plus petit élément de la + # tranche liste[a:i] est ind_min + if comp(liste[i], liste[ind_min]) == -1: + ind_min = i + # alors l'indice du plus petit élément de la tranche liste[a:i+1] + # est ind_min + # à l'issue de l'itération l'indice du plus petit élément de la tranche + # liste[a:b] est ind_min + return ind_min + + +def tri_select(liste: list[T], comp: Callable[[T, T], int] = compare) -> NoneType: + """ + modifie la liste liste en triant ses éléments selon l'ordre défini par comp + Algorithme du tri par sélection du minimum + précondition: liste liste homogène d'éléments comparables selon comp + exemples: + + $$$ liste = [3, 1, 4, 1, 5, 9, 2] + $$$ tri_select(liste) + $$$ liste == [1, 1, 2, 3, 4, 5, 9] + True + $$$ from random import randrange + $$$ l1 = [randrange(1000) for k in range(randrange(100))] + $$$ l2 = l1.copy() + $$$ tri_select(l2) + $$$ est_trie(l2) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l1) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l2) + True + """ + n = len(liste) + # la tranche liste[0:1] est triée + for i in range(n - 1): + # supposons la tranche liste[0:i+1] triée + ind_min = select_min(liste, i, n, comp=comp) + echanger(liste, i, ind_min) + # alors la tranche liste[0:i+1] est triée + # à l'issue de l'itération la tranche liste[0:n] est triée + + +################################################ +# TRI PAR INSERTION # +################################################ + +def inserer(liste: list[T], i: int, comp: Callable[[T, T], int] = compare) -> NoneType: + """ + insère l'élément liste[i] à sa place dans la tranche + liste[0:i+1] de sorte que cette tranche soit triée + si liste[0:i] l'est auparavant + + précondition: 0 <= i < long(liste) + éléments de liste comparables par comp + exemples: + + $$$ liste = [1, 2, 4, 5, 3, 7, 6] + $$$ inserer(liste, 4) + $$$ liste == [1, 2, 3, 4, 5, 7, 6] + True + $$$ inserer(liste, 5) + $$$ liste == [1, 2, 3, 4, 5, 7, 6] + True + $$$ inserer(liste, 6) + $$$ liste == [1, 2, 3, 4, 5, 6, 7] + True + """ + aux = liste[i] + k = i + while k >= 1 and comp(aux, liste[k - 1]) == -1: + liste[k] = liste[k - 1] + k = k - 1 + liste[k] = aux + + +def tri_insert(liste: list[T], comp: Callable[[T, T], int] = compare) -> NoneType: + """ + modifie la liste liste en triant ses éléments selon l'ordre défini par comp Algorithme du tri par insertion + précondition: liste liste homogène d'éléments comparables selon comp + exemples: + + $$$ liste = [3, 1, 4, 1, 5, 9, 2] + $$$ tri_insert(liste) + $$$ liste == [1, 1, 2, 3, 4, 5, 9] + True + $$$ from random import randrange + $$$ l1 = [randrange(1000) for k in range(randrange(100))] + $$$ l2 = l1.copy() + $$$ tri_insert(l2) + $$$ est_trie(l2) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l1) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l2) + True + """ + n = len(liste) + # la tranche liste[0:1] est triée + for i in range(1, n): + # supposons la tranche liste[0:i] triée + inserer(liste, i, comp=comp) + # alors la tranche liste[0:i+1] est triée + # à l'issue de l'itération la tranche liste[0:n] est triée + + +if (__name__ == '__main__'): + import apl1test + apl1test.testmod('tris.py')