Skip to content
Snippets Groups Projects
Commit 8035ae64 authored by Angy Wallot's avatar Angy Wallot
Browse files

tp.6

parent 61251e59
Branches
No related tags found
No related merge requests found
#!/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)
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))
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
:mod:`association` module : un module pour les associations clé-valeur
:author: `FIL - Faculté des Sciences et Technologies -
Univ. Lille <http://portail.fil.univ-lille1.fr>`_
:date: 2024 février
"""
from ap_decorators import count
from typing import TypeVar
# On définit deux types génériques :
# - C pour le type des clés
# - V pour le type des valeurs
C = TypeVar('C')
V = TypeVar('V')
class Association:
"""Classe d'une association clé-valeur
"""
def __init__(self, cle: C, valeur: V):
"""
$$$ asso1 = Association('a', 1)
$$$ asso1.cle
'a'
$$$ asso1.valeur
1
"""
...
def __repr__(self) -> str:
"""
$$$ repr(Association(2, 3))
'Association(2, 3)'
$$$ repr(Association('a', 1))
"Association('a', 1)"
$$$ repr(Association((1, True), [1, 2, 3]))
'Association((1, True), [1, 2, 3])'
$$$ repr(Association(1+1 == 2, "Vrai"))
"Association(True, 'Vrai')"
"""
...
def __eq__(self, autre) -> bool:
"""
$$$ Association('a', 1) == Association('a', 1)
True
$$$ Association('a', 1) == Association('a', 2)
False
$$$ Association('a', 1) == Association(1, 'a')
False
$$$ Association('a', 1) == ('a', 1)
False
"""
...
@count
def comp_asso(a1: Association, a2: Association) -> int:
"""Renvoie 0 si les clés de a1 et a2 sont identiques
-1 si la clé de a1 < la clé de a2
1 si la clé de a1 > la clé de a2
Precondition : les clés de a1 et a2 sont comparables
$$$ comp_asso(Association(1, 'a'), Association(1, 'c'))
0
$$$ comp_asso(Association(1, 'a'), Association(2, 'a'))
-1
$$$ comp_asso(Association(1, 'd'), Association(0, 'c'))
1
"""
...
if __name__ == '__main__':
import apl1test
apl1test.testmod('association.py')
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
:mod:`dicotrie` module : un module pour les ensembles d'associations
:author: `FIL - Faculté des Sciences et Technologies -
Univ. Lille <http://portail.fil.univ-lille1.fr>`_
:date: 2024 février
"""
from association import Association, C, V, comp_asso
from recherches import indice_dicho, inserer
from types import NoneType
class DicoTrie:
"""Classe d'une association clé-valeur
"""
def __init__(self, liste_assos: list[Association]):
"""
"""
...
def __repr__(self) -> str:
"""
$$$ repr(DicoTrie([Association('a', 1)]))
"DicoTrie([Association('a', 1)])"
$$$ repr(DicoTrie([Association('a', 1), Association('b', 2)]))
"DicoTrie([Association('a', 1), Association('b', 2)])"
$$$ repr(DicoTrie([Association('c', 3), Association('a', 2), Association('b', 1)]))
"DicoTrie([Association('a', 2), Association('b', 1), Association('c', 3)])"
"""
...
def __eq__(self, autre) -> bool:
"""
$$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)])
$$$ d2 = DicoTrie([Association("b", 2), Association("a", 1)])
$$$ d3 = DicoTrie([Association("a", 1), Association("b", 2), Association("c", 3)])
$$$ d1 == d2
True
$$$ d1 == d3
False
$$$ d1 == {"a": 1, "b": 2}
False
"""
...
def __setitem__(self, cle: C, valeur: V) -> NoneType:
"""
$$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)])
$$$ d1["c"] = 3
$$$ d1
DicoTrie([Association("a", 1), Association("b", 2), Association("c", 3)])
"""
...
def __getitem__(self, cle: C) -> V:
"""
$$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)])
$$$ d1['a']
1
$$$ d1['b']
2
$$e d1['c']
KeyError
"""
...
def __delitem__(self, cle: C) -> NoneType:
"""
$$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)])
$$$ del d1['a']
$$$ d1
DicoTrie([Association("b", 2)])
$$e del d1['c']
KeyError
"""
...
def __contains__(self, cle: C) -> bool:
"""
$$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)])
$$$ 'a' in d1
True
$$$ 'c' in d1
False
"""
...
if __name__ == '__main__':
import apl1test
apl1test.testmod('dicotrie.py')
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
:mod:`mesures` module : un module pour les mesures de temps
:author: `FIL - Faculté des Sciences et Technologies -
Univ. Lille <http://portail.fil.univ-lille1.fr>`_
:date: 2024 février
"""
from dicotrie import DicoTrie
from association import Association
from types import NoneType
from timeit import timeit
from random import randrange
import matplotlib.pyplot as plt
def generation_dict(tailles: list[int]) -> list[dict[str, NoneType]]:
"""Renvoie une liste de dictionnaires dont les clés sont les
représentations des n entiers compris entre 0 et n-1 et les valeurs
associées None pour chaque entier n dans la liste tailles.
Précondition : tous les entiers de tailles sont positifs ou nuls
$$$ generation_dict([0, 2, 4])
[{}, {'0': None, '1':None}, {'0': None, '1': None, '2': None, '3': None}]
"""
...
def generation_dicotrie(tailles: list[int]) -> list[DicoTrie]:
"""Renvoie une liste de DicoTrie dont les clés sont les représentations
des n entiers compris entre 0 et n-1 et les valeurs associées None pour
chaque entier n dans la liste tailles.
Précondition : tous les entiers de tailles sont positifs ou nuls
$$$ generation_dicotrie([0, 2])
[DicoTrie([]), DicoTrie([Association('0', None), Association('1', None)])]
"""
...
def mesure_temps_acces(taille : int, d: dict[str, NoneType] | DicoTrie) -> float:
"""Renvoie le temps moyen mis pour accéder à 1000 éléments quelconques
du dictionnaire d.
Précondition : les clés de d sont les représentations des entiers
compris entre 0 et taille - 1.
"""
cles_a_tester = [str(randrange(taille)) for _ in range(1000)]
stmt = "all(d[cle] == None for cle in cles_a_tester)"
return timeit(stmt = stmt, globals = locals(), number = 1) / 1000
def mesures_temps_acces_dict(tailles: list[int]) -> list[float]:
"""Renvoie les listes des temps moyens pour accéder à 1000 éléments quelconques
de chacun des dictionnaires dont les clés sont les remprésentations des
n entiers compris entre 1 et n-1 pour chaque entier n dans la liste
tailles.
Précondition : tous les entiers de tailles sont positifs ou nuls
"""
...
def mesures_temps_acces_dicotrie(tailles: list[int]) -> list[float]:
"""Renvoie les listes des temps moyens pour accéder à 1000 éléments quelconques
de chacun des DicoTrie dont les clés sont les remprésentations des
n entiers compris entre 1 et n-1 pour chaque entier n dans la liste
tailles.
Précondition : tous les entiers de tailles sont positifs ou nuls
"""
...
if __name__ == '__main__':
import apl1test
apl1test.testmod('mesures.py')
# Écrivez ici le code permettant de faire des hypothèses sur la
# vitesse d'accès aux dictionnaires.
# linéaire
# tailles = list(range(0, 100000, 1000)
# temps_dict = mesures_temps_acces_dict(tailles)
# temps_dicotrie = mesures_temps_acces_dicotrie(tailles)
# plt.plot(tailles, temps_dict, '+')
# plt.plot(tailles, temps_dicotrie, '.')
# plt.show()
# log
# tailles = [2**n for n in range(16)]
# temps_dict = mesures_temps_acces_dict(tailles)
# temps_dicotrie = mesures_temps_acces_dicotrie(tailles)
# plt.plot(range(16), temps_dict, '+')
# plt.plot(range(16), temps_dicotrie, '.')
# plt.show()
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
:mod:`recherches` module : un module pour les recherches
:author: `FIL - Faculté des Sciences et Technologies -
Univ. Lille <http://portail.fil.univ-lille1.fr>`_
:date: 2024 février
"""
from typing import TypeVar, Callable
from types import NoneType
# On définit un type générique :
C = TypeVar('C')
def indice_seq(elem: C, liste: list[C], comp: Callable[[C, C], int]) \
-> tuple[bool, int]:
"""Renvoie un couple (trouve, i) tel que:
- si elem est un élément de liste,
* trouve = True
* i est l'indice de première occurence de elem dans liste
- si elem n'est pas un élément de la liste : * trouve = False
* i = len(liste)
Précondition : comp est une fonction de comparaison sur C
$$$ def compare(x, y): return 0 if x == y else 1 if x > y else -1
$$$ indice_seq(0, [1, 3, 5], compare)
(False, 3)
$$$ indice_seq(3, [1, 3, 5], compare)
(True, 1)
$$$ indice_seq(4, [1, 3, 5], compare)
(False, 3)
$$$ indice_seq(5, [1, 3, 5], compare)
(True, 2)
$$$ indice_seq(6, [1, 3, 5], compare)
(False, 3)
$$$ indice_seq(42, [], compare)
(False, 0)
"""
...
def indice_dicho(elem: C, liste: list[C], comp: Callable[[C, C], int]) \
-> tuple[bool, int]:
"""Renvoie un couple (trouve, i) tel que:
- si elem est un élément de liste,
* trouve = True
* i est l'indice de première occurence de elem dans liste
- si elem n'est pas un élément de la liste :
* trouve = False
* pour tout j < i, liste[j] < liste[i]
* pour tout j > i, liste[j] > liste[i]
Précondition : comp est une fonction de comparaison et liste est triée pour comp
$$$ def compare(x, y): return 0 if x == y else 1 if x > y else -1
$$$ indice_dicho(0, [1, 3, 5], compare)
(False, 0)
$$$ indice_dicho(3, [1, 3, 5], compare)
(True, 1)
$$$ indice_dicho(4, [1, 3, 5], compare)
(False, 2)
$$$ indice_dicho(5, [1, 3, 5], compare)
(True, 2)
$$$ indice_dicho(6, [1, 3, 5], compare)
(False, 3)
$$$ indice_dicho(42, [], compare)
(False, 0)
"""
...
def inserer(indice: int, elem: C, liste: list[C]) -> NoneType:
"""Insère l'élément elem à l'indice indice de la liste liste.
Précondition : 0 ≤ indice ≤ len(liste)
$$$ l = [1, 3, 5]
$$$ inserer(0, 0, l)
$$$ l
[0, 1, 3, 5]
$$$ inserer(4, 6, l)
$$$ l
[0, 1, 3, 5, 6]
$$$ inserer(3, 4, l)
$$$ l
[0, 1, 3, 4, 5, 6]
$$$ vide = []
$$$ inserer(0, 42, vide)
$$$ vide
[42]
"""
...
if __name__ == '__main__':
import apl1test
apl1test.testmod('recherches.py')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment