00001
00002
00003
00004
00005
00006
00007
00028 #ifndef POLYNOMIAL_cc_
00029 #define POLYNOMIAL_cc_
00030
00031 #include <cstdlib>
00032 #include <iostream>
00033 #include <new>
00034 #include "utils.H"
00035
00036 #include "polynomial.H"
00037
00038
00040 namespace polynomial
00041 {
00042
00043
00044
00045
00046
00047
00048
00049 using std::cout;
00050 using std::cerr;
00051 using std::endl;
00052 using std::cin;
00053
00054
00055 void print (const TconstPolynom P, int k)
00056 {
00057
00058 while (--k>0)
00059 {
00060 mpz_out_str(stdout,10,P[k]);
00061 cout << "*x^" << k << " + ";
00062 }
00063 if (k==0) mpz_out_str(stdout,10,P[0]);
00064 else cout << "0";
00065 }
00066
00067 void eval(mpz_t res, const TconstPolynom P, const int k, const mpz_t x, const mpz_t m)
00068
00069 {
00070 mpz_t y;
00071 mpz_init_set(y,P[k-1]);
00072 for (int i=k-2; i>=0; --i)
00073 {
00074 mpz_mul(y,y,x); mpz_add(y,y,P[i]); mpz_mod(y,y,m);
00075 }
00076 mpz_set(res,y);
00077 mpz_clear(y);
00078 }
00079
00080
00081
00082 template<typename T> inline T ld(T n)
00083 {
00084
00085 T r = 0;
00086 while(n>>=1) ++r;
00087 return r;
00088 }
00089
00090 }
00091
00092
00093
00094
00095 #ifdef USE_DFT
00096 #include "dft.cc"
00097 #endif
00098
00099
00100
00101 namespace polynomial
00102 {
00103
00104 int classic_mul(const TPolynom __restrict__ Pr, const int kr,
00105 const TconstPolynom P1, const int k1,
00106 const TconstPolynom P2, const int k2)
00107
00108
00109
00110
00111 {
00112 if (kr<k1+k2-1) cerr << "classic_mul: Not enough memory for result polynomial" << endl;
00113 for (int i=0; i<kr; ++i) mpz_set_ui(Pr[i],0);
00114
00115 for (int i=0; i<k1; ++i)
00116 for (int j=0; j<k2; ++j)
00117 mpz_addmul(Pr[i+j],P1[i],P2[j]);
00118
00119 return k1+k2-1;
00120 }
00121
00122 int classic_mul(const TPolynom __restrict__ Pr, const int kr,
00123 const TconstPolynom P1, const int k1,
00124 const TconstPolynom P2, const int k2, const mpz_t m)
00125
00126
00127
00128
00129 {
00130 if (kr<k1+k2-1) cerr << "classic_mul: Not enough memory for result polynomial" << endl;
00131 for (int i=0; i<kr; ++i) mpz_set_ui(Pr[i],0);
00132
00133 for (int i=0; i<k1; ++i)
00134 for (int j=0; j<k2; ++j)
00135 mpz_addmul(Pr[i+j],P1[i],P2[j]);
00136
00137
00138 for (int i=k1+k2-2; i>=0; --i)
00139 mpz_mod(Pr[i],Pr[i],m);
00140 return k1+k2-1;
00141 }
00142
00143
00144 static int square_rek(const TPolynom R, const int kR,
00145 const TconstPolynom P, const int k,
00146 const TPolynom temp)
00147
00148
00149
00150
00151 {
00152 #if 1
00153 if (k==2)
00154 {
00155 mpz_mul(R[0],P[0],P[0]);
00156 mpz_mul(R[1],P[0],P[1]); mpz_mul_2exp(R[1],R[1],1);
00157 mpz_mul(R[2],P[1],P[1]);
00158 return 3;
00159 }
00160 #endif
00161 if (k==1)
00162 {
00163 mpz_mul(R[0],P[0],P[0]);
00164 return 1;
00165 }
00166
00167
00168 const int Middle=k/2;
00169
00170
00171
00172
00173
00174 const TconstPolynom PL=&P[0]; const int kPL=Middle;
00175 const TconstPolynom PH=&P[kPL]; const int kPH=k-Middle;
00176
00177 const int kH1=MAX(kPL,kPH);
00178 const TPolynom H1=&R[0];
00179 for (int i=0; i<kPL; ++i) mpz_add(H1[i],PH[i],PL[i]);
00180 for (int i=kPL; i<kH1; ++i) mpz_set(H1[i], PH[i]);
00181
00182 int kM=2*kH1-1;
00183 const TPolynom M=&R[Middle];
00184 const TPolynom temp2 = &temp[2*kH1-1];
00185 kM=square_rek(temp,kM,H1,kH1,temp2);
00186
00187 for (int i=kR-1; i>=0; --i) mpz_set_ui(R[i],0);
00188
00189 int kL=kPL+kPL-1;
00190 const TPolynom L=R;
00191 kL=square_rek(L,kL,PL,kPL,temp2);
00192
00193 int kH=kPH+kPH-1;
00194 const TPolynom H=&R[Middle*2];
00195 kH=square_rek(H,kH,PH,kPH,temp2);
00196
00197 for (int i=0; i<kL; ++i) { mpz_sub(temp[i], temp[i], L[i]); }
00198 for (int i=0; i<kH; ++i) { mpz_sub(temp[i], temp[i], H[i]); }
00199 for (int i=0; i<kM; ++i) { mpz_add(M[i], M[i], temp[i]); }
00200
00201 return 2*k-1;
00202 }
00203
00204
00205 static int mul_rek(const TPolynom R, const int kR,
00206 const TconstPolynom P1, const int k1, const TconstPolynom P2, const int k2,
00207 const TPolynom temp)
00208
00209
00210
00211
00212 {
00213 if (k1==2)
00214 {
00215 if (k2==2)
00216 {
00217
00218 mpz_add(temp[0],P1[0],P1[1]); mpz_add(temp[1],P2[0],P2[1]);
00219 mpz_mul(R[0],P1[0],P2[0]); mpz_mul(R[2],P1[1],P2[1]);
00220 mpz_mul(R[1],temp[0],temp[1]);
00221 mpz_sub(R[1],R[1],R[0]); mpz_sub(R[1],R[1],R[2]);
00222 return 3;
00223 }
00224 if (k2==3)
00225 {
00226
00227
00228
00229 mpz_add(temp[0],P1[0],P1[1]); mpz_add(temp[1],P2[0],P2[2]);
00230 mpz_add(temp[2],temp[1],P2[1]);
00231 mpz_mul(R[1],temp[0],temp[2]);
00232 mpz_sub(temp[1],temp[1],P2[1]); mpz_sub(temp[0],P1[0],P1[1]);
00233 mpz_mul(R[2],temp[0],temp[1]);
00234 mpz_mul(R[0],P1[0],P2[0]);
00235 mpz_mul(R[3],P1[1],P2[2]);
00236
00237 mpz_add(R[2],R[2],R[1]);
00238 mpz_tdiv_q_2exp(R[2],R[2],1);
00239 mpz_sub(R[1],R[1],R[2]);
00240 mpz_sub(R[2],R[2],R[0]);
00241 mpz_sub(R[1],R[1],R[3]);
00242
00243 return 4;
00244 }
00245 #ifdef VERBOSE
00246 cout << __FUNCTION__ << ": no hand-optimized code for " << k1 << "," << k2 << "." << endl;
00247 #endif
00248 }
00249
00250 if (k1==1 || k2==1)
00251 {
00252 if (k1==1 && k2==1)
00253 {
00254 mpz_mul(R[0],P1[0],P2[0]);
00255 return 1;
00256 }
00257 if (k1==1)
00258 {
00259 for (int i=0; i<k2; ++i) mpz_mul(R[i],P1[0],P2[i]);
00260 return k2;
00261 }
00262 if (k2==1)
00263 {
00264 for (int i=0; i<k1; ++i) mpz_mul(R[i],P2[0],P1[i]);
00265 return k1;
00266 }
00267 }
00268
00269
00270 #ifdef VERBOSE
00271 if (k1<4 || k2<4)
00272 {
00273 if (k1==3 && k2==3)
00274 cout << __FUNCTION__ << " : 3x3!" << endl;
00275 else
00276 cout << __FUNCTION__ << ": " << k1 << ", " << k2 << endl;
00277 }
00278 #endif
00279
00280 const int Middle=MIN(k1,k2)/2;
00281
00282
00283
00284
00285
00286
00287
00288
00289 const TconstPolynom P1L=&P1[0]; const int kP1L=Middle;
00290 const TconstPolynom P1H=&P1[kP1L]; const int kP1H=k1-Middle;
00291 const TconstPolynom P2L=&P2[0]; const int kP2L=Middle;
00292 const TconstPolynom P2H=&P2[kP2L]; const int kP2H=k2-Middle;
00293
00294 const int kH1=MAX(kP1L,kP1H), kH2=MAX(kP2L,kP2H);
00295 const TPolynom H1=&R[0], H2=&R[kH1];
00296 for (int i=0; i<kP1L; ++i) mpz_add(H1[i],P1H[i],P1L[i]);
00297 for (int i=kP1L; i<kH1; ++i) mpz_set(H1[i], P1H[i]);
00298 for (int i=0; i<kP2L; ++i) mpz_add(H2[i],P2H[i],P2L[i]);
00299 for (int i=kP2L; i<kH2; ++i) mpz_set(H2[i], P2H[i]);
00300
00301 int kM=kH1+kH2-1;
00302 const TPolynom M=&R[Middle];
00303 const TPolynom temp2 = &temp[kH1+kH2-1];
00304 kM=mul_rek(temp,kM,H1,kH1,H2,kH2,temp2);
00305
00306 for (int i=kR-1; i>=0; --i) mpz_set_ui(R[i],0);
00307
00308 int kL=kP1L+kP2L-1;
00309 const TPolynom L=R;
00310 kL=mul_rek(L,kL,P1L,kP1L,P2L,kP2L,temp2);
00311
00312 int kH=kP1H+kP2H-1;
00313 const TPolynom H=&R[Middle*2];
00314 kH=mul_rek(H,kH,P1H,kP1H,P2H,kP2H,temp2);
00315
00316 for (int i=0; i<kL; ++i) { mpz_sub(temp[i], temp[i], L[i]); }
00317 for (int i=0; i<kH; ++i) { mpz_sub(temp[i], temp[i], H[i]); }
00318 for (int i=0; i<kM; ++i) { mpz_add(M[i], M[i], temp[i]); }
00319
00320 return k1+k2-1;
00321 }
00322
00323
00324
00325 int monic_mul(const TPolynom R, const int kR,
00326 const TconstPolynom P1, int k1,
00327 const TconstPolynom P2, int k2, const mpz_t m);
00328 int monic_square(const TPolynom R, const int kR,
00329 const TconstPolynom P, int k, const mpz_t m);
00330
00331
00332 int square(const TPolynom R, const int kR, const TconstPolynom P, const int k, const mpz_t m)
00333
00334
00335
00336 {
00337 if (kR<2*k-1)
00338 {
00339 MARK;
00340 cerr << "Not enough memory for target polynomial!" << endl;
00341 cerr << "-> k=" << k << ", kR=" << kR << endl;
00342 }
00343
00344
00345
00346
00347 #ifdef USE_DFT
00348 if (dft_square_is_recommended(k))
00349 {
00350 return get_dft(2*k-1,m)->squaremod(R,kR,P,k);
00351 }
00352 #endif
00353
00354 const int estimated_operand_size = 2*mpz_sizeinbase(m,2)+5;
00355 const int tempsize = 2*2*k;
00356 const TTempPolynom temp(tempsize,estimated_operand_size);
00357
00358 const int ret=square_rek(R,kR,P,k,temp);
00359
00360 for (int i=0; i<ret; ++i)
00361 mpz_mod(R[i],R[i],m);
00362
00363 return ret;
00364 }
00365
00366
00367 int square(const TPolynom R, const int kR, const TconstPolynom P, const int k)
00368
00369
00370
00371 {
00372 if (kR<2*k-1)
00373 {
00374 MARK;
00375 cerr << "Not enough memory for result polynomial!" << endl;
00376 cerr << "-> k=" << k << ", kR=" << kR << endl;
00377 }
00378
00379 #if 0 && defined(USE_DFT)
00380
00381
00382
00383
00384
00385
00386
00387
00388 if (dft_square_is_recommended(k))
00389 {
00390 if (mpz_cmp_ui(P[k-1],1)==0) { MARK; cout << k << " -> " << 2*k-1 << endl; }
00391 return get_dft(2*k-1,m)->square(R,kR,P,k);
00392 }
00393 #endif
00394
00395 const int tempsize = 2*2*k;
00396 const TTempPolynom temp(tempsize);
00397
00398 const int ret=square_rek(R,kR,P,k,temp);
00399
00400 return ret;
00401 }
00402
00403
00404 int mul(const TPolynom R, const int kR,
00405 TconstPolynom P1, int k1,
00406 TconstPolynom P2, int k2, const mpz_t m)
00407
00408
00409
00410
00411 {
00412
00413
00414 if (kR<k1+k2-1)
00415 {
00416 MARK; cerr << "Not enough memory for result polynomial!" << endl;
00417 cerr << "-> k1=" << k1 << ", k2=" << k2 << ", kR=" << kR << endl;
00418 }
00419
00420 #if 1
00421 if ( ((k1+k2-1)&1) && mpz_cmp_ui(P1[k1-1],1)==0 && mpz_cmp_ui(P2[k2-1],1)==0 )
00422 {
00423
00424
00425 return monic_mul(R,kR,P1,k1,P2,k2,m);
00426 }
00427 #endif
00428
00429 #ifdef USE_DFT
00430 if (dft_mul_is_recommended(k1,k2))
00431 {
00432 return get_dft(k1+k2-1,m)->mulmod(R,kR,P1,k1,P2,k2);
00433 }
00434 #endif
00435
00436 if (k2<k1) { std::swap(k1,k2); std::swap(P1,P2); }
00437
00438
00439 if (2*k2>3*k1)
00440 {
00441 #if defined(VERBOSE)
00442 MARK;
00443 cout << "using classic mul for " << k1 << ", " << k2 << endl;
00444 #endif
00445 return classic_mul(R,kR,P1,k1,P2,k2,m);
00446 }
00447
00448
00449
00450 const int estimated_operand_size = 2*mpz_sizeinbase(m,2)+5;
00451 const int tempsize = 4*k2;
00452 const TTempPolynom temp(tempsize,estimated_operand_size);
00453
00454 const int ret = mul_rek(R,kR,P1,k1,P2,k2,temp);
00455 for (int i=0; i<ret; ++i)
00456 mpz_mod(R[i],R[i],m);
00457
00458 return ret;
00459 }
00460
00461 int mul(const TPolynom R, const int kR,
00462 TconstPolynom P1, int k1,
00463 TconstPolynom P2, int k2)
00464
00465
00466
00467 {
00468
00469
00470 if (kR<k1+k2-1)
00471 {
00472 cerr << "karamul: Not enough memory for result polynomial!" << endl;
00473 cerr << "-> k1=" << k1 << ", k2=" << k2 << ", kR=" << kR << endl;
00474 }
00475
00476 if (k2<k1) { std::swap(k1,k2); std::swap(P1,P2); }
00477
00478
00479 if (2*k2>3*k1)
00480 {
00481 #if defined(VERBOSE)
00482 MARK;
00483 cout << "using classic mul for " << k1 << ", " << k2 << endl;
00484 #endif
00485 return classic_mul(R,kR,P1,k1,P2,k2);
00486 }
00487
00488
00489 const int tempsize = 4*k2;
00490 const TTempPolynom temp(tempsize);
00491
00492 const int ret = mul_rek(R,kR,P1,k1,P2,k2,temp);
00493
00494 return ret;
00495 }
00496
00497
00498 int monic_mul(const TPolynom R, const int kR,
00499 const TconstPolynom P1, int k1,
00500 const TconstPolynom P2, int k2, const mpz_t m)
00501
00502
00503
00504 {
00505 if (kR<k1+k2-1)
00506 {
00507 cerr << "monic mul: Not enough memory for result polynomial!" << endl;
00508 cerr << "-> k1=" << k1 << ", k2=" << k2 << ", kR=" << kR << endl;
00509 }
00510
00511 k1--; while (mpz_cmp_ui(P1[k1],0)==0) --k1;
00512 k2--; while (mpz_cmp_ui(P2[k2],0)==0) --k2;
00513
00514 if (mpz_cmp_ui(P1[k1],1)!=0 || mpz_cmp_ui(P2[k2],1)!=0)
00515 {
00516 cerr << __FUNCTION__ << ": polynomial is not monic!" << endl;
00517 cout << "P1="; print(P1,k1+1); cout << endl;
00518 cout << "P2="; print(P2,k2+1); cout << endl;
00519 exit(1);
00520 }
00521
00522 #if 1
00523
00524 if (k1==1 && k2==1)
00525 {
00526 mpz_mul(R[0],P1[0],P2[0]); mpz_mod(R[0],R[0],m);
00527 mpz_add(R[1],P1[0],P2[0]); mpz_mod(R[1],R[1],m);
00528 mpz_set_ui(R[2],1);
00529 return 3;
00530 }
00531 #endif
00532
00533
00534
00535
00536
00537
00538
00539
00540 #ifdef USE_DFT
00541 int ret;
00542 if (dft_mul_is_recommended(k1,k2))
00543 {
00544 if (mpz_cmp_ui(P1[k1-1],1)==0 && mpz_cmp_ui(P2[k2-1],1)==0) { MARK; cout << k1+k2-1 << endl; }
00545 ret=get_dft(k1+k2-1,m)->mul(R,kR,P1,k1,P2,k2);
00546 }
00547 else
00548 ret=mul(R,kR,P1,k1,P2,k2);
00549 #else
00550 int ret=mul(R,kR,P1,k1,P2,k2);
00551 #endif
00552
00553
00554
00555
00556 while (ret<k1+k2) mpz_set_ui(R[ret++],0);
00557 mpz_set_ui(R[ret++],1);
00558
00559
00560
00561
00562
00563 for (int i=0; i<k1; ++i) mpz_add(R[i+k2],R[i+k2],P1[i]);
00564 for (int i=0; i<k2; ++i) mpz_add(R[i+k1],R[i+k1],P2[i]);
00565 for (int i=0; i<ret-1; ++i) mpz_mod(R[i],R[i],m);
00566 return ret;
00567 }
00568
00569 int monic_square(const TPolynom R, const int kR,
00570 const TconstPolynom P, int k, const mpz_t m)
00571
00572
00573
00574 {
00575 if (kR<2*k-1)
00576 {
00577 cerr << "monic square: Not enough memory for result polynomial!" << endl;
00578 cerr << "-> k=" << k << ", kR=" << kR << endl;
00579 }
00580
00581 k--; while (k && mpz_cmp_ui(P[k],0)==0) --k;
00582
00583 if (mpz_cmp_ui(P[k],1)!=0)
00584 {
00585 cerr << __FUNCTION__ << ": polynomial is not monic!" << endl;
00586 cout << "P="; print(P,k+1); cout << endl;
00587 exit(1);
00588 }
00589
00590
00591 if (k==0)
00592 {
00593 mpz_set_ui(R[0],1); return 1;
00594 }
00595
00596 #if 1
00597
00598 if (k==1)
00599 {
00600 mpz_mul(R[0],P[0],P[0]); mpz_mod(R[0],R[0],m);
00601 mpz_add(R[1],P[0],P[0]); mpz_mod(R[1],R[1],m);
00602 mpz_set_ui(R[2],1);
00603 return 3;
00604 }
00605 #endif
00606
00607
00608
00609
00610
00611
00612
00613
00614 #ifdef USE_DFT
00615 int ret;
00616 if (dft_square_is_recommended(k))
00617 {
00618 ret=get_dft(2*k-1,m)->square(R,kR,P,k);
00619 }
00620 else
00621 {
00622 ret=square(R,kR,P,k);
00623 }
00624 #else
00625 int ret=square(R,kR,P,k);
00626 #endif
00627
00628
00629
00630 while (ret<2*k) mpz_set_ui(R[ret++],0);
00631 mpz_set_ui(R[ret++],1);
00632
00633
00634
00635
00636
00637 for (int i=0; i<k; ++i) mpz_addmul_ui(R[i+k],P[i],2);
00638 for (int i=0; i<ret-1; ++i) mpz_mod(R[i],R[i],m);
00639 return ret;
00640 }
00641
00642
00643 void reciprocal2p1(TPolynom R, int &kR, const TconstPolynom f, const int np1, const mpz_t m)
00644 {
00645 const int n=np1-1;
00646 const TPolynom R1 = &R[1];
00647 TTempPolynom R2(2*np1), H(2*np1);
00648 mpz_t e, fni, x;
00649 mpz_init(e); mpz_init(fni); mpz_init(x);
00650
00651 mpz_invert(fni,f[n],m); mpz_mod(fni,fni,m);
00652 kR=1; mpz_set(R1[0],fni);
00653 mpz_neg(e,f[n-1]); mpz_mul(e,e,fni); mpz_mod(e,e,m);
00654
00655 for (int k=2; k<=n; k*=2)
00656 {
00657 const int kR2=square(R2,2*np1,R1,kR,m);
00658
00659 mul(H,2*np1,R2,kR2,&f[n-(k-1)],k,m);
00660 for (int i=0; i<k/2; ++i)
00661 {
00662 mpz_mul_2exp(R1[k/2+i],R1[i],1);
00663 mpz_set_ui(R1[i],0);
00664 }
00665 for (int i=0; i<k; ++i) mpz_sub(R1[i],R1[i],H[i+k-2]);
00666
00667 mpz_mul(e,e,e); mpz_mod(e,e,m);
00668 if (k==2)
00669 mpz_set_ui(x,0);
00670 else
00671 {
00672 mpz_mul(x,H[k-3],f[n]); mpz_mod(x,x,m);
00673 }
00674 mpz_sub(e,e,x);
00675 mpz_mul(x,f[n-k],fni); mpz_mod(x,x,m);
00676 mpz_sub(e,e,x); mpz_mod(e,e,m);
00677 kR=k;
00678 }
00679
00680
00681 mpz_mul(x,e,fni); mpz_mod(R[0],x,m);
00682 kR++;
00683
00684 mpz_clear(e); mpz_clear(fni); mpz_clear(x);
00685 }
00686
00687
00688 void reciprocal2(TPolynom R, int &kR, const TconstPolynom P, const int k, const mpz_t m)
00689 {
00690
00691
00692
00693
00694 if (k==1)
00695 {
00696 if (mpz_invert(R[0],P[0],m)==0)
00697 {
00698 cerr << __FUNCTION__ << ": inverse does not exist!" << endl;
00699 cout << "P="; print(P,k); cout << endl;
00700 char ch; cin >> ch;
00701 }
00702 kR=1;
00703 }
00704 else
00705 {
00706
00707 const int mem_kQ=3*(k>>1); TTempPolynom Q(mem_kQ);
00708 int kQ=mem_kQ;
00709 reciprocal2(Q,kQ,&P[k>>1],k>>1,m);
00710
00711
00712 const int mem_kQQ=2*kQ; TTempPolynom QQ(mem_kQQ);
00713 int kQQ=square(QQ,mem_kQQ,Q,kQ,m);
00714
00715
00716 const int mem_kB=kQQ+k; TTempPolynom B(mem_kB);
00717 int kB=mul(B,mem_kB,QQ,kQQ,P,k,m);
00718
00719
00720 for (int i=0; i<kR; ++i) mpz_set_ui(R[i],0);
00721
00722 const int d = k>>1;
00723 for (int i=0; i<kQ; ++i) mpz_mul_ui(R[d+i],Q[i],2);
00724 for (int i=k-2; i<kB; ++i) mpz_sub(R[i-(k-2)],R[i-(k-2)],B[i]);
00725 kR = d+kQ >= kB-(k-2) ? d+kQ : kB-(k-2);
00726 kR--;
00727 while (kR>0 && (mpz_cmp_ui(R[kR],0)==0)) kR--;
00728 kR++;
00729 for (int i=0; i<kR; ++i) mpz_mod(R[i],R[i],m);
00730
00731 }
00732 }
00733
00734 void reciprocal(TPolynom R, int &kR, const TconstPolynom P, const int k, const mpz_t m, const unsigned int scale )
00735 {
00736
00737
00738
00739
00740
00741 int z=1, h=k+scale;
00742 while (z<h) z<<=1;
00743
00744 int d=z-h;
00745 if (d==0 && scale==0)
00746 {
00747
00748 #if defined(VERBOSE)
00749 cout << "calling recip with power of 2" << endl;
00750 #endif
00751 reciprocal2(R,kR,P,k,m);
00752 }
00753 if (k==d+2 && scale==0)
00754 {
00755
00756 #if defined(VERBOSE)
00757 cout << "calling recip with 1+power of 2" << endl;
00758 #endif
00759 reciprocal2p1(R,kR,P,k,m);
00760 }
00761 else
00762 {
00763
00764 d+=scale;
00765 #if defined(VERBOSE)
00766 if (scale) cout << "scaling polynomial!" << endl;
00767 else cout << "no power of 2: " << k << ", " << z << ", " << d << endl;
00768 #endif
00769
00770 const int kH=z; TTempPolynom H(kH);
00771 for (int i=0; i<k; ++i) mpz_set(H[i+d],P[i]);
00772 int kR2=2*kH; TTempPolynom R2(kR2);
00773 #ifdef VERBOSE
00774 cout << __FUNCTION__ << ": calling recip" << endl;
00775 #endif
00776 reciprocal2(R2,kR2,H,kH,m);
00777 #ifdef VERBOSE
00778 cout << __FUNCTION__ << ": ...back (of calling recip)" << endl;
00779 #endif
00780 #ifdef DEBUG
00781 cout << "->"; print(R2,kR2); cout << endl;
00782 #endif
00783 d-=scale;
00784 if (kR<kR2-d) cerr << __FUNCTION__ << ": too little memory in target polynomial!" << endl;
00785 kR=kR2-d;
00786 for (int i=0; i<kR; ++i) mpz_set_ui(R[i],0);
00787 for (int i=d; i<kR2; ++i) mpz_set(R[i-d],R2[i]);
00788 }
00789 }
00790
00791
00792 void classic_div(TPolynom Q, int &kQ, TPolynom R, int &kR,
00793 const TconstPolynom P1, int k1,
00794 const TconstPolynom P2, int k2, const mpz_t m)
00795 {
00796
00797
00798
00799
00800 for (int i=0; i<kQ; ++i) mpz_set_ui(Q[i],0);
00801 for (int i=0; i<kR; ++i) mpz_set(R[i],P1[i]);
00802 kR=k1;
00803 mpz_t inv,x,y;
00804 mpz_init(inv); mpz_init(x); mpz_init(y);
00805
00806 if (k2==0)
00807 {
00808 cout << endl;
00809 MARK; cerr << "polynomial division: Division by zero (empty polynomial)!" << endl;
00810 exit(1);
00811 }
00812 kR--; k2--; k1--;
00813 while (k2>=0 && (mpz_cmp_ui(P2[k2],0))==0) k2--;
00814 if (k2<0)
00815 {
00816 cout << endl;
00817 MARK; cerr << "polynomial division: Division by zero (empty polynomial)!" << endl;
00818 exit(1);
00819 }
00820 if (mpz_invert(inv,P2[k2],m)==0)
00821 {
00822 cout << "--->";
00823 print(P2,k2+1);
00824 cout << endl;
00825 MARK; cerr << "polynomial division: Inverse doesn't exist!" << endl;
00826 exit(1);
00827 }
00828 if (k1<0)
00829 {
00830 MARK; cout << "dividend polynomial is empty." << endl;
00831 kQ=kR=0;
00832 goto done;
00833 }
00834
00835 while (kR>=k2)
00836 {
00837 const int Graddifferenz=kR-k2;
00838
00839
00840 mpz_mul(x,inv,R[kR]); mpz_mod(x,x,m);
00841 mpz_set(Q[Graddifferenz],x);
00842 mpz_set_ui(R[kR],0);
00843 kR--;
00844 for (int i=k2-1; i>=0; --i )
00845 {
00846 int j = kR+i-(k2-1);
00847 mpz_mul(y,P2[i],x);
00848 mpz_sub(y,R[j],y);
00849 mpz_mod(R[j],y,m);
00850 }
00851 }
00852
00853 while (kR>=0 && mpz_cmp_ui(R[kR],0)==0) kR--;
00854
00855 kQ=k1-k2+1; kR++;
00856 done:
00857 mpz_clear(inv); mpz_clear(x); mpz_clear(y);
00858 #if 1
00859 cout << "polynomdivision Result:" << endl;
00860 cout << "A(x) = "; print(P1,k1+1); cout << endl;
00861 cout << "B(x) = "; print(P2,k2+1); cout << endl;
00862 cout << "Q(x) = "; print(Q,kQ); cout << endl;
00863 cout << "R(x) = "; print(R,kR); cout << endl;
00864 #endif
00865 }
00866
00867
00868 void classic_mod(TPolynom R, int &kR,
00869 const TconstPolynom P1, int k1,
00870 const TconstPolynom P2, int k2, const mpz_t m)
00871
00872
00873 {
00874 #ifdef DEBUG
00875 cout << "POLMOD IN (old)" << endl;
00876 #endif
00877 for (int i=0; i<kR; ++i) mpz_set(R[i],P1[i]);
00878 kR=k1;
00879
00880
00881
00882
00883
00884
00885
00886
00887 mpz_t inv,x;
00888 mpz_init(inv); mpz_init(x);
00889
00890 if (k2==0)
00891 {
00892 cout << endl;
00893 cerr << "polynomial division: division by zero polynomial!" << endl;
00894 exit(1);
00895 }
00896 kR--; k2--; k1--;
00897 while (k2>=0 && (mpz_cmp_ui(P2[k2],0))==0) k2--;
00898 if (k2<0)
00899 {
00900 cout << endl;
00901 cerr << "polynomial division: division by zero polynomial! (-1)" << endl;
00902 exit(1);
00903 }
00904 if (mpz_invert(inv,P2[k2],m)==0)
00905 {
00906 cout << "--->";
00907 print(P2,k2+1);
00908 cout << endl;
00909 cerr << "polynomial division: inverse does not exist!" << endl;
00910 exit(1);
00911 }
00912 if (k1<0)
00913 {
00914 cout << "Division using zero-polynomial as dividend!" << endl;
00915 kR=0;
00916 goto done;
00917 }
00918
00919 while (kR>=k2)
00920 {
00921
00922 mpz_mod(R[kR],R[kR],m); mpz_mul(x,inv,R[kR]); mpz_mod(x,x,m);
00923 mpz_set_ui(R[kR],0);
00924 for (int i=k2-1; i>=0; --i)
00925 {
00926 mpz_submul(R[kR-k2+i],P2[i],x);
00927 }
00928 --kR;
00929 }
00930
00931 for (int i=kR; i>=0; --i)
00932 mpz_mod(R[i],R[i],m);
00933 while (kR>=0 && mpz_cmp_ui(R[kR],0)==0) kR--;
00934 kR++;
00935 done:
00936 mpz_clear(inv); mpz_clear(x);
00937 #ifdef DEBUG
00938 cout << "polynomial division (MODULO) Result:" << endl;
00939 cout << "A(x) = "; print(P1,k1+1); cout << endl;
00940 cout << "B(x) = "; print(P2,k2+1); cout << endl;
00941 cout << "R(x) = "; print(R,kR); cout << endl;
00942 cout << "POLMOD OUT (old)" << endl;
00943 #endif
00944 }
00945
00946
00947 void div(TPolynom Q, int &kQ,
00948 const TconstPolynom P1, const int k1,
00949 const TconstPolynom P2, const int k2, const mpz_t m)
00950 {
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962 #ifdef DEBUG
00963 cout << "div-in" << " k1=" << k1 << ", k2=" << k2 << endl;
00964 cout << "div:P1="; print(P1,k1); cout << endl;
00965 cout << "div:P2="; print(P2,k2); cout << endl;
00966 #endif
00967
00968 if ( kQ < k1-k2+1 ) cerr << "div: Zielpolynom zu klein!" << endl;
00969 if (k2<1) cerr << "Warnung: Null-Polynome bei Division!" << endl;
00970 if ( (k1>0 && mpz_cmp_ui(P1[k1-1],0)==0) ||
00971 (k2>0 && mpz_cmp_ui(P2[k2-1],0)==0) )
00972 {
00973 cerr << "div: leading zeroes! (not wanted!)" << endl;
00974 exit(1);
00975 }
00976
00977 if (k1==k2)
00978 {
00979
00980 cout << "div: Grad P1=P2 -> easy-div" << endl;
00981
00982 if (kQ<1) cerr << "Speicherproblem!" << endl;
00983 mpz_invert(Q[0],P2[k2-1],m);
00984 mpz_mul(Q[0],Q[0],P1[k1-1]); mpz_mod(Q[0],Q[0],m);
00985 kQ=(mpz_cmp_ui(Q[0],0)==0) ? 0 : 1;
00986 return;
00987 }
00988
00989 int scale=0;
00990 if (k1>=2*k2)
00991 {
00992 #ifdef VERBOSE
00993 cout << __FUNCTION__ << ": problems with reciprocal polynomial: k1>=2*k2!"
00994 << " k1,k2=" << k1 << "," << k2 << endl;
00995 #endif
00996 scale=k1-k2-1;
00997 }
00998
00999
01000 const int mem_kRP2=k2+scale; TTempPolynom RP2(mem_kRP2);
01001 int kRP2 = mem_kRP2;
01002 reciprocal(RP2,kRP2,P2,k2,m,scale);
01003
01004
01005
01006
01007 const int startP1=k1-(k1-k2+1);
01008 const int startRP2=kRP2-(k1-k2+1);
01009 #ifdef VERBOSE
01010 cout << "div-shortcut: " << startP1 << ", " << startRP2 << endl;
01011 #endif
01012 const int mem_kH=(k1-startP1)+(kRP2-startRP2)-1; TTempPolynom H(mem_kH);
01013
01014 const int kH=mul(H,mem_kH,&P1[startP1],k1-startP1,&RP2[startRP2],kRP2-startRP2,m);
01015
01016
01017 #if 0
01018 cout << "Divisionsergebnis: " << endl;
01019 cout << "full: "; print(H,kH); cout << endl;
01020 cout << "kRP2=" << kRP2 << ", k2=" << k2 << endl;
01021 #endif
01022
01023
01024 for (int i=0; i<=k1-k2; ++i) mpz_set(Q[i],H[kH-1-(k1-k2)+i]);
01025 kQ=k1-k2;
01026 while (kQ>=0 && mpz_cmp_ui(Q[kQ],0)==0) kQ--;
01027 kQ++;
01028
01029 #ifdef DEBUG
01030 cout << "div-out" << endl;
01031 #endif
01032 }
01033
01034
01035 void mod(TPolynom R, int &kR,
01036 const TconstPolynom P1, int k1,
01037 const TconstPolynom P2, int k2, const mpz_t m)
01038
01039
01040
01041
01042 {
01043
01044 #if 0 || defined(DEBUG)
01045 cout << "POLMOD IN (new)" << endl;
01046 cout << "k1=" << k1 << ", k2=" << k2 << ", kR=" << kR << endl;
01047
01048
01049 #endif
01050
01051 if (k2<1) cerr << "Warning: Null-Polynomials in mod!" << endl;
01052
01053 #ifdef VERBOSE
01054 if ( (k1>0 && mpz_cmp_ui(P1[k1-1],0)==0) ||
01055 (k2>0 && mpz_cmp_ui(P2[k2-1],0)==0) )
01056 {
01057 cerr << __FUNCTION__ << ": Unwanted leading zeros!" << "(for " << k1 << "x" << k2 << ")" <<endl;
01058 }
01059 #endif
01060
01061 k1--; while (k1>=0 && mpz_cmp_ui(P1[k1],0)==0) k1--; k1++;
01062 k2--; while (k2>=0 && mpz_cmp_ui(P2[k2],0)==0) k2--; k2++;
01063
01064 #ifdef DEBUG
01065 cout << "k1=" << k1 << ", k2=" << k2 << ", kR=" << kR << endl;
01066 cout << "mod:P1="; print(P1,k1); cout << endl;
01067 cout << "mod:P2="; print(P2,k2); cout << endl;
01068 #endif
01069
01070 if (k2>k1)
01071 {
01072 cout << "trivial mod: P1 mod P2 -> P1 for P2>P1" << endl;
01073 if (kR<k1) cerr << "Too little memory in target polynomial!" << endl;
01074 for (int i=0; i<k1; ++i) mpz_set(R[i],P1[i]);
01075 kR=k1;
01076 return;
01077 }
01078
01079 #if 1
01080
01081
01082 if (k1<150 || k2<16)
01083 {
01084
01085 classic_mod(R,kR,P1,k1,P2,k2,m);
01086 return;
01087 }
01088 #endif
01089
01090
01091 const int mem_kQ=k1-k2+1; TTempPolynom Q(mem_kQ);
01092 int kQ=mem_kQ;
01093 div(Q,kQ,P1,k1,P2,k2,m);
01094
01095
01096 const int mem_kM=kQ+k2-1; TTempPolynom M(mem_kM);
01097 if (kQ>k2)
01098 {
01099 #ifdef VERBOSE_INFO
01100 cout << "shortcut possible! kQ=" << kQ << ", k2=" << k2 << endl;
01101 #endif
01102 kQ=k2;
01103
01104 }
01105
01106
01107 #if 1
01108 mul(M,mem_kM,Q,kQ,P2,k2,m);
01109 #else
01110 int kM=mul(M,mem_kM,Q,kQ,P2,k2,m);
01111 if (kM<k2-1) cerr << "mod: problems with remainder" << endl;
01112 cout << "prod: "; print(M,kM); cout << endl;
01113 #endif
01114
01115
01116 {
01117 int i=k2-2; while (i>=0 && mpz_cmp(P1[i],M[i])==0) --i;
01118 if (i+1>kR) cerr << "mod: not enough memory in target polynomial!" << endl;
01119 kR=i+1;
01120 while (i>=0)
01121 {
01122 mpz_sub(R[i],P1[i],M[i]); mpz_mod(R[i],R[i],m);
01123 --i;
01124 }
01125 }
01126
01127 #ifdef DEBUG
01128 cout << "polynomial division (fast MODULO) Result:" << endl;
01129 cout << "A(x) = "; print(P1,k1); cout << endl;
01130 cout << "B(x) = "; print(P2,k2); cout << endl;
01131 cout << "R(x) = "; print(R,kR); cout << endl;
01132 cout << "POLMOD OUT (new)" << endl;
01133 #endif
01134 }
01135
01136
01137 static void multipoint_eval_rek(const TPolynom* R, const TconstPolynom P, const int k, TPolynom* A, const int h,
01138 const mpz_t m, mpz_t* &res, int* const pos, const int* const step, const int* const stop)
01139
01140 {
01141 #ifdef DEBUG
01142 cout << "recursive call for h=" << h << endl;
01143 #endif
01144 if (h==0)
01145 {
01146
01147 if (k==1)
01148 mpz_mod(res[0],P[0],m);
01149 else
01150 {
01151 mpz_mul(res[0],P[1],A[h][pos[h]]);
01152 mpz_sub(res[0],P[0],res[0]);
01153 mpz_mod(res[0],res[0],m);
01154 }
01155 res++;
01156 }
01157 else
01158 {
01159 int kR=k;
01160 mod(&R[h][0],kR,P,k,&A[h][pos[h]],step[h],m);
01161 multipoint_eval_rek(R,R[h],kR, A,h-1, m,res,pos,step,stop);
01162 if (pos[h-1]<stop[h-1])
01163 multipoint_eval_rek(R,R[h],kR, A,h-1, m,res,pos,step,stop);
01164 }
01165 pos[h]+=step[h];
01166 }
01167
01168
01169 void multipoint_eval(mpz_t* res,
01170 const TconstPolynom P, const int k,
01171 const mpz_t* const array_of_arguments, const int size,
01172 const mpz_t m)
01173 {
01174 if ( k<3 || size<3 || size>k-1 )
01175 {
01176 cerr << "multipoint_eval: invalid parameters!" << endl;
01177 exit(1);
01178 }
01179
01180 const int MaxHoehe = ld(size)+1;
01181
01182 TPolynom* const A = new TPolynom[MaxHoehe];
01183 int* const pos = new int[MaxHoehe];
01184 int* const steparray = new int[MaxHoehe];
01185 int* const stop = new int[MaxHoehe];
01186
01187 for (int i=0; i<MaxHoehe; ++i) pos[i]=steparray[i]=stop[i]=0;
01188
01189
01190
01191
01192 const unsigned int estimated_operand_size = 2*mpz_sizeinbase(m,2)+5;
01193
01194
01195
01196
01197
01198
01199 int h = 0, anz=size, step=2, s=anz*step;
01200 steparray[h]=step; stop[h]=s;
01201
01202 #ifdef VERBOSE
01203 cout << "calculating polynomials for depth " << h << endl;
01204 #endif
01205 A[h] = new mpz_t[s];
01206 for (int i=0, j=0; i<anz; ++i, j+=step)
01207 {
01208
01209 mpz_init_set_ui(A[h][j+1],1);
01210 mpz_init_set(A[h][j],array_of_arguments[i]); mpz_neg(A[h][j],A[h][j]);
01211 }
01212
01213
01214 while ( anz>2 || (anz==2 && k==2*size+1) )
01215 {
01216 ++h;
01217 if (h>=MaxHoehe)
01218 {
01219 cout << __FILE__ << ", " << __FUNCTION__ << ": line " << __LINE__ << endl;
01220 cerr << "too many iteration steps..." << endl;
01221 cerr << "please increase MaxHoehe and recompile!" << endl;
01222 exit(1);
01223 }
01224
01225 const int oldstep = step;
01226 const int rest = anz % 2;
01227 steparray[h]=step=step*2-1; anz=(anz/2); stop[h]=s=(anz+rest)*step;
01228 #ifdef VERBOSE
01229 cout << "calculating polynomials for depth " << h << endl;
01230 #endif
01231 A[h] = new mpz_t[s];
01232 for (int j=0; j<s; ++j) mpz_init2(A[h][j],estimated_operand_size);
01233
01234 for (int i=0, j=0; i<anz; ++i, j+=step)
01235 {
01236 monic_mul(&A[h][j],step,
01237 &A[h-1][2*i*oldstep],oldstep, &A[h-1][(2*i+1)*oldstep],oldstep,m);
01238 }
01239 if (rest)
01240 {
01241 for (int i=0; i<oldstep; i++)
01242 mpz_set(A[h][s-step+i],A[h-1][stop[h-1]-oldstep+i]);
01243 }
01244 anz+=rest;
01245 }
01246
01247
01248
01249
01250 TPolynom* const R = new TPolynom[MaxHoehe];
01251 for (int i=0; i<MaxHoehe; ++i)
01252 {
01253 R[i]=new mpz_t[k];
01254 for (int j=0; j<k; ++j) mpz_init2(R[i][j],estimated_operand_size);
01255 }
01256
01257 for (int i=0; i<anz; i++) multipoint_eval_rek(R,P,k,A,h,m,res,pos,steparray,stop);
01258
01259 for (int i=MaxHoehe-1; i>=0; --i)
01260 {
01261 for (int j=k-1; j>=0; --j) mpz_clear(R[i][j]);
01262 delete [] R[i];
01263 }
01264 delete [] R;
01265
01266 while (h>=0)
01267 {
01268 for (int i=stop[h]-1; i>=0; --i) mpz_clear(A[h][i]);
01269 delete [] A[h];
01270 --h;
01271 }
01272 delete [] pos;
01273 delete [] steparray;
01274 delete [] stop;
01275 delete [] A;
01276 }
01277
01278
01279 int construct_polynomial_from_roots
01280 (TPolynom &res,
01281 const mpz_t* const roots_array, const int size,
01282 const mpz_t m)
01283 {
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294 if (res!=NULL)
01295 {
01296 cerr << __FILE__ << ", " << __FUNCTION__ << ": line " << __LINE__ << endl;
01297 cerr << "First parameter is a call by reference," << endl;
01298 cerr << "it should initially point to NULL (to avoid memory-leaks)," << endl;
01299 cerr << "because a new pointer to new data will be generated and" << endl;
01300 cerr << "there is no need for initially data pointed by res!" << endl;
01301 exit(1);
01302 }
01303
01304 if ( size < 3 )
01305 {
01306 cerr << __FILE__ << ", " << __FUNCTION__ << ": line " << __LINE__ << endl;
01307 cerr << "Invalid parameters!" << endl;
01308 exit(1);
01309 }
01310
01311
01312
01313
01314 const unsigned int estimated_operand_size = 2*mpz_sizeinbase(m,2)+5;
01315
01316
01317
01318
01319
01320 TPolynom A,B;
01321 int h = 0, anz=size, step=2, s=anz*step;
01322 #ifdef VERBOSE
01323 cout << "calculating polynomials for depth " << h << endl;
01324 #endif
01325 A = new mpz_t[s];
01326 for (int i=0, j=0; i<anz; ++i, j+=step)
01327 {
01328
01329 mpz_init_set_ui(A[j+1],1);
01330 mpz_init_set(A[j],roots_array[i]); mpz_neg(A[j],A[j]);
01331 }
01332
01333 while (anz>1)
01334 {
01335 ++h; B=A;
01336 const int oldstep = step;
01337 const int olds = s;
01338 const int rest = anz % 2;
01339 step=step*2-1; anz=(anz/2); s=(anz+rest)*step;
01340 #ifdef VERBOSE
01341 cout << "calculating polynomials for depth " << h << endl;
01342 #endif
01343 A = new mpz_t[s];
01344 for (int j=0; j<s; ++j) mpz_init2(A[j],estimated_operand_size);
01345 for (int i=0, j=0; i<anz; ++i, j+=step)
01346 {
01347 monic_mul(&A[j],step,
01348 &B[2*i*oldstep],oldstep, &B[(2*i+1)*oldstep],oldstep,m);
01349 }
01350 if (rest)
01351 {
01352 for (int i=0; i<oldstep; i++)
01353 mpz_set(A[s-step+i],B[olds-oldstep+i]);
01354 }
01355
01356
01357
01358 for (int i=0; i<olds; ++i) mpz_clear(B[i]);
01359 delete [] B;
01360
01361 anz+=rest;
01362 }
01363
01364 --s;
01365 while (s>=0 && mpz_cmp_ui(A[s],0)==0) { mpz_clear(A[s]); --s; }
01366 ++s;
01367 res=A;
01368 return s;
01369 }
01370
01371
01372 }
01373
01374 #endif