Les nombres ci-dessus, disposés géométriquement en triangle vous rappellent probablement quelques choses…
Ils s’agit des coefficients binomiaux que l’on obtient en développement des expressions du genre (a+b)2=1a2+2ab+1b2
Dans cet disposition géométrique chacun des nombres s’obtient en ajoutant le nombre du dessus et son voisin de gauche.
Ces nombres nous les avons déjà évoqués ici, il s’agit des C(n,p) qui servent à dénombrer le nombres de parties à p éléments d’un ensemble à n éléments.
(Par exemple on a vu dans ce billet que C(52,5)=2 598 960 nous donne le nombres de mains au poker)
On démontre aisément que C(n,p) = C (n-1,p-1) + C (n-1, p), et on peut utiliser cette formule pour se créer une fonction en Python pour calculer de façon récursive les C(n,p)
def cnp2 (n,p): if p==0 or n==p: return 1
exit return cnp2(n-1,p-1)+cnp2(n-1,p)
Je ne suis pas passionné de généalogie, mais je m’intéresse à la façon de numéroter ses ancêtres (Le côté mathématique de la chose).
Ainsi à la trentième génération vous avez plus de cinq cents millions d’aïeuls !
Les généalogistes utilisent pour leur associer un code différents à chacun, la méthode SOSA :
La personne dont on dresse l’ascendance porte le numéro 1. Son père porte le numéro 2 et sa mère le numéro 3. Ainsi on associe toujours au père le double du code de l’enfant, et à la mère le code du père augmenté de 1.
Ainsi à part la première personne qui peut-être un homme ou une femme, chaque individu de code pair est un homme et chaque individu de code impair est une femme.
Le problème c’est qu’un nombre est peu parlant. Qui est l’ancêtre numéro 54 ?
J’ai développé une petite application en Python qui nous en dit plus !
Cette application vous permet de trouver également le code SOSA du père de la mère du grand-père d’un individu :
# -*- coding: UTF-8 -*-#Wouf 16/12/2018# Autour du SOSA#Fonctions principales chaine() et sosa()def chaine(n):
""" n est un entier (code SOSA) la fonction renvoie une chaîne
formée de M et P""" if n==1:
return"" else:
if n%2==0:
return"P" +chaine(n//2)
else:
return"M" +chaine((n-1)//2)
def sosa(chaine):
""" renvoie le SOSA d'une chaine de la forme PPM
pour le père du père de la mère"""
code=1
for lettre in chaine[::-1]:
code*=2
if lettre=="M" :
code+=1
return code
#Fonctions entrée/sortie : ecrire() et francais()def ecrire():
q="""Entrez un code SOSA (entier)
ou une chaine formée de P et de M (pour père/mère)
(Entrée pour quitter)
""" print(q)
reponse=input("> " ).upper()
print()
nb=set("0123456789" )
digit=set("PM" )
if reponse=="" or reponse=="0" :
return False
elif set(reponse) <= nb:
print(chaine(int(reponse)))
print(francais(chaine(int(reponse))))
return True
elif set(reponse)<= digit:
print("Le code SOSA est " ,sosa(reponse))
print(francais(reponse))
return True
else:
returnFalse#pour quitter l'applidef francais(chaine):
"""Reçois une chaine genre PPMPM et la traduit en français"""
arriere_grand_parent=len(chaine)//3
reste=len(chaine)%3
grand_parent=reste//2
parent=reste%2
reponse="" for i in range(arriere_grand_parent):
if i==0:
if chaine[0]=="P" :
reponse="L'arrière grand-père" else:
reponse="L'arrière grand-mère" else:
if chaine[i*3]=="P" :
reponse+=" de l'arrière grand-père" else:
reponse+=" de l'arrière grand-mère" for i in range(grand_parent):
if arriere_grand_parent==0 and i==0:
if chaine[0]=="P" :
reponse="Le grand-père" else:
reponse="La grand-mère" else:
if chaine[arriere_grand_parent*3+i*2]=="P" :
reponse+=" du grand-père" else:
reponse+=" de la grand-mère" for i in range(parent):
if arriere_grand_parent==0 and grand_parent==0 and i==0:
if chaine[0]=="P" :
reponse="Le père" else:
reponse="La mère" else:
if chaine[arriere_grand_parent*3+grand_parent*2+i]=="P" :
reponse+=" du père" else:
reponse+=" de la mère" if chaine=="" :
reponse="L'individu" else:
reponse+=" de l'individu"
reponse+="\n Génération :" +str(len(chaine))+"\n ______________________________" return reponse
#__________________________________________ le corps du progif ecrire():
print()
while ecrire():
print()
Les statistiques de fréquentation d’un blog peuvent être surprenantes. Ainsi vous êtes nombreux à arriver ici en faisant une recherche sur la fonction yield de Python.
Pour la comprendre, il faut d’abord savoir ce qu’est un générateur. Pour simplifier un générateur est une fonction qui retourne successivement plusieurs valeurs. Non pas en utilisant le mot réservé RETURN, mais en utilisant YIELD.
L’ambiguïté qu’il faut signaler est que dans le langage courant, on confond souvent la fonction et l’objet généré.
Dans l’exemple suivant, la fonction CouleurIterateur (), qui émule un feu tricolore, renvoie à chaque fois que l’on rencontre YIELD, successivement : Vert, Orange et Rouge
# Exemple d’utilisation de yield
# Wouf 2008
def CouleurIterateur ():
while 1: #Une boucle infinie
for i in (‘Vert’,‘Orange’,‘Rouge’):
yield i
# A chaque instruction yield
# rencontrée l’execution
# s’arrête, la fonction
# renvoie i.
# L’execution reprendra
# Au prochain next()
couleur=CouleurIterateur()
for i inrange(10) :
print couleur.next()
Dans le corps du programme l’instruction couleur=CouleurIterateur() crée un objet itérateur qui bénéficie, et c’est là l’intérêt de YIELD de la popriété next():
La première fois que le programme rencontre couleur.next(), il va exécuter la fonction CouleurIterateur () jusqu’à rencontrer YIELD, il va à ce moment là geler l’exécution de la fonction et retourner la valeur de i (Soit : Vert)
La seconde fois, et les fois suivante où le programme rencontrera couleur.next() (Il y a dix itérations dans cet exemple) , c’est pareil, il exécutera le code jusqu’à YIELD, gèlera l’exécution, et renverra la valeur de i.
La qualité numéro 1 du langage de programmation Python est son accessibilité, même pour les débutants. Le code est lisible, compréhensible rapidement. Python est LE langage par excellence pour apprendre à programmer.
Si vous ne l’avez pas encore installer sur votre système, je vous engage fortement à le faire à partir du site officiel.
L’exemple de script que nous allons étudier aujourd’hui est basé sur une fonction crée par l’utilisateur, qui inverse une chaîne de caractère. Elle renverra par exemple TOM si on lui envoie MOT.
def envers (mot):
"inverse une chaine de caractères"
resultat="" # La chaine résultat est videfor lettre in mot: # Pour chaque lettre de la chaine
resultat=lettre+resultat # On l'insère en première positionreturn resultat # Et on retourne la chaine# Pour tester dans L'IDLE
a=input("chaine : " )
print (envers(a))
Le rouge sert à afficher les commentaires, ceux-ci sont précédés du caractère #.Les commentaires ne sont pas des instructions exécutées par Python, mais sont destinés à la compréhension du code (Pour permettre de se replonger dans ses anciens scripts, sans risquer de maux de tête, par exemple)
En orange : les mots réservés du langage Python ici nous avons def, for, in et return
En violet : les fonctions prédéfinies (non créées par l’utilisateur ) seule la fonction input() est utilisée dans ce script.
En bleu : Les fonctions crées par l’utilisateur Ici une seule fonction : envers()
En vert : Les chaînes de caractères. On en dénombre 3, dans des contextes très différents.
Une remarque importante, les espaces dans le code ont une importance capitale (On parle d’indentation du code), ainsi le bloc de code qui constitue le corps de la fonction envers est décalé de deux espaces vers la droite. Ainsi Python reconnaît la fin des instructions de cette fonction à l’arrêt de cette indentation.
Le mot clef def sert à définir notre propre fonction, il est suivi du nom de cette fonction (Ne pas utiliser de mots réservés ou de nom de fonctions prédéfinies!) puis de parenthèses enserrant une « variable » est du caractère « : »
def envers (mot):
On peut voir une fonction comme une usine, elle reçoit une matière première (ici une chaîne de caractère), effectue un travail (dans le bloc indenté) et livre (avec le mot clef return) un produit fini (ici, une autre chaîne de caractère)
« inverse une chaîne de caractères »
Cette ligne est étrange, c’est une chaîne de caractères, seule, sans mot clefs qui demanderait à Python de faire quelque chose, sans affectation (On y reviendra). Elle semble ne servir à rien… Et pourtant son rôle est très pratique ! Si cette fonction est chargée en mémoire, en tapant envers ( avec une parenthèse ouvrante, cette phrase apparaît dans une bulle d’aide :
resultat=« » On définit au départ la variable resultat comme une chaîne vide. A noter pour les vrais débutants en développement, le sens particulier du signe égal. Ce caractère est le symbole de l’affectation. On range la chaîne vide « » dans une « boite » qu’on a appelé resultat. Le contenue de cette boite changera au cours du script, cette boite est une variable.
for lettre in mot:
littéralement : Pour lettre dans mot
mot est la matière première livrée à la fonction envers, une chaîne de caractères. Une chaîne de caractères étant constituée de lettres, l’expression for lettre in mot signifie que l’on va successivement affecter à la variable lettre les lettres contenues dans la chaîne mot (celle envoyée à la fonction).
Les deux points qui suivent, ainsi que l’indentation du code indique à Python que ce bloc indenté devra être exécuter pour chacune de ces lettres.
resultat=lettre+resultat
On reconnaît à nouveau ce signe égal d’affectation. On va placer dans le membre de gauche (la variable resultat) l’évaluation de l’expression lettre + resultat. Je comprends l’étonnement de certain ! lettre est un caractère et resultat une chaîne ! Que signifie donc le signe + ? Python comprend simplement +, pour des chaîne de caractère comme un ordre de concaténation :
« abc »+ »def »= »abcdef »
Un exemple de ce qui se passe dans ce programme: Supposons qu’on ait envoyé à la fonction envers, la chaîne « CHAT »
resultat est d’abord vide (resultat= » ») puis la boucle FOR IN parcourt les lettres de CHAT 1. resultat= »C »+ » » soit « C » 2. resultat = »H »+ »C » soit « HC » 3. resultat = »A » + »HC » soit « AHC » 4. resultat = »T » + »AHC » soit « TAHC »
la variable resultat contient donc une fois toutes les itérations de la boucles terminées, la chaîne de départ inversée.
Et l’usine envers() peut donc livrer son produit fini:
return resultat
La dernière partie du script, sert à tester la fonction:
a=input(« chaine : « )
input() est une fonction prédéfinie, son utilisation est aisée. On range dans la variable a, la chaîne de caractères saisie au clavier par l’utilisateur. Notez entre parenthèses une phrase d’invite pour lui indiquer ce qu’il doit faire.
print(envers(a))
Le mot réservé print
affiche à l’écran envers(a), le produit de la fonction envers quand on lui envoie la variable a.
Une photo de Python pour vous parler du langage de développement Python, c’est une erreur…
Le nom Python ne viendrait pas du nom d’un reptile mais du Monty Python Flying Circus, un groupe de comiques complètement déjantés qui ont sévis sur la BBC dans les années 60-70.
Van Rossum le principal auteur de Python, est qualifié de « Dictateur bienveillant à vie », cela reste dans l’esprit des Monty Python!
J’ai déjà aborder ici, ce langage étonnant à diverses occasions, et ne cesse de répéter que ce Python est fantastique, pour paraphraser un ouvrage de référence.
Je vous propose aujourd’hui un script que je viens de terminer (en beta) qui traduit un script Python en HTML :
En mathématiques, la notion de permutation correspond simplement à un changement d’ordre des objets d’un ensemble (ordonné).
Si on considère par exemple les anagrammes du mot LOSANGE, on se pose la question de savoir combien de mots (pas au sens littéraire, ces suites de lettres n’ont pas besoin d’avoir un sens) on peut écrire avec les lettres :
L-O-S-A-N-G-E .
Les lettres étant toutes différentes, on parle de permutation sans répétition, et le nombre de ces permutations est la factorielle du nombre d’objet (ici, ce sont des lettres).
soit : 7!= 5040
(Vérification avec le programme Python évoqué ici)
Par contre dans le mot MESSAGES, la lettre E apparaît deux fois, tandis que le S apparaît 3 fois. On parle alors de permutation avec répétition. Pour les dénombrer, on divise la factorielle du nombres d’objet (8!) par le produit des factorielles de deux et de trois (le nombre d’apparition des objets « répétés »):
On trouve : 8!/(2!x3!) = 40320 / 12 = 3360
On peut résumer la méthode à employer pour dénombrer les permutations avec répétitions :
– On compte le nombre d’objet (lettres). CHERCHEREZ est écrit avec 10 lettres.
– On se construit un petit tableau avec les objets répétés:
Objets : nombre de répétitions
C : 2
H : 2
E : 3
R : 2
Le nombre de permutation de CHERCHEREZ est 10! / (2! x 2! x 3! x 2!) = 10! / 48 =75600
Cette méthode algorithmique nous incite à développer un petit programme qui affichera le nombre d’anagrammes d’un mot entré au clavier par l’utilisateur. (Non plus en les listant comme dans l’exemple étudié la dernière fois mais en calculant )
def fact(n):
"renvoie la factorielle de n"
if n==1: return 1
else : return n*fact(n-1)
mot=raw_input("Entrez votre mot (ENTREE pour quitter) : ")
while mot&lt;&gt;"":
lettre={}
a=0
while(a1:
denominateur=denominateur*fact(a)
chaine=chaine + str(a) +"!"if chaine&lt;&gt;"" : chaine = "/(" + chaine + ")"
print len(mot),"!",chaine,"=",fact(len(mot)),"/",denominateur,
print "=",fact(len(mot))/denominateur
print "Le nombre d'anagrammes de ",mot," est : ",fact(len(mot))/denominateur
print
print
mot=raw_input("un autre mot ? (ENTREE pour quitter) : ")
Combien ananas a-il d’anagrammes ? Si toutes les lettres étaient différentes on répondrait sans hésiter factorielle de 6 (6!=720) mais les 3 A et les deux N nous obligent à réfléchir davantage…
Pour le doublons N (Nous avons étudier ce cas précédemment) il suffira de diviser par 2… Mais pour les 3A ? L’erreur commune (et attendue) est la division par 3 (donc par 3 fois 2, soit par 6 pour trouver en fin de compte 120=5!)
Réfléchissons mieux 😉
Nos 3 A que l’on pourrait baptiser A1, A2 et A3 ont combien de façons de s’agencer les uns par rapports aux autres ?
A1 A2 A3
A1 A3 A2
A2…
Nous avons déjà étudié ce problème c’est le nombre de permutation d’un ensemble à 3 éléments ! Il ya 3!=6 façons de permuter nos 3.
Et tout se tient ! Il y avait effectivement 2!=2 façons de permuter nos N
La réponse au problème est maintenant limpide :
Il y a 60 anagrammes à ANANAS
Il peut arriver de douter de son raisonnement et le développement d’un petit programme en Python peut nous conforter :
1 : a a a s n n 2 : a a a n s n 3 : a a a n n s 4 : a a s a n n 5 : a a s n a n 6 : a a s n n a 7 : a a n a s n 8 : a a n a n s 9 : a a n s a n 10 : a a n s n a 11 : a a n n a s 12 : a a n n s a 13 : a s a a n n 14 : a s a n a n 15 : a s a n n a 16 : a s n a a n 17 : a s n a n a 18 : a s n n a a 19 : a n a a s n 20 : a n a a n s 21 : a n a s a n 22 : a n a s n a 23 : a n a n a s 24 : a n a n s a 25 : a n s a a n 26 : a n s a n a 27 : a n s n a a 28 : a n n a a s 29 : a n n a s a 30 : a n n s a a 31 : s a a a n n 32 : s a a n a n 33 : s a a n n a 34 : s a n a a n 35 : s a n a n a 36 : s a n n a a 37 : s n a a a n 38 : s n a a n a 39 : s n a n a a 40 : s n n a a a 41 : n a a a s n 42 : n a a a n s 43 : n a a s a n 44 : n a a s n a 45 : n a a n a s 46 : n a a n s a 47 : n a s a a n 48 : n a s a n a 49 : n a s n a a 50 : n a n a a s 51 : n a n a s a 52 : n a n s a a 53 : n s a a a n 54 : n s a a n a 55 : n s a n a a 56 : n s n a a a 57 : n n a a a s 58 : n n a a s a 59 : n n a s a a 60 : n n s a a a