From bd10478bb230df65dad6b24d0f3ebf446af7677d Mon Sep 17 00:00:00 2001
From: Dahmane Lynda <lynda.dahmane.etu@118p28.fil.univ-lille.fr>
Date: Wed, 21 Feb 2024 11:48:19 +0100
Subject: [PATCH] Tp6

---
 Tp6/associations.zip              | Bin 0 -> 6090 bytes
 Tp6/associations/ap_decorators.py | 135 ++++++++++++++++++++++++++++++
 Tp6/associations/apl1test.py      |  89 ++++++++++++++++++++
 Tp6/associations/association.py   |  89 ++++++++++++++++++++
 Tp6/associations/dicotrie.py      |  98 ++++++++++++++++++++++
 Tp6/associations/mesures.py       |  98 ++++++++++++++++++++++
 Tp6/associations/recherches.py    | 117 ++++++++++++++++++++++++++
 7 files changed, 626 insertions(+)
 create mode 100644 Tp6/associations.zip
 create mode 100644 Tp6/associations/ap_decorators.py
 create mode 100644 Tp6/associations/apl1test.py
 create mode 100755 Tp6/associations/association.py
 create mode 100755 Tp6/associations/dicotrie.py
 create mode 100644 Tp6/associations/mesures.py
 create mode 100755 Tp6/associations/recherches.py

diff --git a/Tp6/associations.zip b/Tp6/associations.zip
new file mode 100644
index 0000000000000000000000000000000000000000..d0bdeb1d8c6796026cdf8a32e602d3c46f493c16
GIT binary patch
literal 6090
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

literal 0
HcmV?d00001

diff --git a/Tp6/associations/ap_decorators.py b/Tp6/associations/ap_decorators.py
new file mode 100644
index 0000000..5f4adc9
--- /dev/null
+++ b/Tp6/associations/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/Tp6/associations/apl1test.py b/Tp6/associations/apl1test.py
new file mode 100644
index 0000000..8533cca
--- /dev/null
+++ b/Tp6/associations/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/Tp6/associations/association.py b/Tp6/associations/association.py
new file mode 100755
index 0000000..179219e
--- /dev/null
+++ b/Tp6/associations/association.py
@@ -0,0 +1,89 @@
+#!/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
+        """
+        self.cle=cle
+        self.valeur=valeur
+
+    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])'
+        """
+        return f"Association{(self.cle,self.valeur)}"
+
+    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
+        $$$ AssertionError('a', 1) == ('a', 1)
+        False
+        """
+        if isinstance(autre,Association):
+            return self.cle==autre.cle and self.valeur==autre.valeur
+        return 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 a1.cle==a2.cle:
+        return 0
+    elif a1.cle< a2.cle:
+        return -1
+    else:
+        return 1
+
+if __name__ == '__main__':
+    import apl1test
+    apl1test.testmod('association.py')
+
diff --git a/Tp6/associations/dicotrie.py b/Tp6/associations/dicotrie.py
new file mode 100755
index 0000000..b863fbb
--- /dev/null
+++ b/Tp6/associations/dicotrie.py
@@ -0,0 +1,98 @@
+#!/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]):
+        """
+        """
+        self.liste_assos=liste_assos
+
+    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')
+
diff --git a/Tp6/associations/mesures.py b/Tp6/associations/mesures.py
new file mode 100644
index 0000000..ae603e7
--- /dev/null
+++ b/Tp6/associations/mesures.py
@@ -0,0 +1,98 @@
+#!/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()
+    
+
diff --git a/Tp6/associations/recherches.py b/Tp6/associations/recherches.py
new file mode 100755
index 0000000..fa01a60
--- /dev/null
+++ b/Tp6/associations/recherches.py
@@ -0,0 +1,117 @@
+#!/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)
+    """
+    trouve=False
+    i=len(liste)
+    
+    for index, element in enumerate(liste):
+        if comp(elem,element)==0:
+            trouve=True
+            i=index
+            
+    return trouve,i
+# 
+# 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 indice==len(liste):
+        liste.append(elem)
+    else:
+        liste.append(None)
+        for i in range (len(liste)-1, indice, -1):
+            liste[i]=liste[i-1]
+        liste[indice]=elem
+
+        
+if __name__ == '__main__':
+    import apl1test
+    apl1test.testmod('recherches.py')
+
-- 
GitLab