informatique commune
Corrigé
Détection de cycles
Question 1.
def itere(f, x0):
lst = []
j, x = 0, x0
while not xin lst:
lst.append(x)
j += 1
x = f(x)
i = lst.index(x)
return (ji, i)
Le coût spatial est lié au calcul du tableau [x0,x1,...,xλ+µ1] ; c’est un Θ(λ+µ).
Si on admet que le coût de la méthode
append
est un
Θ
(1), le coût de cette fonction est principalement lié à la recherche
d’un élément dans le tableau. C’est une recherche de coût linéaire donc le coût temporel total de cette fonction est un
O((λ+µ)2).
Question 2. On montre sans peine que pour tout nN,yn=x2n. Mais :
x2n=xn(n>µet 2nnmod λ)(n>µet λdivise n)
donc l’algorithme de Floyd se termine et retourne le plus petit multiple de λqui soit supérieur ou égal à µ.
def floyd1(f, x0):
x, y = f(x0), f(f(x0))
while x != y:
x, y = f(x), f(f(y))
return x
def floyd2(f, x0):
i=1
x, y = f(x0), f(f(x0))
while x != y:
i += 1
x, y = f(x), f(f(y))
return i
La suite des itérés de
xi
est une suite périodique : sa pré-période est nulle et sa période égale à
λ
; la fonction
floyd2
appliquée à xiretourne donc la valeur de λ. D’où la fonction :
def periode(f, x0):
xi = floyd1(f, x0)
return floyd2(f, xi)
Puisque
i
est un multiple de
λ
on a
xi+µ
=
xµ
. Il sut donc pour trouver
µ
de comparer les suites des itérés de
x0
et de
xi
jusqu’à trouver une valeur commune.
def pre_periode(f, x0):
x, y = x0, floyd1(f, x0)
mu = 0
while x != y:
mu += 1
x, y = f(x), f(y)
return mu
page 1
Le coût spatial de chacune de ces fonctions est un
Θ
(1). Le coût temporel de l’algorithme de Floyd est un
Θ
(
i
), où
i
est le
plus petit multiple de
λ
qui soit supérieur ou égal à
µ
. Ce dernier est compris entre
µ
et
µ
+
λ
donc le coût temporel de
l’algorithme de Floyd est un O(
λ
+
µ
) et un
(
µ
). À ce coût s’ajoute un
Θ
(
λ
) pour le calcul de la période et un
Θ
(
µ
) pour la
pré-période donc le coût total de ces deux fonctions est un Θ(λ+µ).
Question 3.
def brent(f, x0):
i,j=0,1
xi, xj = x0, f(x0)
while xi != xj:
if j == 2 *i + 1:
i, xi = j, xj
j, xj = j + 1, f(xj)
return (i, j)
On constate sans peine que les valeurs prises par
i
sont les entiers de la forme
i
= 2
n
1 et que pour un tel entier
j
prend
toutes les valeurs de l’intervalle ~2n,2n+1 1.
Mais
xi
=
xj
(
i>µet λdivise ji
), avec 1
6ji6
2
n
. Notons donc
n0
le plus petit entier vérifiant 2
n
1
>µ
et
2n>λ. Lalgorithme de Brent se termine lorsque i= 2n01 et j=λ+i.
On a 2n016µ62n01 donc 2n0162µ1 et ainsi j6λ+ 2µ1.Le coût de cet algorithme est donc un Θ(λ+µ).
Il y a deux avantages à appliquer l’algorithme de Brent plutôt que celui de Floyd : il nest nécessaire que de faire un seul
parcours pour obtenir la valeur de
λ
, et à chaque étape un seul calcul de
f
est eectué, contre trois pour l’algorithme
précédent.
Question 4. On calcule bien entendu le pgcd à l’aide de l’algorithme d’Euclide :
def pgcd(a, b):
while b > 0:
a,b=b,a%b
return a
Il reste alors à définir :
def pollard(n, c):
def f(x):
return (x *x+c)%n
i,j=0,1
xi, xj = 2, f(2)
while xi != xj:
d = pgcd(n, abs(xj xi))
if d > 1:
return d
if j == 2 *i + 1:
i, xi = j, xj
j, xj = j + 1, f(xj)
return None
À l’aide de cette fonction on obtient instantanément le diviseur 274177 de F6= 226+ 1 = 18446744073709551617.
Considérons v1,...,vkdes valeurs prises aléatoirement dans ~0,n 1et pour deux de ces valeurs viet vjnotons
Xij =
1 si vi=vj
0 sinon
La probabilité pour que vi=vjest égale à 1
ndonc E[Xij ] = 1
n.
Notons
X
la variable aléatoire qui compte le nombre de paires de valeurs égales :
X =
k
X
i=1
k
X
j=i+1
Xij
. Par linéarité de
l’espérance nous avons :
E[X] =
k
X
i=1
k
X
j=i+1
E[Xij ] = k(k1)
2n.
Ainsi, dès lors que k(k1) >2nau moins une collision a probablement eu lieu, c’est-à-dire pour :
k>1 + 1 + 8n
22n.
page 2
Ceci laisse espérer qu’en moyenne on a
λ
+
µ62n
. Or dans l’algorithme de Brent on a
i6j6λ
+ 2
µ
1 donc le nombre
moyen d’étapes avant la première collision est bien un Θ(n).
Si
p
est un diviseur non trivial de
n
et
x0
i
=
ximod p
, cette suite vérifie la relation de récurrence
x0
i+1
=
˜
f
(
xi
) avec
˜
f
(
x
) =
x2
+
cmod p
. D’après ce qui précède, au bout d’un nombre d’étapes en
Θ
(
p
) l’algorithme de Brent va produire
deux valeurs
i
et
j
telles que
x0
i
=
x0
j
, ce qui implique que
p
divise
xixj
et donc
pgcd
(
n,|xixj|
). Or si
pn
il y a des
chances pour que xi,xjet donc que pgcd(n,|xixj|)< n, nous donnant ainsi un diviseur non trivial de n.
Cependant il se peut que dans certains cas la collision entre
x0
i
et
x0
j
se produise en même temps que celle entre
xi
et
xj
;
dans ce cas la méthode échoue, mais dans ce cas il est possible de recommencer avec une autre valeur de
c
. Compte tenu
du calcul précédent, plus pest petit devant n, meilleures sont les chances que la méthode réussisse.
page 3
1 / 3 100%