Maple : décomposition en facteurs premiers

Discutez d'informatique ici !
Lemniscate
Membre Relatif
Messages: 300
Enregistré le: 18 Jan 2009, 20:55

Maple : décomposition en facteurs premiers

par Lemniscate » 01 Fév 2009, 02:36

Bonjour,

J'ai fait une procédure Maple (v11) pour trouver la décomposition en produit de puissances de facteurs premiers de tout entier naturel.

La voici :

prochainpremier:=proc(a::prime)
> p:=a+1;
> while irem((p-1)!,p)(p-1) do p:=p+1;od;
> p;
> end:

premierpremier:=proc(a::integer)
> n:=a;
> p:=2;
> while irem(a,p)0 do p:=prochainpremier(p); od;
> p;
> end:

premierpremierpuissance:=proc(a::integer)
> n:=a;
> p:=premierpremier(n);
> q:=premierpremier(n);
> m:=0;
> while irem(n,p)=0 do p:=p*q;od;
> m:=ln(p/q)/ln(q);
> m;
> end:

decompremier:=proc(a::integer)
> n:=a;
> p:=premierpremier(n);
> b:=premierpremierpuissance(n);
> m:=a/(p^b);
> L:=[p^{b}];
> while m>1 do L:=[op(L),premierpremier(m)^{premierpremierpuissance(m)}]; m:=m/(premierpremier(m)^premierpremierpuissance(m));od;
> L;
> end:


Et par exemple :

> decompremier(17^3*2^3*19);
[CENTER][2^{3}, 17^{3}, 19^{1}][/CENTER]

> decompremier(126842);
[CENTER][2^{1}, 63421^{1}][/CENTER]


Pour le premier exemple, ca va très vite, mais pour le second (j'ai tapé un nombre au hasard du clavier) ca met 80 secondes environ et si je rajoute encore plusieurs chiffres mon PC n'a pas assez de mémoire !

Donc j'aimerais savoir si mon algorithme est optimisable en gardant a peu près les mêmes idées, ou si je dois plutôt chercher des exemples d'algorithmes faits par d'autres pour voir s'ils vont plus vite (ou s'il faut que j'achète un PC à la NASA !) ?

Merci pour vos réponses...

NB : J'ai utilisé le théorème de Wilson pour la procédure "prochain premier".



Avatar de l’utilisateur
fatal_error
Modérateur
Messages: 6610
Enregistré le: 22 Nov 2007, 13:00

par fatal_error » 01 Fév 2009, 03:12

Salut,

plusieurs remarques :
Code: Tout sélectionner
> p:=premierpremier(n);
> q:=premierpremier(n);

Pourquoi appeler deux fois premierpremier alors que tu peux faire p:=q
Code: Tout sélectionner
while m>1 do L:=[op(L),premierpremier(m)^{premierpremierpuissance(m )}]; m:=m/(premierpremier(m)^premierpremierpuissance(m));od;

Même remarque : tu appele deux fois premierpremier ainsi que premierpremierpuissance
De plus tu réalises deux fois l'opération puissance :
opte plutot pour
Code: Tout sélectionner
t1:=premierpermier(m);
t2:=premierpremierpuissance(n);
t3:=t1^t2;
L:=[op(L),t3];
m:=m/t3


Ensuite, tu peux appeler tes fonctions par des noms plus courts. Apres c'est mieux d'optimiser un algo que la syntaxe, mais bon, premierpermierpuissance, c'est pas tellement explicite, donc t'y perds rien...
la vie est une fête :)

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 10:52

Optimisable ? Oui : utiliser le théorème de Wilson pour détecter la primalité d'un entier, c'est totalement inefficace. Tu transformes un problème "linéaire en N" en un problème de complexité factorielle N (pire que exp(N) ! :cry: )

En plus, on n'en pas pas besoin car le plus petit diviseur > 1 d'un entier est obligatoirement premier...

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 12:53

> L:=[p^{b}];
> while m>1 do L:=[op(L),premierpremier(m)^{premierpremierpuissance(m )}];


Là, tu collectes des "choses". Si j'étais toi, j'utiliserais la structure de suite plutôt que celle de liste -> l'écrire serait plus simple !

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 12:55

Je peux te proposer un programme simple (en code maple) si tu veux, histoire de voir autre chose que ta stratégie "horrible" (tu passes plus de 99% du temps à détecter si un nombre est premier, alors que c'est absolument inutile...)

Ps : ne vois aucune agressivité dans mes lignes. :id: mes expressions sont un peu forcées, c'est tout :id:

Lemniscate
Membre Relatif
Messages: 300
Enregistré le: 18 Jan 2009, 20:55

par Lemniscate » 01 Fév 2009, 13:29

fatal_error a écrit:Ensuite, tu peux appeler tes fonctions par des noms plus courts. Apres c'est mieux d'optimiser un algo que la syntaxe, mais bon, premierpermierpuissance, c'est pas tellement explicite, donc t'y perds rien...

Je comprends pas pourquoi changer la syntaxe influe sur le nombres d'opérations de mon algorithme ? Sinon pour moi les notations étaient explicites :). Merci pour ta suggestion.

leon1789 a écrit:Je peux te proposer un programme simple (en code maple) si tu veux, histoire de voir autre chose que ta stratégie "horrible" (tu passes plus de 99% du temps à détecter si un nombre est premier, alors que c'est absolument inutile...)

Ps : ne vois aucune agressivité dans mes lignes. :id: mes expressions sont un peu forcées, c'est tout :id:


:)

Ok merci pour tes conseils. En fait je suis plutôt niveau débutant en maple, et en arithmétique je suis pas super calé non plus...

Donc je comprends tout à fait ta réaction si tu vois des choses "horribles" ! C'est comme si je faisais 10 pages de démonstration d'un résultat qui se démontre en 2 lignes !

En fait pour détecter si un nombre est premier je ne voyais pas comment faire mais tu as dit que :
le plus petit diviseur > 1 d'un entier est obligatoirement premier

je pense que c'est bon en regardant justement par exemple la décomposition en premiers du nombre ! Donc déjà la je peux aller plus vite.

j'utiliserais la structure de suite plutôt que celle de liste -> l'écrire serait plus simple !

Ok en fait je ne sais pas comment écrire une suite en Maple, mais je vois pas l'avantage par rapport à une liste (c'est pas la même chose pour Maple ? puisqu'ici la suite sera fini car je mets des nombres finis...). Peut-être que ca simplifie juste l'écriture ?

Je veux bien que tu me montres en Message Privé le programme dont tu me parles. Cela dit je suis quand même content que mon algorithme marche, même s'il n'est pas très efficace !

Merci pour vos réactions, à bientôt.

Avatar de l’utilisateur
fatal_error
Modérateur
Messages: 6610
Enregistré le: 22 Nov 2007, 13:00

par fatal_error » 01 Fév 2009, 14:20

Pour la syntaxe, ca augmente pas le nombre d'opérations de ton algo, ca doit plus etre coté gestion mémoire.
Je peux pas t'en dire plus, tout simplement parce que j'en connais pas assez (pas du tout même ( j'avouerai que l'asm c'est pas mon dada) ). En revanche c'était ecris dans mon poly de c++.
Apres, concernant maple, qui est interprété, il y a au moins le temps de lire pour la premiere fois le nom de la variable(/fonction). Ensuite, la aussi je sais pas comment ca se passe, mais si c'est des GOTO (while) sur la syntaxe de ton algo, il relit n fois le nom de la variable, et ca rajoute un peu de temps... (ce qui n'est que supposition)
la vie est une fête :)

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 17:11

Voilà ce que je te propose :

Code: Tout sélectionner
premier_diviseur := proc(N) # N est supposé >= 2
 local p ;
   p := 2 ;
   while irem(N,p)>0 do p:=p+1 od ;
   RETURN(p) ;
end :

decomposition := proc(N) # N est supposé >= 2
 local n,p,e,q,f ;
  n := N ; f := NULL ;
  while n>1 do
    p := premier_diviseur(n) ;
    e := 0 ;
    while irem(n,p,'q')=0 do n := q ; e := e +1 od ;
    f := f, p^{e} ; 
  od ;
  RETURN([f]) ;
end ;


Eviter la fonction ln (on n'est pas dans les réel ici :id:)
et utiliser la fonction RETURN pour être plus clair.

Dans la seconde proc, la variable f est une suite : tu vois la syntaxe plus simple par rapport aux listes (-> dans le but de collecter)

Je reste à ta disposition pour toute question :zen:

PS :
on peut encore optimiser facilement la recherche du plus petit diviseur de N dans la première procédure. Je te laisse proposer des trucs ...

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 17:21

Et je suis d'accord avec ffpower : évite de demander plusieurs fois le même calcul. Stocke le résultat dans une variable si tu en as besoin plusieurs fois. :zen:

Lemniscate
Membre Relatif
Messages: 300
Enregistré le: 18 Jan 2009, 20:55

par Lemniscate » 01 Fév 2009, 19:05

Merci pour ta réponse leon,

Alors, la fonction RETURN, c'est juste pour être plus compréhensible c'est ça ? On pourrait l'enlver, ca reviendrait au même ?

Je n'avais pas pensé à faire intervenir le quotient q de la division, euclidienne, c'est vrai que ca simplifie l'affaire.

leon1789 a écrit:on peut encore optimiser facilement la recherche du plus petit diviseur de N dans la première procédure. Je te laisse proposer des trucs ...


Euhh je vais dire une connerie mais on peut utiliser ma procédure "prochainpremier" :), ok c'est contre-productif...

Sinon au lieu de faire p:=p+1, on peut faire p:=p+1 la première fois (2:=3) puis aller de 2 en 2 après puisque tous les nombres premiers sauf 2 sont impairs (p:=p+2 donc 3:=5, 5:=7, etc...)

Après je sais pas comment écrire cela mais on peut faire une procédure spécifique pour les nombres N pairs (celle que tu m'as proposée, telle quelle), et une procédure spécifique pour les N impairs, qui sera la même que la tiennes sauf que la prmière procédure démarre à p:=3 et après on fait p:=p+2 !
Sinon au lieu de faire 2 procédure on peut faire

if irem(N,2)=0 then
while irem(N,p)>0 do p:=p+1;od;
else
p:=3
while irem(N,p)>0 do p:=p+2;od ;
fi;

Je vais chercher d'autres idées pour optimiser...

Avatar de l’utilisateur
fatal_error
Modérateur
Messages: 6610
Enregistré le: 22 Nov 2007, 13:00

par fatal_error » 01 Fév 2009, 19:15

(moi c'est fatal_error mais pe que ffpower a supprimé son post en passant)

Concernant le bout de code :
if irem(N,2)=0 then
while irem(N,p)>0 do p:=p+1;od;
else
p:=3
while irem(N,p)>0 do p:=p+2;od ;
fi;


Vous m'avez largué dès wilson, mais en tout cas, pour ci-dessus ca s'optimise :
pas:=1;
if irem(N,2)!=0 then
p:=3;
pas:=2;
fi;
while irem(N,p)>0 do p:=p+pas; od;
la vie est une fête :)

Lemniscate
Membre Relatif
Messages: 300
Enregistré le: 18 Jan 2009, 20:55

par Lemniscate » 01 Fév 2009, 19:22

fatal_error a écrit:Vous m'avez largué dès wilson


Ben en fait justement je ne voulais pas l'utiliser là, je l'ai juste utilisé dans le programme que j'ai écrit au début du post :)

Sinon, merci pour l'optimisation avec le "pas", l'idée est la même que la mienne mais c'est un chouya plus rapide !

Je me demandais si on pouvais, de la même manière, avoir un "pas" qui augment selon le premier diviseur premier de N ? mais alors il faudrait savoir le premier diviseur, et ca se mord la queue !

Sauf si le premier diviseur est 2 mais ca on vient de l'optimiser...

En tout ca là je trouve la procédure assez rapide

Bye !

EDIT : je crois juste qu'il y a un "!" en trop dans ce que tu as écris fatal_error :)

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 19:31

Lemniscate a écrit:Merci pour ta réponse leon,

Alors, la fonction RETURN, c'est juste pour être plus compréhensible c'est ça ? On pourrait l'enlver, ca reviendrait au même ?

En maple, en fin de proc, on peut l'enlever ok, mais :
-1- ton prof de programmation te dira peut-être que c'est plus "standard" de le mettre (comme dans d'autres langages)
-2- en plus, on voit clairement les endroits où on sort de la proc.


if irem(N,2)=0 then
while irem(N,p)>0 do p:=p+1;od;
else
p:=3
while irem(N,p)>0 do p:=p+2;od ;
fi;

Ton idée de regarder uniquement les nombres impairs est bonne, mais c'est mal programmé : le while du then sert à quoi ?

Fais plutôt comme ça (ou comme fatal_error) :
Code: Tout sélectionner
if irem(N,2)=0 then RETURN(2) fi ;
p:=3
while irem(N,p)0 do p:=p+2;od ;
RETURN(p) ;


Autre astuce : si par hasard N est premier, tu le sauras pour quelle(s) valeur(s) de p ?

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 19:35

fatal_error a écrit:(moi c'est fatal_error mais pe que ffpower a supprimé son post en passant)

Ah oui... bon faut que j'arrive de boire du champagne par bouteille entière :dingue2:

fatal_error a écrit:Vous m'avez largué dès wilson, mais en tout cas, pour ci-dessus ca s'optimise :

Le théorème de Wilson, c'est : soit p un entier > 1. Alors
p divise (p-1) ! +1 p premier

Mais il est clair que calculer (p-1) ! mod p , c'est assez utopique.

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 19:45

Lemniscate a écrit:Je me demandais si on pouvais, de la même manière, avoir un "pas" qui augment selon le premier diviseur premier de N ? mais alors il faudrait savoir le premier diviseur, et ca se mord la queue !

modulo 6, à quoi peuvent être congrus les nombres premiers ?

Lemniscate a écrit:EDIT : je crois juste qu'il y a un "!" en trop dans ce que tu as écris fatal_error :)

:!: le "!" de fatal_error, c'est pour dire "différent de". En maple, cela s'écrit "".

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 19:47

Au fait, pour vérifier tes résultats, tu as les fonction "nextprime" et "ifactor" de maple (mais tu les sais surement déjà).

Lemniscate
Membre Relatif
Messages: 300
Enregistré le: 18 Jan 2009, 20:55

par Lemniscate » 01 Fév 2009, 19:54

Re,

Alors j'ai essayé "l'optimisation" proposée par fatal_error, et il se trouve que pour calculer :
decomposition(1684565136),

1/ ca met plus de 100 sec avec fatal_error (j'ai arrêté à ce moment), donc je comprends pas pourquoi mais c'est contre productif.

EDIT : en fait ca met 13,4 sec j'avais pas compris le "=!" !


2/ Ca met 6,6 sec avec ton optimisation leon,

3/ Ca met 13,3 sec avec ton programme initial leon.

Sinon je suis d'accord que j'ai été maladroit dans l'optimisation que j'ai proposée (même si j'avais l'idée) car si N est pair, on a le résultat voulu à savoir p=2 ! donc ta procédure d'optimisation est la bonne leon...

Sinon leon, je n'ai pas de prof d'info depuis le 1er trimestre de sup (en fait j'ai pris l'option sciences industrielles au lieu d'info, contre ma volonté, parce que j'avais de trop mauvaises notes en Maths à l'époque), je suis donc en "freelance" ou en autodidacte :)

Merci pour toutes vos suggestions !

Lemniscate
Membre Relatif
Messages: 300
Enregistré le: 18 Jan 2009, 20:55

par Lemniscate » 01 Fév 2009, 20:15

leonRevolution a écrit:modulo 6, à quoi peuvent être congrus les nombres premiers ?


Alors, pour les nombres premiers compris entre 5 et 97, je trouve que les restes modulos 6 valent 5 ou 1, mais de façon "irrégulière" (enfin je ne vois pas de "suite logique" dans la succession des 1 et des 5)
Je trouve cette succession :
5,1,5,1,5,1,5,5,1,1,5,1,5,5,5,1,1,5,1,1,5,5,1.

Après pour l'utiliser dans la procédure... je vois pas encore, j'ai pas trop réfléchi mais ca me saute pas aux yeux quoi...

leon220 a écrit:Autre astuce : si par hasard N est premier, tu le sauras pour quelle(s) valeur(s) de p ?


J'ai pas compris ce que t'as voulu dire...

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 20:23

Lemniscate a écrit:Alors j'ai essayé "l'optimisation" proposée par fatal_error, et il se trouve que pour calculer :
decomposition(1684565136),

1/ ca met plus de 100 sec avec fatal_error (j'ai arrêté à ce moment), donc je comprends pas pourquoi mais c'est contre productif.

EDIT : en fait ca met 13,4 sec j'avais pas compris le "=!" !


2/ Ca met 6,6 sec avec ton optimisation leon,

3/ Ca met 13,3 sec avec ton programme initial leon.

autant !!! :hein: Chez moi, c'est instantané ! (j'ai pourtant un PC qui a 5 ans, mais maple 7...)

Pour factoriser 10^8+1 , ça commence à compter en secondes...

Avatar de l’utilisateur
leon1789
Membre Transcendant
Messages: 5475
Enregistré le: 27 Nov 2007, 16:25

par leon1789 » 01 Fév 2009, 20:29

Lemniscate a écrit:Alors, pour les nombres premiers compris entre 5 et 97, je trouve que les restes modulos 6 valent 5 ou 1, mais de façon "irrégulière" (enfin je ne vois pas de "suite logique" dans la succession des 1 et des 5)
Je trouve cette succession :
5,1,5,1,5,1,5,5,1,1,5,1,5,5,5,1,1,5,1,1,5,5,1.

Après pour l'utiliser dans la procédure... je vois pas encore, j'ai pas trop réfléchi mais ca me saute pas aux yeux quoi...

Oui, mis à part les premiers 2 et 3, tous les autres nombres premiers sont congru à 1 ou -1 mod 6

Ainsi, on peut encore accélérer : au lieu de tester 2 puis 3 +2+2+2 ..., on peut tester 2 et 3, puis tester les nombres 5 +2+4 +2+4 +2+4...
On va alors gagner un tiers du temps de calcul.

Tu vois pourquoi ?

Lemniscate a écrit:J'ai pas compris ce que t'as voulu dire...

Dans la recherche de premier diviseur, si alors N est premier, donc on peut renvoyer N ! Là, on gagne bcp si N est un grand premier...

A toi de programmer maintenant :id:

 

Retourner vers ϟ Informatique

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 4 invités

cron

Tu pars déja ?



Fais toi aider gratuitement sur Maths-forum !

Créé un compte en 1 minute et pose ta question dans le forum ;-)
Inscription gratuite

Identification

Pas encore inscrit ?

Ou identifiez-vous :

Inscription gratuite