Les solutions proposées par les candidats pour le qcm 2011

« En plus tu fais quand même beaucoup d'affirmations gratuites dans ta "preuve" »
C'est exact. C'est pour ça que ça n'a rien d'une preuve, c'est juste une description d'algorithme.
Mais presque tout est simple à prouver.

« - « Une multiplication classique de polynôme se fait O(n²/log n), que l'on peut accélérer facilement en O(n²/log² n). », les « algos classiques » c'est Karatsuba en n\^(log_2(7 ou 3, il parait :p)) et c'est mieux que tes trucs et la FFT est encore mieux. »
Merci, tu es gentil.
Tu peux donc lire la suite :
« On peut aussi utiliser Karastuba, qui donne des résultats pas mauvais »
« Enfin, on peut faire une FFT »

« tu *dérives* ? un grand O ? »
Un grand O, à l'intérieur il y a une fonction, donc oui je dérive une fonction (étrange, hein ?).
http://www.math-info.univ-paris5.fr/\~avner/MC1/L1_S1/cours/dl/node11.html

« Finalement, ton code c'est une escroquerie »
Merci. J'apprécie.
On peut voir le tien ?

« moi j'y vois juste un pivot »
Je te laisse donc zieuter le code complet
http://pastebin.com/BFDcvyQA
Je pensais juste que balancer un code beaucoup plus simple, plus lent et qui reprend pas mal de concepts de l'explication pourrait être utile.
Manifestement, tu as envie de lire 500 lignes de code franchement pas simple (les multiplications rapides par x\^k mod x\^2n+x\^n+1 j'en ai bavé...), donc te voilà rassasié.

« et d'ailleurs la complexité que tu annonces a l'air fausse (d'où vient le M(n) ?) »
Elle vient du fait que l'on peut résoudre un système linéaire carré quelconque en autant de temps qu'il en faut pour faire une multiplication.
Ici, c'est codé avec M(n)=O(N³/ln N).

Si tu veux, j'ai un algo encore plus rapide pour résoudre le problème d'un facteur sqrt(log log n). Mais comme il est encore plus dégueulasse (j'utilise toutes les lettres de l'alphabet jusqu'à M), je te laisse le chercher, le prouver et le mettre ici.

Disons que ça regroupe plusieurs algos bien différents et pas forcément très connus, donc j'ai pensé qu'il valait mieux tout développer et de mettre la liste des algos à la fin pour ceux qui n'aiment pas mes explications.
Et non je ne calcule pas A\^-1 (ni A): comment le faire en O(n²) ???
Je me ramène à p(T)x=v et j'adapte un algo pour résoudre des équations du Ax=v avec A matrice creuse pour qu'il marche dans notre cas, et que j'accélère au passage.

« Serais tu en train d'utiliser : g = O(f) alors g' = O(f') ? »
Non, je fais la même chose avec des thêtas qui ont le désavantage de mal s'écrire avec l'alphabet latin.
Le but n'était pas d'être rigoureux à fond (tu as dû remarquer que quand j'écris vecteur je ne précise pas si c'est un vecteur ligne ou colonne... les détails sont laissés au lecteur).

« La multiplication en O(n / ln(n) ) : Haveo doit se demander quel était l'algo classique ayant cette complexité (moi je vois pas) ? »
Moi non plus, c'est pourquoi j'ai mis n²/log n ; n²/log² n ; Karatsuba en n\^log 3/log n ; FFT en n log log n.
Une FFT en n/log n ça doit intéresser pas mal de monde.

Pas évident de résumer 2 semaines de travail ;)
Je laisse ça à Prologin, qui va nous faire une beeeellllllleeeeee correction.

PS : C'est qui "le gros tarée" ?

@pole4, et à un gros tarée

Edit : Le gros tarée c'est le surnom (affectif) donné à Haveo

Dérivation d'un O ... Oui étrange ... je vois pas bien à quoi ca peut servir ... Serais tu en train d'utiliser : g = O(f) alors g' = O(f') ?

La multiplication en O(n\^2 / ln(n) ) : Haveo doit se demander quel était l'algo classique ayant cette complexité (moi je vois pas) ?

Edit : nan mais O(n\^2 / ln(n) ) je vois non plus et Karatsuba c'est n\^log_2(3) pas de /ln(n) ?

En fait tu fais comme tout ceux qui le font efficacement :

0- Tu vides la grille car on peut facilement se ramener à une image nulle sauf sur un bord
1- Tu te ramènes à un système d'équations de la forme A*x = v
2- Tu trouves A\^-1
3- Tu résous ce système par A\^-1*v

Sauf que :
- Tu donnes des noms compliqués pour l'étape 1. Si tu veux, mais pas besoin d'algèbre pour faire ça ...
- Tu donnes le nom de l'algo que tu utilises pour la seconde mais en "exercice", bizarre.

Le problème de ta longue explication c'est que y a pas de parties bien déterminées, pas de plan bien clair, pas de hiérarchie, ... Et puis c'est ni une explication ni une preuve ... c'est pas clair. En tout, ce qui a pu agacer certains, c'est de voir que les gens prennent ton travail pour du "génie mathématique" et qu'ils comprennent rien parce que tu as tout caché sous couvert d'explications obscures (foireuses?). Alors que c'est dommage car c'est pas du "génie mathématique" certes mais c'est du bon boulot, du très bon boulot même de faire ces algos et sans se planter ... mais tu aurais pu les aider à comprendre \^\^

( J'ai eu du mal à comprendre, en connaissant les algos )

Tu aurais mieux fait (je pense) de donner l'idée de ton algo, un court pseudo code et des liens (wikipedia?) vers les algos que tu as utilisés (et puis c'est pas forcément utile pour le public de prologin de connaître des algos pointus de théorie des nombres).

Louis appelé par Haveo pour pourfendre le pauvre Pole4 qui écris des trucs tellement incompréhensibles qu'on dirait qu'il le fait exprès.

Moi j'pense que quitte à vouloir une solution efficace bien expliquée, autant attendre la correction des orga', ça sera sans doute plus clair que les explications à Pole4 xD

Quel débat animé, dommage que je ne comprend rien. A propos, quand est-ce que la correction du QCM sortira t'elle ? J'ai vu que l'année passée elle était déjà disponible au 22 janvier. Enfin vous êtes pas obligé de vous cassez 2 mois la tête sur la solution d'une unique personne :D

« Dérivation d'un O ... Oui étrange ... je vois pas bien à quoi ca peut servir ... Serais tu en train d'utiliser : g = O(f) alors g' = O(f') ? »
Rah vous m'avez embrouillé.
Donc on a un code qui a une complexité de f(n,m,k)=Thêta(g(n,m,k)).
On dérive g par rapport à k pour trouver le minimum de g(n,m,k) pour tout k. On a une application n,m -> k que l'on va appeler mini.
Alors pour tout application h : n,m -> k, g(n,m,h(n,m))=Oméga(g(n,m,mini(n,m)) et f(n,m,h(n,m))=Oméga(g(n,m,mini(n,m)).
Si je puis me permettre, ce n'est pas ce genre de détail qui aide...

« On peut l'obtenir en élevant à la puissance m la matrice tridiagonale, on utilise l'exponentiation rapide et un algorithme de multiplication de notre choix. »
Non.
Cas n=3, m=3
A*(1 0 0)=(1 0 1) :
1 0 0
0 0 0
0 0 0
Inversion ligne 1, colonne 0
0 0 0
1 1 0
1 0 0
Inversion ligne 2, colonne 0
0 0 0
0 1 0
0 1 0
Inversion ligne 2, colonne 1
0 0 0
0 0 0
1 0 1
Alors que T³*(1 0 0)=T²*(1 1 0)=T*(1 1 1)=(0 1 1).
En fait, A=T²+T⁰.
Tu devrais relire le début de mon post (P(2)=x²-1 magie magie).

Bon, tout le monde est un génie (surtout Pole4 :p , et un génie des mathématiques (nan je ne met pas de l'huile sur le feu \^\^)) , comme ca, tout le monde est content!
Arrêtez de vous chamailler!

Sinon, plutôt que de continuer le troll je peux donner ma solution pour l'exo 4 en quelques lignes puisqu'apparemment elle n'a pas encore été postée. C'est une solution polynomiale et assez directe. La complexité est O(n³ + log(m)*M(n) +n*m), n est la largeur et m la hauteur.

1/ On annule la grille sur toutes les lignes sauf la dernière. On appelle la dernière ligne b. Temps en n*m.
2/ On détermine la matrice A (l'application linéaire, en fait) qui à une action sur la première ligne associe l'effet sur la dernière (après avoir à nouveau annulé la grille sur toutes les lignes sauf la dernière). On peut l'obtenir en élevant à la puissance m la matrice tridiagonale, on utilise l'exponentiation rapide et un algorithme de multiplication de notre choix. Temps en log(m)*M(n).
3/ On résout Ax = b avec un simple pivot de Gauss sur F_2 (aka Z/2Z aka {0,1} aka les booléens). Temps en n³.

Et j'ai pas de code sous la main, parce qu'il se fait tard mais si la demande est insistante je peux en fournir (ça sera en OCaml).

EDIT : attention erreur à l'étape 2 cf. post de Pole4 (puis le mien) plus bas.

Effectivement je me suis un peu emporté puisqu'il faut considérer deux lignes à la fois. Avec le recul, ça correspond au début de ton algo donc sur ce point là on fait pareil. Je remet la matrice ici pour le principe :

T I
I 0

Encore désolé pour l'erreur grossière, ça devrait bien mieux marcher maintenant.

PS : j'ai pas été relire ton post mais si je l'avais fait je suis pas sur que « P(2)=x²-1 » m'aurait beaucoup aidé à rectifier mon algorithme ...
PPS : tu ne le mentionnes pas mais tes polynômes sont des polynômes de Fibonacci qui servent pas mal quand on travaille sur ces grilles.

« PPS : tu ne le mentionnes pas mais tes polynômes sont des polynômes de Fibonacci qui servent pas mal quand on travaille sur ces grilles. »
C'est normal, je ne connais pas les "polynômes de Fibonacci".

Je n'y connais rien en mathématique, mais je ne vois pas l'utilité de recoder std::bitset…
Voici ton interface :
template \<ul Taille>
struct Bitset{
Bitset (ul a=0);
void reset();
Bitset operator\^ (const Bitset\<Taille> &a) const;
void operator \^= (const Bitset\<Taille> &a);
Bitset\<Taille> operator \<\< (const int &a) const;
Bitset\<Taille> operator >> (const int &a) const;
Bitset\<Taille> operator & (const Bitset\<Taille> &a) const;
void operator = (const Bitset &a);
bool operator[] (const int &i) const;
void set (const int &i,const bool val=true);
int count() const;
void random(ul N);
bool none() const;
bool operator == (const Bitset &a) const;
void copie(ul* donnees,int nbBits);
};
Je t'invite maintenant à regarder 20.5 de n3225 (je suis pauvre j'utilise les drafts moi :p ).
La seule fonction membre de ta structure qui n'est pas déjà dans le standard est random()… 80 de tes lignes sont donc inutiles… et la sémantique standard des opérateurs n'est pas respecté (c'est secondaire ça, certes).

je ne sais pas si tu as vraiment soumis ce code, mais il y a des choses assez troublantes…
int K;

int calcK(){
K=min(2*X+1.,max(X*tailleFFT/V,1.));
}
Je ne suis pas contre les variables globales en algo, on s'en fou un peu de tout ça… mais l’absence de return me fait douter… :D

Pour ce qui est de la partie maths, malgré ce que dit haveo ça reste quand même un gros travail, mais je pense comme lui que ça a été complexifié, peut être involontairement, mais quand on voit les explications de rrk275 ou de haveo… on comprend directement l'idée, même si il nous manque des algos pour voir comment atteindre la complexité annoncé… on saisie l'idée.

Je dirais donc merci à haveo et rrk275 pour avoir expliqué aux pauvres monocéphales que nous sommes les profondeurs de l'exo 4. :p

Lorem ipsum dolor sit amet, consectetur adipiscing elit. In magna turpis, egestas eu scelerisque aliquet, tempus vel dolor. Etiam vel ante tortor. Pellentesque sed nisi ac velit facilisis semper in eu turpis. Proin condimentum vehicula leo, sit amet rutrum quam pellentesque eget. Proin pretium cursus velit et viverra. Phasellus risus ligula, tristique vitae luctus at, rutrum sed tortor. Nam iaculis, nisl interdum placerat semper, orci nibh pharetra est, at mattis dolor lorem at diam. Cras sed turpis leo. Proin vel facilisis lacus. Pellentesque ut est arcu, nec posuere lorem. Nulla metus tellus, elementum ut aliquam eu, sollicitudin at massa. Praesent tristique massa quis nibh tempus in dignissim ipsum euismod. Sed tempor, ante nec fermentum vulputate, lorem velit vestibulum felis, quis vehicula tellus sem sed felis. In vehicula tincidunt sapien, nec vulputate est vestibulum sit amet. Sed eget ornare nibh. Donec sit amet lorem non urna interdum bibendum.

Fusce nisi dui, faucibus eu commodo quis, dapibus ut leo. Phasellus non mi non eros mollis condimentum. Quisque commodo, nibh a porta gravida, lorem purus varius ligula, vitae tincidunt metus neque et velit. Curabitur dui neque, feugiat ut convallis id, tristique ut enim. Pellentesque eget dui neque, a aliquet erat. Sed non mi turpis, sagittis pulvinar ligula. In hac habitasse platea dictumst. Proin tincidunt porttitor mollis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean sed sapien non urna imperdiet luctus vitae vitae lectus. Aliquam erat volutpat. Sed quis lectus facilisis elit tempus auctor. Proin lacinia orci varius tortor lacinia ultricies. Ut consequat lacus a ipsum elementum et egestas eros placerat. Nullam ut nunc magna. Suspendisse feugiat massa ligula.

In convallis neque ac metus ornare vel pellentesque dui sodales. Sed cursus pulvinar ante nec rutrum. Maecenas malesuada porttitor tortor, ac tempus magna rhoncus in. Suspendisse pellentesque lectus sit amet felis posuere accumsan. Morbi bibendum tincidunt ante, dignissim placerat odio scelerisque in. Etiam sed ante dui. Aliquam semper dui id augue viverra vehicula. Nam eget leo nisi. Ut aliquam tortor sed odio viverra tristique. Vivamus pulvinar facilisis est, vitae ultrices turpis lobortis ut. Donec in dolor sit amet arcu convallis mollis. In pellentesque sollicitudin urna. Suspendisse velit lorem, lobortis vel euismod vitae, imperdiet et neque. Maecenas id sapien felis. Praesent vestibulum ornare luctus. Suspendisse potenti. Etiam vitae laoreet dolor.

« Je t'invite maintenant à regarder 20.5 de n3225 (je suis pauvre j'utilise les drafts moi :p ). »
Si tu veux bien me donner un lien...
Mais je doute que celle-ci permette d'accéder par blocs de 32 bits d'un coup. :/

Si vous aimez les résumés :
- on se ramène à la résolution d'un système d'équation du type Ax=B
- A=p(T) où T est une matrice tridiagonale et p un polynôme facilement calculable
- on utilise l'algorithme de Wiedemann pour résoudre p(T)x=B
- on calcule vp\^k(T)u en calculant les p\^k (modulo un polynôme annulateur de T) en effectuant les multiplications avec des FFT adaptées à Z/2Z[X]
- utilisation d'un algorithme pas de bébé/pas de géant pour diminuer le nombre de FFT.

Bande de flemmards :D

Ok ok...
Gros spoiler, donc. La fin n'est pas très amusante et franchement pas nécessaire pour comprendre le cœur de l'algo.
Bonne lecture (déconseillée aux moins de 18 ans) !

On remarque qu'une fois que l'on a choisi les applications effectuées sur la première ligne, on peut déduire celles qui sont effectuées ensuite. En effet, un 1 sur une ligne où l'on ne peut plus effectuer d'application ne peut être formé qu'en effectuant une application sur la même colonne, une ligne en-dessous.
On peut écrire cela matriciellement :
A=
(T I) T : matrice tridiagonale remplie de 1
(I 0) I : matrice identité 0 : matrice nulle.
Multiplier cette matrice par un vecteur (u v) correspond à effectuer les applications nécessaires sur u, et renvoyez les deux lignes suivantes, la ligne après u étant v, la ligne après v étant nulle.
On peut ramener le problème initial au même problème avec une image nulle, sauf sur la dernière ligne dont les valeurs sont les coordonnées du vecteur C et où on n'effectue que des applications sur la première ligne, le reste se déduisant.
Il faut donc résoudre A\^(m-1)*(x 0)=(C y).
Pour cela, on introduit B tel que B corresponde aux n premières lignes et colonnes de A\^(m-1).
On doit alors résoudre Bx=C. Cela permet de coder un algorithme en O(M(n)*log m) M(n) étant le coût d'une multiplication de matrice nxn (O(n³) en général).
Soit P(-1)=0,P(0)=1,P(n+1)=P(n)X-P(n-1) (avec P(n) € (Z/2Z)[X])
On peut prouver que A\^m=
(P(m)(T) P(m-1)(T)) T étant la même matrice tridiagonale.
(P(m-1)(T) P(m-2)(T))
Le polynôme caractéristique chi de T est P(n) o (x-1). Par le théorème de Cayley-Hamilton, il est annulateur.
Pour obtenir B, on peut donc calculer (P(m-1) % chi)(T).
On a alors un algorithme en O(n³/log n+nm/log n).
À partir d'ici, on considère que B est inversible et qu'il faut retrouver x (c'est plus simple à expliquer, plus sympa et il n'est pas très compliqué de répondre au problème d'origine une fois que l'on a compris comme faire ça).
Cherchons un polynôme annulateur non nul q de B.
Pour cela, on calcule vB\^ku pour kSoit ai tel que q=somme pour tout i de ai*x\^i
On a donc somme aiB\^i=0 et somme ai*(vB\^ku)=0, ce qui veut dire que la suite des vB\^ku est une suite récurrente linéaire à coefficient constant pour tout u et v.
L'algorithme de Berlekamp-Massey (il s'agit essentiellement d'une algorithme d'Euclide étendu sur polynômes) permet, connaissant les vB\^ku, de connaître le polynôme annulateur de la suite vB\^ku. Avec un peu de chance, celui-ci est annulateur de B. On prend donc les vecteurs u et v au hasard.
On a alors q(0)=1 et q(B)=0.
On décompose q en 1+x*r.
I+B*r(B)=0 donc I=B*r(B) et B\^-1=r(B).
Enfin x=r(B)C et pour calculer x, il faut calculer des B\^kC.
Il ne reste plus que ce problème : calculer efficacement des vecteurs ayant un rapport avec B\^ku pour 0Soit K un entier.
On calcule P\^k(m) % chi en effectuant O(K) multiplications (la réduction se fait en effectuant une multiplication par l'inverse).
On veut calculer maintenant vB\^ku pour tout 0Clairement, vB\^ku=vB\^(k/K)B\^(k%K)u.
On a l'algo suivant qui répond à cette question :
pour chaque k/K
calculer u'=B\^(k/K)u
calculer w, vecteur dont la coordonnée i est vT\^iu', pour 0 pour chaque chaque k%K
vB\^ku=(p\^(k%K) % chi)*w (produit scalaire, le polynôme étant considéré comme un vecteur)

De même, on veut calculer x=somme aiB\^iu.
x=0
pour chaque k/K
calculer u'=B\^(k/K)u
calculer T\^iu' pour 0 v=0
pour chaque chaque k%K
si ai=1
v+=p\^(k%K) % chi (le polynôme étant considéré comme un vecteur)
pour chaque i avec vi=1
x+=T\^iu'
Et voilà :)
Soit MM(n) le temps mis pour effectuer le produit de 2 polynômes de degré n sur Z/2Z[X].
Le temps total est de O(KMM(n)+n/K*n²/log n+nm/log n).
On dérive en fonction de K : MM(n)-n³/log n/K²
On choisit donc K=sqrt(n³/log n/MM(n)).
Une multiplication classique de polynôme se fait O(n²/log n), que l'on peut accélérer facilement en O(n²/log² n).
Cela donne un algorithme en O(n²/log²n*sqrt(n/log n)+nm/log n).
On peut aussi utiliser Karastuba, qui donne des résultats pas mauvais :
(ax\^n+b)(cx\^n+d)=acx\^2n+((a+b)(c+d)-ac-bd)x\^n+bd que l'on applique récursivement.
Enfin, on peut faire une FFT dans l'anneau Z/2Z[X]/(X\^2n+X\^n+1).
Les diviseurs de 0 sont les puissances de x²+x+1
On a :
- pour tout 0 0
- x\^2n=x\^n+1
- pour tout 2n0
- x\^3n=x\^n*x\^2n=x\^n(x\^n+1)=x\^2n+x\^n=1
- x\^(1+2k)=x mod x²+x+1
- x\^(2+2k)=x+1 mod x²+x+1
x est donc une racine primitive d'ordre 3n
Soit f(x)=a0+a1x+a2x\^2...
On cherche F(k)=f(omega\^k)=f(x\^k)=a0+a1x\^k+a2x\^2k...
On définit g(x)=a0+a3x\^k+a6x\^2k..., h(x)=a1+a4x\^k..., i(x)=a2+a5x\^k... et G(k), H(k), I(k) comme F(k).
On a alors F(k)=a0+a1x\^k+a2\^2k...=(a0+a3x\^3k...)+(a1x\^k+a4x\^4k...)+(a2x\^2k+a5x\^5k...)=(a0+a3x\^3k...)+x\^k(a1+a4x\^3k...)+x\^2k(a2+a5x\^3k...)=G(3k)+x\^kH(3k)+x\^2kI(3k)
Enfin, on a x\^3n=1 donc G(3(k+n))=G(3k+3n)=a0+a3x\^3kx\^3n...=a0+a3x\^3k...=G(3k).
x*x\^(3n-1)=1 donc x\^(3n-1) permet d'obtenir la FFT inverse.
De plus, on a x\^3n=1 donc x\^(3n+k)=x\^k donc on peut calculer l'exposant modulo 3n.
Pour que l'algorithme marche, il y a plusieurs conditions :
- x soit une racine primitive d'ordre 3n pour effectuer une FFT sur 3n coefficients
- les coefficients du produit doivent être de degré - le degré du produit doit lui-même être - 3n soit une puissance de 3
Cela implique que les coefficients des polynômes devant être multipliés soit de degré

L'algorithme pour multiplier 2 polynômes p,q de degré n est donc le suivant :
calculer FFT(p),FFT(q)
calculer le produit de convolution FFT(p)*FFT(q) en utilisant le même algorithme
retourner FFTinv(FFT(p)*FFT(q))

La complexité est C(n)=O(n)+sqrt(n)*C(sqrt(n))=n log log n (O(n) par étage, O(log log n) étages)
K=sqrt(n³/log n/(n log log n))=n/sqrt(log n*log log n)
D'où la complexité finale O(n²sqrt(log log n/log n)+nm/log n).
Sauf que l'on a oublié la lecture des nm entrées, chacune se fait en O(1) et donc on a un temps linéaire.

Note : ça peut se généraliser et résoudre rapidement toute équation du type p(A)x=b où A est creuse.

Exo (pour voir si vous avez bien suivi :) ) : retrouvez l'algorithme de Schönnage-Strassen, l'algorithme de Wiedemann et l'algorithme pas de bébé-pas de géant dans l'explication.
Code (pour l'algo en O(M(N)+nm/log n)) : http://pastebin.com/mWYURBrh (3 µs/matrice 15x100)

Exemple pour :
0 0 0
0 0 1
1 0 0
n=3, m=3
On appuie sur la dernière ligne, dernière colonne et ça donne comme dernière ligne :
1 1 1
A=
1 1 0 1 0 0
1 1 1 0 1 0
0 1 1 0 0 1
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
A\^3=
0 1 1 1 0 1
1 1 1 0 0 0
1 1 0 1 0 1
1 0 1 1 1 0
0 0 0 1 1 1
1 0 1 0 1 1
Donc B=
0 1 1
1 1 1
1 1 0
On cherche à résoudre
Bx=(1 1 1)
x=(0 1 0) est la seule solution.
Pour aller vite :
P(-1)=0
P(0)=1
P(1)=x
P(2)=x²+1
P(3)=x³
chi=P(3) o (x-1)=(x+1)³=x³+x²+x+1
On peut vérifier que T³+T²+T+T\^0=0
T=
1 1 0
1 1 1
0 1 1
P¹(3)=x³=x²+x+1 : on peut vérifier que B¹=T²+T+1
P²(3)=(x²+x+1)*(x²+x+1)=x⁴+x²+x=x² mod chi : on peut vérifier que B²=T²
P³(3)=x²*(x²+x+1)=x⁴+x³+x²=x mod chi : on peut vérifier que B³=T
P⁴(3)=x*(x²+x+1)=x³+x²+x=1 mod chi : on peut vérifier que B⁴=T⁰=I
P⁵(3)=1*(x²+x+1)=x²+x+1 mod chi : on peut vérifier que B⁵=T²+T+T⁰
P⁶(3)=(x²+x+1)*(x²+x+1)=x² mod chi : on peut vérifier que B⁶=T²
On choisit au hasard u=(0 0 1), v=(1 0 0).
T⁰u=(0 0 1) vT⁰u=0
T¹u=(0 1 1) vT¹u=0
T²u=(1 0 0) vT²u=1
vB⁰u=vT⁰u=0
vB¹u=vT²u+vT¹u+vT⁰u=1
vB²u=vT²u=1
vB³u=vT¹u=0
vB⁴u=vT⁰u=0
vB⁵u=vT²u+vT¹u+vT⁰u=1
vB⁶u=vT²u=1
On a donc la suite récurrente linéaire à coefficients constants 0 1 1 0 0 1 1, on cherche les coefficients.
u(n)=u(n-1)+u(n-2)+u(n-3)+u(n-4)
et u(-3)=1 u(-2)=1 u(-1)=0
Donc on peut espérer que B³+B²+B¹+B⁰=0.
D'où B⁻¹=B²+B¹+B⁰
La dernière ligne était u=(1 1 1)
T⁰u=(1 1 1)
T¹u=(0 1 0)
T²u=(1 1 1)
B⁰=T⁰
B¹=T²+T¹+T⁰
B²=T²
Donc B⁻¹=T¹
On calcule x=T¹u=(0 1 0).
Matrice des applications :
0 1 0 (x)
1 1 1
0 0 1

Résumé :
- on se ramène à la résolution d'un système d'équation du type Ax=B
- A=p(T) où T est une matrice tridiagonale et p un polynôme facilement calculable
- on utilise l'algorithme de Wiedemann pour résoudre p(T)x=B
- on calcule vp\^k(T)u en calculant les p\^k modulo un polynôme annulateur de T en effectuant les multiplications avec des FFT adaptées à Z/2Z[X]
- utilisation d'un algorithme pas de bébé/pas de géant pour diminuer le nombre de FFT.

@Pole4 : avec un peu d'imagination… facilement. Tu shift beaucoup Bitset::tab quand tu l'utilise hors de Bitset, et quand tu ne le shift pas c'est juste pour faire une affectation ou pire, un std::fill… 20.5.4 est là pour ça.
Sachant que c'est dans la lib standard, ce sera mieux optimisé que ton code en plus.

Mais ça reste du détail par rapport au reste de l'algo j'en conviens, c'est juste que je suis plus C++ que matrice moi, donc ça attire mon regard facilement. :) sry

20.5.4 c'est une section du standard ISO C++… tu devrais pouvoir le trouver en fouillant sur le site de l'ISO, et donc tu peux le faire en faisant une conjonction puis un shift, sachant que tu fais déjà des shifts, tu ne perdra pas en rapidité, surtout que comme je l'ai déjà dit ton code sera moins bien optimisé.
Pour le « je prend un petit bitset et je le xor avec un gros »… si tu veux faire ça avec un tableau d'unsigned il te faut une boucle, des shifts, des conjonctions, des divisions et des modulos. Avec un bitset, t'as seulement des shifts et des conjonctions, pas besoin de faire des boucles, divisions et des modulos comme tu le fais.
Dans ton code il y a par exemple :

for (int idBloc=0;idBloc\<tailleFFT/16;idBloc++){
bits.tab[idBit/32]\^=retenue|(polynome.tab[idBloc]\<\<(idBit%32));
retenue=((ull)polynome.tab[idBloc])>>(32-idBit%32);
idBit+=32;
}
bits.tab[idBit/32]\^=retenue|(polynome.tab[tailleFFT/16]\<\<(idBit%32));
if (idBit%32+(2*tailleFFT)%32>=32)
bits.tab[idBit/32+1]\^=((ull)polynome.tab[tailleFFT/16])>>(32-idBit%32);

Tu es même obligé d'introduire une retenue à cause de l'alignement… Avec un bitset, tu devrais certes le shift au début à cause de idBit, mais après, ça se limite à un simple xor et une affectation.

Ça aurait pu te simplifier la vie et ton code…

Tu veux prendre un slice de A à B d'un bitset de taille T ?
tonbitset>>A&\~std::bitset\<T>()>>T-B+A
en une ligne… je te propose de faire pareil avec des tableaux… moi ça me donne mal à la tête rien que d'imaginer.

Répondre au sujet

Vous devez vous enregistrer ou vous connecter pour poster des messages.