Le calcul symbolique (parfois appelé calcul formel) permet de travailler sur des formules mathématiques dotées de variables et de réaliser des calculs sur ses formules sans forcément affecter une valeur aux variables. Les exemples les plus parlant sont, pour une fonction $f(x)$ donnée, de calculer sa dérivée, son intégrale ou la limite de la fonction.
Python propose le package sympy (symbolic mathematics) qui permet de faire du calcul symbolique.
Voici quelques exemples d'utilisation de sympy :
Fonction f(x):
3 2
x + 2⋅x + 3⋅x + 4
Derivée f'(x):
2
3⋅x + 4⋅x + 3
Fonction f(x):
1
─
x
Limite de f(x) lorsque x tend vers l'infini:
0
Fonction f(x):
3⋅x - 5
Valeur de f(x) pour x = 1/2 :
-3.50000000000000
Le jeu Nerdle consiste à résoudre un casse-tête basé sur des nombres.
On dispose de 8 cases à remplir avec des symboles (chiffres, opérateurs et symbol '=') de manière à générer une formule correcte. Par exemple 54/9-4=2.
Le but du jeu consiste à découvrir la formule cachée en 6 coups maximum.
Pour gagner en jouant à Nerdle il suffit de commencer par saisir les formules suivantes :
En effet, ces deux formules permettent de déterminer :
On considère que la formule cachée connue de Nerdle est la formule précédente (54/9-4=2). On imagine que le joueur a pu déterminer :
Exercice 12.1
On vous demande d'écrire un programme Python nommé
Pour cela, vous devez fournir en paramètres du programme :
La notation "2|1|1" signifie que $x$ comporte deux chiffres, que $y$ et $z$ ne comportent qu'un seul chiffre. Cela implique que l'on fera varier $x$ dans l'intervalle $[0-99]$, $y$ et $z$ quant à eux varieront dans l'intervalle $[0-9]$.
Afin d'évaluer la formule, il faudra la transformer pour vérifier qu'elle est égale à 0. Pour cela on modifie la formule initiale en "x/y-z=2" en "x/y-z-(2)" :
expression = sp.sympify(expression.replace("=", "-(") + ")")
Testez votre programme avec :
\$ python3 assistant_nerdle.py "x/y-z=2" "2|1|1"
Vous devriez obtenir 90 solutions :
ces premières solutions ne sont pas valides car x ne comporte qu'un chiffre
cela sera corrigé dans la version améliorée
{'x': 2, 'y': 1, 'z': 0}
{'x': 3, 'y': 1, 'z': 1}
{'x': 4, 'y': 1, 'z': 2}
{'x': 4, 'y': 2, 'z': 0}
{'x': 5, 'y': 1, 'z': 3}
{'x': 6, 'y': 1, 'z': 4}
{'x': 6, 'y': 2, 'z': 1}
{'x': 6, 'y': 3, 'z': 0}
{'x': 7, 'y': 1, 'z': 5}
{'x': 8, 'y': 1, 'z': 6}
{'x': 8, 'y': 2, 'z': 2}
{'x': 8, 'y': 4, 'z': 0}
{'x': 9, 'y': 1, 'z': 7}
{'x': 9, 'y': 3, 'z': 1}
{'x': 10, 'y': 1, 'z': 8}
{'x': 10, 'y': 2, 'z': 3}
{'x': 10, 'y': 5, 'z': 0}
{'x': 11, 'y': 1, 'z': 9}
{'x': 12, 'y': 2, 'z': 4}
{'x': 12, 'y': 3, 'z': 2}
{'x': 12, 'y': 4, 'z': 1}
{'x': 12, 'y': 6, 'z': 0}
{'x': 14, 'y': 2, 'z': 5}
{'x': 14, 'y': 7, 'z': 0}
{'x': 15, 'y': 3, 'z': 3}
{'x': 15, 'y': 5, 'z': 1}
{'x': 16, 'y': 2, 'z': 6}
{'x': 16, 'y': 4, 'z': 2}
{'x': 16, 'y': 8, 'z': 0}
{'x': 18, 'y': 2, 'z': 7}
{'x': 18, 'y': 3, 'z': 4}
{'x': 18, 'y': 6, 'z': 1}
{'x': 18, 'y': 9, 'z': 0}
{'x': 20, 'y': 2, 'z': 8}
{'x': 20, 'y': 4, 'z': 3}
{'x': 20, 'y': 5, 'z': 2}
{'x': 21, 'y': 3, 'z': 5}
{'x': 21, 'y': 7, 'z': 1}
{'x': 22, 'y': 2, 'z': 9}
{'x': 24, 'y': 3, 'z': 6}
{'x': 24, 'y': 4, 'z': 4}
{'x': 24, 'y': 6, 'z': 2}
{'x': 24, 'y': 8, 'z': 1}
{'x': 25, 'y': 5, 'z': 3}
{'x': 27, 'y': 3, 'z': 7}
{'x': 27, 'y': 9, 'z': 1}
{'x': 28, 'y': 4, 'z': 5}
{'x': 28, 'y': 7, 'z': 2}
{'x': 30, 'y': 3, 'z': 8}
{'x': 30, 'y': 5, 'z': 4}
{'x': 30, 'y': 6, 'z': 3}
{'x': 32, 'y': 4, 'z': 6}
{'x': 32, 'y': 8, 'z': 2}
{'x': 33, 'y': 3, 'z': 9}
{'x': 35, 'y': 5, 'z': 5}
{'x': 35, 'y': 7, 'z': 3}
{'x': 36, 'y': 4, 'z': 7}
{'x': 36, 'y': 6, 'z': 4}
{'x': 36, 'y': 9, 'z': 2}
{'x': 40, 'y': 4, 'z': 8}
{'x': 40, 'y': 5, 'z': 6}
{'x': 40, 'y': 8, 'z': 3}
{'x': 42, 'y': 6, 'z': 5}
{'x': 42, 'y': 7, 'z': 4}
{'x': 44, 'y': 4, 'z': 9}
{'x': 45, 'y': 5, 'z': 7}
{'x': 45, 'y': 9, 'z': 3}
{'x': 48, 'y': 6, 'z': 6}
{'x': 48, 'y': 8, 'z': 4}
{'x': 49, 'y': 7, 'z': 5}
{'x': 50, 'y': 5, 'z': 8}
{'x': 54, 'y': 6, 'z': 7}
{'x': 54, 'y': 9, 'z': 4}
{'x': 55, 'y': 5, 'z': 9}
{'x': 56, 'y': 7, 'z': 6}
{'x': 56, 'y': 8, 'z': 5}
{'x': 60, 'y': 6, 'z': 8}
{'x': 63, 'y': 7, 'z': 7}
{'x': 63, 'y': 9, 'z': 5}
{'x': 64, 'y': 8, 'z': 6}
{'x': 66, 'y': 6, 'z': 9}
{'x': 70, 'y': 7, 'z': 8}
{'x': 72, 'y': 8, 'z': 7}
{'x': 72, 'y': 9, 'z': 6}
{'x': 77, 'y': 7, 'z': 9}
{'x': 80, 'y': 8, 'z': 8}
{'x': 81, 'y': 9, 'z': 7}
{'x': 88, 'y': 8, 'z': 9}
{'x': 90, 'y': 9, 'z': 8}
{'x': 99, 'y': 9, 'z': 9}
il y a 90 solutions
Exercice 12.2
Dans un second temps, on modifiera le programme précédent afin d'introduire un troisième paramètre qui indique la forme de $x$, $y$ et $z$, comme par exemple "5.|.|."
Où ici, "5.|.|." indique que $x$ commence par $5$ et est suivi d'un chiffre (compris entre 0 et 9) et que $y$ et $z$ sont composés d'un chiffre quelconque.
Modifiez le programme comme suit :
Testez votre programme modifié avec les alternatives suivantes, vous devriez obtenir les résultats indiqués :
\$ python3 assistant_nerdle.py "x/y-z=2" "2|1|1" "5.|.|."
il y a 90 solution(s)
il y a 6 solution(s) après filtrage
{'x': 50, 'y': 5, 'z': 8}
{'x': 54, 'y': 6, 'z': 7}
{'x': 54, 'y': 9, 'z': 4}
{'x': 55, 'y': 5, 'z': 9}
{'x': 56, 'y': 7, 'z': 6}
{'x': 56, 'y': 8, 'z': 5}
\$ python3 assistant_nerdle.py "x/y-z=2" "2|1|1" "7.|.|."
il y a 90 solution(s)
il y a 4 solution(s) après filtrage
{'x': 70, 'y': 7, 'z': 8}
{'x': 72, 'y': 8, 'z': 7}
{'x': 72, 'y': 9, 'z': 6}
{'x': 77, 'y': 7, 'z': 9}
\$ python3 assistant_nerdle.py "x/y-z=2" "2|1|1" "5.|6|."
il y a 90 solution(s)
il y a 1 solution(s) après filtrage
{'x': 54, 'y': 6, 'z': 7}