CC-251003 Science des données

Notebook originel: cc251003_magic.ipynb

CC-251003 Science des données🔗

Date: 03 octobre 2025
Durée: 1 h

Consignes🔗

Créez un répertoire CC251003_Nom_Prenom/ dans lequel vous travaillerez, et où sera stocké le package python en développement, selon les instructions ci-dessous.

Vous devez alors mettre ce répertoire sous contrôle git sur un projet dédié sur le serveur https://gitlab.in2p3.fr, et en transmettre l’adresse à y.copin@ipnl.in2p3.fr.

Si, par manque de temps ou de connaissance, vous ne pouvez pas créer un dépôt git, envoyez par mail la distribution source du package voir ci-dessous) à y.copin@ipnl.in2p3.fr (cette solution sera pénalisée dans la notation).

Dans tous les cas, vous devez envoyer quelque chose!

Carré magique🔗

Un carré magique d’ordre n est un tableau carré \(n × n\) dans lequel on écrit une et une seule fois les nombres entiers de 1 à \(n^2\), de sorte que la somme des n nombres de chaque ligne, colonne ou diagonale principale soit constante.

Pour les carrés magiques d’ordre impair, on dispose de l’algorithme suivant — (i,j) désignant la case de la ligne i, colonne j du carré, avec une indexation « naturelle » commençant à 1:

  • initialisation: la case \((n, (n + 1)/2)\) contient 1 ;

  • itération: si la case \((i, j)\) contient la valeur \(k\), alors on place la valeur \(k+1\) dans la case \((i + 1, j + 1)\) si cette case est vide, ou dans la case \((i - 1, j)\) sinon. On respecte la règle du carré « torique » (modulo n).

  1. Écrire une fonction empty_magic_square(n) qui retourne un tableau 2D (liste de listes) \(n×n\) de 0, en utilisant une double liste en compréhension.

[1]:
def empty_magic_square(n):
    """
    Retourne un tableau 2D (liste de listes) n×n de 0.

    Utiliser une double liste en compréhension.
    """

    return [[0]]
  1. Écrire une fonction init_magic_square(square) qui initialise l’algorithme en remplissant (sur place) la case 1 du tableau square (supposé être \(n×n\)), et en retournant les coordonnées de cette case (indexation à 1).

[2]:
def init_magic_square(square):
    """
    Initialise l'algorithme en remplissant (sur place) la case '1',
    et en retournant les coordonnées de la case (indexation à 1).

    square est supposé être un tableau n×n.
    """

    return 0, 0
  1. Écrire une fonction iterate_magic_square(square, i, j, k) qui itère l’algorithme en remplissant (sur place) la case \(k+1\) du tableau square (supposé être \(n×n\)), et en retournant les coordonnées de cette case (indexation à 1), en supposant que la case \(k\), de coordonnées \((i, j)\), est déjà remplie.

[3]:
def iterate_magic_square(square, i, j, k):
    """
    Itère l'algorithme en remplissant (sur place) la case 'k+1',
    et en retournant les coordonnées de la case (indexation à 1),
    en supposant que la case 'k', de coordonnées (i, j), est déjà remplie.

    square est supposé être un tableau n×n.
    """

    return 0, 0
  1. Écrire une fonction magic_square(n) qui implémente l’algorithme en retournant le carré magique d’ordre \(n\) (tableau \(n×n\)). Elle doit générer une exception AssertionError si l’ordre \(n\) n’est pas impair.

[4]:
def magic_square(n):
    """
    Implémentation de l'algo.

    * vérifier que l'ordre est impair (assert)
    * retourner le carré magique totalement rempli (tableau n×n)
    """

    return [[1]]
  1. Écrire une fonction str_magic_square(n) convertissant un carré magique en une chaîne de caractères correctement formattée, p.ex.

>>> print(str_magic_square(5))
11 18 25  2  9
10 12 19 21  3
 4  6 13 20 22
23  5  7 14 16
17 24  1  8 15
[5]:
def str_magic_square(square):
    """
    Retourne une représentation str du carré magique.

    Utiliser la méthode str.join pour construire la chaîne
    à partir des lignes et des cellules, et
    f"{val:>{m}d}" pour afficher l'entier val aligné
    à droite sur m caractères.
    """

    return "1"

Packaging🔗

  1. Créez un package magic_nom_prenom constitué du seul module magic.py incluant l’ensemble des fonctions précédemment définies (ne pas ajouter la section de tests), avec l’arborescence suivante:

    CC251003_Nom_Prenom/
    ├── magic_nom_prenom
    │   ├── magic.py
    │   └── __init__.py
    ├── pyproject.toml
    └── ...
    
  2. En utilisant les fonctions définies à la partie précédente, ajoutez un fichier __main__.py à votre package pour pouvoir exécuter:

    $ python -m magic 5
    11 18 25  2  9
    10 12 19 21  3
     4  6 13 20 22
    23  5  7 14 16
    17 24  1  8 15
    
  3. Ajoutez un point d’entrée magicsquare à votre package pour pouvoir exécuter:

    $ magicsquare 5
    11 18 25  2  9
    10 12 19 21  3
     4  6 13 20 22
    23  5  7 14 16
    17 24  1  8 15
    

    (Vous pouvez créer de nouvelles fonctions intermédiaires si nécessaire.)

  4. Finalement, commit/push toutes vos modifications sur votre répo central git, et envoyer l’adresse de ce répo à y.copin@ipnl.in2p3.fr.

    Si vous n’avez pas réussi à stocker votre package sous git, générer une distribution des sources de votre package avec la commande

    $ python -m build
    

    et envoyer l’archive correspondante (générée sous dist/) à y.copin@ipnl.in2p3.fr.

    Si vous n’avez pas non plus réussi à configurer votre package, générer manuellement une archive de votre package:

    $ tar cvzf CC251003_NOM_Prenom.tgz CC251003_NOM_Prenom/
    

    et envoyer le tarball.

[6]:
import unittest

class TestNotebook(unittest.TestCase):

    def test_01_empty(self):
        self.assertEqual(empty_magic_square(3), [[0] * 3] * 3)

    def test_02_init(self):
        sq = empty_magic_square(3)
        i, j = init_magic_square(sq)
        self.assertEqual((i, j), (3, 2))
        self.assertEqual(sq, [[0, 0, 0], [0, 0, 0], [0, 1, 0]])

    def test_03_iterate(self):
        sq = [[0, 0, 0], [0, 0, 0], [0, 1, 0]]
        i, j = iterate_magic_square(sq, 3, 2, 1)
        self.assertEqual((i, j), (1, 0))
        self.assertEqual(sq, [[0, 0, 2], [0, 0, 0], [0, 1, 0]])
        i, j = iterate_magic_square(sq, 1, 0, 2)
        self.assertEqual((i, j), (2, 1))
        self.assertEqual(sq, [[0, 0, 2], [3, 0, 0], [0, 1, 0]])

    def test_04_all(self):
        self.assertEqual(magic_square(3), [[4, 9, 2], [3, 5, 7], [8, 1, 6]])
        with self.assertRaises(AssertionError):
            magic_square(4)

    def test_05_str(self):
        self.assertEqual(
            str_magic_square(magic_square(3)),
            '4 9 2\n3 5 7\n8 1 6')
        self.assertEqual(
            str_magic_square(magic_square(5)),
            '11 18 25  2  9\n10 12 19 21  3\n 4  6 13 20 22\n23  5  7 14 16\n17 24  1  8 15')

unittest.main(argv=[''], verbosity=2, exit=False)
test_01_empty (__main__.TestNotebook) ... FAIL
test_02_init (__main__.TestNotebook) ... FAIL
test_03_iterate (__main__.TestNotebook) ... FAIL
test_04_all (__main__.TestNotebook) ... FAIL
test_05_str (__main__.TestNotebook) ... FAIL

======================================================================
FAIL: test_01_empty (__main__.TestNotebook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/ipykernel_568061/3897433415.py", line 6, in test_01_empty
    self.assertEqual(empty_magic_square(3), [[0] * 3] * 3)
AssertionError: Lists differ: [[0]] != [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

First differing element 0:
[0]
[0, 0, 0]

Second list contains 2 additional elements.
First extra element 1:
[0, 0, 0]

- [[0]]
+ [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

======================================================================
FAIL: test_02_init (__main__.TestNotebook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/ipykernel_568061/3897433415.py", line 11, in test_02_init
    self.assertEqual((i, j), (3, 2))
AssertionError: Tuples differ: (0, 0) != (3, 2)

First differing element 0:
0
3

- (0, 0)
+ (3, 2)

======================================================================
FAIL: test_03_iterate (__main__.TestNotebook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/ipykernel_568061/3897433415.py", line 17, in test_03_iterate
    self.assertEqual((i, j), (1, 0))
AssertionError: Tuples differ: (0, 0) != (1, 0)

First differing element 0:
0
1

- (0, 0)
?  ^

+ (1, 0)
?  ^


======================================================================
FAIL: test_04_all (__main__.TestNotebook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/ipykernel_568061/3897433415.py", line 24, in test_04_all
    self.assertEqual(magic_square(3), [[4, 9, 2], [3, 5, 7], [8, 1, 6]])
AssertionError: Lists differ: [[1]] != [[4, 9, 2], [3, 5, 7], [8, 1, 6]]

First differing element 0:
[1]
[4, 9, 2]

Second list contains 2 additional elements.
First extra element 1:
[3, 5, 7]

- [[1]]
+ [[4, 9, 2], [3, 5, 7], [8, 1, 6]]

======================================================================
FAIL: test_05_str (__main__.TestNotebook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/ipykernel_568061/3897433415.py", line 29, in test_05_str
    self.assertEqual(
AssertionError: '1' != '4 9 2\n3 5 7\n8 1 6'
- 1
+ 4 9 2
3 5 7
8 1 6


----------------------------------------------------------------------
Ran 5 tests in 0.005s

FAILED (failures=5)
[6]:
<unittest.main.TestProgram at 0x7f7ce98f3700>

Cette page a été générée à partir de cc251003_magic.ipynb.